| 
version 1.1.1.3, 2016/11/01 09:54:32
 | 
version 1.1.1.4, 2021/03/17 00:32:36
 | 
| 
 Line 4
 | 
 Line 4
 | 
 |   * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org> | 
   * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org> | 
 |   * Copyright (C) 1996 Paul Mackerras | 
   * Copyright (C) 1996 Paul Mackerras | 
 |   * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org> | 
   * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org> | 
|  * Copyright (C) 2003-2015 Wayne Davison |  * Copyright (C) 2003-2020 Wayne Davison | 
 |   * | 
   * | 
 |   * This program is free software; you can redistribute it and/or modify | 
   * 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 | 
   * it under the terms of the GNU General Public License as published by | 
| 
 Line 22
 | 
 Line 22
 | 
 |   | 
   | 
 |  #include "rsync.h" | 
  #include "rsync.h" | 
 |  #include "inums.h" | 
  #include "inums.h" | 
 |   | 
  #include "ifuncs.h" | 
 |  #include "io.h" | 
  #include "io.h" | 
 |  #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H | 
  #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H | 
 |  #include <locale.h> | 
  #include <locale.h> | 
 |  #endif | 
  #endif | 
 |   | 
  #include <popt.h> | 
 |   | 
  #ifdef __TANDEM | 
 |   | 
  #include <floss.h(floss_execlp)> | 
 |   | 
  #endif | 
 |   | 
  #ifdef SUPPORT_FORCE_CHANGE | 
 |   | 
  #include <sys/sysctl.h> | 
 |   | 
  #endif | 
 |   | 
  #ifdef SUPPORT_HFS_COMPRESSION | 
 |   | 
  #include <sys/attr.h> /* For getattrlist() */ | 
 |   | 
  #include <sys/mount.h> /* For statfs() */ | 
 |   | 
  #endif | 
 |   | 
   | 
 |  extern int force_change; | 
  extern int force_change; | 
 |  extern int dry_run; | 
  extern int dry_run; | 
| 
 Line 35  extern int am_root;
 | 
 Line 47  extern int am_root;
 | 
 |  extern int am_server; | 
  extern int am_server; | 
 |  extern int am_sender; | 
  extern int am_sender; | 
 |  extern int am_daemon; | 
  extern int am_daemon; | 
 |   | 
  extern int am_dbadmin; | 
 |  extern int inc_recurse; | 
  extern int inc_recurse; | 
 |  extern int blocking_io; | 
  extern int blocking_io; | 
 |  extern int always_checksum; | 
  extern int always_checksum; | 
 |  extern int remove_source_files; | 
  extern int remove_source_files; | 
 |  extern int output_needs_newline; | 
  extern int output_needs_newline; | 
 |   | 
  extern int called_from_signal_handler; | 
 |  extern int need_messages_from_generator; | 
  extern int need_messages_from_generator; | 
 |  extern int kluge_around_eof; | 
  extern int kluge_around_eof; | 
 |  extern int got_xfer_error; | 
  extern int got_xfer_error; | 
 |   | 
  extern int force_change; | 
 |  extern int msgs2stderr; | 
  extern int msgs2stderr; | 
 |  extern int module_id; | 
  extern int module_id; | 
 |  extern int read_only; | 
  extern int read_only; | 
| 
 Line 51  extern int copy_dirlinks;
 | 
 Line 66  extern int copy_dirlinks;
 | 
 |  extern int copy_unsafe_links; | 
  extern int copy_unsafe_links; | 
 |  extern int keep_dirlinks; | 
  extern int keep_dirlinks; | 
 |  extern int preserve_hard_links; | 
  extern int preserve_hard_links; | 
 |   | 
  extern int preserve_hfs_compression; | 
 |  extern int protocol_version; | 
  extern int protocol_version; | 
 |   | 
  extern int always_checksum; | 
 |   | 
  extern int mkpath_dest_arg; | 
 |  extern int file_total; | 
  extern int file_total; | 
 |  extern int recurse; | 
  extern int recurse; | 
 |  extern int xfer_dirs; | 
  extern int xfer_dirs; | 
| 
 Line 76  extern pid_t cleanup_child_pid;
 | 
 Line 94  extern pid_t cleanup_child_pid;
 | 
 |  extern size_t bwlimit_writemax; | 
  extern size_t bwlimit_writemax; | 
 |  extern unsigned int module_dirlen; | 
  extern unsigned int module_dirlen; | 
 |  extern BOOL flist_receiving_enabled; | 
  extern BOOL flist_receiving_enabled; | 
 |  extern BOOL shutting_down; | 
   | 
 |  extern BOOL want_progress_now; | 
  extern BOOL want_progress_now; | 
 |   | 
  extern BOOL shutting_down; | 
 |  extern int backup_dir_len; | 
  extern int backup_dir_len; | 
 |  extern int basis_dir_cnt; | 
  extern int basis_dir_cnt; | 
 |   | 
  extern int default_af_hint; | 
 |  extern struct stats stats; | 
  extern struct stats stats; | 
 |  extern char *stdout_format; | 
  extern char *stdout_format; | 
 |  extern char *logfile_format; | 
  extern char *logfile_format; | 
 |  extern char *filesfrom_host; | 
  extern char *filesfrom_host; | 
 |  extern char *partial_dir; | 
  extern char *partial_dir; | 
 |  extern char *dest_option; | 
   | 
 |  extern char *rsync_path; | 
  extern char *rsync_path; | 
 |   | 
  extern char *db_config; | 
 |  extern char *shell_cmd; | 
  extern char *shell_cmd; | 
 |  extern char *batch_name; | 
   | 
 |  extern char *password_file; | 
  extern char *password_file; | 
 |  extern char *backup_dir; | 
  extern char *backup_dir; | 
 |   | 
  extern char *copy_as; | 
 |   | 
  extern char *tmpdir; | 
 |  extern char curr_dir[MAXPATHLEN]; | 
  extern char curr_dir[MAXPATHLEN]; | 
 |  extern char backup_dir_buf[MAXPATHLEN]; | 
  extern char backup_dir_buf[MAXPATHLEN]; | 
 |  extern char *basis_dir[MAX_BASIS_DIRS+1]; | 
  extern char *basis_dir[MAX_BASIS_DIRS+1]; | 
| 
 Line 102  gid_t our_gid;
 | 
 Line 122  gid_t our_gid;
 | 
 |  int am_receiver = 0;  /* Only set to 1 after the receiver/generator fork. */ | 
  int am_receiver = 0;  /* Only set to 1 after the receiver/generator fork. */ | 
 |  int am_generator = 0; /* Only set to 1 after the receiver/generator fork. */ | 
  int am_generator = 0; /* Only set to 1 after the receiver/generator fork. */ | 
 |  int local_server = 0; | 
  int local_server = 0; | 
| int daemon_over_rsh = 0; | int daemon_connection = 0; /* 0 = no daemon, 1 = daemon via remote shell, -1 = daemon via socket */ | 
 |  mode_t orig_umask = 0; | 
  mode_t orig_umask = 0; | 
 |  int batch_gen_fd = -1; | 
  int batch_gen_fd = -1; | 
 |  int sender_keeps_checksum = 0; | 
  int sender_keeps_checksum = 0; | 
 |   | 
  int fs_supports_hfs_compression = 0; | 
 |   | 
  int raw_argc, cooked_argc; | 
 |   | 
  char **raw_argv, **cooked_argv; | 
 |   | 
   | 
 |  /* There's probably never more than at most 2 outstanding child processes, | 
  /* There's probably never more than at most 2 outstanding child processes, | 
 |   * but set it higher, just in case. */ | 
   * but set it higher, just in case. */ | 
| 
 Line 156  pid_t wait_process(pid_t pid, int *status_ptr, int fla
 | 
 Line 179  pid_t wait_process(pid_t pid, int *status_ptr, int fla
 | 
 |          return waited_pid; | 
          return waited_pid; | 
 |  } | 
  } | 
 |   | 
   | 
 |   | 
  int shell_exec(const char *cmd) | 
 |   | 
  { | 
 |   | 
          char *shell = getenv("RSYNC_SHELL"); | 
 |   | 
          int status; | 
 |   | 
          pid_t pid; | 
 |   | 
   | 
 |   | 
          if (!shell) | 
 |   | 
                  return system(cmd); | 
 |   | 
   | 
 |   | 
          if ((pid = fork()) < 0) | 
 |   | 
                  return -1; | 
 |   | 
   | 
 |   | 
          if (pid == 0) { | 
 |   | 
                  execlp(shell, shell, "-c", cmd, NULL); | 
 |   | 
                  _exit(1); | 
 |   | 
          } | 
 |   | 
   | 
 |   | 
          int ret = wait_process(pid, &status, 0); | 
 |   | 
          return ret < 0 ? -1 : status; | 
 |   | 
  } | 
 |   | 
   | 
 |  /* Wait for a process to exit, calling io_flush while waiting. */ | 
  /* Wait for a process to exit, calling io_flush while waiting. */ | 
| static void wait_process_with_flush(pid_t pid, int *exit_code_ptr) | void wait_process_with_flush(pid_t pid, int *exit_code_ptr) | 
 |  { | 
  { | 
 |          pid_t waited_pid; | 
          pid_t waited_pid; | 
 |          int status; | 
          int status; | 
| 
 Line 184  static void wait_process_with_flush(pid_t pid, int *ex
 | 
 Line 228  static void wait_process_with_flush(pid_t pid, int *ex
 | 
 |                          *exit_code_ptr = RERR_TERMINATED; | 
                          *exit_code_ptr = RERR_TERMINATED; | 
 |                  else | 
                  else | 
 |                          *exit_code_ptr = RERR_WAITCHILD; | 
                          *exit_code_ptr = RERR_WAITCHILD; | 
|         } else |         } else { | 
 |                  *exit_code_ptr = WEXITSTATUS(status); | 
                  *exit_code_ptr = WEXITSTATUS(status); | 
 |   | 
                  if (*exit_code_ptr == RERR_WECRASHED) | 
 |   | 
                          *exit_code_ptr = RERR_CRASHED; | 
 |   | 
          } | 
 |  } | 
  } | 
 |   | 
   | 
 |  void write_del_stats(int f) | 
  void write_del_stats(int f) | 
| 
 Line 212  void read_del_stats(int f)
 | 
 Line 259  void read_del_stats(int f)
 | 
 |          stats.deleted_files += stats.deleted_specials = read_varint(f); | 
          stats.deleted_files += stats.deleted_specials = read_varint(f); | 
 |  } | 
  } | 
 |   | 
   | 
 |   | 
  static void become_copy_as_user() | 
 |   | 
  { | 
 |   | 
          char *gname; | 
 |   | 
          uid_t uid; | 
 |   | 
          gid_t gid; | 
 |   | 
   | 
 |   | 
          if (!copy_as) | 
 |   | 
                  return; | 
 |   | 
   | 
 |   | 
          if (DEBUG_GTE(CMD, 2)) | 
 |   | 
                  rprintf(FINFO, "[%s] copy_as=%s\n", who_am_i(), copy_as); | 
 |   | 
   | 
 |   | 
          if ((gname = strchr(copy_as, ':')) != NULL) | 
 |   | 
                  *gname++ = '\0'; | 
 |   | 
   | 
 |   | 
          if (!user_to_uid(copy_as, &uid, True)) { | 
 |   | 
                  rprintf(FERROR, "Invalid copy-as user: %s\n", copy_as); | 
 |   | 
                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
          } | 
 |   | 
   | 
 |   | 
          if (gname) { | 
 |   | 
                  if (!group_to_gid(gname, &gid, True)) { | 
 |   | 
                          rprintf(FERROR, "Invalid copy-as group: %s\n", gname); | 
 |   | 
                          exit_cleanup(RERR_SYNTAX); | 
 |   | 
                  } | 
 |   | 
          } else { | 
 |   | 
                  struct passwd *pw; | 
 |   | 
                  if ((pw = getpwuid(uid)) == NULL) { | 
 |   | 
                          rsyserr(FERROR, errno, "getpwuid failed"); | 
 |   | 
                          exit_cleanup(RERR_SYNTAX); | 
 |   | 
                  } | 
 |   | 
                  gid = pw->pw_gid; | 
 |   | 
          } | 
 |   | 
   | 
 |   | 
          if (setgid(gid) < 0) { | 
 |   | 
                  rsyserr(FERROR, errno, "setgid failed"); | 
 |   | 
                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
          } | 
 |   | 
  #ifdef HAVE_SETGROUPS | 
 |   | 
          if (setgroups(1, &gid)) { | 
 |   | 
                  rsyserr(FERROR, errno, "setgroups failed"); | 
 |   | 
                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
          } | 
 |   | 
  #endif | 
 |   | 
  #ifdef HAVE_INITGROUPS | 
 |   | 
          if (!gname && initgroups(copy_as, gid) < 0) { | 
 |   | 
                  rsyserr(FERROR, errno, "initgroups failed"); | 
 |   | 
                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
          } | 
 |   | 
  #endif | 
 |   | 
   | 
 |   | 
          if (setuid(uid) < 0 | 
 |   | 
  #ifdef HAVE_SETEUID | 
 |   | 
           || seteuid(uid) < 0 | 
 |   | 
  #endif | 
 |   | 
          ) { | 
 |   | 
                  rsyserr(FERROR, errno, "setuid failed"); | 
 |   | 
                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
          } | 
 |   | 
   | 
 |   | 
          our_uid = MY_UID(); | 
 |   | 
          our_gid = MY_GID(); | 
 |   | 
          am_root = (our_uid == ROOT_UID); | 
 |   | 
   | 
 |   | 
          if (gname) | 
 |   | 
                  gname[-1] = ':'; | 
 |   | 
  } | 
 |   | 
   | 
 |  /* This function gets called from all 3 processes.  We want the client side | 
  /* 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 | 
   * 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. | 
   * all the stats we need.  So, if we're a client sender, we do the report. | 
| 
 Line 304  static void output_itemized_counts(const char *prefix,
 | 
 Line 419  static void output_itemized_counts(const char *prefix,
 | 
 |          rprintf(FINFO, "%s: %s%s\n", prefix, comma_num(total), buf); | 
          rprintf(FINFO, "%s: %s%s\n", prefix, comma_num(total), buf); | 
 |  } | 
  } | 
 |   | 
   | 
 |   | 
  static const char *bytes_per_sec_human_dnum(void) | 
 |   | 
  { | 
 |   | 
          if (starttime == (time_t)-1 || endtime == (time_t)-1) | 
 |   | 
                  return "UNKNOWN"; | 
 |   | 
          return human_dnum((total_written + total_read) / (0.5 + (endtime - starttime)), 2); | 
 |   | 
  } | 
 |   | 
   | 
 |  static void output_summary(void) | 
  static void output_summary(void) | 
 |  { | 
  { | 
 |          if (INFO_GTE(STATS, 2)) { | 
          if (INFO_GTE(STATS, 2)) { | 
| 
 Line 344  static void output_summary(void)
 | 
 Line 466  static void output_summary(void)
 | 
 |                  rprintf(FINFO, | 
                  rprintf(FINFO, | 
 |                          "sent %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_num(total_written), human_num(total_read), | 
|                         human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2)); |                         bytes_per_sec_human_dnum()); | 
 |                  rprintf(FINFO, "total size is %s  speedup is %s%s\n", | 
                  rprintf(FINFO, "total size is %s  speedup is %s%s\n", | 
 |                          human_num(stats.total_size), | 
                          human_num(stats.total_size), | 
 |                          comma_dnum((double)stats.total_size / (total_written+total_read), 2), | 
                          comma_dnum((double)stats.total_size / (total_written+total_read), 2), | 
| 
 Line 413  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 535  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |                  if (!cmd) | 
                  if (!cmd) | 
 |                          cmd = RSYNC_RSH; | 
                          cmd = RSYNC_RSH; | 
 |                  cmd = need_to_free = strdup(cmd); | 
                  cmd = need_to_free = strdup(cmd); | 
 |                  if (!cmd) | 
   | 
 |                          goto oom; | 
   | 
 |   | 
   | 
 |                  for (t = f = cmd; *f; f++) { | 
                  for (t = f = cmd; *f; f++) { | 
 |                          if (*f == ' ') | 
                          if (*f == ' ') | 
| 
 Line 427  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 547  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |                                  if (!*f) { | 
                                  if (!*f) { | 
 |                                          if (in_quote) { | 
                                          if (in_quote) { | 
 |                                                  rprintf(FERROR, | 
                                                  rprintf(FERROR, | 
|                                                     "Missing trailing-%c in remote-shell command.\n", |                                                         "Missing trailing-%c in remote-shell command.\n", | 
|                                                     in_quote); |                                                         in_quote); | 
 |                                                  exit_cleanup(RERR_SYNTAX); | 
                                                  exit_cleanup(RERR_SYNTAX); | 
 |                                          } | 
                                          } | 
 |                                          f--; | 
                                          f--; | 
| 
 Line 449  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 569  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |                          *t++ = '\0'; | 
                          *t++ = '\0'; | 
 |                  } | 
                  } | 
 |   | 
   | 
|                 /* check to see if we've already been given '-l user' in |                 /* NOTE: must preserve t == start of command name until the end of the args handling! */ | 
|                  * the remote-shell command */ |                 if ((t = strrchr(cmd, '/')) != NULL) | 
|   |                         t++; | 
|   |                 else | 
|   |                         t = cmd; | 
|   |  | 
|   |                 /* Check to see if we've already been given '-l user' in the remote-shell command. */ | 
 |                  for (i = 0; i < argc-1; i++) { | 
                  for (i = 0; i < argc-1; i++) { | 
 |                          if (!strcmp(args[i], "-l") && args[i+1][0] != '-') | 
                          if (!strcmp(args[i], "-l") && args[i+1][0] != '-') | 
 |                                  dash_l_set = 1; | 
                                  dash_l_set = 1; | 
| 
 Line 459  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 584  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |  #ifdef HAVE_REMSH | 
  #ifdef HAVE_REMSH | 
 |                  /* remsh (on HPUX) takes the arguments the other way around */ | 
                  /* remsh (on HPUX) takes the arguments the other way around */ | 
 |                  args[argc++] = machine; | 
                  args[argc++] = machine; | 
|                 if (user && !(daemon_over_rsh && dash_l_set)) { |                 if (user && !(daemon_connection && dash_l_set)) { | 
 |                          args[argc++] = "-l"; | 
                          args[argc++] = "-l"; | 
 |                          args[argc++] = user; | 
                          args[argc++] = user; | 
 |                  } | 
                  } | 
 |  #else | 
  #else | 
|                 if (user && !(daemon_over_rsh && dash_l_set)) { |                 if (user && !(daemon_connection && dash_l_set)) { | 
 |                          args[argc++] = "-l"; | 
                          args[argc++] = "-l"; | 
 |                          args[argc++] = user; | 
                          args[argc++] = user; | 
 |                  } | 
                  } | 
 |   | 
  #ifdef AF_INET | 
 |   | 
                  if (default_af_hint == AF_INET && strcmp(t, "ssh") == 0) | 
 |   | 
                          args[argc++] = "-4"; /* we're using ssh so we can add a -4 option */ | 
 |   | 
  #endif | 
 |   | 
  #ifdef AF_INET6 | 
 |   | 
                  if (default_af_hint == AF_INET6 && strcmp(t, "ssh") == 0) | 
 |   | 
                          args[argc++] = "-6"; /* we're using ssh so we can add a -6 option */ | 
 |   | 
  #endif | 
 |                  args[argc++] = machine; | 
                  args[argc++] = machine; | 
 |  #endif | 
  #endif | 
 |   | 
   | 
 |                  args[argc++] = rsync_path; | 
                  args[argc++] = rsync_path; | 
 |   | 
   | 
|                 if (blocking_io < 0) { |                 if (blocking_io < 0 && (strcmp(t, "rsh") == 0 || strcmp(t, "remsh") == 0)) | 
|                         char *cp; |                         blocking_io = 1; | 
|                         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 (daemon_connection > 0) { | 
|   |                         args[argc++] = "--server"; | 
|   |                         args[argc++] = "--daemon"; | 
|   |                 } else | 
|   |                         server_options(args, &argc); | 
 |   | 
   | 
 |                  if (argc >= MAX_ARGS - 2) | 
                  if (argc >= MAX_ARGS - 2) | 
 |                          goto arg_overflow; | 
                          goto arg_overflow; | 
| 
 Line 491  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 621  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |   | 
   | 
 |          args[argc++] = "."; | 
          args[argc++] = "."; | 
 |   | 
   | 
|         if (!daemon_over_rsh) { |         if (!daemon_connection) { | 
 |                  while (remote_argc > 0) { | 
                  while (remote_argc > 0) { | 
 |                          if (argc >= MAX_ARGS - 1) { | 
                          if (argc >= MAX_ARGS - 1) { | 
 |                            arg_overflow: | 
                            arg_overflow: | 
| 
 Line 544  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 674  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |  #ifdef ICONV_CONST | 
  #ifdef ICONV_CONST | 
 |                  setup_iconv(); | 
                  setup_iconv(); | 
 |  #endif | 
  #endif | 
|                 if (protect_args && !daemon_over_rsh) |                 if (protect_args && !daemon_connection) | 
 |                          send_protected_args(*f_out_p, args); | 
                          send_protected_args(*f_out_p, args); | 
 |          } | 
          } | 
 |   | 
   | 
| 
 Line 552  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 682  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |                  free(need_to_free); | 
                  free(need_to_free); | 
 |   | 
   | 
 |          return pid; | 
          return pid; | 
 |   | 
  } | 
 |   | 
   | 
|   oom: | #ifdef SUPPORT_HFS_COMPRESSION | 
|         out_of_memory("do_cmd"); | static void hfs_receiver_check(void) | 
|         return 0; /* not reached */ | { | 
|   |         struct statfs fsb; | 
|   |         struct attrlist attrs; | 
|   |         struct { | 
|   |                 int32_t len; | 
|   |                 vol_capabilities_set_t caps; | 
|   |         } attrData; | 
|   |  | 
|   |         if (preserve_hfs_compression != 1) | 
|   |                 return; /* Nothing to check if --hfs-compression option isn't enabled. */ | 
|   |  | 
|   |         if (statfs(".", &fsb) < 0) { | 
|   |                 rsyserr(FERROR, errno, "statfs %s failed", curr_dir); | 
|   |                 exit_cleanup(RERR_FILESELECT); | 
|   |         } | 
|   |  | 
|   |         bzero(&attrs, sizeof attrs); | 
|   |         attrs.bitmapcount = ATTR_BIT_MAP_COUNT; | 
|   |         attrs.volattr = ATTR_VOL_CAPABILITIES; | 
|   |  | 
|   |         bzero(&attrData, sizeof attrData); | 
|   |         attrData.len = sizeof attrData; | 
|   |  | 
|   |         if (getattrlist(fsb.f_mntonname, &attrs, &attrData, sizeof attrData, 0) < 0) { | 
|   |                 rsyserr(FERROR, errno, "getattrlist %s failed", curr_dir); | 
|   |                 exit_cleanup(RERR_FILESELECT); | 
|   |         } | 
|   |  | 
|   |         if (!(attrData.caps[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION)) { | 
|   |                 rprintf(FERROR, "The destination filesystem does not support HFS+ compression.\n"); | 
|   |                 exit_cleanup(RERR_UNSUPPORTED); | 
|   |         } | 
 |  } | 
  } | 
 |   | 
  #endif | 
 |   | 
   | 
 |  /* The receiving side operates in one of two modes: | 
  /* The receiving side operates in one of two modes: | 
 |   * | 
   * | 
| 
 Line 574  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 Line 737  static pid_t do_cmd(char *cmd, char *machine, char *us
 | 
 |  static char *get_local_name(struct file_list *flist, char *dest_path) | 
  static char *get_local_name(struct file_list *flist, char *dest_path) | 
 |  { | 
  { | 
 |          STRUCT_STAT st; | 
          STRUCT_STAT st; | 
|         int statret; |         int statret, trailing_slash; | 
 |          char *cp; | 
          char *cp; | 
 |   | 
   | 
 |          if (DEBUG_GTE(RECV, 1)) { | 
          if (DEBUG_GTE(RECV, 1)) { | 
| 
 Line 587  static char *get_local_name(struct file_list *flist, c
 | 
 Line 750  static char *get_local_name(struct file_list *flist, c
 | 
 |   | 
   | 
 |          /* Treat an empty string as a copy into the current directory. */ | 
          /* Treat an empty string as a copy into the current directory. */ | 
 |          if (!*dest_path) | 
          if (!*dest_path) | 
|             dest_path = "."; |                 dest_path = "."; | 
 |   | 
   | 
 |          if (daemon_filter_list.head) { | 
          if (daemon_filter_list.head) { | 
 |                  char *slash = strrchr(dest_path, '/'); | 
                  char *slash = strrchr(dest_path, '/'); | 
| 
 Line 607  static char *get_local_name(struct file_list *flist, c
 | 
 Line 770  static char *get_local_name(struct file_list *flist, c
 | 
 |          } | 
          } | 
 |   | 
   | 
 |          /* See what currently exists at the destination. */ | 
          /* See what currently exists at the destination. */ | 
|         if ((statret = do_stat(dest_path, &st)) == 0) { |         statret = do_stat(dest_path, &st); | 
|   |         cp = strrchr(dest_path, '/'); | 
|   |         trailing_slash = cp && !cp[1]; | 
|   |  | 
|   |         if (mkpath_dest_arg && statret < 0 && (cp || file_total > 1)) { | 
|   |                 int ret = make_path(dest_path, ACCESSPERMS, file_total > 1 && !trailing_slash ? 0 : MKP_DROP_NAME); | 
|   |                 if (ret < 0) | 
|   |                         goto mkdir_error; | 
|   |                 if (INFO_GTE(NAME, 1)) { | 
|   |                         if (file_total == 1 || trailing_slash) | 
|   |                                 *cp = '\0'; | 
|   |                         rprintf(FINFO, "created %d director%s for %s\n", ret, ret == 1 ? "y" : "ies", dest_path); | 
|   |                         if (file_total == 1 || trailing_slash) | 
|   |                                 *cp = '/'; | 
|   |                 } | 
|   |                 if (file_total > 1 || trailing_slash) | 
|   |                         statret = do_stat(dest_path, &st); | 
|   |         } | 
|   |  | 
|   |         if (statret == 0) { | 
 |                  /* If the destination is a dir, enter it and use mode 1. */ | 
                  /* If the destination is a dir, enter it and use mode 1. */ | 
 |                  if (S_ISDIR(st.st_mode)) { | 
                  if (S_ISDIR(st.st_mode)) { | 
 |                          if (!change_dir(dest_path, CD_NORMAL)) { | 
                          if (!change_dir(dest_path, CD_NORMAL)) { | 
| 
 Line 616  static char *get_local_name(struct file_list *flist, c
 | 
 Line 798  static char *get_local_name(struct file_list *flist, c
 | 
 |                                  exit_cleanup(RERR_FILESELECT); | 
                                  exit_cleanup(RERR_FILESELECT); | 
 |                          } | 
                          } | 
 |                          filesystem_dev = st.st_dev; /* ensures --force works right w/-x */ | 
                          filesystem_dev = st.st_dev; /* ensures --force works right w/-x */ | 
 |   | 
  #ifdef SUPPORT_HFS_COMPRESSION | 
 |   | 
                          hfs_receiver_check(); | 
 |   | 
  #endif | 
 |                          return NULL; | 
                          return NULL; | 
 |                  } | 
                  } | 
 |                  if (file_total > 1) { | 
                  if (file_total > 1) { | 
| 
 Line 637  static char *get_local_name(struct file_list *flist, c
 | 
 Line 822  static char *get_local_name(struct file_list *flist, c
 | 
 |                  exit_cleanup(RERR_FILESELECT); | 
                  exit_cleanup(RERR_FILESELECT); | 
 |          } | 
          } | 
 |   | 
   | 
 |          cp = strrchr(dest_path, '/'); | 
   | 
 |   | 
   | 
 |          /* If we need a destination directory because the transfer is not | 
          /* If we need a destination directory because the transfer is not | 
 |           * of a single non-directory or the user has requested one via a | 
           * 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. */ | 
           * destination path ending in a slash, create one and use mode 1. */ | 
|         if (file_total > 1 || (cp && !cp[1])) { |         if (file_total > 1 || trailing_slash) { | 
|                 /* Lop off the final slash (if any). */ |                 if (trailing_slash) | 
|                 if (cp && !cp[1]) |                         *cp = '\0'; /* Lop off the final slash (if any). */ | 
|                         *cp = '\0'; |   | 
 |   | 
   | 
 |                  if (statret == 0) { | 
                  if (statret == 0) { | 
|                         rprintf(FERROR, |                         rprintf(FERROR, "ERROR: destination path is not a directory\n"); | 
|                             "ERROR: destination path is not a directory\n"); |   | 
 |                          exit_cleanup(RERR_SYNTAX); | 
                          exit_cleanup(RERR_SYNTAX); | 
 |                  } | 
                  } | 
 |   | 
   | 
 |                  if (do_mkdir(dest_path, ACCESSPERMS) != 0) { | 
                  if (do_mkdir(dest_path, ACCESSPERMS) != 0) { | 
 |   | 
                      mkdir_error: | 
 |                          rsyserr(FERROR, errno, "mkdir %s failed", | 
                          rsyserr(FERROR, errno, "mkdir %s failed", | 
 |                                  full_fname(dest_path)); | 
                                  full_fname(dest_path)); | 
 |                          exit_cleanup(RERR_FILEIO); | 
                          exit_cleanup(RERR_FILEIO); | 
| 
 Line 676  static char *get_local_name(struct file_list *flist, c
 | 
 Line 858  static char *get_local_name(struct file_list *flist, c
 | 
 |                                  full_fname(dest_path)); | 
                                  full_fname(dest_path)); | 
 |                          exit_cleanup(RERR_FILESELECT); | 
                          exit_cleanup(RERR_FILESELECT); | 
 |                  } | 
                  } | 
 | #ifdef SUPPORT_HFS_COMPRESSION | 
|   |                 hfs_receiver_check(); | 
|   | #endif | 
 |                  return NULL; | 
                  return NULL; | 
 |          } | 
          } | 
 |   | 
   | 
| 
 Line 696  static char *get_local_name(struct file_list *flist, c
 | 
 Line 880  static char *get_local_name(struct file_list *flist, c
 | 
 |                          full_fname(dest_path)); | 
                          full_fname(dest_path)); | 
 |                  exit_cleanup(RERR_FILESELECT); | 
                  exit_cleanup(RERR_FILESELECT); | 
 |          } | 
          } | 
 |   | 
  #ifdef SUPPORT_HFS_COMPRESSION | 
 |   | 
          hfs_receiver_check(); | 
 |   | 
  #endif | 
 |          *cp = '/'; | 
          *cp = '/'; | 
 |   | 
   | 
 |          return cp + 1; | 
          return cp + 1; | 
| 
 Line 720  static void check_alt_basis_dirs(void)
 | 
 Line 907  static void check_alt_basis_dirs(void)
 | 
 |                  if (dry_run > 1 && *bdir != '/') { | 
                  if (dry_run > 1 && *bdir != '/') { | 
 |                          int len = curr_dir_len + 1 + bd_len + 1; | 
                          int len = curr_dir_len + 1 + bd_len + 1; | 
 |                          char *new = new_array(char, len); | 
                          char *new = new_array(char, len); | 
 |                          if (!new) | 
   | 
 |                                  out_of_memory("check_alt_basis_dirs"); | 
   | 
 |                          if (slash && strncmp(bdir, "../", 3) == 0) { | 
                          if (slash && strncmp(bdir, "../", 3) == 0) { | 
|                             /* We want to remove only one leading "../" prefix for |                                 /* We want to remove only one leading "../" prefix for | 
|                              * the directory we couldn't create in dry-run mode: |                                  * the directory we couldn't create in dry-run mode: | 
|                              * this ensures that any other ".." references get |                                  * this ensures that any other ".." references get | 
|                              * evaluated the same as they would for a live copy. */ |                                  * evaluated the same as they would for a live copy. */ | 
|                             *slash = '\0'; |                                 *slash = '\0'; | 
|                             pathjoin(new, len, curr_dir, bdir + 3); |                                 pathjoin(new, len, curr_dir, bdir + 3); | 
|                             *slash = '/'; |                                 *slash = '/'; | 
 |                          } else | 
                          } else | 
|                             pathjoin(new, len, curr_dir, bdir); |                                 pathjoin(new, len, curr_dir, bdir); | 
 |                          basis_dir[j] = bdir = new; | 
                          basis_dir[j] = bdir = new; | 
 |                  } | 
                  } | 
 |                  if (do_stat(bdir, &st) < 0) | 
                  if (do_stat(bdir, &st) < 0) | 
|                         rprintf(FWARNING, "%s arg does not exist: %s\n", dest_option, bdir); |                         rprintf(FWARNING, "%s arg does not exist: %s\n", alt_dest_opt(0), bdir); | 
 |                  else if (!S_ISDIR(st.st_mode)) | 
                  else if (!S_ISDIR(st.st_mode)) | 
|                         rprintf(FWARNING, "%s arg is not a dir: %s\n", dest_option, bdir); |                         rprintf(FWARNING, "%s arg is not a dir: %s\n", alt_dest_opt(0), bdir); | 
 |          } | 
          } | 
 |  } | 
  } | 
 |   | 
   | 
| 
 Line 778  static void read_final_goodbye(int f_in, int f_out)
 | 
 Line 963  static void read_final_goodbye(int f_in, int f_out)
 | 
 |  static void do_server_sender(int f_in, int f_out, int argc, char *argv[]) | 
  static void do_server_sender(int f_in, int f_out, int argc, char *argv[]) | 
 |  { | 
  { | 
 |          struct file_list *flist; | 
          struct file_list *flist; | 
|         char *dir = argv[0]; |         char *dir; | 
 |   | 
   | 
 |          if (DEBUG_GTE(SEND, 1)) | 
          if (DEBUG_GTE(SEND, 1)) | 
 |                  rprintf(FINFO, "server_sender starting pid=%d\n", (int)getpid()); | 
                  rprintf(FINFO, "server_sender starting pid=%d\n", (int)getpid()); | 
| 
 Line 786  static void do_server_sender(int f_in, int f_out, int 
 | 
 Line 971  static void do_server_sender(int f_in, int f_out, int 
 | 
 |          if (am_daemon && lp_write_only(module_id)) { | 
          if (am_daemon && lp_write_only(module_id)) { | 
 |                  rprintf(FERROR, "ERROR: module is write only\n"); | 
                  rprintf(FERROR, "ERROR: module is write only\n"); | 
 |                  exit_cleanup(RERR_SYNTAX); | 
                  exit_cleanup(RERR_SYNTAX); | 
 |                  return; | 
   | 
 |          } | 
          } | 
 |          if (am_daemon && read_only && remove_source_files) { | 
          if (am_daemon && read_only && remove_source_files) { | 
 |                  rprintf(FERROR, | 
                  rprintf(FERROR, | 
|                     "ERROR: --remove-%s-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"); |                         remove_source_files == 1 ? "source" : "sent"); | 
 |                  exit_cleanup(RERR_SYNTAX); | 
                  exit_cleanup(RERR_SYNTAX); | 
 |                  return; | 
   | 
 |          } | 
          } | 
 |   | 
          if (argc < 1) { | 
 |   | 
                  rprintf(FERROR, "ERROR: do_server_sender called without args\n"); | 
 |   | 
                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
          } | 
 |   | 
   | 
 |   | 
          become_copy_as_user(); | 
 |   | 
   | 
 |   | 
          dir = argv[0]; | 
 |          if (!relative_paths) { | 
          if (!relative_paths) { | 
 |                  if (!change_dir(dir, CD_NORMAL)) { | 
                  if (!change_dir(dir, CD_NORMAL)) { | 
 |                          rsyserr(FERROR, errno, "change_dir#3 %s failed", | 
                          rsyserr(FERROR, errno, "change_dir#3 %s failed", | 
| 
 Line 842  static int do_recv(int f_in, int f_out, char *local_na
 | 
 Line 1032  static int do_recv(int f_in, int f_out, char *local_na
 | 
 |           * points to an identical file won't be replaced by the referent. */ | 
           * points to an identical file won't be replaced by the referent. */ | 
 |          copy_links = copy_dirlinks = copy_unsafe_links = 0; | 
          copy_links = copy_dirlinks = copy_unsafe_links = 0; | 
 |   | 
   | 
 |   | 
  #ifdef SUPPORT_FORCE_CHANGE | 
 |   | 
          if (force_change & SYS_IMMUTABLE) { | 
 |   | 
                  /* Determine whether we'll be able to unlock a system immutable item. */ | 
 |   | 
                  int mib[2]; | 
 |   | 
                  int securityLevel = 0; | 
 |   | 
                  size_t len = sizeof securityLevel; | 
 |   | 
   | 
 |   | 
                  mib[0] = CTL_KERN; | 
 |   | 
                  mib[1] = KERN_SECURELVL; | 
 |   | 
                  if (sysctl(mib, 2, &securityLevel, &len, NULL, 0) == 0 && securityLevel > 0) { | 
 |   | 
                          rprintf(FERROR, "System security level is too high to force mutability on system immutable files and directories.\n"); | 
 |   | 
                          exit_cleanup(RERR_UNSUPPORTED); | 
 |   | 
                  } | 
 |   | 
          } | 
 |   | 
  #endif | 
 |   | 
   | 
 |  #ifdef SUPPORT_HARD_LINKS | 
  #ifdef SUPPORT_HARD_LINKS | 
 |          if (preserve_hard_links && !inc_recurse) | 
          if (preserve_hard_links && !inc_recurse) | 
 |                  match_hard_links(first_flist); | 
                  match_hard_links(first_flist); | 
| 
 Line 867  static int do_recv(int f_in, int f_out, char *local_na
 | 
 Line 1073  static int do_recv(int f_in, int f_out, char *local_na
 | 
 |                                  rprintf(FERROR, "Failed to stat %s: %s\n", backup_dir_buf, strerror(errno)); | 
                                  rprintf(FERROR, "Failed to stat %s: %s\n", backup_dir_buf, strerror(errno)); | 
 |                                  exit_cleanup(RERR_FILEIO); | 
                                  exit_cleanup(RERR_FILEIO); | 
 |                          } | 
                          } | 
|                         rprintf(FINFO, "(new) backup_dir is %s\n", backup_dir_buf); |                         if (INFO_GTE(BACKUP, 1)) | 
|   |                                 rprintf(FINFO, "(new) backup_dir is %s\n", backup_dir_buf); | 
 |                  } else if (INFO_GTE(BACKUP, 1)) | 
                  } else if (INFO_GTE(BACKUP, 1)) | 
 |                          rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf); | 
                          rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf); | 
 |                  if (backup_dir_len > 1) | 
                  if (backup_dir_len > 1) | 
 |                          backup_dir_buf[backup_dir_len-1] = '/'; | 
                          backup_dir_buf[backup_dir_len-1] = '/'; | 
 |          } | 
          } | 
 |   | 
   | 
 |   | 
          if (tmpdir) { | 
 |   | 
                  STRUCT_STAT st; | 
 |   | 
                  int ret = do_stat(tmpdir, &st); | 
 |   | 
                  if (ret < 0 || !S_ISDIR(st.st_mode)) { | 
 |   | 
                          if (ret == 0) { | 
 |   | 
                                  rprintf(FERROR, "The temp-dir is not a directory: %s\n", tmpdir); | 
 |   | 
                                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
                          } | 
 |   | 
                          if (errno == ENOENT) { | 
 |   | 
                                  rprintf(FERROR, "The temp-dir does not exist: %s\n", tmpdir); | 
 |   | 
                                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
                          } | 
 |   | 
                          rprintf(FERROR, "Failed to stat temp-dir %s: %s\n", tmpdir, strerror(errno)); | 
 |   | 
                          exit_cleanup(RERR_FILEIO); | 
 |   | 
                  } | 
 |   | 
          } | 
 |   | 
   | 
 |          io_flush(FULL_FLUSH); | 
          io_flush(FULL_FLUSH); | 
 |   | 
   | 
 |          if ((pid = do_fork()) == -1) { | 
          if ((pid = do_fork()) == -1) { | 
| 
 Line 980  static void do_server_recv(int f_in, int f_out, int ar
 | 
 Line 1204  static void do_server_recv(int f_in, int f_out, int ar
 | 
 |          char *local_name = NULL; | 
          char *local_name = NULL; | 
 |          int negated_levels; | 
          int negated_levels; | 
 |   | 
   | 
|         if (filesfrom_fd >= 0 && !msgs2stderr && protocol_version < 31) { |         if (filesfrom_fd >= 0 && msgs2stderr != 1 && protocol_version < 31) { | 
 |                  /* We can't mix messages with files-from data on the socket, | 
                  /* We can't mix messages with files-from data on the socket, | 
 |                   * so temporarily turn off info/debug messages. */ | 
                   * so temporarily turn off info/debug messages. */ | 
 |                  negate_output_levels(); | 
                  negate_output_levels(); | 
| 
 Line 997  static void do_server_recv(int f_in, int f_out, int ar
 | 
 Line 1221  static void do_server_recv(int f_in, int f_out, int ar
 | 
 |                  return; | 
                  return; | 
 |          } | 
          } | 
 |   | 
   | 
 |   | 
          become_copy_as_user(); | 
 |   | 
   | 
 |          if (argc > 0) { | 
          if (argc > 0) { | 
 |                  char *dir = argv[0]; | 
                  char *dir = argv[0]; | 
 |                  argc--; | 
                  argc--; | 
| 
 Line 1029  static void do_server_recv(int f_in, int f_out, int ar
 | 
 Line 1255  static void do_server_recv(int f_in, int f_out, int ar
 | 
 |                  rprintf(FERROR,"server_recv: recv_file_list error\n"); | 
                  rprintf(FERROR,"server_recv: recv_file_list error\n"); | 
 |                  exit_cleanup(RERR_FILESELECT); | 
                  exit_cleanup(RERR_FILESELECT); | 
 |          } | 
          } | 
 |   | 
   | 
 |          if (inc_recurse && file_total == 1) | 
          if (inc_recurse && file_total == 1) | 
 |                  recv_additional_file_list(f_in); | 
                  recv_additional_file_list(f_in); | 
 |   | 
   | 
| 
 Line 1064  static void do_server_recv(int f_in, int f_out, int ar
 | 
 Line 1289  static void do_server_recv(int f_in, int f_out, int ar
 | 
 |                  if (partial_dir && *partial_dir == '/' | 
                  if (partial_dir && *partial_dir == '/' | 
 |                   && check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) { | 
                   && check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) { | 
 |                      options_rejected: | 
                      options_rejected: | 
|                         rprintf(FERROR, |                         rprintf(FERROR, "Your options have been rejected by the server.\n"); | 
|                                 "Your options have been rejected by the server.\n"); |   | 
 |                          exit_cleanup(RERR_SYNTAX); | 
                          exit_cleanup(RERR_SYNTAX); | 
 |                  } | 
                  } | 
 |          } | 
          } | 
| 
 Line 1095  void start_server(int f_in, int f_out, int argc, char 
 | 
 Line 1319  void start_server(int f_in, int f_out, int argc, char 
 | 
 |          if (am_daemon && io_timeout && protocol_version >= 31) | 
          if (am_daemon && io_timeout && protocol_version >= 31) | 
 |                  send_msg_int(MSG_IO_TIMEOUT, io_timeout); | 
                  send_msg_int(MSG_IO_TIMEOUT, io_timeout); | 
 |   | 
   | 
 |   | 
          if (db_config) | 
 |   | 
                  db_read_config(FERROR, db_config); | 
 |   | 
   | 
 |          if (am_sender) { | 
          if (am_sender) { | 
 |                  keep_dirlinks = 0; /* Must be disabled on the sender. */ | 
                  keep_dirlinks = 0; /* Must be disabled on the sender. */ | 
 |                  if (need_messages_from_generator) | 
                  if (need_messages_from_generator) | 
| 
 Line 1157  int client_run(int f_in, int f_out, pid_t pid, int arg
 | 
 Line 1384  int client_run(int f_in, int f_out, pid_t pid, int arg
 | 
 |   | 
   | 
 |                  if (write_batch && !am_server) | 
                  if (write_batch && !am_server) | 
 |                          start_write_batch(f_out); | 
                          start_write_batch(f_out); | 
 |   | 
   | 
 |   | 
                  become_copy_as_user(); | 
 |   | 
   | 
 |                  flist = send_file_list(f_out, argc, argv); | 
                  flist = send_file_list(f_out, argc, argv); | 
 |                  if (DEBUG_GTE(FLIST, 3)) | 
                  if (DEBUG_GTE(FLIST, 3)) | 
 |                          rprintf(FINFO,"file list sent\n"); | 
                          rprintf(FINFO,"file list sent\n"); | 
| 
 Line 1190  int client_run(int f_in, int f_out, pid_t pid, int arg
 | 
 Line 1420  int client_run(int f_in, int f_out, pid_t pid, int arg
 | 
 |                          io_start_buffering_out(f_out); | 
                          io_start_buffering_out(f_out); | 
 |          } | 
          } | 
 |   | 
   | 
 |   | 
          become_copy_as_user(); | 
 |   | 
   | 
 |          send_filter_list(read_batch ? -1 : f_out); | 
          send_filter_list(read_batch ? -1 : f_out); | 
 |   | 
   | 
 |          if (filesfrom_fd >= 0) { | 
          if (filesfrom_fd >= 0) { | 
| 
 Line 1224  int client_run(int f_in, int f_out, pid_t pid, int arg
 | 
 Line 1456  int client_run(int f_in, int f_out, pid_t pid, int arg
 | 
 |          return MAX(exit_code, exit_code2); | 
          return MAX(exit_code, exit_code2); | 
 |  } | 
  } | 
 |   | 
   | 
| static int copy_argv(char *argv[]) | static void dup_argv(char *argv[]) | 
 |  { | 
  { | 
 |          int i; | 
          int i; | 
 |   | 
   | 
|         for (i = 0; argv[i]; i++) { |         for (i = 0; argv[i]; i++) | 
|                 if (!(argv[i] = strdup(argv[i]))) { |                 argv[i] = strdup(argv[i]); | 
|                         rprintf (FERROR, "out of memory at %s(%d)\n", |   | 
|                                  __FILE__, __LINE__); |   | 
|                         return RERR_MALLOC; |   | 
|                 } |   | 
|         } |   | 
 |   | 
|         return 0; |   | 
 |  } | 
  } | 
 |   | 
   | 
 |   | 
   | 
| 
 Line 1250  static int start_client(int argc, char *argv[])
 | 
 Line 1475  static int start_client(int argc, char *argv[])
 | 
 |  { | 
  { | 
 |          char *p, *shell_machine = NULL, *shell_user = NULL; | 
          char *p, *shell_machine = NULL, *shell_user = NULL; | 
 |          char **remote_argv; | 
          char **remote_argv; | 
|         int remote_argc; |         int remote_argc, env_port = rsync_port; | 
 |          int f_in, f_out; | 
          int f_in, f_out; | 
 |          int ret; | 
          int ret; | 
 |          pid_t pid; | 
          pid_t pid; | 
 |   | 
   | 
 |          /* Don't clobber argv[] so that ps(1) can still show the right | 
          /* Don't clobber argv[] so that ps(1) can still show the right | 
 |           * command line. */ | 
           * command line. */ | 
|         if ((ret = copy_argv(argv)) != 0) |         dup_argv(argv); | 
|                 return ret; |   | 
 |   | 
   | 
 |          if (!read_batch) { /* for read_batch, NO source is specified */ | 
          if (!read_batch) { /* for read_batch, NO source is specified */ | 
 |                  char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); | 
                  char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); | 
 |   | 
   | 
 |   | 
                  if (shell_machine && !shell_machine[0]) { | 
 |   | 
  #ifdef HAVE_LIBSLP | 
 |   | 
                          /* User entered just rsync:// URI */ | 
 |   | 
                          if (lp_use_slp()) { | 
 |   | 
                                  print_service_list(); | 
 |   | 
                                  exit_cleanup(0); | 
 |   | 
                          } | 
 |   | 
                          rprintf(FINFO, "SLP is disabled, cannot browse\n"); | 
 |   | 
                          exit_cleanup(RERR_SYNTAX); | 
 |   | 
  #else /* No SLP, die here */ | 
 |   | 
                          rprintf(FINFO, "No SLP support, cannot browse\n"); | 
 |   | 
                          exit_cleanup(RERR_SYNTAX); | 
 |   | 
  #endif | 
 |   | 
                  } | 
 |   | 
   | 
 |                  if (path) { /* source is remote */ | 
                  if (path) { /* source is remote */ | 
 |                          char *dummy_host; | 
                          char *dummy_host; | 
 |                          int dummy_port = 0; | 
                          int dummy_port = 0; | 
| 
 Line 1279  static int start_client(int argc, char *argv[])
 | 
 Line 1519  static int start_client(int argc, char *argv[])
 | 
 |                                  remote_argc--; /* don't count dest */ | 
                                  remote_argc--; /* don't count dest */ | 
 |                                  argc = 1; | 
                                  argc = 1; | 
 |                          } | 
                          } | 
|                         if (filesfrom_host && *filesfrom_host |                         if (filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { | 
|                             && strcmp(filesfrom_host, shell_machine) != 0) { |   | 
 |                                  rprintf(FERROR, | 
                                  rprintf(FERROR, | 
 |                                          "--files-from hostname is not the same as the transfer hostname\n"); | 
                                          "--files-from hostname is not the same as the transfer hostname\n"); | 
 |                                  exit_cleanup(RERR_SYNTAX); | 
                                  exit_cleanup(RERR_SYNTAX); | 
 |                          } | 
                          } | 
 |                          am_sender = 0; | 
                          am_sender = 0; | 
 |                          if (rsync_port) | 
                          if (rsync_port) | 
|                                 daemon_over_rsh = shell_cmd ? 1 : -1; |                                 daemon_connection = shell_cmd ? 1 : -1; | 
 |                  } else { /* source is local, check dest arg */ | 
                  } else { /* source is local, check dest arg */ | 
 |                          am_sender = 1; | 
                          am_sender = 1; | 
 |   | 
   | 
| 
 Line 1302  static int start_client(int argc, char *argv[])
 | 
 Line 1541  static int start_client(int argc, char *argv[])
 | 
 |                          remote_argc = 1; | 
                          remote_argc = 1; | 
 |   | 
   | 
 |                          path = check_for_hostspec(p, &shell_machine, &rsync_port); | 
                          path = check_for_hostspec(p, &shell_machine, &rsync_port); | 
|                         if (path && filesfrom_host && *filesfrom_host |                         if (path && filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { | 
|                             && strcmp(filesfrom_host, shell_machine) != 0) { |   | 
 |                                  rprintf(FERROR, | 
                                  rprintf(FERROR, | 
 |                                          "--files-from hostname is not the same as the transfer hostname\n"); | 
                                          "--files-from hostname is not the same as the transfer hostname\n"); | 
 |                                  exit_cleanup(RERR_SYNTAX); | 
                                  exit_cleanup(RERR_SYNTAX); | 
| 
 Line 1316  static int start_client(int argc, char *argv[])
 | 
 Line 1554  static int start_client(int argc, char *argv[])
 | 
 |                                          exit_cleanup(RERR_SYNTAX); | 
                                          exit_cleanup(RERR_SYNTAX); | 
 |                                  } | 
                                  } | 
 |                                  shell_machine = NULL; | 
                                  shell_machine = NULL; | 
 |   | 
                                  rsync_port = 0; | 
 |                          } else { /* hostspec was found, so dest is remote */ | 
                          } else { /* hostspec was found, so dest is remote */ | 
 |                                  argv[argc] = path; | 
                                  argv[argc] = path; | 
 |                                  if (rsync_port) | 
                                  if (rsync_port) | 
|                                         daemon_over_rsh = shell_cmd ? 1 : -1; |                                         daemon_connection = shell_cmd ? 1 : -1; | 
 |                          } | 
                          } | 
 |                  } | 
                  } | 
 |          } else {  /* read_batch */ | 
          } else {  /* read_batch */ | 
| 
 Line 1330  static int start_client(int argc, char *argv[])
 | 
 Line 1569  static int start_client(int argc, char *argv[])
 | 
 |                  } | 
                  } | 
 |                  remote_argv = argv += argc - 1; | 
                  remote_argv = argv += argc - 1; | 
 |                  remote_argc = argc = 1; | 
                  remote_argc = argc = 1; | 
 |   | 
                  rsync_port = 0; | 
 |          } | 
          } | 
 |   | 
   | 
 |          if (!rsync_port && remote_argc && !**remote_argv) /* Turn an empty arg into a dot dir. */ | 
          if (!rsync_port && remote_argc && !**remote_argv) /* Turn an empty arg into a dot dir. */ | 
| 
 Line 1339  static int start_client(int argc, char *argv[])
 | 
 Line 1579  static int start_client(int argc, char *argv[])
 | 
 |                  char *dummy_host; | 
                  char *dummy_host; | 
 |                  int dummy_port = rsync_port; | 
                  int dummy_port = rsync_port; | 
 |                  int i; | 
                  int i; | 
 |   | 
                  if (!argv[0][0]) | 
 |   | 
                          goto invalid_empty; | 
 |                  /* For local source, extra source args must not have hostspec. */ | 
                  /* For local source, extra source args must not have hostspec. */ | 
 |                  for (i = 1; i < argc; i++) { | 
                  for (i = 1; i < argc; i++) { | 
 |   | 
                          if (!argv[i][0]) { | 
 |   | 
                              invalid_empty: | 
 |   | 
                                  rprintf(FERROR, "Empty source arg specified.\n"); | 
 |   | 
                                  exit_cleanup(RERR_SYNTAX); | 
 |   | 
                          } | 
 |                          if (check_for_hostspec(argv[i], &dummy_host, &dummy_port)) { | 
                          if (check_for_hostspec(argv[i], &dummy_host, &dummy_port)) { | 
 |                                  rprintf(FERROR, "Unexpected remote arg: %s\n", argv[i]); | 
                                  rprintf(FERROR, "Unexpected remote arg: %s\n", argv[i]); | 
 |                                  exit_cleanup(RERR_SYNTAX); | 
                                  exit_cleanup(RERR_SYNTAX); | 
| 
 Line 1376  static int start_client(int argc, char *argv[])
 | 
 Line 1623  static int start_client(int argc, char *argv[])
 | 
 |                  } | 
                  } | 
 |          } | 
          } | 
 |   | 
   | 
|         if (daemon_over_rsh < 0) |         if (rsync_port < 0) | 
|   |                 rsync_port = RSYNC_PORT; | 
|   |         else | 
|   |                 env_port = rsync_port; | 
|   |  | 
|   |         if (db_config) | 
|   |                 db_read_config(FERROR, db_config); | 
|   |  | 
|   |         if (daemon_connection < 0) | 
 |                  return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv); | 
                  return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv); | 
 |   | 
   | 
|         if (password_file && !daemon_over_rsh) { |         if (password_file && !daemon_connection) { | 
 |                  rprintf(FERROR, "The --password-file option may only be " | 
                  rprintf(FERROR, "The --password-file option may only be " | 
 |                                  "used when accessing an rsync daemon.\n"); | 
                                  "used when accessing an rsync daemon.\n"); | 
 |                  exit_cleanup(RERR_SYNTAX); | 
                  exit_cleanup(RERR_SYNTAX); | 
| 
 Line 1406  static int start_client(int argc, char *argv[])
 | 
 Line 1661  static int start_client(int argc, char *argv[])
 | 
 |                          NS(remote_argv[0])); | 
                          NS(remote_argv[0])); | 
 |          } | 
          } | 
 |   | 
   | 
|         pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc, | #ifdef HAVE_PUTENV | 
|                      &f_in, &f_out); |         if (daemon_connection) | 
|   |                 set_env_num("RSYNC_PORT", env_port); | 
|   | #endif | 
 |   | 
   | 
 |   | 
          pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc, &f_in, &f_out); | 
 |   | 
   | 
 |          /* if we're running an rsync server on the remote host over a | 
          /* if we're running an rsync server on the remote host over a | 
 |           * remote shell command, we need to do the RSYNCD protocol first */ | 
           * remote shell command, we need to do the RSYNCD protocol first */ | 
|         if (daemon_over_rsh) { |         if (daemon_connection) { | 
 |                  int tmpret; | 
                  int tmpret; | 
|                 tmpret = start_inband_exchange(f_in, f_out, shell_user, remote_argc, remote_argv); |                 tmpret = start_inband_exchange(f_in, f_out, shell_user, shell_machine, remote_argc, remote_argv); | 
 |                  if (tmpret < 0) | 
                  if (tmpret < 0) | 
 |                          return tmpret; | 
                          return tmpret; | 
 |          } | 
          } | 
| 
 Line 1429  static int start_client(int argc, char *argv[])
 | 
 Line 1688  static int start_client(int argc, char *argv[])
 | 
 |   | 
   | 
 |  static void sigusr1_handler(UNUSED(int val)) | 
  static void sigusr1_handler(UNUSED(int val)) | 
 |  { | 
  { | 
 |   | 
          called_from_signal_handler = 1; | 
 |          exit_cleanup(RERR_SIGNAL1); | 
          exit_cleanup(RERR_SIGNAL1); | 
 |  } | 
  } | 
 |   | 
   | 
| 
 Line 1442  static void sigusr2_handler(UNUSED(int val))
 | 
 Line 1702  static void sigusr2_handler(UNUSED(int val))
 | 
 |          _exit(0); | 
          _exit(0); | 
 |  } | 
  } | 
 |   | 
   | 
| #ifdef SIGINFO | #if defined SIGINFO || defined SIGVTALRM | 
 |  static void siginfo_handler(UNUSED(int val)) | 
  static void siginfo_handler(UNUSED(int val)) | 
 |  { | 
  { | 
 |         if (!am_server && !INFO_GTE(PROGRESS, 1)) | 
|         if (!am_server) |   | 
 |                  want_progress_now = True; | 
                  want_progress_now = True; | 
 |  } | 
  } | 
 |  #endif | 
  #endif | 
| 
 Line 1470  void remember_children(UNUSED(int val))
 | 
 Line 1729  void remember_children(UNUSED(int val))
 | 
 |                                  break; | 
                                  break; | 
 |                          } | 
                          } | 
 |                  } | 
                  } | 
 |   | 
                  if (WIFSIGNALED(status)) { | 
 |   | 
                          rprintf(FLOG, | 
 |   | 
                                  "rsync error: (1) Child proccess has unexpectedly died with signal %d\n", | 
 |   | 
                                  WTERMSIG(status)); | 
 |   | 
                  } else if (WIFEXITED(status) && WEXITSTATUS(status) == RERR_WECRASHED) { | 
 |   | 
                          rprintf(FLOG, | 
 |   | 
                                  "rsync error: (1) Child proccess has CRASHED.\n"); | 
 |   | 
                  } | 
 |          } | 
          } | 
 |  #endif | 
  #endif | 
 |  #ifndef HAVE_SIGACTION | 
  #ifndef HAVE_SIGACTION | 
| 
 Line 1498  const char *get_panic_action(void)
 | 
 Line 1765  const char *get_panic_action(void)
 | 
 |   | 
   | 
 |          if (cmd_fmt) | 
          if (cmd_fmt) | 
 |                  return cmd_fmt; | 
                  return cmd_fmt; | 
|         else |         return "xterm -display :0 -T Panic -n Panic -e gdb /proc/%d/exe %d"; | 
|                 return "xterm -display :0 -T Panic -n Panic " |   | 
|                         "-e gdb /proc/%d/exe %d"; |   | 
 |  } | 
  } | 
 |   | 
   | 
 |   | 
   | 
| 
 Line 1521  static void rsync_panic_handler(UNUSED(int whatsig))
 | 
 Line 1786  static void rsync_panic_handler(UNUSED(int whatsig))
 | 
 |   | 
   | 
 |          /* Unless we failed to execute gdb, we allow the process to | 
          /* Unless we failed to execute gdb, we allow the process to | 
 |           * continue.  I'm not sure if that's right. */ | 
           * continue.  I'm not sure if that's right. */ | 
|         ret = system(cmd_buf); |         ret = shell_exec(cmd_buf); | 
 |          if (ret) | 
          if (ret) | 
 |                  _exit(ret); | 
                  _exit(ret); | 
 |  } | 
  } | 
 |  #endif | 
  #endif | 
 |   | 
   | 
 |   | 
  static void rsync_crash_handler(UNUSED(int whatsig)) | 
 |   | 
  { | 
 |   | 
          log_exit(RERR_WECRASHED, __FILE__, __LINE__); | 
 |   | 
          logfile_close(); | 
 |   | 
          _exit(RERR_WECRASHED); | 
 |   | 
  } | 
 |   | 
   | 
 |  int main(int argc,char *argv[]) | 
  int main(int argc,char *argv[]) | 
 |  { | 
  { | 
 |          int ret; | 
          int ret; | 
|         int orig_argc = argc; |  | 
|         char **orig_argv = argv; |         raw_argc = argc; | 
|   |         raw_argv = argv; | 
|   |  | 
 |  #ifdef HAVE_SIGACTION | 
  #ifdef HAVE_SIGACTION | 
 |  # ifdef HAVE_SIGPROCMASK | 
  # ifdef HAVE_SIGPROCMASK | 
 |          sigset_t sigmask; | 
          sigset_t sigmask; | 
| 
 Line 1549  int main(int argc,char *argv[])
 | 
 Line 1822  int main(int argc,char *argv[])
 | 
 |          SIGACTMASK(SIGFPE, rsync_panic_handler); | 
          SIGACTMASK(SIGFPE, rsync_panic_handler); | 
 |          SIGACTMASK(SIGABRT, rsync_panic_handler); | 
          SIGACTMASK(SIGABRT, rsync_panic_handler); | 
 |          SIGACTMASK(SIGBUS, rsync_panic_handler); | 
          SIGACTMASK(SIGBUS, rsync_panic_handler); | 
 |   | 
  #else | 
 |   | 
          SIGACTMASK(SIGSEGV, rsync_crash_handler); | 
 |   | 
          SIGACTMASK(SIGFPE, rsync_crash_handler); | 
 |   | 
          SIGACTMASK(SIGABRT, rsync_crash_handler); | 
 |   | 
          SIGACTMASK(SIGBUS, rsync_crash_handler); | 
 |  #endif | 
  #endif | 
 |  #ifdef SIGINFO | 
  #ifdef SIGINFO | 
 |          SIGACTMASK(SIGINFO, siginfo_handler); | 
          SIGACTMASK(SIGINFO, siginfo_handler); | 
 |  #endif | 
  #endif | 
 |   | 
  #ifdef SIGVTALRM | 
 |   | 
          SIGACTMASK(SIGVTALRM, siginfo_handler); | 
 |   | 
  #endif | 
 |   | 
   | 
 |          starttime = time(NULL); | 
          starttime = time(NULL); | 
 |          our_uid = MY_UID(); | 
          our_uid = MY_UID(); | 
 |          our_gid = MY_GID(); | 
          our_gid = MY_GID(); | 
|         am_root = our_uid == 0; |         am_root = our_uid == ROOT_UID; | 
 |   | 
   | 
 |          memset(&stats, 0, sizeof(stats)); | 
          memset(&stats, 0, sizeof(stats)); | 
 |   | 
   | 
 |   | 
          /* Even a non-daemon runs needs the default config values to be set, e.g. | 
 |   | 
           * lp_dont_compress() is queried when no --skip-compress option is set. */ | 
 |   | 
          reset_daemon_vars(); | 
 |   | 
   | 
 |          if (argc < 2) { | 
          if (argc < 2) { | 
 |                  usage(FERROR); | 
                  usage(FERROR); | 
 |                  exit_cleanup(RERR_SYNTAX); | 
                  exit_cleanup(RERR_SYNTAX); | 
| 
 Line 1576  int main(int argc,char *argv[])
 | 
 Line 1861  int main(int argc,char *argv[])
 | 
 |  #endif | 
  #endif | 
 |   | 
   | 
 |          if (!parse_arguments(&argc, (const char ***) &argv)) { | 
          if (!parse_arguments(&argc, (const char ***) &argv)) { | 
 |                  /* FIXME: We ought to call the same error-handling | 
   | 
 |                   * code here, rather than relying on getopt. */ | 
   | 
 |                  option_error(); | 
                  option_error(); | 
 |                  exit_cleanup(RERR_SYNTAX); | 
                  exit_cleanup(RERR_SYNTAX); | 
 |          } | 
          } | 
 |   | 
          if (write_batch | 
 |   | 
           && poptDupArgv(argc, (const char **)argv, &cooked_argc, (const char ***)&cooked_argv) != 0) | 
 |   | 
                  out_of_memory("main"); | 
 |   | 
   | 
 |          SIGACTMASK(SIGINT, sig_int); | 
          SIGACTMASK(SIGINT, sig_int); | 
 |          SIGACTMASK(SIGHUP, sig_int); | 
          SIGACTMASK(SIGHUP, sig_int); | 
| 
 Line 1602  int main(int argc,char *argv[])
 | 
 Line 1888  int main(int argc,char *argv[])
 | 
 |           * that implement getcwd that way "pwd" can't be found after chroot. */ | 
           * that implement getcwd that way "pwd" can't be found after chroot. */ | 
 |          change_dir(NULL, CD_NORMAL); | 
          change_dir(NULL, CD_NORMAL); | 
 |   | 
   | 
 |          init_flist(); | 
   | 
 |   | 
   | 
 |          if ((write_batch || read_batch) && !am_server) { | 
          if ((write_batch || read_batch) && !am_server) { | 
|                 if (write_batch) |                 open_batch_files(); /* sets batch_fd */ | 
|                         write_batch_shell_file(orig_argc, orig_argv, argc); |   | 
 |   | 
|                 if (read_batch && strcmp(batch_name, "-") == 0) |   | 
|                         batch_fd = STDIN_FILENO; |   | 
|                 else { |   | 
|                         batch_fd = do_open(batch_name, |   | 
|                                    write_batch ? O_WRONLY | O_CREAT | O_TRUNC |   | 
|                                    : O_RDONLY, S_IRUSR | S_IWUSR); |   | 
|                 } |   | 
|                 if (batch_fd < 0) { |   | 
|                         rsyserr(FERROR, errno, "Batch file %s open error", |   | 
|                                 full_fname(batch_name)); |   | 
|                         exit_cleanup(RERR_FILEIO); |   | 
|                 } |   | 
 |                  if (read_batch) | 
                  if (read_batch) | 
 |                          read_stream_flags(batch_fd); | 
                          read_stream_flags(batch_fd); | 
 |                  else | 
                  else |