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 35 #include <sys/types.h> 36 #include <sys/event.h> 37 #include <sys/time.h> 38 #include <sys/stat.h> 39 #include <stdio.h> 40 #include <stdarg.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <string.h> 44 #include <fcntl.h> 45 46 typedef struct monitor_elm { 47 const char *path; 48 int fd; 49 } *monitor_elm_t; 50 51 static void usage(int exit_code); 52 static void monitor_add(const char *path); 53 static void monitor_events(void); 54 55 static int VerboseOpt; 56 static int QuietOpt; 57 static int ExitOpt; 58 static int KQueueFd; 59 static int NumFiles; 60 static int MaxFiles; 61 static monitor_elm_t *Elms; 62 63 int 64 main(int ac, char **av) 65 { 66 int ch; 67 int i; 68 69 while ((ch = getopt(ac, av, "qvx")) != -1) { 70 switch (ch) { 71 case 'q': 72 if (VerboseOpt > 0) 73 --VerboseOpt; 74 else 75 ++QuietOpt; 76 break; 77 case 'v': 78 if (QuietOpt > 0) 79 --QuietOpt; 80 else 81 ++VerboseOpt; 82 break; 83 case 'x': 84 ExitOpt = 1; 85 break; 86 default: 87 usage(1); 88 /* not reached */ 89 } 90 } 91 ac -= optind; 92 av += optind; 93 94 if (ac < 1) { 95 usage(1); 96 /* not reached */ 97 } 98 99 if ((KQueueFd = kqueue()) < 0) { 100 perror("kqueue"); 101 exit(1); 102 } 103 NumFiles = MaxFiles = 16; 104 Elms = calloc(MaxFiles, sizeof(monitor_elm_t)); 105 106 for (i = 0; i < ac; ++i) { 107 monitor_add(av[i]); 108 } 109 fflush(stdout); 110 do { 111 monitor_events(); 112 fflush(stdout); 113 } while (ExitOpt == 0); 114 exit(0); 115 } 116 117 static 118 void 119 monitor_add(const char *path) 120 { 121 monitor_elm_t elm; 122 struct kevent kev; 123 int n; 124 125 elm = malloc(sizeof(*elm)); 126 bzero(elm, sizeof(*elm)); 127 elm->path = path; 128 elm->fd = open(path, O_RDONLY); 129 if (elm->fd < 0) { 130 printf("%s\tnot found\n", path); 131 return; 132 } 133 EV_SET(&kev, elm->fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR, 134 NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB| 135 NOTE_LINK|NOTE_RENAME|NOTE_REVOKE, 136 0, NULL); 137 n = kevent(KQueueFd, &kev, 1, NULL, 0, NULL); 138 if (n < 0) { 139 perror("kqueue"); 140 exit(1); 141 } 142 143 if (elm->fd >= NumFiles) { 144 MaxFiles = (elm->fd + 16) * 3 / 2; 145 Elms = realloc(Elms, MaxFiles * sizeof(elm)); 146 bzero(&Elms[NumFiles], (MaxFiles - NumFiles) * sizeof(elm)); 147 NumFiles = MaxFiles; 148 } 149 Elms[elm->fd] = elm; 150 } 151 152 static 153 void 154 monitor_events(void) 155 { 156 struct kevent kev_array[1]; 157 struct kevent *kev; 158 monitor_elm_t elm; 159 struct stat st; 160 int bno; 161 int i; 162 int n; 163 164 n = kevent(KQueueFd, NULL, 0, kev_array, 1, NULL); 165 for (i = 0; i < n; ++i) { 166 kev = &kev_array[i]; 167 elm = Elms[kev->ident]; 168 printf("%-23s", elm->path); 169 if (VerboseOpt && fstat(kev->ident, &st) == 0 && 170 S_ISREG(st.st_mode)) { 171 printf(" %10jd", (intmax_t)st.st_size); 172 } 173 while (QuietOpt == 0 && (bno = ffs(kev->fflags)) > 0) { 174 printf(" "); 175 --bno; 176 kev->fflags &= ~(1 << bno); 177 switch (1 << bno) { 178 case NOTE_DELETE: 179 printf("delete"); 180 break; 181 case NOTE_WRITE: 182 printf("write"); 183 break; 184 case NOTE_EXTEND: 185 printf("extend"); 186 break; 187 case NOTE_ATTRIB: 188 printf("attrib"); 189 break; 190 case NOTE_LINK: 191 printf("link"); 192 break; 193 case NOTE_RENAME: 194 printf("rename"); 195 break; 196 case NOTE_REVOKE: 197 printf("revoke"); 198 break; 199 default: 200 printf("%08x", 1 << bno); 201 break; 202 } 203 } 204 printf("\n"); 205 } 206 } 207 208 static 209 void 210 usage(int exit_code) 211 { 212 fprintf(stderr, 213 "monitor [-vx] files...\n" 214 " -v Be more verbose\n" 215 " -x Exit after first event reported\n" 216 ); 217 exit(exit_code); 218 } 219 220