rfkilld

An rfkill daemon, which runs scripts according to rfkill events.
git clone git://r-36.net/rfkilld
Log | Files | Refs | LICENSE

commit cb0a601f08208245331447ec00db5de4b447ce50
parent 3e475d9f0d2322e6a31dd70f4c1416e79a41aa76
Author: Christoph Lohmann <20h@r-36.net>
Date:   Sat, 26 Feb 2011 21:31:38 +0100

Initial commit of rfkilld.

Diffstat:
Makefile | 68+++++++++++++++++++++++++++++++++++++++++++++++---------------------
README.md | 20++++++++++++++++++++
arg.h | 19+++++++++++++++++++
bin/rfkilld | 96-------------------------------------------------------------------------------
config.mk | 16+++++++++++++++-
etc/conf.d/rfkilld | 5+++++
etc/rc.d/rfkilld | 37+++++++++++++++++++++++++++++++++++++
etc/rfkilld/bluetooth.sh | 15+++++++++++++++
etc/rfkilld/wlan.sh | 16++++++++++++++++
etc/rfkilld/wwan.sh | 15+++++++++++++++
rfkilld.c | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 359 insertions(+), 118 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,29 +1,55 @@ -# rfkilld - rfkill daemon +# rfkilld - rfkill daemon # See LICENSE file for copyright and license details. include config.mk -dist: +SRC = ${NAME}.c +OBJ = ${SRC:.c=.o} + +all: options ${NAME} + +options: + @echo ${NAME} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.mk + +${NAME}: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f ${NAME} ${OBJ} ${NAME}-${VERSION}.tar.gz + +dist: clean @echo creating dist tarball - @mkdir -p rfkilld-${VERSION} - @cp -R LICENSE README.md Makefile config.mk \ - bin etc rfkilld-${VERSION} - @tar -cf rfkilld-${VERSION}.tar rfkilld-${VERSION} - @gzip rfkilld-${VERSION}.tar - @rm -rf rfkilld-${VERSION} - -install: - @echo installing rfkilld script to ${DESTDIR}${PREFIX}/bin - @cp bin/rfkilld ${DESTDIR}${PREFIX}/bin - @chmod 755 ${DESTDIR}${PREFIX}/bin/rfkilld - @echo installing etc files into ${DESTDIR}/etc/rfkilld - @mkdir -p ${DESTDIR}/etc/rfkilld - @cp -R etc/rfkilld ${DESTDIR}/etc/rfkilld + @mkdir -p ${NAME}-${VERSION} + @cp -R LICENSE Makefile README.md config.mk \ + etc ${SRC} *.h ${NAME}-${VERSION} + @tar -cf ${NAME}-${VERSION}.tar ${NAME}-${VERSION} + @gzip ${NAME}-${VERSION}.tar + @rm -rf ${NAME}-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f ${NAME} ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} + @echo installing etc files into ${DESTDIR}/etc/${NAME} + @mkdir -p ${DESTDIR}/etc/${NAME} + @cp -R etc/${NAME} ${DESTDIR}/etc/${NAME} uninstall: - @echo removing rfkilld script from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/rfkilld - @echo removing etc files from ${DESTDIR}/etc/rfkilld - @rm -rf ${DESTDIR}/etc/rfkilld + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/${NAME} + @echo removing etc files from ${DESTDIR}/etc/${NAME} + @rm -rf ${DESTDIR}/etc/${NAME} -.PHONY: dist install uninstall +.PHONY: all options clean dist install uninstall diff --git a/README.md b/README.md @@ -0,0 +1,20 @@ +# rfkilld - a rfkill daemon + +This daemon listens for rfkill events from the kernel, over a netlink, +for the »rfkill« subsystem. When an event occurs, the specific proper- +ties (NAME, TYPE, STATE) are taken and the files + + /etc/rfkilld/$name $state $type + /etc/rfkilld/$type $state $name + +are run using the shown arguments. + +Included are rc.d and conf.d files for being used in Archlinux. + +It is recommended to run this in conjunction with conn [0]. + + +Have fun! + +[0] http://git.r-36.net/conn/ + diff --git a/arg.h b/arg.h @@ -0,0 +1,19 @@ +#ifndef ARG_H +#define ARG_H + +#define USED(x) ((void)(x)) + +extern char *argv0; + +#define ARGBEGIN for(argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0]=='-' && argv[0][1];\ + 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) :\ + (argc--, argv++, argv[0])) + +#endif + diff --git a/bin/rfkilld b/bin/rfkilld @@ -1,96 +0,0 @@ -#!/bin/sh - -usage() { - echo "usage: `basename $1` [-hbl] [-p pidfile] [-e etcdir] [-b]" -} - -UDEVMONITORCMD="/usr/bin/nlmon -p -k" -ETCDIR="/etc/rfkilld" -PIDFILE="/var/run/rfkilld.pid" -dobackground=0 -dodebug=0 -dolog=0 - -while getopts "ldp:e:" opt; -do - case $opt in - d) - dodebug=1 - ;; - p) - PIDFILE="$OPTARG" - ;; - e) - ETCDIR="$OPTARG" - ;; - l) - dolog=1 - ;; - *) - usage $0 - exit 1 - ;; - esac -done -shift $(($OPTIND - 1)) - -debugcmd="" -if [ $dodebug -eq 1 ]; -then - debugcmd="-d" - set -x -fi - -echo $$ > $PIDFILE 2>&1 >/dev/null -trap "[ -e $PIDFILE ] && rm $PIDFILE; exit 0;" 2 3 6 9 15 - -name= -type= -state= - -$UDEVMONITORCMD | \ -while read status -do - [[ "$status" =~ ^RFKILL_NAME=(.*)$ ]] \ - && name="${BASH_REMATCH[1]}" - [[ "$status" =~ ^RFKILL_TYPE=(.*)$ ]] \ - && type="${BASH_REMATCH[1]}" - [[ "$status" =~ ^RFKILL_STATE=(.*)$ ]] \ - && state="${BASH_REMATCH[1]}" - - if [ "$status" == "" ]; - then - if [ "$name" == "" ] || [ "$type" == "" ] \ - || [ "$state" == "" ]; - then - continue - fi - - [ $dodebug -eq 1 ] \ - && logger -t rfkilld "req $name $type $state" - - if [ -x $ETCDIR/$name.sh ]; - then - $ETCDIR/$name.sh $state 2>&1 >/dev/null & - - [ $dolog -eq 1 ] \ - && logger -t rfkilld "ran $name.sh $state" - fi - - if [ -x $ETCDIR/$type.sh ]; - then - $ETCDIR/$type.sh $state $name 2>&1 >/dev/null & - - [ $dolog -eq 1 ] \ - && logger -t rfkilld \ - "ran $type.sh $state $name" - fi - - name= - type= - state= - fi -done - -exit 0 - diff --git a/config.mk b/config.mk @@ -1,4 +1,5 @@ -# rfkilld version +# rfkilld metadata +NAME = rfkilld VERSION = 0.2 # Customize below to fit your system @@ -7,3 +8,16 @@ VERSION = 0.2 PREFIX = /usr MANPREFIX = ${PREFIX}/share/man +# includes and libs +INCS = -I. -I/usr/include +LIBS = -L/usr/lib -lc -ludev + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" +CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +LDFLAGS = -g ${LIBS} +#LDFLAGS = -s ${LIBS} + +# compiler and linker +CC = cc + diff --git a/etc/conf.d/rfkilld b/etc/conf.d/rfkilld @@ -0,0 +1,5 @@ +# +# Parameters to be passed to rfkilld. +# +RFKILLD_ARGS="-l -b" + diff --git a/etc/rc.d/rfkilld b/etc/rc.d/rfkilld @@ -0,0 +1,37 @@ +#!/bin/bash + +. /etc/rc.conf +. /etc/rc.d/functions +. /etc/conf.d/rfkilld + +PID=`pidof -o %PPID /usr/bin/rfkilld` +case "$1" in + start) + stat_busy "Starting rfkilld" + [ -z "$PID" ] && /usr/bin/rfkilld $RFKILLD_ARGS 2>&1 + if [ $? -gt 0 ]; then + stat_fail + else + PID=`pidof -o %PPID /usr/bin/rfkilld` + add_daemon rfkilld + stat_done + fi + ;; + stop) + stat_busy "Stopping rfkilld" + [ ! -z "$PID" ] && kill -KILL $PID &>/dev/null + if [ $? -gt 0 ]; then + stat_fail + else + rm_daemon rfkilld + stat_done + fi + ;; + restart) + $0 stop + $0 start + ;; + *) + echo "usage: $0 {start|stop|restart}" +esac +exit 0 diff --git a/etc/rfkilld/bluetooth.sh b/etc/rfkilld/bluetooth.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +case $1 in + 0) + ;; + 1) + rfkill block bluetooth + ;; + *) + exit 1 + ;; +esac + +exit 0 + diff --git a/etc/rfkilld/wlan.sh b/etc/rfkilld/wlan.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +case $1 in + 0) + conn -k wifi + ;; + 1) + conn -s wifi + ;; + *) + exit 1 + ;; +esac + +exit 0 + diff --git a/etc/rfkilld/wwan.sh b/etc/rfkilld/wwan.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +case $1 in + 0) + ;; + 1|2) + # conn -s wwan + ;; + *) + exit 1 + ;; +esac + +exit 0 + diff --git a/rfkilld.c b/rfkilld.c @@ -0,0 +1,170 @@ +/* + * Copy me if you can. + * by 20h + */ + +#define _XOPEN_SOURCE +#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 <strings.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "arg.h" + +char *argv0; +char *etcdir = "/etc/rfkilld"; +int running = 1; +int dolog = 0; + +void +runifexecutable(char *file, char *oname, char *ostate) +{ + char cmd[512], name[64], state[16]; + int pid; + + strncpy(name, oname, sizeof(name)); + strncpy(state, ostate, sizeof(state)); + + snprintf(cmd, sizeof(cmd), "%s/%s.sh", etcdir, file); + if (!access(cmd, X_OK)) { + if (!(pid = fork())) { + if (!fork()) + if(execl(cmd, name, state, NULL) < 0) + perror("execl"); + exit(EXIT_SUCCESS); + } + waitpid(pid, NULL, 0); + } +} + +void +runscripts(struct udev_device *dev) +{ + 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 (dolog) + syslog(LOG_NOTICE, "name: %s; type: %s; state: %s;\n", + name, type, state); + + runifexecutable(name, type, state); + runifexecutable(type, name, state); +} + +void +sighandler(int sig) +{ + switch(sig) { + case SIGCHLD: + while(waitpid(-1, NULL, WNOHANG) > 0); + break; + case SIGHUP: + case SIGINT: + case SIGQUIT: + case SIGABRT: + case SIGTERM: + closelog(); + running = 0; + break; + default: + break; + } +} + +void +initsignals(void) +{ + signal(SIGCHLD, sighandler); + signal(SIGHUP, sighandler); + signal(SIGINT, sighandler); + signal(SIGQUIT, sighandler); + signal(SIGABRT, sighandler); + signal(SIGTERM, sighandler); + signal(SIGKILL, sighandler); +} + +void +usage(void) +{ + fprintf(stderr, "usage: %s [-hbl] [-e etcdir]\n", argv0); + fflush(stderr); + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ + struct udev *udev; + struct udev_monitor *mon; + struct udev_device *dev; + struct pollfd fds[1]; + int ret, dodaemonize; + + dodaemonize = 0; + + ARGBEGIN { + case 'b': + dodaemonize = 1; + break; + case 'l': + dolog = 1; + break; + case 'e': + etcdir = EARGF(usage()); + break; + default: + usage(); + } ARGEND; + + if(dodaemonize) + daemon(0, 0); + + if(dolog) + openlog("rfkilld", 0, LOG_DAEMON); + + initsignals(); + + udev = udev_new(); + if (!udev) { + perror("udev_new"); + exit(EXIT_FAILURE); + } + + mon = udev_monitor_new_from_netlink(udev, "kernel"); + udev_monitor_filter_add_match_subsystem_devtype(mon, "rfkill", NULL); + udev_monitor_enable_receiving(mon); + + fds[0].fd = udev_monitor_get_fd(mon); + fds[0].events = POLLIN|POLLPRI; + while(running) { + ret = poll(fds, 1, 500); + 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); + } + } + } + } + + exit(EXIT_SUCCESS); +} +