clsync
Loading...
Searching...
No Matches
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
59static 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
180static 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
189static 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
215
233
234static 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
257
258uint32_t xcsc_to_csc[] = {
261};
262
263static 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
271enum 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};
286static 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
296static 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
305static char *const socketauth[] = {
306 [SOCKAUTH_UNSET] = "",
307 [SOCKAUTH_NULL] = "null",
308// [SOCKAUTH_PAM] = "pam",
309 NULL
310};
311
312#ifdef THREADING_SUPPORT
313static 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
322static char *const splitting_modes[] = {
323 [SM_OFF] = "off",
324 [SM_THREAD] = "thread",
325 [SM_PROCESS] = "process",
326 NULL
327};
328#endif
329
330static 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
342static char *const output_methods[] = {
343 [OM_STDERR] = "stderr",
344 [OM_STDOUT] = "stdout",
345 [OM_SYSLOG] = "syslog",
346 NULL
347};
348
349static 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
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
386pid_t parent_pid = 0;
387
388pid_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
440int 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__
451void *watchforparent ( void *parent_pid_p )
452{
453 while ( 1 ) {
455 sleep ( SLEEP_SECONDS );
456 }
457
458 return NULL;
459}
460# endif
461
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
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"
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 */
565const 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 */
599const 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 */
634const 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 */
852const 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
877static 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
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
921static 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
926static 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 */
932static 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
948static 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
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: {
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 ) {
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
1988int 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
2046void 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
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
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
2218 ret = errno = EINVAL;
2219 error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--only-initialsync\"." );
2220 }
2221
2223 ret = errno = EINVAL;
2224 error ( "Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--exit-on-no-events\"." );
2225 }
2226
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
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
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
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 )
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
2547int 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
2560int 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
2725char **argv;
2726#define UGID_PRESERVE (1<<16)
2727int 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:
2823 break;
2824
2825 case MODE_DIRECT:
2827 break;
2828
2829 case MODE_SHELL:
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 ) {
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 ) {
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 ) {
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
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
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
int clsync_cgroup_attach(ctx_t *ctx_p)
Definition cgroup.c:65
int clsync_cgroup_init(ctx_t *ctx_p)
Definition cgroup.c:26
__extension__ int clsync_cgroup_forbid_extra_devices()
Definition cgroup.c:34
#define CLSYNC_API_VERSION
Definition clsync.h:27
@ NE_UNDEFINED
Definition common.h:105
@ NE_INOTIFY
Definition common.h:107
@ NE_FANOTIFY
Definition common.h:106
@ NE_KQUEUE
Definition common.h:108
@ NE_GIO
Definition common.h:112
@ NE_BSM_PREFETCH
Definition common.h:110
@ NE_DTRACEPIPE
Definition common.h:111
@ NE_BSM
Definition common.h:109
@ SM_PROCESS
Definition common.h:126
@ SM_OFF
Definition common.h:124
@ SM_THREAD
Definition common.h:125
enum splittingmode_enum splittingmode_t
Definition common.h:128
enum paramsource_enum paramsource_t
Definition common.h:101
enum threadingmode threadingmode_t
Definition common.h:121
@ PS_UNKNOWN
Definition common.h:93
@ PS_CONTROL
Definition common.h:96
@ PS_DEFAULTS
Definition common.h:97
@ PS_ARGUMENT
Definition common.h:94
@ PS_CORRECTION
Definition common.h:99
@ PS_CONFIG
Definition common.h:95
threadingmode
Definition common.h:116
@ PM_SAFE
Definition common.h:118
@ PM_OFF
Definition common.h:117
@ PM_FULL
Definition common.h:119
enum notifyengine_enum notifyengine_t
Definition common.h:114
#define DEFAULT_UID
#define DEFAULT_LABEL
#define DEFAULT_RETRIES
#define DEFAULT_SYNCHANDLER_ARGS_RDIRECT_E
#define DEFAULT_BFILECOLLECTDELAY
#define MAXARGUMENTS
#define PIVOT_AUTO_DIR
#define DEFAULT_GID
#define DEFAULT_SYNCHANDLER_ARGS_SHELL_R
#define DEFAULT_PIVOT_MODE
#define DEFAULT_DUMPDIR
#define RSYNC_ARGS_E
#define DEFAULT_GROUP
#define DEFAULT_SYNCHANDLER_ARGS_SIMPLE
#define DEFAULT_VERBOSE
#define DEFAULT_DETACH_IPC
#define DEFAULT_SYNCDELAY
#define MAXSIGNALNUM
#define DEFAULT_USER
#define MAXMOUNTPOINTS
#define MAXRULES
#define WAITPID_TIMED_GRANULARITY
#define DEFAULT_CLUSTERIPPORT
#define CONFIG_PATHS
#define TMPDIR_TEMPLATE
#define DEFAULT_CP_PATH
#define DEFAULT_CLUSTERHDLMIN
#define DEFAULT_BFILETHRESHOLD
#define DEFAULT_COLLECTDELAY
#define DEFAULT_PRESERVE_CAPABILITIES
#define SLEEP_SECONDS
#define DEFAULT_CLUSTERSDLMAX
#define DEFAULT_RULES_PERM
#define DEFAULT_CLUSTERTIMEOUT
#define DEFAULT_CLUSTERHDLMAX
#define DEFAULT_RSYNC_PATH
#define MAXPERMITTEDHOOKFILES
#define DEFAULT_SYNCHANDLER_ARGS_DIRECT
#define DEFAULT_SYNCHANDLER_ARGS_RSHELL_I
#define DEFAULT_CG_GROUPNAME
#define DEFAULT_SYNCHANDLER_ARGS_RDIRECT_I
#define DEFAULT_SYNCHANDLER_ARGS_SHELL_NR
#define TMPDIR_PATH
#define DEFAULT_CLUSTERIPADDR
#define GROUP_LEN
#define DEFAULT_SYNCTIMEOUT
#define DEFAULT_SYNCHANDLER_ARGS_RSHELL_E
#define USER_LEN
#define DEFAULT_RSYNCINCLUDELINESLIMIT
#define RSYNC_ARGS_I
#define DEFAULT_CONFIG_BLOCK
#define DEFAULT_CAPS_INHERIT
#define ALLOC_PORTION
#define CAP_PRESERVE_TRY
Definition ctx.h:313
@ QUEUE_NORMAL
Definition ctx.h:173
@ QUEUE_LOCKWAIT
Definition ctx.h:176
@ QUEUE_INSTANT
Definition ctx.h:175
@ QUEUE_BIGFILE
Definition ctx.h:174
@ SOCKETAUTH
Definition ctx.h:97
@ CLUSTERIFACE
Definition ctx.h:60
@ SYNCHANDLERARGS1
Definition ctx.h:106
@ SECURESPLITTING
Definition ctx.h:121
@ DEBUG
Definition ctx.h:71
@ SYNCDELAY
Definition ctx.h:69
@ CLUSTERMCASTIPADDR
Definition ctx.h:61
@ SYNCHANDLERUID
Definition ctx.h:111
@ LABEL
Definition ctx.h:81
@ CLUSTERMCASTIPPORT
Definition ctx.h:62
@ MOUNTPOINTS
Definition ctx.h:109
@ SOCKETOWN
Definition ctx.h:99
@ INITFULL
Definition ctx.h:79
@ STANDBYFILE
Definition ctx.h:93
@ RSYNCPREFERINCLUDE
Definition ctx.h:86
@ CLUSTERTIMEOUT
Definition ctx.h:63
@ AUTORULESW
Definition ctx.h:75
@ DELAY
Definition ctx.h:67
@ HAVERECURSIVESYNC
Definition ctx.h:84
@ SYNCLISTSIMPLIFY
Definition ctx.h:87
@ DONTUNLINK
Definition ctx.h:78
@ ONEFILESYSTEM
Definition ctx.h:88
@ BFILEDELAY
Definition ctx.h:68
@ SYNCHANDLER
Definition ctx.h:43
@ GID
Definition ctx.h:53
@ CLUSTERHDLMIN
Definition ctx.h:65
@ SOCKETPATH
Definition ctx.h:46
@ CANCEL_SYSCALLS
Definition ctx.h:128
@ SYNCHANDLERARGS0
Definition ctx.h:105
@ SYNCTIMEOUT
Definition ctx.h:80
@ FORGET_PRIVTHREAD_INFO
Definition ctx.h:120
@ PERMIT_MPROTECT
Definition ctx.h:125
@ UID
Definition ctx.h:52
@ PRIVILEGEDUID
Definition ctx.h:131
@ SOCKETMOD
Definition ctx.h:98
@ OUTPUT_METHOD
Definition ctx.h:57
@ QUIET
Definition ctx.h:72
@ MAXITERATIONS
Definition ctx.h:100
@ CUSTOMSIGNALS
Definition ctx.h:107
@ CLUSTERNODENAME
Definition ctx.h:64
@ EXITONSYNCSKIP
Definition ctx.h:129
@ SKIPINITSYNC
Definition ctx.h:90
@ SECCOMP_FILTER
Definition ctx.h:119
@ SHM_MPROTECT
Definition ctx.h:126
@ FORBIDDEVICES
Definition ctx.h:123
@ PRIVILEGEDGID
Definition ctx.h:132
@ CONFIGBLOCK
Definition ctx.h:50
@ BFILETHRESHOLD
Definition ctx.h:70
@ DETACH_NETWORK
Definition ctx.h:116
@ RETRIES
Definition ctx.h:56
@ CHECK_EXECVP_ARGS
Definition ctx.h:114
@ CG_GROUPNAME
Definition ctx.h:124
@ MODE
Definition ctx.h:76
@ CLUSTERSDLMAX
Definition ctx.h:95
@ DETACH_MISCELLANEA
Definition ctx.h:117
@ RULESFILE
Definition ctx.h:44
@ MONITOR
Definition ctx.h:104
@ RSYNCINCLIMIT
Definition ctx.h:85
@ PIVOT_ROOT
Definition ctx.h:115
@ MODSIGN
Definition ctx.h:127
@ SHOW_VERSION
Definition ctx.h:82
@ CLUSTERHDLMAX
Definition ctx.h:66
@ EXITHOOK
Definition ctx.h:94
@ HELP
Definition ctx.h:48
@ THREADING
Definition ctx.h:55
@ BACKGROUND
Definition ctx.h:51
@ CAP_PRESERVE
Definition ctx.h:54
@ CAPS_INHERIT
Definition ctx.h:113
@ PIDFILE
Definition ctx.h:59
@ DESTDIR
Definition ctx.h:45
@ WATCHDIR
Definition ctx.h:42
@ CHROOT
Definition ctx.h:108
@ DETACH_IPC
Definition ctx.h:130
@ FTS_EXPERIMENTAL_OPTIMIZATION
Definition ctx.h:122
@ VERBOSE
Definition ctx.h:73
@ IGNOREFAILURES
Definition ctx.h:101
@ ONLYINITSYNC
Definition ctx.h:91
@ CONFIGBLOCKINHERITS
Definition ctx.h:103
@ EXCLUDEMOUNTPOINTS
Definition ctx.h:58
@ DUMPDIR
Definition ctx.h:102
@ SYNCHANDLERGID
Definition ctx.h:112
@ OUTLISTSDIR
Definition ctx.h:74
@ EXITONNOEVENTS
Definition ctx.h:92
@ STATUSFILE
Definition ctx.h:89
@ CONFIGFILE
Definition ctx.h:49
@ SPLITTING
Definition ctx.h:110
@ ADDPERMITTEDHOOKFILES
Definition ctx.h:118
@ PREEXITHOOK
Definition ctx.h:96
@ IGNOREEXITCODE
Definition ctx.h:77
@ SOFTEXITSYNC
Definition ctx.h:133
enum state_enum state_t
Definition ctx.h:272
@ MODE_RSYNCSHELL
Definition ctx.h:165
@ MODE_DIRECT
Definition ctx.h:163
@ MODE_RSYNCSO
Definition ctx.h:167
@ MODE_SIMPLE
Definition ctx.h:162
@ MODE_UNSET
Definition ctx.h:161
@ MODE_RSYNCDIRECT
Definition ctx.h:166
@ MODE_SO
Definition ctx.h:168
@ MODE_SHELL
Definition ctx.h:164
enum pivotroot_way pivotroot_way_t
Definition ctx.h:150
enum detachnetwork_way detachnetwork_way_t
Definition ctx.h:142
#define STATE_STARTING(state_p)
Definition ctx.h:257
shargsid
Definition ctx.h:244
@ SHARGS_PRIMARY
Definition ctx.h:245
@ SHARGS_INITIAL
Definition ctx.h:246
@ SHARGS_MAX
Definition ctx.h:247
static char *const status_descr[]
Definition ctx.h:274
syscall_bitmask
Definition ctx.h:308
@ CSC_MON_STAT
Definition ctx.h:310
@ CSC_RESET
Definition ctx.h:309
@ SHFL_EXCLUDE_LIST_PATH
Definition ctx.h:240
@ SHFL_RSYNC_ARGS
Definition ctx.h:237
@ SHFL_INCLUDE_LIST_PATH
Definition ctx.h:239
@ SHFL_INCLUDE_LIST
Definition ctx.h:238
enum capsinherit capsinherit_t
Definition ctx.h:158
capsinherit
Definition ctx.h:152
@ CI_CLSYNC
Definition ctx.h:155
@ CI_DONTTOUCH
Definition ctx.h:153
@ CI_EMPTY
Definition ctx.h:156
@ CI_PERMITTED
Definition ctx.h:154
stat_fields
Definition ctx.h:289
@ STAT_FIELD_RDEV
Definition ctx.h:297
@ STAT_FIELD_ATIME
Definition ctx.h:301
@ STAT_FIELD_INO
Definition ctx.h:292
@ STAT_FIELD_CTIME
Definition ctx.h:303
@ STAT_FIELD_BLOCKS
Definition ctx.h:300
@ STAT_FIELD_NLINK
Definition ctx.h:294
@ STAT_FIELD_RESET
Definition ctx.h:290
@ STAT_FIELD_SIZE
Definition ctx.h:298
@ STAT_FIELD_MTIME
Definition ctx.h:302
@ STAT_FIELD_GID
Definition ctx.h:296
@ STAT_FIELD_UID
Definition ctx.h:295
@ STAT_FIELD_MODE
Definition ctx.h:293
@ STAT_FIELD_DEV
Definition ctx.h:291
@ STAT_FIELD_BLKSIZE
Definition ctx.h:299
@ STAT_FIELD_ALL
Definition ctx.h:305
@ RA_NONE
Definition ctx.h:190
@ PW_AUTO
Definition ctx.h:147
@ PW_OFF
Definition ctx.h:145
@ PW_AUTORO
Definition ctx.h:148
@ PW_DIRECT
Definition ctx.h:146
detachnetwork_way
Definition ctx.h:137
@ DN_NONPRIVILEGED
Definition ctx.h:139
@ DN_EVERYWHERE
Definition ctx.h:140
@ DN_OFF
Definition ctx.h:138
#define OPTION_FLAGS
Definition ctx.h:37
#define OPTION_LONGOPTONLY
Definition ctx.h:38
@ STATE_UNKNOWN
Definition ctx.h:270
#define OPTION_CONFIGONLY
Definition ctx.h:39
void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug)
Definition error.c:356
void error_init_ipc(ipc_type_t _ipc_type)
Definition error.c:367
void error_deinit()
Definition error.c:389
#define critical(...)
Definition error.h:32
#define error(...)
Definition error.h:36
#define debug(debug_level,...)
Definition error.h:50
outputmethod
Definition error.h:69
@ OM_STDOUT
Definition error.h:71
@ OM_STDERR
Definition error.h:70
@ OM_SYSLOG
Definition error.h:72
#define info(...)
Definition error.h:43
#define warning(...)
Definition error.h:40
@ IPCT_SHARED
Definition error.h:61
@ IPCT_PRIVATE
Definition error.h:60
#define critical_on(cond)
Definition error.h:33
enum outputmethod outputmethod_t
Definition error.h:76
#define error_on(cond)
Definition error.h:37
short int fileutils_calcdirlevel(const char *path)
Calculates directory level of a canonized path (actually it just counts "/"-s)
Definition fileutils.c:138
int main()
#define XTOSTR(a)
Definition macros.h:45
#define COLLECTDELAY_INSTANT
Definition macros.h:47
#define SAFE(code, onfail)
Definition macros.h:56
pid_t fork_helper()
Definition main.c:463
#define PEF_UNSET_VARIABLE
Definition main.c:672
void child_sigchld()
Definition main.c:430
int arguments_parse(int argc, char *argv[], struct ctx *ctx_p)
Definition main.c:1988
int ctx_set(ctx_t *ctx_p, const char *const parameter_name, const char *const parameter_value)
Definition main.c:2560
#define PEF_NONE
Definition main.c:670
static int synchandler_arg0(char *arg, size_t arg_len, void *_ctx_p)
Definition main.c:921
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
static int synchandler_arg1(char *arg, size_t arg_len, void *_ctx_p)
Definition main.c:926
static __extension__ int parse_customsignals(ctx_t *ctx_p, char *arg)
Definition main.c:968
int ctx_check(ctx_t *ctx_p)
Definition main.c:2145
#define UGID_PRESERVE
Definition main.c:2726
uint32_t xstatfield_to_statfield[]
Definition main.c:216
#define PEF_UNEXPECTED_END
Definition main.c:671
int ncpus
Definition main.c:385
#define PEF_LAZY_SUBSTITUTION
Definition main.c:673
int config_block_parse(ctx_t *ctx_p, const char *const config_block_name)
Definition main.c:2547
static char *const notify_engines[]
Definition main.c:330
void gkf_parse(ctx_t *ctx_p, GKeyFile *gkf, paramsource_t paramsource)
Definition main.c:2046
int becomedaemon()
Definition main.c:2619
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
static int synchandler_arg(char *arg, size_t arg_len, void *_ctx_p, enum shargsid shargsid)
Definition main.c:877
FILE * main_statusfile_f
Definition main.c:2672
static long xstrtol(const char *str, int *err)
Definition main.c:932
void * watchforparent(void *parent_pid_p)
Definition main.c:451
uint32_t xcsc_to_csc[]
Definition main.c:258
int clsyncapi_getapiversion()
Returns currect API version.
Definition main.c:550
pthread_t pthread_watchforparent
Definition main.c:462
int configs_parse(ctx_t *ctx_p, paramsource_t paramsource)
Definition main.c:2083
pid_t parent_pid
Definition main.c:386
static long xstrtol_trim(char *str, int *err)
Definition main.c:948
int parent_isalive()
Definition main.c:415
int syntax()
Definition main.c:361
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
pid_t waitpid_timed(pid_t child_pid, int *status_p, long sec, long nsec)
Definition main.c:388
static char *const socketauth[]
Definition main.c:305
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
static const struct option long_options[]
Definition main.c:59
int main_cleanup(ctx_t *ctx_p)
Definition main.c:2642
xstatfield
Definition main.c:198
@ X_STAT_FIELD_INO
Definition main.c:201
@ X_STAT_FIELD_MTIME
Definition main.c:211
@ X_STAT_FIELD_DEV
Definition main.c:200
@ X_STAT_FIELD_SIZE
Definition main.c:207
@ X_STAT_FIELD_CTIME
Definition main.c:212
@ X_STAT_FIELD_UID
Definition main.c:204
@ X_STAT_FIELD_ATIME
Definition main.c:210
@ X_STAT_FIELD_RESET
Definition main.c:199
@ X_STAT_FIELD_GID
Definition main.c:205
@ X_STAT_FIELD_BLKSIZE
Definition main.c:208
@ X_STAT_FIELD_RDEV
Definition main.c:206
@ X_STAT_FIELD_ALL
Definition main.c:213
@ X_STAT_FIELD_NLINK
Definition main.c:203
@ X_STAT_FIELD_MODE
Definition main.c:202
@ X_STAT_FIELD_BLOCKS
Definition main.c:209
static char *const output_methods[]
Definition main.c:342
x_csc_bm
Definition main.c:253
@ X_CSC_MON_STAT
Definition main.c:255
@ X_CSC_RESET
Definition main.c:254
int argc
Definition main.c:2724
int main_status_update(ctx_t *ctx_p)
Definition main.c:2673
int main_rehash(ctx_t *ctx_p)
Definition main.c:2653
void ctx_cleanup(ctx_t *ctx_p)
Definition main.c:2582
static char *const syscalls_bitmask[]
Definition main.c:263
int version()
Definition main.c:484
static char *const modes[]
Definition main.c:349
const char * parametersource_get_name(paramsource_t paramsource)
Gets the name of the parameter source by it's id.
Definition main.c:852
int sethandler_sigchld(void(*handler)())
Definition main.c:440
char ** argv
Definition main.c:2725
static __extension__ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t paramsource)
Definition main.c:1060
int memory_init()
Definition malloc.c:177
char * xstrncpy(char *dest, const char *src, size_t n)
Definition malloc.c:94
ctx_t * ctx_p
Definition mon_kqueue.c:85
struct stat64 stat64_t
Definition port-hacks.h:65
#define posixhacks_deinit()
Definition posix-hacks.h:35
#define posixhacks_init()
Definition posix-hacks.h:34
#define VERSION_MID
Definition program.h:22
#define VERSION_MIN
Definition program.h:23
#define URL
Definition program.h:25
#define AUTHOR
Definition program.h:24
#define PROGRAM
Definition program.h:20
#define VERSION_MAJ
Definition program.h:21
int parse_rules_fromfile(ctx_t *ctx_p)
Definition rules.c:56
@ SOCKAUTH_UNSET
Definition socket.h:200
@ SOCKAUTH_NULL
Definition socket.h:201
int str_splitargs(char *_instr, int(*handler)(char *, size_t, void *), void *arg)
Definition stringex.c:75
Definition ctx.h:315
char * listoutdir
Definition ctx.h:387
size_t destdirwslashsize
Definition ctx.h:380
size_t pid_str_len
Definition ctx.h:320
int flags_set[(1<< 10)]
Definition ctx.h:339
char * statusfile
Definition ctx.h:354
unsigned int syncdelay
Definition ctx.h:391
char * handlerfpath
Definition ctx.h:382
size_t destdirsize
Definition ctx.h:378
char * flags_values_raw[(1<< 10)]
Definition ctx.h:337
size_t watchdirsize
Definition ctx.h:377
size_t rulfpathsize
Definition ctx.h:386
int retries
Definition ctx.h:389
char * preexithookfile
Definition ctx.h:349
char * watchdirwslash
Definition ctx.h:352
char * destdir
Definition ctx.h:350
char * pidfile
Definition ctx.h:346
shflags_t synchandler_argf
Definition ctx.h:416
short int watchdir_dirlevel
Definition ctx.h:381
size_t bfilethreshold
Definition ctx.h:390
char * exithookfile
Definition ctx.h:348
mode_t socketmod
Definition ctx.h:361
char * destdirwslash
Definition ctx.h:353
uid_t socketuid
Definition ctx.h:362
gid_t synchandler_gid
Definition ctx.h:326
char * chroot_dir
Definition ctx.h:401
pid_t pid
Definition ctx.h:318
const char * config_block
Definition ctx.h:342
char * socketpath
Definition ctx.h:355
char * label
Definition ctx.h:344
char * watchdir
Definition ctx.h:345
uid_t uid
Definition ctx.h:321
char * config_path
Definition ctx.h:341
dev_t st_dev
Definition ctx.h:335
unsigned int synctimeout
Definition ctx.h:395
gid_t socketgid
Definition ctx.h:363
queueinfo_t _queues[QUEUE_MAX]
Definition ctx.h:392
volatile state_t state
Definition ctx.h:317
char pid_str[65]
Definition ctx.h:319
size_t watchdirwslashsize
Definition ctx.h:379
uid_t synchandler_uid
Definition ctx.h:325
char * dump_path
Definition ctx.h:356
char * standbyfile
Definition ctx.h:347
int flags[(1<< 10)]
Definition ctx.h:338
unsigned int rsyncinclimit
Definition ctx.h:393
size_t watchdirlen
Definition ctx.h:375
gid_t privileged_gid
Definition ctx.h:324
char * rulfpath
Definition ctx.h:385
char * customsignal[MAXSIGNALNUM+1]
Definition ctx.h:343
size_t destdirlen
Definition ctx.h:376
synchandler_args_t synchandler_args[SHARGS_MAX]
Definition ctx.h:415
rule_t rules[MAXRULES]
Definition ctx.h:333
char * destproto
Definition ctx.h:351
uid_t privileged_uid
Definition ctx.h:323
gid_t gid
Definition ctx.h:322
char isignoredexitcode[(1<< 8)]
Definition ctx.h:397
char excf_path[PATH_MAX+1]
Definition common.h:162
char outf_path[PATH_MAX+1]
Definition common.h:163
unsigned int collectdelay
Definition ctx.h:216
ruleaction_t perm
Definition ctx.h:210
ruleaction_t mask
Definition ctx.h:211
regex_t expr
Definition ctx.h:208
char isexpanded[MAXARGUMENTS]
Definition ctx.h:253
char * v[MAXARGUMENTS]
Definition ctx.h:251
const char * sync_parameter_get(const char *variable_name, void *_dosync_arg_p)
Definition sync.c:1548
volatile int exitcode
Definition sync.c:547
__extension__ int sync_run(ctx_t *ctx_p)
Definition sync.c:3998
int pivot_root(const char *new_root, const char *old_root)