I have created something like "linux pipe" to redirect output from one program to another and it's working like a charm. But now I want to save final output to a file. On the internet I saw that I need to create double pipe, but everything I create is not working.
Here is my actual code of "pipe":
int pipes[2];
int pid;
pipe(pipes);
if(pid=fork()){
int fd = open("t.txt", O_CREAT | O_TRUNC | O_RDWR, 0644);
if (fd < 0) {
perror("open()");
exit(EXIT_FAILURE);
}
close(pipes[1]);
dup2(pipes[0],STDIN_FILENO);
execvp(sec_command[0],sec_command);
}
else{
close(pipes[0]);
dup2(pipes[1],STDOUT_FILENO);
execvp(first_command[0],first_command);
}
Thanks
No. You don't need to. You just need to do a second dup2 in the child process (which will be capturing its input from the pipe) to the file descriptor of the file you want the output to go. You haven't post a Minimal, Reproducible Example, and your code is wrong (it execs in the parent and child process) so i've tried to work a complete solution. Here it is:
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t
subcommand_to_file(
char **subcommand_args,
char *file)
{
int pipes[2];
pipe(pipes);
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
} else if (pid == 0) { /* child */
int fd = open(file,
O_CREAT | O_TRUNC | O_RDWR,
0666); /* permissions controled by umask */
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
close(pipes[1]); /* close output descriptor of pipe */
dup2(pipes[0], STDIN_FILENO); /* redirect input */
close(pipes[0]); /* not needed after dup2 */
dup2(fd, STDOUT_FILENO); /* rediect output */
close(fd); /* not needed after dup2 */
execvp(subcommand_args[0], subcommand_args);
perror("execvp");
exit(EXIT_FAILURE);
}
/* parent */
close(pipes[0]); /* close input descriptor of pipe */
dup2(pipes[1], STDOUT_FILENO);
close(pipes[1]); /* not needed, after dup */
return pid; /* so if you want to wait for the child */
}
int
main( int argc,
char **argv)
{
int opt;
char file[256];
/* default value for filename */
snprintf(file, sizeof file, "%s.out", argv[0]);
while ((opt = getopt(argc, argv, "f:")) != EOF) {
switch (opt) {
case 'f':
strncpy(file, optarg, sizeof file);
break;
}
}
argc -= optind;
argv += optind;
pid_t child = subcommand_to_file(argv, file);
if (child < 0) {
fprintf(stderr,
"subcommand_to_file: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
/* copy input to output to pass stdin to subprocess */
int c;
while((c = getchar()) != EOF) {
putchar(c);
}
close(STDOUT_FILENO);
wait(NULL);
fprintf(stderr, "%s terminated\n", argv[0]);
exit(EXIT_SUCCESS);
}
The above program is called as
$ a.out -f output_file command [args ...]
and will end when the command program is finished. Just try
$ a.out -f out.txt echo a b c
and you will get
$ cat out.txt
a b c
$ _
Related
I'm writing a program to execute another program as a forked process and redirect it's output to a file or /dev/null on demand.
Currently I have forked and executed the external program using execvp().
Then redirected the stdout from a thread created before forking as the forked process will inherit parents file descriptor table allowing me to redirect after foking.
But, I can initially redirect stdout to a desired file and both parents and child's stdouts are being redirected. However if I try to redirect it again to another file, only parents stdout is redirected, child's stdout stays the same.
Here's the code without all the error checking bits.
struct params {
const char *p;
int fd;
int wait;
};
#define EXIT_NOEXEC 126
#define EXIT_NOTFOUND 127
#define EXIT_MISC 127
static void dofile(struct params* st);
void dupit(const char *p, struct params* st);
void* reload_config(void* para);
int
main(int argc, char *argv[]) {
int exit_status, prog_status;
struct params init;
pid_t prog_pid;
dofile(&init);
prog_pid = fork();
if (prog_pid == 0) {
execvp(*argv, argv);
exit_status = (errno == ENOENT) ? EXIT_NOTFOUND : EXIT_NOEXEC;
err(exit_status, "%s", argv[0]);
exit(EXIT_FAILURE);
} else {
while (wait(&prog_status) != prog_pid);
return prog_status;
}
}
static void dofile(struct params* st) {
const char *p
p = out.txt;
dupit(p, st);
}
void dupit(const char *p, struct params* st) {
pthread_t tid;
st->wait = 0;
int err = pthread_create(&(tid), NULL, &reload_config, st);
if (err != 0) {
printf("\ncan't create thread :[%s]", strerror(err));
exit(1);
} else {
while (st->wait == 0) {
sleep(1)
}
}
}
void* reload_config(void* para) {
struct params *passed = (struct params *) para;
int pre_config = 3;
int cur_config = 1;
int saved_stdout = dup(STDOUT_FILENO);
char infile[5];
int devNull = open("/dev/null", O_WRONLY);
int file = open("out.txt", O_WRONLY);
FILE *config;
config = fopen("config.txt", "r");
if (access("config.txt", F_OK) != -1) {
while (1) {
fgets(infile, 5, config);
fclose(config);
cur_config = infile[0] - '0';
printf("output from thread, current config = %d\n", cur_config);
if (pre_config != cur_config) {
if (cur_config == 1) {
if (dup2(file, STDOUT_FILENO) == -1) {
err(EXIT_MISC, NULL);
}
} else {
dup2(devNull, STDOUT_FILENO);
}
pre_config = cur_config;
}
if (passed->wait==0) {
passed->wait = 1;
}
sleep(1);
}
} else {
if (dup2(passed->fd, STDOUT_FILENO) == -1) {
err(EXIT_MISC, NULL);
}
}
}
Well, I changed the code a bit so you guys will understand, so some parts will make no sense. But you get the basic idea.
How can I redirect child's stdout as I wish after forking.
Since you asked, here is a simple example. Some shortcuts have been taken for brevity but hopefully it gives you some idea. The program opens file1 and redirects stdout to that file. It then does a fork. The child process writes a counter to stdout (via printf) every 1 second. After a few seconds the parent process uses IPC, a pipe in this example, to tell the child to switch redirect file.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char **argv)
{
pid_t pid;
const char *file1 = "file1.txt";
const char *file2 = "file2.txt";
int pipefd[2];
int fd;
int rval;
fd = open(file1, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
if (fd == -1) {
perror("file1 open");
exit(-1);
}
/*
* This pipe will be used by parent process to tell child which file
* to redirect to.
*/
rval = pipe2(pipefd, O_NONBLOCK);
if (fd == -1) {
perror("pipe");
exit(-1);
}
/* Redirect stdout to the file opened before the fork. */
dup2(fd, STDOUT_FILENO);
pid = fork();
if (pid == -1) {
perror("fork");
exit(-1);
} else if (pid == 0) {
/* Child process. */
int ix;
char redirect_file[100];
close(pipefd[1]);
for (ix = 0; ix < 10; ix++) {
printf("%d\n", ix);
sleep(1);
rval = read(pipefd[0], redirect_file, sizeof(redirect_file));
if (rval > 0) {
/*
* Parent process has written a filename to the pipe.
*/
fd = open(redirect_file, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
if (fd == -1) {
perror("file2 open");
exit(-1);
}
/* Ensure previous output has been written to current file. */
fflush(stdout);
/* Change redirect now. */
dup2(fd, STDOUT_FILENO);
}
}
} else {
/* Parent process. */
close(pipefd[0]);
/* Wait a little and then tell child to change redirect file. */
sleep(5);
write(pipefd[1], file2, strlen(file2) + 1);
wait();
}
}
If this program is run you will find that half the child output went to file1 (first redirect) and other half of the output goes to file2 (second redirect).
$ cat file1.txt
0
1
2
3
4
$ cat file2.txt
5
6
7
8
9
One final note. The example program does the first dup before the fork. I did it like that because that's how your code was shown and also to emphasise the before and after fork aspect of the issue. But in real code the conventional way of doing that is to do fork first, then dup and finally exec. The dup is done after the fork so that only the child process gets affected and not the parent (unless that is really what you want).
I know this topic came up already several times, but I'm still stuck at one point.
I need to write a program that emulates cmd1 | cmd2 | cmd3 ... piping.
My code is here: http://ideone.com/fedrB8
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void pipeline( char * ar[], int pos, int in_fd);
void error_exit(const char*);
static int child = 0; /* whether it is a child process relative to main() */
int main(int argc, char * argv[]) {
if(argc < 2){
printf("Usage: %s option (option) ...\n", argv[0]);
exit(1);
}
pipeline(argv, 1, STDIN_FILENO);
return 0;
}
void error_exit(const char *kom){
perror(kom);
(child ? _exit : exit)(EXIT_FAILURE);
}
void pipeline(char *ar[], int pos, int in_fd){
if(ar[pos+1] == NULL){ /*last command */
if(in_fd != STDIN_FILENO){
if(dup2(in_fd, STDIN_FILENO) != -1)
close(in_fd); /*successfully redirected*/
else error_exit("dup2");
}
execlp(ar[pos], ar[pos], NULL);
error_exit("execlp last");
}
else{
int fd[2];
pid_t childpid;
if ((pipe(fd) == -1) || ((childpid = fork()) == -1)) {
error_exit("Failed to setup pipeline");
}
if (childpid == 0){ /* child executes current command */
child = 1;
close(fd[0]);
if (dup2(in_fd, STDIN_FILENO) == -1) /*read from in_fd */
perror("Failed to redirect stdin");
if (dup2(fd[1], STDOUT_FILENO) == -1) /*write to fd[1]*/
perror("Failed to redirect stdout");
else if ((close(fd[1]) == -1) || (close(in_fd) == - 1))
perror("Failed to close extra pipe descriptors");
else {
execlp(ar[pos], ar[pos], NULL);
error_exit("Failed to execlp");
}
}
close(fd[1]); /* parent executes the rest of commands */
close(in_fd);
pipeline(ar, pos+1, fd[0]);
}
}
It works completely fine for up to 3 commands, but when it comes to 4 and more it doesnt any more and after hours of analysing, I still cant get where the problem is.
Example:
./prog ls uniq sort head
gives:
sort: stat failed: -: Bad file descriptor
Not an expert, but it seems the following line is the problem:
((close(fd[1]) == -1) || (close(in_fd) == - 1))
Try not to close in_fd there.
I think, the parent is trying to close the same fd that is closed by child.
When you use dup2() you do not need to close the files as dup2() already closes the file.
Hi i'm trying to build a shell on linux and i'm stuck with the pipelining part.First i take the inputs from the user like "ls | sort" then when i try to run the program it lookls like the commands ls and sort doesnt work
It looks like i've done everything right but it still cant seem to work. can you help please. thanks in advance
include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <fcntl.h>
#include <sys/stat.h>
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int setup();
int main(int argc, const char * argv[])
{
while(1)
{
printf("333sh: ");
if(setup())
break;
}
return 0;
}
int setup(){
char input [128];
char *arg[32];
int i = 1;
while(fgets(input,128,stdin)!=NULL)
{
arg[0] = strtok(input," \n");
while((arg[i]=strtok(NULL," \n")) != NULL){
i++;
}
if (arg[1]!=NULL && strcmp(arg[1],"|")==0 && arg[2]!=NULL ){
pid_t pid;
int fd[3];
pipe(fd);
pid=fork();
if(pid<0){
printf("fork");
}
else if(pid==0){
pid_t cpid;
cpid=fork();
if(cpid==0){
dup2(fd[2], 1); // Replace stdin with the read end of the pipe
close(fd[0]); // Don't need another copy of the pipe read end hanging about
close(fd[2]);
execvp(arg[0],arg);
}
else if(pid>0){
dup2(fd[0], 0); // Replace stdout with the write end of the pipe
close(fd[0]); //close read from pipe, in parent
close(fd[2]); // Don't need another copy of the pipe write end hanging about
execvp(arg[2], arg);
}
}
else if(pid>0){
waitpid(pid, NULL,0);
}
}
}
}
Your biggest problem is that your argument lists for your commands are malformed (after you've resolved the index 2 vs index 1 issue with the pipe file descriptors diagnosed by Ben Jackson in his answer).
I added a function:
static void dump_args(int pid, char **argv)
{
int i = 0;
fprintf(stderr, "args for %d:\n", pid);
while (*argv != 0)
fprintf(stderr, "%d: [%s]\n", i++, *argv++);
}
and called it just before the calls to execvp(), and the output I got was:
$ ./ns
333sh: ls | sort
args for 29780:
0: [ls]
1: [|]
2: [sort]
ls: sort: No such file or directory
ls: |: No such file or directory
^C
$
The control-C was me interrupting the program. The arguments for each command must be 'the command name' (conventionally, the name of the executable), followed by the remaining arguments and a null pointer.
Your tokenization code is not providing two correct commands.
You also have a problem with which PID you're looking at:
cpid = fork();
if (cpid == 0)
{
dup2(fd[1], 1);
close(fd[0]);
close(fd[1]);
dump_args(getpid(), arg);
execvp(arg[0], arg);
fprintf(stderr, "Failed to exec %s\n", arg[0]);
exit(1);
}
else if (pid > 0) // should be cpid!
{
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);
dump_args(pid, arg);
execvp(arg[1], arg);
fprintf(stderr, "Failed to exec %s\n", arg[1]);
exit(1);
}
You also need to close the pipe file descriptors in the parent process before waiting.
This code compiles and 'works' for simple x | y command sequences such as ls | sort or ls | sort -r. However, it is far from being a general solution; you'll need to fix your argument parsing code quite a lot before you reach a general solution.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int setup(void);
int main(void)
{
while (1)
{
printf("333sh: ");
if (setup())
break;
}
return 0;
}
static void dump_args(int pid, char **argv)
{
int i = 0;
fprintf(stderr, "args for %d:\n", pid);
while (*argv != 0)
fprintf(stderr, "%d: [%s]\n", i++, *argv++);
}
int setup(void)
{
char input[128];
char *arg[32];
int i = 1;
while (fgets(input, sizeof(input), stdin) != NULL)
{
arg[0] = strtok(input, " \n");
while ((arg[i] = strtok(NULL, " \n")) != NULL)
{
i++;
}
if (arg[1] != NULL && strcmp(arg[1], "|") == 0 && arg[2] != NULL)
{
pid_t pid;
int fd[2];
arg[1] = NULL;
pipe(fd);
pid = fork();
if (pid < 0)
{
fprintf(stderr, "fork failed\n");
return 1;
}
else if (pid == 0)
{
pid_t cpid = fork();
if (cpid < 0)
{
fprintf(stderr, "fork failed\n");
return 1;
}
else if (cpid == 0)
{
printf("Writer: [%s]\n", arg[0]);
dup2(fd[1], 1);
close(fd[0]);
close(fd[1]);
dump_args(getpid(), arg);
execvp(arg[0], arg);
fprintf(stderr, "Failed to exec %s\n", arg[0]);
exit(1);
}
else
{
printf("Reader: [%s]\n", arg[2]);
assert(cpid > 0);
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);
dump_args(getpid(), &arg[2]);
execvp(arg[2], &arg[2]);
fprintf(stderr, "Failed to exec %s\n", arg[2]);
exit(1);
}
}
else
{
close(fd[0]);
close(fd[1]);
assert(pid > 0);
while (waitpid(pid, NULL, 0) != -1)
;
}
}
}
return 1;
}
You're using fd[0] and fd[2] but pipe(fd) only sets fd[0] and fd[1].
Couple of immediate problems:
setup() has no return value, but you expect an int
The definition of fgets is:
char * fgets ( char * str, int num, FILE * stream );
Get string from stream
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str.
fgets() returns NULL on an error; otherwise it returns a pointer to str. So this seems like a very unsound test condition in your while loop.
I have a program that parses the command given, and allocates all the arguments/programs to a struct. In my main program that executes the commands, I am trying to redirect the output of the pipe command to a file if a ">" is given. For example, my program will successfuly execute the command
cat filea | grep pattern
but I want to also be able to execute the command
cat filea | grep pattern > outfile
As a side note, it's not too important to understand the exact mechanics of cmdscan.c as it was given as sort of a helper program to help parse the command string and fill in the struct values which makes it easier to check for cases in the main program hsh.c. Also, the argv1 and argv2 are the left and right hand side of the pipe, so argv2 is only filled up when there is a pipe. And if there is redirection of any sort then the name of the file will be stored in infile/outfile depending on the redirection
This is my main program hsh.c that executes the commands:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <string.h>
#define BUFSIZE 500
struct cmd
{
int redirect_in; /* Any stdin redirection? */
int redirect_out; /* Any stdout redirection? */
int redirect_append; /* Append stdout redirection? */
int background; /* Put process in background? */
int piping; /* Pipe prog1 into prog2? */
char *infile; /* Name of stdin redirect file */
char *outfile; /* Name of stdout redirect file */
char *argv1[10]; /* First program to execute */
char *argv2[10]; /* Second program in pipe */
};
int cmdscan(char *cmdbuf, struct cmd *com);
int main() {
char buf[BUFSIZE];
struct cmd command;
pid_t pid;
int status;
int fd[2];
pipe(fd);
int fdout;
while((fgets(buf,BUFSIZE,stdin) != NULL)) {
if(cmdscan(buf,&command)==-1) {
printf("illegal format\n");
continue;
}
if((pid=fork()) <0)
perror("fork error\n");
if(strcmp(command.argv1[0],"exit") == 0) {
return 0;
}
else if (pid == 0) {
//if the command has piping
if(command.piping){
if((pid = fork()) <0)
perror("fork error");
//fork again so we can do more commands after this one
else if(pid == 0) {
if((pid = fork()) < 0)
perror("fork error");
else if (pid == 0){
//fdout = open(command.outfile, O_CREAT | O_WRONLY);
//dup2(fdout, STDOUT_FILENO);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
execvp(*command.argv1,command.argv1);
} else {
dup2(fd[0],STDIN_FILENO);
close(fd[0]);
execvp(*command.argv2,command.argv2);
}
}
//execute normal command
}else {
//if normal command has redirection
if(command.redirect_out){
fdout = open(command.outfile, O_CREAT | O_WRONLY);
dup2(fdout,STDOUT_FILENO);
close(fd[0]);
execvp(*command.argv1,command.argv1);
}
else{
execvp(*command.argv1,command.argv1);
}
}
//..
exit(0);
} else {
if(wait(&status)!=pid)
perror("wait error");
}
}
return 0;
}
This is the program that parses the command line, cmdscan.c.:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
struct cmd
{
int redirect_in; /* Any stdin redirection? */
int redirect_out; /* Any stdout redirection? */
int redirect_append; /* Append stdout redirection? */
int background; /* Put process in background? */
int piping; /* Pipe prog1 into prog2? */
char *infile; /* Name of stdin redirect file */
char *outfile; /* Name of stdout redirect file */
char *argv1[10]; /* First program to execute */
char *argv2[10]; /* Second program in pipe */
};
#define TRUE 1
#define FALSE 0
int
cmdscan(char *cmdbuf, struct cmd *com)
{
char *token;
char *curcmd; /* pointer to current command string */
char swtch[256]; /* buffer to hold copy of switch */
char *separators = " \t\n";
int i;
com->redirect_in = FALSE;
com->redirect_out = FALSE;
com->redirect_append = FALSE;
com->background = FALSE;
com->piping = FALSE;
if ( (com->argv1[0] = strtok(cmdbuf,separators) ) == NULL)
return(-1);
i = 1;
while( (com->argv1[i++] = (token = strtok(NULL,separators))) != NULL && strcmp(token,">") &&
strcmp(token,"<") && strcmp(token,">>") && strcmp(token,"&") && strcmp(token,"|") );
com->argv1[i-1] = NULL;
if ( token != NULL && strcmp(token,"|") == 0 )
{
com->piping = TRUE;
i = 0;
while( (com->argv2[i++] = (token = strtok(NULL,separators))) != NULL && strcmp(token,">") &&
strcmp(token,"<") && strcmp(token,">>") && strcmp(token,"&") && strcmp(token,"|") );
com->argv2[i-1] = NULL;
if ( com->argv2[0] == NULL )
return(-1);
}
while ( token != NULL ){
if ( !strcmp(token,">") || !strcmp(token,">>") )
{
if ( com->redirect_out )
return(-1);
com->redirect_out = TRUE;
if ( !strcmp(token,">>") )
com->redirect_append = TRUE;
if ( (com->outfile = strtok(NULL,separators)) == NULL )
return(-1);
}
else if ( !strcmp(token,"<") )
{
if ( com->redirect_in )
return(-1);
com->redirect_in = TRUE;
if ( (com->infile = strtok(NULL,separators)) == NULL )
return(-1);
}
else if ( !strcmp(token,"|") )
{
if ( com->piping )
return(-1);
}
else if ( !strcmp(token,"&") )
{
if ( com->background )
return(-1);
com->background = TRUE;
if ( (token = strtok(NULL,separators)) != NULL )
return(-1);
break;
}
else
return(-1);
token = strtok(NULL,separators);
}
return(0);
}
I tried applying the same logic as the simple command for redirection but I couldn't get it to work and got sort of confused about the pipes.
Before we get output redirection to work, there's a basic error to fix: You create one pipe in the main program, and this pipe remains open until the end of the program; every process that reads from the pipe until EOF will not terminate before the end of the main program, so the more pipe command lines you enter during a run, the more waiting processes will hang around (you can observe this with ps). To correct this, create the pipe just before the fork for the pipeline processes; in addition you must close both ends of the pipe after the dup2 (see below).
After this, the output redirection is simple, similar to what you did in case if normal command has redirection, but you violated the rule:
int open(const char *pathname, int flags, mode_t mode);
mode specifies the permissions to use in case a new file is
created. This argument must be supplied when O_CREAT is
specified in flags;
So the core of your piping code becomes:
pipe(fd);
if ((pid = fork()) < 0)
perror("fork error");
else if (pid == 0) {
dup2(fd[1], STDOUT_FILENO);
close(fd[0]); // close both fd in child
close(fd[1]);
execvp(*command.argv1, command.argv1);
} else {
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]); // close both fd in parent
if (command.redirect_out)
{
fdout =
open(command.outfile, O_CREAT|O_WRONLY|O_TRUNC, 0666);
dup2(fdout, STDOUT_FILENO);
}
execvp(*command.argv2, command.argv2);
}
In the following snippet i am redirecting the output of the ls command to input of wc -l which works perfectly .Now i also want to redirect the output of ls command to a file named "beejoutput.txt" using the following code but its not working. Need help.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int pfds[2];
pipe(pfds);
if (!fork())
{
dup2(pfds[1],1);
close(pfds[0]);
execlp("ls", "ls",NULL);
}
else
{
FILE *outputO=fopen ("beejoutput.txt", "w"); //opening file for writing
dup2(pfds[0],0);
dup2(fileno(outputO),pfds[0]);
close(pfds[1]);
execlp("wc", "wc","-l", NULL);
}
return 0;
}
The dup function duplicates a file descriptor, that is, both the old and new file descriptors refer to the same open file afterwards. That is different from having a single file descriptor refer to two different files at the same time.
If you want to send the same data to two different destinations, you need to spawn both commands in separate processes, and do the copying yourself, or spawn a copy of the "tee" command -- either way, you end up with three processes.
This worked for me :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int pfds[2];
pipe(pfds);
pid_t childpid = fork();
if (childpid == 0) {
/* Child */
dup2(pfds[1],1);
close(pfds[0]);
execlp("ls", "ls",NULL);
} else {
/* Parent */
pid_t retpid;
int child_stat;
while ((retpid = waitpid(childpid, &child_stat, 0)) != childpid && retpid != (pid_t) -1)
;
close(pfds[1]);
char buf[100];
ssize_t bytesread;
int fd = open("beejoutput.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1) {
fprintf(stderr, "Opening of beejoutput.txt failed!\n");
exit(1);
}
/* This part writes to beejoutput.txt */
while ((bytesread = read(pfds[0], buf, 100)) > 0) {
write(fd, buf, bytesread);
}
lseek(fd, (off_t) 0, SEEK_SET);
dup2(fd, 0);
execlp("wc", "wc", "-l", NULL);
}
return 0;
}
Try checking the result codes of all the system calls that you do (including dup2). This will possibly lead you to an answer. This is a good habbit, anyway.