source: MondoRescue/branches/3.3/mindi-busybox/debianutils/run_parts.c@ 3906

Last change on this file since 3906 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 6.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini run-parts implementation for busybox
4 *
5 * Copyright (C) 2007 Bernhard Reutner-Fischer
6 *
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>
9 *
10 * Based on the Debian run-parts program, version 1.15
11 * Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>,
12 * Copyright (C) 1996-1999 Guy Maor <maor@debian.org>
13 *
14 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
15 */
16
17/* This is my first attempt to write a program in C (well, this is my first
18 * attempt to write a program! :-) . */
19
20/* This piece of code is heavily based on the original version of run-parts,
21 * taken from debian-utils. I've only removed the long options and the
22 * report mode. As the original run-parts support only long options, I've
23 * broken compatibility because the BusyBox policy doesn't allow them.
24 */
25//config:config RUN_PARTS
26//config: bool "run-parts"
27//config: default y
28//config: help
29//config: run-parts is a utility designed to run all the scripts in a directory.
30//config:
31//config: It is useful to set up a directory like cron.daily, where you need to
32//config: execute all the scripts in that directory.
33//config:
34//config: In this implementation of run-parts some features (such as report
35//config: mode) are not implemented.
36//config:
37//config: Unless you know that run-parts is used in some of your scripts
38//config: you can safely say N here.
39//config:
40//config:config FEATURE_RUN_PARTS_LONG_OPTIONS
41//config: bool "Enable long options"
42//config: default y
43//config: depends on RUN_PARTS && LONG_OPTS
44//config: help
45//config: Support long options for the run-parts applet.
46//config:
47//config:config FEATURE_RUN_PARTS_FANCY
48//config: bool "Support additional arguments"
49//config: default y
50//config: depends on RUN_PARTS
51//config: help
52//config: Support additional options:
53//config: -l --list print the names of the all matching files (not
54//config: limited to executables), but don't actually run them.
55
56//applet:IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts))
57
58//kbuild:lib-$(CONFIG_RUN_PARTS) += run_parts.o
59
60//usage:#define run_parts_trivial_usage
61//usage: "[-a ARG]... [-u UMASK] "
62//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS("[--reverse] [--test] [--exit-on-error] "IF_FEATURE_RUN_PARTS_FANCY("[--list] "))
63//usage: "DIRECTORY"
64//usage:#define run_parts_full_usage "\n\n"
65//usage: "Run a bunch of scripts in DIRECTORY\n"
66//usage: "\n -a ARG Pass ARG as argument to scripts"
67//usage: "\n -u UMASK Set UMASK before running scripts"
68//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS(
69//usage: "\n --reverse Reverse execution order"
70//usage: "\n --test Dry run"
71//usage: "\n --exit-on-error Exit if a script exits with non-zero"
72//usage: IF_FEATURE_RUN_PARTS_FANCY(
73//usage: "\n --list Print names of matching files even if they are not executable"
74//usage: )
75//usage: )
76//usage:
77//usage:#define run_parts_example_usage
78//usage: "$ run-parts -a start /etc/init.d\n"
79//usage: "$ run-parts -a stop=now /etc/init.d\n\n"
80//usage: "Let's assume you have a script foo/dosomething:\n"
81//usage: "#!/bin/sh\n"
82//usage: "for i in $*; do eval $i; done; unset i\n"
83//usage: "case \"$1\" in\n"
84//usage: "start*) echo starting something;;\n"
85//usage: "stop*) set -x; shutdown -h $stop;;\n"
86//usage: "esac\n\n"
87//usage: "Running this yields:\n"
88//usage: "$run-parts -a stop=+4m foo/\n"
89//usage: "+ shutdown -h +4m"
90
91#include "libbb.h"
92#include "common_bufsiz.h"
93
94struct globals {
95 char **names;
96 int cur;
97 char *cmd[2 /* using 1 provokes compiler warning */];
98} FIX_ALIASING;
99#define G (*(struct globals*)bb_common_bufsiz1)
100#define names (G.names)
101#define cur (G.cur )
102#define cmd (G.cmd )
103#define INIT_G() do { setup_common_bufsiz(); } while (0)
104
105enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 };
106
107enum {
108 OPT_a = (1 << 0),
109 OPT_u = (1 << 1),
110 OPT_r = (1 << 2) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS,
111 OPT_t = (1 << 3) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS,
112 OPT_e = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS,
113 OPT_l = (1 << 5) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
114 * ENABLE_FEATURE_RUN_PARTS_FANCY,
115};
116
117/* Is this a valid filename (upper/lower alpha, digits,
118 * underscores, and hyphens only?)
119 */
120static bool invalid_name(const char *c)
121{
122 c = bb_basename(c);
123
124 while (*c && (isalnum(*c) || *c == '_' || *c == '-'))
125 c++;
126
127 return *c; /* TRUE (!0) if terminating NUL is not reached */
128}
129
130static int bb_alphasort(const void *p1, const void *p2)
131{
132 int r = strcmp(*(char **) p1, *(char **) p2);
133 return (option_mask32 & OPT_r) ? -r : r;
134}
135
136static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUSED_PARAM, int depth)
137{
138 if (depth == 1)
139 return TRUE;
140
141 if (depth == 2
142 && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK))
143 || invalid_name(file)
144 || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0))
145 ) {
146 return SKIP;
147 }
148
149 names = xrealloc_vector(names, 4, cur);
150 names[cur++] = xstrdup(file);
151 /*names[cur] = NULL; - xrealloc_vector did it */
152
153 return TRUE;
154}
155
156#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
157static const char runparts_longopts[] ALIGN1 =
158 "arg\0" Required_argument "a"
159 "umask\0" Required_argument "u"
160//TODO: "verbose\0" No_argument "v"
161 "reverse\0" No_argument "\xf0"
162 "test\0" No_argument "\xf1"
163 "exit-on-error\0" No_argument "\xf2"
164#if ENABLE_FEATURE_RUN_PARTS_FANCY
165 "list\0" No_argument "\xf3"
166#endif
167 ;
168#endif
169
170int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
171int run_parts_main(int argc UNUSED_PARAM, char **argv)
172{
173 const char *umask_p = "22";
174 llist_t *arg_list = NULL;
175 unsigned n;
176 int ret;
177
178 INIT_G();
179
180#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
181 applet_long_options = runparts_longopts;
182#endif
183 /* We require exactly one argument: the directory name */
184 opt_complementary = "=1:a::";
185 getopt32(argv, "a:u:", &arg_list, &umask_p);
186
187 umask(xstrtou_range(umask_p, 8, 0, 07777));
188
189 n = 1;
190 while (arg_list && n < NUM_CMD) {
191 cmd[n++] = llist_pop(&arg_list);
192 }
193 /* cmd[n] = NULL; - is already zeroed out */
194
195 /* run-parts has to sort executables by name before running them */
196
197 recursive_action(argv[optind],
198 ACTION_RECURSE|ACTION_FOLLOWLINKS,
199 act, /* file action */
200 act, /* dir action */
201 NULL, /* user data */
202 1 /* depth */
203 );
204
205 if (!names)
206 return 0;
207
208 qsort(names, cur, sizeof(char *), bb_alphasort);
209
210 n = 0;
211 while (1) {
212 char *name = *names++;
213 if (!name)
214 break;
215 if (option_mask32 & (OPT_t | OPT_l)) {
216 puts(name);
217 continue;
218 }
219 cmd[0] = name;
220 ret = spawn_and_wait(cmd);
221 if (ret == 0)
222 continue;
223 n = 1;
224 if (ret < 0)
225 bb_perror_msg("can't execute '%s'", name);
226 else /* ret > 0 */
227 bb_error_msg("%s: exit status %u", name, ret & 0xff);
228
229 if (option_mask32 & OPT_e)
230 xfunc_die();
231 }
232
233 return n;
234}
Note: See TracBrowser for help on using the repository browser.