33# include <bsm/audit_kevents.h>
64#define SEQID_WINDOW (((unsigned int)~0)>>1)
65#define SEQID_EQ(a, b) ((a)==(b))
66#define SEQID_GE(a, b) ((a)-(b) < SEQID_WINDOW)
67#define SEQID_LE(a, b) ((b)-(a) < SEQID_WINDOW)
68#define SEQID_GT(a, b) ((!SEQID_EQ(a, b)) && (SEQID_GE(a, b)))
69#define SEQID_LT(a, b) ((!SEQID_EQ(a, b)) && (SEQID_LE(a, b)))
78 char iterations[
sizeof (
"4294967296" )];
79 sprintf ( iterations,
"%i", iteration_num );
80 setenv (
"CLSYNC_ITERATION", iterations, 1 );
89#ifdef THREADING_SUPPORT
95 debug ( 3,
"next iteration: %u/%u",
104 memcpy ( ei_dup, ei,
sizeof ( *ei ) );
105 return ( gpointer ) ei_dup;
110 debug ( 3,
"evinfo_dst: seqid_min == %u; seqid_max == %u; objtype_old == %i; objtype_new == %i; \t"
111 "evinfo_src: seqid_min == %u; seqid_max == %u; objtype_old == %i; objtype_new == %i",
115#if KQUEUE_SUPPORT | INOTIFY_SUPPORT
122#ifdef INOTIFY_SUPPORT
170 error (
"Got non-zero exitcode %i from __sync_exec().",
exitcode );
181 if ( err )
error (
"Got error-report from exitcode_process().\nExitcode is %i, strerror(%i) returns \"%s\". However strerror() is not ensures compliance "
182 "between exitcode and error description for every utility. So, e.g if you're using rsync, you should look for the error description "
183 "into rsync's manpage (\"man 1 rsync\"). Also some advices about diagnostics can be found in clsync's manpage (\"man 1 clsync\", see DIAGNOSTICS)",
199 error (
"Cannot pthread_mutex_init()." );
204 error (
"Cannot pthread_cond_init()." );
217#ifdef THREADING_SUPPORT
218#define thread_info_lock() _thread_info_lock(__func__)
219static inline threadsinfo_t *_thread_info_lock (
const char *
const function_name )
222 debug ( 4,
"used by %s()", function_name );
224 return threadsinfo_p;
227#define thread_info_unlock(...) _thread_info_unlock(__func__, __VA_ARGS__)
228static inline int _thread_info_unlock (
const char *
const function_name,
int rc )
231 debug ( 4,
"used by %s()", function_name );
242 if ( threadsinfo_p == NULL )
243 return thread_info_unlock ( EINVAL );
249 while ( i < threadsinfo_p->used ) {
253 if ( ( rc = funct ( threadinfo_p, arg ) ) )
258 return thread_info_unlock ( rc );
263 time_t nextexpiretime = 0;
267 if ( threadsinfo_p == NULL )
268 return thread_info_unlock ( 0 );
271 int thread_num = threadsinfo_p->
used;
273 while ( thread_num-- ) {
275 debug ( 3,
"threadsinfo_p->threads[%i].state == %i;\tthreadsinfo_p->threads[%i].pthread == %p;\tthreadsinfo_p->threads[%i].expiretime == %i",
276 thread_num, threadinfo_p->
state, thread_num, threadinfo_p->
pthread, thread_num, threadinfo_p->
expiretime );
282 if ( nextexpiretime )
283 nextexpiretime = MIN ( nextexpiretime, threadinfo_p->
expiretime );
289 thread_info_unlock ( 0 );
290 debug ( 3,
"nextexpiretime == %i", nextexpiretime );
291 return nextexpiretime;
299 if ( threadsinfo_p == NULL ) {
300 thread_info_unlock ( 0 );
314 debug ( 2,
"Reallocated memory for threadsinfo -> %i.", threadsinfo_p->
allocated );
321 thread_num = threadsinfo_p->
used++;
322 threadinfo_p = &threadsinfo_p->
threads[thread_num];
326 memset ( threadinfo_p, 0,
sizeof ( *threadinfo_p ) );
334 debug ( 2,
"thread_new -> thread_num: %i; used: %i", thread_num, threadsinfo_p->
used );
335 thread_info_unlock ( 0 );
339int thread_del_bynum (
int thread_num )
341 debug ( 2,
"thread_del_bynum(%i)", thread_num );
345 if ( threadsinfo_p == NULL )
346 return thread_info_unlock ( errno );
350 if ( thread_num >= threadsinfo_p->
used )
351 return thread_info_unlock ( EINVAL );
355 char **ptr = threadinfo_p->
argv;
359 free ( * ( ptr++ ) );
361 free ( threadinfo_p->
argv );
364 if ( thread_num == ( threadsinfo_p->
used - 1 ) ) {
365 threadsinfo_p->
used--;
366 debug ( 3,
"thread_del_bynum(%i): there're %i threads left (#0).", thread_num, threadsinfo_p->
used - threadsinfo_p->
stacklen );
367 return thread_info_unlock ( 0 );
373 threadsinfo_p->
used--;
374 debug ( 3,
"%i [%p] -> %i [%p]; left: %i",
376 memcpy ( threadinfo_p, t,
sizeof ( *threadinfo_p ) );
381 error (
"Threads metadata structures pointers stack overflowed!" );
382 return thread_info_unlock ( EINVAL );
389 debug ( 3,
"thread_del_bynum(%i): there're %i threads left (#1).", thread_num, threadsinfo_p->
used - threadsinfo_p->
stacklen );
390 return thread_info_unlock ( 0 );
396 time_t tm = time ( NULL );
397 debug ( 3,
"tm == %i; thread %p", tm, pthread_self() );
405 if ( threadsinfo_p == NULL )
406 return thread_info_unlock ( errno );
409 debug ( 2,
"There're %i threads.", threadsinfo_p->
used );
412 while ( ++thread_num < threadsinfo_p->used ) {
415 debug ( 3,
"Trying thread #%i (==%i) (state: %i; expire at: %i, now: %i, exitcode: %i, errcode: %i; i_p: %p; p: %p).",
423 if ( pthread_tryjoin_np ( threadinfo_p->
pthread, NULL ) ) {
424 error (
"Debug3: thread_gc(): Thread #%i is alive too long: %lu <= %lu (started at %lu)", thread_num, threadinfo_p->
expiretime, tm, threadinfo_p->
starttime );
425 return thread_info_unlock (
ETIME );
432 debug ( 3,
"Thread #%i is busy, skipping (#0).", thread_num );
437 debug ( 3,
"Trying to join thread #%i: %p", thread_num, threadinfo_p->
pthread );
440 switch ( ( err = pthread_join ( threadinfo_p->
pthread, NULL ) ) ) {
443 switch ( ( err = pthread_tryjoin_np ( threadinfo_p->
pthread, NULL ) ) ) {
445 debug ( 3,
"Thread #%i is busy, skipping (#1).", thread_num );
452 debug ( 3,
"Thread #%i is finished with exitcode %i (errcode %i), deleting. threadinfo_p == %p",
453 thread_num, threadinfo_p->
exitcode, threadinfo_p->
errcode, threadinfo_p );
457 error (
"Got error while pthread_join() or pthread_tryjoin_np().", strerror ( err ), err );
458 return thread_info_unlock ( errno );
462 error (
"Got error from thread #%i: errcode %i.", thread_num, threadinfo_p->
errcode );
463 thread_info_unlock ( 0 );
464 thread_del_bynum ( thread_num );
468 thread_info_unlock ( 0 );
470 if ( thread_del_bynum ( thread_num ) )
476 debug ( 3,
"There're %i threads left.", threadsinfo_p->
used - threadsinfo_p->
stacklen );
477 return thread_info_unlock ( 0 );
487 if ( threadsinfo_p == NULL )
488 return thread_info_unlock ( errno );
492 debug ( 1,
"There're %i opened threads. Waiting.", threadsinfo_p->
used );
494 while ( threadsinfo_p->
used ) {
502 debug ( 1,
"killing pid %i with SIGTERM", threadinfo_p->
child_pid );
503 kill ( threadinfo_p->
child_pid, SIGTERM );
504 pthread_join ( threadinfo_p->
pthread, NULL );
505 debug ( 2,
"thread #%i exitcode: %i", threadsinfo_p->
used, threadinfo_p->
exitcode );
511 char **ptr = threadinfo_p->
argv;
514 free ( * ( ptr++ ) );
516 free ( threadinfo_p->
argv );
519 debug ( 3,
"All threads are closed." );
523 free ( threadsinfo_p->
threads );
531 pthread_mutex_destroy ( &threadsinfo_p->
mutex[i] );
532 pthread_cond_destroy ( &threadsinfo_p->
cond [i] );
539 memset ( threadsinfo_p, 0,
sizeof ( *threadsinfo_p ) );
541 debug ( 3,
"done." );
542 return thread_info_unlock ( 0 );
548#define SHOULD_THREAD(ctx_p) ((ctx_p->flags[THREADING] != PM_OFF) && (ctx_p->flags[THREADING] != PM_SAFE || ctx_p->iteration_num))
552 debug ( 3,
"Thread %p.", pthread_self() );
558 debug ( 3,
"Child pid is %u", pid );
566 sigset_t sigset_exec, sigset_old;
567 sigemptyset ( &sigset_exec );
569 pthread_sigmask ( SIG_BLOCK, &sigset_exec, &sigset_old );
576 debug ( 2,
"Child %u is already dead.", pid );
580 error (
"Cannot waitid()." );
587 pthread_sigmask ( SIG_SETMASK, &sigset_old, NULL );
590 int exitcode = WEXITSTATUS ( status );
591 debug ( 3,
"execution completed with exitcode %i",
exitcode );
595#ifdef THREADING_SUPPORT
600#if _DEBUG_FORCE | VERYPARANOID
602 if ( threadinfo_p->
pthread != pthread_self() ) {
603 error (
"pthread id mismatch! (i_p->p) %p != (p) %p""", threadinfo_p->
pthread, pthread_self() );
611 debug ( 3,
"thread %p, argv: ", threadinfo_p->
pthread );
621 error (
"Got error from callback function.", strerror ( err ), err );
628 debug ( 3,
"thread %p is sending signal to sighandler to call GC", threadinfo_p->
pthread );
641 if ( ei_i->
path == NULL ) {
642 warning (
"ei_i->path == NULL" );
648 free ( (
char * ) ei_i->
path );
659#ifdef THREADING_SUPPORT
662 debug ( 3,
"thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p",
665 int n = threadinfo_p->
n;
667 int err = 0, rc = 0, try_again = 0;
671 threadinfo_p->
try_n++;
676 warning (
"Bad exitcode %i (errcode %i). %s.", rc, err, try_again ?
"Retrying" :
"Give up" );
686 error (
"Bad exitcode %i (errcode %i)", rc, err );
692 if ( ( err = thread_exit ( threadinfo_p, rc ) ) ) {
703 debug ( 2,
"n == %i", n );
704#ifdef THREADING_SUPPORT
708 int rc = 0, ret = 0, err = 0;
709 int try_n = 0, try_again;
729 warning (
"Bad exitcode %i (errcode %i). %s.", rc, err, try_again ?
"Retrying" :
"Give up" );
739 error (
"Bad exitcode %i (errcode %i)", rc, err );
750#ifdef THREADING_SUPPORT
755 if ( threadinfo_p == NULL )
758 threadinfo_p->
try_n = 0;
760 threadinfo_p->
argv = NULL;
765 threadinfo_p->
ei = ei;
771 if ( pthread_create ( &threadinfo_p->
pthread, NULL, (
void * ( * ) (
void * ) ) so_call_sync_thread, threadinfo_p ) ) {
772 error (
"Cannot pthread_create()." );
789 if ( inclistfile == NULL ) {
790 error (
"inclistfile == NULL." );
794 debug ( 3,
"unlink()-ing \"%s\"", inclistfile );
795 ret0 = unlink ( inclistfile );
800 if ( exclistfile == NULL ) {
801 error (
"exclistfile == NULL." );
805 debug ( 3,
"unlink()-ing \"%s\"", exclistfile );
806 ret1 = unlink ( exclistfile );
807 return ret0 == 0 ? ret1 : ret0;
810#ifdef THREADING_SUPPORT
813 debug ( 3,
"thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p",
817 int err = 0, rc = 0, try_again;
821 threadinfo_p->
try_n++;
826 warning (
"Bad exitcode %i (errcode %i). %s.", rc, err, try_again ?
"Retrying" :
"Give up" );
833 }
while ( try_again );
836 error (
"Bad exitcode %i (errcode %i)", rc, err );
849 if ( ( err = thread_exit ( threadinfo_p, rc ) ) ) {
860 debug ( 2,
"inclistfile == \"%s\"; exclistfile == \"%s\"", inclistfile, exclistfile );
861#ifdef THREADING_SUPPORT
869 int try_n = 0, try_again;
887 warning (
"Bad exitcode %i (errcode %i). %s.", rc, err, try_again ?
"Retrying" :
"Give up" );
894 }
while ( try_again );
897 error (
"Bad exitcode %i (errcode %i)", rc, err );
909 return rc ? rc : ret_cleanup;
912#ifdef THREADING_SUPPORT
917 if ( threadinfo_p == NULL )
920 threadinfo_p->
try_n = 0;
922 threadinfo_p->
argv = xmalloc (
sizeof (
char * ) * 3 );
927 threadinfo_p->
argv[0] = strdup ( inclistfile );
928 threadinfo_p->
argv[1] = strdup ( exclistfile );
933 if ( pthread_create ( &threadinfo_p->
pthread, NULL, (
void * ( * ) (
void * ) ) so_call_rsync_thread, threadinfo_p ) ) {
934 error (
"Cannot pthread_create()." );
946#ifdef THREADING_SUPPORT
947#define SYNC_EXEC_ARGV(...) (SHOULD_THREAD(ctx_p) ? sync_exec_argv_thread : sync_exec_argv)(__VA_ARGS__)
949#define SYNC_EXEC_ARGV(...) sync_exec_argv(__VA_ARGS__)
952#define debug_argv_dump(level, argv)\
953 if (unlikely(ctx_p->flags[DEBUG] >= level))\
954 argv_dump(level, argv)
959 debug ( 19,
"(%u, %p)", debug_level,
argv );
961 char **argv_p =
argv;
963 while ( *argv_p != NULL ) {
964 debug ( debug_level,
"%p: \"%s\"", *argv_p, *argv_p );
971#define _sync_exec_getargv(argv, firstarg, COPYARG) {\
973 va_start(arglist, firstarg);\
978 if(i >= MAXARGUMENTS) {\
979 error("Too many arguments (%i >= %i).", i, MAXARGUMENTS);\
982 arg = (char *)va_arg(arglist, const char *const);\
983 argv[i] = arg!=NULL ? COPYARG : NULL;\
984 } while(argv[i++] != NULL);\
990 if ( path_rel == NULL )
993 if ( path_rel_len == -1 )
994 path_rel_len = strlen ( path_rel );
1000 size_t path_abs_len = path_rel_len + watchdirlen + 1;
1001 path_abs = ( path_abs_len_p == NULL || path_abs_len >= *path_abs_len_p ) ?
1002 xrealloc ( path_abs_oldptr, path_abs_len + 1 ) :
1005 if ( path_abs_oldptr == NULL ) {
1007 path_abs[watchdirlen] =
'/';
1010 memcpy ( &path_abs[watchdirlen + 1], path_rel, path_rel_len + 1 );
1012 if ( path_abs_len_p != NULL )
1013 *path_abs_len_p = path_abs_len;
1020 if ( path_abs == NULL )
1023 if ( path_abs_len == -1 )
1024 path_abs_len = strlen ( path_abs );
1026 size_t path_rel_len;
1028 size_t watchdirlen =
1030 signed long path_rel_len_signed = path_abs_len - ( watchdirlen + 1 );
1031 path_rel_len = ( path_rel_len_signed > 0 ) ? path_rel_len_signed : 0;
1032 path_rel = ( path_rel_len_p == NULL || path_rel_len >= *path_rel_len_p ) ?
1033 xrealloc ( path_rel_oldptr, path_rel_len + 1 ) :
1036 if ( !path_rel_len ) {
1041 memcpy ( path_rel, &path_abs[watchdirlen + 1], path_rel_len + 1 );
1044 debug ( 3,
"\"%s\" (len: %i) --%i--> \"%s\" (len: %i) + ",
1045 path_abs, path_abs_len, path_rel[path_rel_len - 1] ==
'/',
1048 if ( path_rel[path_rel_len - 1] ==
'/' )
1049 path_rel[--path_rel_len] = 0x00;
1051 debug ( 3,
"\"%s\" (len: %i)", path_rel, path_rel_len );
1054 if ( path_rel_len_p != NULL )
1055 *path_rel_len_p = path_rel_len;
1067 while ( i < ctx_p->children ) {
1069 if ( errno == ECHILD )
1093 int exitcode = 0, ret = 0, err = 0;
1094 int try_n = 0, try_again;
1115 warning (
"Bad exitcode %i (errcode %i). %s.",
exitcode, err, try_again ?
"Retrying" :
"Give up" );
1122 }
while ( try_again );
1132 if ( callback != NULL ) {
1133 int nret = callback (
ctx_p, callback_arg_p );
1136 error (
"Got error while callback()." );
1138 if ( !ret ) ret = nret;
1163#ifdef THREADING_SUPPORT
1168 debug ( 3,
"thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p""",
1169 threadinfo_p->
thread_num, threadinfo_p, threadinfo_p->
pthread, pthread_self() );
1170 int err = 0, exec_exitcode = 0, try_again;
1174 threadinfo_p->
try_n++;
1179 warning (
"__sync_exec_thread(): Bad exitcode %i (errcode %i). %s.", exec_exitcode, err, try_again ?
"Retrying" :
"Give up" );
1186 }
while ( try_again );
1189 error (
"Bad exitcode %i (errcode %i)", exec_exitcode, err );
1193 g_hash_table_destroy ( threadinfo_p->
fpath2ei_ht );
1195 if ( ( err = thread_exit ( threadinfo_p, exec_exitcode ) ) ) {
1200 debug ( 3,
"thread_num == %i; threadinfo_p == %p; i_p->pthread %p; thread %p""; errcode %i",
1202 return exec_exitcode;
1211 if ( threadinfo_p == NULL )
1214 threadinfo_p->
try_n = 0;
1219 threadinfo_p->
starttime = time ( NULL );
1226 if ( pthread_create ( &threadinfo_p->
pthread, NULL, (
void * ( * ) (
void * ) ) __sync_exec_thread, threadinfo_p ) ) {
1227 error (
"Cannot pthread_create()." );
1266 if ( strchr ( fpath_rel,
'\n' ) ) {
1268 debug ( 3,
"There's \"\\n\" character in path \"%s\". Ignoring it :(. Feedback to: https://github.com/clsync/clsync/issues/12", fpath_rel );
1272#ifdef CLUSTER_SUPPORT
1274 if (
ctx_p->cluster_iface )
1275 cluster_capture ( fpath_rel );
1280 if ( evinfo_q == NULL ) {
1282 memcpy ( evinfo_dup, evinfo,
sizeof ( *evinfo_dup ) );
1283 return indexes_queueevent ( indexes_p, strdup ( fpath_rel ), evinfo_dup,
queue_id );
1294#ifdef FANOTIFY_SUPPORT
1297 critical (
"fanotify is not supported" );
1300#if INOTIFY_SUPPORT | KQUEUE_SUPPORT
1301#ifdef INOTIFY_SUPPORT
1305#ifdef KQUEUE_SUPPORT
1319 evinfo_p->
evmask = ( isdir ? AUE_MKDIR : AUE_OPEN_RWC );
1325 evinfo_p->
evmask = G_FILE_MONITOR_EVENT_CREATED;
1350 const char *rootpaths[] = {dirpath, NULL};
1356 char rsync_and_prefer_excludes =
1381 int fts_opts = FTS_NOCHDIR | FTS_PHYSICAL |
1382 ( fts_no_stat ? FTS_NOSTAT : 0 ) |
1384 debug ( 3,
"fts_opts == %p", (
void * ) (
long ) fts_opts );
1385 tree =
privileged_fts_open ( (
char *
const * ) &rootpaths, fts_opts, NULL, PC_SYNC_INIIALSYNC_WALK_FTS_OPEN );
1387 if ( tree == NULL ) {
1388 error (
"Cannot privileged_fts_open() on \"%s\".", dirpath );
1392 memset ( &evinfo, 0,
sizeof ( evinfo ) );
1394 char *path_rel = NULL;
1395 size_t path_rel_len = 0;
1401 switch ( node->fts_info ) {
1421 int fts_errno = node->fts_errno;
1423 if ( fts_errno == ENOENT ) {
1424 debug ( 1,
"Got error while privileged_fts_read(): %s (errno: %i; fts_info: %i).", strerror ( fts_errno ), fts_errno, node->fts_info );
1427 error (
"Got error while privileged_fts_read(): %s (errno: %i; fts_info: %i).", strerror ( fts_errno ), fts_errno, node->fts_info );
1428 ret = node->fts_errno;
1429 goto l_sync_initialsync_walk_end;
1434 error (
"Got unknown fts_info vlaue while privileged_fts_read(): %i.", node->fts_info );
1436 goto l_sync_initialsync_walk_end;
1440 debug ( 3,
"Pointing to \"%s\" (node->fts_info == %i)", path_rel, node->fts_info );
1443 if ( rsync_and_prefer_excludes ) {
1445 debug ( 3,
"Excluding \"%s\" due to location on other device: node->fts_statp->st_dev [0x%o] != ctx_p->st_dev [0x%o]", path_rel, node->fts_statp->st_dev,
ctx_p->
st_dev );
1455 fts_set ( tree, node, FTS_SKIP );
1458 error (
"Excluding mount points is not implentemted for non \"rsync*\" modes." );
1461 mode_t st_mode = fts_no_stat ? ( node->fts_info == FTS_D ? S_IFDIR : S_IFREG ) : node->fts_statp->st_mode;
1463 if ( !skip_rules ) {
1467 debug ( 3,
"Rejecting to walk into \"%s\".", path_rel );
1468 fts_set ( tree, node, FTS_SKIP );
1472 debug ( 3,
"Excluding \"%s\".", path_rel );
1474 if ( rsync_and_prefer_excludes ) {
1479 indexes_addexclude ( indexes_p, strdup ( path_rel ),
EVIF_NONE, i++ );
1488 if ( !rsync_and_prefer_excludes ) {
1504 evinfo.
fsize = fts_no_stat ? 0 : node->fts_statp->st_size;
1505 debug ( 3,
"queueing \"%s\" (depth: %i) with int-flags %p", node->fts_path, node->fts_level, (
void * ) (
unsigned long ) evinfo.
flags );
1509 error (
"Got error while queueing \"%s\".", node->fts_path );
1511 goto l_sync_initialsync_walk_end;
1520 node->fts_info == FTS_D &&
1523 debug ( 4,
"\"FTS optimizator\"" );
1524 fts_set ( tree, node, FTS_SKIP );
1529 error (
"Got error while privileged_fts_read() and related routines." );
1531 goto l_sync_initialsync_walk_end;
1535 error (
"Got error while privileged_fts_close()." );
1537 goto l_sync_initialsync_walk_end;
1540l_sync_initialsync_walk_end:
1542 if ( path_rel != NULL )
1550 struct dosync_arg *dosync_arg_p = _dosync_arg_p;
1560 else if ( !strcmp ( variable_name,
"TYPE" ) )
1562 else if ( !strcmp ( variable_name,
"EVENT-MASK" ) )
1576 while ( s < args_p->c ) {
1577 char *arg = args_p->
v[s];
1581 debug ( 30,
"\"%s\" [%p]", arg, arg );
1586 debug ( 19,
"\"%s\" [%p] is already expanded, just strdup()-ing it", arg, arg );
1588 argv[d++] = strdup ( arg );
1592 if ( !strcmp ( arg,
"%INCLUDE-LIST%" ) ) {
1596 debug ( 19,
"INCLUDE-LIST: e == %u; d,s: %u,%u", e, d, s );
1610 debug ( 19,
"include-list: argv[%u] == %p", d - 1,
argv[d - 1] );
1653 while ( *argv_p != NULL ) {
1655 debug ( 25,
"free(%p)", *argv_p );
1657 free ( * ( argv_p++ ) );
1675 debug ( 3,
"(\"%s\", ctx_p, indexes_p, %i)", path,
initsync );
1676#ifdef CLUSTER_SUPPORT
1679 if (
ctx_p->cluster_iface )
1680 return cluster_initialsync();
1698 debug ( 3,
"syncing \"%s\"", path );
1704 memset ( ei, 0,
sizeof ( *ei ) );
1709 ei->
path = strdup ( path );
1731#ifdef THREADING_SUPPORT
1743 sync_exec_argv_thread ( NULL, NULL );
1748 error (
"Cannot get synclist" );
1762 memset ( evinfo, 0,
sizeof ( *evinfo ) );
1772 error (
"Cannot get exclude what to exclude" );
1776 debug ( 3,
"queueing \"%s\" with int-flags %p", path, (
void * ) (
unsigned long ) evinfo->
flags );
1778 ret = indexes_queueevent ( indexes_p, path_rel, evinfo,
queue_id );
1789 debug ( 3,
"(..., \"%s\", %i,...)", path, pathlen );
1790 int wd = indexes_fpath2wd ( indexes_p, path );
1793 debug ( 1,
"\"%s\" is already marked (wd: %i). Skipping.", path, wd );
1797 debug ( 5,
"ctx_p->notifyenginefunct.add_watch_dir(ctx_p, indexes_p, \"%s\")", accpath );
1800 if ( errno == ENOENT )
1803 error (
"Cannot ctx_p->notifyenginefunct.add_watch_dir() on \"%s\".",
1808 debug ( 6,
"endof ctx_p->notifyenginefunct.add_watch_dir(ctx_p, indexes_p, \"%s\")", accpath );
1809 indexes_add_wd ( indexes_p, wd, path, pathlen );
1813#ifdef CLUSTER_SUPPORT
1814static inline int sync_mark_walk_cluster_modtime_update (
ctx_t *
ctx_p,
const char *path,
short int dirlevel, mode_t st_mode )
1816 if (
ctx_p->cluster_iface ) {
1817 int ret = cluster_modtime_update ( path, dirlevel, st_mode );
1819 if ( ret )
error (
"cannot cluster_modtime_update()" );
1831 const char *rootpaths[] = {dirpath, NULL};
1834 debug ( 2,
"(ctx_p, \"%s\", indexes_p).", dirpath );
1836 debug ( 3,
"fts_opts == %p", (
void * ) (
long ) fts_opts );
1837 tree =
privileged_fts_open ( (
char *
const * ) rootpaths, fts_opts, NULL, PC_SYNC_MARK_WALK_FTS_OPEN );
1839 if ( tree == NULL ) {
1845 char *path_rel = NULL;
1846 size_t path_rel_len = 0;
1852#ifdef CLUSTER_SUPPORT
1855 debug ( 2,
"walking: \"%s\" (depth %u): fts_info == %i", node->fts_path, node->fts_level, node->fts_info );
1857 switch ( node->fts_info ) {
1868#ifdef CLUSTER_SUPPORT
1869 if ( ( ret = sync_mark_walk_cluster_modtime_update (
ctx_p, node->fts_path, node->fts_level, S_IFREG ) ) )
1870 goto l_sync_mark_walk_end;
1879#ifdef CLUSTER_SUPPORT
1880 if ( ( ret = sync_mark_walk_cluster_modtime_update (
ctx_p, node->fts_path, node->fts_level, S_IFDIR ) ) )
1881 goto l_sync_mark_walk_end;
1890 if ( errno == ENOENT ) {
1891 debug ( 1,
"Got error while privileged_fts_read(); fts_info: %i.", node->fts_info );
1896 goto l_sync_mark_walk_end;
1902 goto l_sync_mark_walk_end;
1907 debug ( 3,
"perm == 0x%o", perm );
1910 debug ( 2,
"setting an FTS_SKIP on the directory" );
1912 if ( fts_set ( tree, node, FTS_SKIP ) )
1913 warning (
"Got error while fts_set(tree, node, FTS_SKIP): %s", path_rel );
1917 debug ( 2,
"don't mark the directory" );
1921 debug ( 2,
"marking \"%s\" (depth %u)", node->fts_path, node->fts_level );
1922 int wd =
sync_notify_mark (
ctx_p, node->fts_accpath, node->fts_path, node->fts_pathlen, indexes_p );
1927 goto l_sync_mark_walk_end;
1930 debug ( 2,
"watching descriptor is %i.", wd );
1936 goto l_sync_mark_walk_end;
1942 goto l_sync_mark_walk_end;
1945l_sync_mark_walk_end:
1947 if ( path_rel != NULL )
1956#ifdef FANOTIFY_SUPPORT
1970#ifdef INOTIFY_SUPPORT
1975# if INOTIFY_FLAGS != 0
1976# warning Do not know how to set inotify flags (too old system)
1991#ifdef KQUEUE_SUPPORT
1996 if ( kqueue_d == -1 ) {
1997 error (
"cannot kqueue_init(ctx_p)." );
2011 if ( bsm_d == -1 ) {
2012 error (
"cannot bsm_init(ctx_p)." );
2039 debug ( 20,
"(ctx_p, indexes_p, \"%s\", \"%s\")",
evmask_str, fpath );
2051#ifdef THREADING_SUPPORT
2060 sync_exec_argv_thread ( NULL, NULL );
2067#ifdef CLUSTER_SUPPORT
2068 ret = cluster_lock ( fpath );
2070 if ( ret )
return ret;
2077#ifdef CLUSTER_SUPPORT
2078 ret = cluster_unlock_all();
2088 debug ( 9,
"Checking modification signature" );
2089 fileinfo_t *finfo = indexes_fileinfo ( indexes_p, path_rel );
2091 if ( finfo != NULL ) {
2095 debug ( 8,
"Modification signature: File not changed: \"%s\"", path_rel );
2102 debug ( 8,
"Modification signature: Deleting information about \"%s\"", path_rel );
2103 indexes_fileinfo_add ( indexes_p, path_rel, NULL );
2106 debug ( 8,
"Modification signature: Updating information about \"%s\"", path_rel );
2107 memcpy ( &finfo->
lst, lst_p, sizeof ( finfo->
lst ) );
2110 debug ( 8,
"There's no information about this file/dir: \"%s\". Just remembering the current state.", path_rel );
2112 finfo = xmalloc (
sizeof ( *finfo ) );
2113 memcpy ( &finfo->
lst, lst_p, sizeof ( finfo->
lst ) );
2114 indexes_fileinfo_add ( indexes_p, path_rel, finfo );
2122 static const char fpath_dot[] =
".";
2123 const char *fpath_fixed;
2124 fpath_fixed = fpath;
2131 fpath_fixed = fpath_dot;
2139 return indexes_fpath2ei_add ( indexes_p, strdup ( fpath_fixed ), evinfo );
2149 const char *path_full,
2150 const char *path_rel,
2157 uint32_t event_mask,
2163 size_t *path_buf_len_p,
2168 debug ( 10,
"%i %p %p %p %p %p %i %i 0x%o %i %i %i %p %p %p",
2188 if ( ( path_buf_p == NULL || path_buf_len_p == NULL ) && ( path_full == NULL || path_rel == NULL ) ) {
2189 error (
"path_rel_p == NULL || path_rel_len_p == NULL" );
2196 if ( path_full == NULL && path_rel == NULL ) {
2197 error (
"path_full == NULL && path_rel == NULL" );
2203 if ( path_rel == NULL ) {
2205 path_rel = *path_buf_p;
2223 debug ( 4,
"is_dir == %x; is_created == %x; is_deleted == %x", is_dir, is_created, is_deleted );
2230 if ( path_full == NULL ) {
2232 path_full = *path_buf_p;
2239 debug ( 1,
"Seems, that directory \"%s\" disappeared, while trying to mark it.", path_full );
2249 error (
"Got error from sync_initialsync()" );
2257 }
else if ( is_deleted ) {
2258 debug ( 2,
"Disappeared \".../%s\".", path_rel );
2267 debug ( 4,
"The file/dir is not changed. Returning." );
2273 if ( path_full == NULL ) {
2275 path_full = *path_buf_p;
2278 return SAFE (
sync_dosync ( path_full, event_mask,
ctx_p, indexes_p ),
debug ( 1,
"fpath == \"%s\"; evmask == 0x%o", path_full, event_mask );
return -1; );
2287 if ( evinfo == NULL )
2288 evinfo = indexes_fpath2ei ( indexes_p, path_rel );
2292 if ( evinfo == NULL ) {
2293 evinfo = (
eventinfo_t * ) xmalloc (
sizeof ( *evinfo ) );
2294 memset ( evinfo, 0,
sizeof ( *evinfo ) );
2295 evinfo->
fsize = st_size;
2296 evinfo->
wd = event_wd;
2301 debug ( 3,
"new event: fsize == %i; wd == %i", evinfo->
fsize, evinfo->
wd );
2307#ifdef KQUEUE_SUPPORT
2311#ifdef INOTIFY_SUPPORT
2314#if KQUEUE_SUPPORT | INOTIFY_SUPPORT
2315 evinfo->
evmask |= event_mask;
2322 evinfo->
evmask = event_mask;
2328 evinfo->
evmask = event_mask;
2334 debug ( 2,
"path_rel == \"%s\"; evinfo->objtype_old == %i; evinfo->objtype_new == %i; "
2335 "evinfo->seqid_min == %u; evinfo->seqid_max == %u",
2349 char *fpath = (
char * ) fpath_gp;
2351 debug ( 3,
"\"%s\", %u (%p).", fpath, GPOINTER_TO_INT ( flags_gp ), flags_gp );
2352 indexes_addexclude_aggr ( indexes_p, strdup ( fpath ), (
eventinfo_flags_t ) GPOINTER_TO_INT ( flags_gp ) );
2359 static char buf[PATH_MAX + 2] = {0};
2361 eventinfo_t *evinfo = g_hash_table_lookup ( ht, fpath );
2362 debug ( 5,
"looking up for \"%s\": %p", fpath, evinfo );
2364 if ( evinfo != NULL )
2370 evinfo = g_hash_table_lookup ( ht,
"" );
2372 if ( evinfo != NULL ) {
2379 size_t fpath_len = strlen ( fpath );
2380 memcpy (
buf, fpath, fpath_len + 1 );
2382 end = &
buf[fpath_len];
2384 while ( ptr < end ) {
2385 if ( *ptr ==
'/' ) {
2387 evinfo = g_hash_table_lookup ( ht,
buf );
2389 if ( evinfo != NULL ) {
2406 char *fpath = _fpath;
2408 debug ( 4,
"scanning thread %p: fpath<%s> -> evinfo<%p>", threadinfo_p->
pthread, fpath, evinfo );
2410 if ( evinfo != NULL )
2418#ifdef THREADING_SUPPORT
2420 debug ( 3,
"<%s>: %u", fpath, rc );
2429 char *fpath = (
char * ) fpath_gp;
2439 debug ( 3,
"\"%s\" is locked, dropping to waitlock queue", fpath );
2440 eventinfo_t *evinfo_dup = xmalloc (
sizeof ( *evinfo_dup ) );
2441 memcpy ( evinfo_dup, evinfo,
sizeof ( *evinfo ) );
2447 debug ( 3,
"calling sync_dosync()" );
2453 eventinfo_t *evinfo_idx = indexes_fpath2ei ( indexes_p, fpath );
2455 if ( evinfo_idx == NULL ) {
2456 evinfo_idx = (
eventinfo_t * ) xmalloc (
sizeof ( *evinfo_idx ) );
2457 memset ( evinfo_idx, 0,
sizeof ( *evinfo_idx ) );
2477 eventinfo_t *evinfo_q = indexes_lookupinqueue ( indexes_p, fpath, _queue_id );
2479 if ( evinfo_q != NULL ) {
2481 indexes_removefromqueue ( indexes_p, fpath, _queue_id );
2483 if ( !indexes_queuelen ( indexes_p, _queue_id ) )
2491 debug ( 4,
"Collecting \"%s\"", fpath );
2506 char *fpath = (
char * ) fpath_gp;
2510 indexes_t *indexes_p = arg_p->indexes_p;
2519 critical (
"Cannot re-queue \"%s\" to be synced", fpath );
2531 int ret0 = 0, ret1 = 0;
2536 debug ( 3,
"(ctx_p, {inc: %p, exc: %p}) thread %p", arg_p->
incfpath, arg_p->
excfpath, pthread_self() );
2539 debug ( 3,
"unlink()-ing exclude-file: \"%s\"", arg_p->
excfpath );
2545 debug ( 3,
"unlink()-ing include-file: \"%s\"", arg_p->
incfpath );
2551 return ret0 ? ret0 : ret1;
2556 char *fpath_rel = (
char * ) fpath_gp;
2569 debug ( 3,
"collected %i events per this time.", g_hash_table_size ( indexes_p->
fpath2ei_ht ) );
2571 g_hash_table_remove_all ( indexes_p->
fpath2ei_ht );
2577 time_t tm = time ( NULL );
2587 debug ( 3,
"(%i, ...): evcount_real == %i",
queue_id, evcount_real );
2589 if ( evcount_real <= 0 ) {
2628 pid_t pid = getpid();
2629 time_t tm = time ( NULL );
2634 snprintf ( fpath, PATH_MAX,
"%s/.clsync-%s.%u.%lu.%lu.%u",
ctx_p->
listoutdir, name, pid, (
long ) pthread_self(), (
unsigned long ) tm, rand() );
2635 lstat64 ( fpath, &stat64 );
2638 error (
"Cannot find unused filename for list-file. The last try was \"%s\".", fpath );
2641 }
while ( errno != ENOENT );
2649 debug ( 3,
"Creating %s file", name );
2655 error (
"sync_idle_dosync_collectedevents_listcreate: Cannot get unique file name." );
2659 dosync_arg_p->
outf = fopen ( fpath,
"w" );
2661 if ( dosync_arg_p->
outf == NULL ) {
2662 error (
"Cannot open \"%s\" as file for writing.", fpath );
2666 setbuffer ( dosync_arg_p->
outf, dosync_arg_p->
buf,
BUFSIZ );
2667 debug ( 3,
"Created list-file \"%s\"", fpath );
2683 size_t sc_count = 0;
2687 switch ( path[i] ) {
2689 goto l_rsync_escape_loop0_end;
2702l_rsync_escape_loop0_end:
2706 size_t required_size = i + sc_count + 1;
2719 switch ( path[i] ) {
2742 debug ( 3,
"Recursively \"%s\": Writing to rsynclist: \"%s/*""**\".", outline, outline );
2743 critical_on ( fprintf ( outf,
"%s/*""**\n", outline ) <= 0 );
2745 debug ( 3,
"Content-recursively \"%s\": Writing to rsynclist: \"%s/*""*\".", outline, outline );
2746 critical_on ( fprintf ( outf,
"%s/*""*\n", outline ) <= 0 );
2748 debug ( 3,
"Non-recursively \"%s\": Writing to rsynclist: \"%s\".", outline, outline );
2749 critical_on ( fprintf ( outf,
"%s\n", outline ) <= 0 );
2755gboolean
rsync_aggrout ( gpointer outline_gp, gpointer flags_gp, gpointer arg_gp )
2758 char *outline = (
char * ) outline_gp;
2765 error (
"Got error from rsync_outline(). Exit." );
2776 if ( fpath_len > 0 ) {
2778 fpathwslash = alloca ( fpath_len + 2 );
2779 fpathwslash[0] =
'/';
2780 memcpy ( &fpathwslash[1], fpath, fpath_len + 1 );
2783 fpathwslash = (
char * ) fpath;
2787 char *end = fpathwslash;
2788 debug ( 3,
"\"%s\": Adding to rsynclist: \"%s\" with flags %p.",
2789 fpathwslash, fpathwslash, (
void * ) (
long ) flags );
2790 indexes_outaggr_add ( indexes_p, strdup ( fpathwslash ), flags );
2792 if ( linescount_p != NULL )
2793 ( *linescount_p )++;
2795 while ( end != NULL ) {
2796 if ( *fpathwslash == 0x00 )
2799 debug ( 3,
"Non-recursively \"%s\": Adding to rsynclist: \"%s\".", fpathwslash, fpathwslash );
2800 indexes_outaggr_add ( indexes_p, strdup ( fpathwslash ),
EVIF_NONE );
2802 if ( linescount_p != NULL )
2803 ( *linescount_p )++;
2805 end = strrchr ( fpathwslash,
'/' );
2810 if ( end - fpathwslash <= 0 )
2822 char *fpath = (
char * ) fpath_gp;
2823 FILE *excf = dosync_arg_p->
outf;
2827 debug ( 3,
"\"%s\"", fpath );
2828 size_t fpath_len = strlen ( fpath );
2831 if ( fpath_len > 0 ) {
2833 fpathwslash = alloca ( fpath_len + 2 );
2834 fpathwslash[0] =
'/';
2835 memcpy ( &fpathwslash[1], fpath, fpath_len + 1 );
2838 fpathwslash = fpath;
2844 if ( ( ret =
rsync_outline ( excf, fpathwslash, flags ) ) ) {
2845 error (
"Got error from rsync_outline(). Exit." );
2855 indexes_t *indexes_p = dosync_arg_p->indexes_p;
2865 if ( dosync_arg_p->
outf != NULL ) {
2867 dosync_arg_p->
outf = NULL;
2870 if ( dosync_arg_p->
evcount > 0 ) {
2887 callback_arg_p = xcalloc ( 1,
sizeof ( *callback_arg_p ) );
2900 ?
"rsynclist" :
"synclist";
2913#ifdef THREADING_SUPPORT
2926 sync_exec_argv_thread ( NULL, NULL );
2933 char newexc_path[PATH_MAX + 1];
2938 error (
"Cannot get unique file name." );
2943 error (
"Cannot copy file \"%s\" to \"%s\".", dosync_arg_p->
excf_path, newexc_path );
2954 error (
"Cannot commit list-file \"%s\"", dosync_arg_p->
outf_path );
2962 strcpy ( dosync_arg_p->
excf_path, newexc_path );
2965 error (
"Cannot create new list-file" );
2976 char *fpath = (
char * ) fpath_gp;
2981 unsigned int *linescount_p = &dosync_arg_p->
linescount;
2982 indexes_t *indexes_p = dosync_arg_p->indexes_p;
2985 debug ( 3,
"\"%s\" with int-flags %p. "
2986 "evinfo: seqid_min == %u, seqid_max == %u type_o == %i, type_n == %i",
2987 fpath, (
void * ) (
unsigned long ) evinfo->
flags,
3000 ei->
path = strdup ( fpath );
3047 if ( ( ret =
rsync_listpush ( indexes_p, fpath, strlen ( fpath ), evinfo->
flags, linescount_p ) ) ) {
3048 error (
"Got error from rsync_listpush(). Exit." );
3061 char isrsyncpreferexclude =
3070 g_hash_table_remove_all ( indexes_p->
fpath2ei_ht );
3072 if ( isrsyncpreferexclude )
3095 error (
"Got error while processing queue #%i\n.",
queue_id );
3096 g_hash_table_remove_all ( indexes_p->
fpath2ei_ht );
3098 if ( isrsyncpreferexclude )
3108 debug ( 3,
"Summary events' count is zero. Return 0." );
3125 if ( isrsyncpreferexclude ) {
3127 error (
"Cannot create list-file" );
3144 error (
"Cannot create list-file" );
3159 g_hash_table_remove_all ( indexes_p->
fpath2ei_ht );
3163 g_hash_table_remove_all ( indexes_p->
fpath2ei_ht );
3175 if ( listfile == NULL ) {
3176 error (
"listfile == NULL." );
3183 rsync_listpush ( indexes_p, apievinfo[i].path, apievinfo[i].path_len, apievinfo[i].flags, NULL );
3200#ifdef THREADING_SUPPORT
3201 ret = thread_gc (
ctx_p );
3203 if ( ret )
return ret;
3226 debug ( 3,
"calling sync_idle_dosync_collectedevents()" );
3227#ifdef CLUSTER_SUPPORT
3228 ret = cluster_lock_byindexes();
3230 if ( ret )
return ret;
3235 if ( ret )
return ret;
3237#ifdef CLUSTER_SUPPORT
3238 ret = cluster_unlock_all();
3240 if ( ret )
return ret;
3248 static struct timeval tv;
3249 time_t tm = time ( NULL );
3250 long delay = ( (
unsigned long ) ~0 >> 1 );
3252 debug ( 4,
"pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
3264 debug ( 3,
"There're events in instant queue (#%i), don't waiting.",
queue_id - 1 );
3274 delay = MIN ( delay, qdelay );
3277 long synctime_delay = ( ( long )
ctx_p->
synctime ) - ( (
long ) tm );
3278 synctime_delay = synctime_delay > 0 ? synctime_delay : 0;
3279 debug ( 3,
"delay = MAX(%li, %li)", delay, synctime_delay );
3280 delay = MAX ( delay, synctime_delay );
3281 delay = delay > 0 ? delay : 0;
3282#ifdef THREADING_SUPPORT
3286 debug ( 3,
"thread_nextexpiretime == %i", _thread_nextexpiretime );
3288 if ( _thread_nextexpiretime ) {
3290 debug ( 3,
"thread_expiredelay == %i", thread_expiredelay );
3291 thread_expiredelay = thread_expiredelay > 0 ? thread_expiredelay : 0;
3292 debug ( 3,
"delay = MIN(%li, %li)", delay, thread_expiredelay );
3293 delay = MIN ( delay, thread_expiredelay );
3300 debug ( 4,
"forcing: no events (delay is %li, state is %s)",
3317 debug ( 4,
"pthread_mutex_lock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
3323 debug ( 4,
"pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
3331 if ( ( ret == -1 ) && ( errno == EINTR ) ) {
3336 debug ( 4,
"pthread_mutex_lock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE])" );
3350#define SYNC_LOOP_IDLE {\
3352 if((ret=sync_idle(ctx_p, indexes_p))) {\
3353 error("got error while sync_idle().");\
3358#define SYNC_LOOP_CONTINUE_UNLOCK {\
3359 pthread_cond_broadcast(&threadsinfo_p->cond[PTHREAD_MUTEX_STATE]);\
3360 debug(4, "pthread_mutex_unlock()");\
3361 pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);\
3371 critical (
"ctx_p->preexithookfile == NULL" );
3388 debug ( 4,
"pthread_mutex_lock(): PTHREAD_MUTEX_STATE" );
3390 debug ( 3,
"current state is \"%s\" (%i) (iteration: %u/%u); threadsinfo_p->used == %u",
3395 debug ( 1,
"We are in non-threading mode but have %u syncer threads. Waiting for them end.", threadsinfo_p->
used );
3405#ifdef THREADING_SUPPORT
3407 if ( thread_gc (
ctx_p ) ) {
3427 if ( ret )
return ret;
3459 debug ( 1,
"preparing to exit" );
3474 debug ( 3,
"notify_wait ( ctx_p, indexes_p ) [lastsync]" );
3480 debug ( 3,
"notify_wait ( ctx_p, indexes_p )" );
3492 debug ( 1,
"rehashing." );
3511 debug ( 4,
"pthread_mutex_unlock(): PTHREAD_MUTEX_STATE" );
3514 if ( events == 0 ) {
3515 debug ( 2,
"events == 0" );
3521 error (
"Got error while waiting for event from notify subsystem." );
3525 debug ( 3,
"ctx_p->notifyenginefunct.handle" );
3529 error (
"Cannot handle with notify events." );
3539 debug ( 1,
"last SYNC_LOOP_IDLE" );
3550 debug ( 2,
"%i: Thread %p", signal, pthread_self() );
3555int _sync_tryforcecycle_i;
3559 ( void ) pthread_parent;
3560 debug ( 3,
"sending signal to interrupt blocking operations like select()-s and so on (ctx_p->blockthread_count == %i)",
ctx_p->
blockthread_count );
3566 while ( i < count ) {
3575 error (
"Seems we got a deadlock." );
3580#ifdef SYNC_SWITCHSTATE_COND_TIMEDWAIT
3581 struct timespec time_timeout;
3582 clock_gettime ( CLOCK_REALTIME, &time_timeout );
3583 time_timeout.tv_sec++;
3585 debug ( 3,
"pthread_cond_timedwait() until %li.%li", time_timeout.tv_sec, time_timeout.tv_nsec );
3587 if ( pthread_cond_timedwait ( pthread_cond_state, pthread_mutex_state, &time_timeout ) != ETIMEDOUT )
3600 debug ( 3,
"sync_switch_state(ctx_p, %p, %i), but state_p == NULL", pthread_parent, newstate );
3604 debug ( 3,
"sync_switch_state(ctx_p, %p, %i)", pthread_parent, newstate );
3608 if ( threadsinfo_p == NULL ) {
3610 goto l_sync_parent_interrupt_end;
3615 goto l_sync_parent_interrupt_end;
3623 _sync_tryforcecycle_i = 0;
3625 debug ( 4,
"while(pthread_mutex_trylock( pthread_mutex_state ))" );
3627 while ( pthread_mutex_trylock ( pthread_mutex_state ) == EBUSY ) {
3630 if ( rc && rc != EINPROGRESS )
3638 _sync_tryforcecycle_i = 0;
3640 debug ( 4,
"while(pthread_mutex_trylock( pthread_mutex_select ))" );
3642 while ( pthread_mutex_trylock ( pthread_mutex_select ) == EBUSY ) {
3645 if ( rc && rc != EINPROGRESS )
3658 debug ( 4,
"pthread_cond_broadcast(). New state is %i.", *
state_p );
3659 pthread_cond_broadcast ( pthread_cond_state );
3660 debug ( 4,
"pthread_mutex_unlock( pthread_mutex_state )" );
3661 pthread_mutex_unlock ( pthread_mutex_state );
3662 debug ( 4,
"pthread_mutex_unlock( pthread_mutex_select )" );
3663 pthread_mutex_unlock ( pthread_mutex_select );
3664#ifdef THREADING_SUPPORT
3665 return thread_info_unlock ( 0 );
3669l_sync_parent_interrupt_end:
3672#ifdef THREADING_SUPPORT
3673 return thread_info_unlock ( 0 );
3704 char *fpath = (
char * ) fpath_gp;
3709 if ( fpath == NULL || evinfo == NULL )
3712 switch ( arg->
data ) {
3734 dprintf ( arg->
fd_out,
"%c%c\t%s\n", act, num, fpath );
3751 "thread:\n\titeration == %u\n\tnum == %u\n\tpthread == %lx\n\tstarttime == %lu\n\texpiretime == %lu\n\tchild_pid == %u\n\ttry_n == %u\nCommand:",
3754 (
long ) threadinfo_p->
pthread,
3762 while ( *
argv != NULL )
3763 dprintf ( arg->
fd_out,
" \"%s\"", * (
argv++ ) );
3765 dprintf ( arg->
fd_out,
"\n" );
3780 debug ( 3,
"%s", dir_path );
3782 if ( dir_path == NULL )
3785 static const char *
const subdirs[] = {
3792 if ( rootfd == -1 ) {
3793 error (
"Cannot open directory \"%s\"", dir_path );
3794 goto l_sync_dump_end;
3800 error (
"Cannot open file \"%s\" for writing" );
3801 goto l_sync_dump_end;
3804 dprintf (
fd_out,
"status == %s\n", getenv (
"CLSYNC_STATUS" ) );
3816 const char *
const subdir = subdirs[dirfd_obj];
3819 if ( arg.
dirfd[dirfd_obj] == -1 ) {
3820 error (
"Cannot open directory \"%s\"", subdir );
3821 goto l_sync_dump_end;
3845#ifdef THREADING_SUPPORT
3852 if ( arg.
dirfd[dirfd_obj] != -1 && arg.
dirfd[dirfd_obj] != 0 )
3853 close ( arg.
dirfd[dirfd_obj] );
3859 error (
"Cannot create the dump to \"%s\"", dir_path );
3876 int signal = 0, ret;
3877 sigset_t sigset_full;
3882 int *exitcode_p = sighandler_arg_p->
exitcode_p;
3885 sigfillset ( &sigset_full );
3888 debug ( 3,
"waiting for signal (is sigset filled == %i)", sigismember ( &sigset_full, SIGTERM ) );
3889 ret = sigwait ( &sigset_full, &signal );
3894 *exitcode_p =
ETIME;
3901 exit ( *exitcode_p );
3905 warning (
"Got signal %i, but the main loop is not started, yet. Ignoring the signal.", signal );
3912 debug ( 3,
"got signal %i. ctx_p->state == %i.", signal,
ctx_p->
state );
3920 *exitcode_p = errno;
3929 *exitcode_p =
ETIME;
3946 if ( signal != SIGQUIT )
3950 if ( signal != SIGTERM )
3981 error (
"Unknown signal: %i. Exit.", signal );
3987 debug ( 3,
"signal handler closed." );
4003 debug ( 9,
"Creating signal handler thread" );
4007 sigset_t sigset_sighandler;
4008 sigemptyset ( &sigset_sighandler );
4009 sigaddset ( &sigset_sighandler, SIGALRM );
4010 sigaddset ( &sigset_sighandler, SIGHUP );
4011 sigaddset ( &sigset_sighandler, SIGQUIT );
4012 sigaddset ( &sigset_sighandler, SIGTERM );
4013 sigaddset ( &sigset_sighandler, SIGINT );
4014 sigaddset ( &sigset_sighandler, SIGCHLD );
4022 sigaddset ( &sigset_sighandler, i );
4027 ret = pthread_sigmask ( SIG_BLOCK, &sigset_sighandler, NULL );
4029 if ( ret )
return ret;
4037 if ( ret )
return ret;
4039 sigset_t sigset_parent;
4040 sigemptyset ( &sigset_parent );
4042 ret = pthread_sigmask ( SIG_UNBLOCK, &sigset_parent, NULL );
4044 if ( ret )
return ret;
4048 debug ( 9,
"Creating hash tables" );
4074 debug ( 9,
"Loading dynamical libraries" );
4078 struct stat so_stat;
4086 if ( !S_ISREG ( so_stat.st_mode ) ) {
4087 error (
"Shared object \"%s\" must be a regular file (or symlink to a regular file).",
4093 if ( so_stat.st_uid && so_stat.st_uid != getuid() ) {
4095 struct stat cl_stat;
4096 char *cl_str = alloca ( 20 );
4098 snprintf ( cl_str, 20,
"/proc/%i/exe", getpid() );
4101 if ( ( ret = stat ( cl_str, &cl_stat ) ) == -1 ) {
4102 error (
"Can't stat clsync binary file \"%s\": %s", cl_str, strerror ( errno ) );
4105 if ( ret == -1 || so_stat.st_uid != cl_stat.st_uid ) {
4106 error (
"Wrong owner for shared object \"%s\": %i. "
4107 "Only root, clsync file owner and user started the program are allowed.",
4114 if ( so_stat.st_mode & ( S_ISUID | S_ISGID | S_ISVTX | S_IWGRP | S_IWOTH ) ) {
4115 error (
"Wrong shared object \"%s\" permissions: %#lo"
4116 "Special bits, group and world writable are not allowed.",
4122 void *synchandler_handle = dlopen (
ctx_p->
handlerfpath, RTLD_NOW | RTLD_LOCAL );
4124 if ( synchandler_handle == NULL ) {
4137 char *dlerror_str = dlerror();
4138 error (
"Cannot resolve symbol "API_PREFIX"rsync in shared object \"%s\": %s",
4139 ctx_p->
handlerfpath, dlerror_str != NULL ? dlerror_str :
"No error description returned." );
4145 char *dlerror_str = dlerror();
4146 error (
"Cannot resolve symbol "API_PREFIX"sync in shared object \"%s\": %s",
4147 ctx_p->
handlerfpath, dlerror_str != NULL ? dlerror_str :
"No error description returned." );
4156 error (
"Cannot init sync-handler module." );
4164 srand ( time ( NULL ) );
4167 debug ( 9,
"Initializing FS monitor kernel subsystem in this userspace application" );
4179#ifdef INOTIFY_SUPPORT
4187#ifdef KQUEUE_SUPPORT
4212#ifdef DTRACEPIPE_SUPPORT
4227#ifdef CLUSTER_SUPPORT
4230 if (
ctx_p->cluster_iface != NULL ) {
4234 error (
"Cannot initialize cluster subsystem." );
4251 debug ( 30,
"Running recursive notify marking function" );
4254 if ( ret )
return ret;
4260 if ( ret )
return ret;
4262 debug ( 1,
"sync_loop() ended" );
4270 debug ( 1,
"killing sighandler" );
4277#ifdef THREADING_SUPPORT
4278 thread_cleanup (
ctx_p );
4280 debug ( 2,
"Deinitializing the FS monitor subsystem" );
4283#ifdef INOTIFY_SUPPORT
4289#ifdef KQUEUE_SUPPORT
4308#ifdef DTRACEPIPE_SUPPORT
4322 error (
"Cannot deinit sync-handler module." );
4324 if ( !ret ) ret = _ret;
4328 error (
"Cannot unload shared object file \"%s\": %s",
4331 if ( !ret ) ret = -1;
4340 debug ( 3,
"Closing hash tables" );
4364#ifdef CLUSTER_SUPPORT
4365 debug ( 3,
"Deinitializing cluster subsystem" );
4367 if (
ctx_p->cluster_iface != NULL ) {
4369 _ret = cluster_deinit();
4372 error (
"Cannot deinitialize cluster subsystem.", strerror ( _ret ), _ret );
4390#ifdef CGROUP_SUPPORT
4391 debug ( 3,
"Cleaning up cgroups staff" );
4397 debug ( 3,
"privileged_deinit()" );
4399 debug ( 3,
"finish" );
int(* api_funct_init)(struct ctx *, struct indexes *)
@ EVIF_CONTENTRECURSIVELY
int(* api_funct_sync)(int n, api_eventinfo_t *)
int(* api_funct_rsync)(const char *inclist, const char *exclist)
int(* api_funct_deinit)()
enum eventinfo_flags eventinfo_flags_t
enum eventobjtype eventobjtype_t
@ PTHREAD_MUTEX_THREADSINFO
int control_run(ctx_t *ctx_p)
int control_cleanup(ctx_t *ctx_p)
#define STATE_STARTING(state_p)
enum ruleaction_enum ruleaction_t
static char *const status_descr[]
#define register_blockthread(thread)
#define error_or_debug(debug_level,...)
#define debug(debug_level,...)
#define critical_on(cond)
int mkdirat_open(const char *const dir_path, int dirfd_parent, mode_t dir_mode)
Combination of mkdirat() and openat()
int fileutils_copy(const char *path_from, const char *path_to)
Copies file.
uint32_t stat_diff(stat64_t *a, stat64_t *b)
GHashTable * g_hash_table_dup(GHashTable *src, GHashFunc hash_funct, GEqualFunc key_equal_funct, GDestroyNotify key_destroy_funct, GDestroyNotify value_destroy_funct, GDupFunc key_dup_funct, GDupFunc value_dup_funct)
#define MSG_SECURITY_PROBLEM(a)
#define COLLECTDELAY_INSTANT
#define SAFE(code, onfail)
#define require_strlen_le(str, limit)
int config_block_parse(ctx_t *ctx_p, const char *const config_block_name)
char * parameter_expand(ctx_t *ctx_p, char *arg, int exceptionflags, int *macro_count_p, int *expand_count_p, const char *(*parameter_get)(const char *variable_name, void *arg), void *parameter_get_arg)
Expands option values, e. g. "/var/log/clsync-%label%.pid" -> "/var/log/clsync-clone....
int main_status_update(ctx_t *ctx_p)
int main_rehash(ctx_t *ctx_p)
int sethandler_sigchld(void(*handler)())
int(* bsm_handle)(struct ctx *ctx_p, struct indexes *indexes_p)
int bsm_deinit(ctx_t *ctx_p)
int(* bsm_wait)(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p)
int bsm_init(ctx_t *ctx_p)
int bsm_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath)
int dtracepipe_deinit(ctx_t *ctx_p)
int dtracepipe_wait(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p)
int dtracepipe_handle(struct ctx *ctx_p, struct indexes *indexes_p)
int dtracepipe_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath)
int gio_deinit(ctx_t *ctx_p)
int gio_init(ctx_t *ctx_p)
int gio_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath)
int gio_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p)
int gio_handle(ctx_t *ctx_p, indexes_t *indexes_p)
int inotify_handle(ctx_t *ctx_p, indexes_t *indexes_p)
int inotify_deinit(ctx_t *ctx_p)
int inotify_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p)
int inotify_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath)
int kqueue_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p)
int kqueue_handle(ctx_t *ctx_p, indexes_t *indexes_p)
int kqueue_deinit(ctx_t *ctx_p)
int kqueue_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath)
int privileged_init(ctx_t *ctx_p)
int privileged_deinit(ctx_t *ctx_p)
#define privileged_fts_read(a, b)
#define privileged_check(...)
#define privileged_kill_child
#define privileged_waitpid
#define privileged_fts_open(a, b, c, d)
#define privileged_fork_execvp
#define privileged_fts_close(a, b)
ruleaction_t rules_getperm(const char *fpath, mode_t st_mode, rule_t *rules_p, ruleaction_t ruleactions)
ruleaction_t rules_search_getperm(const char *fpath, mode_t st_mode, rule_t *rules_p, const ruleaction_t ruleaction, rule_t **rule_pp)
Checks file path by rules' expressions (parsed from file)
eventobjtype_t objtype_new
eventobjtype_t objtype_old
pid_t child_pid[MAXCHILDREN]
pthread_t blockthread[(1<< 4)]
shflags_t synchandler_argf
api_functs_t handler_funct
queueinfo_t _queues[QUEUE_MAX]
struct notifyenginefuncts notifyenginefunct
unsigned int rsyncinclimit
char * customsignal[MAXSIGNALNUM+1]
synchandler_args_t synchandler_args[SHARGS_MAX]
char isignoredexitcode[(1<< 8)]
char excf_path[PATH_MAX+1]
const char * list_type_str
char outf_path[PATH_MAX+1]
size_t include_list_count
const char * include_list[(1<< 8)+2]
eventobjtype_t objtype_new
eventobjtype_t objtype_old
GHashTable * fpath2ei_coll_ht[QUEUE_MAX]
GHashTable * exc_fpath_ht
GHashTable * out_lines_aggr_ht
GHashTable * nonthreaded_syncing_fpath2ei_ht
GHashTable * exc_fpath_coll_ht[QUEUE_MAX]
int(* add_watch_dir)(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath)
int(* handle)(struct ctx *ctx_p, struct indexes *indexes_p)
int(* wait)(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *tv_p)
unsigned int collectdelay
int dirfd[DUMP_DIRFD_MAX]
char isexpanded[MAXARGUMENTS]
thread_callbackfunct_arg_t * callback_arg
thread_callbackfunct_t callback
threadinfo_t ** threadsstack
pthread_mutex_t mutex[PTHREAD_MUTEX_MAX]
pthread_cond_t cond[PTHREAD_MUTEX_MAX]
char * sync_path_abs2rel(ctx_t *ctx_p, const char *path_abs, ssize_t path_abs_len, size_t *path_rel_len_p, char *path_rel_oldptr)
int sync_term(int exitcode)
static char ** sync_customargv(ctx_t *ctx_p, struct dosync_arg *dosync_arg_p, synchandler_args_t *args_p)
eventinfo_t * ht_fpath_isincluded(GHashTable *ht, const char *const fpath)
static void so_call_sync_finished(int n, api_eventinfo_t *ei)
pthread_t pthread_sighandler
static int so_call_rsync_finished(ctx_t *ctx_p, const char *inclistfile, const char *exclistfile)
void rsync_escape_cleanup()
static unsigned int sync_seqid()
static void argv_free(char **argv)
static int sync_indexes_fpath2ei_addfixed(ctx_t *ctx_p, indexes_t *indexes_p, const char *fpath, eventinfo_t *evinfo)
static int _exitcode_process(ctx_t *ctx_p, int exitcode)
int sync_idle(ctx_t *ctx_p, indexes_t *indexes_p)
static void setenv_iteration(uint32_t iteration_num)
const char * sync_parameter_get(const char *variable_name, void *_dosync_arg_p)
int sync_sighandler(sighandler_arg_t *sighandler_arg_p)
void sync_queuesync_wrapper(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp)
int exec_argv(char **argv, int *child_pid)
static int rsync_outline(FILE *outf, char *outline, eventinfo_flags_t flags)
int sync_idle_dosync_collectedevents(ctx_t *ctx_p, indexes_t *indexes_p)
static void api_evinfo_initialevmask(ctx_t *ctx_p, api_eventinfo_t *evinfo_p, int isdir)
void sync_sig_int(int signal)
int sync_prequeue_unload(ctx_t *ctx_p, indexes_t *indexes_p)
int sync_notify_mark(ctx_t *ctx_p, const char *accpath, const char *path, size_t pathlen, indexes_t *indexes_p)
static int sync_initialsync_finish(ctx_t *ctx_p, initsync_t initsync, int ret)
int sync_initialsync_walk(ctx_t *ctx_p, const char *dirpath, indexes_t *indexes_p, queue_id_t queue_id, initsync_t initsync)
char * rsync_escape_result
gboolean sync_trylocked(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp)
static int sync_queuesync(const char *fpath_rel, eventinfo_t *evinfo, ctx_t *ctx_p, indexes_t *indexes_p, queue_id_t queue_id)
size_t rsync_escape_result_size
int sync_dump_thread(threadinfo_t *threadinfo_p, void *_arg)
static int sync_dosync_exec(ctx_t *ctx_p, indexes_t *indexes_p, const char *evmask_str, const char *fpath)
static void argv_dump(int debug_level, char **argv)
void hook_preexit(ctx_t *ctx_p)
threadsinfo_t * thread_info()
#define SYNC_EXEC_ARGV(...)
int sync_exec_argv(ctx_t *ctx_p, indexes_t *indexes_p, thread_callbackfunct_t callback, thread_callbackfunct_arg_t *callback_arg_p, char **argv)
#define SYNC_LOOP_CONTINUE_UNLOCK
int sync_idle_dosync_collectedevents_cleanup(ctx_t *ctx_p, thread_callbackfunct_arg_t *arg_p)
int sync_mark_walk(ctx_t *ctx_p, const char *dirpath, indexes_t *indexes_p)
char * sync_path_rel2abs(ctx_t *ctx_p, const char *path_rel, ssize_t path_rel_len, size_t *path_abs_len_p, char *path_abs_oldptr)
int * sync_sighandler_exitcode_p
int apievinfo2rsynclist(indexes_t *indexes_p, FILE *listfile, int n, api_eventinfo_t *apievinfo)
Writes the list to list-file for "--include-from" option of rsync using array of api_eventinfo_t.
int sync_idle_dosync_collectedevents_commitpart(struct dosync_arg *dosync_arg_p)
static int sync_islocked(const char *const fpath)
static void evinfo_merge(ctx_t *ctx_p, eventinfo_t *evinfo_dst, eventinfo_t *evinfo_src)
int sync_dump(ctx_t *ctx_p, const char *const dir_path)
int fileischanged(ctx_t *ctx_p, indexes_t *indexes_p, const char *path_rel, stat64_t *lst_p, int is_deleted)
static void finish_iteration(ctx_t *ctx_p)
gpointer eidup(gpointer ei_gp)
static unsigned int _sync_seqid_value
static int so_call_rsync(ctx_t *ctx_p, indexes_t *indexes_p, const char *inclistfile, const char *exclistfile)
static int rsync_listpush(indexes_t *indexes_p, const char *fpath, size_t fpath_len, eventinfo_flags_t flags, unsigned int *linescount_p)
void sync_dump_liststep(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp)
int sync_switch_state(ctx_t *ctx_p, pthread_t pthread_parent, int newstate)
gboolean sync_idle_dosync_collectedevents_rsync_exclistpush(gpointer fpath_gp, gpointer flags_gp, gpointer arg_gp)
int sync_notify_init(ctx_t *ctx_p)
int sync_loop(ctx_t *ctx_p, indexes_t *indexes_p)
static int so_call_sync(ctx_t *ctx_p, indexes_t *indexes_p, int n, api_eventinfo_t *ei)
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)
void sync_inclist_rotate(ctx_t *ctx_p, struct dosync_arg *dosync_arg_p)
int sync_initialsync(const char *path, ctx_t *ctx_p, indexes_t *indexes_p, initsync_t initsync)
int _sync_islocked(threadinfo_t *threadinfo_p, void *_fpath)
pid_t clsyncapi_fork(ctx_t *ctx_p)
clsync's wrapper for function "fork()". Should be used instead of "fork()" directly,...
int sync_idle_dosync_collectedevents_aggrqueue(queue_id_t queue_id, ctx_t *ctx_p, indexes_t *indexes_p, struct dosync_arg *dosync_arg)
const char * rsync_escape(const char *path)
int sync_idle_dosync_collectedevents_uniqfname(ctx_t *ctx_p, char *fpath, char *name)
void _sync_idle_dosync_collectedevents(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp)
void _sync_idle_dosync_collectedexcludes(gpointer fpath_gp, gpointer flags_gp, gpointer arg_gp)
#define SHOULD_THREAD(ctx_p)
void sync_idle_dosync_collectedevents_listpush(gpointer fpath_gp, gpointer evinfo_gp, gpointer arg_gp)
gboolean rsync_aggrout(gpointer outline_gp, gpointer flags_gp, gpointer arg_gp)
#define debug_argv_dump(level, argv)
int notify_wait(ctx_t *ctx_p, indexes_t *indexes_p)
int sync_idle_dosync_collectedevents_listcreate(struct dosync_arg *dosync_arg_p, char *name)
__extension__ int sync_run(ctx_t *ctx_p)
volatile state_t * state_p
int sync_tryforcecycle(ctx_t *ctx_p, pthread_t pthread_parent)
static void evinfo_initialevmask(ctx_t *ctx_p, eventinfo_t *evinfo_p, int isdir)
int sync_dosync(const char *fpath, uint32_t evmask, ctx_t *ctx_p, indexes_t *indexes_p)
int exitcode_process(ctx_t *ctx_p, int exitcode)
int(* thread_callbackfunct_t)(ctx_t *ctx_p, thread_callbackfunct_arg_t *arg_p)
int threads_foreach(int(*funct)(threadinfo_t *, void *), state_t state, void *arg)
time_t thread_nextexpiretime()