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 26extern 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 43static char MORE[] = "more"; 44extern char *getenv PROTOTYPE((const char *)); 45 46char *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 78int 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 */ 105int ss_pager_create() 106{ 107 int fd; 108 fd = open("/dev/tty", O_WRONLY, 0); 109 return fd; 110} 111#endif 112 113static 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 132void 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