pager.c revision 935a123f3b9156e18d1397a05e5b5f1a5e021f22
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#ifdef HAVE_UNISTD_H
18#include <unistd.h>
19#endif
20#ifdef HAVE_ERRNO_H
21#include <errno.h>
22#else
23extern int errno;
24#endif
25
26#include "ss_internal.h"
27#include <stdio.h>
28#include <sys/types.h>
29#include <sys/file.h>
30#include <signal.h>
31#ifdef HAVE_SYS_PRCTL_H
32#include <sys/prctl.h>
33#else
34#define PR_GET_DUMPABLE 3
35#endif
36#if (!defined(HAVE_PRCTL) && defined(linux))
37#include <sys/syscall.h>
38#endif
39
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