- make getopt_ulflags aware of CONFIG_GETOPT_LONG
[oweals/busybox.git] / libbb / run_parts.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * run command from specified directory
4  *
5  *
6  * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it>
7  * rewrite to vfork usage by
8  * Copyright (C) 2002 by Vladimir Oleynik <dzo@simtreas.ru>
9  *
10  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
11  */
12
13
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <stdlib.h>
17 #include <dirent.h>
18 #include <unistd.h>
19 #include <ctype.h>
20 #include <errno.h>
21
22 #include "libbb.h"
23
24 /* valid_name */
25 /* True or false? Is this a valid filename (upper/lower alpha, digits,
26  * underscores, and hyphens only?)
27  */
28 static int valid_name(const struct dirent *d)
29 {
30         char *c = d->d_name;
31
32         while (*c) {
33                 if (!isalnum(*c) && (*c != '_') && (*c != '-')) {
34                         return 0;
35                 }
36                 ++c;
37         }
38         return 1;
39 }
40
41 /* test mode = 1 is the same as official run_parts
42  * test_mode = 2 means to fail silently on missing directories
43  */
44
45 int run_parts(char **args, const unsigned char test_mode, char **env)
46 {
47         struct dirent **namelist = 0;
48         struct stat st;
49         char *filename;
50         char *arg0 = args[0];
51         int entries;
52         int i;
53         int exitstatus = 0;
54
55 #if __GNUC__
56         /* Avoid longjmp clobbering */
57         (void) &i;
58         (void) &exitstatus;
59 #endif
60         /* scandir() isn't POSIX, but it makes things easy. */
61         entries = scandir(arg0, &namelist, valid_name, alphasort);
62
63         if (entries == -1) {
64                 if (test_mode & 2) {
65                         return(2);
66                 }
67                 bb_perror_msg_and_die("unable to open `%s'", arg0);
68         }
69
70         for (i = 0; i < entries; i++) {
71
72                 filename = concat_path_file(arg0, namelist[i]->d_name);
73
74                 xstat(filename, &st);
75                 if (S_ISREG(st.st_mode) && !access(filename, X_OK)) {
76                         if (test_mode) {
77                                 puts(filename);
78                         } else {
79                                 /* exec_errno is common vfork variable */
80                                 volatile int exec_errno = 0;
81                                 int result;
82                                 int pid;
83
84                                 if ((pid = vfork()) < 0) {
85                                         bb_perror_msg_and_die("failed to fork");
86                                 } else if (!pid) {
87                                         args[0] = filename;
88                                         execve(filename, args, env);
89                                         exec_errno = errno;
90                                         _exit(1);
91                                 }
92
93                                 waitpid(pid, &result, 0);
94                                 if(exec_errno) {
95                                         errno = exec_errno;
96                                         bb_perror_msg("failed to exec %s", filename);
97                                         exitstatus = 1;
98                                 }
99                                 if (WIFEXITED(result) && WEXITSTATUS(result)) {
100                                         bb_perror_msg("%s exited with return code %d", filename, WEXITSTATUS(result));
101                                         exitstatus = 1;
102                                 } else if (WIFSIGNALED(result)) {
103                                         bb_perror_msg("%s exited because of uncaught signal %d", filename, WTERMSIG(result));
104                                         exitstatus = 1;
105                                 }
106                         }
107                 }
108                 else if (!S_ISDIR(st.st_mode)) {
109                         bb_error_msg("component %s is not an executable plain file", filename);
110                         exitstatus = 1;
111                 }
112
113                 free(namelist[i]);
114                 free(filename);
115         }
116         free(namelist);
117
118         return(exitstatus);
119 }