X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/c5260884d6885538ccc5640aebcfab8c3aa6c1ac..4fd842f98df4970f6e49a0365dbed60774e56c09:/main.c diff --git a/main.c b/main.c index 21111f11..494adfbc 100644 --- a/main.c +++ b/main.c @@ -4,12 +4,11 @@ * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison + * Copyright (C) 2003-2007 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 2 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -17,11 +16,11 @@ * 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + * with this program; if not, visit the http://fsf.org website. */ #include "rsync.h" +#include "io.h" #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H #include #endif @@ -34,8 +33,9 @@ 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_sent_files; +extern int remove_source_files; extern int daemon_over_rsh; extern int need_messages_from_generator; extern int kluge_around_eof; @@ -47,17 +47,18 @@ extern int copy_dirlinks; extern int keep_dirlinks; extern int preserve_hard_links; extern int protocol_version; +extern int file_total; extern int recurse; 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 batch_gen_fd; extern int filesfrom_fd; extern pid_t cleanup_child_pid; extern struct stats stats; @@ -67,11 +68,14 @@ 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 filter_list_struct server_filter_list; int local_server = 0; +int new_root_dir = 0; mode_t orig_umask = 0; -struct file_list *the_file_list; +int batch_gen_fd = -1; /* There's probably never more than at most 2 outstanding child processes, * but set it higher, just in case. */ @@ -100,7 +104,11 @@ static void show_malloc_stats(void); * 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 = waitpid(pid, status_ptr, 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 @@ -182,12 +190,12 @@ static void handle_stats(int f) if (am_server) { if (am_sender) { - write_longint(f, total_read); - write_longint(f, total_written); - write_longint(f, stats.total_size); + write_varlong30(f, total_read, 3); + write_varlong30(f, total_written, 3); + write_varlong30(f, stats.total_size, 3); if (protocol_version >= 29) { - write_longint(f, stats.flist_buildtime); - write_longint(f, stats.flist_xfertime); + write_varlong30(f, stats.flist_buildtime, 3); + write_varlong30(f, stats.flist_xfertime, 3); } } return; @@ -200,22 +208,22 @@ static void handle_stats(int f) 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_longint(f); - total_read = read_longint(f); - stats.total_size = read_longint(f); + 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_longint(f); - stats.flist_xfertime = read_longint(f); + 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_longint(batch_fd, total_read); - write_longint(batch_fd, total_written); - write_longint(batch_fd, stats.total_size); + 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_longint(batch_fd, stats.flist_buildtime); - write_longint(batch_fd, stats.flist_xfertime); + write_varlong30(batch_fd, stats.flist_buildtime, 3); + write_varlong30(batch_fd, stats.flist_xfertime, 3); } } } @@ -223,7 +231,8 @@ static void handle_stats(int f) static void output_summary(void) { if (do_stats) { - rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files); + 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", @@ -234,7 +243,8 @@ static void output_summary(void) human_num(stats.literal_data)); rprintf(FINFO,"Matched data: %s bytes\n", human_num(stats.matched_data)); - rprintf(FINFO,"File list size: %d\n", stats.flist_size); + 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", @@ -250,8 +260,9 @@ static void output_summary(void) } if (verbose || do_stats) { + rprintf(FCLIENT, "\n"); rprintf(FINFO, - "\nsent %s bytes received %s bytes %s bytes/sec\n", + "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\n", @@ -274,7 +285,8 @@ static void show_malloc_stats(void) mi = mallinfo(); - rprintf(FINFO, "\n" RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n", + 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", @@ -410,8 +422,8 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path, if (verbose > 3) { for (i = 0; i < argc; i++) - rprintf(FINFO, "cmd[%d]=%s ", i, args[i]); - rprintf(FINFO, "\n"); + rprintf(FCLIENT, "cmd[%d]=%s ", i, args[i]); + rprintf(FCLIENT, "\n"); } if (read_batch) { @@ -452,87 +464,87 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path, * 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 and return - * either a NULL for mode 1, or the local-name for mode 2. We also - * change directory if there are any path components in dest_path. */ + * 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", - flist->count, NS(dest_path)); + file_total, NS(dest_path)); } if (!dest_path || list_only) return NULL; - /* If the destination path refers to an existing directory, enter - * it and use mode 1. If there is something other than a directory - * at the destination path, we must be transferring one file - * (anything at the destination will be overwritten). */ - if (safe_stat(dest_path, &st) == 0) { + /* See what currently exists at the destination. */ + if ((statret = do_stat(dest_path, &st)) == 0) { + /* If the destination is a dir, enter it and use mode 1. */ if (S_ISDIR(st.st_mode)) { - if (sanitize_paths) - die_on_unsafe_path(dest_path, 0); - if (!push_dir(dest_path)) { + if (!push_dir(dest_path, 0)) { rsyserr(FERROR, errno, "push_dir#1 %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } return NULL; } - if (sanitize_paths && S_ISLNK(st.st_mode)) - die_on_unsafe_path(dest_path, 0); - if (flist->count > 1) { + if (file_total > 1) { rprintf(FERROR, "ERROR: destination must be a directory when" " copying more than 1 file\n"); exit_cleanup(RERR_FILESELECT); } - /* Caution: flist->count could be 0! */ - if (flist->count == 1 && S_ISDIR(flist->files[0]->mode)) { + if (file_total == 1 && S_ISDIR(flist->files[0]->mode)) { rprintf(FERROR, "ERROR: cannot overwrite non-directory" " with a directory\n"); exit_cleanup(RERR_FILESELECT); } } else if (errno != ENOENT) { - rsyserr(FERROR, errno, "cannot stat destination %s", + /* If we don't know what's at the destination, fail. */ + rsyserr(FERROR, errno, "ERROR: cannot stat destination %s", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } cp = strrchr(dest_path, '/'); - /* If the destination path ends in a slash or we are transferring - * multiple files, create a directory at the destination path, - * enter the new directory, and use mode 1. */ - if (flist->count > 1 || (cp && !cp[1])) { + /* If we need a destination directory because the transfer is not + * of a single non-directory or the user has requested one via a + * destination path ending in a slash, create one and use mode 1. */ + if (file_total > 1 || (cp && !cp[1])) { /* Lop off the final slash (if any). */ if (cp && !cp[1]) *cp = '\0'; + if (statret == 0) { + rprintf(FERROR, + "ERROR: destination path is not a directory\n"); + exit_cleanup(RERR_SYNTAX); + } + if (mkdir_defmode(dest_path) != 0) { rsyserr(FERROR, errno, "mkdir %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILEIO); } + new_root_dir = 1; + if (verbose) rprintf(FINFO, "created directory %s\n", dest_path); if (dry_run) { - /* Indicate that the destination directory doesn't - * really exist and return mode 1. */ + /* Indicate that dest dir doesn't really exist. */ dry_run++; - return NULL; } - if (sanitize_paths) - die_on_unsafe_path(dest_path, 0); - if (!push_dir(dest_path)) { + if (!push_dir(dest_path, dry_run > 1)) { rsyserr(FERROR, errno, "push_dir#2 %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); @@ -552,9 +564,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path) dest_path = "/"; *cp = '\0'; - if (sanitize_paths) - die_on_unsafe_path(dest_path, 0); - if (!push_dir(dest_path)) { + if (!push_dir(dest_path, 0)) { rsyserr(FERROR, errno, "push_dir#3 %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); @@ -564,31 +574,60 @@ static char *get_local_name(struct file_list *flist, char *dest_path) return cp + 1; } +/* Call this if the destination dir (which is assumed to be in curr_dir) + * does not yet exist and we can't create it due to being in dry-run + * mode. We'll fix dirs that can be relative to the non-existent dir. */ +static void fix_basis_dirs(void) +{ + char **dir, *new, *slash; + int len; + + if (dry_run <= 1) + return; + + slash = strrchr(curr_dir, '/'); + + for (dir = basis_dir; *dir; dir++) { + if (**dir == '/') + continue; + len = curr_dir_len + 1 + strlen(*dir) + 1; + if (!(new = new_array(char, len))) + out_of_memory("fix_basis_dirs"); + if (slash && strncmp(*dir, "../", 3) == 0) { + /* We want to remove only one leading "../" prefix for + * the directory we couldn't create in dry-run mode: + * this ensures that any other ".." references get + * evaluated the same as they would for a live copy. */ + *slash = '\0'; + pathjoin(new, len, curr_dir, *dir + 3); + *slash = '/'; + } else + pathjoin(new, len, curr_dir, *dir); + *dir = new; + } +} /* This is only called by the sender. */ -static void read_final_goodbye(int f_in, int f_out) +static void read_final_goodbye(int f_in) { - int i; + int i, iflags, xlen; + uchar fnamecmp_type; + char xname[MAXPATHLEN]; if (protocol_version < 29) i = read_int(f_in); else { - while ((i = read_int(f_in)) == the_file_list->count - && read_shortint(f_in) == ITEM_IS_NEW) { - /* Forward the keep-alive (no-op) to the receiver. */ - write_int(f_out, the_file_list->count); - write_shortint(f_out, ITEM_IS_NEW); - } + i = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type, + xname, &xlen); } - if (i != -1) { + if (i != NDX_DONE) { rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n", i, who_am_i()); exit_cleanup(RERR_PROTOCOL); } } - static void do_server_sender(int f_in, int f_out, int argc, char *argv[]) { struct file_list *flist; @@ -604,17 +643,16 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[]) exit_cleanup(RERR_SYNTAX); return; } - if (am_daemon && lp_read_only(module_id) && remove_sent_files) { + if (am_daemon && lp_read_only(module_id) && remove_source_files) { rprintf(FERROR, - "ERROR: --remove-sent-files cannot be used with a read-only module\n"); + "ERROR: --remove-%s-files cannot be used with a read-only module\n", + remove_source_files == 1 ? "source" : "sent"); exit_cleanup(RERR_SYNTAX); return; } if (!relative_paths) { - if (sanitize_paths) - die_on_unsafe_path(dir, 0); - if (!push_dir(dir)) { + if (!push_dir(dir, 0)) { rsyserr(FERROR, errno, "push_dir#3 %s failed", full_fname(dir)); exit_cleanup(RERR_FILESELECT); @@ -630,25 +668,22 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[]) } flist = send_file_list(f_out,argc,argv); - if (!flist || flist->count == 0) { + if (!flist || flist->count == 0) exit_cleanup(0); - } - the_file_list = flist; - io_start_buffering_in(); - io_start_buffering_out(); + io_start_buffering_in(f_in); - send_files(flist,f_out,f_in); + send_files(f_in, f_out); io_flush(FULL_FLUSH); handle_stats(f_out); if (protocol_version >= 24) - read_final_goodbye(f_in, f_out); + read_final_goodbye(f_in); io_flush(FULL_FLUSH); exit_cleanup(0); } -static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) +static int do_recv(int f_in, int f_out, char *local_name) { int pid; int exit_code = 0; @@ -658,8 +693,10 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) * points to an identical file won't be replaced by the referent. */ copy_links = copy_dirlinks = 0; +#ifdef SUPPORT_HARD_LINKS if (preserve_hard_links) - init_hard_links(); + match_hard_links(); +#endif if (fd_pair(error_pipe) < 0) { rsyserr(FERROR, errno, "pipe failed in do_recv"); @@ -679,26 +716,32 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) close(f_out); /* we can't let two processes write to the socket at one time */ - close_multiplexing_out(); + io_end_multiplex_out(); /* set place to send errors */ set_msg_fd_out(error_pipe[1]); + io_start_buffering_out(error_pipe[1]); - recv_files(f_in, flist, local_name); + recv_files(f_in, local_name); io_flush(FULL_FLUSH); handle_stats(f_in); - send_msg(MSG_DONE, "", 0); + send_msg(MSG_DONE, "", 1, 0); + write_varlong(error_pipe[1], stats.total_read, 3); io_flush(FULL_FLUSH); /* Handle any keep-alive packets from the post-processing work * that the generator does. */ if (protocol_version >= 29) { + int iflags, xlen; + uchar fnamecmp_type; + char xname[MAXPATHLEN]; + kluge_around_eof = -1; /* This should only get stopped via a USR2 signal. */ - while (read_int(f_in) == flist->count - && read_shortint(f_in) == ITEM_IS_NEW) {} + read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type, + xname, &xlen); rprintf(FERROR, "Invalid packet at end of run [%s]\n", who_am_i()); @@ -713,7 +756,8 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) } am_generator = 1; - close_multiplexing_in(); + + io_end_multiplex_in(); if (write_batch && !am_server) stop_write_batch(); @@ -721,17 +765,18 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) if (f_in != f_out) close(f_in); - io_start_buffering_out(); + io_start_buffering_out(f_out); set_msg_fd_in(error_pipe[0]); + io_start_buffering_in(error_pipe[0]); - generate_files(f_out, flist, local_name); + generate_files(f_out, local_name); handle_stats(-1); io_flush(FULL_FLUSH); if (protocol_version >= 24) { /* send a final goodbye message */ - write_int(f_out, -1); + write_ndx(f_out, NDX_DONE); } io_flush(FULL_FLUSH); @@ -741,8 +786,7 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) return exit_code; } - -static void do_server_recv(int f_in, int f_out, int argc,char *argv[]) +static void do_server_recv(int f_in, int f_out, int argc, char *argv[]) { int exit_code; struct file_list *flist; @@ -771,14 +815,17 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[]) dir = argv[0]; argc--; argv++; - if (!am_daemon && !push_dir(dir)) { + if (!am_daemon && !push_dir(dir, 0)) { rsyserr(FERROR, errno, "push_dir#4 %s failed", full_fname(dir)); exit_cleanup(RERR_FILESELECT); } } - io_start_buffering_in(); + if (protocol_version >= 30) + io_start_multiplex_in(); + else + io_start_buffering_in(f_in); recv_filter_list(f_in); if (filesfrom_fd >= 0) { @@ -792,12 +839,13 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[]) } flist = recv_file_list(f_in); - verbose = save_verbose; if (!flist) { rprintf(FERROR,"server_recv: recv_file_list error\n"); exit_cleanup(RERR_FILESELECT); } - the_file_list = flist; + if (inc_recurse && file_total == 1) + recv_additional_file_list(f_in); + verbose = save_verbose; if (argc > 0) local_name = get_local_name(flist,argv[0]); @@ -808,15 +856,13 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[]) char **dir; for (dir = basis_dir; *dir; dir++) { *dir = sanitize_path(NULL, *dir, NULL, curr_dir_depth, NULL); - die_on_unsafe_path(*dir, 0); } if (partial_dir) { partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, NULL); - /* A relative path gets this checked at every dir change. */ - if (*partial_dir == '/') - die_on_unsafe_path(partial_dir, 0); } } + fix_basis_dirs(); + if (server_filter_list.head) { char **dir; struct filter_list_struct *elp = &server_filter_list; @@ -834,7 +880,7 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[]) } } - exit_code = do_recv(f_in,f_out,flist,local_name); + exit_code = do_recv(f_in, f_out, local_name); exit_cleanup(exit_code); } @@ -853,7 +899,7 @@ void start_server(int f_in, int f_out, int argc, char *argv[]) io_set_sock_fds(f_in, f_out); setup_protocol(f_out, f_in); -#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H +#ifdef ICONV_CONST setup_iconv(); #endif @@ -864,12 +910,10 @@ void start_server(int f_in, int f_out, int argc, char *argv[]) keep_dirlinks = 0; /* Must be disabled on the sender. */ if (need_messages_from_generator) io_start_multiplex_in(); - recv_filter_list(f_in); do_server_sender(f_in, f_out, argc, argv); - } else { + } else do_server_recv(f_in, f_out, argc, argv); - } exit_cleanup(0); } @@ -892,13 +936,10 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) io_set_sock_fds(f_in, f_out); setup_protocol(f_out,f_in); -#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H +#ifdef ICONV_CONST setup_iconv(); #endif - if (protocol_version >= 23 && !read_batch) - io_start_multiplex_in(); - /* We set our stderr file handle to blocking because ssh might have * set it to non-blocking. This can be particularly troublesome if * stderr is a clone of stdout, because ssh would have set our stdout @@ -911,7 +952,10 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) if (am_sender) { keep_dirlinks = 0; /* Must be disabled on the sender. */ - io_start_buffering_out(); + if (protocol_version >= 30) + io_start_multiplex_out(); + else + io_start_buffering_out(f_out); if (!filesfrom_host) set_msg_fd_in(f_in); send_filter_list(f_out); @@ -924,14 +968,16 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) set_msg_fd_in(-1); if (verbose > 3) rprintf(FINFO,"file list sent\n"); - the_file_list = flist; + + if (protocol_version >= 23) + io_start_multiplex_in(); io_flush(NORMAL_FLUSH); - send_files(flist,f_out,f_in); + send_files(f_in, f_out); io_flush(FULL_FLUSH); handle_stats(-1); if (protocol_version >= 24) - read_final_goodbye(f_in, f_out); + read_final_goodbye(f_in); if (pid != -1) { if (verbose > 3) rprintf(FINFO,"client_run waiting on %d\n", (int) pid); @@ -943,8 +989,12 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) exit_cleanup(exit_code); } - if (need_messages_from_generator && !read_batch) - io_start_multiplex_out(); + if (!read_batch) { + if (protocol_version >= 23) + io_start_multiplex_in(); + if (need_messages_from_generator) + io_start_multiplex_out(); + } if (argc == 0) list_only |= 1; @@ -959,12 +1009,15 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) if (write_batch && !am_server) start_write_batch(f_in); flist = recv_file_list(f_in); - the_file_list = flist; + if (inc_recurse && file_total == 1) + recv_additional_file_list(f_in); if (flist && flist->count > 0) { local_name = get_local_name(flist, argv[0]); - exit_code2 = do_recv(f_in, f_out, flist, local_name); + fix_basis_dirs(); + + exit_code2 = do_recv(f_in, f_out, local_name); } else { handle_stats(-1); output_summary(); @@ -980,7 +1033,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) return MAX(exit_code, exit_code2); } -static int copy_argv (char *argv[]) +static int copy_argv(char *argv[]) { int i; @@ -1092,6 +1145,12 @@ static int start_client(int argc, char *argv[]) } } + if (password_file && !daemon_over_rsh) { + rprintf(FERROR, "The --password-file option may only be " + "used when accessing an rsync daemon.\n"); + exit_cleanup(RERR_SYNTAX); + } + if (shell_machine) { p = strrchr(shell_machine,'@'); if (p) { @@ -1222,8 +1281,8 @@ static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig)) char cmd_buf[300]; int ret; - sprintf(cmd_buf, get_panic_action(), - getpid(), getpid()); + snprintf(cmd_buf, sizeof cmd_buf, get_panic_action(), + getpid(), getpid()); /* Unless we failed to execute gdb, we allow the process to * continue. I'm not sure if that's right. */ @@ -1300,7 +1359,7 @@ int main(int argc,char *argv[]) * (implemented by forking "pwd" and reading its output) doesn't * work when there are other child processes. Also, on all systems * that implement getcwd that way "pwd" can't be found after chroot. */ - push_dir(NULL); + push_dir(NULL, 0); init_flist(); @@ -1322,6 +1381,9 @@ int main(int argc,char *argv[]) } if (read_batch) read_stream_flags(batch_fd); + else + write_stream_flags(batch_fd); + } if (write_batch < 0) dry_run = 1;