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, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 /* Define STANDALONE to get the /bin/test version. Otherwise, you get
24 the shell builtin version. */
25 /* #define STANDALONE */
28 #include "bashtypes.h"
30 #if !defined (STANDALONE)
31 # if !defined (_POSIX_VERSION)
32 # include <sys/file.h>
33 # endif /* !_POSIX_VERSION */
34 # include "posixstat.h"
35 # include "filecntl.h"
37 #else /* STANDALONE */
39 # if !defined (S_IXUGO)
42 # if defined (HAVE_UNISTD_H)
44 # endif /* HAVE_UNISTD_H */
45 # define whitespace(c) (((c) == ' ') || ((c) == '\t'))
46 # define digit(c) ((c) >= '0' && (c) <= '9')
47 # define digit_value(c) ((c) - '0')
48 #endif /* STANDALONE */
51 # define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
60 # define STREQ(a, b) ((a)[0] == (b)[0] && strcmp (a, b) == 0)
64 # define member(c, s) (int)((c) ? (char *)strchr ((s), (c)) : 0)
67 /* Make gid_t and uid_t mean something for non-posix systems. */
68 #if !defined (_POSIX_VERSION) && !defined (HAVE_UID_T)
75 #endif /* !_POSIX_VERSION */
77 /* What type are the user and group ids? GID_T is actually the type of
78 the members of the array that getgroups(3) fills in from its second
80 #if defined (INT_GROUPS_ARRAY)
83 #else /* !INT_GROUPS_ARRAY */
86 #endif /* !INT_GROUPS_ARRAY */
88 #if !defined (Linux) && !defined (USGr4_2) && !defined (SunOS5)
89 extern gid_t getegid ();
90 extern uid_t geteuid ();
92 extern gid_t getgid ();
94 #endif /* !Linux && !USGr4_2 && !SunOS5 */
103 /* The following few defines control the truth and false output of each stage.
104 TRUE and FALSE are what we use to compute the final output value.
105 SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
106 TRUTH_OR is how to do logical or with TRUE and FALSE.
107 TRUTH_AND is how to do logical and with TRUE and FALSE..
108 Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b,
109 SHELL_BOOLEAN = (!value). */
112 #define SHELL_BOOLEAN(value) (!(value))
113 #define TRUTH_OR(a, b) ((a) | (b))
114 #define TRUTH_AND(a, b) ((a) & (b))
116 #if defined (STANDALONE)
117 # define test_exit(val) exit (val)
119 static jmp_buf test_exit_buf;
120 static int test_error_return = 0;
121 # define test_exit(val) \
122 do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0)
123 #endif /* STANDALONE */
126 /* We have to use access(2) for machines running AFS, because it's
127 not a Unix file system. This may produce incorrect answers for
128 non-AFS files. I hate AFS. */
129 # define EACCESS(path, mode) access(path, mode)
131 # define EACCESS(path, mode) eaccess(path, mode)
134 static int pos; /* The offset of the current argument in ARGV. */
135 static int argc; /* The number of arguments present in ARGV. */
136 static char **argv; /* The argument list. */
142 static int unary_operator ();
143 static int binary_operator ();
144 static int two_arguments ();
145 static int three_arguments ();
146 static int posixtest ();
154 test_syntax_error (format, arg)
157 #if !defined (STANDALONE)
158 extern int interactive_shell;
159 extern char *get_name_for_error ();
160 if (!interactive_shell)
161 fprintf (stderr, "%s: ", get_name_for_error ());
163 fprintf (stderr, "%s: ", argv[0]);
164 fprintf (stderr, format, arg);
166 test_exit (SHELL_BOOLEAN (FALSE));
169 /* A wrapper for stat () which disallows pathnames that are empty strings
170 and handles /dev/fd emulation on systems that don't have it. */
172 test_stat (path, finfo)
181 #if !defined (HAVE_DEV_FD)
182 if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
185 if (isint (path + 8, &fd))
186 return (fstat (fd, finfo));
193 #endif /* !HAVE_DEV_FD */
194 return (stat (path, finfo));
197 /* Do the same thing access(2) does, but use the effective uid and gid,
198 and don't make the mistake of telling root that any file is
206 static int euid = -1;
208 if (test_stat (path, &st) < 0)
213 euid = current_user.euid;
220 /* Root can read or write any file. */
224 /* Root can execute any file that has any one of the execute
226 if (st.st_mode & S_IXUGO)
230 if (st.st_uid == euid) /* owner */
232 else if (group_member (st.st_gid))
235 if (st.st_mode & mode)
241 #if defined (HAVE_GETGROUPS)
242 /* The number of groups that this user is a member of. */
243 static int ngroups = 0;
244 static GID_T *group_array = (GID_T *)NULL;
245 static int default_group_array_size = 0;
246 #endif /* HAVE_GETGROUPS */
248 #if !defined (NOGROUP)
249 # define NOGROUP (GID_T) -1
252 /* Return non-zero if GID is one that we have in our groups list. */
257 static GID_T pgid = (GID_T)NOGROUP;
258 static GID_T egid = (GID_T)NOGROUP;
260 if (pgid == (GID_T)NOGROUP)
262 pgid = (GID_T) current_user.gid;
264 pgid = (GID_T) getgid ();
267 if (egid == (GID_T)NOGROUP)
269 egid = (GID_T) current_user.egid;
271 egid = (GID_T) getegid ();
274 if (gid == pgid || gid == egid)
277 #if defined (HAVE_GETGROUPS)
278 /* getgroups () returns the number of elements that it was able to
279 place into the array. We simply continue to call getgroups ()
280 until the number of elements placed into the array is smaller than
281 the physical size of the array. */
283 while (ngroups == default_group_array_size)
285 default_group_array_size += 64;
287 group_array = (GID_T *)
288 xrealloc (group_array, default_group_array_size * sizeof (GID_T));
290 ngroups = getgroups (default_group_array_size, group_array);
293 /* In case of error, the user loses. */
297 /* Search through the list looking for GID. */
301 for (i = 0; i < ngroups; i++)
302 if (gid == group_array[i])
305 #endif /* HAVE_GETGROUPS */
310 /* Increment our position in the argument list. Check that we're not
311 past the end of the argument list. This check is supressed if the
312 argument is FALSE. Made a macro for efficiency. */
314 #define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0)
317 #if !defined (advance)
324 if (f && pos >= argc)
329 #define unary_advance() do { advance (1); ++pos; } while (0)
332 * beyond - call when we're beyond the end of the argument list (an
338 test_syntax_error ("argument expected\n", (char *)NULL);
341 /* Syntax error for when an integer argument was expected, but
342 something else was found. */
344 integer_expected_error (pch)
347 test_syntax_error ("integer expression expected %s\n", pch);
350 /* Return non-zero if the characters pointed to by STRING constitute a
351 valid number. Stuff the converted number into RESULT if RESULT is
352 a non-null pointer to a long. */
354 isint (string, result)
355 register char *string;
367 /* Skip leading whitespace characters. */
368 while (whitespace (*string))
374 /* We allow leading `-' or `+'. */
375 if (*string == '-' || *string == '+')
377 if (!digit (string[1]))
386 while (digit (*string))
389 value = (value * 10) + digit_value (*string);
393 /* Skip trailing whitespace, if any. */
394 while (whitespace (*string))
397 /* Error if not at end of string. */
410 /* Find the modification time of FILE, and stuff it into AGE, a pointer
411 to a long. Return non-zero if successful, else zero. */
413 age_of (filename, age)
419 if (test_stat (filename, &finfo) < 0)
423 *age = finfo.st_mtime;
429 * term - parse a term and return 1 or 0 depending on whether the term
430 * evaluates to true or false, respectively.
433 * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
434 * '-'('L'|'x') filename
436 * '-'('z'|'n') string
438 * string ('!='|'=') string
439 * <int> '-'(eq|ne|le|lt|ge|gt) <int>
440 * file '-'(nt|ot|ef) file
444 * positive and negative integers
454 /* Deal with leading "not"'s. */
455 if ('!' == argv[pos][0] && '\000' == argv[pos][1])
458 while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
464 return (value ^ (term ()));
467 /* A paren-bracketed argument. */
468 if (argv[pos][0] == '(' && !argv[pos][1])
473 test_syntax_error ("`)' expected\n");
474 else if (argv[pos][0] != ')' || argv[pos][1])
475 test_syntax_error ("`)' expected, found %s\n", argv[pos]);
477 return (TRUE == (value));
480 /* are there enough arguments left that this could be dyadic? */
481 if (((pos + 3 <= argc) && binop (argv[pos + 1])) ||
482 ((pos + 4 <= argc && STREQ (argv[pos], "-l") && binop (argv[pos + 2]))))
483 value = binary_operator ();
485 /* Might be a switch type argument */
486 else if ('-' == argv[pos][0] && 0 == argv[pos][2])
488 if (unop (argv[pos][1]))
489 value = unary_operator ();
491 test_syntax_error ("%s: unary operator expected\n", argv[pos]);
495 value = (argv[pos][0] != '\0');
506 struct stat stat_buf, stat_spare;
507 long int l, r, value;
508 /* Are the left and right integer expressions of the form '-l string'? */
511 if (argv[pos][0] == '-' && argv[pos][1] == 'l' && !argv[pos][2])
516 /* Make sure that OP is still a valid binary operator. */
517 if ((op >= argc - 1) || (binop (argv[op]) == 0))
518 test_syntax_error ("%s: binary operator expected\n", argv[op]);
528 if ((op < argc - 2) &&
529 (argv[op + 1][0] == '-' && argv[op + 1][1] == 'l' && !argv[op + 1][2]))
537 if (argv[op][0] == '-')
539 /* check for eq, nt, and stuff */
546 if (argv[op][2] == 't' && !argv[op][3])
550 l = strlen (argv[op - 1]);
553 if (!isint (argv[op - 1], &l))
554 integer_expected_error ("before -lt");
558 r = strlen (argv[op + 2]);
561 if (!isint (argv[op + 1], &r))
562 integer_expected_error ("after -lt");
565 return (TRUE == (l < r));
568 if (argv[op][2] == 'e' && !argv[op][3])
572 l = strlen (argv[op - 1]);
575 if (!isint (argv[op - 1], &l))
576 integer_expected_error ("before -le");
579 r = strlen (argv[op + 2]);
582 if (!isint (argv[op + 1], &r))
583 integer_expected_error ("after -le");
586 return (TRUE == (l <= r));
591 if (argv[op][2] == 't' && !argv[op][3])
593 /* gt integer greater than */
595 l = strlen (argv[op - 1]);
598 if (!isint (argv[op - 1], &l))
599 integer_expected_error ("before -gt");
602 r = strlen (argv[op + 2]);
605 if (!isint (argv[op + 1], &r))
606 integer_expected_error ("after -gt");
609 return (TRUE == (l > r));
612 if (argv[op][2] == 'e' && !argv[op][3])
614 /* ge - integer greater than or equal to */
616 l = strlen (argv[op - 1]);
619 if (!isint (argv[op - 1], &l))
620 integer_expected_error ("before -ge");
623 r = strlen (argv[op + 2]);
626 if (!isint (argv[op + 1], &r))
627 integer_expected_error ("after -ge");
630 return (TRUE == (l >= r));
635 if (argv[op][2] == 't' && !argv[op][3])
637 /* nt - newer than */
639 if (l_is_l || r_is_l)
640 test_syntax_error ("-nt does not accept -l\n", (char *)NULL);
641 if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
642 return (TRUE == (l > r));
647 if (argv[op][2] == 'e' && !argv[op][3])
649 /* ne - integer not equal */
651 l = strlen (argv[op - 1]);
654 if (!isint (argv[op - 1], &l))
655 integer_expected_error ("before -ne");
658 r = strlen (argv[op + 2]);
661 if (!isint (argv[op + 1], &r))
662 integer_expected_error ("after -ne");
665 return (TRUE == (l != r));
670 if (argv[op][2] == 'q' && !argv[op][3])
672 /* eq - integer equal */
674 l = strlen (argv[op - 1]);
677 if (!isint (argv[op - 1], &l))
678 integer_expected_error ("before -eq");
681 r = strlen (argv[op + 2]);
684 if (!isint (argv[op + 1], &r))
685 integer_expected_error ("after -eq");
688 return (TRUE == (l == r));
691 if (argv[op][2] == 'f' && !argv[op][3])
693 /* ef - hard link? */
695 if (l_is_l || r_is_l)
696 test_syntax_error ("-ef does not accept -l\n", (char *)NULL);
697 if (test_stat (argv[op - 1], &stat_buf) < 0)
699 if (test_stat (argv[op + 1], &stat_spare) < 0)
702 (stat_buf.st_dev == stat_spare.st_dev &&
703 stat_buf.st_ino == stat_spare.st_ino));
708 if ('t' == argv[op][2] && '\000' == argv[op][3])
710 /* ot - older than */
712 if (l_is_l || r_is_l)
713 test_syntax_error ("-nt does not accept -l\n", (char *)NULL);
714 if (age_of (argv[op - 1], &l) && age_of (argv[op + 1], &r))
715 return (TRUE == (l < r));
720 test_syntax_error ("%s: unknown binary operator", argv[op]);
723 if (argv[op][0] == '=' && !argv[op][1])
725 value = (argv[pos][0] == argv[pos+2][0]) &&
726 (strcmp (argv[pos], argv[pos + 2]) == 0);
728 return (TRUE == value);
731 if (argv[op][0] == '!' && argv[op][1] == '=' && !argv[op][2])
733 value = (argv[pos][0] != argv[pos + 2][0]) ||
734 (strcmp (argv[pos], argv[pos + 2]) != 0);
736 return (TRUE == value);
745 struct stat stat_buf;
747 switch (argv[pos][1])
752 /* All of the following unary operators use unary_advance (), which
753 checks to make sure that there is an argument, and then advances
754 pos right past it. This means that pos - 1 is the location of the
757 case 'a': /* file exists in the file system? */
760 value = -1 != test_stat (argv[pos - 1], &stat_buf);
761 return (TRUE == value);
763 case 'r': /* file is readable? */
765 value = -1 != EACCESS (argv[pos - 1], R_OK);
766 return (TRUE == value);
768 case 'w': /* File is writeable? */
770 value = -1 != EACCESS (argv[pos - 1], W_OK);
771 return (TRUE == value);
773 case 'x': /* File is executable? */
775 value = -1 != EACCESS (argv[pos - 1], X_OK);
776 return (TRUE == value);
778 case 'O': /* File is owned by you? */
780 if (test_stat (argv[pos - 1], &stat_buf) < 0)
784 return (TRUE == ((UID_T) current_user.euid == (UID_T) stat_buf.st_uid));
786 return (TRUE == ((UID_T) geteuid () == (UID_T) stat_buf.st_uid));
789 case 'G': /* File is owned by your group? */
791 if (test_stat (argv[pos - 1], &stat_buf) < 0)
794 return (TRUE == ((GID_T) getegid () == (GID_T) stat_buf.st_gid));
796 case 'f': /* File is a file? */
798 if (test_stat (argv[pos - 1], &stat_buf) < 0)
801 /* Under POSIX, -f is true if the given file exists
802 and is a regular file. */
804 return (TRUE == ((S_ISREG (stat_buf.st_mode)) ||
805 (0 == (stat_buf.st_mode & S_IFMT))));
807 return (TRUE == (S_ISREG (stat_buf.st_mode)));
810 case 'd': /* File is a directory? */
812 if (test_stat (argv[pos - 1], &stat_buf) < 0)
815 return (TRUE == (S_ISDIR (stat_buf.st_mode)));
817 case 's': /* File has something in it? */
819 if (test_stat (argv[pos - 1], &stat_buf) < 0)
822 return (TRUE == (stat_buf.st_size > (off_t) 0));
824 case 'S': /* File is a socket? */
825 #if !defined (S_ISSOCK)
830 if (test_stat (argv[pos - 1], &stat_buf) < 0)
833 return (TRUE == (S_ISSOCK (stat_buf.st_mode)));
834 #endif /* S_ISSOCK */
836 case 'c': /* File is character special? */
838 if (test_stat (argv[pos - 1], &stat_buf) < 0)
841 return (TRUE == (S_ISCHR (stat_buf.st_mode)));
843 case 'b': /* File is block special? */
845 if (test_stat (argv[pos - 1], &stat_buf) < 0)
848 return (TRUE == (S_ISBLK (stat_buf.st_mode)));
850 case 'p': /* File is a named pipe? */
855 if (test_stat (argv[pos - 1], &stat_buf) < 0)
857 return (TRUE == (S_ISFIFO (stat_buf.st_mode)));
858 #endif /* S_ISFIFO */
860 case 'L': /* Same as -h */
863 case 'h': /* File is a symbolic link? */
868 /* An empty filename is not a valid pathname. */
869 if ((argv[pos - 1][0] == '\0') ||
870 (lstat (argv[pos - 1], &stat_buf) < 0))
873 return (TRUE == (S_ISLNK (stat_buf.st_mode)));
876 case 'u': /* File is setuid? */
878 if (test_stat (argv[pos - 1], &stat_buf) < 0)
881 return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
883 case 'g': /* File is setgid? */
885 if (test_stat (argv[pos - 1], &stat_buf) < 0)
888 return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
890 case 'k': /* File has sticky bit set? */
892 if (test_stat (argv[pos - 1], &stat_buf) < 0)
894 #if !defined (S_ISVTX)
895 /* This is not Posix, and is not defined on some Posix systems. */
898 return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
901 case 't': /* File (fd) is a terminal? (fd) defaults to stdout. */
903 if (pos < argc && isint (argv[pos], &r))
906 return (TRUE == (isatty ((int) r)));
908 return (TRUE == (isatty (1)));
910 case 'n': /* True if arg has some length. */
912 return (TRUE == (argv[pos - 1][0] != 0));
914 case 'z': /* True if arg has no length. */
916 return (TRUE == (argv[pos - 1][0] == '\0'));
931 while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2])
934 value = TRUTH_AND (value, and ());
936 return (TRUE == value);
951 while (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2])
954 value = TRUTH_OR (value, or ());
957 return (TRUE == value);
970 return (FALSE ^ (or ())); /* Same with this. */
973 /* Return TRUE if S is one of the test command's binary operators. */
978 return ((STREQ (s, "=")) || (STREQ (s, "!=")) || (STREQ (s, "-nt")) ||
979 (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
980 (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
981 (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
984 /* Return non-zero if OP is one of the test command's unary operators. */
989 return (member (op, "abcdefgkLhprsStuwxOGnz"));
997 if (argv[pos][0] == '!' && !argv[pos][1])
998 value = argv[pos + 1][0] == '\0';
999 else if ((argv[pos][0] == '-') && (argv[pos][2] == '\0'))
1001 if (unop (argv[pos][1]))
1002 value = unary_operator ();
1004 test_syntax_error ("%s: unary operator expected\n", argv[pos]);
1007 test_syntax_error ("%s: unary operator expected\n", argv[pos]);
1017 if (argv[pos][0] == '!' && !argv[pos][1])
1020 value = !two_arguments ();
1022 else if (binop (argv[pos+1]))
1024 value = binary_operator ();
1027 /* Check for -a or -o or a parenthesized subexpression. */
1028 else if ((argv[pos+1][0] == '-' && !argv[pos+1][2] &&
1029 (argv[pos+1][1] == 'a' || argv[pos+1][1] == 'o')) ||
1030 (argv[pos][0] == '('))
1033 test_syntax_error ("%s: binary operator expected\n", argv[pos+1]);
1037 /* This is an implementation of a Posix.2 proposal by David Korn. */
1043 switch (argc - 1) /* one extra passed in */
1051 value = argv[1][0] != '\0';
1056 value = two_arguments ();
1061 value = three_arguments ();
1065 if (STREQ (argv[pos], "!"))
1068 value = !three_arguments ();
1087 #if defined (STANDALONE)
1090 test_command (margc, margv)
1091 #endif /* STANDALONE */
1097 #if !defined (STANDALONE)
1100 code = setjmp (test_exit_buf);
1103 return (test_error_return);
1104 #endif /* STANDALONE */
1108 if (margv[0] && margv[0][0] == '[' && !margv[0][1])
1113 test_exit (SHELL_BOOLEAN (FALSE));
1115 if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1]))
1116 test_syntax_error ("missing `]'\n", (char *)NULL);
1123 test_exit (SHELL_BOOLEAN (FALSE));
1126 value = posixtest ();
1129 test_syntax_error ("too many arguments\n", (char *)NULL);
1131 test_exit (SHELL_BOOLEAN (value));