My goal is to take a command which is input by the user and execute it with a forked child process, but rather than have the child process print it to the screen, store the output in a named pipe and have the parent process display the output after the child process has completed.
I'm attempting to do so by using dup2() to redirect standard output to the named pipe I've made, but the child process simply prints the output of the command and when attempting to read from the pipe in the parent process, I get the following error:
Error reading from pipe: Bad file descriptor
I've searched for similar questions on this site but have only found solutions for using regular pipes to store the output of exec(), and I wasn't able to adapt those solutions to named pipes. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define CMDSIZE 50
#define BUFSIZE 5000
int main() {
char cmd[CMDSIZE], arg[CMDSIZE], buf[BUFSIZE];
int fd, n;
pid_t pid = fork();
if (pid < 0) {
perror("Error creating process");
return 1;
}
else if (pid == 0) {
printf("SHELL > ");
fgets(buf, BUFSIZE, stdin);
sscanf(buf, "%s %s", cmd, arg);
memset(buf, 0, BUFSIZE);
printf("Working on request...\n");
unlink("cmdpipe");
mkfifo("cmdpipe", 0777);
fd = open("cmdpipe", 0777);
dup2(fd, STDOUT_FILENO);
close(fd);
if (arg[0] == '\0')
execlp(cmd, cmd, NULL);
else
execlp(cmd, cmd, arg, NULL);
}
else {
wait(NULL);
printf("...Output ready! Displaying now.\n");
fd = open("cmdpipe", 0777);
if ((n = read(fd, buf, BUFSIZE)) < 0) {
perror("Error reading from pipe");
return n;
}
close(fd);
printf("%s\n", buf);
}
return 0;
}
Thanks.
Related
I am trying to catch the output from running the command /bin/lsx -lah /.
The output should be: bash: /bin/lsx: no such file or directory
However, I am just not getting anything in the printf().
This is the code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
int main() {
int link[2];
pid_t pid;
char foo[4096];
if (pipe(link)==-1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if(pid == 0) {
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execl("/bin/lsx", "ls", "-1", (char *)0);
die("execl");
} else {
close(link[1]);
int nbytes = read(link[0], foo, sizeof(foo));
printf("Output: (%.*s)\n", nbytes, foo);
wait(NULL);
}
return 0;
}
I am just wondering why the output is not being captured and printed in the bottom printf().
As John pointed out, you are only capturing stdout, not stderr, and well-formed programs usually send error messages to stderr (the die macro you have shown is an example of this).
A quick solution is to redirect the child processes' stderr to its stdout with another call to dup2
dup2(link[1], STDOUT_FILENO);
dup2(STDOUT_FILENO, STDERR_FILENO);
which will redirect both output streams to the single pipe.
Alternatively, capture both streams with two pipes to retain their separation as they propagate.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
ssize_t push_through(const char *prefix,
FILE *out, int in,
char *buf, size_t bufsz)
{
ssize_t bytes = read(in, buf, bufsz);
if (bytes > 0)
fprintf(out, "%s: (%.*s)\n", prefix, (int) bytes, buf);
return bytes;
}
int main(void)
{
pid_t pid;
int stdout_pipe[2];
int stderr_pipe[2];
char buffer[4096];
if (pipe(stdout_pipe) == -1 || pipe(stderr_pipe) == -1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if (pid == 0) {
close(stdout_pipe[0]);
close(stderr_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
dup2(stderr_pipe[1], STDERR_FILENO);
close(stdout_pipe[1]);
close(stderr_pipe[1]);
execl("/bin/lsx", "ls", "-1", (char *) NULL);
perror("execl failed because");
die("execl");
} else {
ssize_t outbytes, errbytes;
close(stdout_pipe[1]);
close(stderr_pipe[1]);
do {
outbytes = push_through("out", stdout, stdout_pipe[0],
buffer, sizeof buffer);
errbytes = push_through("err", stderr, stderr_pipe[0],
buffer, sizeof buffer);
} while (outbytes > 0 || errbytes > 0);
wait(NULL);
}
}
In the event that execl fails, it might be useful to call perror to print a more detailed error message.
Note that expecting the error
bash: /bin/lsx: no such file or directory
is possibly misguided, as exec* functions only defer to a shell under certain conditions.
The only mention of a shell in man 3 exec is with regards to execlp, execvp, and execvpe:
If the header of a file isn't recognized (the attempted execve(2)
failed with the error ENOEXEC), these functions will execute the
shell (/bin/sh) with the path of the file as its first argument.
(If this attempt fails, no further searching is done.)
So i am trying to understand how pipes work in UNIX and i am trying to pipe a text into sort, sort them and pipe them back to main to doo. But when the execution reaches:
Note: The program takes the text file as an argument.
execlp("sort", "sort",(char *)0);
The program stops and stays still there like its waiting from the pipe something. I know that there must be something with my understanding of UNIX piping.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid;
FILE *fdin;
long fsize;
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid = fork()) == -1){
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid != 0){
char buf[1024];
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
fread(buf, sizeof(buf), 1, fdin);
fclose(fdin);
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
}
else if (childpid == 0){
char buf[1024];
close(pipe1[1]);
close(pipe2[0]);
//dup2(pipe2[1], STDOUT_FILENO);
//dup2(pipe1[0], STDIN_FILENO);
read(pipe1[0], buf, sizeof(buf));
close(pipe1[0]);
printf("%s\n\n", buf);
dup2(pipe2[1], STDOUT_FILENO);
close(pipe2[1]);
execlp("sort", "sort",(char *)0);
printf("%s\n", buf);
exit(0);
}
// wait child
wait(NULL);
// parent read pipe 2 and print
if (childpid != 0){
// DOOOO
//read(pipe2[0], buf, 1024);
//printf("%s\n", buf);
}
return 0;
}
Dead Locked
Updated
UPDATE: 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
//char *message = "This is a message!!!";
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid[2];
FILE *fdin;
char buf[1024];
//long fsize;
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid[0] = fork()) == -1)
{
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid[0] != 0){
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
fread(buf, sizeof(buf), 1, fdin);
fclose(fdin);
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
}
else if (childpid[0] == 0){
buf[0] = '\0';
int pipe3[2];
pipe(pipe3);
close(pipe1[1]);
close(pipe2[0]);
//dup2(pipe2[1], STDOUT_FILENO);
dup2(pipe1[0], STDIN_FILENO);
//dup2(pipe3[1],STDOUT_FILENO);
read(pipe1[0], buf, sizeof(buf));
close(pipe1[0]);
write(pipe3[1], buf, sizeof(buf));
printf("-PIPED BUFF-\n%s\n\n", buf);
if ((childpid[1] = fork()) == -1){
perror("fork second child");
exit(1);
}
// Child of child (sort call)
if (childpid[1] != 0){
close(pipe2[1]);
close(pipe3[0]);
printf("I AM YOUR FATHER LOOK\n");
}else{
printf("a\n");
buf[0] = '\0';
printf("b\n");
close(pipe3[1]);
printf("c\n\n");
dup2(pipe3[0], STDIN_FILENO);
read(pipe3[0], buf, sizeof(buf));
close(pipe3[0]);
printf("-SORT BUFF-\n%s\n\n", buf);
//dup2(pipe2[1], STDOUT_FILENO);
close(pipe2[1]);
execlp("sort","sort",(char *)0);
printf("-SORTED BUFF-\n%s\n\n", buf);
exit(0);
}
// wait second child exec
wait(NULL);
//printf("%s\n", buf);
exit(0);
}
// wait child exec
//wait(NULL);
int status;
pid_t pid;
int n = 2;
while (n > 0){
pid = wait(&status);
printf("-SORTED BUFF-\n%s\n\n", buf);
--n;
}
// parent read pipe 2 and print
if (childpid[0] != 0){
printf("asd\n");
buf[0] = '\0';
dup2(pipe2[0], STDIN_FILENO);
read(pipe2[0], buf, sizeof(buf));
close(pipe2[0]);
printf("-SORTED BUFF-\n%s\n\n", buf);
}
return 0;
}
Part 1
In your parent code, you have:
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
This is problematic on multiple counts:
The parent's standard output is now the write end of the pipe used for sending information to the child. That means the parent will have to open a file or terminal or something to write the results of sort to its original standard output.
When you close(pipe1[1]), there is still an open file descriptor for the pipe (the parent's standard output), so sort never gets EOF on the pipe.
You didn't record how much data you read, so you don't know how much data you should write. You could be writing garbage to the pipe unless you know the file is bigger than 1024 bytes. You should capture the amount of data read from the file and only write that much data to the pipe. You should think about ensuring the information ends with a newline.
Since you wait() for the child to complete, but the child doesn't know its input is complete, you have a deadlock. You then have the code to read the input data, but it isn't clear where you're going to write because of the dup2().
First stage fix: remove the identified dup2().
Fretting about deadlocks
In principle, the whole design only works because sort has to read all its input before it can write any of its output. If you had a command such as awk or sed that can write output before it finishes reading its input, your two-way pipe scheme wouldn't work well on large volumes of data. The child might fill the pipe buffer (and not be able to write any more to it) while the parent is still trying to write and finds its pipe buffer is full. Both processes would be stuck in a write waiting for the other to read. There are ways around that — select(), poll(), multiple threads, etc. — but they're beyond the scope of what you want, or need, to deal with now.
Also, your program limits the input to sort to at most 1024 bytes. That isn't enough to fill any pipe buffer, which means that unless the executed command increases the amount of data it has to write back compared with what it reads in — for example, if you sent URLs to a process that fetched the data from those URLs — then you won't run into deadlocks.
Part 2
The child code seems to read the data from the pipe, then launches sort (but there's nothing left for sort to read), and seems to expect execlp() to return. The code simply needs to connect the correct ends of the pipes to standard input and output, close all the pipe file descriptors, and then execute sort. If execlp() returns, it failed — report the error.
Second stage fix: simplify the child process, and make sort do the reading and writing.
Working code
Lots of commented out bits left behind. Key error checking added. For example, check that the command line is correct before doing anything else. Often, you'd open the file before forking; this time, it is better not to do that. Report errors on standard error.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid;
FILE *fdin;
if (argc != 2)
{
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(1);
}
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid = fork()) == -1){
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid != 0){
//long fsize;
char buf[1024];
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
if (fdin == 0)
{
fprintf(stderr, "%s: failed to open file '%s'\n", argv[0], argv[1]);
exit(1);
}
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
int nbytes = fread(buf, 1, sizeof(buf), fdin);
if (nbytes <= 0)
{
fprintf(stderr, "%s: no data in file '%s'\n", argv[0], argv[1]);
exit(1);
}
fclose(fdin);
//dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, nbytes);
close(pipe1[1]);
}
else if (childpid == 0){
//char buf[1024];
close(pipe1[1]);
close(pipe2[0]);
dup2(pipe2[1], STDOUT_FILENO);
dup2(pipe1[0], STDIN_FILENO);
close(pipe2[1]);
close(pipe1[0]);
//read(pipe1[0], buf, sizeof(buf));
//close(pipe1[0]);
//printf("%s\n\n", buf);
//dup2(pipe2[1], STDOUT_FILENO);
//close(pipe2[1]);
execlp("sort", "sort",(char *)0);
fprintf(stderr, "%s: failed to exec 'sort'\n", argv[0]);
exit(1);
}
// wait child
wait(NULL);
// parent read pipe 2 and print
if (childpid != 0){
char buf[1024];
int nbytes;
while ((nbytes = read(pipe2[0], buf, sizeof(buf))) > 0)
printf("%.*s", nbytes, buf);
}
return 0;
}
Note the careful trapping of sizes on both read operations.
Consider an input file:
Harlequin
Preposterous
Animagus
Zealot
Queensbury Rules
Quaternion
Hedwig
Tensor
Tenser
The output I get is:
Animagus
Harlequin
Hedwig
Preposterous
Quaternion
Queensbury Rules
Tenser
Tensor
Zealot
This looks correct to me.
The purpose is to have the parent that open the file and write it to a pipe. In the same time we have a child that create a second pipe and read it. And again in the same time we have a second child that exec sort.
We need 2 child and 2 pipe. The first parent wait the first child and the first child wait the second child.
I don't know if it's perfect because I can't test and this king of thing is very complex:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
static int wait_and_return(pid_t pid) {
int status;
if (waitpid(pid, &status, 0) == -1) {
perror("waitpid()");
return 1;
}
return status;
}
static pid_t create_pipe_and_fork(int fd_pipe[2]) {
if (pipe(fd_pipe) == -1) {
perror("pipe()");
return -1;
}
pid_t pid = fork();
if (pid == -1) {
close(fd_pipe[0]);
close(fd_pipe[1]);
perror("fork()");
return -1;
}
return pid;
}
static int exec_sort(int fd_in, int fd_out) {
if (dup2(fd_in, STDIN_FILENO) == -1 || dup2(fd_out, STDOUT_FILENO) == -1) {
close(fd_in);
close(fd_out);
perror("dup2()");
return 1;
}
close(fd_in);
close(fd_out);
execlp("sort", "sort", (char *)NULL);
perror("execlp()");
return 1;
}
static int child(int fd) {
int fd_pipe[2];
pid_t pid = create_pipe_and_fork(fd_pipe);
if (pid == -1) {
close(fd);
return 1;
}
if (pid != 0) {
close(fd);
close(fd_pipe[1]);
char buf[4048];
ssize_t ret;
while ((ret = read(fd_pipe[0], buf, sizeof buf)) > 0) {
if (ret > INT_MAX) {
close(fd_pipe[0]);
wait_and_return(pid);
return 1;
}
printf("%.*s", (int)ret, buf);
}
close(fd_pipe[0]);
return wait_and_return(pid);
} else {
close(fd_pipe[0]);
return exec_sort(fd, fd_pipe[1]);
}
}
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "wrong argument\n");
return 1;
}
int fd_pipe[2];
pid_t pid = create_pipe_and_fork(fd_pipe);
if (pid == -1) {
return 1;
}
if (pid != 0) {
close(fd_pipe[0]);
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("fopen():");
close(fd_pipe[1]);
wait_and_return(pid);
return 1;
}
char buf[4048];
size_t ret;
while ((ret = fread(buf, sizeof *buf, sizeof buf / sizeof *buf, file))) {
write(fd_pipe[1], buf, ret);
}
fclose(file);
close(fd_pipe[1]);
return wait_and_return(pid);
} else {
close(fd_pipe[1]);
return child(fd_pipe[0]);
}
}
It possible to inverse the role of main and the last child so the main will read the result and the child will open the file. I let you try.
Here is a minimal example demonstrating my problem. I have a program forking a new subprocess and redirecting stdout to it. It works fine. Then I fork a second subprocess and redirect stdout to it and I close the first pipe. I would expect that the first subprocess receives EOF in its input pipe and terminates. Instead it remains in reading state until the main task exits. I do not understand why. I would expect the first pipe to be closed and the first child process to become a zombie.
Here is the code demonstrating the issue:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int popenin(char *command) {
int pin[2];
pid_t pid;
if (pipe(pin) != 0) exit(1);
pid = fork();
if (pid < 0) exit(1);
if (pid == 0) {
close(pin[1]);
dup2(pin[0], 0);
close(pin[0]);
execlp("bash", "bash", "-c", command, NULL);
perror("Error:");
exit(1);
} else {
close(pin[0]);
return(pin[1]);
}
}
int main() {
int fd;
fd = popenin("gzip > foo1.gz");
dup2(fd, 1);
close(fd);
printf("foo 1 content\n");fflush(stdout);
fd = popenin("gzip > foo2.gz");
close(1);
dup(fd);
close(fd);
printf("foo 2 content\n");fflush(stdout);
sleep(10000);
}
This program creates two files foo1.gz and foo2.gz, both empty and there are two gzip processes running in the system. I'd expect to see the first file completed, closed and the first gzip process to exit.
If I modify the minimal example in the following way, it works as expected.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int popenin(char *command) {
int pin[2];
pid_t pid;
if (pipe(pin) != 0) exit(1);
pid = fork();
if (pid < 0) exit(1);
if (pid == 0) {
close(pin[1]);
dup2(pin[0], 0);
close(pin[0]);
execlp("bash", "bash", "-c", command, NULL);
perror("Error:");
exit(1);
} else {
close(pin[0]);
return(pin[1]);
}
}
int main() {
int fd;
fd = popenin("gzip > foo1.gz");
dup2(fd, 1);
close(fd);
printf("foo 1 content\n");fflush(stdout);
close(1); // close(1) is moved before popenin
fd = popenin("gzip > foo2.gz");
dup(fd);
close(fd);
printf("foo 2 content\n");fflush(stdout);
sleep(10000);
}
Can somebody explain why the first version does not work?
I'm trying to make a FIFO between two programs (one being a child process of the other) so that the child can write data back to the parent. Here's what I have so far:
(Parent)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_BUF 1024
int main(int argc, char *argv[]) {
//number of seperate processes to create
int num_processes = 4;
int i = 0;
//FIFO accross processes
int fd;
char * myfifo = "/tmp/myfifo";
char buf[MAX_BUF];
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
for (i; i < num_processes; i++) {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
else if (pid == 0) {
//child now exec's
char* args[] = {"./child", "args", NULL};
execv("./child", args);
}
}
printf("Parent doing stuff\n");
//Parent wait for child
printf("Parent waiting on child\n");
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
if (fcntl(fd, F_GETFD) == -1) {
perror("fd failed");
exit(1);
}
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
//Wait for child processes to finish
int j = 0;
for (j; j < num_processes; j++) {
wait(NULL);
}
//Close FIFO
close(fd);
return 0;
}
(Child, created 4 times)
void main() {
printf("Completed\n");
//Create FIFO
int fd;
char * myfifo = "/tmp/myfifo";
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
if (fcntl(fd, F_GETFD) == -1) {
perror("open failed");
exit(1);
}
write(fd, "Hi", sizeof("Hi"));
//close(fd);
/* remove the FIFO */
//unlink(myfifo);
}
Right now, "Completed" is being printed 4 times, showing that there are 4 seperate processes running as there should be. However, only one "Received: Hi" is printed in the terminal. How come I am not getting a FIFO response from the other processes?
Any help would be greatly appreciated!
You need to check fd and make sure the open succeeded. And note that it can only succeed once, because the first child will unlink(myfifo).
The parent should also wait for all of the children to finish before reading from the fifo. And the parent should read the fifo in a loop until the fifo is empty.
The problem in your code is that there are multiple child writing to the same FIFO.
As pointed out also by user3386109 you have to wait each child and read the FIFO.
here is a sample code:
//Wait for child processes to finish
int child_status = 0;
while (wait(&child_status) != -1) {
if (WIFEXITED (child_status)) {
fprintf (stdout, "the child process exited normally, with exit code %d\n", WEXITSTATUS (child_status));
// Read The buffer
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
}
else fprintf (stderr, "the child process exited abnormally\n");
}
I also suggest to pass to the child an id (this is just a sample add checks if needed):
else if (pid == 0) {
//child now exec's
char mypid[10];
snprintf(mypid, 10, "%d", i);
char* args[] = {"./child", mypid, NULL};
execv("./child", args);
sleep(1);
That each child read in argv[1]
int mypid = atoi(argv[1]);
Please, see also this post: C Named pipe (fifo). Parent process gets stuck
Solved by putting my read statements into the loop waiting for the child processes to finish:
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
if (fcntl(fd, F_GETFD) == -1) {
perror("fd failed");
exit(1);
}
//Wait for child processes to finish
int j = 0;
for (j; j < num_processes; j++) {
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
wait(NULL);
}
//Close
close(fd);
return 0;
Question asked again and code modified...
I need to create three programs named as program0 program1 and program2 in linux.
Program0:Creates a parent with two child processes and executes program 1 and program 2 with its childs waits them to finish and close.
Program1:Takes a file name from the user and writes text to the file.It finishes writing when CTNL+D pressed and creates a pipe.After that by using cat command it writes file to stdout and uses dup() to create pipe which has file in it.
Program2:It reads filename from the pipe with the help of dup() and then executes wc command.
So far I managed to create all programs and I have no compling errors.Program 0 executes both programs.Program1 is also working and sends file to the pipe but program2 cannot read it from the pipe is prints weird symbols..
When I try to read from the pipe within the program1 it works(see the deactivated code in program1) but same code is not working if I put it inside program2.
So what how can I make program2 to read from the pipe after that I will try to execute wc command in program2 but first I should be able to see that its taking file input from the stdout so how?
I know its kinda long but please help me guys...
Program 0
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX 999
int main()
{
pid_t pid1, pid2;
pid1 = fork();
if(pid1<0)
{
fprintf(stderr,"Fork basarisiz");
exit(-1);
}
else if (pid1 ==0)/*child prosesleri*/
{
printf("program1\n");
execlp("./program1","program1",NULL);
execlp("./program2","program2",NULL);
}
else /*parent procsesleri */
{
wait(NULL);
pid2 = fork();
if(pid2<0)
{
fprintf(stderr,"Fork basarisiz");
exit(-1);
}
else if (pid2 ==0)/*child prosesleri*/
{
printf("\n");
printf("Program 2\n");
printf("\n");
execlp("./program2","program2",NULL);
//printf("\n");
}
else
{
}
/////////////////////////////////////////////////////////////////////////
wait(NULL);
printf("\n");
printf("Parent:Two child processes have successfully been created\n");
printf("Parent:Two child processes have successfully been terminated\n");
printf("Parent:This process will now terminate\n");
printf("\n");
exit(0);
}
}
Program 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX 999
int main()
{
char c[10000];
char file[10000];
int words;
printf("Child1:A text file will be created\n");
printf("Child1:Enter the name of the file\n");
scanf("%123s",file);
strcat(file,".txt");
FILE * pf;
pf = fopen(file, "w" );
if (!pf)
fprintf( stderr, "I couldn't open the file.\n" );
else
{
printf("Child1: Input a number of text lines ended, each ended by a CR (carriage return).\n");
/////////////////////////////
do
{
if (NULL != fgets(c, sizeof(c), stdin))
{
if (0 == strcmp(c, ".\n"))
{
break;
}
fprintf(pf, "%s", c);
}
else
{
if (0 != ferror(stdin))
{
fprintf(stderr, "An error occured while reading from stdin\n");
}
else
{
printf("Child1: Finish the input by CNTL^D\n");
}
break;
}
} while (1);
/////////////////////////////
}
printf("\nChild1:The file %s is succesfully created and saved in the current dictionary\n",file);
//////////////////////////////////////////////
/////////////////////////pipe///////////////
fclose(pf); // close file
char ch;
int outcount = 0;
int fd[2], nbytes;
pid_t childpid;
int i;
char f2[2];
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{ printf("\nChild1:The file written to pipe with cat\n");
close(1) ;
dup(fd[1]);
close(fd[0]);
execlp("/bin/cat", "cat", file,NULL);
}
else
{
wait(NULL);
//close(0) ;
//dup(fd[0]) ;
//close(fd[1]);
//nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
//printf("%s\n",readbuffer);
}
return(0);
}
Program 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd[2],nbytes;
pid_t childpid;
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
}
else
{
close(0) ;
dup(fd[0]) ;
close(fd[1]);
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("%s\n",readbuffer);
}
return(0);
}
You may want to check the man pages for execve(2) (for starting cat) and dup2(2) (for overriding stdin and stdout as needed) for this one. execve will overwrite the currently executing program by a different one (same PID, same file descriptors), while dup2 will allow you re-define any of the standard file descriptors to point into any file descriptor you provide to it (such as any of the ends of your pipe).