Added /etc/mdev.conf support. Adds about 1.9k to mdev.
authorRob Landley <rob@landley.net>
Sat, 17 Dec 2005 10:52:30 +0000 (10:52 -0000)
committerRob Landley <rob@landley.net>
Sat, 17 Dec 2005 10:52:30 +0000 (10:52 -0000)
util-linux/Config.in
util-linux/mdev.c

index 5ab54e038f22aeda118a2a7a10de26dd13e346c9..bf3e13b2af1a765e75d220ef293d7ada1cfe86b2 100644 (file)
@@ -254,7 +254,7 @@ config CONFIG_MDEV
          have it handle hotplug events afterwards.  Device names are taken
          from sysfs.
 
-config CONFIG_FEATURE_MDEV_CONFIG
+config CONFIG_FEATURE_MDEV_CONF
        bool "  Support /etc/mdev.conf"
        default n
        depends on CONFIG_MDEV
index 49904d17aa724d4c916457deda8b900670b630dc..688100c3ac20b9436a0259283d76fe691cc299b0 100644 (file)
@@ -8,25 +8,31 @@
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
 
+#include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include "busybox.h"
+#include "xregex.h"
 
-#define DEV_PATH       "/dev"
-#define DEV_MODE       0660
+#define DEV_PATH       "/tmp/dev"
 
 #include <busybox.h>
 
 /* mknod in /dev based on a path like "/sys/block/hda/hda1" */
-void make_device(char *path)
+static void make_device(char *path)
 {
-       char *device_name, *s;
+       char *device_name,*s;
        int major,minor,type,len,fd;
+       int mode=0660;
+       uid_t uid=0;
+       gid_t gid=0;
 
        RESERVE_CONFIG_BUFFER(temp,PATH_MAX);
 
@@ -44,8 +50,8 @@ void make_device(char *path)
        device_name = strrchr(path, '/') + 1;
        type = strncmp(path+5, "block/" ,6) ? S_IFCHR : S_IFBLK;
        major = minor = 0;
-       for(s = temp; *s; s++) {
-               if(*s == ':') {
+       for (s = temp; *s; s++) {
+               if (*s == ':') {
                        major = minor;
                        minor = 0;
                } else {
@@ -54,14 +60,115 @@ void make_device(char *path)
                }
        }
 
-/* Open config file here, look up permissions */       
+       /* If we have a config file, look up permissions for this device */
+       
+       if (ENABLE_FEATURE_MDEV_CONF) {
+               char *conf,*pos,*end;
+
+               /* mmap the config file */
+               if (-1!=(fd=open("/etc/mdev.conf",O_RDONLY))) {
+                       len=lseek(fd,0,SEEK_END);
+                       conf=mmap(NULL,len,PROT_READ,MAP_SHARED,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;
+                                                               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);
+               }
+       }
 
        sprintf(temp, "%s/%s", DEV_PATH, device_name);
-       if(mknod(temp, DEV_MODE | type, makedev(major, minor)) && errno != EEXIST)
+       umask(0);
+       if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
                bb_perror_msg_and_die("mknod %s failed", temp);
-       
-/* Perform shellout here */
 
+       if (ENABLE_FEATURE_MDEV_CONF) chown(temp,uid,gid);
+       
 end:
        RELEASE_CONFIG_BUFFER(temp);
 }
@@ -69,18 +176,18 @@ end:
 /* 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. */
 
-void find_dev(char *path)
+static void find_dev(char *path)
 {
        DIR *dir;
        int len=strlen(path);
 
-       if(!(dir = opendir(path)))
+       if (!(dir = opendir(path)))
                bb_perror_msg_and_die("No %s",path);
 
-       for(;;) {
+       for (;;) {
                struct dirent *entry = readdir(dir);
                
-               if(!entry) break;
+               if (!entry) break;
 
                /* Skip "." and ".." (also skips hidden files, which is ok) */
 
@@ -103,7 +210,7 @@ void find_dev(char *path)
 int mdev_main(int argc, char *argv[])
 {
        if (argc > 1) {
-               if(argc == 2 && !strcmp(argv[1],"-s")) {
+               if (argc == 2 && !strcmp(argv[1],"-s")) {
                        RESERVE_CONFIG_BUFFER(temp,PATH_MAX);
                        strcpy(temp,"/sys/block");
                        find_dev(temp);