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