1 /* 2 * Pager: Routines to create a "more" running out of a particular file 3 * descriptor. 4 * 5 * Copyright 1987, 1988 by MIT Student Information Processing Board 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose is hereby granted, provided that 9 * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in 10 * advertising or publicity pertaining to distribution of the software 11 * without specific, written prior permission. M.I.T. and the 12 * M.I.T. S.I.P.B. make no representations about the suitability of 13 * this software for any purpose. It is provided "as is" without 14 * express or implied warranty. 15 */ 16 17 #include "config.h" 18 #ifdef HAVE_UNISTD_H 19 #include <unistd.h> 20 #endif 21 #ifdef HAVE_ERRNO_H 22 #include <errno.h> 23 #else 24 extern int errno; 25 #endif 26 27 #include "ss_internal.h" 28 #include <stdio.h> 29 #include <sys/types.h> 30 #include <sys/file.h> 31 #include <signal.h> 32 #ifdef HAVE_SYS_PRCTL_H 33 #include <sys/prctl.h> 34 #else 35 #define PR_GET_DUMPABLE 3 36 #endif 37 #if (!defined(HAVE_PRCTL) && defined(linux)) 38 #include <sys/syscall.h> 39 #endif 40 41 static char MORE[] = "more"; 42 extern char *getenv PROTOTYPE((const char *)); 43 44 char *ss_safe_getenv(const char *arg) 45 { 46 if ((getuid() != geteuid()) || (getgid() != getegid())) 47 return NULL; 48 #if HAVE_PRCTL 49 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) 50 return NULL; 51 #else 52 #if (defined(linux) && defined(SYS_prctl)) 53 if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) 54 return NULL; 55 #endif 56 #endif 57 58 #if defined(HAVE_SECURE_GETENV) 59 return secure_getenv(arg); 60 #elif defined(HAVE___SECURE_GETENV) 61 return __secure_getenv(arg); 62 #else 63 return getenv(arg); 64 #endif 65 } 66 67 /* 68 * this needs a *lot* of work.... 69 * 70 * run in same process 71 * handle SIGINT sensibly 72 * allow finer control -- put-page-break-here 73 */ 74 75 #ifndef NO_FORK 76 int ss_pager_create(void) 77 { 78 int filedes[2]; 79 80 if (pipe(filedes) != 0) 81 return(-1); 82 83 switch(fork()) { 84 case -1: 85 return(-1); 86 case 0: 87 /* 88 * Child; dup read half to 0, close all but 0, 1, and 2 89 */ 90 if (dup2(filedes[0], 0) == -1) 91 exit(1); 92 ss_page_stdin(); 93 default: 94 /* 95 * Parent: close "read" side of pipe, return 96 * "write" side. 97 */ 98 (void) close(filedes[0]); 99 return(filedes[1]); 100 } 101 } 102 #else /* don't fork */ 103 int ss_pager_create() 104 { 105 int fd; 106 fd = open("/dev/tty", O_WRONLY, 0); 107 return fd; 108 } 109 #endif 110 111 static int write_all(int fd, char *buf, size_t count) 112 { 113 ssize_t ret; 114 int c = 0; 115 116 while (count > 0) { 117 ret = write(fd, buf, count); 118 if (ret < 0) { 119 if ((errno == EAGAIN) || (errno == EINTR)) 120 continue; 121 return -1; 122 } 123 count -= ret; 124 buf += ret; 125 c += ret; 126 } 127 return c; 128 } 129 130 void ss_page_stdin(void) 131 { 132 int i; 133 sigset_t mask; 134 135 for (i = 3; i < 32; i++) 136 (void) close(i); 137 (void) signal(SIGINT, SIG_DFL); 138 sigprocmask(SIG_BLOCK, 0, &mask); 139 sigdelset(&mask, SIGINT); 140 sigprocmask(SIG_SETMASK, &mask, 0); 141 if (_ss_pager_name == (char *)NULL) { 142 if ((_ss_pager_name = ss_safe_getenv("PAGER")) == (char *)NULL) 143 _ss_pager_name = MORE; 144 } 145 (void) execlp(_ss_pager_name, _ss_pager_name, (char *) NULL); 146 { 147 /* minimal recovery if pager program isn't found */ 148 char buf[80]; 149 register int n; 150 while ((n = read(0, buf, 80)) > 0) 151 write_all(1, buf, n); 152 } 153 exit(errno); 154 } 155