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