commit 361feba39eb798d0d3c1c037a4b77d4d8fbadf9e
parent 8e7750e0150e3975826c7922043193fdca882dd0
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:
6 files changed, 246 insertions(+), 100 deletions(-)
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
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
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
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)
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
 		;;
 	*)
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;
 }