commit 733f60dba2b8c878945b856c23a6bc44de52fc11
Author: sin <sin@2f30.org>
Date: Tue, 20 Aug 2013 13:26:10 +0100
Initial commit
Diffstat:
A | LICENSE | | | 21 | +++++++++++++++++++++ |
A | Makefile | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | arg.h | | | 55 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | config.h | | | 26 | ++++++++++++++++++++++++++ |
A | config.mk | | | 12 | ++++++++++++ |
A | smdev.c | | | 209 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | util.h | | | 13 | +++++++++++++ |
A | util/agetcwd.c | | | 18 | ++++++++++++++++++ |
A | util/apathmax.c | | | 25 | +++++++++++++++++++++++++ |
A | util/eprintf.c | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | util/estrtol.c | | | 27 | +++++++++++++++++++++++++++ |
A | util/recurse.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
12 files changed, 551 insertions(+), 0 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,21 @@
+MIT/X Consortium License
+
+© 2013 sin <sin@2f30.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,59 @@
+include config.mk
+
+.POSIX:
+.SUFFIXES: .c .o
+
+LIB = \
+ util/agetcwd.o \
+ util/apathmax.o \
+ util/eprintf.o \
+ util/estrtol.o \
+ util/recurse.o
+
+SRC = smdev.c
+
+OBJ = $(SRC:.c=.o) $(LIB)
+BIN = $(SRC:.c=)
+MAN = $(SRC:.c=.1)
+
+all: options binlib
+
+options:
+ @echo mdev build options:
+ @echo "CFLAGS = $(CFLAGS)"
+ @echo "LDFLAGS = $(LDFLAGS)"
+ @echo "CC = $(CC)"
+
+binlib: util.a
+ $(MAKE) bin
+
+bin: $(BIN)
+
+$(OBJ): util.h config.mk
+
+.o:
+ @echo LD $@
+ @$(LD) -o $@ $< util.a $(LDFLAGS)
+
+.c.o:
+ @echo CC $<
+ @$(CC) -c -o $@ $< $(CFLAGS)
+
+util.a: $(LIB)
+ @echo AR $@
+ @$(AR) -r -c $@ $(LIB)
+ @ranlib $@
+
+install: all
+ @echo installing executable to $(DESTDIR)$(PREFIX)/sbin
+ @mkdir -p $(DESTDIR)$(PREFIX)/sbin
+ @cp -f $(BIN) $(DESTDIR)$(PREFIX)/sbin
+ @cd $(DESTDIR)$(PREFIX)/sbin && chmod 755 $(BIN)
+
+uninstall:
+ @echo removing executable from $(DESTDIR)$(PREFIX)/sbin
+ @cd $(DESTDIR)$(PREFIX)/sbin && rm -f $(BIN)
+
+clean:
+ @echo cleaning
+ @rm -f $(BIN) $(OBJ) $(LIB) util.a
diff --git a/arg.h b/arg.h
@@ -0,0 +1,55 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef __ARG_H__
+#define __ARG_H__
+
+extern char *argv0;
+
+#define USED(x) ((void)(x))
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][1]\
+ && argv[0][0] == '-';\
+ argc--, argv++) {\
+ char _argc;\
+ char **_argv;\
+ int brk;\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk = 0, argv[0]++, _argv = argv;\
+ argv[0][0] && !brk;\
+ argv[0]++) {\
+ if (_argv != argv)\
+ break;\
+ _argc = argv[0][0];\
+ switch (_argc)
+
+#define ARGEND }\
+ USED(_argc);\
+ }\
+ USED(argv);\
+ USED(argc);
+
+#define ARGC() _argc
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ (char *)0 :\
+ (brk = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#endif
+
diff --git a/config.h b/config.h
@@ -0,0 +1,26 @@
+/* See LICENSE file for copyright and license details. */
+struct {
+ const char *devregex;
+ const char *user;
+ const char *group;
+ int mode;
+ const char *path;
+ const char *cmd;
+} Rules[] = {
+ { "null", "root", "root", 0666, NULL, "@chmod 666 $SMDEV" },
+ { "zero", "root", "root", 0666, NULL, NULL },
+ { "full", "root", "root", 0666, NULL, NULL },
+ { "random", "root", "root", 0666, NULL, NULL },
+ { "urandom", "root", "root", 0666, NULL, NULL },
+ { "mem", "root", "root", 0640, NULL, NULL },
+ { "kmem", "root", "root", 0640, NULL, NULL },
+ { "console", "root", "tty", 0600, NULL, "@chmod 600 $SMDEV" },
+ { "ptmx", "root", "tty", 0666, NULL, NULL },
+ { "pty.*", "root", "tty", 0660, NULL, NULL },
+ { "tty", "root", "tty", 0666, NULL, NULL },
+ { "tty[0-9]*", "root", "tty", 0660, NULL, NULL },
+ { "vcsa*[0-9]*","root", "tty", 0660, NULL, NULL },
+ { "sd[a-z].*", "root", "disk", 0660, NULL, NULL },
+ { "sr[0-9]*", "root", "cdrom", 0660, NULL, "@ln -sf $SMDEV cdrom" },
+ { ".*", "root", "root", 0777, NULL, NULL },
+};
diff --git a/config.mk b/config.mk
@@ -0,0 +1,12 @@
+# smdev version
+VERSION = 0.0
+
+# paths
+PREFIX = /usr/local
+
+#CC = gcc
+#CC = musl-gcc
+LD = $(CC)
+CPPFLAGS = -D_BSD_SOURCE -D_GNU_SOURCE
+CFLAGS = -g -ansi -Wall $(CPPFLAGS)
+LDFLAGS = -g
diff --git a/smdev.c b/smdev.c
@@ -0,0 +1,209 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <regex.h>
+#include "config.h"
+#include "util.h"
+
+static int devtomajmin(const char *path, int *maj, int *min);
+static int devtype(const char *majmin);
+static int create_dev(const char *path);
+static void sysrecurse(const char *path);
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-s]\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int sflag = 0;
+
+ ARGBEGIN {
+ case 's':
+ sflag = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!sflag)
+ usage();
+
+ recurse("/sys/devices", sysrecurse);
+
+ return 0;
+}
+
+/* Example `path' is /sys/devices/virtual/tty/tty0/dev */
+static int
+devtomajmin(const char *path, int *maj, int *min)
+{
+ char buf[BUFSIZ];
+ int fd;
+ ssize_t n;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ eprintf("open %s:", path);
+ n = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (n < 0)
+ eprintf("%s: read error:", path);
+ if (!n)
+ return -1;
+ if (buf[n - 1] == '\n')
+ buf[n - 1] = '\0';
+ buf[n] = '\0';
+ sscanf(buf, "%d:%d", maj, min);
+ return 0;
+}
+
+static int
+devtype(const char *majmin)
+{
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "/sys/dev/block/%s", majmin);
+ if (!access(path, F_OK))
+ return S_IFBLK;
+ snprintf(path, sizeof(path), "/sys/dev/char/%s", majmin);
+ if (!access(path, F_OK))
+ return S_IFCHR;
+ return -1;
+}
+
+static int
+create_dev(const char *path)
+{
+ struct passwd *pw;
+ struct group *gr;
+ regex_t match;
+ regmatch_t off;
+ char *regex;
+ char buf[64], *p;
+ char tmppath[PATH_MAX], devpath[PATH_MAX], *dev;
+ char *devname;
+ int maj, min, type;
+ int i, ret;
+
+ p = strrchr(path, '/');
+ if (!p)
+ return -1;
+ p++;
+ devname = strdup(p);
+ if (!devname)
+ eprintf("strdup:");
+ snprintf(devpath, sizeof(devpath), "/dev/%s", devname);
+
+ snprintf(tmppath, sizeof(tmppath), "%s/dev", path);
+ ret = devtomajmin(tmppath, &maj, &min);
+ if (ret < 0) {
+ free(devname);
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf), "%d:%d", maj, min);
+ type = devtype(buf);
+ if (type < 0) {
+ free(devname);
+ return -1;
+ }
+
+ for (i = 0; i < LEN(Rules); i++) {
+ regex = strdup(Rules[i].devregex);
+ if (!regex)
+ eprintf("strdup:");
+
+ ret = regcomp(&match, regex, REG_EXTENDED);
+ if (ret < 0)
+ eprintf("regcomp:");
+
+ ret = regexec(&match, devname, 1, &off, 0);
+ regfree(&match);
+ free(regex);
+
+ if (ret || off.rm_so || off.rm_eo != strlen(devname))
+ continue;
+
+ if (Rules[i].cmd) {
+ switch (Rules[i].cmd[0]) {
+ case '@':
+ case '$':
+ case '*':
+ fprintf(stderr, "Unsupported command '%s' for target '%s'\n",
+ Rules[i].cmd, Rules[i].devregex);
+ break;
+ default:
+ eprintf("Invalid command '%s'\n", Rules[i].cmd);
+ }
+ }
+
+ dev = devpath;
+ if (Rules[i].path) {
+ switch (Rules[i].path[0]) {
+ case '=':
+ if (Rules[i].path[strlen(Rules[i].path) - 1] == '/') {
+ snprintf(devpath, sizeof(devpath), "/dev/%s", &Rules[i].path[1]);
+ if (mkdir(devpath, 0755) < 0)
+ eprintf("mkdir %s:", devpath);
+ strcat(devpath, devname);
+ } else {
+ snprintf(devpath, sizeof(devpath),
+ "/dev/%s", &Rules[i].path[1]);
+ }
+ break;
+ case '>':
+ fprintf(stderr, "Unsupported path '%s' for target '%s'\n",
+ Rules[i].path, Rules[i].devregex);
+ break;
+ default:
+ eprintf("Invalid path '%s'\n", Rules[i].path);
+ }
+ }
+
+ ret = mknod(dev, Rules[i].mode | type, makedev(maj, min));
+ if (ret < 0 && errno != EEXIST)
+ eprintf("mknod %s:", dev);
+
+ pw = getpwnam(Rules[i].user);
+ if (!pw)
+ eprintf("getpwnam %s:", Rules[i].user);
+
+ gr = getgrnam(Rules[i].group);
+ if (!gr)
+ eprintf("getgrnam %s:", Rules[i].group);
+
+ ret = chown(dev, pw->pw_uid, gr->gr_gid);
+ if (ret < 0)
+ eprintf("chown %s:", dev);
+ break;
+ }
+
+ free(devname);
+ return 0;
+}
+
+static void
+sysrecurse(const char *path)
+{
+ char *cwd;
+
+ recurse(path, sysrecurse);
+ if (!strcmp(path, "dev")) {
+ cwd = agetcwd();
+ create_dev(cwd);
+ free(cwd);
+ }
+}
diff --git a/util.h b/util.h
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "arg.h"
+
+#define LEN(x) (sizeof (x) / sizeof *(x))
+
+extern char *argv0;
+
+char *agetcwd(void);
+void apathmax(char **, long *);
+void enprintf(int, const char *, ...);
+void eprintf(const char *, ...);
+long estrtol(const char *, int);
+void recurse(const char *, void (*)(const char *));
diff --git a/util/agetcwd.c b/util/agetcwd.c
@@ -0,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+#include <unistd.h>
+
+#include "../util.h"
+
+char *
+agetcwd(void)
+{
+ char *buf;
+ long size;
+
+ apathmax(&buf, &size);
+ if(!getcwd(buf, size))
+ eprintf("getcwd:");
+
+ return buf;
+}
+
diff --git a/util/apathmax.c b/util/apathmax.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "../util.h"
+
+void
+apathmax(char **p, long *size)
+{
+ errno = 0;
+
+ if((*size = pathconf("/", _PC_PATH_MAX)) == -1) {
+ if(errno == 0) {
+ *size = BUFSIZ;
+ } else {
+ eprintf("pathconf:");
+ }
+ }
+
+ if(!(*p = malloc(*size)))
+ eprintf("malloc:");
+}
+
diff --git a/util/eprintf.c b/util/eprintf.c
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../util.h"
+
+char *argv0;
+
+static void venprintf(int, const char *, va_list);
+
+void
+eprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ venprintf(EXIT_FAILURE, fmt, ap);
+ va_end(ap);
+}
+
+void
+enprintf(int status, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ venprintf(status, fmt, ap);
+ va_end(ap);
+}
+
+void
+venprintf(int status, const char *fmt, va_list ap)
+{
+ /*fprintf(stderr, "%s: ", argv0);*/
+
+ vfprintf(stderr, fmt, ap);
+
+ if(fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ }
+
+ exit(status);
+}
diff --git a/util/estrtol.c b/util/estrtol.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../util.h"
+
+long
+estrtol(const char *s, int base)
+{
+ char *end;
+ long n;
+
+ errno = 0;
+ n = strtol(s, &end, base);
+ if(*end != '\0') {
+ if(base == 0)
+ eprintf("%s: not an integer\n", s);
+ else
+ eprintf("%s: not a base %d integer\n", s, base);
+ }
+ if(errno != 0)
+ eprintf("%s:", s);
+
+ return n;
+}
+
diff --git a/util/recurse.c b/util/recurse.c
@@ -0,0 +1,40 @@
+/* See LICENSE file for copyright and license details. */
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "../util.h"
+
+void
+recurse(const char *path, void (*fn)(const char *))
+{
+ char *cwd;
+ struct dirent *d;
+ struct stat st;
+ DIR *dp;
+
+ if(lstat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
+ return;
+ } else if(!(dp = opendir(path))) {
+ eprintf("opendir %s:", path);
+ }
+
+ cwd = agetcwd();
+ if(chdir(path) == -1)
+ eprintf("chdir %s:", path);
+
+ while((d = readdir(dp))) {
+ if(strcmp(d->d_name, ".") && strcmp(d->d_name, ".."))
+ fn(d->d_name);
+ }
+
+ closedir(dp);
+ if(chdir(cwd) == -1)
+ eprintf("chdir %s:", cwd);
+
+ free(cwd);
+}
+