clsync
mon_inotify.c
Go to the documentation of this file.
1 /*
2  clsync - file tree sync utility based on inotify/kqueue
3 
4  Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "common.h"
21 #include "error.h"
22 #include "sync.h"
23 #include "indexes.h"
24 #include "privileged.h"
25 #include "mon_inotify.h"
26 
27 enum event_bits {
28  UEM_DIR = 0x01,
29  UEM_CREATED = 0x02,
30  UEM_DELETED = 0x04,
31 };
32 
36 };
37 
38 static inline void recognize_event ( struct recognize_event_return *r, uint32_t event )
39 {
40  eventobjtype_t type;
41  int is_created;
42  int is_deleted;
43  type = ( event & IN_ISDIR ? EOT_DIR : EOT_FILE );
44  is_created = event & ( IN_CREATE | IN_MOVED_TO );
45  is_deleted = event & ( IN_DELETE_SELF | IN_DELETE | IN_MOVED_FROM );
46  debug ( 4, "type == %x; is_created == %x; is_deleted == %x", type, is_created, is_deleted );
47  r->objtype_old = ( is_created ? EOT_DOESNTEXIST : type );
48  r->objtype_new = ( is_deleted ? EOT_DOESNTEXIST : type );
49  return;
50 }
51 
52 int inotify_add_watch_dir ( ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath )
53 {
54  ( void ) indexes_p;
55  int inotify_d = ( int ) ( long ) ctx_p->fsmondata;
56  return privileged_inotify_add_watch ( inotify_d, accpath, INOTIFY_MARKMASK, PC_INOTIFY_ADD_WATCH_DIR );
57 }
58 
59 int inotify_wait ( ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p )
60 {
61  ( void ) indexes_p;
62  int inotify_d = ( int ) ( long ) ctx_p->fsmondata;
63  debug ( 3, "select with timeout %li secs (fd == %u).", tv_p->tv_sec, inotify_d );
64  fd_set rfds;
65  FD_ZERO ( &rfds );
66  FD_SET ( inotify_d, &rfds );
67  return select ( inotify_d + 1, &rfds, NULL, NULL, tv_p );
68 }
69 
70 #define INOTIFY_HANDLE_CONTINUE {\
71  ptr += sizeof(struct inotify_event) + event->len;\
72  count++;\
73  continue;\
74  }
75 
76 int inotify_handle ( ctx_t *ctx_p, indexes_t *indexes_p )
77 {
78  static struct timeval tv = {0};
79  int inotify_d = ( int ) ( long ) ctx_p->fsmondata;
80  int count = 0;
81  fd_set rfds;
82  FD_ZERO ( &rfds );
83  FD_SET ( inotify_d, &rfds );
84  char *path_rel = NULL;
85  size_t path_rel_len = 0;
86  char *path_full = NULL;
87  size_t path_full_size = 0;
88 
89  while ( select ( FD_SETSIZE, &rfds, NULL, NULL, &tv ) ) {
90  char buf[BUFSIZ + 1];
91  size_t r = read ( inotify_d, buf, BUFSIZ );
92 
93  if ( r <= 0 ) {
94  error ( "Got error while reading events from inotify with read()." );
95  count = -1;
96  goto l_inotify_handle_end;
97  }
98 
99 #ifdef PARANOID
100  g_hash_table_remove_all ( indexes_p->fpath2ei_ht );
101 #endif
102  char *ptr = buf;
103  char *end = &buf[r];
104 
105  while ( ptr < end ) {
106  struct inotify_event *event = ( struct inotify_event * ) ptr;
107 
108  // Removing stale wd-s
109 
110  if ( event->mask & IN_IGNORED ) {
111  debug ( 2, "Cleaning up info about watch descriptor %i.", event->wd );
112  indexes_remove_bywd ( indexes_p, event->wd );
114  }
115 
116  // Getting path
117  char *fpath = indexes_wd2fpath ( indexes_p, event->wd );
118 
119  if ( fpath == NULL ) {
120  debug ( 2, "Event %p on stale watch (wd: %i).", ( void * ) ( long ) event->mask, event->wd );
122  }
123 
124  debug ( 2, "Event %p on \"%s\" (wd: %i; fpath: \"%s\").", ( void * ) ( long ) event->mask, event->len > 0 ? event->name : "", event->wd, fpath );
125  // Getting full path
126  size_t path_full_memreq = strlen ( fpath ) + event->len + 2;
127 
128  if ( path_full_size < path_full_memreq ) {
129  path_full = xrealloc ( path_full, path_full_memreq );
130  path_full_size = path_full_memreq;
131  }
132 
133  if ( event->len > 0 )
134  sprintf ( path_full, "%s/%s", fpath, event->name );
135  else
136  sprintf ( path_full, "%s", fpath );
137 
138  // Getting infomation about file/dir/etc
139  struct recognize_event_return r = {0};
140  recognize_event ( &r, event->mask );
141  stat64_t lst, *lst_p;
142  mode_t st_mode;
143  size_t st_size;
144 
145  if ( ( r.objtype_new == EOT_DOESNTEXIST ) || ( ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT ) || privileged_lstat64 ( path_full, &lst, PC_MON_HANDLE_LSTAT64 ) ) {
146  debug ( 2, "Cannot lstat64(\"%s\", lst). Seems, that the object had been deleted (%i) or option \"--cancel-syscalls mon_stat\" (%i) is set.", path_full, r.objtype_new == EOT_DOESNTEXIST, ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT );
147  st_mode = ( event->mask & IN_ISDIR ? S_IFDIR : S_IFREG );
148  st_size = 0;
149  lst_p = NULL;
150  } else {
151  st_mode = lst.st_mode;
152  st_size = lst.st_size;
153  lst_p = &lst;
154  }
155 
156  if ( sync_prequeue_loadmark ( 1, ctx_p, indexes_p, path_full, NULL, lst_p, r.objtype_old, r.objtype_new, event->mask, event->wd, st_mode, st_size, &path_rel, &path_rel_len, NULL ) ) {
157  count = -1;
158  goto l_inotify_handle_end;
159  }
160 
162  }
163 
164  // Globally queueing captured events:
165  // Moving events from local queue to global ones
166  sync_prequeue_unload ( ctx_p, indexes_p );
167  }
168 
169 l_inotify_handle_end:
170 
171  if ( path_full != NULL )
172  free ( path_full );
173 
174  if ( path_rel != NULL )
175  free ( path_rel );
176 
177  return count;
178 }
179 
181 {
182  int inotify_d = ( int ) ( long ) ctx_p->fsmondata;
183  debug ( 3, "Closing inotify_d" );
184  return close ( inotify_d );
185 }
186 
sync_prequeue_unload
int sync_prequeue_unload(ctx_t *ctx_p, indexes_t *indexes_p)
Definition: sync.c:2564
ctx
Definition: ctx.h:315
inotify_deinit
int inotify_deinit(ctx_t *ctx_p)
Definition: mon_inotify.c:180
close
close(fd_w)
sync.h
EOT_DOESNTEXIST
@ EOT_DOESNTEXIST
Definition: clsync.h:31
eventobjtype_t
enum eventobjtype eventobjtype_t
Definition: clsync.h:37
ctx::fsmondata
void * fsmondata
Definition: ctx.h:419
recognize_event_return
Definition: mon_bsm.c:61
sync_prequeue_loadmark
int sync_prequeue_loadmark(int monitored, ctx_t *ctx_p, indexes_t *indexes_p, const char *path_full, const char *path_rel, stat64_t *lst_p, eventobjtype_t objtype_old, eventobjtype_t objtype_new, uint32_t event_mask, int event_wd, mode_t st_mode, off_t st_size, char **path_buf_p, size_t *path_buf_len_p, eventinfo_t *evinfo)
Definition: sync.c:2143
IN_CREATE
#define IN_CREATE
Definition: mon_kqueue.h:34
indexes
Definition: indexes.h:34
IN_DELETE_SELF
#define IN_DELETE_SELF
Definition: mon_kqueue.h:36
event
Definition: mon_gio.c:41
privileged.h
ctx::flags
int flags[(1<< 10)]
Definition: ctx.h:338
CSC_MON_STAT
@ CSC_MON_STAT
Definition: ctx.h:310
inotify_handle
int inotify_handle(ctx_t *ctx_p, indexes_t *indexes_p)
Definition: mon_inotify.c:76
inotify_wait
int inotify_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p)
Definition: mon_inotify.c:59
recognize_event_return::objtype_new
eventobjtype_t objtype_new
Definition: mon_bsm.c:64
CANCEL_SYSCALLS
@ CANCEL_SYSCALLS
Definition: ctx.h:128
error
#define error(...)
Definition: error.h:36
indexes.h
error.h
event_bits
event_bits
Definition: mon_bsm.c:50
debug
#define debug(debug_level,...)
Definition: error.h:50
IN_ISDIR
#define IN_ISDIR
Definition: mon_kqueue.h:39
IN_IGNORED
#define IN_IGNORED
Definition: mon_kqueue.h:38
BUFSIZ
#define BUFSIZ
Definition: configuration.h:6
inotify_add_watch_dir
int inotify_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath)
Definition: mon_inotify.c:52
recognize_event_return::objtype_old
eventobjtype_t objtype_old
Definition: mon_bsm.c:63
common.h
IN_MOVED_TO
#define IN_MOVED_TO
Definition: mon_kqueue.h:32
privileged_lstat64
#define privileged_lstat64(a, b, c)
Definition: privileged.h:122
IN_MOVED_FROM
#define IN_MOVED_FROM
Definition: mon_kqueue.h:31
stat64_t
struct stat64 stat64_t
Definition: port-hacks.h:65
mon_inotify.h
UEM_CREATED
@ UEM_CREATED
Definition: mon_inotify.c:29
recognize_event
static void recognize_event(struct recognize_event_return *r, uint32_t event)
Definition: mon_inotify.c:38
indexes::fpath2ei_ht
GHashTable * fpath2ei_ht
Definition: indexes.h:37
EOT_FILE
@ EOT_FILE
Definition: clsync.h:32
INOTIFY_MARKMASK
#define INOTIFY_MARKMASK
Definition: configuration.h:109
INOTIFY_HANDLE_CONTINUE
#define INOTIFY_HANDLE_CONTINUE
Definition: mon_inotify.c:70
IN_DELETE
#define IN_DELETE
Definition: mon_kqueue.h:35
EOT_DIR
@ EOT_DIR
Definition: clsync.h:33
UEM_DIR
@ UEM_DIR
Definition: mon_inotify.c:28
privileged_inotify_add_watch
#define privileged_inotify_add_watch(a, b, c, d)
Definition: privileged.h:128
UEM_DELETED
@ UEM_DELETED
Definition: mon_inotify.c:30
ctx_p
ctx_t * ctx_p
Definition: mon_kqueue.c:85