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.8 (Berkeley) 07/25/88"; 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 <stdio.h> 37 #include <signal.h> 38 #include <setjmp.h> 39 #include "less.h" 40 41 char *getenv(); 42 43 public int reading; 44 45 extern int screen_trashed; 46 47 static jmp_buf read_label; 48 49 /* 50 * Pass the specified command to a shell to be executed. 51 * Like plain "system()", but handles resetting terminal modes, etc. 52 */ 53 public void 54 lsystem(cmd) 55 char *cmd; 56 { 57 int inp; 58 char cmdbuf[256]; 59 char *shell; 60 61 /* 62 * Print the command which is to be executed, 63 * unless the command starts with a "-". 64 */ 65 if (cmd[0] == '-') 66 cmd++; 67 else 68 { 69 lower_left(); 70 clear_eol(); 71 putstr("!"); 72 putstr(cmd); 73 putstr("\n"); 74 } 75 76 /* 77 * De-initialize the terminal and take out of raw mode. 78 */ 79 deinit(); 80 flush(); 81 raw_mode(0); 82 83 /* 84 * Restore signals to their defaults. 85 */ 86 init_signals(0); 87 88 /* 89 * Force standard input to be the terminal, "/dev/tty", 90 * even if less's standard input is coming from a pipe. 91 */ 92 inp = dup(0); 93 close(0); 94 if (open("/dev/tty", 0) < 0) 95 dup(inp); 96 97 /* 98 * Pass the command to the system to be executed. 99 * If we have a SHELL environment variable, use 100 * <$SHELL -c "command"> instead of just <command>. 101 * If the command is empty, just invoke a shell. 102 */ 103 if ((shell = getenv("SHELL")) != NULL && *shell != '\0') 104 { 105 if (*cmd == '\0') 106 cmd = shell; 107 else 108 { 109 (void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd); 110 cmd = cmdbuf; 111 } 112 } 113 if (*cmd == '\0') 114 cmd = "sh"; 115 116 system(cmd); 117 118 /* 119 * Restore standard input, reset signals, raw mode, etc. 120 */ 121 close(0); 122 dup(inp); 123 close(inp); 124 125 init_signals(1); 126 raw_mode(1); 127 init(); 128 screen_trashed = 1; 129 #if defined(SIGWINCH) || defined(SIGWIND) 130 /* 131 * Since we were ignoring window change signals while we executed 132 * the system command, we must assume the window changed. 133 */ 134 winch(); 135 #endif 136 } 137 138 /* 139 * Like read() system call, but is deliberately interruptable. 140 * A call to intread() from a signal handler will interrupt 141 * any pending iread(). 142 */ 143 public int 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 public void 167 intread() 168 { 169 sigsetmask(0L); 170 longjmp(read_label, 1); 171 } 172 173 public long 174 get_time() 175 { 176 time_t time(); 177 178 return(time((long *)NULL)); 179 } 180 181 /* 182 * Expand a filename, substituting any environment variables, etc. 183 * The implementation of this is necessarily very operating system 184 * dependent. This implementation is unabashedly only for Unix systems. 185 */ 186 FILE *popen(); 187 188 public char * 189 glob(filename) 190 char *filename; 191 { 192 FILE *f; 193 char *p; 194 int ch; 195 char *cmd, *malloc(); 196 static char buffer[FILENAME]; 197 198 if (filename[0] == '#') 199 return (filename); 200 201 /* 202 * We get the shell to expand the filename for us by passing 203 * an "echo" command to the shell and reading its output. 204 */ 205 p = getenv("SHELL"); 206 if (p == NULL || *p == '\0') 207 { 208 /* 209 * Read the output of <echo filename>. 210 */ 211 cmd = malloc((u_int)(strlen(filename)+8)); 212 if (cmd == NULL) 213 return (filename); 214 (void)sprintf(cmd, "echo \"%s\"", filename); 215 } else 216 { 217 /* 218 * Read the output of <$SHELL -c "echo filename">. 219 */ 220 cmd = malloc((u_int)(strlen(p)+12)); 221 if (cmd == NULL) 222 return (filename); 223 (void)sprintf(cmd, "%s -c \"echo %s\"", p, filename); 224 } 225 226 if ((f = popen(cmd, "r")) == NULL) 227 return (filename); 228 free(cmd); 229 230 for (p = buffer; p < &buffer[sizeof(buffer)-1]; p++) 231 { 232 if ((ch = getc(f)) == '\n' || ch == EOF) 233 break; 234 *p = ch; 235 } 236 *p = '\0'; 237 pclose(f); 238 return (buffer); 239 } 240 241 /* 242 * Returns NULL if the file can be opened and 243 * is an ordinary file, otherwise an error message 244 * (if it cannot be opened or is a directory, etc.) 245 */ 246 247 #include <sys/types.h> 248 #include <sys/stat.h> 249 250 public char * 251 bad_file(filename, message, len) 252 char *filename; 253 char *message; 254 unsigned int len; 255 { 256 struct stat statbuf; 257 char *strcat(); 258 259 if (stat(filename, &statbuf) < 0) 260 return (errno_message(filename, message, len)); 261 262 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) 263 { 264 static char is_dir[] = " is a directory"; 265 strtcpy(message, filename, len-sizeof(is_dir)-1); 266 (void)strcat(message, is_dir); 267 return (message); 268 } 269 if ((statbuf.st_mode & S_IFMT) != S_IFREG) 270 { 271 static char not_reg[] = " is not a regular file"; 272 strtcpy(message, filename, len-sizeof(not_reg)-1); 273 (void)strcat(message, not_reg); 274 return (message); 275 } 276 return (NULL); 277 } 278 279 /* 280 * errno_message: Return an error message based on the value of "errno". 281 * okreadfail: Return true if the previous failure of a read 282 * (on the input tty) should be considered ok. 283 */ 284 285 extern char *sys_errlist[]; 286 extern int sys_nerr; 287 extern int errno; 288 289 public char * 290 errno_message(filename, message, len) 291 char *filename; 292 char *message; 293 unsigned int len; 294 { 295 char *p; 296 char msg[16]; 297 298 if (errno < sys_nerr) 299 p = sys_errlist[errno]; 300 else 301 { 302 (void)sprintf(msg, "Error %d", errno); 303 p = msg; 304 } 305 strtcpy(message, filename, len-strlen(p)-3); 306 (void)strcat(message, ": "); 307 (void)strcat(message, p); 308 return (message); 309 } 310