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