Wednesday, 2004-08-25, 12:00:05 EST CHANGES: * Fixed an error I had made in substparm() which can cause a stack overflow in main(). * The error() function was missing a call to lseek(2) for non-interactive shells. This has been added for general compatibility with the Thompson shell. Please note that this change causes some of the tests run by `make check' to fail. This is expected; the tests in question need modification to deal with this. This will be done before the next release of osh. * Changed a few more instances of exit(...) to DOEXIT(...). This is a simple macro that calls exit(3) or _exit(2) as needed... Basically, exit(3) in the parent process or _exit(2) in the child process. * Did some general cleaning here and there... Jeffrey Allen Neitzel ============================================================ --- osh.c.orig Thu Aug 12 11:27:33 2004 +++ osh.c Wed Aug 25 12:00:05 2004 @@ -218,7 +218,7 @@ int pxpipe(char *, int, int); char *quote(char *, int); void rcfile(int *); -char *readline(char *, int, size_t); +char *readline(char *, size_t); int *redirect(char **, int *, int); void shell_init(void); void sigmsg(int, pid_t); @@ -235,13 +235,12 @@ main(int argc, char **argv) { off_t ioff; - int ch, rcflag; - unsigned char tflag; + int ch, onecmd, rcflag; char line[LINELEN]; char *bs, *pr; shell_init(); - rcflag = tflag = 0; + rcflag = 0; /* Setup the positional parameters. */ cmdnam = argv[1]; @@ -248,28 +247,22 @@ posav = &argv[1]; posac = argc - 1; - /* Determine how the shell was invoked and act accordingly. */ - if (argc == 1) { - if (isatty(STDIN_FILENO) && isatty(STDERR_FILENO)) { - if (signal(SIGINT, SIG_IGN) == SIG_DFL) - dointr = 1; - signal(SIGQUIT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - if (*argv[0] == '-') - rcfile(&rcflag); - } else - shtype = OTHER; - } else if (*argv[1] == '-') { /* non-interactive shell */ - /* - * This implementation behaves exactly like the Sixth Edition - * Unix shell WRT options. For compatibility, any option is - * accepted w/o producing an error. - */ + /* + * This implementation behaves exactly like the Sixth Edition + * Unix shell WRT options. For compatibility, any option is + * accepted w/o producing an error. + */ + if (argc > 1 && *argv[1] == '-') { + shtype = OTHER; + pr = NULL; + onecmd = 0; + if (signal(SIGINT, SIG_IGN) == SIG_DFL) dointr = 1; signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); + switch (*(argv[1] + 1)) { case 'c': /* osh -c [string] @@ -278,7 +271,6 @@ if (argv[2] == NULL) /* read from input w/o prompting */ break; - /* Resetting posav and posac here is not compatible. */ posav += 1; posac -= 1; @@ -285,23 +277,18 @@ strncpy(line, argv[2], (size_t)LINELEN); if (line[LINELEN - 1] != '\0') error("Command line overflow"); - - /* Deal w/ '\' characters at end of string. */ pr = line + strlen(line) - 1; - for (bs = pr; bs >= line && *bs == '\\'; --bs) - ; /* nothing */ - if ((pr - bs) % 2 == 1) - return(0); - - /* Parse and execute string as a command line. */ - if (substparm(line) && !pxline(line, PX_SYNEXEC)) - error("syntax error"); - return(status); + onecmd = 1; + break; case 't': /* osh -t * XXX: `-tanything' works too (compatible). */ - tflag = 1; + pr = readline(line, (size_t)LINELEN); + if (pr == NULL) + return(0); + pr -= 1; + onecmd = 1; break; default: /* XXX (undocumented): @@ -310,6 +297,30 @@ */ break; } + + if (onecmd) { + /* Deal w/ '\' characters at end of command line. */ + for (bs = pr; bs >= line && *bs == '\\'; --bs) + ; /* nothing */ + if ((pr - bs) % 2 == 1) + return(0); + + /* Parse and execute command line. */ + if (substparm(line) && !pxline(line, PX_SYNEXEC)) + error("syntax error"); + return(status); + } + + } else if (argc == 1) { + if (isatty(STDIN_FILENO) && isatty(STDERR_FILENO)) { + if (signal(SIGINT, SIG_IGN) == SIG_DFL) + dointr = 1; + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + if (*argv[0] == '-') + rcfile(&rcflag); + } else + shtype = OTHER; } else { /* osh file [arg1 ...] */ shtype = COMMANDFILE; @@ -336,7 +347,7 @@ if (INTERACTIVE) write(STDERR_FILENO, si.uid ? "% " : "# ", (size_t)2); - pr = readline(line, STDIN_FILENO, (size_t)LINELEN); + pr = readline(line, (size_t)LINELEN); if (pr == NULL) break; if (pr == (char *)-1) @@ -351,11 +362,8 @@ ; /* nothing */ if ((pr - bs - 1) % 2 == 0) break; - if (tflag) - return(0); *(pr - 1) = ' '; - pr = readline(pr, STDIN_FILENO, - (size_t)LINELEN - (pr - line)); + pr = readline(pr, (size_t)LINELEN - (pr - line)); if (pr == NULL) goto done; if (pr == (char *)-1) @@ -365,8 +373,6 @@ /* Parse and execute command line. */ if (substparm(line) && !pxline(line, PX_SYNEXEC)) error("syntax error"); - if (tflag) - break; } done: @@ -509,7 +515,7 @@ } /* - * Read a line from fd, with error checking. + * Read a line from the shell's standard input. * If read(2) returns -1, terminate the shell w/ non-zero status. * If command line overflow occurs in a non-interactive shell, * terminate w/ non-zero status. Otherwise, return -1. @@ -517,7 +523,7 @@ * Return NULL at EOF. */ char * -readline(char *b, int fd, size_t len) +readline(char *b, size_t len) { unsigned char eot; char *end, *p; @@ -524,7 +530,7 @@ end = b + len; for (eot = 0, p = b; p < end; p++) { - switch (read(fd, p, (size_t)1)) { + switch (read(STDIN_FILENO, p, (size_t)1)) { case -1: exit(1); case 0: @@ -540,18 +546,18 @@ write(STDERR_FILENO, "\n", (size_t)1); return(NULL); } - eot = 0; if (*p == '\n') { *p = '\0'; return(p); } + eot = 0; } /* Flush all unread characters from the input queue if * command line overflow occurs and input is from a tty. */ - if (isatty(fd)) - tcflush(fd, TCIFLUSH); + if (isatty(STDIN_FILENO)) + tcflush(STDIN_FILENO, TCIFLUSH); error("Command line overflow"); return((char *)-1); } @@ -569,11 +575,8 @@ char dbuf[LINELEN], tbuf[32]; char *d, *eos, *p, *t; - if (*(s = de_blank(s)) == '\0') - return(1); - eos = dbuf + LINELEN - 1; - for (copy = 0, d = dbuf, p = s; *p != '\0'; d++, p++) { + for (copy = 0, d = dbuf, p = de_blank(s); *p != '\0'; d++, p++) { /* Skip quoted characters while ignoring `( ... )'. */ if ((t = quote(p, 0)) == NULL) { @@ -1104,7 +1107,7 @@ if (!INTERACTIVE) { lseek(STDIN_FILENO, (off_t)0, SEEK_END); if (shtype & (RCFILE | COMMANDFILE)) - exit(status); + DOEXIT(status); } return; case SBILOGIN: @@ -1311,7 +1314,7 @@ continue; lseek(STDIN_FILENO, (off_t)0, SEEK_END); if (shtype & COMMANDFILE) - exit(status); + DOEXIT(status); } } else @@ -1812,8 +1815,10 @@ { if (msg != NULL) fprintf(stderr, "%s\n", msg); - if (!INTERACTIVE) + if (!INTERACTIVE) { + lseek(STDIN_FILENO, (off_t)0, SEEK_END); DOEXIT(1); + } status = 1; } @@ -2023,7 +2028,7 @@ lseek(STDIN_FILENO, (off_t)0, SEEK_END); if (shtype & COMMANDFILE) - exit(status); + DOEXIT(status); } } else