]> git.pld-linux.org Git - packages/ash.git/blob - ash-test.patch
- dropped pre-cvs changelog
[packages/ash.git] / ash-test.patch
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
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.150785 seconds and 3 git commands to generate.