From 1e3b54fcb93e2db160a5da345060dca68464a9c5 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 16 Oct 2008 17:23:20 +0000 Subject: [PATCH] Add a new utility called 'monitor' which uses kqueue to monitor a list of files and directories specified on the command line. --- usr.bin/Makefile | 3 +- usr.bin/monitor/Makefile | 6 ++ usr.bin/monitor/monitor.1 | 69 ++++++++++++ usr.bin/monitor/monitor.c | 217 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 usr.bin/monitor/Makefile create mode 100644 usr.bin/monitor/monitor.1 create mode 100644 usr.bin/monitor/monitor.c diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 34cec791fc..002fbd6ef7 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -1,6 +1,6 @@ # From: @(#)Makefile 8.3 (Berkeley) 1/7/94 # $FreeBSD: src/usr.bin/Makefile,v 1.144.2.17 2003/01/04 17:17:07 obrien Exp $ -# $DragonFly: src/usr.bin/Makefile,v 1.45 2008/07/12 14:57:33 pavalos Exp $ +# $DragonFly: src/usr.bin/Makefile,v 1.46 2008/10/16 17:23:18 dillon Exp $ # XXX MISSING: deroff diction graph learn plot # spell spline struct xsend @@ -118,6 +118,7 @@ SUBDIR= alias \ mklocale \ mkstr \ mktemp \ + monitor \ msgs \ mt \ ncal \ diff --git a/usr.bin/monitor/Makefile b/usr.bin/monitor/Makefile new file mode 100644 index 0000000000..6bb73d88f0 --- /dev/null +++ b/usr.bin/monitor/Makefile @@ -0,0 +1,6 @@ +# +# $DragonFly: src/usr.bin/monitor/Makefile,v 1.1 2008/10/16 17:23:20 dillon Exp $ + +PROG= monitor + +.include diff --git a/usr.bin/monitor/monitor.1 b/usr.bin/monitor/monitor.1 new file mode 100644 index 0000000000..f5d1498e98 --- /dev/null +++ b/usr.bin/monitor/monitor.1 @@ -0,0 +1,69 @@ +.\" Copyright (c) 2008 The DragonFly Project. All rights reserved. +.\" +.\" This code is derived from software contributed to The DragonFly Project +.\" by Matthew Dillon +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" 3. Neither the name of The DragonFly Project nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific, prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, +.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $DragonFly: src/usr.bin/monitor/monitor.1,v 1.1 2008/10/16 17:23:20 dillon Exp $ +.Dd October 16, 2008 +.Dt MONITOR 1 +.Os +.Sh NAME +.Nm monitor +.Nd File and directory monitoring utility +.Sh SYNOPSIS +.Nm +.Op Fl qvx +.Ar files +.Sh DESCRIPTION +The +.Nm +utility monitors one or more files or directories and outputs the +appropriate file name to stdout whenever a change occurs. +Supported options are as follows: +.Bl -tag -width indent +.It Fl q +Be more quiet. +Specifying this option will cause only the file paths to be output. +.It Fl v +Be more verbose. +.It Fl x +Exit after first hit. +.Nm +will exit after reporting the first event. +.El +.\".Sh EXAMPLES +.\".Sh SEE ALSO +.Sh HISTORY +The +.Nm +utility first appeared in +.Dx 2.1 . +.Sh AUTHORS +.An Matthew Dillon Aq dillon@backplane.com diff --git a/usr.bin/monitor/monitor.c b/usr.bin/monitor/monitor.c new file mode 100644 index 0000000000..18b5e3ab5b --- /dev/null +++ b/usr.bin/monitor/monitor.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2008 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/usr.bin/monitor/monitor.c,v 1.1 2008/10/16 17:23:20 dillon Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct monitor_elm { + const char *path; + int fd; +} *monitor_elm_t; + +static void usage(int exit_code); +static void monitor_add(const char *path); +static void monitor_events(void); + +static int VerboseOpt; +static int QuietOpt; +static int ExitOpt; +static int KQueueFd; +static int NumFiles; +static int MaxFiles; +static monitor_elm_t *Elms; + +int +main(int ac, char **av) +{ + int ch; + int i; + + while ((ch = getopt(ac, av, "qvx")) != -1) { + switch(ch) { + case 'q': + if (VerboseOpt > 0) + --VerboseOpt; + else + ++QuietOpt; + break; + case 'v': + if (QuietOpt > 0) + --QuietOpt; + else + ++VerboseOpt; + break; + case 'x': + ExitOpt = 1; + break; + default: + usage(1); + /* not reached */ + } + } + ac -= optind; + av += optind; + + if (ac < 1) { + usage(1); + /* not reached */ + } + + if ((KQueueFd = kqueue()) < 0) { + perror("kqueue"); + exit(1); + } + NumFiles = MaxFiles = 16; + Elms = calloc(MaxFiles, sizeof(monitor_elm_t)); + + for (i = 0; i < ac; ++i) { + monitor_add(av[i]); + } + fflush(stdout); + do { + monitor_events(); + fflush(stdout); + } while (ExitOpt == 0); + exit(0); +} + +static +void +monitor_add(const char *path) +{ + monitor_elm_t elm; + struct kevent kev; + int n; + + elm = malloc(sizeof(*elm)); + bzero(elm, sizeof(*elm)); + elm->path = path; + elm->fd = open(path, O_RDONLY); + if (elm->fd < 0) { + printf("%s\tnot found\n", path); + return; + } + EV_SET(&kev, elm->fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR, + NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB| + NOTE_LINK|NOTE_RENAME|NOTE_REVOKE, + 0, NULL); + n = kevent(KQueueFd, &kev, 1, NULL, 0, NULL); + + if (elm->fd >= NumFiles) { + MaxFiles = (elm->fd + 16) * 3 / 2; + Elms = realloc(Elms, MaxFiles * sizeof(elm)); + bzero(&Elms[NumFiles], (NumFiles - MaxFiles) * sizeof(elm)); + NumFiles = MaxFiles; + } + Elms[elm->fd] = elm; +} + +static +void +monitor_events(void) +{ + struct kevent kev_array[1]; + struct kevent *kev; + monitor_elm_t elm; + struct stat st; + int bno; + int i; + int n; + + n = kevent(KQueueFd, NULL, 0, kev_array, 1, NULL); + for (i = 0; i < n; ++i) { + kev = &kev_array[i]; + elm = Elms[kev->ident]; + printf("%-23s", elm->path); + if (VerboseOpt && fstat(kev->ident, &st) == 0 && + S_ISREG(st.st_mode)) { + printf(" %10lld", st.st_size); + } + while (QuietOpt == 0 && (bno = ffs(kev->fflags)) > 0) { + printf(" "); + --bno; + kev->fflags &= ~(1 << bno); + switch(1 << bno) { + case NOTE_DELETE: + printf("delete"); + break; + case NOTE_WRITE: + printf("write"); + break; + case NOTE_EXTEND: + printf("extend"); + break; + case NOTE_ATTRIB: + printf("attrib"); + break; + case NOTE_LINK: + printf("link"); + break; + case NOTE_RENAME: + printf("rename"); + break; + case NOTE_REVOKE: + printf("revoke"); + break; + default: + printf("%08x", 1 << bno); + break; + } + } + printf("\n"); + } +} + +static +void +usage(int exit_code) +{ + fprintf(stderr, + "monitor [-vx] files...\n" + " -v Be more verbose\n" + " -x Exit after first event reported\n" + ); + exit(exit_code); +} + -- 2.41.0