nlmon

NetLink MONitor; a lightweight udevadm monitor replacement.
git clone git://r-36.net/nlmon
Log | Files | Refs | LICENSE

nlmon.c (2840B)


      1 /*
      2  * Copy me if you can.
      3  * by 20h
      4  */
      5 
      6 #include <unistd.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <stdarg.h>
     10 #include <poll.h>
     11 #include <ctype.h>
     12 #include <string.h>
     13 #include <errno.h>
     14 #include <sys/socket.h>
     15 #include <sys/types.h>
     16 #include <linux/types.h>
     17 #include <linux/netlink.h>
     18 
     19 #include "arg.h"
     20 
     21 char *argv0;
     22 
     23 void
     24 edie(char *fmt, ...)
     25 {
     26 	va_list fmtargs;
     27 
     28 	va_start(fmtargs, fmt);
     29 	vfprintf(stderr, fmt, fmtargs);
     30 	va_end(fmtargs);
     31 	fprintf(stderr, ": ");
     32 
     33 	perror(NULL);
     34 
     35 	exit(1);
     36 }
     37 
     38 void
     39 die(char *fmt, ...)
     40 {
     41 	va_list fmtargs;
     42 
     43 	va_start(fmtargs, fmt);
     44 	vfprintf(stderr, fmt, fmtargs);
     45 	va_end(fmtargs);
     46 
     47 	exit(1);
     48 }
     49 
     50 void
     51 usage(void)
     52 {
     53 	die("usage: %s [-h] [-kl] [-f subsystem]\n", argv0);
     54 }
     55 
     56 int
     57 main(int argc, char *argv[])
     58 {
     59 	struct sockaddr_nl nls, cnls;
     60 	struct pollfd fds;
     61 	struct msghdr hdr;
     62 	struct iovec iov;
     63 	char buf[4097], obuf[4098], *subsystem;
     64 	int i, len, olen, slen, showudev, showkernel;
     65 
     66 	showkernel = 1;
     67 	showudev = 1;
     68 	subsystem = NULL;
     69 
     70 	ARGBEGIN {
     71 	case 'f':
     72 		subsystem = EARGF(usage());
     73 		break;
     74 	case 'k':
     75 		showudev = 0;
     76 		break;
     77 	case 'l':
     78 		showkernel = 0;
     79 		break;
     80 	default:
     81 		usage();
     82 	} ARGEND;
     83 
     84 	memset(&nls, 0, sizeof(nls));
     85 	nls.nl_family = AF_NETLINK;
     86 	nls.nl_pid = getpid();
     87 	nls.nl_groups = -1;
     88 
     89 	/*
     90 	 * The whole process of decoding the kernel messages is
     91 	 * kept simple to avoid clashes with root rights. One
     92 	 * goal of nlmon is to be able to decode the kernel
     93 	 * messages in userspace.
     94 	 */
     95 
     96 	fds.events = POLLIN;
     97 	fds.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
     98 	if (fds.fd < 0)
     99 		edie("socket");
    100 
    101 	/*
    102 	 * Setting the sockopts here will require root rights.
    103 	 * Just keep it that way and pretend to have a big
    104 	 * enough buffer.
    105 	 */
    106 
    107 	if (bind(fds.fd, (void *)&nls, sizeof(nls)))
    108 		edie("bind");
    109 
    110 	buf[sizeof(buf)-1] = '\0';
    111 	while (poll(&fds, 1, -1) > -1) {
    112 		iov.iov_base = &buf;
    113 		iov.iov_len = sizeof(buf);
    114 		memset(&hdr, 0, sizeof(hdr));
    115 		hdr.msg_iov = &iov;
    116 		hdr.msg_iovlen = 1;
    117 		hdr.msg_name = &cnls;
    118 		hdr.msg_namelen = sizeof(cnls);
    119 
    120 		len = recvmsg(fds.fd, &hdr, 0);
    121 		if (len < 0) {
    122 			if (errno == EINTR)
    123 				continue;
    124 			edie("recvmsg");
    125 		}
    126 		if (len < 32 || len >= sizeof(buf))
    127 			continue;
    128 
    129 		if (!memcmp(buf, "libudev", 8)) {
    130 			if (!showudev)
    131 				continue;
    132 		} else {
    133 			if (!showkernel)
    134 				continue;
    135 
    136 			/*
    137 			 * Kernel messages should be from root.
    138 			 */
    139 			if (cnls.nl_pid > 0)
    140 				continue;
    141 		}
    142 
    143 		for (i = 0, olen = 0; i < len; i += slen + 1) {
    144 			slen = strlen(buf+i);
    145 			if (!slen || !strchr(buf+i, '='))
    146 				continue;
    147 			if (subsystem && !strncmp(buf+i, "SUBSYSTEM=", 10)
    148 					&& !strstr(buf+i+10, subsystem)) {
    149 				olen = 0;
    150 				break;
    151 			}
    152 
    153 			snprintf(obuf+olen, sizeof(obuf)-olen-2,
    154 					"%s\n", buf+i);
    155 			olen += slen + 1;
    156 		}
    157 		if (olen > 0) {
    158 			obuf[olen] = '\n';
    159 			write(1, obuf, olen+1);
    160 		}
    161 	}
    162 
    163 	return 0;
    164 }
    165