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 if (n < 0) { 141 perror("kqueue"); 142 exit(1); 143 } 144 145 if (elm->fd >= NumFiles) { 146 MaxFiles = (elm->fd + 16) * 3 / 2; 147 Elms = realloc(Elms, MaxFiles * sizeof(elm)); 148 bzero(&Elms[NumFiles], (MaxFiles - NumFiles) * sizeof(elm)); 149 NumFiles = MaxFiles; 150 } 151 Elms[elm->fd] = elm; 152 } 153 154 static 155 void 156 monitor_events(void) 157 { 158 struct kevent kev_array[1]; 159 struct kevent *kev; 160 monitor_elm_t elm; 161 struct stat st; 162 int bno; 163 int i; 164 int n; 165 166 n = kevent(KQueueFd, NULL, 0, kev_array, 1, NULL); 167 for (i = 0; i < n; ++i) { 168 kev = &kev_array[i]; 169 elm = Elms[kev->ident]; 170 printf("%-23s", elm->path); 171 if (VerboseOpt && fstat(kev->ident, &st) == 0 && 172 S_ISREG(st.st_mode)) { 173 printf(" %10jd", (intmax_t)st.st_size); 174 } 175 while (QuietOpt == 0 && (bno = ffs(kev->fflags)) > 0) { 176 printf(" "); 177 --bno; 178 kev->fflags &= ~(1 << bno); 179 switch(1 << bno) { 180 case NOTE_DELETE: 181 printf("delete"); 182 break; 183 case NOTE_WRITE: 184 printf("write"); 185 break; 186 case NOTE_EXTEND: 187 printf("extend"); 188 break; 189 case NOTE_ATTRIB: 190 printf("attrib"); 191 break; 192 case NOTE_LINK: 193 printf("link"); 194 break; 195 case NOTE_RENAME: 196 printf("rename"); 197 break; 198 case NOTE_REVOKE: 199 printf("revoke"); 200 break; 201 default: 202 printf("%08x", 1 << bno); 203 break; 204 } 205 } 206 printf("\n"); 207 } 208 } 209 210 static 211 void 212 usage(int exit_code) 213 { 214 fprintf(stderr, 215 "monitor [-vx] files...\n" 216 " -v Be more verbose\n" 217 " -x Exit after first event reported\n" 218 ); 219 exit(exit_code); 220 } 221 222