Introduce struct Event and add primitive hotplugging support - smdev - suckless… | |
git clone git://git.suckless.org/smdev | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit cf0ac2f526b5e82d94a1cd02428ebd8bfb5cb00b | |
parent 18552e102e3d739d8c03379716b8acbc9ddbc8f7 | |
Author: sin <[email protected]> | |
Date: Thu, 22 Aug 2013 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: | |
M config.h | 10 +++++----- | |
M 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->p… | |
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", … | |
} | |
} | |
/* 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], dev… | |
- 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); | |
} | |
} |