Removing udev, fixing arg.h and fixing the scripts. - rfkilld - An rfkill daemon, which runs scripts according to rfkill events.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit 361feba39eb798d0d3c1c037a4b77d4d8fbadf9e
 (DIR) parent 8e7750e0150e3975826c7922043193fdca882dd0
 (HTM) Author: Christoph Lohmann <20h@r-36.net>
       Date:   Wed,  2 May 2012 21:20:50 +0200
       
       Removing udev, fixing arg.h and fixing the scripts.
       
       Diffstat:
         arg.h                               |      42 +++++++++++++++++++++++--------
         config.mk                           |      10 +++++-----
         etc/rfkilld/bluetooth.sh            |       2 +-
         etc/rfkilld/wlan.sh                 |       2 +-
         etc/rfkilld/wwan.sh                 |       4 ++--
         rfkilld.c                           |     286 ++++++++++++++++++++++---------
       
       6 files changed, 246 insertions(+), 100 deletions(-)
       ---
 (DIR) diff --git a/arg.h b/arg.h
       @@ -1,18 +1,40 @@
       -#ifndef ARG_H
       -#define ARG_H
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
        
       -#define USED(x) ((void)(x))
       +#ifndef __ARG_H__
       +#define __ARG_H__
        
        extern char *argv0;
        
       -#define        ARGBEGIN        for(argv0 = *argv, argv++, argc--;\
       -                            argv[0] && argv[0][0]=='-' && argv[0][1];\
       -                            argc--, argv++) {\
       +#define USED(x) ((void)(x))
       +
       +#define ARGBEGIN        for (argv0 = *argv, argv++, argc--;\
       +                                        argv[0] && argv[0][1]\
       +                                        && argv[0][0] == '-';\
       +                                        argc--, argv++) {\
                                        char _argc;\
       -                                _argc = argv[0][1];\
       -                                switch(_argc)
       -#define        ARGEND                USED(_argc);} USED(argv);USED(argc);
       -#define        EARGF(x)        ((argv[1] == NULL)? ((x), abort(), (char *)0) :\
       +                                char **_argv;\
       +                                if (argv[0][1] == '-' && argv[0][2] == '\0') {\
       +                                        argv++;\
       +                                        argc--;\
       +                                        break;\
       +                                }\
       +                                for (argv[0]++, _argv = argv; argv[0][0];\
       +                                                argv[0]++) {\
       +                                        if (_argv != argv)\
       +                                                break;\
       +                                        _argc = argv[0][0];\
       +                                        switch (_argc)
       +
       +#define ARGEND                        }\
       +                                USED(_argc);\
       +                        }\
       +                        USED(argv);\
       +                        USED(argc);
       +
       +#define EARGF(x)        ((argv[1] == NULL)? ((x), abort(), (char *)0) :\
                                (argc--, argv++, argv[0]))
        
        #endif
 (DIR) diff --git a/config.mk b/config.mk
       @@ -1,21 +1,21 @@
        # rfkilld metadata
        NAME = rfkilld
       -VERSION = 0.3
       +VERSION = 0.4
        
        # Customize below to fit your system
        
        # paths
       -PREFIX ?= /usr/local
       +PREFIX = /usr/local
        MANPREFIX = ${PREFIX}/share/man
        
        # includes and libs
        INCS = -I. -I/usr/include
       -LIBS = -L/usr/lib -lc -ludev
       +LIBS = -L/usr/lib -lc
        
        # flags
       -CPPFLAGS = -DVERSION=\"${VERSION}\"
       +CPPFLAGS = -DVERSION=\"${VERSION}\" -D_GNU_SOURCE
        CFLAGS = -g -std=gnu99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
       -LDFLAGS = -g ${LIBS}
       +LDFLAGS = -static -g ${LIBS}
        #LDFLAGS = -s ${LIBS}
        
        # compiler and linker
 (DIR) diff --git a/etc/rfkilld/bluetooth.sh b/etc/rfkilld/bluetooth.sh
       @@ -1,7 +1,7 @@
        #!/bin/sh
        
        case $1 in
       -        0)
       +        0|2)
                        ;;
                1)
                        rfkill block bluetooth
 (DIR) diff --git a/etc/rfkilld/wlan.sh b/etc/rfkilld/wlan.sh
       @@ -1,7 +1,7 @@
        #!/bin/sh
        
        case $1 in
       -        0)
       +        0|2)
                        conn -k wifi
                        ;;
                1)
 (DIR) diff --git a/etc/rfkilld/wwan.sh b/etc/rfkilld/wwan.sh
       @@ -1,9 +1,9 @@
        #!/bin/sh
        
        case $1 in
       -        0)
       +        0|2)
                        ;;
       -        1|2)
       +        1)
                        # conn -s wwan
                        ;;
                *)
 (DIR) diff --git a/rfkilld.c b/rfkilld.c
       @@ -6,28 +6,71 @@
        #include <unistd.h>
        #include <stdio.h>
        #include <stdlib.h>
       -#include <libudev.h>
        #include <poll.h>
        #include <ctype.h>
        #include <string.h>
        #include <stdarg.h>
        #include <syslog.h>
        #include <signal.h>
       +#include <errno.h>
        #include <strings.h>
        #include <sys/wait.h>
        #include <sys/types.h>
        #include <sys/stat.h>
       +#include <sys/socket.h>
        #include <fcntl.h>
       +#include <linux/types.h>
       +#include <linux/netlink.h>
        
        #include "arg.h"
        
        char *argv0;
        char *etcdir = "/etc/rfkilld";
       -char *lastname = NULL;
       -char *lasttype = NULL;
       -char *laststate = NULL;
       -int running = 1;
       -int dolog = 0;
       +char lastname[129];
       +char lasttype[129];
       +int listfd = -1;
       +int dolog = 0, dodebug = 0;
       +
       +void
       +edie(char *fmt, ...)
       +{
       +        va_list fmtargs;
       +
       +        va_start(fmtargs, fmt);
       +        vfprintf(stderr, fmt, fmtargs);
       +        va_end(fmtargs);
       +        fprintf(stderr, ": ");
       +
       +        perror(NULL);
       +
       +        exit(1);
       +}
       +
       +void
       +die(char *fmt, ...)
       +{
       +        va_list fmtargs;
       +
       +        va_start(fmtargs, fmt);
       +        vfprintf(stderr, fmt, fmtargs);
       +        va_end(fmtargs);
       +
       +        exit(1);
       +}
       +
       +void
       +dbg(char *fmt, ...)
       +{
       +        va_list fmtargs;
       +
       +        if (dodebug) {
       +                fprintf(stderr, "%s: ", argv0);
       +                va_start(fmtargs, fmt);
       +                vfprintf(stderr, fmt, fmtargs);
       +                va_end(fmtargs);
       +                fprintf(stderr, "\n");
       +        }
       +}
        
        int
        setnonblocking(int fd)
       @@ -47,7 +90,7 @@ void
        runifexecutable(char *file, char *oname, char *ostate)
        {
                char cmd[512], name[64], state[16];
       -        int pid;
       +        int pid, fd;
        
                strncpy(name, oname, sizeof(name)-1);
                name[sizeof(name)-1] = '\0';
       @@ -57,9 +100,15 @@ runifexecutable(char *file, char *oname, char *ostate)
                snprintf(cmd, sizeof(cmd), "%s/%s.sh", etcdir, file);
                if (!access(cmd, X_OK)) {
                        if (!(pid = fork())) {
       -                        if (!fork())
       +                        if (!fork()) {
       +                                fd = open("/dev/null", O_RDWR);
       +                                dup2(fd, 1);
       +                                dup2(fd, 2);
       +                                if (fd > 2)
       +                                        close(fd);
                                        if(execl(cmd, name, state, NULL) < 0)
       -                                        perror("execl");
       +                                        edie("execl");
       +                        }
                                exit(0);
                        }
                        waitpid(pid, NULL, 0);
       @@ -67,40 +116,17 @@ runifexecutable(char *file, char *oname, char *ostate)
        }
        
        void
       -runscripts(struct udev_device *dev)
       +runscripts(char *name, char *type, char *state)
        {
       -        struct udev_list_entry *props;
       -        char *type, *name, *state;
       -
       -        props = udev_device_get_properties_list_entry(dev);
       -        type = (char *)udev_device_get_property_value(dev, "RFKILL_NAME");
       -        name = (char *)udev_device_get_property_value(dev, "RFKILL_TYPE");
       -        state = (char *)udev_device_get_property_value(dev, "RFKILL_STATE");
       -
       -        if (lasttype != NULL && lastname != NULL && laststate != NULL) {
       -                if (!strcmp(lasttype, type) && !strcmp(lastname, name)
       -                                && !strcmp(laststate, state))
       -                        goto runscriptshandlecleanup;
       -        }
       +        dbg("runscripts: %s %s %s", name, type, state);
        
       -        if (dolog)
       +        if (dolog) {
                        syslog(LOG_NOTICE, "name: %s; type: %s; state: %s;\n",
                                        name, type, state);
       +        }
        
                runifexecutable(name, type, state);
                runifexecutable(type, name, state);
       -
       -runscriptshandlecleanup:
       -        if (lasttype != NULL)
       -                free(lasttype);
       -        if (lastname != NULL)
       -                free(lastname);
       -        if (laststate != NULL)
       -                free(laststate);
       -
       -        lasttype = strdup(type);
       -        lastname = strdup(name);
       -        laststate = strdup(state);
        }
        
        void
       @@ -117,7 +143,11 @@ sighandler(int sig)
                case SIGTERM:
                        if (dolog)
                                closelog();
       -                running = 0;
       +                if (listfd >= 0) {
       +                        shutdown(listfd, SHUT_RDWR);
       +                        close(listfd);
       +                }
       +                exit(0);
                        break;
                default:
                        break;
       @@ -140,27 +170,34 @@ initsignals(void)
        void
        usage(void)
        {
       -        fprintf(stderr, "usage: %s [-hbl] [-e etcdir]\n",
       -                        argv0);
       -        fflush(stderr);
       -        exit(1);
       +        die("usage: %s [-hbdl] [-e etcdir]\n", argv0);
        }
        
        int
        main(int argc, char *argv[])
        {
       -        struct udev *udev;
       -        struct udev_monitor *mon;
       -        struct udev_device *dev;
       -        struct pollfd fds[1];
       -        int ret, dodaemonize;
       +        struct sockaddr_nl nls, cnls;
       +        struct msghdr hdr;
       +        struct iovec iov;
       +        char buf[4097], *key, *value, *type, *name, *state,
       +             cbuf[CMSG_SPACE(sizeof(struct ucred))], *subsystem;
       +        struct cmsghdr *chdr;
       +        struct ucred *cred;
       +        struct pollfd fds;
       +        int i, len, slen, dodaemonize;
        
                dodaemonize = 0;
       +        memset(lastname, 0, sizeof(lastname));
       +        memset(lasttype, 0, sizeof(lasttype));
        
                ARGBEGIN {
                case 'b':
                        dodaemonize = 1;
                        break;
       +        case 'd':
       +                printf("dodebug = 1\n");
       +                dodebug = 1;
       +                break;
                case 'l':
                        dolog = 1;
                        break;
       @@ -171,54 +208,141 @@ main(int argc, char *argv[])
                        usage();
                } ARGEND;
        
       -        if(dodaemonize)
       -                daemon(0, 0);
       +        memset(&nls, 0, sizeof(nls));
       +        nls.nl_family = AF_NETLINK;
       +        nls.nl_pid = getpid();
       +        nls.nl_groups = -1;
       +
       +        fds.events = POLLIN;
       +        fds.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
       +        listfd = fds.fd;
       +        if (fds.fd < 0)
       +                edie("socket");
       +
       +        slen = 128*1024*1024;
       +        if (setsockopt(fds.fd, SOL_SOCKET, SO_RCVBUFFORCE, &slen,
       +                                sizeof(slen)) < 0) {
       +                edie("setsockopt");
       +        }
       +        slen = 1;
       +        if (setsockopt(fds.fd, SOL_SOCKET, SO_PASSCRED, &slen,
       +                                sizeof(slen)) < 0) {
       +                edie("setsockopt");
       +        }
       +
       +        if (bind(fds.fd, (void *)&nls, sizeof(nls)))
       +                edie("bind");
       +
       +        if(dodaemonize) {
       +                if (daemon(0, 0) < 0)
       +                        edie("daemon");
       +                umask(022);
       +        }
        
                if(dolog)
                        openlog("rfkilld", 0, LOG_DAEMON);
        
                initsignals();
        
       -        udev = udev_new();
       -        if (!udev) {
       -                perror("udev_new");
       -                exit(1);
       -        }
       +        while (poll(&fds, 1, -1) > -1) {
       +                iov.iov_base = &buf;
       +                iov.iov_len = sizeof(buf);
       +                memset(&hdr, 0, sizeof(hdr));
       +                hdr.msg_iov = &iov;
       +                hdr.msg_iovlen = 1;
       +                hdr.msg_control = cbuf;
       +                hdr.msg_controllen = sizeof(cbuf);
       +                hdr.msg_name = &cnls;
       +                hdr.msg_namelen = sizeof(cnls);
        
       -        mon = udev_monitor_new_from_netlink(udev, "kernel");
       -        udev_monitor_filter_add_match_subsystem_devtype(mon, "rfkill", NULL);
       -        udev_monitor_enable_receiving(mon);
       +                len = recvmsg(fds.fd, &hdr, 0);
       +                if (len < 0) {
       +                        if (errno == EINTR)
       +                                continue;
       +                        edie("recvmsg");
       +                }
       +                if (len < 32 || len >= sizeof(buf))
       +                        continue;
        
       -        fds[0].fd = udev_monitor_get_fd(mon);
       -        fds[0].events = POLLIN|POLLPRI;
       -        if (setnonblocking(fds[0].fd)) {
       -                perror("setnonblocking");
       -                exit(1);
       -        }
       -        while(running) {
       -                ret = poll(fds, 1, -1);
       -                if (ret > 0) {
       -                        if ((fds[0].revents & POLLIN) \
       -                                        || (fds[0].revents & POLLPRI)) {
       -                                dev = udev_monitor_receive_device(mon);
       -                                if (dev) {
       -                                        runscripts(dev);
       -                                        udev_device_unref(dev);
       -                                }
       +                chdr = CMSG_FIRSTHDR(&hdr);
       +                if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS)
       +                        continue;
       +
       +                /*
       +                 * Don't allow anyone but root to send us messages.
       +                 *
       +                 * We will allow users to send us messages, when
       +                 * udev is enabled. Udev is just a toy you should
       +                 * only use for testing.
       +                 */
       +                cred = (struct ucred *)CMSG_DATA(chdr);
       +                if (cred->uid != 0)
       +                        continue;
       +
       +                if (!memcmp(buf, "libudev", 8)) {
       +                        continue;
       +                } else {
       +                        if (cnls.nl_pid > 0)
       +                                continue;
       +                }
       +
       +                type = NULL;
       +                name = NULL;
       +                state = NULL;
       +                for (i = 0; i < len; i += slen + 1) {
       +                        key = buf + i;
       +                        value = strchr(key, '=');
       +                        slen = strlen(buf+i);
       +                        if (!slen || value == NULL)
       +                                continue;
       +
       +                        value[0] = '\0';
       +                        value++;
       +
       +                        printf("%s = %s\n", key, value);
       +                        if (!strcmp(key, "SUBSYSTEM"))
       +                                subsystem = value;
       +                        if (!strcmp(key, "RFKILL_NAME"))
       +                                name = value;
       +                        if (!strcmp(key, "RFKILL_TYPE"))
       +                                type = value;
       +                        /*
       +                         * 0 -> soft blocked
       +                         * 1 -> unblocked
       +                         * 2 -> hard blocked
       +                         */
       +                        if (!strcmp(key, "RFKILL_STATE"))
       +                                state = value;
       +                }
       +                dbg("name = %s, type = %s, state = %s", name, type,
       +                                state);
       +                if (strcmp(subsystem, "rfkill"))
       +                        continue;
       +
       +                if (name != NULL && type != NULL && state != NULL) {
       +                        if (strcmp(name, lastname) &&
       +                                        strcmp(type, lasttype)) {
       +                                slen = strlen(name);
       +                                if (slen > sizeof(lastname)-1)
       +                                        die("name is too large\n");
       +                                memmove(lastname, name, slen+1);
       +
       +                                slen = strlen(type);
       +                                if (slen > sizeof(lasttype)-1)
       +                                        die("type is too large\n");
       +                                memmove(lasttype, type, slen+1);
       +
       +                                runscripts(name, type, state);
                                }
                        }
                }
        
       -        udev_monitor_unref(mon);
       -        udev_unref(udev);
                if (dolog)
                        closelog();
       -        if (lasttype != NULL)
       -                free(lasttype);
       -        if (lastname != NULL)
       -                free(lastname);
       -        if (laststate != NULL)
       -                free(laststate);
       -        exit(0);
       +
       +        shutdown(listfd, SHUT_RDWR);
       +        close(listfd);
       +
       +        return 0;
        }