1 /* GNU test program (ksb and mjb) */
3 /* Modified to run with the GNU shell Apr 25, 1988 by bfox. */
5 /* Copyright (C) 1987, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
7 This file is part of GNU Bash, the Bourne Again SHell.
9 Bash is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
14 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License along
20 with Bash; see the file COPYING. If not, write to the Free Software
21 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 /* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching
25 /* #define PATTERN_MATCHING */
27 #if defined (HAVE_CONFIG_H)
33 #include "bashtypes.h"
35 #if defined (HAVE_LIMITS_H)
38 # include <sys/param.h>
41 #if defined (HAVE_UNISTD_H)
50 #if !defined (_POSIX_VERSION)
51 # include <sys/file.h>
52 #endif /* !_POSIX_VERSION */
53 #include "posixstat.h"
59 #include "builtins/common.h"
61 #include <glob/fnmatch.h>
64 # define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
68 # define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0)
89 /* The following few defines control the truth and false output of each stage.
90 TRUE and FALSE are what we use to compute the final output value.
91 SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
92 Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */
95 #define SHELL_BOOLEAN(value) (!(value))
97 #define TEST_ERREXIT_STATUS 2
99 static procenv_t test_exit_buf;
100 static int test_error_return;
101 #define test_exit(val) \
102 do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0)
104 /* We have to use access(2) for machines running AFS, because it's
105 not a Unix file system. This may produce incorrect answers for
106 non-AFS files. I hate AFS. */
108 # define EACCESS(path, mode) access(path, mode)
110 # define EACCESS(path, mode) test_eaccess(path, mode)
113 static int pos; /* The offset of the current argument in ARGV. */
114 static int argc; /* The number of arguments present in ARGV. */
115 static char **argv; /* The argument list. */
118 static int unary_operator ();
119 static int binary_operator ();
120 static int two_arguments ();
121 static int three_arguments ();
122 static int posixtest ();
129 static void beyond ();
132 test_syntax_error (format, arg)
135 extern int interactive_shell;
136 extern char *get_name_for_error ();
137 if (interactive_shell == 0)
138 fprintf (stderr, "%s: ", get_name_for_error ());
139 fprintf (stderr, "%s: ", argv[0]);
140 fprintf (stderr, format, arg);
141 fprintf (stderr, "\n");
143 test_exit (TEST_ERREXIT_STATUS);
147 * beyond - call when we're beyond the end of the argument list (an
153 test_syntax_error ("argument expected", (char *)NULL);
156 /* Syntax error for when an integer argument was expected, but
157 something else was found. */
159 integer_expected_error (pch)
162 test_syntax_error ("%s: integer expression expected", pch);
165 /* A wrapper for stat () which disallows pathnames that are empty strings
166 and handles /dev/fd emulation on systems that don't have it. */
168 test_stat (path, finfo)
177 if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
179 #if !defined (HAVE_DEV_FD)
181 if (legal_number (path + 8, &fd))
182 return (fstat ((int)fd, finfo));
189 /* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a
190 trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx.
191 On most systems, with the notable exception of linux, this is
192 effectively a no-op. */
194 strcpy (pbuf, DEV_FD_PREFIX);
195 strcat (pbuf, path + 8);
196 return (stat (pbuf, finfo));
197 #endif /* !HAVE_DEV_FD */
199 #if !defined (HAVE_DEV_STDIN)
200 else if (STREQN (path, "/dev/std", 8))
202 if (STREQ (path+8, "in"))
203 return (fstat (0, finfo));
204 else if (STREQ (path+8, "out"))
205 return (fstat (1, finfo));
206 else if (STREQ (path+8, "err"))
207 return (fstat (2, finfo));
209 return (stat (path, finfo));
211 #endif /* !HAVE_DEV_STDIN */
212 return (stat (path, finfo));
215 /* Do the same thing access(2) does, but use the effective uid and gid,
216 and don't make the mistake of telling root that any file is
219 test_eaccess (path, mode)
225 if (test_stat (path, &st) < 0)
228 if (current_user.euid == 0)
230 /* Root can read or write any file. */
234 /* Root can execute any file that has any one of the execute
236 if (st.st_mode & S_IXUGO)
240 if (st.st_uid == current_user.euid) /* owner */
242 else if (group_member (st.st_gid))
245 if (st.st_mode & mode)
252 /* Increment our position in the argument list. Check that we're not
253 past the end of the argument list. This check is supressed if the
254 argument is FALSE. Made a macro for efficiency. */
255 #define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0)
256 #define unary_advance() do { advance (1); ++pos; } while (0)
268 return (FALSE ^ or ()); /* Same with this. */
282 while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2])
286 return (value || v2);
303 while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2])
307 return (value && v2);
313 * term - parse a term and return 1 or 0 depending on whether the term
314 * evaluates to true or false, respectively.
317 * '-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'k'|'p'|'r'|'s'|'u'|'w'|'x') filename
318 * '-'('G'|'L'|'O'|'S'|'N') filename
320 * '-'('z'|'n') string
323 * string ('!='|'='|'==') string
324 * <int> '-'(eq|ne|le|lt|ge|gt) <int>
325 * file '-'(nt|ot|ef) file
328 * positive and negative integers
338 /* Deal with leading `not's. */
339 if (argv[pos][0] == '!' && argv[pos][1] == '\0')
342 while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0')
348 return (value ? !term() : term());
351 /* A paren-bracketed argument. */
352 if (argv[pos][0] == '(' && argv[pos][1] == '\0')
357 test_syntax_error ("`)' expected", (char *)NULL);
358 else if (argv[pos][0] != ')' || argv[pos][1])
359 test_syntax_error ("`)' expected, found %s", argv[pos]);
364 /* are there enough arguments left that this could be dyadic? */
365 if ((pos + 3 <= argc) && test_binop (argv[pos + 1]))
366 value = binary_operator ();
368 /* Might be a switch type argument */
369 else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
371 if (test_unop (argv[pos]))
372 value = unary_operator ();
374 test_syntax_error ("%s: unary operator expected", argv[pos]);
378 value = argv[pos][0] != '\0';
390 struct stat st1, st2;
392 if (test_stat (s, &st1) < 0)
398 if (test_stat (t, &st2) < 0)
407 case OT: return (st1.st_mtime < st2.st_mtime);
408 case NT: return (st1.st_mtime > st2.st_mtime);
409 case EF: return ((st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino));
415 arithcomp (s, t, op, flags)
422 if (flags & TEST_ARITHEXP)
424 l = evalexp (s, &expok);
426 return (FALSE); /* should probably longjmp here */
427 r = evalexp (t, &expok);
429 return (FALSE); /* ditto */
433 if (legal_number (s, &l) == 0)
434 integer_expected_error (s);
435 if (legal_number (t, &r) == 0)
436 integer_expected_error (t);
441 case EQ: return (l == r);
442 case NE: return (l != r);
443 case LT: return (l < r);
444 case GT: return (l > r);
445 case LE: return (l <= r);
446 case GE: return (l >= r);
453 patcomp (string, pat, op)
459 m = fnmatch (pat, string, FNMATCH_EXTFLAG);
460 return ((op == EQ) ? (m == 0) : (m != 0));
464 binary_test (op, arg1, arg2, flags)
465 char *op, *arg1, *arg2;
470 patmatch = (flags & TEST_PATMATCH);
472 if (op[0] == '=' && (op[1] == '\0' || (op[1] == '=' && op[2] == '\0')))
473 return (patmatch ? patcomp (arg1, arg2, EQ) : STREQ (arg1, arg2));
475 else if ((op[0] == '>' || op[0] == '<') && op[1] == '\0')
476 return ((op[0] == '>') ? (strcmp (arg1, arg2) > 0) : (strcmp (arg1, arg2) < 0));
478 else if (op[0] == '!' && op[1] == '=' && op[2] == '\0')
479 return (patmatch ? patcomp (arg1, arg2, NE) : (STREQ (arg1, arg2) == 0));
481 else if (op[2] == 't')
485 case 'n': return (filecomp (arg1, arg2, NT)); /* -nt */
486 case 'o': return (filecomp (arg1, arg2, OT)); /* -ot */
487 case 'l': return (arithcomp (arg1, arg2, LT, flags)); /* -lt */
488 case 'g': return (arithcomp (arg1, arg2, GT, flags)); /* -gt */
491 else if (op[1] == 'e')
495 case 'f': return (filecomp (arg1, arg2, EF)); /* -ef */
496 case 'q': return (arithcomp (arg1, arg2, EQ, flags)); /* -eq */
499 else if (op[2] == 'e')
503 case 'n': return (arithcomp (arg1, arg2, NE, flags)); /* -ne */
504 case 'g': return (arithcomp (arg1, arg2, GE, flags)); /* -ge */
505 case 'l': return (arithcomp (arg1, arg2, LE, flags)); /* -le */
509 return (FALSE); /* should never get here */
520 if ((w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) || /* =, == */
521 ((w[0] == '>' || w[0] == '<') && w[1] == '\0') || /* <, > */
522 (w[0] == '!' && w[1] == '=' && w[2] == '\0')) /* != */
524 value = binary_test (w, argv[pos], argv[pos + 2], 0);
529 #if defined (PATTERN_MATCHING)
530 if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0')
532 value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE);
538 if ((w[0] != '-' || w[3] != '\0') || test_binop (w) == 0)
540 test_syntax_error ("%s: binary operator expected", w);
545 value = binary_test (w, argv[pos], argv[pos + 2], 0);
557 if (test_unop (op) == 0)
560 /* the only tricky case is `-t', which may or may not take an argument. */
566 if (legal_number (argv[pos], &r))
569 return (unary_test (op, argv[pos - 1]));
575 return (unary_test (op, "1"));
578 /* All of the unary operators take an argument, so we first call
579 unary_advance (), which checks to make sure that there is an
580 argument, and then advances pos right past it. This means that
581 pos - 1 is the location of the argument. */
583 return (unary_test (op, argv[pos - 1]));
591 struct stat stat_buf;
595 case 'a': /* file exists in the file system? */
597 return (test_stat (arg, &stat_buf) == 0);
599 case 'r': /* file is readable? */
600 return (EACCESS (arg, R_OK) == 0);
602 case 'w': /* File is writeable? */
603 return (EACCESS (arg, W_OK) == 0);
605 case 'x': /* File is executable? */
606 return (EACCESS (arg, X_OK) == 0);
608 case 'O': /* File is owned by you? */
609 return (test_stat (arg, &stat_buf) == 0 &&
610 (uid_t) current_user.euid == (uid_t) stat_buf.st_uid);
612 case 'G': /* File is owned by your group? */
613 return (test_stat (arg, &stat_buf) == 0 &&
614 (gid_t) current_user.egid == (gid_t) stat_buf.st_gid);
617 return (test_stat (arg, &stat_buf) == 0 &&
618 stat_buf.st_atime <= stat_buf.st_mtime);
620 case 'f': /* File is a file? */
621 if (test_stat (arg, &stat_buf) < 0)
624 /* -f is true if the given file exists and is a regular file. */
626 return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0);
628 return (S_ISREG (stat_buf.st_mode));
631 case 'd': /* File is a directory? */
632 return (test_stat (arg, &stat_buf) == 0 && (S_ISDIR (stat_buf.st_mode)));
634 case 's': /* File has something in it? */
635 return (test_stat (arg, &stat_buf) == 0 && stat_buf.st_size > (off_t) 0);
637 case 'S': /* File is a socket? */
638 #if !defined (S_ISSOCK)
641 return (test_stat (arg, &stat_buf) == 0 && S_ISSOCK (stat_buf.st_mode));
642 #endif /* S_ISSOCK */
644 case 'c': /* File is character special? */
645 return (test_stat (arg, &stat_buf) == 0 && S_ISCHR (stat_buf.st_mode));
647 case 'b': /* File is block special? */
648 return (test_stat (arg, &stat_buf) == 0 && S_ISBLK (stat_buf.st_mode));
650 case 'p': /* File is a named pipe? */
654 return (test_stat (arg, &stat_buf) == 0 && S_ISFIFO (stat_buf.st_mode));
655 #endif /* S_ISFIFO */
657 case 'L': /* Same as -h */
658 case 'h': /* File is a symbolic link? */
659 #if !defined (S_ISLNK) || !defined (HAVE_LSTAT)
662 return ((arg[0] != '\0') &&
663 (lstat (arg, &stat_buf) == 0) && S_ISLNK (stat_buf.st_mode));
664 #endif /* S_IFLNK && HAVE_LSTAT */
666 case 'u': /* File is setuid? */
667 return (test_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISUID) != 0);
669 case 'g': /* File is setgid? */
670 return (test_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISGID) != 0);
672 case 'k': /* File has sticky bit set? */
673 #if !defined (S_ISVTX)
674 /* This is not Posix, and is not defined on some Posix systems. */
677 return (test_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISVTX) != 0);
680 case 't': /* File fd is a terminal? */
681 if (legal_number (arg, &r) == 0)
683 return (isatty ((int)r));
685 case 'n': /* True if arg has some length. */
686 return (arg[0] != '\0');
688 case 'z': /* True if arg has no length. */
689 return (arg[0] == '\0');
691 case 'o': /* True if option `arg' is set. */
692 return (minus_o_option_value (arg) == 1);
696 /* Return TRUE if OP is one of the test command's binary operators. */
701 if (op[0] == '=' && op[1] == '\0')
702 return (1); /* '=' */
703 else if ((op[0] == '<' || op[0] == '>') && op[1] == '\0') /* string <, > */
705 else if ((op[0] == '=' || op[0] == '!') && op[1] == '=' && op[2] == '\0')
706 return (1); /* `==' and `!=' */
707 #if defined (PATTERN_MATCHING)
708 else if (op[2] == '\0' && op[1] == '~' && (op[0] == '=' || op[0] == '!'))
711 else if (op[0] != '-' || op[2] == '\0' || op[3] != '\0')
726 else if (op[1] == 'e')
735 else if (op[2] == 'e')
750 /* Return non-zero if OP is one of the test command's unary operators. */
760 case 'a': case 'b': case 'c': case 'd': case 'e':
761 case 'f': case 'g': case 'h': case 'k': case 'n':
762 case 'o': case 'p': case 'r': case 's': case 't':
763 case 'u': case 'w': case 'x': case 'z':
764 case 'G': case 'L': case 'O': case 'S': case 'N':
774 if (argv[pos][0] == '!' && argv[pos][1] == '\0')
775 return (argv[pos + 1][0] == '\0');
776 else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
778 if (test_unop (argv[pos]))
779 return (unary_operator ());
781 test_syntax_error ("%s: unary operator expected", argv[pos]);
784 test_syntax_error ("%s: unary operator expected", argv[pos]);
789 #define ANDOR(s) (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o'))
791 #define ONE_ARG_TEST(s) ((s)[0] != '\0')
798 if (test_binop (argv[pos+1]))
800 value = binary_operator ();
803 else if (ANDOR (argv[pos+1]))
805 if (argv[pos+1][1] == 'a')
806 value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]);
808 value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]);
811 else if (argv[pos][0] == '!' && argv[pos][1] == '\0')
814 value = !two_arguments ();
816 else if (argv[pos][0] == '(' && argv[pos+2][0] == ')')
818 value = ONE_ARG_TEST(argv[pos+1]);
822 test_syntax_error ("%s: binary operator expected", argv[pos+1]);
827 /* This is an implementation of a Posix.2 proposal by David Korn. */
833 switch (argc - 1) /* one extra passed in */
841 value = ONE_ARG_TEST(argv[1]);
846 value = two_arguments ();
851 value = three_arguments ();
855 if (argv[pos][0] == '!' && argv[pos][1] == '\0')
858 value = !three_arguments ();
876 test_command (margc, margv)
884 code = setjmp (test_exit_buf);
887 return (test_error_return);
891 if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0')
895 if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1]))
896 test_syntax_error ("missing `]'", (char *)NULL);
899 test_exit (SHELL_BOOLEAN (FALSE));
906 test_exit (SHELL_BOOLEAN (FALSE));
909 value = posixtest ();
912 test_syntax_error ("too many arguments", (char *)NULL);
914 test_exit (SHELL_BOOLEAN (value));