[BACK]Return to main.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rsync

Annotation of src/usr.bin/rsync/main.c, Revision 1.71

1.71    ! claudio     1: /*     $OpenBSD: main.c,v 1.70 2023/11/27 10:14:19 claudio Exp $ */
1.1       benno       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: #include <sys/socket.h>
                     19: #include <sys/wait.h>
                     20:
                     21: #include <assert.h>
                     22: #include <err.h>
                     23: #include <getopt.h>
                     24: #include <stdint.h>
                     25: #include <stdio.h>
                     26: #include <stdlib.h>
                     27: #include <string.h>
                     28: #include <unistd.h>
1.62      claudio    29: #include <util.h>
1.1       benno      30:
                     31: #include "extern.h"
                     32:
1.45      benno      33: int verbose;
1.64      job        34: int poll_contimeout;
1.50      claudio    35: int poll_timeout;
1.45      benno      36:
1.1       benno      37: /*
                     38:  * A remote host is has a colon before the first path separator.
                     39:  * This works for rsh remote hosts (host:/foo/bar), implicit rsync
                     40:  * remote hosts (host::/foo/bar), and explicit (rsync://host/foo).
                     41:  * Return zero if local, non-zero if remote.
                     42:  */
                     43: static int
                     44: fargs_is_remote(const char *v)
                     45: {
                     46:        size_t   pos;
                     47:
                     48:        pos = strcspn(v, ":/");
1.6       deraadt    49:        return v[pos] == ':';
1.1       benno      50: }
                     51:
                     52: /*
                     53:  * Test whether a remote host is specifically an rsync daemon.
                     54:  * Return zero if not, non-zero if so.
                     55:  */
                     56: static int
                     57: fargs_is_daemon(const char *v)
                     58: {
                     59:        size_t   pos;
                     60:
1.6       deraadt    61:        if (strncasecmp(v, "rsync://", 8) == 0)
1.1       benno      62:                return 1;
                     63:
                     64:        pos = strcspn(v, ":/");
1.6       deraadt    65:        return v[pos] == ':' && v[pos + 1] == ':';
1.1       benno      66: }
                     67:
                     68: /*
                     69:  * Take the command-line filenames (e.g., rsync foo/ bar/ baz/) and
                     70:  * determine our operating mode.
                     71:  * For example, if the first argument is a remote file, this means that
                     72:  * we're going to transfer from the remote to the local.
                     73:  * We also make sure that the arguments are consistent, that is, if
                     74:  * we're going to transfer from the local to the remote, that no
                     75:  * filenames for the local transfer indicate remote hosts.
                     76:  * Always returns the parsed and sanitised options.
                     77:  */
                     78: static struct fargs *
1.26      deraadt    79: fargs_parse(size_t argc, char *argv[], struct opts *opts)
1.1       benno      80: {
                     81:        struct fargs    *f = NULL;
1.26      deraadt    82:        char            *cp, *ccp;
1.1       benno      83:        size_t           i, j, len = 0;
                     84:
                     85:        /* Allocations. */
                     86:
1.6       deraadt    87:        if ((f = calloc(1, sizeof(struct fargs))) == NULL)
1.54      claudio    88:                err(ERR_NOMEM, NULL);
1.1       benno      89:
                     90:        f->sourcesz = argc - 1;
1.6       deraadt    91:        if ((f->sources = calloc(f->sourcesz, sizeof(char *))) == NULL)
1.54      claudio    92:                err(ERR_NOMEM, NULL);
1.1       benno      93:
                     94:        for (i = 0; i < argc - 1; i++)
1.6       deraadt    95:                if ((f->sources[i] = strdup(argv[i])) == NULL)
1.54      claudio    96:                        err(ERR_NOMEM, NULL);
1.1       benno      97:
1.6       deraadt    98:        if ((f->sink = strdup(argv[i])) == NULL)
1.54      claudio    99:                err(ERR_NOMEM, NULL);
1.1       benno     100:
                    101:        /*
                    102:         * Test files for its locality.
                    103:         * If the last is a remote host, then we're sending from the
                    104:         * local to the remote host ("sender" mode).
                    105:         * If the first, remote to local ("receiver" mode).
                    106:         * If neither, a local transfer in sender style.
                    107:         */
                    108:
                    109:        f->mode = FARGS_SENDER;
                    110:
                    111:        if (fargs_is_remote(f->sink)) {
                    112:                f->mode = FARGS_SENDER;
1.6       deraadt   113:                if ((f->host = strdup(f->sink)) == NULL)
1.54      claudio   114:                        err(ERR_NOMEM, NULL);
1.1       benno     115:        }
                    116:
                    117:        if (fargs_is_remote(f->sources[0])) {
1.6       deraadt   118:                if (f->host != NULL)
1.54      claudio   119:                        errx(ERR_SYNTAX, "both source and destination "
                    120:                            "cannot be remote files");
1.1       benno     121:                f->mode = FARGS_RECEIVER;
1.6       deraadt   122:                if ((f->host = strdup(f->sources[0])) == NULL)
1.54      claudio   123:                        err(ERR_NOMEM, NULL);
1.1       benno     124:        }
                    125:
1.6       deraadt   126:        if (f->host != NULL) {
                    127:                if (strncasecmp(f->host, "rsync://", 8) == 0) {
1.30      benno     128:                        /* rsync://host[:port]/module[/path] */
1.1       benno     129:                        f->remote = 1;
                    130:                        len = strlen(f->host) - 8 + 1;
                    131:                        memmove(f->host, f->host + 8, len);
1.6       deraadt   132:                        if ((cp = strchr(f->host, '/')) == NULL)
1.54      claudio   133:                                errx(ERR_SYNTAX,
                    134:                                    "rsync protocol requires a module name");
1.1       benno     135:                        *cp++ = '\0';
                    136:                        f->module = cp;
1.6       deraadt   137:                        if ((cp = strchr(f->module, '/')) != NULL)
1.1       benno     138:                                *cp = '\0';
1.52      claudio   139:                        if ((cp = strchr(f->host, ':')) != NULL) {
1.26      deraadt   140:                                /* host:port --> extract port */
                    141:                                *cp++ = '\0';
                    142:                                opts->port = cp;
                    143:                        }
1.1       benno     144:                } else {
                    145:                        /* host:[/path] */
                    146:                        cp = strchr(f->host, ':');
1.6       deraadt   147:                        assert(cp != NULL);
1.1       benno     148:                        *cp++ = '\0';
1.6       deraadt   149:                        if (*cp == ':') {
1.1       benno     150:                                /* host::module[/path] */
                    151:                                f->remote = 1;
                    152:                                f->module = ++cp;
                    153:                                cp = strchr(f->module, '/');
1.6       deraadt   154:                                if (cp != NULL)
1.1       benno     155:                                        *cp = '\0';
                    156:                        }
                    157:                }
1.6       deraadt   158:                if ((len = strlen(f->host)) == 0)
1.54      claudio   159:                        errx(ERR_SYNTAX, "empty remote host");
1.6       deraadt   160:                if (f->remote && strlen(f->module) == 0)
1.54      claudio   161:                        errx(ERR_SYNTAX, "empty remote module");
1.1       benno     162:        }
                    163:
                    164:        /* Make sure we have the same "hostspec" for all files. */
                    165:
1.4       deraadt   166:        if (!f->remote) {
1.6       deraadt   167:                if (f->mode == FARGS_SENDER)
1.1       benno     168:                        for (i = 0; i < f->sourcesz; i++) {
1.4       deraadt   169:                                if (!fargs_is_remote(f->sources[i]))
1.1       benno     170:                                        continue;
1.54      claudio   171:                                errx(ERR_SYNTAX,
1.35      deraadt   172:                                    "remote file in list of local sources: %s",
                    173:                                    f->sources[i]);
1.1       benno     174:                        }
1.6       deraadt   175:                if (f->mode == FARGS_RECEIVER)
1.1       benno     176:                        for (i = 0; i < f->sourcesz; i++) {
                    177:                                if (fargs_is_remote(f->sources[i]) &&
1.4       deraadt   178:                                    !fargs_is_daemon(f->sources[i]))
1.1       benno     179:                                        continue;
                    180:                                if (fargs_is_daemon(f->sources[i]))
1.54      claudio   181:                                        errx(ERR_SYNTAX,
                    182:                                            "remote daemon in list of remote "
                    183:                                            "sources: %s", f->sources[i]);
                    184:                                errx(ERR_SYNTAX, "local file in list of "
                    185:                                    "remote sources: %s", f->sources[i]);
1.1       benno     186:                        }
                    187:        } else {
1.6       deraadt   188:                if (f->mode != FARGS_RECEIVER)
1.54      claudio   189:                        errx(ERR_SYNTAX, "sender mode for remote "
1.1       benno     190:                                "daemon receivers not yet supported");
                    191:                for (i = 0; i < f->sourcesz; i++) {
                    192:                        if (fargs_is_daemon(f->sources[i]))
                    193:                                continue;
1.54      claudio   194:                        errx(ERR_SYNTAX, "non-remote daemon file "
1.1       benno     195:                                "in list of remote daemon sources: "
                    196:                                "%s", f->sources[i]);
                    197:                }
                    198:        }
                    199:
                    200:        /*
                    201:         * If we're not remote and a sender, strip our hostname.
                    202:         * Then exit if we're a sender or a local connection.
                    203:         */
                    204:
1.4       deraadt   205:        if (!f->remote) {
1.6       deraadt   206:                if (f->host == NULL)
1.1       benno     207:                        return f;
1.6       deraadt   208:                if (f->mode == FARGS_SENDER) {
                    209:                        assert(f->host != NULL);
1.1       benno     210:                        assert(len > 0);
                    211:                        j = strlen(f->sink);
                    212:                        memmove(f->sink, f->sink + len + 1, j - len);
                    213:                        return f;
1.6       deraadt   214:                } else if (f->mode != FARGS_RECEIVER)
1.1       benno     215:                        return f;
                    216:        }
                    217:
                    218:        /*
                    219:         * Now strip the hostnames from the remote host.
                    220:         *   rsync://host/module/path -> module/path
                    221:         *   host::module/path -> module/path
                    222:         *   host:path -> path
                    223:         * Also make sure that the remote hosts are the same.
                    224:         */
                    225:
1.6       deraadt   226:        assert(f->host != NULL);
1.1       benno     227:        assert(len > 0);
                    228:
                    229:        for (i = 0; i < f->sourcesz; i++) {
                    230:                cp = f->sources[i];
                    231:                j = strlen(cp);
                    232:                if (f->remote &&
1.6       deraadt   233:                    strncasecmp(cp, "rsync://", 8) == 0) {
1.66      job       234:                        /* rsync://host[:port]/path */
                    235:                        size_t module_offset = len;
1.1       benno     236:                        cp += 8;
1.66      job       237:                        /* skip :port */
                    238:                        if ((ccp = strchr(cp, ':')) != NULL) {
1.26      deraadt   239:                                *ccp = '\0';
1.66      job       240:                                module_offset += strcspn(ccp + 1, "/") + 1;
                    241:                        }
1.1       benno     242:                        if (strncmp(cp, f->host, len) ||
1.11      benno     243:                            (cp[len] != '/' && cp[len] != '\0'))
1.54      claudio   244:                                errx(ERR_SYNTAX, "different remote host: %s",
1.35      deraadt   245:                                    f->sources[i]);
1.1       benno     246:                        memmove(f->sources[i],
1.66      job       247:                                f->sources[i] + module_offset + 8 + 1,
                    248:                                j - module_offset - 8);
1.6       deraadt   249:                } else if (f->remote && strncmp(cp, "::", 2) == 0) {
1.1       benno     250:                        /* ::path */
                    251:                        memmove(f->sources[i],
                    252:                                f->sources[i] + 2, j - 1);
                    253:                } else if (f->remote) {
                    254:                        /* host::path */
                    255:                        if (strncmp(cp, f->host, len) ||
1.6       deraadt   256:                            (cp[len] != ':' && cp[len] != '\0'))
1.54      claudio   257:                                errx(ERR_SYNTAX, "different remote host: %s",
1.35      deraadt   258:                                    f->sources[i]);
1.11      benno     259:                        memmove(f->sources[i], f->sources[i] + len + 2,
                    260:                            j - len - 1);
1.6       deraadt   261:                } else if (cp[0] == ':') {
1.1       benno     262:                        /* :path */
                    263:                        memmove(f->sources[i], f->sources[i] + 1, j);
                    264:                } else {
                    265:                        /* host:path */
                    266:                        if (strncmp(cp, f->host, len) ||
1.6       deraadt   267:                            (cp[len] != ':' && cp[len] != '\0'))
1.54      claudio   268:                                errx(ERR_SYNTAX, "different remote host: %s",
1.35      deraadt   269:                                    f->sources[i]);
1.1       benno     270:                        memmove(f->sources[i],
                    271:                                f->sources[i] + len + 1, j - len);
                    272:                }
                    273:        }
                    274:
                    275:        return f;
                    276: }
                    277:
1.56      claudio   278: static struct opts      opts;
                    279:
                    280: #define OP_ADDRESS     1000
                    281: #define OP_PORT                1001
                    282: #define OP_RSYNCPATH   1002
                    283: #define OP_TIMEOUT     1003
1.57      claudio   284: #define OP_EXCLUDE     1005
                    285: #define OP_INCLUDE     1006
                    286: #define OP_EXCLUDE_FROM        1007
                    287: #define OP_INCLUDE_FROM        1008
1.60      claudio   288: #define OP_COMP_DEST   1009
                    289: #define OP_COPY_DEST   1010
                    290: #define OP_LINK_DEST   1011
1.61      claudio   291: #define OP_MAX_SIZE    1012
                    292: #define OP_MIN_SIZE    1013
1.64      job       293: #define OP_CONTIMEOUT  1014
1.56      claudio   294:
                    295: const struct option     lopts[] = {
                    296:     { "address",       required_argument, NULL,                OP_ADDRESS },
                    297:     { "archive",       no_argument,    NULL,                   'a' },
1.60      claudio   298:     { "compare-dest",  required_argument, NULL,                OP_COMP_DEST },
                    299: #if 0
                    300:     { "copy-dest",     required_argument, NULL,                OP_COPY_DEST },
                    301:     { "link-dest",     required_argument, NULL,                OP_LINK_DEST },
                    302: #endif
1.56      claudio   303:     { "compress",      no_argument,    NULL,                   'z' },
1.64      job       304:     { "contimeout",    required_argument, NULL,                OP_CONTIMEOUT },
1.56      claudio   305:     { "del",           no_argument,    &opts.del,              1 },
                    306:     { "delete",                no_argument,    &opts.del,              1 },
                    307:     { "devices",       no_argument,    &opts.devices,          1 },
                    308:     { "no-devices",    no_argument,    &opts.devices,          0 },
                    309:     { "dry-run",       no_argument,    &opts.dry_run,          1 },
1.63      deraadt   310:     { "exclude",       required_argument, NULL,                OP_EXCLUDE },
1.57      claudio   311:     { "exclude-from",  required_argument, NULL,                OP_EXCLUDE_FROM },
1.56      claudio   312:     { "group",         no_argument,    &opts.preserve_gids,    1 },
                    313:     { "no-group",      no_argument,    &opts.preserve_gids,    0 },
                    314:     { "help",          no_argument,    NULL,                   'h' },
1.68      claudio   315:     { "ignore-times",  no_argument,    NULL,                   'I' },
1.63      deraadt   316:     { "include",       required_argument, NULL,                OP_INCLUDE },
1.57      claudio   317:     { "include-from",  required_argument, NULL,                OP_INCLUDE_FROM },
1.56      claudio   318:     { "links",         no_argument,    &opts.preserve_links,   1 },
1.61      claudio   319:     { "max-size",      required_argument, NULL,                OP_MAX_SIZE },
                    320:     { "min-size",      required_argument, NULL,                OP_MIN_SIZE },
1.56      claudio   321:     { "no-links",      no_argument,    &opts.preserve_links,   0 },
                    322:     { "no-motd",       no_argument,    &opts.no_motd,          1 },
                    323:     { "numeric-ids",   no_argument,    &opts.numeric_ids,      1 },
1.69      job       324:     { "omit-dir-times",        no_argument,    &opts.ignore_dir_times, 1 },
1.70      claudio   325:     { "no-O",          no_argument,    &opts.ignore_dir_times, 0 },
1.71    ! claudio   326:     { "no-omit-dir-times",     no_argument,    &opts.ignore_dir_times, 0 },
        !           327:     { "omit-link-times",       no_argument,    &opts.ignore_link_times, 1 },
        !           328:     { "no-J",          no_argument,    &opts.ignore_link_times, 0 },
        !           329:     { "no-omit-link-times",    no_argument,    &opts.ignore_link_times, 0 },
1.56      claudio   330:     { "owner",         no_argument,    &opts.preserve_uids,    1 },
                    331:     { "no-owner",      no_argument,    &opts.preserve_uids,    0 },
                    332:     { "perms",         no_argument,    &opts.preserve_perms,   1 },
                    333:     { "no-perms",      no_argument,    &opts.preserve_perms,   0 },
                    334:     { "port",          required_argument, NULL,                OP_PORT },
                    335:     { "recursive",     no_argument,    &opts.recursive,        1 },
                    336:     { "no-recursive",  no_argument,    &opts.recursive,        0 },
                    337:     { "rsh",           required_argument, NULL,                'e' },
                    338:     { "rsync-path",    required_argument, NULL,                OP_RSYNCPATH },
                    339:     { "sender",                no_argument,    &opts.sender,           1 },
                    340:     { "server",                no_argument,    &opts.server,           1 },
1.68      claudio   341:     { "size-only",     no_argument,    &opts.size_only,        1 },
1.56      claudio   342:     { "specials",      no_argument,    &opts.specials,         1 },
                    343:     { "no-specials",   no_argument,    &opts.specials,         0 },
                    344:     { "timeout",       required_argument, NULL,                OP_TIMEOUT },
                    345:     { "times",         no_argument,    &opts.preserve_times,   1 },
                    346:     { "no-times",      no_argument,    &opts.preserve_times,   0 },
                    347:     { "verbose",       no_argument,    &verbose,               1 },
                    348:     { "no-verbose",    no_argument,    &verbose,               0 },
1.67      claudio   349:     { "version",       no_argument,    NULL,                   'V' },
1.56      claudio   350:     { NULL,            0,              NULL,                   0 }
                    351: };
                    352:
1.1       benno     353: int
                    354: main(int argc, char *argv[])
                    355: {
1.2       benno     356:        pid_t            child;
1.60      claudio   357:        int              fds[2], sd = -1, rc, c, st, i, lidx;
                    358:        size_t           basedir_cnt = 0;
1.62      claudio   359:        struct sess      sess;
1.1       benno     360:        struct fargs    *fargs;
1.32      deraadt   361:        char            **args;
1.63      deraadt   362:        const char      *errstr;
1.57      claudio   363:
1.1       benno     364:        /* Global pledge. */
                    365:
1.19      florian   366:        if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw proc exec unveil",
1.6       deraadt   367:            NULL) == -1)
1.54      claudio   368:                err(ERR_IPC, "pledge");
1.1       benno     369:
1.62      claudio   370:        opts.max_size = opts.min_size = -1;
                    371:
1.71    ! claudio   372:        while ((c = getopt_long(argc, argv, "aDe:ghIJlnOoprtVvxz",
        !           373:            lopts, &lidx)) != -1) {
1.1       benno     374:                switch (c) {
1.19      florian   375:                case 'D':
                    376:                        opts.devices = 1;
                    377:                        opts.specials = 1;
                    378:                        break;
                    379:                case 'a':
                    380:                        opts.recursive = 1;
                    381:                        opts.preserve_links = 1;
                    382:                        opts.preserve_perms = 1;
                    383:                        opts.preserve_times = 1;
                    384:                        opts.preserve_gids = 1;
                    385:                        opts.preserve_uids = 1;
                    386:                        opts.devices = 1;
                    387:                        opts.specials = 1;
                    388:                        break;
1.1       benno     389:                case 'e':
1.9       deraadt   390:                        opts.ssh_prog = optarg;
1.1       benno     391:                        break;
1.10      benno     392:                case 'g':
                    393:                        opts.preserve_gids = 1;
                    394:                        break;
1.68      claudio   395:                case 'I':
                    396:                        opts.ignore_times = 1;
                    397:                        break;
1.71    ! claudio   398:                case 'J':
        !           399:                        opts.ignore_link_times = 1;
        !           400:                        break;
1.1       benno     401:                case 'l':
                    402:                        opts.preserve_links = 1;
                    403:                        break;
                    404:                case 'n':
                    405:                        opts.dry_run = 1;
                    406:                        break;
1.69      job       407:                case 'O':
                    408:                        opts.ignore_dir_times = 1;
                    409:                        break;
1.13      florian   410:                case 'o':
                    411:                        opts.preserve_uids = 1;
                    412:                        break;
1.1       benno     413:                case 'p':
                    414:                        opts.preserve_perms = 1;
                    415:                        break;
                    416:                case 'r':
                    417:                        opts.recursive = 1;
                    418:                        break;
                    419:                case 't':
                    420:                        opts.preserve_times = 1;
                    421:                        break;
                    422:                case 'v':
1.45      benno     423:                        verbose++;
1.1       benno     424:                        break;
1.67      claudio   425:                case 'V':
                    426:                        fprintf(stderr, "openrsync: protocol version %u\n",
                    427:                            RSYNC_PROTOCOL);
                    428:                        exit(0);
1.44      bket      429:                case 'x':
                    430:                        opts.one_file_system++;
                    431:                        break;
1.36      deraadt   432:                case 'z':
                    433:                        fprintf(stderr, "%s: -z not supported yet\n", getprogname());
                    434:                        break;
1.1       benno     435:                case 0:
                    436:                        /* Non-NULL flag values (e.g., --sender). */
                    437:                        break;
1.56      claudio   438:                case OP_ADDRESS:
                    439:                        opts.address = optarg;
1.1       benno     440:                        break;
1.64      job       441:                case OP_CONTIMEOUT:
                    442:                        poll_contimeout = strtonum(optarg, 0, 60*60, &errstr);
                    443:                        if (errstr != NULL)
                    444:                                errx(ERR_SYNTAX, "timeout is %s: %s",
                    445:                                    errstr, optarg);
                    446:                        break;
1.56      claudio   447:                case OP_PORT:
1.26      deraadt   448:                        opts.port = optarg;
                    449:                        break;
1.56      claudio   450:                case OP_RSYNCPATH:
                    451:                        opts.rsync_path = optarg;
1.48      claudio   452:                        break;
1.56      claudio   453:                case OP_TIMEOUT:
1.50      claudio   454:                        poll_timeout = strtonum(optarg, 0, 60*60, &errstr);
                    455:                        if (errstr != NULL)
1.54      claudio   456:                                errx(ERR_SYNTAX, "timeout is %s: %s",
                    457:                                    errstr, optarg);
1.57      claudio   458:                        break;
                    459:                case OP_EXCLUDE:
                    460:                        if (parse_rule(optarg, RULE_EXCLUDE) == -1)
                    461:                                errx(ERR_SYNTAX, "syntax error in exclude: %s",
                    462:                                    optarg);
                    463:                        break;
                    464:                case OP_INCLUDE:
                    465:                        if (parse_rule(optarg, RULE_INCLUDE) == -1)
                    466:                                errx(ERR_SYNTAX, "syntax error in include: %s",
                    467:                                    optarg);
                    468:                        break;
                    469:                case OP_EXCLUDE_FROM:
1.59      claudio   470:                        parse_file(optarg, RULE_EXCLUDE);
1.57      claudio   471:                        break;
                    472:                case OP_INCLUDE_FROM:
1.59      claudio   473:                        parse_file(optarg, RULE_INCLUDE);
1.50      claudio   474:                        break;
1.60      claudio   475:                case OP_COMP_DEST:
                    476:                        if (opts.alt_base_mode !=0 &&
                    477:                            opts.alt_base_mode != BASE_MODE_COMPARE) {
                    478:                                errx(1, "option --%s conflicts with %s",
                    479:                                    lopts[lidx].name,
                    480:                                    alt_base_mode(opts.alt_base_mode));
                    481:                        }
                    482:                        opts.alt_base_mode = BASE_MODE_COMPARE;
                    483: #if 0
                    484:                        goto basedir;
                    485:                case OP_COPY_DEST:
                    486:                        if (opts.alt_base_mode !=0 &&
                    487:                            opts.alt_base_mode != BASE_MODE_COPY) {
                    488:                                errx(1, "option --%s conflicts with %s",
                    489:                                    lopts[lidx].name,
                    490:                                    alt_base_mode(opts.alt_base_mode));
                    491:                        }
                    492:                        opts.alt_base_mode = BASE_MODE_COPY;
                    493:                        goto basedir;
                    494:                case OP_LINK_DEST:
                    495:                        if (opts.alt_base_mode !=0 &&
                    496:                            opts.alt_base_mode != BASE_MODE_LINK) {
                    497:                                errx(1, "option --%s conflicts with %s",
                    498:                                    lopts[lidx].name,
                    499:                                    alt_base_mode(opts.alt_base_mode));
                    500:                        }
                    501:                        opts.alt_base_mode = BASE_MODE_LINK;
                    502:
                    503: basedir:
                    504: #endif
                    505:                        if (basedir_cnt >= MAX_BASEDIR)
                    506:                                errx(1, "too many --%s directories specified",
                    507:                                    lopts[lidx].name);
                    508:                        opts.basedir[basedir_cnt++] = optarg;
1.61      claudio   509:                        break;
                    510:                case OP_MAX_SIZE:
1.62      claudio   511:                        if (scan_scaled(optarg, &opts.max_size) == -1)
                    512:                                err(1, "bad max-size");
                    513:                        break;
1.61      claudio   514:                case OP_MIN_SIZE:
1.62      claudio   515:                        if (scan_scaled(optarg, &opts.min_size) == -1)
                    516:                                err(1, "bad min-size");
1.60      claudio   517:                        break;
1.21      deraadt   518:                case 'h':
1.1       benno     519:                default:
                    520:                        goto usage;
                    521:                }
                    522:        }
                    523:
                    524:        argc -= optind;
                    525:        argv += optind;
                    526:
                    527:        /* FIXME: reference implementation rsync accepts this. */
                    528:
                    529:        if (argc < 2)
                    530:                goto usage;
                    531:
1.26      deraadt   532:        if (opts.port == NULL)
1.29      benno     533:                opts.port = "rsync";
1.26      deraadt   534:
1.64      job       535:        /* by default and for --contimeout=0 disable poll_contimeout */
                    536:        if (poll_contimeout == 0)
                    537:                poll_contimeout = -1;
                    538:        else
                    539:                poll_contimeout *= 1000;
                    540:
1.51      claudio   541:        /* by default and for --timeout=0 disable poll_timeout */
                    542:        if (poll_timeout == 0)
1.64      job       543:                poll_timeout = -1;
                    544:        else
1.51      claudio   545:                poll_timeout *= 1000;
                    546:
1.1       benno     547:        /*
                    548:         * This is what happens when we're started with the "hidden"
                    549:         * --server option, which is invoked for the rsync on the remote
                    550:         * host by the parent.
                    551:         */
                    552:
1.32      deraadt   553:        if (opts.server)
                    554:                exit(rsync_server(&opts, (size_t)argc, argv));
1.50      claudio   555:
1.1       benno     556:        /*
                    557:         * Now we know that we're the client on the local machine
                    558:         * invoking rsync(1).
                    559:         * At this point, we need to start the client and server
                    560:         * initiation logic.
                    561:         * The client is what we continue running on this host; the
                    562:         * server is what we'll use to connect to the remote and
                    563:         * invoke rsync with the --server option.
                    564:         */
                    565:
1.26      deraadt   566:        fargs = fargs_parse(argc, argv, &opts);
1.6       deraadt   567:        assert(fargs != NULL);
1.1       benno     568:
                    569:        /*
                    570:         * If we're contacting an rsync:// daemon, then we don't need to
                    571:         * fork, because we won't start a server ourselves.
1.41      naddy     572:         * Route directly into the socket code, unless a remote shell
                    573:         * has explicitly been specified.
1.1       benno     574:         */
                    575:
1.41      naddy     576:        if (fargs->remote && opts.ssh_prog == NULL) {
1.6       deraadt   577:                assert(fargs->mode == FARGS_RECEIVER);
1.47      naddy     578:                if ((rc = rsync_connect(&opts, &sd, fargs)) == 0) {
1.41      naddy     579:                        rc = rsync_socket(&opts, sd, fargs);
1.47      naddy     580:                        close(sd);
                    581:                }
1.41      naddy     582:                exit(rc);
1.1       benno     583:        }
                    584:
                    585:        /* Drop the dns/inet possibility. */
                    586:
1.19      florian   587:        if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw proc exec unveil",
1.6       deraadt   588:            NULL) == -1)
1.54      claudio   589:                err(ERR_IPC, "pledge");
1.1       benno     590:
                    591:        /* Create a bidirectional socket and start our child. */
                    592:
1.6       deraadt   593:        if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds) == -1)
1.54      claudio   594:                err(ERR_IPC, "socketpair");
1.1       benno     595:
1.32      deraadt   596:        switch ((child = fork())) {
                    597:        case -1:
1.54      claudio   598:                err(ERR_IPC, "fork");
1.32      deraadt   599:        case 0:
1.1       benno     600:                close(fds[0]);
1.32      deraadt   601:                if (pledge("stdio exec", NULL) == -1)
1.54      claudio   602:                        err(ERR_IPC, "pledge");
1.32      deraadt   603:
                    604:                memset(&sess, 0, sizeof(struct sess));
                    605:                sess.opts = &opts;
1.1       benno     606:
1.54      claudio   607:                args = fargs_cmdline(&sess, fargs, NULL);
1.1       benno     608:
1.32      deraadt   609:                for (i = 0; args[i] != NULL; i++)
1.45      benno     610:                        LOG2("exec[%d] = %s", i, args[i]);
1.1       benno     611:
1.32      deraadt   612:                /* Make sure the child's stdin is from the sender. */
1.54      claudio   613:                if (dup2(fds[1], STDIN_FILENO) == -1)
                    614:                        err(ERR_IPC, "dup2");
                    615:                if (dup2(fds[1], STDOUT_FILENO) == -1)
                    616:                        err(ERR_IPC, "dup2");
1.32      deraadt   617:                execvp(args[0], args);
1.54      claudio   618:                _exit(ERR_IPC);
1.1       benno     619:                /* NOTREACHED */
1.32      deraadt   620:        default:
                    621:                close(fds[1]);
1.41      naddy     622:                if (!fargs->remote)
                    623:                        rc = rsync_client(&opts, fds[0], fargs);
                    624:                else
                    625:                        rc = rsync_socket(&opts, fds[0], fargs);
1.32      deraadt   626:                break;
1.1       benno     627:        }
                    628:
1.47      naddy     629:        close(fds[0]);
1.1       benno     630:
1.6       deraadt   631:        if (waitpid(child, &st, 0) == -1)
1.54      claudio   632:                err(ERR_WAITPID, "waitpid");
1.34      deraadt   633:
                    634:        /*
                    635:         * If we don't already have an error (rc == 0), then inherit the
                    636:         * error code of rsync_server() if it has exited.
                    637:         * If it hasn't exited, it overrides our return value.
                    638:         */
                    639:
1.54      claudio   640:        if (rc == 0) {
                    641:                if (WIFEXITED(st))
                    642:                        rc = WEXITSTATUS(st);
                    643:                else if (WIFSIGNALED(st))
                    644:                        rc = ERR_TERMIMATED;
                    645:                else
                    646:                        rc = ERR_WAITPID;
                    647:        }
1.34      deraadt   648:
1.32      deraadt   649:        exit(rc);
1.1       benno     650: usage:
1.42      schwarze  651:        fprintf(stderr, "usage: %s"
1.71    ! claudio   652:            " [-aDgIJlnOoprtVvx] [-e program] [--address=sourceaddr]\n"
1.65      tb        653:            "\t[--contimeout=seconds] [--compare-dest=dir] [--del] [--exclude]\n"
1.64      job       654:            "\t[--exclude-from=file] [--include] [--include-from=file]\n"
                    655:            "\t[--no-motd] [--numeric-ids] [--port=portnumber]\n"
1.68      claudio   656:            "\t[--rsync-path=program] [--size-only] [--timeout=seconds]\n"
1.64      job       657:            "\tsource ... directory\n",
1.32      deraadt   658:            getprogname());
1.54      claudio   659:        exit(ERR_SYNTAX);
1.1       benno     660: }