~ubuntu-branches/ubuntu/trusty/bash/trusty-security

1.5.1 by Matthias Klose
Import upstream version 4.3~rc1
1
/* test.c - GNU test program (ksb and mjb) */
2
3
/* Modified to run with the GNU shell Apr 25, 1988 by bfox. */
4
5
/* Copyright (C) 1987-2010 Free Software Foundation, Inc.
6
7
   This file is part of GNU Bash, the Bourne Again SHell.
8
9
   Bash is free software: you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation, either version 3 of the License, or
12
   (at your option) any later version.
13
14
   Bash is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
19
   You should have received a copy of the GNU General Public License
20
   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
21
*/
22
23
/* Define PATTERN_MATCHING to get the csh-like =~ and !~ pattern-matching
24
   binary operators. */
25
/* #define PATTERN_MATCHING */
26
27
#if defined (HAVE_CONFIG_H)
28
#  include <config.h>
29
#endif
30
31
#include <stdio.h>
32
33
#include "bashtypes.h"
34
35
#if !defined (HAVE_LIMITS_H) && defined (HAVE_SYS_PARAM_H)
36
#  include <sys/param.h>
37
#endif
38
39
#if defined (HAVE_UNISTD_H)
40
#  include <unistd.h>
41
#endif
42
43
#include <errno.h>
44
#if !defined (errno)
45
extern int errno;
46
#endif /* !errno */
47
48
#if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H)
49
#  include <sys/file.h>
50
#endif /* !_POSIX_VERSION */
51
#include "posixstat.h"
52
#include "filecntl.h"
53
#include "stat-time.h"
54
55
#include "bashintl.h"
56
57
#include "shell.h"
58
#include "pathexp.h"
59
#include "test.h"
60
#include "builtins/common.h"
61
62
#include <glob/strmatch.h>
63
64
#if !defined (STRLEN)
65
#  define STRLEN(s) ((s)[0] ? ((s)[1] ? ((s)[2] ? strlen(s) : 2) : 1) : 0)
66
#endif
67
68
#if !defined (STREQ)
69
#  define STREQ(a, b) ((a)[0] == (b)[0] && strcmp ((a), (b)) == 0)
70
#endif /* !STREQ */
71
#define STRCOLLEQ(a, b) ((a)[0] == (b)[0] && strcoll ((a), (b)) == 0)
72
73
#if !defined (R_OK)
74
#define R_OK 4
75
#define W_OK 2
76
#define X_OK 1
77
#define F_OK 0
78
#endif /* R_OK */
79
80
#define EQ	0
81
#define NE	1
82
#define LT	2
83
#define GT	3
84
#define LE	4
85
#define GE	5
86
87
#define NT	0
88
#define OT	1
89
#define EF	2
90
91
/* The following few defines control the truth and false output of each stage.
92
   TRUE and FALSE are what we use to compute the final output value.
93
   SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
94
   Default is TRUE = 1, FALSE = 0, SHELL_BOOLEAN = (!value). */
95
#define TRUE 1
96
#define FALSE 0
97
#define SHELL_BOOLEAN(value) (!(value))
98
99
#define TEST_ERREXIT_STATUS	2
100
101
static procenv_t test_exit_buf;
102
static int test_error_return;
103
#define test_exit(val) \
104
	do { test_error_return = val; longjmp (test_exit_buf, 1); } while (0)
105
106
extern int sh_stat __P((const char *, struct stat *));
107
108
static int pos;		/* The offset of the current argument in ARGV. */
109
static int argc;	/* The number of arguments present in ARGV. */
110
static char **argv;	/* The argument list. */
111
static int noeval;
112
113
static void test_syntax_error __P((char *, char *)) __attribute__((__noreturn__));
114
static void beyond __P((void)) __attribute__((__noreturn__));
115
static void integer_expected_error __P((char *)) __attribute__((__noreturn__));
116
117
static int unary_operator __P((void));
118
static int binary_operator __P((void));
119
static int two_arguments __P((void));
120
static int three_arguments __P((void));
121
static int posixtest __P((void));
122
123
static int expr __P((void));
124
static int term __P((void));
125
static int and __P((void));
126
static int or __P((void));
127
128
static int filecomp __P((char *, char *, int));
129
static int arithcomp __P((char *, char *, int, int));
130
static int patcomp __P((char *, char *, int));
131
132
static void
133
test_syntax_error (format, arg)
134
     char *format, *arg;
135
{
136
  builtin_error (format, arg);
137
  test_exit (TEST_ERREXIT_STATUS);
138
}
139
140
/*
141
 * beyond - call when we're beyond the end of the argument list (an
142
 *	error condition)
143
 */
144
static void
145
beyond ()
146
{
147
  test_syntax_error (_("argument expected"), (char *)NULL);
148
}
149
150
/* Syntax error for when an integer argument was expected, but
151
   something else was found. */
152
static void
153
integer_expected_error (pch)
154
     char *pch;
155
{
156
  test_syntax_error (_("%s: integer expression expected"), pch);
157
}
158
159
/* Increment our position in the argument list.  Check that we're not
160
   past the end of the argument list.  This check is suppressed if the
161
   argument is FALSE.  Made a macro for efficiency. */
162
#define advance(f) do { ++pos; if (f && pos >= argc) beyond (); } while (0)
163
#define unary_advance() do { advance (1); ++pos; } while (0)
164
165
/*
166
 * expr:
167
 *	or
168
 */
169
static int
170
expr ()
171
{
172
  if (pos >= argc)
173
    beyond ();
174
175
  return (FALSE ^ or ());		/* Same with this. */
176
}
177
178
/*
179
 * or:
180
 *	and
181
 *	and '-o' or
182
 */
183
static int
184
or ()
185
{
186
  int value, v2;
187
188
  value = and ();
189
  if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'o' && !argv[pos][2])
190
    {
191
      advance (0);
192
      v2 = or ();
193
      return (value || v2);
194
    }
195
196
  return (value);
197
}
198
199
/*
200
 * and:
201
 *	term
202
 *	term '-a' and
203
 */
204
static int
205
and ()
206
{
207
  int value, v2;
208
209
  value = term ();
210
  if (pos < argc && argv[pos][0] == '-' && argv[pos][1] == 'a' && !argv[pos][2])
211
    {
212
      advance (0);
213
      v2 = and ();
214
      return (value && v2);
215
    }
216
  return (value);
217
}
218
219
/*
220
 * term - parse a term and return 1 or 0 depending on whether the term
221
 *	evaluates to true or false, respectively.
222
 *
223
 * term ::=
224
 *	'-'('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'k'|'p'|'r'|'s'|'u'|'w'|'x') filename
225
 *	'-'('G'|'L'|'O'|'S'|'N') filename
226
 * 	'-t' [int]
227
 *	'-'('z'|'n') string
228
 *	'-o' option
229
 *	string
230
 *	string ('!='|'='|'==') string
231
 *	<int> '-'(eq|ne|le|lt|ge|gt) <int>
232
 *	file '-'(nt|ot|ef) file
233
 *	'(' <expr> ')'
234
 * int ::=
235
 *	positive and negative integers
236
 */
237
static int
238
term ()
239
{
240
  int value;
241
242
  if (pos >= argc)
243
    beyond ();
244
245
  /* Deal with leading `not's. */
246
  if (argv[pos][0] == '!' && argv[pos][1] == '\0')
247
    {
248
      value = 0;
249
      while (pos < argc && argv[pos][0] == '!' && argv[pos][1] == '\0')
250
	{
251
	  advance (1);
252
	  value = 1 - value;
253
	}
254
255
      return (value ? !term() : term());
256
    }
257
258
  /* A paren-bracketed argument. */
259
  if (argv[pos][0] == '(' && argv[pos][1] == '\0') /* ) */
260
    {
261
      advance (1);
262
      value = expr ();
263
      if (argv[pos] == 0) /* ( */
264
	test_syntax_error (_("`)' expected"), (char *)NULL);
265
      else if (argv[pos][0] != ')' || argv[pos][1]) /* ( */
266
	test_syntax_error (_("`)' expected, found %s"), argv[pos]);
267
      advance (0);
268
      return (value);
269
    }
270
271
  /* are there enough arguments left that this could be dyadic? */
272
  if ((pos + 3 <= argc) && test_binop (argv[pos + 1]))
273
    value = binary_operator ();
274
275
  /* Might be a switch type argument */
276
  else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
277
    {
278
      if (test_unop (argv[pos]))
279
	value = unary_operator ();
280
      else
281
	test_syntax_error (_("%s: unary operator expected"), argv[pos]);
282
    }
283
  else
284
    {
285
      value = argv[pos][0] != '\0';
286
      advance (0);
287
    }
288
289
  return (value);
290
}
291
292
static int
293
stat_mtime (fn, st, ts)
294
     char *fn;
295
     struct stat *st;
296
     struct timespec *ts;
297
{
298
  int r;
299
300
  r = sh_stat (fn, st);
301
  if (r < 0)
302
    return r;
303
  *ts = get_stat_mtime (st);
304
  return 0;
305
}
306
307
static int
308
filecomp (s, t, op)
309
     char *s, *t;
310
     int op;
311
{
312
  struct stat st1, st2;
313
  struct timespec ts1, ts2;
314
  int r1, r2;
315
316
  if ((r1 = stat_mtime (s, &st1, &ts1)) < 0)
317
    {
318
      if (op == EF)
319
	return (FALSE);
320
    }
321
  if ((r2 = stat_mtime (t, &st2, &ts2)) < 0)
322
    {
323
      if (op == EF)
324
	return (FALSE);
325
    }
326
  
327
  switch (op)
328
    {
329
    case OT: return (r1 < r2 || (r2 == 0 && timespec_cmp (ts1, ts2) < 0));
330
    case NT: return (r1 > r2 || (r1 == 0 && timespec_cmp (ts1, ts2) > 0));
331
    case EF: return (same_file (s, t, &st1, &st2));
332
    }
333
  return (FALSE);
334
}
335
336
static int
337
arithcomp (s, t, op, flags)
338
     char *s, *t;
339
     int op, flags;
340
{
341
  intmax_t l, r;
342
  int expok;
343
344
  if (flags & TEST_ARITHEXP)
345
    {
346
      l = evalexp (s, &expok);
347
      if (expok == 0)
348
	return (FALSE);		/* should probably longjmp here */
349
      r = evalexp (t, &expok);
350
      if (expok == 0)
351
	return (FALSE);		/* ditto */
352
    }
353
  else
354
    {
355
      if (legal_number (s, &l) == 0)
356
	integer_expected_error (s);
357
      if (legal_number (t, &r) == 0)
358
	integer_expected_error (t);
359
    }
360
361
  switch (op)
362
    {
363
    case EQ: return (l == r);
364
    case NE: return (l != r);
365
    case LT: return (l < r);
366
    case GT: return (l > r);
367
    case LE: return (l <= r);
368
    case GE: return (l >= r);
369
    }
370
371
  return (FALSE);
372
}
373
374
static int
375
patcomp (string, pat, op)
376
     char *string, *pat;
377
     int op;
378
{
379
  int m;
380
381
  m = strmatch (pat, string, FNMATCH_EXTFLAG|FNMATCH_IGNCASE);
382
  return ((op == EQ) ? (m == 0) : (m != 0));
383
}
384
385
int
386
binary_test (op, arg1, arg2, flags)
387
     char *op, *arg1, *arg2;
388
     int flags;
389
{
390
  int patmatch;
391
392
  patmatch = (flags & TEST_PATMATCH);
393
394
  if (op[0] == '=' && (op[1] == '\0' || (op[1] == '=' && op[2] == '\0')))
395
    return (patmatch ? patcomp (arg1, arg2, EQ) : STREQ (arg1, arg2));
396
  else if ((op[0] == '>' || op[0] == '<') && op[1] == '\0')
397
    {
398
#if defined (HAVE_STRCOLL)
399
      if (shell_compatibility_level > 40 && flags & TEST_LOCALE)
400
	return ((op[0] == '>') ? (strcoll (arg1, arg2) > 0) : (strcoll (arg1, arg2) < 0));
401
      else
402
#endif
403
	return ((op[0] == '>') ? (strcmp (arg1, arg2) > 0) : (strcmp (arg1, arg2) < 0));
404
    }
405
  else if (op[0] == '!' && op[1] == '=' && op[2] == '\0')
406
    return (patmatch ? patcomp (arg1, arg2, NE) : (STREQ (arg1, arg2) == 0));
407
    
408
409
  else if (op[2] == 't')
410
    {
411
      switch (op[1])
412
	{
413
	case 'n': return (filecomp (arg1, arg2, NT));		/* -nt */
414
	case 'o': return (filecomp (arg1, arg2, OT));		/* -ot */
415
	case 'l': return (arithcomp (arg1, arg2, LT, flags));	/* -lt */
416
	case 'g': return (arithcomp (arg1, arg2, GT, flags));	/* -gt */
417
	}
418
    }
419
  else if (op[1] == 'e')
420
    {
421
      switch (op[2])
422
	{
423
	case 'f': return (filecomp (arg1, arg2, EF));		/* -ef */
424
	case 'q': return (arithcomp (arg1, arg2, EQ, flags));	/* -eq */
425
	}
426
    }
427
  else if (op[2] == 'e')
428
    {
429
      switch (op[1])
430
	{
431
	case 'n': return (arithcomp (arg1, arg2, NE, flags));	/* -ne */
432
	case 'g': return (arithcomp (arg1, arg2, GE, flags));	/* -ge */
433
	case 'l': return (arithcomp (arg1, arg2, LE, flags));	/* -le */
434
	}
435
    }
436
437
  return (FALSE);	/* should never get here */
438
}
439
440
441
static int
442
binary_operator ()
443
{
444
  int value;
445
  char *w;
446
447
  w = argv[pos + 1];
448
  if ((w[0] == '=' && (w[1] == '\0' || (w[1] == '=' && w[2] == '\0'))) || /* =, == */
449
      ((w[0] == '>' || w[0] == '<') && w[1] == '\0') ||		/* <, > */
450
      (w[0] == '!' && w[1] == '=' && w[2] == '\0'))		/* != */
451
    {
452
      value = binary_test (w, argv[pos], argv[pos + 2], 0);
453
      pos += 3;
454
      return (value);
455
    }
456
457
#if defined (PATTERN_MATCHING)
458
  if ((w[0] == '=' || w[0] == '!') && w[1] == '~' && w[2] == '\0')
459
    {
460
      value = patcomp (argv[pos], argv[pos + 2], w[0] == '=' ? EQ : NE);
461
      pos += 3;
462
      return (value);
463
    }
464
#endif
465
466
  if ((w[0] != '-' || w[3] != '\0') || test_binop (w) == 0)
467
    {
468
      test_syntax_error (_("%s: binary operator expected"), w);
469
      /* NOTREACHED */
470
      return (FALSE);
471
    }
472
473
  value = binary_test (w, argv[pos], argv[pos + 2], 0);
474
  pos += 3;
475
  return value;
476
}
477
478
static int
479
unary_operator ()
480
{
481
  char *op;
482
  intmax_t r;
483
484
  op = argv[pos];
485
  if (test_unop (op) == 0)
486
    return (FALSE);
487
488
  /* the only tricky case is `-t', which may or may not take an argument. */
489
  if (op[1] == 't')
490
    {
491
      advance (0);
492
      if (pos < argc)
493
	{
494
	  if (legal_number (argv[pos], &r))
495
	    {
496
	      advance (0);
497
	      return (unary_test (op, argv[pos - 1]));
498
	    }
499
	  else
500
	    return (FALSE);
501
	}
502
      else
503
	return (unary_test (op, "1"));
504
    }
505
506
  /* All of the unary operators take an argument, so we first call
507
     unary_advance (), which checks to make sure that there is an
508
     argument, and then advances pos right past it.  This means that
509
     pos - 1 is the location of the argument. */
510
  unary_advance ();
511
  return (unary_test (op, argv[pos - 1]));
512
}
513
514
int
515
unary_test (op, arg)
516
     char *op, *arg;
517
{
518
  intmax_t r;
519
  struct stat stat_buf;
520
  SHELL_VAR *v;
521
     
522
  switch (op[1])
523
    {
524
    case 'a':			/* file exists in the file system? */
525
    case 'e':
526
      return (sh_stat (arg, &stat_buf) == 0);
527
528
    case 'r':			/* file is readable? */
529
      return (sh_eaccess (arg, R_OK) == 0);
530
531
    case 'w':			/* File is writeable? */
532
      return (sh_eaccess (arg, W_OK) == 0);
533
534
    case 'x':			/* File is executable? */
535
      return (sh_eaccess (arg, X_OK) == 0);
536
537
    case 'O':			/* File is owned by you? */
538
      return (sh_stat (arg, &stat_buf) == 0 &&
539
	      (uid_t) current_user.euid == (uid_t) stat_buf.st_uid);
540
541
    case 'G':			/* File is owned by your group? */
542
      return (sh_stat (arg, &stat_buf) == 0 &&
543
	      (gid_t) current_user.egid == (gid_t) stat_buf.st_gid);
544
545
    case 'N':
546
      return (sh_stat (arg, &stat_buf) == 0 &&
547
	      stat_buf.st_atime <= stat_buf.st_mtime);
548
549
    case 'f':			/* File is a file? */
550
      if (sh_stat (arg, &stat_buf) < 0)
551
	return (FALSE);
552
553
      /* -f is true if the given file exists and is a regular file. */
554
#if defined (S_IFMT)
555
      return (S_ISREG (stat_buf.st_mode) || (stat_buf.st_mode & S_IFMT) == 0);
556
#else
557
      return (S_ISREG (stat_buf.st_mode));
558
#endif /* !S_IFMT */
559
560
    case 'd':			/* File is a directory? */
561
      return (sh_stat (arg, &stat_buf) == 0 && (S_ISDIR (stat_buf.st_mode)));
562
563
    case 's':			/* File has something in it? */
564
      return (sh_stat (arg, &stat_buf) == 0 && stat_buf.st_size > (off_t) 0);
565
566
    case 'S':			/* File is a socket? */
567
#if !defined (S_ISSOCK)
568
      return (FALSE);
569
#else
570
      return (sh_stat (arg, &stat_buf) == 0 && S_ISSOCK (stat_buf.st_mode));
571
#endif /* S_ISSOCK */
572
573
    case 'c':			/* File is character special? */
574
      return (sh_stat (arg, &stat_buf) == 0 && S_ISCHR (stat_buf.st_mode));
575
576
    case 'b':			/* File is block special? */
577
      return (sh_stat (arg, &stat_buf) == 0 && S_ISBLK (stat_buf.st_mode));
578
579
    case 'p':			/* File is a named pipe? */
580
#ifndef S_ISFIFO
581
      return (FALSE);
582
#else
583
      return (sh_stat (arg, &stat_buf) == 0 && S_ISFIFO (stat_buf.st_mode));
584
#endif /* S_ISFIFO */
585
586
    case 'L':			/* Same as -h  */
587
    case 'h':			/* File is a symbolic link? */
588
#if !defined (S_ISLNK) || !defined (HAVE_LSTAT)
589
      return (FALSE);
590
#else
591
      return ((arg[0] != '\0') &&
592
	      (lstat (arg, &stat_buf) == 0) && S_ISLNK (stat_buf.st_mode));
593
#endif /* S_IFLNK && HAVE_LSTAT */
594
595
    case 'u':			/* File is setuid? */
596
      return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISUID) != 0);
597
598
    case 'g':			/* File is setgid? */
599
      return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISGID) != 0);
600
601
    case 'k':			/* File has sticky bit set? */
602
#if !defined (S_ISVTX)
603
      /* This is not Posix, and is not defined on some Posix systems. */
604
      return (FALSE);
605
#else
606
      return (sh_stat (arg, &stat_buf) == 0 && (stat_buf.st_mode & S_ISVTX) != 0);
607
#endif
608
609
    case 't':	/* File fd is a terminal? */
610
      if (legal_number (arg, &r) == 0)
611
	return (FALSE);
612
      return ((r == (int)r) && isatty ((int)r));
613
614
    case 'n':			/* True if arg has some length. */
615
      return (arg[0] != '\0');
616
617
    case 'z':			/* True if arg has no length. */
618
      return (arg[0] == '\0');
619
620
    case 'o':			/* True if option `arg' is set. */
621
      return (minus_o_option_value (arg) == 1);
622
623
    case 'v':
624
      v = find_variable (arg);
1.4.3 by Matthias Klose
Import upstream version 4.3
625
#if defined (ARRAY_VARS)
626
      if (v == 0 && valid_array_reference (arg))
627
	{
628
	  char *t;
629
	  t = array_value (arg, 0, 0, (int *)0, (arrayind_t *)0);
630
	  return (t ? TRUE : FALSE);
631
	}
632
     else if (v && invisible_p (v) == 0 && array_p (v))
633
	{
634
	  char *t;
635
	  /* [[ -v foo ]] == [[ -v foo[0] ]] */
636
	  t = array_reference (array_cell (v), 0);
637
	  return (t ? TRUE : FALSE);
638
	}
639
      else if (v && invisible_p (v) == 0 && assoc_p (v))
640
	{
641
	  char *t;
642
	  t = assoc_reference (assoc_cell (v), "0");
643
	  return (t ? TRUE : FALSE);
644
	}
645
#endif
1.5.1 by Matthias Klose
Import upstream version 4.3~rc1
646
      return (v && invisible_p (v) == 0 && var_isset (v) ? TRUE : FALSE);
647
648
    case 'R':
2.1.25 by Matthias Klose
* Apply upstream patches 001 - 008:
649
      v = find_variable_noref (arg);
650
      return ((v && invisible_p (v) == 0 && var_isset (v) && nameref_p (v)) ? TRUE : FALSE);
1.5.1 by Matthias Klose
Import upstream version 4.3~rc1
651
    }
652
653
  /* We can't actually get here, but this shuts up gcc. */
654
  return (FALSE);
655
}
656
657
/* Return TRUE if OP is one of the test command's binary operators. */
658
int
659
test_binop (op)
660
     char *op;
661
{
662
  if (op[0] == '=' && op[1] == '\0')
663
    return (1);		/* '=' */
664
  else if ((op[0] == '<' || op[0] == '>') && op[1] == '\0')  /* string <, > */
665
    return (1);
666
  else if ((op[0] == '=' || op[0] == '!') && op[1] == '=' && op[2] == '\0')
667
    return (1);		/* `==' and `!=' */
668
#if defined (PATTERN_MATCHING)
669
  else if (op[2] == '\0' && op[1] == '~' && (op[0] == '=' || op[0] == '!'))
670
    return (1);
671
#endif
672
  else if (op[0] != '-' || op[2] == '\0' || op[3] != '\0')
673
    return (0);
674
  else
675
    {
676
      if (op[2] == 't')
677
	switch (op[1])
678
	  {
679
	  case 'n':		/* -nt */
680
	  case 'o':		/* -ot */
681
	  case 'l':		/* -lt */
682
	  case 'g':		/* -gt */
683
	    return (1);
684
	  default:
685
	    return (0);
686
	  }
687
      else if (op[1] == 'e')
688
	switch (op[2])
689
	  {
690
	  case 'q':		/* -eq */
691
	  case 'f':		/* -ef */
692
	    return (1);
693
	  default:
694
	    return (0);
695
	  }
696
      else if (op[2] == 'e')
697
	switch (op[1])
698
	  {
699
	  case 'n':		/* -ne */
700
	  case 'g':		/* -ge */
701
	  case 'l':		/* -le */
702
	    return (1);
703
	  default:
704
	    return (0);
705
	  }
706
      else
707
	return (0);
708
    }
709
}
710
711
/* Return non-zero if OP is one of the test command's unary operators. */
712
int
713
test_unop (op)
714
     char *op;
715
{
716
  if (op[0] != '-' || op[2] != 0)
717
    return (0);
718
719
  switch (op[1])
720
    {
721
    case 'a': case 'b': case 'c': case 'd': case 'e':
722
    case 'f': case 'g': case 'h': case 'k': case 'n':
723
    case 'o': case 'p': case 'r': case 's': case 't':
724
    case 'u': case 'v': case 'w': case 'x': case 'z':
725
    case 'G': case 'L': case 'O': case 'S': case 'N':
2.1.25 by Matthias Klose
* Apply upstream patches 001 - 008:
726
    case 'R':
1.5.1 by Matthias Klose
Import upstream version 4.3~rc1
727
      return (1);
728
    }
729
730
  return (0);
731
}
732
733
static int
734
two_arguments ()
735
{
736
  if (argv[pos][0] == '!' && argv[pos][1] == '\0')
737
    return (argv[pos + 1][0] == '\0');
738
  else if (argv[pos][0] == '-' && argv[pos][2] == '\0')
739
    {
740
      if (test_unop (argv[pos]))
741
	return (unary_operator ());
742
      else
743
	test_syntax_error (_("%s: unary operator expected"), argv[pos]);
744
    }
745
  else
746
    test_syntax_error (_("%s: unary operator expected"), argv[pos]);
747
748
  return (0);
749
}
750
751
#define ANDOR(s)  (s[0] == '-' && !s[2] && (s[1] == 'a' || s[1] == 'o'))
752
753
/* This could be augmented to handle `-t' as equivalent to `-t 1', but
754
   POSIX requires that `-t' be given an argument. */
755
#define ONE_ARG_TEST(s)		((s)[0] != '\0')
756
757
static int
758
three_arguments ()
759
{
760
  int value;
761
762
  if (test_binop (argv[pos+1]))
763
    {
764
      value = binary_operator ();
765
      pos = argc;
766
    }
767
  else if (ANDOR (argv[pos+1]))
768
    {
769
      if (argv[pos+1][1] == 'a')
770
	value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]);
771
      else
772
	value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]);
773
      pos = argc;
774
    }
775
  else if (argv[pos][0] == '!' && argv[pos][1] == '\0')
776
    {
777
      advance (1);
778
      value = !two_arguments ();
779
    }
780
  else if (argv[pos][0] == '(' && argv[pos+2][0] == ')')
781
    {
782
      value = ONE_ARG_TEST(argv[pos+1]);
783
      pos = argc;
784
    }
785
  else
786
    test_syntax_error (_("%s: binary operator expected"), argv[pos+1]);
787
788
  return (value);
789
}
790
791
/* This is an implementation of a Posix.2 proposal by David Korn. */
792
static int
793
posixtest ()
794
{
795
  int value;
796
797
  switch (argc - 1)	/* one extra passed in */
798
    {
799
      case 0:
800
	value = FALSE;
801
	pos = argc;
802
	break;
803
804
      case 1:
805
	value = ONE_ARG_TEST(argv[1]);
806
	pos = argc;
807
	break;
808
809
      case 2:
810
	value = two_arguments ();
811
	pos = argc;
812
	break;
813
814
      case 3:
815
	value = three_arguments ();
816
	break;
817
818
      case 4:
819
	if (argv[pos][0] == '!' && argv[pos][1] == '\0')
820
	  {
821
	    advance (1);
822
	    value = !three_arguments ();
823
	    break;
824
	  }
825
	/* FALLTHROUGH */
826
      default:
827
	value = expr ();
828
    }
829
830
  return (value);
831
}
832
833
/*
834
 * [:
835
 *	'[' expr ']'
836
 * test:
837
 *	test expr
838
 */
839
int
840
test_command (margc, margv)
841
     int margc;
842
     char **margv;
843
{
844
  int value;
845
  int code;
846
847
  USE_VAR(margc);
848
849
  code = setjmp_nosigs (test_exit_buf);
850
851
  if (code)
852
    return (test_error_return);
853
854
  argv = margv;
855
856
  if (margv[0] && margv[0][0] == '[' && margv[0][1] == '\0')
857
    {
858
      --margc;
859
860
      if (margv[margc] && (margv[margc][0] != ']' || margv[margc][1]))
861
	test_syntax_error (_("missing `]'"), (char *)NULL);
862
863
      if (margc < 2)
864
	test_exit (SHELL_BOOLEAN (FALSE));
865
    }
866
867
  argc = margc;
868
  pos = 1;
869
870
  if (pos >= argc)
871
    test_exit (SHELL_BOOLEAN (FALSE));
872
873
  noeval = 0;
874
  value = posixtest ();
875
876
  if (pos != argc)
877
    test_syntax_error (_("too many arguments"), (char *)NULL);
878
879
  test_exit (SHELL_BOOLEAN (value));
880
}