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 */
lsystem(cmd)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 */
iread(fd,buf,len)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
intread()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 *
glob(filename)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 *
bad_file(filename,message,len)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 */
strtcpy(to,from,len)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