inotify: new applet by Vladimir Dronnikov <dronnikov AT gmail.com>
function old new delta inotifyd_main - 453 +453 packed_usage 24246 24450 +204 inotify_add_watch - 47 +47 inotify_init - 29 +29 mask_names - 13 +13 signal_handler 130 140 +10 applet_names 1859 1868 +9 applet_main 1132 1136 +4 applet_nameofs 566 568 +2 signalled 1 2 +1
This commit is contained in:
		@@ -185,6 +185,7 @@ USE_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_NEVER))
 | 
			
		||||
USE_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifup))
 | 
			
		||||
USE_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
 | 
			
		||||
USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER))
 | 
			
		||||
USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER))
 | 
			
		||||
USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
 | 
			
		||||
USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 | 
			
		||||
#if ENABLE_FEATURE_IP_ADDRESS \
 | 
			
		||||
 
 | 
			
		||||
@@ -1833,6 +1833,30 @@
 | 
			
		||||
"	::shutdown:/bin/umount -a -r\n" \
 | 
			
		||||
"	::shutdown:/sbin/swapoff -a\n"
 | 
			
		||||
 | 
			
		||||
#define inotifyd_trivial_usage \
 | 
			
		||||
	"/user/space/agent dir/or/file/being/watched[:mask] ..."
 | 
			
		||||
#define inotifyd_full_usage "\n\n" \
 | 
			
		||||
       "Spawn userspace agent on filesystem changes." \
 | 
			
		||||
     "\nWhen a filesystem event matching the mask occurs" \
 | 
			
		||||
     "\non specified file/directory an userspace agent is spawned" \
 | 
			
		||||
     "\nwith the parameters:" \
 | 
			
		||||
     "\n1. actual event(s)" \
 | 
			
		||||
     "\n2. file/directory name" \
 | 
			
		||||
     "\n3. name of subfile (if any), in case of watching a directory" \
 | 
			
		||||
     "\n" \
 | 
			
		||||
     "\n	a	File is accessed" \
 | 
			
		||||
     "\n	c	File is modified" \
 | 
			
		||||
     "\n	e	Metadata changed" \
 | 
			
		||||
     "\n	w	Writtable file is closed" \
 | 
			
		||||
     "\n	0	Unwrittable file is closed" \
 | 
			
		||||
     "\n	r	File is opened" \
 | 
			
		||||
     "\n	m	File is moved from X" \
 | 
			
		||||
     "\n	y	File is moved to Y" \
 | 
			
		||||
     "\n	n	Subfile is created" \
 | 
			
		||||
     "\n	d	Subfile is deleted" \
 | 
			
		||||
     "\n	D	Self is deleted" \
 | 
			
		||||
     "\n	M	Self is moved" \
 | 
			
		||||
 | 
			
		||||
#define insmod_trivial_usage \
 | 
			
		||||
	USE_FEATURE_2_4_MODULES("[OPTION]... ") "MODULE [symbol=value]..."
 | 
			
		||||
#define insmod_full_usage "\n\n" \
 | 
			
		||||
 
 | 
			
		||||
@@ -222,6 +222,12 @@ config FBSPLASH
 | 
			
		||||
	    "NN" (ASCII decimal number) - percentage to show on progress bar
 | 
			
		||||
	    "exit" - well you guessed it
 | 
			
		||||
 | 
			
		||||
config INOTIFYD
 | 
			
		||||
	bool "inotifyd"
 | 
			
		||||
	default n
 | 
			
		||||
	help
 | 
			
		||||
	  Simple inotify daemon. Reports filesystem changes. Requires kernel >= 2.6.13
 | 
			
		||||
 | 
			
		||||
config LAST
 | 
			
		||||
	bool "last"
 | 
			
		||||
	default n
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ lib-$(CONFIG_DEVFSD)      += devfsd.o
 | 
			
		||||
lib-$(CONFIG_EJECT)       += eject.o
 | 
			
		||||
lib-$(CONFIG_FBSPLASH)    += fbsplash.o
 | 
			
		||||
lib-$(CONFIG_HDPARM)      += hdparm.o
 | 
			
		||||
lib-$(CONFIG_INOTIFYD)    += inotifyd.o
 | 
			
		||||
lib-$(CONFIG_FEATURE_LAST_SMALL)+= last.o
 | 
			
		||||
lib-$(CONFIG_FEATURE_LAST_FANCY)+= last_fancy.o
 | 
			
		||||
lib-$(CONFIG_LESS)        += less.o
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										152
									
								
								miscutils/inotifyd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								miscutils/inotifyd.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
/* vi: set sw=4 ts=4: */
 | 
			
		||||
/*
 | 
			
		||||
 * simple inotify daemon
 | 
			
		||||
 * reports filesystem changes via userspace agent
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under GPLv2, see file LICENSE in this tarball for details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Use as follows:
 | 
			
		||||
 * # inotifyd /user/space/agent dir/or/file/being/watched[:mask] ...
 | 
			
		||||
 *
 | 
			
		||||
 * When a filesystem event matching the specified mask is occured on specified file (or directory)
 | 
			
		||||
 * a userspace agent is spawned and given the following parameters:
 | 
			
		||||
 * $1. actual event(s)
 | 
			
		||||
 * $2. file (or directory) name
 | 
			
		||||
 * $3. name of subfile (if any), in case of watching a directory
 | 
			
		||||
 *
 | 
			
		||||
 * E.g. inotifyd ./dev-watcher /dev:n
 | 
			
		||||
 *
 | 
			
		||||
 * ./dev-watcher can be, say:
 | 
			
		||||
 * #!/bin/sh
 | 
			
		||||
 * echo "We have new device in here! Hello, $3!"
 | 
			
		||||
 *
 | 
			
		||||
 * See below for mask names explanation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libbb.h"
 | 
			
		||||
#include <linux/inotify.h>
 | 
			
		||||
 | 
			
		||||
static volatile smallint signalled;
 | 
			
		||||
 | 
			
		||||
static void signal_handler(int signo)
 | 
			
		||||
{
 | 
			
		||||
	signalled = signo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char mask_names[] ALIGN1 =
 | 
			
		||||
	"a"	// 0x00000001	File was accessed
 | 
			
		||||
	"c"	// 0x00000002	File was modified
 | 
			
		||||
	"e"	// 0x00000004	Metadata changed
 | 
			
		||||
	"w"	// 0x00000008	Writtable file was closed
 | 
			
		||||
	"0"	// 0x00000010	Unwrittable file closed
 | 
			
		||||
	"r"	// 0x00000020	File was opened
 | 
			
		||||
	"m"	// 0x00000040	File was moved from X
 | 
			
		||||
	"y"	// 0x00000080	File was moved to Y
 | 
			
		||||
	"n"	// 0x00000100	Subfile was created
 | 
			
		||||
	"d"	// 0x00000200	Subfile was deleted
 | 
			
		||||
	"D"	// 0x00000400	Self was deleted
 | 
			
		||||
	"M"	// 0x00000800	Self was moved
 | 
			
		||||
;
 | 
			
		||||
 | 
			
		||||
extern int inotify_init(void);
 | 
			
		||||
extern int inotify_add_watch(int fd, const char *path, uint32_t mask);
 | 
			
		||||
 | 
			
		||||
int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 | 
			
		||||
int inotifyd_main(int argc ATTRIBUTE_UNUSED, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	unsigned mask = IN_ALL_EVENTS; // assume we want all events
 | 
			
		||||
	struct pollfd pfd;
 | 
			
		||||
	char **watched = ++argv; // watched name list
 | 
			
		||||
	const char *args[] = { *argv, NULL, NULL, NULL, NULL };
 | 
			
		||||
 | 
			
		||||
	// sanity check: agent and at least one watch must be given
 | 
			
		||||
	if (!argv[1])
 | 
			
		||||
		bb_show_usage();
 | 
			
		||||
 | 
			
		||||
	// open inotify
 | 
			
		||||
	pfd.fd = inotify_init();
 | 
			
		||||
	if (pfd.fd < 0)
 | 
			
		||||
		bb_perror_msg_and_die("no kernel support");
 | 
			
		||||
 | 
			
		||||
	// setup watched
 | 
			
		||||
	while (*++argv) {
 | 
			
		||||
		char *path = *argv;
 | 
			
		||||
		char *masks = strchr(path, ':');
 | 
			
		||||
		int wd; // watch descriptor
 | 
			
		||||
		// if mask is specified ->
 | 
			
		||||
		if (masks) {
 | 
			
		||||
			*masks = '\0'; // split path and mask
 | 
			
		||||
			// convert mask names to mask bitset
 | 
			
		||||
			mask = 0;
 | 
			
		||||
			while (*++masks) {
 | 
			
		||||
				int i = strchr(mask_names, *masks) - mask_names;
 | 
			
		||||
				if (i >= 0) {
 | 
			
		||||
					mask |= (1 << i);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// add watch
 | 
			
		||||
		wd = inotify_add_watch(pfd.fd, path, mask);
 | 
			
		||||
		if (wd < 0) {
 | 
			
		||||
			bb_perror_msg_and_die("add watch (%s) failed", path);
 | 
			
		||||
//		} else {
 | 
			
		||||
//			bb_error_msg("added %d [%s]:%4X", wd, path, mask);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// setup signals
 | 
			
		||||
	bb_signals(0
 | 
			
		||||
		+ (1 << SIGHUP)
 | 
			
		||||
		+ (1 << SIGINT)
 | 
			
		||||
		+ (1 << SIGTERM)
 | 
			
		||||
		+ (1 << SIGPIPE)
 | 
			
		||||
		, signal_handler);
 | 
			
		||||
 | 
			
		||||
	// do watch
 | 
			
		||||
 | 
			
		||||
//	pfd.fd = fd;
 | 
			
		||||
	pfd.events = POLLIN;
 | 
			
		||||
 | 
			
		||||
	while (!signalled && poll(&pfd, 1, -1) > 0) {
 | 
			
		||||
		ssize_t len;
 | 
			
		||||
		void *buf;
 | 
			
		||||
		struct inotify_event *ie;
 | 
			
		||||
 | 
			
		||||
		// read out all pending events
 | 
			
		||||
		xioctl(pfd.fd, FIONREAD, &len);
 | 
			
		||||
#define eventbuf bb_common_bufsiz1
 | 
			
		||||
		ie = buf = (len <= sizeof(eventbuf)) ? eventbuf : xmalloc(len);
 | 
			
		||||
		len = full_read(pfd.fd, buf, len);
 | 
			
		||||
		// process events. N.B. events may vary in length
 | 
			
		||||
		while (len > 0) {
 | 
			
		||||
			int i;
 | 
			
		||||
			char events[12];
 | 
			
		||||
			char *s = events;
 | 
			
		||||
			unsigned m = ie->mask;
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < 12; ++i, m >>= 1) {
 | 
			
		||||
				if (m & 1) {
 | 
			
		||||
					*s++ = mask_names[i];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			*s = '\0';
 | 
			
		||||
//			bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, ie->mask, events, watched[ie->wd], ie->len ? ie->name : "");
 | 
			
		||||
			args[1] = events;
 | 
			
		||||
			args[2] = watched[ie->wd];
 | 
			
		||||
			args[3] = ie->len ? ie->name : NULL;
 | 
			
		||||
			xspawn((char **)args);
 | 
			
		||||
			// next event
 | 
			
		||||
			i = sizeof(struct inotify_event) + ie->len;
 | 
			
		||||
			len -= i;
 | 
			
		||||
			ie = (void*)((char*)ie + i);
 | 
			
		||||
		}
 | 
			
		||||
		if (eventbuf != buf)
 | 
			
		||||
			free(buf);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user