dup2, pipe and fork in C - c

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.

Related

I want an existing program work for two external processes as a child

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);
}

Linux c fork - process dont stop

I'm trying to create simple program with using pipes. Unfortunately program donesn't end correctly as if some descriptor was not closed.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <string.h>
int main(){
int fd[2];
pipe(fd);
if(fork()==0){
close(fd[0]);
dup2(fd[1],1);
close(fd[1]);
execlp("ls", "ls", NULL);
}
else{
if(fork() == 0){
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
execlp("tr", "tr", "a-z", "A-Z", NULL);
}
}
return 0;
}
As long as all the functions succeed (you should absolutely do error-checking in the production version, though), your program should work fine.
If you want to wait for the two children, however:
wait(0); wait(0); //also skimping on the error checking
//stuck
return 0;
it will get stuck because tr will try to read its whole stdin (the pipe) and the pipe can't end as long as the parent still holds a reference to the write end.
With
close(fd[1]);
wait(0); wait(0); //also skimping on the error checking
//stuck
return 0;
it should again run smoothly.
The program gives the impression it "doesn't end" because both operations are done in a forked process, and the main process dies ahead of the 2 children, thus gives back the hand to the shell before the results are printed.
Add this line before the return 0
wait(NULL);
to have the main process wait for all children before dying, to fix this.
Note that you could also not fork again the main process (that does the tr) and you'd get the same result.
else{
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
execlp("tr", "tr", "a-z", "A-Z", NULL);
}

linux terminal command with a pipe in c code

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]);
}

Piping two child processes, one for ls, the other for sort, but sort is not working

I'm trying to create two child processes and pipe them, but the second child is not sorting the output produced by the first child which does ls. What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int pipefd[2];
pid_t ls_pid, wc_pid;
pipe(pipefd);
if ((ls_pid = fork()) == 0) {
dup2(pipefd[1],STDOUT_FILENO);
close(pipefd[0]);
execl("/bin/ls", "ls", 0);
perror("exec ls failed");
exit(EXIT_FAILURE);
}
if ((wc_pid = fork()) == 0) {
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[1]);
execl("/usr/bin/sort", "sort", NULL);
perror("exec wc failed");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
The sort should work, but there are 2 caveats in your code, first, make sure close fd in all the processes that holds references to the fd, otherwise the fd won't close, and that's why the sort process hangs there when done, because it does not receive the EOF from stdin, and that's because the pipefd in the parent process were not closed. The other one is make sure wait the children to exit and check their exit status. Add the following to the send of main function:
close(pipefd[0]);
close(pipefd[1]);
int status;
int pid = waitpid(ls_pid, &status, 0);
pid = waitpid(wc_pid, &status, 0);
You have to pass NULL as the third parameter of the firtexecl just like you do in the second one. What happens is that execl executes correctly (that's why you dont get an error) but the ls command does not work as you give it an invalid command.
Btw, you should make error control on all OS requests, like in fork()
Combining all comments, and tested:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int pipefd[2];
pid_t ls_pid, wc_pid;
int status;
pipe(pipefd);
if ((ls_pid = fork()) == 0) {
dup2(pipefd[1],STDOUT_FILENO);
close(pipefd[0]);
close(pipefd[1]);
execlp("ls", "ls", NULL);
perror("exec ls failed");
exit(EXIT_FAILURE);
}
if ((wc_pid = fork()) == 0) {
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
close(pipefd[1]);
execlp("sort", "sort", NULL);
perror("exec sort failed");
exit(EXIT_FAILURE);
}
close (pipefd[0]);
close (pipefd[1]);
/* wait for two children to finish */
wait(&status);
wait(&status);
return EXIT_SUCCESS;
}

Using dup2 for piping

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.

Resources