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