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