Pipe to and from child process is not working - c

I am trying to learn pipes and I am trying out this program:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<fcntl.h>
#define MAXLINE 100
void main(){
int pipe1[2],pipe2[2];
pid_t childpid;
if(pipe(pipe1)<0){
perror("Unable to create the pipe for pipe1");
exit(-1);
}
if(pipe(pipe2)<0){
perror("Unable to create the pipe for pipe1");
exit(-1);
}
childpid=fork();
printf("The child PID is:%d\n",childpid);
if(childpid==0){
printf("In the child process");
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0],pipe2[1]);
exit(0);
}
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0],pipe1[1]);
waitpid(childpid,NULL,0);
exit(0);
}
void client(int readfd,int writefd){
int n,len;
char buff[MAXLINE];
printf("Please enter the name of the file to be read:");
fgets(buff,MAXLINE,stdin);
len=strlen(buff);
if(buff[len-1]=='\n')
len--;
write(writefd,buff,len);
printf("File name written into the pipe\n");
printf("The num of bytes written are:\n",read(readfd,buff,MAXLINE));
while((n-read(readfd,buff,MAXLINE))>0){
printf("Trying to read the content\n");
write(STDOUT_FILENO,buff,n);
}
}
void server(int readfd,int writefd){
int fd,n;
char buff[MAXLINE + 1];
write(writefd,"Yello in the server process",strlen("Yello in the server process"));
if((n=read(readfd,buff,MAXLINE))==0)
perror("End of file while reading");
buff[n]='\0';
if((fd=fopen(buff,O_RDONLY))<0){
snprintf(buff+n,sizeof(buff)-n,"Can't open, %s",strerror(errno));
n=strlen(buff);
write(writefd,buff,n);
}
while( (n=read(fd,buff,MAXLINE))>0){
write(writefd,buff,n);
close(fd);
}
}
The problem is I enter the file name and the program just exits. I tried to gdb the child process by setting set "follow-fork-mode child", and still nothing happens. Any ideas as to where I could be going wrong?
Ok, some more additional debugging info is: I set the follow-fork-mode to child.and it is causing a segmentation fault at the opening of the file.
Program received signal SIGSEGV, Segmentation fault.
[Switching to process 28025]
0x00197f08 in _IO_file_fopen () from /lib/libc.so.6

This code in client() looks suspicious:
while((n-read(readfd,buff,MAXLINE))>0){
Surely, that should be:
while ((n = read(readfd, buff, MAXLINE)) > 0)
{
The change from - to = is the important one, of course; the rest are cosmetic (and one is even controversial).
You should also pay attention to compiler warnings. Given:
int fd,n;
...
if((fd=fopen(buff,O_RDONLY))<0){
There's no way this should be compiling without major warnings; fopen() returns a FILE *, not a file descriptor (int).
You also seem to have some odd communications. The server sends a message to the client before reading the file name from the client. The client, OTOH, does not necessarily read that message separately; it gets a glob of information and reports how many bytes it got. That may have included some of the file as well as the introductory message.
You shouldn't close a file in the loop that is reading from it:
while( (n=read(fd,buff,MAXLINE))>0){
write(writefd,buff,n);
close(fd);
}
The close should be outside the loop.
This code more or less works; it is messier than I'd like, but it does more or less work.
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXLINE 100
static void server(int readfd, int writefd);
static void client(int readfd, int writefd);
int main(void)
{
int pipe1[2], pipe2[2];
pid_t childpid;
if (pipe(pipe1)<0)
{
perror("Unable to create the pipe for pipe1");
exit(-1);
}
if (pipe(pipe2)<0)
{
perror("Unable to create the pipe for pipe2");
exit(-1);
}
childpid = fork();
printf("The child PID is:%d\n", childpid);
if (childpid == 0)
{
printf("In the child process\n");
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0], pipe2[1]);
exit(0);
}
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0], pipe1[1]);
waitpid(childpid, NULL, 0);
return 0;
}
static void client(int readfd, int writefd)
{
int n, len;
char buff[MAXLINE];
printf("Please enter the name of the file to be read:");
fgets(buff, MAXLINE, stdin);
len = strlen(buff);
if (buff[len-1]=='\n')
len--;
write(writefd, buff, len);
printf("File name (%.*s) written into the pipe\n", len, buff);
printf("The num of bytes written are: %d\n", (int)read(readfd, buff, MAXLINE));
while ((n = read(readfd, buff, MAXLINE)) > 0)
{
printf("Trying to read the content\n");
write(STDOUT_FILENO, buff, n);
}
}
static void server(int readfd, int writefd)
{
int fd, n;
char buff[MAXLINE + 1];
fprintf(stderr, "Server: %d\n", (int)getpid());
write(writefd, "Yello in the server process", strlen("Yello in the server process"));
if ((n = read(readfd, buff, MAXLINE))==0)
perror("End of file while reading");
buff[n] = '\0';
if ((fd = open(buff, O_RDONLY)) < 0)
{
snprintf(buff+n, sizeof(buff)-n, "Can't open, %s", strerror(errno));
n = strlen(buff);
write(writefd, buff, n);
}
else
{
while ((n = read(fd, buff, MAXLINE)) > 0)
{
if (write(writefd, buff, n) != n)
{
fprintf(stderr, "Write failed in server\n");
break;
}
}
close(fd);
}
}
Note that the code does not try using a file descriptor that it fails to open. It does not crash; the n-read(...) problem is one major part of the trouble, comments notwithstanding. The misuse of fopen() for open() was another major part of the trouble.

Related

How to use pipe and dup2 in c

I have to simulate this command using pipes in c: echo "<exp>" | bc -lq.
Process A must read a string and send it to process B;
Process B executes the "bc -lq" command and returns the result to A.
The code is this, but I can't understand why it doesn't work; in particular, the "bc" command appears to be unable to read the expression from stdin.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define LEGGI(stringa) if(scanf("%s", stringa) == 0) \
{ \
perror("Impossibile leggere la stringa"); \
exit(EXIT_FAILURE); \
} \
void closePipe(int pipeFd);
void Dup2(int pipeTempFd, int fd);
void Write(int pipeTempFd, char stringa[], int n);
void Read(int pipeTempFd, char stringa[], int n);
int main()
{
char stringa[N];
LEGGI(stringa);
int pipeFd[2];
int pRicezioneFd[2];
if(pipe(pipeFd) == -1 || pipe(pRicezioneFd) == -1)
{
perror("impossibile eseguire la pipe");
exit(EXIT_FAILURE);
}
if(strncmp(stringa, "exit", N) != 0)
{
pid_t processPid;
if((processPid = fork()) == 1)
{
perror("impossibile eseguire la fork");
exit(EXIT_FAILURE);
}
if(processPid != 0)
{
closePipe(pipeFd[0]);
closePipe(pRicezioneFd[1]);
printf("operazione: %s\n", stringa);
Write(pipeFd[1], stringa, N);
closePipe(pipeFd[1]);
read(pRicezioneFd[0], stringa, N);
closePipe(pRicezioneFd[0]);
if(wait(NULL) == -1)
{
perror("Impossibile eseguire la wait");
exit(EXIT_FAILURE);
}
printf("%s\n", stringa);
}
else
{
closePipe(pipeFd[1]);
closePipe(pRicezioneFd[0]);
Dup2(pipeFd[0], 0);
Dup2(pRicezioneFd[1], 1);
Dup2(pRicezioneFd[1], 2);
// closePipe(pipeFd[0]);
// closePipe(pRicezioneFd[1]);
if(execl("/usr/bin/bc", "bc", "-lq", NULL) == -1)
{
perror("programma non reperibile");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
void closePipe(int pipeFd)
{
if(close(pipeFd) == -1)
{
perror("impossibile chiudere il fd della pipe");
exit(EXIT_FAILURE);
}
}
void Dup2(int pipeTempFd, int fd)
{
if(dup2(pipeTempFd, fd) == -1)
{
perror("Impossibile eseguire la dup2");
exit(EXIT_FAILURE);
}
}
void Write(int pipeTempFd, char stringa[], int n)
{
if(write(pipeTempFd, stringa, n) == -1)
{
perror("impossibile scrivere sulla pipa");
exit(EXIT_FAILURE);
}
}
void Read(int pipeTempFd, char stringa[], int n)
{
if(read(pipeTempFd, stringa, n) == -1)
{
perror("impossibile leggere dalla pipe pipa");
exit(EXIT_FAILURE);
}
}
You are writing all 1024 bytes of the mostly uninitialized stringa to bc, which is then choking on illegal characters. bc expects newline terminated, "plain text" expressions.
#define N 1024
char stringa[N]; // stringa := "\236\0\0\241\177>\0\0\3704\241..."
scanf("%s", stringa); // stringa := "1+2\0\177>\0\0\3704\241..."
// ^^^^^^^^^^^^^^^^^^^^
....
Write(pipeFd[1], stringa, N); // ohimè!
You'll want something like this, instead:
Write(pipeFd[1], stringa, strlen(stringa));
Write(pipeFd[1], "\n", 1);
I think my code is similar to yours, one main change was the arguments to the exec call. Another change was that I only have 2 dup2 calls in the child process, one for changing stdin and the other for stdout. You only need to change these.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define READ_END 0
#define WRITE_END 1
int main()
{
char *input = NULL;
size_t len = 0;
ssize_t amt_read = 0;
puts("Please enter a string: ");
amt_read = getline(&input, &len, stdin);
if(amt_read < 0)
exit(EXIT_FAILURE);
pid_t pid;
int fd[2];
int fd_return[2];
// Create the pipes
pipe(fd);
pipe(fd_return);
pid = fork();
if(pid==0)
{ // If child process
dup2(fd[READ_END], STDIN_FILENO);
dup2(fd_return[WRITE_END], STDOUT_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
close(fd_return[WRITE_END]);
close(fd_return[READ_END]);
execl("/usr/bin/bc", "/usr/bin/bc", "-lq", (char *)NULL);
fprintf(stderr, "Failed to execute\n");
exit(EXIT_FAILURE);
}
else
{ // If parent process
int status;
close(fd[READ_END]);
close(fd_return[WRITE_END]);
// Write to the pipe
write(fd[WRITE_END], input, strlen(input));
close(fd[WRITE_END]);
// Wait for the child to finish
waitpid(pid, &status, 0);
char buff[N];
buff[N-1] = 0;
read(fd_return[READ_END], buff, N-1);
*(index(buff, '\n')) = '\0'; // Add null terminator on your own
close(fd_return[READ_END]);
printf("The Result is: %s\n", buff);
}
free(input);
return 0;
}
EDIT:
I edited the code and debugged it. I also changed the user input schematic so now you no longer allocated static storage for the user input, rather it is allocated dynamically and then this storage is freed at the end with free();
Note, I did leave the static storage for reading the input back in, you can change this in the future if you want.
illegal character: ^# comes from the fact that write() was writing too much, notice that now we only write strlen(buff) amount.
Note: The input to bc will not work unless the string ends like "...\n\0" luckily getline() does this by default.
Also, I left all the pipe closing the same, that was not causing the issue.

named pipe won't open in C program

I have user read/write permissions on a pipe. Group has read. Other has read. But program gets "stuck" when I run it. Program 1 is the "parent". Program 2 is the "child".
Program 1:
int main(int argc, char * argv[])
{
FILE *fptr; //for opening and closing input file
int fdw;// write to pipe;
int fdr; //read to pipe;
pid_t pid;
int inputarray[500];
int arraylength = 0; int j =0;
char *mypipe = "mypipe";
if (argc < 2)
{
printf("Need to provide the file's name. \n");
return EXIT_FAILURE;
}
//open input file
fptr = fopen(argv[1], "r");
if (fptr==NULL)
{
printf("fopen fail.\n");
return EXIT_FAILURE;
}
//read input file and fill array with integers
while (!feof(fptr))
{
fscanf(fptr,"%d",&inputarray[arraylength]);
arraylength = arraylength + 1;
}
fclose(fptr); //close input file
pid = fork();
mkfifo(mypipe, 0666);
fdw = open("mypipe",O_WRONLY);
if (fdw < 0)
{
perror("File can't open to write.");
return;
}
int b;
b=3;
write(fdw,&b,sizeof(b));
close(fdw);
if ( pid ==-1)
{
perror("fork");
exit(1);
}
int status; //exit status of child
if(pid==0)//if child process
{
execl("program2", (char*) NULL);
}
else //if parent process
{
wait(&status);}
if((WIFEXITED(status)))
{
printf("Child's exit code %d", WEXITSTATUS(status));
}
else{
printf("Child did not terminate with exit");}
}
Program 2:
int fdl;
int data;
fdl = open("mypipe",O_RDONLY);
if ( fdl < 0)
{
perror("File can't open to read.");
return;
}
read(fdl,&data,sizeof(data));
close(fdl);
The program will block on writing to the fifo until what it's writing is being read. The reading in the child process won't happen since the execl() doesn't happen until after the writing.
Also, it looks like both processes will actually attempt to write to the fifo since you fork() and then immediately start writing.
You should fork(), then test on the returned PID. The parent should then write to the fifo while the child should call execl(). The fifo should be created by the parent before the fork() call.
You should also consider using indent or clang-format to properly format your code, which eases reading it and may expose bugs (forgotten curly braces etc.).
A simple complete example program. The parent writes a string to the child and the child reads it character by character and outputs it to standard output:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
void parent(void);
void child(void);
int main(void) {
pid_t pid;
mkfifo("myfifo", 0666); /* fails if exists, but we don't care here */
if ((pid = fork()) < 0)
abort();
if (pid == 0)
child(); /* will not return */
else
parent();
return EXIT_SUCCESS;
}
void parent(void) {
int fd;
int len;
int ret;
int stat;
char *ptr;
char *msg = "Hello World!";
if ((fd = open("myfifo", O_WRONLY)) < 0)
abort();
len = strlen(msg) + 1;
ptr = msg;
puts("Parent: About to write to child");
while ((ret = write(fd, ptr, len)) != 0) {
if (ret > 0) {
len -= ret;
ptr += ret;
} else
abort();
}
close(fd);
puts("Parent: Waiting for child to exit");
wait(&stat);
printf("Parent: Child exited with status %d\n", stat);
}
void child(void) {
int fd;
int ret;
char ch;
if ((fd = open("myfifo", O_RDONLY)) < 0)
abort();
puts("Child: About to read from parent");
while ((ret = read(fd, &ch, 1)) != 0) {
if (ret > 0)
putchar(ch);
else
abort();
}
putchar('\n');
close(fd);
puts("Child: I'm done here");
exit(EXIT_SUCCESS);
}
In this case, since both child and parent processes are in the same context, I could have used an anonymous pipe pair created with pipe(), but this illustrates the flow, including the creation of the named pipe.

Pipe to sort and back to main

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.

Parent process killing child process in infinite loop

To solve my problem, I set
prctl(PR_SET_PDEATHSIG, SIGHUP); as in stackoverflow answer before i called exec*, and took out the part where we pipe the PID. It works!!!!! Wow....
HOWEVER, stackoverflow won't let me say I've answered my own question yet...
So I tried to write a program, which I want to run a program, and kill that program after a cpl seconds if it doesn't finish. DADDY forks off a CHILD, which forks off another BABY, CHILD pipes the PID of the BABY to DADDY, which then waits a second and kills them both if they haven't wrapped up their business (it's a macabre scene). But it doesn't work, DADDY stays in S+ State, and the infinite loop that is Baby goes on forever until I ctr+c. On the bright side, this code is an amalgamation of everything I've learnt on stack-overflow. Here we go.
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
if (fscanf(stream, "%d", &c) != 1)
{
fprintf(stderr, "Failed to read integer from pipe\n");
exit(1);
}
fclose(stream);
return c;
}
static void write_to_pipe(int file, int pidRacket)
{
FILE *stream = fdopen(file, "w");
fprintf(stream, "%d", pidRacket);
fclose(stream);
}
static int spawnpipe(char *fileName, int *fd)
{
int pid;
int pipe_fds[2];
char *command[] = {"racket", fileName, NULL};
if (pipe(pipe_fds) < 0)
{
fprintf(stderr, "FE: pipe\n");
exit(1);
}
switch ((pid = fork()))
{
case -1:
printf("syserr");
exit(1);
case 0:
close(1);
close(2);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execvp(*command, command);
perror("execv");
exit(EXIT_FAILURE);
default:
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
static int spawnfp(char *fileName, FILE **fpp)
{
int fd, pid;
pid = spawnpipe(fileName, &fd);
*fpp = fdopen(fd, "r");
return pid;
}
int main(int argc, char *argv[])
{
pid_t pid;
int mypipe[2];
if (pipe(mypipe))
{
fprintf(stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
pid = fork();
if (pid < (pid_t) 0)
{
fprintf(stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
else if (pid != (pid_t) 0)
{
double diff = 0;
clock_t launch = clock();
close(mypipe[1]);
int pidRacket = read_from_pipe(mypipe[0]);
while (diff < 1.3)
{
clock_t done = clock();
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
}
kill(pidRacket, SIGKILL);
kill(pid, SIGKILL);
return EXIT_SUCCESS;
}
else if (pid == (pid_t) 0)
{
close(mypipe[0]);
char buf[100];
FILE *fp;
char *fileName = argv[1];
int pidRacket = spawnfp(fileName, &fp);
write_to_pipe(mypipe[1], pidRacket);
if (argc == 1)
{
printf("Not enough arguments!");
_exit(EXIT_FAILURE);
}
else if (argc == 2)
{
}
sleep(1);
while (fgets(buf, sizeof buf, fp))
{
printf("%s\n", buf);
}
fclose(fp);
kill(pid, SIGKILL);
return 0;
}
}
Credit to quinsley and vijay!
Various comments as I look at the code:
End messages with newlines; you're on Linux now, not Windows. Windows systems seem to encourage people to leave messages without newlines, but it won't work well on Unix in general and Linux in particular.
Don't use _exit() if you want your error messages to appear, especially ones that don't end in a newline.
Don't report error messages on standard output; report them on standard error (that's what it is for!).
Writing else if (argc == 2) { } (with nothing in the braces) is a little odd if there is an else clause after it, but it is pointless when there is no else clause. You should arguably test for argc != 2 since that is the correct number of arguments (or, perhaps more accurately, any arguments beyond argc == 2 are ignored).
If you want to sleep for a time involving sub-second timing (e.g. 1.3 seconds), use one of the appropriate sub-second sleep commands. In this case, nanosleep() is probably the function to use.
Don't use SIGKILL except in dire emergency. The process signalled with SIGKILL has no chance to clean up or anything; it is killed immediately (assuming your process is allowed to send a signal to the other at all, of course).
case -1: printf("syserr"); with no break; after it means that on error, the flow of control goes into the following case 0: code, which is not what's required. Either break; or exit(1); is probably appropriate. (Bullet 3 applies too.)
Don't close standard error. The code:
close(1);
close(2);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execvp(*command, command);
perror("execv");
_exit(EXIT_FAILURE);
is never going to report an error; you closed standard error. Remember that programs are entitled to have a standard error channel. The C standard guarantees it, but you have to cooperate and make sure you've not closed standard error.
Some of the casts in:
diff = ((double)((uintmax_t)(clock_t)done) - (double)((uintmax_t)(clock_t)launch)) / (double)CLOCKS_PER_SEC;
are unnecessary. Since both done and launch are of the type clock_t, the casts to clock_t are unnecessary. The intermediate cast to uintmax_t also isn't really necessary. You could simply write:
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
and even then, two of the three casts are theoretically redundant (any two of the three could be removed).
The code in read_from_pipe() is curious and error prone. Since you've got a file stream, simply read an integer from it using fscanf(), rather than the curious construct using double arithmetic and fractional values that are then multiplied at the end. This is especially appropriate since the write_to_pipe() code uses printf("%d", ...); to write the data. Since c is already an int, the cast in return (int)c; is superfluous.
Theoretically, it would be a good idea to check the streams returned by fdopen() to ensure that the operation did not fail.
If the pipe() function fails, you report the error on standard output and then continue as nothing had gone wrong.
It is not clear what the racket command actually does. It doesn't exist on my machine.
argv in spawnfp() is unused.
pid = fork(); if (pidDos < (pid_t) 0) generates a warning (accurately) that pidDos might be used uninitialized. The condition should presumably be using pid, not pidDos. You then send a SIGKILL signal to the PID identified at random by pidDos, which is unlikely to lead to happiness.
When I copy cat to racket and invoke the following code (as a program mk built from mk.c) as mk /etc/passwd, I get to see the password file double-spaced (and the message from the shell about Killed: 9.
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
if (fscanf(stream, "%d", &c) != 1)
{
fprintf(stderr, "Failed to read integer from pipe\n");
exit(1);
}
fclose(stream);
return c;
}
static void write_to_pipe(int file, int pidRacket)
{
FILE *stream = fdopen(file, "w");
fprintf(stream, "%d", pidRacket);
fclose(stream);
}
static int spawnpipe(char *fileName, int *fd)
{
int pid;
int pipe_fds[2];
char *command[] = {"racket", fileName, NULL};
if (pipe(pipe_fds) < 0)
{
fprintf(stderr, "FE: pipe\n");
exit(1);
}
switch ((pid = fork()))
{
case -1:
printf("syserr");
exit(1);
case 0:
close(1);
close(2);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execvp(*command, command);
perror("execv");
exit(EXIT_FAILURE);
default:
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
static int spawnfp(char *fileName, FILE **fpp)
{
int fd, pid;
pid = spawnpipe(fileName, &fd);
*fpp = fdopen(fd, "r");
return pid;
}
int main(int argc, char *argv[])
{
pid_t pid;
int mypipe[2];
if (pipe(mypipe))
{
fprintf(stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
pid = fork();
if (pid < (pid_t) 0)
{
fprintf(stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
else if (pid != (pid_t) 0)
{
double diff = 0;
clock_t launch = clock();
close(mypipe[1]);
int pidRacket = read_from_pipe(mypipe[0]);
while (diff < 1.3)
{
clock_t done = clock();
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
}
kill(pidRacket, SIGKILL);
kill(pid, SIGKILL);
return EXIT_SUCCESS;
}
else if (pid == (pid_t) 0)
{
close(mypipe[0]);
char buf[100];
FILE *fp;
char *fileName = argv[1];
int pidRacket = spawnfp(fileName, &fp);
write_to_pipe(mypipe[1], pidRacket);
if (argc == 1)
{
printf("Not enough arguments!");
_exit(EXIT_FAILURE);
}
else if (argc == 2)
{
}
sleep(1);
while (fgets(buf, sizeof buf, fp))
{
printf("%s\n", buf);
}
fclose(fp);
kill(pid, SIGKILL);
return 0;
}
}
I fixed some, but by no means all, of the issues identified in this revision of the code.
Oh, and item 16: the read end of the pipe isn't closed until the third process terminates. You need to pass mypipe[1] to spawnfp(), which needs to relay it to spawnpipe(), and the child created there needs to close the pipe descriptor before executing 'racket'. This is compounded by fscanf() looking for either EOF or a non-digit at the end of the PID it reads from the pipe. You could provide a newline or something at the end and that would also free up the parent process to spin in its timing loop. Since you say racket doesn't terminate, that's why you don't see anything much.
It's easier to paste the whole program again than present the diffs:
#include <assert.h>
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
assert(stream != 0);
if (fscanf(stream, "%d", &c) != 1)
{
fprintf(stderr, "Failed to read integer from pipe\n");
exit(1);
}
fclose(stream);
return c;
}
static void write_to_pipe(int file, int pidRacket)
{
FILE *stream = fdopen(file, "w");
assert(stream != 0);
fprintf(stderr, "%d: pidRacket = %d\n", (int)getpid(), pidRacket);
fprintf(stream, "%d", pidRacket);
fclose(stream);
}
static int spawnpipe(char *fileName, int *fd, int pfd)
{
int pid;
int pipe_fds[2];
char *command[] = {"racket", fileName, NULL};
if (pipe(pipe_fds) < 0)
{
fprintf(stderr, "FE: pipe\n");
exit(1);
}
switch ((pid = fork()))
{
case -1:
printf("syserr");
exit(1);
case 0:
close(pfd);
close(1);
//close(2);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execvp(*command, command);
perror("execv");
exit(EXIT_FAILURE);
default:
fprintf(stderr, "%d: pid = %d\n", (int)getpid(), pid);
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
static int spawnfp(char *fileName, FILE **fpp, int pfd)
{
int fd, pid;
pid = spawnpipe(fileName, &fd, pfd);
*fpp = fdopen(fd, "r");
assert(*fpp != 0);
return pid;
}
int main(int argc, char *argv[])
{
pid_t pid;
int mypipe[2];
if (pipe(mypipe))
{
fprintf(stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
pid = fork();
if (pid < (pid_t) 0)
{
fprintf(stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
else if (pid != (pid_t) 0)
{
double diff = 0.0;
clock_t launch = clock();
close(mypipe[1]);
fprintf(stderr, "%d: Reading from pipe:\n", (int)getpid());
int pidRacket = read_from_pipe(mypipe[0]);
fprintf(stderr, "%d: Read PID %d from pipe\n", (int)getpid(), pidRacket);
while (diff < 1.3)
{
clock_t done = clock();
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
printf("%f\n", diff);
}
kill(pidRacket, SIGKILL);
kill(pid, SIGKILL);
return EXIT_SUCCESS;
}
else if (pid == (pid_t) 0)
{
close(mypipe[0]);
char buf[100];
FILE *fp;
char *fileName = argv[1];
int pidRacket = spawnfp(fileName, &fp, mypipe[1]);
fprintf(stderr, "%d: Writing PID %d to pipe\n", (int)getpid(), pidRacket);
write_to_pipe(mypipe[1], pidRacket);
fprintf(stderr, "%d: Written PID to pipe\n", (int)getpid());
if (argc == 1)
{
printf("Not enough arguments!");
_exit(EXIT_FAILURE);
}
else if (argc == 2)
{
}
sleep(1);
while (fgets(buf, sizeof buf, fp))
{
printf("%s\n", buf);
}
fclose(fp);
fprintf(stderr, "%d: Finished reading from pipe\n", (int)getpid());
kill(pid, SIGKILL);
return 0;
}
}
I made this a while back for stupid fun, it uses up a big chunk of your cpu to run but I'm sure you can modify it to break at a certain point or to fit your needs maybe.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc, char*argv[])
{
int childpid;
int pids[100];
int count1 = 0, count2 = 0;
int count3 = 0;
L1:
childpid = fork();
if(childpid == 0)
{
}
else
{
if(childpid != 0 && childpid != -1)
{
if(count3 < 100)
{
pids[count3] = childpid;
printf("Pid:%d\n",pids[count3]);
count3++;
goto L1;
}
else
{
count3--;
goto L2;
}
}
L2:
while(count3 > 0)
{
if(pids[count3] != -1 || pids[count3] != 1)
{
printf("Killing pid:%d\n",pids[count3]);
kill(pids[count3],SIGKILL);
}
count3--;
}
if(count3 == 0)
{
goto L1;
}
}
return 0;
}

bad file descriptor realted to threads

/*Write a server application that does the following :
open 5 named pipes in read­only mode & read from each in a separate thread created in your process – meaning, one thread per named pipe ; main threadoes not read from a named pipe, instead joins all the threads and 
terminates; each thread uses its own individual buffer for reading data from 
a specific named pipe
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<pthread.h>
#include<fcntl.h>
void* thread_routine1(void*fd1)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd1,buff,20)) >0)
{
printf("%s\n", buff);
write(stdout,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){perror("error"); }
close((int)fd1);
}
void* thread_routine2(void*fd2)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd2,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd2);
}
void* thread_routine3(void*fd3)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd3,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd3);
}
void* thread_routine4(void*fd4)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd4,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd4);
}
void* thread_routine5(void*fd5)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd5,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd5);
}
int main()
{
pthread_t thid[5];
int status,ret;
int fd1,fd2,fd3,fd4,fd5;
int res = mkfifo("/tmp/my_fifo1", 0777);
if (res == 0)
printf("FIFO 1created\n");
if(res<0)
perror("FIFO already created");
res = mkfifo("/tmp/my_fifo2", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO 2already created");
res = mkfifo("/tmp/my_fifo3", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO 3already created");
res = mkfifo("/tmp/my_fifo4", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO 4already created");
res = mkfifo("/tmp/my_fifo5", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO5 already created");
fd1=open("/tmp/my_fifo1",O_RDONLY);
perror("open status is");
sleep(5);
fd2=open("/tmp/my_fifo2",O_RDONLY);
perror("open status is");
fd3=open("/tmp/my_fifo3",O_RDONLY);
perror("open status is");
fd4=open("/tmp/my_fifo4",O_RDONLY);
perror("open status is");
fd5=open("/tmp/my_fifo5",O_RDONLY);
perror("open status is");
ret=pthread_create(&thid[0],NULL,thread_routine1,(void*)&fd1);
if(ret<0)
perror("error in thread create1");
ret=pthread_create(&thid[4],NULL,thread_routine4,(void*)&fd5);
if(ret<0)
perror("error in thread create2");
ret=pthread_create(&thid[1],NULL,thread_routine3,(void*)&fd2);
if(ret<0)
perror("error in thread create3");
ret=pthread_create(&thid[2],NULL,thread_routine2,(void*)fd3);
if(ret<0)
perror("error in thread create4");
ret=pthread_create(&thid[3],NULL,thread_routine5,(void*)fd4);
if(ret<0)
perror("error in thread create5");
ret=pthread_join(thid[0],NULL);
ret=pthread_join(thid[1],NULL);
ret=pthread_join(thid[2],NULL);
ret=pthread_join(thid[3],NULL);
ret=pthread_join(thid[4],NULL);
ret=pthread_join(thid[5],NULL);
}
the above code for a process that creates a named pipe FIFO
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<strings.h>
int main(int argc, char *argv[])
{
char buf[512],wr_buf[512];
int ret,ret1,status;
int npfd1,npfd2,npfd3,npfd4,npfd5;
struct stat s1,s2;
// ret = mkfifo(argv[1],0600);
npfd1 = open("/tmp/my_fifo1", O_WRONLY); //opening the named pipe for reading
npfd2= open("/tmp/my_fifo2", O_WRONLY); //opening the named pipe for reading
npfd3 = open("/tmp/my_fifo3", O_WRONLY); //opening the named pipe for reading
npfd4 = open("/tmp/my_fifo4", O_WRONLY); //opening the named pipe for reading
npfd5 = open("/tmp/my_fifo5", O_WRONLY); //opening the named pipe for reading
//only
if(npfd1<0) {perror("error in opening the named pipe"); exit(1); }
printf("enter someting into the buffer\n");
bzero(buf,sizeof(buf));
gets(buf);
ret1 = write(npfd1,buf,20);
//printf("%s\n", buf);
write(STDOUT_FILENO,buf,ret1);
//fflush(stdout);
if(ret1<0){ printf("nothing is there\n");}
close(npfd1);
exit(0);
}
The above code is where i am creating the write end of FIFO. Now after running the two programs in different terminal i am getting a BAD FILE DESCRIPTOR error. when i try to write something to the first namedpipe ie. my_fifo1. Is it possible to pass the filedescriptor that is opened in main to threads the way i have done?
Your main() function is passing a pointer-to-int, but your thread functions are casting that back to an int and then trying to use it as a file descriptor. That's not going to work - you need to dereference the passed pointer in the thread functions (this is OK in this case, because those variables in main() are allocated one-per-thread, and main() doesn't exit until all the threads have finished).
void *thread_routine1(void *fd1)
{
char buff[512];
int bytes_read;
int fd = *(int *)fd1;
while ((bytes_read = read(fd,buff,20)) > 0)
/* ... */

Resources