diff --git a/Makefile.in b/Makefile.in index f912f31..e6232b6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -41,7 +41,7 @@ OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \ OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \ fileio.o batch.o clientname.o chmod.o acls.o xattrs.o OBJS3=progress.o pipe.o -DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o +DAEMON_OBJ = params.o loadparm.o clientserver.o access.o authenticate.o popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ popt/popthelp.o popt/poptparse.o OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@ @@ -60,7 +60,7 @@ CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash. # note that the -I. is needed to handle config.h when using VPATH .c.o: @OBJ_SAVE@ - $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@ + $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -flto -c $< @CC_SHOBJ_FLAG@ @OBJ_RESTORE@ all: Makefile rsync$(EXEEXT) rsync-ssl stunnel-rsync stunnel-rsyncd.conf @MAKE_MAN@ @@ -91,7 +91,7 @@ install-strip: $(MAKE) INSTALL_STRIP='-s' install rsync$(EXEEXT): $(OBJS) - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + $(CC) $(CFLAGS) $(LDFLAGS) -lrt -flto -ljemalloc -o $@ $(OBJS) $(LIBS) $(OBJS): $(HEADERS) $(CHECK_OBJS): $(HEADERS) diff --git a/acls.c b/acls.c index 007ba29..d16e2ee 100644 --- a/acls.c +++ b/acls.c @@ -28,7 +28,7 @@ extern int dry_run; extern int am_root; extern int read_only; extern int list_only; -extern int orig_umask; +extern mode_t orig_umask; extern int numeric_ids; extern int inc_recurse; extern int preserve_devices; diff --git a/authenticate.c b/authenticate.c index d60ee20..1ca7bbe 100644 --- a/authenticate.c +++ b/authenticate.c @@ -60,15 +60,15 @@ static void gen_challenge(const char *addr, char *challenge) { char input[32]; char digest[MAX_DIGEST_LEN]; - struct timeval tv; + struct timespec tsp; int len; memset(input, 0, sizeof input); strlcpy(input, addr, 17); - sys_gettimeofday(&tv); - SIVAL(input, 16, tv.tv_sec); - SIVAL(input, 20, tv.tv_usec); + clock_gettime(CLOCK_REALTIME, &tsp); + SIVAL(input, 16, tsp.tv_sec); + SIVAL(input, 20, tsp.tv_nsec); SIVAL(input, 24, getpid()); sum_init(-1, 0); diff --git a/checksum.c b/checksum.c index 8b38833..5779173 100644 --- a/checksum.c +++ b/checksum.c @@ -96,7 +96,7 @@ int canonical_checksum(int csum_type) } /* - a simple 32 bit checksum that can be upadted from either end + a simple 32 bit checksum that can be updated from either end (inspired by Mark Adler's Adler-32 checksum) */ uint32 get_checksum1(char *buf1, int32 len) diff --git a/clientname.c b/clientname.c index 89ce2a8..c86428d 100644 --- a/clientname.c +++ b/clientname.c @@ -91,7 +91,7 @@ static int get_sockaddr_family(const struct sockaddr_storage *ss) **/ char *client_name(int fd) { - static char name_buf[100]; + static char name_buf[256]; static char port_buf[100]; static int initialised; struct sockaddr_storage ss; @@ -224,8 +224,10 @@ int lookup_name(int fd, const struct sockaddr_storage *ss, NI_NAMEREQD | NI_NUMERICSERV); if (name_err != 0) { strlcpy(name_buf, default_name, name_buf_size); +#if RSYNC_DNS_DEBUG rprintf(FLOG, "name lookup failed for %s: %s\n", client_addr(fd), gai_strerror(name_err)); +#endif return name_err; } @@ -316,8 +318,10 @@ int check_name(int fd, hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(name_buf, NULL, &hints, &res0); if (error) { +#if RSYNC_DNS_DEBUG rprintf(FLOG, "forward name lookup for %s failed: %s\n", name_buf, gai_strerror(error)); +#endif strlcpy(name_buf, default_name, name_buf_size); return error; } @@ -332,14 +336,18 @@ int check_name(int fd, if (!res0) { /* We hit the end of the list without finding an * address that was the same as ss. */ +#if RSYNC_DNS_DEBUG rprintf(FLOG, "no known address for \"%s\": " "spoofed address?\n", name_buf); +#endif strlcpy(name_buf, default_name, name_buf_size); } else if (res == NULL) { /* We hit the end of the list without finding an * address that was the same as ss. */ +#if RSYNC_DNS_DEBUG rprintf(FLOG, "%s is not a known address for \"%s\": " "spoofed address?\n", client_addr(fd), name_buf); +#endif strlcpy(name_buf, default_name, name_buf_size); } diff --git a/clientserver.c b/clientserver.c index 91aee27..0fa16e5 100644 --- a/clientserver.c +++ b/clientserver.c @@ -546,20 +546,6 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char name, host, addr); } - if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) { - if (errno) { - rsyserr(FLOG, errno, "failed to open lock file %s", - lp_lock_file(i)); - io_printf(f_out, "@ERROR: failed to open lock file\n"); - } else { - rprintf(FLOG, "max connections (%d) reached\n", - lp_max_connections(i)); - io_printf(f_out, "@ERROR: max connections (%d) reached -- try again later\n", - lp_max_connections(i)); - } - return -1; - } - read_only = lp_read_only(i); /* may also be overridden by auth_server() */ auth_user = auth_server(f_in, f_out, i, host, addr, "@RSYNCD: AUTHREQD "); @@ -1086,11 +1072,6 @@ int start_daemon(int f_in, int f_out) return -1; } -#ifdef HAVE_SIGACTION - sigact.sa_flags = SA_NOCLDSTOP; -#endif - SIGACTION(SIGCHLD, remember_children); - return rsync_module(f_in, f_out, i, addr, host); } diff --git a/connection.c b/connection.c deleted file mode 100644 index 6281861..0000000 --- a/connection.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Support the max connections option. - * - * Copyright (C) 1998 Andrew Tridgell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, visit the http://fsf.org website. - */ - -#include "rsync.h" - -/* A simple routine to do connection counting. This returns 1 on success - * and 0 on failure, with errno also being set if the open() failed (errno - * will be 0 if the lock request failed). */ -int claim_connection(char *fname, int max_connections) -{ - int fd, i; - - if (max_connections == 0) - return 1; - - if ((fd = open(fname, O_RDWR|O_CREAT, 0600)) < 0) - return 0; - - /* Find a free spot. */ - for (i = 0; i < max_connections; i++) { - if (lock_range(fd, i*4, 4)) - return 1; - } - - close(fd); - - /* A lock failure needs to return an errno of 0. */ - errno = 0; - return 0; -} diff --git a/exclude.c b/exclude.c index 0aaa19b..b139a8a 100644 --- a/exclude.c +++ b/exclude.c @@ -37,7 +37,7 @@ extern int protocol_version; extern int module_id; extern char curr_dir[MAXPATHLEN]; -extern unsigned int curr_dir_len; +extern size_t curr_dir_len; extern unsigned int module_dirlen; filter_rule_list filter_list = { .debug_type = "" }; @@ -377,7 +377,7 @@ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr, /* Sets the dirbuf and dirbuf_len values. */ void set_filter_dir(const char *dir, unsigned int dirlen) { - unsigned int len; + size_t len; if (*dir != '/') { memcpy(dirbuf, curr_dir, curr_dir_len); dirbuf[curr_dir_len] = '/'; @@ -910,8 +910,8 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr, default: invalid: rprintf(FERROR, - "invalid modifier '%c' at position %d in filter rule: %s\n", - *s, (int)(s - (const uchar *)*rulestr_ptr), *rulestr_ptr); + "invalid modifier '%c' at position %zd in filter rule: %s\n", + *s, (s - (const uchar *)*rulestr_ptr), *rulestr_ptr); exit_cleanup(RERR_SYNTAX); case '-': if (!BITS_SETnUNSET(rule->rflags, FILTRULE_MERGE_FILE, FILTRULE_NO_PREFIXES)) diff --git a/getgroups.c b/getgroups.c index b2139b4..dbfc5e9 100644 --- a/getgroups.c +++ b/getgroups.c @@ -37,6 +37,10 @@ main(UNUSED(int argc), UNUSED(char *argv[])) n = 0; #endif + if ((n == INT_MAX) || ((size_t)n + 1 > (SIZE_MAX / sizeof(gid_t)))) { + fprintf(stderr, "not enough memory, getgroups returned %d\n", n); + exit(1); + } list = (gid_t*)malloc(sizeof (gid_t) * (n + 1)); if (!list) { fprintf(stderr, "out of memory!\n"); diff --git a/loadparm.c b/loadparm.c index 6d75b4d..e547b6d 100644 --- a/loadparm.c +++ b/loadparm.c @@ -119,7 +119,6 @@ typedef struct { char *include; char *include_from; char *incoming_chmod; - char *lock_file; char *log_file; char *log_format; char *name; @@ -195,7 +194,6 @@ static const all_vars Defaults = { /* include; */ NULL, /* include_from; */ NULL, /* incoming_chmod; */ NULL, - /* lock_file; */ DEFAULT_LOCK_FILE, /* log_file; */ NULL, /* log_format; */ "%o %h [%a] %m (%u) %f %l", /* name; */ NULL, @@ -337,7 +335,6 @@ static struct parm_struct parm_table[] = {"include", P_STRING, P_LOCAL, &Vars.l.include, NULL,0}, {"incoming chmod", P_STRING, P_LOCAL, &Vars.l.incoming_chmod, NULL,0}, {"list", P_BOOL, P_LOCAL, &Vars.l.list, NULL,0}, - {"lock file", P_STRING, P_LOCAL, &Vars.l.lock_file, NULL,0}, {"log file", P_STRING, P_LOCAL, &Vars.l.log_file, NULL,0}, {"log format", P_STRING, P_LOCAL, &Vars.l.log_format, NULL,0}, {"max connections", P_INTEGER,P_LOCAL, &Vars.l.max_connections, NULL,0}, @@ -464,7 +461,6 @@ FN_LOCAL_STRING(lp_hosts_deny, hosts_deny) FN_LOCAL_STRING(lp_include, include) FN_LOCAL_STRING(lp_include_from, include_from) FN_LOCAL_STRING(lp_incoming_chmod, incoming_chmod) -FN_LOCAL_STRING(lp_lock_file, lock_file) FN_LOCAL_STRING(lp_log_file, log_file) FN_LOCAL_STRING(lp_log_format, log_format) FN_LOCAL_STRING(lp_name, name) diff --git a/log.c b/log.c index f7da1e5..11d9891 100644 --- a/log.c +++ b/log.c @@ -125,8 +125,13 @@ static void logit(int priority, const char *buf) if (logfile_was_closed) logfile_reopen(); if (logfile_fp) { - fprintf(logfile_fp, "%s [%d] %s", timestring(time(NULL)), (int)getpid(), buf); - fflush(logfile_fp); + if (logfile_fp != stderr) { + fprintf(logfile_fp, "%s [%d] %s", + timestring(time(NULL)), (int)getpid(), buf); + fflush(logfile_fp); + } else { + fprintf(logfile_fp, "[%d] %s", (int)getpid(), buf); + } } else { syslog(priority, "%s", buf); } @@ -159,6 +164,11 @@ static void syslog_init() static void logfile_open(void) { mode_t old_umask = umask(022 | orig_umask); + + if (!strcmp(logfile_name, "-")) { + logfile_fp = stderr; + return; + } logfile_fp = fopen(logfile_name, "a"); umask(old_umask); if (!logfile_fp) { @@ -178,8 +188,10 @@ void log_init(int restart) return; if (strcmp(logfile_name, lp_log_file(module_id)) != 0) { if (logfile_fp) { - fclose(logfile_fp); - logfile_fp = NULL; + if (logfile_fp != stderr) { + fclose(logfile_fp); + logfile_fp = NULL; + } } else closelog(); logfile_name = NULL; @@ -209,7 +221,7 @@ void log_init(int restart) void logfile_close(void) { - if (logfile_fp) { + if (logfile_fp && (logfile_fp != stderr)) { logfile_was_closed = 1; fclose(logfile_fp); logfile_fp = NULL; diff --git a/main.c b/main.c index 3908ccf..1cb4d88 100644 --- a/main.c +++ b/main.c @@ -58,7 +58,7 @@ extern int protect_args; extern int relative_paths; extern int sanitize_paths; extern int curr_dir_depth; -extern int curr_dir_len; +extern size_t curr_dir_len; extern int module_id; extern int rsync_port; extern int whole_file; @@ -723,7 +723,10 @@ static void check_alt_basis_dirs(void) if (bd_len > 1 && bdir[bd_len-1] == '/') bdir[--bd_len] = '\0'; if (dry_run > 1 && *bdir != '/') { - int len = curr_dir_len + 1 + bd_len + 1; + size_t len = curr_dir_len; + if (len > SIZE_MAX - 1 - bd_len - 1) + out_of_memory("check_alt_basis_dirs"); + len += 1 + bd_len + 1; char *new = new_array(char, len); if (!new) out_of_memory("check_alt_basis_dirs"); diff --git a/options.c b/options.c index 6ba13b7..076730e 100644 --- a/options.c +++ b/options.c @@ -50,6 +50,7 @@ int append_mode = 0; int keep_dirlinks = 0; int copy_dirlinks = 0; int copy_links = 0; +int do_fsync = 0; int preserve_links = 0; int preserve_hard_links = 0; int preserve_acls = 0; @@ -748,6 +749,7 @@ void usage(enum logcode F) rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); rprintf(F," --delay-updates put all updated files into place at transfer's end\n"); rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n"); + rprintf(F," --fsync fsync every written file\n"); rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); rprintf(F," --usermap=STRING custom username mapping\n"); rprintf(F," --groupmap=STRING custom groupname mapping\n"); @@ -1016,6 +1018,7 @@ static struct poptOption long_options[] = { {"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 }, {"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 }, {"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 }, + {"fsync", 0, POPT_ARG_NONE, &do_fsync, 0, 0, 0 }, {"no-contimeout", 0, POPT_ARG_VAL, &connect_timeout, 0, 0, 0 }, {"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 }, {"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 }, @@ -2722,6 +2725,9 @@ void server_options(char **args, int *argc_p) args[ac++] = tmpdir; } + if (do_fsync) + args[ac++] = "--fsync"; + if (basis_dir[0]) { /* the server only needs this option if it is not the sender, * and it may be an older version that doesn't know this diff --git a/receiver.c b/receiver.c index bed5328..b572e6d 100644 --- a/receiver.c +++ b/receiver.c @@ -40,6 +40,7 @@ extern int relative_paths; extern int preserve_hard_links; extern int preserve_perms; extern int preserve_xattrs; +extern int do_fsync; extern int basis_dir_cnt; extern int make_backups; extern int cleanup_got_literal; @@ -242,7 +243,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, int32 len; OFF_T offset = 0; OFF_T offset2; - char *data; + char *data = NULL; int32 i; char *map = NULL; @@ -390,6 +391,12 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, if (INFO_GTE(PROGRESS, 1)) end_progress(total_size); + if (do_fsync && fd != -1 && fsync(fd) != 0) { + rsyserr(FERROR, errno, "fsync failed on %s", + full_fname(fname)); + exit_cleanup(RERR_FILEIO); + } + checksum_len = sum_end(file_sum1); if (mapbuf) diff --git a/rsync.h b/rsync.h index 6e1e1dd..8978ce2 100644 --- a/rsync.h +++ b/rsync.h @@ -29,7 +29,6 @@ /* RSYNCD_SYSCONF is now set in config.h */ #define RSYNCD_USERCONF "rsyncd.conf" -#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock" #define URL_PREFIX "rsync://" #define SYMLINK_PREFIX "/rsyncd-munged/" /* This MUST have a trailing slash! */ @@ -131,7 +130,7 @@ #define RSYNC_PORT 873 -#define SPARSE_WRITE_SIZE (1024) +#define SPARSE_WRITE_SIZE (32768) #define WRITE_SIZE (32*1024) #define CHUNK_SIZE (32*1024) #define MAX_MAP_SIZE (256*1024) @@ -642,6 +641,9 @@ struct ht_int64_node { #define MAXHOSTNAMELEN 256 #endif +/* Change to 1 if you want to log if there is PTR/A record mismatch */ +#define RSYNC_DNS_DEBUG 0 + #define SUM_LENGTH 16 #define SHORT_SUM_LENGTH 2 #define BLOCKSUM_BIAS 10 diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo index 64156ae..f7f5693 100644 --- a/rsyncd.conf.yo +++ b/rsyncd.conf.yo @@ -48,7 +48,7 @@ rsync. The daemon must run with root privileges if you wish to use chroot, to bind to a port numbered under 1024 (as is the default 873), or to set file ownership. Otherwise, it must just have permission to read and -write the appropriate data, log, and lock files. +write the appropriate data and log files. You can launch it either via inetd, as a stand-alone daemon, or from an rsync client via a remote shell. If run as a stand-alone daemon then @@ -285,7 +285,6 @@ specify the maximum number of simultaneous connections you will allow. Any clients connecting when the maximum has been reached will receive a message telling them to try later. The default is 0, which means no limit. A negative value disables the module. -See also the "lock file" parameter. dit(bf(log file)) When the "log file" parameter is set to a non-empty string, the rsync daemon will log messages to the indicated file rather diff --git a/socket.c b/socket.c index 7955ea9..24b5621 100644 --- a/socket.c +++ b/socket.c @@ -39,9 +39,45 @@ extern char *sockopts; extern int default_af_hint; extern int connect_timeout; -#ifdef HAVE_SIGACTION -static struct sigaction sigact; -#endif +extern int module_id; + +static void sig_pause(void) +{ + sigset_t ss; + + sigemptyset(&ss); + sigsuspend(&ss); +} + +static void sig_block(int sig) +{ + sigset_t ss; + + sigemptyset(&ss); + sigaddset(&ss,sig); + sigprocmask(SIG_BLOCK,&ss,(sigset_t *) 0); +} + +static void sig_unblock(int sig) +{ + sigset_t ss; + + sigemptyset(&ss); + sigaddset(&ss,sig); + sigprocmask(SIG_UNBLOCK,&ss,(sigset_t *) 0); +} + +static void sig_catch(int sig, void (*f)(int)) +{ + struct sigaction sa; + + sa.sa_handler = f; + sa.sa_flags = (sig == SIGCHLD) ? SA_NOCLDSTOP : 0; + sigemptyset(&sa.sa_mask); + sigaction(sig,&sa,(struct sigaction *) 0); +} + +#define sig_uncatch(s) (sig_catch(s, SIG_DFL)) static int sock_exec(const char *prog); @@ -271,7 +307,7 @@ int open_socket_out(char *host, int port, const char *bind_addr, continue; } if (connect_timeout > 0) { - SIGACTION(SIGALRM, contimeout_handler); + sig_catch(SIGALRM, contimeout_handler); alarm(connect_timeout); } @@ -528,27 +564,37 @@ int is_a_socket(int fd) return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0; } +static int volatile numchildren; + +static void printstatus(void) +{ + rprintf(FINFO, "%d/%d childs\n", numchildren, lp_max_connections(module_id)); +} static void sigchld_handler(UNUSED(int val)) { -#ifdef WNOHANG - while (waitpid(-1, NULL, WNOHANG) > 0) {} -#endif + int wstat; + int pid; + int crashed; + + while ((pid = waitpid(-1, &wstat, WNOHANG)) > 0) { + crashed = WIFSIGNALED(wstat); + rprintf(FINFO, "children %d status %s %d\n", pid, crashed ? "signal" : "exit", + crashed ? WTERMSIG(wstat) : WEXITSTATUS(wstat)); + if (numchildren) --numchildren; + printstatus(); + } + #ifndef HAVE_SIGACTION signal(SIGCHLD, sigchld_handler); #endif } - void start_accept_loop(int port, int (*fn)(int, int)) { fd_set deffds; int *sp, maxfd, i; -#ifdef HAVE_SIGACTION - sigact.sa_flags = SA_NOCLDSTOP; -#endif - /* open an incoming socket */ sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint); if (sp == NULL) @@ -572,6 +618,13 @@ void start_accept_loop(int port, int (*fn)(int, int)) maxfd = sp[i]; } + sig_block(SIGCHLD); +#ifndef HAVE_SIGACTION + signal(SIGCHLD, sigchld_handler); +#else + sig_catch(SIGCHLD, sigchld_handler); +#endif + /* now accept incoming connections - forking a new process * for each incoming connection */ while (1) { @@ -586,14 +639,20 @@ void start_accept_loop(int port, int (*fn)(int, int)) * forever */ logfile_close(); + while (numchildren >= lp_max_connections(module_id)) sig_pause(); + #ifdef FD_COPY FD_COPY(&deffds, &fds); #else fds = deffds; #endif - if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1) + sig_unblock(SIGCHLD); + if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1) { + sig_block(SIGCHLD); continue; + } + sig_unblock(SIGCHLD); for (i = 0, fd = -1; sp[i] >= 0; i++) { if (FD_ISSET(sp[i], &fds)) { @@ -602,16 +661,20 @@ void start_accept_loop(int port, int (*fn)(int, int)) break; } } + sig_block(SIGCHLD); if (fd < 0) continue; - SIGACTION(SIGCHLD, sigchld_handler); + ++numchildren; + printstatus(); if ((pid = fork()) == 0) { int ret; for (i = 0; sp[i] >= 0; i++) close(sp[i]); + sig_uncatch(SIGCHLD); + sig_unblock(SIGCHLD); /* Re-open log file in child before possibly giving * up privileges (see logfile_close() above). */ logfile_reopen(); @@ -621,15 +684,11 @@ void start_accept_loop(int port, int (*fn)(int, int)) } else if (pid < 0) { rsyserr(FERROR, errno, "could not create child server process"); - close(fd); - /* This might have happened because we're - * overloaded. Sleep briefly before trying to - * accept again. */ - sleep(2); - } else { - /* Parent doesn't need this fd anymore. */ - close(fd); + --numchildren; + printstatus(); } + /* Parent doesn't need this fd anymore. */ + close(fd); } } diff --git a/t_stub.c b/t_stub.c index fc1ee3b..89516d5 100644 --- a/t_stub.c +++ b/t_stub.c @@ -21,6 +21,7 @@ #include "rsync.h" +int do_fsync = 0; int inplace = 0; int modify_window = 0; int preallocate_files = 0; diff --git a/tls.c b/tls.c index d5a2896..496ce55 100644 --- a/tls.c +++ b/tls.c @@ -122,7 +122,7 @@ static void list_file(const char *fname) { STRUCT_STAT buf; char permbuf[PERMSTRING_SIZE]; - struct tm *mt; + struct tm tmbuf; char datebuf[50]; char linkbuf[4096]; @@ -164,18 +164,17 @@ static void list_file(const char *fname) if (buf.st_mtime) { int len; - mt = gmtime(&buf.st_mtime); - + gmtime_r(&buf.st_mtime, &tmbuf); len = snprintf(datebuf, sizeof datebuf, "%04d-%02d-%02d %02d:%02d:%02d", - (int)mt->tm_year + 1900, - (int)mt->tm_mon + 1, - (int)mt->tm_mday, - (int)mt->tm_hour, - (int)mt->tm_min, - (int)mt->tm_sec); + (int)tmbuf.tm_year + 1900, + (int)tmbuf.tm_mon + 1, + (int)tmbuf.tm_mday, + (int)tmbuf.tm_hour, + (int)tmbuf.tm_min, + (int)tmbuf.tm_sec); #ifdef ST_MTIME_NSEC - if (nsec_times) { + if (nsec_times && len > 0) { snprintf(datebuf + len, sizeof datebuf - len, ".%09d", (int)buf.ST_MTIME_NSEC); } diff --git a/token.c b/token.c index ad9b9bc..d80821e 100644 --- a/token.c +++ b/token.c @@ -639,7 +639,7 @@ void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, } /* - * receive a token or buffer from the other end. If the reurn value is >0 then + * receive a token or buffer from the other end. If the return value is >0 then * it is a data buffer of that length, and *data will point at the data. * if the return value is -i then it represents token i-1 * if the return value is 0 then the end has been reached diff --git a/util.c b/util.c index 49c5b71..4b02fe1 100644 --- a/util.c +++ b/util.c @@ -27,6 +27,7 @@ extern int dry_run; extern int module_id; +extern int do_fsync; extern int protect_args; extern int modify_window; extern int relative_paths; @@ -41,7 +42,7 @@ extern filter_rule_list daemon_filter_list; int sanitize_paths = 0; char curr_dir[MAXPATHLEN]; -unsigned int curr_dir_len; +size_t curr_dir_len; int curr_dir_depth; /* This is only set for a sanitizing daemon. */ /* Set a fd into nonblocking mode. */ @@ -122,9 +123,13 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) static int switch_step = 0; if (DEBUG_GTE(TIME, 1)) { + struct tm tmbuf; + char ascbuf[32]; + + localtime_r(&modtime, &tmbuf); + asctime_r(&tmbuf, ascbuf); rprintf(FINFO, "set modtime of %s to (%ld) %s", - fname, (long)modtime, - asctime(localtime(&modtime))); + fname, (long)modtime, ascbuf); } switch (switch_step) { @@ -396,6 +401,13 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode) full_fname(source)); } + if (do_fsync && fsync(ofd) < 0) { + rsyserr(FERROR, errno, "fsync failed on %s", + full_fname(dest)); + close(ofd); + return -1; + } + /* Source file might have shrunk since we fstatted it. * Cut off any extra preallocated zeros from dest file. */ if (offset < prealloc_len && do_ftruncate(ofd, offset) < 0) { @@ -902,11 +914,12 @@ int count_dir_elements(const char *p) * resulting name would be empty, returns ".". */ int clean_fname(char *name, int flags) { - char *limit = name - 1, *t = name, *f = name; + char *limit, *t = name, *f = name; int anchored; if (!name) return 0; + limit = name - 1; #define DOT_IS_DOT_DOT_DIR(bp) (bp[1] == '.' && (bp[2] == '/' || !bp[2])) @@ -1326,11 +1339,12 @@ int unsafe_symlink(const char *dest, const char *src) char *timestring(time_t t) { static char TimeBuf[200]; - struct tm *tm = localtime(&t); + struct tm tmbuf; char *p; + localtime_r(&t, &tmbuf); #ifdef HAVE_STRFTIME - strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm); + strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", &tmbuf); #else strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf); #endif