135209Sbostic /*
235209Sbostic * Copyright (c) 1988 Mark Nudleman
3*62131Sbostic * Copyright (c) 1988, 1993
4*62131Sbostic * The Regents of the University of California. All rights reserved.
535209Sbostic *
642742Sbostic * %sccs.include.redist.c%
735209Sbostic */
835209Sbostic
935209Sbostic #ifndef lint
10*62131Sbostic static char sccsid[] = "@(#)os.c 8.1 (Berkeley) 06/06/93";
1135209Sbostic #endif /* not lint */
1235209Sbostic
1335209Sbostic /*
1435209Sbostic * Operating system dependent routines.
1535209Sbostic *
1635209Sbostic * Most of the stuff in here is based on Unix, but an attempt
1735209Sbostic * has been made to make things work on other operating systems.
1835209Sbostic * This will sometimes result in a loss of functionality, unless
1935209Sbostic * someone rewrites code specifically for the new operating system.
2035209Sbostic *
2135209Sbostic * The makefile provides defines to decide whether various
2235209Sbostic * Unix features are present.
2335209Sbostic */
2435209Sbostic
2536253Sbostic #include <sys/param.h>
2636253Sbostic #include <sys/stat.h>
2736253Sbostic #include <sys/file.h>
2835209Sbostic #include <signal.h>
2935209Sbostic #include <setjmp.h>
3036253Sbostic #include <stdio.h>
3136253Sbostic #include <less.h>
3237919Sbostic #include "pathnames.h"
3335209Sbostic
3436253Sbostic int reading;
3535209Sbostic
3635209Sbostic extern int screen_trashed;
3735209Sbostic
3835209Sbostic static jmp_buf read_label;
3935209Sbostic
4035209Sbostic /*
4135209Sbostic * Pass the specified command to a shell to be executed.
4235209Sbostic * Like plain "system()", but handles resetting terminal modes, etc.
4335209Sbostic */
lsystem(cmd)4435209Sbostic lsystem(cmd)
4535209Sbostic char *cmd;
4635209Sbostic {
4735209Sbostic int inp;
4835209Sbostic char cmdbuf[256];
4936253Sbostic char *shell, *getenv();
5035209Sbostic
5135209Sbostic /*
5235209Sbostic * Print the command which is to be executed,
5335209Sbostic * unless the command starts with a "-".
5435209Sbostic */
5535209Sbostic if (cmd[0] == '-')
5635209Sbostic cmd++;
5735209Sbostic else
5835209Sbostic {
5935209Sbostic lower_left();
6035209Sbostic clear_eol();
6135209Sbostic putstr("!");
6235209Sbostic putstr(cmd);
6335209Sbostic putstr("\n");
6435209Sbostic }
6535209Sbostic
6635209Sbostic /*
6735209Sbostic * De-initialize the terminal and take out of raw mode.
6835209Sbostic */
6935209Sbostic deinit();
7035209Sbostic flush();
7135209Sbostic raw_mode(0);
7235209Sbostic
7335209Sbostic /*
7435209Sbostic * Restore signals to their defaults.
7535209Sbostic */
7635209Sbostic init_signals(0);
7735209Sbostic
7835209Sbostic /*
7935209Sbostic * Force standard input to be the terminal, "/dev/tty",
8035209Sbostic * even if less's standard input is coming from a pipe.
8135209Sbostic */
8235209Sbostic inp = dup(0);
8336253Sbostic (void)close(0);
8437919Sbostic if (open(_PATH_TTY, O_RDONLY, 0) < 0)
8536253Sbostic (void)dup(inp);
8635209Sbostic
8735209Sbostic /*
8835209Sbostic * Pass the command to the system to be executed.
8935209Sbostic * If we have a SHELL environment variable, use
9035209Sbostic * <$SHELL -c "command"> instead of just <command>.
9135209Sbostic * If the command is empty, just invoke a shell.
9235209Sbostic */
9335209Sbostic if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
9435209Sbostic {
9535209Sbostic if (*cmd == '\0')
9635209Sbostic cmd = shell;
9735209Sbostic else
9835209Sbostic {
9935244Sbostic (void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd);
10035209Sbostic cmd = cmdbuf;
10135209Sbostic }
10235209Sbostic }
10335209Sbostic if (*cmd == '\0')
10435209Sbostic cmd = "sh";
10535209Sbostic
10636253Sbostic (void)system(cmd);
10735209Sbostic
10835209Sbostic /*
10935209Sbostic * Restore standard input, reset signals, raw mode, etc.
11035209Sbostic */
11136253Sbostic (void)close(0);
11236253Sbostic (void)dup(inp);
11336253Sbostic (void)close(inp);
11435209Sbostic
11535209Sbostic init_signals(1);
11635209Sbostic raw_mode(1);
11735209Sbostic init();
11835209Sbostic screen_trashed = 1;
11935209Sbostic #if defined(SIGWINCH) || defined(SIGWIND)
12035209Sbostic /*
12135209Sbostic * Since we were ignoring window change signals while we executed
12235209Sbostic * the system command, we must assume the window changed.
12335209Sbostic */
12435209Sbostic winch();
12535209Sbostic #endif
12635209Sbostic }
12735209Sbostic
12835209Sbostic /*
12935209Sbostic * Like read() system call, but is deliberately interruptable.
13035209Sbostic * A call to intread() from a signal handler will interrupt
13135209Sbostic * any pending iread().
13235209Sbostic */
iread(fd,buf,len)13335209Sbostic iread(fd, buf, len)
13435209Sbostic int fd;
13535209Sbostic char *buf;
13635209Sbostic int len;
13735209Sbostic {
13835209Sbostic register int n;
13935209Sbostic
14035209Sbostic if (setjmp(read_label))
14135209Sbostic /*
14235209Sbostic * We jumped here from intread.
14335209Sbostic */
14435209Sbostic return (READ_INTR);
14535209Sbostic
14635209Sbostic flush();
14735209Sbostic reading = 1;
14835209Sbostic n = read(fd, buf, len);
14935209Sbostic reading = 0;
15035209Sbostic if (n < 0)
15135209Sbostic return (-1);
15235209Sbostic return (n);
15335209Sbostic }
15435209Sbostic
intread()15535209Sbostic intread()
15635209Sbostic {
15736253Sbostic (void)sigsetmask(0L);
15835209Sbostic longjmp(read_label, 1);
15935209Sbostic }
16035209Sbostic
16135209Sbostic /*
16235209Sbostic * Expand a filename, substituting any environment variables, etc.
16335209Sbostic * The implementation of this is necessarily very operating system
16435209Sbostic * dependent. This implementation is unabashedly only for Unix systems.
16535209Sbostic */
16635209Sbostic FILE *popen();
16735209Sbostic
16836253Sbostic char *
glob(filename)16935209Sbostic glob(filename)
17035209Sbostic char *filename;
17135209Sbostic {
17235209Sbostic FILE *f;
17335209Sbostic char *p;
17435209Sbostic int ch;
17536253Sbostic char *cmd, *malloc(), *getenv();
17636253Sbostic static char buffer[MAXPATHLEN];
17735209Sbostic
17835209Sbostic if (filename[0] == '#')
17935209Sbostic return (filename);
18035209Sbostic
18135209Sbostic /*
18235209Sbostic * We get the shell to expand the filename for us by passing
18335209Sbostic * an "echo" command to the shell and reading its output.
18435209Sbostic */
18535209Sbostic p = getenv("SHELL");
18635209Sbostic if (p == NULL || *p == '\0')
18735209Sbostic {
18835209Sbostic /*
18935209Sbostic * Read the output of <echo filename>.
19035209Sbostic */
19135244Sbostic cmd = malloc((u_int)(strlen(filename)+8));
19235209Sbostic if (cmd == NULL)
19335209Sbostic return (filename);
19435244Sbostic (void)sprintf(cmd, "echo \"%s\"", filename);
19535209Sbostic } else
19635209Sbostic {
19735209Sbostic /*
19835209Sbostic * Read the output of <$SHELL -c "echo filename">.
19935209Sbostic */
20035244Sbostic cmd = malloc((u_int)(strlen(p)+12));
20135209Sbostic if (cmd == NULL)
20235209Sbostic return (filename);
20335244Sbostic (void)sprintf(cmd, "%s -c \"echo %s\"", p, filename);
20435209Sbostic }
20535209Sbostic
20635209Sbostic if ((f = popen(cmd, "r")) == NULL)
20735209Sbostic return (filename);
20835209Sbostic free(cmd);
20935209Sbostic
21035209Sbostic for (p = buffer; p < &buffer[sizeof(buffer)-1]; p++)
21135209Sbostic {
21235209Sbostic if ((ch = getc(f)) == '\n' || ch == EOF)
21335209Sbostic break;
21435209Sbostic *p = ch;
21535209Sbostic }
21635209Sbostic *p = '\0';
21736253Sbostic (void)pclose(f);
21836253Sbostic return(buffer);
21935209Sbostic }
22035209Sbostic
22136253Sbostic char *
bad_file(filename,message,len)22235209Sbostic bad_file(filename, message, len)
22336253Sbostic char *filename, *message;
22436253Sbostic u_int len;
22535209Sbostic {
22636253Sbostic extern int errno;
22735209Sbostic struct stat statbuf;
22836253Sbostic char *strcat(), *strerror();
22935209Sbostic
23036253Sbostic if (stat(filename, &statbuf) < 0) {
23136253Sbostic (void)sprintf(message, "%s: %s", filename, strerror(errno));
23236253Sbostic return(message);
23336253Sbostic }
23436253Sbostic if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
23536253Sbostic static char is_dir[] = " is a directory";
23635209Sbostic
23736253Sbostic strtcpy(message, filename, (int)(len-sizeof(is_dir)-1));
23835244Sbostic (void)strcat(message, is_dir);
23936253Sbostic return(message);
24035209Sbostic }
24136253Sbostic return((char *)NULL);
24235209Sbostic }
24335209Sbostic
24435209Sbostic /*
24536253Sbostic * Copy a string, truncating to the specified length if necessary.
24636253Sbostic * Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
24735209Sbostic */
strtcpy(to,from,len)24836253Sbostic strtcpy(to, from, len)
24936253Sbostic char *to, *from;
25036253Sbostic int len;
25135209Sbostic {
25236253Sbostic char *strncpy();
25335209Sbostic
25436253Sbostic (void)strncpy(to, from, (int)len);
25536253Sbostic to[len-1] = '\0';
25635209Sbostic }
25736253Sbostic
258