Commit | Line | Data |
---|---|---|
2ec5f51d NW |
1 | /* |
2 | * Copyright (c) 1988 Mark Nudleman | |
3 | * Copyright (c) 1988 Regents of the University of California. | |
4 | * 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 5.12 (Berkeley) 3/1/91"; | |
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 |