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