I'm trying to execute the Linux command "ls -l | tail -n 2" with a simple pipe in a c code.
I added your tips and now this works but the output isn't exactly as it should be. It prints the output in a single line instead of two and waits for a user input to close.
here is the new code:
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "sys/wait.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void main()
{
char line[100];
pid_t pid;
int fd[2];
int status;
char* ls_arguments[] = {"ls", "-l", NULL};
char* tail_arguments[] = {"tail", "-n", "2", NULL};
pipe(fd);
pid = fork();
if(pid == 0)//ls client
{
close(1);
dup(fd[1]);
close(fd[0]);
execvp("ls", ls_arguments);
}
pid = fork();
if(pid == 0)//tail client
{
close(0);
close(fd[1]);
dup(fd[0]);
execvp("tail", tail_arguments);
}
wait(pid, 0, WNOHANG);
close(fd[0]);
close(fd[1]);
}
this should run the "ls -l" command and output to the pipe and the next "tail" client would get it as input and run the "tail -n 2" command and print out the final output but the terminal prints nothing. Any help?
First of all, there is not such wait function, here is what the man says:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
I think you meant to use waitpid.
Then, you child process doesn't finish because the pipe is still opened somewhere: in the parent. Indeed you should first close the descriptors and then wait for your childs process. I would write:
close(fd[0]);
close(fd[1]);
wait(NULL); // Wait for the first child to finish
wait(NULL); // Wait fot the second one
return 0;
}
Instead of:
wait(pid, 0, WNOHANG);
close(fd[0]);
close(fd[1]);
}
Related
I want to do the following things:
Child process run a program by exec()
Parent process read from STDIN and do something to the input
Pass the input to child process's default input stream.
I know that the child and the parent share the same STDIO, and I'm not familiar with pipe or how to make child read from other pipe.
Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
int fd[2];
pid_t pid = fork();
pipe(fd);
if (!pid) {
dup2(fd[0], STDIN_FILENO);
char arg_pipe_id[10];
sprintf(arg_pipe_id, "<&%d", fd[0]);
close(fd[1]);
// Error here, cannot use <&id or <id in this execl
execl("/bin/bash", "/bin/bash", "-i", arg_pipe_id, NULL);
} else {
char input[2048];
close(fd[0]);
while (fgets(input, 2048, stdin)) {
...
process the input...
...
if (condition) {
write(fd[1], input, strlen(input));
}
}
close(fd[1]);
kill(pid, SIGKILL);
wait(NULL);
}
}
I'd appreciate it if you could help me!
I wrote the following code in order to pipe two commands:
#include <stdlib.h>
#include <unistd.h>
char *program_1[3] = {"/bin/cat", "/dev/random", NULL};
char *program_2[2] = {"/bin/ls", NULL};
char *program_3[2] = {"/usr/bin/sort", NULL};
int main(void)
{
int fd[2];
int pid;
pipe(fd);
if ((pid = fork()) == 0) //Child process
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
execve(program_3[0], program_3, NULL);
}
else if (pid > 0) //Parent process
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
execve(program_2[0], program_2, NULL);
}
return (EXIT_SUCCESS);
}
Each pair of program_x / program_y where x != y works fine, except this one.
When i pipe sort into ls, ls well prints its output on stdout, but then, sort throw this error: sort: Input/output error.
When I type sort | ls into bash, it prints ls result as my program, but then waits for input.
Am I doing someting wrong ?
edit: I'm trying to reimplement the shell's behaviour
The problem is that when ls finishes, the parent process will exit which will close the read-end of the pipe, which will lead to an error being propagated to the write-end of the pipe which is detected by sort and it write the error message.
That it doesn't happen in the shell is because shells handle pipes differently than your simple example program, and it keeps the right-hand side of the pipe open and running (possibly in the background) until you pass EOF (Ctrl-D) to the sort program.
Your program isn't quite equivalent to what a shell typically does.
You're replacing the parent with ls; whereas shell would create who child processes and connect them and wait for them to finish.
It's more like:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
char *program_2[2] = {"/bin/ls", NULL};
char *program_3[2] = {"/usr/bin/sort", NULL};
int main(void)
{
int fd[2];
pid_t pid;
pid_t pid2;
pipe(fd);
if ((pid = fork()) == 0) //Child process
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
execve(program_3[0], program_3, NULL);
}
else if (pid > 0) //Parent process
{
if ( (pid2 = fork()) == 0) {
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
execve(program_2[0], program_2, NULL);
}
}
waitpid(pid, 0, 0);
waitpid(pid2, 0, 0);
return (EXIT_SUCCESS);
}
I finally found the solution, we were close to:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
char *cat[3] = {"/bin/cat", "/dev/random", NULL};
char *ls[2] = {"/bin/ls", NULL};
char *sort[2] = {"/usr/bin/sort", NULL};
int main(void)
{
int fd[2];
pid_t pid;
pid_t pid2;
pipe(fd);
if ((pid = fork()) == 0)
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
execve(cat[0], cat, NULL);
}
else if (pid > 0)
{
if ( (pid2 = fork()) == 0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
execve(ls[0], ls, NULL);
}
waitpid(pid2, 0, 0);
close(fd[0]);
}
waitpid(pid, 0, 0);
return (EXIT_SUCCESS);
}
We need to close the read end of the pipe once the last process ends, this way, if the first process tries to write on the pipe, an error will be throwed and the process will exit, else if it only reads from stdin as sort, it will keep reading as stdin is still open
I have a program that pipes two child processes. But I want these two processes (child) as external independent C program.
I want to connect the output of first process to input of a pipe and connect the input of second process as output of first pipe
Basically I want a program that works like this command in unix:
./myprogram prog1 | prog2
This is the code:
As I am a beginner, I took return value of prog1 and dup2 the output to the Standard Input of pipe and gave value to of the standard output to prog2 and tried to connect in prog2 program through dup2.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
printf("%s \n", argv[1]);
printf("%s \n", argv[2]);
int pipefd[2], status, done = 0;
int cpid;
pipe(pipefd);
cpid = fork();
if (cpid == 0) {
// Child 1 - Process 1
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
execlp(argv[1], argv[1], (char *)NULL);
}
cpid = fork();
if (cpid == 0) {
// Child 2 - Process 2
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
execlp(argv[2], argv[2], (char *)NULL);
}
close(pipefd[0]);
close(pipefd[1]);
waitpid(-1, &status, 0);
waitpid(-1, &status, 0);
return (0);
}
I'm supposed to implement a program that will simulate the behavior of "ls -l | sort -n", I've written my code and according to my logic everything should work perfectly, but it does not.
I've been trying to debug this for the last few hours so any additional input would be much appreciated.
Here's the code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
int fd[2];
int errcheck;
errcheck = pipe(fd);
printf("Errcheck after pipe call: %d\n", errcheck);
pid_t childpid;
childpid=fork();
if(childpid==0)
{
printf("Entering child\n");
errcheck = dup2(fd[1], STDOUT_FILENO);
printf("Errcheck after dup2 child: %d\n", errcheck);
close(fd[0]);
execl("bin/ls", "ls", "-l", NULL);
}
printf("Before sort call\n");
errcheck = dup2(fd[0], STDIN_FILENO);
printf("Errcheck after dup2 parent: %d\n", errcheck);
close(fd[1]);
execl("/usr/bin/sort", "sort", "-n", NULL);
}
The program gets stuck after "Entering child", I really don't understand why the child dup2 call doesn't complete...
Thank you in advance for any help.
Is there a reason not to use dirent to list the files - opendir readdir and so on? Or is this a school assignment? If it is meant for production consider using dirent.h and stat.h.
For schoolwork it is up to your prof what you need to do. Please label this as homework if that is the case.
How do I use dup2 to perform the following command?
ls -al | grep alpha | more
A Little example with the first two commands. You need to create a pipe with the pipe() function that will go between ls and grep and other pipe between grep and more. What dup2 does is copy a file descriptor into another. Pipe works by connecting the input in fd[0] to the output of fd[1]. You should read the man pages of pipe and dup2. I may try and simplify the example later if you have some other doubts.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define READ_END 0
#define WRITE_END 1
int
main(int argc, char* argv[])
{
pid_t pid;
int fd[2];
pipe(fd);
pid = fork();
if(pid==0)
{
printf("i'm the child used for ls \n");
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[WRITE_END]);
execlp("ls", "ls", "-al", NULL);
}
else
{
pid=fork();
if(pid==0)
{
printf("i'm in the second child, which will be used to run grep\n");
dup2(fd[READ_END], STDIN_FILENO);
close(fd[READ_END]);
execlp("grep", "grep", "alpha",NULL);
}
}
return 0;
}
You would use pipe(2,3p) as well. Create the pipe, fork, duplicate the appropriate end of the pipe onto FD 0 or FD 1 of the child, then exec.