]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/more/os.c
BSD 4.4 Lite Usr.bin Sources
[FreeBSD/FreeBSD.git] / usr.bin / more / os.c
1 /*
2  * Copyright (c) 1988 Mark Nudleman
3  * Copyright (c) 1988, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by the University of
17  *      California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #ifndef lint
36 static char sccsid[] = "@(#)os.c        8.1 (Berkeley) 6/6/93";
37 #endif /* not lint */
38
39 /*
40  * Operating system dependent routines.
41  *
42  * Most of the stuff in here is based on Unix, but an attempt
43  * has been made to make things work on other operating systems.
44  * This will sometimes result in a loss of functionality, unless
45  * someone rewrites code specifically for the new operating system.
46  *
47  * The makefile provides defines to decide whether various
48  * Unix features are present.
49  */
50
51 #include <sys/param.h>
52 #include <sys/stat.h>
53 #include <sys/file.h>
54 #include <signal.h>
55 #include <setjmp.h>
56 #include <stdio.h>
57 #include <less.h>
58 #include "pathnames.h"
59
60 int reading;
61
62 extern int screen_trashed;
63
64 static jmp_buf read_label;
65
66 /*
67  * Pass the specified command to a shell to be executed.
68  * Like plain "system()", but handles resetting terminal modes, etc.
69  */
70 lsystem(cmd)
71         char *cmd;
72 {
73         int inp;
74         char cmdbuf[256];
75         char *shell, *getenv();
76
77         /*
78          * Print the command which is to be executed,
79          * unless the command starts with a "-".
80          */
81         if (cmd[0] == '-')
82                 cmd++;
83         else
84         {
85                 lower_left();
86                 clear_eol();
87                 putstr("!");
88                 putstr(cmd);
89                 putstr("\n");
90         }
91
92         /*
93          * De-initialize the terminal and take out of raw mode.
94          */
95         deinit();
96         flush();
97         raw_mode(0);
98
99         /*
100          * Restore signals to their defaults.
101          */
102         init_signals(0);
103
104         /*
105          * Force standard input to be the terminal, "/dev/tty",
106          * even if less's standard input is coming from a pipe.
107          */
108         inp = dup(0);
109         (void)close(0);
110         if (open(_PATH_TTY, O_RDONLY, 0) < 0)
111                 (void)dup(inp);
112
113         /*
114          * Pass the command to the system to be executed.
115          * If we have a SHELL environment variable, use
116          * <$SHELL -c "command"> instead of just <command>.
117          * If the command is empty, just invoke a shell.
118          */
119         if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
120         {
121                 if (*cmd == '\0')
122                         cmd = shell;
123                 else
124                 {
125                         (void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd);
126                         cmd = cmdbuf;
127                 }
128         }
129         if (*cmd == '\0')
130                 cmd = "sh";
131
132         (void)system(cmd);
133
134         /*
135          * Restore standard input, reset signals, raw mode, etc.
136          */
137         (void)close(0);
138         (void)dup(inp);
139         (void)close(inp);
140
141         init_signals(1);
142         raw_mode(1);
143         init();
144         screen_trashed = 1;
145 #if defined(SIGWINCH) || defined(SIGWIND)
146         /*
147          * Since we were ignoring window change signals while we executed
148          * the system command, we must assume the window changed.
149          */
150         winch();
151 #endif
152 }
153
154 /*
155  * Like read() system call, but is deliberately interruptable.
156  * A call to intread() from a signal handler will interrupt
157  * any pending iread().
158  */
159 iread(fd, buf, len)
160         int fd;
161         char *buf;
162         int len;
163 {
164         register int n;
165
166         if (setjmp(read_label))
167                 /*
168                  * We jumped here from intread.
169                  */
170                 return (READ_INTR);
171
172         flush();
173         reading = 1;
174         n = read(fd, buf, len);
175         reading = 0;
176         if (n < 0)
177                 return (-1);
178         return (n);
179 }
180
181 intread()
182 {
183         (void)sigsetmask(0L);
184         longjmp(read_label, 1);
185 }
186
187 /*
188  * Expand a filename, substituting any environment variables, etc.
189  * The implementation of this is necessarily very operating system
190  * dependent.  This implementation is unabashedly only for Unix systems.
191  */
192 FILE *popen();
193
194 char *
195 glob(filename)
196         char *filename;
197 {
198         FILE *f;
199         char *p;
200         int ch;
201         char *cmd, *malloc(), *getenv();
202         static char buffer[MAXPATHLEN];
203
204         if (filename[0] == '#')
205                 return (filename);
206
207         /*
208          * We get the shell to expand the filename for us by passing
209          * an "echo" command to the shell and reading its output.
210          */
211         p = getenv("SHELL");
212         if (p == NULL || *p == '\0')
213         {
214                 /*
215                  * Read the output of <echo filename>.
216                  */
217                 cmd = malloc((u_int)(strlen(filename)+8));
218                 if (cmd == NULL)
219                         return (filename);
220                 (void)sprintf(cmd, "echo \"%s\"", filename);
221         } else
222         {
223                 /*
224                  * Read the output of <$SHELL -c "echo filename">.
225                  */
226                 cmd = malloc((u_int)(strlen(p)+12));
227                 if (cmd == NULL)
228                         return (filename);
229                 (void)sprintf(cmd, "%s -c \"echo %s\"", p, filename);
230         }
231
232         if ((f = popen(cmd, "r")) == NULL)
233                 return (filename);
234         free(cmd);
235
236         for (p = buffer;  p < &buffer[sizeof(buffer)-1];  p++)
237         {
238                 if ((ch = getc(f)) == '\n' || ch == EOF)
239                         break;
240                 *p = ch;
241         }
242         *p = '\0';
243         (void)pclose(f);
244         return(buffer);
245 }
246
247 char *
248 bad_file(filename, message, len)
249         char *filename, *message;
250         u_int len;
251 {
252         extern int errno;
253         struct stat statbuf;
254         char *strcat(), *strerror();
255
256         if (stat(filename, &statbuf) < 0) {
257                 (void)sprintf(message, "%s: %s", filename, strerror(errno));
258                 return(message);
259         }
260         if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
261                 static char is_dir[] = " is a directory";
262
263                 strtcpy(message, filename, (int)(len-sizeof(is_dir)-1));
264                 (void)strcat(message, is_dir);
265                 return(message);
266         }
267         return((char *)NULL);
268 }
269
270 /*
271  * Copy a string, truncating to the specified length if necessary.
272  * Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
273  */
274 strtcpy(to, from, len)
275         char *to, *from;
276         int len;
277 {
278         char *strncpy();
279
280         (void)strncpy(to, from, (int)len);
281         to[len-1] = '\0';
282 }
283