Home | History | Annotate | Line # | Download | only in more
      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