nldev

NetLink DEVice manager; a lightweight netlink frontend for mdev.
git clone git://r-36.net/nldev
Log | Files | Refs | LICENSE

commit 1953099f5f153e6e6bb19db54bd334bc25e6f655
parent b30694187cbd260d08dfc38dd468d41938d5bff9
Author: Christoph Lohmann <20h@r-36.net>
Date:   Sun, 12 Sep 2021 20:59:58 +0200

Push v0.4 with major changes.

* nltrigger in C instead of old script
* nltrigger.1 manpage
* make now follows bitreich simpler output rules
* there is now a config.h with selection of when to trigger commands
	* this filters and speeds up the whole system init

Thanks Platon Ryzhikov <ihummer63@yandex.ru> for sending in
the proposal and giving me the motivation to renew nldev
to this stage.

Diffstat:
Makefile | 72+++++++++++++++++++++++++++++++++---------------------------------------
config.mk | 6+++---
nldev.c | 37+++++++++++++++++++++----------------
nltrigger | 83-------------------------------------------------------------------------------
nltrigger.1 | 48++++++++++++++++++++++++++++++++++++++++++++++++
nltrigger.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 265 insertions(+), 141 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,20 +3,13 @@ include config.mk -SRC = ${NAME}.c +SRC = ${NAME}.c nltrigger.c OBJ = ${SRC:.c=.o} -all: options ${NAME} - -options: - @echo ${NAME} build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" +all: ${NAME} nltrigger .c.o: - @echo CC $< - @${CC} -c ${CFLAGS} $< + ${CC} -c ${CFLAGS} $< ${OBJ}: config.h config.mk @@ -24,40 +17,41 @@ config.h: cp config.def.h $@ ${NAME}: ${OBJ} - @echo CC -o $@ - @${CC} -o $@ ${OBJ} ${LDFLAGS} + ${CC} -o $@ $@.o ${LDFLAGS} + +nltrigger: ${OBJ} + ${CC} -o $@ $@.o ${LDFLAGS} + clean: - @echo cleaning - @rm -f ${NAME} ${OBJ} ${NAME}-${VERSION}.tar.gz + rm -f ${NAME} ${OBJ} nltrigger ${NAME}-${VERSION}.tar.gz dist: clean - @echo creating dist tarball - @mkdir -p ${NAME}-${VERSION} - @cp -R LICENSE Makefile README.md FIXES.md config.def.h config.mk \ - ${SRC} ${NAME}.8 *.h ${NAME}-${VERSION} - @tar -cf ${NAME}-${VERSION}.tar ${NAME}-${VERSION} - @gzip ${NAME}-${VERSION}.tar - @rm -rf ${NAME}-${VERSION} + mkdir -p ${NAME}-${VERSION} + cp -R LICENSE Makefile README.md FIXES.md config.def.h config.mk \ + ${SRC} ${NAME}.8 nltrigger.1 *.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 - @cp -f run_${NAME} ${DESTDIR}${PREFIX}/bin - @cp -f nltrigger ${DESTDIR}${PREFIX}/bin - @chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} - @echo installing manual page to ${DESTDIR}${MANPREFIX}/man8 - @mkdir -p ${DESTDIR}${MANPREFIX}/man8 - @cp -f ${NAME}.8 ${DESTDIR}${MANPREFIX}/man8 - @chmod 644 ${DESTDIR}${MANPREFIX}/man8/${NAME}.8 + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f ${NAME} ${DESTDIR}${PREFIX}/bin + cp -f run_${NAME} ${DESTDIR}${PREFIX}/bin + cp -f nltrigger ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} + mkdir -p ${DESTDIR}${MANPREFIX}/man8 + cp -f ${NAME}.8 ${DESTDIR}${MANPREFIX}/man8 + chmod 644 ${DESTDIR}${MANPREFIX}/man8/${NAME}.8 + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + cp -f nltrigger.1 ${DESTDIR}${MANPREFIX}/man1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/nltrigger.1 uninstall: - @echo removing executable file from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/${NAME} - @rm -f ${DESTDIR}${PREFIX}/bin/run_${NAME} - @rm -f ${DESTDIR}${PREFIX}/bin/nltrigger - @echo removing manual page from ${DESTDIR}${PREFIX}/man8 - @rm -f ${DESTDIR}${MANPREFIX}/man8/${NAME}.8 - -.PHONY: all options clean dist install uninstall + rm -f ${DESTDIR}${PREFIX}/bin/${NAME} + rm -f ${DESTDIR}${PREFIX}/bin/run_${NAME} + rm -f ${DESTDIR}${PREFIX}/bin/nltrigger + rm -f ${DESTDIR}${MANPREFIX}/man8/${NAME}.8 + rm -f ${DESTDIR}${MANPREFIX}/man1/nltrigger.1 + +.PHONY: all clean dist install uninstall diff --git a/config.mk b/config.mk @@ -1,6 +1,6 @@ # nldev metadata NAME = nldev -VERSION = 0.3 +VERSION = 0.4 # Customize below to fit your system @@ -14,8 +14,8 @@ LIBS = -L/usr/lib -lc # flags CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -D_GNU_SOURCE -CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} -LDFLAGS = -static -g ${LIBS} +CFLAGS = -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +LDFLAGS = -static ${LIBS} #LDFLAGS = -s ${LIBS} # compiler and linker diff --git a/nldev.c b/nldev.c @@ -1,7 +1,4 @@ -/* - * Copy me if you can. - * by 20h - */ +/* See LICENSE for copyright information. */ #include <unistd.h> #include <stdio.h> @@ -22,10 +19,10 @@ #include <linux/netlink.h> typedef struct { - const char *action; /* ACTION to run rule for */ - const char *subsystem; /* SUBSYSTEM to run the rule for, NULL for any */ - const char *envvar; /* other environment variable to run rule for, NULL for any */ - const char *runpath; + char *action; /* ACTION to run rule for */ + char *subsystem; /* SUBSYSTEM to run the rule for, NULL for any */ + char *envvar; /* other environment variable to run rule for, NULL for any */ + char *runpath; } Rule; #include "arg.h" @@ -336,20 +333,28 @@ main(int argc, char *argv[]) getenv("DEVPATH") != NULL && getenv("SUBSYSTEM") != NULL && getenv("SEQNUM") != NULL) { - if (runpath) + if (runpath) { child(runpath); - else { + } else { for (i = 0; i < LENGTH(rules); i+=1) { - if (rules[i].action == NULL || rules[i].runpath == NULL) /* rule must have non-NULL action and runpath */ + if (rules[i].action == NULL + || rules[i].runpath == NULL) { continue; - if (strcmp(getenv("ACTION"), rules[i].action)) + } + if (strcmp(getenv("ACTION"), rules[i].action)) { continue; - if (rules[i].subsystem != NULL) - if (strcmp(getenv("SUBSYSTEM"), rules[i].subsystem)) + } + if (rules[i].subsystem != NULL) { + if (strcmp(getenv("SUBSYSTEM"), + rules[i].subsystem)) { continue; - if (rules[i].envvar != NULL) - if (getenv(rules[i].envvar) == NULL) + } + } + if (rules[i].envvar != NULL) { + if (getenv(rules[i].envvar) == NULL) { continue; + } + } child(rules[i].runpath); } } diff --git a/nltrigger b/nltrigger @@ -1,83 +0,0 @@ -#!/bin/busybox ash - -usage() { - printf "usage: %s [add|list|del|action] [subsystem]\n" "$(basename $1)" >&2 - exit 1 -} - -action="list" -if [ $# -gt 0 ]; -then - action="$1" -fi - -if [ "$action" = "list" ]; -then - printf "class:\n" - for i in /sys/class/*; - do - printf "\t%s\n" $(basename $i) - done - - printf "bus:\n" - for i in /sys/bus/*; - do - printf "\t%s\n" $(basename $i) - done - - printf "devices:\n" - for i in /sys/devices/*; - do - printf "\t%s\n" $(basename $i) - done - - exit 0 -fi - -if [ $# -lt 2 ]; -then - usage "$0" -fi -subsystem="$2" - -if [ "$subsystem" != "all" ]; -then - if [ -d /sys/class/$subsystem ]; - then - for i in /sys/class/$subsystem/*/uevent; - do - echo $action > $i - done - exit 0 - fi - - if [ -d /sys/bus/$subsystem ]; - then - for i in /sys/bus/$subsystem/devices/*/uevent; - do - echo $action > $i - done - exit 0 - fi - - if [ -d /sys/devices/$subsystem ]; - then - for i in /sys/devices/$subsystem/*/uevent \ - /sys/devices/$subsystem/*/*/uevent; - do - echo $action > $i - done - exit 0 - fi - - printf "Could not find subsystem '%s'.\n" $i >&2 - exit 1 -fi - -for i in $(find /sys -name uevent -print | sed -e 's/ /,/g'); -do - echo $action > "$(echo $i | sed -e 's/,/ /g')" -done - -exit 0 - diff --git a/nltrigger.1 b/nltrigger.1 @@ -0,0 +1,48 @@ +.Dd September 12, 2021 +.Dt NLTRIGGER 1 +.Os +. +.Sh NAME +.Nm nltrigger +.Nd a tool to trigger netlink device events +. +.Sh SYNOPSIS +.Nm +.Bk -words +.Ar path +.Op Ar add|list|del|action +.Op Ar delay +.Ek +. +.Sh DESCRIPTION +.Bd -filled +.Nm +is a simple tool to trigger netlink device events at a certain +.Ar path +with a certain +.Ar action +and a certain +.Ar delay. +. +.Sh OPTIONS +.Pp +.Bl -tag -width Ds +.Ar Path +to be used as target. +.Ar Action +of [add|list|del|action] +should be triggered. +.Ar Delay +of usecs to wait after the +.Ar action +has been triggered. +(Default is 1000 usecs.) +.El +.Sh AUTHORS +See the LICENSE file for the authors of this software. +. +.Sh LICENSE +.Nm +is released under the MIT/X Consortium License. +. + diff --git a/nltrigger.c b/nltrigger.c @@ -0,0 +1,160 @@ +/* See LICENSE file for copyright. */ +/* + * Based on smdev -s code. Thanks for the prework! + */ +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "arg.h" + +char *argv0; +static char *action = "add"; +static useconds_t delay = 1000; +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) +{ + vfprintf(stderr, fmt, ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } + + exit(status); +} + +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:"); +} + +char * +agetcwd(void) +{ + char *buf; + long size; + + apathmax(&buf, &size); + if(!getcwd(buf, size)) + eprintf("getcwd:"); + + return buf; +} + +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); +} + +void +trigger(const char *path) +{ + int fd; + + recurse(path, trigger); + if (strstr(path, "uevent")) { + if ((fd = open("uevent", O_WRONLY | O_CLOEXEC)) != -1) { + dprintf(fd, "%s\n", action); + close(fd); + usleep(delay); + } + } +} + +void usage(void) +{ + eprintf("usage: %s path [add|list|del|action] [delay]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + char *path = NULL; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if (argc == 0) + usage(); + + path = argv[0]; + if (argc > 0) { + action = argv[0]; + argc--; argv++; + } + if (argc > 0) + delay = atol(argv[0]); + + trigger(path); + + return 0; +} +