I am using pipes to display file contents. When I comment the wait command (in the last part of the parent process), I expect to see the parent process in the ps
command's output (after a while, because reading is completed and I am still browsing output generated by child process), but I see both parent and child processes in the output.
The following code shows argv1 content. After building the program (for example xpager
) it should be executed as xpager filename
.
My platform is Ubuntu 22.04.4 LTS
.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
#define BUFSIZE 8192
#define PPAGER "/usr/bin/less"
int main(int argc, char *argv[]) {
pid_t pid;
int eerrno, n;
int in, pfd[2];
char buf[BUFSIZE];
char *pager, *argv0;
if (argc != 2) {
printf("usage: %s <pathname>\n", argv[0]);
exit(1);
}
if ( (in = open(argv[1], O_RDONLY)) < 0) {
eerrno = errno;
printf("Open error. %s(%d)\n", strerror(errno), errno);
exit(eerrno);
}
if ( pipe(pfd) < 0) {
eerrno = errno;
printf("pipe error. %s(%d)\n", strerror(errno), errno);
exit(eerrno);
}
pid = fork();
switch (pid) {
case -1:
eerrno = errno;
printf("fork error. %s(%d)\n", strerror(errno), errno);
exit(eerrno);
case 0:
close(pfd[1]);
close(in);
if (STDIN_FILENO != pfd[0]) {
if (dup2(pfd[0], STDIN_FILENO) < 0) {
eerrno = errno;
printf("dup2 error. %s(%d)\n", strerror(errno), errno);
exit(eerrno);
}
close(pfd[0]);
}
if ((pager=getenv("PPAGER")) == NULL)
pager = PPAGER;
if ((argv0=strrchr(pager, '/')) != NULL)
argv0++;
else
argv0=pager;
execlp(pager, argv0, argv[1], (char *)0);
default:
close(pfd[0]);
while((n=read(in, buf, BUFSIZE)) > 0) {
if (write(pfd[1], buf, n) < 0) {
eerrno = errno;
printf("write errno. %s(%d)\n", strerror(errno), errno);
kill (pid, 9);
exit(eerrno);
}
}
if (n < 0) {
eerrno = errno;
printf("read error. %s(%d)\n", strerror(errno), errno);
kill(pid, 9);
exit(eerrno);
}
close(pfd[1]);
// wait(NULL);
}
exit(0);
}
For easier reading, summarized code is as follow:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/wait.h>
#define BUFSIZE 8192
#define PPAGER "/usr/bin/less"
int main(int argc, char *argv[]) {
pid_t pid;
int n,in, pfd[2];
char buf[BUFSIZE];
char *pager, *argv0;
in = open(argv[1], O_RDONLY);
pipe(pfd);
pid = fork();
switch (pid) {
case 0:
close(pfd[1]);
dup2(pfd[0], STDIN_FILENO);
pager = PPAGER;
argv0="less";
execlp(pager, argv0, argv[1], (char *)0);
default:
close(pfd[0]);
while ((n=read(in, buf, BUFSIZE)) > 0)
write(pfd[1], buf, n);
close(pfd[1]);
// wait(NULL);
}
return(0);
}
Get rid of the filename argument when calling the pager in the child process. When it's not given a filename, it will read from its standard input by default, and stdin has been redirected to the pipe:
So change
execlp(pager, argv0, argv[1], (char *)0);
to
execlp(pager, argv0, (char *)0);