[PATCH, revised] mdev command execution - cleanup

Alberto Donato alberto.donato at gmail.com
Thu May 18 16:58:19 PDT 2006


On 5/18/06, Rob Landley <rob at landley.net> wrote:
> Yesterday a marvelous patch for mdev.c came in adding shellout support.
> Except it's not configurable, and it adds a flag to conditionally disable
> some behavior in make_device which is the wrong way to go about it; it would
> be better to break make_device into two functions so we could call what we
> needed with fewer ifs in the code.

You are absolutely right about make_device. I considered splitting
that function, but thought it would have required significant
modifications to the code and took the easy way. Actually, it was
mainly matter of moving some vars as global.
This patch should clean up the code a little bit.

Alberto
-------------- next part --------------
Index: util-linux/Config.in
===================================================================
--- util-linux/Config.in	(revision 15108)
+++ util-linux/Config.in	(working copy)
@@ -265,16 +265,21 @@
 
 	  That's device name (with regex match), uid:gid, and permissions.
 
-	  Optionally, that can be followed (on the same line) by an asterisk
-	  and a command line to run after creating the corresponding device(s),
-	  ala:
-
-	    hdc root:cdrom 660  *ln -s hdc cdrom
-
 	  Config file parsing stops on the first matching line.  If no config
 	  entry is matched, devices are created with default 0:0 660.  (Make
 	  the last line match .* to override this.)
 
+config CONFIG_FEATURE_MDEV_EXEC
+	bool "Support command execution at device addition/removal"
+	default n
+	depends on CONFIG_FEATURE_MDEV_CONF
+	help
+	  This adds support for an optional field to /etc/mdev.conf, consisting of 
+	  an asterisk and a command line to run after creating the corresponding 
+	  device(s) and before removing, ala:
+
+	    hdc root:cdrom 660  *ln -s hdc cdrom
+
 config CONFIG_MKSWAP
 	bool "mkswap"
 	default n
Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c	(revision 15108)
+++ util-linux/mdev.c	(working copy)
@@ -30,14 +30,152 @@
 
 int root_major, root_minor;
 
+int major, minor, type;
+int mode = 0660;
+uid_t uid = 0;
+gid_t gid = 0;
+char *command = NULL;
+
+#ifdef ENABLE_FEATURE_MDEV_CONF
+/* If we have a config file, look up permissions for this device */
+
+static void get_device_config(char *device_name)
+{
+  int len, fd;
+  char *conf, *pos, *end, *s;
+
+  /* Default settings for device node */  
+  mode = 0660;
+  uid = 0;
+  gid = 0;
+  command = NULL;
+
+  /* mmap the config file */
+  if (-1 != (fd=open(MDEV_CONF,O_RDONLY))) {
+    len = lseek(fd, 0, SEEK_END);
+    conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (conf) {
+      int line = 0;
+      
+      /* Loop through lines in mmaped file*/
+      for (pos=conf; pos-conf<len;) {
+	int field;
+	char *end2;
+	
+	line++;
+	/* find end of this line */
+	for(end=pos; end-conf<len && *end!='\n'; end++)
+	  ;
+
+	/* Four fields: regex, uid:gid, mode, command to exec (if any) */
+	for (field=4; field; field--) {
+	  /* Skip whitespace */
+	  while (pos<end && isspace(*pos))
+	    pos++;
+	  if (pos==end || *pos=='#')
+	    break;
+	  for (end2=pos; end2<end && !isspace(*end2) && *end2!='#'; end2++)
+	    ;
+	  
+	  switch (field) {
+	    /* Regex to match this device */
+	  case 4:
+	    {
+	      char *regex = strndupa(pos,end2-pos);
+	      regex_t match;
+	      regmatch_t off;
+	      int result;
+	      
+	      /* Is this it? */
+	      xregcomp(&match,regex,REG_EXTENDED);
+	      result = regexec(&match,device_name,1,&off,0);
+	      regfree(&match);
+	      
+	      /* If not this device, skip rest of line */
+	      if (result || off.rm_so || off.rm_eo!=strlen(device_name))
+		goto end_line;
+	      
+	      break;
+	    }
+	    /* uid:gid */
+	  case 3:
+	    {
+	      char *s2;
+	      
+	      /* Find : */
+	      for(s=pos; s<end2 && *s!=':'; s++)
+		;
+	      if (s == end2)
+		goto end_line;
+	      
+	      /* Parse UID */
+	      uid = strtoul(pos,&s2,10);
+	      if (s != s2) {
+		struct passwd *pass;
+		pass = getpwnam(strndupa(pos,s-pos));
+		if (!pass)
+		  goto end_line;
+		uid = pass->pw_uid;
+	      }
+	      s++;
+	      /* parse GID */
+	      gid = strtoul(s,&s2,10);
+	      if (end2 != s2) {
+		struct group *grp;
+		grp = getgrnam(strndupa(s,end2-s));
+		if (!grp)
+		  goto end_line;
+		gid = grp->gr_gid;
+	      }
+	      break;
+	    }
+	    /* mode */
+	  case 2:
+	    {
+	      mode = strtoul(pos,&pos,8);
+	      if (end2 == end)
+		goto found_device;
+	      
+	      break;
+	    }
+	    /* command */
+	  case 1:
+	    {
+	      if (*pos++ != '*')
+		goto end_line;
+	      
+	      if (pos != end) 
+		command = strndup(pos, end-pos);
+	      
+	      goto found_device;
+	    }
+
+	  }
+	  pos = end2;
+	}
+      end_line:
+	/* Did everything parse happily? */
+	if (field && field!=4)
+	  bb_error_msg_and_die("Bad line %d",line);
+
+	/* Next line */
+	pos = ++end;
+      }
+    found_device:
+      munmap(conf, len);
+    }
+    close(fd);
+  }
+
+}
+#endif
+
+
 /* mknod in /dev based on a path like "/sys/block/hda/hda1" */
 static void make_device(char *path)
 {
-	char *device_name, *s;
-	int major, minor, type, len, fd;
-	int mode = 0660;
-	uid_t uid = 0;
-	gid_t gid = 0;
+	char *device_name;
+	int len, fd;
 	char *temp = path + strlen(path);
 
 	/* Try to read major/minor string.  Note that the kernel puts \n after
@@ -58,117 +196,8 @@
 	type = path[5]=='c' ? S_IFCHR : S_IFBLK;
 	if (sscanf(temp, "%d:%d", &major, &minor) != 2) return;
 
-	/* If we have a config file, look up permissions for this device */
+	if (ENABLE_FEATURE_MDEV_CONF) get_device_config(device_name);
 
-	if (ENABLE_FEATURE_MDEV_CONF) {
-		char *conf, *pos, *end;
-
-		/* mmap the config file */
-		if (-1 != (fd=open(MDEV_CONF,O_RDONLY))) {
-			len = lseek(fd, 0, SEEK_END);
-			conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
-			if (conf) {
-				int line = 0;
-
-				/* Loop through lines in mmaped file*/
-				for (pos=conf; pos-conf<len;) {
-					int field;
-					char *end2;
-
-					line++;
-					/* find end of this line */
-					for(end=pos; end-conf<len && *end!='\n'; end++)
-						;
-
-					/* Three fields: regex, uid:gid, mode */
-					for (field=3; field; field--) {
-						/* Skip whitespace */
-						while (pos<end && isspace(*pos))
-							pos++;
-						if (pos==end || *pos=='#')
-							break;
-						for (end2=pos; end2<end && !isspace(*end2) && *end2!='#'; end2++)
-							;
-
-						switch (field) {
-							/* Regex to match this device */
-							case 3:
-							{
-								char *regex = strndupa(pos,end2-pos);
-								regex_t match;
-								regmatch_t off;
-								int result;
-
-								/* Is this it? */
-								xregcomp(&match,regex,REG_EXTENDED);
-								result = regexec(&match,device_name,1,&off,0);
-								regfree(&match);
-
-								/* If not this device, skip rest of line */
-								if (result || off.rm_so || off.rm_eo!=strlen(device_name))
-									goto end_line;
-
-								break;
-							}
-							/* uid:gid */
-							case 2:
-							{
-								char *s2;
-
-								/* Find : */
-								for(s=pos; s<end2 && *s!=':'; s++)
-									;
-								if (s == end2)
-									goto end_line;
-
-								/* Parse UID */
-								uid = strtoul(pos,&s2,10);
-								if (s != s2) {
-									struct passwd *pass;
-									pass = getpwnam(strndupa(pos,s-pos));
-									if (!pass)
-										goto end_line;
-									uid = pass->pw_uid;
-								}
-								s++;
-								/* parse GID */
-								gid = strtoul(s,&s2,10);
-								if (end2 != s2) {
-									struct group *grp;
-									grp = getgrnam(strndupa(s,end2-s));
-									if (!grp)
-										goto end_line;
-									gid = grp->gr_gid;
-								}
-								break;
-							}
-							/* mode */
-							case 1:
-							{
-								mode = strtoul(pos,&pos,8);
-								if (pos != end2)
-									goto end_line;
-								else
-									goto found_device;
-							}
-						}
-						pos = end2;
-					}
-end_line:
-					/* Did everything parse happily? */
-					if (field && field!=3)
-						bb_error_msg_and_die("Bad line %d",line);
-
-					/* Next line */
-					pos = ++end;
-				}
-found_device:
-				munmap(conf, len);
-			}
-			close(fd);
-		}
-	}
-
 	umask(0);
 	if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST)
 		bb_perror_msg_and_die("mknod %s failed", device_name);
@@ -177,8 +206,30 @@
 		symlink(device_name, "root");
 	
 	if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);
+
+	if (ENABLE_FEATURE_MDEV_EXEC)
+	  if (command && system(command) == -1) {
+	    free(command);
+	    bb_perror_msg_and_die("could not exec '%s'", command);
+	  }
 }
 
+/* remove device nodes */
+static void remove_device(char *path)
+{
+  if (access(path, F_OK)) return;
+
+  if (ENABLE_FEATURE_MDEV_CONF) get_device_config(path);
+
+  if (ENABLE_FEATURE_MDEV_EXEC)
+    if (command && system(command) == -1) {
+      free(command);
+      bb_perror_msg_and_die("could not exec '%s'", command);
+    }
+
+  unlink(path);
+}
+
 /* Recursive search of /sys/block or /sys/class.  path must be a writeable
  * buffer of size PATH_MAX containing the directory string to start at. */
 
@@ -245,7 +296,7 @@
 			sprintf(temp, "/sys%s", env_path);
 			make_device(temp);
 		} else if (!strcmp(action, "remove")) {
-			unlink(strrchr(env_path, '/') + 1);
+			remove_device(strrchr(env_path, '/') + 1);
 		}
 	}
 




More information about the busybox mailing list