1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/usr.bin/monitor/monitor.c,v 1.1 2008/10/16 17:23:20 dillon Exp $ 35 */ 36 37 #include <sys/types.h> 38 #include <sys/event.h> 39 #include <sys/time.h> 40 #include <sys/stat.h> 41 #include <stdio.h> 42 #include <stdarg.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include <string.h> 46 #include <fcntl.h> 47 48 typedef struct monitor_elm { 49 const char *path; 50 int fd; 51 } *monitor_elm_t; 52 53 static void usage(int exit_code); 54 static void monitor_add(const char *path); 55 static void monitor_events(void); 56 57 static int VerboseOpt; 58 static int QuietOpt; 59 static int ExitOpt; 60 static int KQueueFd; 61 static int NumFiles; 62 static int MaxFiles; 63 static monitor_elm_t *Elms; 64 65 int 66 main(int ac, char **av) 67 { 68 int ch; 69 int i; 70 71 while ((ch = getopt(ac, av, "qvx")) != -1) { 72 switch(ch) { 73 case 'q': 74 if (VerboseOpt > 0) 75 --VerboseOpt; 76 else 77 ++QuietOpt; 78 break; 79 case 'v': 80 if (QuietOpt > 0) 81 --QuietOpt; 82 else 83 ++VerboseOpt; 84 break; 85 case 'x': 86 ExitOpt = 1; 87 break; 88 default: 89 usage(1); 90 /* not reached */ 91 } 92 } 93 ac -= optind; 94 av += optind; 95 96 if (ac < 1) { 97 usage(1); 98 /* not reached */ 99 } 100 101 if ((KQueueFd = kqueue()) < 0) { 102 perror("kqueue"); 103 exit(1); 104 } 105 NumFiles = MaxFiles = 16; 106 Elms = calloc(MaxFiles, sizeof(monitor_elm_t)); 107 108 for (i = 0; i < ac; ++i) { 109 monitor_add(av[i]); 110 } 111 fflush(stdout); 112 do { 113 monitor_events(); 114 fflush(stdout); 115 } while (ExitOpt == 0); 116 exit(0); 117 } 118 119 static 120 void 121 monitor_add(const char *path) 122 { 123 monitor_elm_t elm; 124 struct kevent kev; 125 int n; 126 127 elm = malloc(sizeof(*elm)); 128 bzero(elm, sizeof(*elm)); 129 elm->path = path; 130 elm->fd = open(path, O_RDONLY); 131 if (elm->fd < 0) { 132 printf("%s\tnot found\n", path); 133 return; 134 } 135 EV_SET(&kev, elm->fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR, 136 NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB| 137 NOTE_LINK|NOTE_RENAME|NOTE_REVOKE, 138 0, NULL); 139 n = kevent(KQueueFd, &kev, 1, NULL, 0, NULL); 140 141 if (elm->fd >= NumFiles) { 142 MaxFiles = (elm->fd + 16) * 3 / 2; 143 Elms = realloc(Elms, MaxFiles * sizeof(elm)); 144 bzero(&Elms[NumFiles], (MaxFiles - NumFiles) * sizeof(elm)); 145 NumFiles = MaxFiles; 146 } 147 Elms[elm->fd] = elm; 148 } 149 150 static 151 void 152 monitor_events(void) 153 { 154 struct kevent kev_array[1]; 155 struct kevent *kev; 156 monitor_elm_t elm; 157 struct stat st; 158 int bno; 159 int i; 160 int n; 161 162 n = kevent(KQueueFd, NULL, 0, kev_array, 1, NULL); 163 for (i = 0; i < n; ++i) { 164 kev = &kev_array[i]; 165 elm = Elms[kev->ident]; 166 printf("%-23s", elm->path); 167 if (VerboseOpt && fstat(kev->ident, &st) == 0 && 168 S_ISREG(st.st_mode)) { 169 printf(" %10jd", (intmax_t)st.st_size); 170 } 171 while (QuietOpt == 0 && (bno = ffs(kev->fflags)) > 0) { 172 printf(" "); 173 --bno; 174 kev->fflags &= ~(1 << bno); 175 switch(1 << bno) { 176 case NOTE_DELETE: 177 printf("delete"); 178 break; 179 case NOTE_WRITE: 180 printf("write"); 181 break; 182 case NOTE_EXTEND: 183 printf("extend"); 184 break; 185 case NOTE_ATTRIB: 186 printf("attrib"); 187 break; 188 case NOTE_LINK: 189 printf("link"); 190 break; 191 case NOTE_RENAME: 192 printf("rename"); 193 break; 194 case NOTE_REVOKE: 195 printf("revoke"); 196 break; 197 default: 198 printf("%08x", 1 << bno); 199 break; 200 } 201 } 202 printf("\n"); 203 } 204 } 205 206 static 207 void 208 usage(int exit_code) 209 { 210 fprintf(stderr, 211 "monitor [-vx] files...\n" 212 " -v Be more verbose\n" 213 " -x Exit after first event reported\n" 214 ); 215 exit(exit_code); 216 } 217 218