23 #ifdef CAPABILITIES_SUPPORT
24 # include <sys/capability.h>
26 #if defined(__linux__) | defined(CAPABILITIES_SUPPORT)
27 # include <sys/prctl.h>
35 #ifdef UNSHARE_SUPPORT
38 #ifdef GETMNTENT_SUPPORT
40 # include <sys/mount.h>
60 {
"watch-dir", required_argument, NULL,
WATCHDIR},
61 {
"sync-handler", required_argument, NULL,
SYNCHANDLER},
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},
73 {
"background", optional_argument, NULL,
BACKGROUND},
74 {
"config-file", required_argument, NULL,
CONFIGFILE},
75 {
"config-block", required_argument, NULL,
CONFIGBLOCK},
78 {
"pid-file", required_argument, NULL,
PIDFILE},
79 {
"uid", required_argument, NULL,
UID},
80 {
"gid", required_argument, NULL,
GID},
85 {
"chroot", required_argument, NULL,
CHROOT},
86 #ifdef PIVOTROOT_OPT_SUPPORT
87 {
"pivot-root", required_argument, NULL,
PIVOT_ROOT},
89 #ifdef UNSHARE_SUPPORT
91 {
"detach-ipc", required_argument, NULL,
DETACH_IPC},
94 #ifdef CAPABILITIES_SUPPORT
95 # ifdef SECCOMP_SUPPORT
98 {
"splitting", required_argument, NULL,
SPLITTING},
101 # ifdef SECCOMP_SUPPORT
106 {
"shm-mprotect", optional_argument, NULL,
SHM_MPROTECT},
108 #ifdef UNSHARE_SUPPORT
109 # ifdef GETMNTENT_SUPPORT
110 {
"mountpoints", required_argument, NULL,
MOUNTPOINTS},
113 #ifdef CAPABILITIES_SUPPORT
114 {
"preserve-capabilities", required_argument, NULL,
CAP_PRESERVE},
115 {
"inherit-capabilities", optional_argument, NULL,
CAPS_INHERIT},
117 #ifdef CGROUP_SUPPORT
119 {
"cgroup-group-name", required_argument, NULL,
CG_GROUPNAME},
121 #ifdef THREADING_SUPPORT
122 {
"threading", required_argument, NULL,
THREADING},
124 {
"retries", required_argument, NULL,
RETRIES},
126 {
"exit-on-sync-skipping", optional_argument, NULL,
EXITONSYNCSKIP},
130 #ifdef CLUSTER_SUPPORT
131 {
"cluster-iface", required_argument, NULL,
CLUSTERIFACE},
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},
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},
149 {
"lists-dir", required_argument, NULL,
OUTLISTSDIR},
153 {
"auto-add-rules-w", optional_argument, NULL,
AUTORULESW},
158 {
"dont-unlink-lists", optional_argument, NULL,
DONTUNLINK},
160 {
"full-initialsync", optional_argument, NULL,
INITFULL},
161 {
"only-initialsync", optional_argument, NULL,
ONLYINITSYNC},
162 {
"skip-initialsync", optional_argument, NULL,
SKIPINITSYNC},
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},
179 #ifdef UNSHARE_SUPPORT
180 static char *
const detachnetworkways[] = {
188 #ifdef PIVOTROOT_OPT_SUPPORT
189 static char *
const pivotrootways[] = {
269 #ifdef CAPABILITIES_SUPPORT
271 enum x_capabilities {
273 X_CAP_DAC_READ_SEARCH,
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,
286 static char *
const capabilities[] = {
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",
294 #define XCAP_TO_CAP(x) (xcap_to_cap[x])
296 static char *
const capsinherits[] = {
312 #ifdef THREADING_SUPPORT
313 static char *
const threading_modes[] = {
321 #ifdef CAPABILITIES_SUPPORT
322 static char *
const splitting_modes[] = {
363 info (
"possible options:" );
379 (
long_options[i].has_arg == required_argument ?
" argument" :
"" ) );
395 while ( ts.tv_sec >= 0 ) {
396 if ( waitpid ( child_pid, &status, WNOHANG ) < 0 ) {
397 if ( errno == ECHILD )
401 }
else if ( status_p != NULL )
406 if ( ts.tv_nsec < 0 ) {
407 ts.tv_nsec += 1000 * 1000 * 1000;
421 if ( errno == ESRCH ) {
422 debug ( 1,
"kill(%u, 0) => %i; errno => %s",
parent_pid, rc, strerror ( errno ) );
432 if ( getppid() != 1 )
435 debug ( 1,
"Got SIGCHLD (parent ended). Exit." );
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 );
473 prctl ( PR_SET_PDEATHSIG, SIGCHLD );
487 #ifdef _DEBUG_SUPPORT
493 #ifdef KQUEUE_SUPPORT
496 #ifdef INOTIFY_SUPPORT
502 #ifdef FANOTIFY_SUPPORT
503 " -DFANOTIFY_SUPPORT"
511 #ifdef DTRACEPIPE_SUPPORT
512 " -DDTRACEPIPE_SUPPORT"
514 #ifdef BACKTRACE_SUPPORT
515 " -DBACKTRACE_SUPPORT"
517 #ifdef CAPABILITIES_SUPPORT
518 " -DCAPABILITIES_SUPPORT"
520 #ifdef SECCOMP_SUPPORT
523 #ifdef GETMNTENT_SUPPORT
524 " -DGETMNTENT_SUPPORT"
526 #ifdef UNSHARE_SUPPORT
529 #ifdef PIVOTROOT_OPT_SUPPORT
530 " -DPIVOTROOT_OPT_SUPPORT"
532 #ifdef CGROUP_SUPPORT
538 #ifdef THREADING_SUPPORT
539 " -DTHREADING_SUPPORT"
570 debug ( 8,
"(\"%s\", %p)", variable_name,
ctx_p );
572 while ( long_option_p->name != NULL ) {
573 if ( !strcmp ( long_option_p->name, variable_name ) ) {
574 param_id = long_option_p->val;
581 if ( param_id == -1 ) {
602 const char *param_name = NULL;
603 debug ( 8,
"(%u)", param_id );
605 while ( long_option_p->name != NULL ) {
606 if ( long_option_p->val == param_id ) {
607 param_name = long_option_p->name;
614 if ( param_name == NULL ) {
619 debug ( 9,
"param: %u -> \"%s\"", param_id, param_name );
638 debug ( 9,
"(\"%s\", %p)", variable_name, _ctx_p );
640 if ( *variable_name < 'A' || *variable_name >
'Z' )
643 if ( !strcmp ( variable_name,
"RSYNC-ARGS" ) ) {
648 if ( !strcmp ( variable_name,
"INCLUDE-LIST" ) ) {
671 #define PEF_UNEXPECTED_END 1
672 #define PEF_UNSET_VARIABLE 2
673 #define PEF_LAZY_SUBSTITUTION 4
699 const char * ( *
parameter_get ) (
const char *variable_name,
void *arg ),
700 void *parameter_get_arg
703 debug ( 9,
"(ctx_p, \"%s\" [%p], ...)", arg, arg );
705 size_t ret_size = 0, ret_len = 0;
715 if ( macro_count_p != NULL )
718 if ( expand_count_p != NULL )
721 char *ptr = &arg[-1];
729 debug ( 3,
"Expanding value \"%s\" to \"%s\" (case #1)", arg, arg );
734 debug ( 3,
"Expanding value \"%s\" to \"%s\" (case #0)", arg, ret );
739 if ( ptr[1] ==
'%' ) {
740 ret[ret_len++] = * ( ptr++ );
744 debug ( 25,
"A macro" );
745 char nest_searching = 1;
746 char *ptr_nest = ptr;
748 while ( nest_searching ) {
751 switch ( *ptr_nest ) {
756 warning (
"Unexpected end of macro-substitution \"%s\" in value \"%s\"; result value is \"%s\"", ptr, arg, ret );
763 const char *variable_value;
764 size_t variable_value_len;
766 if ( macro_count_p != NULL )
767 ( *macro_count_p )++;
771 variable_name = &ptr[1];
772 debug ( 15,
"The macro is \"%s\"", variable_name );
774 if ( !strcmp ( variable_name,
"PID" ) ) {
775 debug ( 35,
"\"PID\"", variable_name );
784 }
else if ( *variable_name >=
'A' && *variable_name <=
'Z' && ( exceptionflags &
PEF_LAZY_SUBSTITUTION ) ) {
785 debug ( 35,
"Lazy substitution", variable_name );
786 variable_value = ptr;
787 variable_value_len = ( ptr_nest - ptr + 1 );
790 debug ( 35,
"Substitution", variable_name );
792 variable_value =
parameter_get ( variable_name, parameter_get_arg );
794 if ( variable_value == NULL ) {
796 warning (
"Variable \"%s\" is not set (%s)", variable_name, strerror ( errno ) );
803 variable_value_len = strlen ( variable_value );
805 if ( expand_count_p != NULL )
806 ( *expand_count_p )++;
811 if ( ret_len + variable_value_len + 1 >= ret_size ) {
813 ret = xrealloc ( ret, ret_size );
816 memcpy ( &ret[ret_len], variable_value, variable_value_len );
817 ret_len += variable_value_len;
828 if ( ret_len + 2 >= ret_size ) {
830 ret = xrealloc ( ret, ret_size );
833 ret[ret_len++] = *ptr;
839 error (
"Unknown internal error" );
854 switch ( paramsource ) {
856 return "unknown_case_0";
859 return "cli_arguments";
874 return "unknown_case_1";
880 debug ( 9,
"(\"%s\" [%p], %u, %p, %u)", arg, arg, arg_len, _ctx_p,
shargsid );
882 if ( !strcmp ( arg,
"%RSYNC-ARGS%" ) ) {
887 while ( *args_p != NULL ) {
890 if ( !strcmp ( *args_p,
"%RSYNC-ARGS%" ) ) {
892 critical (
"Infinite recursion detected" );
908 error (
"There're too many sync-handler arguments "
932 static inline long xstrtol (
const char *str,
int *err )
937 res = strtol ( str, &endptr, 0 );
939 if ( errno || *endptr ) {
940 error (
"argument \"%s\" can't be parsed as a number", str );
951 while ( *str ==
' ' || *str ==
'\t' || *str ==
'\r' || *str ==
'\n' ) str++;
956 while ( *end !=
'\0' ) end++;
960 while ( *end ==
' ' || *end ==
'\t' || *end ==
'\r' || *end ==
'\n' ) end--;
970 char *ptr = arg, *start = arg;
981 signal = (
unsigned int ) atoi ( start );
1002 fprintf ( stderr,
"Force-Debug: parse_parameter(): Reset custom signals.\n" );
1005 if ( *ptr !=
':' ) {
1009 error (
"Expected \":\" in \"%s\"", start );
1019 while ( *end && *end !=
',' ) end++;
1023 error (
"Empty config block name on signal \"%u\"", signal );
1038 fprintf ( stderr,
"Force-Debug: parse_parameter(): Adding custom signal %u.\n", signal );
1052 error (
"Expected a digit, comma (or colon) but got \"%c\"", *ptr );
1055 }
while ( * ( ptr++ ) );
1064 fprintf ( stderr,
"Force-Debug: parse_parameter(): %i: %i = \"%s\"\n", paramsource, param_id, arg );
1067 switch ( paramsource ) {
1088 error (
"Parameter #%i is already set. No need in setting the default value.", param_id );
1105 debug ( 9,
"Correcting setting %i -> \"%s\"", param_id, arg );
1109 error (
"Unknown parameter #%i source (value \"%s\").", param_id, arg != NULL ? arg :
"" );
1113 if ( ( arg != NULL ) ) {
1123 switch ( param_id ) {
1142 warning (
"Cannot change \"custom-signal\" in run-time. Ignoring." );
1152 struct passwd *pwd = getpwnam ( arg );
1155 if ( pwd == NULL ) {
1165 struct group *grp = getgrnam ( arg );
1168 if ( grp == NULL ) {
1177 #ifdef CAPABILITIES_SUPPORT
1178 # ifdef SECCOMP_SUPPORT
1197 char *value, *arg_orig = arg;
1204 splittingmode_t splittingmode = getsubopt ( &arg, splitting_modes, &value );
1206 if ( (
int ) splittingmode == -1 ) {
1208 error (
"Invalid splitting mode entered: \"%s\"", arg_orig );
1217 switch ( splittingmode ) {
1227 error (
"Cannot understand \"--secure-splitting=off\". This configuration line have no sence." );
1240 char *subopts = arg;
1243 while ( *subopts != 0 ) {
1245 __u32 cap = getsubopt ( &subopts, capabilities, &value );
1246 debug ( 4,
"cap == 0x%x", cap );
1248 if ( cap != X_CAP_RESET )
1249 ctx_p->caps |= CAP_TO_MASK ( XCAP_TO_CAP ( cap ) );
1256 char *value, *arg_orig = arg;
1267 error (
"Invalid capabilities inheriting mode entered: \"%s\"", arg_orig );
1278 struct passwd *pwd = getpwnam ( arg );
1281 if ( pwd == NULL ) {
1293 struct group *grp = getgrnam ( arg );
1296 if ( grp == NULL ) {
1308 struct passwd *pwd = getpwnam ( arg );
1311 if ( pwd == NULL ) {
1323 struct group *grp = getgrnam ( arg );
1326 if ( grp == NULL ) {
1339 warning (
"Cannot change \"chroot\" in run-time. Ignoring." );
1351 #ifdef PIVOTROOT_OPT_SUPPORT
1354 char *value, *arg_orig = arg;
1363 if ( (
int ) pivotway == -1 ) {
1365 error (
"Invalid pivot_root use way entered: \"%s\"", arg_orig );
1374 #ifdef UNSHARE_SUPPORT
1377 char *value, *arg_orig = arg;
1388 error (
"Invalid network detach way entered: \"%s\"", arg_orig );
1397 #ifdef CAPABILITIES_SUPPORT
1403 warning (
"Cannot change \"add-permitted-hook-files\" in run-time. Ignoring." );
1407 while (
ctx_p->permitted_hookfiles )
1408 free (
ctx_p->permitted_hookfile[--
ctx_p->permitted_hookfiles] );
1413 char *end = strchr ( ptr,
',' );
1419 while (
ctx_p->permitted_hookfiles )
1420 free (
ctx_p->permitted_hookfile[--
ctx_p->permitted_hookfiles] );
1430 error (
"Too many permitted hook files" );
1434 ctx_p->permitted_hookfile[
ctx_p->permitted_hookfiles++] = strdup ( ptr );
1447 #ifdef UNSHARE_SUPPORT
1448 # ifdef GETMNTENT_SUPPORT
1454 warning (
"Cannot change \"mountpoints\" in run-time. Ignoring." );
1458 while (
ctx_p->mountpoints )
1459 free (
ctx_p->mountpoint[--
ctx_p->mountpoints] );
1467 char *end = strchr ( ptr,
',' );
1473 while (
ctx_p->mountpoints )
1474 free (
ctx_p->mountpoint[--
ctx_p->mountpoints] );
1484 error (
"Too many mountpoints" );
1488 ctx_p->mountpoint[
ctx_p->mountpoints++] = strdup ( ptr );
1505 warning (
"Cannot change \"pid-file\" in run-time. Ignoring." );
1515 #ifdef THREADING_SUPPORT
1518 char *value, *arg_orig = arg;
1529 error (
"Invalid threading mode entered: \"%s\"", arg_orig );
1540 char *value, *arg_orig = arg;
1551 error (
"Invalid log writing destination entered: \"%s\"", arg_orig );
1559 #ifdef CLUSTER_SUPPORT
1562 ctx_p->cluster_iface = arg;
1566 ctx_p->cluster_mcastipaddr = arg;
1578 ctx_p->cluster_nodename = arg;
1601 #ifdef CGROUP_SUPPORT
1604 ctx_p->cg_groupname = arg;
1609 if ( strlen ( arg ) ) {
1620 char *subopts = arg;
1623 while ( *subopts != 0 ) {
1653 char *subopts = arg;
1655 while ( *subopts != 0 ) {
1672 char *value, *arg_orig = arg;
1675 warning (
"Cannot change \"monitor\" in run-time. Ignoring." );
1686 if ( (
int ) notifyengine == -1 ) {
1688 error (
"Invalid FS monitor subsystem entered: \"%s\"", arg_orig );
1692 switch ( notifyengine ) {
1693 #ifdef FANOTIFY_SUPPORT
1697 #ifdef INOTIFY_SUPPORT
1700 #ifdef KQUEUE_SUPPORT
1710 #ifdef DTRACEPIPE_SUPPORT
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 );
1733 if ( strlen ( arg ) ) {
1744 if ( strlen ( arg ) ) {
1755 char *ptr = arg, *start = arg;
1763 exitcode = (
unsigned char ) atoi ( start );
1773 fprintf ( stderr,
"Force-Debug: parse_parameter(): Reset ignored exitcodes.\n" );
1778 fprintf ( stderr,
"Force-Debug: parse_parameter(): Adding ignored exitcode %u.\n",
exitcode );
1790 error (
"Expected a digit or comma but got \"%c\"", *ptr );
1793 }
while ( * ( ptr++ ) );
1804 warning (
"Cannot change \"watch-dir\" in run-time. Ignoring." );
1820 char *sep = strstr ( arg,
"://" );
1829 if ( sep == NULL ) {
1830 char *at_ptr = strchr ( arg,
'@' );
1831 char *cl_ptr = strchr ( arg,
':' );
1833 if ( at_ptr != NULL && cl_ptr != NULL && at_ptr < cl_ptr ) {
1844 while ( ptr < sep ) {
1845 if ( *ptr < 'a' || *ptr >
'z' )
1852 size_t len = ( ptr - arg ) + 1;
1873 error (
"Wrong socket auth mech entered: \"%s\"", arg );
1879 if ( !sscanf ( arg,
"%o", (
unsigned int * ) &
ctx_p->
socketmod ) ) {
1880 error (
"Non octal value passed to --socket-mod: \"%s\"", arg );
1888 char *colon = strchr ( arg,
':' );
1892 if ( colon == NULL ) {
1893 struct passwd *pwent = getpwnam ( arg );
1895 if ( pwent == NULL ) {
1896 error (
"Cannot find username \"%s\" (case #0)",
1901 uid = pwent->pw_uid;
1902 gid = pwent->pw_gid;
1905 memcpy ( user, arg, MIN (
USER_LEN, colon - arg ) );
1906 user[colon - arg] = 0;
1909 struct passwd *pwent = getpwnam ( user );
1911 if ( pwent == NULL ) {
1912 error (
"Cannot find username \"%s\" (case #1)",
1918 struct group *grent = getgrnam ( group );
1920 if ( grent == NULL ) {
1921 error (
"Cannot find group \"%s\"",
1926 uid = pwent->pw_uid;
1927 gid = grent->gr_gid;
1933 debug ( 2,
"socket: uid == %u; gid == %u", uid, gid );
1950 error (
"Wrong mode name entered: \"%s\"", arg );
1972 fprintf ( stderr,
"Force-Debug: flag %i is set to %i\n", param_id & 0xff,
ctx_p->
flags[param_id] );
1978 if ( arg == NULL ) {
1991 int option_index = 0;
1993 char *optstring = alloca ( ( (
'z' -
'a' + 1 ) * 3 +
'9' -
'0' + 1 ) * 3 + 1 );
1994 char *optstring_ptr = optstring;
1997 while ( lo_ptr->name != NULL ) {
1999 * ( optstring_ptr++ ) = lo_ptr->val & 0xff;
2001 if ( lo_ptr->has_arg == required_argument )
2002 * ( optstring_ptr++ ) =
':';
2004 if ( lo_ptr->has_arg == optional_argument ) {
2005 * ( optstring_ptr++ ) =
':';
2006 * ( optstring_ptr++ ) =
':';
2015 fprintf ( stderr,
"Force-Debug: %s\n", optstring );
2022 if ( c == -1 )
break;
2026 if ( ret )
return ret;
2029 if ( optind <
argc ) {
2033 free ( args_p->
v[--args_p->
c] );
2035 if ( ( optind + 1 !=
argc ) || ( *
argv[optind] ) ) {
2039 }
while ( optind <
argc );
2051 while ( config_block != NULL ) {
2059 while ( lo_ptr->name != NULL ) {
2060 gchar *value = g_key_file_get_value ( gkf, config_block, lo_ptr->name, NULL );
2062 if ( value != NULL ) {
2065 if ( ret ) exit ( ret );
2072 free ( config_block );
2076 if ( config_block != NULL )
2077 debug ( 2,
"Next block is: %s", config_block );
2086 gkf = g_key_file_new();
2089 GError *g_error = NULL;
2092 debug ( 2,
"Empty path to config file. Don't read any of config files." );
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 );
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 ) );
2111 while ( *config_path_p != NULL ) {
2112 size_t config_path_len = strlen ( *config_path_p );
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 );
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 );
2124 memcpy ( config_path_real, *config_path_p, config_path_len + 1 );
2126 debug ( 1,
"Trying config-file \"%s\" (case #1)", config_path_real );
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 );
2138 free ( config_path_real );
2141 g_key_file_free ( gkf );
2148 #ifdef CLUSTER_SUPPORT
2149 struct utsname utsname;
2151 #ifndef _DEBUG_SUPPORT
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" );
2161 #ifndef ENABLE_SOCKET
2163 error (
"clsync is compiled without control socket support, option \"--socket\" cannot be used." );
2171 ret = errno = EINVAL;
2172 error (
"\"--socket-own\" is useless without \"--socket\"" );
2176 ret = errno = EINVAL;
2177 error (
"\"--socket-mod\" is useless without \"--socket\"" );
2181 ret = errno = EINVAL;
2182 error (
"\"--socket-auth\" is useless without \"--socket\"" );
2185 #ifdef PIVOTROOT_OPT_SUPPORT
2188 ret = errno = EINVAL;
2189 error (
"\"--pivot-root\" cannot be used without \"--chroot\"" );
2192 # ifdef UNSHARE_SUPPORT
2193 # ifdef GETMNTENT_SUPPORT
2196 warning (
"\"--mountpoints\" is set while \"--pivot-root\" is set, too" );
2203 ret = errno = EINVAL;
2204 error (
"Sorry but option \"--standby-file\" cannot be used in mode \"simple\", yet." );
2207 #ifdef THREADING_SUPPORT
2208 # ifdef VERYPARANOID
2211 ret = errno = EINVAL;
2212 error (
"\"--retries\" values should be equal to \"1\" for this \"--threading\" value." );
2218 ret = errno = EINVAL;
2219 error (
"Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--only-initialsync\"." );
2223 ret = errno = EINVAL;
2224 error (
"Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--exit-on-no-events\"." );
2228 ret = errno = EINVAL;
2229 error (
"Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--max-iterations\"." );
2233 ret = errno = EINVAL;
2234 error (
"Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--pre-exit-hook\"." );
2238 ret = errno = EINVAL;
2239 error (
"Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--splitting=thread\"." );
2242 # ifdef SECCOMP_SUPPORT
2245 ret = errno = EINVAL;
2246 error (
"Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--seccomp-filter\"." );
2253 ret = errno = EINVAL;
2254 error (
"Conflicting options: \"--skip-initialsync\" and \"--exit-on-no-events\" cannot be used together." );
2258 ret = errno = EINVAL;
2259 error (
"Conflicting options: \"--only-initialsync\" and \"--exit-on-no-events\" cannot be used together." );
2263 ret = errno = EINVAL;
2264 error (
"Conflicting options: \"--skip-initialsync\" and \"--only-initialsync\" cannot be used together." );
2268 ret = errno = EINVAL;
2269 error (
"Conflicting options: \"--full-initialsync\" and \"--skip-initialsync\" cannot be used together." );
2273 ret = errno = EINVAL;
2274 error (
"Conflicting options: \"--modification-signature\" and \"--cancel-syscalls=mon_stat\" cannot be used together." );
2281 ret = errno = EINVAL;
2282 error (
"\"--mode\" is not set." );
2286 ret = errno = EINVAL;
2287 error (
"\"--watch-dir\" is not set." );
2301 ret = errno = EINVAL;
2302 error (
"\"--sync-handler\" path is not set." );
2320 ret = errno = EINVAL;
2321 error (
"Mode \"rsyncdirect\" cannot be used without specifying \"--destination-dir\"." );
2324 #ifdef CLUSTER_SUPPORT
2327 ret = errno = EINVAL;
2328 error (
"Mode \"rsyncdirect\" cannot be used in conjunction with \"--cluster-iface\"." );
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\"." );
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\"." );
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\"." );
2346 if ( !
ctx_p->cluster_timeout )
2349 if ( !
ctx_p->cluster_mcastipport )
2352 if ( !
ctx_p->cluster_mcastipaddr )
2355 if (
ctx_p->cluster_iface != NULL ) {
2356 #ifndef _DEBUG_FORCE
2357 ret = errno = EINVAL;
2358 error (
"Cluster subsystem is not implemented, yet. Sorry." );
2361 if (
ctx_p->cluster_nodename == NULL ) {
2362 if ( !uname ( &utsname ) )
2363 ctx_p->cluster_nodename = strdup ( utsname.nodename );
2365 debug ( 1,
"cluster node name is: %s",
ctx_p->cluster_nodename );
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()." );
2372 ctx_p->cluster_nodename_len = strlen (
ctx_p->cluster_nodename );
2376 #endif // CLUSTER_SUPPORT
2393 warning (
"Option \"--rsyncpreferinclude\" is useless if mode is not \"rsyncdirect\", \"rsyncshell\" or \"rsyncso\"." );
2405 warning (
"Option \"--auto-add-rules-w\" in modes \"rsyncdirect\", \"rsyncshell\" and \"rsyncso\" may cause unexpected problems." );
2424 ret = errno = EINVAL;
2425 error (
"Option \"--have-recursive-sync\" with nodes \"rsyncdirect\", \"rsyncshell\" and \"rsyncso\" are incompatible." );
2429 ret = errno = EINVAL;
2430 error (
"Option \"--dir-lists\" should be set to use option \"--synclist-simplify\"." );
2441 ret = errno = EINVAL;
2442 error (
"Option \"--synclist-simplify\" with nodes \"rsyncdirect\" and \"rsyncshell\" are incompatible." );
2446 # ifdef SECCOMP_SUPPORT
2449 ret = errno = EINVAL;
2450 error (
"GIO is not compatible with seccomp filter (\"--monitor=gio\" and \"--seccomp-filter\" are incompatible)" );
2455 #ifdef FANOTIFY_SUPPORT
2458 critical (
"fanotify is not supported, now!" );
2462 #ifdef INOTIFY_SUPPORT
2466 #ifdef FANOTIFY_SUPPORT
2469 #ifdef KQUEUE_SUPPORT
2479 #ifdef DTRACEPIPE_SUPPORT
2485 ret = errno = EINVAL;
2486 char monitor_types[] =
2487 #ifdef INOTIFY_SUPPORT
2488 " \"--monitor=inotify\""
2490 #ifdef FANOTIFY_SUPPORT
2491 " \"--monitor=fanotify\""
2493 #ifdef KQUEUE_SUPPORT
2494 " \"--monitor=kqueue\""
2497 " \"--monitor=bsm\""
2500 " \"--monitor=gio\""
2502 #ifdef DTRACEPIPE_SUPPORT
2503 " \"--monitor=dtracepipe\""
2506 error (
"Required one of the next options: %s", monitor_types );
2514 ret = errno = EINVAL;
2515 error (
"ctx_p->exithookfile == NULL" );
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)." );
2550 debug ( 1,
"(ctx_p, \"%s\")", config_block_name );
2565 while ( lo_ptr->name != NULL ) {
2566 if ( !strcmp ( lo_ptr->name, parameter_name ) ) {
2577 critical (
"Cannot continue with this setup" );
2622 signal ( SIGPIPE, SIG_IGN );
2624 switch ( ( pid = fork() ) ) {
2626 error (
"Cannot fork()." );
2634 debug ( 1,
"fork()-ed, pid is %i.", pid );
2663 error (
"Got error from parse_rules_fromfile()." );
2677 debug ( 4,
"%u", state );
2679 if ( state == state_old ) {
2680 debug ( 3,
"State unchanged: %u == %u", state, state_old );
2687 error (
"status_descr[%u] == NULL.", state );
2702 error (
"Cannot ftruncate() the file \"%s\".",
2710 error (
"Cannot write to file \"%s\".",
2716 error (
"Cannot fflush() on file \"%s\".",
2726 #define UGID_PRESERVE (1<<16)
2727 int main (
int _argc,
char *_argv[] )
2732 int ret = 0, nret, rm_listoutdir = 0;
2743 #ifdef CLUSTER_SUPPORT
2751 #ifdef PIVOTROOT_OPT_SUPPORT
2754 #ifdef CAPABILITIES_SUPPORT
2760 ncpus = sysconf ( _SC_NPROCESSORS_ONLN );
2777 if ( nret ) ret = nret;
2782 if ( nret ) ret = nret;
2785 debug ( 5,
"after arguments_parse(): uid == %d, gid == %d, privileged_uid == %d, privileged_gid == %d, synchandler_uid == %d, synchandler_gid == %d",
2800 debug ( 4,
"uid == %d, gid == %d, privileged_uid == %d, privileged_gid == %d, synchandler_uid == %d, synchandler_gid == %d",
2803 #ifdef CGROUP_SUPPORT
2805 if (
ctx_p->cg_groupname == NULL ) {
2818 char *args_line0 = NULL, *args_line1 = NULL;
2846 if ( args_line0 != NULL ) {
2847 char *args_line = strdup ( args_line0 );
2851 if ( args_line1 != NULL ) {
2852 char *args_line = strdup ( args_line1 );
2863 if ( rwatchdir == NULL ) {
2868 debug ( 5,
"rwatchdir == \"%s\"", rwatchdir );
2942 ret = errno = EINVAL;
2943 error (
"Very-Paranoid: --watch-dir is supposed to be not \"/\"." );
2956 char *newwatchdir = xmalloc ( size );
2969 if ( rdestdir == NULL ) {
2974 debug ( 5,
"rdestdir == \"%s\"", rdestdir );
2982 ret = errno = EINVAL;
2983 error (
"destdir is supposed to be not \"/\"." );
2989 char *newdestdir = xmalloc ( size );
3003 error (
"Cannot find rules-file. Got error while realpath(\"%s\")",
ctx_p->
rulfpath );
3019 if ( rhandlerfpath != NULL )
3042 debug ( 9,
"Custom arguments %u count: %u", n - 1, args_p->
c );
3045 while ( i < args_p->c ) {
3046 int macros_count = -1, expanded = -1;
3048 debug ( 12,
"args_p->v[%u] == \"%s\" (t: %u; e: %u)", i, args_p->
v[i], macros_count, expanded );
3050 if ( macros_count == expanded )
3059 #ifdef UNSHARE_SUPPORT
3060 # ifdef GETMNTENT_SUPPORT
3065 if (
ctx_p->mountpoints ) {
3067 ent_f = setmntent (
"/proc/mounts",
"r" );
3069 if ( ent_f == NULL ) {
3070 error (
"Got error while setmntent(\"/proc/mounts\", \"r\")" );
3076 # define unshare_wrapper(a) \
3078 error("Got error from unshare("TOSTR(a)")");\
3083 unshare ( CLONE_NEWUTS );
3088 unshare ( CLONE_NEWIPC );
3089 unshare ( CLONE_NEWUTS );
3090 unshare ( CLONE_SYSVSEM );
3094 unshare_wrapper ( CLONE_FILES );
3095 unshare_wrapper ( CLONE_FS );
3096 unshare_wrapper ( CLONE_NEWNS );
3100 unshare_wrapper ( CLONE_NEWNET );
3102 # undef unshare_wrapper
3106 #ifdef PIVOTROOT_OPT_SUPPORT
3120 if ( mkdir (
"old_root", 0700 ) ) {
3121 if ( errno != EEXIST ) {
3122 error (
"Got error from mkdir(\"old_root\", 0700)" );
3129 if ( errno != EEXIST ) {
3136 unsigned long mount_flags = MS_BIND | MS_REC |
3140 error (
"Got error while mount(\"%s\", \"%s\", NULL, %o, NULL)",
3160 #ifdef UNSHARE_SUPPORT
3161 # ifdef GETMNTENT_SUPPORT
3163 if (
ctx_p->mountpoints && ( ent_f != NULL ) ) {
3165 while ( NULL != ( ent = getmntent ( ent_f ) ) ) {
3167 debug ( 8,
"Checking should \"%s\" be umount or not", ent->mnt_dir );
3170 while ( i < ctx_p->mountpoints ) {
3171 debug ( 9,
"\"%s\" <?> \"%s\"", ent->mnt_dir,
ctx_p->mountpoint[i] );
3173 if ( !strcmp ( ent->mnt_dir,
ctx_p->mountpoint[i] ) ) {
3174 debug ( 9,
"found" );
3181 if ( i >=
ctx_p->mountpoints ) {
3182 debug ( 1,
"umount2(\"%s\", MNT_DETACH)", ent->mnt_dir );
3184 if ( umount2 ( ent->mnt_dir, MNT_DETACH ) && errno != ENOENT && errno != EINVAL ) {
3185 error (
"Got error while umount2(\"%s\", MNT_DETACH)", ent->mnt_dir );
3191 endmntent ( ent_f );
3198 #ifdef PIVOTROOT_OPT_SUPPORT
3209 error (
"Got error while pivot_root(\".\", \"old_root\")" );
3218 debug ( 7,
"chroot(\".\")" );
3220 if ( chroot (
"." ) ) {
3221 error (
"Got error while chroot(\".\")" );
3225 #ifdef PIVOTROOT_OPT_SUPPORT
3235 if ( umount2 (
"old_root", MNT_DETACH ) ) {
3236 error (
"Got error while umount2(\"old_root\", MNT_DETACH)" );
3249 debug ( 1,
"Trying to open the status file for writing." );
3255 debug ( 1,
"Changing owner of the status file to %u:%u", uid, gid );
3258 warning (
"Cannot fchown(%u -> \"%s\", %u, %u)",
3265 #ifdef CAPABILITIES_SUPPORT
3266 debug ( 1,
"Preserving Linux capabilities" );
3269 if ( prctl ( PR_SET_KEEPCAPS, 1 ) < 0 ) {
3270 error (
"Cannot prctl(PR_SET_KEEPCAPS, 1) to preserve capabilities" );
3275 #ifdef CGROUP_SUPPORT
3291 debug ( 3,
"Trying to drop effective gid to %i",
ctx_p->
gid );
3302 debug ( 3,
"Trying to drop effective uid to %i",
ctx_p->
uid );
3312 debug ( 1,
"Trying to open the status file for writing (after setuid()/setgid())." );
3316 error (
"Cannot open file \"%s\" for writing.",
3326 if ( !ret ) ret = rc;
3340 char *tempdir = getenv (
"TMPDIR" );
3344 size_t tempdir_len = strlen(tempdir);
3345 size_t tempsuff_len = strlen(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;
3357 error (
"Cannot create temporary dir for list files by template '%s'",
template );
3363 struct stat st = {0};
3367 if ( errno == ENOENT ) {
3383 if ( st.st_mode & ( S_IRWXG | S_IRWXO ) ) {
3385 ret = errno = EACCES;
3402 pid_t pid = getpid();
3405 if ( pidfile == NULL ) {
3407 if ( errno == EACCES ) {
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 );
3414 if ( !errno )
SAFE ( seteuid ( 0 ), ret = errno );
3416 if ( !errno )
SAFE ( ( fd = open (
ctx_p->
pidfile, O_CREAT | O_WRONLY, 0644 ) ) == -1, ret = errno );
3418 if ( !errno )
SAFE ( fchown ( fd, euid, egid ), ret = errno );
3420 if ( !errno )
SAFE (
close ( fd ), ret = errno );
3422 if ( !errno )
SAFE ( seteuid ( euid ), ret = errno );
3427 if ( pidfile == NULL ) {
3428 error (
"Cannot open file \"%s\" to write a pid there",
3434 if ( pidfile != NULL ) {
3435 if ( fprintf ( pidfile,
"%u", pid ) < 0 ) {
3436 error (
"Cannot write pid into file \"%s\"",
3445 debug ( 3,
"Current errno is %i.", ret );
3456 debug ( 1,
"Cannot unlink pidfile \"%s\": %s. Just truncating the file.",
3460 if ( pidfile != NULL )
3468 error (
"Cannot close file \"%s\".",
3474 error (
"Cannot unlink status file \"%s\"",
3486 if ( rm_listoutdir == 2 )
3509 debug ( 1,
"finished, exitcode: %i: %s.", ret, strerror ( ret ) );
3511 #ifndef __FreeBSD__ // Hanging up with 100%CPU eating, https://github.com/clsync/clsync/issues/97