Closing bug 730. libbb run_parts is using scandir (a GNUism), and it is used only by run_parts applet, so move it there. Also saved ~30 bytes (prolly gcc autoinlining...).
No binary (build failed)
—
(log yok)
| @@ -37,17 +37,108 @@ | |
| #include "busybox.h" | |
| #include <getopt.h> | |
| - | #include <stdlib.h> |
| - | |
| static const struct option runparts_long_options[] = { | |
| - | { "test", 0, NULL, 't' }, |
| - | { "umask", 1, NULL, 'u' }, |
| - | { "arg", 1, NULL, 'a' }, |
| - | { 0, 0, 0, 0 } |
| + | { "test", 0, NULL, 't' }, |
| + | { "umask", 1, NULL, 'u' }, |
| + | { "arg", 1, NULL, 'a' }, |
| + | { 0, 0, 0, 0 } |
| }; | |
| - | extern char **environ; |
| + | /* valid_name */ |
| + | /* True or false? Is this a valid filename (upper/lower alpha, digits, |
| + | * underscores, and hyphens only?) |
| + | */ |
| + | static int valid_name(const struct dirent *d) |
| + | { |
| + | const char *c = d->d_name; |
| + | |
| + | while (*c) { |
| + | if (!isalnum(*c) && (*c != '_') && (*c != '-')) { |
| + | return 0; |
| + | } |
| + | ++c; |
| + | } |
| + | return 1; |
| + | } |
| + | |
| + | /* test mode = 1 is the same as official run_parts |
| + | * test_mode = 2 means to fail silently on missing directories |
| + | */ |
| + | static int run_parts(char **args, const unsigned char test_mode) |
| + | { |
| + | struct dirent **namelist = 0; |
| + | struct stat st; |
| + | char *filename; |
| + | char *arg0 = args[0]; |
| + | int entries; |
| + | int i; |
| + | int exitstatus = 0; |
| + | |
| + | #if __GNUC__ |
| + | /* Avoid longjmp clobbering */ |
| + | (void) &i; |
| + | (void) &exitstatus; |
| + | #endif |
| + | /* scandir() isn't POSIX, but it makes things easy. */ |
| + | entries = scandir(arg0, &namelist, valid_name, alphasort); |
| + | |
| + | if (entries == -1) { |
| + | if (test_mode & 2) { |
| + | return(2); |
| + | } |
| + | bb_perror_msg_and_die("cannot open '%s'", arg0); |
| + | } |
| + | |
| + | for (i = 0; i < entries; i++) { |
| + | filename = concat_path_file(arg0, namelist[i]->d_name); |
| + | |
| + | xstat(filename, &st); |
| + | if (S_ISREG(st.st_mode) && !access(filename, X_OK)) { |
| + | if (test_mode) { |
| + | puts(filename); |
| + | } else { |
| + | /* exec_errno is common vfork variable */ |
| + | volatile int exec_errno = 0; |
| + | int result; |
| + | int pid; |
| + | |
| + | if ((pid = vfork()) < 0) { |
| + | bb_perror_msg_and_die("failed to fork"); |
| + | } else if (!pid) { |
| + | args[0] = filename; |
| + | execve(filename, args, environ); |
| + | exec_errno = errno; |
| + | _exit(1); |
| + | } |
| + | |
| + | waitpid(pid, &result, 0); |
| + | if (exec_errno) { |
| + | errno = exec_errno; |
| + | bb_perror_msg("failed to exec %s", filename); |
| + | exitstatus = 1; |
| + | } |
| + | if (WIFEXITED(result) && WEXITSTATUS(result)) { |
| + | bb_perror_msg("%s exited with return code %d", filename, WEXITSTATUS(result)); |
| + | exitstatus = 1; |
| + | } else if (WIFSIGNALED(result)) { |
| + | bb_perror_msg("%s exited because of uncaught signal %d", filename, WTERMSIG(result)); |
| + | exitstatus = 1; |
| + | } |
| + | } |
| + | } else if (!S_ISDIR(st.st_mode)) { |
| + | bb_error_msg("component %s is not an executable plain file", filename); |
| + | exitstatus = 1; |
| + | } |
| + | |
| + | free(namelist[i]); |
| + | free(filename); |
| + | } |
| + | free(namelist); |
| + | |
| + | return exitstatus; |
| + | } |
| + | |
| /* run_parts_main */ | |
| /* Process options */ | |
| @@ -96,5 +187,5 @@ int run_parts_main(int argc, char **argv) | |
| args[0] = argv[optind]; | |
| args[argcount] = 0; | |
| - | return(run_parts(args, test_mode, environ)); |
| + | return run_parts(args, test_mode); |
| } | |
| @@ -449,7 +449,6 @@ extern void run_shell(const char *shell, int loginshell, const char *command, co | |
| extern void renew_current_security_context(void); | |
| extern void set_current_security_context(security_context_t sid); | |
| #endif | |
| - | extern int run_parts(char **args, const unsigned char test_mode, char **env); |
| extern int restricted_shell(const char *shell); | |
| extern void setup_environment(const char *shell, int loginshell, int changeenv, const struct passwd *pw); | |
| extern int correct_password(const struct passwd *pw); | |
| @@ -65,7 +65,6 @@ lib-y += read.o | |
| lib-y += recursive_action.o | |
| lib-y += remove_file.o | |
| lib-y += restricted_shell.o | |
| - | lib-y += run_parts.o |
| lib-y += run_shell.o | |
| lib-y += safe_strncpy.o | |
| lib-y += safe_strtol.o | |
| @@ -1,119 +0,0 @@ | |
| - | /* vi: set sw=4 ts=4: */ |
| - | /* |
| - | * run command from specified directory |
| - | * |
| - | * |
| - | * Copyright (C) 2001 by Emanuele Aina <[email protected]> |
| - | * rewrite to vfork usage by |
| - | * Copyright (C) 2002 by Vladimir Oleynik <[email protected]> |
| - | * |
| - | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| - | */ |
| - | |
| - | |
| - | #include <sys/types.h> |
| - | #include <sys/wait.h> |
| - | #include <stdlib.h> |
| - | #include <dirent.h> |
| - | #include <unistd.h> |
| - | #include <ctype.h> |
| - | #include <errno.h> |
| - | |
| - | #include "libbb.h" |
| - | |
| - | /* valid_name */ |
| - | /* True or false? Is this a valid filename (upper/lower alpha, digits, |
| - | * underscores, and hyphens only?) |
| - | */ |
| - | static int valid_name(const struct dirent *d) |
| - | { |
| - | const char *c = d->d_name; |
| - | |
| - | while (*c) { |
| - | if (!isalnum(*c) && (*c != '_') && (*c != '-')) { |
| - | return 0; |
| - | } |
| - | ++c; |
| - | } |
| - | return 1; |
| - | } |
| - | |
| - | /* test mode = 1 is the same as official run_parts |
| - | * test_mode = 2 means to fail silently on missing directories |
| - | */ |
| - | |
| - | int run_parts(char **args, const unsigned char test_mode, char **env) |
| - | { |
| - | struct dirent **namelist = 0; |
| - | struct stat st; |
| - | char *filename; |
| - | char *arg0 = args[0]; |
| - | int entries; |
| - | int i; |
| - | int exitstatus = 0; |
| - | |
| - | #if __GNUC__ |
| - | /* Avoid longjmp clobbering */ |
| - | (void) &i; |
| - | (void) &exitstatus; |
| - | #endif |
| - | /* scandir() isn't POSIX, but it makes things easy. */ |
| - | entries = scandir(arg0, &namelist, valid_name, alphasort); |
| - | |
| - | if (entries == -1) { |
| - | if (test_mode & 2) { |
| - | return(2); |
| - | } |
| - | bb_perror_msg_and_die("cannot open '%s'", arg0); |
| - | } |
| - | |
| - | for (i = 0; i < entries; i++) { |
| - | |
| - | filename = concat_path_file(arg0, namelist[i]->d_name); |
| - | |
| - | xstat(filename, &st); |
| - | if (S_ISREG(st.st_mode) && !access(filename, X_OK)) { |
| - | if (test_mode) { |
| - | puts(filename); |
| - | } else { |
| - | /* exec_errno is common vfork variable */ |
| - | volatile int exec_errno = 0; |
| - | int result; |
| - | int pid; |
| - | |
| - | if ((pid = vfork()) < 0) { |
| - | bb_perror_msg_and_die("failed to fork"); |
| - | } else if (!pid) { |
| - | args[0] = filename; |
| - | execve(filename, args, env); |
| - | exec_errno = errno; |
| - | _exit(1); |
| - | } |
| - | |
| - | waitpid(pid, &result, 0); |
| - | if(exec_errno) { |
| - | errno = exec_errno; |
| - | bb_perror_msg("failed to exec %s", filename); |
| - | exitstatus = 1; |
| - | } |
| - | if (WIFEXITED(result) && WEXITSTATUS(result)) { |
| - | bb_perror_msg("%s exited with return code %d", filename, WEXITSTATUS(result)); |
| - | exitstatus = 1; |
| - | } else if (WIFSIGNALED(result)) { |
| - | bb_perror_msg("%s exited because of uncaught signal %d", filename, WTERMSIG(result)); |
| - | exitstatus = 1; |
| - | } |
| - | } |
| - | } |
| - | else if (!S_ISDIR(st.st_mode)) { |
| - | bb_error_msg("component %s is not an executable plain file", filename); |
| - | exitstatus = 1; |
| - | } |
| - | |
| - | free(namelist[i]); |
| - | free(filename); |
| - | } |
| - | free(namelist); |
| - | |
| - | return(exitstatus); |
| - | } |