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 #if HAVE_SECURE_GETENV 18 #define _GNU_SOURCE 19 #endif 20 #ifdef HAVE_UNISTD_H 21 #include <unistd.h> 22 #endif 23 #ifdef HAVE_ERRNO_H 24 #include <errno.h> 25 #else 26 extern int errno; 27 #endif 28 29 #include "ss_internal.h" 30 #include <stdio.h> 31 #include <sys/types.h> 32 #include <sys/file.h> 33 #include <signal.h> 34 #ifdef HAVE_SYS_PRCTL_H 35 #include <sys/prctl.h> 36 #else 37 #define PR_GET_DUMPABLE 3 38 #endif 39 #if (!defined(HAVE_PRCTL) && defined(linux)) 40 #include <sys/syscall.h> 41 #endif 42 43 static char MORE[] = "more"; 44 extern char *getenv PROTOTYPE((const char *)); 45 46 char *ss_safe_getenv(const char *arg) 47 { 48 if ((getuid() != geteuid()) || (getgid() != getegid())) 49 return NULL; 50 #if HAVE_PRCTL 51 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) 52 return NULL; 53 #else 54 #if (defined(linux) && defined(SYS_prctl)) 55 if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) 56 return NULL; 57 #endif 58 #endif 59 60 #if defined(HAVE_SECURE_GETENV) 61 return secure_getenv(arg); 62 #elif defined(HAVE___SECURE_GETENV) 63 return __secure_getenv(arg); 64 #else 65 return getenv(arg); 66 #endif 67 } 68 69 /* 70 * this needs a *lot* of work.... 71 * 72 * run in same process 73 * handle SIGINT sensibly 74 * allow finer control -- put-page-break-here 75 */ 76 77 #ifndef NO_FORK 78 int ss_pager_create(void) 79 { 80 int filedes[2]; 81 82 if (pipe(filedes) != 0) 83 return(-1); 84 85 switch(fork()) { 86 case -1: 87 return(-1); 88 case 0: 89 /* 90 * Child; dup read half to 0, close all but 0, 1, and 2 91 */ 92 if (dup2(filedes[0], 0) == -1) 93 exit(1); 94 ss_page_stdin(); 95 default: 96 /* 97 * Parent: close "read" side of pipe, return 98 * "write" side. 99 */ 100 (void) close(filedes[0]); 101 return(filedes[1]); 102 } 103 } 104 #else /* don't fork */ 105 int ss_pager_create() 106 { 107 int fd; 108 fd = open("/dev/tty", O_WRONLY, 0); 109 return fd; 110 } 111 #endif 112 113 static int write_all(int fd, char *buf, size_t count) 114 { 115 ssize_t ret; 116 int c = 0; 117 118 while (count > 0) { 119 ret = write(fd, buf, count); 120 if (ret < 0) { 121 if ((errno == EAGAIN) || (errno == EINTR)) 122 continue; 123 return -1; 124 } 125 count -= ret; 126 buf += ret; 127 c += ret; 128 } 129 return c; 130 } 131 132 void ss_page_stdin(void) 133 { 134 int i; 135 sigset_t mask; 136 137 for (i = 3; i < 32; i++) 138 (void) close(i); 139 (void) signal(SIGINT, SIG_DFL); 140 sigprocmask(SIG_BLOCK, 0, &mask); 141 sigdelset(&mask, SIGINT); 142 sigprocmask(SIG_SETMASK, &mask, 0); 143 if (_ss_pager_name == (char *)NULL) { 144 if ((_ss_pager_name = ss_safe_getenv("PAGER")) == (char *)NULL) 145 _ss_pager_name = MORE; 146 } 147 (void) execlp(_ss_pager_name, _ss_pager_name, (char *) NULL); 148 { 149 /* minimal recovery if pager program isn't found */ 150 char buf[80]; 151 register int n; 152 while ((n = read(0, buf, 80)) > 0) 153 write_all(1, buf, n); 154 } 155 exit(errno); 156 } 157