1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini run-parts implementation for busybox 4 * 5 * Copyright (C) 2007 Bernhard 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 * 15 * Licensed under GPL v2 or later, see file LICENSE in this tarball for details. 16 */ 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, 22 * taken from debian-utils. I've only removed the long options and a the 23 * report mode. As the original run-parts support only long options, I've 24 * broken compatibility because the BusyBox policy doesn't allow them. 25 * The supported options are: 26 * -t test. Print the name of the files to be executed, without 27 * execute them. 28 * -a ARG argument. Pass ARG as an argument the program executed. It can 29 * be repeated to pass multiple arguments. 30 * -u MASK umask. Set the umask of the program executed to MASK. 31 */ 32 33#include <getopt.h> 34 35#include "libbb.h" 36 37#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS 38static const char runparts_longopts[] ALIGN1 = 39 "arg\0" Required_argument "a" 40 "umask\0" Required_argument "u" 41 "test\0" No_argument "t" 42#if ENABLE_FEATURE_RUN_PARTS_FANCY 43 "list\0" No_argument "l" 44//TODO: "reverse\0" No_argument "r" 45//TODO: "verbose\0" No_argument "v" 46#endif 47 ; 48#endif 49 50struct globals { 51 smalluint mode; 52 char *cmd[10]; /* merely arbitrary arg count */ 53}; 54#define G (*(struct globals*)&bb_common_bufsiz1) 55 56/* valid_name */ 57/* True or false? Is this a valid filename (upper/lower alpha, digits, 58 * underscores, and hyphens only?) 59 */ 60static bool invalid_name(const char *c) 61{ 62 c = bb_basename(c); 63 64 while (*c && (isalnum(*c) || *c == '_' || *c == '-')) 65 c++; 66 67 return *c; /* TRUE (!0) if terminating NUL is not reached */ 68} 69 70#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) 75#endif 76 77#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 83 84static 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; 100 } 101 G.cmd[0] = (char*)file; 102 ret = wait4pid(spawn(G.cmd)); 103 if (ret < 0) { 104 bb_perror_msg("failed to exec %s", file); 105 } else if (ret > 0) { 106 bb_error_msg("%s exited with return code %d", file, ret); 107 } 108 return !ret; 109} 110 111int run_parts_main(int argc, char **argv); 112int run_parts_main(int argc, char **argv) 113{ 114 char *umask_p; 115 llist_t *arg_list = NULL; 116 unsigned tmp; 117 118 umask(022); 119 /* We require exactly one argument: the directory name */ 120 opt_complementary = "=1:a::"; 121#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS 122 applet_long_options = runparts_longopts; 123#endif 124 tmp = getopt32(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)); 133 } 134 for (tmp = 1; arg_list; arg_list = arg_list->link, tmp++) 135 G.cmd[tmp] = arg_list->data; 136 /* G.cmd[tmp] = NULL; - G is already zeroed out */ 137 if (!recursive_action(argv[argc - 1], 138 ACTION_RECURSE|ACTION_FOLLOWLINKS, 139 act, /* file action */ 140 act, /* dir action */ 141 NULL, /* user data */ 142 1 /* depth */ 143 )) 144 return EXIT_FAILURE; 145 return EXIT_SUCCESS; 146} 147