blob: cb4a4e4c7b82b8be396e653804ca6f715ab47be7 [file] [log] [blame]
Eric Andersen7d682902001-10-31 10:59:29 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Mini run-parts implementation for busybox
4 *
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +00005 * Copyright (C) 2007 Bernhard Fischer
Eric Andersen7d682902001-10-31 10:59:29 +00006 *
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +00007 * Based on a older version that was in busybox which was 1k big..
8 * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it>
Eric Andersen7d682902001-10-31 10:59:29 +00009 *
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>
Eric Andersenc7bda1c2004-03-15 08:29:22 +000013 *
Eric Andersen7d682902001-10-31 10:59:29 +000014 *
Bernhard Reutner-Fischer7fee0c42006-09-13 16:39:19 +000015 * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
Eric Andersen7d682902001-10-31 10:59:29 +000016 */
17
18/* This is my first attempt to write a program in C (well, this is my first
19 * attempt to write a program! :-) . */
20
21/* This piece of code is heavily based on the original version of run-parts,
Eric Andersenc7bda1c2004-03-15 08:29:22 +000022 * taken from debian-utils. I've only removed the long options and a the
Eric Andersen7d682902001-10-31 10:59:29 +000023 * report mode. As the original run-parts support only long options, I've
Eric Andersenc7bda1c2004-03-15 08:29:22 +000024 * broken compatibility because the BusyBox policy doesn't allow them.
25 * The supported options are:
Eric Andersen7d682902001-10-31 10:59:29 +000026 * -t test. Print the name of the files to be executed, without
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000027 * execute them.
Eric Andersenc7bda1c2004-03-15 08:29:22 +000028 * -a ARG argument. Pass ARG as an argument the program executed. It can
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000029 * be repeated to pass multiple arguments.
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000030 * -u MASK umask. Set the umask of the program executed to MASK.
Eric Andersenfb74a452001-12-18 14:06:03 +000031 */
Eric Andersen7d682902001-10-31 10:59:29 +000032
Eric Andersen7d682902001-10-31 10:59:29 +000033#include <getopt.h>
Eric Andersen7d682902001-10-31 10:59:29 +000034
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000035#include "libbb.h"
36
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000037#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
Eric Andersena1ed06b2003-07-26 09:16:00 +000038static const struct option runparts_long_options[] = {
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000039 { "arg", 1, NULL, 'a' },
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000040 { "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
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000047 { 0, 0, 0, 0 }
Eric Andersena1ed06b2003-07-26 09:16:00 +000048};
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000049#endif
50
51struct globals {
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000052 smalluint mode;
Denis Vlasenko45cd0892007-03-28 22:04:04 +000053 char *cmd[10]; /* merely arbitrary arg count */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000054};
55#define G (*(struct globals*)&bb_common_bufsiz1)
Eric Andersena1ed06b2003-07-26 09:16:00 +000056
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000057/* valid_name */
58/* True or false? Is this a valid filename (upper/lower alpha, digits,
59 * underscores, and hyphens only?)
60 */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000061static bool invalid_name(const char *c)
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000062{
Denis Vlasenkod4728142007-04-29 23:38:12 +000063 const char *base_name = strrchr(c, '/');
64
65 if (base_name)
66 c = base_name + 1;
67
68 while (*c && (isalnum(*c) || *c == '_' || *c == '-'))
69 c++;
70
71 return *c; /* TRUE (!0) if terminating NUL is not reached */
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000072}
Denis Vlasenkod4728142007-04-29 23:38:12 +000073
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000074#define RUN_PARTS_OPT_a (1<<0)
75#define RUN_PARTS_OPT_u (1<<1)
76#define RUN_PARTS_OPT_t (1<<2)
77#if ENABLE_FEATURE_RUN_PARTS_FANCY
78#define RUN_PARTS_OPT_l (1<<3)
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000079#endif
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000080
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000081#define test_mode (G.mode & RUN_PARTS_OPT_t)
82#if ENABLE_FEATURE_RUN_PARTS_FANCY
83#define list_mode (G.mode & RUN_PARTS_OPT_l)
84#else
85#define list_mode (0)
86#endif
Denis Vlasenkod4728142007-04-29 23:38:12 +000087
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000088static int act(const char *file, struct stat *statbuf, void *args, int depth)
89{
90 int ret;
91
92 if (depth == 1)
93 return TRUE;
94
95 if (depth == 2 &&
96 ((!list_mode && access(file, X_OK)) ||
97 invalid_name(file) ||
98 !(statbuf->st_mode & (S_IFREG | S_IFLNK))) )
99 return SKIP;
100
101 if (test_mode || list_mode) {
102 puts(file);
103 return TRUE;
Denis Vlasenkoe5667c12006-11-26 20:13:39 +0000104 }
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000105 G.cmd[0] = (char*)file;
106 ret = wait4pid(spawn(G.cmd));
107 if (ret < 0) {
Denis Vlasenko45cd0892007-03-28 22:04:04 +0000108 bb_perror_msg("failed to exec %s", file);
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000109 } else if (ret > 0) {
Denis Vlasenko45cd0892007-03-28 22:04:04 +0000110 bb_error_msg("%s exited with return code %d", file, ret);
Denis Vlasenkoe5667c12006-11-26 20:13:39 +0000111 }
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000112 return !ret;
Denis Vlasenkoe5667c12006-11-26 20:13:39 +0000113}
114
Denis Vlasenko06af2162007-02-03 17:28:39 +0000115int run_parts_main(int argc, char **argv);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000116int run_parts_main(int argc, char **argv)
Eric Andersen7d682902001-10-31 10:59:29 +0000117{
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000118 char *umask_p;
119 llist_t *arg_list = NULL;
120 unsigned tmp;
Eric Andersen7d682902001-10-31 10:59:29 +0000121
Glenn L McGrath545106f2002-11-11 06:21:00 +0000122 umask(022);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000123 /* We require exactly one argument: the directory name */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000124 opt_complementary = "=1:a::";
125#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
126 applet_long_options = runparts_long_options;
127#endif
128 tmp = getopt32(argc, argv, "a:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
129 G.mode = tmp &~ (RUN_PARTS_OPT_a|RUN_PARTS_OPT_u);
130 if (tmp & RUN_PARTS_OPT_u) {
131 /* Check and set the umask of the program executed.
132 * As stated in the original run-parts, the octal conversion in
133 * libc is not foolproof; it will take the 8 and 9 digits under
134 * some circumstances. We'll just have to live with it.
135 */
Denis Vlasenko45cd0892007-03-28 22:04:04 +0000136 umask(xstrtoul_range(umask_p, 8, 0, 07777));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000137 }
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000138 for (tmp = 1; arg_list; arg_list = arg_list->link, tmp++)
139 G.cmd[tmp] = arg_list->data;
Denis Vlasenkoc7d4b982007-03-28 22:05:38 +0000140 /* G.cmd[tmp] = NULL; - G is already zeroed out */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000141 if (!recursive_action(argv[argc - 1],
Denis Vlasenkobbd695d2007-04-08 10:52:28 +0000142 ACTION_RECURSE|ACTION_FOLLOWLINKS,
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000143 act, /* file action */
144 act, /* dir action */
145 NULL, /* user data */
146 1 /* depth */
147 ))
148 return EXIT_FAILURE;
149 return EXIT_SUCCESS;
Eric Andersen7d682902001-10-31 10:59:29 +0000150}