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