blob: bb149d69e91edd385b6c96404dc688397830ac44 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
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 *
Theodore Ts'o06cefee1999-10-23 01:16:22 +00007 * 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.
Theodore Ts'o3839e651997-04-26 13:21:57 +000015 */
16
JP Abgralle0ed7402014-03-19 19:08:39 -070017#if HAVE_SECURE_GETENV
18#define _GNU_SOURCE
19#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +000020#ifdef HAVE_UNISTD_H
Theodore Ts'of3db3561997-04-26 13:34:30 +000021#include <unistd.h>
22#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +000023#ifdef HAVE_ERRNO_H
24#include <errno.h>
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000025#else
26extern int errno;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000027#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000028
Theodore Ts'o3839e651997-04-26 13:21:57 +000029#include "ss_internal.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000030#include <stdio.h>
31#include <sys/types.h>
32#include <sys/file.h>
33#include <signal.h>
Theodore Ts'o762c7c62005-04-06 14:44:16 -040034#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
Theodore Ts'o3839e651997-04-26 13:21:57 +000042
43static char MORE[] = "more";
Theodore Ts'o546a1ff2002-03-07 23:52:56 -050044extern char *getenv PROTOTYPE((const char *));
Theodore Ts'o3839e651997-04-26 13:21:57 +000045
Theodore Ts'o762c7c62005-04-06 14:44:16 -040046char *ss_safe_getenv(const char *arg)
47{
Theodore Ts'o09f3eba2005-04-16 13:56:03 -040048 if ((getuid() != geteuid()) || (getgid() != getegid()))
Theodore Ts'o762c7c62005-04-06 14:44:16 -040049 return NULL;
50#if HAVE_PRCTL
Theodore Ts'o583d1f82005-07-25 11:36:43 -050051 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
Theodore Ts'o762c7c62005-04-06 14:44:16 -040052 return NULL;
53#else
54#if (defined(linux) && defined(SYS_prctl))
Theodore Ts'o583d1f82005-07-25 11:36:43 -050055 if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
Theodore Ts'o762c7c62005-04-06 14:44:16 -040056 return NULL;
57#endif
58#endif
59
JP Abgralle0ed7402014-03-19 19:08:39 -070060#if defined(HAVE_SECURE_GETENV)
61 return secure_getenv(arg);
62#elif defined(HAVE___SECURE_GETENV)
Theodore Ts'o3af0a452005-05-08 02:15:02 -040063 return __secure_getenv(arg);
Theodore Ts'o762c7c62005-04-06 14:44:16 -040064#else
Theodore Ts'o3af0a452005-05-08 02:15:02 -040065 return getenv(arg);
Theodore Ts'o762c7c62005-04-06 14:44:16 -040066#endif
67}
68
Theodore Ts'o3839e651997-04-26 13:21:57 +000069/*
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 */
Theodore Ts'o3839e651997-04-26 13:21:57 +000076
77#ifndef NO_FORK
Theodore Ts'oefc6f622008-08-27 23:07:54 -040078int ss_pager_create(void)
Theodore Ts'o3839e651997-04-26 13:21:57 +000079{
80 int filedes[2];
Theodore Ts'oefc6f622008-08-27 23:07:54 -040081
Theodore Ts'o3839e651997-04-26 13:21:57 +000082 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
Theodore Ts'o935a1232009-04-22 14:48:59 -0400113static 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
JP Abgralle0ed7402014-03-19 19:08:39 -0700132void ss_page_stdin(void)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000133{
134 int i;
Theodore Ts'o91835c12003-03-30 22:26:13 -0500135 sigset_t mask;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400136
Theodore Ts'o3839e651997-04-26 13:21:57 +0000137 for (i = 3; i < 32; i++)
138 (void) close(i);
139 (void) signal(SIGINT, SIG_DFL);
Theodore Ts'o91835c12003-03-30 22:26:13 -0500140 sigprocmask(SIG_BLOCK, 0, &mask);
141 sigdelset(&mask, SIGINT);
142 sigprocmask(SIG_SETMASK, &mask, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000143 if (_ss_pager_name == (char *)NULL) {
Theodore Ts'o762c7c62005-04-06 14:44:16 -0400144 if ((_ss_pager_name = ss_safe_getenv("PAGER")) == (char *)NULL)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000145 _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)
Theodore Ts'o935a1232009-04-22 14:48:59 -0400153 write_all(1, buf, n);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000154 }
155 exit(errno);
156}