xref: /openbsd-src/usr.bin/rsync/fargs.c (revision 9f11ffb7133c203312a01e4b986886bc88c7d74b)
1 /*	$Id: fargs.c,v 1.9 2019/02/13 19:13:18 deraadt 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 <stdint.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "extern.h"
25 
26 #define	RSYNC_PATH	"rsync"
27 
28 char **
29 fargs_cmdline(struct sess *sess, const struct fargs *f)
30 {
31 	char		**args = NULL, **new;
32 	size_t		  i = 0, n = 1, j, argsz = 0;
33 	char		 *rsync_path;
34 
35 	assert(f != NULL);
36 	assert(f->sourcesz > 0);
37 
38 	if ((rsync_path = sess->opts->rsync_path) == NULL)
39 		rsync_path = RSYNC_PATH;
40 
41 	/* Be explicit with array size. */
42 
43 	argsz += 1;	/* dot separator */
44 	argsz += 1;	/* sink file */
45 	argsz += 5;	/* per-mode maximum */
46 	argsz += 11;	/* shared args */
47 	argsz += 1;	/* NULL pointer */
48 	argsz += f->sourcesz;
49 
50 	args = calloc(argsz, sizeof(char *));
51 	if (args == NULL)
52 		goto out;
53 
54 	if (f->host != NULL) {
55 		assert(f->host != NULL);
56 
57 		if (sess->opts->ssh_prog) {
58 			char *ap = strdup(sess->opts->ssh_prog);
59 
60 			if (ap == NULL)
61 				goto out;
62 			while ((args[i] = strsep(&ap, " \t")) != NULL) {
63 				if (args[i][0] == '\0') {
64 					ap++;	/* skip seperators */
65 					continue;
66 				}
67 
68 				/* Grow command-area of array */
69 				if (i++ < n)
70 					continue;
71 				n += 10;
72 				new = reallocarray(args, argsz + n, sizeof(char *));
73 				if (new == NULL)
74 					goto out;
75 				args = new;
76 				argsz += n;
77 			}
78 		} else
79 			args[i++] = "ssh";
80 		args[i++] = f->host;
81 		args[i++] = rsync_path;
82 		args[i++] = "--server";
83 		if (f->mode == FARGS_RECEIVER)
84 			args[i++] = "--sender";
85 	} else {
86 		args[i++] = rsync_path;
87 		args[i++] = "--server";
88 	}
89 
90 	/* Shared arguments. */
91 
92 	if (sess->opts->del)
93 		args[i++] = "--delete";
94 	if (sess->opts->preserve_gids)
95 		args[i++] = "-g";
96 	if (sess->opts->preserve_links)
97 		args[i++] = "-l";
98 	if (sess->opts->dry_run)
99 		args[i++] = "-n";
100 	if (sess->opts->preserve_perms)
101 		args[i++] = "-p";
102 	if (sess->opts->recursive)
103 		args[i++] = "-r";
104 	if (sess->opts->preserve_times)
105 		args[i++] = "-t";
106 	if (sess->opts->verbose > 3)
107 		args[i++] = "-v";
108 	if (sess->opts->verbose > 2)
109 		args[i++] = "-v";
110 	if (sess->opts->verbose > 1)
111 		args[i++] = "-v";
112 	if (sess->opts->verbose > 0)
113 		args[i++] = "-v";
114 
115 	/* Terminate with a full-stop for reasons unknown. */
116 
117 	args[i++] = ".";
118 
119 	if (f->mode == FARGS_RECEIVER) {
120 		for (j = 0; j < f->sourcesz; j++)
121 			args[i++] = f->sources[j];
122 	} else
123 		args[i++] = f->sink;
124 
125 	args[i] = NULL;
126 	return args;
127 out:
128 	free(args);
129 	ERR(sess, "calloc");
130 	return NULL;
131 }
132