diff options
-rw-r--r-- | coreutils/test.c | 91 | ||||
-rw-r--r-- | include/libbb.h | 14 | ||||
-rw-r--r-- | libbb/bb_getgroups.c | 34 | ||||
-rw-r--r-- | libbb/hash_md5_sha.c | 2 | ||||
-rw-r--r-- | networking/libiproute/iplink.c | 21 | ||||
-rw-r--r-- | shell/ash.c | 56 |
6 files changed, 169 insertions, 49 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index 008d90b25..b63e33cc0 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
@@ -426,8 +426,7 @@ struct test_statics { | |||
426 | /* set only by check_operator(), either to bogus struct | 426 | /* set only by check_operator(), either to bogus struct |
427 | * or points to matching operator_t struct. Never NULL. */ | 427 | * or points to matching operator_t struct. Never NULL. */ |
428 | const struct operator_t *last_operator; | 428 | const struct operator_t *last_operator; |
429 | gid_t *group_array; | 429 | struct cached_groupinfo *groupinfo; |
430 | int ngroups; | ||
431 | #if BASH_TEST2 | 430 | #if BASH_TEST2 |
432 | bool bash_test2; | 431 | bool bash_test2; |
433 | #endif | 432 | #endif |
@@ -440,8 +439,7 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; | |||
440 | #define S (*test_ptr_to_statics) | 439 | #define S (*test_ptr_to_statics) |
441 | #define args (S.args ) | 440 | #define args (S.args ) |
442 | #define last_operator (S.last_operator) | 441 | #define last_operator (S.last_operator) |
443 | #define group_array (S.group_array ) | 442 | #define groupinfo (S.groupinfo ) |
444 | #define ngroups (S.ngroups ) | ||
445 | #define bash_test2 (S.bash_test2 ) | 443 | #define bash_test2 (S.bash_test2 ) |
446 | #define leaving (S.leaving ) | 444 | #define leaving (S.leaving ) |
447 | 445 | ||
@@ -449,7 +447,6 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; | |||
449 | XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ | 447 | XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ |
450 | } while (0) | 448 | } while (0) |
451 | #define DEINIT_S() do { \ | 449 | #define DEINIT_S() do { \ |
452 | free(group_array); \ | ||
453 | free(test_ptr_to_statics); \ | 450 | free(test_ptr_to_statics); \ |
454 | } while (0) | 451 | } while (0) |
455 | 452 | ||
@@ -637,62 +634,52 @@ static int binop(void) | |||
637 | /*return 1; - NOTREACHED */ | 634 | /*return 1; - NOTREACHED */ |
638 | } | 635 | } |
639 | 636 | ||
640 | static void initialize_group_array(void) | ||
641 | { | ||
642 | group_array = bb_getgroups(&ngroups, NULL); | ||
643 | } | ||
644 | |||
645 | /* Return non-zero if GID is one that we have in our groups list. */ | 637 | /* Return non-zero if GID is one that we have in our groups list. */ |
646 | //XXX: FIXME: duplicate of existing libbb function? | ||
647 | // see toplevel TODO file: | ||
648 | // possible code duplication ingroup() and is_a_group_member() | ||
649 | static int is_a_group_member(gid_t gid) | 638 | static int is_a_group_member(gid_t gid) |
650 | { | 639 | { |
651 | int i; | ||
652 | |||
653 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ | 640 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ |
654 | if (gid == getgid() || gid == getegid()) | 641 | if (gid == get_cached_egid(&groupinfo->egid)) |
655 | return 1; | 642 | return 1; |
656 | 643 | ||
657 | if (ngroups == 0) | 644 | return is_in_supplementary_groups(groupinfo, gid); |
658 | initialize_group_array(); | ||
659 | |||
660 | /* Search through the list looking for GID. */ | ||
661 | for (i = 0; i < ngroups; i++) | ||
662 | if (gid == group_array[i]) | ||
663 | return 1; | ||
664 | |||
665 | return 0; | ||
666 | } | 645 | } |
667 | 646 | ||
668 | 647 | /* | |
669 | /* Do the same thing access(2) does, but use the effective uid and gid, | 648 | * Similar to what access(2) does, but uses the effective uid and gid. |
670 | and don't make the mistake of telling root that any file is | 649 | * Doesn't make the mistake of telling root that any file is executable. |
671 | executable. */ | 650 | * Returns non-zero if the file is accessible. |
672 | static int test_eaccess(struct stat *st, int mode) | 651 | */ |
652 | static int test_st_mode(struct stat *st, int mode) | ||
673 | { | 653 | { |
674 | unsigned int euid = geteuid(); | 654 | enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH }; |
655 | unsigned euid; | ||
656 | |||
657 | if (mode == X_OK) { | ||
658 | /* Do we already know with no extra syscalls? */ | ||
659 | //if (!S_ISREG(st->st_mode)) | ||
660 | // return 0; /* not a regular file */ | ||
661 | // ^^^ bash 5.2.15 "test -x" does not check this! | ||
662 | if ((st->st_mode & ANY_IX) == 0) | ||
663 | return 0; /* no one can execute */ | ||
664 | if ((st->st_mode & ANY_IX) == ANY_IX) | ||
665 | return 1; /* anyone can execute */ | ||
666 | } | ||
675 | 667 | ||
668 | euid = get_cached_euid(&groupinfo->euid); | ||
676 | if (euid == 0) { | 669 | if (euid == 0) { |
677 | /* Root can read or write any file. */ | 670 | /* Root can read or write any file. */ |
678 | if (mode != X_OK) | 671 | if (mode != X_OK) |
679 | return 0; | 672 | return 1; |
680 | 673 | ||
681 | /* Root can execute any file that has any one of the execute | 674 | /* Root can execute any file that has any one of the execute |
682 | * bits set. */ | 675 | * bits set. */ |
683 | if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) | 676 | mode = S_IXUSR | S_IXGRP | S_IXOTH; |
684 | return 0; | 677 | } else if (st->st_uid == euid) /* owner */ |
685 | } | ||
686 | |||
687 | if (st->st_uid == euid) /* owner */ | ||
688 | mode <<= 6; | 678 | mode <<= 6; |
689 | else if (is_a_group_member(st->st_gid)) | 679 | else if (is_a_group_member(st->st_gid)) |
690 | mode <<= 3; | 680 | mode <<= 3; |
691 | 681 | ||
692 | if (st->st_mode & mode) | 682 | return st->st_mode & mode; |
693 | return 0; | ||
694 | |||
695 | return -1; | ||
696 | } | 683 | } |
697 | 684 | ||
698 | 685 | ||
@@ -722,7 +709,7 @@ static int filstat(char *nm, enum token mode) | |||
722 | i = W_OK; | 709 | i = W_OK; |
723 | if (mode == FILEX) | 710 | if (mode == FILEX) |
724 | i = X_OK; | 711 | i = X_OK; |
725 | return test_eaccess(&s, i) == 0; | 712 | return test_st_mode(&s, i); |
726 | } | 713 | } |
727 | if (is_file_type(mode)) { | 714 | if (is_file_type(mode)) { |
728 | if (mode == FILREG) | 715 | if (mode == FILREG) |
@@ -760,7 +747,7 @@ static int filstat(char *nm, enum token mode) | |||
760 | return ((s.st_mode & i) != 0); | 747 | return ((s.st_mode & i) != 0); |
761 | } | 748 | } |
762 | if (mode == FILGZ) | 749 | if (mode == FILGZ) |
763 | return s.st_size > 0L; | 750 | return s.st_size != 0L; /* shorter than "> 0" test */ |
764 | if (mode == FILUID) | 751 | if (mode == FILUID) |
765 | return s.st_uid == geteuid(); | 752 | return s.st_uid == geteuid(); |
766 | if (mode == FILGID) | 753 | if (mode == FILGID) |
@@ -891,7 +878,7 @@ static number_t primary(enum token n) | |||
891 | } | 878 | } |
892 | 879 | ||
893 | 880 | ||
894 | int test_main(int argc, char **argv) | 881 | int FAST_FUNC test_main2(struct cached_groupinfo *pgroupinfo, int argc, char **argv) |
895 | { | 882 | { |
896 | int res; | 883 | int res; |
897 | const char *arg0; | 884 | const char *arg0; |
@@ -924,6 +911,7 @@ int test_main(int argc, char **argv) | |||
924 | 911 | ||
925 | /* We must do DEINIT_S() prior to returning */ | 912 | /* We must do DEINIT_S() prior to returning */ |
926 | INIT_S(); | 913 | INIT_S(); |
914 | groupinfo = pgroupinfo; | ||
927 | 915 | ||
928 | #if BASH_TEST2 | 916 | #if BASH_TEST2 |
929 | bash_test2 = bt2; | 917 | bash_test2 = bt2; |
@@ -1026,3 +1014,18 @@ int test_main(int argc, char **argv) | |||
1026 | DEINIT_S(); | 1014 | DEINIT_S(); |
1027 | return res; | 1015 | return res; |
1028 | } | 1016 | } |
1017 | |||
1018 | int test_main(int argc, char **argv) | ||
1019 | { | ||
1020 | struct cached_groupinfo info; | ||
1021 | int r; | ||
1022 | |||
1023 | info.euid = -1; | ||
1024 | info.egid = -1; | ||
1025 | info.ngroups = 0; | ||
1026 | info.supplementary_array = NULL; | ||
1027 | r = test_main2(&info, argc, argv); | ||
1028 | free(info.supplementary_array); | ||
1029 | |||
1030 | return r; | ||
1031 | } | ||
diff --git a/include/libbb.h b/include/libbb.h index b68f9b684..ff4a67481 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1261,6 +1261,19 @@ void die_if_bad_username(const char* name) FAST_FUNC; | |||
1261 | * Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call). | 1261 | * Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call). |
1262 | */ | 1262 | */ |
1263 | gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; | 1263 | gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; |
1264 | /* | ||
1265 | * True if GID is in our getgroups() result. | ||
1266 | * getgroups() is cached in supplementary_array[], to make successive calls faster. | ||
1267 | */ | ||
1268 | struct cached_groupinfo { | ||
1269 | uid_t euid; | ||
1270 | gid_t egid; | ||
1271 | int ngroups; | ||
1272 | gid_t *supplementary_array; | ||
1273 | }; | ||
1274 | uid_t FAST_FUNC get_cached_euid(uid_t *euid); | ||
1275 | gid_t FAST_FUNC get_cached_egid(gid_t *egid); | ||
1276 | int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid); | ||
1264 | 1277 | ||
1265 | #if ENABLE_FEATURE_UTMP | 1278 | #if ENABLE_FEATURE_UTMP |
1266 | void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); | 1279 | void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); |
@@ -1612,6 +1625,7 @@ int test_main(int argc, char **argv) | |||
1612 | MAIN_EXTERNALLY_VISIBLE | 1625 | MAIN_EXTERNALLY_VISIBLE |
1613 | #endif | 1626 | #endif |
1614 | ; | 1627 | ; |
1628 | int FAST_FUNC test_main2(struct cached_groupinfo *pgroupinfo, int argc, char **argv); | ||
1615 | int kill_main(int argc, char **argv) | 1629 | int kill_main(int argc, char **argv) |
1616 | #if ENABLE_KILL || ENABLE_KILLALL || ENABLE_KILLALL5 | 1630 | #if ENABLE_KILL || ENABLE_KILLALL || ENABLE_KILLALL5 |
1617 | MAIN_EXTERNALLY_VISIBLE | 1631 | MAIN_EXTERNALLY_VISIBLE |
diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c index 5d83c729a..31cff2b41 100644 --- a/libbb/bb_getgroups.c +++ b/libbb/bb_getgroups.c | |||
@@ -45,3 +45,37 @@ gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) | |||
45 | *ngroups = n; | 45 | *ngroups = n; |
46 | return group_array; | 46 | return group_array; |
47 | } | 47 | } |
48 | |||
49 | uid_t FAST_FUNC get_cached_euid(uid_t *euid) | ||
50 | { | ||
51 | if (*euid == (uid_t)-1) | ||
52 | *euid = geteuid(); | ||
53 | return *euid; | ||
54 | } | ||
55 | |||
56 | gid_t FAST_FUNC get_cached_egid(gid_t *egid) | ||
57 | { | ||
58 | if (*egid == (gid_t)-1) | ||
59 | *egid = getegid(); | ||
60 | return *egid; | ||
61 | } | ||
62 | |||
63 | /* Return non-zero if GID is in our supplementary group list. */ | ||
64 | int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) | ||
65 | { | ||
66 | int i; | ||
67 | int ngroups; | ||
68 | gid_t *group_array; | ||
69 | |||
70 | if (groupinfo->ngroups == 0) | ||
71 | groupinfo->supplementary_array = bb_getgroups(&groupinfo->ngroups, NULL); | ||
72 | ngroups = groupinfo->ngroups; | ||
73 | group_array = groupinfo->supplementary_array; | ||
74 | |||
75 | /* Search through the list looking for GID. */ | ||
76 | for (i = 0; i < ngroups; i++) | ||
77 | if (gid == group_array[i]) | ||
78 | return 1; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 57a801459..75a61c32c 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
@@ -1313,7 +1313,9 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) | |||
1313 | hash_size = 8; | 1313 | hash_size = 8; |
1314 | if (ctx->process_block == sha1_process_block64 | 1314 | if (ctx->process_block == sha1_process_block64 |
1315 | #if ENABLE_SHA1_HWACCEL | 1315 | #if ENABLE_SHA1_HWACCEL |
1316 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | ||
1316 | || ctx->process_block == sha1_process_block64_shaNI | 1317 | || ctx->process_block == sha1_process_block64_shaNI |
1318 | # endif | ||
1317 | #endif | 1319 | #endif |
1318 | ) { | 1320 | ) { |
1319 | hash_size = 5; | 1321 | hash_size = 5; |
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 37ed114bc..67602a466 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c | |||
@@ -51,6 +51,27 @@ struct ifla_vlan_flags { | |||
51 | }; | 51 | }; |
52 | #endif | 52 | #endif |
53 | 53 | ||
54 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
55 | # ifndef CAN_CTRLMODE_ONE_SHOT | ||
56 | # define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ | ||
57 | # endif | ||
58 | # ifndef CAN_CTRLMODE_BERR_REPORTING | ||
59 | # define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ | ||
60 | # endif | ||
61 | # ifndef CAN_CTRLMODE_FD | ||
62 | # define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ | ||
63 | # endif | ||
64 | # ifndef CAN_CTRLMODE_PRESUME_ACK | ||
65 | # define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ | ||
66 | # endif | ||
67 | # ifndef CAN_CTRLMODE_FD_NON_ISO | ||
68 | # define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ | ||
69 | # endif | ||
70 | # ifndef IFLA_CAN_TERMINATION | ||
71 | # define IFLA_CAN_TERMINATION 11 | ||
72 | # endif | ||
73 | #endif | ||
74 | |||
54 | /* taken from linux/sockios.h */ | 75 | /* taken from linux/sockios.h */ |
55 | #define SIOCSIFNAME 0x8923 /* set interface name */ | 76 | #define SIOCSIFNAME 0x8923 /* set interface name */ |
56 | 77 | ||
diff --git a/shell/ash.c b/shell/ash.c index 679846574..b37446233 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -671,6 +671,10 @@ struct globals_misc { | |||
671 | char **trap_ptr; /* used only by "trap hack" */ | 671 | char **trap_ptr; /* used only by "trap hack" */ |
672 | 672 | ||
673 | /* Rarely referenced stuff */ | 673 | /* Rarely referenced stuff */ |
674 | |||
675 | /* Cached supplementary group array (for testing executable'ity of files) */ | ||
676 | struct cached_groupinfo groupinfo; | ||
677 | |||
674 | #if ENABLE_ASH_RANDOM_SUPPORT | 678 | #if ENABLE_ASH_RANDOM_SUPPORT |
675 | random_t random_gen; | 679 | random_t random_gen; |
676 | #endif | 680 | #endif |
@@ -714,6 +718,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
714 | #define may_have_traps (G_misc.may_have_traps ) | 718 | #define may_have_traps (G_misc.may_have_traps ) |
715 | #define trap (G_misc.trap ) | 719 | #define trap (G_misc.trap ) |
716 | #define trap_ptr (G_misc.trap_ptr ) | 720 | #define trap_ptr (G_misc.trap_ptr ) |
721 | #define groupinfo (G_misc.groupinfo ) | ||
717 | #define random_gen (G_misc.random_gen ) | 722 | #define random_gen (G_misc.random_gen ) |
718 | #define backgndpid (G_misc.backgndpid ) | 723 | #define backgndpid (G_misc.backgndpid ) |
719 | 724 | ||
@@ -729,6 +734,8 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
729 | curdir = nullstr; \ | 734 | curdir = nullstr; \ |
730 | physdir = nullstr; \ | 735 | physdir = nullstr; \ |
731 | trap_ptr = trap; \ | 736 | trap_ptr = trap; \ |
737 | groupinfo.euid = -1; \ | ||
738 | groupinfo.egid = -1; \ | ||
732 | } while (0) | 739 | } while (0) |
733 | 740 | ||
734 | 741 | ||
@@ -2579,7 +2586,7 @@ initvar(void) | |||
2579 | #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT | 2586 | #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT |
2580 | vps1.var_text = "PS1=\\w \\$ "; | 2587 | vps1.var_text = "PS1=\\w \\$ "; |
2581 | #else | 2588 | #else |
2582 | if (!geteuid()) | 2589 | if (!get_cached_euid(&groupinfo.euid)); |
2583 | vps1.var_text = "PS1=# "; | 2590 | vps1.var_text = "PS1=# "; |
2584 | #endif | 2591 | #endif |
2585 | vp = varinit; | 2592 | vp = varinit; |
@@ -11342,7 +11349,7 @@ static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, a | |||
11342 | static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } | 11349 | static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } |
11343 | #endif | 11350 | #endif |
11344 | #if ENABLE_ASH_TEST || BASH_TEST2 | 11351 | #if ENABLE_ASH_TEST || BASH_TEST2 |
11345 | static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } | 11352 | static int FAST_FUNC testcmd(int argc, char **argv) { return test_main2(&groupinfo, argc, argv); } |
11346 | #endif | 11353 | #endif |
11347 | #if ENABLE_ASH_SLEEP | 11354 | #if ENABLE_ASH_SLEEP |
11348 | static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); } | 11355 | static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); } |
@@ -15101,6 +15108,42 @@ readcmdfile(char *name) | |||
15101 | 15108 | ||
15102 | /* ============ find_command inplementation */ | 15109 | /* ============ find_command inplementation */ |
15103 | 15110 | ||
15111 | static int test_exec(/*const char *fullname,*/ struct stat *statb) | ||
15112 | { | ||
15113 | /* | ||
15114 | * TODO: use faccessat(AT_FDCWD, fullname, X_OK, AT_EACCESS) | ||
15115 | * instead: executability may depend on ACLs, capabilities | ||
15116 | * and who knows what else, not just mode bits. | ||
15117 | * (faccessat2 syscall was added to Linux in May 14 2020) | ||
15118 | */ | ||
15119 | mode_t stmode; | ||
15120 | uid_t euid; | ||
15121 | enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH }; | ||
15122 | |||
15123 | /* Do we already know with no extra syscalls? */ | ||
15124 | if (!S_ISREG(statb->st_mode)) | ||
15125 | return 0; /* not a regular file */ | ||
15126 | if ((statb->st_mode & ANY_IX) == 0) | ||
15127 | return 0; /* no one can execute */ | ||
15128 | if ((statb->st_mode & ANY_IX) == ANY_IX) | ||
15129 | return 1; /* anyone can execute */ | ||
15130 | |||
15131 | /* Executability depends on our euid/egid/supplementary groups */ | ||
15132 | stmode = S_IXOTH; | ||
15133 | euid = get_cached_euid(&groupinfo.euid); | ||
15134 | if (euid == 0) | ||
15135 | /* for root user, any X bit is good enough */ | ||
15136 | stmode = ANY_IX; | ||
15137 | else if (statb->st_uid == euid) | ||
15138 | stmode = S_IXUSR; | ||
15139 | else if (statb->st_gid == get_cached_egid(&groupinfo.egid)) | ||
15140 | stmode = S_IXGRP; | ||
15141 | else if (is_in_supplementary_groups(&groupinfo, statb->st_gid)) | ||
15142 | stmode = S_IXGRP; | ||
15143 | |||
15144 | return statb->st_mode & stmode; | ||
15145 | } | ||
15146 | |||
15104 | /* | 15147 | /* |
15105 | * Resolve a command name. If you change this routine, you may have to | 15148 | * Resolve a command name. If you change this routine, you may have to |
15106 | * change the shellexec routine as well. | 15149 | * change the shellexec routine as well. |
@@ -15128,9 +15171,12 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15128 | if (errno == EINTR) | 15171 | if (errno == EINTR) |
15129 | continue; | 15172 | continue; |
15130 | #endif | 15173 | #endif |
15174 | absfail: | ||
15131 | entry->cmdtype = CMDUNKNOWN; | 15175 | entry->cmdtype = CMDUNKNOWN; |
15132 | return; | 15176 | return; |
15133 | } | 15177 | } |
15178 | if (!test_exec(/*name,*/ &statb)) | ||
15179 | goto absfail; | ||
15134 | } | 15180 | } |
15135 | entry->cmdtype = CMDNORMAL; | 15181 | entry->cmdtype = CMDNORMAL; |
15136 | return; | 15182 | return; |
@@ -15275,9 +15321,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15275 | e = errno; | 15321 | e = errno; |
15276 | goto loop; | 15322 | goto loop; |
15277 | } | 15323 | } |
15278 | e = EACCES; /* if we fail, this will be the error */ | ||
15279 | if (!S_ISREG(statb.st_mode)) | ||
15280 | continue; | ||
15281 | if (lpathopt) { /* this is a %func directory */ | 15324 | if (lpathopt) { /* this is a %func directory */ |
15282 | stalloc(len); | 15325 | stalloc(len); |
15283 | /* NB: stalloc will return space pointed by fullname | 15326 | /* NB: stalloc will return space pointed by fullname |
@@ -15290,6 +15333,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15290 | stunalloc(fullname); | 15333 | stunalloc(fullname); |
15291 | goto success; | 15334 | goto success; |
15292 | } | 15335 | } |
15336 | e = EACCES; /* if we fail, this will be the error */ | ||
15337 | if (!test_exec(/*fullname,*/ &statb)) | ||
15338 | continue; | ||
15293 | TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); | 15339 | TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); |
15294 | if (!updatetbl) { | 15340 | if (!updatetbl) { |
15295 | entry->cmdtype = CMDNORMAL; | 15341 | entry->cmdtype = CMDNORMAL; |