| [261] | 1 | /* SAMHAIN file system integrity testing                                   */ | 
|---|
|  | 2 | /* Copyright (C) 2009 Rainer Wichmann                                      */ | 
|---|
|  | 3 | /*                                                                         */ | 
|---|
|  | 4 | /*  This program is free software; you can redistribute it                 */ | 
|---|
|  | 5 | /*  and/or modify                                                          */ | 
|---|
|  | 6 | /*  it under the terms of the GNU General Public License as                */ | 
|---|
|  | 7 | /*  published by                                                           */ | 
|---|
|  | 8 | /*  the Free Software Foundation; either version 2 of the License, or      */ | 
|---|
|  | 9 | /*  (at your option) any later version.                                    */ | 
|---|
|  | 10 | /*                                                                         */ | 
|---|
|  | 11 | /*  This program is distributed in the hope that it will be useful,        */ | 
|---|
|  | 12 | /*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */ | 
|---|
|  | 13 | /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */ | 
|---|
|  | 14 | /*  GNU General Public License for more details.                           */ | 
|---|
|  | 15 | /*                                                                         */ | 
|---|
|  | 16 | /*  You should have received a copy of the GNU General Public License      */ | 
|---|
|  | 17 | /*  along with this program; if not, write to the Free Software            */ | 
|---|
|  | 18 | /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */ | 
|---|
|  | 19 |  | 
|---|
|  | 20 | #include "config_xor.h" | 
|---|
|  | 21 |  | 
|---|
|  | 22 | #if defined(HAVE_SYS_INOTIFY_H) | 
|---|
|  | 23 |  | 
|---|
| [474] | 24 | #if defined(GCC_VERSION_MAJOR) && !defined(__clang__) | 
|---|
| [465] | 25 | #if (GCC_VERSION_MAJOR > 4) || ((GCC_VERSION_MAJOR == 4) && (GCC_VERSION_MINOR > 8)) | 
|---|
|  | 26 | #pragma GCC diagnostic ignored "-Wclobbered" | 
|---|
|  | 27 | #endif | 
|---|
|  | 28 | #endif | 
|---|
|  | 29 |  | 
|---|
| [261] | 30 | #undef  FIL__ | 
|---|
|  | 31 | #define FIL__  _("sh_inotify.c") | 
|---|
|  | 32 |  | 
|---|
|  | 33 | /* printf */ | 
|---|
|  | 34 | #include <stdio.h> | 
|---|
|  | 35 | #include <stdlib.h> | 
|---|
|  | 36 | #include <string.h> | 
|---|
|  | 37 | #include <sys/inotify.h> | 
|---|
|  | 38 | #include <errno.h> | 
|---|
|  | 39 | #include <unistd.h> | 
|---|
|  | 40 | #include <fcntl.h> | 
|---|
|  | 41 |  | 
|---|
|  | 42 | #include "samhain.h" | 
|---|
|  | 43 | #include "sh_pthread.h" | 
|---|
|  | 44 | #include "sh_calls.h" | 
|---|
|  | 45 | #include "sh_inotify.h" | 
|---|
|  | 46 | #include "sh_mem.h" | 
|---|
| [364] | 47 | #include "sh_utils.h" | 
|---|
| [261] | 48 | #include "slib.h" | 
|---|
|  | 49 |  | 
|---|
|  | 50 | /************************************************** | 
|---|
|  | 51 | * | 
|---|
|  | 52 | * Make the inotify fd thread-specific by | 
|---|
|  | 53 | * encapsulating it in get/set functions: | 
|---|
|  | 54 | * sh_get_inotify_fd() / sh_set_inotify_fd() | 
|---|
|  | 55 | * | 
|---|
|  | 56 | **************************************************/ | 
|---|
|  | 57 |  | 
|---|
|  | 58 | #if defined(HAVE_PTHREAD) | 
|---|
| [367] | 59 |  | 
|---|
|  | 60 | SH_MUTEX_STATIC(mutex_list_dormant, PTHREAD_MUTEX_INITIALIZER); | 
|---|
|  | 61 | SH_MUTEX_STATIC(mutex_watches,      PTHREAD_MUTEX_INITIALIZER); | 
|---|
|  | 62 |  | 
|---|
| [261] | 63 | static pthread_key_t  inotify_key; | 
|---|
|  | 64 | static pthread_once_t inotify_key_once = PTHREAD_ONCE_INIT; | 
|---|
|  | 65 |  | 
|---|
|  | 66 | static void make_inotify_key() | 
|---|
|  | 67 | { | 
|---|
|  | 68 | (void) pthread_key_create(&inotify_key, free); | 
|---|
|  | 69 | } | 
|---|
|  | 70 |  | 
|---|
|  | 71 | static int sh_get_inotify_fd() | 
|---|
|  | 72 | { | 
|---|
|  | 73 | void * ptr; | 
|---|
|  | 74 | int  * fp; | 
|---|
|  | 75 |  | 
|---|
|  | 76 | (void) pthread_once(&inotify_key_once, make_inotify_key); | 
|---|
|  | 77 |  | 
|---|
|  | 78 | if ((ptr = pthread_getspecific(inotify_key)) == NULL) | 
|---|
|  | 79 | { | 
|---|
| [454] | 80 | ptr = calloc(1,sizeof(int)); | 
|---|
| [261] | 81 | if (ptr) | 
|---|
|  | 82 | { | 
|---|
|  | 83 | fp  = (int*) ptr; | 
|---|
|  | 84 | *fp = -1; | 
|---|
|  | 85 | (void) pthread_setspecific(inotify_key, ptr); | 
|---|
|  | 86 | } | 
|---|
|  | 87 | else | 
|---|
|  | 88 | { | 
|---|
|  | 89 | return -1; | 
|---|
|  | 90 | } | 
|---|
|  | 91 | } | 
|---|
|  | 92 | else | 
|---|
|  | 93 | { | 
|---|
|  | 94 | fp  = (int*) ptr; | 
|---|
|  | 95 | } | 
|---|
|  | 96 | return *fp; | 
|---|
|  | 97 | } | 
|---|
|  | 98 |  | 
|---|
|  | 99 | static void sh_set_inotify_fd(int fd) | 
|---|
|  | 100 | { | 
|---|
|  | 101 | int  * fp; | 
|---|
|  | 102 |  | 
|---|
|  | 103 | fp = (int*) pthread_getspecific(inotify_key); | 
|---|
|  | 104 | if (fp) | 
|---|
|  | 105 | *fp = fd; | 
|---|
|  | 106 | return; | 
|---|
|  | 107 | } | 
|---|
|  | 108 |  | 
|---|
|  | 109 | /* !defined(HAVE_PTHREAD) */ | 
|---|
|  | 110 | #else | 
|---|
|  | 111 |  | 
|---|
|  | 112 | static int sh_inotify_fd = -1; | 
|---|
|  | 113 |  | 
|---|
|  | 114 | static inline int sh_get_inotify_fd() | 
|---|
|  | 115 | { | 
|---|
|  | 116 | return sh_inotify_fd; | 
|---|
|  | 117 | } | 
|---|
|  | 118 |  | 
|---|
|  | 119 | static inline void sh_set_inotify_fd(int fd) | 
|---|
|  | 120 | { | 
|---|
|  | 121 | sh_inotify_fd = fd; | 
|---|
|  | 122 | } | 
|---|
|  | 123 |  | 
|---|
|  | 124 | #endif | 
|---|
|  | 125 |  | 
|---|
|  | 126 | /*--- nothing thread-related below this point --- */ | 
|---|
|  | 127 |  | 
|---|
| [364] | 128 | #include "zAVLTree.h" | 
|---|
| [261] | 129 |  | 
|---|
| [364] | 130 | typedef struct | 
|---|
|  | 131 | { | 
|---|
|  | 132 | int    watch; | 
|---|
| [372] | 133 | short  flag; | 
|---|
|  | 134 | short  type; | 
|---|
| [367] | 135 | int    class; | 
|---|
| [373] | 136 | int    rdepth; | 
|---|
| [481] | 137 | unsigned long check_flags; | 
|---|
| [364] | 138 | char * file; | 
|---|
|  | 139 | } sh_watch; | 
|---|
|  | 140 |  | 
|---|
| [261] | 141 | /************************************************** | 
|---|
|  | 142 | * | 
|---|
|  | 143 | * Get inotify fd, initialize inotify if necessary | 
|---|
|  | 144 | * | 
|---|
|  | 145 | **************************************************/ | 
|---|
|  | 146 | #define SH_INOTIFY_FAILED -2 | 
|---|
|  | 147 |  | 
|---|
|  | 148 | static int sh_inotify_getfd() | 
|---|
|  | 149 | { | 
|---|
|  | 150 | int ifd = sh_get_inotify_fd(); | 
|---|
|  | 151 |  | 
|---|
|  | 152 | if (ifd >= 0) | 
|---|
|  | 153 | { | 
|---|
|  | 154 | return ifd; | 
|---|
|  | 155 | } | 
|---|
|  | 156 |  | 
|---|
|  | 157 | else if (ifd == SH_INOTIFY_FAILED) | 
|---|
|  | 158 | { | 
|---|
|  | 159 | return -1; | 
|---|
|  | 160 | } | 
|---|
|  | 161 |  | 
|---|
|  | 162 | else /* if (ifd == -1) */ | 
|---|
|  | 163 | { | 
|---|
|  | 164 | #if defined(HAVE_INOTIFY_INIT1) | 
|---|
|  | 165 | ifd = inotify_init1(IN_CLOEXEC); | 
|---|
|  | 166 | #else | 
|---|
|  | 167 | ifd = inotify_init(); | 
|---|
|  | 168 | if (ifd >= 0) | 
|---|
|  | 169 | { | 
|---|
|  | 170 | long sflags; | 
|---|
|  | 171 |  | 
|---|
| [268] | 172 | sflags = retry_fcntl(FIL__, __LINE__, ifd, F_GETFD, 0); | 
|---|
|  | 173 | retry_fcntl(FIL__, __LINE__, ifd, F_SETFD, sflags|FD_CLOEXEC); | 
|---|
| [261] | 174 | } | 
|---|
|  | 175 | #endif | 
|---|
|  | 176 |  | 
|---|
|  | 177 | if (ifd < 0) | 
|---|
|  | 178 | { | 
|---|
|  | 179 | sh_set_inotify_fd(SH_INOTIFY_FAILED); | 
|---|
|  | 180 | return -1; | 
|---|
|  | 181 | } | 
|---|
|  | 182 |  | 
|---|
|  | 183 | sh_set_inotify_fd(ifd); | 
|---|
|  | 184 | return ifd; | 
|---|
|  | 185 | } | 
|---|
|  | 186 | } | 
|---|
|  | 187 |  | 
|---|
|  | 188 | /************************************************** | 
|---|
|  | 189 | * | 
|---|
|  | 190 | * Public function: | 
|---|
|  | 191 | *  int sh_inotify_wait_for_change(char * filename, | 
|---|
|  | 192 | *                                 int watch, | 
|---|
|  | 193 | *                                 int * errnum, | 
|---|
|  | 194 | *                                 int   waitsec); | 
|---|
|  | 195 | * Returns: watch, if nonnegative | 
|---|
|  | 196 | *          -1 on error or reopen required | 
|---|
|  | 197 | *             (check errnum != 0) | 
|---|
|  | 198 | * | 
|---|
|  | 199 | * Caller needs to keep track of watch descriptor | 
|---|
|  | 200 | * | 
|---|
|  | 201 | **************************************************/ | 
|---|
|  | 202 |  | 
|---|
|  | 203 | #define SH_INOTIFY_REOPEN 0 | 
|---|
|  | 204 | #define SH_INOTIFY_MODIFY 1 | 
|---|
|  | 205 |  | 
|---|
| [367] | 206 | void sh_inotify_init(sh_watches * watches) | 
|---|
| [261] | 207 | { | 
|---|
| [367] | 208 | SH_MUTEX_LOCK_UNSAFE(mutex_watches); | 
|---|
| [364] | 209 | watches->list_of_watches = NULL; | 
|---|
|  | 210 | watches->count           = 0; | 
|---|
|  | 211 | watches->max_count       = 0; | 
|---|
| [367] | 212 | SH_MUTEX_UNLOCK_UNSAFE(mutex_watches); | 
|---|
|  | 213 |  | 
|---|
|  | 214 | SH_MUTEX_LOCK_UNSAFE(mutex_list_dormant); | 
|---|
|  | 215 | watches->dormant_watches = NULL; | 
|---|
|  | 216 | SH_MUTEX_UNLOCK_UNSAFE(mutex_list_dormant); | 
|---|
|  | 217 |  | 
|---|
| [364] | 218 | return; | 
|---|
|  | 219 | } | 
|---|
| [261] | 220 |  | 
|---|
| [367] | 221 | ssize_t sh_inotify_read(char * buffer, size_t count) | 
|---|
|  | 222 | { | 
|---|
| [371] | 223 | ssize_t len = -1; | 
|---|
| [367] | 224 | int     ifd = sh_inotify_getfd(); | 
|---|
|  | 225 |  | 
|---|
|  | 226 | do { | 
|---|
| [369] | 227 | len = read (ifd, buffer, count); | 
|---|
| [371] | 228 | } while (len < 0 && (errno == EINTR || errno == EAGAIN)); | 
|---|
| [367] | 229 |  | 
|---|
|  | 230 | return len; | 
|---|
|  | 231 | } | 
|---|
|  | 232 |  | 
|---|
| [371] | 233 | ssize_t sh_inotify_read_timeout(char * buffer, size_t count, int timeout) | 
|---|
|  | 234 | { | 
|---|
|  | 235 | ssize_t len; | 
|---|
|  | 236 | int     ifd = sh_inotify_getfd(); | 
|---|
|  | 237 |  | 
|---|
| [568] | 238 | len = sl_read_timeout_fd_once (ifd, buffer, count, timeout, S_FALSE); | 
|---|
| [371] | 239 |  | 
|---|
|  | 240 | return len; | 
|---|
|  | 241 | } | 
|---|
|  | 242 |  | 
|---|
|  | 243 |  | 
|---|
| [364] | 244 | static void sh_inotify_free_watch(void * item) | 
|---|
|  | 245 | { | 
|---|
|  | 246 | sh_watch * this = (sh_watch *) item; | 
|---|
|  | 247 |  | 
|---|
|  | 248 | if (this->file) | 
|---|
|  | 249 | SH_FREE(this->file); | 
|---|
|  | 250 | SH_FREE(this); | 
|---|
|  | 251 | return; | 
|---|
|  | 252 | } | 
|---|
|  | 253 |  | 
|---|
| [382] | 254 | static sh_watch * sh_inotify_create_watch(const char * file, | 
|---|
|  | 255 | int nwatch, int flag) | 
|---|
| [364] | 256 | { | 
|---|
|  | 257 | sh_watch * this = SH_ALLOC(sizeof(sh_watch)); | 
|---|
|  | 258 |  | 
|---|
| [382] | 259 | this->file  = sh_util_strdup_track(file, __FILE__, __LINE__); | 
|---|
| [364] | 260 | this->watch = nwatch; | 
|---|
|  | 261 | this->flag  = flag; | 
|---|
|  | 262 | return this; | 
|---|
|  | 263 | } | 
|---|
|  | 264 |  | 
|---|
|  | 265 | /********** List Handling ******************/ | 
|---|
|  | 266 |  | 
|---|
|  | 267 | struct sh_inotify_litem | 
|---|
|  | 268 | { | 
|---|
|  | 269 | sh_watch * watch; | 
|---|
|  | 270 | struct sh_inotify_litem * next; | 
|---|
|  | 271 | }; | 
|---|
|  | 272 |  | 
|---|
| [367] | 273 | static void sh_inotify_listitem_destroy(struct sh_inotify_litem * this) | 
|---|
|  | 274 | { | 
|---|
|  | 275 | if (this) | 
|---|
|  | 276 | SH_FREE(this); | 
|---|
|  | 277 | return; | 
|---|
|  | 278 | } | 
|---|
|  | 279 |  | 
|---|
|  | 280 | /* No Mutex in the list cursor functions, must be in the caller | 
|---|
|  | 281 | * function... | 
|---|
|  | 282 | */ | 
|---|
| [364] | 283 | typedef struct { | 
|---|
|  | 284 | struct sh_inotify_litem *prenode; | 
|---|
|  | 285 | struct sh_inotify_litem *curnode; | 
|---|
|  | 286 | } sh_inotify_listCursor; | 
|---|
|  | 287 |  | 
|---|
| [367] | 288 | static sh_watch * sh_inotify_list_first(sh_inotify_listCursor * listcursor, | 
|---|
|  | 289 | sh_watches * watches) | 
|---|
| [364] | 290 | { | 
|---|
|  | 291 | listcursor->prenode = watches->dormant_watches; | 
|---|
|  | 292 | listcursor->curnode = watches->dormant_watches; | 
|---|
|  | 293 |  | 
|---|
| [367] | 294 | if (listcursor->curnode) | 
|---|
|  | 295 | return listcursor->curnode->watch; | 
|---|
|  | 296 | return NULL; | 
|---|
| [364] | 297 | } | 
|---|
|  | 298 |  | 
|---|
| [367] | 299 | static sh_watch * sh_inotify_list_next(sh_inotify_listCursor * listcursor, | 
|---|
|  | 300 | sh_watches * watches) | 
|---|
| [364] | 301 | { | 
|---|
|  | 302 | (void) watches; | 
|---|
|  | 303 |  | 
|---|
|  | 304 | listcursor->prenode = listcursor->curnode; | 
|---|
|  | 305 |  | 
|---|
|  | 306 | if (listcursor->curnode) | 
|---|
| [367] | 307 | { | 
|---|
|  | 308 | listcursor->curnode = listcursor->curnode->next; | 
|---|
| [371] | 309 | if (listcursor->curnode) | 
|---|
|  | 310 | return listcursor->curnode->watch; | 
|---|
|  | 311 | else | 
|---|
|  | 312 | return NULL; | 
|---|
| [367] | 313 | } | 
|---|
|  | 314 |  | 
|---|
| [364] | 315 | return NULL; | 
|---|
|  | 316 | } | 
|---|
|  | 317 |  | 
|---|
| [367] | 318 | static sh_watch * sh_inotify_list_del_cur(sh_inotify_listCursor * listcursor, | 
|---|
|  | 319 | sh_watches * watches) | 
|---|
| [364] | 320 | { | 
|---|
|  | 321 | sh_watch * ret = NULL; | 
|---|
|  | 322 |  | 
|---|
|  | 323 | if (listcursor->curnode) | 
|---|
| [261] | 324 | { | 
|---|
| [364] | 325 | struct sh_inotify_litem * this = listcursor->curnode; | 
|---|
|  | 326 |  | 
|---|
|  | 327 | if (listcursor->prenode == this) | 
|---|
| [261] | 328 | { | 
|---|
| [364] | 329 | watches->dormant_watches = this->next; | 
|---|
|  | 330 |  | 
|---|
|  | 331 | listcursor->prenode = watches->dormant_watches; | 
|---|
|  | 332 | listcursor->curnode = watches->dormant_watches; | 
|---|
| [261] | 333 | } | 
|---|
| [364] | 334 | else | 
|---|
|  | 335 | { | 
|---|
|  | 336 | listcursor->prenode->next = this->next; | 
|---|
|  | 337 | listcursor->curnode       = this->next; | 
|---|
|  | 338 | } | 
|---|
| [367] | 339 | if (listcursor->curnode) | 
|---|
|  | 340 | ret = listcursor->curnode->watch; | 
|---|
|  | 341 | else | 
|---|
|  | 342 | ret = NULL; | 
|---|
| [364] | 343 | sh_inotify_listitem_destroy(this); | 
|---|
| [261] | 344 | } | 
|---|
| [364] | 345 | return ret; | 
|---|
|  | 346 | } | 
|---|
|  | 347 |  | 
|---|
|  | 348 | static int sh_inotify_add_dormant(sh_watches * watches, sh_watch * item) | 
|---|
|  | 349 | { | 
|---|
| [367] | 350 | struct sh_inotify_litem * this; | 
|---|
| [364] | 351 |  | 
|---|
| [367] | 352 | SH_MUTEX_LOCK(mutex_list_dormant); | 
|---|
|  | 353 | this = SH_ALLOC(sizeof(struct sh_inotify_litem)); | 
|---|
|  | 354 |  | 
|---|
| [364] | 355 | this->watch = item; | 
|---|
|  | 356 | this->next  = (struct sh_inotify_litem *) watches->dormant_watches; | 
|---|
|  | 357 |  | 
|---|
|  | 358 | watches->dormant_watches = this; | 
|---|
| [367] | 359 | SH_MUTEX_UNLOCK(mutex_list_dormant); | 
|---|
| [364] | 360 | return 0; | 
|---|
|  | 361 | } | 
|---|
|  | 362 |  | 
|---|
| [367] | 363 | static void * sh_dummy_popret = NULL; | 
|---|
|  | 364 |  | 
|---|
|  | 365 | char * sh_inotify_pop_dormant(sh_watches * watches, | 
|---|
| [481] | 366 | int * class, unsigned long * check_flags, | 
|---|
| [373] | 367 | int * type, int * rdepth) | 
|---|
| [367] | 368 | { | 
|---|
|  | 369 | char * popret = NULL; | 
|---|
|  | 370 | struct sh_inotify_litem * this; | 
|---|
|  | 371 |  | 
|---|
|  | 372 | /* Take the address to keep gcc from putting it into a register. | 
|---|
|  | 373 | * Avoids the 'clobbered by longjmp' warning. | 
|---|
|  | 374 | */ | 
|---|
|  | 375 | sh_dummy_popret = (void *) &popret; | 
|---|
|  | 376 |  | 
|---|
|  | 377 | SH_MUTEX_LOCK(mutex_list_dormant); | 
|---|
|  | 378 |  | 
|---|
|  | 379 | this = (struct sh_inotify_litem *) watches->dormant_watches; | 
|---|
|  | 380 |  | 
|---|
|  | 381 | if (this) | 
|---|
|  | 382 | { | 
|---|
| [373] | 383 | *class  = this->watch->class; | 
|---|
|  | 384 | *type   = this->watch->type; | 
|---|
|  | 385 | *rdepth = this->watch->rdepth; | 
|---|
| [481] | 386 | *check_flags = this->watch->check_flags; | 
|---|
| [382] | 387 | popret  = sh_util_strdup_track(this->watch->file, __FILE__, __LINE__); | 
|---|
| [367] | 388 |  | 
|---|
|  | 389 | watches->dormant_watches = this->next; | 
|---|
|  | 390 |  | 
|---|
|  | 391 | sh_inotify_free_watch(this->watch); | 
|---|
|  | 392 | SH_FREE(this); | 
|---|
|  | 393 | } | 
|---|
|  | 394 | SH_MUTEX_UNLOCK(mutex_list_dormant); | 
|---|
|  | 395 |  | 
|---|
| [383] | 396 | sh_dummy_popret = NULL; | 
|---|
| [367] | 397 | return popret; | 
|---|
|  | 398 | } | 
|---|
|  | 399 |  | 
|---|
|  | 400 | void sh_inotify_purge_dormant(sh_watches * watches) | 
|---|
|  | 401 | { | 
|---|
|  | 402 | struct sh_inotify_litem * this; | 
|---|
|  | 403 |  | 
|---|
|  | 404 | SH_MUTEX_LOCK(mutex_list_dormant); | 
|---|
|  | 405 | this = (struct sh_inotify_litem *) watches->dormant_watches; | 
|---|
|  | 406 |  | 
|---|
|  | 407 | watches->dormant_watches = NULL; | 
|---|
|  | 408 |  | 
|---|
|  | 409 | while (this) | 
|---|
|  | 410 | { | 
|---|
|  | 411 | struct sh_inotify_litem * cur = this; | 
|---|
|  | 412 |  | 
|---|
|  | 413 | this = this->next; | 
|---|
|  | 414 |  | 
|---|
|  | 415 | sh_inotify_free_watch(cur->watch); | 
|---|
|  | 416 | SH_FREE(cur); | 
|---|
|  | 417 | } | 
|---|
|  | 418 | SH_MUTEX_UNLOCK(mutex_list_dormant); | 
|---|
|  | 419 | return; | 
|---|
|  | 420 | } | 
|---|
|  | 421 |  | 
|---|
| [364] | 422 | /********** End List Handling **************/ | 
|---|
|  | 423 |  | 
|---|
|  | 424 | static zAVLKey sh_inotify_getkey(void const *item) | 
|---|
|  | 425 | { | 
|---|
| [481] | 426 | return (&((const sh_watch *)item)->watch); | 
|---|
| [364] | 427 | } | 
|---|
|  | 428 |  | 
|---|
| [496] | 429 | void sh_inotify_close() | 
|---|
|  | 430 | { | 
|---|
|  | 431 | int     ifd = sh_inotify_getfd(); | 
|---|
| [364] | 432 |  | 
|---|
| [496] | 433 | if (ifd >= 0) | 
|---|
|  | 434 | close(ifd); | 
|---|
|  | 435 | sh_set_inotify_fd(-1); | 
|---|
|  | 436 |  | 
|---|
|  | 437 | return; | 
|---|
|  | 438 | } | 
|---|
|  | 439 |  | 
|---|
|  | 440 |  | 
|---|
| [364] | 441 | /* This function removes all watches from the list, | 
|---|
|  | 442 | * and closes the inode file descriptor in this thread. | 
|---|
|  | 443 | */ | 
|---|
|  | 444 | void sh_inotify_remove(sh_watches * watches) | 
|---|
|  | 445 | { | 
|---|
| [367] | 446 | zAVLTree   * all_watches; | 
|---|
| [364] | 447 |  | 
|---|
| [367] | 448 | SH_MUTEX_LOCK(mutex_watches); | 
|---|
|  | 449 | all_watches = (zAVLTree *)(watches->list_of_watches); | 
|---|
|  | 450 |  | 
|---|
| [364] | 451 | if (all_watches) | 
|---|
|  | 452 | zAVLFreeTree(all_watches, sh_inotify_free_watch); | 
|---|
|  | 453 |  | 
|---|
| [367] | 454 | watches->list_of_watches = NULL; | 
|---|
|  | 455 | watches->count = 0; | 
|---|
|  | 456 | SH_MUTEX_UNLOCK(mutex_watches); | 
|---|
| [364] | 457 |  | 
|---|
| [496] | 458 | sh_inotify_close(); | 
|---|
| [261] | 459 | return; | 
|---|
|  | 460 | } | 
|---|
|  | 461 |  | 
|---|
|  | 462 | static int index_watched_file(char * filename, sh_watches * watches) | 
|---|
|  | 463 | { | 
|---|
| [364] | 464 | sh_watch   * item; | 
|---|
|  | 465 | zAVLCursor   avlcursor; | 
|---|
|  | 466 | zAVLTree   * all_watches = (zAVLTree *)(watches->list_of_watches); | 
|---|
| [261] | 467 |  | 
|---|
| [364] | 468 | if (all_watches) | 
|---|
| [261] | 469 | { | 
|---|
| [364] | 470 | for (item = (sh_watch *) zAVLFirst(&avlcursor, all_watches); item; | 
|---|
|  | 471 | item = (sh_watch *) zAVLNext(&avlcursor)) | 
|---|
|  | 472 | { | 
|---|
|  | 473 | if (item->file) | 
|---|
|  | 474 | { | 
|---|
|  | 475 | if (0 == strcmp(filename, item->file)) | 
|---|
|  | 476 | return item->watch; | 
|---|
|  | 477 | } | 
|---|
|  | 478 | } | 
|---|
| [261] | 479 | } | 
|---|
|  | 480 | return -1; | 
|---|
|  | 481 | } | 
|---|
|  | 482 |  | 
|---|
| [405] | 483 | #if !defined(IN_DONT_FOLLOW) | 
|---|
|  | 484 | #define IN_DONT_FOLLOW 0 | 
|---|
|  | 485 | #endif | 
|---|
|  | 486 |  | 
|---|
| [367] | 487 | #define SH_INOTIFY_FILEFLAGS \ | 
|---|
| [405] | 488 | (IN_ATTRIB|IN_MODIFY|IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_DONT_FOLLOW) | 
|---|
| [367] | 489 | #define SH_INOTIFY_DIRFLAGS \ | 
|---|
|  | 490 | (SH_INOTIFY_FILEFLAGS|IN_DELETE|IN_CREATE|IN_MOVED_FROM|IN_MOVED_TO) | 
|---|
|  | 491 |  | 
|---|
|  | 492 | #define SH_INOTIFY_FLAGS (SH_INOTIFY_FILEFLAGS|SH_INOTIFY_DIRFLAGS) | 
|---|
|  | 493 |  | 
|---|
| [405] | 494 |  | 
|---|
| [367] | 495 | /* Create an item and put it on the 'dormant' list for later watch creation | 
|---|
|  | 496 | */ | 
|---|
| [373] | 497 | int sh_inotify_add_watch_later(const char * filename, sh_watches * watches, | 
|---|
| [367] | 498 | int * errnum, | 
|---|
| [481] | 499 | int class, unsigned long check_flags, int type, | 
|---|
| [382] | 500 | int rdepth) | 
|---|
| [367] | 501 | { | 
|---|
|  | 502 | sh_watch   * item; | 
|---|
|  | 503 |  | 
|---|
|  | 504 | item = sh_inotify_create_watch(filename, -1, /* flag */ 0); | 
|---|
|  | 505 |  | 
|---|
|  | 506 | item->class      = class; | 
|---|
| [372] | 507 | item->type       = (short) type; | 
|---|
| [373] | 508 | item->rdepth     = (short) rdepth; | 
|---|
| [481] | 509 | item->check_flags = check_flags; | 
|---|
| [367] | 510 |  | 
|---|
|  | 511 | sh_inotify_add_dormant(watches, item); | 
|---|
|  | 512 | if (errnum) | 
|---|
|  | 513 | *errnum = 0; | 
|---|
|  | 514 |  | 
|---|
|  | 515 | return 0; | 
|---|
|  | 516 | } | 
|---|
|  | 517 |  | 
|---|
|  | 518 | int sh_inotify_rm_watch (sh_watches * watches, sh_watches * save, int wd) | 
|---|
|  | 519 | { | 
|---|
|  | 520 | int ifd = sh_get_inotify_fd(); | 
|---|
|  | 521 |  | 
|---|
|  | 522 | if (watches) | 
|---|
|  | 523 | { | 
|---|
|  | 524 | sh_watch   * item; | 
|---|
|  | 525 |  | 
|---|
|  | 526 | SH_MUTEX_LOCK(mutex_watches); | 
|---|
|  | 527 | item = zAVLSearch(watches->list_of_watches, &wd); | 
|---|
|  | 528 |  | 
|---|
|  | 529 | if (item) | 
|---|
|  | 530 | { | 
|---|
|  | 531 | zAVLDelete(watches->list_of_watches, &wd); | 
|---|
|  | 532 | if (save) /* optionally save the item */ | 
|---|
|  | 533 | { | 
|---|
|  | 534 | item->watch = -1; | 
|---|
|  | 535 | sh_inotify_add_dormant(save, item); | 
|---|
|  | 536 | } | 
|---|
|  | 537 | else | 
|---|
|  | 538 | { | 
|---|
|  | 539 | sh_inotify_free_watch(item); | 
|---|
|  | 540 | } | 
|---|
|  | 541 | } | 
|---|
|  | 542 | SH_MUTEX_UNLOCK(mutex_watches); | 
|---|
|  | 543 | } | 
|---|
|  | 544 | return inotify_rm_watch(ifd, wd); | 
|---|
|  | 545 | } | 
|---|
|  | 546 |  | 
|---|
|  | 547 | #if (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)) | 
|---|
|  | 548 | static void * sh_dummy_litem; | 
|---|
|  | 549 |  | 
|---|
|  | 550 | int sh_inotify_recheck_watches (sh_watches * watches, sh_watches * save) | 
|---|
|  | 551 | { | 
|---|
|  | 552 | sh_watch   * litem; | 
|---|
|  | 553 | sh_inotify_listCursor listcursor; | 
|---|
|  | 554 | int ifd = sh_get_inotify_fd(); | 
|---|
|  | 555 |  | 
|---|
| [371] | 556 | extern void sh_fInotify_report_add(char * path, | 
|---|
| [481] | 557 | int class, unsigned long check_flags); | 
|---|
| [367] | 558 |  | 
|---|
|  | 559 | sh_dummy_litem = (void*) &litem; | 
|---|
|  | 560 |  | 
|---|
|  | 561 | /* -- Check dormant watches for reopening. | 
|---|
|  | 562 | */ | 
|---|
|  | 563 | SH_MUTEX_LOCK(mutex_list_dormant); | 
|---|
|  | 564 |  | 
|---|
| [371] | 565 | litem = sh_inotify_list_first(&listcursor, save); | 
|---|
|  | 566 |  | 
|---|
|  | 567 | while (litem) | 
|---|
| [367] | 568 | { | 
|---|
|  | 569 | have_next: | 
|---|
|  | 570 |  | 
|---|
|  | 571 | /* sh_inotify_list_del_cur may return NULL */ | 
|---|
|  | 572 | if (litem && litem->file && litem->watch == -1) | 
|---|
|  | 573 | { | 
|---|
|  | 574 | litem->watch = inotify_add_watch (ifd, litem->file, | 
|---|
|  | 575 | SH_INOTIFY_FLAGS); | 
|---|
|  | 576 |  | 
|---|
|  | 577 | if (litem->watch >= 0) | 
|---|
|  | 578 | { | 
|---|
|  | 579 | SH_MUTEX_LOCK(mutex_watches); | 
|---|
|  | 580 | if (watches->list_of_watches) | 
|---|
|  | 581 | zAVLInsert(watches->list_of_watches, litem); | 
|---|
|  | 582 | SH_MUTEX_UNLOCK(mutex_watches); | 
|---|
|  | 583 |  | 
|---|
| [481] | 584 | sh_fInotify_report_add(litem->file, litem->class, litem->check_flags); | 
|---|
| [367] | 585 |  | 
|---|
|  | 586 | litem = sh_inotify_list_del_cur(&listcursor, save); | 
|---|
|  | 587 |  | 
|---|
|  | 588 | goto have_next; | 
|---|
|  | 589 | } | 
|---|
|  | 590 | } | 
|---|
| [371] | 591 | litem = sh_inotify_list_next(&listcursor, save); | 
|---|
| [367] | 592 | } | 
|---|
|  | 593 | SH_MUTEX_UNLOCK(mutex_list_dormant); | 
|---|
|  | 594 | return 0; | 
|---|
|  | 595 | } | 
|---|
|  | 596 | #endif | 
|---|
|  | 597 |  | 
|---|
| [261] | 598 | /* This function is idempotent; it will add the watch only once | 
|---|
|  | 599 | */ | 
|---|
| [367] | 600 | int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum, | 
|---|
| [481] | 601 | int class, unsigned long check_flags, int type, int rdepth) | 
|---|
| [261] | 602 | { | 
|---|
| [367] | 603 | volatile int retval = 0; | 
|---|
|  | 604 |  | 
|---|
|  | 605 | SH_MUTEX_LOCK(mutex_watches); | 
|---|
|  | 606 |  | 
|---|
| [261] | 607 | *errnum = 0; | 
|---|
|  | 608 |  | 
|---|
|  | 609 | if (filename) | 
|---|
|  | 610 | { | 
|---|
|  | 611 | int nwatch; | 
|---|
| [364] | 612 | sh_watch   * item; | 
|---|
| [261] | 613 | int index = index_watched_file(filename, watches); | 
|---|
|  | 614 |  | 
|---|
|  | 615 | if (index < 0) | 
|---|
|  | 616 | { | 
|---|
|  | 617 | int     ifd = sh_inotify_getfd(); | 
|---|
|  | 618 |  | 
|---|
| [364] | 619 | /************************************* | 
|---|
|  | 620 |  | 
|---|
| [261] | 621 | if (watches->count == SH_INOTIFY_MAX) | 
|---|
|  | 622 | { | 
|---|
|  | 623 | #ifdef EMFILE | 
|---|
|  | 624 | *errnum = EMFILE; | 
|---|
|  | 625 | #else | 
|---|
|  | 626 | *errnum = 24; | 
|---|
|  | 627 | #endif | 
|---|
|  | 628 | return -1; | 
|---|
|  | 629 | } | 
|---|
| [364] | 630 | **************************************/ | 
|---|
| [261] | 631 |  | 
|---|
|  | 632 | nwatch = inotify_add_watch (ifd, filename, | 
|---|
| [367] | 633 | SH_INOTIFY_FLAGS); | 
|---|
| [261] | 634 | if (nwatch < 0) | 
|---|
|  | 635 | { | 
|---|
|  | 636 | *errnum = errno; | 
|---|
| [367] | 637 | retval = -1; | 
|---|
|  | 638 | goto retpoint; | 
|---|
| [261] | 639 | } | 
|---|
| [364] | 640 |  | 
|---|
|  | 641 | item = sh_inotify_create_watch(filename, nwatch, /* flag */ 0); | 
|---|
| [367] | 642 |  | 
|---|
|  | 643 | item->class      = class; | 
|---|
| [372] | 644 | item->type       = type; | 
|---|
| [373] | 645 | item->rdepth     = rdepth; | 
|---|
| [481] | 646 | item->check_flags = check_flags; | 
|---|
| [261] | 647 |  | 
|---|
| [364] | 648 | if (NULL == watches->list_of_watches) | 
|---|
| [367] | 649 | watches->list_of_watches = zAVLAllocTree (sh_inotify_getkey, | 
|---|
|  | 650 | zAVL_KEY_INT); | 
|---|
| [364] | 651 |  | 
|---|
|  | 652 | if (watches->list_of_watches) | 
|---|
|  | 653 | { | 
|---|
| [367] | 654 | *errnum =  zAVLInsert((zAVLTree *)(watches->list_of_watches), | 
|---|
|  | 655 | item); | 
|---|
|  | 656 |  | 
|---|
| [364] | 657 | if (*errnum != 0) | 
|---|
|  | 658 | { | 
|---|
| [405] | 659 | /* zAVLInsert returns -1 on malloc() error and 3 if | 
|---|
|  | 660 | * the node already exists. | 
|---|
|  | 661 | */ | 
|---|
|  | 662 | *errnum = (*errnum == -1) ? ENOMEM : EEXIST; | 
|---|
| [364] | 663 | sh_inotify_free_watch(item); | 
|---|
| [367] | 664 | retval = -1; | 
|---|
|  | 665 | goto retpoint; | 
|---|
| [364] | 666 | } | 
|---|
|  | 667 | } | 
|---|
|  | 668 | else | 
|---|
|  | 669 | { | 
|---|
| [367] | 670 | *errnum = ENOMEM; | 
|---|
| [382] | 671 | sh_inotify_free_watch(item); | 
|---|
| [367] | 672 | retval = -1; | 
|---|
|  | 673 | goto retpoint; | 
|---|
| [364] | 674 | } | 
|---|
| [261] | 675 |  | 
|---|
|  | 676 | ++(watches->count); | 
|---|
|  | 677 | } | 
|---|
| [373] | 678 | else if (type == SH_INOTIFY_DIR) /* watch exists */ | 
|---|
|  | 679 | { | 
|---|
|  | 680 | /* This covers the case that a directory has been added, | 
|---|
|  | 681 | * but is watched as file at first because it is also | 
|---|
|  | 682 | * specified as file in the config. | 
|---|
|  | 683 | */ | 
|---|
|  | 684 | item = zAVLSearch(watches->list_of_watches, &index); | 
|---|
|  | 685 |  | 
|---|
|  | 686 | if (item && item->type == SH_INOTIFY_FILE) | 
|---|
|  | 687 | { | 
|---|
|  | 688 | item->type = SH_INOTIFY_DIR; | 
|---|
|  | 689 | } | 
|---|
|  | 690 | } | 
|---|
| [261] | 691 | } | 
|---|
| [367] | 692 | retpoint: | 
|---|
| [377] | 693 | ; /* 'label at end of compound statement' */ | 
|---|
| [367] | 694 | SH_MUTEX_UNLOCK(mutex_watches); | 
|---|
|  | 695 | return retval; | 
|---|
| [261] | 696 | } | 
|---|
|  | 697 |  | 
|---|
| [367] | 698 | static void * sh_dummy_sret = NULL; | 
|---|
|  | 699 |  | 
|---|
|  | 700 | char * sh_inotify_search_item(sh_watches * watches, int watch, | 
|---|
| [481] | 701 | int * class, unsigned long * check_flags, | 
|---|
| [373] | 702 | int * type, int * rdepth) | 
|---|
| [367] | 703 | { | 
|---|
|  | 704 | sh_watch * item; | 
|---|
|  | 705 | char     * sret = NULL; | 
|---|
|  | 706 |  | 
|---|
|  | 707 | /* Take the address to keep gcc from putting it into a register. | 
|---|
|  | 708 | * Avoids the 'clobbered by longjmp' warning. | 
|---|
|  | 709 | */ | 
|---|
|  | 710 | sh_dummy_sret = (void *) &sret; | 
|---|
|  | 711 |  | 
|---|
|  | 712 | SH_MUTEX_LOCK(mutex_watches); | 
|---|
|  | 713 | item = zAVLSearch(watches->list_of_watches, &watch); | 
|---|
|  | 714 |  | 
|---|
|  | 715 | if (item) | 
|---|
|  | 716 | { | 
|---|
|  | 717 | *class      = item->class; | 
|---|
| [481] | 718 | *check_flags = item->check_flags; | 
|---|
| [372] | 719 | *type       = item->type; | 
|---|
| [373] | 720 | *rdepth     = item->rdepth; | 
|---|
| [382] | 721 | sret = sh_util_strdup_track(item->file, __FILE__, __LINE__); | 
|---|
| [367] | 722 | } | 
|---|
|  | 723 | SH_MUTEX_UNLOCK(mutex_watches); | 
|---|
|  | 724 | return sret; | 
|---|
|  | 725 | } | 
|---|
|  | 726 |  | 
|---|
|  | 727 | static void * sh_dummy_litem = NULL; | 
|---|
|  | 728 |  | 
|---|
| [261] | 729 | int sh_inotify_wait_for_change(char * filename, sh_watches * watches, | 
|---|
|  | 730 | int  * errnum, int waitsec) | 
|---|
|  | 731 | { | 
|---|
| [367] | 732 | sh_watch   * litem; | 
|---|
|  | 733 | sh_watch   * zitem; | 
|---|
| [364] | 734 | int          ifd = sh_inotify_getfd(); | 
|---|
| [367] | 735 |  | 
|---|
|  | 736 | /* Take the address to keep gcc from putting it into a register. | 
|---|
|  | 737 | * Avoids the 'clobbered by longjmp' warning. | 
|---|
|  | 738 | */ | 
|---|
|  | 739 | sh_dummy_litem = (void*) &litem; | 
|---|
|  | 740 |  | 
|---|
| [261] | 741 | *errnum = 0; | 
|---|
|  | 742 |  | 
|---|
|  | 743 | start_it: | 
|---|
|  | 744 |  | 
|---|
|  | 745 | if (ifd >= 0) | 
|---|
|  | 746 | { | 
|---|
| [367] | 747 | volatile ssize_t  i  = 0; | 
|---|
| [261] | 748 | ssize_t len = -1; | 
|---|
|  | 749 | int  flag = 0; | 
|---|
|  | 750 | char buffer[1024]; | 
|---|
|  | 751 |  | 
|---|
| [364] | 752 | sh_inotify_listCursor listcursor; | 
|---|
|  | 753 |  | 
|---|
| [261] | 754 | /* -- Add watch if required | 
|---|
|  | 755 | */ | 
|---|
|  | 756 | if (filename) | 
|---|
|  | 757 | { | 
|---|
| [373] | 758 | if (sh_inotify_add_watch(filename, watches, errnum, | 
|---|
|  | 759 | 0, 0, SH_INOTIFY_FILE, 0) < 0) | 
|---|
| [261] | 760 | { | 
|---|
|  | 761 | retry_msleep(waitsec, 0); | 
|---|
|  | 762 | return -1; | 
|---|
|  | 763 | } | 
|---|
|  | 764 | } | 
|---|
|  | 765 |  | 
|---|
| [364] | 766 | /* -- Check dormant watches for reopening. | 
|---|
|  | 767 | */ | 
|---|
| [367] | 768 | SH_MUTEX_LOCK(mutex_list_dormant); | 
|---|
|  | 769 |  | 
|---|
|  | 770 | for (litem = sh_inotify_list_first(&listcursor, watches); litem; | 
|---|
|  | 771 | litem = sh_inotify_list_next(&listcursor, watches)) | 
|---|
| [261] | 772 | { | 
|---|
| [364] | 773 | have_next: | 
|---|
| [367] | 774 | /* sh_inotify_list_del_cur may return NULL */ | 
|---|
|  | 775 | if (litem && litem->file && litem->watch == -1) | 
|---|
| [364] | 776 | { | 
|---|
| [367] | 777 | litem->watch = inotify_add_watch (ifd, litem->file, | 
|---|
|  | 778 | SH_INOTIFY_FLAGS); | 
|---|
|  | 779 |  | 
|---|
|  | 780 | if (litem->watch >= 0) | 
|---|
| [364] | 781 | { | 
|---|
| [367] | 782 | SH_MUTEX_LOCK(mutex_watches); | 
|---|
|  | 783 | if (watches->list_of_watches) | 
|---|
|  | 784 | zAVLInsert(watches->list_of_watches, litem); | 
|---|
|  | 785 | SH_MUTEX_UNLOCK(mutex_watches); | 
|---|
|  | 786 | litem = sh_inotify_list_del_cur(&listcursor, watches); | 
|---|
| [364] | 787 | goto have_next; | 
|---|
|  | 788 | } | 
|---|
|  | 789 | } | 
|---|
| [261] | 790 | } | 
|---|
| [367] | 791 | SH_MUTEX_UNLOCK(mutex_list_dormant); | 
|---|
| [261] | 792 |  | 
|---|
|  | 793 |  | 
|---|
|  | 794 | /* -- Blocking read on inotify file descriptor | 
|---|
|  | 795 | */ | 
|---|
| [371] | 796 | len = sh_inotify_read(buffer, sizeof(buffer)); | 
|---|
| [261] | 797 |  | 
|---|
|  | 798 | if (len > 0) | 
|---|
|  | 799 | { | 
|---|
|  | 800 | struct inotify_event *event; | 
|---|
|  | 801 |  | 
|---|
|  | 802 | i = 0; | 
|---|
|  | 803 |  | 
|---|
|  | 804 | while (i < len) { | 
|---|
|  | 805 |  | 
|---|
|  | 806 | event = (struct inotify_event *) &buffer[i]; | 
|---|
|  | 807 |  | 
|---|
| [367] | 808 | SH_MUTEX_LOCK(mutex_watches); | 
|---|
|  | 809 | zitem = zAVLSearch(watches->list_of_watches, &(event->wd)); | 
|---|
| [364] | 810 |  | 
|---|
| [367] | 811 | if (zitem) | 
|---|
| [261] | 812 | { | 
|---|
| [364] | 813 | if (event->mask & IN_MODIFY) | 
|---|
| [261] | 814 | { | 
|---|
| [367] | 815 | zitem->flag |= SH_INOTIFY_MODIFY; | 
|---|
| [364] | 816 | flag |= SH_INOTIFY_MODIFY; | 
|---|
| [261] | 817 | } | 
|---|
| [364] | 818 | else if (event->mask & IN_DELETE_SELF || | 
|---|
|  | 819 | event->mask & IN_UNMOUNT     || | 
|---|
|  | 820 | event->mask & IN_MOVE_SELF   ) | 
|---|
|  | 821 | { | 
|---|
| [367] | 822 | zitem->flag |= SH_INOTIFY_REOPEN; | 
|---|
|  | 823 | (void) inotify_rm_watch(ifd, zitem->watch); | 
|---|
|  | 824 | zAVLDelete(watches->list_of_watches, zitem); | 
|---|
|  | 825 | sh_inotify_add_dormant(watches, zitem); | 
|---|
|  | 826 | zitem->watch    = -1; | 
|---|
| [364] | 827 | flag |= SH_INOTIFY_REOPEN; | 
|---|
|  | 828 | } | 
|---|
| [261] | 829 | } | 
|---|
| [367] | 830 | SH_MUTEX_UNLOCK(mutex_watches); | 
|---|
| [364] | 831 |  | 
|---|
| [261] | 832 | i += sizeof (struct inotify_event) + event->len; | 
|---|
|  | 833 | } | 
|---|
|  | 834 | } | 
|---|
|  | 835 | else if (len == -1) | 
|---|
|  | 836 | { | 
|---|
|  | 837 | *errnum = errno; | 
|---|
|  | 838 | retry_msleep(waitsec, 0); | 
|---|
|  | 839 |  | 
|---|
|  | 840 | return -1; | 
|---|
|  | 841 | } | 
|---|
|  | 842 |  | 
|---|
|  | 843 | if (flag & SH_INOTIFY_REOPEN) | 
|---|
|  | 844 | { | 
|---|
|  | 845 | if (flag & SH_INOTIFY_MODIFY) | 
|---|
|  | 846 | return 0; | 
|---|
|  | 847 | else | 
|---|
|  | 848 | goto start_it; | 
|---|
|  | 849 | } | 
|---|
|  | 850 |  | 
|---|
|  | 851 | return 0; | 
|---|
|  | 852 | } | 
|---|
|  | 853 |  | 
|---|
|  | 854 | /* Inotify not working, sleep | 
|---|
|  | 855 | */ | 
|---|
|  | 856 | retry_msleep(waitsec, 0); | 
|---|
|  | 857 |  | 
|---|
|  | 858 | *errnum = 0; | 
|---|
|  | 859 | return -1; | 
|---|
|  | 860 | } | 
|---|
|  | 861 |  | 
|---|
| [367] | 862 |  | 
|---|
| [261] | 863 | /* !defined(HAVE_SYS_INOTIFY_H) */ | 
|---|
|  | 864 | #else | 
|---|
|  | 865 |  | 
|---|
|  | 866 | #include "sh_calls.h" | 
|---|
| [269] | 867 | #include "sh_inotify.h" | 
|---|
| [261] | 868 |  | 
|---|
|  | 869 | void sh_inotify_remove(sh_watches * watches) | 
|---|
|  | 870 | { | 
|---|
|  | 871 | (void) watches; | 
|---|
|  | 872 | return; | 
|---|
|  | 873 | } | 
|---|
|  | 874 |  | 
|---|
|  | 875 | int sh_inotify_wait_for_change(char * filename, sh_watches * watches, | 
|---|
|  | 876 | int *  errnum, int waitsec) | 
|---|
|  | 877 | { | 
|---|
|  | 878 | (void) filename; | 
|---|
|  | 879 | (void) watches; | 
|---|
|  | 880 |  | 
|---|
|  | 881 | /* Inotify not working, sleep for waitsec seconds | 
|---|
|  | 882 | */ | 
|---|
|  | 883 | retry_msleep(waitsec, 0); | 
|---|
|  | 884 |  | 
|---|
| [388] | 885 | if (errnum) | 
|---|
|  | 886 | *errnum = 0; | 
|---|
| [261] | 887 | return -1; | 
|---|
|  | 888 | } | 
|---|
|  | 889 |  | 
|---|
| [367] | 890 | int sh_inotify_add_watch(char * filename, sh_watches * watches, int  * errnum, | 
|---|
| [481] | 891 | int class, unsigned long check_flags, int type, int rdepth) | 
|---|
| [261] | 892 | { | 
|---|
|  | 893 | (void) filename; | 
|---|
|  | 894 | (void) watches; | 
|---|
| [367] | 895 | (void) class; | 
|---|
| [481] | 896 | (void) check_flags; | 
|---|
| [373] | 897 | (void) type; | 
|---|
|  | 898 | (void) rdepth; | 
|---|
| [388] | 899 |  | 
|---|
|  | 900 | if (errnum) | 
|---|
|  | 901 | *errnum = 0; | 
|---|
| [261] | 902 | return 0; | 
|---|
|  | 903 | } | 
|---|
|  | 904 |  | 
|---|
| [373] | 905 | int sh_inotify_add_watch_later(const char * filename, sh_watches * watches, | 
|---|
| [367] | 906 | int  * errnum, | 
|---|
| [481] | 907 | int class, unsigned long check_flags, int type, int rdepth) | 
|---|
| [367] | 908 | { | 
|---|
|  | 909 | (void) filename; | 
|---|
|  | 910 | (void) watches; | 
|---|
|  | 911 | (void) class; | 
|---|
| [481] | 912 | (void) check_flags; | 
|---|
| [373] | 913 | (void) type; | 
|---|
|  | 914 | (void) rdepth; | 
|---|
| [388] | 915 |  | 
|---|
|  | 916 | if (errnum) | 
|---|
|  | 917 | *errnum = 0; | 
|---|
| [367] | 918 | return 0; | 
|---|
|  | 919 | } | 
|---|
|  | 920 |  | 
|---|
| [261] | 921 | #endif | 
|---|
| [367] | 922 |  | 
|---|
|  | 923 | #ifdef SH_CUTEST | 
|---|
|  | 924 | #include "CuTest.h" | 
|---|
|  | 925 | void Test_inotify(CuTest *tc) { | 
|---|
|  | 926 | #if defined(HAVE_SYS_INOTIFY_H) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)) | 
|---|
|  | 927 |  | 
|---|
|  | 928 | int          ret; | 
|---|
|  | 929 | sh_watches   twatch = SH_INOTIFY_INITIALIZER; | 
|---|
|  | 930 | sh_watch   * litem; | 
|---|
|  | 931 | sh_inotify_listCursor listcursor; | 
|---|
|  | 932 | char * p; | 
|---|
|  | 933 | int class; | 
|---|
| [373] | 934 | int type; | 
|---|
|  | 935 | int rdepth; | 
|---|
| [481] | 936 | unsigned long check_flags; | 
|---|
| [367] | 937 | int           nrun = 0; | 
|---|
|  | 938 |  | 
|---|
| [373] | 939 | sh_watch aw1 = { -1, 0, 0, 1, 99, 1, "a1" }; | 
|---|
|  | 940 | sh_watch aw2 = { -1, 0, 0, 2, 99, 1, "a2" }; | 
|---|
|  | 941 | sh_watch aw3 = {  2, 0, 0, 3, 99, 1, "a3" }; | 
|---|
|  | 942 | sh_watch aw4 = { -1, 0, 0, 4, 99, 1, "a4" }; | 
|---|
|  | 943 | sh_watch aw5 = {  5, 0, 0, 5, 99, 1, "a5" }; | 
|---|
| [367] | 944 |  | 
|---|
|  | 945 | do { | 
|---|
|  | 946 |  | 
|---|
|  | 947 | int          count = 0; | 
|---|
|  | 948 |  | 
|---|
|  | 949 | sh_watch * w1 = SH_ALLOC(sizeof(sh_watch)); | 
|---|
|  | 950 | sh_watch * w2 = SH_ALLOC(sizeof(sh_watch)); | 
|---|
|  | 951 | sh_watch * w3 = SH_ALLOC(sizeof(sh_watch)); | 
|---|
|  | 952 | sh_watch * w4 = SH_ALLOC(sizeof(sh_watch)); | 
|---|
|  | 953 | sh_watch * w5 = SH_ALLOC(sizeof(sh_watch)); | 
|---|
|  | 954 |  | 
|---|
|  | 955 | memcpy(w1, &aw1, sizeof(sh_watch)); | 
|---|
|  | 956 | w1->file = sh_util_strdup(aw1.file); | 
|---|
|  | 957 | memcpy(w2, &aw2, sizeof(sh_watch)); | 
|---|
|  | 958 | w2->file = sh_util_strdup(aw2.file); | 
|---|
|  | 959 | memcpy(w3, &aw3, sizeof(sh_watch)); | 
|---|
|  | 960 | w3->file = sh_util_strdup(aw3.file); | 
|---|
|  | 961 | memcpy(w4, &aw4, sizeof(sh_watch)); | 
|---|
|  | 962 | w4->file = sh_util_strdup(aw4.file); | 
|---|
|  | 963 | memcpy(w5, &aw5, sizeof(sh_watch)); | 
|---|
|  | 964 | w5->file = sh_util_strdup(aw5.file); | 
|---|
|  | 965 |  | 
|---|
|  | 966 | ret = sh_inotify_add_dormant(&twatch, w1); | 
|---|
|  | 967 | CuAssertIntEquals(tc, ret, 0); | 
|---|
|  | 968 | ret = sh_inotify_add_dormant(&twatch, w2); | 
|---|
|  | 969 | CuAssertIntEquals(tc, ret, 0); | 
|---|
|  | 970 | ret = sh_inotify_add_dormant(&twatch, w3); | 
|---|
|  | 971 | CuAssertIntEquals(tc, ret, 0); | 
|---|
|  | 972 | ret = sh_inotify_add_dormant(&twatch, w4); | 
|---|
|  | 973 | CuAssertIntEquals(tc, ret, 0); | 
|---|
|  | 974 | ret = sh_inotify_add_dormant(&twatch, w5); | 
|---|
|  | 975 | CuAssertIntEquals(tc, ret, 0); | 
|---|
|  | 976 |  | 
|---|
|  | 977 | /* -- Check dormant watches for reopening. | 
|---|
|  | 978 | */ | 
|---|
|  | 979 | for (litem = sh_inotify_list_first(&listcursor, &twatch); litem; | 
|---|
|  | 980 | litem = sh_inotify_list_next(&listcursor, &twatch)) | 
|---|
|  | 981 | { | 
|---|
|  | 982 | have_next: | 
|---|
|  | 983 |  | 
|---|
|  | 984 | /* sh_inotify_list_del_cur may return NULL */ | 
|---|
|  | 985 | if (litem) | 
|---|
|  | 986 | { | 
|---|
|  | 987 | ++count; | 
|---|
|  | 988 |  | 
|---|
|  | 989 | if (litem->file && litem->watch == -1) | 
|---|
|  | 990 | { | 
|---|
|  | 991 |  | 
|---|
|  | 992 | switch (litem->class) | 
|---|
|  | 993 | { | 
|---|
|  | 994 | case 1: | 
|---|
|  | 995 | CuAssertStrEquals(tc, litem->file, "a1"); | 
|---|
|  | 996 | break; | 
|---|
|  | 997 | case 2: | 
|---|
|  | 998 | CuAssertStrEquals(tc, litem->file, "a2"); | 
|---|
|  | 999 | break; | 
|---|
|  | 1000 | case 3: | 
|---|
|  | 1001 | CuAssertStrEquals(tc, litem->file, "deadbeef"); | 
|---|
|  | 1002 | break; | 
|---|
|  | 1003 | case 4: | 
|---|
|  | 1004 | CuAssertStrEquals(tc, litem->file, "a4"); | 
|---|
|  | 1005 | break; | 
|---|
|  | 1006 | case 5: | 
|---|
|  | 1007 | CuAssertStrEquals(tc, litem->file, "deadbeef"); | 
|---|
|  | 1008 | break; | 
|---|
|  | 1009 | default: | 
|---|
|  | 1010 | CuAssertStrEquals(tc, litem->file, "deadbeef"); | 
|---|
|  | 1011 | } | 
|---|
|  | 1012 | litem = sh_inotify_list_del_cur(&listcursor, &twatch); | 
|---|
|  | 1013 | goto have_next; | 
|---|
|  | 1014 | } | 
|---|
|  | 1015 | switch (litem->class) | 
|---|
|  | 1016 | { | 
|---|
|  | 1017 | case 3: | 
|---|
|  | 1018 | CuAssertStrEquals(tc, litem->file, "a3"); | 
|---|
|  | 1019 | break; | 
|---|
|  | 1020 | case 5: | 
|---|
|  | 1021 | CuAssertStrEquals(tc, litem->file, "a5"); | 
|---|
|  | 1022 | break; | 
|---|
|  | 1023 | default: | 
|---|
|  | 1024 | CuAssertStrEquals(tc, litem->file, "foobar"); | 
|---|
|  | 1025 | } | 
|---|
|  | 1026 | } | 
|---|
|  | 1027 | } | 
|---|
|  | 1028 |  | 
|---|
|  | 1029 | CuAssertIntEquals(tc, count, 5); | 
|---|
|  | 1030 |  | 
|---|
| [481] | 1031 | p = sh_inotify_pop_dormant(&twatch, &class, &check_flags, &type, &rdepth); | 
|---|
| [367] | 1032 | CuAssertStrEquals(tc, p, "a5"); | 
|---|
|  | 1033 |  | 
|---|
| [481] | 1034 | p = sh_inotify_pop_dormant(&twatch, &class, &check_flags, &type, &rdepth); | 
|---|
| [367] | 1035 | CuAssertStrEquals(tc, p, "a3"); | 
|---|
|  | 1036 | CuAssertIntEquals(tc, class, 3); | 
|---|
|  | 1037 |  | 
|---|
| [481] | 1038 | p = sh_inotify_pop_dormant(&twatch, &class, &check_flags, &type, &rdepth); | 
|---|
| [367] | 1039 | CuAssertTrue(tc, NULL == p); | 
|---|
|  | 1040 | CuAssertTrue(tc, NULL == twatch.dormant_watches); | 
|---|
|  | 1041 |  | 
|---|
|  | 1042 | ++nrun; | 
|---|
|  | 1043 |  | 
|---|
|  | 1044 | } while (nrun < 100); | 
|---|
|  | 1045 |  | 
|---|
|  | 1046 | #else | 
|---|
|  | 1047 | (void) tc; | 
|---|
|  | 1048 | #endif | 
|---|
|  | 1049 |  | 
|---|
|  | 1050 | return; | 
|---|
|  | 1051 | } | 
|---|
|  | 1052 | #endif | 
|---|