1 /* $NetBSD: os.c,v 1.4 1998/02/04 11:09:01 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1988 Mark Nudleman 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)os.c 8.1 (Berkeley) 6/6/93"; 41 #else 42 __RCSID("$NetBSD: os.c,v 1.4 1998/02/04 11:09:01 christos Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 /* 47 * Operating system dependent routines. 48 * 49 * Most of the stuff in here is based on Unix, but an attempt 50 * has been made to make things work on other operating systems. 51 * This will sometimes result in a loss of functionality, unless 52 * someone rewrites code specifically for the new operating system. 53 * 54 * The makefile provides defines to decide whether various 55 * Unix features are present. 56 */ 57 58 #include <sys/param.h> 59 #include <sys/stat.h> 60 #include <sys/file.h> 61 #include <signal.h> 62 #include <setjmp.h> 63 #include <stdio.h> 64 #include <string.h> 65 #include <stdlib.h> 66 #include <unistd.h> 67 #include <errno.h> 68 69 #include "less.h" 70 #include "extern.h" 71 #include "pathnames.h" 72 73 int reading; 74 75 static jmp_buf read_label; 76 77 /* 78 * Pass the specified command to a shell to be executed. 79 * Like plain "system()", but handles resetting terminal modes, etc. 80 */ 81 void 82 lsystem(cmd) 83 char *cmd; 84 { 85 int inp; 86 char cmdbuf[256]; 87 char *shell; 88 89 /* 90 * Print the command which is to be executed, 91 * unless the command starts with a "-". 92 */ 93 if (cmd[0] == '-') 94 cmd++; 95 else 96 { 97 lower_left(); 98 clear_eol(); 99 putstr("!"); 100 putstr(cmd); 101 putstr("\n"); 102 } 103 104 /* 105 * De-initialize the terminal and take out of raw mode. 106 */ 107 deinit(); 108 flush(); 109 raw_mode(0); 110 111 /* 112 * Restore signals to their defaults. 113 */ 114 init_signals(0); 115 116 /* 117 * Force standard input to be the terminal, "/dev/tty", 118 * even if less's standard input is coming from a pipe. 119 */ 120 inp = dup(0); 121 (void)close(0); 122 if (open(_PATH_TTY, O_RDONLY, 0) < 0) 123 (void)dup(inp); 124 125 /* 126 * Pass the command to the system to be executed. 127 * If we have a SHELL environment variable, use 128 * <$SHELL -c "command"> instead of just <command>. 129 * If the command is empty, just invoke a shell. 130 */ 131 if ((shell = getenv("SHELL")) != NULL && *shell != '\0') 132 { 133 if (*cmd == '\0') 134 cmd = shell; 135 else 136 { 137 (void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd); 138 cmd = cmdbuf; 139 } 140 } 141 if (*cmd == '\0') 142 cmd = "sh"; 143 144 (void)system(cmd); 145 146 /* 147 * Restore standard input, reset signals, raw mode, etc. 148 */ 149 (void)close(0); 150 (void)dup(inp); 151 (void)close(inp); 152 153 init_signals(1); 154 raw_mode(1); 155 init(); 156 screen_trashed = 1; 157 #if defined(SIGWINCH) || defined(SIGWIND) 158 /* 159 * Since we were ignoring window change signals while we executed 160 * the system command, we must assume the window changed. 161 */ 162 winch(SIGWINCH); 163 #endif 164 } 165 166 /* 167 * Like read() system call, but is deliberately interruptable. 168 * A call to intread() from a signal handler will interrupt 169 * any pending iread(). 170 */ 171 int 172 iread(fd, buf, len) 173 int fd; 174 char *buf; 175 int len; 176 { 177 int n; 178 179 if (setjmp(read_label)) 180 /* 181 * We jumped here from intread. 182 */ 183 return (READ_INTR); 184 185 flush(); 186 reading = 1; 187 n = read(fd, buf, len); 188 reading = 0; 189 if (n < 0) 190 return (-1); 191 return (n); 192 } 193 194 void 195 intread() 196 { 197 (void)sigsetmask(0L); 198 longjmp(read_label, 1); 199 } 200 201 /* 202 * Expand a filename, substituting any environment variables, etc. 203 * The implementation of this is necessarily very operating system 204 * dependent. This implementation is unabashedly only for Unix systems. 205 */ 206 char * 207 glob(filename) 208 char *filename; 209 { 210 FILE *f; 211 char *p; 212 int ch; 213 char *cmd; 214 static char buffer[MAXPATHLEN]; 215 216 if (filename[0] == '#') 217 return (filename); 218 219 /* 220 * We get the shell to expand the filename for us by passing 221 * an "echo" command to the shell and reading its output. 222 */ 223 p = getenv("SHELL"); 224 if (p == NULL || *p == '\0') 225 { 226 /* 227 * Read the output of <echo filename>. 228 */ 229 cmd = malloc((u_int)(strlen(filename)+8)); 230 if (cmd == NULL) 231 return (filename); 232 (void)sprintf(cmd, "echo \"%s\"", filename); 233 } else 234 { 235 /* 236 * Read the output of <$SHELL -c "echo filename">. 237 */ 238 cmd = malloc((u_int)(strlen(p)+12)); 239 if (cmd == NULL) 240 return (filename); 241 (void)sprintf(cmd, "%s -c \"echo %s\"", p, filename); 242 } 243 244 if ((f = popen(cmd, "r")) == NULL) 245 return (filename); 246 free(cmd); 247 248 for (p = buffer; p < &buffer[sizeof(buffer)-1]; p++) 249 { 250 if ((ch = getc(f)) == '\n' || ch == EOF) 251 break; 252 *p = ch; 253 } 254 *p = '\0'; 255 (void)pclose(f); 256 return(buffer); 257 } 258 259 char * 260 bad_file(filename, message, len) 261 char *filename, *message; 262 u_int len; 263 { 264 struct stat statbuf; 265 266 if (stat(filename, &statbuf) < 0) { 267 (void)sprintf(message, "%s: %s", filename, strerror(errno)); 268 return(message); 269 } 270 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { 271 static char is_dir[] = " is a directory"; 272 273 strtcpy(message, filename, (int)(len-sizeof(is_dir)-1)); 274 (void)strcat(message, is_dir); 275 return(message); 276 } 277 return((char *)NULL); 278 } 279 280 /* 281 * Copy a string, truncating to the specified length if necessary. 282 * Unlike strncpy(), the resulting string is guaranteed to be null-terminated. 283 */ 284 void 285 strtcpy(to, from, len) 286 char *to, *from; 287 int len; 288 { 289 (void)strncpy(to, from, (int)len); 290 to[len-1] = '\0'; 291 } 292 293