OSDN Git Service

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