I'm currently trying to run an ls command in my C code and then pipe the outputted strings to the parent process via a fd.
The problem I'm currently facing is, that I execv the ls command but I don't know how to store the strings (if that is even necessary) and then pipe them to my parent process and execute another command with the given input like I wrote in the comment. Is there also a way to block the ls output to the terminal in my child process?
int main(void)
{
int fd1[2]; // Used to store two ends of first pipe
int fd2[2]; // Used to store two ends of second pipe
pid_t p;
p = fork(); // Now forking to create a child
// Parent process
else if (p > 0)
{
close(fd1[0]); // Close reading end of first pipe
// Wait for child to send the strings
wait(NULL);
close(fd2[1]); // Close writing end of second pipe
// Read strings from child, print it and close
// reading end.
read(fd2[0], "", 100);
close(fd2[0]);
// todo another command like "wc -l" and print the result to the terminal with write
}
// Child process
else
{
close(fd1[1]); // Close writing end of first pipe
// execute ls command and send the strings to the parent
int status;
char *args[2];
args[0] = "/bin/ls"; // first arg is the full path to the executable
args[1] = NULL; // list of args must be NULL terminated
execv( args[0], args ); // child: call execv with the path and the args
// Close both reading ends
close(fd1[0]);
close(fd2[0]);
// write the strings to the parent
write(fd2[1], "", strlen("") 1);
close(fd2[1]);
exit(0);
}
return EXIT_SUCCESS;
}
I'm sorry if this is a silly question, but I'm very new to forking and using pipes.
CodePudding user response:
To start, must call pipe
on an int [2]
to create a pipe. You have not done this.
In the parent process:
This read
call
read(fd2[0], "", 100);
does not make sense. ""
is a read-only, char [1]
. Trying to store data in it will invoke Undefined Behavior.
You need a reasonably sized buffer (array) to store the data you read in. Additionally, you should check if any data was actually read by testing the return value of read
, which is the number of bytes read.
Remember that this data is not null terminated - it is raw bytes, not a string. If you want to treat it as a string, you need to null terminate the buffer manually (make sure to leave room).
In the child process:
To redirect the standard output of ls
to be the write end of the pipe, instead of the terminal, dup2
is used:
dup2
makes the file descriptor specified by its second argument refer to the same file description as its first argument.
The code after execv
makes little sense, as execv
never returns if it succeeds. You should close any unnecessary file descriptors before this point, and only handle failure states afterwards.
A cursory example of all this.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int my_pipe[2];
if (pipe(my_pipe)) {
perror("pipe");
return 1;
}
if (fork()) {
ssize_t bytes;
char buffer[512];
close(my_pipe[1]);
while ((bytes = read(my_pipe[0], buffer, sizeof buffer - 1)) > 0) {
buffer[bytes] = 0;
printf("Parent got:\n%s\n", buffer);
}
close(my_pipe[0]);
wait(NULL);
} else {
char *args[] = {
"/bin/ls",
NULL
};
close(my_pipe[0]);
dup2(my_pipe[1], fileno(stdout));
close(my_pipe[1]);
execv(args[0], args);
/* we only get here if execv fails */
perror("execv");
}
}