diff --git a/Makefile.in b/Makefile.in index fee32b7..7901d93 100644 --- a/Makefile.in +++ b/Makefile.in @@ -37,7 +37,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) $(ZLIBOBJ) @BUILD_POPT@ diff --git a/checksum.c b/checksum.c index 0460626..1c1e402 100644 --- a/checksum.c +++ b/checksum.c @@ -27,7 +27,7 @@ extern int protocol_version; int csum_length = SHORT_SUM_LENGTH; /* initial value */ /* - 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 9efecbc..bfb3490 100644 --- a/clientname.c +++ b/clientname.c @@ -89,7 +89,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; @@ -219,8 +219,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; } @@ -311,8 +313,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; } @@ -327,14 +331,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 3619810..234719e 100644 --- a/clientserver.c +++ b/clientserver.c @@ -74,10 +74,6 @@ unsigned int module_dirlen = 0; static int rl_nulls = 0; -#ifdef HAVE_SIGACTION -static struct sigaction sigact; -#endif - /** * Run a client connected to an rsyncd. The alternative to this * function for remote-shell connections is do_cmd(). @@ -416,20 +412,6 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) 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; - } - auth_user = auth_server(f_in, f_out, i, host, addr, "@RSYNCD: AUTHREQD "); if (!auth_user) { @@ -918,11 +900,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/loadparm.c b/loadparm.c index 8b3e9f7..10fd36b 100644 --- a/loadparm.c +++ b/loadparm.c @@ -136,7 +136,6 @@ typedef struct char *include; char *include_from; char *incoming_chmod; - char *lock_file; char *log_file; char *log_format; char *name; @@ -187,7 +186,6 @@ static service sDefault = /* 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, @@ -321,7 +319,6 @@ static struct parm_struct parm_table[] = {"include", P_STRING, P_LOCAL, &sDefault.include, NULL,0}, {"incoming chmod", P_STRING, P_LOCAL, &sDefault.incoming_chmod, NULL,0}, {"list", P_BOOL, P_LOCAL, &sDefault.list, NULL,0}, - {"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL,0}, {"log file", P_STRING, P_LOCAL, &sDefault.log_file, NULL,0}, {"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL,0}, {"max connections", P_INTEGER,P_LOCAL, &sDefault.max_connections, NULL,0}, @@ -410,7 +407,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 c5dcbb9..4ab3dbb 100644 --- a/log.c +++ b/log.c @@ -114,9 +114,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); } @@ -149,6 +153,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) { @@ -168,8 +177,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; @@ -199,7 +210,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/rsync.h b/rsync.h index d6a4b18..69e0860 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/" @@ -570,6 +569,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 1d3bacd..2bba231 100644 --- a/rsyncd.conf.yo +++ b/rsyncd.conf.yo @@ -47,7 +47,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 @@ -245,7 +245,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" option. dit(bf(log file)) When the "log file" option is set to a non-empty string, the rsync daemon will log messages to the indicated file rather @@ -275,12 +274,6 @@ the maximum amount of verbose information that you'll allow the daemon to generate (since the information goes into the log file). The default is 1, which allows the client to request one level of verbosity. -dit(bf(lock file)) The "lock file" option specifies the file to use to -support the "max connections" option. The rsync daemon uses record -locking on this file to ensure that the max connections limit is not -exceeded for the modules sharing the lock file. -The default is tt(/var/run/rsyncd.lock). - dit(bf(read only)) The "read only" option determines whether clients will be able to upload files or not. If "read only" is true then any attempted uploads will fail. If "read only" is false then uploads will diff --git a/socket.c b/socket.c index 89f285a..f58cb4f 100644 --- a/socket.c +++ b/socket.c @@ -34,9 +34,45 @@ extern char *bind_address; 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)) /** * Establish a proxy connection on an open socket to a web proxy by @@ -268,7 +304,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); } @@ -508,27 +544,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 RETSIGTYPE 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) @@ -537,7 +583,7 @@ void start_accept_loop(int port, int (*fn)(int, int)) /* ready to listen */ FD_ZERO(&deffds); for (i = 0, maxfd = -1; sp[i] >= 0; i++) { - if (listen(sp[i], 5) < 0) { + if (listen(sp[i], 256) < 0) { rsyserr(FERROR, errno, "listen() on socket failed"); #ifdef INET6 if (errno == EADDRINUSE && i > 0) { @@ -552,6 +598,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) { @@ -566,15 +619,21 @@ 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)) { fd = accept(sp[i], (struct sockaddr *)&addr, @@ -582,16 +641,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(); @@ -601,15 +664,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); } }