You want a pipe like:
ls | cat
But, you're setting this up like:
cat | ls
And, in your current code, for the ls
side, you're doing:
close(fd[1]);
dup2(fd[1], STDIN_FILENO);
This is wrong for two reasons:
- You're closing the wrong side of the pipe, so the
dup2
gets a closed fd as its first argument
- You're attaching the output side of the pipe to the command's input side
So, we need to reverse the pipe order and fix the closing.
Also, after doing dup2(X,...)
we want to do close(X)
.
Also, note that doing waitpid
_after execve
will have no effect unless the execve
fails.
Here is the refactored and working code:
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int
main(void)
{
extern char **environ;
char *argv_cat[] = { "cat", NULL };
char *argv_ls[] = { "ls", NULL };
int fd[2];
pid_t pid;
int ret;
pipe(fd);
pid = fork();
// we want:
// ls | cat
if (pid == 0) {
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execve("/bin/cat", argv_cat, environ);
exit(0);
}
else if (pid > 0) {
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
execve("/bin/ls", argv_ls, environ);
waitpid(pid, &ret, 0);
}
return (0);
}
UPDATE:
waitpid
after execve
is pointless. –
William Pursell
Not quite. It reaps the [stuck] child process so that it doesn't become a child of the init/systemd
process.
In the above example, I had forgotten to add a close(STDOUT_FILENO)
before the waitpid
to "release" the cat
process.
Here is the adjusted code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
int opt_f;
int
main(int argc,char **argv)
{
extern char **environ;
char *argv_cat[] = { "cat", NULL };
char *argv_ls[] = { "ls", NULL };
int fd[2];
pid_t pid;
int status;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'f':
opt_f = ! opt_f;
break;
}
}
pipe(fd);
pid = fork();
// we want:
// ls | cat
if (pid == 0) {
if (opt_f)
fprintf(stderr,"cld: getpid=%d\n",getpid());
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execve("/bin/cat", argv_cat, environ);
exit(0);
}
else if (pid > 0) {
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
const char *ls = opt_f ? "/bin/gooch" : "/bin/ls";
execve(ls, argv_ls, environ);
fprintf(stderr,"execve failure of '%s' -- %s\n",ls,strerror(errno));
// release other process (cat)
close(STDOUT_FILENO);
// reap the child
pid_t ret = waitpid(pid, &status, 0);
fprintf(stderr,"ret=%d pid=%d status=%8.8X\n",ret,pid,status);
}
return (0);
}