1 /* $OpenBSD: fargs.c,v 1.26 2023/11/27 11:30:49 claudio Exp $ */ 2 /* 3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/stat.h> 18 19 #include <assert.h> 20 #include <err.h> 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include "extern.h" 26 27 #define RSYNC_PATH "rsync" 28 29 const char * 30 alt_base_mode(int mode) 31 { 32 switch (mode) { 33 case BASE_MODE_COMPARE: 34 return "--compare-dest"; 35 case BASE_MODE_COPY: 36 return "--copy-dest"; 37 case BASE_MODE_LINK: 38 return "--link-dest"; 39 default: 40 errx(1, "unknown base mode %d", mode); 41 } 42 } 43 44 char ** 45 fargs_cmdline(struct sess *sess, const struct fargs *f, size_t *skip) 46 { 47 arglist args; 48 size_t j; 49 char *rsync_path, *ap, *arg; 50 51 memset(&args, 0, sizeof args); 52 53 assert(f != NULL); 54 assert(f->sourcesz > 0); 55 56 if ((rsync_path = sess->opts->rsync_path) == NULL) 57 rsync_path = RSYNC_PATH; 58 59 if (f->host != NULL) { 60 /* 61 * Splice arguments from -e "foo bar baz" into array 62 * elements required for execve(2). 63 * This doesn't do anything fancy: it splits along 64 * whitespace into the array. 65 */ 66 67 if (sess->opts->ssh_prog) { 68 ap = strdup(sess->opts->ssh_prog); 69 if (ap == NULL) 70 err(ERR_NOMEM, NULL); 71 72 while ((arg = strsep(&ap, " \t")) != NULL) { 73 if (arg[0] == '\0') { 74 ap++; /* skip separators */ 75 continue; 76 } 77 78 addargs(&args, "%s", arg); 79 } 80 } else 81 addargs(&args, "ssh"); 82 83 addargs(&args, "%s", f->host); 84 addargs(&args, "%s", rsync_path); 85 if (skip) 86 *skip = args.num; 87 addargs(&args, "--server"); 88 if (f->mode == FARGS_RECEIVER) 89 addargs(&args, "--sender"); 90 } else { 91 addargs(&args, "%s", rsync_path); 92 addargs(&args, "--server"); 93 } 94 95 /* Shared arguments. */ 96 97 if (sess->opts->del) 98 addargs(&args, "--delete"); 99 if (sess->opts->numeric_ids) 100 addargs(&args, "--numeric-ids"); 101 if (sess->opts->preserve_gids) 102 addargs(&args, "-g"); 103 if (sess->opts->preserve_links) 104 addargs(&args, "-l"); 105 if (sess->opts->dry_run) 106 addargs(&args, "-n"); 107 if (sess->opts->preserve_uids) 108 addargs(&args, "-o"); 109 if (sess->opts->preserve_perms) 110 addargs(&args, "-p"); 111 if (sess->opts->devices) 112 addargs(&args, "-D"); 113 if (sess->opts->recursive) 114 addargs(&args, "-r"); 115 if (sess->opts->preserve_times) 116 addargs(&args, "-t"); 117 if (sess->opts->ignore_times) 118 addargs(&args, "-I"); 119 if (verbose > 3) 120 addargs(&args, "-v"); 121 if (verbose > 2) 122 addargs(&args, "-v"); 123 if (verbose > 1) 124 addargs(&args, "-v"); 125 if (verbose > 0) 126 addargs(&args, "-v"); 127 if (sess->opts->one_file_system > 1) 128 addargs(&args, "-x"); 129 if (sess->opts->one_file_system > 0) 130 addargs(&args, "-x"); 131 if (sess->opts->specials && !sess->opts->devices) 132 addargs(&args, "--specials"); 133 if (!sess->opts->specials && sess->opts->devices) 134 /* --devices is sent as -D --no-specials */ 135 addargs(&args, "--no-specials"); 136 if (sess->opts->max_size >= 0) 137 addargs(&args, "--max-size=%lld", sess->opts->max_size); 138 if (sess->opts->min_size >= 0) 139 addargs(&args, "--min-size=%lld", sess->opts->min_size); 140 141 /* extra options for the receiver (local is sender) */ 142 if (f->mode == FARGS_SENDER) { 143 if (sess->opts->ignore_dir_times) 144 addargs(&args, "-O"); 145 if (sess->opts->ignore_link_times) 146 addargs(&args, "-J"); 147 if (sess->opts->size_only) 148 addargs(&args, "--size-only"); 149 150 /* only add --compare-dest, etc if this is the sender */ 151 if (sess->opts->alt_base_mode != 0) { 152 for (j = 0; j < MAX_BASEDIR; j++) { 153 if (sess->opts->basedir[j] == NULL) 154 break; 155 addargs(&args, "%s=%s", 156 alt_base_mode(sess->opts->alt_base_mode), 157 sess->opts->basedir[j]); 158 } 159 } 160 } 161 162 /* Terminate with a full-stop for reasons unknown. */ 163 164 addargs(&args, "."); 165 166 if (f->mode == FARGS_RECEIVER) { 167 for (j = 0; j < f->sourcesz; j++) 168 addargs(&args, "%s", f->sources[j]); 169 } else 170 addargs(&args, "%s", f->sink); 171 172 return args.list; 173 } 174