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