run_parts.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. *
  15. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  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. /* This piece of code is heavily based on the original version of run-parts,
  20. * taken from debian-utils. I've only removed the long options and a the
  21. * report mode. As the original run-parts support only long options, I've
  22. * broken compatibility because the BusyBox policy doesn't allow them.
  23. * The supported options are:
  24. * -t test. Print the name of the files to be executed, without
  25. * execute them.
  26. * -a ARG argument. Pass ARG as an argument the program executed. It can
  27. * be repeated to pass multiple arguments.
  28. * -u MASK umask. Set the umask of the program executed to MASK.
  29. */
  30. //usage:#define run_parts_trivial_usage
  31. //usage: "[-t] "IF_FEATURE_RUN_PARTS_FANCY("[-l] ")"[-a ARG] [-u MASK] DIRECTORY"
  32. //usage:#define run_parts_full_usage "\n\n"
  33. //usage: "Run a bunch of scripts in DIRECTORY\n"
  34. //usage: "\n -t Print what would be run, but don't actually run anything"
  35. //usage: "\n -a ARG Pass ARG as argument for every program"
  36. //usage: "\n -u MASK Set the umask to MASK before running every program"
  37. //usage: IF_FEATURE_RUN_PARTS_FANCY(
  38. //usage: "\n -l Print names of all matching files even if they are not executable"
  39. //usage: )
  40. //usage:
  41. //usage:#define run_parts_example_usage
  42. //usage: "$ run-parts -a start /etc/init.d\n"
  43. //usage: "$ run-parts -a stop=now /etc/init.d\n\n"
  44. //usage: "Let's assume you have a script foo/dosomething:\n"
  45. //usage: "#!/bin/sh\n"
  46. //usage: "for i in $*; do eval $i; done; unset i\n"
  47. //usage: "case \"$1\" in\n"
  48. //usage: "start*) echo starting something;;\n"
  49. //usage: "stop*) set -x; shutdown -h $stop;;\n"
  50. //usage: "esac\n\n"
  51. //usage: "Running this yields:\n"
  52. //usage: "$run-parts -a stop=+4m foo/\n"
  53. //usage: "+ shutdown -h +4m"
  54. #include "libbb.h"
  55. struct globals {
  56. char **names;
  57. int cur;
  58. char *cmd[1];
  59. } FIX_ALIASING;
  60. #define G (*(struct globals*)&bb_common_bufsiz1)
  61. #define names (G.names)
  62. #define cur (G.cur )
  63. #define cmd (G.cmd )
  64. enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 };
  65. enum {
  66. OPT_r = (1 << 0),
  67. OPT_a = (1 << 1),
  68. OPT_u = (1 << 2),
  69. OPT_t = (1 << 3),
  70. OPT_l = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_FANCY,
  71. };
  72. #if ENABLE_FEATURE_RUN_PARTS_FANCY
  73. #define list_mode (option_mask32 & OPT_l)
  74. #else
  75. #define list_mode 0
  76. #endif
  77. /* Is this a valid filename (upper/lower alpha, digits,
  78. * underscores, and hyphens only?)
  79. */
  80. static bool invalid_name(const char *c)
  81. {
  82. c = bb_basename(c);
  83. while (*c && (isalnum(*c) || *c == '_' || *c == '-'))
  84. c++;
  85. return *c; /* TRUE (!0) if terminating NUL is not reached */
  86. }
  87. static int bb_alphasort(const void *p1, const void *p2)
  88. {
  89. int r = strcmp(*(char **) p1, *(char **) p2);
  90. return (option_mask32 & OPT_r) ? -r : r;
  91. }
  92. static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUSED_PARAM, int depth)
  93. {
  94. if (depth == 1)
  95. return TRUE;
  96. if (depth == 2
  97. && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK))
  98. || invalid_name(file)
  99. || (!list_mode && access(file, X_OK) != 0))
  100. ) {
  101. return SKIP;
  102. }
  103. names = xrealloc_vector(names, 4, cur);
  104. names[cur++] = xstrdup(file);
  105. /*names[cur] = NULL; - xrealloc_vector did it */
  106. return TRUE;
  107. }
  108. #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
  109. static const char runparts_longopts[] ALIGN1 =
  110. "arg\0" Required_argument "a"
  111. "umask\0" Required_argument "u"
  112. "test\0" No_argument "t"
  113. #if ENABLE_FEATURE_RUN_PARTS_FANCY
  114. "list\0" No_argument "l"
  115. "reverse\0" No_argument "r"
  116. //TODO: "verbose\0" No_argument "v"
  117. #endif
  118. ;
  119. #endif
  120. int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  121. int run_parts_main(int argc UNUSED_PARAM, char **argv)
  122. {
  123. const char *umask_p = "22";
  124. llist_t *arg_list = NULL;
  125. unsigned n;
  126. int ret;
  127. #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
  128. applet_long_options = runparts_longopts;
  129. #endif
  130. /* We require exactly one argument: the directory name */
  131. opt_complementary = "=1:a::";
  132. getopt32(argv, "ra:u:t"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
  133. umask(xstrtou_range(umask_p, 8, 0, 07777));
  134. n = 1;
  135. while (arg_list && n < NUM_CMD) {
  136. cmd[n++] = llist_pop(&arg_list);
  137. }
  138. /* cmd[n] = NULL; - is already zeroed out */
  139. /* run-parts has to sort executables by name before running them */
  140. recursive_action(argv[optind],
  141. ACTION_RECURSE|ACTION_FOLLOWLINKS,
  142. act, /* file action */
  143. act, /* dir action */
  144. NULL, /* user data */
  145. 1 /* depth */
  146. );
  147. if (!names)
  148. return 0;
  149. qsort(names, cur, sizeof(char *), bb_alphasort);
  150. n = 0;
  151. while (1) {
  152. char *name = *names++;
  153. if (!name)
  154. break;
  155. if (option_mask32 & (OPT_t | OPT_l)) {
  156. puts(name);
  157. continue;
  158. }
  159. cmd[0] = name;
  160. ret = spawn_and_wait(cmd);
  161. if (ret == 0)
  162. continue;
  163. n = 1;
  164. if (ret < 0)
  165. bb_perror_msg("can't execute '%s'", name);
  166. else /* ret > 0 */
  167. bb_error_msg("%s exited with code %d", name, ret & 0xff);
  168. }
  169. return n;
  170. }