Magellan Linux

Annotation of /tags/mkinitrd-6_1_12/busybox/miscutils/devfsd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (hide annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 5 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/miscutils/devfsd.c
File MIME type: text/plain
File size: 54962 byte(s)
-updated to busybox-1.13.4
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
4     */
5    
6     /*
7     devfsd implementation for busybox
8    
9     Copyright (C) 2003 by Tito Ragusa <farmatito@tiscali.it>
10    
11     Busybox version is based on some previous work and ideas
12     Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it>
13    
14     devfsd.c
15    
16     Main file for devfsd (devfs daemon for Linux).
17    
18     Copyright (C) 1998-2002 Richard Gooch
19    
20     devfsd.h
21    
22     Header file for devfsd (devfs daemon for Linux).
23    
24     Copyright (C) 1998-2000 Richard Gooch
25    
26     compat_name.c
27    
28     Compatibility name file for devfsd (build compatibility names).
29    
30     Copyright (C) 1998-2002 Richard Gooch
31    
32     expression.c
33    
34     This code provides Borne Shell-like expression expansion.
35    
36     Copyright (C) 1997-1999 Richard Gooch
37    
38     This program is free software; you can redistribute it and/or modify
39     it under the terms of the GNU General Public License as published by
40     the Free Software Foundation; either version 2 of the License, or
41     (at your option) any later version.
42    
43     This program is distributed in the hope that it will be useful,
44     but WITHOUT ANY WARRANTY; without even the implied warranty of
45     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46     GNU General Public License for more details.
47    
48     You should have received a copy of the GNU General Public License
49     along with this program; if not, write to the Free Software
50     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
51    
52     Richard Gooch may be reached by email at rgooch@atnf.csiro.au
53     The postal address is:
54     Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
55     */
56 niro 816 #include "libbb.h"
57     #include "xregex.h"
58     #include <syslog.h>
59 niro 532
60     #include <sys/un.h>
61     #include <sys/sysmacros.h>
62    
63     /* Various defines taken from linux/major.h */
64     #define IDE0_MAJOR 3
65     #define IDE1_MAJOR 22
66     #define IDE2_MAJOR 33
67     #define IDE3_MAJOR 34
68     #define IDE4_MAJOR 56
69     #define IDE5_MAJOR 57
70     #define IDE6_MAJOR 88
71     #define IDE7_MAJOR 89
72     #define IDE8_MAJOR 90
73     #define IDE9_MAJOR 91
74    
75    
76     /* Various defines taken from linux/devfs_fs.h */
77     #define DEVFSD_PROTOCOL_REVISION_KERNEL 5
78     #define DEVFSD_IOCTL_BASE 'd'
79     /* These are the various ioctls */
80     #define DEVFSDIOC_GET_PROTO_REV _IOR(DEVFSD_IOCTL_BASE, 0, int)
81     #define DEVFSDIOC_SET_EVENT_MASK _IOW(DEVFSD_IOCTL_BASE, 2, int)
82     #define DEVFSDIOC_RELEASE_EVENT_QUEUE _IOW(DEVFSD_IOCTL_BASE, 3, int)
83     #define DEVFSDIOC_SET_CONFIG_DEBUG_MASK _IOW(DEVFSD_IOCTL_BASE, 4, int)
84     #define DEVFSD_NOTIFY_REGISTERED 0
85     #define DEVFSD_NOTIFY_UNREGISTERED 1
86     #define DEVFSD_NOTIFY_ASYNC_OPEN 2
87     #define DEVFSD_NOTIFY_CLOSE 3
88     #define DEVFSD_NOTIFY_LOOKUP 4
89     #define DEVFSD_NOTIFY_CHANGE 5
90     #define DEVFSD_NOTIFY_CREATE 6
91     #define DEVFSD_NOTIFY_DELETE 7
92     #define DEVFS_PATHLEN 1024
93     /* Never change this otherwise the binary interface will change */
94    
95     struct devfsd_notify_struct
96 niro 816 { /* Use native C types to ensure same types in kernel and user space */
97     unsigned int type; /* DEVFSD_NOTIFY_* value */
98     unsigned int mode; /* Mode of the inode or device entry */
99     unsigned int major; /* Major number of device entry */
100     unsigned int minor; /* Minor number of device entry */
101     unsigned int uid; /* Uid of process, inode or device entry */
102     unsigned int gid; /* Gid of process, inode or device entry */
103     unsigned int overrun_count; /* Number of lost events */
104     unsigned int namelen; /* Number of characters not including '\0' */
105     /* The device name MUST come last */
106     char devname[DEVFS_PATHLEN]; /* This will be '\0' terminated */
107 niro 532 };
108    
109     #define BUFFER_SIZE 16384
110     #define DEVFSD_VERSION "1.3.25"
111     #define CONFIG_FILE "/etc/devfsd.conf"
112     #define MODPROBE "/sbin/modprobe"
113     #define MODPROBE_SWITCH_1 "-k"
114     #define MODPROBE_SWITCH_2 "-C"
115     #define CONFIG_MODULES_DEVFS "/etc/modules.devfs"
116     #define MAX_ARGS (6 + 1)
117     #define MAX_SUBEXPR 10
118     #define STRING_LENGTH 255
119    
120     /* for get_uid_gid() */
121     #define UID 0
122     #define GID 1
123    
124     /* fork_and_execute() */
125     # define DIE 1
126     # define NO_DIE 0
127    
128     /* for dir_operation() */
129     #define RESTORE 0
130     #define SERVICE 1
131     #define READ_CONFIG 2
132    
133     /* Update only after changing code to reflect new protocol */
134     #define DEVFSD_PROTOCOL_REVISION_DAEMON 5
135    
136     /* Compile-time check */
137     #if DEVFSD_PROTOCOL_REVISION_KERNEL != DEVFSD_PROTOCOL_REVISION_DAEMON
138     #error protocol version mismatch. Update your kernel headers
139     #endif
140    
141     #define AC_PERMISSIONS 0
142     #define AC_MODLOAD 1
143     #define AC_EXECUTE 2
144     #define AC_MFUNCTION 3 /* not supported by busybox */
145     #define AC_CFUNCTION 4 /* not supported by busybox */
146     #define AC_COPY 5
147     #define AC_IGNORE 6
148     #define AC_MKOLDCOMPAT 7
149     #define AC_MKNEWCOMPAT 8
150     #define AC_RMOLDCOMPAT 9
151     #define AC_RMNEWCOMPAT 10
152     #define AC_RESTORE 11
153    
154     struct permissions_type
155     {
156 niro 816 mode_t mode;
157     uid_t uid;
158     gid_t gid;
159 niro 532 };
160    
161     struct execute_type
162     {
163 niro 816 char *argv[MAX_ARGS + 1]; /* argv[0] must always be the programme */
164 niro 532 };
165    
166     struct copy_type
167     {
168 niro 816 const char *source;
169     const char *destination;
170 niro 532 };
171    
172     struct action_type
173     {
174 niro 816 unsigned int what;
175     unsigned int when;
176 niro 532 };
177    
178     struct config_entry_struct
179     {
180 niro 816 struct action_type action;
181     regex_t preg;
182     union
183     {
184 niro 532 struct permissions_type permissions;
185     struct execute_type execute;
186     struct copy_type copy;
187 niro 816 }
188     u;
189     struct config_entry_struct *next;
190 niro 532 };
191    
192     struct get_variable_info
193     {
194 niro 816 const struct devfsd_notify_struct *info;
195     const char *devname;
196     char devpath[STRING_LENGTH];
197 niro 532 };
198    
199 niro 816 static void dir_operation(int , const char * , int, unsigned long*);
200 niro 532 static void service(struct stat statbuf, char *path);
201 niro 816 static int st_expr_expand(char *, unsigned, const char *, const char *(*)(const char *, void *), void *);
202 niro 532 static const char *get_old_name(const char *, unsigned, char *, unsigned, unsigned);
203 niro 816 static int mksymlink(const char *oldpath, const char *newpath);
204     static void read_config_file(char *path, int optional, unsigned long *event_mask);
205     static void process_config_line(const char *, unsigned long *);
206     static int do_servicing(int, unsigned long);
207     static void service_name(const struct devfsd_notify_struct *);
208     static void action_permissions(const struct devfsd_notify_struct *, const struct config_entry_struct *);
209     static void action_execute(const struct devfsd_notify_struct *, const struct config_entry_struct *,
210 niro 532 const regmatch_t *, unsigned);
211 niro 816 static void action_modload(const struct devfsd_notify_struct *info, const struct config_entry_struct *entry);
212     static void action_copy(const struct devfsd_notify_struct *, const struct config_entry_struct *,
213 niro 532 const regmatch_t *, unsigned);
214 niro 816 static void action_compat(const struct devfsd_notify_struct *, unsigned);
215     static void free_config(void);
216 niro 532 static void restore(char *spath, struct stat source_stat, int rootlen);
217 niro 816 static int copy_inode(const char *, const struct stat *, mode_t, const char *, const struct stat *);
218     static mode_t get_mode(const char *);
219     static void signal_handler(int);
220     static const char *get_variable(const char *, void *);
221     static int make_dir_tree(const char *);
222 niro 532 static int expand_expression(char *, unsigned, const char *, const char *(*)(const char *, void *), void *,
223 niro 816 const char *, const regmatch_t *, unsigned);
224     static void expand_regexp(char *, size_t, const char *, const char *, const regmatch_t *, unsigned);
225 niro 532 static const char *expand_variable( char *, unsigned, unsigned *, const char *,
226 niro 816 const char *(*)(const char *, void *), void *);
227     static const char *get_variable_v2(const char *, const char *(*)(const char *, void *), void *);
228     static char get_old_ide_name(unsigned , unsigned);
229     static char *write_old_sd_name(char *, unsigned, unsigned, const char *);
230 niro 532
231     /* busybox functions */
232 niro 816 static int get_uid_gid(int flag, const char *string);
233     static void safe_memcpy(char * dest, const char * src, int len);
234     static unsigned int scan_dev_name_common(const char *d, unsigned int n, int addendum, const char *ptr);
235     static unsigned int scan_dev_name(const char *d, unsigned int n, const char *ptr);
236 niro 532
237     /* Structs and vars */
238     static struct config_entry_struct *first_config = NULL;
239     static struct config_entry_struct *last_config = NULL;
240 niro 816 static char *mount_point = NULL;
241 niro 532 static volatile int caught_signal = FALSE;
242     static volatile int caught_sighup = FALSE;
243 niro 816 static struct initial_symlink_struct {
244     const char *dest;
245     const char *name;
246     } initial_symlinks[] = {
247     {"/proc/self/fd", "fd"},
248     {"fd/0", "stdin"},
249     {"fd/1", "stdout"},
250     {"fd/2", "stderr"},
251     {NULL, NULL},
252 niro 532 };
253    
254 niro 816 static struct event_type {
255     unsigned int type; /* The DEVFSD_NOTIFY_* value */
256     const char *config_name; /* The name used in the config file */
257     } event_types[] = {
258     {DEVFSD_NOTIFY_REGISTERED, "REGISTER"},
259     {DEVFSD_NOTIFY_UNREGISTERED, "UNREGISTER"},
260     {DEVFSD_NOTIFY_ASYNC_OPEN, "ASYNC_OPEN"},
261     {DEVFSD_NOTIFY_CLOSE, "CLOSE"},
262     {DEVFSD_NOTIFY_LOOKUP, "LOOKUP"},
263     {DEVFSD_NOTIFY_CHANGE, "CHANGE"},
264     {DEVFSD_NOTIFY_CREATE, "CREATE"},
265     {DEVFSD_NOTIFY_DELETE, "DELETE"},
266     {0xffffffff, NULL}
267 niro 532 };
268    
269     /* Busybox messages */
270    
271 niro 816 static const char bb_msg_proto_rev[] ALIGN1 = "protocol revision";
272     static const char bb_msg_bad_config[] ALIGN1 = "bad %s config file: %s";
273     static const char bb_msg_small_buffer[] ALIGN1 = "buffer too small";
274     static const char bb_msg_variable_not_found[] ALIGN1 = "variable: %s not found";
275 niro 532
276     /* Busybox stuff */
277 niro 816 #if ENABLE_DEVFSD_VERBOSE || ENABLE_DEBUG
278     #define info_logger(p, fmt, args...) bb_info_msg(fmt, ## args)
279     #define msg_logger(p, fmt, args...) bb_error_msg(fmt, ## args)
280     #define msg_logger_and_die(p, fmt, args...) bb_error_msg_and_die(fmt, ## args)
281     #define error_logger(p, fmt, args...) bb_perror_msg(fmt, ## args)
282     #define error_logger_and_die(p, fmt, args...) bb_perror_msg_and_die(fmt, ## args)
283 niro 532 #else
284 niro 816 #define info_logger(p, fmt, args...)
285 niro 532 #define msg_logger(p, fmt, args...)
286 niro 816 #define msg_logger_and_die(p, fmt, args...) exit(EXIT_FAILURE)
287     #define error_logger(p, fmt, args...)
288     #define error_logger_and_die(p, fmt, args...) exit(EXIT_FAILURE)
289 niro 532 #endif
290    
291 niro 816 static void safe_memcpy(char *dest, const char *src, int len)
292 niro 532 {
293 niro 816 memcpy(dest , src, len);
294 niro 532 dest[len] = '\0';
295     }
296    
297 niro 816 static unsigned int scan_dev_name_common(const char *d, unsigned int n, int addendum, const char *ptr)
298 niro 532 {
299 niro 816 if (d[n - 4] == 'd' && d[n - 3] == 'i' && d[n - 2] == 's' && d[n - 1] == 'c')
300 niro 532 return 2 + addendum;
301 niro 816 if (d[n - 2] == 'c' && d[n - 1] == 'd')
302 niro 532 return 3 + addendum;
303 niro 816 if (ptr[0] == 'p' && ptr[1] == 'a' && ptr[2] == 'r' && ptr[3] == 't')
304 niro 532 return 4 + addendum;
305 niro 816 if (ptr[n - 2] == 'm' && ptr[n - 1] == 't')
306 niro 532 return 5 + addendum;
307     return 0;
308     }
309    
310 niro 816 static unsigned int scan_dev_name(const char *d, unsigned int n, const char *ptr)
311 niro 532 {
312 niro 816 if (d[0] == 's' && d[1] == 'c' && d[2] == 's' && d[3] == 'i' && d[4] == '/') {
313     if (d[n - 7] == 'g' && d[n - 6] == 'e' && d[n - 5] == 'n'
314     && d[n - 4] == 'e' && d[n - 3] == 'r' && d[n - 2] == 'i' && d[n - 1] == 'c'
315     )
316 niro 532 return 1;
317     return scan_dev_name_common(d, n, 0, ptr);
318     }
319 niro 816 if (d[0] == 'i' && d[1] == 'd' && d[2] == 'e' && d[3] == '/'
320     && d[4] == 'h' && d[5] == 'o' && d[6] == 's' && d[7] == 't'
321     )
322 niro 532 return scan_dev_name_common(d, n, 4, ptr);
323 niro 816 if (d[0] == 's' && d[1] == 'b' && d[2] == 'p' && d[3] == '/')
324 niro 532 return 10;
325 niro 816 if (d[0] == 'v' && d[1] == 'c' && d[2] == 'c' && d[3] == '/')
326 niro 532 return 11;
327 niro 816 if (d[0] == 'p' && d[1] == 't' && d[2] == 'y' && d[3] == '/')
328 niro 532 return 12;
329     return 0;
330     }
331    
332     /* Public functions follow */
333    
334 niro 816 int devfsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
335     int devfsd_main(int argc, char **argv)
336 niro 532 {
337     int print_version = FALSE;
338     int do_daemon = TRUE;
339     int no_polling = FALSE;
340     int do_scan;
341     int fd, proto_rev, count;
342     unsigned long event_mask = 0;
343     struct sigaction new_action;
344     struct initial_symlink_struct *curr;
345    
346     if (argc < 2)
347     bb_show_usage();
348    
349 niro 816 for (count = 2; count < argc; ++count) {
350     if (argv[count][0] == '-') {
351     if (argv[count][1] == 'v' && !argv[count][2]) /* -v */
352     print_version = TRUE;
353     else if (ENABLE_DEVFSD_FG_NP && argv[count][1] == 'f'
354     && argv[count][2] == 'g' && !argv[count][3]) /* -fg */
355     do_daemon = FALSE;
356     else if (ENABLE_DEVFSD_FG_NP && argv[count][1] == 'n'
357     && argv[count][2] == 'p' && !argv[count][3]) /* -np */
358     no_polling = TRUE;
359 niro 532 else
360     bb_show_usage();
361     }
362     }
363    
364 niro 816 mount_point = bb_simplify_path(argv[1]);
365 niro 532
366 niro 816 xchdir(mount_point);
367 niro 532
368 niro 816 fd = xopen(".devfsd", O_RDONLY);
369     close_on_exec_on(fd);
370     xioctl(fd, DEVFSDIOC_GET_PROTO_REV, &proto_rev);
371 niro 532
372     /*setup initial entries */
373 niro 816 for (curr = initial_symlinks; curr->dest != NULL; ++curr)
374     symlink(curr->dest, curr->name);
375 niro 532
376     /* NB: The check for CONFIG_FILE is done in read_config_file() */
377    
378 niro 816 if (print_version || (DEVFSD_PROTOCOL_REVISION_DAEMON != proto_rev)) {
379     printf("%s v%s\nDaemon %s:\t%d\nKernel-side %s:\t%d\n",
380     applet_name, DEVFSD_VERSION, bb_msg_proto_rev,
381     DEVFSD_PROTOCOL_REVISION_DAEMON, bb_msg_proto_rev, proto_rev);
382 niro 532 if (DEVFSD_PROTOCOL_REVISION_DAEMON != proto_rev)
383 niro 816 bb_error_msg_and_die("%s mismatch!", bb_msg_proto_rev);
384 niro 532 exit(EXIT_SUCCESS); /* -v */
385     }
386 niro 816 /* Tell kernel we are special(i.e. we get to see hidden entries) */
387     xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, 0);
388 niro 532
389 niro 816 /* Set up SIGHUP and SIGUSR1 handlers */
390     sigemptyset(&new_action.sa_mask);
391 niro 532 new_action.sa_flags = 0;
392     new_action.sa_handler = signal_handler;
393 niro 816 sigaction_set(SIGHUP, &new_action);
394     sigaction_set(SIGUSR1, &new_action);
395 niro 532
396 niro 816 printf("%s v%s started for %s\n", applet_name, DEVFSD_VERSION, mount_point);
397 niro 532
398     /* Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions */
399 niro 816 umask(0);
400     read_config_file((char*)CONFIG_FILE, FALSE, &event_mask);
401 niro 532 /* Do the scan before forking, so that boot scripts see the finished product */
402 niro 816 dir_operation(SERVICE, mount_point, 0, NULL);
403 niro 532
404     if (ENABLE_DEVFSD_FG_NP && no_polling)
405 niro 816 exit(EXIT_SUCCESS);
406    
407     if (ENABLE_DEVFSD_VERBOSE || ENABLE_DEBUG)
408     logmode = LOGMODE_BOTH;
409     else if (do_daemon == TRUE)
410     logmode = LOGMODE_SYSLOG;
411     /* This is the default */
412     /*else
413     logmode = LOGMODE_STDIO; */
414    
415     if (do_daemon) {
416 niro 532 /* Release so that the child can grab it */
417 niro 816 xioctl(fd, DEVFSDIOC_RELEASE_EVENT_QUEUE, 0);
418     bb_daemonize_or_rexec(0, argv);
419     } else if (ENABLE_DEVFSD_FG_NP) {
420     setpgid(0, 0); /* Become process group leader */
421 niro 532 }
422    
423 niro 816 while (TRUE) {
424     do_scan = do_servicing(fd, event_mask);
425 niro 532
426 niro 816 free_config();
427     read_config_file((char*)CONFIG_FILE, FALSE, &event_mask);
428 niro 532 if (do_scan)
429 niro 816 dir_operation(SERVICE, mount_point, 0, NULL);
430 niro 532 }
431 niro 816 if (ENABLE_FEATURE_CLEAN_UP) free(mount_point);
432 niro 532 } /* End Function main */
433    
434    
435     /* Private functions follow */
436    
437 niro 816 static void read_config_file(char *path, int optional, unsigned long *event_mask)
438 niro 532 /* [SUMMARY] Read a configuration database.
439     <path> The path to read the database from. If this is a directory, all
440 niro 816 entries in that directory will be read(except hidden entries).
441 niro 532 <optional> If TRUE, the routine will silently ignore a missing config file.
442     <event_mask> The event mask is written here. This is not initialised.
443     [RETURNS] Nothing.
444     */
445     {
446     struct stat statbuf;
447     FILE *fp;
448     char buf[STRING_LENGTH];
449 niro 816 char *line = NULL;
450     char *p;
451 niro 532
452 niro 816 if (stat(path, &statbuf) == 0) {
453 niro 532 /* Don't read 0 length files: ignored */
454 niro 816 /*if (statbuf.st_size == 0)
455 niro 532 return;*/
456 niro 816 if (S_ISDIR(statbuf.st_mode)) {
457     p = bb_simplify_path(path);
458     dir_operation(READ_CONFIG, p, 0, event_mask);
459     free(p);
460 niro 532 return;
461     }
462 niro 816 fp = fopen_for_read(path);
463     if (fp != NULL) {
464     while (fgets(buf, STRING_LENGTH, fp) != NULL) {
465 niro 532 /* Skip whitespace */
466 niro 816 line = buf;
467     line = skip_whitespace(line);
468     if (line[0] == '\0' || line[0] == '#')
469 niro 532 continue;
470 niro 816 process_config_line(line, event_mask);
471 niro 532 }
472 niro 816 fclose(fp);
473 niro 532 } else {
474     goto read_config_file_err;
475     }
476     } else {
477     read_config_file_err:
478 niro 816 if (optional == 0 && errno == ENOENT)
479     error_logger_and_die(LOG_ERR, "read config file: %s", path);
480 niro 532 }
481     } /* End Function read_config_file */
482    
483 niro 816 static void process_config_line(const char *line, unsigned long *event_mask)
484 niro 532 /* [SUMMARY] Process a line from a configuration file.
485     <line> The configuration line.
486     <event_mask> The event mask is written here. This is not initialised.
487     [RETURNS] Nothing.
488     */
489     {
490     int num_args, count;
491     struct config_entry_struct *new;
492     char p[MAX_ARGS][STRING_LENGTH];
493     char when[STRING_LENGTH], what[STRING_LENGTH];
494     char name[STRING_LENGTH];
495 niro 816 const char *msg = "";
496 niro 532 char *ptr;
497     int i;
498    
499     /* !!!! Only Uppercase Keywords in devsfd.conf */
500 niro 816 static const char options[] ALIGN1 =
501     "CLEAR_CONFIG\0""INCLUDE\0""OPTIONAL_INCLUDE\0"
502     "RESTORE\0""PERMISSIONS\0""MODLOAD\0""EXECUTE\0"
503     "COPY\0""IGNORE\0""MKOLDCOMPAT\0""MKNEWCOMPAT\0"
504     "RMOLDCOMPAT\0""RMNEWCOMPAT\0";
505 niro 532
506 niro 816 for (count = 0; count < MAX_ARGS; ++count)
507     p[count][0] = '\0';
508     num_args = sscanf(line, "%s %s %s %s %s %s %s %s %s %s",
509 niro 532 when, name, what,
510     p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
511    
512 niro 816 i = index_in_strings(options, when);
513 niro 532
514 niro 816 /* "CLEAR_CONFIG" */
515     if (i == 0) {
516     free_config();
517 niro 532 *event_mask = 0;
518     return;
519     }
520    
521 niro 816 if (num_args < 2)
522 niro 532 goto process_config_line_err;
523    
524     /* "INCLUDE" & "OPTIONAL_INCLUDE" */
525 niro 816 if (i == 1 || i == 2) {
526     st_expr_expand(name, STRING_LENGTH, name, get_variable, NULL);
527     info_logger(LOG_INFO, "%sinclude: %s", (toupper(when[0]) == 'I') ? "": "optional_", name);
528     read_config_file(name, (toupper(when[0]) == 'I') ? FALSE : TRUE, event_mask);
529 niro 532 return;
530     }
531     /* "RESTORE" */
532 niro 816 if (i == 3) {
533     dir_operation(RESTORE, name, strlen(name),NULL);
534 niro 532 return;
535     }
536     if (num_args < 3)
537     goto process_config_line_err;
538    
539 niro 816 new = xzalloc(sizeof *new);
540 niro 532
541 niro 816 for (count = 0; event_types[count].config_name != NULL; ++count) {
542     if (strcasecmp(when, event_types[count].config_name) != 0)
543 niro 532 continue;
544     new->action.when = event_types[count].type;
545     break;
546     }
547 niro 816 if (event_types[count].config_name == NULL) {
548     msg = "WHEN in";
549 niro 532 goto process_config_line_err;
550     }
551    
552 niro 816 i = index_in_strings(options, what);
553 niro 532
554 niro 816 switch (i) {
555 niro 532 case 4: /* "PERMISSIONS" */
556     new->action.what = AC_PERMISSIONS;
557     /* Get user and group */
558 niro 816 ptr = strchr(p[0], '.');
559     if (ptr == NULL) {
560     msg = "UID.GID";
561 niro 532 goto process_config_line_err; /*"missing '.' in UID.GID"*/
562     }
563    
564     *ptr++ = '\0';
565 niro 816 new->u.permissions.uid = get_uid_gid(UID, p[0]);
566     new->u.permissions.gid = get_uid_gid(GID, ptr);
567 niro 532 /* Get mode */
568 niro 816 new->u.permissions.mode = get_mode(p[1]);
569 niro 532 break;
570     case 5: /* MODLOAD */
571 niro 816 /*This action will pass "/dev/$devname"(i.e. "/dev/" prefixed to
572 niro 532 the device name) to the module loading facility. In addition,
573     the /etc/modules.devfs configuration file is used.*/
574     if (ENABLE_DEVFSD_MODLOAD)
575     new->action.what = AC_MODLOAD;
576     break;
577     case 6: /* EXECUTE */
578     new->action.what = AC_EXECUTE;
579     num_args -= 3;
580    
581     for (count = 0; count < num_args; ++count)
582 niro 816 new->u.execute.argv[count] = xstrdup(p[count]);
583 niro 532
584     new->u.execute.argv[num_args] = NULL;
585     break;
586     case 7: /* COPY */
587     new->action.what = AC_COPY;
588     num_args -= 3;
589     if (num_args != 2)
590     goto process_config_line_err; /* missing path and function in line */
591    
592 niro 816 new->u.copy.source = xstrdup(p[0]);
593     new->u.copy.destination = xstrdup(p[1]);
594 niro 532 break;
595     case 8: /* IGNORE */
596     /* FALLTROUGH */
597     case 9: /* MKOLDCOMPAT */
598     /* FALLTROUGH */
599     case 10: /* MKNEWCOMPAT */
600     /* FALLTROUGH */
601     case 11:/* RMOLDCOMPAT */
602     /* FALLTROUGH */
603     case 12: /* RMNEWCOMPAT */
604     /* AC_IGNORE 6
605     AC_MKOLDCOMPAT 7
606     AC_MKNEWCOMPAT 8
607     AC_RMOLDCOMPAT 9
608     AC_RMNEWCOMPAT 10*/
609     new->action.what = i - 2;
610     break;
611     default:
612 niro 816 msg = "WHAT in";
613 niro 532 goto process_config_line_err;
614     /*esac*/
615     } /* switch (i) */
616    
617 niro 816 xregcomp(&new->preg, name, REG_EXTENDED);
618 niro 532
619     *event_mask |= 1 << new->action.when;
620     new->next = NULL;
621     if (first_config == NULL)
622     first_config = new;
623     else
624     last_config->next = new;
625     last_config = new;
626     return;
627 niro 816
628     process_config_line_err:
629 niro 532 msg_logger_and_die(LOG_ERR, bb_msg_bad_config, msg , line);
630     } /* End Function process_config_line */
631    
632 niro 816 static int do_servicing(int fd, unsigned long event_mask)
633 niro 532 /* [SUMMARY] Service devfs changes until a signal is received.
634     <fd> The open control file.
635     <event_mask> The event mask.
636     [RETURNS] TRUE if SIGHUP was caught, else FALSE.
637     */
638     {
639     ssize_t bytes;
640     struct devfsd_notify_struct info;
641    
642 niro 816 /* (void*) cast is only in order to match prototype */
643     xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, (void*)event_mask);
644     while (!caught_signal) {
645 niro 532 errno = 0;
646 niro 816 bytes = read(fd,(char *) &info, sizeof info);
647 niro 532 if (caught_signal)
648     break; /* Must test for this first */
649     if (errno == EINTR)
650     continue; /* Yes, the order is important */
651     if (bytes < 1)
652     break;
653 niro 816 service_name(&info);
654 niro 532 }
655 niro 816 if (caught_signal) {
656 niro 532 int c_sighup = caught_sighup;
657    
658     caught_signal = FALSE;
659     caught_sighup = FALSE;
660     return c_sighup;
661     }
662     msg_logger_and_die(LOG_ERR, "read error on control file");
663     } /* End Function do_servicing */
664    
665 niro 816 static void service_name(const struct devfsd_notify_struct *info)
666 niro 532 /* [SUMMARY] Service a single devfs change.
667     <info> The devfs change.
668     [RETURNS] Nothing.
669     */
670     {
671     unsigned int n;
672     regmatch_t mbuf[MAX_SUBEXPR];
673     struct config_entry_struct *entry;
674    
675     if (ENABLE_DEBUG && info->overrun_count > 0)
676 niro 816 msg_logger(LOG_ERR, "lost %u events", info->overrun_count);
677 niro 532
678     /* Discard lookups on "/dev/log" and "/dev/initctl" */
679 niro 816 if (info->type == DEVFSD_NOTIFY_LOOKUP
680     && ((info->devname[0] == 'l' && info->devname[1] == 'o'
681     && info->devname[2] == 'g' && !info->devname[3])
682     || (info->devname[0] == 'i' && info->devname[1] == 'n'
683     && info->devname[2] == 'i' && info->devname[3] == 't'
684     && info->devname[4] == 'c' && info->devname[5] == 't'
685     && info->devname[6] == 'l' && !info->devname[7]))
686     )
687     return;
688    
689     for (entry = first_config; entry != NULL; entry = entry->next) {
690 niro 532 /* First check if action matches the type, then check if name matches */
691 niro 816 if (info->type != entry->action.when
692     || regexec(&entry->preg, info->devname, MAX_SUBEXPR, mbuf, 0) != 0)
693 niro 532 continue;
694 niro 816 for (n = 0;(n < MAX_SUBEXPR) && (mbuf[n].rm_so != -1); ++n)
695 niro 532 /* VOID */;
696    
697 niro 816 switch (entry->action.what) {
698 niro 532 case AC_PERMISSIONS:
699 niro 816 action_permissions(info, entry);
700 niro 532 break;
701     case AC_MODLOAD:
702 niro 816 if (ENABLE_DEVFSD_MODLOAD)
703     action_modload(info, entry);
704 niro 532 break;
705     case AC_EXECUTE:
706 niro 816 action_execute(info, entry, mbuf, n);
707 niro 532 break;
708     case AC_COPY:
709 niro 816 action_copy(info, entry, mbuf, n);
710 niro 532 break;
711     case AC_IGNORE:
712     return;
713     /*break;*/
714     case AC_MKOLDCOMPAT:
715     case AC_MKNEWCOMPAT:
716     case AC_RMOLDCOMPAT:
717     case AC_RMNEWCOMPAT:
718 niro 816 action_compat(info, entry->action.what);
719 niro 532 break;
720     default:
721     msg_logger_and_die(LOG_ERR, "Unknown action");
722     }
723     }
724     } /* End Function service_name */
725    
726 niro 816 static void action_permissions(const struct devfsd_notify_struct *info,
727 niro 532 const struct config_entry_struct *entry)
728     /* [SUMMARY] Update permissions for a device entry.
729     <info> The devfs change.
730     <entry> The config file entry.
731     [RETURNS] Nothing.
732     */
733     {
734     struct stat statbuf;
735    
736 niro 816 if (stat(info->devname, &statbuf) != 0
737     || chmod(info->devname, (statbuf.st_mode & S_IFMT) | (entry->u.permissions.mode & ~S_IFMT)) != 0
738     || chown(info->devname, entry->u.permissions.uid, entry->u.permissions.gid) != 0
739     )
740     error_logger(LOG_ERR, "Can't chmod or chown: %s", info->devname);
741 niro 532 } /* End Function action_permissions */
742    
743 niro 816 static void action_modload(const struct devfsd_notify_struct *info,
744     const struct config_entry_struct *entry UNUSED_PARAM)
745 niro 532 /* [SUMMARY] Load a module.
746     <info> The devfs change.
747     <entry> The config file entry.
748     [RETURNS] Nothing.
749     */
750     {
751     char *argv[6];
752    
753 niro 816 argv[0] = (char*)MODPROBE;
754     argv[1] = (char*)MODPROBE_SWITCH_1; /* "-k" */
755     argv[2] = (char*)MODPROBE_SWITCH_2; /* "-C" */
756     argv[3] = (char*)CONFIG_MODULES_DEVFS;
757     argv[4] = concat_path_file("/dev", info->devname); /* device */
758 niro 532 argv[5] = NULL;
759    
760 niro 816 wait4pid(xspawn(argv));
761     free(argv[4]);
762 niro 532 } /* End Function action_modload */
763    
764 niro 816 static void action_execute(const struct devfsd_notify_struct *info,
765 niro 532 const struct config_entry_struct *entry,
766     const regmatch_t *regexpr, unsigned int numexpr)
767     /* [SUMMARY] Execute a programme.
768     <info> The devfs change.
769     <entry> The config file entry.
770 niro 816 <regexpr> The number of subexpression(start, end) offsets within the
771 niro 532 device name.
772     <numexpr> The number of elements within <<regexpr>>.
773     [RETURNS] Nothing.
774     */
775     {
776     unsigned int count;
777     struct get_variable_info gv_info;
778     char *argv[MAX_ARGS + 1];
779     char largv[MAX_ARGS + 1][STRING_LENGTH];
780    
781     gv_info.info = info;
782     gv_info.devname = info->devname;
783 niro 816 snprintf(gv_info.devpath, sizeof(gv_info.devpath), "%s/%s", mount_point, info->devname);
784     for (count = 0; entry->u.execute.argv[count] != NULL; ++count) {
785     expand_expression(largv[count], STRING_LENGTH,
786 niro 532 entry->u.execute.argv[count],
787     get_variable, &gv_info,
788 niro 816 gv_info.devname, regexpr, numexpr);
789 niro 532 argv[count] = largv[count];
790     }
791     argv[count] = NULL;
792 niro 816 wait4pid(spawn(argv));
793 niro 532 } /* End Function action_execute */
794    
795    
796 niro 816 static void action_copy(const struct devfsd_notify_struct *info,
797 niro 532 const struct config_entry_struct *entry,
798     const regmatch_t *regexpr, unsigned int numexpr)
799     /* [SUMMARY] Copy permissions.
800     <info> The devfs change.
801     <entry> The config file entry.
802 niro 816 <regexpr> This list of subexpression(start, end) offsets within the
803 niro 532 device name.
804     <numexpr> The number of elements in <<regexpr>>.
805     [RETURNS] Nothing.
806     */
807     {
808     mode_t new_mode;
809     struct get_variable_info gv_info;
810     struct stat source_stat, dest_stat;
811     char source[STRING_LENGTH], destination[STRING_LENGTH];
812     int ret = 0;
813    
814     dest_stat.st_mode = 0;
815    
816 niro 816 if ((info->type == DEVFSD_NOTIFY_CHANGE) && S_ISLNK(info->mode))
817 niro 532 return;
818     gv_info.info = info;
819     gv_info.devname = info->devname;
820    
821 niro 816 snprintf(gv_info.devpath, sizeof(gv_info.devpath), "%s/%s", mount_point, info->devname);
822     expand_expression(source, STRING_LENGTH, entry->u.copy.source,
823 niro 532 get_variable, &gv_info, gv_info.devname,
824     regexpr, numexpr);
825    
826 niro 816 expand_expression(destination, STRING_LENGTH, entry->u.copy.destination,
827 niro 532 get_variable, &gv_info, gv_info.devname,
828     regexpr, numexpr);
829    
830 niro 816 if (!make_dir_tree(destination) || lstat(source, &source_stat) != 0)
831 niro 532 return;
832 niro 816 lstat(destination, &dest_stat);
833 niro 532 new_mode = source_stat.st_mode & ~S_ISVTX;
834     if (info->type == DEVFSD_NOTIFY_CREATE)
835     new_mode |= S_ISVTX;
836 niro 816 else if ((info->type == DEVFSD_NOTIFY_CHANGE) &&(dest_stat.st_mode & S_ISVTX))
837 niro 532 new_mode |= S_ISVTX;
838 niro 816 ret = copy_inode(destination, &dest_stat, new_mode, source, &source_stat);
839 niro 532 if (ENABLE_DEBUG && ret && (errno != EEXIST))
840 niro 816 error_logger(LOG_ERR, "copy_inode: %s to %s", source, destination);
841 niro 532 } /* End Function action_copy */
842    
843 niro 816 static void action_compat(const struct devfsd_notify_struct *info, unsigned int action)
844 niro 532 /* [SUMMARY] Process a compatibility request.
845     <info> The devfs change.
846     <action> The action to take.
847     [RETURNS] Nothing.
848     */
849     {
850     int ret;
851     const char *compat_name = NULL;
852     const char *dest_name = info->devname;
853 niro 816 const char *ptr;
854 niro 532 char compat_buf[STRING_LENGTH], dest_buf[STRING_LENGTH];
855     int mode, host, bus, target, lun;
856     unsigned int i;
857     char rewind_;
858     /* 1 to 5 "scsi/" , 6 to 9 "ide/host" */
859     static const char *const fmt[] = {
860     NULL ,
861     "sg/c%db%dt%du%d", /* scsi/generic */
862     "sd/c%db%dt%du%d", /* scsi/disc */
863     "sr/c%db%dt%du%d", /* scsi/cd */
864     "sd/c%db%dt%du%dp%d", /* scsi/part */
865     "st/c%db%dt%du%dm%d%c", /* scsi/mt */
866     "ide/hd/c%db%dt%du%d", /* ide/host/disc */
867     "ide/cd/c%db%dt%du%d", /* ide/host/cd */
868     "ide/hd/c%db%dt%du%dp%d", /* ide/host/part */
869     "ide/mt/c%db%dt%du%d%s", /* ide/host/mt */
870     NULL
871     };
872    
873     /* First construct compatibility name */
874 niro 816 switch (action) {
875 niro 532 case AC_MKOLDCOMPAT:
876     case AC_RMOLDCOMPAT:
877 niro 816 compat_name = get_old_name(info->devname, info->namelen, compat_buf, info->major, info->minor);
878 niro 532 break;
879     case AC_MKNEWCOMPAT:
880     case AC_RMNEWCOMPAT:
881 niro 816 ptr = bb_basename(info->devname);
882     i = scan_dev_name(info->devname, info->namelen, ptr);
883 niro 532
884     /* nothing found */
885 niro 816 if (i == 0 || i > 9)
886 niro 532 return;
887    
888 niro 816 sscanf(info->devname + ((i < 6) ? 5 : 4), "host%d/bus%d/target%d/lun%d/", &host, &bus, &target, &lun);
889     snprintf(dest_buf, sizeof(dest_buf), "../%s", info->devname + (( i > 5) ? 4 : 0));
890 niro 532 dest_name = dest_buf;
891     compat_name = compat_buf;
892    
893    
894     /* 1 == scsi/generic 2 == scsi/disc 3 == scsi/cd 6 == ide/host/disc 7 == ide/host/cd */
895 niro 816 if (i == 1 || i == 2 || i == 3 || i == 6 || i ==7)
896     sprintf(compat_buf, fmt[i], host, bus, target, lun);
897 niro 532
898     /* 4 == scsi/part 8 == ide/host/part */
899 niro 816 if (i == 4 || i == 8)
900     sprintf(compat_buf, fmt[i], host, bus, target, lun, atoi(ptr + 4));
901 niro 532
902     /* 5 == scsi/mt */
903 niro 816 if (i == 5) {
904 niro 532 rewind_ = info->devname[info->namelen - 1];
905     if (rewind_ != 'n')
906     rewind_ = '\0';
907     mode=0;
908 niro 816 if (ptr[2] == 'l' /*108*/ || ptr[2] == 'm'/*109*/)
909 niro 532 mode = ptr[2] - 107; /* 1 or 2 */
910 niro 816 if (ptr[2] == 'a')
911 niro 532 mode = 3;
912 niro 816 sprintf(compat_buf, fmt[i], host, bus, target, lun, mode, rewind_);
913 niro 532 }
914    
915     /* 9 == ide/host/mt */
916 niro 816 if (i == 9)
917     snprintf(compat_buf, sizeof(compat_buf), fmt[i], host, bus, target, lun, ptr + 2);
918 niro 532 /* esac */
919     } /* switch (action) */
920    
921 niro 816 if (compat_name == NULL)
922 niro 532 return;
923    
924     /* Now decide what to do with it */
925 niro 816 switch (action) {
926 niro 532 case AC_MKOLDCOMPAT:
927     case AC_MKNEWCOMPAT:
928 niro 816 mksymlink(dest_name, compat_name);
929 niro 532 break;
930     case AC_RMOLDCOMPAT:
931     case AC_RMNEWCOMPAT:
932 niro 816 ret = unlink(compat_name);
933 niro 532 if (ENABLE_DEBUG && ret)
934 niro 816 error_logger(LOG_ERR, "unlink: %s", compat_name);
935 niro 532 break;
936     /*esac*/
937     } /* switch (action) */
938     } /* End Function action_compat */
939    
940     static void restore(char *spath, struct stat source_stat, int rootlen)
941     {
942 niro 816 char *dpath;
943 niro 532 struct stat dest_stat;
944    
945     dest_stat.st_mode = 0;
946 niro 816 dpath = concat_path_file(mount_point, spath + rootlen);
947     lstat(dpath, &dest_stat);
948     free(dpath);
949     if (S_ISLNK(source_stat.st_mode) || (source_stat.st_mode & S_ISVTX))
950     copy_inode(dpath, &dest_stat,(source_stat.st_mode & ~S_ISVTX) , spath, &source_stat);
951 niro 532
952 niro 816 if (S_ISDIR(source_stat.st_mode))
953 niro 532 dir_operation(RESTORE, spath, rootlen,NULL);
954     }
955    
956    
957 niro 816 static int copy_inode(const char *destpath, const struct stat *dest_stat,
958 niro 532 mode_t new_mode,
959     const char *sourcepath, const struct stat *source_stat)
960     /* [SUMMARY] Copy an inode.
961     <destpath> The destination path. An existing inode may be deleted.
962     <dest_stat> The destination stat(2) information.
963     <new_mode> The desired new mode for the destination.
964     <sourcepath> The source path.
965     <source_stat> The source stat(2) information.
966     [RETURNS] TRUE on success, else FALSE.
967     */
968     {
969     int source_len, dest_len;
970     char source_link[STRING_LENGTH], dest_link[STRING_LENGTH];
971     int fd, val;
972     struct sockaddr_un un_addr;
973     char symlink_val[STRING_LENGTH];
974    
975 niro 816 if ((source_stat->st_mode & S_IFMT) ==(dest_stat->st_mode & S_IFMT)) {
976 niro 532 /* Same type */
977 niro 816 if (S_ISLNK(source_stat->st_mode)) {
978     source_len = readlink(sourcepath, source_link, STRING_LENGTH - 1);
979     if ((source_len < 0)
980     || (dest_len = readlink(destpath, dest_link, STRING_LENGTH - 1)) < 0
981     )
982 niro 532 return FALSE;
983     source_link[source_len] = '\0';
984     dest_link[dest_len] = '\0';
985 niro 816 if ((source_len != dest_len) || (strcmp(source_link, dest_link) != 0)) {
986     unlink(destpath);
987     symlink(source_link, destpath);
988 niro 532 }
989     return TRUE;
990     } /* Else not a symlink */
991 niro 816 chmod(destpath, new_mode & ~S_IFMT);
992     chown(destpath, source_stat->st_uid, source_stat->st_gid);
993 niro 532 return TRUE;
994     }
995     /* Different types: unlink and create */
996 niro 816 unlink(destpath);
997     switch (source_stat->st_mode & S_IFMT) {
998 niro 532 case S_IFSOCK:
999 niro 816 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1000     if (fd < 0)
1001 niro 532 break;
1002     un_addr.sun_family = AF_UNIX;
1003 niro 816 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s", destpath);
1004     val = bind(fd,(struct sockaddr *) &un_addr,(int) sizeof un_addr);
1005     close(fd);
1006     if (val != 0 || chmod(destpath, new_mode & ~S_IFMT) != 0)
1007 niro 532 break;
1008     goto do_chown;
1009     case S_IFLNK:
1010 niro 816 val = readlink(sourcepath, symlink_val, STRING_LENGTH - 1);
1011     if (val < 0)
1012 niro 532 break;
1013     symlink_val[val] = '\0';
1014 niro 816 if (symlink(symlink_val, destpath) == 0)
1015 niro 532 return TRUE;
1016     break;
1017     case S_IFREG:
1018 niro 816 fd = open(destpath, O_RDONLY | O_CREAT, new_mode & ~S_IFMT);
1019     if (fd < 0)
1020 niro 532 break;
1021 niro 816 close(fd);
1022     if (chmod(destpath, new_mode & ~S_IFMT) != 0)
1023 niro 532 break;
1024     goto do_chown;
1025     case S_IFBLK:
1026     case S_IFCHR:
1027     case S_IFIFO:
1028 niro 816 if (mknod(destpath, new_mode, source_stat->st_rdev) != 0)
1029 niro 532 break;
1030     goto do_chown;
1031     case S_IFDIR:
1032 niro 816 if (mkdir(destpath, new_mode & ~S_IFMT) != 0)
1033 niro 532 break;
1034     do_chown:
1035 niro 816 if (chown(destpath, source_stat->st_uid, source_stat->st_gid) == 0)
1036 niro 532 return TRUE;
1037     /*break;*/
1038     }
1039     return FALSE;
1040     } /* End Function copy_inode */
1041    
1042 niro 816 static void free_config(void)
1043 niro 532 /* [SUMMARY] Free the configuration information.
1044     [RETURNS] Nothing.
1045     */
1046     {
1047     struct config_entry_struct *c_entry;
1048     void *next;
1049    
1050 niro 816 for (c_entry = first_config; c_entry != NULL; c_entry = next) {
1051 niro 532 unsigned int count;
1052    
1053     next = c_entry->next;
1054 niro 816 regfree(&c_entry->preg);
1055     if (c_entry->action.what == AC_EXECUTE) {
1056     for (count = 0; count < MAX_ARGS; ++count) {
1057 niro 532 if (c_entry->u.execute.argv[count] == NULL)
1058     break;
1059 niro 816 free(c_entry->u.execute.argv[count]);
1060 niro 532 }
1061     }
1062 niro 816 free(c_entry);
1063 niro 532 }
1064     first_config = NULL;
1065     last_config = NULL;
1066     } /* End Function free_config */
1067    
1068 niro 816 static int get_uid_gid(int flag, const char *string)
1069 niro 532 /* [SUMMARY] Convert a string to a UID or GID value.
1070     <flag> "UID" or "GID".
1071     <string> The string.
1072     [RETURNS] The UID or GID value.
1073     */
1074     {
1075     struct passwd *pw_ent;
1076     struct group *grp_ent;
1077 niro 816 static const char *msg;
1078 niro 532
1079     if (ENABLE_DEVFSD_VERBOSE)
1080 niro 816 msg = "user";
1081 niro 532
1082 niro 816 if (isdigit(string[0]) ||((string[0] == '-') && isdigit(string[1])))
1083 niro 532 return atoi(string);
1084    
1085 niro 816 if (flag == UID && (pw_ent = getpwnam(string)) != NULL)
1086 niro 532 return pw_ent->pw_uid;
1087    
1088 niro 816 if (flag == GID && (grp_ent = getgrnam(string)) != NULL)
1089 niro 532 return grp_ent->gr_gid;
1090 niro 816 else if (ENABLE_DEVFSD_VERBOSE)
1091     msg = "group";
1092 niro 532
1093 niro 816 if (ENABLE_DEVFSD_VERBOSE)
1094     msg_logger(LOG_ERR, "unknown %s: %s, defaulting to %cid=0", msg, string, msg[0]);
1095 niro 532 return 0;
1096     }/* End Function get_uid_gid */
1097    
1098 niro 816 static mode_t get_mode(const char *string)
1099 niro 532 /* [SUMMARY] Convert a string to a mode value.
1100     <string> The string.
1101     [RETURNS] The mode value.
1102     */
1103     {
1104     mode_t mode;
1105     int i;
1106    
1107 niro 816 if (isdigit(string[0]))
1108 niro 532 return strtoul(string, NULL, 8);
1109 niro 816 if (strlen(string) != 9)
1110 niro 532 msg_logger_and_die(LOG_ERR, "bad mode: %s", string);
1111    
1112     mode = 0;
1113 niro 816 i = S_IRUSR;
1114     while (i > 0) {
1115     if (string[0] == 'r' || string[0] == 'w' || string[0] == 'x')
1116     mode += i;
1117     i = i / 2;
1118 niro 532 string++;
1119     }
1120     return mode;
1121     } /* End Function get_mode */
1122    
1123 niro 816 static void signal_handler(int sig)
1124 niro 532 {
1125     caught_signal = TRUE;
1126     if (sig == SIGHUP)
1127     caught_sighup = TRUE;
1128    
1129 niro 816 info_logger(LOG_INFO, "Caught signal %d", sig);
1130 niro 532 } /* End Function signal_handler */
1131    
1132 niro 816 static const char *get_variable(const char *variable, void *info)
1133 niro 532 {
1134 niro 816 static char sbuf[sizeof(int)*3 + 2]; /* sign and NUL */
1135     static char *hostname;
1136    
1137 niro 532 struct get_variable_info *gv_info = info;
1138 niro 816 const char *field_names[] = {
1139     "hostname", "mntpt", "devpath", "devname",
1140     "uid", "gid", "mode", hostname, mount_point,
1141     gv_info->devpath, gv_info->devname, NULL
1142     };
1143 niro 532 int i;
1144    
1145 niro 816 if (!hostname)
1146     hostname = safe_gethostname();
1147 niro 532 /* index_in_str_array returns i>=0 */
1148 niro 816 i = index_in_str_array(field_names, variable);
1149 niro 532
1150 niro 816 if (i > 6 || i < 0 || (i > 1 && gv_info == NULL))
1151     return NULL;
1152     if (i >= 0 && i <= 3)
1153     return field_names[i + 7];
1154 niro 532
1155 niro 816 if (i == 4)
1156     sprintf(sbuf, "%u", gv_info->info->uid);
1157     else if (i == 5)
1158     sprintf(sbuf, "%u", gv_info->info->gid);
1159     else if (i == 6)
1160     sprintf(sbuf, "%o", gv_info->info->mode);
1161 niro 532 return sbuf;
1162     } /* End Function get_variable */
1163    
1164     static void service(struct stat statbuf, char *path)
1165     {
1166     struct devfsd_notify_struct info;
1167    
1168 niro 816 memset(&info, 0, sizeof info);
1169 niro 532 info.type = DEVFSD_NOTIFY_REGISTERED;
1170     info.mode = statbuf.st_mode;
1171 niro 816 info.major = major(statbuf.st_rdev);
1172     info.minor = minor(statbuf.st_rdev);
1173 niro 532 info.uid = statbuf.st_uid;
1174     info.gid = statbuf.st_gid;
1175 niro 816 snprintf(info.devname, sizeof(info.devname), "%s", path + strlen(mount_point) + 1);
1176     info.namelen = strlen(info.devname);
1177     service_name(&info);
1178     if (S_ISDIR(statbuf.st_mode))
1179     dir_operation(SERVICE, path, 0, NULL);
1180 niro 532 }
1181    
1182     static void dir_operation(int type, const char * dir_name, int var, unsigned long *event_mask)
1183     /* [SUMMARY] Scan a directory tree and generate register events on leaf nodes.
1184     <flag> To choose which function to perform
1185     <dp> The directory pointer. This is closed upon completion.
1186     <dir_name> The name of the directory.
1187     <rootlen> string length parameter.
1188     [RETURNS] Nothing.
1189     */
1190     {
1191     struct stat statbuf;
1192     DIR *dp;
1193     struct dirent *de;
1194 niro 816 char *path;
1195 niro 532
1196 niro 816 dp = warn_opendir(dir_name);
1197     if (dp == NULL)
1198 niro 532 return;
1199    
1200 niro 816 while ((de = readdir(dp)) != NULL) {
1201 niro 532
1202 niro 816 if (de->d_name && DOT_OR_DOTDOT(de->d_name))
1203 niro 532 continue;
1204 niro 816 path = concat_path_file(dir_name, de->d_name);
1205     if (lstat(path, &statbuf) == 0) {
1206     switch (type) {
1207     case SERVICE:
1208     service(statbuf, path);
1209     break;
1210     case RESTORE:
1211     restore(path, statbuf, var);
1212     break;
1213     case READ_CONFIG:
1214     read_config_file(path, var, event_mask);
1215     break;
1216     }
1217 niro 532 }
1218 niro 816 free(path);
1219 niro 532 }
1220 niro 816 closedir(dp);
1221 niro 532 } /* End Function do_scan_and_service */
1222    
1223 niro 816 static int mksymlink(const char *oldpath, const char *newpath)
1224 niro 532 /* [SUMMARY] Create a symlink, creating intervening directories as required.
1225     <oldpath> The string contained in the symlink.
1226     <newpath> The name of the new symlink.
1227     [RETURNS] 0 on success, else -1.
1228     */
1229     {
1230 niro 816 if (!make_dir_tree(newpath))
1231 niro 532 return -1;
1232    
1233 niro 816 if (symlink(oldpath, newpath) != 0) {
1234     if (errno != EEXIST)
1235 niro 532 return -1;
1236     }
1237     return 0;
1238     } /* End Function mksymlink */
1239    
1240    
1241 niro 816 static int make_dir_tree(const char *path)
1242 niro 532 /* [SUMMARY] Creating intervening directories for a path as required.
1243 niro 816 <path> The full pathname(including the leaf node).
1244 niro 532 [RETURNS] TRUE on success, else FALSE.
1245     */
1246     {
1247 niro 816 if (bb_make_directory(dirname((char *)path), -1, FILEUTILS_RECUR) == -1)
1248 niro 532 return FALSE;
1249     return TRUE;
1250     } /* End Function make_dir_tree */
1251    
1252     static int expand_expression(char *output, unsigned int outsize,
1253     const char *input,
1254     const char *(*get_variable_func)(const char *variable, void *info),
1255     void *info,
1256     const char *devname,
1257     const regmatch_t *ex, unsigned int numexp)
1258     /* [SUMMARY] Expand environment variables and regular subexpressions in string.
1259     <output> The output expanded expression is written here.
1260     <length> The size of the output buffer.
1261     <input> The input expression. This may equal <<output>>.
1262     <get_variable> A function which will be used to get variable values. If
1263     this returns NULL, the environment is searched instead. If this is NULL,
1264     only the environment is searched.
1265     <info> An arbitrary pointer passed to <<get_variable>>.
1266     <devname> Device name; specifically, this is the string that contains all
1267     of the regular subexpressions.
1268     <ex> Array of start / end offsets into info->devname for each subexpression
1269     <numexp> Number of regular subexpressions found in <<devname>>.
1270     [RETURNS] TRUE on success, else FALSE.
1271     */
1272     {
1273     char temp[STRING_LENGTH];
1274    
1275 niro 816 if (!st_expr_expand(temp, STRING_LENGTH, input, get_variable_func, info))
1276 niro 532 return FALSE;
1277 niro 816 expand_regexp(output, outsize, temp, devname, ex, numexp);
1278 niro 532 return TRUE;
1279     } /* End Function expand_expression */
1280    
1281 niro 816 static void expand_regexp(char *output, size_t outsize, const char *input,
1282 niro 532 const char *devname,
1283 niro 816 const regmatch_t *ex, unsigned int numex)
1284 niro 532 /* [SUMMARY] Expand all occurrences of the regular subexpressions \0 to \9.
1285     <output> The output expanded expression is written here.
1286     <outsize> The size of the output buffer.
1287     <input> The input expression. This may NOT equal <<output>>, because
1288     supporting that would require yet another string-copy. However, it's not
1289     hard to write a simple wrapper function to add this functionality for those
1290     few cases that need it.
1291     <devname> Device name; specifically, this is the string that contains all
1292     of the regular subexpressions.
1293     <ex> An array of start and end offsets into <<devname>>, one for each
1294     subexpression
1295     <numex> Number of subexpressions in the offset-array <<ex>>.
1296     [RETURNS] Nothing.
1297     */
1298     {
1299     const char last_exp = '0' - 1 + numex;
1300     int c = -1;
1301    
1302     /* Guarantee NULL termination by writing an explicit '\0' character into
1303     the very last byte */
1304     if (outsize)
1305     output[--outsize] = '\0';
1306     /* Copy the input string into the output buffer, replacing '\\' with '\'
1307     and '\0' .. '\9' with subexpressions 0 .. 9, if they exist. Other \x
1308     codes are deleted */
1309 niro 816 while ((c != '\0') && (outsize != 0)) {
1310 niro 532 c = *input;
1311     ++input;
1312 niro 816 if (c == '\\') {
1313 niro 532 c = *input;
1314     ++input;
1315 niro 816 if (c != '\\') {
1316     if ((c >= '0') && (c <= last_exp)) {
1317 niro 532 const regmatch_t *subexp = ex + (c - '0');
1318     unsigned int sublen = subexp->rm_eo - subexp->rm_so;
1319    
1320     /* Range checking */
1321     if (sublen > outsize)
1322     sublen = outsize;
1323 niro 816 strncpy(output, devname + subexp->rm_so, sublen);
1324 niro 532 output += sublen;
1325     outsize -= sublen;
1326     }
1327     continue;
1328     }
1329     }
1330     *output = c;
1331     ++output;
1332     --outsize;
1333     } /* while */
1334     } /* End Function expand_regexp */
1335    
1336    
1337     /* from compat_name.c */
1338    
1339     struct translate_struct
1340     {
1341 niro 816 const char *match; /* The string to match to(up to length) */
1342     const char *format; /* Format of output, "%s" takes data past match string,
1343     NULL is effectively "%s"(just more efficient) */
1344 niro 532 };
1345    
1346     static struct translate_struct translate_table[] =
1347     {
1348     {"sound/", NULL},
1349     {"printers/", "lp%s"},
1350     {"v4l/", NULL},
1351     {"parports/", "parport%s"},
1352     {"fb/", "fb%s"},
1353     {"netlink/", NULL},
1354     {"loop/", "loop%s"},
1355     {"floppy/", "fd%s"},
1356     {"rd/", "ram%s"},
1357     {"md/", "md%s"}, /* Meta-devices */
1358     {"vc/", "tty%s"},
1359     {"misc/", NULL},
1360     {"isdn/", NULL},
1361     {"pg/", "pg%s"}, /* Parallel port generic ATAPI interface*/
1362     {"i2c/", "i2c-%s"},
1363     {"staliomem/", "staliomem%s"}, /* Stallion serial driver control */
1364     {"tts/E", "ttyE%s"}, /* Stallion serial driver */
1365     {"cua/E", "cue%s"}, /* Stallion serial driver callout */
1366     {"tts/R", "ttyR%s"}, /* Rocketport serial driver */
1367     {"cua/R", "cur%s"}, /* Rocketport serial driver callout */
1368     {"ip2/", "ip2%s"}, /* Computone serial driver control */
1369     {"tts/F", "ttyF%s"}, /* Computone serial driver */
1370     {"cua/F", "cuf%s"}, /* Computone serial driver callout */
1371     {"tts/C", "ttyC%s"}, /* Cyclades serial driver */
1372     {"cua/C", "cub%s"}, /* Cyclades serial driver callout */
1373     {"tts/", "ttyS%s"}, /* Generic serial: must be after others */
1374     {"cua/", "cua%s"}, /* Generic serial: must be after others */
1375     {"input/js", "js%s"}, /* Joystick driver */
1376     {NULL, NULL}
1377     };
1378    
1379 niro 816 const char *get_old_name(const char *devname, unsigned int namelen,
1380 niro 532 char *buffer, unsigned int major, unsigned int minor)
1381     /* [SUMMARY] Translate a kernel-supplied name into an old name.
1382     <devname> The device name provided by the kernel.
1383     <namelen> The length of the name.
1384     <buffer> A buffer that may be used. This should be at least 128 bytes long.
1385     <major> The major number for the device.
1386     <minor> The minor number for the device.
1387     [RETURNS] A pointer to the old name if known, else NULL.
1388     */
1389     {
1390     const char *compat_name = NULL;
1391 niro 816 const char *ptr;
1392 niro 532 struct translate_struct *trans;
1393     unsigned int i;
1394     char mode;
1395     int indexx;
1396     const char *pty1;
1397     const char *pty2;
1398     size_t len;
1399     /* 1 to 5 "scsi/" , 6 to 9 "ide/host", 10 sbp/, 11 vcc/, 12 pty/ */
1400     static const char *const fmt[] = {
1401     NULL ,
1402     "sg%u", /* scsi/generic */
1403     NULL, /* scsi/disc */
1404     "sr%u", /* scsi/cd */
1405     NULL, /* scsi/part */
1406     "nst%u%c", /* scsi/mt */
1407     "hd%c" , /* ide/host/disc */
1408     "hd%c" , /* ide/host/cd */
1409     "hd%c%s", /* ide/host/part */
1410     "%sht%d", /* ide/host/mt */
1411     "sbpcd%u", /* sbp/ */
1412     "vcs%s", /* vcc/ */
1413     "%cty%c%c", /* pty/ */
1414     NULL
1415     };
1416    
1417 niro 816 for (trans = translate_table; trans->match != NULL; ++trans) {
1418     len = strlen(trans->match);
1419 niro 532
1420 niro 816 if (strncmp(devname, trans->match, len) == 0) {
1421 niro 532 if (trans->format == NULL)
1422     return devname + len;
1423 niro 816 sprintf(buffer, trans->format, devname + len);
1424 niro 532 return buffer;
1425     }
1426     }
1427    
1428 niro 816 ptr = bb_basename(devname);
1429 niro 532 i = scan_dev_name(devname, namelen, ptr);
1430    
1431 niro 816 if (i > 0 && i < 13)
1432 niro 532 compat_name = buffer;
1433     else
1434     return NULL;
1435    
1436     /* 1 == scsi/generic, 3 == scsi/cd, 10 == sbp/ */
1437 niro 816 if (i == 1 || i == 3 || i == 10)
1438     sprintf(buffer, fmt[i], minor);
1439 niro 532
1440     /* 2 ==scsi/disc, 4 == scsi/part */
1441 niro 816 if (i == 2 || i == 4)
1442     compat_name = write_old_sd_name(buffer, major, minor,((i == 2) ? "" : (ptr + 4)));
1443 niro 532
1444     /* 5 == scsi/mt */
1445 niro 816 if (i == 5) {
1446 niro 532 mode = ptr[2];
1447     if (mode == 'n')
1448     mode = '\0';
1449 niro 816 sprintf(buffer, fmt[i], minor & 0x1f, mode);
1450 niro 532 if (devname[namelen - 1] != 'n')
1451     ++compat_name;
1452     }
1453     /* 6 == ide/host/disc, 7 == ide/host/cd, 8 == ide/host/part */
1454 niro 816 if (i == 6 || i == 7 || i == 8)
1455 niro 532 /* last arg should be ignored for i == 6 or i== 7 */
1456 niro 816 sprintf(buffer, fmt[i] , get_old_ide_name(major, minor), ptr + 4);
1457 niro 532
1458     /* 9 == ide/host/mt */
1459 niro 816 if (i == 9)
1460     sprintf(buffer, fmt[i], ptr + 2, minor & 0x7f);
1461 niro 532
1462     /* 11 == vcc/ */
1463 niro 816 if (i == 11) {
1464     sprintf(buffer, fmt[i], devname + 4);
1465 niro 532 if (buffer[3] == '0')
1466     buffer[3] = '\0';
1467     }
1468     /* 12 == pty/ */
1469 niro 816 if (i == 12) {
1470 niro 532 pty1 = "pqrstuvwxyzabcde";
1471     pty2 = "0123456789abcdef";
1472 niro 816 indexx = atoi(devname + 5);
1473     sprintf(buffer, fmt[i], (devname[4] == 'm') ? 'p' : 't', pty1[indexx >> 4], pty2[indexx & 0x0f]);
1474 niro 532 }
1475     return compat_name;
1476     } /* End Function get_old_name */
1477    
1478 niro 816 static char get_old_ide_name(unsigned int major, unsigned int minor)
1479 niro 532 /* [SUMMARY] Get the old IDE name for a device.
1480     <major> The major number for the device.
1481     <minor> The minor number for the device.
1482     [RETURNS] The drive letter.
1483     */
1484     {
1485 niro 816 char letter = 'y'; /* 121 */
1486     char c = 'a'; /* 97 */
1487     int i = IDE0_MAJOR;
1488 niro 532
1489     /* I hope it works like the previous code as it saves a few bytes. Tito ;P */
1490     do {
1491 niro 816 if (i == IDE0_MAJOR || i == IDE1_MAJOR || i == IDE2_MAJOR
1492     || i == IDE3_MAJOR || i == IDE4_MAJOR || i == IDE5_MAJOR
1493     || i == IDE6_MAJOR || i == IDE7_MAJOR || i == IDE8_MAJOR
1494     || i == IDE9_MAJOR
1495     ) {
1496     if ((unsigned int)i == major) {
1497     letter = c;
1498 niro 532 break;
1499     }
1500 niro 816 c += 2;
1501 niro 532 }
1502     i++;
1503 niro 816 } while (i <= IDE9_MAJOR);
1504 niro 532
1505     if (minor > 63)
1506     ++letter;
1507     return letter;
1508     } /* End Function get_old_ide_name */
1509    
1510 niro 816 static char *write_old_sd_name(char *buffer,
1511 niro 532 unsigned int major, unsigned int minor,
1512 niro 816 const char *part)
1513 niro 532 /* [SUMMARY] Write the old SCSI disc name to a buffer.
1514     <buffer> The buffer to write to.
1515     <major> The major number for the device.
1516     <minor> The minor number for the device.
1517     <part> The partition string. Must be "" for a whole-disc entry.
1518     [RETURNS] A pointer to the buffer on success, else NULL.
1519     */
1520     {
1521     unsigned int disc_index;
1522    
1523 niro 816 if (major == 8) {
1524     sprintf(buffer, "sd%c%s", 'a' + (minor >> 4), part);
1525 niro 532 return buffer;
1526     }
1527 niro 816 if ((major > 64) && (major < 72)) {
1528     disc_index = ((major - 64) << 4) +(minor >> 4);
1529 niro 532 if (disc_index < 26)
1530 niro 816 sprintf(buffer, "sd%c%s", 'a' + disc_index, part);
1531 niro 532 else
1532 niro 816 sprintf(buffer, "sd%c%c%s", 'a' +(disc_index / 26) - 1, 'a' + disc_index % 26, part);
1533 niro 532 return buffer;
1534     }
1535     return NULL;
1536     } /* End Function write_old_sd_name */
1537    
1538    
1539     /* expression.c */
1540    
1541     /*EXPERIMENTAL_FUNCTION*/
1542    
1543 niro 816 int st_expr_expand(char *output, unsigned int length, const char *input,
1544     const char *(*get_variable_func)(const char *variable,
1545 niro 532 void *info),
1546     void *info)
1547     /* [SUMMARY] Expand an expression using Borne Shell-like unquoted rules.
1548     <output> The output expanded expression is written here.
1549     <length> The size of the output buffer.
1550     <input> The input expression. This may equal <<output>>.
1551     <get_variable> A function which will be used to get variable values. If
1552     this returns NULL, the environment is searched instead. If this is NULL,
1553     only the environment is searched.
1554     <info> An arbitrary pointer passed to <<get_variable>>.
1555     [RETURNS] TRUE on success, else FALSE.
1556     */
1557     {
1558     char ch;
1559     unsigned int len;
1560     unsigned int out_pos = 0;
1561     const char *env;
1562     const char *ptr;
1563     struct passwd *pwent;
1564     char buffer[BUFFER_SIZE], tmp[STRING_LENGTH];
1565    
1566     if (length > BUFFER_SIZE)
1567     length = BUFFER_SIZE;
1568 niro 816 for (; TRUE; ++input) {
1569     switch (ch = *input) {
1570 niro 532 case '$':
1571     /* Variable expansion */
1572 niro 816 input = expand_variable(buffer, length, &out_pos, ++input, get_variable_func, info);
1573 niro 532 if (input == NULL)
1574     return FALSE;
1575     break;
1576     case '~':
1577     /* Home directory expansion */
1578     ch = input[1];
1579 niro 816 if (isspace(ch) ||(ch == '/') ||(ch == '\0')) {
1580 niro 532 /* User's own home directory: leave separator for next time */
1581 niro 816 env = getenv("HOME");
1582     if (env == NULL) {
1583     info_logger(LOG_INFO, bb_msg_variable_not_found, "HOME");
1584 niro 532 return FALSE;
1585     }
1586 niro 816 len = strlen(env);
1587 niro 532 if (len + out_pos >= length)
1588     goto st_expr_expand_out;
1589 niro 816 memcpy(buffer + out_pos, env, len + 1);
1590 niro 532 out_pos += len;
1591     continue;
1592     }
1593     /* Someone else's home directory */
1594 niro 816 for (ptr = ++input; !isspace(ch) && (ch != '/') && (ch != '\0'); ch = *++ptr)
1595     /* VOID */;
1596 niro 532 len = ptr - input;
1597     if (len >= sizeof tmp)
1598     goto st_expr_expand_out;
1599 niro 816 safe_memcpy(tmp, input, len);
1600 niro 532 input = ptr - 1;
1601 niro 816 pwent = getpwnam(tmp);
1602     if (pwent == NULL) {
1603     info_logger(LOG_INFO, "no pwent for: %s", tmp);
1604 niro 532 return FALSE;
1605     }
1606 niro 816 len = strlen(pwent->pw_dir);
1607 niro 532 if (len + out_pos >= length)
1608     goto st_expr_expand_out;
1609 niro 816 memcpy(buffer + out_pos, pwent->pw_dir, len + 1);
1610 niro 532 out_pos += len;
1611     break;
1612     case '\0':
1613     /* Falltrough */
1614     default:
1615     if (out_pos >= length)
1616     goto st_expr_expand_out;
1617     buffer[out_pos++] = ch;
1618 niro 816 if (ch == '\0') {
1619     memcpy(output, buffer, out_pos);
1620 niro 532 return TRUE;
1621     }
1622     break;
1623     /* esac */
1624     }
1625     }
1626     return FALSE;
1627     st_expr_expand_out:
1628 niro 816 info_logger(LOG_INFO, bb_msg_small_buffer);
1629 niro 532 return FALSE;
1630     } /* End Function st_expr_expand */
1631    
1632    
1633     /* Private functions follow */
1634    
1635 niro 816 static const char *expand_variable(char *buffer, unsigned int length,
1636 niro 532 unsigned int *out_pos, const char *input,
1637 niro 816 const char *(*func)(const char *variable,
1638 niro 532 void *info),
1639     void *info)
1640     /* [SUMMARY] Expand a variable.
1641     <buffer> The buffer to write to.
1642     <length> The length of the output buffer.
1643     <out_pos> The current output position. This is updated.
1644     <input> A pointer to the input character pointer.
1645     <func> A function which will be used to get variable values. If this
1646     returns NULL, the environment is searched instead. If this is NULL, only
1647     the environment is searched.
1648     <info> An arbitrary pointer passed to <<func>>.
1649     <errfp> Diagnostic messages are written here.
1650     [RETURNS] A pointer to the end of this subexpression on success, else NULL.
1651     */
1652     {
1653     char ch;
1654     int len;
1655     unsigned int open_braces;
1656     const char *env, *ptr;
1657     char tmp[STRING_LENGTH];
1658    
1659     ch = input[0];
1660 niro 816 if (ch == '$') {
1661 niro 532 /* Special case for "$$": PID */
1662 niro 816 sprintf(tmp, "%d",(int) getpid());
1663     len = strlen(tmp);
1664 niro 532 if (len + *out_pos >= length)
1665     goto expand_variable_out;
1666    
1667 niro 816 memcpy(buffer + *out_pos, tmp, len + 1);
1668 niro 532 out_pos += len;
1669     return input;
1670     }
1671     /* Ordinary variable expansion, possibly in braces */
1672 niro 816 if (ch != '{') {
1673 niro 532 /* Simple variable expansion */
1674 niro 816 for (ptr = input; isalnum(ch) || (ch == '_') || (ch == ':'); ch = *++ptr)
1675     /* VOID */;
1676 niro 532 len = ptr - input;
1677     if ((size_t)len >= sizeof tmp)
1678     goto expand_variable_out;
1679    
1680 niro 816 safe_memcpy(tmp, input, len);
1681 niro 532 input = ptr - 1;
1682 niro 816 env = get_variable_v2(tmp, func, info);
1683     if (env == NULL) {
1684     info_logger(LOG_INFO, bb_msg_variable_not_found, tmp);
1685 niro 532 return NULL;
1686     }
1687 niro 816 len = strlen(env);
1688 niro 532 if (len + *out_pos >= length)
1689     goto expand_variable_out;
1690    
1691 niro 816 memcpy(buffer + *out_pos, env, len + 1);
1692 niro 532 *out_pos += len;
1693     return input;
1694     }
1695     /* Variable in braces: check for ':' tricks */
1696     ch = *++input;
1697 niro 816 for (ptr = input; isalnum(ch) || (ch == '_'); ch = *++ptr)
1698 niro 532 /* VOID */;
1699 niro 816 if (ch == '}') {
1700 niro 532 /* Must be simple variable expansion with "${var}" */
1701     len = ptr - input;
1702     if ((size_t)len >= sizeof tmp)
1703     goto expand_variable_out;
1704    
1705 niro 816 safe_memcpy(tmp, input, len);
1706     ptr = expand_variable(buffer, length, out_pos, tmp, func, info);
1707 niro 532 if (ptr == NULL)
1708     return NULL;
1709     return input + len;
1710     }
1711 niro 816 if (ch != ':' || ptr[1] != '-') {
1712     info_logger(LOG_INFO, "illegal char in var name");
1713 niro 532 return NULL;
1714     }
1715     /* It's that handy "${var:-word}" expression. Check if var is defined */
1716     len = ptr - input;
1717     if ((size_t)len >= sizeof tmp)
1718     goto expand_variable_out;
1719    
1720 niro 816 safe_memcpy(tmp, input, len);
1721 niro 532 /* Move input pointer to ':' */
1722     input = ptr;
1723     /* First skip to closing brace, taking note of nested expressions */
1724     ptr += 2;
1725     ch = ptr[0];
1726 niro 816 for (open_braces = 1; open_braces > 0; ch = *++ptr) {
1727     switch (ch) {
1728 niro 532 case '{':
1729     ++open_braces;
1730     break;
1731     case '}':
1732     --open_braces;
1733     break;
1734     case '\0':
1735 niro 816 info_logger(LOG_INFO, "\"}\" not found in: %s", input);
1736 niro 532 return NULL;
1737     default:
1738     break;
1739     }
1740     }
1741     --ptr;
1742     /* At this point ptr should point to closing brace of "${var:-word}" */
1743 niro 816 env = get_variable_v2(tmp, func, info);
1744     if (env != NULL) {
1745 niro 532 /* Found environment variable, so skip the input to the closing brace
1746     and return the variable */
1747     input = ptr;
1748 niro 816 len = strlen(env);
1749 niro 532 if (len + *out_pos >= length)
1750     goto expand_variable_out;
1751    
1752 niro 816 memcpy(buffer + *out_pos, env, len + 1);
1753 niro 532 *out_pos += len;
1754     return input;
1755     }
1756     /* Environment variable was not found, so process word. Advance input
1757     pointer to start of word in "${var:-word}" */
1758     input += 2;
1759     len = ptr - input;
1760     if ((size_t)len >= sizeof tmp)
1761     goto expand_variable_out;
1762    
1763 niro 816 safe_memcpy(tmp, input, len);
1764 niro 532 input = ptr;
1765 niro 816 if (!st_expr_expand(tmp, STRING_LENGTH, tmp, func, info))
1766 niro 532 return NULL;
1767 niro 816 len = strlen(tmp);
1768 niro 532 if (len + *out_pos >= length)
1769     goto expand_variable_out;
1770    
1771 niro 816 memcpy(buffer + *out_pos, tmp, len + 1);
1772 niro 532 *out_pos += len;
1773     return input;
1774     expand_variable_out:
1775 niro 816 info_logger(LOG_INFO, bb_msg_small_buffer);
1776 niro 532 return NULL;
1777     } /* End Function expand_variable */
1778    
1779    
1780 niro 816 static const char *get_variable_v2(const char *variable,
1781     const char *(*func)(const char *variable, void *info),
1782 niro 532 void *info)
1783     /* [SUMMARY] Get a variable from the environment or .
1784     <variable> The variable name.
1785     <func> A function which will be used to get the variable. If this returns
1786     NULL, the environment is searched instead. If this is NULL, only the
1787     environment is searched.
1788     [RETURNS] The value of the variable on success, else NULL.
1789     */
1790     {
1791     const char *value;
1792    
1793 niro 816 if (func != NULL) {
1794     value = (*func)(variable, info);
1795 niro 532 if (value != NULL)
1796     return value;
1797     }
1798     return getenv(variable);
1799     } /* End Function get_variable */
1800    
1801     /* END OF CODE */