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