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

Last change on this file since 3621 was 3621, checked in by Bruno Cornec, 7 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.