source: trunk/src/sh_fInotify.c

Last change on this file was 568, checked in by katerina, 3 months ago

Fix for ticket #458 (inotify issue).

File size: 18.9 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2011       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/***************************************************************************
21 *
22 * This file provides a module for samhain to use inotify for file checking.
23 *
24 */
25
26#include "config_xor.h"
27
28#if (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
29
30#include "samhain.h"
31#include "sh_utils.h"
32#include "sh_modules.h"
33#include "sh_pthread.h"
34#include "sh_inotify.h"
35#include "sh_unix.h"
36#include "sh_hash.h"
37#include "sh_dbIO.h"
38#include "sh_files.h"
39#include "sh_ignore.h"
40
41#define FIL__  _("sh_fInotify.c")
42
43sh_watches sh_file_watches = SH_INOTIFY_INITIALIZER;
44
45#if defined(HAVE_SYS_INOTIFY_H)
46
47static sh_watches sh_file_missing = SH_INOTIFY_INITIALIZER;
48
49#include <sys/inotify.h>
50
51/* --- Configuration ------- */
52
53static int ShfInotifyActive = S_FALSE;
54static int ShfInotifyClose  = S_FALSE; /* for reconf, mark instance for closing */
55
56static unsigned long ShfInotifyWatches = 0;
57
58static int sh_fInotify_active(const char *s) 
59{
60  int value;
61   
62  SL_ENTER(_("sh_fInotify_active"));
63  value = sh_util_flagval(s, &ShfInotifyActive);
64  if (value == 0 && ShfInotifyActive != S_FALSE)
65    {
66      sh.flag.inotify |= SH_INOTIFY_USE;
67      sh.flag.inotify |= SH_INOTIFY_DOSCAN;
68      sh.flag.inotify |= SH_INOTIFY_NEEDINIT;
69    }
70  if (value == 0 && ShfInotifyActive == S_FALSE)
71    {
72      sh.flag.inotify = 0;
73    }
74  SL_RETURN((value), _("sh_fInotify_active"));
75}
76
77static int sh_fInotify_watches(const char *s) 
78{
79  int retval = -1;
80  char * foo;
81  unsigned long value;
82   
83  SL_ENTER(_("sh_fInotify_watches"));
84
85  value = strtoul(s, &foo, 0);
86  if (*foo == '\0')
87    {
88      ShfInotifyWatches = (value > 2147483647) ? 2147483647 /* MAX_INT_32 */: value;
89      retval = 0;
90    }
91  SL_RETURN((retval), _("sh_fInotify_watches"));
92}
93 
94 
95sh_rconf sh_fInotify_table[] = {
96    {
97        N_("inotifyactive"),
98        sh_fInotify_active,
99    },
100    {
101        N_("inotifywatches"),
102        sh_fInotify_watches,
103    },
104    {
105        NULL,
106        NULL
107    }
108};
109
110/* --- End Configuration --- */
111
112static int sh_fInotify_init_internal(void);
113static int sh_fInotify_process(struct inotify_event * event);
114static int sh_fInotify_report(struct inotify_event * event, char * filename,
115                              int class, unsigned long check_flags, int ftype, int rdepth);
116
117int sh_fInotify_init(struct mod_type * arg)
118{
119#ifndef HAVE_PTHREAD
120  (void) arg;
121  return SH_MOD_FAILED;
122#else
123
124  if (ShfInotifyActive == S_FALSE)
125    return SH_MOD_FAILED;
126
127  if (sh.flag.checkSum == SH_CHECK_INIT)
128    return SH_MOD_FAILED;
129
130  if (arg != NULL && arg->initval < 0 &&
131      (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
132    {
133      /* Init from main thread */
134      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN;   );
135      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
136
137      if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
138        {
139          return SH_MOD_THREAD;
140        }
141      else
142        {
143          sh.flag.inotify = 0;
144          return SH_MOD_FAILED;
145        }
146    }
147  else if (arg != NULL && arg->initval < 0 &&
148      (sh.flag.isdaemon != S_TRUE && sh.flag.loop != S_TRUE))
149    {
150      sh.flag.inotify = 0;
151      return SH_MOD_FAILED;
152    }
153  else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
154           (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
155    {
156      /* Reconfigure from main thread */
157
158      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN;   );
159      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
160      return SH_MOD_THREAD;
161    }
162
163  /* Within thread, init */
164  return sh_fInotify_init_internal();
165#endif
166}
167
168int sh_fInotify_run()
169{
170  ssize_t len = -1;
171  char *  buffer;
172  static int count  = 0;
173  static int count2 = 0;
174
175  if (ShfInotifyActive == S_FALSE)
176    {
177      return SH_MOD_FAILED;
178    }
179
180  if (ShfInotifyClose == S_TRUE)
181    {
182      ShfInotifyClose = S_FALSE;
183      sh_inotify_close();
184    }
185
186  if ( (sh.flag.inotify & SH_INOTIFY_DOSCAN) ||
187       (sh.flag.inotify & SH_INOTIFY_NEEDINIT))
188    {
189      if (0 != sh_fInotify_init_internal())
190        {
191          return SH_MOD_FAILED;
192        }
193    }
194
195  buffer = SH_ALLOC(16384);
196
197  /* Blocking read from inotify file descriptor.
198   */
199  len = sh_inotify_read_timeout (buffer, 16384, 1);
200 
201  if (len > 0)
202    {
203      struct inotify_event *event;
204      long i = 0;
205
206      while (i < len) 
207        {
208          event = (struct inotify_event *) &(buffer[i]);
209         
210          sh_fInotify_process(event);
211         
212          i += sizeof (struct inotify_event) + event->len;
213        }
214
215      if ( (sh.flag.inotify & SH_INOTIFY_DOSCAN) ||
216           (sh.flag.inotify & SH_INOTIFY_NEEDINIT))
217        {
218          if (0 != sh_fInotify_init_internal())
219            {
220              SH_FREE(buffer);
221              return SH_MOD_FAILED;
222            }
223        }
224     }
225
226  /* Re-scan 'dormant' list of sh_file_missing.
227   */ 
228  sh_inotify_recheck_watches (&sh_file_watches, &sh_file_missing);
229
230  ++count; 
231  ++count2;
232
233  if (count >= 10)
234    {
235      count = 0; /* Re-expand glob patterns to discover added files. */
236      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_INSCAN; );
237      sh_files_check_globFilePatterns();
238      SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_INSCAN;  );
239      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
240    }
241
242  if (count2 >= 300)
243    {
244      count2 = 0; /* Update baseline database. */
245      if (sh.flag.checkSum == SH_CHECK_CHECK && sh.flag.update == S_TRUE)
246        sh_dbIO_writeout_update ();
247    }
248
249  SH_FREE(buffer);
250  return 0;
251}
252
253/* We block in the read() call on the inotify descriptor,
254 * so we always run.
255 */
256int sh_fInotify_timer(time_t tcurrent)
257{
258  (void) tcurrent;
259  return 1;
260}
261
262int sh_fInotify_cleanup()
263{
264  sh_inotify_purge_dormant(&sh_file_watches);
265  sh_inotify_remove(&sh_file_watches);
266  sh_inotify_init(&sh_file_watches);
267  return 0;
268}
269
270/* This runs in the main thread, so it won't close
271 * the (threadspecific) inotify instance.
272 */
273int sh_fInotify_reconf()
274{
275  sh.flag.inotify   = 0;
276
277  ShfInotifyWatches = 0;
278  ShfInotifyActive  = 0;
279
280  ShfInotifyClose   = S_TRUE;
281
282  return sh_fInotify_cleanup();
283}
284
285#define PROC_WATCHES_MAX _("/proc/sys/fs/inotify/max_user_watches")
286
287static void sh_fInotify_set_nwatches()
288{
289  static int fails = 0;
290
291  if (ShfInotifyWatches == 0 || fails == 1)
292    return;
293
294  if (0 == access(PROC_WATCHES_MAX, R_OK|W_OK)) /* flawfinder: ignore */
295    {
296      FILE * fd;
297
298      if (NULL != (fd = fopen(PROC_WATCHES_MAX, "r+")))
299        {
300          char   str[128];
301          char * ret;
302          char * ptr;
303          unsigned long  wn;
304
305          str[0] = '\0';
306          ret = fgets(str, 128, fd);
307          if (ret && *str != '\0')
308            {
309              wn = strtoul(str, &ptr, 0);
310              if (*ptr == '\0' || *ptr == '\n')
311                {
312                  if (wn < ShfInotifyWatches)
313                    {
314                      sl_snprintf(str, sizeof(str), "%lu\n", ShfInotifyWatches);
315                      (void) fseek(fd, 0L, SEEK_SET);
316                      fputs(str, fd);
317                    }
318                  sl_fclose(FIL__, __LINE__, fd);
319                  return;
320                }
321            }
322          sl_fclose(FIL__, __LINE__, fd);
323        }
324    }
325  SH_MUTEX_LOCK(mutex_thread_nolog);
326  sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, 
327                  _("Cannot set max_user_watches"), 
328                  _("sh_fInotify_set_nwatches"));
329  SH_MUTEX_UNLOCK(mutex_thread_nolog);
330  fails = 1;
331  return;
332}
333
334/* The watch fd is thread specific. To have it in the fInotify thread,
335 * the main thread writes a list of files/dirs to watch, and here we
336 * now pop files from the list to add watches for them.
337 */
338static int sh_fInotify_init_internal()
339{
340  char * filename;
341  int    class;
342  int    type;
343  int    rdepth;
344  unsigned long check_flags;
345  int    retval;
346  int    errnum;
347
348  if (ShfInotifyActive == S_FALSE)
349    return SH_MOD_FAILED;
350
351  /* Wait until file scan is finished.
352   */
353  while((sh.flag.inotify & SH_INOTIFY_DOSCAN) != 0)
354    {
355      retry_msleep(1,0);
356
357      if (ShfInotifyActive == S_FALSE)
358        return SH_MOD_FAILED;
359    }
360
361  sh_fInotify_set_nwatches();
362
363  while (NULL != (filename = sh_inotify_pop_dormant(&sh_file_watches, 
364                                                    &class, &check_flags, 
365                                                    &type, &rdepth)))
366    {
367      retval = sh_inotify_add_watch(filename, &sh_file_watches, &errnum,
368                                    class, check_flags, type, rdepth);
369
370      if (retval < 0)
371        {
372          char errbuf[SH_ERRBUF_SIZE];
373
374          sh_error_message(errnum, errbuf, sizeof(errbuf));
375
376          if ((errnum == ENOENT) || (errnum == EEXIST))
377            {
378              /* (1) Did it exist at init ?
379               */
380              if (sh_hash_have_it (filename) >= 0)
381                {
382                  /* (2) Do we want to report on it ?
383                   */
384                  if (S_FALSE == sh_ignore_chk_del(filename))
385                    {
386                      char * epath = sh_util_safe_name (filename);
387
388                      SH_MUTEX_LOCK(mutex_thread_nolog);
389                      sh_error_handle( SH_ERR_ALL /* debug */,
390                                       FIL__, __LINE__, errnum, MSG_E_SUBGPATH, 
391                                       errbuf, _("sh_fInotify_init_internal"), epath);
392                      SH_MUTEX_UNLOCK(mutex_thread_nolog);
393                      SH_FREE(epath);
394                    }
395                }
396            }
397          else
398            {
399              SH_MUTEX_LOCK(mutex_thread_nolog);
400              sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN, 
401                               errbuf, _("sh_fInotify_init_internal"));
402              SH_MUTEX_UNLOCK(mutex_thread_nolog);
403            }
404        }
405      SH_FREE(filename);
406    }
407
408  /* Need this because mod_check() may run after
409   * DOSCAN is finished, hence wouldn't call init().
410   */
411  SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_NEEDINIT; );
412
413  return 0;
414}
415
416static void sh_fInotify_logmask(struct inotify_event * event)
417{
418  char dbgbuf[256];
419 
420  sl_strlcpy (dbgbuf, "inotify mask: ", sizeof(dbgbuf));
421 
422  if (event->mask & IN_ACCESS) sl_strlcat(dbgbuf, "IN_ACCESS ", sizeof(dbgbuf));
423  if (event->mask & IN_ATTRIB) sl_strlcat(dbgbuf, "IN_ATTRIB ", sizeof(dbgbuf));
424  if (event->mask & IN_CLOSE_WRITE) sl_strlcat(dbgbuf, "IN_CLOSE_WRITE ", sizeof(dbgbuf));
425  if (event->mask & IN_CLOSE_NOWRITE) sl_strlcat(dbgbuf, "IN_CLOSE_NOWRITE ", sizeof(dbgbuf));
426  if (event->mask & IN_CREATE) sl_strlcat(dbgbuf, "IN_CREATE ", sizeof(dbgbuf));
427  if (event->mask & IN_DELETE) sl_strlcat(dbgbuf, "IN_DELETE ", sizeof(dbgbuf));
428  if (event->mask & IN_DELETE_SELF) sl_strlcat(dbgbuf, "IN_DELETE_SELF ", sizeof(dbgbuf));
429  if (event->mask & IN_MODIFY) sl_strlcat(dbgbuf, "IN_MODIFY ", sizeof(dbgbuf));
430  if (event->mask & IN_MOVE_SELF) sl_strlcat(dbgbuf, "IN_MOVE_SELF ", sizeof(dbgbuf));
431  if (event->mask & IN_MOVED_FROM) sl_strlcat(dbgbuf, "IN_MOVED_FROM ", sizeof(dbgbuf));
432  if (event->mask & IN_MOVED_TO) sl_strlcat(dbgbuf, "IN_MOVED_TO ", sizeof(dbgbuf));
433  if (event->mask & IN_OPEN) sl_strlcat(dbgbuf, "IN_OPEN ", sizeof(dbgbuf));
434  if (event->mask & IN_IGNORED) sl_strlcat(dbgbuf, "IN_IGNORED ", sizeof(dbgbuf));
435  if (event->mask & IN_ISDIR) sl_strlcat(dbgbuf, "IN_ISDIR ", sizeof(dbgbuf));
436  if (event->mask & IN_Q_OVERFLOW) sl_strlcat(dbgbuf, "IN_Q_OVERFLOW ", sizeof(dbgbuf));
437  if (event->mask & IN_UNMOUNT) sl_strlcat(dbgbuf, "IN_UNMOUNT ", sizeof(dbgbuf));
438 
439  SH_MUTEX_LOCK(mutex_thread_nolog);
440  sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
441                  dbgbuf, _("sh_fInotify_process"));
442  SH_MUTEX_UNLOCK(mutex_thread_nolog);
443}
444
445static int sh_fInotify_process(struct inotify_event * event)
446{
447  int class;
448  int ftype;
449  int rdepth;
450  unsigned long check_flags;
451  char * filename;
452  extern int flag_err_debug;
453
454  if (flag_err_debug == S_TRUE)
455    {
456      sh_fInotify_logmask(event);
457    }
458
459  if (event->wd >= 0)
460    {
461      filename = sh_inotify_search_item(&sh_file_watches, event->wd, 
462                                        &class, &check_flags, &ftype, &rdepth);
463
464      if (filename)
465        {
466          sh_fInotify_report(event, filename, class, check_flags, ftype, rdepth);
467          SH_FREE(filename);
468        }
469      else if (sh.flag.inotify & SH_INOTIFY_NEEDINIT)
470        {
471          return 1;
472        }
473      else if ((event->mask & IN_UNMOUNT) == 0 && (event->mask & IN_IGNORED) == 0)
474        {
475          /* Remove watch ? Seems reasonable. */
476          sh_inotify_rm_watch(NULL, NULL, event->wd);
477
478          SH_MUTEX_LOCK(mutex_thread_nolog);
479          sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, event->wd, MSG_E_SUBGEN, 
480                          _("Watch removed: file path unknown"), 
481                          _("sh_fInotify_process"));
482          SH_MUTEX_UNLOCK(mutex_thread_nolog);
483        }
484    }
485  else if ((event->mask & IN_Q_OVERFLOW) != 0)
486    {
487      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN;   );
488      SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
489
490      SH_MUTEX_LOCK(mutex_thread_nolog);
491      sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, event->wd, MSG_E_SUBGEN, 
492                      _("Inotify queue overflow"), 
493                      _("sh_fInotify_process"));
494      SH_MUTEX_UNLOCK(mutex_thread_nolog);
495      return 1;
496    }
497
498  return 0;
499}
500
501void sh_fInotify_report_add(char * path, int class, unsigned long check_flags)
502{
503  if (S_FALSE == sh_ignore_chk_new(path))
504    {
505      int reported = 0;
506
507      sh_files_clear_file_reported(path);
508     
509      sh_files_search_file(path, &class, &check_flags, &reported);
510     
511      sh_files_filecheck (class, check_flags, path, NULL,
512                          &reported, 0);
513      if (SH_FFLAG_REPORTED_SET(reported))
514        sh_files_set_file_reported(path);
515    }
516  return;
517}
518
519
520static void sh_fInotify_report_miss(char * name, int level)
521{
522  char * tmp = sh_util_safe_name (name);
523
524  SH_MUTEX_LOCK(mutex_thread_nolog);
525  if (!sh_global_check_silent)
526    sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_MISS, tmp);
527  SH_MUTEX_UNLOCK(mutex_thread_nolog);
528  ++sh.statistics.files_report;
529  SH_FREE(tmp);
530  return;
531}
532
533static int sh_fInotify_report_change (struct inotify_event * event, 
534                                      char * path, char * filename,
535                                      int class, unsigned long check_flags, int ftype)
536{
537  int    reported;
538  int ret;
539
540
541  if (S_FALSE == sh_ignore_chk_mod(path))
542    {
543      ret  = sh_files_search_file(path, &class, &check_flags, &reported);
544
545      if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
546        {
547          ; /* do nothing, watch was for directory monitored as file only */
548        }
549      else
550        {
551          sh_files_filecheck (class, check_flags, filename,
552                              (event->len > 0) ? event->name : NULL,
553                              &reported, 0);
554        }
555    }
556  return 0;
557}
558
559
560static int sh_fInotify_report_missing (struct inotify_event * event, 
561                                       char * path,
562                                       int class, unsigned long check_flags, int ftype)
563{
564  int    reported;
565  int isdir = (event->mask & IN_ISDIR);
566  int level = (class == SH_LEVEL_ALLIGNORE) ? 
567    ShDFLevel[class] : 
568    ShDFLevel[(isdir == 0) ? SH_ERR_T_FILE : SH_ERR_T_DIR];
569
570  if (S_FALSE == sh_ignore_chk_del(path))
571    {
572      if (0 != hashreport_missing(path, level))
573        {
574          int ret = sh_files_search_file(path, &class, &check_flags, &reported);
575         
576          if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
577            {
578              ; /* do nothing, watch was for directory monitored as file only */
579            }
580          else
581            {
582              /* Removal of a directory triggers:
583               * (1) IN_DELETE IN_ISDIR
584               * (2) IN_DELETE_SELF
585               */
586              if ((event->mask & IN_DELETE_SELF) == 0)
587                sh_fInotify_report_miss(path, level);
588            }
589        }
590    }
591
592  sh_hash_set_missing(path);
593
594  if (sh.flag.reportonce == S_TRUE)
595    sh_files_set_file_reported(path);
596
597  /* Move to 'dormant' list, if not file within directory.
598   */
599  if (event->len == 0)
600    sh_inotify_rm_watch(&sh_file_watches, &sh_file_missing, event->wd);
601
602  return 0;
603}
604
605static int sh_fInotify_report_added (struct inotify_event * event, 
606                                     char * path, char * filename,
607                                     int class, unsigned long check_flags, 
608                                     int ftype, int rdepth)
609{
610  if (S_FALSE == sh_ignore_chk_new(path))
611    {
612      int reported;
613      int ret;
614      int retD = 0;
615      int rdepthD = rdepth;
616     
617      sh_files_clear_file_reported(path);
618         
619      ret = sh_files_search_file(path, &class, &check_flags, &reported);
620     
621      if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
622        {
623          ; /* do nothing, watch was for directory monitored as file only */
624        }
625      else
626        {
627          int classD = class;
628          int reportedD = reported; 
629          unsigned long check_flagsD = check_flags;
630         
631          if (event->mask & IN_ISDIR)
632            {
633              retD = sh_files_search_dir(path, &classD, &check_flagsD, 
634                                         &reportedD, &rdepthD);
635
636              if (retD != 0)
637                {
638                  if (ret == 0) /* because checked as file below */
639                    {
640                      class      = classD;
641                      check_flags = check_flagsD;
642                    }
643                }
644              rdepthD -= 1; if (rdepthD < -1) rdepthD = -1;
645            }
646         
647          sh_files_filecheck (class, check_flags, filename,
648                              (event->len > 0) ? event->name : NULL,
649                              &reported, 0);
650         
651          if (event->mask & IN_ISDIR)
652            {
653              SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_INSCAN;   );
654              /* Here we use classD because we check as directory now */
655              sh_files_checkdir (classD, check_flagsD, rdepthD, 
656                                 path, (event->len > 0) ? event->name : NULL);
657              SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_INSCAN;  );
658              SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
659              sh_dirs_reset  ();
660              sh_files_reset ();
661            }
662        }
663     
664      if (SH_FFLAG_REPORTED_SET(reported))
665        sh_files_set_file_reported(path);
666     
667      if ((ret != 0) || (event->mask & IN_ISDIR))
668        {
669          int inotify_type = SH_INOTIFY_FILE;
670         
671          if ((event->mask & IN_ISDIR) && (rdepthD >= 0))
672            inotify_type = SH_INOTIFY_DIR;
673
674          sh_inotify_add_watch(path, &sh_file_watches, &ret,
675                               class, check_flags, 
676                               inotify_type, 
677                               rdepthD);
678        }
679    }
680  return 0;
681}
682
683static int sh_fInotify_report(struct inotify_event * event, char * filename,
684                              int class, unsigned long check_flags, int ftype, int rdepth)
685{
686  char * fullpath = NULL;
687  char * path;
688
689  if (event->len > 0)
690    {
691      fullpath = sh_util_strconcat(filename, "/", event->name, NULL);
692      path = fullpath;
693    }
694  else
695    {
696      path = filename;
697    }
698
699  if ( (event->mask & (IN_ATTRIB|IN_MODIFY)) != 0)
700    {
701      sh_fInotify_report_change (event, path, filename,
702                                 class, check_flags, ftype);
703    }
704  else if ((event->mask & (IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF|IN_MOVED_FROM)) != 0)
705    {
706      sh_fInotify_report_missing (event, path,
707                                  class, check_flags, ftype);
708   }
709  else if((event->mask & (IN_CREATE|IN_MOVED_TO)) != 0)
710    {
711      sh_fInotify_report_added (event, path, filename,
712                                class, check_flags, 
713                                ftype, rdepth);
714    }
715
716  if (fullpath)
717    SH_FREE(fullpath);
718
719  return 0;
720}
721
722
723#endif
724
725#endif
Note: See TracBrowser for help on using the repository browser.