Basically I'm programming my own xargs implementation for practicing. The main difference with the original xargs is that what I do is to buffer the first 4 lines I get from stdin in the parent process and write it in the pipe I created, so it processes 4 lines at a time instead of each line. Then, in the child process I redirect stdin to the reading pipe so when I call exec it should receive the arguments. After that, when child ends, the parent should do this again until all stdin was read.
So let's say I do cat directories.txt | ./my_xargs ls where directories is a file that has:
/var/
/opt/
/dev/
I should get the result of running ls /var/ /opt/ /dev/. But instead I'm getting as if I've run just ls without parameters.
I tried several things:
Writing a file and redirecting that file descriptor to stdin. Didn't work.
I already checked the pipe is written correctly debugging and also printing the result of reading the pipe instead of calling exec.
closing stdin and opening a new file and write what I read in the child to that file. When I debug I can even see that that file descriptor is 0.
removing the line close(pd[0]); didn't work either.
#ifndef NARGS
#define NARGS 4
#endif
#define LINE_SIZE 1024
#define PATH_MAX 1024
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
typedef enum { false, true } bool;
int
main(int argc, char *argv[])
{
bool eof = false;
int pd[2];
size_t len = 0;
while (!eof) {
if (pipe(pd) == -1) {
fprintf(stderr, "Error creating pipe\n");
}
pid_t pid;
pid = fork();
if (pid == -1) {
fprintf(stderr, "Fork error\n");
}
if (pid == 0) { // child
close(pd[1]); // child doesn't write
dup2(pd[0], 0); // changing reading pipe por stdin
close(pd[0]);
execvp(argv[1], argv + 1);
perror("Exec failed.\n");
} else {
close(pd[0]); // parent doesn't read
char total_params[PATH_MAX] = "";
char* newLine = NULL;
int i = 0;
while (i < NARGS && !eof) {
// Reading stdin
eof = getline(&newLine, &len, stdin) < 1;
// Removing '\n'
if ( i+1 < NARGS) {
newLine[strcspn(newLine, "\n")] = ' ';
} else {
newLine[strcspn(newLine, "\n")] = '\0';
}
strcat(total_params, newLine);
i++;
}
free(newLine);
write(pd[1], &total_params, strlen(total_params));
close(pd[1]);
wait(NULL);
}
}
return 0;
}
Related
I am working on a program where the main program forks itself and the child process calls exec. I have set it up so that the parent process has 2 pipes StdOutPipe and StdInPipe, and the child process calls dup so that stdout writes to the StdOutPipe and stdin reads from StdInPipe. Then the parent process calls wait, after which i would like to read the entirety of the StdOutPipe into a buffer. I know you can do so by reading one character at a time, but is there a faster way to do so?
For performance reasons, one typically reads a chunk at a time, not a character at a time.
Loop,
Attempt to enlarge the buffer so it can fit CHUNK_SIZE more bytes.
If an error occurred,
Fail.
Attempt to read CHUNK_SIZE bytes from the pipe into the unused part of the buffer.
If an error occurred,
Fail.
If EOF was reached,
Break.
Increased the total number of bytes read by the number of bytes read.
A pipe is basically a byte stream which means:
There's no concept of messages or message boundaries with pipes
The process reading from a
pipe can read blocks of data of any size, regardless of the size of blocks written by
the writing process
A read from a pipe is usually blocked until atleast a byte is written to the pipe.
That said, here's how i would implement your issue.
Create two pipes, stdinpipe and stdoutpipe
Do a fork
Parent process should close the write end of the pipes and sit in a
loop, waiting until data is written to pipe
Child process should close the read end of the pipes and duplicate
STDOUT to stdoutpipe and STDIN to stdinpipe
Child process can then do an exec.
Sample code:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define STDPIPE_BUFFER_SIZE 4096
#define ARGV_SIZE 3
int main()
{
// Stdoutpipe and stdint pipe
int stdoutpipe[2], stdinpipe[2], stdin_char_count, stdout_char_count, stdout_read, stdin_read;
pid_t pid;
char stdinbuffer[STDPIPE_BUFFER_SIZE], stdoutbuffer[STDPIPE_BUFFER_SIZE];
char *argv[ARGV_SIZE]; // arguments to exec
if (pipe(stdinpipe) == -1 || pipe(stdoutpipe) == -1)
exit(1); // error occurred
// Fork and exec
switch (pid = fork())
{
case -1:
exit(1); // error
case 0:
// child close the read end of both pipes
if (close(stdinpipe[0]) == -1 || close(stdoutpipe[0]) == -1)
exit(1);
// have the pipes as the new STDIN and STDOUT
if (dup2(stdinpipe[1], STDIN_FILENO) == -1 || dup2(stdoutpipe[1], STDOUT_FILENO) == -1)
exit(1);
argv[0] = "/usr/bin/ssh"; // replace with your own program [ssh -V in my case]
argv[1] = "-V";
argv[2] = NULL;
execve(argv[0], argv, NULL);
exit(1); // if we get here something horribly bad happened
default:
// parent process
stdin_char_count = 0;
stdout_char_count = 0;
// parent close write end of both pipes
if (close(stdinpipe[1]) == -1 || close(stdoutpipe[1]) == -1)
exit(1);
for (;;)
{
stdin_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
stdout_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
if (stdin_read == 0 && stdout_read == 0)
{
stdinbuffer[stdin_char_count] = '\0';
stdoutbuffer[stdout_char_count] = '\0';
break;
}
if (stdin_read == -1 && stdout_read == -1)
exit(1); // we cant recover from this
stdin_char_count += stdin_read;
stdout_char_count += stdout_read;
}
printf("%s\n", stdoutbuffer);
wait(NULL);
}
}
source: https://man7.org/linux/man-pages/man2/pipe.2.html
You can convert the pipe into an ordinary stream and then use whatever function you find convenient to read the data. Here, getdelim() can be used to read all text up to a NUL byte which need not be sent over the pipe. Error checking is partially omitted for brevity.
Also be aware that if you want to continue interacting directly with the pipe even after opening the stream, you'll probably want to disable buffering on the stream.
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int fds[2];
if(pipe(fds) == -1) {
perror("Failed to create pipe");
exit(EXIT_FAILURE);
}
const pid_t pid = fork();
if(pid == -1) {
perror("Failed to fork");
exit(EXIT_FAILURE);
}
if(!pid) {
close(fds[0]);
const char *const msg = "Hello, world!";
if(write(fds[1], msg, strlen(msg)) == -1) {
perror("Failed to write");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
close(fds[1]);
FILE *const stream = fdopen(fds[0], "r");
if(!stream) {
perror("Failed to create stream");
exit(EXIT_FAILURE);
}
char *text = NULL;
assert(wait(NULL) != -1);
getdelim(&text, &(size_t){0}, '\0', stream);
fclose(stream);
assert(text);
puts(text);
free(text);
}
We have to write a C program that will essentially redirect stdin of one command/program to another command/program stdout, using pipes. If the program on the command line was passed ./a.out ls -l \; more, it should redirect the stdout of ls -l to more, with the \; being the delimiter. This program should work for any command/program that is in our path so: ./a.out cat filename.c \; more, should be the same as typing: cat filename.c | more.
My problem is that my program can't seem to exec properly or that the pipes are not working as expected. Basically I'm just getting no output aside from the print statement debugging I have placed. To be specific, the program prints: Exec... and then ERROR, which is all in the parent code.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void pipeit(char * pro1, char * pro2, char * p1args[], char * p2args[])
{
pid_t pid;
int fd[2];
int st;
pipe(fd);
pid = fork();
if(pid < 0)
{
printf("Error Forking...\n");
exit(-1);
}
else if(pid == 0)
{
dup2(fd[1],1);
close(fd[0]);
close(1);
printf("Exec 1...\n");
execv(pro1, p1args);
printf("ERROR\n");
}
else
{
waitpid(pid,&st,0);
if(st<0)
{
printf("Child Error\n");
}
dup2(fd[0],0);
close(fd[1]);
close(0);
printf("Exec...\n");
execv(pro2,p2args);
printf("ERROR\n");
}
return;
}
/* THIS IS JUST COMMAND LINE PARSING */
int main(int argc, char * argv[])
{
int i = 1;
char * pro1;
char * pro2;
char * first[argc+1];
char * second[argc+1];
while(i<argc && argv[i][0] != ';')
{
if(i == 1)
{
pro1 = argv[i];
}
else
{
first[i] = argv[i];
}
i++;
}
first[i] = NULL;
while(i<argc)
{
if(argv[i][0] == ';')
{
i++;
pro2 = argv[i];
}
else
{
second[i] = argv[i];
}
i++;
}
second[i] = NULL;
pipeit(pro1,pro2,first, second);
return 0;
}
In the child, you have:
dup2(fd[1],1);
close(fd[0]);
close(1);
This duplicates the pipe to standard output, but then closes standard output. Fix by not closing standard output, and by closing both ends of the pipe. Rule of thumb: if you duplicate one end of a pipe to standard input, output or error, you should close both of the original pipe descriptors.
dup2(fd[1],1);
close(fd[0]);
close(fd[1]);
You have the analogous problem in the parent with standard input being closed.
You also have the wait() in the wrong place. The processes must run concurrently. If the first process in the pipeline generates so much data that the pipe can't hold it all, the process will block. If the other process is waiting for the first process to die before it reads anything, it isn't going to work well.
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).
I have a problem where I must implement a key logger into a shell we have made in class. I am having trouble getting the flow of the program within a while loop to continue looping after a child process is created and it has ran execlp().
Here is a simple program I have made to work on the part I am having trouble with.. My main program, pipe.c, includes the parent/child process with a while loop that "should" continue getting an input from the user with fgets(), create a child process, use dup2(), write to stdout, then the child process invoke the receive.c executable which will get the input from stdin and display it..
/* file: pipe.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
int key_logger_on = 0;
int p[2];
pid_t pid;
char str[256];
char input[1024];
int status;
char * file = "test.txt";
printf("Input :: ");
while(fgets(input, sizeof(input), stdin)) {
if (pipe(p)==-1) {
perror("Pipe create error");
exit(1);
}
if ((pid=fork())==-1) {
perror("Fork create error");
exit(1);
}
if (pid==0) {
close(p[1]); // Close write
dup2(p[0],0);
close(p[0]);
execlp("receive",file,NULL);
}
else {
close(p[0]); // Close read
fflush(stdout);
dup2(p[1],1);
close(p[1]);
write(1, input, strlen(input)+1);
waitpid(pid, NULL, 0);
}
printf("Input :: ");
}
}
Here is the simple receive.c that gets the stdin of the input and displays it. The file is just a test of passing a parameter.
/* file: receive.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char input[256];
fgets(input, sizeof(input), stdin);
printf("FILE: %s RECEIVE: %s", argv[0],input);
return 0;
}
Right now, all this does for me is when ran the first time, it gets the input, sends it to stdout, child calls receive, prints out the input, and then the whole parent program exits, the while loop is ignored, everything just ends. I'm very new to forks and pipes so this is very frustrating to deal with! Even made me post a question on here for the first time! Thank you very much in advance.
Did it today as repetition task for me . CHeck this code . I tested it with your receive too :
#define PREAD 0
#define PWRITE 1
/*
*
*/
int main(int argc, char** argv) {
int key_logger_on = 0;
int pIn[2];
int pOut[2];
pid_t pid;
char str[256];
char input[1024] = "";
int status;
char file[] = "test.txt";
char buf;
printf("Input :: ");
while (fgets(input,sizeof(input),stdin)) {
char nChar;
int nResult;
if (pipe(pIn) < 0) {
perror("allocating pipe for child input redirect");
return -1;
}
if (pipe(pOut) < 0) {
close(pIn[PREAD]);
close(pIn[PWRITE]);
perror("allocating pipe for child output redirect");
return -1;
}
pid = fork();
if ( pid==0) {
// child continues here
// redirect stdin
if (dup2(pIn[PREAD], 0) == -1) {
perror("stdin");
return -1;
}
// redirect stdout
if (dup2(pOut[PWRITE], 1) == -1) {
perror("stdout");
return -1;
}
// redirect stderr
if (dup2(pOut[PWRITE], 2) == -1) {
perror("stderr");
return -1;
}
// all these are for use by parent only
close(pIn[PREAD]);
close(pIn[PWRITE]);
close(pOut[PREAD]);
close(pOut[PWRITE]);
// run child process image
nResult = execl("receive",file,NULL);
exit(nResult);
} else if (pid > 0) {
// parent continues here
// close unused file descriptors, these are for child only
close(pIn[PREAD]);
close(pOut[PWRITE]);
write(pIn[PWRITE], input, strlen(input));
// char by char reading
while (read(pOut[PREAD], &nChar, 1) == 1) {
write(STDOUT_FILENO, &nChar, 1);
}
// close we done
close(pIn[PWRITE]);
close(pOut[PREAD]);
}
printf("Input :: ");
}
}
In the code below, I am simply trying to send a file via stdin to a child process which will exec the cat OS command. The code compiles fine. Here is how I call it from the command line:
$ ./uniquify < words.txt
However, when I run it I get a seg fault error. I am really having a hard time understanding how the flow if information is supposed to work through pipes to children. I am trying to make the code as simple as possible, so I can understand it, but it is not yet making sense. Any help would be appreciated.
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define NUM_CHILDREN 2
int main(int argc, char *argv[])
{
pid_t catPid;
int writeFds[NUM_CHILDREN];
int catFds[2];
int c = 0;
FILE *writeToChildren[NUM_CHILDREN];
//create a pipe
(void) pipe(catFds);
if ((catPid = fork()) < 0) {
perror("cat fork failed");
exit(1);
}
//this is the child case
if (catPid == 0) {
//close the write end of the pipe
close(catFds[1]);
//close stdin?
close(0);
//duplicate the read side of the pipe
dup(catFds[0]);
//exec cat
execl("/bin/cat", "cat", (char *) 0);
perror("***** exec of cat failed");
exit(20);
}
else { //this is the parent case
//close the read end of the pipe
close(catFds[0]);
int p[2];
//create a pipe
pipe(p);
writeToChildren[c] = fdopen(p[1], "w");
} //only the the parent continues from here
//close file descriptor so the cat child can exit
close(catFds[1]);
char words[NUM_CHILDREN][50];
//read through the input file two words at a time
while (fscanf(stdin, "%s %s", words[0], words[1]) != EOF) {
//loop twice passing one of the words to each rev child
for (c = 0; c < NUM_CHILDREN; c++) {
fprintf(writeToChildren[c], "%s\n", words[c]);
}
}
//close all FILEs and fds by sending and EOF
for (c = 0; c < NUM_CHILDREN; c++) {
fclose(writeToChildren[c]);
close(writeFds[c]);
}
int status = 0;
//wait on all children
for (c = 0; c < (NUM_CHILDREN + 1); c++) {
wait(&status);
}
return 0;
}
Since your question seems to be about understanding how pipes and forks work, I hope below programs can help you. Please notice that this is for illustration only. It wouldn't qualify for commercial implementation, but I wanted to keep it short!
You can compile the two programs as follows:
cc pipechild.c -o pipechild
cc pipeparent.c -o pipeparent
Then execute with ./pipeparent
pipeparent.c source
/* pipeparent.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define MESSAGE "HELLO!\n"
#define INBUFSIZE 80
#define RD 0 // Read end of pipe
#define WR 1 // Write end of pipe
int main(void)
{
int ptocpipe[2]; // Parent-to-child pipe
int ctoppipe[2]; // Chile-to-parent pipe
pid_t childpid; // Process ID of child
char inbuf[80]; // Input from child
int rd; // read() return
int rdup; // dup():ed stdin for child
int wdup; // dup():ed stdout for child
char *eol; // End of line
// Create pipe for writing to child
if (pipe(ptocpipe) < 0) {
fprintf(stderr, "pipe(ptocpipe) failed!\n");
return 2;
}
// Create pipe for writing back to parent
if (pipe(ctoppipe) < 0) {
fprintf(stderr, "pipe(ctoppipe) failed!\n");
return 2;
}
// Verify that one of the pipes are working by filling it first
// in one end and then reading it from the other. The OS will
// buffer the contents for us. Note, this is not at all necessary,
// it's just to illustrate how it works!
write(ptocpipe[WR], MESSAGE, strlen(MESSAGE));
read(ptocpipe[RD], inbuf, INBUFSIZE);
if (strlen(inbuf) != strlen(MESSAGE)) {
fprintf(stderr, "Failed to flush the toilet!\n");
return 6;
} else {
printf("Wrote to myself: %s", inbuf);
}
// Next, we want to launch some interactive program which
// replies with exactly one line to each line we send to it,
// until it gets tired and returns EOF to us.
// First, we must clone ourselves by using fork(). Then the
// child process must be replaced by the interactive program.
// Problem is: How do we cheat the program to read its stdin
// from us, and send its stdout back to us?
switch (childpid = fork()) {
case -1: // Error
fprintf(stderr, "Parent: fork() failed!\n");
return 3;
case 0: // Child process
// Close the ends we don't need. If not, we might
// write back to ourselves!
close(ptocpipe[WR]);
close(ctoppipe[RD]);
// Close stdin
close(0);
// Create a "new stdin", which WILL be 0 (zero)
if ((rdup = dup(ptocpipe[RD])) < 0) {
fprintf(stderr, "Failed dup(stdin)\n");
return 4;
}
// Close stdout
close(1);
// Create a "new stdout", which WILL be 1 (one)
if ((wdup = dup(ctoppipe[WR])) < 0) {
fprintf(stderr, "Failed dup(stdout)\n");
return 5;
}
// For debugging, verify stdin and stdout
fprintf(stderr, "rdup: %d, wdup %d\n", rdup, wdup);
// Overload current process by the interactive
// child process which we want to execute.
execlp("./pipechild", "pipechild", (char *) NULL);
// Getting here means we failed to launch the child
fprintf(stderr, "Parent: execl() failed!\n");
return 4;
}
// This code is executed by the parent only!
// Close the ends we don't need, to avoid writing back to ourself
close(ptocpipe[RD]);
close(ctoppipe[WR]);
// Write one line to the child and expect a reply, or EOF.
do {
write(ptocpipe[WR], MESSAGE, strlen(MESSAGE));
if ((rd = read(ctoppipe[RD], inbuf, INBUFSIZE)) > 0) {
// Chop off ending EOL
if ((eol = rindex(inbuf, '\n')) != NULL)
*eol = '\0';
printf("Parent: Read \"%s\" from child.\n", inbuf);
}
} while (rd > 0);
fprintf(stderr, "Parent: Child done!\n");
return 0;
}
pipechild.c source
/* pipechild.c
* Note - This is only for illustration purpose!
* To be stable, we should catch/ignore signals,
* and use select() to read.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#define MAXCOUNT 5 // Maximum input lines toread
#define INBUFSIZE 80 // Buffer size
int main(void)
{
char buff[INBUFSIZE];
int remains = MAXCOUNT;
pid_t mypid;
char *eol;
mypid = getpid(); // Process-ID
fprintf(stderr, "Child %d: Started!\n", mypid);
// For each line read, write one tostdout.
while (fgets(buff, INBUFSIZE, stdin) && remains--) {
// Chop off ending EOL
if ((eol = rindex(buff, '\n')) != NULL)
*eol = '\0';
// Debug to console
fprintf(stderr, "Child %d: I got %s. %d remains.\n",
mypid, buff, 1 + remains);
// Reply to parent
sprintf(buff, "Child %d: %d remains\n", mypid, 1 + remains);
write(1, buff, strlen(buff));
}
fprintf(stderr, "Child %d: I'm done!\n", mypid);
return 0;
}