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;
}