Patch from Tito, size optimisation, cleanup noise when in debugging
authorGlenn L McGrath <bug1@ihug.co.nz>
Sun, 30 Nov 2003 23:46:06 +0000 (23:46 -0000)
committerGlenn L McGrath <bug1@ihug.co.nz>
Sun, 30 Nov 2003 23:46:06 +0000 (23:46 -0000)
mode, adds support for MODLOAD keyword in devfsd.conf, provides a
cleaned up version of example/devfsd.conf

examples/devfsd.conf
miscutils/Config.in
miscutils/devfsd.c

index ea73343749bb885260ab2711658f4e9a98ab7a35..e90e7102b1d8d7c13f7625db526490e33d15748e 100644 (file)
@@ -25,11 +25,10 @@ UNREGISTER  .*              RMNEWCOMPAT
 
 # Enable module autoloading. You may comment this out if you don't use
 # autoloading
-# Not supported by busybox
-#LOOKUP                .*              MODLOAD
-# Maybe one of these works for busybox
-#LOOKUP                .*              EXECUTE /sbin/modprobe -k -v -C /etc/modules.devfs *
-#REGISTER      .*              EXECUTE /sbin/modprobe -k -v -C /etc/modules.devfs *
+# Supported by busybox when CONFIG_DEVFSD_MODLOAD is set.
+# This actually doesn't work with busybox  modutils but needs
+# the real modutils' modprobe
+LOOKUP         .*              MODLOAD
 
 # Uncomment the following if you want to set the group to "tty" for the
 # pseudo-tty devices. This is necessary so that mesg(1) can later be used to
@@ -68,7 +67,6 @@ RESTORE               /lib/dev-state
 REGISTER       ^cdroms/cdrom0$ EXECUTE /bin/ln -sf $devname cdrom
 UNREGISTER     ^cdroms/cdrom0$ EXECUTE /bin/rm -f cdrom
 
-
 #REGISTER      ^v4l/video0$    CFUNCTION GLOBAL mksymlink v4l/video0 video
 #UNREGISTER    ^v4l/video0$    CFUNCTION GLOBAL unlink video
 #REGISTER      ^radio0$        CFUNCTION GLOBAL mksymlink radio0 radio
@@ -80,18 +78,23 @@ REGISTER    ^radio0$                EXECUTE /bin/ln -sf  radio0 radio
 UNREGISTER     ^radio0$                EXECUTE /bin/rm -f radio
 
 # ALSA stuff
-# Not supported by busybox
 #LOOKUP                snd             MODLOAD ACTION snd
-# Maybe this works for busybox
-#LOOKUP                        snd             EXECUTE /sbin/modprobe -k -v -C /etc/modules.devfs snd
 
 # Uncomment this to let PAM manage devfs
+# Not supported by busybox
 #REGISTER      .*              CFUNCTION /lib/security/pam_console_apply_devfsd.so pam_console_apply_single $devpath
 
 # Uncomment this to manage USB mouse
+# Not supported by busybox
 #REGISTER      ^input/mouse0$  CFUNCTION GLOBAL mksymlink $devname usbmouse
 #UNREGISTER    ^input/mouse0$  CFUNCTION GLOBAL unlink usbmouse
 # Busybox
+#REGISTER      ^input/mouse0$  EXECUTE /bin/ln -sf $devname usbmouse
+#UNREGISTER    ^input/mouse0$  EXECUTE /bin/rm -f usbmouse
+# Not supported by busybox
+#REGISTER      ^input/mice$    CFUNCTION GLOBAL mksymlink $devname usbmouse
+#UNREGISTER    ^input/mice$    CFUNCTION GLOBAL unlink usbmouse
+# Busybox
 REGISTER       ^input/mice$    EXECUTE /bin/ln -sf $devname usbmouse
 UNREGISTER     ^input/mice$    EXECUTE /bin/rm -f usbmouse
 
@@ -107,75 +110,24 @@ LOOKUP            ^(ide/hd/c[0-9]+b[0-9]+t[0-9]+u[0-9]+)p[0-9]+$  EXECUTE /bin/dd if=$mntpn
 LOOKUP         ^(hd[a-z])[0-9]+$       EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
 # IDE-SCSI NEWCOMPAT  /dev/sd/* names
 #LOOKUP                ^(sd/c[0-9]+b[0-9]+t[0-9]+u[0-9]+)p[0-9]+$      EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
-# SCSI OLDCOMPAT  /dev/scd? names
+#SCSI OLDCOMPAT  /dev/scd? names
 LOOKUP         ^(scd+)[0-9]+$  EXECUTE /bin/dd if=$mntpnt/\1 of=/dev/null count=1
 
 
 REGISTER ^dvb/card[0-9]+/[^/]+$ PERMISSIONS root.video 0660
-# Busybox
+# Not supported by busybox
 #REGISTER      ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$     CFUNCTION GLOBAL mksymlink /dev/$devname ost/\2\1
 #UNREGISTER    ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$     CFUNCTION GLOBAL unlink ost/\2\1
+# Busybox
 REGISTER       ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$     EXECUTE /bin/ln -sf /dev/$devname ost/\2\1
 UNREGISTER     ^dvb/card([0-9]+)/([^/0-9]*)[0-9]+$     EXECUTE /bin/rm -f ost/\2\1
 
 # Include package-generated files from /etc/devfs/conf.d
 # Supported by busybox
-#OPTIONAL_INCLUDE   /etc/devfs/conf.d/dvd.conf
-#INCLUDE   /etc/devfs/conf.d/dvd.conf
-#OPTIONAL_INCLUDE   /etc/devfs/conf.d/
-#INCLUDE   /etc/devfs/conf.d/
-
-#/etc/devfs/conf.d/dvd.conf
-#REGISTER      ^ide/host0/bus1/target1/lun0/cd$        CFUNCTION GLOBAL mksymlink ide/host0/bus1/target1/lun0/cd dvd
-#UNREGISTER    ^ide/host0/bus1/target1/lun0/cd$        CFUNCTION GLOBAL unlink dvd
-REGISTER       ^ide/host0/bus1/target1/lun0/cd$        EXECUTE ln -sf ide/host0/bus1/target1/lun0/cd dvd
-UNREGISTER     ^ide/host0/bus1/target1/lun0/cd$        EXECUTE rm -f dvd
-
-#/etc/devfs/conf.d/dynamic.conf
-# dynamic desktop and co
-
-REGISTER       .*/part.*       EXECUTE /etc/dynamic/scripts/part.script add $devpath
-UNREGISTER     .*/part.*       EXECUTE /etc/dynamic/scripts/part.script del $devpath
-
-REGISTER       v4l/video.*     EXECUTE /etc/dynamic/scripts/webcam.script add $devpath
-UNREGISTER     v4l/video.*     EXECUTE /etc/dynamic/scripts/webcam.script del $devpath
-
-REGISTER       usb/scanner.*   EXECUTE /etc/dynamic/scripts/scanner.script add $devpath
-UNREGISTER     usb/scanner.*   EXECUTE /etc/dynamic/scripts/scanner.script del $devpath
-
-REGISTER       usb/rio500      EXECUTE /etc/dynamic/scripts/rio500.script add $devpath
-UNREGISTER     usb/rio500      EXECUTE /etc/dynamic/scripts/rio500.script del $devpath
-
-REGISTER       usb/tts/[13579] EXECUTE /etc/dynamic/scripts/visor.script add $devpath
-UNREGISTER     usb/tts/[13579] EXECUTE /etc/dynamic/scripts/visor.script del $devpath
-
-REGISTER       (usb/lp.*|printers/.*)  EXECUTE /etc/dynamic/scripts/lp.script add $devpath
-UNREGISTER     (usb/lp.*|printers/.*)  EXECUTE /etc/dynamic/scripts/lp.script del $devpath
-
-#/etc/devfs/conf.d/modem.conf
-#REGISTER      ^$      CFUNCTION GLOBAL mksymlink  modem
-#UNREGISTER    ^$      CFUNCTION GLOBAL unlink modem
-REGISTER       ^tts/0$ EXECUTE ln -sf  $devname modem
-UNREGISTER     ^$      EXECUTE rm -f modem
-
-#/etc/devfs/conf.d/mouse.conf
-#REGISTER      ^misc/psaux$    CFUNCTION GLOBAL mksymlink misc/psaux mouse
-#UNREGISTER    ^misc/psaux$    CFUNCTION GLOBAL unlink mouse
-REGISTER       ^misc/psaux$    EXECUTE ln -sf misc/psaux mouse
-UNREGISTER     ^misc/psaux$    EXECUTE rm -f mouse
-
-#/etc/devfs/conf.d/psaux.conf
-#REGISTER      ^misc/psaux$    CFUNCTION GLOBAL mksymlink misc/psaux psaux
-#UNREGISTER    ^misc/psaux$    CFUNCTION GLOBAL unlink psaux
-REGISTER       ^misc/psaux$    EXECUTE ln -sf misc/psaux psaux
-UNREGISTER     ^misc/psaux$    EXECUTE rm -f psaux
-
-#/etc/devfs/conf.d/rdvd.conf
-REGISTER       ^ide/host0/bus1/target1/lun0/cd$        EXECUTE /etc/dynamic/scripts/rawdevice.script add /dev/ide/host0/bus1/target1/lun0/cd /dev/rdvd
-UNREGISTER     ^ide/host0/bus1/target1/lun0/cd$        EXECUTE /etc/dynamic/scripts/rawdevice.script del /dev/rdvd
-
-#/etc/devfs/conf.d/ttyS0.conf
-#REGISTER      ^tts/0$ CFUNCTION GLOBAL mksymlink tts/0 ttyS0
-#UNREGISTER    ^tts/0$ CFUNCTION GLOBAL unlink ttyS0
-REGISTER       ^tts/0$ EXECUTE ln -sf $devname ttyS0
-UNREGISTER     ^tts/0$ EXECUTE rm -f ttyS0
+# INCLUDE   /etc/devfs/conf.d/
+INCLUDE   /etc/devfs/busybox/
+# Busybox: just for testing
+#INCLUDE                       /etc/devfs/nothing/
+#INCLUDE                       /etc/devfs/nothing/nothing
+#OPTIONAL_INCLUDE      /etc/devfs/nothing/
+#OPTIONAL_INCLUDE      /etc/devfs/nothing/nothing
index 0afdadb71f208fbe3b2232a7d11e053ad65897ea..4a013cbd5a6fb84d95df64ebbed43d84e6aa86ff 100644 (file)
@@ -47,6 +47,13 @@ config CONFIG_DEVFSD
          Provides compatibility with old device names on a devfs systems.
          You should set it to true if you have devfs enabled.
 
+config CONFIG_DEVFSD_MODLOAD
+       bool "Adds support for MODLOAD action"
+       default n
+       depends on CONFIG_DEVFSD
+       help
+         This actually doesn't work with busybox  modutils but needs the real modutils.
+
 config CONFIG_DEVFSD_VERBOSE
        bool "Increases logging to stderr and syslog"
        default n
index e5d550835907919713d835d6b7383050bc106641..9f998e72348c2fec274f8200d8cce71cc1481a60 100644 (file)
@@ -129,6 +129,8 @@ struct devfsd_notify_struct
 #define BUFFER_SIZE 16384
 #define DEVFSD_VERSION "1.3.25"
 #define CONFIG_FILE  "/etc/devfsd.conf"
+#define MODPROBE               "/sbin/modprobe"
+#define CONFIG_MODULES_DEVFS "/etc/modules.devfs"
 #define MAX_ARGS     (6 + 1)
 #define MAX_SUBEXPR  10
 #define STRING_LENGTH 255
@@ -138,10 +140,15 @@ struct devfsd_notify_struct
 #define GID                    1
 
 /*     for msg_logger(), do_ioctl(),
-       fork_and_execute() and xopendir(). */
-# define DIE                           1
+       fork_and_execute() */
+# define DIE                   1
 # define NO_DIE                        0
 
+/* for dir_operation() */
+#define RESTORE                0
+#define SERVICE                1
+#define READ_CONFIG 2
+
 /*  Update only after changing code to reflect new protocol  */
 #define DEVFSD_PROTOCOL_REVISION_DAEMON  5
 
@@ -151,11 +158,11 @@ struct devfsd_notify_struct
 #endif
 
 #define AC_PERMISSIONS                         0
-#define AC_MODLOAD                                     1       /* not supported by busybox */
+#define AC_MODLOAD                                     1
 #define AC_EXECUTE                                     2
 #define AC_MFUNCTION                           3       /* not supported by busybox */
 #define AC_CFUNCTION                           4       /* not supported by busybox */
-#define AC_COPY                                        5
+#define AC_COPY                                                5
 #define AC_IGNORE                                      6
 #define AC_MKOLDCOMPAT                         7
 #define AC_MKNEWCOMPAT                         8
@@ -209,6 +216,8 @@ struct get_variable_info
     char devpath[STRING_LENGTH];
 };
 
+static void dir_operation(int , const char * , int,  unsigned long* );
+static void service(struct stat statbuf, char *path);
 static int st_expr_expand(char *, unsigned, const char *, const char *(*) (const char *, void *), void *);
 static const char *get_old_name(const char *, unsigned, char *, unsigned, unsigned);
 static int mksymlink (const char *oldpath, const char *newpath);
@@ -219,16 +228,18 @@ static void service_name (const struct devfsd_notify_struct *);
 static void action_permissions (const struct devfsd_notify_struct *, const struct config_entry_struct *);
 static void action_execute (const struct devfsd_notify_struct *, const struct config_entry_struct *,
                                                        const regmatch_t *, unsigned);
+#ifdef CONFIG_DEVFSD_MODLOAD
+static void action_modload (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry);
+#endif
 static void action_copy (const struct devfsd_notify_struct *, const struct config_entry_struct *,
                                                 const regmatch_t *, unsigned);
 static void action_compat (const struct devfsd_notify_struct *, unsigned);
 static void free_config (void);
-static void do_restore (const char *, int);
+static void restore(char *spath, struct stat source_stat, int rootlen);
 static int copy_inode (const char *, const struct stat *, mode_t, const char *, const struct stat *);
 static mode_t get_mode (const char *);
 static void signal_handler (int);
 static const char *get_variable (const char *, void *);
-static void do_scan_and_service (const char *);
 static int make_dir_tree (const char *);
 static int expand_expression(char *, unsigned, const char *, const char *(*)(const char *, void *), void *,
                                                         const char *, const regmatch_t *, unsigned );
@@ -243,7 +254,6 @@ static char *write_old_sd_name (char *, unsigned, unsigned, char *);
 static void msg_logger(int die, int pri, const char * fmt, ... );
 static void do_ioctl(int die, int fd, int request, unsigned long event_mask_flag);
 static void fork_and_execute(int die, char *arg0, char **arg );
-DIR * xopendir(int die, const char * dir_name);
 static int get_uid_gid ( int, const char *);
 static void safe_memcpy( char * dest, const char * src, int len);
 
@@ -318,7 +328,7 @@ static void msg_logger(int die, int pri, const char * fmt, ... )
 static void do_ioctl(int die, int fd, int request, unsigned long event_mask_flag)
 {
        if (ioctl (fd, request, event_mask_flag) != 0)
-               msg_logger(die, LOG_ERR, "ioctl() failed: %m\n");
+               msg_logger(die, LOG_ERR, "ioctl(): %m\n");
 }
 
 static void fork_and_execute(int die, char *arg0, char **arg )
@@ -345,21 +355,10 @@ static void fork_and_execute(int die, char *arg0, char **arg )
        if(arg0 != NULL )
        {
                execvp (arg0, arg);
-               msg_logger(DIE, LOG_ERR, "execvp() failed: %s: %m\n", arg0);
+               msg_logger(DIE, LOG_ERR, "execvp(): %s: %m\n", arg0);
        }
 }
 
-
-DIR * xopendir(int die, const char * dir_name)
-{
-       DIR *dp;
-
-       if ( ( dp = opendir (dir_name) ) == NULL )
-               msg_logger( die, LOG_ERR, "opendir() failed: %s: %m\n", dir_name);
-       /* if die == DIE not reached else return NULL */
-       return dp;
-}
-
 static void safe_memcpy( char *dest, const char *src, int len)
 {
        memcpy (dest , src , len );
@@ -437,7 +436,7 @@ int devfsd_main (int argc, char **argv)
        umask (0);
        read_config_file (CONFIG_FILE, FALSE, &event_mask);
        /*  Do the scan before forking, so that boot scripts see the finished product  */
-       do_scan_and_service (mount_point);
+       dir_operation(SERVICE,mount_point,0,NULL);
        if (no_polling)
                exit (0);
        if (do_daemon)
@@ -457,7 +456,7 @@ int devfsd_main (int argc, char **argv)
                free_config ();
                read_config_file (CONFIG_FILE, FALSE, &event_mask);
                if (do_scan)
-                       do_scan_and_service (mount_point);
+                       dir_operation(SERVICE,mount_point,0,NULL);
        }
 }   /*  End Function main  */
 
@@ -476,32 +475,17 @@ static void read_config_file (const char *path, int optional, unsigned long *eve
        struct stat statbuf;
        FILE *fp;
        char buf[STRING_LENGTH];
+       char *line=NULL;
 
 #ifdef CONFIG_DEVFSD_DEBUG
        msg_logger( NO_DIE, LOG_INFO, "read_config_file()\n");
 #endif
-
        if (stat (path, &statbuf) != 0 || statbuf.st_size == 0 )
-               msg_logger((optional ==  0 )? DIE : NO_DIE, LOG_ERR, " %s: %m\n", path);
+               goto read_config_file_err;
 
        if ( S_ISDIR (statbuf.st_mode) )
        {
-
-               DIR *dp;
-               struct dirent *de;
-
-               dp = xopendir(DIE, path);
-
-               while ( ( de = readdir (dp) ) != NULL )
-               {
-                       char fname[STRING_LENGTH];
-
-                       if (de->d_name[0] == '.')
-                               continue;
-                       snprintf (fname, STRING_LENGTH, "%s/%s", path, de->d_name);
-                       read_config_file (fname, optional, event_mask);
-               }
-               closedir (dp);
+               dir_operation(READ_CONFIG, path, 0, event_mask);
                return;
        }
 
@@ -509,9 +493,13 @@ static void read_config_file (const char *path, int optional, unsigned long *eve
        {
                while (fgets (buf, STRING_LENGTH, fp) != NULL)
                {
-                       char *line;
-
-                       buf[strlen (buf) - 1] = '\0';
+                       /*  GETS(3)       Linux Programmer's Manual
+                       fgets() reads in at most one less than size characters from stream  and
+                       stores  them  into  the buffer pointed to by s.  Reading stops after an
+                       EOF or a newline.  If a newline is read, it is stored into the  buffer.
+                       A '\0' is stored after the last character in the buffer.
+                       */
+                       /*buf[strlen (buf) - 1] = '\0';*/
                        /*  Skip whitespace  */
                        for (line = buf; isspace (*line); ++line)
                                /*VOID*/;
@@ -520,12 +508,13 @@ static void read_config_file (const char *path, int optional, unsigned long *eve
                        process_config_line (line, event_mask);
                }
                fclose (fp);
+               errno=0;
+       }
+read_config_file_err:
 #ifdef CONFIG_DEVFSD_VERBOSE
-               msg_logger( NO_DIE, LOG_INFO, "read config file: %s\n", path);
+       msg_logger(((optional ==  0 ) && (errno == ENOENT))? DIE : NO_DIE, LOG_ERR, "read config file: %s: %m\n", path);
 #endif
-               return;
-       }
-       msg_logger(( (optional == 0) && (errno == ENOENT) )? DIE : NO_DIE, LOG_ERR, " %s: %m\n", path);
+       return;
 }   /*  End Function read_config_file   */
 
 static void process_config_line (const char *line, unsigned long *event_mask)
@@ -541,6 +530,8 @@ static void process_config_line (const char *line, unsigned long *event_mask)
        char when[STRING_LENGTH], what[STRING_LENGTH];
        char name[STRING_LENGTH];
        char * msg="";
+       char *ptr;
+
 #ifdef CONFIG_DEVFSD_DEBUG
        msg_logger( NO_DIE, LOG_INFO, "process_config_line()\n");
 #endif
@@ -562,12 +553,15 @@ static void process_config_line (const char *line, unsigned long *event_mask)
                 (strcasecmp (when, "OPTIONAL_INCLUDE") == 0) )
        {
                st_expr_expand (name, STRING_LENGTH, name, get_variable, NULL );
+#ifdef CONFIG_DEVFSD_VERBOSE
+               msg_logger( NO_DIE, LOG_INFO, "%sinclude: %s\n",(toupper (when[0]) == 'I') ? "": "optional_", name);
+#endif
                read_config_file (name, (toupper (when[0]) == 'I') ? FALSE : TRUE, event_mask);
                return;
        }
        if (strcasecmp (when, "RESTORE") == 0)
        {
-               do_restore ( name, strlen (name) );
+               dir_operation(RESTORE,name, strlen (name),NULL);
                return;
        }
        if (num_args < 3)
@@ -591,8 +585,6 @@ static void process_config_line (const char *line, unsigned long *event_mask)
 
        if (strcasecmp (what, "PERMISSIONS") == 0)
        {
-               char *ptr;
-
                new->action.what = AC_PERMISSIONS;
                /*  Get user and group  */
                if ( ( ptr = strchr (p[0], '.') ) == NULL )
@@ -607,6 +599,14 @@ static void process_config_line (const char *line, unsigned long *event_mask)
                /*  Get mode  */
                new->u.permissions.mode = get_mode (p[1]);
        }
+#ifdef CONFIG_DEVFSD_MODLOAD
+       else if (strcasecmp (what, "MODLOAD") == 0)
+               /*This  action will pass "/dev/$devname" (i.e. "/dev/" prefixed to
+               the device name) to the module loading  facility.  In  addition,
+               the /etc/modules.devfs configuration file is used.*/
+
+                new->action.what = AC_MODLOAD;
+#endif
        else if (strcasecmp (what, "EXECUTE") == 0)
        {
                new->action.what = AC_EXECUTE;
@@ -673,11 +673,6 @@ static int do_servicing (int fd, unsigned long event_mask)
 #endif
        /*  Tell devfs what events we care about  */
        tmp_event_mask = event_mask;
-       /*  May need to trap inode creates to watch for syslogd(8) starting  */
-       /*if (!syslog_is_open &&  !no_syslog)
-       {
-               tmp_event_mask |= 1 << DEVFSD_NOTIFY_CREATE; *//*FIXME  I'm not sure if this line is needed. TITO */
-       /*}*/
        do_ioctl(DIE, fd, DEVFSDIOC_SET_EVENT_MASK, tmp_event_mask);
        while (!caught_signal)
        {
@@ -689,14 +684,6 @@ static int do_servicing (int fd, unsigned long event_mask)
                        continue;  /*  Yes, the order is important  */
                if (bytes < 1)
                        break;
-               /*  Special trap for "/dev/log" creation  */
-               /*  Open syslog, now that "/dev/log" exists  */
-               /*if (!syslog_is_open && !no_syslog &&
-                        (info.type == DEVFSD_NOTIFY_CREATE) &&(strcmp (info.devname, "log") == 0) )
-               {
-                       do_open_syslog ();
-                       do_ioctl(DIE, fd, DEVFSDIOC_SET_EVENT_MASK, event_mask);*/ /*FIXME I'm not sure if this line is needed. TITO */
-               /*}*/
                service_name (&info);
        }
        if (caught_signal)
@@ -752,6 +739,14 @@ static void service_name (const struct devfsd_notify_struct *info)
 #endif
                                action_permissions (info, entry);
                                break;
+#ifdef CONFIG_DEVFSD_MODLOAD
+                       case AC_MODLOAD:
+                               #ifdef CONFIG_DEVFSD_DEBUG
+                               msg_logger( NO_DIE, LOG_INFO, "AC_MODLOAD\n");
+                               #endif
+                               action_modload (info, entry);
+                               break;
+#endif
                        case AC_EXECUTE:
 #ifdef CONFIG_DEVFSD_DEBUG
                                msg_logger( NO_DIE, LOG_INFO, "AC_EXECUTE\n");
@@ -805,13 +800,39 @@ static void action_permissions (const struct devfsd_notify_struct *info,
                 chown (info->devname, entry->u.permissions.uid, entry->u.permissions.gid) != 0)
        {
 #ifdef CONFIG_DEVFSD_VERBOSE
-                       msg_logger( NO_DIE, LOG_ERR, "chmod() or chown() error for: %s: %m\n",info->devname);
+                       msg_logger( NO_DIE, LOG_ERR, "chmod() or chown(): %s: %m\n",info->devname);
 #endif
                return;
        }
 
 }   /*  End Function action_permissions  */
 
+#ifdef CONFIG_DEVFSD_MODLOAD
+static void action_modload (const struct devfsd_notify_struct *info,
+                           const struct config_entry_struct *entry)
+/*  [SUMMARY] Load a module.
+    <info> The devfs change.
+    <entry> The config file entry.
+    [RETURNS] Nothing.
+*/
+{
+       char *argv[6];
+       char device[STRING_LENGTH];
+
+       argv[0] = MODPROBE;
+       argv[1] = "-k";
+       argv[2] = "-C";
+       argv[3] = CONFIG_MODULES_DEVFS;
+       argv[4] = device;
+       argv[5] = NULL;
+       #ifdef CONFIG_DEVFSD_DEBUG
+       msg_logger( NO_DIE, LOG_INFO, "action_modload()\n");
+       #endif
+       snprintf (device, sizeof (device), "/dev/%s", info->devname);
+       fork_and_execute(DIE, argv[0], argv);
+}  /*  End Function action_modload  */
+#endif
+
 static void action_execute (const struct devfsd_notify_struct *info,
                            const struct config_entry_struct *entry,
                            const regmatch_t *regexpr, unsigned int numexpr)
@@ -903,8 +924,7 @@ static void action_copy (const struct devfsd_notify_struct *info,
                                regexpr, numexpr);
 
        if ( !make_dir_tree (destination) || lstat (source, &source_stat) != 0)
-               goto action_copy_error;
-
+                       return;
        lstat (destination, &dest_stat);
        new_mode = source_stat.st_mode & ~S_ISVTX;
        if (info->type == DEVFSD_NOTIFY_CREATE)
@@ -913,13 +933,11 @@ static void action_copy (const struct devfsd_notify_struct *info,
                new_mode |= S_ISVTX;
 #ifdef CONFIG_DEVFSD_VERBOSE
        if ( !copy_inode (destination, &dest_stat, new_mode, source, &source_stat) )
-action_copy_error:
-               msg_logger( NO_DIE, LOG_ERR, "error copying: %s to %s: %m\n", source, destination);
+               msg_logger( NO_DIE, LOG_ERR, "copy_inode(): %s to %s: %m\n", source, destination);
 #else
-       copy_inode (destination, &dest_stat, new_mode, source,&source_stat);
-action_copy_error:
-       return;
+       copy_inode (destination, &dest_stat, new_mode, source, &source_stat);
 #endif
+       return;
 }   /*  End Function action_copy  */
 
 static void action_compat (const struct devfsd_notify_struct *info,
@@ -1041,53 +1059,26 @@ static void action_compat (const struct devfsd_notify_struct *info,
        }
 }   /*  End Function action_compat  */
 
-static void do_restore (const char *dir_name, int rootlen)
-/*  [SUMMARY] Restore state from a directory.
-    <dir_name> The directory containing the backing store.
-    <rootlen> The length of the root of the state directory hierarchy.
-    [RETURNS] Nothing.
-*/
+static void restore(char *spath, struct stat source_stat, int rootlen)
 {
-       DIR *dp;
-       struct dirent *de;
+       char dpath[STRING_LENGTH];
+       struct stat dest_stat;
 
 #ifdef CONFIG_DEVFSD_DEBUG
-       msg_logger( NO_DIE, LOG_INFO, "do_restore()\n");
+       msg_logger( NO_DIE, LOG_INFO, "restore()\n");
 #endif
 
-       if( (dp = xopendir(NO_DIE, dir_name))== NULL)
-               return;
-
-       while ( (de = readdir (dp) ) != NULL )
-       {
-               char spath[STRING_LENGTH], dpath[STRING_LENGTH];
-
-               struct stat source_stat, dest_stat;
-               dest_stat.st_mode = 0;
-
-               if ( (strcmp (de->d_name, ".") == 0) || (strcmp (de->d_name, "..") == 0) )
-                       continue;
-
-               snprintf (spath, sizeof spath, "%s/%s", dir_name, de->d_name);
+       dest_stat.st_mode = 0;
+       snprintf (dpath, sizeof dpath, "%s%s", mount_point, spath + rootlen);
+       lstat (dpath, &dest_stat);
 
-               if (lstat (spath, &source_stat) != 0)
-               {
-#ifdef CONFIG_DEVFSD_VERBOSE
-                       msg_logger( NO_DIE, LOG_ERR, "%s: %m\n", spath);
-#endif
-                       continue;
-               }
-               snprintf (dpath, sizeof dpath, "%s%s", mount_point, spath + rootlen);
-               lstat (dpath, &dest_stat);
+       if ( S_ISLNK (source_stat.st_mode) || (source_stat.st_mode & S_ISVTX) )
+               copy_inode (dpath, &dest_stat, (source_stat.st_mode & ~S_ISVTX) , spath, &source_stat);
 
-               if ( S_ISLNK (source_stat.st_mode) || (source_stat.st_mode & S_ISVTX) )
-                       copy_inode (dpath, &dest_stat, (source_stat.st_mode & ~S_ISVTX) , spath, &source_stat);
+       if ( S_ISDIR (source_stat.st_mode) )
+               dir_operation(RESTORE, spath, rootlen,NULL);
+}
 
-               if ( S_ISDIR (source_stat.st_mode) )
-                       do_restore (spath, rootlen);
-       }
-       closedir (dp);
-}   /*  End Function do_restore  */
 
 static int copy_inode (const char *destpath, const struct stat *dest_stat,
                        mode_t new_mode,
@@ -1148,9 +1139,7 @@ static int copy_inode (const char *destpath, const struct stat *dest_stat,
                        close (fd);
                        if (val != 0 || chmod (destpath, new_mode & ~S_IFMT) != 0)
                                break;
-                       if (chown (destpath, source_stat->st_uid, source_stat->st_gid) == 0)
-                               return (TRUE);
-                       break;
+                       goto do_chown;
                case S_IFLNK:
                        if ( ( val = readlink (sourcepath, symlink_val, STRING_LENGTH - 1) ) < 0 )
                                break;
@@ -1164,23 +1153,19 @@ static int copy_inode (const char *destpath, const struct stat *dest_stat,
                        close (fd);
                        if (chmod (destpath, new_mode & ~S_IFMT) != 0)
                                break;
-                       if (chown (destpath, source_stat->st_uid, source_stat->st_gid) == 0)
-                               return (TRUE);
-                       break;
+                       goto do_chown;
                case S_IFBLK:
                case S_IFCHR:
                case S_IFIFO:
                        if (mknod (destpath, new_mode, source_stat->st_rdev) != 0)
                                break;
-                       if (chown (destpath, source_stat->st_uid, source_stat->st_gid) == 0)
-                               return (TRUE);
-                       break;
+                       goto do_chown;
                case S_IFDIR:
                        if (mkdir (destpath, new_mode & ~S_IFMT) != 0)
                                break;
+do_chown:
                        if (chown (destpath, source_stat->st_uid, source_stat->st_gid) == 0)
                                return (TRUE);
-                       return (TRUE);
                /*break;*/
        }
        return (FALSE);
@@ -1228,15 +1213,14 @@ static int get_uid_gid (int flag, const char *string)
 {
        struct passwd *pw_ent;
        struct group *grp_ent;
-       char * msg_a="user";
-       char * msg_b="U";
+       char * msg="user";
 
 #ifdef CONFIG_DEVFSD_DEBUG
        msg_logger( NO_DIE, LOG_INFO, "get_uid_gid()\n");
 
 
        if(flag != UID && flag != GID )
-               msg_logger( DIE, LOG_ERR,"flag != UID && flag != GID\n");
+               msg_logger( DIE, LOG_ERR,"get_uid_gid(): flag != UID && flag != GID\n");
 #endif
 
        if ( isdigit (string[0]) || ( (string[0] == '-') && isdigit (string[1]) ) )
@@ -1248,12 +1232,9 @@ static int get_uid_gid (int flag, const char *string)
        if ( flag == GID && ( grp_ent = getgrnam (string) ) != NULL )
                return (grp_ent->gr_gid);
        else
-       {
-               msg_a="group";
-               msg_b="G";
-       }
+               msg="group";
 
-       msg_logger( NO_DIE, LOG_ERR,"unknown %s: %s, defaulting to %cID=0\n", msg_a, string, msg_b);
+       msg_logger( NO_DIE, LOG_ERR,"unknown %s: %s, defaulting to %cID=0\n", msg, string, msg[0] - 32);
        return (0);
 }/*  End Function get_uid_gid  */
 
@@ -1264,7 +1245,7 @@ static mode_t get_mode (const char *string)
 */
 {
        mode_t mode;
-
+       int i;
 #ifdef CONFIG_DEVFSD_DEBUG
        msg_logger( NO_DIE, LOG_INFO, "get_mode()\n");
 #endif
@@ -1274,15 +1255,14 @@ static mode_t get_mode (const char *string)
        if (strlen (string) != 9)
                msg_logger( DIE, LOG_ERR, "bad mode: %s\n", string);
        mode = 0;
-       if (string[0] == 'r') mode |= S_IRUSR;
-       if (string[1] == 'w') mode |= S_IWUSR;
-       if (string[2] == 'x') mode |= S_IXUSR;
-       if (string[3] == 'r') mode |= S_IRGRP;
-       if (string[4] == 'w') mode |= S_IWGRP;
-       if (string[5] == 'x') mode |= S_IXGRP;
-       if (string[6] == 'r') mode |= S_IROTH;
-       if (string[7] == 'w') mode |= S_IWOTH;
-       if (string[8] == 'x') mode |= S_IXOTH;
+       i= S_IRUSR;
+       while(i>0)
+       {
+               if(string[0]=='r'||string[0]=='w'||string[0]=='x')
+                       mode+=i;
+               i=i/2;
+               string++;
+       }
        return (mode);
 }   /*  End Function get_mode  */
 
@@ -1341,10 +1321,34 @@ static const char *get_variable (const char *variable, void *info)
        return (NULL);
 }   /*  End Function get_variable  */
 
-static void do_scan_and_service (const char *dir_name)
+static void service(struct stat statbuf, char *path)
+{
+       struct devfsd_notify_struct info;
+
+#ifdef CONFIG_DEVFSD_DEBUG
+       msg_logger( NO_DIE, LOG_INFO, "service()\n");
+#endif
+
+       memset (&info, 0, sizeof info);
+       info.type = DEVFSD_NOTIFY_REGISTERED;
+       info.mode = statbuf.st_mode;
+       info.major = major (statbuf.st_rdev);
+       info.minor = minor (statbuf.st_rdev);
+       info.uid = statbuf.st_uid;
+       info.gid = statbuf.st_gid;
+       snprintf (info.devname, sizeof (info.devname), "%s", path + strlen (mount_point) + 1);
+       info.namelen = strlen (info.devname);
+       service_name (&info);
+       if ( S_ISDIR (statbuf.st_mode) )
+               dir_operation(SERVICE,path,0,NULL);
+}
+
+static void dir_operation(int type, const char * dir_name, int var, unsigned long *event_mask)
 /*  [SUMMARY] Scan a directory tree and generate register events on leaf nodes.
-    <dp> The directory pointer. This is closed upon completion.
+       <flag> To choose which function to perform
+       <dp> The directory pointer. This is closed upon completion.
     <dir_name> The name of the directory.
+       <rootlen> string length parameter.
     [RETURNS] Nothing.
 */
 {
@@ -1353,20 +1357,24 @@ static void do_scan_and_service (const char *dir_name)
        struct dirent *de;
        char path[STRING_LENGTH];
 
+
 #ifdef CONFIG_DEVFSD_DEBUG
-       msg_logger( NO_DIE, LOG_INFO, "do_scan_and_service ()\n");
+       msg_logger( NO_DIE, LOG_INFO, "dir_operation()\n");
 #endif
 
-       if((dp = xopendir(NO_DIE, dir_name))==NULL)
+       if((dp = opendir( dir_name))==NULL)
+       {
+               msg_logger( NO_DIE, LOG_ERR, "opendir(): %s: %m\n", dir_name);
                return;
+       }
 
        while ( (de = readdir (dp) ) != NULL )
        {
-               struct devfsd_notify_struct info;
 
-               if ( (strcmp (de->d_name, ".") == 0) || (strcmp (de->d_name, "..") == 0) )
+               if ( (strcmp (de->d_name, ".") == 0)  || (strcmp (de->d_name, "..") == 0)  )
                        continue;
-               snprintf (path, sizeof (path), "%s/%s", dir_name, de->d_name);
+               snprintf (path, sizeof (path), "%s%s%s", dir_name,(last_char_is(dir_name,'/')==NULL)?"/":"", de->d_name);
+
                if (lstat (path, &statbuf) != 0)
                {
 #ifdef CONFIG_DEVFSD_VERBOSE
@@ -1374,18 +1382,18 @@ static void do_scan_and_service (const char *dir_name)
 #endif
                        continue;
                }
-               memset (&info, 0, sizeof info);
-               info.type = DEVFSD_NOTIFY_REGISTERED;
-               info.mode = statbuf.st_mode;
-               info.major = major (statbuf.st_rdev);
-               info.minor = minor (statbuf.st_rdev);
-               info.uid = statbuf.st_uid;
-               info.gid = statbuf.st_gid;
-               snprintf (info.devname, sizeof (info.devname), "%s", path + strlen (mount_point) + 1);
-               info.namelen = strlen (info.devname);
-               service_name (&info);
-               if ( S_ISDIR (statbuf.st_mode) )
-                       do_scan_and_service (path);
+               switch(type)
+               {
+                       case SERVICE:
+                               service(statbuf,path);
+                               break;
+                       case RESTORE:
+                               restore(path, statbuf, var);
+                               break;
+                       case READ_CONFIG:
+                               read_config_file (path, var, event_mask);
+                               break;
+               }
        }
        closedir (dp);
 }   /*  End Function do_scan_and_service  */
@@ -1408,17 +1416,10 @@ static int mksymlink (const char *oldpath, const char *newpath)
        if (symlink (oldpath, newpath) != 0)
     {
 #ifdef CONFIG_DEVFSD_VERBOSE
-               if (errno == EEXIST)
-                       msg_logger( NO_DIE, LOG_INFO, "symlink(): %s: already exists\n", newpath);
-               else
-               {
-                       msg_logger( NO_DIE, LOG_ERR, "symlink(): %s: %m\n", newpath);
-                       return (-1);
-               }
-#else
+               msg_logger( NO_DIE, LOG_ERR, "symlink(): %s to %s: %m\n", oldpath, newpath);
+#endif
                if (errno != EEXIST)
                        return (-1);
-#endif
        }
     return (0);
 }   /*  End Function mksymlink  */
@@ -1701,7 +1702,6 @@ static char get_old_ide_name (unsigned int major, unsigned int minor)
        char c='a';             /*  97 */
        int i=IDE0_MAJOR;
 
-
 #ifdef CONFIG_DEVFSD_DEBUG
        msg_logger( NO_DIE, LOG_INFO, "get_old_ide_name()\n");
 #endif