pager.c (2096B)
1 #include "config.h" 2 3 #include <sys/wait.h> 4 5 #if HAVE_ERR 6 #include <err.h> 7 #endif 8 #include <errno.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <unistd.h> 12 #include <limits.h> 13 #include <stdint.h> 14 15 enum { 16 PIPE_READ, 17 PIPE_WRITE, 18 }; 19 20 int 21 main(int argc, char **argv) 22 { 23 int fildes[2]; 24 FILE *fpipew = NULL; 25 pid_t child; 26 uint32_t lines = 1024; 27 const char *errstr; 28 /* 29 * F: quit if one screen 30 * X: don't send some special instructions 31 * (e.g. clearing the terminal before starting). 32 */ 33 char *less_argv[] = { "less", "-FX", NULL }; 34 35 #if HAVE_PLEDGE 36 if (pledge("stdio proc exec", NULL) == -1) 37 err(1, "pledge"); 38 #endif 39 if (argc > 2) { 40 warnx("too many arguments: %s", argv[2]); 41 goto usage; 42 } else if (argc == 2) { 43 lines = strtonum(argv[1], 1, UINT_MAX, &errstr); 44 if (errstr != NULL) 45 errx(1, "number of lines is %s: %s", errstr, argv[1]); 46 } 47 48 if (pipe(fildes) == -1) 49 err(1, "pipe"); 50 51 switch (child = fork()) { 52 case -1: 53 err(1, "fork"); 54 case 0: 55 #if HAVE_PLEDGE 56 if (pledge("stdio exec", NULL) == -1) 57 err(1, "pledge"); 58 #endif 59 /* Pager process doesn't write to pipe */ 60 if (close(fildes[PIPE_WRITE]) == -1) 61 err(1, "close"); 62 /* Make PIPE_READ of pipe pager's STDIN */ 63 if (dup2(fildes[PIPE_READ], STDIN_FILENO) == -1) 64 err(1, "dup2"); 65 66 #if HAVE_PLEDGE 67 if (pledge("exec", NULL) == -1) 68 err(1, "pledge"); 69 #endif 70 execvp(less_argv[0], less_argv); 71 err(1, "execvp"); 72 break; 73 default: 74 #if HAVE_PLEDGE 75 if (pledge("stdio", NULL) == -1) 76 err(1, "pledge"); 77 #endif 78 if ((fpipew = fdopen(fildes[PIPE_WRITE], "w")) == NULL) 79 err(1, "fdopen"); 80 /* Parent doesn't read from pipe */ 81 if (close(fildes[PIPE_READ]) == -1) 82 err(1, "close"); 83 84 for (uint32_t i = 1; i <= lines; i++) 85 fprintf(fpipew, "%d\n", i); 86 87 /* Flush the buffer and signal EOF to the pager process. */ 88 if (fclose(fpipew) == EOF) 89 err(1, "fclose"); 90 91 /* Pass a dummy status since we don't set behavior */ 92 if (waitpid(child, &(pid_t){0}, 0) == -1) 93 err(1, "waitpid"); 94 break; 95 } 96 97 return 0; 98 99 usage: 100 fprintf(stderr, "usage: %s [num-lines]\n", getprogname()); 101 102 return 1; 103 }