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