smdev

suckless mdev
git clone git://git.2f30.org/smdev.git
Log | Files | Refs | README | LICENSE

commit cf0ac2f526b5e82d94a1cd02428ebd8bfb5cb00b
parent 18552e102e3d739d8c03379716b8acbc9ddbc8f7
Author: sin <sin@2f30.org>
Date:   Thu Aug 22 10:45:24 +0100

Introduce struct Event and add primitive hotplugging support

This unifies the way we handle hotplug events versus static
population of the /dev directory.  We also remove the assumption
for createdev() to only work correctly if the current directory
is set to the corresponding sysfs entry.

Diffstat:
config.h | 10+++++-----
smdev.c | 144++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
2 files changed, 97 insertions(+), 57 deletions(-)
diff --git a/config.h b/config.h @@ -1,11 +1,11 @@ /* See LICENSE file for copyright and license details. */ struct Rule { - const char *devregex; - const char *user; - const char *group; + char *devregex; + char *user; + char *group; int mode; - const char *path; - const char *cmd; + char *path; + char *cmd; } Rules[] = { { "null", "root", "root", 0666, NULL, "@chmod 666 $SMDEV" }, { "zero", "root", "root", 0666, NULL, NULL }, diff --git a/smdev.c b/smdev.c @@ -15,9 +15,18 @@ #include "mkpath.h" #include "util.h" -static int matchrule(const struct Rule *Rule, const char *devname); -static int create_dev(const char *path); -static void sysrecurse(const char *path); +struct Event { + int min; + int maj; + char *action; + char *devpath; + char *devname; +}; + +static int dohotplug(void); +static int matchrule(struct Rule *Rule, char *devname); +static int createdev(struct Event *ev); +static void populatedev(const char *path); static void usage(void) @@ -38,17 +47,43 @@ main(int argc, char *argv[]) usage(); } ARGEND; - if (!sflag) - usage(); - umask(0); - recurse("/sys/devices", sysrecurse); + if (sflag) + recurse("/sys/devices", populatedev); + else + if (dohotplug() < 0) + return 1; + return 0; +} + +static int +dohotplug(void) +{ + char *min, *maj; + struct Event ev; + + min = getenv("MINOR"); + maj = getenv("MAJOR"); + ev.action = getenv("ACTION"); + ev.devpath = getenv("DEVPATH"); + ev.devname = getenv("DEVNAME"); + if (!min || !maj || !ev.action || !ev.devpath || + !ev.devname) + return -1; + + ev.min = estrtol(min, 10); + ev.maj = estrtol(maj, 10); + + if (!strcmp(ev.action, "add")) + return createdev(&ev); + else + eprintf("Unsupported action '%s'\n", ev.action); return 0; } static int -matchrule(const struct Rule *Rule, const char *devname) +matchrule(struct Rule *Rule, char *devname) { regex_t match; regmatch_t off; @@ -67,37 +102,23 @@ matchrule(const struct Rule *Rule, const char *devname) } static int -create_dev(const char *path) +createdev(struct Event *ev) { struct Rule *Rule; struct passwd *pw; struct group *gr; - char buf[BUFSIZ], *p; - const char *devname; - char origdevname[PATH_MAX]; - int maj, min, type; - int i, ret; - - p = strrchr(path, '/'); - if (!p) - return -1; - p++; - devname = p; - snprintf(origdevname, sizeof(origdevname), "/dev/%s", devname); + char devpath[PATH_MAX], *devname; + char buf[BUFSIZ]; + int type; + int i; - snprintf(buf, sizeof(buf), "%s/dev", path); - ret = devtomajmin(buf, &maj, &min); - if (ret < 0) - return -1; - - snprintf(buf, sizeof(buf), "%d:%d", maj, min); + snprintf(buf, sizeof(buf), "%d:%d", ev->maj, ev->min); type = devtype(buf); if (type < 0) return -1; - if (chdir("/dev") < 0) - eprintf("chdir /dev:"); - + devname = ev->devname; + snprintf(devpath, sizeof(devpath), "/dev/%s", devname); for (i = 0; i < LEN(Rules); i++) { Rule = &Rules[i]; @@ -108,40 +129,53 @@ create_dev(const char *path) if (Rule->path[0] != '=' && Rule->path[0] != '>') eprintf("Invalid path '%s'\n", Rule->path); if (Rule->path[strlen(Rule->path) - 1] == '/') { + snprintf(buf, sizeof(buf), "/dev/%s", &Rule->path[1]); umask(022); - if (mkpath(&Rule->path[1], 0755) < 0) - eprintf("mkdir %s:", &Rule->path[1]); + if (mkpath(buf, 0755) < 0) + eprintf("mkdir %s:", buf); umask(0); - if (chdir(&Rule->path[1]) < 0) - eprintf("chdir %s:", &Rule->path[1]); + snprintf(devpath, sizeof(devpath), "/dev/%s%s", + &Rule->path[1], devname); } else { devname = &Rule->path[1]; + snprintf(devpath, sizeof(devpath), "/dev/%s", devname); } } /* Create the actual dev nodes */ - ret = mknod(devname, Rules[i].mode | type, makedev(maj, min)); - if (ret < 0 && errno != EEXIST) - eprintf("mknod %s:", devname); + if (mknod(devpath, Rules[i].mode | type, + makedev(ev->maj, ev->min)) < 0 && + errno != EEXIST) + eprintf("mknod %s:", devpath); + + errno = 0; pw = getpwnam(Rules[i].user); - if (!pw) + if (errno) eprintf("getpwnam %s:", Rules[i].user); + else if (!pw) + enprintf(1, "getpwnam %s: no such user\n", + Rules[i].user); + + errno = 0; gr = getgrnam(Rules[i].group); - if (!gr) + if (errno) eprintf("getgrnam %s:", Rules[i].group); - ret = chown(devname, pw->pw_uid, gr->gr_gid); - if (ret < 0) - eprintf("chown %s:", devname); + else if (!gr) + enprintf(1, "getgrnam %s: no such group\n", + Rules[i].group); + + if (chown(devpath, pw->pw_uid, gr->gr_gid) < 0) + eprintf("chown %s:", devpath); /* Create symlinks */ if (Rule->path && Rule->path[0] == '>') { - snprintf(buf, sizeof(buf), "%s%s", &Rule->path[1], devname); - if (symlink(buf, origdevname)) + snprintf(buf, sizeof(buf), "/dev/%s", ev->devname); + if (symlink(devpath, buf)) eprintf("symlink %s -> %s:", - origdevname, buf); + ev->devname, devpath); } - snprintf(buf, sizeof(buf), "SMDEV=%s", devname); + snprintf(buf, sizeof(buf), "SMDEV=%s", devpath); if (putenv(buf) < 0) eprintf("putenv:"); @@ -162,21 +196,27 @@ create_dev(const char *path) break; } - if (chdir(path) < 0) - eprintf("chdir %s:", path); - return 0; } static void -sysrecurse(const char *path) +populatedev(const char *path) { + char tmppath[PATH_MAX]; char *cwd; + struct Event ev; - recurse(path, sysrecurse); + recurse(path, populatedev); if (!strcmp(path, "dev")) { cwd = agetcwd(); - create_dev(cwd); + ev.action = "add"; + ev.devpath = cwd + strlen("/sys"); + ev.devname = basename(cwd); + snprintf(tmppath, sizeof(tmppath), "/sys%s/dev", + ev.devpath); + if (devtomajmin(tmppath, &ev.maj, &ev.min) < 0) + return; + createdev(&ev); free(cwd); } }