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