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

📄 main.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * The startup routines, including main(), for rsync. * * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org> * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org> * Copyright (C) 2003-2008 Wayne Davison * * 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"#include "ifuncs.h"#include "io.h"#if defined CONFIG_LOCALE && defined HAVE_LOCALE_H#include <locale.h>#endifextern int verbose;extern int dry_run;extern int list_only;extern int am_root;extern int am_server;extern int am_sender;extern int am_generator;extern int am_daemon;extern int inc_recurse;extern int blocking_io;extern int remove_source_files;extern int need_messages_from_generator;extern int kluge_around_eof;extern int do_stats;extern int got_xfer_error;extern int module_id;extern int copy_links;extern int copy_dirlinks;extern int copy_unsafe_links;extern int keep_dirlinks;extern int preserve_hard_links;extern int protocol_version;extern int file_total;extern int recurse;extern int xfer_dirs;extern int protect_args;extern int relative_paths;extern int sanitize_paths;extern int curr_dir_depth;extern int curr_dir_len;extern int module_id;extern int rsync_port;extern int whole_file;extern int read_batch;extern int write_batch;extern int batch_fd;extern int filesfrom_fd;extern int connect_timeout;extern pid_t cleanup_child_pid;extern unsigned int module_dirlen;extern struct stats stats;extern char *filesfrom_host;extern char *partial_dir;extern char *dest_option;extern char *basis_dir[];extern char *rsync_path;extern char *shell_cmd;extern char *batch_name;extern char *password_file;extern char curr_dir[MAXPATHLEN];extern struct file_list *first_flist;extern struct filter_list_struct daemon_filter_list;uid_t our_uid;int local_server = 0;int daemon_over_rsh = 0;mode_t orig_umask = 0;int batch_gen_fd = -1;/* There's probably never more than at most 2 outstanding child processes, * but set it higher, just in case. */#define MAXCHILDPROCS 7#ifdef HAVE_SIGACTION# ifdef HAVE_SIGPROCMASK#  define SIGACTMASK(n,h) SIGACTION(n,h), sigaddset(&sigmask,(n))# else#  define SIGACTMASK(n,h) SIGACTION(n,h)# endifstatic struct sigaction sigact;#endifstruct pid_status {	pid_t pid;	int status;} pid_stat_table[MAXCHILDPROCS];static time_t starttime, endtime;static int64 total_read, total_written;static void show_malloc_stats(void);/* Works like waitpid(), but if we already harvested the child pid in our * remember_children(), we succeed instead of returning an error. */pid_t wait_process(pid_t pid, int *status_ptr, int flags){	pid_t waited_pid;		do {		waited_pid = waitpid(pid, status_ptr, flags);	} while (waited_pid == -1 && errno == EINTR);	if (waited_pid == -1 && errno == ECHILD) {		/* Status of requested child no longer available:  check to		 * see if it was processed by remember_children(). */		int cnt;		for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {			if (pid == pid_stat_table[cnt].pid) {				*status_ptr = pid_stat_table[cnt].status;				pid_stat_table[cnt].pid = 0;				return pid;			}		}	}	return waited_pid;}/* Wait for a process to exit, calling io_flush while waiting. */static void wait_process_with_flush(pid_t pid, int *exit_code_ptr){	pid_t waited_pid;	int status;	while ((waited_pid = wait_process(pid, &status, WNOHANG)) == 0) {		msleep(20);		io_flush(FULL_FLUSH);	}	/* TODO: If the child exited on a signal, then log an	 * appropriate error message.  Perhaps we should also accept a	 * message describing the purpose of the child.  Also indicate	 * this to the caller so that they know something went wrong. */	if (waited_pid < 0) {		rsyserr(FERROR, errno, "waitpid");		*exit_code_ptr = RERR_WAITCHILD;	} else if (!WIFEXITED(status)) {#ifdef WCOREDUMP		if (WCOREDUMP(status))			*exit_code_ptr = RERR_CRASHED;		else#endif		if (WIFSIGNALED(status))			*exit_code_ptr = RERR_TERMINATED;		else			*exit_code_ptr = RERR_WAITCHILD;	} else		*exit_code_ptr = WEXITSTATUS(status);}/* This function gets called from all 3 processes.  We want the client side * to actually output the text, but the sender is the only process that has * all the stats we need.  So, if we're a client sender, we do the report. * If we're a server sender, we write the stats on the supplied fd.  If * we're the client receiver we read the stats from the supplied fd and do * the report.  All processes might also generate a set of debug stats, if * the verbose level is high enough (this is the only thing that the * generator process and the server receiver ever do here). */static void handle_stats(int f){	endtime = time(NULL);	/* Cache two stats because the read/write code can change it. */	total_read = stats.total_read;	total_written = stats.total_written;	if (do_stats && verbose > 1) {		/* These come out from every process */		show_malloc_stats();		show_flist_stats();	}	if (am_generator)		return;	if (am_daemon) {		if (f == -1 || !am_sender)			return;	}	if (am_server) {		if (am_sender) {			write_varlong30(f, total_read, 3);			write_varlong30(f, total_written, 3);			write_varlong30(f, stats.total_size, 3);			if (protocol_version >= 29) {				write_varlong30(f, stats.flist_buildtime, 3);				write_varlong30(f, stats.flist_xfertime, 3);			}		}		return;	}	/* this is the client */	if (f < 0 && !am_sender) /* e.g. when we got an empty file list. */		;	else if (!am_sender) {		/* Read the first two in opposite order because the meaning of		 * read/write swaps when switching from sender to receiver. */		total_written = read_varlong30(f, 3);		total_read = read_varlong30(f, 3);		stats.total_size = read_varlong30(f, 3);		if (protocol_version >= 29) {			stats.flist_buildtime = read_varlong30(f, 3);			stats.flist_xfertime = read_varlong30(f, 3);		}	} else if (write_batch) {		/* The --read-batch process is going to be a client		 * receiver, so we need to give it the stats. */		write_varlong30(batch_fd, total_read, 3);		write_varlong30(batch_fd, total_written, 3);		write_varlong30(batch_fd, stats.total_size, 3);		if (protocol_version >= 29) {			write_varlong30(batch_fd, stats.flist_buildtime, 3);			write_varlong30(batch_fd, stats.flist_xfertime, 3);		}	}}static void output_summary(void){	if (do_stats) {		rprintf(FCLIENT, "\n");		rprintf(FINFO,"Number of files: %d\n", stats.num_files);		rprintf(FINFO,"Number of files transferred: %d\n",			stats.num_transferred_files);		rprintf(FINFO,"Total file size: %s bytes\n",			human_num(stats.total_size));		rprintf(FINFO,"Total transferred file size: %s bytes\n",			human_num(stats.total_transferred_size));		rprintf(FINFO,"Literal data: %s bytes\n",			human_num(stats.literal_data));		rprintf(FINFO,"Matched data: %s bytes\n",			human_num(stats.matched_data));		rprintf(FINFO,"File list size: %s\n",			human_num(stats.flist_size));		if (stats.flist_buildtime) {			rprintf(FINFO,				"File list generation time: %.3f seconds\n",				(double)stats.flist_buildtime / 1000);			rprintf(FINFO,				"File list transfer time: %.3f seconds\n",				(double)stats.flist_xfertime / 1000);		}		rprintf(FINFO,"Total bytes sent: %s\n",			human_num(total_written));		rprintf(FINFO,"Total bytes received: %s\n",			human_num(total_read));	}	if (verbose || do_stats) {		rprintf(FCLIENT, "\n");		rprintf(FINFO,			"sent %s bytes  received %s bytes  %s bytes/sec\n",			human_num(total_written), human_num(total_read),			human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2));		rprintf(FINFO, "total size is %s  speedup is %.2f%s\n",			human_num(stats.total_size),			(double)stats.total_size / (total_written+total_read),			write_batch < 0 ? " (BATCH ONLY)" : dry_run ? " (DRY RUN)" : "");	}	fflush(stdout);	fflush(stderr);}/** * If our C library can get malloc statistics, then show them to FINFO **/static void show_malloc_stats(void){#ifdef HAVE_MALLINFO	struct mallinfo mi;	mi = mallinfo();	rprintf(FCLIENT, "\n");	rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",		getpid(), am_server ? "server " : "",		am_daemon ? "daemon " : "", who_am_i());	rprintf(FINFO, "  arena:     %10ld   (bytes from sbrk)\n",		(long)mi.arena);	rprintf(FINFO, "  ordblks:   %10ld   (chunks not in use)\n",		(long)mi.ordblks);	rprintf(FINFO, "  smblks:    %10ld\n",		(long)mi.smblks);	rprintf(FINFO, "  hblks:     %10ld   (chunks from mmap)\n",		(long)mi.hblks);	rprintf(FINFO, "  hblkhd:    %10ld   (bytes from mmap)\n",		(long)mi.hblkhd);	rprintf(FINFO, "  allmem:    %10ld   (bytes from sbrk + mmap)\n",		(long)mi.arena + mi.hblkhd);	rprintf(FINFO, "  usmblks:   %10ld\n",		(long)mi.usmblks);	rprintf(FINFO, "  fsmblks:   %10ld\n",		(long)mi.fsmblks);	rprintf(FINFO, "  uordblks:  %10ld   (bytes used)\n",		(long)mi.uordblks);	rprintf(FINFO, "  fordblks:  %10ld   (bytes free)\n",		(long)mi.fordblks);	rprintf(FINFO, "  keepcost:  %10ld   (bytes in releasable chunk)\n",		(long)mi.keepcost);#endif /* HAVE_MALLINFO */}/* Start the remote shell.   cmd may be NULL to use the default. */static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, int remote_argc,		    int *f_in_p, int *f_out_p){	int i, argc = 0;	char *args[MAX_ARGS];	pid_t pid;	int dash_l_set = 0;	if (!read_batch && !local_server) {		char *t, *f, in_quote = '\0';		char *rsh_env = getenv(RSYNC_RSH_ENV);		if (!cmd)			cmd = rsh_env;		if (!cmd)			cmd = RSYNC_RSH;		cmd = strdup(cmd); /* MEMORY LEAK */		if (!cmd)			goto oom;		for (t = f = cmd; *f; f++) {			if (*f == ' ')				continue;			/* Comparison leaves rooms for server_options(). */			if (argc >= MAX_ARGS - MAX_SERVER_ARGS)				goto arg_overflow;			args[argc++] = t;			while (*f != ' ' || in_quote) {				if (!*f) {					if (in_quote) {						rprintf(FERROR,						    "Missing trailing-%c in remote-shell command.\n",						    in_quote);						exit_cleanup(RERR_SYNTAX);					}					f--;					break;				}				if (*f == '\'' || *f == '"') {					if (!in_quote) {						in_quote = *f++;						continue;					}					if (*f == in_quote && *++f != in_quote) {						in_quote = '\0';						continue;					}				}				*t++ = *f++;			}			*t++ = '\0';		}		/* check to see if we've already been given '-l user' in		 * the remote-shell command */		for (i = 0; i < argc-1; i++) {			if (!strcmp(args[i], "-l") && args[i+1][0] != '-')				dash_l_set = 1;		}#ifdef HAVE_REMSH		/* remsh (on HPUX) takes the arguments the other way around */		args[argc++] = machine;		if (user && !(daemon_over_rsh && dash_l_set)) {			args[argc++] = "-l";			args[argc++] = user;		}#else		if (user && !(daemon_over_rsh && dash_l_set)) {			args[argc++] = "-l";			args[argc++] = user;		}		args[argc++] = machine;#endif		args[argc++] = rsync_path;		if (blocking_io < 0) {			char *cp;			if ((cp = strrchr(cmd, '/')) != NULL)				cp++;			else				cp = cmd;			if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)				blocking_io = 1;		}		server_options(args,&argc);		if (argc >= MAX_ARGS - 2)			goto arg_overflow;	}	args[argc++] = ".";	if (!daemon_over_rsh) {		while (remote_argc > 0) {			if (argc >= MAX_ARGS - 1) {			  arg_overflow:				rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");				exit_cleanup(RERR_SYNTAX);			}			args[argc++] = *remote_argv++;			remote_argc--;		}	}	args[argc] = NULL;	if (verbose > 3) {		for (i = 0; i < argc; i++)			rprintf(FCLIENT, "cmd[%d]=%s ", i, args[i]);		rprintf(FCLIENT, "\n");	}	if (read_batch) {		int from_gen_pipe[2];		set_allow_inc_recurse();		if (fd_pair(from_gen_pipe) < 0) {			rsyserr(FERROR, errno, "pipe");			exit_cleanup(RERR_IPC);		}		batch_gen_fd = from_gen_pipe[0];		*f_out_p = from_gen_pipe[1];		*f_in_p = batch_fd;		pid = (pid_t)-1; /* no child pid */#ifdef ICONV_CONST		setup_iconv();#endif	} else if (local_server) {		/* If the user didn't request --[no-]whole-file, force		 * it on, but only if we're not batch processing. */		if (whole_file < 0 && !write_batch)			whole_file = 1;		set_allow_inc_recurse();		pid = local_child(argc, args, f_in_p, f_out_p, child_main);#ifdef ICONV_CONST		setup_iconv();#endif	} else {		pid = piped_child(args, f_in_p, f_out_p);#ifdef ICONV_CONST		setup_iconv();#endif		if (protect_args && !daemon_over_rsh)			send_protected_args(*f_out_p, args);	}	return pid;  oom:	out_of_memory("do_cmd");	return 0; /* not reached */}/* The receiving side operates in one of two modes: * * 1. it receives any number of files into a destination directory, * placing them according to their names in the file-list. * * 2. it receives a single file and saves it using the name in the * destination path instead of its file-list name.  This requires a * "local name" for writing out the destination file. * * So, our task is to figure out what mode/local-name we need. * For mode 1, we change into the destination directory and return NULL. * For mode 2, we change into the directory containing the destination * file (if we aren't already there) and return the local-name. */static char *get_local_name(struct file_list *flist, char *dest_path){	STRUCT_STAT st;	int statret;	char *cp;	if (verbose > 2) {		rprintf(FINFO, "get_local_name count=%d %s\n",			file_total, NS(dest_path));

⌨️ 快捷键说明

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