Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/debianutils/run_parts.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 815 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 2  Line 2 
2  /*  /*
3   * Mini run-parts implementation for busybox   * Mini run-parts implementation for busybox
4   *   *
5     * Copyright (C) 2007 Bernhard Reutner-Fischer
6   *   *
7   * Copyright (C) 2001 by Emanuele Aina <emanuele.aina@tiscali.it>   * 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   * Based on the Debian run-parts program, version 1.15
11   *   Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>,   *   Copyright (C) 1996 Jeff Noxon <jeff@router.patch.net>,
# Line 21  Line 23 
23   * report mode. As the original run-parts support only long options, I've   * report mode. As the original run-parts support only long options, I've
24   * broken compatibility because the BusyBox policy doesn't allow them.   * broken compatibility because the BusyBox policy doesn't allow them.
25   * The supported options are:   * The supported options are:
26   * -t test. Print the name of the files to be executed, without   * -t           test. Print the name of the files to be executed, without
27   * execute them.   *              execute them.
28   * -a ARG argument. Pass ARG as an argument the program executed. It can   * -a ARG       argument. Pass ARG as an argument the program executed. It can
29   * be repeated to pass multiple arguments.   *              be repeated to pass multiple arguments.
30   * -u MASK umask. Set the umask of the program executed to MASK. */   * -u MASK      umask. Set the umask of the program executed to MASK.
   
 /* TODO  
  * done - convert calls to error in perror... and remove error()  
  * done - convert malloc/realloc to their x... counterparts  
  * done - remove catch_sigchld  
  * done - use bb's concat_path_file()  
  * done - declare run_parts_main() as extern and any other function as static?  
31   */   */
32    
33  #include "busybox.h"  #include "libbb.h"
 #include <getopt.h>  
34    
35  static const struct option runparts_long_options[] = {  struct globals {
36   { "test",       0,      NULL,   't' },   char **names;
37   { "umask",      1,      NULL,   'u' },   int    cur;
38   { "arg",        1,      NULL,   'a' },   char  *cmd[1];
  { 0,            0,      0,      0   }  
39  };  };
40    #define G (*(struct globals*)&bb_common_bufsiz1)
41    #define names (G.names)
42    #define cur   (G.cur  )
43    #define cmd   (G.cmd  )
44    
45    enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 };
46    
47    enum {
48     OPT_r = (1 << 0),
49     OPT_a = (1 << 1),
50     OPT_u = (1 << 2),
51     OPT_t = (1 << 3),
52     OPT_l = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_FANCY,
53    };
54    
55    #if ENABLE_FEATURE_RUN_PARTS_FANCY
56    #define list_mode (option_mask32 & OPT_l)
57    #else
58    #define list_mode 0
59    #endif
60    
61  /* valid_name */  /* Is this a valid filename (upper/lower alpha, digits,
 /* True or false? Is this a valid filename (upper/lower alpha, digits,  
62   * underscores, and hyphens only?)   * underscores, and hyphens only?)
63   */   */
64  static int valid_name(const struct dirent *d)  static bool invalid_name(const char *c)
65  {  {
66   const char *c = d->d_name;   c = bb_basename(c);
67    
68   while (*c) {   while (*c && (isalnum(*c) || *c == '_' || *c == '-'))
69   if (!isalnum(*c) && (*c != '_') && (*c != '-')) {   c++;
70   return 0;  
71   }   return *c; /* TRUE (!0) if terminating NUL is not reached */
  ++c;  
  }  
  return 1;  
72  }  }
73    
74  /* test mode = 1 is the same as official run_parts  static int bb_alphasort(const void *p1, const void *p2)
  * test_mode = 2 means to fail silently on missing directories  
  */  
 static int run_parts(char **args, const unsigned char test_mode)  
75  {  {
76   struct dirent **namelist = 0;   int r = strcmp(*(char **) p1, *(char **) p2);
77   struct stat st;   return (option_mask32 & OPT_r) ? -r : r;
78   char *filename;  }
  char *arg0 = args[0];  
  int entries;  
  int i;  
  int exitstatus = 0;  
   
 #if __GNUC__  
  /* Avoid longjmp clobbering */  
  (void) &i;  
  (void) &exitstatus;  
 #endif  
  /* scandir() isn't POSIX, but it makes things easy. */  
  entries = scandir(arg0, &namelist, valid_name, alphasort);  
   
  if (entries == -1) {  
  if (test_mode & 2) {  
  return 2;  
  }  
  bb_perror_msg_and_die("cannot open '%s'", arg0);  
  }  
   
  for (i = 0; i < entries; i++) {  
  filename = concat_path_file(arg0, namelist[i]->d_name);  
79    
80   xstat(filename, &st);  static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUSED_PARAM, int depth)
81   if (S_ISREG(st.st_mode) && !access(filename, X_OK)) {  {
82   if (test_mode) {   if (depth == 1)
83   puts(filename);   return TRUE;
  } else {  
  /* exec_errno is common vfork variable */  
  volatile int exec_errno = 0;  
  int result;  
  int pid;  
   
  if ((pid = vfork()) < 0) {  
  bb_perror_msg_and_die("failed to fork");  
  } else if (!pid) {  
  args[0] = filename;  
  execve(filename, args, environ);  
  exec_errno = errno;  
  _exit(1);  
  }  
   
  waitpid(pid, &result, 0);  
  if (exec_errno) {  
  errno = exec_errno;  
  bb_perror_msg("failed to exec %s", filename);  
  exitstatus = 1;  
  }  
  if (WIFEXITED(result) && WEXITSTATUS(result)) {  
  bb_perror_msg("%s exited with return code %d", filename, WEXITSTATUS(result));  
  exitstatus = 1;  
  } else if (WIFSIGNALED(result)) {  
  bb_perror_msg("%s exited because of uncaught signal %d", filename, WTERMSIG(result));  
  exitstatus = 1;  
  }  
  }  
  } else if (!S_ISDIR(st.st_mode)) {  
  bb_error_msg("component %s is not an executable plain file", filename);  
  exitstatus = 1;  
  }  
84    
85   free(namelist[i]);   if (depth == 2
86   free(filename);   && (  !(statbuf->st_mode & (S_IFREG | S_IFLNK))
87        || invalid_name(file)
88        || (!list_mode && access(file, X_OK) != 0))
89     ) {
90     return SKIP;
91   }   }
  free(namelist);  
92    
93   return exitstatus;   names = xrealloc_vector(names, 4, cur);
94     names[cur++] = xstrdup(file);
95     /*names[cur] = NULL; - xrealloc_vector did it */
96    
97     return TRUE;
98  }  }
99    
100    #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
101    static const char runparts_longopts[] ALIGN1 =
102     "arg\0"     Required_argument "a"
103     "umask\0"   Required_argument "u"
104     "test\0"    No_argument       "t"
105    #if ENABLE_FEATURE_RUN_PARTS_FANCY
106     "list\0"    No_argument       "l"
107     "reverse\0" No_argument       "r"
108    //TODO: "verbose\0" No_argument       "v"
109    #endif
110     ;
111    #endif
112    
113  /* run_parts_main */  int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
114  /* Process options */  int run_parts_main(int argc UNUSED_PARAM, char **argv)
 int run_parts_main(int argc, char **argv)  
115  {  {
116   char **args = xmalloc(2 * sizeof(char *));   const char *umask_p = "22";
117   unsigned char test_mode = 0;   llist_t *arg_list = NULL;
118   unsigned short argcount = 1;   unsigned n;
119   int opt;   int ret;
   
  umask(022);  
   
  while ((opt = getopt_long(argc, argv, "tu:a:",  
  runparts_long_options, NULL)) > 0)  
  {  
  switch (opt) {  
  /* Enable test mode */  
  case 't':  
  test_mode++;  
  break;  
  /* Set the umask of the programs executed */  
  case 'u':  
  /* Check and set the umask of the program executed. As stated in the original  
  * run-parts, the octal conversion in libc is not foolproof; it will take the  
  * 8 and 9 digits under some circumstances. We'll just have to live with it.  
  */  
  umask(xstrtoul_range(optarg, 8, 0, 07777));  
  break;  
  /* Pass an argument to the programs */  
  case 'a':  
  /* Add an argument to the commands that we will call.  
  * Called once for every argument. */  
  args = xrealloc(args, (argcount + 2) * (sizeof(char *)));  
  args[argcount++] = optarg;  
  break;  
  default:  
  bb_show_usage();  
  }  
  }  
120    
121    #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
122     applet_long_options = runparts_longopts;
123    #endif
124   /* We require exactly one argument: the directory name */   /* We require exactly one argument: the directory name */
125   if (optind != (argc - 1)) {   /* We require exactly one argument: the directory name */
126   bb_show_usage();   opt_complementary = "=1:a::";
127     getopt32(argv, "ra:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
128    
129     umask(xstrtou_range(umask_p, 8, 0, 07777));
130    
131     n = 1;
132     while (arg_list && n < NUM_CMD) {
133     cmd[n++] = llist_pop(&arg_list);
134   }   }
135     /* cmd[n] = NULL; - is already zeroed out */
136    
137     /* run-parts has to sort executables by name before running them */
138    
139   args[0] = argv[optind];   recursive_action(argv[optind],
140   args[argcount] = 0;   ACTION_RECURSE|ACTION_FOLLOWLINKS,
141     act,            /* file action */
142     act,            /* dir action */
143     NULL,           /* user data */
144     1               /* depth */
145     );
146    
147     if (!names)
148     return 0;
149    
150     qsort(names, cur, sizeof(char *), bb_alphasort);
151    
152     n = 0;
153     while (1) {
154     char *name = *names++;
155     if (!name)
156     break;
157     if (option_mask32 & (OPT_t | OPT_l)) {
158     puts(name);
159     continue;
160     }
161     cmd[0] = name;
162     ret = wait4pid(spawn(cmd));
163     if (ret == 0)
164     continue;
165     n = 1;
166     if (ret < 0)
167     bb_perror_msg("can't exec %s", name);
168     else /* ret > 0 */
169     bb_error_msg("%s exited with code %d", name, ret);
170     }
171    
172   return run_parts(args, test_mode);   return n;
173  }  }

Legend:
Removed from v.815  
changed lines
  Added in v.816