pipe.c:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#define DEF_PAGER "/bin/more" // Default Pager program
#define MAXLINE 20
int main(int argc, char* argv[])
{
int n;
int fd[2];
pid_t pid;
char *pager, *argv0;
char line[MAXLINE];
FILE *fp;
// Open the file
if((fp = fopen(argv[1], "r")) == NULL) {
printf("can't open %s", argv[1]);
exit(1);
}
// Build the pipe
if(pipe(fd) < 0) {
printf("pipe error!\n");
exit(2);
}
if((pid = fork()) < 0) {
printf("fork error!\n");
exit(3);
} else if(pid > 0) {
close(fd[0]); // close read end
// Copy the content to pipe
while(fgets(line, MAXLINE, fp) != NULL) {
n = strlen(line);
if(write(fd[1], line, n) != n) {
printf("write error to pipe\n");
exit(4);
}
}
if(ferror(fp)) {
printf("fgets error!\n");
exit(5);
}
// close the write end
close(fd[1]);
if(waitpid(pid, NULL, 0) < 0) {
printf("waitpid error!\n");
exit(6);
}
} else {
close(fd[1]);
// duplicate the file descriptor if fd[0] is not standard input
// after this step, both fd[0] and STDIN_FILENO point to the same
// file table entry
if(fd[0] != STDIN_FILENO) {
if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
printf("dup2 error to stdin\n");
exit(7);
}
close(fd[0]);
}
// Get the pager
if((pager = getenv("PAGER")) == NULL) {
pager = DEF_PAGER;
}
// Make argv0 point to the next char of last '/' in pager path
if((argv0 = strrchr(pager, '/')) != NULL)
argv0++;
else
argv0 = pager;
// Execute the pager with pipe input from parent process
if(execl(pager, argv0, (char*)0) < 0) {
printf("execl error for %s\n", pager);
exit(8);
}
}
exit(0);
}
shell:
The program create the child process which make pipe file descriptor pointing to the standard input, and it will just make kernel give the pipe content through standard input.
So in the end the pager: /bin/more just print out the 2 lines from test1:
Hello world!
amazing world!
ubuntu@ip-172-31-23-227:~$ ./pipe.out test1
Hello world!
amazing world!
No comments:
Post a Comment