Using dup2 for piping - c

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.

Related

redirection using dup2 command

I know this is a simple exercise but I'm having troubles with it.
ps | sed 1d | wc -l
I am trying to generate an output of the above terminal command using c code for my school exercise. I have written a code that is redirecting all the inputs and outputs to the required destination but I am not getting any output on the console as I haven't redirected the final output in any file so it must be displayed on console.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#define READ 0
#define WRITE 1
int main()
{
//fd fd1
//ps | sed 1d | wc -l
pid_t pid;
pid_t pid1;
pid_t pid2;
int fd[2];
int fd1[2];
pipe(fd);
pipe(fd1);
pid=fork();
if(pid==0)
{ //redirecting into sed 1d
close(fd[READ]);
dup2(fd[WRITE],1);
close(fd[WRITE]);
execlp("ps","ps",NULL);
}
else
{
pid1=fork();
if(pid1==0)
{ //redirecting into wc -l
close(fd[WRITE]);
dup2(fd[READ],0);
close(fd[READ]);
close(fd1[READ]);
dup2(fd1[WRITE],1);
close(fd1[WRITE]);
execlp("sed","sed","1d",NULL);
}
else
{
pid2=fork();
if(pid2==0)
{ //must display on console
close(fd1[WRITE]);
dup2(fd1[READ],0);
close(fd1[READ]);
execlp("wc","wc","-l",NULL);
}
else
{
close(fd[READ]);
close(fd[WRITE]);
close(fd1[READ]);
close(fd1[WRITE]);
wait(NULL);
}
}
}
}
What can be the problem?
The ps process has both ends of the fd1 pipe open, which it shouldn't. Also, the wc -l process has both ends of the fd pipe open, which it shouldn't. Fix both of those things and your program will stop hanging. Also, wait(NULL) only waits for one child process to terminate, not all of them, so you're risking the terminal prompt reappearing before your program is actually done.

How to make wc accept a pipe file to take input from instead of stdin?

This is a homework problem. The task is to replicate the command: ls | wc -l in a C program using execlp, fork, and pipes.
My Approach
I think the problem can be solved this way:
Create a pipe file: pipe.txt
Create a child process using fork()
Map the stdout of the child process to pipe.txt
Execute ls using execlp
This puts the output of ls into pipe.txt
Inside of parent process
Map the stdin of the parent process to pipe.txt
Execute wc -l using execlp without giving any further arguments so it reads from stdin instead
Since the stdout of this parent process is still the terminal itself, so it should print out the number of lines on the terminal
My Code
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
int main() {
int pipefds[2];
int returnstatus;
int pid;
char argArr[30] = {'\n'};
returnstatus = pipe(pipefds);
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
int file_desc = open("pipe.txt", O_RDWR | O_APPEND | O_CREAT);
pid = fork();
if (pid == 0) {
int copy_desc = dup2(file_desc, 1);
execlp("ls", "ls", NULL);
} else {
int copy_desc = dup2(file_desc, 0);
close(copy_desc);
execlp("wc", "wc", "-l", NULL);
}
return 0;
}
Actual Output
main.cpp blabla.cpp main pipe.txt
>
Problems
Two things that are wrong with this:
Since I set the stdout of the child to be the pipe.txt file, why does it still output on the terminal? NOTE: It does put the output in the pipe.txt file too. But why does it display on the terminal too?
It starts waiting for the user to provide the input? Shouldn't it get the input from pipe file instead of the user?
Expected Output
5
*if there are 5 files in the current directory
Tried Solutions
Using just the pipe: (Got a bad file descriptor error)
int main() {
int pipefds[2];
int returnstatus;
int pid;
returnstatus = pipe(pipefds);
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
pid = fork();
if (pid == 0) {
dup2(pipefds[0], 1);
close(pipefds[1]);
execlp("ls", "ls", NULL);
} else {
dup2(pipefds[1], 0);
close(pipefds[0]);
execlp("wc", "wc", "-l", NULL);
}
return 0;
}
Thanks for the helpful comments.
The problem in the code is that I am not using pipes at all. I was doing all my work with a file that I created. So that was the basic problem.
Here's the new code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
int main() {
// Step1. Create pipe file descriptors: pipefd[0] for reading from pipe, pipefd[1] for writing to the pipe
int pipefds[2];
// Helping variables
int returnstatus;
int pid;
// Step2. Create a pipe with the file descriptors
returnstatus = pipe(pipefds);
// Check if pipe was successfully created
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
// Step3. Fork to create a child process
pid = fork();
if (pid == 0) {
// Inside the child process
// Step4. Duplicate the file descriptor of the write end of the pipe and set it equal to the stdout of the process
dup2(pipefds[1], 1);
// Step5. Close both ends of the pipe
close(pipefds[0]);
close(pipefds[1]);
// Step6. Execute the LS command. It ouputs to stdout which we set equal to the pipe in Step4.
// So essentially, we send all output of ls to our pipe
returnstatus = execlp("ls", "ls", NULL);
// Error checking the execlp command
if (returnstatus == -1){
perror("Error executing execlp: ");
}
} else {
// Inside the parent process
// Step7. Duplicate the file descriptor the READ end of the pipe and set it equal to the stdin of the process
dup2(pipefds[0], 0);
// Step8. Close the both ends of the pipe
close(pipefds[0]);
close(pipefds[1]);
// Step9. Execute the WC command. It takes the file as an argument usually but if no file is given, it will take
// stdin as input. Since the stdin is the pipe, therefore it will read all the data from the pipe.
// The output of the wc command is stdout which is the terminal for this process so we will get the number of
// files/directories in the current directory as an output on the terminal
returnstatus = execlp("wc", "wc", "-l", NULL);
// Error checking the execlp command
if (returnstatus == -1){
perror("Error executing execlp: ");
}
}
return 0;
}

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

sed command using pipes causes infinite loop

So I am trying to use pipes to cat a file and to sed into a file called newfile.txt Currently the cat command works, using execvp, however it's outputing onto the command display. And then the program goes into an infinite loop when it goes to the sed command.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
char *myargv2[]={"sed", "-e" "s/color/colour/g", NULL};
char *myargv1[]={"cat", "colorfile.txt", NULL};
main()
{
int f_des[2];
int fd[2];
int pipe(int filedes[2]);
int file = open("newfile.txt",O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (file < 0)
return 1;
// create a pipe
// Open a pipe and report error if it fails
if (pipe(f_des)==-1)
{
perror("Pipe");
exit(2);
}
//fork the process
// Use switch for fork, because parent doesn't need child's pid.
switch (fork())
{
case -1: // Error
perror("Fork");
exit(2);
case 0: // Child
printf("HERE1\n");
//child will call dup2 to hook standard output to one end of the pipe. Then, execute the cat command using execvp
dup2(fd[1], fileno(stdout));
execvp(myargv1[0], myargv1);
close(fd[1]);
close(fd[0]);
perror(myargv1[0]);
close(fd[1]);
close(fd[0]);
printf("HERE12\n");
exit(3);
default: // Parent
{
printf("HERE13\n");
//parent will call dup2 to hook standard input to the other end of the pipe. Then, execute the sed command using execvp
dup2(fd[0], fileno(stdin));
execvp(myargv2[0], myargv2);
perror(myargv2[0]);
close(fd[1]);
close(fd[0]);
printf("HERE14\n");
//parent will also call dup2 to hook standard output to the file called newfile.txt
if(dup2(file,0 < 0))
return 1;
}
exit(4);
}
return 0;
}
Obviously I'm struggling here. Can anyone point out what I'm doing wrong and/or point me to a good source of information on how to do this?
Thanks!
One primary problem is that you can't make up your mind whether to use f_des or fd for the pipe file descriptors. You have:
int f_des[2];
int fd[2];
int pipe(int filedes[2]);
…
if (pipe(f_des) == -1)
{
perror("Pipe");
exit(2);
}
The declaration of pipe() is not a good idea; that's what the system headers do. But the serious problem is that you create the pipe in f_des and thereafter work with fd.
The other problem is that you don't close the pipe file descriptors accurately. You also have a fair amount of superfluous code. This code works correctly:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
static char *myargv2[]={"sed", "-e" "s/color/colour/g", NULL};
static char *myargv1[]={"cat", "colorfile.txt", NULL};
int main(void)
{
int fd[2];
int pipe(int filedes[2]);
int file = open("newfile.txt",O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (file < 0)
return 1;
if (pipe(fd)==-1)
{
perror("Pipe");
exit(2);
}
switch (fork())
{
case -1: // Error
perror("Fork");
exit(2);
case 0: // Child
printf("HERE1\n");
dup2(fd[1], fileno(stdout));
close(fd[0]); // Important (in general)
close(fd[1]); // Important (in general)
execvp(myargv1[0], myargv1);
perror(myargv1[0]);
printf("HERE12\n");
exit(3);
default: // Parent
printf("HERE13\n");
dup2(fd[0], fileno(stdin));
close(fd[0]); // Crucial
close(fd[1]); // Important (in general)
execvp(myargv2[0], myargv2);
perror(myargv2[0]);
exit(4);
}
return 0;
}
A simple rule of thumb is:
If you dup() or dup2() one end of a pipe to standard input or standard output, you should close both of the raw pipe file descriptors.
Given input file colorfile.txt containing:
this is the color of danger
coloration is not important
end of file is.
The program's output is:
HERE13
HERE1
this is the colour of danger
colouration is not important
end of file is.
Interestingly, if the output of the program is piped to another program, the debugging information isn't printed. That's a consequence of default buffering.

Resources