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