I can't get this basic communication to work.
All I want to do, is send information via the child's stdout to the parents file descriptor.
I am getting a seg fault.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define READ 0
#define WRITE 1
int main(void){
int fdRead[2];
int pid, i, num;
FILE* output;
char mystring [100];
char c;
pid = fork();
if(pid){
FILE * read;
close(fdRead[WRITE]);
read = fdopen(fdRead[READ], "r");
fgets(mystring,100, read);
printf("parent %d",mystring );
} else {
/* child */
dup2(fdRead[WRITE], STDOUT_FILENO);
close(fdRead[READ]);
close(fdRead[WRITE]);
printf("child" );
}
exit(0);
}
Your code does nothing about pipe.
Code for communicating between parent and child processes using pipe looks as follows
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define READ 0
#define WRITE 1
int main(void){
int pipefd[2];
pid_t pid;
int i, num;
if (pipe(pipefd)<0) { /* create pipe */
perror("pipe");
exit(-1);
}
char mystring [100];
char c;
pid = fork();
if(pid<0){
perror("fork");
exit(-1);
} else if (pid=1) { /* parent */
char *mystring = "message to child";
write(pipefd[WRITE],mystring,strlen(mystring);
sleep(1); /* wait for child read message */
char buf[128]; /* buffer to receive data from child */
read(pipefd[READ],buf, sizeof buf);
close(pipefd[READ]);
close(pipefd[WRITE]);
printf("Returned from child %s",buf );
return 0;
} else { /* child */
char *s="send from child: ";
char buf[128];
read(pipefd[READ],buf, sizeof buf);
write(pipefd[WRITE],s,strlen(s));
close(pipefd[READ]);
close(pipefd[WRITE]);
return 0;
}
}
Related
Hello I'm struggling right now with C language and process so basically I've just learnt about pipe and I want to use them just to exercise myself on it, so I want to try a code that basically use two child and 1 father, by one child the user enter some number then this child send those numbers to the other child and then this second child send them to the father who show them.
here my code so far
`
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
int main(int argc, char const *argv[])
{
pid_t son1;
pid_t son2;
int Pipe1[2];
int pipe2[2];
int sent=0;
int sent2=0;
int recive=0;
int recive2=0;
int j=0;
int mem[3];
if (pipe(Pipe1)==-1)
{
printf("error pipe1");
exit(0);
}
if (pipe(pipe2)==-1)
{
printf("error pipe2");
exit(0);
}
son1=fork();
if (son1==0)
{
close(Pipe1[0]);
//close(pipe2[0]);
//close(pipe2[1]);
printf("i'am the child 1\n");
for (int i = 0; i < 3; i++)
{
printf("type your number \n");
scanf("%d",&sent);
write(Pipe1[1],&sent,sizeof(int));
}
close(Pipe1[1]);
}
son2=fork();
if (son2==0)
{
close(Pipe1[1]);
close(pipe2[0]);
printf("i'am the son number 2 \n");
recive=read(Pipe1[0],&sent,sizeof(int));
while(recive == sizeof(int))
{
printf("nb reçu %d \n",sent);
mem[j]=sent;
recive= read(Pipe1[0],&sent,sizeof(int));
j++;
}
close(Pipe1[0]);
for (int p = 0; p < 3; p++)
{
sent2=mem[p];
printf("sent2 %d",sent2);
write(pipe2[1],&sent2,sizeof(int));
}
close(pipe2[1]);
when i run this code it does work but not how i expect, the commmunication between children work but not between child 2 and the father actualy if you look at the second part of the code of son2 "mem[]" value is not the same before close(pipe[1]) and after and this is why the comunication is mestup but i realy dont know how the value can change.. if someone can explain me it will be really kind of him
`
You create two pipes in the parent which are shared with the children, and the children do not share a pipe with each other. The easiest thing is probably to move the 2nd pipe to the child and have it fork the 2nd child:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int parent_child[2];
if(pipe(parent_child) == -1) {
printf("pipe failed\n");
exit(1);
}
if(!fork()) {
close(parent_child[0]);
int child_grand_child[2];
if(pipe(child_grand_child) == -1) {
printf("pipe failed\n");
exit(1);
}
printf("child write\n");
write(child_grand_child[1], "1", 1);
if(!fork()) {
char buf[1];
ssize_t n = read(child_grand_child[0], buf, sizeof buf);
printf("grand child read\n");
write(parent_child[1], buf, n);
exit(0);
}
close(parent_child[1]);
wait(&(int) {0});
exit(0);
}
close(parent_child[1]);
char buf[1];
ssize_t n = read(parent_child[0], buf, sizeof buf);
printf("parent read %*s\n", n, buf);
wait(&(int) {0});
}
which outputs:
child write
grand child read
parent read 1
I am trying to write a program so that the parent and child process can communicate back and forth between each other. The parent process and the child process ought to print the values from 1-100 where each process prints the value incrementing it by 1 each time. Now the issue I face is that, I know nothing much about pipes. What I gather from reading materials online is that I can use a pipe to read and write values. I have leveraged this to print something in the child process, and send back something to the parent. Now, I am not sure how to get the parent to return to the child after printing for itself? I know my code is probably all wrong, but I am really not sure what I should do.
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, const char * argv[]) {
int fd[2];
if (pipe(fd)== -1){
printf("An error occured while opening the pipe\n");
}
int id = fork();
int i = 0;
if (id == 0){
close(fd[0]);
printf("In child: %d", i);
i ++;
write(fd[1], &i, sizeof(int));
close(fd[1]);
} else {
wait(NULL);
close(fd[1]);
int y;
read(fd[0],&y, sizeof(int));
close(fd[0]);
}
}
To keep it simple, it's up to you to check return values and handle errors. This will only do it between 0 - 9 and you will have to expand the mathematics.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int pipefd_1[2];
int pipefd_2[2];
pid_t cpid;
pipe(pipefd_1);
pipe(pipefd_2);
cpid = fork();
if (cpid == 0) { /* Child reads from pipe 1, writes to pipe 2*/
char cval[] = {'0'};
close(pipefd_1[1]); /* Close unused write and read ends */
close(pipefd_2[0]);
while (atoi(cval) != 9) {
read(pipefd_1[0], cval, 1);
printf("Child print %d\n", atoi(cval));
cval[0] += 1;
write(pipefd_2[1], cval, 1);
}
} else {
char cval[] = {'0'}; /* Parent writes buf to pipe 1 */
close(pipefd_1[0]); /* Close unused read end */
close(pipefd_2[1]);
while (atoi(cval) != 9) {
write(pipefd_1[1], cval, 1);
read(pipefd_2[0], cval, 1);
printf("Parent print %d\n", atoi(cval));
cval[0] += 1;
}
}
}
Output
I made a pipe using stdin and stdout to communicate but I can't figure out how to restore stdin after closing it in my father process.
Here is an example :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
void readPBM(char *output)
{
char tmp[1024];
int fd[2] = {0,0};
int pid;
//Open the pipe for inter-process communication
pipe(&fd[0]);
//Fork and test if we are child or parent process
pid = fork();
if(pid) //Parent process
{
wait(NULL); //Wait for child's end
close(fd[1]);//Close pipe's write stream
close(0);//Close stdin
dup(fd[0]);
close(fd[0]);
strcpy(output, "");// Init output at 0
while(fgets(tmp, 1024, stdin) != NULL) //Put remainings entry in output
{
strcat(output, tmp);
}
strcat(output, "It works\n");
}
else if(pid == 0) //Child process
{
close(fd[0]);//Close pipe's read stream
close(1);//Close stdout
dup(fd[1]);//Duplicate stdin
close(fd[1]);
printf("A random string ...\n");
exit(0);
}
else //Print error if fork failed
{
printf("Error creating a new process");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
int i, j;
char *str = NULL;
char c;
str = malloc(512 * sizeof(char*));
readPBM(str);
printf("%s", str);
c = getchar();
}
I tried to save stdin using : int stdin_copy = dup(0) then restoring it but my getchar is not working.
I also tried to use freopen("/dev/stdin", "a", stdin) but it still doesn't wait for an input
Using fdopen seems to work well so here is the fixed code :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
void readPBM(char *output)
{
FILE* fp;
char tmp[1024];
int fd[2] = {0,0};
int pid;
//Open the pipe for inter-process communication
pipe(&fd[0]);
//Fork and test if we are child or parent process
pid = fork();
if(pid) //Parent process
{
wait(NULL); //Wait for child's end
close(fd[1]);//Close pipe's write stream
fp = fdopen(fd[0], "r");
strcpy(output, "");// Init output at 0
while(fgets(tmp, 1024, fp) != NULL) //Put remainings entry in output
{
strcat(output, tmp);
}
strcat(output, "It works\n");
fclose(fp);
}
else if(pid == 0) //Child process
{
close(fd[0]);//Close pipe's read stream
close(1);//Close stdout
dup(fd[1]);//Duplicate stdin
close(fd[1]);
printf("A random string ...\n");
exit(0);
}
else //Print error if fork failed
{
printf("Error creating a new process");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
int i, j;
char *str = NULL;
char c;
str = malloc(512 * sizeof(char*));
readPBM(str);
printf("%s", str);
c = getchar();
}
I'm trying to create two-way communication between parent and child processes using 2 pipes in C.the prog1 running in child1
I want to read 3+4+5 from prog1 after that send something to prog1 with write but I could not.
Where is the wrong?
/* prog1.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void
main(void){
int FD;
unsigned int buf;
char buf[15];
printf("7+5+11=?\n");
FD=read(0,buf,10);
if(FD<0){
perror("FAIL\n");
exit(EXIT_FAILURE);
}
printf("TAKED:%s\n",buf);
}
prog2.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
void ERR_SYS(const char *msg);
int
main(void){
char buf[15];
int pipe1[2];
int pipe2[2];
pid_t childpid;
memset(buf,'\0',14);
if(pipe(pipe1) < 0 || pipe(pipe2) < 0)
ERR_SYS("fail_pipe");
if((childpid = fork()) < 0)
ERR_SYS("fail_fork");
if(childpid==0)
{
dup2(pipe2[1],1);
dup2(pipe1[0],0);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
close(pipe1[0]);
//close(1);
//close(0);
execle("./prog1",NULL,NULL,NULL);
}else{
close(pipe1[0]);
close(pipe2[1]);
read(pipe2[0],buf,4); /*I hope to read 3+4+5*/
printf("BuF::%s\n",buf);
write(pipe1[1],"off",3);/*send {off}*/
wait(NULL);
}
return 0;
}
void
ERR_SYS(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
There are few problems with your program:
You are not checking returned values of read, write and execle in prog2.c
You are sending "7+5+11=?\n" string which is 10 characters long but only expecting 4 characters ( 3+4+5 is not even four characters ).
Also "off" you are sending is 3 characters long but without including null termination.
When you read from an fd you will in both cases not get null terminated string and then you are trying to printf it. It's a quick way to undefined behaviour. Put an '\0' after the end of buffer you read from any file descriptor!
Especially what read returns is very important as it tells you how many characters were read. You should never ignore returned value of read (in some cases it's the same with write function).
Next time also provide some output of your program as it will be easier to give some help.
I didn't follow all your logic in setting up the pipes, so I modified and hopefully clarified your original. I should note that for whatever reason I named fd_in and fd_out from the external program's (prog1) point of view (e.g. fd_out is where prog1 is writing to, fd_in is where prog1 is reading from).
Here's the contents of my prog3.c:
...
#define READ_END 0
#define WRITE_END 1
void ERR_SYS(const char *msg);
int main(void) {
char buff[15];
char *msg = "hello";
int fd_out[2];
int fd_in[2];
int nbytes;
pid_t childpid;
if(pipe(fd_out) < 0 || pipe(fd_in) < 0) {
ERR_SYS("fail_pipe");
}
if((childpid = fork()) < 0) {
ERR_SYS("fail_fork");
}
if(childpid==0) { //child
//connect the write end of fd_out to stdout
dup2(fd_out[WRITE_END], STDOUT_FILENO);
close(fd_out[WRITE_END]);
//connect the read end of fd_in to stdin
dup2(fd_in[READ_END], STDIN_FILENO);
close(fd_in[READ_END]);
//the exec'd prog1 will inherit the streams
execlp("./prog1", "prog1", NULL); //TODO: check return
} else { //parent
nbytes = write(fd_in[WRITE_END], msg, strlen(msg));
//TODO: handle any errors from write
nbytes = read(fd_out[READ_END],buff,sizeof(buff)-1);
//TODO: handle any errors from read
buff[nbytes] = '\0';
printf("contents of buff::%s",buff);
}
return 0;
}
void ERR_SYS(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
And here's the contents of my prog1.c
int main(void){
char buff[15];
int nbytes;
nbytes = read(STDIN_FILENO, buff, sizeof(buff)-1);
buff[nbytes] = '\0';
printf("%s world\n", buff);
return 0;
}
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 :: ");
}
}