aboutsummaryrefslogtreecommitdiff
path: root/toys/other/mdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/other/mdev.c')
-rw-r--r--toys/other/mdev.c346
1 files changed, 172 insertions, 174 deletions
diff --git a/toys/other/mdev.c b/toys/other/mdev.c
index 6d030d14..b89ac2ca 100644
--- a/toys/other/mdev.c
+++ b/toys/other/mdev.c
@@ -1,6 +1,4 @@
-/* vi:set ts=4:
- *
- * mdev.c - Populate /dev directory and handle hotplug events
+/* mdev.c - Populate /dev directory and handle hotplug events
*
* Copyright 2005, 2008 Rob Landley <rob@landley.net>
* Copyright 2005 Frank Sorenson <frank@tuxrocks.com>
@@ -8,27 +6,27 @@
USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
config MDEV
- bool "mdev"
- default n
- help
- usage: mdev [-s]
+ bool "mdev"
+ default n
+ help
+ usage: mdev [-s]
- Create devices in /dev using information from /sys.
+ Create devices in /dev using information from /sys.
- -s Scan all entries in /sys to populate /dev.
+ -s Scan all entries in /sys to populate /dev.
config MDEV_CONF
- bool "Configuration file for mdev"
- default y
- depends on MDEV
- help
- The mdev config file (/etc/mdev.conf) contains lines that look like:
- hd[a-z][0-9]* 0:3 660
-
- Each line must contain three whitespace separated fields. The first
- field is a regular expression matching one or more device names, and
- the second and third fields are uid:gid and file permissions for
- matching devies.
+ bool "Configuration file for mdev"
+ default y
+ depends on MDEV
+ help
+ The mdev config file (/etc/mdev.conf) contains lines that look like:
+ hd[a-z][0-9]* 0:3 660
+
+ Each line must contain three whitespace separated fields. The first
+ field is a regular expression matching one or more device names, and
+ the second and third fields are uid:gid and file permissions for
+ matching devies.
*/
#include "toys.h"
@@ -39,173 +37,173 @@ config MDEV_CONF
// mknod in /dev based on a path like "/sys/block/hda/hda1"
static void make_device(char *path)
{
- char *device_name, *s, *temp;
- int major, minor, type, len, fd;
- int mode = 0660;
- uid_t uid = 0;
- gid_t gid = 0;
-
- // Try to read major/minor string
-
- temp = strrchr(path, '/');
- fd = open(path, O_RDONLY);
- *temp=0;
- temp = toybuf;
- len = read(fd, temp, 64);
- close(fd);
- if (len<1) return;
- temp[len] = 0;
-
- // Determine device name, type, major and minor
-
- device_name = strrchr(path, '/') + 1;
- type = path[5]=='c' ? S_IFCHR : S_IFBLK;
- major = minor = 0;
- sscanf(temp, "%u:%u", &major, &minor);
-
- // If we have a config file, look up permissions for this device
-
- if (CFG_MDEV_CONF) {
- char *conf, *pos, *end;
-
- // mmap the config file
- if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) {
- len = fdlength(fd);
- 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 = strndup(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);
- free(regex);
-
- // 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;
- char *str = strndup(pos, s-pos);
- pass = getpwnam(str);
- free(str);
- if (!pass) goto end_line;
- uid = pass->pw_uid;
- }
- s++;
- // parse GID
- gid = strtoul(s,&s2,10);
- if (end2!=s2) {
- struct group *grp;
- char *str = strndup(s, end2-s);
- grp = getgrnam(str);
- free(str);
- 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;
- }
+ char *device_name, *s, *temp;
+ int major, minor, type, len, fd;
+ int mode = 0660;
+ uid_t uid = 0;
+ gid_t gid = 0;
+
+ // Try to read major/minor string
+
+ temp = strrchr(path, '/');
+ fd = open(path, O_RDONLY);
+ *temp=0;
+ temp = toybuf;
+ len = read(fd, temp, 64);
+ close(fd);
+ if (len<1) return;
+ temp[len] = 0;
+
+ // Determine device name, type, major and minor
+
+ device_name = strrchr(path, '/') + 1;
+ type = path[5]=='c' ? S_IFCHR : S_IFBLK;
+ major = minor = 0;
+ sscanf(temp, "%u:%u", &major, &minor);
+
+ // If we have a config file, look up permissions for this device
+
+ if (CFG_MDEV_CONF) {
+ char *conf, *pos, *end;
+
+ // mmap the config file
+ if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) {
+ len = fdlength(fd);
+ 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 = strndup(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);
+ free(regex);
+
+ // 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;
+ char *str = strndup(pos, s-pos);
+ pass = getpwnam(str);
+ free(str);
+ if (!pass) goto end_line;
+ uid = pass->pw_uid;
+ }
+ s++;
+ // parse GID
+ gid = strtoul(s,&s2,10);
+ if (end2!=s2) {
+ struct group *grp;
+ char *str = strndup(s, end2-s);
+ grp = getgrnam(str);
+ free(str);
+ 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) error_exit("Bad line %d", line);
+ // Did everything parse happily?
+ if (field && field!=3) error_exit("Bad line %d", line);
- // Next line
- pos = ++end;
- }
+ // Next line
+ pos = ++end;
+ }
found_device:
- munmap(conf, len);
- }
- close(fd);
- }
- }
+ munmap(conf, len);
+ }
+ close(fd);
+ }
+ }
- sprintf(temp, "/dev/%s", device_name);
- if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
- perror_exit("mknod %s failed", temp);
+ sprintf(temp, "/dev/%s", device_name);
+ if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
+ perror_exit("mknod %s failed", temp);
- if (CFG_MDEV_CONF) mode=chown(temp, uid, gid);
+ if (CFG_MDEV_CONF) mode=chown(temp, uid, gid);
}
static int callback(struct dirtree *node)
{
- // Entries in /sys/class/block aren't char devices, so skip 'em. (We'll
- // get block devices out of /sys/block.)
- if(!strcmp(node->name, "block")) return 0;
-
- // Does this directory have a "dev" entry in it?
- // This is path based because the hotplug callbacks are
- if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) {
- int len=4;
- char *dev = dirtree_path(node, &len);
- strcpy(dev+len, "/dev");
- if (!access(dev, R_OK)) make_device(dev);
- free(dev);
- }
-
- // Circa 2.6.25 the entries more than 2 deep are all either redundant
- // (mouse#, event#) or unnamed (every usb_* entry is called "device").
-
- return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE;
+ // Entries in /sys/class/block aren't char devices, so skip 'em. (We'll
+ // get block devices out of /sys/block.)
+ if(!strcmp(node->name, "block")) return 0;
+
+ // Does this directory have a "dev" entry in it?
+ // This is path based because the hotplug callbacks are
+ if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) {
+ int len=4;
+ char *dev = dirtree_path(node, &len);
+ strcpy(dev+len, "/dev");
+ if (!access(dev, R_OK)) make_device(dev);
+ free(dev);
+ }
+
+ // Circa 2.6.25 the entries more than 2 deep are all either redundant
+ // (mouse#, event#) or unnamed (every usb_* entry is called "device").
+
+ return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE;
}
void mdev_main(void)
{
- // Handle -s
+ // Handle -s
- if (toys.optflags) {
- dirtree_read("/sys/class", callback);
- dirtree_read("/sys/block", callback);
- }
+ if (toys.optflags) {
+ dirtree_read("/sys/class", callback);
+ dirtree_read("/sys/block", callback);
+ }
- // hotplug support goes here
+ // hotplug support goes here
}