diff options
author | sjg <sjg@FreeBSD.org> | 2013-09-05 20:18:59 +0000 |
---|---|---|
committer | sjg <sjg@FreeBSD.org> | 2013-09-05 20:18:59 +0000 |
commit | 62bb1062226d3ce6a2350808256a25508978352d (patch) | |
tree | 22b131dceb13c3df96da594fbaadb693504797c7 /bin | |
parent | 72ab90509b3a51ab361bf710338f2ef44a4e360d (diff) | |
parent | 04932445481c2cb89ff69a83b961bdef3d64757e (diff) | |
download | FreeBSD-src-62bb1062226d3ce6a2350808256a25508978352d.zip FreeBSD-src-62bb1062226d3ce6a2350808256a25508978352d.tar.gz |
Merge from head
Diffstat (limited to 'bin')
56 files changed, 583 insertions, 1152 deletions
diff --git a/bin/cat/cat.c b/bin/cat/cat.c index 9e12d3e..0daac7c 100644 --- a/bin/cat/cat.c +++ b/bin/cat/cat.c @@ -68,7 +68,7 @@ static int bflag, eflag, lflag, nflag, sflag, tflag, vflag; static int rval; static const char *filename; -static void usage(void); +static void usage(void) __dead2; static void scanfiles(char *argv[], int cooked); static void cook_cat(FILE *); static void raw_cat(int); @@ -153,6 +153,7 @@ main(int argc, char *argv[]) static void usage(void) { + fprintf(stderr, "usage: cat [-belnstuv] [file ...]\n"); exit(1); /* NOTREACHED */ diff --git a/bin/chflags/chflags.1 b/bin/chflags/chflags.1 index fe9d700..47d5b18 100644 --- a/bin/chflags/chflags.1 +++ b/bin/chflags/chflags.1 @@ -32,7 +32,7 @@ .\" @(#)chflags.1 8.4 (Berkeley) 5/2/95 .\" $FreeBSD$ .\" -.Dd March 3, 2006 +.Dd April 8, 2013 .Dt CHFLAGS 1 .Os .Sh NAME @@ -101,20 +101,36 @@ The following keywords are currently defined: .Bl -tag -offset indent -width ".Cm opaque" .It Cm arch , archived set the archived flag (super-user only) -.It Cm opaque -set the opaque flag (owner or super-user only) .It Cm nodump set the nodump flag (owner or super-user only) +.It Cm opaque +set the opaque flag (owner or super-user only) .It Cm sappnd , sappend set the system append-only flag (super-user only) .It Cm schg , schange , simmutable set the system immutable flag (super-user only) +.It Cm snapshot +set the snapshot flag (filesystems do not allow changing this flag) .It Cm sunlnk , sunlink set the system undeletable flag (super-user only) .It Cm uappnd , uappend set the user append-only flag (owner or super-user only) +.It Cm uarch , uarchive +set the archive flag (owner or super-user only) .It Cm uchg , uchange , uimmutable set the user immutable flag (owner or super-user only) +.It Cm uhidden , hidden +set the hidden file attribute (owner or super-user only) +.It Cm uoffline , offline +set the offline file attribute (owner or super-user only) +.It Cm urdonly , rdonly , readonly +set the DOS, Windows and CIFS readonly flag (owner or super-user only) +.It Cm usparse , sparse +set the sparse file attribute (owner or super-user only) +.It Cm usystem , system +set the DOS, Windows and CIFS system flag (owner or super-user only) +.It Cm ureparse , reparse +set the Windows reparse point file attribute (owner or super-user only) .It Cm uunlnk , uunlink set the user undeletable flag (owner or super-user only) .El diff --git a/bin/chio/chio.c b/bin/chio/chio.c index 9bb11d7..5a2a7ba 100644 --- a/bin/chio/chio.c +++ b/bin/chio/chio.c @@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <langinfo.h> +#include <locale.h> #include "defs.h" #include "pathnames.h" @@ -81,6 +83,7 @@ static int do_status(const char *, int, char **); static int do_ielem(const char *, int, char **); static int do_return(const char *, int, char **); static int do_voltag(const char *, int, char **); +static void print_designator(const char *, u_int8_t, u_int8_t); #ifndef CHET_VT #define CHET_VT 10 /* Completely Arbitrary */ @@ -723,6 +726,10 @@ do_status(const char *cname, int argc, char **argv) putchar('?'); putchar('>'); } + if (ces->ces_designator_length > 0) + print_designator(ces->ces_designator, + ces->ces_code_set, + ces->ces_designator_length); putchar('\n'); } @@ -1177,3 +1184,66 @@ usage(void) "arg1 arg2 [arg3 [...]]\n", getprogname()); exit(1); } + +#define UTF8CODESET "UTF-8" + +static void +print_designator(const char *designator, u_int8_t code_set, + u_int8_t designator_length) +{ + printf(" serial number: <"); + switch (code_set) { + case CES_CODE_SET_ASCII: { + /* + * The driver insures that the string is always NUL terminated. + */ + printf("%s", designator); + break; + } + case CES_CODE_SET_UTF_8: { + char *cs_native; + + setlocale(LC_ALL, ""); + cs_native = nl_langinfo(CODESET); + + /* See if we can natively print UTF-8 */ + if (strcmp(cs_native, UTF8CODESET) == 0) + cs_native = NULL; + + if (cs_native == NULL) { + /* We can natively print UTF-8, so use printf. */ + printf("%s", designator); + } else { + int i; + + /* + * We can't natively print UTF-8. We should + * convert it to the terminal's codeset, but that + * requires iconv(3) and FreeBSD doesn't have + * iconv(3) in the base system yet. So we use %XX + * notation for non US-ASCII characters instead. + */ + for (i = 0; i < designator_length && + designator[i] != '\0'; i++) { + if ((unsigned char)designator[i] < 0x80) + printf("%c", designator[i]); + else + printf("%%%02x", + (unsigned char)designator[i]); + } + } + break; + } + case CES_CODE_SET_BINARY: { + int i; + + for (i = 0; i < designator_length; i++) + printf("%02X%s", designator[i], + (i == designator_length - 1) ? "" : " "); + break; + } + default: + break; + } + printf(">"); +} diff --git a/bin/dd/args.c b/bin/dd/args.c index 161fbfc..cc702f9 100644 --- a/bin/dd/args.c +++ b/bin/dd/args.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <inttypes.h> #include <limits.h> +#include <signal.h> #include <stdlib.h> #include <string.h> diff --git a/bin/dd/conv_tab.c b/bin/dd/conv_tab.c index 07449fd..ce585df 100644 --- a/bin/dd/conv_tab.c +++ b/bin/dd/conv_tab.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> +#include <signal.h> #include <stdint.h> #include "dd.h" diff --git a/bin/dd/dd.c b/bin/dd/dd.c index 01b66fc..7e5bd91 100644 --- a/bin/dd/dd.c +++ b/bin/dd/dd.c @@ -81,6 +81,7 @@ size_t cbsz; /* conversion block size */ uintmax_t files_cnt = 1; /* # of files to copy */ const u_char *ctab; /* conversion table */ char fill_char; /* Character to fill with if defined */ +volatile sig_atomic_t need_summary; int main(int argc __unused, char *argv[]) @@ -89,7 +90,7 @@ main(int argc __unused, char *argv[]) jcl(argv); setup(); - (void)signal(SIGINFO, summaryx); + (void)signal(SIGINFO, siginfo_handler); (void)signal(SIGINT, terminate); atexit(summary); @@ -358,7 +359,7 @@ dd_in(void) * than noerror, notrunc or sync are specified, the block * is output without buffering as it is read. */ - if (ddflags & C_BS) { + if ((ddflags & ~(C_NOERROR | C_NOTRUNC | C_SYNC)) == C_BS) { out.dbcnt = in.dbcnt; dd_out(1); in.dbcnt = 0; @@ -375,6 +376,9 @@ dd_in(void) in.dbp += in.dbrcnt; (*cfunc)(); + if (need_summary) { + summary(); + } } } diff --git a/bin/dd/extern.h b/bin/dd/extern.h index 9c540ad..6984f6d 100644 --- a/bin/dd/extern.h +++ b/bin/dd/extern.h @@ -43,7 +43,7 @@ void jcl(char **); void pos_in(void); void pos_out(void); void summary(void); -void summaryx(int); +void siginfo_handler(int); void terminate(int); void unblock(void); void unblock_close(void); @@ -61,3 +61,4 @@ extern const u_char e2a_32V[], e2a_POSIX[]; extern const u_char a2ibm_32V[], a2ibm_POSIX[]; extern u_char casetab[]; extern char fill_char; +extern volatile sig_atomic_t need_summary; diff --git a/bin/dd/misc.c b/bin/dd/misc.c index 8edc5a5..84cc5ee 100644 --- a/bin/dd/misc.c +++ b/bin/dd/misc.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <inttypes.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -57,41 +58,32 @@ summary(void) { struct timeval tv; double secs; - char buf[100]; (void)gettimeofday(&tv, NULL); secs = tv.tv_sec + tv.tv_usec * 1e-6 - st.start; if (secs < 1e-6) secs = 1e-6; - /* Use snprintf(3) so that we don't reenter stdio(3). */ - (void)snprintf(buf, sizeof(buf), + (void)fprintf(stderr, "%ju+%ju records in\n%ju+%ju records out\n", st.in_full, st.in_part, st.out_full, st.out_part); - (void)write(STDERR_FILENO, buf, strlen(buf)); - if (st.swab) { - (void)snprintf(buf, sizeof(buf), "%ju odd length swab %s\n", + if (st.swab) + (void)fprintf(stderr, "%ju odd length swab %s\n", st.swab, (st.swab == 1) ? "block" : "blocks"); - (void)write(STDERR_FILENO, buf, strlen(buf)); - } - if (st.trunc) { - (void)snprintf(buf, sizeof(buf), "%ju truncated %s\n", + if (st.trunc) + (void)fprintf(stderr, "%ju truncated %s\n", st.trunc, (st.trunc == 1) ? "block" : "blocks"); - (void)write(STDERR_FILENO, buf, strlen(buf)); - } - (void)snprintf(buf, sizeof(buf), + (void)fprintf(stderr, "%ju bytes transferred in %.6f secs (%.0f bytes/sec)\n", st.bytes, secs, st.bytes / secs); - (void)write(STDERR_FILENO, buf, strlen(buf)); + need_summary = 0; } /* ARGSUSED */ void -summaryx(int notused __unused) +siginfo_handler(int signo __unused) { - int save_errno = errno; - summary(); - errno = save_errno; + need_summary = 1; } /* ARGSUSED */ diff --git a/bin/dd/position.c b/bin/dd/position.c index a638597..57bfde5 100644 --- a/bin/dd/position.c +++ b/bin/dd/position.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <err.h> #include <errno.h> #include <inttypes.h> +#include <signal.h> #include <unistd.h> #include "dd.h" @@ -91,6 +92,8 @@ pos_in(void) } } else --cnt; + if (need_summary) + summary(); continue; } diff --git a/bin/df/df.1 b/bin/df/df.1 index 8d14248..b5cf859 100644 --- a/bin/df/df.1 +++ b/bin/df/df.1 @@ -196,7 +196,9 @@ If the value is outside, it will be set to the appropriate limit. .Xr localeconv 3 , .Xr fstab 5 , .Xr mount 8 , -.Xr quot 8 . +.Xr pstat 8 , +.Xr quot 8 , +.Xr swapinfo 8 . .Sh STANDARDS With the exception of most options, the diff --git a/bin/df/df.c b/bin/df/df.c index 77b7a40..13ef129 100644 --- a/bin/df/df.c +++ b/bin/df/df.c @@ -114,6 +114,7 @@ main(int argc, char *argv[]) fstype = "ufs"; (void)setlocale(LC_ALL, ""); + memset(&maxwidths, 0, sizeof(maxwidths)); memset(&totalbuf, 0, sizeof(totalbuf)); totalbuf.f_bsize = DEV_BSIZE; strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN); @@ -200,7 +201,7 @@ main(int argc, char *argv[]) } else { /* just the filesystems specified on the command line */ mntbuf = malloc(argc * sizeof(*mntbuf)); - if (mntbuf == 0) + if (mntbuf == NULL) err(1, "malloc()"); mntsize = 0; /* continued in for loop below */ @@ -209,13 +210,13 @@ main(int argc, char *argv[]) /* iterate through specified filesystems */ for (; *argv; argv++) { if (stat(*argv, &stbuf) < 0) { - if ((mntpt = getmntpt(*argv)) == 0) { + if ((mntpt = getmntpt(*argv)) == NULL) { warn("%s", *argv); rv = 1; continue; } } else if (S_ISCHR(stbuf.st_mode)) { - if ((mntpt = getmntpt(*argv)) == 0) { + if ((mntpt = getmntpt(*argv)) == NULL) { mdev.fspec = *argv; mntpath = strdup("/tmp/df.XXXXXX"); if (mntpath == NULL) { @@ -282,7 +283,7 @@ main(int argc, char *argv[]) mntbuf[mntsize++] = statfsbuf; } - bzero(&maxwidths, sizeof(maxwidths)); + memset(&maxwidths, 0, sizeof(maxwidths)); for (i = 0; i < mntsize; i++) { if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) { update_maxwidths(&maxwidths, &mntbuf[i]); @@ -309,7 +310,7 @@ getmntpt(const char *name) if (!strcmp(mntbuf[i].f_mntfromname, name)) return (mntbuf[i].f_mntonname); } - return (0); + return (NULL); } /* diff --git a/bin/domainname/domainname.1 b/bin/domainname/domainname.1 index 0f92450..099a40e 100644 --- a/bin/domainname/domainname.1 +++ b/bin/domainname/domainname.1 @@ -29,7 +29,7 @@ .\" From: @(#)hostname.1 8.1 (Berkeley) 5/31/93 .\" $FreeBSD$ .\" -.Dd September 18, 1994 +.Dd April 22, 2013 .Dt DOMAINNAME 1 .Os .Sh NAME @@ -43,10 +43,11 @@ The .Nm utility prints the name of the current YP/NIS domain. The super-user can -set the domain name by supplying an argument; this is usually done in the -network initialization script -.Pa /etc/rc.network , -normally run at boot +set the domain name by supplying an argument; this is usually done with the +.Va nisdomainname +variable in the +.Pa /etc/rc.conf +file, normally run at boot time. .Sh NOTES The YP/NIS (formerly ``Yellow Pages'' but renamed for legal reasons) @@ -54,7 +55,8 @@ domain name does not necessarily have anything to do with the Domain Name System domain name, although they are often set equal for administrative convenience. .Sh SEE ALSO -.Xr getdomainname 3 +.Xr getdomainname 3 , +.Xr rc.conf 5 .Sh HISTORY The .Nm diff --git a/bin/ed/ed.1 b/bin/ed/ed.1 index dbfb3dd..8342645 100644 --- a/bin/ed/ed.1 +++ b/bin/ed/ed.1 @@ -914,9 +914,9 @@ that line. .El .Sh FILES .Bl -tag -width /tmp/ed.* -compact -.It /tmp/ed.* +.It Pa /tmp/ed.* buffer file -.It ed.hup +.It Pa ed.hup the file to which .Nm attempts to write the buffer if the terminal hangs up diff --git a/bin/ed/re.c b/bin/ed/re.c index 08a330d..03a3436 100644 --- a/bin/ed/re.c +++ b/bin/ed/re.c @@ -89,7 +89,7 @@ extract_pattern(int delimiter) default: break; case '[': - if ((nd = parse_char_class(++nd)) == NULL) { + if ((nd = parse_char_class(nd + 1)) == NULL) { errmsg = "unbalanced brackets ([])"; return NULL; } diff --git a/bin/expr/Makefile b/bin/expr/Makefile index 544853e..b86cf66 100644 --- a/bin/expr/Makefile +++ b/bin/expr/Makefile @@ -4,4 +4,6 @@ PROG= expr SRCS= expr.y YFLAGS= +NO_WMISSING_VARIABLE_DECLARATIONS= + .include <bsd.prog.mk> diff --git a/bin/hostname/hostname.c b/bin/hostname/hostname.c index 87136eb..ecc319d 100644 --- a/bin/hostname/hostname.c +++ b/bin/hostname/hostname.c @@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <unistd.h> -static void usage(void); +static void usage(void) __dead2; int main(int argc, char *argv[]) diff --git a/bin/kenv/kenv.c b/bin/kenv/kenv.c index 5ba9a5e..dad8a91 100644 --- a/bin/kenv/kenv.c +++ b/bin/kenv/kenv.c @@ -37,9 +37,9 @@ __FBSDID("$FreeBSD$"); static void usage(void); static int kdumpenv(void); -static int kgetenv(char *); -static int ksetenv(char *, char *); -static int kunsetenv(char *); +static int kgetenv(const char *); +static int ksetenv(const char *, char *); +static int kunsetenv(const char *); static int hflag = 0; static int Nflag = 0; @@ -170,7 +170,7 @@ kdumpenv(void) } static int -kgetenv(char *env) +kgetenv(const char *env) { char buf[1024]; int ret; @@ -186,7 +186,7 @@ kgetenv(char *env) } static int -ksetenv(char *env, char *val) +ksetenv(const char *env, char *val) { int ret; @@ -197,7 +197,7 @@ ksetenv(char *env, char *val) } static int -kunsetenv(char *env) +kunsetenv(const char *env) { int ret; diff --git a/bin/kill/kill.c b/bin/kill/kill.c index 671d1cb..2d41f78 100644 --- a/bin/kill/kill.c +++ b/bin/kill/kill.c @@ -156,7 +156,7 @@ signame_to_signum(const char *sig) { int n; - if (!strncasecmp(sig, "SIG", (size_t)3)) + if (strncasecmp(sig, "SIG", 3) == 0) sig += 3; for (n = 1; n < sys_nsig; n++) { if (!strcasecmp(sys_signame[n], sig)) diff --git a/bin/ln/ln.c b/bin/ln/ln.c index 4169e62..f50802a 100644 --- a/bin/ln/ln.c +++ b/bin/ln/ln.c @@ -65,8 +65,8 @@ static int wflag; /* Warn if symlink target does not * exist, and -f is not enabled. */ static char linkch; -int linkit(const char *, const char *, int); -void usage(void); +static int linkit(const char *, const char *, int); +static void usage(void); int main(int argc, char *argv[]) @@ -219,7 +219,7 @@ samedirent(const char *path1, const char *path2) return sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino; } -int +static int linkit(const char *source, const char *target, int isdir) { struct stat sb; @@ -347,7 +347,7 @@ linkit(const char *source, const char *target, int isdir) return (0); } -void +static void usage(void) { (void)fprintf(stderr, "%s\n%s\n%s\n", diff --git a/bin/ls/ls.1 b/bin/ls/ls.1 index 7c72652..8b7672b 100644 --- a/bin/ls/ls.1 +++ b/bin/ls/ls.1 @@ -232,6 +232,9 @@ output. Include the file flags in a long .Pq Fl l output. +See +.Xr chflags 1 +for a list of file flags and their meanings. .It Fl p Write a slash .Pq Ql / diff --git a/bin/mkdir/mkdir.c b/bin/mkdir/mkdir.c index fda9c24..ea19209 100644 --- a/bin/mkdir/mkdir.c +++ b/bin/mkdir/mkdir.c @@ -135,7 +135,7 @@ main(int argc, char *argv[]) * Returns 1 if a directory has been created, * 2 if it already existed, and 0 on failure. */ -int +static int build(char *path, mode_t omode) { struct stat sb; @@ -208,7 +208,7 @@ build(char *path, mode_t omode) return (retval); } -void +static void usage(void) { diff --git a/bin/pkill/pkill.1 b/bin/pkill/pkill.1 index db7d78c..1ca383f 100644 --- a/bin/pkill/pkill.1 +++ b/bin/pkill/pkill.1 @@ -29,7 +29,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd February 11, 2010 +.Dd August 9, 2013 .Dt PKILL 1 .Os .Sh NAME @@ -44,6 +44,7 @@ .Op Fl N Ar system .Op Fl P Ar ppid .Op Fl U Ar uid +.Op Fl c Ar class .Op Fl d Ar delim .Op Fl g Ar pgrp .Op Fl j Ar jid @@ -60,6 +61,7 @@ .Op Fl N Ar system .Op Fl P Ar ppid .Op Fl U Ar uid +.Op Fl c Ar class .Op Fl g Ar pgrp .Op Fl j Ar jid .Op Fl s Ar sid @@ -130,6 +132,9 @@ or process and all of its ancestors are excluded (unless .Fl v is used). +.It Fl c Ar class +Restrict matches to processes running with specified login class +.Ar class . .It Fl f Match against full argument lists. The default is to match against process names. diff --git a/bin/pkill/pkill.c b/bin/pkill/pkill.c index cd91976..23ac0e9 100644 --- a/bin/pkill/pkill.c +++ b/bin/pkill/pkill.c @@ -79,12 +79,14 @@ enum listtype { LT_TTY, LT_PGRP, LT_JID, - LT_SID + LT_SID, + LT_CLASS }; struct list { SLIST_ENTRY(list) li_chain; long li_number; + char *li_name; }; SLIST_HEAD(listhead, list); @@ -116,6 +118,7 @@ static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); +static struct listhead classlist = SLIST_HEAD_INITIALIZER(classlist); static void usage(void) __attribute__((__noreturn__)); static int killact(const struct kinfo_proc *); @@ -179,7 +182,7 @@ main(int argc, char **argv) execf = NULL; coref = _PATH_DEVNULL; - while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1) + while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ac:d:fg:ij:lnoqs:t:u:vx")) != -1) switch (ch) { case 'D': debug_opt++; @@ -222,6 +225,10 @@ main(int argc, char **argv) case 'a': ancestors++; break; + case 'c': + makelist(&classlist, LT_CLASS, optarg); + criteria = 1; + break; case 'd': if (!pgrep) usage(); @@ -469,6 +476,20 @@ main(int argc, char **argv) continue; } + SLIST_FOREACH(li, &classlist, li_chain) { + /* + * We skip P_SYSTEM processes to match ps(1) output. + */ + if ((kp->ki_flag & P_SYSTEM) == 0 && + kp->ki_loginclass != NULL && + strcmp(kp->ki_loginclass, li->li_name) == 0) + break; + } + if (SLIST_FIRST(&classlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + if (argc == 0) selected[i] = 1; } @@ -562,9 +583,9 @@ usage(void) fprintf(stderr, "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" - " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n" - " [-t tty] [-u euid] pattern ...\n", getprogname(), - ustr); + " [-P ppid] [-U uid] [-c class] [-g pgrp] [-j jid]\n" + " [-s sid] [-t tty] [-u euid] pattern ...\n", + getprogname(), ustr); exit(STATUS_BADUSAGE); } @@ -664,8 +685,10 @@ makelist(struct listhead *head, enum listtype type, char *src) SLIST_INSERT_HEAD(head, li, li_chain); empty = 0; - li->li_number = (uid_t)strtol(sp, &ep, 0); - if (*ep == '\0') { + if (type != LT_CLASS) + li->li_number = (uid_t)strtol(sp, &ep, 0); + + if (type != LT_CLASS && *ep == '\0') { switch (type) { case LT_PGRP: if (li->li_number == 0) @@ -750,6 +773,12 @@ foundtty: if ((st.st_mode & S_IFCHR) == 0) errx(STATUS_BADUSAGE, "Invalid jail ID `%s'", sp); break; + case LT_CLASS: + li->li_number = -1; + li->li_name = strdup(sp); + if (li->li_name == NULL) + err(STATUS_ERROR, "Cannot allocate memory"); + break; default: usage(); } diff --git a/bin/ps/keyword.c b/bin/ps/keyword.c index 5861129..21e6791 100644 --- a/bin/ps/keyword.c +++ b/bin/ps/keyword.c @@ -87,6 +87,7 @@ static VAR var[] = { {"etimes", "ELAPSED", NULL, USER, elapseds, 0, CHAR, NULL, 0}, {"euid", "", "uid", 0, NULL, 0, CHAR, NULL, 0}, {"f", "F", NULL, 0, kvar, KOFF(ki_flag), INT, "x", 0}, + {"fib", "FIB", NULL, 0, kvar, KOFF(ki_fibnum), INT, "d", 0}, {"flags", "", "f", 0, NULL, 0, CHAR, NULL, 0}, {"gid", "GID", NULL, 0, kvar, KOFF(ki_groups), UINT, UIDFMT, 0}, {"group", "GROUP", NULL, LJUST, egroupname, 0, CHAR, NULL, 0}, diff --git a/bin/ps/ps.1 b/bin/ps/ps.1 index 1a364f5..81a1f6d 100644 --- a/bin/ps/ps.1 +++ b/bin/ps/ps.1 @@ -512,6 +512,9 @@ elapsed running time, format minutes:seconds. .It Cm etimes elapsed running time, in decimal integer seconds +.It Cm fib +default FIB number, see +.Xr setfib 1 .It Cm flags the process flags, in hexadecimal (alias .Cm f ) diff --git a/bin/rm/rm.1 b/bin/rm/rm.1 index 3588f38..824b627 100644 --- a/bin/rm/rm.1 +++ b/bin/rm/rm.1 @@ -32,7 +32,7 @@ .\" @(#)rm.1 8.5 (Berkeley) 12/5/94 .\" $FreeBSD$ .\" -.Dd March 15, 2013 +.Dd April 25, 2013 .Dt RM 1 .Os .Sh NAME @@ -42,7 +42,7 @@ .Sh SYNOPSIS .Nm .Op Fl f | i -.Op Fl dIPRrvW +.Op Fl dIPRrvWx .Ar .Nm unlink .Ar file @@ -132,6 +132,8 @@ Attempt to undelete the named files. Currently, this option can only be used to recover files covered by whiteouts in a union file system (see .Xr undelete 2 ) . +.It Fl x +When removing a hierarchy, do not cross mount points. .El .Pp The diff --git a/bin/rm/rm.c b/bin/rm/rm.c index a450057..976b4ee 100644 --- a/bin/rm/rm.c +++ b/bin/rm/rm.c @@ -59,19 +59,19 @@ __FBSDID("$FreeBSD$"); #include <unistd.h> static int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok; -static int rflag, Iflag; +static int rflag, Iflag, xflag; static uid_t uid; static volatile sig_atomic_t info; -int check(char *, char *, struct stat *); -int check2(char **); -void checkdot(char **); -void checkslash(char **); -void rm_file(char **); -int rm_overwrite(char *, struct stat *); -void rm_tree(char **); +static int check(const char *, const char *, struct stat *); +static int check2(char **); +static void checkdot(char **); +static void checkslash(char **); +static void rm_file(char **); +static int rm_overwrite(const char *, struct stat *); +static void rm_tree(char **); static void siginfo(int __unused); -void usage(void); +static void usage(void); /* * rm -- @@ -106,8 +106,8 @@ main(int argc, char *argv[]) exit(eval); } - Pflag = rflag = 0; - while ((ch = getopt(argc, argv, "dfiIPRrvW")) != -1) + Pflag = rflag = xflag = 0; + while ((ch = getopt(argc, argv, "dfiIPRrvWx")) != -1) switch(ch) { case 'd': dflag = 1; @@ -136,6 +136,9 @@ main(int argc, char *argv[]) case 'W': Wflag = 1; break; + case 'x': + xflag = 1; + break; default: usage(); } @@ -170,7 +173,7 @@ main(int argc, char *argv[]) exit (eval); } -void +static void rm_tree(char **argv) { FTS *fts; @@ -196,6 +199,8 @@ rm_tree(char **argv) flags |= FTS_NOSTAT; if (Wflag) flags |= FTS_WHITEOUT; + if (xflag) + flags |= FTS_XDEV; if (!(fts = fts_open(argv, flags, NULL))) { if (fflag && errno == ENOENT) return; @@ -335,7 +340,7 @@ err: fts_close(fts); } -void +static void rm_file(char **argv) { struct stat sb; @@ -412,8 +417,8 @@ rm_file(char **argv) * System V file system). In a logging or COW file system, you'll have to * have kernel support. */ -int -rm_overwrite(char *file, struct stat *sbp) +static int +rm_overwrite(const char *file, struct stat *sbp) { struct stat sb, sb2; struct statfs fsb; @@ -479,8 +484,8 @@ err: eval = 1; } -int -check(char *path, char *name, struct stat *sp) +static int +check(const char *path, const char *name, struct stat *sp) { int ch, first; char modep[15], *flagsp; @@ -491,7 +496,7 @@ check(char *path, char *name, struct stat *sp) else { /* * If it's not a symbolic link and it's unwritable and we're - * talking to a terminal, ask. Symbolic links are excluded + * talking to a terminal, ask. Symbolic links are excluded * because their permissions are meaningless. Check stdin_ok * first because we may not have stat'ed the file. */ @@ -524,7 +529,7 @@ check(char *path, char *name, struct stat *sp) } #define ISSLASH(a) ((a)[0] == '/' && (a)[1] == '\0') -void +static void checkslash(char **argv) { char **t, **u; @@ -544,7 +549,7 @@ checkslash(char **argv) } } -int +static int check2(char **argv) { struct stat st; @@ -595,7 +600,7 @@ check2(char **argv) } #define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) -void +static void checkdot(char **argv) { char *p, **save, **t; @@ -619,12 +624,12 @@ checkdot(char **argv) } } -void +static void usage(void) { (void)fprintf(stderr, "%s\n%s\n", - "usage: rm [-f | -i] [-dIPRrvW] file ...", + "usage: rm [-f | -i] [-dIPRrvWx] file ...", " unlink file"); exit(EX_USAGE); } diff --git a/bin/sh/Makefile b/bin/sh/Makefile index cc04aa4..00d34fa 100644 --- a/bin/sh/Makefile +++ b/bin/sh/Makefile @@ -8,7 +8,7 @@ SHSRCS= alias.c arith_yacc.c arith_yylex.c cd.c echo.c error.c eval.c \ histedit.c input.c jobs.c kill.c mail.c main.c memalloc.c miscbltin.c \ mystring.c options.c output.c parser.c printf.c redir.c show.c \ test.c trap.c var.c -GENSRCS= builtins.c init.c nodes.c syntax.c +GENSRCS= builtins.c nodes.c syntax.c GENHDRS= builtins.h nodes.h syntax.h token.h SRCS= ${SHSRCS} ${GENSRCS} ${GENHDRS} @@ -30,26 +30,21 @@ WFORMAT=0 ${.CURDIR}/../test \ ${.CURDIR}/../../usr.bin/printf -CLEANFILES+= mkinit mkinit.o mknodes mknodes.o \ +CLEANFILES+= mknodes mknodes.o \ mksyntax mksyntax.o CLEANFILES+= ${GENSRCS} ${GENHDRS} -build-tools: mkinit mknodes mksyntax +build-tools: mknodes mksyntax .ORDER: builtins.c builtins.h builtins.c builtins.h: mkbuiltins builtins.def sh ${.CURDIR}/mkbuiltins ${.CURDIR} -init.c: mkinit alias.c eval.c exec.c input.c jobs.c options.c parser.c \ - redir.c trap.c var.c - ./mkinit ${.ALLSRC:S/^mkinit$//} - # XXX this is just to stop the default .c rule being used, so that the # intermediate object has a fixed name. # XXX we have a default .c rule, but no default .o rule. .o: ${CC} ${CFLAGS} ${LDFLAGS} ${.IMPSRC} ${LDLIBS} -o ${.TARGET} -mkinit: mkinit.o mknodes: mknodes.o mksyntax: mksyntax.o diff --git a/bin/sh/TOUR b/bin/sh/TOUR index 13438b5..e9bbe9b 100644 --- a/bin/sh/TOUR +++ b/bin/sh/TOUR @@ -25,38 +25,11 @@ programs is: program input files generates ------- ----------- --------- mkbuiltins builtins builtins.h builtins.c - mkinit *.c init.c mknodes nodetypes nodes.h nodes.c mksyntax - syntax.h syntax.c mktokens - token.h -There are undoubtedly too many of these. Mkinit searches all the -C source files for entries looking like: - - RESET { - x = 2; /* executed when the shell does a longjmp - back to the main command loop */ - } - -It pulls this code out into routines which are when particular -events occur. The intent is to improve modularity by isolating -the information about which modules need to be explicitly -initialized/reset within the modules themselves. - -Mkinit recognizes several constructs for placing declarations in -the init.c file. - INCLUDE "file.h" -includes a file. The storage class MKINIT makes a declaration -available in the init.c file, for example: - MKINIT int funcnest; /* depth of function calls */ -MKINIT alone on a line introduces a structure or union declara- -tion: - MKINIT - struct redirtab { - short renamed[10]; - }; -Preprocessor #define statements are copied to init.c without any -special action to request this. +There are undoubtedly too many of these. EXCEPTIONS: Code for dealing with exceptions appears in exceptions.c. The C language doesn't include exception handling, diff --git a/bin/sh/alias.c b/bin/sh/alias.c index da995bb..044c869 100644 --- a/bin/sh/alias.c +++ b/bin/sh/alias.c @@ -237,17 +237,19 @@ printaliases(void) } int -aliascmd(int argc, char **argv) +aliascmd(int argc __unused, char **argv __unused) { char *n, *v; int ret = 0; struct alias *ap; - if (argc == 1) { + nextopt(""); + + if (*argptr == NULL) { printaliases(); return (0); } - while ((n = *++argv) != NULL) { + while ((n = *argptr++) != NULL) { if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */ if ((ap = lookupalias(n, 0)) == NULL) { warning("%s: not found", n); diff --git a/bin/sh/arith_yylex.c b/bin/sh/arith_yylex.c index f6eebdb..ad08184 100644 --- a/bin/sh/arith_yylex.c +++ b/bin/sh/arith_yylex.c @@ -218,9 +218,13 @@ checkeqcur: value += ARITH_REM - '%'; goto checkeq; case '+': + if (buf[1] == '+') + return ARITH_BAD; value += ARITH_ADD - '+'; goto checkeq; case '-': + if (buf[1] == '-') + return ARITH_BAD; value += ARITH_SUB - '-'; goto checkeq; case '~': diff --git a/bin/sh/eval.c b/bin/sh/eval.c index d3708b3..b8f76d5 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -76,7 +76,7 @@ __FBSDID("$FreeBSD$"); int evalskip; /* set if we are skipping commands */ int skipcount; /* number of levels to skip */ -MKINIT int loopnest; /* current loop nesting level */ +static int loopnest; /* current loop nesting level */ int funcnest; /* depth of function calls */ static int builtin_flags; /* evalcommand flags for builtins */ @@ -104,16 +104,12 @@ static void prehash(union node *); * Called to reset things after an exception. */ -#ifdef mkinit -INCLUDE "eval.h" - -RESET { +void +reseteval(void) +{ evalskip = 0; loopnest = 0; - funcnest = 0; } -#endif - /* @@ -328,7 +324,7 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { } if (evalskip == SKIPBREAK && --skipcount <= 0) evalskip = 0; - if (evalskip == SKIPFUNC || evalskip == SKIPFILE) + if (evalskip == SKIPRETURN) status = exitstatus; break; } @@ -589,7 +585,8 @@ evalpipe(union node *n) pip[1] = -1; if (lp->next) { if (pipe(pip) < 0) { - close(prevfd); + if (prevfd >= 0) + close(prevfd); error("Pipe call failed: %s", strerror(errno)); } } @@ -1071,7 +1068,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd) funcnest--; popredir(); INTON; - if (evalskip == SKIPFUNC) { + if (evalskip == SKIPRETURN) { evalskip = 0; skipcount = 0; } @@ -1308,14 +1305,8 @@ returncmd(int argc, char **argv) { int ret = argc > 1 ? number(argv[1]) : oexitstatus; - if (funcnest) { - evalskip = SKIPFUNC; - skipcount = 1; - } else { - /* skip the rest of the file */ - evalskip = SKIPFILE; - skipcount = 1; - } + evalskip = SKIPRETURN; + skipcount = 1; return ret; } diff --git a/bin/sh/eval.h b/bin/sh/eval.h index 724e157..4129757 100644 --- a/bin/sh/eval.h +++ b/bin/sh/eval.h @@ -46,6 +46,8 @@ struct backcmd { /* result of evalbackcmd */ struct job *jp; /* job structure for command */ }; +void reseteval(void); + /* flags in argument to evaltree/evalstring */ #define EV_EXIT 01 /* exit after evaluating tree */ #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ @@ -65,5 +67,4 @@ extern int skipcount; /* reasons for skipping commands (see comment on breakcmd routine) */ #define SKIPBREAK 1 #define SKIPCONT 2 -#define SKIPFUNC 3 -#define SKIPFILE 4 +#define SKIPRETURN 3 diff --git a/bin/sh/exec.c b/bin/sh/exec.c index 6c3a6dd..9f8e029 100644 --- a/bin/sh/exec.c +++ b/bin/sh/exec.c @@ -70,7 +70,6 @@ __FBSDID("$FreeBSD$"); #include "syntax.h" #include "memalloc.h" #include "error.h" -#include "init.h" #include "mystring.h" #include "show.h" #include "jobs.h" @@ -763,5 +762,7 @@ typecmd_impl(int argc, char **argv, int cmd, const char *path) int typecmd(int argc, char **argv) { + if (argc > 2 && strcmp(argv[1], "--") == 0) + argc--, argv++; return typecmd_impl(argc, argv, TYPECMD_TYPE, bltinlookup("PATH", 1)); } diff --git a/bin/sh/init.h b/bin/sh/init.h deleted file mode 100644 index 384bb69..0000000 --- a/bin/sh/init.h +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)init.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD$ - */ - -void reset(void); diff --git a/bin/sh/input.c b/bin/sh/input.c index 62e82a0..e46095d 100644 --- a/bin/sh/input.c +++ b/bin/sh/input.c @@ -92,7 +92,7 @@ struct parsefile { int plinno = 1; /* input line number */ int parsenleft; /* copy of parsefile->nleft */ -MKINIT int parselleft; /* copy of parsefile->lleft */ +static int parselleft; /* copy of parsefile->lleft */ const char *parsenextc; /* copy of parsefile->nextc */ static char basebuf[BUFSIZ + 1];/* buffer for top level input file */ static struct parsefile basepf = { /* top level input file */ @@ -108,15 +108,12 @@ static void pushfile(void); static int preadfd(void); static void popstring(void); -#ifdef mkinit -INCLUDE "input.h" -INCLUDE "error.h" - -RESET { +void +resetinput(void) +{ popallfiles(); parselleft = parsenleft = 0; /* clear input buffer */ } -#endif /* @@ -397,10 +394,10 @@ setinputfile(const char *fname, int push) int fd2; INTOFF; - if ((fd = open(fname, O_RDONLY)) < 0) + if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0) error("cannot open %s: %s", fname, strerror(errno)); if (fd < 10) { - fd2 = fcntl(fd, F_DUPFD, 10); + fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10); close(fd); if (fd2 < 0) error("Out of file descriptors"); @@ -412,14 +409,13 @@ setinputfile(const char *fname, int push) /* - * Like setinputfile, but takes an open file descriptor. Call this with - * interrupts off. + * Like setinputfile, but takes an open file descriptor (which should have + * its FD_CLOEXEC flag already set). Call this with interrupts off. */ void setinputfd(int fd, int push) { - (void)fcntl(fd, F_SETFD, FD_CLOEXEC); if (push) { pushfile(); parsefile->buf = ckmalloc(BUFSIZ + 1); diff --git a/bin/sh/input.h b/bin/sh/input.h index 70f675e..cc54eed 100644 --- a/bin/sh/input.h +++ b/bin/sh/input.h @@ -47,6 +47,7 @@ extern const char *parsenextc; /* next character in input buffer */ struct alias; struct parsefile; +void resetinput(void); char *pfgets(char *, int); int pgetc(void); int preadbuffer(void); diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c index c978e3d..bbb954a 100644 --- a/bin/sh/jobs.c +++ b/bin/sh/jobs.c @@ -77,24 +77,25 @@ __FBSDID("$FreeBSD$"); static struct job *jobtab; /* array of jobs */ static int njobs; /* size of array */ -MKINIT pid_t backgndpid = -1; /* pid of last background process */ -MKINIT struct job *bgjob = NULL; /* last background process */ +static pid_t backgndpid = -1; /* pid of last background process */ +static struct job *bgjob = NULL; /* last background process */ #if JOBS static struct job *jobmru; /* most recently used job list */ static pid_t initialpgrp; /* pgrp of shell on invocation */ #endif -int in_waitcmd = 0; /* are we in waitcmd()? */ -volatile sig_atomic_t breakwaitcmd = 0; /* should wait be terminated? */ static int ttyfd = -1; /* mode flags for dowait */ #define DOWAIT_BLOCK 0x1 /* wait until a child exits */ -#define DOWAIT_SIG 0x2 /* if DOWAIT_BLOCK, abort on signals */ +#define DOWAIT_SIG 0x2 /* if DOWAIT_BLOCK, abort on SIGINT/SIGQUIT */ +#define DOWAIT_SIG_ANY 0x4 /* if DOWAIT_SIG, abort on any signal */ #if JOBS static void restartjob(struct job *); #endif static void freejob(struct job *); +static int waitcmdloop(struct job *); +static struct job *getjob_nonotfound(char *); static struct job *getjob(char *); pid_t getjobpgrp(char *); static pid_t dowait(int, struct job *); @@ -114,7 +115,7 @@ static void showjob(struct job *, int); * Turn job control on and off. */ -MKINIT int jobctl; +static int jobctl; #if JOBS void @@ -127,11 +128,12 @@ setjobctl(int on) if (on) { if (ttyfd != -1) close(ttyfd); - if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) { + if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) < 0) { i = 0; while (i <= 2 && !isatty(i)) i++; - if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0) + if (i > 2 || + (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) goto out; } if (ttyfd < 10) { @@ -139,7 +141,7 @@ setjobctl(int on) * Keep our TTY file descriptor out of the way of * the user's redirections. */ - if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) { + if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) { close(ttyfd); ttyfd = -1; goto out; @@ -147,11 +149,6 @@ setjobctl(int on) close(ttyfd); ttyfd = i; } - if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) { - close(ttyfd); - ttyfd = -1; - goto out; - } do { /* while we are in the background */ initialpgrp = tcgetpgrp(ttyfd); if (initialpgrp < 0) { @@ -185,13 +182,14 @@ out: out2fmt_flush("sh: can't access tty; job control turned off\n"); #if JOBS int -fgcmd(int argc __unused, char **argv) +fgcmd(int argc __unused, char **argv __unused) { struct job *jp; pid_t pgrp; int status; - jp = getjob(argv[1]); + nextopt(""); + jp = getjob(*argptr); if (jp->jobctl == 0) error("job not created under job control"); printjobcmd(jp); @@ -212,8 +210,9 @@ bgcmd(int argc, char **argv) { struct job *jp; + nextopt(""); do { - jp = getjob(*++argv); + jp = getjob(*argptr); if (jp->jobctl == 0) error("job not created under job control"); if (jp->state == JOBDONE) @@ -222,7 +221,7 @@ bgcmd(int argc, char **argv) jp->foreground = 0; out1fmt("[%td] ", jp - jobtab + 1); printjobcmd(jp); - } while (--argc > 1); + } while (*argptr != NULL && *++argptr != NULL); return 0; } @@ -417,13 +416,15 @@ showjobs(int change, int mode) if (change && ! jp->changed) continue; showjob(jp, mode); - jp->changed = 0; - /* Hack: discard jobs for which $! has not been referenced - * in interactive mode when they terminate. - */ - if (jp->state == JOBDONE && !jp->remembered && - (iflag || jp != bgjob)) { - freejob(jp); + if (mode == SHOWJOBS_DEFAULT || mode == SHOWJOBS_VERBOSE) { + jp->changed = 0; + /* Hack: discard jobs for which $! has not been + * referenced in interactive mode when they terminate. + */ + if (jp->state == JOBDONE && !jp->remembered && + (iflag || jp != bgjob)) { + freejob(jp); + } } } } @@ -461,32 +462,41 @@ int waitcmd(int argc __unused, char **argv __unused) { struct job *job; - int status, retval; - struct job *jp; + int retval; nextopt(""); - if (*argptr != NULL) { - job = getjob(*argptr); - } else { - job = NULL; - } + if (*argptr == NULL) + return (waitcmdloop(NULL)); + + do { + job = getjob_nonotfound(*argptr); + if (job == NULL) + retval = 127; + else + retval = waitcmdloop(job); + argptr++; + } while (*argptr != NULL); + + return (retval); +} + +static int +waitcmdloop(struct job *job) +{ + int status, retval, sig; + struct job *jp; /* * Loop until a process is terminated or stopped, or a SIGINT is * received. */ - in_waitcmd++; do { if (job != NULL) { - if (job->state) { + if (job->state == JOBDONE) { status = job->ps[job->nprocs - 1].status; if (WIFEXITED(status)) retval = WEXITSTATUS(status); -#if JOBS - else if (WIFSTOPPED(status)) - retval = WSTOPSIG(status) + 128; -#endif else retval = WTERMSIG(status) + 128; if (! iflag || ! job->changed) @@ -496,7 +506,6 @@ waitcmd(int argc __unused, char **argv __unused) if (job == bgjob) bgjob = NULL; } - in_waitcmd--; return retval; } } else { @@ -512,7 +521,6 @@ waitcmd(int argc __unused, char **argv __unused) } for (jp = jobtab ; ; jp++) { if (jp >= jobtab + njobs) { /* no running procs */ - in_waitcmd--; return 0; } if (jp->used && jp->state == 0) @@ -520,20 +528,22 @@ waitcmd(int argc __unused, char **argv __unused) } } } while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1); - in_waitcmd--; - return pendingsig + 128; + sig = pendingsig_waitcmd; + pendingsig_waitcmd = 0; + return sig + 128; } int -jobidcmd(int argc __unused, char **argv) +jobidcmd(int argc __unused, char **argv __unused) { struct job *jp; int i; - jp = getjob(argv[1]); + nextopt(""); + jp = getjob(*argptr); for (i = 0 ; i < jp->nprocs ; ) { out1fmt("%d", (int)jp->ps[i].pid); out1c(++i < jp->nprocs? ' ' : '\n'); @@ -548,7 +558,7 @@ jobidcmd(int argc __unused, char **argv) */ static struct job * -getjob(char *name) +getjob_nonotfound(char *name) { int jobno; struct job *found, *jp; @@ -613,12 +623,22 @@ currentjob: if ((jp = getcurjob(NULL)) == NULL) return jp; } } - error("No such job: %s", name); - /*NOTREACHED*/ return NULL; } +static struct job * +getjob(char *name) +{ + struct job *jp; + + jp = getjob_nonotfound(name); + if (jp == NULL) + error("No such job: %s", name); + return (jp); +} + + pid_t getjobpgrp(char *name) { @@ -967,7 +987,8 @@ waitforjob(struct job *jp, int *origstatus) INTOFF; TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1)); while (jp->state == 0) - if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG : 0), jp) == -1) + if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG | + DOWAIT_SIG_ANY : 0), jp) == -1) dotrap(); #if JOBS if (jp->jobctl) { @@ -1058,12 +1079,17 @@ dowait(int mode, struct job *job) pid = wait3(&status, wflags, (struct rusage *)NULL); TRACE(("wait returns %d, status=%d\n", (int)pid, status)); if (pid == 0 && (mode & DOWAIT_SIG) != 0) { - sigsuspend(&omask); pid = -1; + if (((mode & DOWAIT_SIG_ANY) != 0 ? + pendingsig : pendingsig_waitcmd) != 0) { + errno = EINTR; + break; + } + sigsuspend(&omask); if (int_pending()) break; } - } while (pid == -1 && errno == EINTR && breakwaitcmd == 0); + } while (pid == -1 && errno == EINTR); if (pid == -1 && errno == ECHILD && job != NULL) job->state = JOBDONE; if ((mode & DOWAIT_SIG) != 0) { @@ -1072,11 +1098,6 @@ dowait(int mode, struct job *job) sigprocmask(SIG_SETMASK, &omask, NULL); INTON; } - if (breakwaitcmd != 0) { - breakwaitcmd = 0; - if (pid <= 0) - return -1; - } if (pid <= 0) return pid; INTOFF; diff --git a/bin/sh/jobs.h b/bin/sh/jobs.h index 1570b46..892f129 100644 --- a/bin/sh/jobs.h +++ b/bin/sh/jobs.h @@ -83,8 +83,6 @@ enum { }; extern int job_warning; /* user was warned about stopped jobs */ -extern int in_waitcmd; /* are we in waitcmd()? */ -extern volatile sig_atomic_t breakwaitcmd; /* break wait to process traps? */ void setjobctl(int); void showjobs(int, int); diff --git a/bin/sh/main.c b/bin/sh/main.c index 84a1ef2..e4974ea 100644 --- a/bin/sh/main.c +++ b/bin/sh/main.c @@ -68,10 +68,10 @@ __FBSDID("$FreeBSD$"); #include "show.h" #include "memalloc.h" #include "error.h" -#include "init.h" #include "mystring.h" #include "exec.h" #include "cd.h" +#include "redir.h" #include "builtins.h" int rootpid; @@ -79,6 +79,7 @@ int rootshell; struct jmploc main_handler; int localeisutf8, initial_localeisutf8; +static void reset(void); static void cmdloop(int); static void read_profile(const char *); static char *find_dot_file(char *); @@ -170,8 +171,8 @@ state3: if (minusc) { evalstring(minusc, sflag ? 0 : EV_EXIT); } +state4: if (sflag || minusc == NULL) { -state4: /* XXX ??? - why isn't this before the "if" statement */ cmdloop(1); } exitshell(exitstatus); @@ -179,6 +180,12 @@ state4: /* XXX ??? - why isn't this before the "if" statement */ return 0; } +static void +reset(void) +{ + reseteval(); + resetinput(); +} /* * Read and execute commands. "Top" is nonzero for the top level command @@ -224,7 +231,7 @@ cmdloop(int top) popstackmark(&smark); setstackmark(&smark); if (evalskip != 0) { - if (evalskip == SKIPFILE) + if (evalskip == SKIPRETURN) evalskip = 0; break; } @@ -248,7 +255,7 @@ read_profile(const char *name) if (expandedname == NULL) return; INTOFF; - if ((fd = open(expandedname, O_RDONLY)) >= 0) + if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC)) >= 0) setinputfd(fd, 1); INTON; if (fd < 0) diff --git a/bin/sh/memalloc.c b/bin/sh/memalloc.c index f33a15c..cb330d0 100644 --- a/bin/sh/memalloc.c +++ b/bin/sh/memalloc.c @@ -124,7 +124,6 @@ struct stack_block { #define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block))) static struct stack_block *stackp; -static struct stackmark *markp; char *stacknxt; int stacknleft; char *sstrend; @@ -186,8 +185,9 @@ setstackmark(struct stackmark *mark) mark->stackp = stackp; mark->stacknxt = stacknxt; mark->stacknleft = stacknleft; - mark->marknext = markp; - markp = mark; + /* Ensure this block stays in place. */ + if (stackp != NULL && stacknxt == SPACE(stackp)) + stalloc(1); } @@ -197,7 +197,6 @@ popstackmark(struct stackmark *mark) struct stack_block *sp; INTOFF; - markp = mark->marknext; while (stackp != mark->stackp) { sp = stackp; stackp = sp->prev; @@ -229,7 +228,6 @@ growstackblock(int min) int oldlen; struct stack_block *sp; struct stack_block *oldstackp; - struct stackmark *xmark; if (min < stacknleft) min = stacknleft; @@ -254,18 +252,6 @@ growstackblock(int min) stacknxt = SPACE(sp); stacknleft = newlen - (stacknxt - (char*)sp); sstrend = stacknxt + stacknleft; - - /* - * Stack marks pointing to the start of the old block - * must be relocated to point to the new block - */ - xmark = markp; - while (xmark != NULL && xmark->stackp == oldstackp) { - xmark->stackp = stackp; - xmark->stacknxt = stacknxt; - xmark->stacknleft = stacknleft; - xmark = xmark->marknext; - } INTON; } else { newlen -= ALIGN(sizeof(struct stack_block)); diff --git a/bin/sh/memalloc.h b/bin/sh/memalloc.h index 95a6594..a22fa39 100644 --- a/bin/sh/memalloc.h +++ b/bin/sh/memalloc.h @@ -39,7 +39,6 @@ struct stackmark { struct stack_block *stackp; char *stacknxt; int stacknleft; - struct stackmark *marknext; }; diff --git a/bin/sh/miscbltin.c b/bin/sh/miscbltin.c index b81cc82..2ecd4f2 100644 --- a/bin/sh/miscbltin.c +++ b/bin/sh/miscbltin.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include "error.h" #include "mystring.h" #include "syntax.h" +#include "trap.h" #undef eflag @@ -102,6 +103,8 @@ readcmd(int argc __unused, char **argv __unused) struct timeval tv; char *tvptr; fd_set ifds; + ssize_t nread; + int sig; rflag = 0; prompt = NULL; @@ -156,8 +159,10 @@ readcmd(int argc __unused, char **argv __unused) /* * If there's nothing ready, return an error. */ - if (status <= 0) - return(1); + if (status <= 0) { + sig = pendingsig; + return (128 + (sig != 0 ? sig : SIGALRM)); + } } status = 0; @@ -165,7 +170,19 @@ readcmd(int argc __unused, char **argv __unused) backslash = 0; STARTSTACKSTR(p); for (;;) { - if (read(STDIN_FILENO, &c, 1) != 1) { + nread = read(STDIN_FILENO, &c, 1); + if (nread == -1) { + if (errno == EINTR) { + sig = pendingsig; + if (sig == 0) + continue; + status = 128 + sig; + break; + } + warning("read error: %s", strerror(errno)); + status = 2; + break; + } else if (nread != 1) { status = 1; break; } diff --git a/bin/sh/mkinit.c b/bin/sh/mkinit.c deleted file mode 100644 index d73e0e2..0000000 --- a/bin/sh/mkinit.c +++ /dev/null @@ -1,480 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static char const copyright[] = -"@(#) Copyright (c) 1991, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95"; -#endif -#endif /* not lint */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * This program scans all the source files for code to handle various - * special events and combines this code into one file. This (allegedly) - * improves the structure of the program since there is no need for - * anyone outside of a module to know that that module performs special - * operations on particular events. - * - * Usage: mkinit sourcefile... - */ - - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - - -/* - * OUTFILE is the name of the output file. Output is initially written - * to the file OUTTEMP, which is then moved to OUTFILE. - */ - -#define OUTFILE "init.c" -#define OUTTEMP "init.c.new" - - -/* - * A text structure is basically just a string that grows as more characters - * are added onto the end of it. It is implemented as a linked list of - * blocks of characters. The routines addstr and addchar append a string - * or a single character, respectively, to a text structure. Writetext - * writes the contents of a text structure to a file. - */ - -#define BLOCKSIZE 512 - -struct text { - char *nextc; - int nleft; - struct block *start; - struct block *last; -}; - -struct block { - struct block *next; - char text[BLOCKSIZE]; -}; - - -/* - * There is one event structure for each event that mkinit handles. - */ - -struct event { - const char *name; /* name of event (e.g. RESET) */ - const char *routine; /* name of routine called on event */ - const char *comment; /* comment describing routine */ - struct text code; /* code for handling event */ -}; - - -char writer[] = "\ -/*\n\ - * This file was generated by the mkinit program.\n\ - */\n\ -\n"; - -char reset[] = "\ -/*\n\ - * This routine is called when an error or an interrupt occurs in an\n\ - * interactive shell and control is returned to the main command loop.\n\ - */\n"; - - -struct event event[] = { - { "RESET", "reset", reset, { NULL, 0, NULL, NULL } }, - { NULL, NULL, NULL, { NULL, 0, NULL, NULL } } -}; - - -const char *curfile; /* current file */ -int linno; /* current line */ -char *header_files[200]; /* list of header files */ -struct text defines; /* #define statements */ -struct text decls; /* declarations */ -int amiddecls; /* for formatting */ - - -void readfile(const char *); -int match(const char *, const char *); -int gooddefine(const char *); -void doevent(struct event *, FILE *, const char *); -void doinclude(char *); -void dodecl(char *, FILE *); -void output(void); -void addstr(const char *, struct text *); -void addchar(int, struct text *); -void writetext(struct text *, FILE *); -FILE *ckfopen(const char *, const char *); -void *ckmalloc(size_t); -char *savestr(const char *); -void error(const char *); - -#define equal(s1, s2) (strcmp(s1, s2) == 0) - -int -main(int argc __unused, char *argv[]) -{ - char **ap; - - header_files[0] = savestr("\"shell.h\""); - header_files[1] = savestr("\"mystring.h\""); - header_files[2] = savestr("\"init.h\""); - for (ap = argv + 1 ; *ap ; ap++) - readfile(*ap); - output(); - rename(OUTTEMP, OUTFILE); - exit(0); -} - - -/* - * Parse an input file. - */ - -void -readfile(const char *fname) -{ - FILE *fp; - char line[1024]; - struct event *ep; - - fp = ckfopen(fname, "r"); - curfile = fname; - linno = 0; - amiddecls = 0; - while (fgets(line, sizeof line, fp) != NULL) { - linno++; - for (ep = event ; ep->name ; ep++) { - if (line[0] == ep->name[0] && match(ep->name, line)) { - doevent(ep, fp, fname); - break; - } - } - if (line[0] == 'I' && match("INCLUDE", line)) - doinclude(line); - if (line[0] == 'M' && match("MKINIT", line)) - dodecl(line, fp); - if (line[0] == '#' && gooddefine(line)) { - char *cp; - char line2[1024]; - static const char undef[] = "#undef "; - - strcpy(line2, line); - memcpy(line2, undef, sizeof(undef) - 1); - cp = line2 + sizeof(undef) - 1; - while(*cp && (*cp == ' ' || *cp == '\t')) - cp++; - while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') - cp++; - *cp++ = '\n'; *cp = '\0'; - addstr(line2, &defines); - addstr(line, &defines); - } - } - fclose(fp); -} - - -int -match(const char *name, const char *line) -{ - const char *p, *q; - - p = name, q = line; - while (*p) { - if (*p++ != *q++) - return 0; - } - if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') - return 0; - return 1; -} - - -int -gooddefine(const char *line) -{ - const char *p; - - if (! match("#define", line)) - return 0; /* not a define */ - p = line + 7; - while (*p == ' ' || *p == '\t') - p++; - while (*p != ' ' && *p != '\t') { - if (*p == '(') - return 0; /* macro definition */ - p++; - } - while (*p != '\n' && *p != '\0') - p++; - if (p[-1] == '\\') - return 0; /* multi-line definition */ - return 1; -} - - -void -doevent(struct event *ep, FILE *fp, const char *fname) -{ - char line[1024]; - int indent; - const char *p; - - sprintf(line, "\n /* from %s: */\n", fname); - addstr(line, &ep->code); - addstr(" {\n", &ep->code); - for (;;) { - linno++; - if (fgets(line, sizeof line, fp) == NULL) - error("Unexpected EOF"); - if (equal(line, "}\n")) - break; - indent = 6; - for (p = line ; *p == '\t' ; p++) - indent += 8; - for ( ; *p == ' ' ; p++) - indent++; - if (*p == '\n' || *p == '#') - indent = 0; - while (indent >= 8) { - addchar('\t', &ep->code); - indent -= 8; - } - while (indent > 0) { - addchar(' ', &ep->code); - indent--; - } - addstr(p, &ep->code); - } - addstr(" }\n", &ep->code); -} - - -void -doinclude(char *line) -{ - char *p; - char *name; - char **pp; - - for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); - if (*p == '\0') - error("Expecting '\"' or '<'"); - name = p; - while (*p != ' ' && *p != '\t' && *p != '\n') - p++; - if (p[-1] != '"' && p[-1] != '>') - error("Missing terminator"); - *p = '\0'; - - /* name now contains the name of the include file */ - for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); - if (*pp == NULL) - *pp = savestr(name); -} - - -void -dodecl(char *line1, FILE *fp) -{ - char line[1024]; - char *p, *q; - - if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ - addchar('\n', &decls); - do { - linno++; - if (fgets(line, sizeof line, fp) == NULL) - error("Unterminated structure declaration"); - addstr(line, &decls); - } while (line[0] != '}'); - amiddecls = 0; - } else { - if (! amiddecls) - addchar('\n', &decls); - q = NULL; - for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) - continue; - if (*p == '=') { /* eliminate initialization */ - for (q = p ; *q && *q != ';' ; q++); - if (*q == '\0') - q = NULL; - else { - while (p[-1] == ' ') - p--; - *p = '\0'; - } - } - addstr("extern", &decls); - addstr(line1 + 6, &decls); - if (q != NULL) - addstr(q, &decls); - amiddecls = 1; - } -} - - - -/* - * Write the output to the file OUTTEMP. - */ - -void -output(void) -{ - FILE *fp; - char **pp; - struct event *ep; - - fp = ckfopen(OUTTEMP, "w"); - fputs(writer, fp); - for (pp = header_files ; *pp ; pp++) - fprintf(fp, "#include %s\n", *pp); - fputs("\n\n\n", fp); - writetext(&defines, fp); - fputs("\n\n", fp); - writetext(&decls, fp); - for (ep = event ; ep->name ; ep++) { - fputs("\n\n\n", fp); - fputs(ep->comment, fp); - fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine); - writetext(&ep->code, fp); - fprintf(fp, "}\n"); - } - fclose(fp); -} - - -/* - * A text structure is simply a block of text that is kept in memory. - * Addstr appends a string to the text struct, and addchar appends a single - * character. - */ - -void -addstr(const char *s, struct text *text) -{ - while (*s) { - if (--text->nleft < 0) - addchar(*s++, text); - else - *text->nextc++ = *s++; - } -} - - -void -addchar(int c, struct text *text) -{ - struct block *bp; - - if (--text->nleft < 0) { - bp = ckmalloc(sizeof *bp); - if (text->start == NULL) - text->start = bp; - else - text->last->next = bp; - text->last = bp; - text->nextc = bp->text; - text->nleft = BLOCKSIZE - 1; - } - *text->nextc++ = c; -} - -/* - * Write the contents of a text structure to a file. - */ -void -writetext(struct text *text, FILE *fp) -{ - struct block *bp; - - if (text->start != NULL) { - for (bp = text->start ; bp != text->last ; bp = bp->next) - fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); - fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); - } -} - -FILE * -ckfopen(const char *file, const char *mode) -{ - FILE *fp; - - if ((fp = fopen(file, mode)) == NULL) { - fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); - exit(2); - } - return fp; -} - -void * -ckmalloc(size_t nbytes) -{ - char *p; - - if ((p = malloc(nbytes)) == NULL) - error("Out of space"); - return p; -} - -char * -savestr(const char *s) -{ - char *p; - - p = ckmalloc(strlen(s) + 1); - strcpy(p, s); - return p; -} - -void -error(const char *msg) -{ - if (curfile != NULL) - fprintf(stderr, "%s:%d: ", curfile, linno); - fprintf(stderr, "%s\n", msg); - exit(2); -} diff --git a/bin/sh/output.c b/bin/sh/output.c index d26adce..bf8e17d 100644 --- a/bin/sh/output.c +++ b/bin/sh/output.c @@ -75,25 +75,6 @@ struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; struct output *out1 = &output; struct output *out2 = &errout; - - -#ifdef mkinit - -INCLUDE "output.h" -INCLUDE "memalloc.h" - -RESET { - out1 = &output; - out2 = &errout; - if (memout.buf != NULL) { - ckfree(memout.buf); - memout.buf = NULL; - } -} - -#endif - - void outcslow(int c, struct output *file) { diff --git a/bin/sh/parser.c b/bin/sh/parser.c index 073c2b6..a0def64 100644 --- a/bin/sh/parser.c +++ b/bin/sh/parser.c @@ -96,9 +96,9 @@ static struct heredoc *heredoclist; /* list of here documents to read */ static int doprompt; /* if set, prompt the user */ static int needprompt; /* true if interactive and at start of line */ static int lasttoken; /* last token read */ -MKINIT int tokpushback; /* last token pushed back */ +static int tokpushback; /* last token pushed back */ static char *wordtext; /* text of last word returned by readtoken */ -MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ +static int checkkwd; static struct nodelist *backquotelist; static union node *redirnode; static struct heredoc *heredoc; @@ -108,12 +108,13 @@ static int funclinno; /* line # where the current function started */ static struct parser_temp *parser_temp; -static union node *list(int, int); +static union node *list(int); static union node *andor(void); static union node *pipeline(void); static union node *command(void); static union node *simplecmd(union node **, union node *); static union node *makename(void); +static union node *makebinary(int type, union node *n1, union node *n2); static void parsefname(void); static void parseheredoc(void); static int peektoken(void); @@ -121,6 +122,7 @@ static int readtoken(void); static int xxreadtoken(void); static int readtoken1(int, const char *, const char *, int); static int noexpand(char *); +static void consumetoken(int); static void synexpect(int) __dead2; static void synerror(const char *) __dead2; static void setprompt(int); @@ -210,6 +212,7 @@ parsecmd(int interact) heredoclist = NULL; tokpushback = 0; + checkkwd = 0; doprompt = interact; if (doprompt) setprompt(1); @@ -222,18 +225,18 @@ parsecmd(int interact) if (t == TNL) return NULL; tokpushback++; - return list(1, 1); + return list(1); } static union node * -list(int nlflag, int erflag) +list(int nlflag) { union node *ntop, *n1, *n2, *n3; int tok; checkkwd = CHKNL | CHKKWD | CHKALIAS; - if (!nlflag && !erflag && tokendlist[peektoken()]) + if (!nlflag && tokendlist[peektoken()]) return NULL; ntop = n1 = NULL; for (;;) { @@ -255,17 +258,11 @@ list(int nlflag, int erflag) if (ntop == NULL) ntop = n2; else if (n1 == NULL) { - n1 = (union node *)stalloc(sizeof (struct nbinary)); - n1->type = NSEMI; - n1->nbinary.ch1 = ntop; - n1->nbinary.ch2 = n2; + n1 = makebinary(NSEMI, ntop, n2); ntop = n1; } else { - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = NSEMI; - n3->nbinary.ch1 = n1->nbinary.ch2; - n3->nbinary.ch2 = n2; + n3 = makebinary(NSEMI, n1->nbinary.ch2, n2); n1->nbinary.ch2 = n3; n1 = n3; } @@ -286,8 +283,7 @@ list(int nlflag, int erflag) tokpushback++; } checkkwd = CHKNL | CHKKWD | CHKALIAS; - if (!nlflag && (erflag ? peektoken() == TEOF : - tokendlist[peektoken()])) + if (!nlflag && tokendlist[peektoken()]) return ntop; break; case TEOF: @@ -297,7 +293,7 @@ list(int nlflag, int erflag) pungetc(); /* push back EOF on input */ return ntop; default: - if (nlflag || erflag) + if (nlflag) synexpect(-1); tokpushback++; return ntop; @@ -310,10 +306,10 @@ list(int nlflag, int erflag) static union node * andor(void) { - union node *n1, *n2, *n3; + union node *n; int t; - n1 = pipeline(); + n = pipeline(); for (;;) { if ((t = readtoken()) == TAND) { t = NAND; @@ -321,14 +317,9 @@ andor(void) t = NOR; } else { tokpushback++; - return n1; + return n; } - n2 = pipeline(); - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = t; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; + n = makebinary(t, n, pipeline()); } } @@ -410,49 +401,39 @@ command(void) case TIF: n1 = (union node *)stalloc(sizeof (struct nif)); n1->type = NIF; - if ((n1->nif.test = list(0, 0)) == NULL) + if ((n1->nif.test = list(0)) == NULL) synexpect(-1); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n1->nif.ifpart = list(0, 0); + consumetoken(TTHEN); + n1->nif.ifpart = list(0); n2 = n1; while (readtoken() == TELIF) { n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); n2 = n2->nif.elsepart; n2->type = NIF; - if ((n2->nif.test = list(0, 0)) == NULL) + if ((n2->nif.test = list(0)) == NULL) synexpect(-1); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n2->nif.ifpart = list(0, 0); + consumetoken(TTHEN); + n2->nif.ifpart = list(0); } if (lasttoken == TELSE) - n2->nif.elsepart = list(0, 0); + n2->nif.elsepart = list(0); else { n2->nif.elsepart = NULL; tokpushback++; } - if (readtoken() != TFI) - synexpect(TFI); + consumetoken(TFI); checkkwd = CHKKWD | CHKALIAS; break; case TWHILE: - case TUNTIL: { - int got; - n1 = (union node *)stalloc(sizeof (struct nbinary)); - n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; - if ((n1->nbinary.ch1 = list(0, 0)) == NULL) + case TUNTIL: + t = lasttoken; + if ((n1 = list(0)) == NULL) synexpect(-1); - if ((got=readtoken()) != TDO) { -TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); - synexpect(TDO); - } - n1->nbinary.ch2 = list(0, 0); - if (readtoken() != TDONE) - synexpect(TDONE); + consumetoken(TDO); + n1 = makebinary((t == TWHILE)? NWHILE : NUNTIL, n1, list(0)); + consumetoken(TDONE); checkkwd = CHKKWD | CHKALIAS; break; - } case TFOR: if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) synerror("Bad for loop variable"); @@ -464,10 +445,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) { app = ≈ while (readtoken() == TWORD) { - n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; + n2 = makename(); *app = n2; app = &n2->narg.next; } @@ -499,21 +477,15 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); t = TEND; else synexpect(-1); - n1->nfor.body = list(0, 0); - if (readtoken() != t) - synexpect(t); + n1->nfor.body = list(0); + consumetoken(t); checkkwd = CHKKWD | CHKALIAS; break; case TCASE: n1 = (union node *)stalloc(sizeof (struct ncase)); n1->type = NCASE; - if (readtoken() != TWORD) - synexpect(TWORD); - n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; - n2->narg.next = NULL; + consumetoken(TWORD); + n1->ncase.expr = makename(); while (readtoken() == TNL); if (lasttoken != TWORD || ! equal(wordtext, "in")) synerror("expecting \"in\""); @@ -526,10 +498,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); if (lasttoken == TLP) readtoken(); for (;;) { - *app = ap = (union node *)stalloc(sizeof (struct narg)); - ap->type = NARG; - ap->narg.text = wordtext; - ap->narg.backquote = backquotelist; + *app = ap = makename(); checkkwd = CHKNL | CHKKWD; if (readtoken() != TPIPE) break; @@ -539,7 +508,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); ap->narg.next = NULL; if (lasttoken != TRP) synexpect(TRP); - cp->nclist.body = list(0, 0); + cp->nclist.body = list(0); checkkwd = CHKNL | CHKKWD | CHKALIAS; if ((t = readtoken()) != TESAC) { @@ -559,34 +528,31 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); case TLP: n1 = (union node *)stalloc(sizeof (struct nredir)); n1->type = NSUBSHELL; - n1->nredir.n = list(0, 0); + n1->nredir.n = list(0); n1->nredir.redirect = NULL; - if (readtoken() != TRP) - synexpect(TRP); + consumetoken(TRP); checkkwd = CHKKWD | CHKALIAS; is_subshell = 1; break; case TBEGIN: - n1 = list(0, 0); - if (readtoken() != TEND) - synexpect(TEND); + n1 = list(0); + consumetoken(TEND); checkkwd = CHKKWD | CHKALIAS; break; - /* Handle an empty command like other simple commands. */ + /* A simple command must have at least one redirection or word. */ case TBACKGND: case TSEMI: case TAND: case TOR: - /* - * An empty command before a ; doesn't make much sense, and - * should certainly be disallowed in the case of `if ;'. - */ + case TPIPE: + case TENDCASE: + case TFALLTHRU: + case TEOF: + case TNL: + case TRP: if (!redir) synexpect(-1); - case TNL: - case TEOF: case TWORD: - case TRP: tokpushback++; n1 = simplecmd(rpp, redir); return n1; @@ -644,10 +610,7 @@ simplecmd(union node **rpp, union node *redir) for (;;) { checkkwd = savecheckkwd; if (readtoken() == TWORD) { - n = (union node *)stalloc(sizeof (struct narg)); - n->type = NARG; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; + n = makename(); *app = n; app = &n->narg.next; if (savecheckkwd != 0 && !isassignment(wordtext)) @@ -659,8 +622,7 @@ simplecmd(union node **rpp, union node *redir) } else if (lasttoken == TLP && app == &args->narg.next && rpp == orig_rpp) { /* We have a function */ - if (readtoken() != TRP) - synexpect(TRP); + consumetoken(TRP); funclinno = plinno; /* * - Require plain text. @@ -708,6 +670,18 @@ makename(void) return n; } +static union node * +makebinary(int type, union node *n1, union node *n2) +{ + union node *n; + + n = (union node *)stalloc(sizeof (struct nbinary)); + n->type = type; + n->nbinary.ch1 = n1; + n->nbinary.ch2 = n2; + return (n); +} + void fixredir(union node *n, const char *text, int err) { @@ -734,8 +708,7 @@ parsefname(void) { union node *n = redirnode; - if (readtoken() != TWORD) - synexpect(-1); + consumetoken(TWORD); if (n->type == NHERE) { struct heredoc *here = heredoc; struct heredoc *p; @@ -786,11 +759,7 @@ parseheredoc(void) } readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, here->eofmark, here->striptabs); - n = (union node *)stalloc(sizeof (struct narg)); - n->narg.type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; + n = makename(); here->here->nhere.doc = n; } } @@ -1090,14 +1059,14 @@ done: doprompt = 0; } - n = list(0, oldstyle); + n = list(0); - if (oldstyle) + if (oldstyle) { + if (peektoken() != TEOF) + synexpect(-1); doprompt = saveprompt; - else { - if (readtoken() != TRP) - synexpect(TRP); - } + } else + consumetoken(TRP); (*nlpp)->n = n; if (oldstyle) { @@ -1819,14 +1788,6 @@ parsearith: { } /* end of readtoken */ - -#ifdef mkinit -RESET { - tokpushback = 0; - checkkwd = 0; -} -#endif - /* * Returns true if the text contains nothing to expand (no dollar signs * or backquotes). @@ -1888,6 +1849,14 @@ isassignment(const char *p) } +static void +consumetoken(int token) +{ + if (readtoken() != token) + synexpect(token); +} + + /* * Called when an unexpected token is read during the parse. The argument * is the token that is expected, or -1 if more than one type of token can diff --git a/bin/sh/parser.h b/bin/sh/parser.h index b803f76..d500d2f 100644 --- a/bin/sh/parser.h +++ b/bin/sh/parser.h @@ -68,11 +68,9 @@ /* * NEOF is returned by parsecmd when it encounters an end of file. It - * must be distinct from NULL, so we use the address of a variable that - * happens to be handy. + * must be distinct from NULL. */ -extern int tokpushback; -#define NEOF ((union node *)&tokpushback) +#define NEOF ((union node *)-1) extern int whichprompt; /* 1 == PS1, 2 == PS2 */ extern const char *const parsekwd[]; diff --git a/bin/sh/redir.c b/bin/sh/redir.c index fda094d2..9325545 100644 --- a/bin/sh/redir.c +++ b/bin/sh/redir.c @@ -66,14 +66,13 @@ __FBSDID("$FreeBSD$"); #define CLOSED -1 /* fd was not open before redir */ -MKINIT struct redirtab { struct redirtab *next; int renamed[10]; }; -MKINIT struct redirtab *redirlist; +static struct redirtab *redirlist; /* * We keep track of whether or not fd0 has been redirected. This is for @@ -121,7 +120,7 @@ redirect(union node *redir, int flags) if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { INTOFF; - if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { + if ((i = fcntl(fd, F_DUPFD_CLOEXEC, 10)) == -1) { switch (errno) { case EBADF: i = CLOSED; @@ -131,8 +130,7 @@ redirect(union node *redir, int flags) error("%d: %s", fd, strerror(errno)); break; } - } else - (void)fcntl(i, F_SETFD, FD_CLOEXEC); + } sv->renamed[fd] = i; INTON; } @@ -321,21 +319,6 @@ popredir(void) INTON; } -/* - * Undo all redirections. Called on error or interrupt. - */ - -#ifdef mkinit - -INCLUDE "redir.h" - -RESET { - while (redirlist) - popredir(); -} - -#endif - /* Return true if fd 0 has already been redirected at least once. */ int fd0_redirected_p(void) diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 01cb775..ea1d899 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -32,7 +32,7 @@ .\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95 .\" $FreeBSD$ .\" -.Dd March 24, 2013 +.Dd June 14, 2013 .Dt SH 1 .Os .Sh NAME @@ -1036,6 +1036,9 @@ The current working directory as set by The file creation mask as set by .Ic umask . .It +Resource limits as set by +.Ic ulimit . +.It References to open files. .It Traps as set by @@ -1142,8 +1145,10 @@ command is .Pp .D1 Ic return Op Ar exitstatus .Pp -It terminates the current executional scope, returning from the previous -nested function, sourced script, or shell instance, in that order. +It terminates the current executional scope, returning from the closest +nested function or sourced script; +if no function or sourced script is being executed, +it exits the shell instance. The .Ic return command is implemented as a special built-in command. @@ -1340,9 +1345,33 @@ The primary prompt string, which defaults to .Dq Li "$ " , unless you are the superuser, in which case it defaults to .Dq Li "# " . +.Va PS1 +may include any of the following formatting sequences, +which are replaced by the given information: +.Bl -tag -width indent +.It Li \eH +The local hostname. +.It Li \eh +The fully-qualified hostname. +.It Li \eW +The final component of the current working directory. +.It Li \ew +The entire path of the current working directory. +.It Li \e$ +Superuser status. +.Dq Li "$ " +for normal users and +.Dq Li "# " +for superusers. +.It Li \e\e +A literal backslash. +.El .It Va PS2 The secondary prompt string, which defaults to .Dq Li "> " . +.Va PS2 +may include any of the formatting sequences from +.Va PS1 . .It Va PS4 The prefix for the trace output (if .Fl x @@ -2348,7 +2377,9 @@ option is specified and the elapses before a complete line of input is supplied, the .Ic read -command will return an exit status of 1 without assigning any values. +command will return an exit status as if terminated by +.Dv SIGALRM +without assigning any values. The .Ar timeout value may optionally be followed by one of @@ -2364,6 +2395,11 @@ is assumed. The .Fl e option exists only for backward compatibility with older scripts. +.Pp +The exit status is 0 on success, 1 on end of file, +between 2 and 128 if an error occurs +and greater than 128 if a trapped signal interrupts +.Ic read . .It Ic readonly Oo Fl p Oc Op Ar name ... Each specified .Ar name @@ -2611,12 +2647,17 @@ If the option is specified, the .Ar name arguments are treated as function names. -.It Ic wait Op Ar job -Wait for the specified +.It Ic wait Op Ar job ... +Wait for each specified .Ar job to complete and return the exit status of the last process in the +last specified .Ar job . -If the argument is omitted, wait for all jobs to complete +If any +.Ar job +specified is unknown to the shell, it is treated as if it +were a known job that exited with exit status 127. +If no operands are given, wait for all jobs to complete and return an exit status of zero. .El .Ss Commandline Editing diff --git a/bin/sh/shell.h b/bin/sh/shell.h index 5f6d0ac..679efc7 100644 --- a/bin/sh/shell.h +++ b/bin/sh/shell.h @@ -63,7 +63,6 @@ typedef intmax_t arith_t; #define ARITH_MAX INTMAX_MAX typedef void *pointer; -#define MKINIT /* empty */ #include <sys/cdefs.h> diff --git a/bin/sh/trap.c b/bin/sh/trap.c index 3138029..3fc8566 100644 --- a/bin/sh/trap.c +++ b/bin/sh/trap.c @@ -72,8 +72,9 @@ __FBSDID("$FreeBSD$"); #define S_RESET 5 /* temporary - to reset a hard ignored sig */ -MKINIT char sigmode[NSIG]; /* current value of signal */ +static char sigmode[NSIG]; /* current value of signal */ volatile sig_atomic_t pendingsig; /* indicates some signal received */ +volatile sig_atomic_t pendingsig_waitcmd; /* indicates SIGINT/SIGQUIT received */ int in_dotrap; /* do we execute in a trap handler? */ static char *volatile trap[NSIG]; /* trap handler commands */ static volatile sig_atomic_t gotsig[NSIG]; @@ -389,23 +390,13 @@ onsig(int signo) } /* If we are currently in a wait builtin, prepare to break it */ - if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) { - breakwaitcmd = 1; - pendingsig = signo; - } + if (signo == SIGINT || signo == SIGQUIT) + pendingsig_waitcmd = signo; if (trap[signo] != NULL && trap[signo][0] != '\0' && (signo != SIGCHLD || !ignore_sigchld)) { gotsig[signo] = 1; pendingsig = signo; - - /* - * If a trap is set, not ignored and not the null command, we - * need to make sure traps are executed even when a child - * blocks signals. - */ - if (Tflag && !(trap[signo][0] == ':' && trap[signo][1] == '\0')) - breakwaitcmd = 1; } #ifndef NO_HISTORY @@ -428,6 +419,7 @@ dotrap(void) in_dotrap++; for (;;) { pendingsig = 0; + pendingsig_waitcmd = 0; for (i = 1; i < NSIG; i++) { if (gotsig[i]) { gotsig[i] = 0; diff --git a/bin/sh/trap.h b/bin/sh/trap.h index 0a05d8d..a962251 100644 --- a/bin/sh/trap.h +++ b/bin/sh/trap.h @@ -34,6 +34,7 @@ */ extern volatile sig_atomic_t pendingsig; +extern volatile sig_atomic_t pendingsig_waitcmd; extern int in_dotrap; extern volatile sig_atomic_t gotwinch; diff --git a/bin/sh/var.c b/bin/sh/var.c index 3f29a48..c20d032 100644 --- a/bin/sh/var.c +++ b/bin/sh/var.c @@ -710,6 +710,7 @@ localcmd(int argc __unused, char **argv __unused) { char *name; + nextopt(""); if (! in_function()) error("Not in a function"); while ((name = *argptr++) != NULL) { @@ -877,7 +878,7 @@ unsetvar(const char *s) /* - * Returns true if the two strings specify the same varable. The first + * Returns true if the two strings specify the same variable. The first * variable name is terminated by '='; the second may be terminated by * either '=' or '\0'. */ @@ -898,7 +899,7 @@ varequal(const char *p, const char *q) * Search for a variable. * 'name' may be terminated by '=' or a NUL. * vppp is set to the pointer to vp, or the list head if vp isn't found - * lenp is set to the number of charactets in 'name' + * lenp is set to the number of characters in 'name' */ static struct var * diff --git a/bin/sleep/sleep.c b/bin/sleep/sleep.c index fa7deb2..ca08272 100644 --- a/bin/sleep/sleep.c +++ b/bin/sleep/sleep.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <err.h> +#include <errno.h> #include <limits.h> #include <signal.h> #include <stdint.h> @@ -81,14 +82,20 @@ main(int argc, char *argv[]) time_to_sleep.tv_nsec = 1e9 * (d - time_to_sleep.tv_sec); signal(SIGINFO, report_request); + + /* + * Note: [EINTR] is supposed to happen only when a signal was handled + * but the kernel also returns it when a ptrace-based debugger + * attaches. This is a bug but it is hard to fix. + */ while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) { if (report_requested) { /* Reporting does not bother with nanoseconds. */ warnx("about %d second(s) left out of the original %d", (int)time_to_sleep.tv_sec, (int)original); report_requested = 0; - } else - break; + } else if (errno != EINTR) + err(1, "nanosleep"); } return (0); } diff --git a/bin/test/test.1 b/bin/test/test.1 index 76a4a9c..136ee57 100644 --- a/bin/test/test.1 +++ b/bin/test/test.1 @@ -32,7 +32,7 @@ .\" @(#)test.1 8.1 (Berkeley) 5/31/93 .\" $FreeBSD$ .\" -.Dd December 27, 2012 +.Dd June 1, 2013 .Dt TEST 1 .Os .Sh NAME @@ -169,65 +169,15 @@ True if .Ar file exists and is a socket. .It Ar file1 Fl nt Ar file2 -True if both -.Ar file1 -and -.Ar file2 -exist and -.Ar file1 -is newer than -.Ar file2 . -.It Ar file1 Fl nt Ns Ar X Ns Ar Y Ar file2 -True if both -.Ar file1 -and -.Ar file2 -exist and +True if .Ar file1 -has a more recent last access time -.Pq Ar X Ns = Ns Cm a , -inode creation time -.Pq Ar X Ns = Ns Cm b , -change time -.Pq Ar X Ns = Ns Cm c , -or modification time -.Pq Ar X Ns = Ns Cm m -than the last access time -.Pq Ar Y Ns = Ns Cm a , -inode creation time -.Pq Ar Y Ns = Ns Cm b , -change time -.Pq Ar Y Ns = Ns Cm c , -or modification time -.Pq Ar Y Ns = Ns Cm m -of +exists and is newer than .Ar file2 . -Note that -.Ic -ntmm -is equivalent to -.Ic -nt . .It Ar file1 Fl ot Ar file2 -True if both -.Ar file1 -and -.Ar file2 -exist and +True if .Ar file1 -is older than +exists and is older than .Ar file2 . -Note that -.Ar file1 -.Ic -ot -.Ar file2 -is equivalent to -.Ar file2 -.Ic -nt -.Ar file1 -.It Ar file1 Fl ot Ns Ar X Ns Ar Y Ar file2 -Equivalent to -.Ar file2 -.Ic -nt Ns Ar Y Ns Ar X -.Ar file1 . .It Ar file1 Fl ef Ar file2 True if .Ar file1 @@ -381,6 +331,20 @@ missing. .It >1 An error occurred. .El +.Sh EXAMPLES +Implement +.Li test FILE1 -nt FILE2 +using only +.Tn POSIX +functionality: +.Pp +.Dl test -n \&"$(find -L -- FILE1 -prune -newer FILE2 2>/dev/null)\&" +.Pp +This can be modified using non-standard +.Xr find 1 +primaries like +.Cm -newerca +to compare other timestamps. .Sh COMPATIBILITY For compatibility with some other implementations, the @@ -391,7 +355,9 @@ with the same meaning. .Sh SEE ALSO .Xr builtin 1 , .Xr expr 1 , +.Xr find 1 , .Xr sh 1 , +.Xr stat 1 , .Xr symlink 7 .Sh STANDARDS The @@ -399,6 +365,17 @@ The utility implements a superset of the .St -p1003.2 specification. +The primaries +.Cm < , +.Cm == , +.Cm > , +.Fl ef , +.Fl nt , +.Fl ot , +.Fl G , +and +.Fl O +are extensions. .Sh BUGS Both sides are always evaluated in .Fl a diff --git a/bin/test/test.c b/bin/test/test.c index eaa2f40..96aa9f5 100644 --- a/bin/test/test.c +++ b/bin/test/test.c @@ -63,7 +63,7 @@ error(const char *msg, ...) "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| - "-nt"|"-nt[abcm][abcm]"|"-ot"|"-ot[abcm][abcm])"|"-ef"; + "-nt"|"-ot"|"-ef"; operand ::= <any legal UNIX file name> */ @@ -85,38 +85,8 @@ enum token { FILSUID, FILSGID, FILSTCK, - FILNTAA, - FILNTAB, - FILNTAC, - FILNTAM, - FILNTBA, - FILNTBB, - FILNTBC, - FILNTBM, - FILNTCA, - FILNTCB, - FILNTCC, - FILNTCM, - FILNTMA, - FILNTMB, - FILNTMC, - FILNTMM, - FILOTAA, - FILOTAB, - FILOTAC, - FILOTAM, - FILOTBA, - FILOTBB, - FILOTBC, - FILOTBM, - FILOTCA, - FILOTCB, - FILOTCC, - FILOTCM, - FILOTMA, - FILOTMB, - FILOTMC, - FILOTMM, + FILNT, + FILOT, FILEQ, FILUID, FILGID, @@ -148,16 +118,9 @@ enum token_types { PAREN }; -enum time_types { - ATIME, - BTIME, - CTIME, - MTIME -}; - static struct t_op { - char op_text[6]; - char op_num, op_type; + char op_text[4]; + short op_num, op_type; } const ops [] = { {"-r", FILRD, UNOP}, {"-w", FILWR, UNOP}, @@ -191,40 +154,8 @@ static struct t_op { {"-gt", INTGT, BINOP}, {"-le", INTLE, BINOP}, {"-lt", INTLT, BINOP}, - {"-nt", FILNTMM, BINOP}, - {"-ntaa", FILNTAA, BINOP}, - {"-ntab", FILNTAB, BINOP}, - {"-ntac", FILNTAC, BINOP}, - {"-ntam", FILNTAM, BINOP}, - {"-ntba", FILNTBA, BINOP}, - {"-ntbb", FILNTBB, BINOP}, - {"-ntbc", FILNTBC, BINOP}, - {"-ntbm", FILNTBM, BINOP}, - {"-ntca", FILNTCA, BINOP}, - {"-ntcb", FILNTCB, BINOP}, - {"-ntcc", FILNTCC, BINOP}, - {"-ntcm", FILNTCM, BINOP}, - {"-ntma", FILNTMA, BINOP}, - {"-ntmb", FILNTMB, BINOP}, - {"-ntmc", FILNTMC, BINOP}, - {"-ntmm", FILNTMM, BINOP}, - {"-ot", FILOTMM, BINOP}, - {"-otaa", FILOTAA, BINOP}, - {"-otab", FILOTBB, BINOP}, - {"-otac", FILOTAC, BINOP}, - {"-otam", FILOTAM, BINOP}, - {"-otba", FILOTBA, BINOP}, - {"-otbb", FILOTBB, BINOP}, - {"-otbc", FILOTBC, BINOP}, - {"-otbm", FILOTBM, BINOP}, - {"-otca", FILOTCA, BINOP}, - {"-otcb", FILOTCB, BINOP}, - {"-otcc", FILOTCC, BINOP}, - {"-otcm", FILOTCM, BINOP}, - {"-otma", FILOTMA, BINOP}, - {"-otmb", FILOTMB, BINOP}, - {"-otmc", FILOTMC, BINOP}, - {"-otmm", FILOTMM, BINOP}, + {"-nt", FILNT, BINOP}, + {"-ot", FILOT, BINOP}, {"-ef", FILEQ, BINOP}, {"!", UNOT, BUNOP}, {"-a", BAND, BBINOP}, @@ -249,10 +180,10 @@ static int intcmp(const char *, const char *); static int isunopoperand(void); static int islparenoperand(void); static int isrparenoperand(void); -static int newerf(const char *, const char *, enum time_types, - enum time_types); +static int newerf(const char *, const char *); static int nexpr(enum token); static int oexpr(enum token); +static int olderf(const char *, const char *); static int primary(enum token); static void syntax(const char *, const char *); static enum token t_lex(char *); @@ -422,70 +353,10 @@ binop(void) return intcmp(opnd1, opnd2) <= 0; case INTLT: return intcmp(opnd1, opnd2) < 0; - case FILNTAA: - return newerf(opnd1, opnd2, ATIME, ATIME); - case FILNTAB: - return newerf(opnd1, opnd2, ATIME, BTIME); - case FILNTAC: - return newerf(opnd1, opnd2, ATIME, CTIME); - case FILNTAM: - return newerf(opnd1, opnd2, ATIME, MTIME); - case FILNTBA: - return newerf(opnd1, opnd2, BTIME, ATIME); - case FILNTBB: - return newerf(opnd1, opnd2, BTIME, BTIME); - case FILNTBC: - return newerf(opnd1, opnd2, BTIME, CTIME); - case FILNTBM: - return newerf(opnd1, opnd2, BTIME, MTIME); - case FILNTCA: - return newerf(opnd1, opnd2, CTIME, ATIME); - case FILNTCB: - return newerf(opnd1, opnd2, CTIME, BTIME); - case FILNTCC: - return newerf(opnd1, opnd2, CTIME, CTIME); - case FILNTCM: - return newerf(opnd1, opnd2, CTIME, MTIME); - case FILNTMA: - return newerf(opnd1, opnd2, MTIME, ATIME); - case FILNTMB: - return newerf(opnd1, opnd2, MTIME, BTIME); - case FILNTMC: - return newerf(opnd1, opnd2, MTIME, CTIME); - case FILNTMM: - return newerf(opnd1, opnd2, MTIME, MTIME); - case FILOTAA: - return newerf(opnd2, opnd1, ATIME, ATIME); - case FILOTAB: - return newerf(opnd2, opnd1, BTIME, ATIME); - case FILOTAC: - return newerf(opnd2, opnd1, CTIME, ATIME); - case FILOTAM: - return newerf(opnd2, opnd1, MTIME, ATIME); - case FILOTBA: - return newerf(opnd2, opnd1, ATIME, BTIME); - case FILOTBB: - return newerf(opnd2, opnd1, BTIME, BTIME); - case FILOTBC: - return newerf(opnd2, opnd1, CTIME, BTIME); - case FILOTBM: - return newerf(opnd2, opnd1, MTIME, BTIME); - case FILOTCA: - return newerf(opnd2, opnd1, ATIME, CTIME); - case FILOTCB: - return newerf(opnd2, opnd1, BTIME, CTIME); - case FILOTCC: - return newerf(opnd2, opnd1, CTIME, CTIME); - case FILOTCM: - return newerf(opnd2, opnd1, MTIME, CTIME); - case FILOTMA: - return newerf(opnd2, opnd1, ATIME, MTIME); - case FILOTMB: - return newerf(opnd2, opnd1, BTIME, MTIME); - case FILOTMC: - return newerf(opnd2, opnd1, CTIME, MTIME); - case FILOTMM: - return newerf(opnd2, opnd1, MTIME, MTIME); + case FILNT: + return newerf (opnd1, opnd2); + case FILOT: + return olderf (opnd1, opnd2); case FILEQ: return equalf (opnd1, opnd2); default: @@ -699,34 +570,25 @@ intcmp (const char *s1, const char *s2) } static int -newerf (const char *f1, const char *f2, enum time_types t1, enum time_types t2) +newerf (const char *f1, const char *f2) { struct stat b1, b2; - struct timespec *ts1, *ts2; if (stat(f1, &b1) != 0 || stat(f2, &b2) != 0) return 0; - switch (t1) { - case ATIME: ts1 = &b1.st_atim; break; - case BTIME: ts1 = &b1.st_birthtim; break; - case CTIME: ts1 = &b1.st_ctim; break; - default: ts1 = &b1.st_mtim; break; - } - - switch (t2) { - case ATIME: ts2 = &b2.st_atim; break; - case BTIME: ts2 = &b2.st_birthtim; break; - case CTIME: ts2 = &b2.st_ctim; break; - default: ts2 = &b2.st_mtim; break; - } - - if (ts1->tv_sec > ts2->tv_sec) + if (b1.st_mtim.tv_sec > b2.st_mtim.tv_sec) return 1; - if (ts1->tv_sec < ts2->tv_sec) + if (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec) return 0; - return (ts1->tv_nsec > ts2->tv_nsec); + return (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec); +} + +static int +olderf (const char *f1, const char *f2) +{ + return (newerf(f2, f1)); } static int |