⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clientserver.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	if (module_dirlen == 1) {		module_dirlen = 0;		set_filter_dir("/", 1);	} else		set_filter_dir(module_dir, module_dirlen);	p = lp_filter(i);	parse_rule(&daemon_filter_list, p, MATCHFLG_WORD_SPLIT,		   XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3);	p = lp_include_from(i);	parse_filter_file(&daemon_filter_list, p, MATCHFLG_INCLUDE,	    XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);	p = lp_include(i);	parse_rule(&daemon_filter_list, p,		   MATCHFLG_INCLUDE | MATCHFLG_WORD_SPLIT,		   XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);	p = lp_exclude_from(i);	parse_filter_file(&daemon_filter_list, p, 0,	    XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);	p = lp_exclude(i);	parse_rule(&daemon_filter_list, p, MATCHFLG_WORD_SPLIT,		   XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES);	log_init(1);#ifdef HAVE_PUTENV	if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) {		char *modname, *modpath, *hostaddr, *hostname, *username;		int status;		if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0		 || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", full_module_path) < 0		 || asprintf(&hostaddr, "RSYNC_HOST_ADDR=%s", addr) < 0		 || asprintf(&hostname, "RSYNC_HOST_NAME=%s", host) < 0		 || asprintf(&username, "RSYNC_USER_NAME=%s", auth_user) < 0)			out_of_memory("rsync_module");		putenv(modname);		putenv(modpath);		putenv(hostaddr);		putenv(hostname);		putenv(username);		umask(orig_umask);		/* For post-xfer exec, fork a new process to run the rsync		 * daemon while this process waits for the exit status and		 * runs the indicated command at that point. */		if (*lp_postxfer_exec(i)) {			pid_t pid = fork();			if (pid < 0) {				rsyserr(FLOG, errno, "fork failed");				io_printf(f_out, "@ERROR: fork failed\n");				return -1;			}			if (pid) {				if (asprintf(&p, "RSYNC_PID=%ld", (long)pid) > 0)					putenv(p);				if (wait_process(pid, &status, 0) < 0)					status = -1;				if (asprintf(&p, "RSYNC_RAW_STATUS=%d", status) > 0)					putenv(p);				if (WIFEXITED(status))					status = WEXITSTATUS(status);				else					status = -1;				if (asprintf(&p, "RSYNC_EXIT_STATUS=%d", status) > 0)					putenv(p);				if (system(lp_postxfer_exec(i)) < 0)					status = -1;				_exit(status);			}		}		/* For pre-xfer exec, fork a child process to run the indicated		 * command, though it first waits for the parent process to		 * send us the user's request via a pipe. */		if (*lp_prexfer_exec(i)) {			int fds[2];			if (asprintf(&p, "RSYNC_PID=%ld", (long)getpid()) > 0)				putenv(p);			if (pipe(fds) < 0 || (pre_exec_pid = fork()) < 0) {				rsyserr(FLOG, errno, "pre-xfer exec preparation failed");				io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n");				return -1;			}			if (pre_exec_pid == 0) {				char buf[BIGPATHBUFLEN];				int j, len;				close(fds[1]);				set_blocking(fds[0]);				len = read_arg_from_pipe(fds[0], buf, BIGPATHBUFLEN);				if (len <= 0)					_exit(1);				if (asprintf(&p, "RSYNC_REQUEST=%s", buf) > 0)					putenv(p);				for (j = 0; ; j++) {					len = read_arg_from_pipe(fds[0], buf,								 BIGPATHBUFLEN);					if (len <= 0) {						if (!len)							break;						_exit(1);					}					if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) > 0)						putenv(p);				}				close(fds[0]);				close(STDIN_FILENO);				close(STDOUT_FILENO);				status = system(lp_prexfer_exec(i));				if (!WIFEXITED(status))					_exit(1);				_exit(WEXITSTATUS(status));			}			close(fds[0]);			set_blocking(fds[1]);			pre_exec_fd = fds[1];		}		umask(0);	}#endif	if (use_chroot) {		/*		 * XXX: The 'use chroot' flag is a fairly reliable		 * source of confusion, because it fails under two		 * important circumstances: running as non-root,		 * running on Win32 (or possibly others).  On the		 * other hand, if you are running as root, then it		 * might be better to always use chroot.		 *		 * So, perhaps if we can't chroot we should just issue		 * a warning, unless a "require chroot" flag is set,		 * in which case we fail.		 */		if (chroot(module_chdir)) {			rsyserr(FLOG, errno, "chroot %s failed", module_chdir);			io_printf(f_out, "@ERROR: chroot failed\n");			return -1;		}		module_chdir = module_dir;	}	if (!change_dir(module_chdir, CD_NORMAL))		return path_failure(f_out, module_chdir, True);	if (module_dirlen || !use_chroot)		sanitize_paths = 1;	if ((munge_symlinks = lp_munge_symlinks(i)) < 0)		munge_symlinks = !use_chroot || module_dirlen;	if (munge_symlinks) {		STRUCT_STAT st;		if (do_stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {			rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n",				SYMLINK_PREFIX);			io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name);			exit_cleanup(RERR_UNSUPPORTED);		}	}	if (am_root) {		/* XXXX: You could argue that if the daemon is started		 * by a non-root user and they explicitly specify a		 * gid, then we should try to change to that gid --		 * this could be possible if it's already in their		 * supplementary groups. */		/* TODO: Perhaps we need to document that if rsyncd is		 * started by somebody other than root it will inherit		 * all their supplementary groups. */		if (setgid(gid)) {			rsyserr(FLOG, errno, "setgid %d failed", (int)gid);			io_printf(f_out, "@ERROR: setgid failed\n");			return -1;		}#ifdef HAVE_SETGROUPS		/* Get rid of any supplementary groups this process		 * might have inheristed. */		if (setgroups(1, &gid)) {			rsyserr(FLOG, errno, "setgroups failed");			io_printf(f_out, "@ERROR: setgroups failed\n");			return -1;		}#endif		if (setuid(uid)) {			rsyserr(FLOG, errno, "setuid %d failed", (int)uid);			io_printf(f_out, "@ERROR: setuid failed\n");			return -1;		}		am_root = (MY_UID() == 0);	}	if (lp_temp_dir(i) && *lp_temp_dir(i)) {		tmpdir = lp_temp_dir(i);		if (strlen(tmpdir) >= MAXPATHLEN - 10) {			rprintf(FLOG,				"the 'temp dir' value for %s is WAY too long -- ignoring.\n",				name);			tmpdir = NULL;		}	}	io_printf(f_out, "@RSYNCD: OK\n");	read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);	orig_argv = argv;	verbose = 0; /* future verbosity is controlled by client options */	ret = parse_arguments(&argc, (const char ***) &argv);	if (protect_args && ret) {		orig_early_argv = orig_argv;		protect_args = 2;		read_args(f_in, name, line, sizeof line, 1, &argv, &argc, &request);		orig_argv = argv;		ret = parse_arguments(&argc, (const char ***) &argv);	} else		orig_early_argv = NULL;	if (pre_exec_pid) {		err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,					  orig_early_argv, orig_argv);	}	if (orig_early_argv)		free(orig_early_argv);	am_server = 1; /* Don't let someone try to be tricky. */	quiet = 0;	if (lp_ignore_errors(module_id))		ignore_errors = 1;	if (write_batch < 0)		dry_run = 1;	if (lp_fake_super(i)) {		if (preserve_xattrs > 1)			preserve_xattrs = 1;		am_root = -1;	} else if (am_root < 0) /* Treat --fake-super from client as --super. */		am_root = 2;	if (filesfrom_fd == 0)		filesfrom_fd = f_in;	if (request) {		if (*auth_user) {			rprintf(FLOG, "rsync %s %s from %s@%s (%s)\n",				am_sender ? "on" : "to",				request, auth_user, host, addr);		} else {			rprintf(FLOG, "rsync %s %s from %s (%s)\n",				am_sender ? "on" : "to",				request, host, addr);		}		free(request);	}#ifndef DEBUG	/* don't allow the logs to be flooded too fast */	if (verbose > lp_max_verbosity(i))		verbose = lp_max_verbosity(i);#endif	if (protocol_version < 23	    && (protocol_version == 22 || am_sender))		io_start_multiplex_out();	else if (!ret || err_msg) {		/* We have to get I/O multiplexing started so that we can		 * get the error back to the client.  This means getting		 * the protocol setup finished first in later versions. */		setup_protocol(f_out, f_in);		if (!am_sender) {			/* Since we failed in our option parsing, we may not			 * have finished parsing that the client sent us a			 * --files-from option, so look for it manually.			 * Without this, the socket would be in the wrong			 * state for the upcoming error message. */			if (!files_from) {				int i;				for (i = 0; i < argc; i++) {					if (strncmp(argv[i], "--files-from", 12) == 0) {						files_from = "";						break;					}				}			}			if (files_from)				write_byte(f_out, 0);		}		io_start_multiplex_out();	}	if (!ret || err_msg) {		if (err_msg)			rwrite(FERROR, err_msg, strlen(err_msg), 0);		else			option_error();		msleep(400);		exit_cleanup(RERR_UNSUPPORTED);	}#ifdef ICONV_OPTION	if (!iconv_opt) {		if (ic_send != (iconv_t)-1) {			iconv_close(ic_send);			ic_send = (iconv_t)-1;		}		if (ic_recv != (iconv_t)-1) {			iconv_close(ic_recv);			ic_recv = (iconv_t)-1;		}	}#endif	if (!numeric_ids	 && (use_chroot ? lp_numeric_ids(i) != False : lp_numeric_ids(i) == True))		numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */	if (lp_timeout(i) && lp_timeout(i) > io_timeout)		set_io_timeout(lp_timeout(i));	/* If we have some incoming/outgoing chmod changes, append them to	 * any user-specified changes (making our changes have priority).	 * We also get a pointer to just our changes so that a receiver	 * process can use them separately if --perms wasn't specified. */	if (am_sender)		p = lp_outgoing_chmod(i);	else		p = lp_incoming_chmod(i);	if (*p && !(daemon_chmod_modes = parse_chmod(p, &chmod_modes))) {		rprintf(FLOG, "Invalid \"%sing chmod\" directive: %s\n",			am_sender ? "outgo" : "incom", p);	}	start_server(f_in, f_out, argc, argv);	return 0;}/* send a list of available modules to the client. Don't list those   with "list = False". */static void send_listing(int fd){	int n = lp_numservices();	int i;	for (i = 0; i < n; i++) {		if (lp_list(i))			io_printf(fd, "%-15s\t%s\n", lp_name(i), lp_comment(i));	}	if (protocol_version >= 25)		io_printf(fd,"@RSYNCD: EXIT\n");}static int load_config(int globals_only){	if (!config_file) {		if (am_server && am_root <= 0)			config_file = RSYNCD_USERCONF;		else			config_file = RSYNCD_SYSCONF;	}	return lp_load(config_file, globals_only);}/* this is called when a connection is established to a client   and we want to start talking. The setup of the system is done from   here */int start_daemon(int f_in, int f_out){	char line[1024];	char *addr, *host;	int i;	io_set_sock_fds(f_in, f_out);	/* We must load the config file before calling any function that	 * might cause log-file output to occur.  This ensures that the	 * "log file" param gets honored for the 2 non-forked use-cases	 * (when rsync is run by init and run by a remote shell). */	if (!load_config(0))		exit_cleanup(RERR_SYNTAX);	addr = client_addr(f_in);	host = client_name(f_in);	rprintf(FLOG, "connect from %s (%s)\n", host, addr);	if (!am_server) {		set_socket_options(f_in, "SO_KEEPALIVE");		set_nonblocking(f_in);	}	if (exchange_protocols(f_in, f_out, line, sizeof line, 0) < 0)		return -1;	line[0] = 0;	if (!read_line_old(f_in, line, sizeof line))		return -1;	if (!*line || strcmp(line, "#list") == 0) {		rprintf(FLOG, "module-list request from %s (%s)\n",			host, addr);		send_listing(f_out);		return -1;	}	if (*line == '#') {		/* it's some sort of command that I don't understand */		io_printf(f_out, "@ERROR: Unknown command '%s'\n", line);		return -1;	}	if ((i = lp_number(line)) < 0) {		rprintf(FLOG, "unknown module '%s' tried from %s (%s)\n",			line, host, addr);		io_printf(f_out, "@ERROR: Unknown module '%s'\n", line);		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);}static void create_pid_file(void){	char *pid_file = lp_pid_file();	char pidbuf[16];	pid_t pid = getpid();	int fd, len;	if (!pid_file || !*pid_file)		return;	cleanup_set_pid(pid);	if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666 & ~orig_umask)) == -1) {	  failure:		cleanup_set_pid(0);		fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno));		rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);		exit_cleanup(RERR_FILEIO);	}	snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);	len = strlen(pidbuf);	if (write(fd, pidbuf, len) != len)		goto failure;	close(fd);}/* Become a daemon, discarding the controlling terminal. */static void become_daemon(void){	int i;	pid_t pid = fork();	if (pid) {		if (pid < 0) {			fprintf(stderr, "failed to fork: %s\n", strerror(errno));			exit_cleanup(RERR_FILEIO);		}		_exit(0);	}	create_pid_file();	/* detach from the terminal */#ifdef HAVE_SETSID	setsid();#elif defined TIOCNOTTY	i = open("/dev/tty", O_RDWR);	if (i >= 0) {		ioctl(i, (int)TIOCNOTTY, (char *)0);		close(i);	}#endif	/* make sure that stdin, stdout an stderr don't stuff things	 * up (library functions, for example) */	for (i = 0; i < 3; i++) {		close(i);		open("/dev/null", O_RDWR);	}}int daemon_main(void){	if (is_a_socket(STDIN_FILENO)) {		int i;		/* we are running via inetd - close off stdout and		 * stderr so that library functions (and getopt) don't		 * try to use them. Redirect them to /dev/null */		for (i = 1; i < 3; i++) {			close(i);			open("/dev/null", O_RDWR);		}		return start_daemon(STDIN_FILENO, STDIN_FILENO);	}	if (!load_config(1)) {		fprintf(stderr, "Failed to parse config file: %s\n", config_file);		exit_cleanup(RERR_SYNTAX);	}	if (no_detach)		create_pid_file();	else		become_daemon();	if (rsync_port == 0 && (rsync_port = lp_rsync_port()) == 0)		rsync_port = RSYNC_PORT;	if (bind_address == NULL && *lp_bind_address())		bind_address = lp_bind_address();	log_init(0);	rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n",		RSYNC_VERSION, rsync_port);	/* TODO: If listening on a particular address, then show that	 * address too.  In fact, why not just do inet_ntop on the	 * local address??? */	start_accept_loop(rsync_port, start_daemon);	return -1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -