clsync
main.c
Go to the documentation of this file.
1 /*
2  clsync - file tree sync utility based on inotify/kqueue/bsm
3 
4  Copyright (C) 2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 #include "common.h"
22 
23 #ifdef CAPABILITIES_SUPPORT
24 # include <sys/capability.h> // for capset()/capget() for --preserve-file-access
25 #endif
26 #if defined(__linux__) | defined(CAPABILITIES_SUPPORT)
27 # include <sys/prctl.h> // for prctl() for --preserve-fil-access
28 #endif
29 
30 #include <pwd.h> // getpwnam()
31 #include <grp.h> // getgrnam()
32 #include <glib.h> // gkf
33 
34 
35 #ifdef UNSHARE_SUPPORT
36 # include <sched.h> // unshare()
37 #endif
38 #ifdef GETMNTENT_SUPPORT
39 # include <mntent.h> // getmntent()
40 # include <sys/mount.h> // umount2()
41 #endif
42 
43 #include "error.h"
44 #include "stringex.h"
45 #include "sync.h"
46 #include "malloc.h"
47 #include "cluster.h"
48 #include "fileutils.h"
49 #include "socket.h"
50 #include "syscalls.h"
51 #include "rules.h"
52 #if CGROUP_SUPPORT
53 # include "cgroup.h"
54 #endif
55 #include "posix-hacks.h"
56 
57 //#include "revision.h"
58 
59 static const struct option long_options[] = {
60  {"watch-dir", required_argument, NULL, WATCHDIR},
61  {"sync-handler", required_argument, NULL, SYNCHANDLER},
62  {"--", required_argument, NULL, SYNCHANDLERARGS0},
63  {"---", required_argument, NULL, SYNCHANDLERARGS1},
64  {"rules-file", required_argument, NULL, RULESFILE},
65  {"destination-dir", required_argument, NULL, DESTDIR},
66  {"mode", required_argument, NULL, MODE},
67  {"socket", required_argument, NULL, SOCKETPATH},
68  {"socket-auth", required_argument, NULL, SOCKETAUTH},
69  {"socket-mod", required_argument, NULL, SOCKETMOD},
70  {"socket-own", required_argument, NULL, SOCKETOWN},
71  {"status-file", required_argument, NULL, STATUSFILE},
72 
73  {"background", optional_argument, NULL, BACKGROUND},
74  {"config-file", required_argument, NULL, CONFIGFILE},
75  {"config-block", required_argument, NULL, CONFIGBLOCK},
76  {"config-block-inherits", required_argument, NULL, CONFIGBLOCKINHERITS},
77  {"custom-signals", required_argument, NULL, CUSTOMSIGNALS},
78  {"pid-file", required_argument, NULL, PIDFILE},
79  {"uid", required_argument, NULL, UID},
80  {"gid", required_argument, NULL, GID},
81  {"privileged-uid", required_argument, NULL, PRIVILEGEDUID},
82  {"privileged-gid", required_argument, NULL, PRIVILEGEDGID},
83  {"sync-handler-uid", required_argument, NULL, SYNCHANDLERUID},
84  {"sync-handler-gid", required_argument, NULL, SYNCHANDLERGID},
85  {"chroot", required_argument, NULL, CHROOT},
86 #ifdef PIVOTROOT_OPT_SUPPORT
87  {"pivot-root", required_argument, NULL, PIVOT_ROOT},
88 #endif
89 #ifdef UNSHARE_SUPPORT
90  {"detach-network", required_argument, NULL, DETACH_NETWORK},
91  {"detach-ipc", required_argument, NULL, DETACH_IPC},
92  {"detach-miscellanea", optional_argument, NULL, DETACH_MISCELLANEA},
93 #endif
94 #ifdef CAPABILITIES_SUPPORT
95 # ifdef SECCOMP_SUPPORT
96  {"secure-splitting", no_argument, NULL, SECURESPLITTING},
97 # endif
98  {"splitting", required_argument, NULL, SPLITTING},
99  {"check-execvp-arguments", optional_argument, NULL, CHECK_EXECVP_ARGS},
100  {"add-permitted-hook-files", required_argument, NULL, ADDPERMITTEDHOOKFILES},
101 # ifdef SECCOMP_SUPPORT
102  {"seccomp-filter", optional_argument, NULL, SECCOMP_FILTER},
103 # endif
104  {"forget-privthread-info", optional_argument, NULL, FORGET_PRIVTHREAD_INFO},
105  {"permit-mprotect", optional_argument, NULL, PERMIT_MPROTECT},
106  {"shm-mprotect", optional_argument, NULL, SHM_MPROTECT},
107 #endif
108 #ifdef UNSHARE_SUPPORT
109 # ifdef GETMNTENT_SUPPORT
110  {"mountpoints", required_argument, NULL, MOUNTPOINTS},
111 # endif
112 #endif
113 #ifdef CAPABILITIES_SUPPORT
114  {"preserve-capabilities", required_argument, NULL, CAP_PRESERVE},
115  {"inherit-capabilities", optional_argument, NULL, CAPS_INHERIT},
116 #endif
117 #ifdef CGROUP_SUPPORT
118  {"forbid-devices", optional_argument, NULL, FORBIDDEVICES},
119  {"cgroup-group-name", required_argument, NULL, CG_GROUPNAME},
120 #endif
121 #ifdef THREADING_SUPPORT
122  {"threading", required_argument, NULL, THREADING},
123 #endif
124  {"retries", required_argument, NULL, RETRIES},
125  {"ignore-failures", optional_argument, NULL, IGNOREFAILURES},
126  {"exit-on-sync-skipping", optional_argument, NULL, EXITONSYNCSKIP},
127  {"output", required_argument, NULL, OUTPUT_METHOD},
128  {"one-file-system", optional_argument, NULL, ONEFILESYSTEM},
129  {"exclude-mount-points", optional_argument, NULL, EXCLUDEMOUNTPOINTS},
130 #ifdef CLUSTER_SUPPORT
131  {"cluster-iface", required_argument, NULL, CLUSTERIFACE}, // Not implemented, yet
132  {"cluster-ip", required_argument, NULL, CLUSTERMCASTIPADDR}, // Not implemented, yet
133  {"cluster-port", required_argument, NULL, CLUSTERMCASTIPPORT}, // Not implemented, yet
134  {"cluster-timeout", required_argument, NULL, CLUSTERTIMEOUT}, // Not implemented, yet
135  {"cluster-node-name", required_argument, NULL, CLUSTERNODENAME}, // Not implemented, yet
136  {"cluster-hash-dl-min", required_argument, NULL, CLUSTERHDLMIN},
137  {"cluster-hash-dl-max", required_argument, NULL, CLUSTERHDLMAX},
138  {"cluster-scan-dl-max", required_argument, NULL, CLUSTERSDLMAX},
139 #endif
140  {"max-iterations", required_argument, NULL, MAXITERATIONS},
141  {"standby-file", required_argument, NULL, STANDBYFILE},
142  {"modification-signature", required_argument, NULL, MODSIGN},
143  {"timeout-sync", required_argument, NULL, SYNCTIMEOUT},
144  {"delay-sync", required_argument, NULL, SYNCDELAY},
145  {"delay-collect", required_argument, NULL, DELAY},
146  {"delay-collect-bigfile", required_argument, NULL, BFILEDELAY},
147  {"threshold-bigfile", required_argument, NULL, BFILETHRESHOLD},
148  {"cancel-syscalls", required_argument, NULL, CANCEL_SYSCALLS},
149  {"lists-dir", required_argument, NULL, OUTLISTSDIR},
150  {"have-recursive-sync", optional_argument, NULL, HAVERECURSIVESYNC},
151  {"synclist-simplify", optional_argument, NULL, SYNCLISTSIMPLIFY},
152 #ifdef AUTORULESW
153  {"auto-add-rules-w", optional_argument, NULL, AUTORULESW},
154 #endif
155  {"rsync-inclimit", required_argument, NULL, RSYNCINCLIMIT},
156  {"rsync-prefer-include", optional_argument, NULL, RSYNCPREFERINCLUDE},
157  {"ignore-exitcode", required_argument, NULL, IGNOREEXITCODE},
158  {"dont-unlink-lists", optional_argument, NULL, DONTUNLINK},
159  {"fts-experimental-optimization", optional_argument, NULL, FTS_EXPERIMENTAL_OPTIMIZATION},
160  {"full-initialsync", optional_argument, NULL, INITFULL},
161  {"only-initialsync", optional_argument, NULL, ONLYINITSYNC},
162  {"skip-initialsync", optional_argument, NULL, SKIPINITSYNC},
163  {"exit-on-no-events", optional_argument, NULL, EXITONNOEVENTS},
164  {"exit-hook", required_argument, NULL, EXITHOOK},
165  {"pre-exit-hook", required_argument, NULL, PREEXITHOOK},
166  {"sync-on-quit", optional_argument, NULL, SOFTEXITSYNC},
167  {"verbose", optional_argument, NULL, VERBOSE},
168  {"debug", optional_argument, NULL, DEBUG},
169  {"dump-dir", required_argument, NULL, DUMPDIR},
170  {"quiet", optional_argument, NULL, QUIET},
171  {"monitor", required_argument, NULL, MONITOR},
172  {"label", required_argument, NULL, LABEL},
173  {"help", optional_argument, NULL, HELP},
174  {"version", optional_argument, NULL, SHOW_VERSION},
175 
176  {NULL, 0, NULL, 0}
177 };
178 
179 #ifdef UNSHARE_SUPPORT
180 static char *const detachnetworkways[] = {
181  [DN_OFF] = "off",
182  [DN_NONPRIVILEGED] = "non-privileged",
183  [DN_EVERYWHERE] = "everywhere",
184  NULL,
185 };
186 #endif
187 
188 #ifdef PIVOTROOT_OPT_SUPPORT
189 static char *const pivotrootways[] = {
190  [PW_OFF] = "off",
191  [PW_DIRECT] = "direct",
192  [PW_AUTO] = "auto",
193  [PW_AUTORO] = "auto-ro",
194  NULL,
195 };
196 #endif
197 
214 };
215 
232 };
233 
234 static char *const stat_fields[] = {
235  [X_STAT_FIELD_RESET] = "",
236  [X_STAT_FIELD_DEV] = "dev",
237  [X_STAT_FIELD_INO] = "ino",
238  [X_STAT_FIELD_MODE] = "mode",
239  [X_STAT_FIELD_NLINK] = "nlink",
240  [X_STAT_FIELD_UID] = "uid",
241  [X_STAT_FIELD_GID] = "gid",
242  [X_STAT_FIELD_RDEV] = "rdev",
243  [X_STAT_FIELD_SIZE] = "size",
244  [X_STAT_FIELD_BLKSIZE] = "blksize",
245  [X_STAT_FIELD_BLOCKS] = "blocks",
246  [X_STAT_FIELD_ATIME] = "atime",
247  [X_STAT_FIELD_MTIME] = "mtime",
248  [X_STAT_FIELD_CTIME] = "ctime",
249  [X_STAT_FIELD_ALL] = "*",
250  NULL
251 };
252 
253 enum x_csc_bm {
256 };
257 
258 uint32_t xcsc_to_csc[] = {
261 };
262 
263 static char *const syscalls_bitmask[] = {
264  [X_CSC_RESET] = "",
265  [X_CSC_MON_STAT] = "mon_stat", // disable {l,}stat{,64}()-s in mon_*.c
266  NULL
267 };
268 
269 #ifdef CAPABILITIES_SUPPORT
270 
271 enum x_capabilities {
272  X_CAP_RESET = 0,
273  X_CAP_DAC_READ_SEARCH,
274  X_CAP_SETUID,
275  X_CAP_SETGID,
276  X_CAP_KILL,
277 
278  X_CAP_MAX
279 };
280 __u32 xcap_to_cap[] = {
281  [X_CAP_DAC_READ_SEARCH] = CAP_DAC_READ_SEARCH,
282  [X_CAP_SETUID] = CAP_SETUID,
283  [X_CAP_SETGID] = CAP_SETGID,
284  [X_CAP_KILL] = CAP_KILL,
285 };
286 static char *const capabilities[] = {
287  [X_CAP_RESET] = "",
288  [X_CAP_DAC_READ_SEARCH] = "CAP_DAC_READ_SEARCH",
289  [X_CAP_SETUID] = "CAP_SETUID",
290  [X_CAP_SETGID] = "CAP_SETGID",
291  [X_CAP_KILL] = "CAP_KILL",
292  NULL
293 };
294 #define XCAP_TO_CAP(x) (xcap_to_cap[x])
295 
296 static char *const capsinherits[] = {
297  [CI_PERMITTED] = "permittied",
298  [CI_DONTTOUCH] = "dont-touch",
299  [CI_CLSYNC] = "clsync",
300  [CI_EMPTY] = "empty",
301 };
302 
303 #endif
304 
305 static char *const socketauth[] = {
306  [SOCKAUTH_UNSET] = "",
307  [SOCKAUTH_NULL] = "null",
308 // [SOCKAUTH_PAM] = "pam",
309  NULL
310 };
311 
312 #ifdef THREADING_SUPPORT
313 static char *const threading_modes[] = {
314  [PM_OFF] = "off",
315  [PM_SAFE] = "safe",
316  [PM_FULL] = "full",
317  NULL
318 };
319 #endif
320 
321 #ifdef CAPABILITIES_SUPPORT
322 static char *const splitting_modes[] = {
323  [SM_OFF] = "off",
324  [SM_THREAD] = "thread",
325  [SM_PROCESS] = "process",
326  NULL
327 };
328 #endif
329 
330 static char *const notify_engines[] = {
331  [NE_UNDEFINED] = "",
332  [NE_INOTIFY] = "inotify",
333  [NE_KQUEUE] = "kqueue",
334  [NE_FANOTIFY] = "fanotify",
335  [NE_BSM] = "bsm",
336  [NE_BSM_PREFETCH] = "bsm_prefetch",
337  [NE_DTRACEPIPE] = "dtracepipe",
338  [NE_GIO] = "gio",
339  NULL
340 };
341 
342 static char *const output_methods[] = {
343  [OM_STDERR] = "stderr",
344  [OM_STDOUT] = "stdout",
345  [OM_SYSLOG] = "syslog",
346  NULL
347 };
348 
349 static char *const modes[] = {
350  [MODE_UNSET] = "",
351  [MODE_SIMPLE] = "simple",
352  [MODE_DIRECT] = "direct",
353  [MODE_SHELL] = "shell",
354  [MODE_RSYNCSHELL] = "rsyncshell",
355  [MODE_RSYNCDIRECT] = "rsyncdirect",
356  [MODE_RSYNCSO] = "rsyncso",
357  [MODE_SO] = "so",
358  NULL
359 };
360 
361 int syntax()
362 {
363  info ( "possible options:" );
364  int i = -1;
365 
366  while ( long_options[++i].name != NULL ) {
367  switch ( long_options[i].val ) {
368  case SYNCHANDLERARGS0:
369  case SYNCHANDLERARGS1:
370  continue;
371  }
372 
373  if ( long_options[i].val & OPTION_CONFIGONLY )
374  continue;
375 
376  info ( "\t--%-24s%c%c%s", long_options[i].name,
377  long_options[i].val & OPTION_LONGOPTONLY ? ' ' : '-',
378  long_options[i].val & OPTION_LONGOPTONLY ? ' ' : long_options[i].val,
379  ( long_options[i].has_arg == required_argument ? " argument" : "" ) );
380  }
381 
382  exit ( EINVAL );
383 }
384 
385 int ncpus;
386 pid_t parent_pid = 0;
387 
388 pid_t waitpid_timed ( pid_t child_pid, int *status_p, long sec, long nsec )
389 {
390  struct timespec ts;
391  int status;
392  ts.tv_sec = sec;
393  ts.tv_nsec = nsec;
394 
395  while ( ts.tv_sec >= 0 ) {
396  if ( waitpid ( child_pid, &status, WNOHANG ) < 0 ) {
397  if ( errno == ECHILD )
398  return child_pid;
399 
400  return -1;
401  } else if ( status_p != NULL )
402  *status_p = status;
403 
404  ts.tv_nsec -= WAITPID_TIMED_GRANULARITY;
405 
406  if ( ts.tv_nsec < 0 ) {
407  ts.tv_nsec += 1000 * 1000 * 1000;
408  ts.tv_sec--;
409  }
410  }
411 
412  return 0;
413 }
414 
416 {
417  int rc;
418  debug ( 12, "parent_pid == %u", parent_pid );
419 
420  if ( ( rc = kill ( parent_pid, 0 ) ) ) {
421  if ( errno == ESRCH ) {
422  debug ( 1, "kill(%u, 0) => %i; errno => %s", parent_pid, rc, strerror ( errno ) );
423  return 0;
424  }
425  }
426 
427  return 1;
428 }
429 
431 {
432  if ( getppid() != 1 )
433  return;
434 
435  debug ( 1, "Got SIGCHLD (parent ended). Exit." );
436  exit ( -1 );
437  return;
438 }
439 
440 int sethandler_sigchld ( void ( *handler ) () )
441 {
442  struct sigaction sa;
443  sa.sa_handler = handler;
444  sigemptyset ( &sa.sa_mask );
445  sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
446  critical_on ( sigaction ( SIGCHLD, &sa, 0 ) == -1 );
447  return 0;
448 }
449 
450 # ifndef __linux__
451 void *watchforparent ( void *parent_pid_p )
452 {
453  while ( 1 ) {
454  child_sigchld();
455  sleep ( SLEEP_SECONDS );
456  }
457 
458  return NULL;
459 }
460 # endif
461 
463 pid_t fork_helper()
464 {
465  pid_t pid = fork();
466 
467  if ( !pid ) { // is child?
468  parent_pid = getppid();
469  // Anti-zombie:
470 # ifdef __linux__
471  // Linux have support of "prctl(PR_SET_PDEATHSIG, signal);"
473  prctl ( PR_SET_PDEATHSIG, SIGCHLD );
474 # else
475  pthread_create ( &pthread_watchforparent, NULL, watchforparent, &parent_pid );
476 # endif
477  debug ( 20, "parent_pid == %u", parent_pid );
478  return 0;
479  }
480 
481  return pid;
482 }
483 
484 int version()
485 {
486  char flags[] =
487 #ifdef _DEBUG_SUPPORT
488  " -D_DEBUG_SUPPORT"
489 #endif
490 #ifdef _DEBUG_FORCE
491  " -D_DEBUG_FORCE"
492 #endif
493 #ifdef KQUEUE_SUPPORT
494  " -DKQUEUE_SUPPORT"
495 #endif
496 #ifdef INOTIFY_SUPPORT
497  " -DINOTIFY_SUPPORT"
498 #endif
499 #ifdef INOTIFY_OLD
500  " -DINOTIFY_OLD"
501 #endif
502 #ifdef FANOTIFY_SUPPORT
503  " -DFANOTIFY_SUPPORT"
504 #endif
505 #ifdef BSM_SUPPORT
506  " -DBSM_SUPPORT"
507 #endif
508 #ifdef GIO_SUPPORT
509  " -DGIO_SUPPORT"
510 #endif
511 #ifdef DTRACEPIPE_SUPPORT
512  " -DDTRACEPIPE_SUPPORT"
513 #endif
514 #ifdef BACKTRACE_SUPPORT
515  " -DBACKTRACE_SUPPORT"
516 #endif
517 #ifdef CAPABILITIES_SUPPORT
518  " -DCAPABILITIES_SUPPORT"
519 #endif
520 #ifdef SECCOMP_SUPPORT
521  " -DSECCOMP_SUPPORT"
522 #endif
523 #ifdef GETMNTENT_SUPPORT
524  " -DGETMNTENT_SUPPORT"
525 #endif
526 #ifdef UNSHARE_SUPPORT
527  " -DUNSHARE_SUPPORT"
528 #endif
529 #ifdef PIVOTROOT_OPT_SUPPORT
530  " -DPIVOTROOT_OPT_SUPPORT"
531 #endif
532 #ifdef CGROUP_SUPPORT
533  " -DCGROUP_SUPPORT"
534 #endif
535 #ifdef TRE_SUPPORT
536  " -DTRE_SUPPORT"
537 #endif
538 #ifdef THREADING_SUPPORT
539  " -DTHREADING_SUPPORT"
540 #endif
541 #ifdef HL_LOCKS
542  " -DHL_LOCKS"
543 #endif
544  ;
545  info ( PROGRAM" v%i.%i.%i"REVISION"\n\t"AUTHOR"\n\t"URL"\n\nCompiled with options: %s"
546  , VERSION_MAJ, VERSION_MID, VERSION_MIN, flags );
547  exit ( 0 );
548 }
549 
551 {
552  return CLSYNC_API_VERSION;
553 }
554 
555 /**
556  * @brief Gets raw (string) an option value by an option name
557  *
558  * @param[in] _ctx_p Context
559  * @param[in] variable_name The name of the option
560  *
561  * @retval char * Pointer to constant string, if successful
562  * @retval NULL On error
563  *
564  */
565 const char *parameter_get ( const char *variable_name, void *_ctx_p )
566 {
567  const ctx_t *ctx_p = _ctx_p;
568  const struct option *long_option_p = long_options;
569  int param_id = -1;
570  debug ( 8, "(\"%s\", %p)", variable_name, ctx_p );
571 
572  while ( long_option_p->name != NULL ) {
573  if ( !strcmp ( long_option_p->name, variable_name ) ) {
574  param_id = long_option_p->val;
575  break;
576  }
577 
578  long_option_p++;
579  }
580 
581  if ( param_id == -1 ) {
582  errno = ENOENT;
583  return NULL;
584  }
585 
586  debug ( 9, "ctx_p->flags_values_raw[%i] == \"%s\"", param_id, ctx_p->flags_values_raw[param_id] );
587  return ctx_p->flags_values_raw[param_id];
588 }
589 
590 /**
591  * @brief Gets the name of the parameter by it's id
592  *
593  * @param[in] param_id The id of the parameter
594  *
595  * @retval char * Pointer to a constant string, if successful
596  * @retval NULL On error
597  *
598  */
599 const char *parameter_get_name_by_id ( const uint16_t param_id )
600 {
601  const struct option *long_option_p = long_options;
602  const char *param_name = NULL;
603  debug ( 8, "(%u)", param_id );
604 
605  while ( long_option_p->name != NULL ) {
606  if ( long_option_p->val == param_id ) {
607  param_name = long_option_p->name;
608  break;
609  }
610 
611  long_option_p++;
612  }
613 
614  if ( param_name == NULL ) {
615  errno = ENOENT;
616  return NULL;
617  }
618 
619  debug ( 9, "param: %u -> \"%s\"", param_id, param_name );
620  return param_name;
621 }
622 
623 /**
624  * @brief Gets raw (string) an option value by an option name and
625  * updates ctx_p->synchandler_argf
626  *
627  * @param[in] _ctx_p Context
628  * @param[in] variable_name The name of the option
629  *
630  * @retval char * Pointer to newly allocated string, if successful
631  * @retval NULL On error
632  *
633  */
634 const char *parameter_get_wmacro ( const char *variable_name, void *_ctx_p )
635 {
636  ctx_t *ctx_p = _ctx_p;
637  static struct dosync_arg dosync_arg = {0};
638  debug ( 9, "(\"%s\", %p)", variable_name, _ctx_p );
639 
640  if ( *variable_name < 'A' || *variable_name > 'Z' )
641  return parameter_get ( variable_name, _ctx_p );
642 
643  if ( !strcmp ( variable_name, "RSYNC-ARGS" ) ) {
645  return NULL;
646  }
647 
648  if ( !strcmp ( variable_name, "INCLUDE-LIST" ) ) {
650  return NULL;
651  }
652 
653  const char *r = sync_parameter_get ( variable_name, &dosync_arg );
654 
655  if ( r == dosync_arg.outf_path ) {
657  return NULL;
658  }
659 
660  if ( r == dosync_arg.excf_path ) {
662  return NULL;
663  }
664 
665  errno = ENOENT;
666  return NULL;
667 }
668 
669 /* Parameter exception flags */
670 #define PEF_NONE 0
671 #define PEF_UNEXPECTED_END 1
672 #define PEF_UNSET_VARIABLE 2
673 #define PEF_LAZY_SUBSTITUTION 4
674 /**
675  * @brief Expands option values, e. g. "/var/log/clsync-%label%.pid" -> "/var/log/clsync-clone.pid"
676  *
677  * @param[in] ctx_p Context
678  * @param[in] arg An allocated string with unexpanded value. Will be free'd
679  * @param[in] exceptionflags A bit field of allowed exceptions during parameter expansion:
680  * - PEF_NONE No exceptions are allowed
681  * - PEF_UNEXPECTED_END Do not warn about unexpected end of macro-substitution
682  * - PEF_UNSET_VARIABLE Do not warn about unset variable
683  * - PEF_LAZY_SUBSTITUTION Perform lazy substitution preserving original value
684  * @param[out] macro_count_p A pointer to count of found macro-s
685  * @param[out] expand_count_p A pointer to count of expanded macro-s
686  * @param[in] parameter_get A function to resolve macro-s
687  * @param[in] parameter_get_arg An argument to the function
688  *
689  * @retval char * Pointer to newly allocated string, if successful
690  * @retval NULL On error
691  *
692  */
694  ctx_t *ctx_p,
695  char *arg,
696  int exceptionflags,
697  int *macro_count_p,
698  int *expand_count_p,
699  const char * ( *parameter_get ) ( const char *variable_name, void *arg ),
700  void *parameter_get_arg
701 )
702 {
703  debug ( 9, "(ctx_p, \"%s\" [%p], ...)", arg, arg );
704  char *ret = NULL;
705  size_t ret_size = 0, ret_len = 0;
706 #ifdef PARANOID
707 
708  if ( arg == NULL ) {
709  errno = EINVAL;
710  return NULL;
711  }
712 
713 #endif
714 
715  if ( macro_count_p != NULL )
716  *macro_count_p = 0;
717 
718  if ( expand_count_p != NULL )
719  *expand_count_p = 0;
720 
721  char *ptr = &arg[-1];
722 
723  while ( 1 ) {
724  ptr++;
725 
726  switch ( *ptr ) {
727  case 0:
728  if ( ret == NULL ) {
729  debug ( 3, "Expanding value \"%s\" to \"%s\" (case #1)", arg, arg );
730  return arg;
731  }
732 
733  ret[ret_len] = 0;
734  debug ( 3, "Expanding value \"%s\" to \"%s\" (case #0)", arg, ret );
735  free ( arg );
736  return ret;
737 
738  case '%': {
739  if ( ptr[1] == '%' ) {
740  ret[ret_len++] = * ( ptr++ );
741  break;
742  }
743 
744  debug ( 25, "A macro" );
745  char nest_searching = 1;
746  char *ptr_nest = ptr;
747 
748  while ( nest_searching ) {
749  ptr_nest++;
750 
751  switch ( *ptr_nest ) {
752  case 0:
753  ret[ret_len] = 0;
754 
755  if ( ! ( exceptionflags & PEF_UNEXPECTED_END ) )
756  warning ( "Unexpected end of macro-substitution \"%s\" in value \"%s\"; result value is \"%s\"", ptr, arg, ret );
757 
758  free ( arg );
759  return ret;
760 
761  case '%': {
762  char *variable_name;
763  const char *variable_value;
764  size_t variable_value_len;
765 
766  if ( macro_count_p != NULL )
767  ( *macro_count_p )++;
768 
769  nest_searching = 0;
770  *ptr_nest = 0;
771  variable_name = &ptr[1];
772  debug ( 15, "The macro is \"%s\"", variable_name );
773 
774  if ( !strcmp ( variable_name, "PID" ) ) {
775  debug ( 35, "\"PID\"", variable_name );
776 
777  if ( !*ctx_p->pid_str ) {
778  snprintf ( ctx_p->pid_str, 64, "%u", ctx_p->pid );
779  ctx_p->pid_str_len = strlen ( ctx_p->pid_str );
780  }
781 
782  variable_value = ctx_p->pid_str;
783  variable_value_len = ctx_p->pid_str_len;
784  } else if ( *variable_name >= 'A' && *variable_name <= 'Z' && ( exceptionflags & PEF_LAZY_SUBSTITUTION ) ) { // Lazy substitution, preserving the value
785  debug ( 35, "Lazy substitution", variable_name );
786  variable_value = ptr;
787  variable_value_len = ( ptr_nest - ptr + 1 );
788  parameter_get ( variable_name, parameter_get_arg );
789  } else { // Substituting
790  debug ( 35, "Substitution", variable_name );
791  errno = 0;
792  variable_value = parameter_get ( variable_name, parameter_get_arg );
793 
794  if ( variable_value == NULL ) {
795  if ( ! ( exceptionflags & PEF_UNSET_VARIABLE ) && ( errno != ENOENT ) )
796  warning ( "Variable \"%s\" is not set (%s)", variable_name, strerror ( errno ) );
797 
798  *ptr_nest = '%';
799  errno = 0;
800  break;
801  }
802 
803  variable_value_len = strlen ( variable_value );
804 
805  if ( expand_count_p != NULL )
806  ( *expand_count_p )++;
807  }
808 
809  *ptr_nest = '%';
810 
811  if ( ret_len + variable_value_len + 1 >= ret_size ) {
812  ret_size = ret_len + variable_value_len + 1 + ALLOC_PORTION;
813  ret = xrealloc ( ret, ret_size );
814  }
815 
816  memcpy ( &ret[ret_len], variable_value, variable_value_len );
817  ret_len += variable_value_len;
818  break;
819  }
820  }
821  }
822 
823  ptr = ptr_nest;
824  break;
825  }
826 
827  default: {
828  if ( ret_len + 2 >= ret_size ) {
829  ret_size += ALLOC_PORTION + 2;
830  ret = xrealloc ( ret, ret_size );
831  }
832 
833  ret[ret_len++] = *ptr;
834  break;
835  }
836  }
837  }
838 
839  error ( "Unknown internal error" );
840  return arg;
841 }
842 
843 /**
844  * @brief Gets the name of the parameter source by it's id
845  *
846  * @param[in] paramsource The id of the parameter source
847  *
848  * @retval char * Pointer to a constant string, if successful
849  * @retval NULL On error
850  *
851  */
852 const char *parametersource_get_name ( paramsource_t paramsource )
853 {
854  switch ( paramsource ) {
855  case PS_UNKNOWN:
856  return "unknown_case_0";
857 
858  case PS_ARGUMENT:
859  return "cli_arguments";
860 
861  case PS_CONFIG:
862  return "config";
863 
864  case PS_CONTROL:
865  return "control";
866 
867  case PS_DEFAULTS:
868  return "defaults";
869 
870  case PS_CORRECTION:
871  return "correction";
872  }
873 
874  return "unknown_case_1";
875 }
876 
877 static inline int synchandler_arg ( char *arg, size_t arg_len, void *_ctx_p, enum shargsid shargsid )
878 {
879  ctx_t *ctx_p = _ctx_p;
880  debug ( 9, "(\"%s\" [%p], %u, %p, %u)", arg, arg, arg_len, _ctx_p, shargsid );
881 
882  if ( !strcmp ( arg, "%RSYNC-ARGS%" ) ) {
883  char *args_e[] = RSYNC_ARGS_E, *args_i[] = RSYNC_ARGS_I, **args_p;
884  free ( arg );
885  args_p = ctx_p->flags[RSYNCPREFERINCLUDE] ? args_i : args_e;
886 
887  while ( *args_p != NULL ) {
888 #ifdef VERYPARANOID
889 
890  if ( !strcmp ( *args_p, "%RSYNC-ARGS%" ) ) {
891  errno = EINVAL;
892  critical ( "Infinite recursion detected" );
893  }
894 
895 #endif
896 
897  if ( synchandler_arg ( strdup ( *args_p ), strlen ( *args_p ), ctx_p, shargsid ) )
898  return errno;
899 
900  args_p++;
901  }
902 
903  return 0;
904  }
905 
906  if ( ctx_p->synchandler_args[shargsid].c >= MAXARGUMENTS - 2 ) {
907  errno = E2BIG;
908  error ( "There're too many sync-handler arguments "
909  "(%u > "XTOSTR ( MAXARGUMENTS - 2 ) "; arg == \"%s\").",
910  arg );
911  return errno;
912  }
913 
914 #ifdef _DEBUG_FORCE
915  debug ( 14, "ctx_p->synchandler_args[%u].v[%u] = %p", shargsid, ctx_p->synchandler_args[shargsid].c, arg );
916 #endif
918  return 0;
919 }
920 
921 static int synchandler_arg0 ( char *arg, size_t arg_len, void *_ctx_p )
922 {
923  return synchandler_arg ( arg, arg_len, _ctx_p, SHARGS_PRIMARY );
924 }
925 
926 static int synchandler_arg1 ( char *arg, size_t arg_len, void *_ctx_p )
927 {
928  return synchandler_arg ( arg, arg_len, _ctx_p, SHARGS_INITIAL );
929 }
930 
931 /* strtol wrapper with error checks */
932 static inline long xstrtol ( const char *str, int *err )
933 {
934  long res;
935  char *endptr;
936  errno = 0;
937  res = strtol ( str, &endptr, 0 );
938 
939  if ( errno || *endptr ) {
940  error ( "argument \"%s\" can't be parsed as a number", str );
941  *err = EINVAL;
942  }
943 
944  return res;
945 }
946 
947 // a wrapper for xstrtol with a trimming of leading and tailing whitespaces
948 static inline long xstrtol_trim ( char *str, int *err )
949 {
950  // Removing whitespace from the beginning
951  while ( *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n' ) str++;
952 
953  // Removing whitespaces from the ending
954  char *end = str;
955 
956  while ( *end != '\0' ) end++; // find the end of the string
957 
958  end--;
959 
960  while ( *end == ' ' || *end == '\t' || *end == '\r' || *end == '\n' ) end--; // find the end of the string excluding whitespaces
961 
962  end++;
963  *end = '\0';
964  // Calling xstrtol(), obviously :)
965  return xstrtol ( str, err );
966 }
967 
968 __extension__ static inline int parse_customsignals ( ctx_t *ctx_p, char *arg )
969 {
970  char *ptr = arg, *start = arg;
971  int ret = 0;
972  unsigned int signal;
973 
974  do {
975  switch ( *ptr ) {
976  case 0:
977  case ',':
978  case ':':
979  // TODO: use xstrtol() instead of atoi()
980  //signal = (unsigned int)xstrtol(start, &ret);
981  signal = ( unsigned int ) atoi ( start );
982 
983  if ( ret ) {
984  errno = ret;
985  return errno;
986  }
987 
988  if ( signal == 0 ) {
989  // flushing the setting
990  int i = 0;
991 
992  while ( i < 256 ) {
993  if ( ctx_p->customsignal[i] ) {
994  free ( ctx_p->customsignal[i] );
995  ctx_p->customsignal[i] = NULL;
996  }
997 
998  i++;
999  }
1000 
1001 #ifdef _DEBUG_FORCE
1002  fprintf ( stderr, "Force-Debug: parse_parameter(): Reset custom signals.\n" );
1003 #endif
1004  } else {
1005  if ( *ptr != ':' ) {
1006  char ch = *ptr;
1007  *ptr = 0;
1008  errno = EINVAL;
1009  error ( "Expected \":\" in \"%s\"", start );
1010  *ptr = ch;
1011  return errno;
1012  }
1013 
1014  {
1015  char ch, *end;
1016  ptr++;
1017  end = ptr;
1018 
1019  while ( *end && *end != ',' ) end++;
1020 
1021  if ( end == ptr ) {
1022  errno = EINVAL;
1023  error ( "Empty config block name on signal \"%u\"", signal );
1024  return errno;
1025  }
1026 
1027  if ( signal > MAXSIGNALNUM ) {
1028  errno = EINVAL;
1029  error ( "Too high value of the signal: \"%u\" > "XTOSTR ( MAXSIGNALNUM ) "", signal );
1030  return errno;
1031  }
1032 
1033  ch = *end;
1034  *end = 0;
1035  ctx_p->customsignal[signal] = strdup ( ptr );
1036  *end = ch;
1037 #ifdef _DEBUG_FORCE
1038  fprintf ( stderr, "Force-Debug: parse_parameter(): Adding custom signal %u.\n", signal );
1039 #endif
1040  ptr = end;
1041  }
1042  }
1043 
1044  start = ptr + 1;
1045  break;
1046 
1047  case '0' ... '9':
1048  break;
1049 
1050  default:
1051  errno = EINVAL;
1052  error ( "Expected a digit, comma (or colon) but got \"%c\"", *ptr );
1053  return errno;
1054  }
1055  } while ( * ( ptr++ ) );
1056 
1057  return 0;
1058 }
1059 
1060 __extension__ static int parse_parameter ( ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t paramsource )
1061 {
1062  int ret = 0;
1063 #ifdef _DEBUG_FORCE
1064  fprintf ( stderr, "Force-Debug: parse_parameter(): %i: %i = \"%s\"\n", paramsource, param_id, arg );
1065 #endif
1066 
1067  switch ( paramsource ) {
1068  case PS_CONTROL:
1069  case PS_ARGUMENT:
1070  if ( param_id & OPTION_CONFIGONLY ) {
1071  syntax();
1072  return 0;
1073  }
1074 
1075  ctx_p->flags_set[param_id] = 1;
1076  break;
1077 
1078  case PS_CONFIG:
1079  if ( ctx_p->flags_set[param_id] )
1080  return 0;
1081 
1082  ctx_p->flags_set[param_id] = 1;
1083  break;
1084 
1085  case PS_DEFAULTS:
1086 #ifdef VERYPARANOID
1087  if ( ctx_p->flags_set[param_id] ) {
1088  error ( "Parameter #%i is already set. No need in setting the default value.", param_id );
1089  return 0;
1090  }
1091 
1092 #endif
1093  break;
1094 
1095  /* case PS_REHASH:
1096  arg = ctx_p->flags_values_raw[param_id];
1097  #ifdef VERYPARANOID
1098  critical_on (arg == NULL);
1099  #endif
1100 
1101  debug(9, "Rehash setting %i -> \"%s\"", param_id, arg);
1102  break;*/
1103  case PS_CORRECTION:
1104  critical_on ( arg == NULL );
1105  debug ( 9, "Correcting setting %i -> \"%s\"", param_id, arg );
1106  break;
1107 
1108  default:
1109  error ( "Unknown parameter #%i source (value \"%s\").", param_id, arg != NULL ? arg : "" );
1110  break;
1111  }
1112 
1113  if ( ( arg != NULL ) /*&& (paramsource != PS_REHASH)*/ ) {
1114  if ( param_id != SYNCHANDLERARGS0 && param_id != SYNCHANDLERARGS1 )
1115  arg = parameter_expand ( ctx_p, arg, PEF_NONE, NULL, NULL, parameter_get, ctx_p );
1116 
1117  if ( ctx_p->flags_values_raw[param_id] != NULL )
1118  free ( ctx_p->flags_values_raw[param_id] );
1119 
1120  ctx_p->flags_values_raw[param_id] = arg;
1121  }
1122 
1123  switch ( param_id ) {
1124  case '?':
1125  case HELP:
1126  syntax();
1127  break;
1128 
1129  case CONFIGFILE:
1130  ctx_p->config_path = *arg ? arg : NULL;
1131  break;
1132 
1133  case CONFIGBLOCK:
1134  ctx_p->config_block = *arg ? arg : NULL;
1135  break;
1136 
1137  case CONFIGBLOCKINHERITS:
1138  break;
1139 
1140  case CUSTOMSIGNALS:
1141  if ( paramsource == PS_CONTROL ) {
1142  warning ( "Cannot change \"custom-signal\" in run-time. Ignoring." );
1143  return 0;
1144  }
1145 
1146  if ( parse_customsignals ( ctx_p, arg ) )
1147  return errno;
1148 
1149  break;
1150 
1151  case UID: {
1152  struct passwd *pwd = getpwnam ( arg );
1153  ctx_p->flags[param_id]++;
1154 
1155  if ( pwd == NULL ) {
1156  ctx_p->uid = ( unsigned int ) xstrtol_trim ( arg, &ret );
1157  break;
1158  }
1159 
1160  ctx_p->uid = pwd->pw_uid;
1161  break;
1162  }
1163 
1164  case GID: {
1165  struct group *grp = getgrnam ( arg );
1166  ctx_p->flags[param_id]++;
1167 
1168  if ( grp == NULL ) {
1169  ctx_p->gid = ( unsigned int ) xstrtol_trim ( arg, &ret );
1170  break;
1171  }
1172 
1173  ctx_p->gid = grp->gr_gid;
1174  break;
1175  }
1176 
1177 #ifdef CAPABILITIES_SUPPORT
1178 # ifdef SECCOMP_SUPPORT
1179 
1180  case SECURESPLITTING: {
1181  if ( ctx_p->flags_values_raw[CHECK_EXECVP_ARGS] == NULL )
1183 
1184  if ( ctx_p->flags_values_raw[SECCOMP_FILTER] == NULL )
1186 
1187  if ( ctx_p->flags_values_raw[FORBIDDEVICES] == NULL )
1189 
1190  if ( ctx_p->flags_values_raw[SPLITTING] != NULL )
1191  break;
1192 
1193  arg = "process";
1194  }
1195 
1196  case SPLITTING: {
1197  char *value, *arg_orig = arg;
1198 
1199  if ( !*arg ) {
1200  ctx_p->flags[param_id] = 0;
1201  return 0;
1202  }
1203 
1204  splittingmode_t splittingmode = getsubopt ( &arg, splitting_modes, &value );
1205 
1206  if ( ( int ) splittingmode == -1 ) {
1207  errno = EINVAL;
1208  error ( "Invalid splitting mode entered: \"%s\"", arg_orig );
1209  return EINVAL;
1210  }
1211 
1212  ctx_p->flags[SPLITTING] = splittingmode;
1213 
1214  if ( param_id != SECURESPLITTING )
1215  break;
1216 
1217  switch ( splittingmode ) {
1218  case SM_THREAD:
1220  break;
1221 
1222  case SM_PROCESS:
1223  break;
1224 
1225  case SM_OFF:
1226  errno = EINVAL;
1227  error ( "Cannot understand \"--secure-splitting=off\". This configuration line have no sence." );
1228  break;
1229  }
1230 
1231  if ( ctx_p->flags_values_raw[PERMIT_MPROTECT] == NULL )
1232  ctx_p->flags[PERMIT_MPROTECT] = ( splittingmode != SM_THREAD );
1233 
1234  break;
1235  }
1236 
1237 # endif
1238 
1239  case CAP_PRESERVE: {
1240  char *subopts = arg;
1241  ctx_p->caps = 0;
1242 
1243  while ( *subopts != 0 ) {
1244  char *value;
1245  __u32 cap = getsubopt ( &subopts, capabilities, &value );
1246  debug ( 4, "cap == 0x%x", cap );
1247 
1248  if ( cap != X_CAP_RESET )
1249  ctx_p->caps |= CAP_TO_MASK ( XCAP_TO_CAP ( cap ) );
1250  }
1251 
1252  break;
1253  }
1254 
1255  case CAPS_INHERIT: {
1256  char *value, *arg_orig = arg;
1257 
1258  if ( !*arg ) {
1259  ctx_p->flags[param_id] = 0;
1260  return 0;
1261  }
1262 
1263  capsinherit_t capsinherit = getsubopt ( &arg, capsinherits, &value );
1264 
1265  if ( ( int ) capsinherit == -1 ) {
1266  errno = EINVAL;
1267  error ( "Invalid capabilities inheriting mode entered: \"%s\"", arg_orig );
1268  return EINVAL;
1269  }
1270 
1272  break;
1273  }
1274 
1275 #endif
1276 
1277  case PRIVILEGEDUID: {
1278  struct passwd *pwd = getpwnam ( arg );
1279  ctx_p->flags[param_id]++;
1280 
1281  if ( pwd == NULL ) {
1282  ctx_p->privileged_uid = ( unsigned int ) xstrtol_trim ( arg, &ret );
1283  debug ( 5, "ctx_p->privileged_uid == %d (case 0)", ctx_p->privileged_uid );
1284  break;
1285  }
1286 
1287  debug ( 5, "ctx_p->privileged_uid == %d (case 1)", ctx_p->privileged_uid );
1288  ctx_p->privileged_uid = pwd->pw_uid;
1289  break;
1290  }
1291 
1292  case PRIVILEGEDGID: {
1293  struct group *grp = getgrnam ( arg );
1294  ctx_p->flags[param_id]++;
1295 
1296  if ( grp == NULL ) {
1297  ctx_p->privileged_gid = ( unsigned int ) xstrtol_trim ( arg, &ret );
1298  debug ( 5, "ctx_p->privileged_gid == %d (case 0)", ctx_p->privileged_gid );
1299  break;
1300  }
1301 
1302  debug ( 5, "ctx_p->privileged_gid == %d (case 1)", ctx_p->privileged_gid );
1303  ctx_p->privileged_gid = grp->gr_gid;
1304  break;
1305  }
1306 
1307  case SYNCHANDLERUID: {
1308  struct passwd *pwd = getpwnam ( arg );
1309  ctx_p->flags[param_id]++;
1310 
1311  if ( pwd == NULL ) {
1312  ctx_p->synchandler_uid = ( unsigned int ) xstrtol_trim ( arg, &ret );
1313  debug ( 5, "ctx_p->synchandler_uid == %d (case 0)", ctx_p->synchandler_uid );
1314  break;
1315  }
1316 
1317  debug ( 5, "ctx_p->synchandler_uid == %d (case 1)", ctx_p->synchandler_uid );
1318  ctx_p->synchandler_uid = pwd->pw_uid;
1319  break;
1320  }
1321 
1322  case SYNCHANDLERGID: {
1323  struct group *grp = getgrnam ( arg );
1324  ctx_p->flags[param_id]++;
1325 
1326  if ( grp == NULL ) {
1327  ctx_p->synchandler_gid = ( unsigned int ) xstrtol_trim ( arg, &ret );
1328  debug ( 5, "ctx_p->synchandler_gid == %d (case 0)", ctx_p->synchandler_gid );
1329  break;
1330  }
1331 
1332  debug ( 5, "ctx_p->synchandler_gid == %d (case 1)", ctx_p->synchandler_gid );
1333  ctx_p->synchandler_gid = grp->gr_gid;
1334  break;
1335  }
1336 
1337  case CHROOT:
1338  if ( paramsource == PS_CONTROL ) {
1339  warning ( "Cannot change \"chroot\" in run-time. Ignoring." );
1340  return 0;
1341  }
1342 
1343  if ( !*arg ) {
1344  free ( ctx_p->chroot_dir );
1345  ctx_p->chroot_dir = NULL;
1346  return 0;
1347  }
1348 
1349  ctx_p->chroot_dir = arg;
1350  break;
1351 #ifdef PIVOTROOT_OPT_SUPPORT
1352 
1353  case PIVOT_ROOT: {
1354  char *value, *arg_orig = arg;
1355 
1356  if ( !*arg ) {
1358  return 0;
1359  }
1360 
1361  pivotroot_way_t pivotway = getsubopt ( &arg, pivotrootways, &value );
1362 
1363  if ( ( int ) pivotway == -1 ) {
1364  errno = EINVAL;
1365  error ( "Invalid pivot_root use way entered: \"%s\"", arg_orig );
1366  return EINVAL;
1367  }
1368 
1369  ctx_p->flags[PIVOT_ROOT] = pivotway;
1370  break;
1371  }
1372 
1373 #endif
1374 #ifdef UNSHARE_SUPPORT
1375 
1376  case DETACH_NETWORK: {
1377  char *value, *arg_orig = arg;
1378 
1379  if ( !*arg ) {
1380  ctx_p->flags[param_id] = 0;
1381  return 0;
1382  }
1383 
1384  detachnetwork_way_t detachnetwork_way = getsubopt ( &arg, detachnetworkways, &value );
1385 
1386  if ( ( int ) detachnetwork_way == -1 ) {
1387  errno = EINVAL;
1388  error ( "Invalid network detach way entered: \"%s\"", arg_orig );
1389  return EINVAL;
1390  }
1391 
1393  break;
1394  }
1395 
1396 #endif
1397 #ifdef CAPABILITIES_SUPPORT
1398 
1399  case ADDPERMITTEDHOOKFILES: {
1400  char *ptr;
1401 
1402  if ( paramsource == PS_CONTROL ) {
1403  warning ( "Cannot change \"add-permitted-hook-files\" in run-time. Ignoring." );
1404  return 0;
1405  }
1406 
1407  while ( ctx_p->permitted_hookfiles )
1408  free ( ctx_p->permitted_hookfile[--ctx_p->permitted_hookfiles] );
1409 
1410  ptr = arg;
1411 
1412  while ( 1 ) {
1413  char *end = strchr ( ptr, ',' );
1414 
1415  if ( end != NULL )
1416  *end = 0;
1417 
1418  if ( !*ptr ) {
1419  while ( ctx_p->permitted_hookfiles )
1420  free ( ctx_p->permitted_hookfile[--ctx_p->permitted_hookfiles] );
1421 
1422  if ( end != NULL )
1423  ptr = &end[1];
1424 
1425  continue;
1426  }
1427 
1428  if ( ctx_p->permitted_hookfiles >= MAXPERMITTEDHOOKFILES ) {
1429  errno = EINVAL;
1430  error ( "Too many permitted hook files" );
1431  return errno;
1432  }
1433 
1434  ctx_p->permitted_hookfile[ctx_p->permitted_hookfiles++] = strdup ( ptr );
1435 
1436  if ( end == NULL )
1437  break;
1438 
1439  *end = ',';
1440  ptr = &end[1];
1441  }
1442 
1443  break;
1444  }
1445 
1446 #endif
1447 #ifdef UNSHARE_SUPPORT
1448 # ifdef GETMNTENT_SUPPORT
1449 
1450  case MOUNTPOINTS: {
1451  char *ptr;
1452 
1453  if ( paramsource == PS_CONTROL ) {
1454  warning ( "Cannot change \"mountpoints\" in run-time. Ignoring." );
1455  return 0;
1456  }
1457 
1458  while ( ctx_p->mountpoints )
1459  free ( ctx_p->mountpoint[--ctx_p->mountpoints] );
1460 
1461  if ( !*arg )
1462  break;
1463 
1464  ptr = arg;
1465 
1466  while ( 1 ) {
1467  char *end = strchr ( ptr, ',' );
1468 
1469  if ( end != NULL )
1470  *end = 0;
1471 
1472  if ( !*ptr ) {
1473  while ( ctx_p->mountpoints )
1474  free ( ctx_p->mountpoint[--ctx_p->mountpoints] );
1475 
1476  if ( end != NULL )
1477  ptr = &end[1];
1478 
1479  continue;
1480  }
1481 
1482  if ( ctx_p->mountpoints >= MAXMOUNTPOINTS ) {
1483  errno = EINVAL;
1484  error ( "Too many mountpoints" );
1485  return errno;
1486  }
1487 
1488  ctx_p->mountpoint[ctx_p->mountpoints++] = strdup ( ptr );
1489 
1490  if ( end == NULL )
1491  break;
1492 
1493  *end = ',';
1494  ptr = &end[1];
1495  }
1496 
1497  break;
1498  }
1499 
1500 # endif
1501 #endif
1502 
1503  case PIDFILE:
1504  if ( paramsource == PS_CONTROL ) {
1505  warning ( "Cannot change \"pid-file\" in run-time. Ignoring." );
1506  return 0;
1507  }
1508 
1509  ctx_p->pidfile = arg;
1510  break;
1511 
1512  case RETRIES:
1513  ctx_p->retries = ( unsigned int ) xstrtol_trim ( arg, &ret );
1514  break;
1515 #ifdef THREADING_SUPPORT
1516 
1517  case THREADING: {
1518  char *value, *arg_orig = arg;
1519 
1520  if ( !*arg ) {
1521  ctx_p->flags[param_id] = 0;
1522  return 0;
1523  }
1524 
1525  threadingmode_t threadingmode = getsubopt ( &arg, threading_modes, &value );
1526 
1527  if ( ( int ) threadingmode == -1 ) {
1528  errno = EINVAL;
1529  error ( "Invalid threading mode entered: \"%s\"", arg_orig );
1530  return EINVAL;
1531  }
1532 
1534  break;
1535  }
1536 
1537 #endif
1538 
1539  case OUTPUT_METHOD: {
1540  char *value, *arg_orig = arg;
1541 
1542  if ( !*arg ) {
1543  ctx_p->flags[param_id] = 0;
1544  return 0;
1545  }
1546 
1547  outputmethod_t outputmethod = getsubopt ( &arg, output_methods, &value );
1548 
1549  if ( ( int ) outputmethod == -1 ) {
1550  errno = EINVAL;
1551  error ( "Invalid log writing destination entered: \"%s\"", arg_orig );
1552  return EINVAL;
1553  }
1554 
1556  break;
1557  }
1558 
1559 #ifdef CLUSTER_SUPPORT
1560 
1561  case CLUSTERIFACE:
1562  ctx_p->cluster_iface = arg;
1563  break;
1564 
1565  case CLUSTERMCASTIPADDR:
1566  ctx_p->cluster_mcastipaddr = arg;
1567  break;
1568 
1569  case CLUSTERMCASTIPPORT:
1570  ctx_p->cluster_mcastipport = ( uint16_t ) xstrtol_trim ( arg, &ret );
1571  break;
1572 
1573  case CLUSTERTIMEOUT:
1574  ctx_p->cluster_timeout = ( unsigned int ) xstrtol_trim ( arg, &ret );
1575  break;
1576 
1577  case CLUSTERNODENAME:
1578  ctx_p->cluster_nodename = arg;
1579  break;
1580 
1581  case CLUSTERHDLMIN:
1582  ctx_p->cluster_hash_dl_min = ( uint16_t ) xstrtol_trim ( arg, &ret );
1583  break;
1584 
1585  case CLUSTERHDLMAX:
1586  ctx_p->cluster_hash_dl_max = ( uint16_t ) xstrtol_trim ( arg, &ret );
1587  break;
1588 
1589  case CLUSTERSDLMAX:
1590  ctx_p->cluster_scan_dl_max = ( uint16_t ) xstrtol_trim ( arg, &ret );
1591  break;
1592 #endif
1593 
1594  case OUTLISTSDIR:
1595  ctx_p->listoutdir = arg;
1596  break;
1597 
1598  case LABEL:
1599  ctx_p->label = arg;
1600  break;
1601 #ifdef CGROUP_SUPPORT
1602 
1603  case CG_GROUPNAME:
1604  ctx_p->cg_groupname = arg;
1605  break;
1606 #endif
1607 
1608  case STANDBYFILE:
1609  if ( strlen ( arg ) ) {
1610  ctx_p->standbyfile = arg;
1611  ctx_p->flags[STANDBYFILE] = 1;
1612  } else {
1613  ctx_p->standbyfile = NULL;
1614  ctx_p->flags[STANDBYFILE] = 0;
1615  }
1616 
1617  break;
1618 
1619  case MODSIGN: {
1620  char *subopts = arg;
1621  ctx_p->flags[MODSIGN] = 0;
1622 
1623  while ( *subopts != 0 ) {
1624  char *value;
1625  typeof ( ctx_p->flags[MODSIGN] ) field = getsubopt ( &subopts, stat_fields, &value );
1626  debug ( 4, "field == %i -> %x (%s)", field, xstatfield_to_statfield[field], value );
1627 
1628  if ( field != X_STAT_FIELD_RESET )
1630  }
1631 
1632  debug ( 5, "ctx_p->flags[MODSIGN] == 0x%x", ctx_p->flags[MODSIGN] );
1633  break;
1634  }
1635 
1636  case SYNCDELAY:
1637  ctx_p->syncdelay = ( unsigned int ) xstrtol_trim ( arg, &ret );
1638  break;
1639 
1640  case DELAY:
1641  ctx_p->_queues[QUEUE_NORMAL].collectdelay = ( unsigned int ) xstrtol_trim ( arg, &ret );
1642  break;
1643 
1644  case BFILEDELAY:
1645  ctx_p->_queues[QUEUE_BIGFILE].collectdelay = ( unsigned int ) xstrtol_trim ( arg, &ret );
1646  break;
1647 
1648  case BFILETHRESHOLD:
1649  ctx_p->bfilethreshold = ( unsigned long ) xstrtol_trim ( arg, &ret );
1650  break;
1651 
1652  case CANCEL_SYSCALLS: {
1653  char *subopts = arg;
1654 
1655  while ( *subopts != 0 ) {
1656  char *value;
1657  typeof ( ctx_p->flags[CANCEL_SYSCALLS] ) syscall_bitmask = getsubopt ( &subopts, syscalls_bitmask, &value );
1658  debug ( 4, "cancel syscall == %i -> 0x%x", syscall_bitmask, xcsc_to_csc[syscall_bitmask] );
1659 
1660  if ( syscall_bitmask == X_CSC_RESET ) {
1661  ctx_p->flags[CANCEL_SYSCALLS] = 0;
1662  continue;
1663  }
1664 
1666  }
1667 
1668  break;
1669  }
1670 
1671  case MONITOR: {
1672  char *value, *arg_orig = arg;
1673 
1674  if ( paramsource == PS_CONTROL ) {
1675  warning ( "Cannot change \"monitor\" in run-time. Ignoring." );
1676  return 0;
1677  }
1678 
1679  if ( !*arg ) {
1680  ctx_p->flags_set[param_id] = 0;
1681  return 0;
1682  }
1683 
1684  notifyengine_t notifyengine = getsubopt ( &arg, notify_engines, &value );
1685 
1686  if ( ( int ) notifyengine == -1 ) {
1687  errno = EINVAL;
1688  error ( "Invalid FS monitor subsystem entered: \"%s\"", arg_orig );
1689  return EINVAL;
1690  }
1691 
1692  switch ( notifyengine ) {
1693 #ifdef FANOTIFY_SUPPORT
1694 
1695  case NE_FANOTIFY:
1696 #endif
1697 #ifdef INOTIFY_SUPPORT
1698  case NE_INOTIFY:
1699 #endif
1700 #ifdef KQUEUE_SUPPORT
1701  case NE_KQUEUE:
1702 #endif
1703 #ifdef BSM_SUPPORT
1704  case NE_BSM:
1705  case NE_BSM_PREFETCH:
1706 #endif
1707 #ifdef GIO_SUPPORT
1708  case NE_GIO:
1709 #endif
1710 #ifdef DTRACEPIPE_SUPPORT
1711  case NE_DTRACEPIPE:
1712 #endif
1713  break;
1714 
1715  default:
1716  error ( PROGRAM" is compiled without %s subsystem support. Recompile with option \"--with-%s\" if you're planning to use it.", arg_orig, arg_orig );
1717  return EINVAL;
1718  }
1719 
1720  ctx_p->flags[MONITOR] = notifyengine;
1721  break;
1722  }
1723 
1724  case RSYNCINCLIMIT:
1725  ctx_p->rsyncinclimit = ( unsigned int ) xstrtol_trim ( arg, &ret );
1726  break;
1727 
1728  case SYNCTIMEOUT:
1729  ctx_p->synctimeout = ( unsigned int ) xstrtol_trim ( arg, &ret );
1730  break;
1731 
1732  case PREEXITHOOK:
1733  if ( strlen ( arg ) ) {
1734  ctx_p->preexithookfile = arg;
1735  ctx_p->flags[PREEXITHOOK] = 1;
1736  } else {
1737  ctx_p->preexithookfile = NULL;
1738  ctx_p->flags[PREEXITHOOK] = 0;
1739  }
1740 
1741  break;
1742 
1743  case EXITHOOK:
1744  if ( strlen ( arg ) ) {
1745  ctx_p->exithookfile = arg;
1746  ctx_p->flags[EXITHOOK] = 1;
1747  } else {
1748  ctx_p->exithookfile = NULL;
1749  ctx_p->flags[EXITHOOK] = 0;
1750  }
1751 
1752  break;
1753 
1754  case IGNOREEXITCODE: {
1755  char *ptr = arg, *start = arg;
1756  unsigned char exitcode;
1757 
1758  do {
1759  switch ( *ptr ) {
1760  case 0:
1761  case ',':
1762 // *ptr=0;
1763  exitcode = ( unsigned char ) atoi ( start );
1764 
1765  if ( exitcode == 0 ) {
1766  // flushing the setting
1767  int i = 0;
1768 
1769  while ( i < 256 )
1770  ctx_p->isignoredexitcode[i++] = 0;
1771 
1772 #ifdef _DEBUG_FORCE
1773  fprintf ( stderr, "Force-Debug: parse_parameter(): Reset ignored exitcodes.\n" );
1774 #endif
1775  } else {
1777 #ifdef _DEBUG_FORCE
1778  fprintf ( stderr, "Force-Debug: parse_parameter(): Adding ignored exitcode %u.\n", exitcode );
1779 #endif
1780  }
1781 
1782  start = ptr + 1;
1783  break;
1784 
1785  case '0' ... '9':
1786  break;
1787 
1788  default:
1789  errno = EINVAL;
1790  error ( "Expected a digit or comma but got \"%c\"", *ptr );
1791  return errno;
1792  }
1793  } while ( * ( ptr++ ) );
1794 
1795  break;
1796  }
1797 
1798  case SHOW_VERSION:
1799  version();
1800  break;
1801 
1802  case WATCHDIR:
1803  if ( paramsource == PS_CONTROL ) {
1804  warning ( "Cannot change \"watch-dir\" in run-time. Ignoring." );
1805  return 0;
1806  }
1807 
1808  ctx_p->watchdir = arg;
1809  break;
1810 
1811  case SYNCHANDLER:
1812  ctx_p->handlerfpath = arg;
1813  break;
1814 
1815  case RULESFILE:
1816  ctx_p->rulfpath = arg;
1817  break;
1818 
1819  case DESTDIR: {
1820  char *sep = strstr ( arg, "://" );
1821 
1822  if ( ctx_p->destproto != NULL ) {
1823  free ( ctx_p->destproto );
1824  ctx_p->destproto = NULL;
1825  }
1826 
1827  ctx_p->destdir = arg;
1828 
1829  if ( sep == NULL ) {
1830  char *at_ptr = strchr ( arg, '@' );
1831  char *cl_ptr = strchr ( arg, ':' );
1832 
1833  if ( at_ptr != NULL && cl_ptr != NULL && at_ptr < cl_ptr ) {
1834  ctx_p->destproto = strdup ( "rsync+ssh" );
1835  debug ( 5, "Destination proto is: %s (case #0)", ctx_p->destproto );
1836  }
1837 
1838  break;
1839  }
1840 
1841  {
1842  char *ptr = arg;
1843 
1844  while ( ptr < sep ) {
1845  if ( *ptr < 'a' || *ptr > 'z' )
1846  break;
1847 
1848  ptr++;
1849  }
1850 
1851  if ( ptr == sep ) {
1852  size_t len = ( ptr - arg ) + 1;
1853  ctx_p->destproto = xmalloc ( len + 1 );
1854  memcpy ( ctx_p->destproto, arg, len );
1855  ctx_p->destproto[len] = 0;
1856  }
1857 
1858  debug ( 5, "Destination proto is: %s (case #1)", ctx_p->destproto );
1859  }
1860 
1861  break;
1862  }
1863 
1864  case SOCKETPATH:
1865  ctx_p->socketpath = arg;
1866  break;
1867 
1868  case SOCKETAUTH: {
1869  char *value;
1870  ctx_p->flags[SOCKETAUTH] = getsubopt ( &arg, socketauth, &value );
1871 
1872  if ( ctx_p->flags[SOCKETAUTH] == -1 ) {
1873  error ( "Wrong socket auth mech entered: \"%s\"", arg );
1874  return EINVAL;
1875  }
1876  }
1877 
1878  case SOCKETMOD:
1879  if ( !sscanf ( arg, "%o", ( unsigned int * ) &ctx_p->socketmod ) ) {
1880  error ( "Non octal value passed to --socket-mod: \"%s\"", arg );
1881  return EINVAL;
1882  }
1883 
1884  ctx_p->flags[param_id]++;
1885  break;
1886 
1887  case SOCKETOWN: {
1888  char *colon = strchr ( arg, ':' );
1889  uid_t uid;
1890  gid_t gid;
1891 
1892  if ( colon == NULL ) {
1893  struct passwd *pwent = getpwnam ( arg );
1894 
1895  if ( pwent == NULL ) {
1896  error ( "Cannot find username \"%s\" (case #0)",
1897  arg );
1898  return EINVAL;
1899  }
1900 
1901  uid = pwent->pw_uid;
1902  gid = pwent->pw_gid;
1903  } else {
1904  char user[USER_LEN + 2], group[GROUP_LEN + 2];
1905  memcpy ( user, arg, MIN ( USER_LEN, colon - arg ) );
1906  user[colon - arg] = 0;
1907  xstrncpy ( group, &colon[1], GROUP_LEN );
1908  errno = 0;
1909  struct passwd *pwent = getpwnam ( user );
1910 
1911  if ( pwent == NULL ) {
1912  error ( "Cannot find username \"%s\" (case #1)",
1913  user );
1914  return EINVAL;
1915  }
1916 
1917  errno = 0;
1918  struct group *grent = getgrnam ( group );
1919 
1920  if ( grent == NULL ) {
1921  error ( "Cannot find group \"%s\"",
1922  group );
1923  return EINVAL;
1924  }
1925 
1926  uid = pwent->pw_uid;
1927  gid = grent->gr_gid;
1928  }
1929 
1930  ctx_p->socketuid = uid;
1931  ctx_p->socketgid = gid;
1932  ctx_p->flags[param_id]++;
1933  debug ( 2, "socket: uid == %u; gid == %u", uid, gid );
1934  break;
1935  }
1936 
1937  case STATUSFILE:
1938  ctx_p->statusfile = arg;
1939  break;
1940 
1941  case DUMPDIR:
1942  ctx_p->dump_path = arg;
1943  break;
1944 
1945  case MODE: {
1946  char *value;
1947  ctx_p->flags[MODE] = getsubopt ( &arg, modes, &value );
1948 
1949  if ( ctx_p->flags[MODE] == -1 ) {
1950  error ( "Wrong mode name entered: \"%s\"", arg );
1951  return EINVAL;
1952  }
1953 
1954  break;
1955  }
1956 
1957  case SYNCHANDLERARGS0:
1959  break;
1960 
1961  case SYNCHANDLERARGS1:
1963  break;
1964 
1965  default:
1966  if ( arg == NULL )
1967  ctx_p->flags[param_id]++;
1968  else
1969  ctx_p->flags[param_id] = xstrtol_trim ( arg, &ret );
1970 
1971 #ifdef _DEBUG_FORCE
1972  fprintf ( stderr, "Force-Debug: flag %i is set to %i\n", param_id & 0xff, ctx_p->flags[param_id] );
1973 #endif
1974  break;
1975  }
1976 
1977  if ( ret != 0 ) {
1978  if ( arg == NULL ) {
1979  error ( "Unable to process option \"%s\" from \"%s\"", parameter_get_name_by_id ( param_id ), parametersource_get_name ( paramsource ) );
1980  } else {
1981  error ( "Unable to process option \"%s\" (with argument: \"%s\") from \"%s\"", parameter_get_name_by_id ( param_id ), arg, parametersource_get_name ( paramsource ) );
1982  }
1983  }
1984 
1985  return ret;
1986 }
1987 
1988 int arguments_parse ( int argc, char *argv[], struct ctx *ctx_p )
1989 {
1990  int c;
1991  int option_index = 0;
1992  // Generating "optstring" (man 3 getopt_long) with using information from struct array "long_options"
1993  char *optstring = alloca ( ( ( 'z' - 'a' + 1 ) * 3 + '9' - '0' + 1 ) * 3 + 1 );
1994  char *optstring_ptr = optstring;
1995  const struct option *lo_ptr = long_options;
1996 
1997  while ( lo_ptr->name != NULL ) {
1998  if ( ! ( lo_ptr->val & ( OPTION_CONFIGONLY | OPTION_LONGOPTONLY ) ) ) {
1999  * ( optstring_ptr++ ) = lo_ptr->val & 0xff;
2000 
2001  if ( lo_ptr->has_arg == required_argument )
2002  * ( optstring_ptr++ ) = ':';
2003 
2004  if ( lo_ptr->has_arg == optional_argument ) {
2005  * ( optstring_ptr++ ) = ':';
2006  * ( optstring_ptr++ ) = ':';
2007  }
2008  }
2009 
2010  lo_ptr++;
2011  }
2012 
2013  *optstring_ptr = 0;
2014 #ifdef _DEBUG_FORCE
2015  fprintf ( stderr, "Force-Debug: %s\n", optstring );
2016 #endif
2017 
2018  // Parsing arguments
2019  while ( 1 ) {
2020  c = getopt_long ( argc, argv, optstring, long_options, &option_index );
2021 
2022  if ( c == -1 ) break;
2023 
2024  int ret = parse_parameter ( ctx_p, c, optarg == NULL ? NULL : strdup ( optarg ), PS_ARGUMENT );
2025 
2026  if ( ret ) return ret;
2027  }
2028 
2029  if ( optind < argc ) {
2031 
2032  while ( args_p->c )
2033  free ( args_p->v[--args_p->c] );
2034 
2035  if ( ( optind + 1 != argc ) || ( *argv[optind] ) ) { // If there's only "" after the "--", just reset "synchandler_argc" to "0", otherwise:
2036  do {
2037  if ( synchandler_arg0 ( strdup ( argv[optind++] ), 0, ctx_p ) )
2038  return errno;
2039  } while ( optind < argc );
2040  }
2041  }
2042 
2043  return 0;
2044 }
2045 
2046 void gkf_parse ( ctx_t *ctx_p, GKeyFile *gkf, paramsource_t paramsource )
2047 {
2048  debug ( 9, "" );
2049  char *config_block = ( char * ) ctx_p->config_block;
2050 
2051  while ( config_block != NULL ) {
2052  const struct option *lo_ptr = long_options;
2053 
2054  if ( config_block != ctx_p->config_block ) {
2057  }
2058 
2059  while ( lo_ptr->name != NULL ) {
2060  gchar *value = g_key_file_get_value ( gkf, config_block, lo_ptr->name, NULL );
2061 
2062  if ( value != NULL ) {
2063  int ret = parse_parameter ( ctx_p, lo_ptr->val, value, paramsource );
2064 
2065  if ( ret ) exit ( ret );
2066  }
2067 
2068  lo_ptr++;
2069  }
2070 
2071  if ( config_block != ctx_p->config_block )
2072  free ( config_block );
2073 
2074  config_block = ctx_p->flags_values_raw[CONFIGBLOCKINHERITS];
2075 
2076  if ( config_block != NULL )
2077  debug ( 2, "Next block is: %s", config_block );
2078  };
2079 
2080  return;
2081 }
2082 
2084 {
2085  GKeyFile *gkf;
2086  gkf = g_key_file_new();
2087 
2088  if ( ctx_p->config_path ) {
2089  GError *g_error = NULL;
2090 
2091  if ( !strcmp ( ctx_p->config_path, "/NULL/" ) ) {
2092  debug ( 2, "Empty path to config file. Don't read any of config files." );
2093  return 0;
2094  }
2095 
2096  debug ( 1, "Trying config-file \"%s\" (case #0)", ctx_p->config_path );
2097 
2098  if ( !g_key_file_load_from_file ( gkf, ctx_p->config_path, G_KEY_FILE_NONE, &g_error ) ) {
2099  error ( "Cannot open/parse file \"%s\" (g_error #%u.%u: %s)", ctx_p->config_path, g_error->domain, g_error->code, g_error->message );
2100  g_key_file_free ( gkf );
2101  return -1;
2102  } else
2103  gkf_parse ( ctx_p, gkf, paramsource );
2104  } else {
2105  char *config_paths[] = CONFIG_PATHS;
2106  char **config_path_p = config_paths, *config_path_real = xmalloc ( PATH_MAX );
2107  size_t config_path_real_size = PATH_MAX;
2108  char *homedir = getenv ( "HOME" );
2109  size_t homedir_len = ( homedir == NULL ? 0 : strlen ( homedir ) );
2110 
2111  while ( *config_path_p != NULL ) {
2112  size_t config_path_len = strlen ( *config_path_p );
2113 
2114  if ( config_path_len + homedir_len + 3 > config_path_real_size ) {
2115  config_path_real_size = config_path_len + homedir_len + 3;
2116  config_path_real = xmalloc ( config_path_real_size );
2117  }
2118 
2119  if ( *config_path_p[0] != '/' ) {
2120  memcpy ( config_path_real, homedir, homedir_len );
2121  config_path_real[homedir_len] = '/';
2122  memcpy ( &config_path_real[homedir_len + 1], *config_path_p, config_path_len + 1 );
2123  } else
2124  memcpy ( config_path_real, *config_path_p, config_path_len + 1 );
2125 
2126  debug ( 1, "Trying config-file \"%s\" (case #1)", config_path_real );
2127 
2128  if ( !g_key_file_load_from_file ( gkf, config_path_real, G_KEY_FILE_NONE, NULL ) ) {
2129  debug ( 1, "Cannot open/parse file \"%s\"", config_path_real );
2130  config_path_p++;
2131  continue;
2132  }
2133 
2134  gkf_parse ( ctx_p, gkf, paramsource );
2135  break;
2136  }
2137 
2138  free ( config_path_real );
2139  }
2140 
2141  g_key_file_free ( gkf );
2142  return 0;
2143 }
2144 
2146 {
2147  int ret = 0;
2148 #ifdef CLUSTER_SUPPORT
2149  struct utsname utsname;
2150 #endif
2151 #ifndef _DEBUG_SUPPORT
2152 
2153  if ( ctx_p->flags[DEBUG] ) {
2154  ret = errno = EINVAL;
2155  error ( "Clsync was compiled without debugging support, please recompile with --enable-debug in order to be able to use debugging" );
2156  }
2157 
2158 #endif
2159 
2160  if ( ctx_p->socketpath != NULL ) {
2161 #ifndef ENABLE_SOCKET
2162  ret = EINVAL;
2163  error ( "clsync is compiled without control socket support, option \"--socket\" cannot be used." );
2164 #endif
2165 
2166  if ( ctx_p->flags[SOCKETAUTH] == SOCKAUTH_UNSET )
2168  }
2169 
2170  if ( ( ctx_p->flags[SOCKETOWN] ) && ( ctx_p->socketpath == NULL ) ) {
2171  ret = errno = EINVAL;
2172  error ( "\"--socket-own\" is useless without \"--socket\"" );
2173  }
2174 
2175  if ( ( ctx_p->flags[SOCKETMOD] ) && ( ctx_p->socketpath == NULL ) ) {
2176  ret = errno = EINVAL;
2177  error ( "\"--socket-mod\" is useless without \"--socket\"" );
2178  }
2179 
2180  if ( ( ctx_p->flags[SOCKETAUTH] ) && ( ctx_p->socketpath == NULL ) ) {
2181  ret = errno = EINVAL;
2182  error ( "\"--socket-auth\" is useless without \"--socket\"" );
2183  }
2184 
2185 #ifdef PIVOTROOT_OPT_SUPPORT
2186 
2187  if ( ( ctx_p->flags[PIVOT_ROOT] != PW_OFF ) && ( ctx_p->chroot_dir == NULL ) ) {
2188  ret = errno = EINVAL;
2189  error ( "\"--pivot-root\" cannot be used without \"--chroot\"" );
2190  }
2191 
2192 # ifdef UNSHARE_SUPPORT
2193 # ifdef GETMNTENT_SUPPORT
2194 
2195  if ( ( ctx_p->flags[PIVOT_ROOT] != PW_OFF ) && ( ctx_p->mountpoints ) )
2196  warning ( "\"--mountpoints\" is set while \"--pivot-root\" is set, too" );
2197 
2198 # endif
2199 # endif
2200 #endif
2201 
2202  if ( ctx_p->flags[STANDBYFILE] && ( ctx_p->flags[MODE] == MODE_SIMPLE ) ) {
2203  ret = errno = EINVAL;
2204  error ( "Sorry but option \"--standby-file\" cannot be used in mode \"simple\", yet." );
2205  }
2206 
2207 #ifdef THREADING_SUPPORT
2208 # ifdef VERYPARANOID
2209 
2210  if ( ( ctx_p->retries != 1 ) && ctx_p->flags[THREADING] ) {
2211  ret = errno = EINVAL;
2212  error ( "\"--retries\" values should be equal to \"1\" for this \"--threading\" value." );
2213  }
2214 
2215 # endif
2216 
2217  if ( ctx_p->flags[THREADING] && ctx_p->flags[ONLYINITSYNC] ) {
2218  ret = errno = EINVAL;
2219  error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--only-initialsync\"." );
2220  }
2221 
2222  if ( ctx_p->flags[THREADING] && ctx_p->flags[EXITONNOEVENTS] ) {
2223  ret = errno = EINVAL;
2224  error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--exit-on-no-events\"." );
2225  }
2226 
2227  if ( ctx_p->flags[THREADING] && ctx_p->flags[MAXITERATIONS] ) {
2228  ret = errno = EINVAL;
2229  error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--max-iterations\"." );
2230  }
2231 
2232  if ( ctx_p->flags[THREADING] && ctx_p->flags[PREEXITHOOK] ) {
2233  ret = errno = EINVAL;
2234  error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--pre-exit-hook\"." );
2235  }
2236 
2237  if ( ctx_p->flags[THREADING] && ctx_p->flags[SPLITTING] == SM_THREAD ) {
2238  ret = errno = EINVAL;
2239  error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--splitting=thread\"." );
2240  }
2241 
2242 # ifdef SECCOMP_SUPPORT
2243 
2244  if ( ctx_p->flags[THREADING] && ctx_p->flags[SECCOMP_FILTER] ) {
2245  ret = errno = EINVAL;
2246  error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--seccomp-filter\"." );
2247  }
2248 
2249 # endif
2250 #endif
2251 
2253  ret = errno = EINVAL;
2254  error ( "Conflicting options: \"--skip-initialsync\" and \"--exit-on-no-events\" cannot be used together." );
2255  }
2256 
2258  ret = errno = EINVAL;
2259  error ( "Conflicting options: \"--only-initialsync\" and \"--exit-on-no-events\" cannot be used together." );
2260  }
2261 
2263  ret = errno = EINVAL;
2264  error ( "Conflicting options: \"--skip-initialsync\" and \"--only-initialsync\" cannot be used together." );
2265  }
2266 
2267  if ( ctx_p->flags[INITFULL] && ctx_p->flags[SKIPINITSYNC] ) {
2268  ret = errno = EINVAL;
2269  error ( "Conflicting options: \"--full-initialsync\" and \"--skip-initialsync\" cannot be used together." );
2270  }
2271 
2273  ret = errno = EINVAL;
2274  error ( "Conflicting options: \"--modification-signature\" and \"--cancel-syscalls=mon_stat\" cannot be used together." );
2275  }
2276 
2277  if ( ctx_p->flags[EXCLUDEMOUNTPOINTS] )
2278  ctx_p->flags[ONEFILESYSTEM] = 1;
2279 
2280  if ( ctx_p->flags[MODE] == MODE_UNSET ) {
2281  ret = errno = EINVAL;
2282  error ( "\"--mode\" is not set." );
2283  }
2284 
2285  if ( ctx_p->watchdir == NULL ) {
2286  ret = errno = EINVAL;
2287  error ( "\"--watch-dir\" is not set." );
2288  }
2289 
2290  if ( ctx_p->handlerfpath == NULL ) {
2291  switch ( ctx_p->flags[MODE] ) {
2292  case MODE_DIRECT:
2294  break;
2295 
2296  case MODE_RSYNCDIRECT:
2298  break;
2299 
2300  default:
2301  ret = errno = EINVAL;
2302  error ( "\"--sync-handler\" path is not set." );
2303  }
2304  }
2305 
2306  /*
2307  if (ctx_p->flags[SYNCHANDLERSO] && ctx_p->flags[RSYNC]) {
2308  ret = EINVAL;
2309  ret = errno = EINVAL;
2310  error("Option \"--rsync\" cannot be used in conjunction with \"--synchandler-so-module\".");
2311  }
2312  */
2313 // if (ctx_p->flags[SYNCHANDLERSO] && (ctx_p->listoutdir != NULL))
2314 // error("Warning: Option \"--dir-lists\" has no effect conjunction with \"--synchandler-so-module\".");
2315 
2316 // if (ctx_p->flags[SYNCHANDLERSO] && (ctx_p->destdir != NULL))
2317 // error("Warning: Destination directory argument has no effect conjunction with \"--synchandler-so-module\".");
2318 
2319  if ( ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) && ( ctx_p->destdir == NULL ) ) {
2320  ret = errno = EINVAL;
2321  error ( "Mode \"rsyncdirect\" cannot be used without specifying \"--destination-dir\"." );
2322  }
2323 
2324 #ifdef CLUSTER_SUPPORT
2325 
2326  if ( ( ctx_p->flags[MODE] == MODE_RSYNCDIRECT ) && ( ctx_p->cluster_iface != NULL ) ) {
2327  ret = errno = EINVAL;
2328  error ( "Mode \"rsyncdirect\" cannot be used in conjunction with \"--cluster-iface\"." );
2329  }
2330 
2331  if ( ( ctx_p->cluster_iface == NULL ) && ( ( ctx_p->cluster_mcastipaddr != NULL ) || ( ctx_p->cluster_nodename != NULL ) || ( ctx_p->cluster_timeout ) || ( ctx_p->cluster_mcastipport ) ) ) {
2332  ret = errno = EINVAL;
2333  error ( "ctx \"--cluster-ip\", \"--cluster-node-name\", \"--cluster_timeout\" and/or \"cluster_ipport\" cannot be used without \"--cluster-iface\"." );
2334  }
2335 
2336  if ( ctx_p->cluster_hash_dl_min > ctx_p->cluster_hash_dl_max ) {
2337  ret = errno = EINVAL;
2338  error ( "\"--cluster-hash-dl-min\" cannot be greater than \"--cluster-hash-dl-max\"." );
2339  }
2340 
2341  if ( ctx_p->cluster_hash_dl_max > ctx_p->cluster_scan_dl_max ) {
2342  ret = errno = EINVAL;
2343  error ( "\"--cluster-hash-dl-max\" cannot be greater than \"--cluster-scan-dl-max\"." );
2344  }
2345 
2346  if ( !ctx_p->cluster_timeout )
2347  ctx_p->cluster_timeout = DEFAULT_CLUSTERTIMEOUT;
2348 
2349  if ( !ctx_p->cluster_mcastipport )
2350  ctx_p->cluster_mcastipport = DEFAULT_CLUSTERIPPORT;
2351 
2352  if ( !ctx_p->cluster_mcastipaddr )
2353  ctx_p->cluster_mcastipaddr = DEFAULT_CLUSTERIPADDR;
2354 
2355  if ( ctx_p->cluster_iface != NULL ) {
2356 #ifndef _DEBUG_FORCE
2357  ret = errno = EINVAL;
2358  error ( "Cluster subsystem is not implemented, yet. Sorry." );
2359 #endif
2360 
2361  if ( ctx_p->cluster_nodename == NULL ) {
2362  if ( !uname ( &utsname ) )
2363  ctx_p->cluster_nodename = strdup ( utsname.nodename );
2364 
2365  debug ( 1, "cluster node name is: %s", ctx_p->cluster_nodename );
2366  }
2367 
2368  if ( ctx_p->cluster_nodename == NULL ) {
2369  ret = errno = EINVAL;
2370  error ( "Option \"--cluster-iface\" is set, but \"--cluster-node-name\" is not set and cannot get the nodename with uname()." );
2371  } else {
2372  ctx_p->cluster_nodename_len = strlen ( ctx_p->cluster_nodename );
2373  }
2374  }
2375 
2376 #endif // CLUSTER_SUPPORT
2377 
2378  switch ( ctx_p->flags[MODE] ) {
2379  case MODE_RSYNCSO:
2382  break;
2383  }
2384 
2385  if (
2387  ! (
2391  )
2392  )
2393  warning ( "Option \"--rsyncpreferinclude\" is useless if mode is not \"rsyncdirect\", \"rsyncshell\" or \"rsyncso\"." );
2394 
2395 #ifdef AUTORULESW
2396 
2397  if (
2398  (
2402  )
2403  && ctx_p->flags[AUTORULESW]
2404  )
2405  warning ( "Option \"--auto-add-rules-w\" in modes \"rsyncdirect\", \"rsyncshell\" and \"rsyncso\" may cause unexpected problems." );
2406 
2407 #endif
2408 
2409  /*
2410  if(ctx_p->flags[HAVERECURSIVESYNC] && (ctx_p->listoutdir == NULL)) {
2411  error("Option \"--dir-lists\" should be set to use option \"--have-recursive-sync\".");
2412  ret = EINVAL;
2413  }
2414  */
2415 
2416  if (
2418  (
2422  )
2423  ) {
2424  ret = errno = EINVAL;
2425  error ( "Option \"--have-recursive-sync\" with nodes \"rsyncdirect\", \"rsyncshell\" and \"rsyncso\" are incompatible." );
2426  }
2427 
2428  if ( ctx_p->flags[SYNCLISTSIMPLIFY] && ( ctx_p->listoutdir == NULL ) ) {
2429  ret = errno = EINVAL;
2430  error ( "Option \"--dir-lists\" should be set to use option \"--synclist-simplify\"." );
2431  }
2432 
2433  if (
2435  (
2439  )
2440  ) {
2441  ret = errno = EINVAL;
2442  error ( "Option \"--synclist-simplify\" with nodes \"rsyncdirect\" and \"rsyncshell\" are incompatible." );
2443  }
2444 
2445 #ifdef GIO_SUPPORT
2446 # ifdef SECCOMP_SUPPORT
2447 
2448  if ( ( ctx_p->flags[MONITOR] == NE_GIO ) && ( ctx_p->flags[SECCOMP_FILTER] ) ) {
2449  ret = errno = EINVAL;
2450  error ( "GIO is not compatible with seccomp filter (\"--monitor=gio\" and \"--seccomp-filter\" are incompatible)" );
2451  }
2452 
2453 # endif
2454 #endif
2455 #ifdef FANOTIFY_SUPPORT
2456 
2457  if ( ctx_p->flags[MONITOR] == NE_FANOTIFY )
2458  critical ( "fanotify is not supported, now!" );
2459  else
2460 #endif
2461  switch ( ctx_p->flags[MONITOR] ) {
2462 #ifdef INOTIFY_SUPPORT
2463 
2464  case NE_INOTIFY:
2465 #endif
2466 #ifdef FANOTIFY_SUPPORT
2467  case NE_FANOTIFY:
2468 #endif
2469 #ifdef KQUEUE_SUPPORT
2470  case NE_KQUEUE:
2471 #endif
2472 #ifdef BSM_SUPPORT
2473  case NE_BSM:
2474  case NE_BSM_PREFETCH:
2475 #endif
2476 #ifdef GIO_SUPPORT
2477  case NE_GIO:
2478 #endif
2479 #ifdef DTRACEPIPE_SUPPORT
2480  case NE_DTRACEPIPE:
2481 #endif
2482  break;
2483 
2484  default: {
2485  ret = errno = EINVAL;
2486  char monitor_types[] =
2487 #ifdef INOTIFY_SUPPORT
2488  " \"--monitor=inotify\""
2489 #endif
2490 #ifdef FANOTIFY_SUPPORT
2491  " \"--monitor=fanotify\""
2492 #endif
2493 #ifdef KQUEUE_SUPPORT
2494  " \"--monitor=kqueue\""
2495 #endif
2496 #ifdef BSM_SUPPORT
2497  " \"--monitor=bsm\""
2498 #endif
2499 #ifdef GIO_SUPPORT
2500  " \"--monitor=gio\""
2501 #endif
2502 #ifdef DTRACEPIPE_SUPPORT
2503  " \"--monitor=dtracepipe\""
2504 #endif
2505  ;
2506  error ( "Required one of the next options: %s", monitor_types );
2507  }
2508  }
2509 
2510  if ( ctx_p->flags[EXITHOOK] ) {
2511 #ifdef VERYPARANOID
2512 
2513  if ( ctx_p->exithookfile == NULL ) {
2514  ret = errno = EINVAL;
2515  error ( "ctx_p->exithookfile == NULL" );
2516  } else
2517 #endif
2518  {
2519  if ( access ( ctx_p->exithookfile, X_OK ) == -1 ) {
2520  error ( "\"%s\" is not executable.", ctx_p->exithookfile );
2521 
2522  if ( !ret )
2523  ret = errno;
2524  }
2525  }
2526  }
2527 
2528  if ( ctx_p->flags[CHECK_EXECVP_ARGS] && ( ctx_p->flags[MODE] == MODE_DIRECT ) ) {
2529  ret = errno = EINVAL;
2530  error ( "Options --check-execvp-arguments/--secure-splitting cannot be used in conjunction with --mode=direct (see \"man 1 clsync\": --check-execvp-arguments)." );
2531  }
2532 
2533 #if 0
2534 
2535  if ( ctx_p->handlerfpath != NULL )
2536  if ( access ( ctx_p->handlerfpath, X_OK ) == -1 ) {
2537  error ( "\"%s\" is not executable.", ctx_p->handlerfpath );
2538 
2539  if ( !ret )
2540  ret = errno;
2541  }
2542 
2543 #endif
2544  return ret;
2545 }
2546 
2547 int config_block_parse ( ctx_t *ctx_p, const char *const config_block_name )
2548 {
2549  int rc;
2550  debug ( 1, "(ctx_p, \"%s\")", config_block_name );
2551  ctx_p->config_block = config_block_name;
2552  rc = configs_parse ( ctx_p, PS_CONTROL );
2553 
2554  if ( !rc )
2555  rc = ctx_check ( ctx_p );
2556 
2557  return errno = rc;
2558 }
2559 
2560 int ctx_set ( ctx_t *ctx_p, const char *const parameter_name, const char *const parameter_value )
2561 {
2562  int ret = ENOENT;
2563  const struct option *lo_ptr = long_options;
2564 
2565  while ( lo_ptr->name != NULL ) {
2566  if ( !strcmp ( lo_ptr->name, parameter_name ) ) {
2567  ret = parse_parameter ( ctx_p, lo_ptr->val, strdup ( parameter_value ), PS_CONTROL );
2568  break;
2569  }
2570 
2571  lo_ptr++;
2572  }
2573 
2574  ret = ctx_check ( ctx_p );
2575 
2576  if ( ret )
2577  critical ( "Cannot continue with this setup" );
2578 
2579  return ret;
2580 }
2581 
2583 {
2584  int i = 0;
2585  debug ( 9, "" );
2586 
2587  while ( i < OPTION_FLAGS ) {
2588  if ( ctx_p->flags_values_raw[i] != NULL ) {
2589  free ( ctx_p->flags_values_raw[i] );
2590  ctx_p->flags_values_raw[i] = NULL;
2591  }
2592 
2593  i++;
2594  }
2595 
2596  {
2597  int n = 0;
2598 
2599  while ( n < SHARGS_MAX ) {
2600  int i = 0, e = ctx_p->synchandler_args[n].c;
2601 
2602  while ( i < e ) {
2603 #ifdef _DEBUG_FORCE
2604  debug ( 14, "synchandler args: %u, %u: free(%p)", n, i, ctx_p->synchandler_args[n].v[i] );
2605 #endif
2606  free ( ctx_p->synchandler_args[n].v[i] );
2607  ctx_p->synchandler_args[n].v[i] = NULL;
2608  i++;
2609  }
2610 
2611  ctx_p->synchandler_args[n].c = 0;
2612  n++;
2613  }
2614  }
2615 
2616  return;
2617 }
2618 
2620 {
2621  int pid;
2622  signal ( SIGPIPE, SIG_IGN );
2623 
2624  switch ( ( pid = fork() ) ) {
2625  case -1:
2626  error ( "Cannot fork()." );
2627  return ( errno );
2628 
2629  case 0:
2630  setsid();
2631  break;
2632 
2633  default:
2634  debug ( 1, "fork()-ed, pid is %i.", pid );
2635  errno = 0;
2636  exit ( 0 );
2637  }
2638 
2639  return 0;
2640 }
2641 
2643 {
2644  int i = 0;
2645 
2646  while ( ( i < MAXRULES ) && ( ctx_p->rules[i].mask != RA_NONE ) )
2647  regfree ( &ctx_p->rules[i++].expr );
2648 
2650  return 0;
2651 }
2652 
2654 {
2655  debug ( 3, "" );
2656  int ret = 0;
2657  main_cleanup ( ctx_p );
2658 
2659  if ( ctx_p->rulfpath != NULL ) {
2660  ret = parse_rules_fromfile ( ctx_p );
2661 
2662  if ( ret )
2663  error ( "Got error from parse_rules_fromfile()." );
2664  } else {
2666  ctx_p->rules[0].mask = RA_NONE; // Terminator. End of rules.
2667  }
2668 
2669  return ret;
2670 }
2671 
2674 {
2675  static state_t state_old = STATE_UNKNOWN;
2676  state_t state = ctx_p->state;
2677  debug ( 4, "%u", state );
2678 
2679  if ( state == state_old ) {
2680  debug ( 3, "State unchanged: %u == %u", state, state_old );
2681  return 0;
2682  }
2683 
2684 #ifdef VERYPARANOID
2685 
2686  if ( status_descr[state] == NULL ) {
2687  error ( "status_descr[%u] == NULL.", state );
2688  return EINVAL;
2689  }
2690 
2691 #endif
2692  setenv ( "CLSYNC_STATUS", status_descr[state], 1 );
2693 
2694  if ( ctx_p->statusfile == NULL )
2695  return 0;
2696 
2697  debug ( 3, "Setting status to %i: %s.", state, status_descr[state] );
2698  state_old = state;
2699  int ret = 0;
2700 
2701  if ( ftruncate ( fileno ( main_statusfile_f ), 0 ) ) {
2702  error ( "Cannot ftruncate() the file \"%s\".",
2703  ctx_p->statusfile );
2704  return errno;
2705  }
2706 
2707  rewind ( main_statusfile_f );
2708 
2709  if ( fprintf ( main_statusfile_f, "%s", status_descr[state] ) <= 0 ) { // TODO: check output length
2710  error ( "Cannot write to file \"%s\".",
2711  ctx_p->statusfile );
2712  return errno;
2713  }
2714 
2715  if ( fflush ( main_statusfile_f ) ) {
2716  error ( "Cannot fflush() on file \"%s\".",
2717  ctx_p->statusfile );
2718  return errno;
2719  }
2720 
2721  return ret;
2722 }
2723 
2724 int argc;
2725 char **argv;
2726 #define UGID_PRESERVE (1<<16)
2727 int main ( int _argc, char *_argv[] )
2728 {
2729  struct ctx *ctx_p = xcalloc ( 1, sizeof ( *ctx_p ) );
2730  argv = _argv;
2731  argc = _argc;
2732  int ret = 0, nret, rm_listoutdir = 0;
2733  SAFE ( posixhacks_init(), errno = ret = _SAFE_rc );
2734  ctx_p->flags[MONITOR] = DEFAULT_NOTIFYENGINE;
2743 #ifdef CLUSTER_SUPPORT
2744  ctx_p->cluster_hash_dl_min = DEFAULT_CLUSTERHDLMIN;
2745  ctx_p->cluster_hash_dl_max = DEFAULT_CLUSTERHDLMAX;
2746  ctx_p->cluster_scan_dl_max = DEFAULT_CLUSTERSDLMAX;
2747 #endif
2751 #ifdef PIVOTROOT_OPT_SUPPORT
2753 #endif
2754 #ifdef CAPABILITIES_SUPPORT
2760  ncpus = sysconf ( _SC_NPROCESSORS_ONLN ); // Get number of available logical CPUs
2761  memory_init();
2762  {
2763  struct passwd *pwd = getpwnam ( DEFAULT_USER );
2764  ctx_p->uid = ( pwd != NULL ) ? pwd->pw_uid : DEFAULT_UID;
2766  }
2767  {
2768  struct group *grp = getgrnam ( DEFAULT_GROUP );
2769  ctx_p->gid = ( grp != NULL ) ? grp->gr_gid : DEFAULT_GID;
2771  }
2772 #endif
2773  ctx_p->pid = getpid();
2775  nret = arguments_parse ( argc, argv, ctx_p );
2776 
2777  if ( nret ) ret = nret;
2778 
2779  if ( !ret ) {
2780  nret = configs_parse ( ctx_p, PS_CONFIG );
2781 
2782  if ( nret ) ret = nret;
2783  }
2784 
2785  debug ( 5, "after arguments_parse(): uid == %d, gid == %d, privileged_uid == %d, privileged_gid == %d, synchandler_uid == %d, synchandler_gid == %d",
2787 
2788  if ( !ctx_p->flags[PRIVILEGEDUID] )
2789  ctx_p->privileged_uid = getuid();
2790 
2791  if ( !ctx_p->flags[PRIVILEGEDGID] )
2792  ctx_p->privileged_gid = getgid();
2793 
2794  if ( !ctx_p->flags[SYNCHANDLERUID] )
2796 
2797  if ( !ctx_p->flags[SYNCHANDLERGID] )
2799 
2800  debug ( 4, "uid == %d, gid == %d, privileged_uid == %d, privileged_gid == %d, synchandler_uid == %d, synchandler_gid == %d",
2802 
2803 #ifdef CGROUP_SUPPORT
2804 
2805  if ( ctx_p->cg_groupname == NULL ) {
2806  ctx_p->cg_groupname = parameter_expand ( ctx_p, strdup ( DEFAULT_CG_GROUPNAME ), PEF_UNSET_VARIABLE, NULL, NULL, parameter_get, ctx_p );
2807  ctx_p->flags_values_raw[CG_GROUPNAME] = ctx_p->cg_groupname;
2808  }
2809 
2810 #endif
2811 
2812  if ( ctx_p->dump_path == NULL ) {
2815  }
2816 
2818  char *args_line0 = NULL, *args_line1 = NULL;
2819 
2820  switch ( ctx_p->flags[MODE] ) {
2821  case MODE_SIMPLE:
2822  args_line0 = DEFAULT_SYNCHANDLER_ARGS_SIMPLE;
2823  break;
2824 
2825  case MODE_DIRECT:
2826  args_line0 = DEFAULT_SYNCHANDLER_ARGS_DIRECT;
2827  break;
2828 
2829  case MODE_SHELL:
2830  args_line0 = DEFAULT_SYNCHANDLER_ARGS_SHELL_NR;
2831  args_line1 = DEFAULT_SYNCHANDLER_ARGS_SHELL_R;
2832  break;
2833 
2834  case MODE_RSYNCDIRECT:
2836  break;
2837 
2838  case MODE_RSYNCSHELL:
2840  break;
2841 
2842  default:
2843  break;
2844  }
2845 
2846  if ( args_line0 != NULL ) {
2847  char *args_line = strdup ( args_line0 );
2849  }
2850 
2851  if ( args_line1 != NULL ) {
2852  char *args_line = strdup ( args_line1 );
2854  }
2855  }
2856 
2857  debug ( 4, "ncpus == %u", ncpus );
2858  debug ( 4, "debugging flags: %u %u %u %u", ctx_p->flags[OUTPUT_METHOD], ctx_p->flags[QUIET], ctx_p->flags[VERBOSE], ctx_p->flags[DEBUG] );
2859 
2860  if ( ctx_p->watchdir != NULL ) {
2861  char *rwatchdir = realpath ( ctx_p->watchdir, NULL );
2862 
2863  if ( rwatchdir == NULL ) {
2864  error ( "Got error while realpath() on \"%s\" [#0].", ctx_p->watchdir );
2865  ret = errno;
2866  }
2867 
2868  debug ( 5, "rwatchdir == \"%s\"", rwatchdir );
2869  stat64_t stat64 = {0};
2870 
2871  if ( lstat64 ( ctx_p->watchdir, &stat64 ) ) {
2872  error ( "Cannot lstat64() on \"%s\"", ctx_p->watchdir );
2873 
2874  if ( !ret )
2875  ret = errno;
2876  } else {
2877  ctx_p->st_dev = stat64.st_dev;
2878  /*
2879  if ((stat64.st_mode & S_IFMT) == S_IFLNK) {
2880  // The proplems may be due to FTS_PHYSICAL option of fts_open() in sync_initialsync_rsync_walk(),
2881  // so if the "watch dir" is just a symlink it doesn't walk recursivly. For example, in "-R" case
2882  // it disables filters, because exclude-list will be empty.
2883  #ifdef VERYPARANOID
2884  error("Watch dir cannot be symlink, but \"%s\" is a symlink.", ctx_p->watchdir);
2885  ret = EINVAL;
2886  #else
2887  char *watchdir_resolved_part = xcalloc(1, PATH_MAX+2);
2888  ssize_t r = readlink(ctx_p->watchdir, watchdir_resolved_part, PATH_MAX+1);
2889 
2890  if (r>=PATH_MAX) { // TODO: check if it's possible
2891  ret = errno = EINVAL;
2892  error("Too long file path resolved from symbolic link \"%s\"", ctx_p->watchdir);
2893  } else
2894  if (r<0) {
2895  error("Cannot resolve symbolic link \"%s\": readlink() error", ctx_p->watchdir);
2896  ret = EINVAL;
2897  } else {
2898  char *watchdir_resolved;
2899  # ifdef PARANOID
2900  if (ctx_p->watchdirsize)
2901  if (ctx_p->watchdir != NULL)
2902  free(ctx_p->watchdir);
2903  # endif
2904 
2905  size_t watchdir_resolved_part_len = strlen(watchdir_resolved_part);
2906  ctx_p->watchdirsize = watchdir_resolved_part_len+1; // Not true for case of relative symlink
2907  if (*watchdir_resolved_part == '/') {
2908  // Absolute symlink
2909  watchdir_resolved = malloc(ctx_p->watchdirsize);
2910  memcpy(watchdir_resolved, watchdir_resolved_part, ctx_p->watchdirsize);
2911  } else {
2912  // Relative symlink :(
2913  char *rslash = strrchr(ctx_p->watchdir, '/');
2914 
2915  char *watchdir_resolved_rel = xmalloc(PATH_MAX+2);
2916  size_t watchdir_resolved_rel_len = rslash-ctx_p->watchdir + 1;
2917  memcpy(watchdir_resolved_rel, ctx_p->watchdir, watchdir_resolved_rel_len);
2918  memcpy(&watchdir_resolved_rel[watchdir_resolved_rel_len], watchdir_resolved_part, watchdir_resolved_part_len+1);
2919 
2920  watchdir_resolved = realpath(watchdir_resolved_rel, NULL);
2921 
2922  free(watchdir_resolved_rel);
2923  }
2924 
2925 
2926  debug(1, "Symlink resolved: watchdir \"%s\" -> \"%s\"", ctx_p->watchdir, watchdir_resolved);
2927  ctx_p->watchdir = watchdir_resolved;
2928  }
2929  free(watchdir_resolved_part);
2930  #endif // VERYPARANOID else
2931  }
2932  */
2933  }
2934 
2935  if ( !ret ) {
2936  parse_parameter ( ctx_p, WATCHDIR, rwatchdir, PS_CORRECTION );
2937  ctx_p->watchdirlen = strlen ( ctx_p->watchdir );
2939 #ifdef VERYPARANOID
2940 
2941  if ( ctx_p->watchdirlen == 1 ) {
2942  ret = errno = EINVAL;
2943  error ( "Very-Paranoid: --watch-dir is supposed to be not \"/\"." );
2944  }
2945 
2946 #endif
2947  }
2948 
2949  if ( !ret ) {
2950  if ( ctx_p->watchdirlen == 1 ) {
2953  ctx_p->watchdir_dirlevel = 0;
2954  } else {
2955  size_t size = ctx_p->watchdirlen + 2;
2956  char *newwatchdir = xmalloc ( size );
2957  memcpy ( newwatchdir, ctx_p->watchdir, ctx_p->watchdirlen );
2958  ctx_p->watchdirwslash = newwatchdir;
2959  ctx_p->watchdirwslashsize = size;
2960  memcpy ( &ctx_p->watchdirwslash[ctx_p->watchdirlen], "/", 2 );
2962  }
2963  }
2964  }
2965 
2966  if ( ( ctx_p->destdir != NULL ) && ( ctx_p->destproto == NULL ) ) { // "ctx_p->destproto == NULL" means "no protocol"/"local directory"
2967  char *rdestdir = realpath ( ctx_p->destdir, NULL );
2968 
2969  if ( rdestdir == NULL ) {
2970  error ( "Got error while realpath() on \"%s\" [#1].", ctx_p->destdir );
2971  ret = errno;
2972  }
2973 
2974  debug ( 5, "rdestdir == \"%s\"", rdestdir );
2975 
2976  if ( !ret ) {
2977  parse_parameter ( ctx_p, DESTDIR, rdestdir, PS_CORRECTION );
2978  ctx_p->destdirlen = strlen ( ctx_p->destdir );
2980 
2981  if ( ctx_p->destdirlen == 1 ) {
2982  ret = errno = EINVAL;
2983  error ( "destdir is supposed to be not \"/\"." );
2984  }
2985  }
2986 
2987  if ( !ret ) {
2988  size_t size = ctx_p->destdirlen + 2;
2989  char *newdestdir = xmalloc ( size );
2990  memcpy ( newdestdir, ctx_p->destdir, ctx_p->destdirlen );
2991  ctx_p->destdirwslash = newdestdir;
2992  ctx_p->destdirwslashsize = size;
2993  memcpy ( &ctx_p->destdirwslash[ctx_p->destdirlen], "/", 2 );
2994  }
2995  } else if ( ctx_p->destproto != NULL )
2997 
2998  if ( ctx_p->rulfpath ) {
2999  if ( *ctx_p->rulfpath != '/' ) {
3000  ctx_p->rulfpath = realpath ( ctx_p->rulfpath, NULL );
3001 
3002  if ( ctx_p->rulfpath == NULL )
3003  error ( "Cannot find rules-file. Got error while realpath(\"%s\")", ctx_p->rulfpath );
3004  else
3005  ctx_p->rulfpathsize = 1;
3006  }
3007  }
3008 
3009  if ( ctx_p->handlerfpath != NULL ) {
3010  char *rhandlerfpath = realpath ( ctx_p->handlerfpath, NULL );
3011  /*
3012  if (rhandlerfpath == NULL) {
3013  error("Got error while realpath() on \"%s\" [#0].", ctx_p->handlerfpath);
3014  ret = errno;
3015  }
3016  debug(5, "rhandlerfpath == \"%s\"", rhandlerfpath);
3017  ctx_p->handlerfpath = rhandlerfpath;*/
3018 
3019  if ( rhandlerfpath != NULL )
3020  ctx_p->handlerfpath = rhandlerfpath;
3021  }
3022 
3023  debug ( 9, "chdir(\"%s\");", ctx_p->watchdir );
3024 
3025  if ( chdir ( ctx_p->watchdir ) ) {
3026  error ( "Got error while chdir(\"%s\")", ctx_p->watchdir );
3027  ret = errno;
3028  }
3029 
3030  /*
3031  if (ctx_p->flags_values_raw[SYNCHANDLERARGS0] != NULL)
3032  parse_parameter(ctx_p, SYNCHANDLERARGS0, NULL, PS_REHASH);
3033 
3034  if (ctx_p->flags_values_raw[SYNCHANDLERARGS1] != NULL)
3035  parse_parameter(ctx_p, SYNCHANDLERARGS1, NULL, PS_REHASH);
3036  */
3037  {
3038  int n = 0;
3039 
3040  while ( n < SHARGS_MAX ) {
3041  synchandler_args_t *args_p = &ctx_p->synchandler_args[n++];
3042  debug ( 9, "Custom arguments %u count: %u", n - 1, args_p->c );
3043  int i = 0;
3044 
3045  while ( i < args_p->c ) {
3046  int macros_count = -1, expanded = -1;
3047  args_p->v[i] = parameter_expand ( ctx_p, args_p->v[i], PEF_LAZY_SUBSTITUTION, &macros_count, &expanded, parameter_get_wmacro, ctx_p );
3048  debug ( 12, "args_p->v[%u] == \"%s\" (t: %u; e: %u)", i, args_p->v[i], macros_count, expanded );
3049 
3050  if ( macros_count == expanded )
3051  args_p->isexpanded[i]++;
3052 
3053  i++;
3054  }
3055  }
3056  }
3058  {
3059 #ifdef UNSHARE_SUPPORT
3060 # ifdef GETMNTENT_SUPPORT
3061  struct mntent *ent;
3062  FILE *ent_f;
3063  ent_f = NULL;
3064 
3065  if ( ctx_p->mountpoints ) {
3066  // Openning the file with mount list
3067  ent_f = setmntent ( "/proc/mounts", "r" );
3068 
3069  if ( ent_f == NULL ) {
3070  error ( "Got error while setmntent(\"/proc/mounts\", \"r\")" );
3071  ret = errno;
3072  }
3073  }
3074 
3075 # endif
3076 # define unshare_wrapper(a) \
3077  if (unshare(a)) {\
3078  error("Got error from unshare("TOSTR(a)")");\
3079  ret = errno;\
3080  }
3081 
3082  if ( ctx_p->flags[DETACH_IPC] ) {
3083  unshare ( CLONE_NEWUTS );
3085  }
3086 
3087  if ( ctx_p->flags[DETACH_MISCELLANEA] ) {
3088  unshare ( CLONE_NEWIPC );
3089  unshare ( CLONE_NEWUTS );
3090  unshare ( CLONE_SYSVSEM );
3091  }
3092 
3093  if ( ( ctx_p->flags[PIVOT_ROOT] != PW_OFF ) || ctx_p->mountpoints ) {
3094  unshare_wrapper ( CLONE_FILES );
3095  unshare_wrapper ( CLONE_FS );
3096  unshare_wrapper ( CLONE_NEWNS );
3097  }
3098 
3100  unshare_wrapper ( CLONE_NEWNET );
3101 
3102 # undef unshare_wrapper
3103 #endif
3104 
3105  if ( ctx_p->chroot_dir != NULL ) {
3106 #ifdef PIVOTROOT_OPT_SUPPORT
3107 
3108  switch ( ctx_p->flags[PIVOT_ROOT] ) {
3109  case PW_OFF:
3110  case PW_DIRECT:
3111  break;
3112 
3113  case PW_AUTO:
3114  case PW_AUTORO: {
3115  if ( chdir ( ctx_p->chroot_dir ) ) {
3116  error ( "Got error while chdir(\"%s\")", ctx_p->chroot_dir );
3117  ret = errno;
3118  }
3119 
3120  if ( mkdir ( "old_root", 0700 ) ) {
3121  if ( errno != EEXIST ) {
3122  error ( "Got error from mkdir(\"old_root\", 0700)" );
3123  ret = errno;
3124  break;
3125  }
3126  }
3127 
3128  if ( mkdir ( PIVOT_AUTO_DIR, 0700 ) ) {
3129  if ( errno != EEXIST ) {
3130  error ( "Got error from mkdir(\""PIVOT_AUTO_DIR"\", 0700)" );
3131  ret = errno;
3132  break;
3133  }
3134  }
3135 
3136  unsigned long mount_flags = MS_BIND | MS_REC |
3137  ( ( ctx_p->flags[PIVOT_ROOT] == PW_AUTORO ) ? MS_RDONLY : 0 );
3138 
3139  if ( mount ( ctx_p->chroot_dir, PIVOT_AUTO_DIR, NULL, mount_flags, NULL ) ) {
3140  error ( "Got error while mount(\"%s\", \"%s\", NULL, %o, NULL)",
3141  ctx_p->chroot_dir, PIVOT_AUTO_DIR, mount_flags );
3142  ret = errno;
3143  break;
3144  }
3145 
3147  break;
3148  }
3149  }
3150 
3151 #endif
3152  debug ( 7, "chdir(\"%s\")", ctx_p->chroot_dir );
3153 
3154  if ( chdir ( ctx_p->chroot_dir ) ) {
3155  error ( "Got error while chdir(\"%s\")", ctx_p->chroot_dir );
3156  ret = errno;
3157  }
3158  }
3159 
3160 #ifdef UNSHARE_SUPPORT
3161 # ifdef GETMNTENT_SUPPORT
3162 
3163  if ( ctx_p->mountpoints && ( ent_f != NULL ) ) {
3164  // Getting mount-points to be umounted
3165  while ( NULL != ( ent = getmntent ( ent_f ) ) ) {
3166  int i;
3167  debug ( 8, "Checking should \"%s\" be umount or not", ent->mnt_dir );
3168  i = 0;
3169 
3170  while ( i < ctx_p->mountpoints ) {
3171  debug ( 9, "\"%s\" <?> \"%s\"", ent->mnt_dir, ctx_p->mountpoint[i] );
3172 
3173  if ( !strcmp ( ent->mnt_dir, ctx_p->mountpoint[i] ) ) {
3174  debug ( 9, "found" );
3175  break;
3176  }
3177 
3178  i++;
3179  }
3180 
3181  if ( i >= ctx_p->mountpoints ) {
3182  debug ( 1, "umount2(\"%s\", MNT_DETACH)", ent->mnt_dir );
3183 
3184  if ( umount2 ( ent->mnt_dir, MNT_DETACH ) && errno != ENOENT && errno != EINVAL ) {
3185  error ( "Got error while umount2(\"%s\", MNT_DETACH)", ent->mnt_dir );
3186  ret = errno;
3187  }
3188  }
3189  }
3190 
3191  endmntent ( ent_f );
3192  }
3193 
3194 # endif
3195 #endif
3196 
3197  if ( ctx_p->chroot_dir != NULL ) {
3198 #ifdef PIVOTROOT_OPT_SUPPORT
3199 
3200  if ( !ret ) {
3201  switch ( ctx_p->flags[PIVOT_ROOT] ) {
3202  case PW_OFF:
3203  break;
3204 
3205  case PW_DIRECT:
3206  case PW_AUTO:
3207  case PW_AUTORO:
3208  if ( pivot_root ( ".", "old_root" ) ) {
3209  error ( "Got error while pivot_root(\".\", \"old_root\")" );
3210  ret = errno;
3211  }
3212 
3213  break;
3214  }
3215  }
3216 
3217 #endif
3218  debug ( 7, "chroot(\".\")" );
3219 
3220  if ( chroot ( "." ) ) {
3221  error ( "Got error while chroot(\".\")" );
3222  ret = errno;
3223  }
3224 
3225 #ifdef PIVOTROOT_OPT_SUPPORT
3226 
3227  if ( !ret ) {
3228  switch ( ctx_p->flags[PIVOT_ROOT] ) {
3229  case PW_OFF:
3230  break;
3231 
3232  case PW_DIRECT:
3233  case PW_AUTO:
3234  case PW_AUTORO:
3235  if ( umount2 ( "old_root", MNT_DETACH ) ) {
3236  error ( "Got error while umount2(\"old_root\", MNT_DETACH)" );
3237  ret = errno;
3238  }
3239 
3240  break;
3241  }
3242  }
3243 
3244 #endif
3245  }
3246  }
3247 
3248  if ( ctx_p->statusfile != NULL ) {
3249  debug ( 1, "Trying to open the status file for writing." );
3250  main_statusfile_f = fopen ( ctx_p->statusfile, "w" );
3251 
3252  if ( main_statusfile_f != NULL ) {
3253  uid_t uid = ctx_p->flags[UID] ? ctx_p->uid : getuid();
3254  gid_t gid = ctx_p->flags[GID] ? ctx_p->gid : getgid();
3255  debug ( 1, "Changing owner of the status file to %u:%u", uid, gid );
3256 
3257  if ( fchown ( fileno ( main_statusfile_f ), uid, gid ) )
3258  warning ( "Cannot fchown(%u -> \"%s\", %u, %u)",
3259  fileno ( main_statusfile_f ), ctx_p->statusfile, uid, gid );
3260 
3262  }
3263  }
3264 
3265 #ifdef CAPABILITIES_SUPPORT
3266  debug ( 1, "Preserving Linux capabilities" );
3267 
3268  // Tell kernel not clear capabilities when dropping root
3269  if ( prctl ( PR_SET_KEEPCAPS, 1 ) < 0 ) {
3270  error ( "Cannot prctl(PR_SET_KEEPCAPS, 1) to preserve capabilities" );
3271  ret = errno;
3272  }
3273 
3274 #endif
3275 #ifdef CGROUP_SUPPORT
3276 
3277  if ( ctx_p->flags[FORBIDDEVICES] ) {
3281  }
3282 
3283 #endif
3284  nret = main_rehash ( ctx_p );
3285 
3286  if ( nret )
3287  ret = nret;
3288 
3289  if ( ctx_p->flags[GID] ) {
3290  int rc;
3291  debug ( 3, "Trying to drop effective gid to %i", ctx_p->gid );
3292  rc = setegid ( ctx_p->gid );
3293 
3294  if ( rc && ( ctx_p->flags[GID] != UGID_PRESERVE ) ) {
3295  error ( "Cannot setegid(%u)", ctx_p->gid );
3296  ret = errno;
3297  }
3298  }
3299 
3300  if ( ctx_p->flags[UID] ) {
3301  int rc;
3302  debug ( 3, "Trying to drop effective uid to %i", ctx_p->uid );
3303  rc = seteuid ( ctx_p->uid );
3304 
3305  if ( rc && ( ctx_p->flags[UID] != UGID_PRESERVE ) ) {
3306  error ( "Cannot seteuid(%u)", ctx_p->uid );
3307  ret = errno;
3308  }
3309  }
3310 
3311  if ( main_statusfile_f == NULL && ctx_p->statusfile != NULL ) {
3312  debug ( 1, "Trying to open the status file for writing (after setuid()/setgid())." );
3313  main_statusfile_f = fopen ( ctx_p->statusfile, "w" );
3314 
3315  if ( main_statusfile_f == NULL ) {
3316  error ( "Cannot open file \"%s\" for writing.",
3317  ctx_p->statusfile );
3318  ret = errno;
3319  }
3320  }
3321 
3322  debug ( 1, "%s [%s] (%p) -> %s [%s] (%p)", ctx_p->watchdir, ctx_p->watchdirwslash, ctx_p->watchdirwslash, ctx_p->destdir ? ctx_p->destdir : "", ctx_p->destdirwslash ? ctx_p->destdirwslash : "", ctx_p->destdirwslash );
3323  {
3324  int rc = ctx_check ( ctx_p );
3325 
3326  if ( !ret ) ret = rc;
3327  }
3328 
3329  if (
3330  ( ctx_p->listoutdir == NULL ) &&
3331  (
3333  (
3336  )
3337  )
3338  ) {
3339  // Use $TMPDIR as the temp directory, fall back to /tmp
3340  char *tempdir = getenv ( "TMPDIR" );
3341  if ( !tempdir )
3342  tempdir = TMPDIR_PATH;
3343  const char *tempsuff = TMPDIR_TEMPLATE;
3344  size_t tempdir_len = strlen(tempdir);
3345  size_t tempsuff_len = strlen(tempsuff);
3346 
3347  // template = "$tempdir$tempsuff"
3348  char *template = xmalloc(tempdir_len + tempsuff_len + 1);
3349  memcpy ( template, tempdir, tempdir_len);
3350  memcpy ( template + tempdir_len, tempsuff, tempsuff_len);
3351  template[tempdir_len + tempsuff_len] = 0;
3352 
3353  ctx_p->listoutdir = mkdtemp ( template );
3354 
3355  if ( ctx_p->listoutdir == NULL ) {
3356  ret = errno;
3357  error ( "Cannot create temporary dir for list files by template '%s'", template );
3358  } else
3359  rm_listoutdir = 2;
3360  }
3361 
3362  if ( ctx_p->listoutdir != NULL ) {
3363  struct stat st = {0};
3364  errno = 0;
3365 
3366  if ( stat ( ctx_p->listoutdir, &st ) ) {
3367  if ( errno == ENOENT ) {
3368  warning ( "Directory \"%s\" doesn't exist. Creating it.", ctx_p->listoutdir );
3369  errno = 0;
3370 
3371  if ( mkdir ( ctx_p->listoutdir, S_IRWXU ) ) {
3372  error ( "Cannot create directory \"%s\".", ctx_p->listoutdir );
3373  ret = errno;
3374  } else
3375  rm_listoutdir = 1;
3376  } else {
3377  error ( "Got error while stat() on \"%s\".", ctx_p->listoutdir );
3378  ret = errno;
3379  }
3380  }
3381 
3382  if ( !errno )
3383  if ( st.st_mode & ( S_IRWXG | S_IRWXO ) ) {
3384 #ifdef PARANOID
3385  ret = errno = EACCES;
3386  error ( "Insecure: Others have access to directory \"%s\". Exit.", ctx_p->listoutdir );
3387 #else
3388  warning ( "Insecure: Others have access to directory \"%s\".", ctx_p->listoutdir );
3389 #endif
3390  }
3391  }
3392 
3393  if ( ctx_p->flags[BACKGROUND] ) {
3394  nret = becomedaemon();
3395 
3396  if ( nret )
3397  ret = nret;
3398  }
3399 
3400  if ( ctx_p->pidfile != NULL ) {
3401  debug ( 2, "Trying to open the pidfile \"%s\"", ctx_p->pidfile );
3402  pid_t pid = getpid();
3403  FILE *pidfile = fopen ( ctx_p->pidfile, "w" );
3404 
3405  if ( pidfile == NULL ) {
3406  // If error
3407  if ( errno == EACCES ) {
3408  int fd;
3409  uid_t euid = geteuid();
3410  gid_t egid = getegid();
3411  debug ( 1, "Don't have permissions to open file \"%s\". Trying seteuid(0)+open()+fchown()+close()+seteuid(%i)", ctx_p->pidfile, euid );
3412  errno = 0;
3413 
3414  if ( !errno ) SAFE ( seteuid ( 0 ), ret = errno );
3415 
3416  if ( !errno ) SAFE ( ( fd = open ( ctx_p->pidfile, O_CREAT | O_WRONLY, 0644 ) ) == -1, ret = errno );
3417 
3418  if ( !errno ) SAFE ( fchown ( fd, euid, egid ), ret = errno );
3419 
3420  if ( !errno ) SAFE ( close ( fd ), ret = errno );
3421 
3422  if ( !errno ) SAFE ( seteuid ( euid ), ret = errno );
3423 
3424  pidfile = fopen ( ctx_p->pidfile, "w" );
3425  }
3426 
3427  if ( pidfile == NULL ) {
3428  error ( "Cannot open file \"%s\" to write a pid there",
3429  ctx_p->pidfile );
3430  ret = errno;
3431  }
3432  }
3433 
3434  if ( pidfile != NULL ) {
3435  if ( fprintf ( pidfile, "%u", pid ) < 0 ) {
3436  error ( "Cannot write pid into file \"%s\"",
3437  ctx_p->pidfile );
3438  ret = errno;
3439  }
3440 
3441  fclose ( pidfile );
3442  }
3443  }
3444 
3445  debug ( 3, "Current errno is %i.", ret );
3446 
3447  // == RUNNING ==
3448  if ( ret == 0 )
3449  ret = sync_run ( ctx_p );
3450 
3451  // == /RUNNING ==
3452 
3453  if ( ctx_p->pidfile != NULL ) {
3454  if ( unlink ( ctx_p->pidfile ) ) {
3455  FILE *pidfile;
3456  debug ( 1, "Cannot unlink pidfile \"%s\": %s. Just truncating the file.",
3457  ctx_p->pidfile, strerror ( errno ) );
3458  SAFE ( ( pidfile = fopen ( ctx_p->pidfile, "w" ) ) == NULL, ret = errno );
3459 
3460  if ( pidfile != NULL )
3461  fclose ( pidfile );
3462  }
3463  }
3464 
3465  if ( ctx_p->statusfile != NULL ) {
3466  if ( main_statusfile_f != NULL )
3467  if ( fclose ( main_statusfile_f ) ) {
3468  error ( "Cannot close file \"%s\".",
3469  ctx_p->statusfile );
3470  ret = errno;
3471  }
3472 
3473  if ( unlink ( ctx_p->statusfile ) ) {
3474  error ( "Cannot unlink status file \"%s\"",
3475  ctx_p->statusfile );
3476  ret = errno;
3477  }
3478  }
3479 
3480  if ( ( !ctx_p->flags[DONTUNLINK] ) && ( ctx_p->listoutdir != NULL ) && rm_listoutdir ) {
3481  debug ( 2, "rmdir(\"%s\")", ctx_p->listoutdir );
3482 
3483  if ( rmdir ( ctx_p->listoutdir ) )
3484  error ( "Cannot rmdir(\"%s\")", ctx_p->listoutdir );
3485 
3486  if ( rm_listoutdir == 2 )
3487  free ( ctx_p->listoutdir );
3488  }
3489 
3490  /*
3491  if (ctx_p->flags[PIVOT_ROOT] == PW_AUTO || ctx_p->flags[PIVOT_ROOT] == PW_AUTORO) {
3492  umount2("/", MNT_DETACH);
3493  // DELETE THE DIRECTORY
3494  }
3495  */
3496  main_cleanup ( ctx_p );
3497 
3498  if ( ctx_p->watchdirwslashsize )
3499  free ( ctx_p->watchdirwslash );
3500 
3501  if ( ctx_p->destdirwslashsize )
3502  free ( ctx_p->destdirwslash );
3503 
3504  if ( ctx_p->rulfpathsize )
3505  free ( ctx_p->rulfpath );
3506 
3507  error_deinit();
3508  ctx_cleanup ( ctx_p );
3509  debug ( 1, "finished, exitcode: %i: %s.", ret, strerror ( ret ) );
3510  free ( ctx_p );
3511 #ifndef __FreeBSD__ // Hanging up with 100%CPU eating, https://github.com/clsync/clsync/issues/97
3512  SAFE ( posixhacks_deinit(), errno = ret = _SAFE_rc );
3513 #endif
3514  return ret;
3515 }
3516 
3517 
IPCT_PRIVATE
@ IPCT_PRIVATE
Definition: error.h:60
X_STAT_FIELD_SIZE
@ X_STAT_FIELD_SIZE
Definition: main.c:207
SM_PROCESS
@ SM_PROCESS
Definition: common.h:126
CONFIGBLOCK
@ CONFIGBLOCK
Definition: ctx.h:50
config_block_parse
int config_block_parse(ctx_t *ctx_p, const char *const config_block_name)
Definition: main.c:2547
MODSIGN
@ MODSIGN
Definition: ctx.h:127
OPTION_CONFIGONLY
#define OPTION_CONFIGONLY
Definition: ctx.h:39
sync_run
__extension__ int sync_run(ctx_t *ctx_p)
Definition: sync.c:3998
CONFIGFILE
@ CONFIGFILE
Definition: ctx.h:49
ctx::config_block
const char * config_block
Definition: ctx.h:342
error_init
void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug)
Definition: error.c:356
xstrncpy
char * xstrncpy(char *dest, const char *src, size_t n)
Definition: malloc.c:94
UID
@ UID
Definition: ctx.h:52
SM_OFF
@ SM_OFF
Definition: common.h:124
DEBUG
@ DEBUG
Definition: ctx.h:71
FORGET_PRIVTHREAD_INFO
@ FORGET_PRIVTHREAD_INFO
Definition: ctx.h:120
CAPS_INHERIT
@ CAPS_INHERIT
Definition: ctx.h:113
DEFAULT_VERBOSE
#define DEFAULT_VERBOSE
Definition: configuration.h:98
ctx::watchdirsize
size_t watchdirsize
Definition: ctx.h:377
syscalls.h
main_status_update
int main_status_update(ctx_t *ctx_p)
Definition: main.c:2673
SOCKAUTH_UNSET
@ SOCKAUTH_UNSET
Definition: socket.h:200
X_STAT_FIELD_CTIME
@ X_STAT_FIELD_CTIME
Definition: main.c:212
SHM_MPROTECT
@ SHM_MPROTECT
Definition: ctx.h:126
TMPDIR_PATH
#define TMPDIR_PATH
Definition: configuration.h:152
child_sigchld
void child_sigchld()
Definition: main.c:430
syscall_bitmask
syscall_bitmask
Definition: ctx.h:308
ctx
Definition: ctx.h:315
QUEUE_LOCKWAIT
@ QUEUE_LOCKWAIT
Definition: ctx.h:176
DELAY
@ DELAY
Definition: ctx.h:67
notify_engines
static char *const notify_engines[]
Definition: main.c:330
cluster.h
X_STAT_FIELD_UID
@ X_STAT_FIELD_UID
Definition: main.c:204
DN_OFF
@ DN_OFF
Definition: ctx.h:138
str_splitargs
int str_splitargs(char *_instr, int(*handler)(char *, size_t, void *), void *arg)
Definition: stringex.c:75
DEFAULT_CLUSTERHDLMIN
#define DEFAULT_CLUSTERHDLMIN
Definition: configuration.h:93
QUEUE_BIGFILE
@ QUEUE_BIGFILE
Definition: ctx.h:174
SYNCTIMEOUT
@ SYNCTIMEOUT
Definition: ctx.h:80
DEFAULT_UID
#define DEFAULT_UID
Definition: configuration.h:192
EXITONSYNCSKIP
@ EXITONSYNCSKIP
Definition: ctx.h:129
MAXRULES
#define MAXRULES
Definition: configuration.h:10
STAT_FIELD_NLINK
@ STAT_FIELD_NLINK
Definition: ctx.h:294
PEF_UNEXPECTED_END
#define PEF_UNEXPECTED_END
Definition: main.c:671
ctx::socketmod
mode_t socketmod
Definition: ctx.h:361
close
close(fd_w)
ctx::destdir
char * destdir
Definition: ctx.h:350
ALLOC_PORTION
#define ALLOC_PORTION
Definition: configuration.h:117
main
int main(int _argc, char *_argv[])
Definition: main.c:2727
STAT_FIELD_MTIME
@ STAT_FIELD_MTIME
Definition: ctx.h:302
CAP_PRESERVE_TRY
#define CAP_PRESERVE_TRY
Definition: ctx.h:313
COLLECTDELAY_INSTANT
#define COLLECTDELAY_INSTANT
Definition: macros.h:47
X_STAT_FIELD_NLINK
@ X_STAT_FIELD_NLINK
Definition: main.c:203
SECURESPLITTING
@ SECURESPLITTING
Definition: ctx.h:121
CONFIGBLOCKINHERITS
@ CONFIGBLOCKINHERITS
Definition: ctx.h:103
CLUSTERSDLMAX
@ CLUSTERSDLMAX
Definition: ctx.h:95
modes
static char *const modes[]
Definition: main.c:349
ctx::bfilethreshold
size_t bfilethreshold
Definition: ctx.h:390
RSYNCPREFERINCLUDE
@ RSYNCPREFERINCLUDE
Definition: ctx.h:86
CLSYNC_API_VERSION
#define CLSYNC_API_VERSION
Definition: clsync.h:27
MAXARGUMENTS
#define MAXARGUMENTS
Definition: configuration.h:13
sync.h
SHFL_EXCLUDE_LIST_PATH
@ SHFL_EXCLUDE_LIST_PATH
Definition: ctx.h:240
VERSION_MID
#define VERSION_MID
Definition: program.h:22
ctx::pid_str_len
size_t pid_str_len
Definition: ctx.h:320
DETACH_IPC
@ DETACH_IPC
Definition: ctx.h:130
DEFAULT_SYNCHANDLER_ARGS_SHELL_NR
#define DEFAULT_SYNCHANDLER_ARGS_SHELL_NR
Definition: configuration.h:163
error_deinit
void error_deinit()
Definition: error.c:389
shargsid
shargsid
Definition: ctx.h:244
rule::mask
ruleaction_t mask
Definition: ctx.h:211
notifyengine_t
enum notifyengine_enum notifyengine_t
Definition: common.h:114
DEFAULT_DETACH_IPC
#define DEFAULT_DETACH_IPC
Definition: configuration.h:100
pivot_root
int pivot_root(const char *new_root, const char *old_root)
OUTPUT_METHOD
@ OUTPUT_METHOD
Definition: ctx.h:57
outputmethod
outputmethod
Definition: error.h:69
posixhacks_deinit
#define posixhacks_deinit()
Definition: posix-hacks.h:35
AUTORULESW
@ AUTORULESW
Definition: ctx.h:75
STATE_UNKNOWN
@ STATE_UNKNOWN
Definition: ctx.h:270
ctx::watchdirlen
size_t watchdirlen
Definition: ctx.h:375
IGNOREEXITCODE
@ IGNOREEXITCODE
Definition: ctx.h:77
STAT_FIELD_CTIME
@ STAT_FIELD_CTIME
Definition: ctx.h:303
ctx_set
int ctx_set(ctx_t *ctx_p, const char *const parameter_name, const char *const parameter_value)
Definition: main.c:2560
X_STAT_FIELD_MODE
@ X_STAT_FIELD_MODE
Definition: main.c:202
OPTION_LONGOPTONLY
#define OPTION_LONGOPTONLY
Definition: ctx.h:38
CONFIG_PATHS
#define CONFIG_PATHS
Definition: configuration.h:122
PRIVILEGEDUID
@ PRIVILEGEDUID
Definition: ctx.h:131
MODE_SHELL
@ MODE_SHELL
Definition: ctx.h:164
ctx::pidfile
char * pidfile
Definition: ctx.h:346
synchandler_args::v
char * v[MAXARGUMENTS]
Definition: ctx.h:251
rule::perm
ruleaction_t perm
Definition: ctx.h:210
MOUNTPOINTS
@ MOUNTPOINTS
Definition: ctx.h:109
OM_SYSLOG
@ OM_SYSLOG
Definition: error.h:72
parameter_get
const char * parameter_get(const char *variable_name, void *_ctx_p)
Gets raw (string) an option value by an option name.
Definition: main.c:565
MODE_SO
@ MODE_SO
Definition: ctx.h:168
ctx::flags_set
int flags_set[(1<< 10)]
Definition: ctx.h:339
version
int version()
Definition: main.c:484
SLEEP_SECONDS
#define SLEEP_SECONDS
Definition: configuration.h:113
PS_CONTROL
@ PS_CONTROL
Definition: common.h:96
NE_KQUEUE
@ NE_KQUEUE
Definition: common.h:108
xcsc_to_csc
uint32_t xcsc_to_csc[]
Definition: main.c:258
STANDBYFILE
@ STANDBYFILE
Definition: ctx.h:93
X_CSC_MON_STAT
@ X_CSC_MON_STAT
Definition: main.c:255
EXITONNOEVENTS
@ EXITONNOEVENTS
Definition: ctx.h:92
synchandler_args::c
int c
Definition: ctx.h:252
posix-hacks.h
DEFAULT_GROUP
#define DEFAULT_GROUP
Definition: configuration.h:191
fileutils.h
STAT_FIELD_BLKSIZE
@ STAT_FIELD_BLKSIZE
Definition: ctx.h:299
FORBIDDEVICES
@ FORBIDDEVICES
Definition: ctx.h:123
ctx::synchandler_argf
shflags_t synchandler_argf
Definition: ctx.h:416
DEFAULT_LABEL
#define DEFAULT_LABEL
Definition: configuration.h:87
ctx::destproto
char * destproto
Definition: ctx.h:351
X_STAT_FIELD_ATIME
@ X_STAT_FIELD_ATIME
Definition: main.c:210
stringex.h
CSC_RESET
@ CSC_RESET
Definition: ctx.h:309
DEFAULT_RSYNCINCLUDELINESLIMIT
#define DEFAULT_RSYNCINCLUDELINESLIMIT
Definition: configuration.h:88
STATUSFILE
@ STATUSFILE
Definition: ctx.h:89
STAT_FIELD_UID
@ STAT_FIELD_UID
Definition: ctx.h:295
info
#define info(...)
Definition: error.h:43
DETACH_MISCELLANEA
@ DETACH_MISCELLANEA
Definition: ctx.h:117
argv
char ** argv
Definition: main.c:2725
ctx::dump_path
char * dump_path
Definition: ctx.h:356
PEF_UNSET_VARIABLE
#define PEF_UNSET_VARIABLE
Definition: main.c:672
NE_BSM_PREFETCH
@ NE_BSM_PREFETCH
Definition: common.h:110
X_STAT_FIELD_MTIME
@ X_STAT_FIELD_MTIME
Definition: main.c:211
ctx::pid
pid_t pid
Definition: ctx.h:318
PRIVILEGEDGID
@ PRIVILEGEDGID
Definition: ctx.h:132
RSYNC_ARGS_E
#define RSYNC_ARGS_E
Definition: configuration.h:170
stat_fields
stat_fields
Definition: ctx.h:289
clsyncapi_getapiversion
int clsyncapi_getapiversion()
Returns currect API version.
Definition: main.c:550
QUEUE_INSTANT
@ QUEUE_INSTANT
Definition: ctx.h:175
ctx::flags
int flags[(1<< 10)]
Definition: ctx.h:338
SHFL_INCLUDE_LIST_PATH
@ SHFL_INCLUDE_LIST_PATH
Definition: ctx.h:239
X_STAT_FIELD_RESET
@ X_STAT_FIELD_RESET
Definition: main.c:199
STAT_FIELD_RESET
@ STAT_FIELD_RESET
Definition: ctx.h:290
NE_DTRACEPIPE
@ NE_DTRACEPIPE
Definition: common.h:111
AUTHOR
#define AUTHOR
Definition: program.h:24
state_t
enum state_enum state_t
Definition: ctx.h:272
clsync_cgroup_attach
int clsync_cgroup_attach(ctx_t *ctx_p)
Definition: cgroup.c:65
DEFAULT_PRESERVE_CAPABILITIES
#define DEFAULT_PRESERVE_CAPABILITIES
Definition: configuration.h:188
sync_parameter_get
const char * sync_parameter_get(const char *variable_name, void *_dosync_arg_p)
Definition: sync.c:1548
DEFAULT_CLUSTERTIMEOUT
#define DEFAULT_CLUSTERTIMEOUT
Definition: configuration.h:90
CAP_PRESERVE
@ CAP_PRESERVE
Definition: ctx.h:54
SYNCDELAY
@ SYNCDELAY
Definition: ctx.h:69
DEFAULT_RSYNC_PATH
#define DEFAULT_RSYNC_PATH
Definition: configuration.h:130
CSC_MON_STAT
@ CSC_MON_STAT
Definition: ctx.h:310
EXCLUDEMOUNTPOINTS
@ EXCLUDEMOUNTPOINTS
Definition: ctx.h:58
SOFTEXITSYNC
@ SOFTEXITSYNC
Definition: ctx.h:133
main_statusfile_f
FILE * main_statusfile_f
Definition: main.c:2672
ctx::rulfpathsize
size_t rulfpathsize
Definition: ctx.h:386
PW_AUTO
@ PW_AUTO
Definition: ctx.h:147
ctx::gid
gid_t gid
Definition: ctx.h:322
queueinfo::collectdelay
unsigned int collectdelay
Definition: ctx.h:216
xstatfield
xstatfield
Definition: main.c:198
ctx::rulfpath
char * rulfpath
Definition: ctx.h:385
becomedaemon
int becomedaemon()
Definition: main.c:2619
CLUSTERMCASTIPPORT
@ CLUSTERMCASTIPPORT
Definition: ctx.h:62
DEFAULT_SYNCHANDLER_ARGS_SHELL_R
#define DEFAULT_SYNCHANDLER_ARGS_SHELL_R
Definition: configuration.h:164
dosync_arg::excf_path
char excf_path[PATH_MAX+1]
Definition: common.h:162
X_STAT_FIELD_GID
@ X_STAT_FIELD_GID
Definition: main.c:205
DEFAULT_CP_PATH
#define DEFAULT_CP_PATH
Definition: configuration.h:129
SOCKETPATH
@ SOCKETPATH
Definition: ctx.h:46
CHECK_EXECVP_ARGS
@ CHECK_EXECVP_ARGS
Definition: ctx.h:114
MODE_RSYNCSO
@ MODE_RSYNCSO
Definition: ctx.h:167
DEFAULT_CLUSTERIPPORT
#define DEFAULT_CLUSTERIPPORT
Definition: configuration.h:92
CG_GROUPNAME
@ CG_GROUPNAME
Definition: ctx.h:124
ctx::flags_values_raw
char * flags_values_raw[(1<< 10)]
Definition: ctx.h:337
DEFAULT_SYNCTIMEOUT
#define DEFAULT_SYNCTIMEOUT
Definition: configuration.h:89
if
if(auditd_restart())
Definition: mon_bsm.c:262
ctx::synchandler_uid
uid_t synchandler_uid
Definition: ctx.h:325
PROGRAM
#define PROGRAM
Definition: program.h:20
CANCEL_SYSCALLS
@ CANCEL_SYSCALLS
Definition: ctx.h:128
PS_CONFIG
@ PS_CONFIG
Definition: common.h:95
MODE_UNSET
@ MODE_UNSET
Definition: ctx.h:161
ctx::socketgid
gid_t socketgid
Definition: ctx.h:363
ctx::customsignal
char * customsignal[MAXSIGNALNUM+1]
Definition: ctx.h:343
detachnetwork_way
detachnetwork_way
Definition: ctx.h:137
SYNCHANDLERUID
@ SYNCHANDLERUID
Definition: ctx.h:111
sethandler_sigchld
int sethandler_sigchld(void(*handler)())
Definition: main.c:440
ctx::synchandler_gid
gid_t synchandler_gid
Definition: ctx.h:326
parameter_expand
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....
Definition: main.c:693
DEFAULT_SYNCHANDLER_ARGS_SIMPLE
#define DEFAULT_SYNCHANDLER_ARGS_SIMPLE
Definition: configuration.h:161
PEF_NONE
#define PEF_NONE
Definition: main.c:670
syscalls_bitmask
static char *const syscalls_bitmask[]
Definition: main.c:263
detachnetwork_way_t
enum detachnetwork_way detachnetwork_way_t
Definition: ctx.h:142
DEFAULT_RULES_PERM
#define DEFAULT_RULES_PERM
Definition: configuration.h:82
dosync_arg::outf_path
char outf_path[PATH_MAX+1]
Definition: common.h:163
IPCT_SHARED
@ IPCT_SHARED
Definition: error.h:61
parameter_get_wmacro
const char * parameter_get_wmacro(const char *variable_name, void *_ctx_p)
Gets raw (string) an option value by an option name and updates ctx_p->synchandler_argf.
Definition: main.c:634
USER_LEN
#define USER_LEN
Definition: configuration.h:21
SOCKETOWN
@ SOCKETOWN
Definition: ctx.h:99
main_cleanup
int main_cleanup(ctx_t *ctx_p)
Definition: main.c:2642
xstrtol_trim
static long xstrtol_trim(char *str, int *err)
Definition: main.c:948
parse_parameter
static __extension__ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t paramsource)
Definition: main.c:1060
DEFAULT_CG_GROUPNAME
#define DEFAULT_CG_GROUPNAME
Definition: configuration.h:238
DEFAULT_CLUSTERSDLMAX
#define DEFAULT_CLUSTERSDLMAX
Definition: configuration.h:95
MODE_RSYNCSHELL
@ MODE_RSYNCSHELL
Definition: ctx.h:165
threadingmode_t
enum threadingmode threadingmode_t
Definition: common.h:121
IGNOREFAILURES
@ IGNOREFAILURES
Definition: ctx.h:101
STAT_FIELD_ATIME
@ STAT_FIELD_ATIME
Definition: ctx.h:301
ctx::pid_str
char pid_str[65]
Definition: ctx.h:319
PW_AUTORO
@ PW_AUTORO
Definition: ctx.h:148
memory_init
int memory_init()
Definition: malloc.c:177
X_CSC_RESET
@ X_CSC_RESET
Definition: main.c:254
CI_DONTTOUCH
@ CI_DONTTOUCH
Definition: ctx.h:153
X_STAT_FIELD_INO
@ X_STAT_FIELD_INO
Definition: main.c:201
CLUSTERHDLMIN
@ CLUSTERHDLMIN
Definition: ctx.h:65
ctx::retries
int retries
Definition: ctx.h:389
capsinherit_t
enum capsinherit capsinherit_t
Definition: ctx.h:158
NE_INOTIFY
@ NE_INOTIFY
Definition: common.h:107
SOCKAUTH_NULL
@ SOCKAUTH_NULL
Definition: socket.h:201
SYNCHANDLERGID
@ SYNCHANDLERGID
Definition: ctx.h:112
ctx::destdirwslashsize
size_t destdirwslashsize
Definition: ctx.h:380
STAT_FIELD_DEV
@ STAT_FIELD_DEV
Definition: ctx.h:291
DEFAULT_PIVOT_MODE
#define DEFAULT_PIVOT_MODE
Definition: configuration.h:195
CLUSTERTIMEOUT
@ CLUSTERTIMEOUT
Definition: ctx.h:63
SHARGS_INITIAL
@ SHARGS_INITIAL
Definition: ctx.h:246
configs_parse
int configs_parse(ctx_t *ctx_p, paramsource_t paramsource)
Definition: main.c:2083
MAXMOUNTPOINTS
#define MAXMOUNTPOINTS
Definition: configuration.h:36
error
#define error(...)
Definition: error.h:36
DN_NONPRIVILEGED
@ DN_NONPRIVILEGED
Definition: ctx.h:139
SOCKETMOD
@ SOCKETMOD
Definition: ctx.h:98
dosync_arg
Definition: common.h:160
ctx::label
char * label
Definition: ctx.h:344
argc
int argc
Definition: main.c:2724
CLUSTERIFACE
@ CLUSTERIFACE
Definition: ctx.h:60
ctx::synctimeout
unsigned int synctimeout
Definition: ctx.h:395
PS_DEFAULTS
@ PS_DEFAULTS
Definition: common.h:97
X_STAT_FIELD_RDEV
@ X_STAT_FIELD_RDEV
Definition: main.c:206
ctx::isignoredexitcode
char isignoredexitcode[(1<< 8)]
Definition: ctx.h:397
ctx::destdirsize
size_t destdirsize
Definition: ctx.h:378
parent_pid
pid_t parent_pid
Definition: main.c:386
error.h
ctx::destdirwslash
char * destdirwslash
Definition: ctx.h:353
DEFAULT_DUMPDIR
#define DEFAULT_DUMPDIR
Definition: configuration.h:99
MODE_SIMPLE
@ MODE_SIMPLE
Definition: ctx.h:162
MONITOR
@ MONITOR
Definition: ctx.h:104
LABEL
@ LABEL
Definition: ctx.h:81
RSYNC_ARGS_I
#define RSYNC_ARGS_I
Definition: configuration.h:180
ctx::handlerfpath
char * handlerfpath
Definition: ctx.h:382
OPTION_FLAGS
#define OPTION_FLAGS
Definition: ctx.h:37
NE_BSM
@ NE_BSM
Definition: common.h:109
DEFAULT_SYNCHANDLER_ARGS_DIRECT
#define DEFAULT_SYNCHANDLER_ARGS_DIRECT
Definition: configuration.h:162
STAT_FIELD_INO
@ STAT_FIELD_INO
Definition: ctx.h:292
malloc.h
ctx::config_path
char * config_path
Definition: ctx.h:341
DEFAULT_SYNCHANDLER_ARGS_RSHELL_I
#define DEFAULT_SYNCHANDLER_ARGS_RSHELL_I
Definition: configuration.h:168
DEFAULT_SYNCHANDLER_ARGS_RDIRECT_I
#define DEFAULT_SYNCHANDLER_ARGS_RDIRECT_I
Definition: configuration.h:166
MODE
@ MODE
Definition: ctx.h:76
gkf_parse
void gkf_parse(ctx_t *ctx_p, GKeyFile *gkf, paramsource_t paramsource)
Definition: main.c:2046
NE_FANOTIFY
@ NE_FANOTIFY
Definition: common.h:106
socketauth
static char *const socketauth[]
Definition: main.c:305
MODE_DIRECT
@ MODE_DIRECT
Definition: ctx.h:163
error_init_ipc
void error_init_ipc(ipc_type_t _ipc_type)
Definition: error.c:367
SPLITTING
@ SPLITTING
Definition: ctx.h:110
debug
#define debug(debug_level,...)
Definition: error.h:50
DN_EVERYWHERE
@ DN_EVERYWHERE
Definition: ctx.h:140
ctx::uid
uid_t uid
Definition: ctx.h:321
DEFAULT_CAPS_INHERIT
#define DEFAULT_CAPS_INHERIT
Definition: configuration.h:194
GID
@ GID
Definition: ctx.h:53
PIVOT_ROOT
@ PIVOT_ROOT
Definition: ctx.h:115
QUIET
@ QUIET
Definition: ctx.h:72
VERBOSE
@ VERBOSE
Definition: ctx.h:73
DONTUNLINK
@ DONTUNLINK
Definition: ctx.h:78
SAFE
#define SAFE(code, onfail)
Definition: macros.h:56
fork_helper
pid_t fork_helper()
Definition: main.c:463
parse_rules_fromfile
int parse_rules_fromfile(ctx_t *ctx_p)
Definition: rules.c:56
UGID_PRESERVE
#define UGID_PRESERVE
Definition: main.c:2726
ONLYINITSYNC
@ ONLYINITSYNC
Definition: ctx.h:91
RETRIES
@ RETRIES
Definition: ctx.h:56
STAT_FIELD_SIZE
@ STAT_FIELD_SIZE
Definition: ctx.h:298
SYNCHANDLERARGS0
@ SYNCHANDLERARGS0
Definition: ctx.h:105
ctx_cleanup
void ctx_cleanup(ctx_t *ctx_p)
Definition: main.c:2582
XTOSTR
#define XTOSTR(a)
Definition: macros.h:45
RSYNCINCLIMIT
@ RSYNCINCLIMIT
Definition: ctx.h:85
INITFULL
@ INITFULL
Definition: ctx.h:79
DEFAULT_CONFIG_BLOCK
#define DEFAULT_CONFIG_BLOCK
Definition: configuration.h:96
DEFAULT_USER
#define DEFAULT_USER
Definition: configuration.h:190
rules.h
ctx::watchdir_dirlevel
short int watchdir_dirlevel
Definition: ctx.h:381
critical
#define critical(...)
Definition: error.h:32
MAXSIGNALNUM
#define MAXSIGNALNUM
Definition: configuration.h:18
parent_isalive
int parent_isalive()
Definition: main.c:415
x_csc_bm
x_csc_bm
Definition: main.c:253
pivotroot_way_t
enum pivotroot_way pivotroot_way_t
Definition: ctx.h:150
HELP
@ HELP
Definition: ctx.h:48
CI_CLSYNC
@ CI_CLSYNC
Definition: ctx.h:155
ctx::rules
rule_t rules[MAXRULES]
Definition: ctx.h:333
RA_NONE
@ RA_NONE
Definition: ctx.h:190
ctx_check
int ctx_check(ctx_t *ctx_p)
Definition: main.c:2145
THREADING
@ THREADING
Definition: ctx.h:55
OM_STDOUT
@ OM_STDOUT
Definition: error.h:71
MODE_RSYNCDIRECT
@ MODE_RSYNCDIRECT
Definition: ctx.h:166
clsync_cgroup_forbid_extra_devices
__extension__ int clsync_cgroup_forbid_extra_devices()
Definition: cgroup.c:34
DEFAULT_RETRIES
#define DEFAULT_RETRIES
Definition: configuration.h:97
warning
#define warning(...)
Definition: error.h:40
parametersource_get_name
const char * parametersource_get_name(paramsource_t paramsource)
Gets the name of the parameter source by it's id.
Definition: main.c:852
PERMIT_MPROTECT
@ PERMIT_MPROTECT
Definition: ctx.h:125
X_STAT_FIELD_ALL
@ X_STAT_FIELD_ALL
Definition: main.c:213
PM_OFF
@ PM_OFF
Definition: common.h:117
ctx::_queues
queueinfo_t _queues[QUEUE_MAX]
Definition: ctx.h:392
output_methods
static char *const output_methods[]
Definition: main.c:342
PIDFILE
@ PIDFILE
Definition: ctx.h:59
NE_UNDEFINED
@ NE_UNDEFINED
Definition: common.h:105
SHFL_INCLUDE_LIST
@ SHFL_INCLUDE_LIST
Definition: ctx.h:238
SYNCHANDLERARGS1
@ SYNCHANDLERARGS1
Definition: ctx.h:106
common.h
WAITPID_TIMED_GRANULARITY
#define WAITPID_TIMED_GRANULARITY
Definition: configuration.h:242
PREEXITHOOK
@ PREEXITHOOK
Definition: ctx.h:96
ctx::chroot_dir
char * chroot_dir
Definition: ctx.h:401
waitpid_timed
pid_t waitpid_timed(pid_t child_pid, int *status_p, long sec, long nsec)
Definition: main.c:388
rule::expr
regex_t expr
Definition: ctx.h:208
ctx::watchdir
char * watchdir
Definition: ctx.h:345
CUSTOMSIGNALS
@ CUSTOMSIGNALS
Definition: ctx.h:107
STAT_FIELD_BLOCKS
@ STAT_FIELD_BLOCKS
Definition: ctx.h:300
CLUSTERHDLMAX
@ CLUSTERHDLMAX
Definition: ctx.h:66
DESTDIR
@ DESTDIR
Definition: ctx.h:45
ncpus
int ncpus
Definition: main.c:385
xstatfield_to_statfield
uint32_t xstatfield_to_statfield[]
Definition: main.c:216
DEFAULT_SYNCHANDLER_ARGS_RSHELL_E
#define DEFAULT_SYNCHANDLER_ARGS_RSHELL_E
Definition: configuration.h:167
pthread_watchforparent
pthread_t pthread_watchforparent
Definition: main.c:462
capsinherit
capsinherit
Definition: ctx.h:152
CLUSTERNODENAME
@ CLUSTERNODENAME
Definition: ctx.h:64
ctx::preexithookfile
char * preexithookfile
Definition: ctx.h:349
PM_SAFE
@ PM_SAFE
Definition: common.h:118
error_on
#define error_on(cond)
Definition: error.h:37
CLUSTERMCASTIPADDR
@ CLUSTERMCASTIPADDR
Definition: ctx.h:61
DEFAULT_COLLECTDELAY
#define DEFAULT_COLLECTDELAY
Definition: configuration.h:83
DEFAULT_CLUSTERHDLMAX
#define DEFAULT_CLUSTERHDLMAX
Definition: configuration.h:94
outputmethod_t
enum outputmethod outputmethod_t
Definition: error.h:76
ONEFILESYSTEM
@ ONEFILESYSTEM
Definition: ctx.h:88
clsync_cgroup_init
int clsync_cgroup_init(ctx_t *ctx_p)
Definition: cgroup.c:26
synchandler_arg0
static int synchandler_arg0(char *arg, size_t arg_len, void *_ctx_p)
Definition: main.c:921
STAT_FIELD_RDEV
@ STAT_FIELD_RDEV
Definition: ctx.h:297
ctx::listoutdir
char * listoutdir
Definition: ctx.h:387
PS_CORRECTION
@ PS_CORRECTION
Definition: common.h:99
socket.h
paramsource_t
enum paramsource_enum paramsource_t
Definition: common.h:101
OUTLISTSDIR
@ OUTLISTSDIR
Definition: ctx.h:74
stat64_t
struct stat64 stat64_t
Definition: port-hacks.h:65
ctx::statusfile
char * statusfile
Definition: ctx.h:354
status_descr
static char *const status_descr[]
Definition: ctx.h:274
BFILETHRESHOLD
@ BFILETHRESHOLD
Definition: ctx.h:70
PIVOT_AUTO_DIR
#define PIVOT_AUTO_DIR
Definition: configuration.h:151
ctx::exithookfile
char * exithookfile
Definition: ctx.h:348
synchandler_arg1
static int synchandler_arg1(char *arg, size_t arg_len, void *_ctx_p)
Definition: main.c:926
X_STAT_FIELD_BLKSIZE
@ X_STAT_FIELD_BLKSIZE
Definition: main.c:208
DEFAULT_CLUSTERIPADDR
#define DEFAULT_CLUSTERIPADDR
Definition: configuration.h:91
MAXPERMITTEDHOOKFILES
#define MAXPERMITTEDHOOKFILES
Definition: configuration.h:37
PEF_LAZY_SUBSTITUTION
#define PEF_LAZY_SUBSTITUTION
Definition: main.c:673
ctx::privileged_uid
uid_t privileged_uid
Definition: ctx.h:323
SHARGS_MAX
@ SHARGS_MAX
Definition: ctx.h:247
synchandler_args
Definition: ctx.h:250
fileutils_calcdirlevel
short int fileutils_calcdirlevel(const char *path)
Calculates directory level of a canonized path (actually it just counts "/"-s)
Definition: fileutils.c:138
SOCKETAUTH
@ SOCKETAUTH
Definition: ctx.h:97
SM_THREAD
@ SM_THREAD
Definition: common.h:125
ctx::destdirlen
size_t destdirlen
Definition: ctx.h:376
ctx::st_dev
dev_t st_dev
Definition: ctx.h:335
ctx::socketuid
uid_t socketuid
Definition: ctx.h:362
posixhacks_init
#define posixhacks_init()
Definition: posix-hacks.h:34
threadingmode
threadingmode
Definition: common.h:116
BFILEDELAY
@ BFILEDELAY
Definition: ctx.h:68
ctx::synchandler_args
synchandler_args_t synchandler_args[SHARGS_MAX]
Definition: ctx.h:415
NE_GIO
@ NE_GIO
Definition: common.h:112
watchforparent
void * watchforparent(void *parent_pid_p)
Definition: main.c:451
URL
#define URL
Definition: program.h:25
ctx::watchdirwslashsize
size_t watchdirwslashsize
Definition: ctx.h:379
long_options
static const struct option long_options[]
Definition: main.c:59
critical_on
#define critical_on(cond)
Definition: error.h:33
X_STAT_FIELD_BLOCKS
@ X_STAT_FIELD_BLOCKS
Definition: main.c:209
DEFAULT_SYNCHANDLER_ARGS_RDIRECT_E
#define DEFAULT_SYNCHANDLER_ARGS_RDIRECT_E
Definition: configuration.h:165
TMPDIR_TEMPLATE
#define TMPDIR_TEMPLATE
Definition: configuration.h:153
X_STAT_FIELD_DEV
@ X_STAT_FIELD_DEV
Definition: main.c:200
parameter_get_name_by_id
const char * parameter_get_name_by_id(const uint16_t param_id)
Gets the name of the parameter by it's id.
Definition: main.c:599
OM_STDERR
@ OM_STDERR
Definition: error.h:70
STATE_STARTING
@ STATE_STARTING
Definition: ctx.h:260
cgroup.h
synchandler_arg
static int synchandler_arg(char *arg, size_t arg_len, void *_ctx_p, enum shargsid shargsid)
Definition: main.c:877
STAT_FIELD_ALL
@ STAT_FIELD_ALL
Definition: ctx.h:305
DETACH_NETWORK
@ DETACH_NETWORK
Definition: ctx.h:116
EXITHOOK
@ EXITHOOK
Definition: ctx.h:94
STAT_FIELD_GID
@ STAT_FIELD_GID
Definition: ctx.h:296
SHFL_RSYNC_ARGS
@ SHFL_RSYNC_ARGS
Definition: ctx.h:237
xstrtol
static long xstrtol(const char *str, int *err)
Definition: main.c:932
PS_ARGUMENT
@ PS_ARGUMENT
Definition: common.h:94
synchandler_args::isexpanded
char isexpanded[MAXARGUMENTS]
Definition: ctx.h:253
exitcode
volatile int exitcode
Definition: sync.c:547
SKIPINITSYNC
@ SKIPINITSYNC
Definition: ctx.h:90
ctx::rsyncinclimit
unsigned int rsyncinclimit
Definition: ctx.h:393
MAXITERATIONS
@ MAXITERATIONS
Definition: ctx.h:100
syntax
int syntax()
Definition: main.c:361
HAVERECURSIVESYNC
@ HAVERECURSIVESYNC
Definition: ctx.h:84
DEFAULT_BFILETHRESHOLD
#define DEFAULT_BFILETHRESHOLD
Definition: configuration.h:85
FTS_EXPERIMENTAL_OPTIMIZATION
@ FTS_EXPERIMENTAL_OPTIMIZATION
Definition: ctx.h:122
arguments_parse
int arguments_parse(int argc, char *argv[], struct ctx *ctx_p)
Definition: main.c:1988
STAT_FIELD_MODE
@ STAT_FIELD_MODE
Definition: ctx.h:293
ctx::standbyfile
char * standbyfile
Definition: ctx.h:347
DEFAULT_SYNCDELAY
#define DEFAULT_SYNCDELAY
Definition: configuration.h:84
SYNCLISTSIMPLIFY
@ SYNCLISTSIMPLIFY
Definition: ctx.h:87
SECCOMP_FILTER
@ SECCOMP_FILTER
Definition: ctx.h:119
PM_FULL
@ PM_FULL
Definition: common.h:119
ADDPERMITTEDHOOKFILES
@ ADDPERMITTEDHOOKFILES
Definition: ctx.h:118
BACKGROUND
@ BACKGROUND
Definition: ctx.h:51
PW_DIRECT
@ PW_DIRECT
Definition: ctx.h:146
SYNCHANDLER
@ SYNCHANDLER
Definition: ctx.h:43
SHOW_VERSION
@ SHOW_VERSION
Definition: ctx.h:82
DEFAULT_BFILECOLLECTDELAY
#define DEFAULT_BFILECOLLECTDELAY
Definition: configuration.h:86
ctx::watchdirwslash
char * watchdirwslash
Definition: ctx.h:352
GROUP_LEN
#define GROUP_LEN
Definition: configuration.h:22
WATCHDIR
@ WATCHDIR
Definition: ctx.h:42
ctx::state
volatile state_t state
Definition: ctx.h:317
SHARGS_PRIMARY
@ SHARGS_PRIMARY
Definition: ctx.h:245
PS_UNKNOWN
@ PS_UNKNOWN
Definition: common.h:93
DEFAULT_GID
#define DEFAULT_GID
Definition: configuration.h:193
PW_OFF
@ PW_OFF
Definition: ctx.h:145
parse_customsignals
static __extension__ int parse_customsignals(ctx_t *ctx_p, char *arg)
Definition: main.c:968
RULESFILE
@ RULESFILE
Definition: ctx.h:44
ctx::socketpath
char * socketpath
Definition: ctx.h:355
DUMPDIR
@ DUMPDIR
Definition: ctx.h:102
QUEUE_NORMAL
@ QUEUE_NORMAL
Definition: ctx.h:173
ctx::privileged_gid
gid_t privileged_gid
Definition: ctx.h:324
CHROOT
@ CHROOT
Definition: ctx.h:108
CI_EMPTY
@ CI_EMPTY
Definition: ctx.h:156
VERSION_MAJ
#define VERSION_MAJ
Definition: program.h:21
VERSION_MIN
#define VERSION_MIN
Definition: program.h:23
ctx::syncdelay
unsigned int syncdelay
Definition: ctx.h:391
ctx_p
ctx_t * ctx_p
Definition: mon_kqueue.c:85
CI_PERMITTED
@ CI_PERMITTED
Definition: ctx.h:154
main_rehash
int main_rehash(ctx_t *ctx_p)
Definition: main.c:2653
splittingmode_t
enum splittingmode_enum splittingmode_t
Definition: common.h:128