i have a problem reading from a pipe that was created from another .c via execl! I have tried it with a lot of different approaches but i still can't find the solution. I'd appreciate it if you could help me!
Here is the first code :
...some other code before for loop...
for (counter=0; counter<arithmos; counter++)
{
if (pipe(pinakas[counter]) == -1)
{
perror("pipe");
exit(1);
}
sem_wait(&sima);
strcpy(buffer,queueHead(q));
write(fd[WRITE], buffer, strlen(buffer));
queueRemove(&q);
nodes--;
sem_post(&sima);
pid = fork();
if (pid < 0)
{
perror("fork error");
exit(1);
}
if (pid == 0)
{
execl("./paidi","paidi", (char*)pinakas[counter], (char*)NULL);
exit(1);
}
if (pid > 0)
{
printf ("I am the parent with pid %d\n", getpid());
wait(NULL);
}
}
And here is what my child does...
includes etc etc...
int main(int argc, char **argv)
{
//char fd[2];
int *fd = (int*) argv[1];
int nbytes;
char buffer[256];
char *command;
int i;
for (i=0; i<256; i++)
{
buffer[i] = '\0';
}
printf("test2 %d\n",fd[READ]);
//close(fd[WRITE]);
printf("test3\n");
read(fd[READ], buffer, 256);
printf("test4\n");
close(fd[READ]);
printf("test5\n");
printf("Received url : %s", buffer );
printf("test6\n");
//sprintf(command,"wget %zd", url);
//system(command);
printf("I am a child with pid %d\n", getpid());
return 0;
}
Seems like i am doing something wrong with execl. I am trying to pass pointer as argument and i have a pipe : bad address error. I also tried it with string but nothing... Any ideas?
execve(2) creates a brand-new memory space for loaded executable, you cannot pass pointers from previous program, they don't make any sense in that new memory space.
The tried and true approach here is to replace child's standard input (file descriptor 0) with read-end of the pipe(2) after the fork(2) but before the execve(2) using dup2(2).
Related
I want to associate the standard output of the parent process with the standard input of the child process through an anonymous pipe. I did achieve my needs, but I also encountered a problem: the program blocks when calling scanf, even if stdin is set to none Buffer, replace scanf with read to run normally! I know this has something to do with the standard I/O function buffer, but I don't know the internal reason, I hope I can get help, thank you!
Code:
int main(void)
{
int fd[2];
int cpid;
pipe(fd);
if((cpid = fork()) < 0)
{
perror("fork error");
exit(-1);
}
else if(cpid == 0)
{
sleep(1);
char buf[100] = {0};
close(fd[1]);
if(dup2(fd[0], 0) < 0)
{
perror("parent - dup2 error");
exit(-1);
}
setbuf(stdin, NULL);
scanf("%s", buf);
//read(0, buf, 100);
printf("child: \n\t%s", buf);
return 0;
}
sleep(1);
close(fd[0]);
if(dup2(fd[1], 1) < 0)
{
perror("parent - dup2 error");
exit(-1);
}
setbuf(stdout, NULL);
printf("123");
wait(NULL);
return 0;
}
Problem is that to scanf to terminates its reading, necessitate that the data is ended in some way.
You are reading a string, but how scanf can know that there is nothing after 123? So it is waiting for something, either the end of communication, space, newlines, whatever can tell it that a string is fully available.
Try adding a simple spacing, a new line in the writing part:
printf("123 ");
or
printf("123\n");
Note that as is, you can not use the closing solution, just because you forgot to close the original descriptors after the dup.
Rewrite the code like this:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void) {
int fd[2];
int cpid;
pipe(fd);
if((cpid = fork()) < 0) {
perror("fork error");
exit(-1);
}
else if(cpid == 0) {
sleep(1);
char buf[100] = {0};
close(fd[1]);
if(dup2(fd[0], 0) < 0) {
perror("parent - dup2 error");
exit(-1);
}
close(fd[0]); // close not useful original desriptor
setbuf(stdin, NULL);
scanf("%s", buf);
printf("child: \n\t%s", buf);
return 0;
}
sleep(1);
close(fd[0]);
if(dup2(fd[1], 1) < 0) {
perror("parent - dup2 error");
exit(-1);
}
close(fd[1]); // close not useful original desriptor
setbuf(stdout, NULL);
printf("123");
close(1); // close the "connexion" (ie the last open for writing descriptor on the pipe)
wait(NULL);
return 0;
}
The goal is to have the cksum_child function create a child process, and execute the checksum command on the provided file. Redirecting the output to a pipe and reading the result from the pipe in the entry function get_cksum which is functioning as the parent.
`
pid_t
create_cksum_child (int *pipe, char *const filename)
{
pid_t pid = fork();
if (pid < 0) {
printf("fork\n");
return NULL;
}
if (pid == 0) {
close(pipe[0]);
dup2(pipe[1], STDOUT_FILENO);
execlp("/usr/bin/cksum", "cksum", filename, NULL);
printf("execlp\n");
exit(1);
}
int status;
waitpid(pid, &status, 0);
return pid;
}
char *
get_cksum (char *const filename)
{
char *buffer = NULL;
int fd[2];
if (pipe(fd) < 0) {
printf("pipe\n");
exit(1);
}
pid_t child_pid = create_cksum_child(fd, filename);
if (child_pid == NULL) {
return NULL;
}
fflush(stdout);
ssize_t bytes_read = read (fd[0], buffer, sizeof (buffer));
close(fd[0]);
close(fd[1]);
if (bytes_read < 1) {
printf("bytes read: %ld\n", bytes_read);
return NULL;
}
return buffer;
}
`
The code I have here closely follows my textbook sections on IPC models, which initially caused a timeout err. From what I've gather from similar questions on SO I needed to fflush() stdout since the output was being buffered which fixed the timeout but the returned string is incorrect. I then added print statement to see how many bytes I'm reading from the pipe and I get -1 bytes on all test files.
What mistakes did I make and what can I do to redirect the output from stdout and read it in the parent properly?
The main issue is that you should merge the 2 functions together because the parent code is not only in the second function but it is splitted into both functions you wrote.
For example you should move the waiting lines
int status;
waitpid(pid, &status, 0);
on the parent side, since the parent has to wait the child and not vice versa.
After that, your code is in a good shape but probably you should refactor it after the merge of the functions.
I am trying to understand why my program hangs. The Parent sends input froma
file it reads to the child program, and the child program will send the result of its computation back to it's parent. However, I have trouble sending the message back through a second pipe. The parent seems to hang when reading from the pipe.
From the other posts, I have read it seems to indicate that the parent should wait for the child to finish by using wait or waitpid (which in my case both of them does not resolve my issue).
I have notice by adding print statement that neither the PARENT or the CHILD finishes.. Could someone please explain to me why this is happening?
Why does this not work?
int main(int argc,char** argv) {
char buffer[1];
int i;
int fd1[2]; int fd2[2];
pipe(fd1); pipe(fd2);
pid_t pid;
// FIRST PROCESS.
// -------------------
pid = fork();
if(pid == 0) {
int cnt;
dup2(fd1[0], STDIN_FILENO);
dup2(fd2[1], STDOUT_FILENO);
for (i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
while(read(STDIN_FILENO, buffer, sizeof(buffer)) > 0) {
fprintf(stderr, "( %s )", buffer);
cnt = cnt + *buffer - 48;
}
write(STDOUT_FILENO, &cnt, sizeof(cnt));
exit(0);
}
// PARENT.
// ------------------------
int file = open(argv[1], O_RDONLY);
// READ THE FILE.
while(read(file, buffer, 1) > 0) {
if (48 <= *buffer && *buffer <= 57) {
// PIPE TO CHILD.
write(fd1[1], buffer, 1);
}
}
// WAIT FOR CHILD TO FINISH SENDING BACK.
// int status = 0;
// waitpid(pid, &status, 0);
// THIS BLOCK DOESN'T RESOLVE ANYTHING. IT HANGS AT WAIT OR WAITPID.
// **** THIS IS THE PART WHERE IT DOESN'T WORK.
while(read(fd2[0], buffer, 1) > 0) {
fprintf(stderr, "RESULT : %s", buffer);
}
// CLOSING PIPES
for (i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
close(file);
exit(0);
}
You aren't closing enough file descriptors in the parent soon enough.
Rule of thumb: If you
dup2()
one end of a pipe to standard input or standard output, close both of the
original file descriptors returned by
pipe()
as soon as possible.
In particular, you should close them before using any of the
exec*()
family of functions.
The rule also applies if you duplicate the descriptors with either
dup()
or
fcntl()
with F_DUPFD
Now, your child process is following the RoT perfectly. But the corollary for parent processes is that they need to close the unused ends of the pipe, and they must close the write end of a pipe that they use to signal EOF to the reading end of that pipe. This is where your code fails.
Arguably, before reading the file, the parent process should close the read end of the pipe it uses to write to the child, and it should close the write end of the pipe it uses to read from the child.
Then, after reading the whole of the file, it should close the write end of the pipe to the child, before going into the 'read from child' loop. That loop never terminates because the parent still has the write end of the pipe open, so there's a process that could (but won't) write to the pipe.
Also, since the child writes the bytes of an integer onto a pipe, the parent should read the bytes of an integer. Using char buffer[1]; with a %s format is pointless; you need a null terminator for the string, and a single char buffer can't hold both a null byte and any data.
Along with various other improvements ('0' instead of 48, for example), you might end up with:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
int fd1[2];
int fd2[2];
char buffer[1];
pipe(fd1);
pipe(fd2);
pid_t pid = fork();
if (pid == 0) {
int cnt = 0;
dup2(fd1[0], STDIN_FILENO);
dup2(fd2[1], STDOUT_FILENO);
for (int i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
while (read(STDIN_FILENO, buffer, sizeof(buffer)) > 0) {
fprintf(stderr, "(%c)", buffer[0]); // Changed
cnt = cnt + buffer[0] - '0';
}
putc('\n', stderr); // Aesthetics
write(STDOUT_FILENO, &cnt, sizeof(cnt));
exit(0);
}
int file = open(argv[1], O_RDONLY);
if (file < 0) {
fprintf(stderr, "failed to open file '%s' for reading\n", argv[1]);
exit(EXIT_FAILURE);
}
close(fd1[0]); // Added
close(fd2[1]); // Added
while (read(file, buffer, sizeof(buffer)) > 0) {
if ('0' <= buffer[0] && buffer[0] <= '9') {
write(fd1[1], buffer, sizeof(buffer));
}
}
close(file); // Moved
close(fd1[1]); // Added
// Rewritten
int result;
while (read(fd2[0], &result, sizeof(result)) == sizeof(result)) {
fprintf(stderr, "RESULT : %d\n", result);
}
close(fd2[0]); // Added
// Close loop removed
return 0;
}
If that is stored in file pipe71.c and compiled, I get the following outputs when it is run:
$ ./pipe71 pipe71.c
(2)(0)(1)(2)(2)(2)(1)(1)(2)(0)(0)(2)(1)(0)(2)(2)(1)(0)(2)(1)(2)(0)(0)(0)(0)(0)(1)(0)(1)(1)(0)(2)(1)(0)(0)(0)(0)(9)(1)(1)(1)(1)(2)(0)(2)(0)(0)
RESULT : 49
$ ./pipe71 pipe71
(0)(0)(8)(0)(0)(2)(2)(0)(8)(1)(1)(5)(1)(1)(1)(1)(5)(1)(1)(1)(8)(5)(1)(9)(8)(5)(1)(1)(0)(4)(4)(4)(6)(0)(2)(8)(0)(0)(0)(2)(7)(1)(3)(8)(3)(0)(4)(3)(0)(4)(9)(0)(0)(0)(0)(7)(1)(9)(8)(1)(3)(0)
RESULT : 178
$
I want to do a program that first creates 3 processes (A) and later, creates one process more (B) and these first processes must write in a pipe that the last process read each time that process write.
I tried something but I don't know the way to do that because the process (B) is created after the processes (A)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHILDREN 3
int main(int argc, char *argv[])
{
pid_t pid;
int fd[2];
char buffer[100];
char str[] = "Hello";
char str2[] = "Hello2";
char str3[] = "Hello3";
for(int num_process = 0; num_process < MAX_CHILDREN; num_process++)
{
if(pipe(fd) == -1)
{
perror( "pipe Failed" );
continue;
}
pid = fork();
if(pid < 0)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{ //child code
if(num_process == 0){
printf("Child %i (pid= %i) send string %s\n", num_process, getpid(),str);
write(fd[1],str,strlen(str));
}
if(num_process == 1){
printf("Child %i (pid= %i) send string %s\n", num_process, getpid(),str2);
write(fd[1],str2,strlen(str2));
}
if(num_process == 2){
printf("Child %i (pid= %i) send string %s\n", num_process, getpid(),str3);
write(fd[1],str3,strlen(str3));
}
exit(0);
}
else{//parent
printf("Im parent %i\n",getpid());
wait(NULL);
}
}
//Creating another child process from parent, this process recieves string sent from
//childs
pid = fork();
if(pid < 0)
{
perror("fork failed");
exit(1);
}
if(pid == 0){//child
printf("The new process %i read fd pipe\n",getpid());
if( read(fd[0],buffer,sizeof(buffer)) <= 0) //read pipe
{
perror("error read");
exit( EXIT_FAILURE );
}
printf("String readed : %s\n",buffer);
}
else{//parent
wait(NULL);
}
return 0;
}
You need to make a number of changes to the code. The parent shouldn't really wait on its children until after they're all launched. Since you create a new pipe for each of the first three children, you need to keep track of which file descriptors are in use. You should use arrays for that, and for the strings to be sent. Neither the read() nor the write() system calls null-terminates strings, and you don't tell it to write a null byte at the end, so you need to tell printf() to print the correct information.
Those changes and sundry others lead to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_CHILDREN 3
int main(void)
{
pid_t pid;
int fd[MAX_CHILDREN][2];
char buffer[100];
const char *str[MAX_CHILDREN] = { "Hello 1", "Hello 2", "Hello 3" };
for (int i = 0; i < MAX_CHILDREN; i++)
{
if (pipe(fd[i]) == -1)
{
perror("pipe Failed");
exit(1);
}
pid = fork();
if (pid < 0)
{
perror("fork failed");
exit(1);
}
if (pid == 0)
{
printf("Child %i (pid= %i) send string %s\n", i + 1, getpid(), str[i]);
write(fd[i][1], str[i], strlen(str[i]));
exit(i + 1);
}
}
pid = fork();
if (pid < 0)
{
perror("fork failed");
exit(1);
}
if (pid == 0)
{
printf("The new process %i read fd pipe\n", getpid());
for (int i = MAX_CHILDREN; i-- > 0; )
{
int nbytes;
if ((nbytes = read(fd[i][0], buffer, sizeof(buffer))) <= 0)
{
perror("error read");
exit(EXIT_FAILURE);
}
printf("String read: %.*s\n", nbytes, buffer);
}
exit(4);
}
int corpse;
int status;
while ((corpse = wait(&status)) >= 0)
printf("child %d exited with status 0x%.4X\n", corpse, status);
return 0;
}
When run, the output might be:
Child 1 (pid= 91027) send string Hello 1
Child 2 (pid= 91028) send string Hello 2
Child 3 (pid= 91029) send string Hello 3
The new process 91030 read fd pipe
String read: Hello 3
String read: Hello 2
String read: Hello 1
child 91027 exited with status 0x0100
child 91028 exited with status 0x0200
child 91029 exited with status 0x0300
child 91030 exited with status 0x0400
I reversed the order of the elements in the reading loop, mainly just for fun. You can use a conventional for (int i = 0; i < MAX_CHILDREN; i++) loop instead if you prefer.
Although it isn't crucial in this program, you aren't closing enough file descriptors in the children or the parent. The parent should close the write ends of the pipes; it isn't going to be using them. The children should close the read ends of the pipes; they aren't going to be using them. Further, the second and third children should close the pipes opened for the first, and the third should close the pipe for the second, as they aren't going to use those, either. If you don't do this and the fourth child looped waiting for EOF (0 bytes returned), it would hang.
Rule of thumb: If you
dup2()
one end of a pipe to standard input or standard output, close both of the
original file descriptors returned by
pipe()
as soon as possible.
In particular, you should close them before using any of the
exec*()
family of functions.
The rule also applies if you duplicate the descriptors with either
dup()
or
fcntl()
with F_DUPFD
Note that an alternative design for the program would create a single pipe outside the loop and the children would all write to the same pipe. You'd probably want to add a newline to the message strings so that the results are separate. You'd definitely want to think about looping the read in the fourth child, and you'd need to worry about the pipe being closed properly, and so on. It'd be a worthwhile sub-exercise to code that.
This is the function that I call inside the main when I recognize a pipe
void execArgsPiped(char* input)
{
char* parsedpipe[MAXCOM];
parsePipe(input,parsedpipe);
pid_t pid;
int in, fd [2];
int i= 0;
in = STDIN_FILENO;
while(i<nCommands-1)
{
pipe (fd);
char *toEx[100];
parseSpace(parsedpipe[i],toEx);
if(i!=nCommands-1)
spawn_proc (in, fd [1], toEx);
close(fd [1]);
in = fd [0];
i++;
}
if (in != 0)
dup2 (in, 0);
char *toEx1[100];
parseSpace(parsedpipe[i],toEx1);
printf(" command %i is %s \n",i,parsedpipe[1]);
if (execvp(toEx1[0], toEx1) < 0) {
printf("\nCould not execute command..");
}
and here is the call to the function that spawns the process to execute the command
void spawn_proc (int in, int out, char **toEx)
{
pid_t pid;
pid = fork();
if (pid < 0)
{
printf("error creating process");
}
else if(pid==0){
if (in != 0)
{
dup2 (in, 0);
close (in);
}
if (out != 1)
{
printf("the if 12");
dup2 (out, 1);
close (out);
}
if (execvp(toEx[0], toEx) < 0) {
printf("\nCould not execute command..");
}
}
else{
wait(NULL);
}
}
My problem is that when I compile and insert two commands connected by a pipe, the Shell goes into a kinda of infinite loop and I have to close the terminal because of that.
I really cannot understand what's wrong with the code, I don't know very much of C.
Any help is really appreciated.