pager.c revision 18a1444b4f1e6a0948fd38fa0de382d86cfe04de
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
26extern 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
43static char MORE[] = "more";
44extern char *getenv PROTOTYPE((const char *));
45
46char *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
78int 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 */
105int ss_pager_create()
106{
107    int fd;
108    fd = open("/dev/tty", O_WRONLY, 0);
109    return fd;
110}
111#endif
112
113static 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
132void 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