From 3860b2ebd6ad9c68a087c2addd1f1c592aaeaee9 Mon Sep 17 00:00:00 2001
From: Glenn L McGrath <bug1@ihug.co.nz>
Date: Sun, 30 Nov 2003 23:46:06 +0000
Subject: Patch from Tito, size optimisation, cleanup noise when in debugging
 mode, adds support for MODLOAD keyword in devfsd.conf, provides a cleaned up
 version of example/devfsd.conf

---
 examples/devfsd.conf |  92 ++++----------
 miscutils/Config.in  |   7 ++
 miscutils/devfsd.c   | 334 +++++++++++++++++++++++++--------------------------
 3 files changed, 196 insertions(+), 237 deletions(-)

diff --git a/examples/devfsd.conf b/examples/devfsd.conf
index ea7334374..e90e7102b 100644
--- a/examples/devfsd.conf
+++ b/examples/devfsd.conf
@@ -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
diff --git a/miscutils/Config.in b/miscutils/Config.in
index 0afdadb71..4a013cbd5 100644
--- a/miscutils/Config.in
+++ b/miscutils/Config.in
@@ -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
diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c
index e5d550835..9f998e723 100644
--- a/miscutils/devfsd.c
+++ b/miscutils/devfsd.c
@@ -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
-- 
cgit v1.2.3