Subversion Repositories HelenOS

Rev

Rev 2714 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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