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