Initial commit - smdev - suckless mdev
 (HTM) git clone git://git.suckless.org/smdev
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 733f60dba2b8c878945b856c23a6bc44de52fc11
 (HTM) 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(-)
       ---
 (DIR) 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.
 (DIR) 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
 (DIR) 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
       +
 (DIR) 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                   },
       +};
 (DIR) 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
 (DIR) 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);
       +        }
       +}
 (DIR) 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 *));
 (DIR) 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;
       +}
       +
 (DIR) 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:");
       +}
       +
 (DIR) 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);
       +}
 (DIR) 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;
       +}
       +
 (DIR) 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);
       +}
       +