summaryrefslogtreecommitdiff
path: root/debianutils/run_parts.c
diff options
context:
space:
mode:
authorBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2007-03-28 20:35:13 +0000
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2007-03-28 20:35:13 +0000
commitb7cffd4bedf14770a7096a11a6e46cc497ff37c6 (patch)
tree56db2b5e6a6592670c47a840798c6ec53639d5e5 /debianutils/run_parts.c
parent0a537a0c5760215f3ea9e5af07f0a656e5bfa408 (diff)
downloadbusybox-w32-b7cffd4bedf14770a7096a11a6e46cc497ff37c6.tar.gz
busybox-w32-b7cffd4bedf14770a7096a11a6e46cc497ff37c6.tar.bz2
busybox-w32-b7cffd4bedf14770a7096a11a6e46cc497ff37c6.zip
- rewrite run-parts
text data bss dec hex filename 1029 0 0 1029 405 debianutils/run_parts.o-old 478 0 0 478 1de debianutils/run_parts.o-new-bare 600 0 0 600 258 debianutils/run_parts.o-new-full bare, i.e. without long opts and fancy stuff ./scripts/bloat-o-meter bb_old busybox_unstripped function old new delta act - 215 +215 run_parts_main 216 201 -15 valid_name 50 - -50 runparts_long_options 64 - -64 .rodata 124323 124163 -160 run_parts 513 - -513 ------------------------------------------------------------------------------ (add/remove: 1/3 grow/shrink: 0/2 up/down: 215/-802) Total: -587 bytes
Diffstat (limited to 'debianutils/run_parts.c')
-rw-r--r--debianutils/run_parts.c219
1 files changed, 89 insertions, 130 deletions
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index a864a0505..aa449c410 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -2,8 +2,10 @@
2/* 2/*
3 * Mini run-parts implementation for busybox 3 * Mini run-parts implementation for busybox
4 * 4 *
5 * Copyright (C) 2007 Bernhard Fischer
5 * 6 *
6 * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it> 7 * Based on a older version that was in busybox which was 1k big..
8 * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it>
7 * 9 *
8 * Based on the Debian run-parts program, version 1.15 10 * Based on the Debian run-parts program, version 1.15
9 * Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>, 11 * Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>,
@@ -25,168 +27,125 @@
25 * execute them. 27 * execute them.
26 * -a ARG argument. Pass ARG as an argument the program executed. It can 28 * -a ARG argument. Pass ARG as an argument the program executed. It can
27 * be repeated to pass multiple arguments. 29 * be repeated to pass multiple arguments.
28 * -u MASK umask. Set the umask of the program executed to MASK. */ 30 * -u MASK umask. Set the umask of the program executed to MASK.
29
30/* TODO
31 * done - convert calls to error in perror... and remove error()
32 * done - convert malloc/realloc to their x... counterparts
33 * done - remove catch_sigchld
34 * done - use bb's concat_path_file()
35 * done - declare run_parts_main() as extern and any other function as static?
36 */ 31 */
37 32
33
38#include "busybox.h" 34#include "busybox.h"
39#include <getopt.h> 35#include <getopt.h>
40 36
37#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
41static const struct option runparts_long_options[] = { 38static const struct option runparts_long_options[] = {
42 { "test", 0, NULL, 't' },
43 { "umask", 1, NULL, 'u' },
44 { "arg", 1, NULL, 'a' }, 39 { "arg", 1, NULL, 'a' },
40 { "umask", 1, NULL, 'u' },
41 { "test", 0, NULL, 't' },
42#if ENABLE_FEATURE_RUN_PARTS_FANCY
43 { "list", 0, NULL, 'l' },
44//XXX:TODO: { "reverse", 0, NULL, 'r' },
45//XXX:TODO: { "verbose", 0, NULL, 'v' },
46#endif
45 { 0, 0, 0, 0 } 47 { 0, 0, 0, 0 }
46}; 48};
49#endif
50
51struct globals {
52 char *cmd[10]; /* merely arbitrary arg count */
53 smalluint mode;
54};
55#define G (*(struct globals*)&bb_common_bufsiz1)
47 56
48/* valid_name */ 57/* valid_name */
49/* True or false? Is this a valid filename (upper/lower alpha, digits, 58/* True or false? Is this a valid filename (upper/lower alpha, digits,
50 * underscores, and hyphens only?) 59 * underscores, and hyphens only?)
51 */ 60 */
52static int valid_name(const struct dirent *d) 61static bool invalid_name(const char *c)
53{ 62{
54 const char *c = d->d_name;
55
56 while (*c) { 63 while (*c) {
57 if (!isalnum(*c) && (*c != '_') && (*c != '-')) { 64 if (!isalnum(*c) && (*c != '_') && (*c != '-' && (*c != '/'))) {
58 return 0; 65 return 1;
59 } 66 }
60 ++c; 67 ++c;
61 } 68 }
62 return 1; 69 return 0;
63} 70}
64 71#define RUN_PARTS_OPT_a (1<<0)
65/* test mode = 1 is the same as official run_parts 72#define RUN_PARTS_OPT_u (1<<1)
66 * test_mode = 2 means to fail silently on missing directories 73#define RUN_PARTS_OPT_t (1<<2)
67 */ 74#if ENABLE_FEATURE_RUN_PARTS_FANCY
68static int run_parts(char **args, const unsigned char test_mode) 75#define RUN_PARTS_OPT_l (1<<3)
69{
70 struct dirent **namelist = 0;
71 struct stat st;
72 char *filename;
73 char *arg0 = args[0];
74 int entries;
75 int i;
76 int exitstatus = 0;
77
78#if __GNUC__
79 /* Avoid longjmp clobbering */
80 (void) &i;
81 (void) &exitstatus;
82#endif 76#endif
83 /* scandir() isn't POSIX, but it makes things easy. */
84 entries = scandir(arg0, &namelist, valid_name, alphasort);
85
86 if (entries == -1) {
87 if (test_mode & 2) {
88 return 2;
89 }
90 bb_perror_msg_and_die("cannot open '%s'", arg0);
91 }
92 77
93 for (i = 0; i < entries; i++) { 78#define test_mode (G.mode & RUN_PARTS_OPT_t)
94 filename = concat_path_file(arg0, namelist[i]->d_name); 79#if ENABLE_FEATURE_RUN_PARTS_FANCY
95 80#define list_mode (G.mode & RUN_PARTS_OPT_l)
96 xstat(filename, &st); 81#else
97 if (S_ISREG(st.st_mode) && !access(filename, X_OK)) { 82#define list_mode (0)
98 if (test_mode) { 83#endif
99 puts(filename); 84static int act(const char *file, struct stat *statbuf, void *args, int depth)
100 } else { 85{
101 /* exec_errno is common vfork variable */ 86 int ret;
102 volatile int exec_errno = 0;
103 int result;
104 int pid;
105 87
106 if ((pid = vfork()) < 0) { 88 if (depth == 1)
107 bb_perror_msg_and_die("failed to fork"); 89 return TRUE;
108 } else if (!pid) {
109 args[0] = filename;
110 execve(filename, args, environ);
111 exec_errno = errno;
112 _exit(1);
113 }
114 90
115 waitpid(pid, &result, 0); 91 if (depth == 2 &&
116 if (exec_errno) { 92 ((!list_mode && access(file, X_OK)) ||
117 errno = exec_errno; 93 invalid_name(file) ||
118 bb_perror_msg("failed to exec %s", filename); 94 !(statbuf->st_mode & (S_IFREG | S_IFLNK))) )
119 exitstatus = 1; 95 return SKIP;
120 }
121 if (WIFEXITED(result) && WEXITSTATUS(result)) {
122 bb_perror_msg("%s exited with return code %d", filename, WEXITSTATUS(result));
123 exitstatus = 1;
124 } else if (WIFSIGNALED(result)) {
125 bb_perror_msg("%s exited because of uncaught signal %d", filename, WTERMSIG(result));
126 exitstatus = 1;
127 }
128 }
129 } else if (!S_ISDIR(st.st_mode)) {
130 bb_error_msg("component %s is not an executable plain file", filename);
131 exitstatus = 1;
132 }
133 96
134 free(namelist[i]); 97 if (test_mode || list_mode) {
135 free(filename); 98 puts(file);
99 return TRUE;
136 } 100 }
137 free(namelist); 101 G.cmd[0] = (char*)file;
138 102 ret = wait4pid(spawn(G.cmd));
139 return exitstatus; 103 if (ret < 0) {
104 bb_error_msg("failed to exec %s", *G.cmd);
105 } else if (ret > 0) {
106 bb_perror_msg("%s exited with return code %d", *G.cmd, ret);
107 }
108 return !ret;
140} 109}
141 110
142
143/* run_parts_main */
144/* Process options */
145int run_parts_main(int argc, char **argv); 111int run_parts_main(int argc, char **argv);
146int run_parts_main(int argc, char **argv) 112int run_parts_main(int argc, char **argv)
147{ 113{
148 char **args = xmalloc(2 * sizeof(char *)); 114 char *umask_p;
149 unsigned char test_mode = 0; 115 llist_t *arg_list = NULL;
150 unsigned short argcount = 1; 116 unsigned tmp;
151 int opt;
152 117
153 umask(022); 118 umask(022);
154
155 while ((opt = getopt_long(argc, argv, "tu:a:",
156 runparts_long_options, NULL)) > 0)
157 {
158 switch (opt) {
159 /* Enable test mode */
160 case 't':
161 test_mode++;
162 break;
163 /* Set the umask of the programs executed */
164 case 'u':
165 /* Check and set the umask of the program executed. As stated in the original
166 * run-parts, the octal conversion in libc is not foolproof; it will take the
167 * 8 and 9 digits under some circumstances. We'll just have to live with it.
168 */
169 umask(xstrtoul_range(optarg, 8, 0, 07777));
170 break;
171 /* Pass an argument to the programs */
172 case 'a':
173 /* Add an argument to the commands that we will call.
174 * Called once for every argument. */
175 args = xrealloc(args, (argcount + 2) * (sizeof(char *)));
176 args[argcount++] = optarg;
177 break;
178 default:
179 bb_show_usage();
180 }
181 }
182
183 /* We require exactly one argument: the directory name */ 119 /* We require exactly one argument: the directory name */
184 if (optind != (argc - 1)) { 120 opt_complementary = "=1:a::";
185 bb_show_usage(); 121#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
122 applet_long_options = runparts_long_options;
123#endif
124 tmp = getopt32(argc, argv, "a:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
125 G.mode = tmp &~ (RUN_PARTS_OPT_a|RUN_PARTS_OPT_u);
126 if (tmp & RUN_PARTS_OPT_u) {
127 /* Check and set the umask of the program executed.
128 * As stated in the original run-parts, the octal conversion in
129 * libc is not foolproof; it will take the 8 and 9 digits under
130 * some circumstances. We'll just have to live with it.
131 */
132 umask(xstrtoul_range(umask_p, 8, 0, 07777));
186 } 133 }
187 134//XXX: FIXME: reverse the list before handing it over to the user.
188 args[0] = argv[optind]; 135//XXX: FIXME: The common case seems to be to use the order given by the user
189 args[argcount] = 0; 136 arg_list = llist_rev(arg_list); /* XXX: getopt32 appends them */
190 137 G.cmd[0] = (char*)"";
191 return run_parts(args, test_mode); 138 for (tmp = 1; arg_list; arg_list = arg_list->link, tmp++)
139 G.cmd[tmp] = arg_list->data;
140 if (!recursive_action(argv[argc - 1],
141 TRUE, /* recurse */
142 TRUE, /* follow links */
143 FALSE, /* depth first */
144 act, /* file action */
145 act, /* dir action */
146 NULL, /* user data */
147 1 /* depth */
148 ))
149 return EXIT_FAILURE;
150 return EXIT_SUCCESS;
192} 151}