diff options
author | Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> | 2007-11-16 12:20:30 +0000 |
---|---|---|
committer | Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> | 2007-11-16 12:20:30 +0000 |
commit | a702457eac1d2b014f108f78605d7fb6424b5844 (patch) | |
tree | 00467733cd82e82073657f53a8a0aceb659cc2b2 /coreutils | |
parent | e8979889b4dc2a995c4136820952a8468a09f066 (diff) | |
download | busybox-w32-a702457eac1d2b014f108f78605d7fb6424b5844.tar.gz busybox-w32-a702457eac1d2b014f108f78605d7fb6424b5844.tar.bz2 busybox-w32-a702457eac1d2b014f108f78605d7fb6424b5844.zip |
- remove most of the forward declarations. No obj-code changes.
Diffstat (limited to 'coreutils')
-rw-r--r-- | coreutils/test.c | 485 |
1 files changed, 241 insertions, 244 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index 3c57cf418..0b94100c1 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
@@ -161,90 +161,7 @@ static gid_t *group_array; | |||
161 | static int ngroups; | 161 | static int ngroups; |
162 | static jmp_buf leaving; | 162 | static jmp_buf leaving; |
163 | 163 | ||
164 | static enum token t_lex(char *s); | ||
165 | static arith_t oexpr(enum token n); | ||
166 | static arith_t aexpr(enum token n); | ||
167 | static arith_t nexpr(enum token n); | ||
168 | static int binop(void); | ||
169 | static arith_t primary(enum token n); | 164 | static arith_t primary(enum token n); |
170 | static int filstat(char *nm, enum token mode); | ||
171 | static arith_t getn(const char *s); | ||
172 | /* UNUSED | ||
173 | static int newerf(const char *f1, const char *f2); | ||
174 | static int olderf(const char *f1, const char *f2); | ||
175 | static int equalf(const char *f1, const char *f2); | ||
176 | */ | ||
177 | static int test_eaccess(char *path, int mode); | ||
178 | static int is_a_group_member(gid_t gid); | ||
179 | static void initialize_group_array(void); | ||
180 | |||
181 | int test_main(int argc, char **argv) | ||
182 | { | ||
183 | int res; | ||
184 | const char *arg0; | ||
185 | bool _off; | ||
186 | |||
187 | arg0 = bb_basename(argv[0]); | ||
188 | if (arg0[0] == '[') { | ||
189 | --argc; | ||
190 | if (!arg0[1]) { /* "[" ? */ | ||
191 | if (NOT_LONE_CHAR(argv[argc], ']')) { | ||
192 | bb_error_msg("missing ]"); | ||
193 | return 2; | ||
194 | } | ||
195 | } else { /* assuming "[[" */ | ||
196 | if (strcmp(argv[argc], "]]") != 0) { | ||
197 | bb_error_msg("missing ]]"); | ||
198 | return 2; | ||
199 | } | ||
200 | } | ||
201 | argv[argc] = NULL; | ||
202 | } | ||
203 | |||
204 | res = setjmp(leaving); | ||
205 | if (res) | ||
206 | return res; | ||
207 | |||
208 | /* resetting ngroups is probably unnecessary. it will | ||
209 | * force a new call to getgroups(), which prevents using | ||
210 | * group data fetched during a previous call. but the | ||
211 | * only way the group data could be stale is if there's | ||
212 | * been an intervening call to setgroups(), and this | ||
213 | * isn't likely in the case of a shell. paranoia | ||
214 | * prevails... | ||
215 | */ | ||
216 | ngroups = 0; | ||
217 | |||
218 | /* Implement special cases from POSIX.2, section 4.62.4 */ | ||
219 | if (argc == 1) | ||
220 | return 1; | ||
221 | if (argc == 2) | ||
222 | return *argv[1] == '\0'; | ||
223 | //assert(argc); | ||
224 | /* remember if we saw argc==4 which wants *no* '!' test */ | ||
225 | _off = argc - 4; | ||
226 | if (_off ? | ||
227 | (LONE_CHAR(argv[1], '!')) | ||
228 | : (argv[1][0] != '!' || argv[1][1] != '\0')) | ||
229 | { | ||
230 | if (argc == 3) | ||
231 | return *argv[2] != '\0'; | ||
232 | |||
233 | t_lex(argv[2 + _off]); | ||
234 | if (t_wp_op && t_wp_op->op_type == BINOP) { | ||
235 | t_wp = &argv[1 + _off]; | ||
236 | return binop() == _off; | ||
237 | } | ||
238 | } | ||
239 | t_wp = &argv[1]; | ||
240 | res = !oexpr(t_lex(*t_wp)); | ||
241 | |||
242 | if (*t_wp != NULL && *++t_wp != NULL) { | ||
243 | bb_error_msg("%s: unknown operand", *t_wp); | ||
244 | return 2; | ||
245 | } | ||
246 | return res; | ||
247 | } | ||
248 | 165 | ||
249 | static void syntax(const char *op, const char *msg) ATTRIBUTE_NORETURN; | 166 | static void syntax(const char *op, const char *msg) ATTRIBUTE_NORETURN; |
250 | static void syntax(const char *op, const char *msg) | 167 | static void syntax(const char *op, const char *msg) |
@@ -257,70 +174,83 @@ static void syntax(const char *op, const char *msg) | |||
257 | longjmp(leaving, 2); | 174 | longjmp(leaving, 2); |
258 | } | 175 | } |
259 | 176 | ||
260 | static arith_t oexpr(enum token n) | 177 | /* atoi with error detection */ |
178 | //XXX: FIXME: duplicate of existing libbb function? | ||
179 | static arith_t getn(const char *s) | ||
261 | { | 180 | { |
262 | arith_t res; | 181 | char *p; |
182 | #if ENABLE_FEATURE_TEST_64 | ||
183 | long long r; | ||
184 | #else | ||
185 | long r; | ||
186 | #endif | ||
263 | 187 | ||
264 | res = aexpr(n); | 188 | errno = 0; |
265 | if (t_lex(*++t_wp) == BOR) { | 189 | #if ENABLE_FEATURE_TEST_64 |
266 | return oexpr(t_lex(*++t_wp)) || res; | 190 | r = strtoll(s, &p, 10); |
267 | } | 191 | #else |
268 | t_wp--; | 192 | r = strtol(s, &p, 10); |
269 | return res; | 193 | #endif |
194 | |||
195 | if (errno != 0) | ||
196 | syntax(s, "out of range"); | ||
197 | |||
198 | if (*(skip_whitespace(p))) | ||
199 | syntax(s, "bad number"); | ||
200 | |||
201 | return r; | ||
270 | } | 202 | } |
271 | 203 | ||
272 | static arith_t aexpr(enum token n) | 204 | /* UNUSED |
205 | static int newerf(const char *f1, const char *f2) | ||
273 | { | 206 | { |
274 | arith_t res; | 207 | struct stat b1, b2; |
275 | 208 | ||
276 | res = nexpr(n); | 209 | return (stat(f1, &b1) == 0 && |
277 | if (t_lex(*++t_wp) == BAND) | 210 | stat(f2, &b2) == 0 && b1.st_mtime > b2.st_mtime); |
278 | return aexpr(t_lex(*++t_wp)) && res; | ||
279 | t_wp--; | ||
280 | return res; | ||
281 | } | 211 | } |
282 | 212 | ||
283 | static arith_t nexpr(enum token n) | 213 | static int olderf(const char *f1, const char *f2) |
284 | { | 214 | { |
285 | if (n == UNOT) | 215 | struct stat b1, b2; |
286 | return !nexpr(t_lex(*++t_wp)); | 216 | |
287 | return primary(n); | 217 | return (stat(f1, &b1) == 0 && |
218 | stat(f2, &b2) == 0 && b1.st_mtime < b2.st_mtime); | ||
288 | } | 219 | } |
289 | 220 | ||
290 | static arith_t primary(enum token n) | 221 | static int equalf(const char *f1, const char *f2) |
291 | { | 222 | { |
292 | arith_t res; | 223 | struct stat b1, b2; |
293 | 224 | ||
294 | if (n == EOI) { | 225 | return (stat(f1, &b1) == 0 && |
295 | syntax(NULL, "argument expected"); | 226 | stat(f2, &b2) == 0 && |
296 | } | 227 | b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino); |
297 | if (n == LPAREN) { | 228 | } |
298 | res = oexpr(t_lex(*++t_wp)); | 229 | */ |
299 | if (t_lex(*++t_wp) != RPAREN) | ||
300 | syntax(NULL, "closing paren expected"); | ||
301 | return res; | ||
302 | } | ||
303 | if (t_wp_op && t_wp_op->op_type == UNOP) { | ||
304 | /* unary expression */ | ||
305 | if (*++t_wp == NULL) | ||
306 | syntax(t_wp_op->op_text, "argument expected"); | ||
307 | if (n == STREZ) | ||
308 | return t_wp[0][0] == '\0'; | ||
309 | if (n == STRNZ) | ||
310 | return t_wp[0][0] != '\0'; | ||
311 | if (n == FILTT) | ||
312 | return isatty(getn(*t_wp)); | ||
313 | return filstat(*t_wp, n); | ||
314 | } | ||
315 | 230 | ||
316 | t_lex(t_wp[1]); | 231 | |
317 | if (t_wp_op && t_wp_op->op_type == BINOP) { | 232 | static enum token t_lex(char *s) |
318 | return binop(); | 233 | { |
234 | const struct t_op *op; | ||
235 | |||
236 | t_wp_op = NULL; | ||
237 | if (s == NULL) { | ||
238 | return EOI; | ||
319 | } | 239 | } |
320 | 240 | ||
321 | return t_wp[0][0] != '\0'; | 241 | op = ops; |
242 | do { | ||
243 | if (strcmp(s, op->op_text) == 0) { | ||
244 | t_wp_op = op; | ||
245 | return op->op_num; | ||
246 | } | ||
247 | op++; | ||
248 | } while (op < ops + ARRAY_SIZE(ops)); | ||
249 | |||
250 | return OPERAND; | ||
322 | } | 251 | } |
323 | 252 | ||
253 | |||
324 | static int binop(void) | 254 | static int binop(void) |
325 | { | 255 | { |
326 | const char *opnd1, *opnd2; | 256 | const char *opnd1, *opnd2; |
@@ -381,6 +311,80 @@ static int binop(void) | |||
381 | return 1; /* NOTREACHED */ | 311 | return 1; /* NOTREACHED */ |
382 | } | 312 | } |
383 | 313 | ||
314 | |||
315 | static void initialize_group_array(void) | ||
316 | { | ||
317 | ngroups = getgroups(0, NULL); | ||
318 | if (ngroups > 0) { | ||
319 | /* FIXME: ash tries so hard to not die on OOM, | ||
320 | * and we spoil it with just one xrealloc here */ | ||
321 | /* We realloc, because test_main can be entered repeatedly by shell. | ||
322 | * Testcase (ash): 'while true; do test -x some_file; done' | ||
323 | * and watch top. (some_file must have owner != you) */ | ||
324 | group_array = xrealloc(group_array, ngroups * sizeof(gid_t)); | ||
325 | getgroups(ngroups, group_array); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | |||
330 | /* Return non-zero if GID is one that we have in our groups list. */ | ||
331 | //XXX: FIXME: duplicate of existing libbb function? | ||
332 | // see toplevel TODO file: | ||
333 | // possible code duplication ingroup() and is_a_group_member() | ||
334 | static int is_a_group_member(gid_t gid) | ||
335 | { | ||
336 | int i; | ||
337 | |||
338 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ | ||
339 | if (gid == getgid() || gid == getegid()) | ||
340 | return 1; | ||
341 | |||
342 | if (ngroups == 0) | ||
343 | initialize_group_array(); | ||
344 | |||
345 | /* Search through the list looking for GID. */ | ||
346 | for (i = 0; i < ngroups; i++) | ||
347 | if (gid == group_array[i]) | ||
348 | return 1; | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | |||
354 | /* Do the same thing access(2) does, but use the effective uid and gid, | ||
355 | and don't make the mistake of telling root that any file is | ||
356 | executable. */ | ||
357 | static int test_eaccess(char *path, int mode) | ||
358 | { | ||
359 | struct stat st; | ||
360 | unsigned int euid = geteuid(); | ||
361 | |||
362 | if (stat(path, &st) < 0) | ||
363 | return -1; | ||
364 | |||
365 | if (euid == 0) { | ||
366 | /* Root can read or write any file. */ | ||
367 | if (mode != X_OK) | ||
368 | return 0; | ||
369 | |||
370 | /* Root can execute any file that has any one of the execute | ||
371 | bits set. */ | ||
372 | if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | if (st.st_uid == euid) /* owner */ | ||
377 | mode <<= 6; | ||
378 | else if (is_a_group_member(st.st_gid)) | ||
379 | mode <<= 3; | ||
380 | |||
381 | if (st.st_mode & mode) | ||
382 | return 0; | ||
383 | |||
384 | return -1; | ||
385 | } | ||
386 | |||
387 | |||
384 | static int filstat(char *nm, enum token mode) | 388 | static int filstat(char *nm, enum token mode) |
385 | { | 389 | { |
386 | struct stat s; | 390 | struct stat s; |
@@ -453,147 +457,140 @@ static int filstat(char *nm, enum token mode) | |||
453 | return 1; /* NOTREACHED */ | 457 | return 1; /* NOTREACHED */ |
454 | } | 458 | } |
455 | 459 | ||
456 | static enum token t_lex(char *s) | ||
457 | { | ||
458 | const struct t_op *op; | ||
459 | |||
460 | t_wp_op = NULL; | ||
461 | if (s == NULL) { | ||
462 | return EOI; | ||
463 | } | ||
464 | |||
465 | op = ops; | ||
466 | do { | ||
467 | if (strcmp(s, op->op_text) == 0) { | ||
468 | t_wp_op = op; | ||
469 | return op->op_num; | ||
470 | } | ||
471 | op++; | ||
472 | } while (op < ops + ARRAY_SIZE(ops)); | ||
473 | 460 | ||
474 | return OPERAND; | 461 | static arith_t nexpr(enum token n) |
475 | } | ||
476 | |||
477 | /* atoi with error detection */ | ||
478 | //XXX: FIXME: duplicate of existing libbb function? | ||
479 | static arith_t getn(const char *s) | ||
480 | { | 462 | { |
481 | char *p; | 463 | if (n == UNOT) |
482 | #if ENABLE_FEATURE_TEST_64 | 464 | return !nexpr(t_lex(*++t_wp)); |
483 | long long r; | 465 | return primary(n); |
484 | #else | ||
485 | long r; | ||
486 | #endif | ||
487 | |||
488 | errno = 0; | ||
489 | #if ENABLE_FEATURE_TEST_64 | ||
490 | r = strtoll(s, &p, 10); | ||
491 | #else | ||
492 | r = strtol(s, &p, 10); | ||
493 | #endif | ||
494 | |||
495 | if (errno != 0) | ||
496 | syntax(s, "out of range"); | ||
497 | |||
498 | if (*(skip_whitespace(p))) | ||
499 | syntax(s, "bad number"); | ||
500 | |||
501 | return r; | ||
502 | } | 466 | } |
503 | 467 | ||
504 | /* UNUSED | ||
505 | static int newerf(const char *f1, const char *f2) | ||
506 | { | ||
507 | struct stat b1, b2; | ||
508 | 468 | ||
509 | return (stat(f1, &b1) == 0 && | 469 | static arith_t aexpr(enum token n) |
510 | stat(f2, &b2) == 0 && b1.st_mtime > b2.st_mtime); | ||
511 | } | ||
512 | |||
513 | static int olderf(const char *f1, const char *f2) | ||
514 | { | 470 | { |
515 | struct stat b1, b2; | 471 | arith_t res; |
516 | 472 | ||
517 | return (stat(f1, &b1) == 0 && | 473 | res = nexpr(n); |
518 | stat(f2, &b2) == 0 && b1.st_mtime < b2.st_mtime); | 474 | if (t_lex(*++t_wp) == BAND) |
475 | return aexpr(t_lex(*++t_wp)) && res; | ||
476 | t_wp--; | ||
477 | return res; | ||
519 | } | 478 | } |
520 | 479 | ||
521 | static int equalf(const char *f1, const char *f2) | 480 | |
481 | static arith_t oexpr(enum token n) | ||
522 | { | 482 | { |
523 | struct stat b1, b2; | 483 | arith_t res; |
524 | 484 | ||
525 | return (stat(f1, &b1) == 0 && | 485 | res = aexpr(n); |
526 | stat(f2, &b2) == 0 && | 486 | if (t_lex(*++t_wp) == BOR) { |
527 | b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino); | 487 | return oexpr(t_lex(*++t_wp)) || res; |
488 | } | ||
489 | t_wp--; | ||
490 | return res; | ||
528 | } | 491 | } |
529 | */ | ||
530 | 492 | ||
531 | /* Do the same thing access(2) does, but use the effective uid and gid, | ||
532 | and don't make the mistake of telling root that any file is | ||
533 | executable. */ | ||
534 | static int test_eaccess(char *path, int mode) | ||
535 | { | ||
536 | struct stat st; | ||
537 | unsigned int euid = geteuid(); | ||
538 | 493 | ||
539 | if (stat(path, &st) < 0) | ||
540 | return -1; | ||
541 | 494 | ||
542 | if (euid == 0) { | 495 | static arith_t primary(enum token n) |
543 | /* Root can read or write any file. */ | 496 | { |
544 | if (mode != X_OK) | 497 | arith_t res; |
545 | return 0; | ||
546 | 498 | ||
547 | /* Root can execute any file that has any one of the execute | 499 | if (n == EOI) { |
548 | bits set. */ | 500 | syntax(NULL, "argument expected"); |
549 | if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) | 501 | } |
550 | return 0; | 502 | if (n == LPAREN) { |
503 | res = oexpr(t_lex(*++t_wp)); | ||
504 | if (t_lex(*++t_wp) != RPAREN) | ||
505 | syntax(NULL, "closing paren expected"); | ||
506 | return res; | ||
507 | } | ||
508 | if (t_wp_op && t_wp_op->op_type == UNOP) { | ||
509 | /* unary expression */ | ||
510 | if (*++t_wp == NULL) | ||
511 | syntax(t_wp_op->op_text, "argument expected"); | ||
512 | if (n == STREZ) | ||
513 | return t_wp[0][0] == '\0'; | ||
514 | if (n == STRNZ) | ||
515 | return t_wp[0][0] != '\0'; | ||
516 | if (n == FILTT) | ||
517 | return isatty(getn(*t_wp)); | ||
518 | return filstat(*t_wp, n); | ||
551 | } | 519 | } |
552 | 520 | ||
553 | if (st.st_uid == euid) /* owner */ | 521 | t_lex(t_wp[1]); |
554 | mode <<= 6; | 522 | if (t_wp_op && t_wp_op->op_type == BINOP) { |
555 | else if (is_a_group_member(st.st_gid)) | 523 | return binop(); |
556 | mode <<= 3; | 524 | } |
557 | |||
558 | if (st.st_mode & mode) | ||
559 | return 0; | ||
560 | 525 | ||
561 | return -1; | 526 | return t_wp[0][0] != '\0'; |
562 | } | 527 | } |
563 | 528 | ||
564 | static void initialize_group_array(void) | 529 | |
530 | int test_main(int argc, char **argv) | ||
565 | { | 531 | { |
566 | ngroups = getgroups(0, NULL); | 532 | int res; |
567 | if (ngroups > 0) { | 533 | const char *arg0; |
568 | /* FIXME: ash tries so hard to not die on OOM, | 534 | bool _off; |
569 | * and we spoil it with just one xrealloc here */ | 535 | |
570 | /* We realloc, because test_main can be entered repeatedly by shell. | 536 | arg0 = bb_basename(argv[0]); |
571 | * Testcase (ash): 'while true; do test -x some_file; done' | 537 | if (arg0[0] == '[') { |
572 | * and watch top. (some_file must have owner != you) */ | 538 | --argc; |
573 | group_array = xrealloc(group_array, ngroups * sizeof(gid_t)); | 539 | if (!arg0[1]) { /* "[" ? */ |
574 | getgroups(ngroups, group_array); | 540 | if (NOT_LONE_CHAR(argv[argc], ']')) { |
541 | bb_error_msg("missing ]"); | ||
542 | return 2; | ||
543 | } | ||
544 | } else { /* assuming "[[" */ | ||
545 | if (strcmp(argv[argc], "]]") != 0) { | ||
546 | bb_error_msg("missing ]]"); | ||
547 | return 2; | ||
548 | } | ||
549 | } | ||
550 | argv[argc] = NULL; | ||
575 | } | 551 | } |
576 | } | ||
577 | 552 | ||
578 | /* Return non-zero if GID is one that we have in our groups list. */ | 553 | res = setjmp(leaving); |
579 | //XXX: FIXME: duplicate of existing libbb function? | 554 | if (res) |
580 | // see toplevel TODO file: | 555 | return res; |
581 | // possible code duplication ingroup() and is_a_group_member() | ||
582 | static int is_a_group_member(gid_t gid) | ||
583 | { | ||
584 | int i; | ||
585 | 556 | ||
586 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ | 557 | /* resetting ngroups is probably unnecessary. it will |
587 | if (gid == getgid() || gid == getegid()) | 558 | * force a new call to getgroups(), which prevents using |
588 | return 1; | 559 | * group data fetched during a previous call. but the |
560 | * only way the group data could be stale is if there's | ||
561 | * been an intervening call to setgroups(), and this | ||
562 | * isn't likely in the case of a shell. paranoia | ||
563 | * prevails... | ||
564 | */ | ||
565 | ngroups = 0; | ||
589 | 566 | ||
590 | if (ngroups == 0) | 567 | /* Implement special cases from POSIX.2, section 4.62.4 */ |
591 | initialize_group_array(); | 568 | if (argc == 1) |
569 | return 1; | ||
570 | if (argc == 2) | ||
571 | return *argv[1] == '\0'; | ||
572 | //assert(argc); | ||
573 | /* remember if we saw argc==4 which wants *no* '!' test */ | ||
574 | _off = argc - 4; | ||
575 | if (_off ? | ||
576 | (LONE_CHAR(argv[1], '!')) | ||
577 | : (argv[1][0] != '!' || argv[1][1] != '\0')) | ||
578 | { | ||
579 | if (argc == 3) | ||
580 | return *argv[2] != '\0'; | ||
592 | 581 | ||
593 | /* Search through the list looking for GID. */ | 582 | t_lex(argv[2 + _off]); |
594 | for (i = 0; i < ngroups; i++) | 583 | if (t_wp_op && t_wp_op->op_type == BINOP) { |
595 | if (gid == group_array[i]) | 584 | t_wp = &argv[1 + _off]; |
596 | return 1; | 585 | return binop() == _off; |
586 | } | ||
587 | } | ||
588 | t_wp = &argv[1]; | ||
589 | res = !oexpr(t_lex(*t_wp)); | ||
597 | 590 | ||
598 | return 0; | 591 | if (*t_wp != NULL && *++t_wp != NULL) { |
592 | bb_error_msg("%s: unknown operand", *t_wp); | ||
593 | return 2; | ||
594 | } | ||
595 | return res; | ||
599 | } | 596 | } |