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