Home | History | Annotate | Download | only in ss
      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