pager.c revision a6ce1349539f866334ef3d5758bc2ee44a454acd
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
2f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles) * Pager: Routines to create a "more" running out of a particular file
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * descriptor.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright 1987, 1988 by MIT Student Information Processing Board
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Permission to use, copy, modify, and distribute this software and
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * its documentation for any purpose is hereby granted, provided that
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * advertising or publicity pertaining to distribution of the software
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * without specific, written prior permission.  M.I.T. and the
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * M.I.T. S.I.P.B. make no representations about the suitability of
13f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles) * this software for any purpose.  It is provided "as is" without
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * express or implied warranty.
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
16f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifdef HAVE_UNISTD_H
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <unistd.h>
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifdef HAVE_ERRNO_H
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <errno.h>
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#else
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)extern int errno;
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
26f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)#include "ss_internal.h"
27d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)#include <stdio.h>
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <sys/types.h>
29bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)#include <sys/file.h>
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <signal.h>
31c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#ifdef HAVE_SYS_PRCTL_H
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <sys/prctl.h>
33f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)#else
34f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)#define PR_GET_DUMPABLE 3
35f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)#endif
36f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)#if (!defined(HAVE_PRCTL) && defined(linux))
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <sys/syscall.h>
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
39f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)
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