]> git.pld-linux.org Git - packages/ash.git/blame - ash-test.patch
- dropped pre-cvs changelog
[packages/ash.git] / ash-test.patch
CommitLineData
cf7098dd
MM
1diff -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
4@@ -0,0 +1,583 @@
5+/* $NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $ */
6+
7+/*
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.
13+ *
14+ * This program is in the Public Domain.
15+ */
16+
17+#include <sys/cdefs.h>
18+#ifndef lint
19+__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $");
20+#endif
21+
22+#include <sys/types.h>
23+#include <sys/stat.h>
24+#include <unistd.h>
25+#include <ctype.h>
26+#include <errno.h>
27+#include <stdio.h>
28+#include <stdlib.h>
29+#include <string.h>
30+#include <err.h>
31+#ifdef __STDC__
32+#include <stdarg.h>
33+#else
34+#include <varargs.h>
35+#endif
36+
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
43+ | operand
44+ | "(" oexpr ")"
45+ ;
46+ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
47+ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
48+
49+ binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
50+ "-nt"|"-ot"|"-ef";
51+ operand ::= <any legal UNIX file name>
52+*/
53+
54+enum token {
55+ EOI,
56+ FILRD,
57+ FILWR,
58+ FILEX,
59+ FILEXIST,
60+ FILREG,
61+ FILDIR,
62+ FILCDEV,
63+ FILBDEV,
64+ FILFIFO,
65+ FILSOCK,
66+ FILSYM,
67+ FILGZ,
68+ FILTT,
69+ FILSUID,
70+ FILSGID,
71+ FILSTCK,
72+ FILNT,
73+ FILOT,
74+ FILEQ,
75+ FILUID,
76+ FILGID,
77+ STREZ,
78+ STRNZ,
79+ STREQ,
80+ STRNE,
81+ STRLT,
82+ STRGT,
83+ INTEQ,
84+ INTNE,
85+ INTGE,
86+ INTGT,
87+ INTLE,
88+ INTLT,
89+ UNOT,
90+ BAND,
91+ BOR,
92+ LPAREN,
93+ RPAREN,
94+ OPERAND
95+};
96+
97+enum token_types {
98+ UNOP,
99+ BINOP,
100+ BUNOP,
101+ BBINOP,
102+ PAREN
103+};
104+
105+static struct t_op {
106+ const char *op_text;
107+ short op_num, op_type;
108+} const ops [] = {
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},
148+ {0, 0, 0}
149+};
150+
151+static char **t_wp;
152+static struct t_op const *t_wp_op;
153+static gid_t *group_array = NULL;
154+static int ngroups;
155+
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();
172+
173+#if defined(SHELL)
174+extern void error __P((const char *, ...)) __attribute__((__noreturn__));
175+#else
176+static void error __P((const char *, ...)) __attribute__((__noreturn__));
177+
178+static void
179+#ifdef __STDC__
180+error(const char *msg, ...)
181+#else
182+error(va_alist)
183+ va_dcl
184+#endif
185+{
186+ va_list ap;
187+#ifndef __STDC__
188+ const char *msg;
189+
190+ va_start(ap);
191+ msg = va_arg(ap, const char *);
192+#else
193+ va_start(ap, msg);
194+#endif
195+ verrx(2, msg, ap);
196+ /*NOTREACHED*/
197+ va_end(ap);
198+}
199+#endif
200+
201+#ifdef SHELL
202+int testcmd __P((int, char **));
203+
204+int
205+testcmd(argc, argv)
206+ int argc;
207+ char **argv;
208+#else
209+int main __P((int, char **));
210+
211+int
212+main(argc, argv)
213+ int argc;
214+ char **argv;
215+#endif
216+{
217+ int res;
218+
219+
220+ if (strcmp(argv[0], "[") == 0) {
221+ if (strcmp(argv[--argc], "]"))
222+ error("missing ]");
223+ argv[argc] = NULL;
224+ }
225+
226+ if (argc < 2)
227+ return 1;
228+
229+ t_wp = &argv[1];
230+ res = !oexpr(t_lex(*t_wp));
231+
232+ if (*t_wp != NULL && *++t_wp != NULL)
233+ syntax(*t_wp, "unexpected operator");
234+
235+ return res;
236+}
237+
238+static void
239+syntax(op, msg)
240+ const char *op;
241+ const char *msg;
242+{
243+ if (op && *op)
244+ error("%s: %s", op, msg);
245+ else
246+ error("%s", msg);
247+}
248+
249+static int
250+oexpr(n)
251+ enum token n;
252+{
253+ int res;
254+
255+ res = aexpr(n);
256+ if (t_lex(*++t_wp) == BOR)
257+ return oexpr(t_lex(*++t_wp)) || res;
258+ t_wp--;
259+ return res;
260+}
261+
262+static int
263+aexpr(n)
264+ enum token n;
265+{
266+ int res;
267+
268+ res = nexpr(n);
269+ if (t_lex(*++t_wp) == BAND)
270+ return aexpr(t_lex(*++t_wp)) && res;
271+ t_wp--;
272+ return res;
273+}
274+
275+static int
276+nexpr(n)
277+ enum token n; /* token */
278+{
279+ if (n == UNOT)
280+ return !nexpr(t_lex(*++t_wp));
281+ return primary(n);
282+}
283+
284+static int
285+primary(n)
286+ enum token n;
287+{
288+ enum token nn;
289+ int res;
290+
291+ if (n == EOI)
292+ return 0; /* missing expression */
293+ if (n == LPAREN) {
294+ if ((nn = t_lex(*++t_wp)) == RPAREN)
295+ return 0; /* missing expression */
296+ res = oexpr(nn);
297+ if (t_lex(*++t_wp) != RPAREN)
298+ syntax(NULL, "closing paren expected");
299+ return res;
300+ }
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");
305+ switch (n) {
306+ case STREZ:
307+ return strlen(*t_wp) == 0;
308+ case STRNZ:
309+ return strlen(*t_wp) != 0;
310+ case FILTT:
311+ return isatty(getn(*t_wp));
312+ default:
313+ return filstat(*t_wp, n);
314+ }
315+ }
316+
317+ if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
318+ return binop();
319+ }
320+
321+ return strlen(*t_wp) > 0;
322+}
323+
324+static int
325+binop()
326+{
327+ const char *opnd1, *opnd2;
328+ struct t_op const *op;
329+
330+ opnd1 = *t_wp;
331+ (void) t_lex(*++t_wp);
332+ op = t_wp_op;
333+
334+ if ((opnd2 = *++t_wp) == (char *)0)
335+ syntax(op->op_text, "argument expected");
336+
337+ switch (op->op_num) {
338+ case STREQ:
339+ return strcmp(opnd1, opnd2) == 0;
340+ case STRNE:
341+ return strcmp(opnd1, opnd2) != 0;
342+ case STRLT:
343+ return strcmp(opnd1, opnd2) < 0;
344+ case STRGT:
345+ return strcmp(opnd1, opnd2) > 0;
346+ case INTEQ:
347+ return getn(opnd1) == getn(opnd2);
348+ case INTNE:
349+ return getn(opnd1) != getn(opnd2);
350+ case INTGE:
351+ return getn(opnd1) >= getn(opnd2);
352+ case INTGT:
353+ return getn(opnd1) > getn(opnd2);
354+ case INTLE:
355+ return getn(opnd1) <= getn(opnd2);
356+ case INTLT:
357+ return getn(opnd1) < getn(opnd2);
358+ case FILNT:
359+ return newerf (opnd1, opnd2);
360+ case FILOT:
361+ return olderf (opnd1, opnd2);
362+ case FILEQ:
363+ return equalf (opnd1, opnd2);
364+ default:
365+ abort();
366+ /* NOTREACHED */
367+ }
368+}
369+
370+static int
371+filstat(nm, mode)
372+ char *nm;
373+ enum token mode;
374+{
375+ struct stat s;
376+
377+ if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
378+ return 0;
379+
380+ switch (mode) {
381+ case FILRD:
382+ return test_eaccess(nm, R_OK) == 0;
383+ case FILWR:
384+ return test_eaccess(nm, W_OK) == 0;
385+ case FILEX:
386+ return test_eaccess(nm, X_OK) == 0;
387+ case FILEXIST:
388+ return 1;
389+ case FILREG:
390+ return S_ISREG(s.st_mode);
391+ case FILDIR:
392+ return S_ISDIR(s.st_mode);
393+ case FILCDEV:
394+ return S_ISCHR(s.st_mode);
395+ case FILBDEV:
396+ return S_ISBLK(s.st_mode);
397+ case FILFIFO:
398+ return S_ISFIFO(s.st_mode);
399+ case FILSOCK:
400+ return S_ISSOCK(s.st_mode);
401+ case FILSYM:
402+ return S_ISLNK(s.st_mode);
403+ case FILSUID:
404+ return (s.st_mode & S_ISUID) != 0;
405+ case FILSGID:
406+ return (s.st_mode & S_ISGID) != 0;
407+ case FILSTCK:
408+ return (s.st_mode & S_ISVTX) != 0;
409+ case FILGZ:
410+ return s.st_size > (off_t)0;
411+ case FILUID:
412+ return s.st_uid == geteuid();
413+ case FILGID:
414+ return s.st_gid == getegid();
415+ default:
416+ return 1;
417+ }
418+}
419+
420+static enum token
421+t_lex(s)
422+ char *s;
423+{
424+ struct t_op const *op = ops;
425+
426+ if (s == 0) {
427+ t_wp_op = (struct t_op *)0;
428+ return EOI;
429+ }
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))
434+ break;
435+ t_wp_op = op;
436+ return op->op_num;
437+ }
438+ op++;
439+ }
440+ t_wp_op = (struct t_op *)0;
441+ return OPERAND;
442+}
443+
444+static int
445+isoperand()
446+{
447+ struct t_op const *op = ops;
448+ char *s;
449+ char *t;
450+
451+ if ((s = *(t_wp+1)) == 0)
452+ return 1;
453+ if ((t = *(t_wp+2)) == 0)
454+ return 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');
459+ op++;
460+ }
461+ return 0;
462+}
463+
464+/* atoi with error detection */
465+static int
466+getn(s)
467+ const char *s;
468+{
469+ char *p;
470+ long r;
471+
472+ errno = 0;
473+ r = strtol(s, &p, 10);
474+
475+ if (errno != 0)
476+ error("%s: out of range", s);
477+
478+ while (isspace((unsigned char)*p))
479+ p++;
480+
481+ if (*p)
482+ error("%s: bad number", s);
483+
484+ return (int) r;
485+}
486+
487+static int
488+newerf (f1, f2)
489+const char *f1, *f2;
490+{
491+ struct stat b1, b2;
492+
493+ return (stat (f1, &b1) == 0 &&
494+ stat (f2, &b2) == 0 &&
495+ b1.st_mtime > b2.st_mtime);
496+}
497+
498+static int
499+olderf (f1, f2)
500+const char *f1, *f2;
501+{
502+ struct stat b1, b2;
503+
504+ return (stat (f1, &b1) == 0 &&
505+ stat (f2, &b2) == 0 &&
506+ b1.st_mtime < b2.st_mtime);
507+}
508+
509+static int
510+equalf (f1, f2)
511+const char *f1, *f2;
512+{
513+ struct stat b1, b2;
514+
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);
519+}
520+
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
523+ executable. */
524+static int
525+test_eaccess (path, mode)
526+char *path;
527+int mode;
528+{
529+ struct stat st;
530+ int euid = geteuid();
531+
532+ if (stat (path, &st) < 0)
533+ return (-1);
534+
535+ if (euid == 0) {
536+ /* Root can read or write any file. */
537+ if (mode != X_OK)
538+ return (0);
539+
540+ /* Root can execute any file that has any one of the execute
541+ bits set. */
542+ if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
543+ return (0);
544+ }
545+
546+ if (st.st_uid == euid) /* owner */
547+ mode <<= 6;
548+ else if (bash_group_member (st.st_gid))
549+ mode <<= 3;
550+
551+ if (st.st_mode & mode)
552+ return (0);
553+
554+ return (-1);
555+}
556+
557+static void
558+initialize_group_array ()
559+{
560+ ngroups = getgroups(0, NULL);
561+ group_array = malloc(ngroups * sizeof(gid_t));
562+ if (!group_array)
563+ error(strerror(ENOMEM));
564+ getgroups(ngroups, group_array);
565+}
566+
567+/* Return non-zero if GID is one that we have in our groups list. */
568+static int
569+bash_group_member (gid)
570+gid_t gid;
571+{
572+ register int i;
573+
574+ /* Short-circuit if possible, maybe saving a call to getgroups(). */
575+ if (gid == getgid() || gid == getegid())
576+ return (1);
577+
578+ if (ngroups == 0)
579+ initialize_group_array ();
580+
581+ /* Search through the list looking for GID. */
582+ for (i = 0; i < ngroups; i++)
583+ if (gid == group_array[i])
584+ return (1);
585+
586+ return (0);
587+}
588
This page took 0.139817 seconds and 4 git commands to generate.