diff options
| -rw-r--r-- | AUTHORS | 20 | ||||
| -rw-r--r-- | ChangeLog | 8 | ||||
| -rw-r--r-- | acinclude.m4 | 36 | ||||
| -rw-r--r-- | builtins.c | 255 | ||||
| -rw-r--r-- | config.h-dist | 204 | ||||
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | fn.c | 11 | ||||
| -rw-r--r-- | glom.c | 2 | ||||
| -rw-r--r-- | main.c | 16 | ||||
| -rw-r--r-- | parse.y | 17 | ||||
| -rw-r--r-- | rc.1 | 30 | ||||
| -rw-r--r-- | rc.h | 6 | ||||
| -rw-r--r-- | signal.c | 10 | ||||
| -rw-r--r-- | status.c | 6 | ||||
| -rw-r--r-- | testcld.c | 19 | ||||
| -rw-r--r-- | trip.rc | 18 |
16 files changed, 264 insertions, 396 deletions
@@ -28,13 +28,13 @@ FTP or HTTP directory as the shell). Please read this paper bearing in mind that it describes a program that was written at AT&T and that the version of rc presented here differs in some respects. -Toby would like to thank these people for their contributions since he took -over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt Kleberg, -Brynjulv Hauksson, Byron Rakitzis, Callum Gibson, Casper Ti. Vector, Chris -Siebenmann, Christian Neukirchen, Dale Scheetz, Dan Moniz, David Luyer, -David Swasey, Decklin Foster, Donn Cave, Erik Quanstrom, Gary Carvell, -Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jakub Wilk, Jeremy -Fitzhardinge, Marc Moorcroft, Mark H Wilkinson, Mark K Gardner, Raymond -Venneker, Rich $alz, Rob Savoye, Scott Schwartz, Stefan Dalibor, Steve -Simon, Thomas Nordin, Tom Culliton, Tom Tromey, Vincent Broman, Wolfgang -Zekoll. +Toby would like to thank these people for their contributions since he +took over maintenance of rc. Aharon Robbins, Arvid Requate, Bengt +Kleberg, Bert Münnich, Brynjulv Hauksson, Byron Rakitzis, Callum Gibson, +Casper Ti. Vector, Chris Siebenmann, Dale Scheetz, Dan Moniz, David +Luyer, David Swasey, Decklin Foster, Donn Cave, Erik Quanstrom, Gary +Carvell, Gerry Tomlinson, Gert-Jan Vons, Ian Lance Taylor, Jakub Wilk, +Jeremy Fitzhardinge, Leah Neukirchen, Marc Moorcroft, Mark H Wilkinson, +Mark K Gardner, Raymond Venneker, Rich $alz, Rob Savoye, Scott Schwartz, +Stefan Dalibor, Steve Simon, Thomas Nordin, Tom Culliton, Tom Tromey, +Vincent Broman, Wolfgang Zekoll. @@ -903,3 +903,11 @@ Changes since rc-1.5b2 2015-05-13 Release: rc-1.7.4. + +[... needs completing] + +2018-03-05 + + Bug: the grammar disallowed local assignments and redirections in the true + branch of `if` when there was an `else` clause (thanks Dražen Borković and + Bert Münnich; github #31). diff --git a/acinclude.m4 b/acinclude.m4 index 3f9ec93..19d0d50 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -128,42 +128,6 @@ AC_DEFUN([RC_TYPE_SIG_ATOMIC_T], [ ]) -dnl Do we have SysV SIGCLD semantics? In other words, if we set the -dnl action for SIGCLD to SIG_IGN does wait() always say ECHILD? Linux, -dnl of course, is bizarre here. It basically implements the SysV -dnl semantics, but if the parent calls wait() before the child calls -dnl exit(), wait() returns with the PID of the child as normal. (Real -dnl SysV waits for all children to exit, then returns with ECHILD.) -dnl Anyway, this is why the `sleep(1)' is there. -AC_DEFUN([RC_SYS_V_SIGCLD], [ - AC_CACHE_CHECK(for SysV SIGCLD semantics, rc_cv_sysv_sigcld, - AC_TRY_RUN([ -#include <errno.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -int main(void) { - int i; - signal(SIGCLD, SIG_IGN); - switch (fork()) { - case -1: - return 1; - case 0: - return 0; - default: - sleep(1); - if (wait(&i) == -1 && errno == ECHILD) return 0; - else return 1; - } -} - ], rc_cv_sysv_sigcld=yes, rc_cv_sysv_sigcld=no, rc_cv_sysv_sigcld=yes)) - case "$rc_cv_sysv_sigcld" in - yes) AC_DEFINE(HAVE_SYSV_SIGCLD, 1, [Has SysV SIGCLD]) ;; - esac -]) - - dnl Do we have /dev/fd or /proc/self/fd? AC_DEFUN([RC_SYS_DEV_FD], [ AC_CACHE_CHECK(for /dev/fd, rc_cv_sys_dev_fd, @@ -46,27 +46,28 @@ static struct { { b_eval, "eval" }, { b_exec, "exec" }, { b_exit, "exit" }, + { b_flag, "flag" }, #if HAVE_SETRLIMIT - { b_limit, "limit" }, + { b_limit, "limit" }, #endif - { b_newpgrp, "newpgrp" }, - { b_return, "return" }, - { b_shift, "shift" }, - { b_umask, "umask" }, - { b_wait, "wait" }, - { b_whatis, "whatis" }, - { b_dot, "." }, + { b_newpgrp, "newpgrp" }, + { b_return, "return" }, + { b_shift, "shift" }, + { b_umask, "umask" }, + { b_wait, "wait" }, + { b_whatis, "whatis" }, + { b_dot, "." }, #ifdef ADDONS - ADDONS + ADDONS #endif }; extern builtin_t *isbuiltin(char *s) { - int i; - for (i = 0; i < arraysize(builtins); i++) - if (streq(builtins[i].name, s)) - return builtins[i].p; - return NULL; + int i; + for (i = 0; i < arraysize(builtins); i++) + if (streq(builtins[i].name, s)) + return builtins[i].p; + return NULL; } /* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */ @@ -89,13 +90,13 @@ extern void funcall(char **av) { } static void arg_count(char *name) { - fprint(2, RC "too many arguments to %s\n", name); - set(FALSE); + fprint(2, RC "too many arguments to %s\n", name); + set(FALSE); } static void badnum(char *num) { - fprint(2, RC "`%s' is a bad number\n", num); - set(FALSE); + fprint(2, RC "`%s' is a bad number\n", num); + set(FALSE); } /* a dummy command. (exec() performs "exec" simply by not forking) */ @@ -107,90 +108,90 @@ extern void b_exec(char **ignore) { /* echo -n omits a newline. echo -- -n echos '-n' */ static void b_echo(char **av) { - char *format = "%A\n"; - if (*++av != NULL) { - if (streq(*av, "-n")) - format = "%A", av++; - else if (streq(*av, "--")) - av++; - } - fprint(1, format, av); - set(TRUE); + char *format = "%A\n"; + if (*++av != NULL) { + if (streq(*av, "-n")) + format = "%A", av++; + else if (streq(*av, "--")) + av++; + } + fprint(1, format, av); + set(TRUE); } #endif /* cd. traverse $cdpath if the directory given is not an absolute pathname */ static void b_cd(char **av) { - List *s, nil; - char *path = NULL; - size_t t, pathlen = 0; - if (*++av == NULL) { - s = varlookup("home"); - *av = (s == NULL) ? "/" : s->w; - } else if (av[1] != NULL) { - arg_count("cd"); - return; - } - if (isabsolute(*av) || streq(*av, ".") || streq(*av, "..")) { /* absolute pathname? */ - if (chdir(*av) < 0) { - set(FALSE); - uerror(*av); - } else - set(TRUE); - } else { - s = varlookup("cdpath"); - if (s == NULL) { - s = &nil; - nil.w = ""; - nil.n = NULL; - } - do { - if (s != &nil && *s->w != '\0') { - t = strlen(*av) + strlen(s->w) + 2; - if (t > pathlen) - path = nalloc(pathlen = t); - strcpy(path, s->w); - if (!streq(s->w, "/")) /* "//" is special to POSIX */ - strcat(path, "/"); - strcat(path, *av); - } else { - pathlen = 0; - path = *av; - } - if (chdir(path) >= 0) { - set(TRUE); - if (interactive && *s->w != '\0' && !streq(s->w, ".")) - fprint(1, "%s\n", path); - return; - } - s = s->n; - } while (s != NULL); - fprint(2, "couldn't cd to %s\n", *av); - set(FALSE); - } + List *s, nil; + char *path = NULL; + size_t t, pathlen = 0; + if (*++av == NULL) { + s = varlookup("home"); + *av = (s == NULL) ? "/" : s->w; + } else if (av[1] != NULL) { + arg_count("cd"); + return; + } + if (isabsolute(*av) || streq(*av, ".") || streq(*av, "..")) { /* absolute pathname? */ + if (chdir(*av) < 0) { + set(FALSE); + uerror(*av); + } else + set(TRUE); + } else { + s = varlookup("cdpath"); + if (s == NULL) { + s = &nil; + nil.w = ""; + nil.n = NULL; + } + do { + if (s != &nil && *s->w != '\0') { + t = strlen(*av) + strlen(s->w) + 2; + if (t > pathlen) + path = nalloc(pathlen = t); + strcpy(path, s->w); + if (!streq(s->w, "/")) /* "//" is special to POSIX */ + strcat(path, "/"); + strcat(path, *av); + } else { + pathlen = 0; + path = *av; + } + if (chdir(path) >= 0) { + set(TRUE); + if (interactive && *s->w != '\0' && !streq(s->w, ".")) + fprint(1, "%s\n", path); + return; + } + s = s->n; + } while (s != NULL); + fprint(2, "couldn't cd to %s\n", *av); + set(FALSE); + } } static void b_umask(char **av) { - int i; - if (*++av == NULL) { - set(TRUE); - i = umask(0); - umask(i); - fprint(1, "0%o\n", i); - } else if (av[1] == NULL) { - i = o2u(*av); - if ((unsigned int) i > 0777) { - fprint(2, "bad umask\n"); - set(FALSE); - } else { - umask(i); - set(TRUE); - } - } else { - arg_count("umask"); - return; - } + int i; + if (*++av == NULL) { + set(TRUE); + i = umask(0); + umask(i); + fprint(1, "0%o\n", i); + } else if (av[1] == NULL) { + i = o2u(*av); + if ((unsigned int) i > 0777) { + fprint(2, "bad umask\n"); + set(FALSE); + } else { + umask(i); + set(TRUE); + } + } else { + arg_count("umask"); + return; + } } static void b_exit(char **av) { @@ -199,6 +200,74 @@ static void b_exit(char **av) { rc_exit(getstatus()); } +static void b_flag(char **av) { + bool *flagp = NULL; + char f; + int mode = 3; /* 0 = reset (-), 1 = set (+), 2 = test */ + const char *usage = "usage: flag f [ + | - ]\n"; + + if (*++av == NULL) { + fprint(2, RC "not enough arguments to flag\n"); + set(FALSE); + return; + } + f = av[0][0]; + if (f == '\0' || av[0][1] != '\0') goto flag_usage; + if (*++av == NULL) { + mode = 2; + } else if (av[0][0] == '+' && av[0][1] == '\0') { + mode = 1; + } else if (av[0][0] == '-' && av[0][1] == '\0') { + mode = 0; + } + if (mode == 3) goto flag_usage; + switch (f) { + case 'c': + if (mode != 2) goto flag_immutable; + set(dashsee[0] != NULL); + return; + case 'd': + if (mode != 2) goto flag_immutable; + flagp = &dashdee; break; + case 'e': flagp = &dashee; break; + case 'i': flagp = &interactive; break; + case 'l': + if (mode != 2) goto flag_immutable; + flagp = &dashell; break; + case 'n': flagp = &dashen; break; + case 'o': + if (mode != 2) goto flag_immutable; + flagp = &dashoh; break; + case 'p': + if (mode != 2) goto flag_immutable; + flagp = &dashpee; break; + case 's': + if (mode != 2) goto flag_immutable; + flagp = &dashess; break; + case 'v': flagp = &dashvee; break; + case 'x': flagp = &dashex; break; + } + if (flagp != NULL) { + if (mode == 2) + set(*flagp); + else { + *flagp = mode; + set(TRUE); + } + } else { + fprint(2, RC "unknown flag"); + set(FALSE); + } + return; +flag_immutable: + fprint(2, RC "flag immutable\n"); + set(FALSE); + return; +flag_usage: + fprint(2, usage); + set(FALSE); +} + /* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */ static void b_return(char **av) { diff --git a/config.h-dist b/config.h-dist deleted file mode 100644 index 5be81eb..0000000 --- a/config.h-dist +++ /dev/null @@ -1,204 +0,0 @@ -/* Copy config.h-dist to config.h and edit config.h, don't edit this file */ - -/* - * Configuration parameters for rc. Suggested defaults are at the bottom - * of this file (you should probably look at those first to see if your - * system matches one of them; you can search for the beginning of the - * defaults section by looking for the string "#ifndef CUSTOM"). If you - * want to override the suggested defaults, define the macro CUSTOM. -#define CUSTOM - */ - -/* - * (Note that certain default settings redefine this macro) - * DEFAULTPATH the default search path that rc uses when it is started - * without either a $PATH or $path environment variable. You must pick - * something sensible for your system if you don't like the path shown - * below. - */ -#define DEFAULTPATH "/usr/ucb", "/usr/bin", "/bin", "." - -/* - * Define the macro NODIRENT if your system has <sys/dir.h> but not - * <dirent.h>. (e.g., NeXT-OS and RISCos) -#define NODIRENT - */ - -/* - * Define the macro SVSIGS if your system has System V signal semantics, - * i.e., if "slow" system calls are interrupted rather than resumed - * after returning from an interrupt handler. (If you are not sure what - * this means, see the man page for signal(2). In any case, it is probably - * safe to leave this macro undefined.) -#define SVSIGS - */ - -/* - * Define the macro NOCMDARG if you do not have /dev/fd or fifos on your - * system. You may also want to define this if you have broken fifos. -#define NOCMDARG - */ - -/* - * Define TMPDIR if you need to have rc create its fifos in a directory - * other than /tmp. For example, if you have a Sun with /tmp mounted - * as a ramdisk (type "tmpfs") then you cannot use fifos in /tmp (sigh). -#define TMPDIR "/var/tmp" - */ - -/* - * Define the macro DEVFD if your system supports /dev/fd. -#define DEVFD - */ - -/* - * Define the macro NOLIMITS if your system does not support Berkeley - * limits. -#define NOLIMITS - */ - -/* - * Define the macro NOSIGCLD if your system uses SIGCLD in the System - * V way. (e.g., sgi's Irix) -#define NOSIGCLD - */ - -/* - * Define the macro READLINE if you want rc to call GNU readline - * instead of read(2) on interactive shells. -#define READLINE - */ - -/* - * Define the macro NOEXECVE if your Unix does not interpret #! in the - * kernel, and uncomment the EXECVE variable in the Makefile. -#define NOEXECVE - */ - -/* - * If you want rc to default to some interpreter for files which don't - * have a legal #! on the first line, define the macro DEFAULTINTERP. -#define DEFAULTINTERP "/bin/sh" - */ - -/* - * If your /bin/sh (or another program you care about) rejects environment - * variables with special characters in them (such as ':' or '-'), rc can - * put out ugly variable names using [_0-9a-zA-Z] that encode the real name; - * define PROTECT_ENV for this hack. (Known offenders: every sh I have tried; - * SunOS (silently discards), NeXT (aborts with error), SGI (aborts with - * error), Ultrix (sh seems to work, sh5 aborts with error)) -#define PROTECT_ENV - */ - -/* - * Define the macro NOECHO if you wish to omit rc's echo builtin from the - * compile. -#define NOECHO - */ - -/* - * Define the NOJOB if you do *not* wish rc to perform backgrounding - * as if it were a job-control shell; that is, if you do *not* wish - * it to put a command spawned in the background into a new process - * group. Since most systems support job control and since there are - * many broken programs that do not behave correctly when backgrounded - * in a v7 non-job-control fashion, rc by default performs a job- - * control-like backgrounding. -#define NOJOB - */ - -/* Beginning of defaults section: */ - -#ifndef CUSTOM - -/* - * Suggested settings for Sun, NeXT and sgi (machines here at TAMU): - */ - -#ifdef NeXT /* Used on NextOS 2.1 */ -#define NODIRENT -#define PROTECT_ENV -#define NOCMDARG -#endif - -#ifdef sgi /* Used on Irix 3.3.[12] */ -#define SVSIGS -#define NOSIGCLD -#define PROTECT_ENV -#undef DEFAULTPATH -#define DEFAULTPATH "/usr/bsd", "/usr/sbin", "/usr/bin", "/bin", "." -#endif - -#ifdef sun /* Used on SunOS 4.1.1 */ -#define PROTECT_ENV -#undef DEFAULTPATH -#define DEFAULTPATH "/usr/ucb", "/usr/bin", "." -#endif - -/* - * Suggested settings for HP300 running 4.3BSD-utah (DWS): - */ - -#if defined(hp300) && !defined(hpux) -#define NODIRENT -#define NOCMDARG -#define DEFAULTINTERP "/bin/sh" -#define PROTECT_ENV -#endif - -/* - * Suggested settings for Ultrix - */ - -#ifdef ultrix -#define PROTECT_ENV -#define DEFAULTINTERP "/bin/sh" /* so /bin/true can work */ -#endif - -/* - * Suggested settings for RISCos 4.52 - */ - -/* - This doesn't work without interfering with other MIPS-based - systems' configuration. Please do it by hand. -*/ - -#if defined(host_mips) && defined(MIPSEB) && defined(SYSTYPE_BSD43) -#define NODIRENT -#define PROTECT_ENV -#endif - -/* - * Suggested settings for AIX - */ - -#ifdef _AIX -#define PROTECT_ENV -#endif - -/* - * Suggested settings for OSF/1 1.0 - */ - -#ifdef OSF1 -#define PROTECT_ENV -#endif - -/* - * Suggested settings for Unicos XXX - */ - -#ifdef cray -#define PROTECT_ENV -#define NOLIMITS -#define word _word -#define DEFAULTINTERP "/bin/sh" -#endif - -#endif /* CUSTOM */ - -#ifndef TMPDIR -#define TMPDIR "/tmp" -#endif diff --git a/configure.ac b/configure.ac index 23ebf8a..c9d1cb4 100644 --- a/configure.ac +++ b/configure.ac @@ -63,8 +63,6 @@ RC_TYPE_RLIM_T RC_TYPE_SIG_ATOMIC_T -RC_SYS_V_SIGCLD - dnl Does the kernel handle `#! /interpreter'? AC_SYS_INTERPRETER case "$ac_cv_sys_interpreter" in @@ -29,10 +29,7 @@ extern void inithandler() { null.type = nBody; null.u[0].p = null.u[1].p = NULL; for (i = 1; i < NUMOFSIGNALS; i++) -#if HAVE_SYSV_SIGCLD - if (i != SIGCLD) -#endif - if (sighandlers[i] == SIG_IGN) + if (i != SIGCHLD && sighandlers[i] == SIG_IGN) fnassign(signals[i].name, NULL); /* ignore incoming ignored signals */ if (interactive || sighandlers[SIGINT] != SIG_IGN) { def_sigint = sigint; @@ -151,10 +148,8 @@ extern void fnassign(char *name, Node *def) { new->def = newdef; new->extdef = NULL; if (strncmp(name, "sig", conststrlen("sig")) == 0) { /* slight optimization */ -#if HAVE_SYSV_SIGCLD /* System V machines treat SIGCLD very specially */ - if (streq(name, "sigcld")) - rc_error("can't trap SIGCLD"); -#endif + if (streq(name, "sigchld") || streq(name, "sigcld")) + rc_error("can't trap SIGCHLD"); if (streq(name, "sigexit")) runexit = TRUE; for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */ @@ -266,7 +266,7 @@ static List *backq(Node *ifs, Node *n) { bq = bqinput(glom(ifs), p[0]); close(p[0]); rc_wait4(pid, &sp, TRUE); - statprint(-1, sp); + setstatus(-1, sp); varassign("bqstatus", word(strstatus(sp), NULL), FALSE); sigchk(); return bq; @@ -6,17 +6,19 @@ #include "input.h" -bool dashdee, dashee, dashvee, dashex, dasheye, - dashen, dashpee, interactive; +bool dashdee, dashee, dasheye, dashell, dashen; +bool dashpee, dashoh, dashess, dashvee, dashex; +bool interactive; +static bool dashEYE; +char *dashsee[2]; pid_t rc_pid; -static bool dashEYE, dashell, dashoh, dashess; static void assigndefault(char *,...); static void checkfd(int, enum redirtype); extern int main(int argc, char *argv[], char *envp[]) { - char *dashsee[2], *dollarzero, *null[1]; + char *dollarzero, *null[1]; int c; initprint(); dashsee[0] = dashsee[1] = NULL; @@ -67,8 +69,10 @@ extern int main(int argc, char *argv[], char *envp[]) { } quitopts: argv += rc_optind; - /* use isatty() iff neither -i nor -I is set, and iff the input is not from a script or -c flags */ - if (!dasheye && !dashEYE && dashsee[0] == NULL && (dashess || *argv == NULL)) + /* use isatty() iff neither -i nor -I is set, and iff the input is not + * from a script or -c flags */ + if (!dasheye && !dashEYE && dashsee[0] == NULL && + (dashess || *argv == NULL)) interactive = isatty(0); if (!dashoh) { checkfd(0, rFrom); @@ -17,7 +17,8 @@ Node *parsetree; /* not using yylval because bison declares it as an auto */ %token OROR PIPE REDIR SREDIR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD HUH %left '^' '=' -%left WHILE ')' ELSE +%right ELSE TWIDDLE +%left WHILE ')' %left ANDAND OROR '\n' %left BANG SUBSHELL %left PIPE @@ -43,7 +44,7 @@ Node *parsetree; /* not using yylval because bison declares it as an auto */ %type <keyword> keyword %type <node> assign body brace case cbody cmd cmdsa cmdsan comword epilog first line nlwords paren redir sword simple iftail word words - arg args + arg args else %start rc @@ -96,8 +97,10 @@ cbody : cmd { $$ = mk(nCbody, $1, NULL); } | case cbody { $$ = mk(nCbody, $1, $2); } | cmdsan cbody { $$ = mk(nCbody, $1, $2); } -iftail : cmd %prec ELSE - | brace ELSE optnl cmd { $$ = mk(nElse,$1,$4); } +iftail : cmd else { $$ = $2 != NULL ? mk(nElse, $1, $2) : $1; } + +else : /* empty */ %prec ELSE { $$ = NULL; } + | ELSE optnl cmd { $$ = $3; } cmd : /* empty */ %prec WHILE { $$ = NULL; } | simple @@ -116,13 +119,13 @@ cmd : /* empty */ %prec WHILE { $$ = NULL; } | BANG optcaret cmd { $$ = mk(nBang,$3); } | SUBSHELL optcaret cmd { $$ = mk(nSubshell,$3); } | FN words brace { $$ = mk(nNewfn,$2,$3); } - | FN words { $$ = mk(nRmfn,$2); } + | FN words %prec ELSE { $$ = mk(nRmfn,$2); } optcaret : /* empty */ %prec '^' | '^' -simple : first - | first args { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); } +simple : first %prec ELSE + | first args %prec ELSE { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); } args : arg | args arg { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); } @@ -1717,6 +1717,36 @@ If no argument is given, the current value of .Cr $status is used. .TP +\fBflag\fR \fIf\fR [ \fB+\fR | \fB\-\fR ] +Test, set (\fB+\fR), or reset (\fB\-\fR) command-line flag +.IR f . +For example, a script that requires ``exit if command fails'' semantics can say +.Ds +.Cr "flag e +" +.De +.TP +\& +Some flags cannot be set or reset using +.BR flag , +but they can still be tested. These are +.BR c , +.BR d , +.BR l , +.BR o , +.BR p , +and +.BR s . +As a special case, +.Cr "flag i" +operates on +.BR rc 's +internal +.IR interactive +flag, which may have been set by +.Cr -i +on the command line, or if standard input was a terminal; there is no +.Cr "flag I" . +.TP \fBlimit \fR[\fB\-h\fR] [\fIresource \fR[\fIvalue\fR]] Similar to the .IR csh (1) @@ -170,7 +170,10 @@ enum { /* main.c */ extern Rq *redirq; -extern bool dashdee, dashee, dashvee, dashex, dasheye, dashen, dashpee, interactive; +extern bool dashdee, dashee, dasheye, dashell, dashen; +extern bool dashpee, dashoh, dashess, dashvee, dashex; +extern bool interactive; +extern char *dashsee[]; extern pid_t rc_pid; extern int lineno; @@ -347,7 +350,6 @@ extern void set(bool); extern void setstatus(pid_t, int); extern List *sgetstatus(void); extern void setpipestatus(int [], int); -extern void statprint(pid_t, int); extern void ssetstatus(char **); extern char *strstatus(int s); @@ -83,14 +83,12 @@ extern void initsignal() { void (*h)(int); int i; -#if HAVE_SYSV_SIGCLD - /* Ensure that SIGCLD is not SIG_IGN. Solaris's rshd does this. :-( */ - h = sys_signal(SIGCLD, SIG_IGN); + /* Ensure that SIGCHLD is not SIG_IGN. Solaris's rshd does this. :-( */ + h = sys_signal(SIGCHLD, SIG_IGN); if (h != SIG_IGN && h != SIG_ERR) - sys_signal(SIGCLD, h); + sys_signal(SIGCHLD, h); else - sys_signal(SIGCLD, SIG_DFL); -#endif + sys_signal(SIGCHLD, SIG_DFL); for (i = 1; i < NUMOFSIGNALS; i++) { #ifdef SIGKILL @@ -7,6 +7,8 @@ /* status == the wait() value of the last command in the pipeline, or the last command */ +static void statprint(pid_t, int); + static int statuses[512]; static int pipelength = 1; @@ -49,8 +51,8 @@ extern void set(bool code) { extern void setpipestatus(int stats[], int num) { int i; for (i = 0; i < (pipelength = num); i++) { - statprint(-1, stats[i]); statuses[i] = stats[i]; + statprint(-1, stats[i]); } } @@ -64,7 +66,7 @@ extern void setstatus(pid_t pid, int i) { /* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */ -extern void statprint(pid_t pid, int i) { +static void statprint(pid_t pid, int i) { if (WIFSIGNALED(i)) { int t = WTERMSIG(i); char *msg = ((t > 0) && (t < NUMOFSIGNALS) ? signals[WTERMSIG(i)].msg : ""); diff --git a/testcld.c b/testcld.c deleted file mode 100644 index 83212e9..0000000 --- a/testcld.c +++ /dev/null @@ -1,19 +0,0 @@ -#include <errno.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -int main(void) { - int i; - sigset(SIGCLD, SIG_IGN); - switch (fork()) { - case -1: - return 1; - case 0: - return 0; - default: - sleep(1); - if (wait(&i) == -1 && errno == ECHILD) return 0; - else return 1; - } -} @@ -690,3 +690,21 @@ if (! ~ $X YYY) { A=``($nl){ $rc -c 'mkdir / >[2=1] | tr a-z A-Z' } B=``($nl){ $rc -c '>[2=1] mkdir / | tr a-z A-Z' } ~ $A $B || fail counter intuitive redirection bug, $A '!=' $B + +# test for github issue #40 +$rc -ec 'false | false' +if (~ $status 0) { + fail '"rc -e" exits with zero status when command in pipeline returns non-zero' +} +$rc -ec 'X=`{false}' +if (~ $status 0) { + fail '"rc -e" exits with zero status when backquote command returns non-zero' +} + +# exercise flag builtin +submatch 'flag' 'rc: not enough arguments to flag' 'flag no args' +submatch 'flag a b c' 'usage: flag f [ + | - ]' 'flag 3 args' +submatch 'flag xx' 'usage: flag f [ + | - ]' 'flag wrong first arg' +submatch 'flag x x' 'usage: flag f [ + | - ]' 'flag wrong second arg' +submatch 'flag c && echo yes' yes 'flag c' +submatch 'flag x +; flag x -' 'flag x -' 'setting x flag' |