blob: 4173987abaeb72fe1a4493535bb29e880de41be4 [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
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +000038static const char runparts_longopts[] =
39 "arg\0" Required_argument "a"
40 "umask\0" Required_argument "u"
41 "test\0" No_argument "t"
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000042#if ENABLE_FEATURE_RUN_PARTS_FANCY
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +000043 "list\0" No_argument "l"
44//TODO: "reverse\0" No_argument "r"
45//TODO: "verbose\0" No_argument "v"
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000046#endif
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +000047 "\0";
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000048#endif
49
50struct globals {
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000051 smalluint mode;
Denis Vlasenko45cd0892007-03-28 22:04:04 +000052 char *cmd[10]; /* merely arbitrary arg count */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000053};
54#define G (*(struct globals*)&bb_common_bufsiz1)
Eric Andersena1ed06b2003-07-26 09:16:00 +000055
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000056/* valid_name */
57/* True or false? Is this a valid filename (upper/lower alpha, digits,
58 * underscores, and hyphens only?)
59 */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000060static bool invalid_name(const char *c)
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000061{
Denis Vlasenkodc757aa2007-06-30 08:04:05 +000062 c = bb_basename(c);
Denis Vlasenkod4728142007-04-29 23:38:12 +000063
64 while (*c && (isalnum(*c) || *c == '_' || *c == '-'))
65 c++;
66
67 return *c; /* TRUE (!0) if terminating NUL is not reached */
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000068}
Denis Vlasenkod4728142007-04-29 23:38:12 +000069
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000070#define RUN_PARTS_OPT_a (1<<0)
71#define RUN_PARTS_OPT_u (1<<1)
72#define RUN_PARTS_OPT_t (1<<2)
73#if ENABLE_FEATURE_RUN_PARTS_FANCY
74#define RUN_PARTS_OPT_l (1<<3)
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000075#endif
Denis Vlasenkoe5667c12006-11-26 20:13:39 +000076
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000077#define test_mode (G.mode & RUN_PARTS_OPT_t)
78#if ENABLE_FEATURE_RUN_PARTS_FANCY
79#define list_mode (G.mode & RUN_PARTS_OPT_l)
80#else
81#define list_mode (0)
82#endif
Denis Vlasenkod4728142007-04-29 23:38:12 +000083
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +000084static int act(const char *file, struct stat *statbuf, void *args, int depth)
85{
86 int ret;
87
88 if (depth == 1)
89 return TRUE;
90
91 if (depth == 2 &&
92 ((!list_mode && access(file, X_OK)) ||
93 invalid_name(file) ||
94 !(statbuf->st_mode & (S_IFREG | S_IFLNK))) )
95 return SKIP;
96
97 if (test_mode || list_mode) {
98 puts(file);
99 return TRUE;
Denis Vlasenkoe5667c12006-11-26 20:13:39 +0000100 }
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000101 G.cmd[0] = (char*)file;
102 ret = wait4pid(spawn(G.cmd));
103 if (ret < 0) {
Denis Vlasenko45cd0892007-03-28 22:04:04 +0000104 bb_perror_msg("failed to exec %s", file);
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000105 } else if (ret > 0) {
Denis Vlasenko45cd0892007-03-28 22:04:04 +0000106 bb_error_msg("%s exited with return code %d", file, ret);
Denis Vlasenkoe5667c12006-11-26 20:13:39 +0000107 }
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000108 return !ret;
Denis Vlasenkoe5667c12006-11-26 20:13:39 +0000109}
110
Denis Vlasenko06af2162007-02-03 17:28:39 +0000111int run_parts_main(int argc, char **argv);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000112int run_parts_main(int argc, char **argv)
Eric Andersen7d682902001-10-31 10:59:29 +0000113{
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000114 char *umask_p;
115 llist_t *arg_list = NULL;
116 unsigned tmp;
Eric Andersen7d682902001-10-31 10:59:29 +0000117
Glenn L McGrath545106f2002-11-11 06:21:00 +0000118 umask(022);
Glenn L McGrath545106f2002-11-11 06:21:00 +0000119 /* We require exactly one argument: the directory name */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000120 opt_complementary = "=1:a::";
121#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
Denis Vlasenkobdc88fd2007-07-23 17:14:14 +0000122 applet_long_options = runparts_longopts;
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000123#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 */
Denis Vlasenko45cd0892007-03-28 22:04:04 +0000132 umask(xstrtoul_range(umask_p, 8, 0, 07777));
Glenn L McGrath545106f2002-11-11 06:21:00 +0000133 }
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000134 for (tmp = 1; arg_list; arg_list = arg_list->link, tmp++)
135 G.cmd[tmp] = arg_list->data;
Denis Vlasenkoc7d4b982007-03-28 22:05:38 +0000136 /* G.cmd[tmp] = NULL; - G is already zeroed out */
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000137 if (!recursive_action(argv[argc - 1],
Denis Vlasenkobbd695d2007-04-08 10:52:28 +0000138 ACTION_RECURSE|ACTION_FOLLOWLINKS,
Bernhard Reutner-Fischerb7cffd42007-03-28 20:35:13 +0000139 act, /* file action */
140 act, /* dir action */
141 NULL, /* user data */
142 1 /* depth */
143 ))
144 return EXIT_FAILURE;
145 return EXIT_SUCCESS;
Eric Andersen7d682902001-10-31 10:59:29 +0000146}