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
118 #ifdef KQUEUE_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__)
219 static 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__)
228 static 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 );
339 int 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;
1540 l_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
1814 static 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;
1945 l_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;
2431 int *evcount_p = & ( (
struct dosync_arg * ) arg_gp )->evcount;
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;
2702 l_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 );
2755 gboolean
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() );
3555 int _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 // Hangs
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 );
3669 l_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 )
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." );
4241 #ifdef ENABLE_SOCKET
4251 debug ( 30,
"Running recursive notify marking function" );
4254 if ( ret )
return ret;
4260 if ( ret )
return ret;
4262 debug ( 1,
"sync_loop() ended" );
4263 #ifdef ENABLE_SOCKET
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" );