1 diff -urN netbsd-sh/bltin/test.c ash-0.3.7.orig/bltin/test.c
2 --- netbsd-sh/bltin/test.c Thu Jan 1 01:00:00 1970
3 +++ ash-0.3.7.orig/bltin/test.c Mon Apr 23 22:16:46 2001
5 +/* $NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $ */
8 + * test(1); version 7-like -- author Erik Baalbergen
9 + * modified by Eric Gisin to be used as built-in.
10 + * modified by Arnold Robbins to add SVR3 compatibility
11 + * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
12 + * modified by J.T. Conklin for NetBSD.
14 + * This program is in the Public Domain.
17 +#include <sys/cdefs.h>
19 +__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $");
22 +#include <sys/types.h>
23 +#include <sys/stat.h>
37 +/* test(1) accepts the following grammar:
38 + oexpr ::= aexpr | aexpr "-o" oexpr ;
39 + aexpr ::= nexpr | nexpr "-a" aexpr ;
40 + nexpr ::= primary | "!" primary
41 + primary ::= unary-operator operand
42 + | operand binary-operator operand
46 + unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
47 + "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
49 + binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
51 + operand ::= <any legal UNIX file name>
105 +static struct t_op {
106 + const char *op_text;
107 + short op_num, op_type;
109 + {"-r", FILRD, UNOP},
110 + {"-w", FILWR, UNOP},
111 + {"-x", FILEX, UNOP},
112 + {"-e", FILEXIST,UNOP},
113 + {"-f", FILREG, UNOP},
114 + {"-d", FILDIR, UNOP},
115 + {"-c", FILCDEV,UNOP},
116 + {"-b", FILBDEV,UNOP},
117 + {"-p", FILFIFO,UNOP},
118 + {"-u", FILSUID,UNOP},
119 + {"-g", FILSGID,UNOP},
120 + {"-k", FILSTCK,UNOP},
121 + {"-s", FILGZ, UNOP},
122 + {"-t", FILTT, UNOP},
123 + {"-z", STREZ, UNOP},
124 + {"-n", STRNZ, UNOP},
125 + {"-h", FILSYM, UNOP}, /* for backwards compat */
126 + {"-O", FILUID, UNOP},
127 + {"-G", FILGID, UNOP},
128 + {"-L", FILSYM, UNOP},
129 + {"-S", FILSOCK,UNOP},
130 + {"=", STREQ, BINOP},
131 + {"!=", STRNE, BINOP},
132 + {"<", STRLT, BINOP},
133 + {">", STRGT, BINOP},
134 + {"-eq", INTEQ, BINOP},
135 + {"-ne", INTNE, BINOP},
136 + {"-ge", INTGE, BINOP},
137 + {"-gt", INTGT, BINOP},
138 + {"-le", INTLE, BINOP},
139 + {"-lt", INTLT, BINOP},
140 + {"-nt", FILNT, BINOP},
141 + {"-ot", FILOT, BINOP},
142 + {"-ef", FILEQ, BINOP},
143 + {"!", UNOT, BUNOP},
144 + {"-a", BAND, BBINOP},
145 + {"-o", BOR, BBINOP},
146 + {"(", LPAREN, PAREN},
147 + {")", RPAREN, PAREN},
152 +static struct t_op const *t_wp_op;
153 +static gid_t *group_array = NULL;
156 +static void syntax __P((const char *, const char *));
157 +static int oexpr __P((enum token));
158 +static int aexpr __P((enum token));
159 +static int nexpr __P((enum token));
160 +static int primary __P((enum token));
161 +static int binop __P((void));
162 +static int filstat __P((char *, enum token));
163 +static enum token t_lex __P((char *));
164 +static int isoperand __P((void));
165 +static int getn __P((const char *));
166 +static int newerf __P((const char *, const char *));
167 +static int olderf __P((const char *, const char *));
168 +static int equalf __P((const char *, const char *));
169 +static int test_eaccess();
170 +static int bash_group_member();
171 +static void initialize_group_array();
174 +extern void error __P((const char *, ...)) __attribute__((__noreturn__));
176 +static void error __P((const char *, ...)) __attribute__((__noreturn__));
180 +error(const char *msg, ...)
191 + msg = va_arg(ap, const char *);
202 +int testcmd __P((int, char **));
209 +int main __P((int, char **));
220 + if (strcmp(argv[0], "[") == 0) {
221 + if (strcmp(argv[--argc], "]"))
222 + error("missing ]");
230 + res = !oexpr(t_lex(*t_wp));
232 + if (*t_wp != NULL && *++t_wp != NULL)
233 + syntax(*t_wp, "unexpected operator");
244 + error("%s: %s", op, msg);
256 + if (t_lex(*++t_wp) == BOR)
257 + return oexpr(t_lex(*++t_wp)) || res;
269 + if (t_lex(*++t_wp) == BAND)
270 + return aexpr(t_lex(*++t_wp)) && res;
277 + enum token n; /* token */
280 + return !nexpr(t_lex(*++t_wp));
292 + return 0; /* missing expression */
294 + if ((nn = t_lex(*++t_wp)) == RPAREN)
295 + return 0; /* missing expression */
297 + if (t_lex(*++t_wp) != RPAREN)
298 + syntax(NULL, "closing paren expected");
301 + if (t_wp_op && t_wp_op->op_type == UNOP) {
302 + /* unary expression */
303 + if (*++t_wp == NULL)
304 + syntax(t_wp_op->op_text, "argument expected");
307 + return strlen(*t_wp) == 0;
309 + return strlen(*t_wp) != 0;
311 + return isatty(getn(*t_wp));
313 + return filstat(*t_wp, n);
317 + if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
321 + return strlen(*t_wp) > 0;
327 + const char *opnd1, *opnd2;
328 + struct t_op const *op;
331 + (void) t_lex(*++t_wp);
334 + if ((opnd2 = *++t_wp) == (char *)0)
335 + syntax(op->op_text, "argument expected");
337 + switch (op->op_num) {
339 + return strcmp(opnd1, opnd2) == 0;
341 + return strcmp(opnd1, opnd2) != 0;
343 + return strcmp(opnd1, opnd2) < 0;
345 + return strcmp(opnd1, opnd2) > 0;
347 + return getn(opnd1) == getn(opnd2);
349 + return getn(opnd1) != getn(opnd2);
351 + return getn(opnd1) >= getn(opnd2);
353 + return getn(opnd1) > getn(opnd2);
355 + return getn(opnd1) <= getn(opnd2);
357 + return getn(opnd1) < getn(opnd2);
359 + return newerf (opnd1, opnd2);
361 + return olderf (opnd1, opnd2);
363 + return equalf (opnd1, opnd2);
377 + if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
382 + return test_eaccess(nm, R_OK) == 0;
384 + return test_eaccess(nm, W_OK) == 0;
386 + return test_eaccess(nm, X_OK) == 0;
390 + return S_ISREG(s.st_mode);
392 + return S_ISDIR(s.st_mode);
394 + return S_ISCHR(s.st_mode);
396 + return S_ISBLK(s.st_mode);
398 + return S_ISFIFO(s.st_mode);
400 + return S_ISSOCK(s.st_mode);
402 + return S_ISLNK(s.st_mode);
404 + return (s.st_mode & S_ISUID) != 0;
406 + return (s.st_mode & S_ISGID) != 0;
408 + return (s.st_mode & S_ISVTX) != 0;
410 + return s.st_size > (off_t)0;
412 + return s.st_uid == geteuid();
414 + return s.st_gid == getegid();
424 + struct t_op const *op = ops;
427 + t_wp_op = (struct t_op *)0;
430 + while (op->op_text) {
431 + if (strcmp(s, op->op_text) == 0) {
432 + if ((op->op_type == UNOP && isoperand()) ||
433 + (op->op_num == LPAREN && *(t_wp+1) == 0))
440 + t_wp_op = (struct t_op *)0;
447 + struct t_op const *op = ops;
451 + if ((s = *(t_wp+1)) == 0)
453 + if ((t = *(t_wp+2)) == 0)
455 + while (op->op_text) {
456 + if (strcmp(s, op->op_text) == 0)
457 + return op->op_type == BINOP &&
458 + (t[0] != ')' || t[1] != '\0');
464 +/* atoi with error detection */
473 + r = strtol(s, &p, 10);
476 + error("%s: out of range", s);
478 + while (isspace((unsigned char)*p))
482 + error("%s: bad number", s);
489 +const char *f1, *f2;
491 + struct stat b1, b2;
493 + return (stat (f1, &b1) == 0 &&
494 + stat (f2, &b2) == 0 &&
495 + b1.st_mtime > b2.st_mtime);
500 +const char *f1, *f2;
502 + struct stat b1, b2;
504 + return (stat (f1, &b1) == 0 &&
505 + stat (f2, &b2) == 0 &&
506 + b1.st_mtime < b2.st_mtime);
511 +const char *f1, *f2;
513 + struct stat b1, b2;
515 + return (stat (f1, &b1) == 0 &&
516 + stat (f2, &b2) == 0 &&
517 + b1.st_dev == b2.st_dev &&
518 + b1.st_ino == b2.st_ino);
521 +/* Do the same thing access(2) does, but use the effective uid and gid,
522 + and don't make the mistake of telling root that any file is
525 +test_eaccess (path, mode)
530 + int euid = geteuid();
532 + if (stat (path, &st) < 0)
536 + /* Root can read or write any file. */
540 + /* Root can execute any file that has any one of the execute
542 + if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
546 + if (st.st_uid == euid) /* owner */
548 + else if (bash_group_member (st.st_gid))
551 + if (st.st_mode & mode)
558 +initialize_group_array ()
560 + ngroups = getgroups(0, NULL);
561 + group_array = malloc(ngroups * sizeof(gid_t));
563 + error(strerror(ENOMEM));
564 + getgroups(ngroups, group_array);
567 +/* Return non-zero if GID is one that we have in our groups list. */
569 +bash_group_member (gid)
574 + /* Short-circuit if possible, maybe saving a call to getgroups(). */
575 + if (gid == getgid() || gid == getegid())
579 + initialize_group_array ();
581 + /* Search through the list looking for GID. */
582 + for (i = 0; i < ngroups; i++)
583 + if (gid == group_array[i])