summaryrefslogtreecommitdiffstats
path: root/source/ap/ash/patches/ash-test.patch
diff options
context:
space:
mode:
Diffstat (limited to 'source/ap/ash/patches/ash-test.patch')
-rw-r--r--source/ap/ash/patches/ash-test.patch588
1 files changed, 588 insertions, 0 deletions
diff --git a/source/ap/ash/patches/ash-test.patch b/source/ap/ash/patches/ash-test.patch
new file mode 100644
index 000000000..14c9f6802
--- /dev/null
+++ b/source/ap/ash/patches/ash-test.patch
@@ -0,0 +1,588 @@
+diff -urN netbsd-sh/bltin/test.c ash-0.3.7.orig/bltin/test.c
+--- netbsd-sh/bltin/test.c Thu Jan 1 01:00:00 1970
++++ ash-0.3.7.orig/bltin/test.c Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,583 @@
++/* $NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $ */
++
++/*
++ * test(1); version 7-like -- author Erik Baalbergen
++ * modified by Eric Gisin to be used as built-in.
++ * modified by Arnold Robbins to add SVR3 compatibility
++ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
++ * modified by J.T. Conklin for NetBSD.
++ *
++ * This program is in the Public Domain.
++ */
++
++#include <sys/cdefs.h>
++#ifndef lint
++__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $");
++#endif
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <ctype.h>
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <err.h>
++#ifdef __STDC__
++#include <stdarg.h>
++#else
++#include <varargs.h>
++#endif
++
++/* test(1) accepts the following grammar:
++ oexpr ::= aexpr | aexpr "-o" oexpr ;
++ aexpr ::= nexpr | nexpr "-a" aexpr ;
++ nexpr ::= primary | "!" primary
++ primary ::= unary-operator operand
++ | operand binary-operator operand
++ | operand
++ | "(" oexpr ")"
++ ;
++ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
++ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
++
++ binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
++ "-nt"|"-ot"|"-ef";
++ operand ::= <any legal UNIX file name>
++*/
++
++enum token {
++ EOI,
++ FILRD,
++ FILWR,
++ FILEX,
++ FILEXIST,
++ FILREG,
++ FILDIR,
++ FILCDEV,
++ FILBDEV,
++ FILFIFO,
++ FILSOCK,
++ FILSYM,
++ FILGZ,
++ FILTT,
++ FILSUID,
++ FILSGID,
++ FILSTCK,
++ FILNT,
++ FILOT,
++ FILEQ,
++ FILUID,
++ FILGID,
++ STREZ,
++ STRNZ,
++ STREQ,
++ STRNE,
++ STRLT,
++ STRGT,
++ INTEQ,
++ INTNE,
++ INTGE,
++ INTGT,
++ INTLE,
++ INTLT,
++ UNOT,
++ BAND,
++ BOR,
++ LPAREN,
++ RPAREN,
++ OPERAND
++};
++
++enum token_types {
++ UNOP,
++ BINOP,
++ BUNOP,
++ BBINOP,
++ PAREN
++};
++
++static struct t_op {
++ const char *op_text;
++ short op_num, op_type;
++} const ops [] = {
++ {"-r", FILRD, UNOP},
++ {"-w", FILWR, UNOP},
++ {"-x", FILEX, UNOP},
++ {"-e", FILEXIST,UNOP},
++ {"-f", FILREG, UNOP},
++ {"-d", FILDIR, UNOP},
++ {"-c", FILCDEV,UNOP},
++ {"-b", FILBDEV,UNOP},
++ {"-p", FILFIFO,UNOP},
++ {"-u", FILSUID,UNOP},
++ {"-g", FILSGID,UNOP},
++ {"-k", FILSTCK,UNOP},
++ {"-s", FILGZ, UNOP},
++ {"-t", FILTT, UNOP},
++ {"-z", STREZ, UNOP},
++ {"-n", STRNZ, UNOP},
++ {"-h", FILSYM, UNOP}, /* for backwards compat */
++ {"-O", FILUID, UNOP},
++ {"-G", FILGID, UNOP},
++ {"-L", FILSYM, UNOP},
++ {"-S", FILSOCK,UNOP},
++ {"=", STREQ, BINOP},
++ {"!=", STRNE, BINOP},
++ {"<", STRLT, BINOP},
++ {">", STRGT, BINOP},
++ {"-eq", INTEQ, BINOP},
++ {"-ne", INTNE, BINOP},
++ {"-ge", INTGE, BINOP},
++ {"-gt", INTGT, BINOP},
++ {"-le", INTLE, BINOP},
++ {"-lt", INTLT, BINOP},
++ {"-nt", FILNT, BINOP},
++ {"-ot", FILOT, BINOP},
++ {"-ef", FILEQ, BINOP},
++ {"!", UNOT, BUNOP},
++ {"-a", BAND, BBINOP},
++ {"-o", BOR, BBINOP},
++ {"(", LPAREN, PAREN},
++ {")", RPAREN, PAREN},
++ {0, 0, 0}
++};
++
++static char **t_wp;
++static struct t_op const *t_wp_op;
++static gid_t *group_array = NULL;
++static int ngroups;
++
++static void syntax __P((const char *, const char *));
++static int oexpr __P((enum token));
++static int aexpr __P((enum token));
++static int nexpr __P((enum token));
++static int primary __P((enum token));
++static int binop __P((void));
++static int filstat __P((char *, enum token));
++static enum token t_lex __P((char *));
++static int isoperand __P((void));
++static int getn __P((const char *));
++static int newerf __P((const char *, const char *));
++static int olderf __P((const char *, const char *));
++static int equalf __P((const char *, const char *));
++static int test_eaccess();
++static int bash_group_member();
++static void initialize_group_array();
++
++#if defined(SHELL)
++extern void error __P((const char *, ...)) __attribute__((__noreturn__));
++#else
++static void error __P((const char *, ...)) __attribute__((__noreturn__));
++
++static void
++#ifdef __STDC__
++error(const char *msg, ...)
++#else
++error(va_alist)
++ va_dcl
++#endif
++{
++ va_list ap;
++#ifndef __STDC__
++ const char *msg;
++
++ va_start(ap);
++ msg = va_arg(ap, const char *);
++#else
++ va_start(ap, msg);
++#endif
++ verrx(2, msg, ap);
++ /*NOTREACHED*/
++ va_end(ap);
++}
++#endif
++
++#ifdef SHELL
++int testcmd __P((int, char **));
++
++int
++testcmd(argc, argv)
++ int argc;
++ char **argv;
++#else
++int main __P((int, char **));
++
++int
++main(argc, argv)
++ int argc;
++ char **argv;
++#endif
++{
++ int res;
++
++
++ if (strcmp(argv[0], "[") == 0) {
++ if (strcmp(argv[--argc], "]"))
++ error("missing ]");
++ argv[argc] = NULL;
++ }
++
++ if (argc < 2)
++ return 1;
++
++ t_wp = &argv[1];
++ res = !oexpr(t_lex(*t_wp));
++
++ if (*t_wp != NULL && *++t_wp != NULL)
++ syntax(*t_wp, "unexpected operator");
++
++ return res;
++}
++
++static void
++syntax(op, msg)
++ const char *op;
++ const char *msg;
++{
++ if (op && *op)
++ error("%s: %s", op, msg);
++ else
++ error("%s", msg);
++}
++
++static int
++oexpr(n)
++ enum token n;
++{
++ int res;
++
++ res = aexpr(n);
++ if (t_lex(*++t_wp) == BOR)
++ return oexpr(t_lex(*++t_wp)) || res;
++ t_wp--;
++ return res;
++}
++
++static int
++aexpr(n)
++ enum token n;
++{
++ int res;
++
++ res = nexpr(n);
++ if (t_lex(*++t_wp) == BAND)
++ return aexpr(t_lex(*++t_wp)) && res;
++ t_wp--;
++ return res;
++}
++
++static int
++nexpr(n)
++ enum token n; /* token */
++{
++ if (n == UNOT)
++ return !nexpr(t_lex(*++t_wp));
++ return primary(n);
++}
++
++static int
++primary(n)
++ enum token n;
++{
++ enum token nn;
++ int res;
++
++ if (n == EOI)
++ return 0; /* missing expression */
++ if (n == LPAREN) {
++ if ((nn = t_lex(*++t_wp)) == RPAREN)
++ return 0; /* missing expression */
++ res = oexpr(nn);
++ if (t_lex(*++t_wp) != RPAREN)
++ syntax(NULL, "closing paren expected");
++ return res;
++ }
++ if (t_wp_op && t_wp_op->op_type == UNOP) {
++ /* unary expression */
++ if (*++t_wp == NULL)
++ syntax(t_wp_op->op_text, "argument expected");
++ switch (n) {
++ case STREZ:
++ return strlen(*t_wp) == 0;
++ case STRNZ:
++ return strlen(*t_wp) != 0;
++ case FILTT:
++ return isatty(getn(*t_wp));
++ default:
++ return filstat(*t_wp, n);
++ }
++ }
++
++ if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
++ return binop();
++ }
++
++ return strlen(*t_wp) > 0;
++}
++
++static int
++binop()
++{
++ const char *opnd1, *opnd2;
++ struct t_op const *op;
++
++ opnd1 = *t_wp;
++ (void) t_lex(*++t_wp);
++ op = t_wp_op;
++
++ if ((opnd2 = *++t_wp) == (char *)0)
++ syntax(op->op_text, "argument expected");
++
++ switch (op->op_num) {
++ case STREQ:
++ return strcmp(opnd1, opnd2) == 0;
++ case STRNE:
++ return strcmp(opnd1, opnd2) != 0;
++ case STRLT:
++ return strcmp(opnd1, opnd2) < 0;
++ case STRGT:
++ return strcmp(opnd1, opnd2) > 0;
++ case INTEQ:
++ return getn(opnd1) == getn(opnd2);
++ case INTNE:
++ return getn(opnd1) != getn(opnd2);
++ case INTGE:
++ return getn(opnd1) >= getn(opnd2);
++ case INTGT:
++ return getn(opnd1) > getn(opnd2);
++ case INTLE:
++ return getn(opnd1) <= getn(opnd2);
++ case INTLT:
++ return getn(opnd1) < getn(opnd2);
++ case FILNT:
++ return newerf (opnd1, opnd2);
++ case FILOT:
++ return olderf (opnd1, opnd2);
++ case FILEQ:
++ return equalf (opnd1, opnd2);
++ default:
++ abort();
++ /* NOTREACHED */
++ }
++}
++
++static int
++filstat(nm, mode)
++ char *nm;
++ enum token mode;
++{
++ struct stat s;
++
++ if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
++ return 0;
++
++ switch (mode) {
++ case FILRD:
++ return test_eaccess(nm, R_OK) == 0;
++ case FILWR:
++ return test_eaccess(nm, W_OK) == 0;
++ case FILEX:
++ return test_eaccess(nm, X_OK) == 0;
++ case FILEXIST:
++ return 1;
++ case FILREG:
++ return S_ISREG(s.st_mode);
++ case FILDIR:
++ return S_ISDIR(s.st_mode);
++ case FILCDEV:
++ return S_ISCHR(s.st_mode);
++ case FILBDEV:
++ return S_ISBLK(s.st_mode);
++ case FILFIFO:
++ return S_ISFIFO(s.st_mode);
++ case FILSOCK:
++ return S_ISSOCK(s.st_mode);
++ case FILSYM:
++ return S_ISLNK(s.st_mode);
++ case FILSUID:
++ return (s.st_mode & S_ISUID) != 0;
++ case FILSGID:
++ return (s.st_mode & S_ISGID) != 0;
++ case FILSTCK:
++ return (s.st_mode & S_ISVTX) != 0;
++ case FILGZ:
++ return s.st_size > (off_t)0;
++ case FILUID:
++ return s.st_uid == geteuid();
++ case FILGID:
++ return s.st_gid == getegid();
++ default:
++ return 1;
++ }
++}
++
++static enum token
++t_lex(s)
++ char *s;
++{
++ struct t_op const *op = ops;
++
++ if (s == 0) {
++ t_wp_op = (struct t_op *)0;
++ return EOI;
++ }
++ while (op->op_text) {
++ if (strcmp(s, op->op_text) == 0) {
++ if ((op->op_type == UNOP && isoperand()) ||
++ (op->op_num == LPAREN && *(t_wp+1) == 0))
++ break;
++ t_wp_op = op;
++ return op->op_num;
++ }
++ op++;
++ }
++ t_wp_op = (struct t_op *)0;
++ return OPERAND;
++}
++
++static int
++isoperand()
++{
++ struct t_op const *op = ops;
++ char *s;
++ char *t;
++
++ if ((s = *(t_wp+1)) == 0)
++ return 1;
++ if ((t = *(t_wp+2)) == 0)
++ return 0;
++ while (op->op_text) {
++ if (strcmp(s, op->op_text) == 0)
++ return op->op_type == BINOP &&
++ (t[0] != ')' || t[1] != '\0');
++ op++;
++ }
++ return 0;
++}
++
++/* atoi with error detection */
++static int
++getn(s)
++ const char *s;
++{
++ char *p;
++ long r;
++
++ errno = 0;
++ r = strtol(s, &p, 10);
++
++ if (errno != 0)
++ error("%s: out of range", s);
++
++ while (isspace((unsigned char)*p))
++ p++;
++
++ if (*p)
++ error("%s: bad number", s);
++
++ return (int) r;
++}
++
++static int
++newerf (f1, f2)
++const char *f1, *f2;
++{
++ struct stat b1, b2;
++
++ return (stat (f1, &b1) == 0 &&
++ stat (f2, &b2) == 0 &&
++ b1.st_mtime > b2.st_mtime);
++}
++
++static int
++olderf (f1, f2)
++const char *f1, *f2;
++{
++ struct stat b1, b2;
++
++ return (stat (f1, &b1) == 0 &&
++ stat (f2, &b2) == 0 &&
++ b1.st_mtime < b2.st_mtime);
++}
++
++static int
++equalf (f1, f2)
++const char *f1, *f2;
++{
++ struct stat b1, b2;
++
++ return (stat (f1, &b1) == 0 &&
++ stat (f2, &b2) == 0 &&
++ b1.st_dev == b2.st_dev &&
++ b1.st_ino == b2.st_ino);
++}
++
++/* Do the same thing access(2) does, but use the effective uid and gid,
++ and don't make the mistake of telling root that any file is
++ executable. */
++static int
++test_eaccess (path, mode)
++char *path;
++int mode;
++{
++ struct stat st;
++ int euid = geteuid();
++
++ if (stat (path, &st) < 0)
++ return (-1);
++
++ if (euid == 0) {
++ /* Root can read or write any file. */
++ if (mode != X_OK)
++ return (0);
++
++ /* Root can execute any file that has any one of the execute
++ bits set. */
++ if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
++ return (0);
++ }
++
++ if (st.st_uid == euid) /* owner */
++ mode <<= 6;
++ else if (bash_group_member (st.st_gid))
++ mode <<= 3;
++
++ if (st.st_mode & mode)
++ return (0);
++
++ return (-1);
++}
++
++static void
++initialize_group_array ()
++{
++ ngroups = getgroups(0, NULL);
++ group_array = malloc(ngroups * sizeof(gid_t));
++ if (!group_array)
++ error(strerror(ENOMEM));
++ getgroups(ngroups, group_array);
++}
++
++/* Return non-zero if GID is one that we have in our groups list. */
++static int
++bash_group_member (gid)
++gid_t gid;
++{
++ register int i;
++
++ /* Short-circuit if possible, maybe saving a call to getgroups(). */
++ if (gid == getgid() || gid == getegid())
++ return (1);
++
++ if (ngroups == 0)
++ initialize_group_array ();
++
++ /* Search through the list looking for GID. */
++ for (i = 0; i < ngroups; i++)
++ if (gid == group_array[i])
++ return (1);
++
++ return (0);
++}
+