version 1.31, 2019/02/21 22:06:26 |
version 1.32, 2019/03/06 18:37:22 |
|
|
|
|
#include "extern.h" |
#include "extern.h" |
|
|
static void |
|
fargs_free(struct fargs *p) |
|
{ |
|
size_t i; |
|
|
|
if (p == NULL) |
|
return; |
|
|
|
if (p->sources != NULL) |
|
for (i = 0; i < p->sourcesz; i++) |
|
free(p->sources[i]); |
|
|
|
free(p->sources); |
|
free(p->sink); |
|
free(p->host); |
|
free(p); |
|
} |
|
|
|
/* |
/* |
* A remote host is has a colon before the first path separator. |
* A remote host is has a colon before the first path separator. |
* This works for rsh remote hosts (host:/foo/bar), implicit rsync |
* This works for rsh remote hosts (host:/foo/bar), implicit rsync |
|
|
{ |
{ |
struct opts opts; |
struct opts opts; |
pid_t child; |
pid_t child; |
int fds[2], rc = 0, c, st; |
int fds[2], rc = 0, c, st, i; |
|
struct sess sess; |
struct fargs *fargs; |
struct fargs *fargs; |
|
char **args; |
struct option lopts[] = { |
struct option lopts[] = { |
{ "port", required_argument, NULL, 3 }, |
{ "port", required_argument, NULL, 3 }, |
{ "rsh", required_argument, NULL, 'e' }, |
{ "rsh", required_argument, NULL, 'e' }, |
|
|
* host by the parent. |
* host by the parent. |
*/ |
*/ |
|
|
if (opts.server) { |
if (opts.server) |
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) |
exit(rsync_server(&opts, (size_t)argc, argv)); |
err(1, "pledge"); |
|
return rsync_server(&opts, (size_t)argc, argv); |
|
} |
|
|
|
/* |
/* |
* Now we know that we're the client on the local machine |
* Now we know that we're the client on the local machine |
|
|
|
|
if (fargs->remote) { |
if (fargs->remote) { |
assert(fargs->mode == FARGS_RECEIVER); |
assert(fargs->mode == FARGS_RECEIVER); |
if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw unveil", |
exit(rsync_socket(&opts, fargs)); |
NULL) == -1) |
|
err(1, "pledge"); |
|
rc = rsync_socket(&opts, fargs); |
|
fargs_free(fargs); |
|
return rc; |
|
} |
} |
|
|
/* Drop the dns/inet possibility. */ |
/* Drop the dns/inet possibility. */ |
|
|
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(1, "socketpair"); |
|
|
if ((child = fork()) == -1) { |
switch ((child = fork())) { |
close(fds[0]); |
case -1: |
close(fds[1]); |
|
err(1, "fork"); |
err(1, "fork"); |
} |
case 0: |
|
|
/* Drop the fork possibility. */ |
|
|
|
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw exec unveil", NULL) == -1) |
|
err(1, "pledge"); |
|
|
|
if (child == 0) { |
|
close(fds[0]); |
close(fds[0]); |
fds[0] = -1; |
|
if (pledge("stdio exec", NULL) == -1) |
if (pledge("stdio exec", NULL) == -1) |
err(1, "pledge"); |
err(1, "pledge"); |
rsync_child(&opts, fds[1], fargs); |
|
|
memset(&sess, 0, sizeof(struct sess)); |
|
sess.opts = &opts; |
|
|
|
if ((args = fargs_cmdline(&sess, fargs)) == NULL) { |
|
ERRX1(&sess, "fargs_cmdline"); |
|
_exit(1); |
|
} |
|
|
|
for (i = 0; args[i] != NULL; i++) |
|
LOG2(&sess, "exec[%d] = %s", i, args[i]); |
|
|
|
/* Make sure the child's stdin is from the sender. */ |
|
if (dup2(fds[1], STDIN_FILENO) == -1) { |
|
ERR(&sess, "dup2"); |
|
_exit(1); |
|
} if (dup2(fds[1], STDOUT_FILENO) == -1) { |
|
ERR(&sess, "dup2"); |
|
_exit(1); |
|
} |
|
execvp(args[0], args); |
|
_exit(1); |
/* NOTREACHED */ |
/* NOTREACHED */ |
|
default: |
|
close(fds[1]); |
|
rc = rsync_client(&opts, fds[0], fargs); |
|
break; |
} |
} |
|
|
close(fds[1]); |
|
fds[1] = -1; |
|
if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) |
|
err(1, "pledge"); |
|
rc = rsync_client(&opts, fds[0], fargs); |
|
fargs_free(fargs); |
|
|
|
/* |
/* |
* If the client has an error and exits, the server may be |
* If the client has an error and exits, the server may be |
* sitting around waiting to get data while we waitpid(). |
* sitting around waiting to get data while we waitpid(). |
* So close the connection here so that they don't hang. |
* So close the connection here so that they don't hang. |
*/ |
*/ |
|
|
if (!rc) { |
if (!rc) |
close(fds[0]); |
close(fds[0]); |
fds[0] = -1; |
|
} |
|
|
|
if (waitpid(child, &st, 0) == -1) |
if (waitpid(child, &st, 0) == -1) |
err(1, "waitpid"); |
err(1, "waitpid"); |
if (!(WIFEXITED(st) && WEXITSTATUS(st) == 0)) |
if (!(WIFEXITED(st) && WEXITSTATUS(st) == 0)) |
rc = 0; |
rc = 0; |
|
exit(rc); |
if (fds[0] != -1) |
|
close(fds[0]); |
|
return rc; |
|
usage: |
usage: |
fprintf(stderr, "usage: %s [-Daglnoprtv] " |
fprintf(stderr, "usage: %s [-Daglnoprtv] " |
"[-e ssh-prog] [--delete] [--rsync-path=prog] src ... dst\n", |
"[-e ssh-prog] [--delete] [--rsync-path=prog] src ... dst\n", |
getprogname()); |
getprogname()); |
return 1; |
exit(1); |
} |
} |