version 1.53, 2021/03/31 19:45:16 |
version 1.54, 2021/05/17 12:04:38 |
|
|
/* Allocations. */ |
/* Allocations. */ |
|
|
if ((f = calloc(1, sizeof(struct fargs))) == NULL) |
if ((f = calloc(1, sizeof(struct fargs))) == NULL) |
err(1, "calloc"); |
err(ERR_NOMEM, NULL); |
|
|
f->sourcesz = argc - 1; |
f->sourcesz = argc - 1; |
if ((f->sources = calloc(f->sourcesz, sizeof(char *))) == NULL) |
if ((f->sources = calloc(f->sourcesz, sizeof(char *))) == NULL) |
err(1, "calloc"); |
err(ERR_NOMEM, NULL); |
|
|
for (i = 0; i < argc - 1; i++) |
for (i = 0; i < argc - 1; i++) |
if ((f->sources[i] = strdup(argv[i])) == NULL) |
if ((f->sources[i] = strdup(argv[i])) == NULL) |
err(1, "strdup"); |
err(ERR_NOMEM, NULL); |
|
|
if ((f->sink = strdup(argv[i])) == NULL) |
if ((f->sink = strdup(argv[i])) == NULL) |
err(1, "strdup"); |
err(ERR_NOMEM, NULL); |
|
|
/* |
/* |
* Test files for its locality. |
* Test files for its locality. |
|
|
if (fargs_is_remote(f->sink)) { |
if (fargs_is_remote(f->sink)) { |
f->mode = FARGS_SENDER; |
f->mode = FARGS_SENDER; |
if ((f->host = strdup(f->sink)) == NULL) |
if ((f->host = strdup(f->sink)) == NULL) |
err(1, "strdup"); |
err(ERR_NOMEM, NULL); |
} |
} |
|
|
if (fargs_is_remote(f->sources[0])) { |
if (fargs_is_remote(f->sources[0])) { |
if (f->host != NULL) |
if (f->host != NULL) |
errx(1, "both source and destination cannot be remote files"); |
errx(ERR_SYNTAX, "both source and destination " |
|
"cannot be remote files"); |
f->mode = FARGS_RECEIVER; |
f->mode = FARGS_RECEIVER; |
if ((f->host = strdup(f->sources[0])) == NULL) |
if ((f->host = strdup(f->sources[0])) == NULL) |
err(1, "strdup"); |
err(ERR_NOMEM, NULL); |
} |
} |
|
|
if (f->host != NULL) { |
if (f->host != NULL) { |
|
|
len = strlen(f->host) - 8 + 1; |
len = strlen(f->host) - 8 + 1; |
memmove(f->host, f->host + 8, len); |
memmove(f->host, f->host + 8, len); |
if ((cp = strchr(f->host, '/')) == NULL) |
if ((cp = strchr(f->host, '/')) == NULL) |
errx(1, "rsync protocol requires a module name"); |
errx(ERR_SYNTAX, |
|
"rsync protocol requires a module name"); |
*cp++ = '\0'; |
*cp++ = '\0'; |
f->module = cp; |
f->module = cp; |
if ((cp = strchr(f->module, '/')) != NULL) |
if ((cp = strchr(f->module, '/')) != NULL) |
|
|
} |
} |
} |
} |
if ((len = strlen(f->host)) == 0) |
if ((len = strlen(f->host)) == 0) |
errx(1, "empty remote host"); |
errx(ERR_SYNTAX, "empty remote host"); |
if (f->remote && strlen(f->module) == 0) |
if (f->remote && strlen(f->module) == 0) |
errx(1, "empty remote module"); |
errx(ERR_SYNTAX, "empty remote module"); |
} |
} |
|
|
/* Make sure we have the same "hostspec" for all files. */ |
/* Make sure we have the same "hostspec" for all files. */ |
|
|
for (i = 0; i < f->sourcesz; i++) { |
for (i = 0; i < f->sourcesz; i++) { |
if (!fargs_is_remote(f->sources[i])) |
if (!fargs_is_remote(f->sources[i])) |
continue; |
continue; |
errx(1, |
errx(ERR_SYNTAX, |
"remote file in list of local sources: %s", |
"remote file in list of local sources: %s", |
f->sources[i]); |
f->sources[i]); |
} |
} |
|
|
!fargs_is_daemon(f->sources[i])) |
!fargs_is_daemon(f->sources[i])) |
continue; |
continue; |
if (fargs_is_daemon(f->sources[i])) |
if (fargs_is_daemon(f->sources[i])) |
errx(1, "remote daemon in list of " |
errx(ERR_SYNTAX, |
"remote sources: %s", |
"remote daemon in list of remote " |
f->sources[i]); |
"sources: %s", f->sources[i]); |
errx(1, "local file in list of remote sources: %s", |
errx(ERR_SYNTAX, "local file in list of " |
f->sources[i]); |
"remote sources: %s", f->sources[i]); |
} |
} |
} else { |
} else { |
if (f->mode != FARGS_RECEIVER) |
if (f->mode != FARGS_RECEIVER) |
errx(1, "sender mode for remote " |
errx(ERR_SYNTAX, "sender mode for remote " |
"daemon receivers not yet supported"); |
"daemon receivers not yet supported"); |
for (i = 0; i < f->sourcesz; i++) { |
for (i = 0; i < f->sourcesz; i++) { |
if (fargs_is_daemon(f->sources[i])) |
if (fargs_is_daemon(f->sources[i])) |
continue; |
continue; |
errx(1, "non-remote daemon file " |
errx(ERR_SYNTAX, "non-remote daemon file " |
"in list of remote daemon sources: " |
"in list of remote daemon sources: " |
"%s", f->sources[i]); |
"%s", f->sources[i]); |
} |
} |
|
|
*ccp = '\0'; |
*ccp = '\0'; |
if (strncmp(cp, f->host, len) || |
if (strncmp(cp, f->host, len) || |
(cp[len] != '/' && cp[len] != '\0')) |
(cp[len] != '/' && cp[len] != '\0')) |
errx(1, "different remote host: %s", |
errx(ERR_SYNTAX, "different remote host: %s", |
f->sources[i]); |
f->sources[i]); |
memmove(f->sources[i], |
memmove(f->sources[i], |
f->sources[i] + len + 8 + 1, |
f->sources[i] + len + 8 + 1, |
|
|
/* host::path */ |
/* host::path */ |
if (strncmp(cp, f->host, len) || |
if (strncmp(cp, f->host, len) || |
(cp[len] != ':' && cp[len] != '\0')) |
(cp[len] != ':' && cp[len] != '\0')) |
errx(1, "different remote host: %s", |
errx(ERR_SYNTAX, "different remote host: %s", |
f->sources[i]); |
f->sources[i]); |
memmove(f->sources[i], f->sources[i] + len + 2, |
memmove(f->sources[i], f->sources[i] + len + 2, |
j - len - 1); |
j - len - 1); |
|
|
/* host:path */ |
/* host:path */ |
if (strncmp(cp, f->host, len) || |
if (strncmp(cp, f->host, len) || |
(cp[len] != ':' && cp[len] != '\0')) |
(cp[len] != ':' && cp[len] != '\0')) |
errx(1, "different remote host: %s", |
errx(ERR_SYNTAX, "different remote host: %s", |
f->sources[i]); |
f->sources[i]); |
memmove(f->sources[i], |
memmove(f->sources[i], |
f->sources[i] + len + 1, j - len); |
f->sources[i] + len + 1, j - len); |
|
|
|
|
if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw proc exec unveil", |
if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw proc exec unveil", |
NULL) == -1) |
NULL) == -1) |
err(1, "pledge"); |
err(ERR_IPC, "pledge"); |
|
|
memset(&opts, 0, sizeof(struct opts)); |
memset(&opts, 0, sizeof(struct opts)); |
|
|
|
|
case 5: |
case 5: |
poll_timeout = strtonum(optarg, 0, 60*60, &errstr); |
poll_timeout = strtonum(optarg, 0, 60*60, &errstr); |
if (errstr != NULL) |
if (errstr != NULL) |
errx(1, "timeout is %s: %s", errstr, optarg); |
errx(ERR_SYNTAX, "timeout is %s: %s", |
|
errstr, optarg); |
break; |
break; |
case 6: |
case 6: |
opts.no_motd = 1; |
opts.no_motd = 1; |
|
|
|
|
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw proc exec unveil", |
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw proc exec unveil", |
NULL) == -1) |
NULL) == -1) |
err(1, "pledge"); |
err(ERR_IPC, "pledge"); |
|
|
/* Create a bidirectional socket and start our child. */ |
/* Create a bidirectional socket and start our child. */ |
|
|
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds) == -1) |
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds) == -1) |
err(1, "socketpair"); |
err(ERR_IPC, "socketpair"); |
|
|
switch ((child = fork())) { |
switch ((child = fork())) { |
case -1: |
case -1: |
err(1, "fork"); |
err(ERR_IPC, "fork"); |
case 0: |
case 0: |
close(fds[0]); |
close(fds[0]); |
if (pledge("stdio exec", NULL) == -1) |
if (pledge("stdio exec", NULL) == -1) |
err(1, "pledge"); |
err(ERR_IPC, "pledge"); |
|
|
memset(&sess, 0, sizeof(struct sess)); |
memset(&sess, 0, sizeof(struct sess)); |
sess.opts = &opts; |
sess.opts = &opts; |
|
|
if ((args = fargs_cmdline(&sess, fargs, NULL)) == NULL) { |
args = fargs_cmdline(&sess, fargs, NULL); |
ERRX1("fargs_cmdline"); |
|
_exit(1); |
|
} |
|
|
|
for (i = 0; args[i] != NULL; i++) |
for (i = 0; args[i] != NULL; i++) |
LOG2("exec[%d] = %s", i, args[i]); |
LOG2("exec[%d] = %s", i, args[i]); |
|
|
/* Make sure the child's stdin is from the sender. */ |
/* Make sure the child's stdin is from the sender. */ |
if (dup2(fds[1], STDIN_FILENO) == -1) { |
if (dup2(fds[1], STDIN_FILENO) == -1) |
ERR("dup2"); |
err(ERR_IPC, "dup2"); |
_exit(1); |
if (dup2(fds[1], STDOUT_FILENO) == -1) |
} |
err(ERR_IPC, "dup2"); |
if (dup2(fds[1], STDOUT_FILENO) == -1) { |
|
ERR("dup2"); |
|
_exit(1); |
|
} |
|
execvp(args[0], args); |
execvp(args[0], args); |
_exit(1); |
_exit(ERR_IPC); |
/* NOTREACHED */ |
/* NOTREACHED */ |
default: |
default: |
close(fds[1]); |
close(fds[1]); |
|
|
close(fds[0]); |
close(fds[0]); |
|
|
if (waitpid(child, &st, 0) == -1) |
if (waitpid(child, &st, 0) == -1) |
err(1, "waitpid"); |
err(ERR_WAITPID, "waitpid"); |
|
|
/* |
/* |
* If we don't already have an error (rc == 0), then inherit the |
* If we don't already have an error (rc == 0), then inherit the |
|
|
* If it hasn't exited, it overrides our return value. |
* If it hasn't exited, it overrides our return value. |
*/ |
*/ |
|
|
if (WIFEXITED(st) && rc == 0) |
if (rc == 0) { |
rc = WEXITSTATUS(st); |
if (WIFEXITED(st)) |
else if (!WIFEXITED(st)) |
rc = WEXITSTATUS(st); |
rc = 1; |
else if (WIFSIGNALED(st)) |
|
rc = ERR_TERMIMATED; |
|
else |
|
rc = ERR_WAITPID; |
|
} |
|
|
exit(rc); |
exit(rc); |
usage: |
usage: |
|
|
"[--rsync-path=program]\n\t[--timeout=seconds] [--version] " |
"[--rsync-path=program]\n\t[--timeout=seconds] [--version] " |
"source ... directory\n", |
"source ... directory\n", |
getprogname()); |
getprogname()); |
exit(1); |
exit(ERR_SYNTAX); |
} |
} |