Annotation of embedaddon/rsync/main.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * The startup routines, including main(), for rsync.
        !             3:  *
        !             4:  * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
        !             5:  * Copyright (C) 1996 Paul Mackerras
        !             6:  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
        !             7:  * Copyright (C) 2003-2009 Wayne Davison
        !             8:  *
        !             9:  * This program is free software; you can redistribute it and/or modify
        !            10:  * it under the terms of the GNU General Public License as published by
        !            11:  * the Free Software Foundation; either version 3 of the License, or
        !            12:  * (at your option) any later version.
        !            13:  *
        !            14:  * This program is distributed in the hope that it will be useful,
        !            15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            17:  * GNU General Public License for more details.
        !            18:  *
        !            19:  * You should have received a copy of the GNU General Public License along
        !            20:  * with this program; if not, visit the http://fsf.org website.
        !            21:  */
        !            22: 
        !            23: #include "rsync.h"
        !            24: #include "ifuncs.h"
        !            25: #include "io.h"
        !            26: #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
        !            27: #include <locale.h>
        !            28: #endif
        !            29: 
        !            30: extern int verbose;
        !            31: extern int dry_run;
        !            32: extern int list_only;
        !            33: extern int am_root;
        !            34: extern int am_server;
        !            35: extern int am_sender;
        !            36: extern int am_daemon;
        !            37: extern int inc_recurse;
        !            38: extern int blocking_io;
        !            39: extern int remove_source_files;
        !            40: extern int need_messages_from_generator;
        !            41: extern int kluge_around_eof;
        !            42: extern int do_stats;
        !            43: extern int got_xfer_error;
        !            44: extern int module_id;
        !            45: extern int copy_links;
        !            46: extern int copy_dirlinks;
        !            47: extern int copy_unsafe_links;
        !            48: extern int keep_dirlinks;
        !            49: extern int preserve_hard_links;
        !            50: extern int protocol_version;
        !            51: extern int file_total;
        !            52: extern int recurse;
        !            53: extern int xfer_dirs;
        !            54: extern int protect_args;
        !            55: extern int relative_paths;
        !            56: extern int sanitize_paths;
        !            57: extern int curr_dir_depth;
        !            58: extern int curr_dir_len;
        !            59: extern int module_id;
        !            60: extern int rsync_port;
        !            61: extern int whole_file;
        !            62: extern int read_batch;
        !            63: extern int write_batch;
        !            64: extern int batch_fd;
        !            65: extern int filesfrom_fd;
        !            66: extern int connect_timeout;
        !            67: extern dev_t filesystem_dev;
        !            68: extern pid_t cleanup_child_pid;
        !            69: extern unsigned int module_dirlen;
        !            70: extern struct stats stats;
        !            71: extern char *filesfrom_host;
        !            72: extern char *partial_dir;
        !            73: extern char *dest_option;
        !            74: extern char *basis_dir[MAX_BASIS_DIRS+1];
        !            75: extern char *rsync_path;
        !            76: extern char *shell_cmd;
        !            77: extern char *batch_name;
        !            78: extern char *password_file;
        !            79: extern char curr_dir[MAXPATHLEN];
        !            80: extern struct file_list *first_flist;
        !            81: extern struct filter_list_struct daemon_filter_list;
        !            82: 
        !            83: uid_t our_uid;
        !            84: int am_receiver = 0;  /* Only set to 1 after the receiver/generator fork. */
        !            85: int am_generator = 0; /* Only set to 1 after the receiver/generator fork. */
        !            86: int local_server = 0;
        !            87: int daemon_over_rsh = 0;
        !            88: mode_t orig_umask = 0;
        !            89: int batch_gen_fd = -1;
        !            90: 
        !            91: /* There's probably never more than at most 2 outstanding child processes,
        !            92:  * but set it higher, just in case. */
        !            93: #define MAXCHILDPROCS 7
        !            94: 
        !            95: #ifdef HAVE_SIGACTION
        !            96: # ifdef HAVE_SIGPROCMASK
        !            97: #  define SIGACTMASK(n,h) SIGACTION(n,h), sigaddset(&sigmask,(n))
        !            98: # else
        !            99: #  define SIGACTMASK(n,h) SIGACTION(n,h)
        !           100: # endif
        !           101: static struct sigaction sigact;
        !           102: #endif
        !           103: 
        !           104: struct pid_status {
        !           105:        pid_t pid;
        !           106:        int status;
        !           107: } pid_stat_table[MAXCHILDPROCS];
        !           108: 
        !           109: static time_t starttime, endtime;
        !           110: static int64 total_read, total_written;
        !           111: 
        !           112: static void show_malloc_stats(void);
        !           113: 
        !           114: /* Works like waitpid(), but if we already harvested the child pid in our
        !           115:  * remember_children(), we succeed instead of returning an error. */
        !           116: pid_t wait_process(pid_t pid, int *status_ptr, int flags)
        !           117: {
        !           118:        pid_t waited_pid;
        !           119:        
        !           120:        do {
        !           121:                waited_pid = waitpid(pid, status_ptr, flags);
        !           122:        } while (waited_pid == -1 && errno == EINTR);
        !           123: 
        !           124:        if (waited_pid == -1 && errno == ECHILD) {
        !           125:                /* Status of requested child no longer available:  check to
        !           126:                 * see if it was processed by remember_children(). */
        !           127:                int cnt;
        !           128:                for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
        !           129:                        if (pid == pid_stat_table[cnt].pid) {
        !           130:                                *status_ptr = pid_stat_table[cnt].status;
        !           131:                                pid_stat_table[cnt].pid = 0;
        !           132:                                return pid;
        !           133:                        }
        !           134:                }
        !           135:        }
        !           136: 
        !           137:        return waited_pid;
        !           138: }
        !           139: 
        !           140: /* Wait for a process to exit, calling io_flush while waiting. */
        !           141: static void wait_process_with_flush(pid_t pid, int *exit_code_ptr)
        !           142: {
        !           143:        pid_t waited_pid;
        !           144:        int status;
        !           145: 
        !           146:        while ((waited_pid = wait_process(pid, &status, WNOHANG)) == 0) {
        !           147:                msleep(20);
        !           148:                io_flush(FULL_FLUSH);
        !           149:        }
        !           150: 
        !           151:        /* TODO: If the child exited on a signal, then log an
        !           152:         * appropriate error message.  Perhaps we should also accept a
        !           153:         * message describing the purpose of the child.  Also indicate
        !           154:         * this to the caller so that they know something went wrong. */
        !           155:        if (waited_pid < 0) {
        !           156:                rsyserr(FERROR, errno, "waitpid");
        !           157:                *exit_code_ptr = RERR_WAITCHILD;
        !           158:        } else if (!WIFEXITED(status)) {
        !           159: #ifdef WCOREDUMP
        !           160:                if (WCOREDUMP(status))
        !           161:                        *exit_code_ptr = RERR_CRASHED;
        !           162:                else
        !           163: #endif
        !           164:                if (WIFSIGNALED(status))
        !           165:                        *exit_code_ptr = RERR_TERMINATED;
        !           166:                else
        !           167:                        *exit_code_ptr = RERR_WAITCHILD;
        !           168:        } else
        !           169:                *exit_code_ptr = WEXITSTATUS(status);
        !           170: }
        !           171: 
        !           172: /* This function gets called from all 3 processes.  We want the client side
        !           173:  * to actually output the text, but the sender is the only process that has
        !           174:  * all the stats we need.  So, if we're a client sender, we do the report.
        !           175:  * If we're a server sender, we write the stats on the supplied fd.  If
        !           176:  * we're the client receiver we read the stats from the supplied fd and do
        !           177:  * the report.  All processes might also generate a set of debug stats, if
        !           178:  * the verbose level is high enough (this is the only thing that the
        !           179:  * generator process and the server receiver ever do here). */
        !           180: static void handle_stats(int f)
        !           181: {
        !           182:        endtime = time(NULL);
        !           183: 
        !           184:        /* Cache two stats because the read/write code can change it. */
        !           185:        total_read = stats.total_read;
        !           186:        total_written = stats.total_written;
        !           187: 
        !           188:        if (do_stats && verbose > 1) {
        !           189:                /* These come out from every process */
        !           190:                show_malloc_stats();
        !           191:                show_flist_stats();
        !           192:        }
        !           193: 
        !           194:        if (am_generator)
        !           195:                return;
        !           196: 
        !           197:        if (am_daemon) {
        !           198:                if (f == -1 || !am_sender)
        !           199:                        return;
        !           200:        }
        !           201: 
        !           202:        if (am_server) {
        !           203:                if (am_sender) {
        !           204:                        write_varlong30(f, total_read, 3);
        !           205:                        write_varlong30(f, total_written, 3);
        !           206:                        write_varlong30(f, stats.total_size, 3);
        !           207:                        if (protocol_version >= 29) {
        !           208:                                write_varlong30(f, stats.flist_buildtime, 3);
        !           209:                                write_varlong30(f, stats.flist_xfertime, 3);
        !           210:                        }
        !           211:                }
        !           212:                return;
        !           213:        }
        !           214: 
        !           215:        /* this is the client */
        !           216: 
        !           217:        if (f < 0 && !am_sender) /* e.g. when we got an empty file list. */
        !           218:                ;
        !           219:        else if (!am_sender) {
        !           220:                /* Read the first two in opposite order because the meaning of
        !           221:                 * read/write swaps when switching from sender to receiver. */
        !           222:                total_written = read_varlong30(f, 3);
        !           223:                total_read = read_varlong30(f, 3);
        !           224:                stats.total_size = read_varlong30(f, 3);
        !           225:                if (protocol_version >= 29) {
        !           226:                        stats.flist_buildtime = read_varlong30(f, 3);
        !           227:                        stats.flist_xfertime = read_varlong30(f, 3);
        !           228:                }
        !           229:        } else if (write_batch) {
        !           230:                /* The --read-batch process is going to be a client
        !           231:                 * receiver, so we need to give it the stats. */
        !           232:                write_varlong30(batch_fd, total_read, 3);
        !           233:                write_varlong30(batch_fd, total_written, 3);
        !           234:                write_varlong30(batch_fd, stats.total_size, 3);
        !           235:                if (protocol_version >= 29) {
        !           236:                        write_varlong30(batch_fd, stats.flist_buildtime, 3);
        !           237:                        write_varlong30(batch_fd, stats.flist_xfertime, 3);
        !           238:                }
        !           239:        }
        !           240: }
        !           241: 
        !           242: static void output_summary(void)
        !           243: {
        !           244:        if (do_stats) {
        !           245:                rprintf(FCLIENT, "\n");
        !           246:                rprintf(FINFO,"Number of files: %d\n", stats.num_files);
        !           247:                rprintf(FINFO,"Number of files transferred: %d\n",
        !           248:                        stats.num_transferred_files);
        !           249:                rprintf(FINFO,"Total file size: %s bytes\n",
        !           250:                        human_num(stats.total_size));
        !           251:                rprintf(FINFO,"Total transferred file size: %s bytes\n",
        !           252:                        human_num(stats.total_transferred_size));
        !           253:                rprintf(FINFO,"Literal data: %s bytes\n",
        !           254:                        human_num(stats.literal_data));
        !           255:                rprintf(FINFO,"Matched data: %s bytes\n",
        !           256:                        human_num(stats.matched_data));
        !           257:                rprintf(FINFO,"File list size: %s\n",
        !           258:                        human_num(stats.flist_size));
        !           259:                if (stats.flist_buildtime) {
        !           260:                        rprintf(FINFO,
        !           261:                                "File list generation time: %.3f seconds\n",
        !           262:                                (double)stats.flist_buildtime / 1000);
        !           263:                        rprintf(FINFO,
        !           264:                                "File list transfer time: %.3f seconds\n",
        !           265:                                (double)stats.flist_xfertime / 1000);
        !           266:                }
        !           267:                rprintf(FINFO,"Total bytes sent: %s\n",
        !           268:                        human_num(total_written));
        !           269:                rprintf(FINFO,"Total bytes received: %s\n",
        !           270:                        human_num(total_read));
        !           271:        }
        !           272: 
        !           273:        if (verbose || do_stats) {
        !           274:                rprintf(FCLIENT, "\n");
        !           275:                rprintf(FINFO,
        !           276:                        "sent %s bytes  received %s bytes  %s bytes/sec\n",
        !           277:                        human_num(total_written), human_num(total_read),
        !           278:                        human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2));
        !           279:                rprintf(FINFO, "total size is %s  speedup is %.2f%s\n",
        !           280:                        human_num(stats.total_size),
        !           281:                        (double)stats.total_size / (total_written+total_read),
        !           282:                        write_batch < 0 ? " (BATCH ONLY)" : dry_run ? " (DRY RUN)" : "");
        !           283:        }
        !           284: 
        !           285:        fflush(stdout);
        !           286:        fflush(stderr);
        !           287: }
        !           288: 
        !           289: 
        !           290: /**
        !           291:  * If our C library can get malloc statistics, then show them to FINFO
        !           292:  **/
        !           293: static void show_malloc_stats(void)
        !           294: {
        !           295: #ifdef HAVE_MALLINFO
        !           296:        struct mallinfo mi;
        !           297: 
        !           298:        mi = mallinfo();
        !           299: 
        !           300:        rprintf(FCLIENT, "\n");
        !           301:        rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
        !           302:                getpid(), am_server ? "server " : "",
        !           303:                am_daemon ? "daemon " : "", who_am_i());
        !           304:        rprintf(FINFO, "  arena:     %10ld   (bytes from sbrk)\n",
        !           305:                (long)mi.arena);
        !           306:        rprintf(FINFO, "  ordblks:   %10ld   (chunks not in use)\n",
        !           307:                (long)mi.ordblks);
        !           308:        rprintf(FINFO, "  smblks:    %10ld\n",
        !           309:                (long)mi.smblks);
        !           310:        rprintf(FINFO, "  hblks:     %10ld   (chunks from mmap)\n",
        !           311:                (long)mi.hblks);
        !           312:        rprintf(FINFO, "  hblkhd:    %10ld   (bytes from mmap)\n",
        !           313:                (long)mi.hblkhd);
        !           314:        rprintf(FINFO, "  allmem:    %10ld   (bytes from sbrk + mmap)\n",
        !           315:                (long)mi.arena + mi.hblkhd);
        !           316:        rprintf(FINFO, "  usmblks:   %10ld\n",
        !           317:                (long)mi.usmblks);
        !           318:        rprintf(FINFO, "  fsmblks:   %10ld\n",
        !           319:                (long)mi.fsmblks);
        !           320:        rprintf(FINFO, "  uordblks:  %10ld   (bytes used)\n",
        !           321:                (long)mi.uordblks);
        !           322:        rprintf(FINFO, "  fordblks:  %10ld   (bytes free)\n",
        !           323:                (long)mi.fordblks);
        !           324:        rprintf(FINFO, "  keepcost:  %10ld   (bytes in releasable chunk)\n",
        !           325:                (long)mi.keepcost);
        !           326: #endif /* HAVE_MALLINFO */
        !           327: }
        !           328: 
        !           329: 
        !           330: /* Start the remote shell.   cmd may be NULL to use the default. */
        !           331: static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, int remote_argc,
        !           332:                    int *f_in_p, int *f_out_p)
        !           333: {
        !           334:        int i, argc = 0;
        !           335:        char *args[MAX_ARGS];
        !           336:        pid_t pid;
        !           337:        int dash_l_set = 0;
        !           338: 
        !           339:        if (!read_batch && !local_server) {
        !           340:                char *t, *f, in_quote = '\0';
        !           341:                char *rsh_env = getenv(RSYNC_RSH_ENV);
        !           342:                if (!cmd)
        !           343:                        cmd = rsh_env;
        !           344:                if (!cmd)
        !           345:                        cmd = RSYNC_RSH;
        !           346:                cmd = strdup(cmd); /* MEMORY LEAK */
        !           347:                if (!cmd)
        !           348:                        goto oom;
        !           349: 
        !           350:                for (t = f = cmd; *f; f++) {
        !           351:                        if (*f == ' ')
        !           352:                                continue;
        !           353:                        /* Comparison leaves rooms for server_options(). */
        !           354:                        if (argc >= MAX_ARGS - MAX_SERVER_ARGS)
        !           355:                                goto arg_overflow;
        !           356:                        args[argc++] = t;
        !           357:                        while (*f != ' ' || in_quote) {
        !           358:                                if (!*f) {
        !           359:                                        if (in_quote) {
        !           360:                                                rprintf(FERROR,
        !           361:                                                    "Missing trailing-%c in remote-shell command.\n",
        !           362:                                                    in_quote);
        !           363:                                                exit_cleanup(RERR_SYNTAX);
        !           364:                                        }
        !           365:                                        f--;
        !           366:                                        break;
        !           367:                                }
        !           368:                                if (*f == '\'' || *f == '"') {
        !           369:                                        if (!in_quote) {
        !           370:                                                in_quote = *f++;
        !           371:                                                continue;
        !           372:                                        }
        !           373:                                        if (*f == in_quote && *++f != in_quote) {
        !           374:                                                in_quote = '\0';
        !           375:                                                continue;
        !           376:                                        }
        !           377:                                }
        !           378:                                *t++ = *f++;
        !           379:                        }
        !           380:                        *t++ = '\0';
        !           381:                }
        !           382: 
        !           383:                /* check to see if we've already been given '-l user' in
        !           384:                 * the remote-shell command */
        !           385:                for (i = 0; i < argc-1; i++) {
        !           386:                        if (!strcmp(args[i], "-l") && args[i+1][0] != '-')
        !           387:                                dash_l_set = 1;
        !           388:                }
        !           389: 
        !           390: #ifdef HAVE_REMSH
        !           391:                /* remsh (on HPUX) takes the arguments the other way around */
        !           392:                args[argc++] = machine;
        !           393:                if (user && !(daemon_over_rsh && dash_l_set)) {
        !           394:                        args[argc++] = "-l";
        !           395:                        args[argc++] = user;
        !           396:                }
        !           397: #else
        !           398:                if (user && !(daemon_over_rsh && dash_l_set)) {
        !           399:                        args[argc++] = "-l";
        !           400:                        args[argc++] = user;
        !           401:                }
        !           402:                args[argc++] = machine;
        !           403: #endif
        !           404: 
        !           405:                args[argc++] = rsync_path;
        !           406: 
        !           407:                if (blocking_io < 0) {
        !           408:                        char *cp;
        !           409:                        if ((cp = strrchr(cmd, '/')) != NULL)
        !           410:                                cp++;
        !           411:                        else
        !           412:                                cp = cmd;
        !           413:                        if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)
        !           414:                                blocking_io = 1;
        !           415:                }
        !           416: 
        !           417:                server_options(args,&argc);
        !           418: 
        !           419:                if (argc >= MAX_ARGS - 2)
        !           420:                        goto arg_overflow;
        !           421:        }
        !           422: 
        !           423:        args[argc++] = ".";
        !           424: 
        !           425:        if (!daemon_over_rsh) {
        !           426:                while (remote_argc > 0) {
        !           427:                        if (argc >= MAX_ARGS - 1) {
        !           428:                          arg_overflow:
        !           429:                                rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
        !           430:                                exit_cleanup(RERR_SYNTAX);
        !           431:                        }
        !           432:                        if (**remote_argv == '-') {
        !           433:                                if (asprintf(args + argc++, "./%s", *remote_argv++) < 0)
        !           434:                                        out_of_memory("do_cmd");
        !           435:                        } else
        !           436:                                args[argc++] = *remote_argv++;
        !           437:                        remote_argc--;
        !           438:                }
        !           439:        }
        !           440: 
        !           441:        args[argc] = NULL;
        !           442: 
        !           443:        if (verbose > 3) {
        !           444:                for (i = 0; i < argc; i++)
        !           445:                        rprintf(FCLIENT, "cmd[%d]=%s ", i, args[i]);
        !           446:                rprintf(FCLIENT, "\n");
        !           447:        }
        !           448: 
        !           449:        if (read_batch) {
        !           450:                int from_gen_pipe[2];
        !           451:                set_allow_inc_recurse();
        !           452:                if (fd_pair(from_gen_pipe) < 0) {
        !           453:                        rsyserr(FERROR, errno, "pipe");
        !           454:                        exit_cleanup(RERR_IPC);
        !           455:                }
        !           456:                batch_gen_fd = from_gen_pipe[0];
        !           457:                *f_out_p = from_gen_pipe[1];
        !           458:                *f_in_p = batch_fd;
        !           459:                pid = (pid_t)-1; /* no child pid */
        !           460: #ifdef ICONV_CONST
        !           461:                setup_iconv();
        !           462: #endif
        !           463:        } else if (local_server) {
        !           464:                /* If the user didn't request --[no-]whole-file, force
        !           465:                 * it on, but only if we're not batch processing. */
        !           466:                if (whole_file < 0 && !write_batch)
        !           467:                        whole_file = 1;
        !           468:                set_allow_inc_recurse();
        !           469:                pid = local_child(argc, args, f_in_p, f_out_p, child_main);
        !           470: #ifdef ICONV_CONST
        !           471:                setup_iconv();
        !           472: #endif
        !           473:        } else {
        !           474:                pid = piped_child(args, f_in_p, f_out_p);
        !           475: #ifdef ICONV_CONST
        !           476:                setup_iconv();
        !           477: #endif
        !           478:                if (protect_args && !daemon_over_rsh)
        !           479:                        send_protected_args(*f_out_p, args);
        !           480:        }
        !           481: 
        !           482:        return pid;
        !           483: 
        !           484:   oom:
        !           485:        out_of_memory("do_cmd");
        !           486:        return 0; /* not reached */
        !           487: }
        !           488: 
        !           489: /* The receiving side operates in one of two modes:
        !           490:  *
        !           491:  * 1. it receives any number of files into a destination directory,
        !           492:  * placing them according to their names in the file-list.
        !           493:  *
        !           494:  * 2. it receives a single file and saves it using the name in the
        !           495:  * destination path instead of its file-list name.  This requires a
        !           496:  * "local name" for writing out the destination file.
        !           497:  *
        !           498:  * So, our task is to figure out what mode/local-name we need.
        !           499:  * For mode 1, we change into the destination directory and return NULL.
        !           500:  * For mode 2, we change into the directory containing the destination
        !           501:  * file (if we aren't already there) and return the local-name. */
        !           502: static char *get_local_name(struct file_list *flist, char *dest_path)
        !           503: {
        !           504:        STRUCT_STAT st;
        !           505:        int statret;
        !           506:        char *cp;
        !           507: 
        !           508:        if (verbose > 2) {
        !           509:                rprintf(FINFO, "get_local_name count=%d %s\n",
        !           510:                        file_total, NS(dest_path));
        !           511:        }
        !           512: 
        !           513:        if (!dest_path || list_only)
        !           514:                return NULL;
        !           515: 
        !           516:        /* Treat an empty string as a copy into the current directory. */
        !           517:        if (!*dest_path)
        !           518:            dest_path = ".";
        !           519: 
        !           520:        if (daemon_filter_list.head) {
        !           521:                char *slash = strrchr(dest_path, '/');
        !           522:                if (slash && (slash[1] == '\0' || (slash[1] == '.' && slash[2] == '\0')))
        !           523:                        *slash = '\0';
        !           524:                else
        !           525:                        slash = NULL;
        !           526:                if ((*dest_path != '.' || dest_path[1] != '\0')
        !           527:                 && (check_filter(&daemon_filter_list, FLOG, dest_path, 0) < 0
        !           528:                  || check_filter(&daemon_filter_list, FLOG, dest_path, 1) < 0)) {
        !           529:                        rprintf(FERROR, "ERROR: daemon has excluded destination \"%s\"\n",
        !           530:                                dest_path);
        !           531:                        exit_cleanup(RERR_FILESELECT);
        !           532:                }
        !           533:                if (slash)
        !           534:                        *slash = '/';
        !           535:        }
        !           536: 
        !           537:        /* See what currently exists at the destination. */
        !           538:        if ((statret = do_stat(dest_path, &st)) == 0) {
        !           539:                /* If the destination is a dir, enter it and use mode 1. */
        !           540:                if (S_ISDIR(st.st_mode)) {
        !           541:                        if (!change_dir(dest_path, CD_NORMAL)) {
        !           542:                                rsyserr(FERROR, errno, "change_dir#1 %s failed",
        !           543:                                        full_fname(dest_path));
        !           544:                                exit_cleanup(RERR_FILESELECT);
        !           545:                        }
        !           546:                        filesystem_dev = st.st_dev; /* ensures --force works right w/-x */
        !           547:                        return NULL;
        !           548:                }
        !           549:                if (file_total > 1) {
        !           550:                        rprintf(FERROR,
        !           551:                                "ERROR: destination must be a directory when"
        !           552:                                " copying more than 1 file\n");
        !           553:                        exit_cleanup(RERR_FILESELECT);
        !           554:                }
        !           555:                if (file_total == 1 && S_ISDIR(flist->files[0]->mode)) {
        !           556:                        rprintf(FERROR,
        !           557:                                "ERROR: cannot overwrite non-directory"
        !           558:                                " with a directory\n");
        !           559:                        exit_cleanup(RERR_FILESELECT);
        !           560:                }
        !           561:        } else if (errno != ENOENT) {
        !           562:                /* If we don't know what's at the destination, fail. */
        !           563:                rsyserr(FERROR, errno, "ERROR: cannot stat destination %s",
        !           564:                        full_fname(dest_path));
        !           565:                exit_cleanup(RERR_FILESELECT);
        !           566:        }
        !           567: 
        !           568:        cp = strrchr(dest_path, '/');
        !           569: 
        !           570:        /* If we need a destination directory because the transfer is not
        !           571:         * of a single non-directory or the user has requested one via a
        !           572:         * destination path ending in a slash, create one and use mode 1. */
        !           573:        if (file_total > 1 || (cp && !cp[1])) {
        !           574:                /* Lop off the final slash (if any). */
        !           575:                if (cp && !cp[1])
        !           576:                        *cp = '\0';
        !           577: 
        !           578:                if (statret == 0) {
        !           579:                        rprintf(FERROR,
        !           580:                            "ERROR: destination path is not a directory\n");
        !           581:                        exit_cleanup(RERR_SYNTAX);
        !           582:                }
        !           583: 
        !           584:                if (mkdir_defmode(dest_path) != 0) {
        !           585:                        rsyserr(FERROR, errno, "mkdir %s failed",
        !           586:                                full_fname(dest_path));
        !           587:                        exit_cleanup(RERR_FILEIO);
        !           588:                }
        !           589: 
        !           590:                if (flist->high >= flist->low
        !           591:                 && strcmp(flist->files[flist->low]->basename, ".") == 0)
        !           592:                        flist->files[0]->flags |= FLAG_DIR_CREATED;
        !           593: 
        !           594:                if (verbose)
        !           595:                        rprintf(FINFO, "created directory %s\n", dest_path);
        !           596: 
        !           597:                if (dry_run) {
        !           598:                        /* Indicate that dest dir doesn't really exist. */
        !           599:                        dry_run++;
        !           600:                }
        !           601: 
        !           602:                if (!change_dir(dest_path, dry_run > 1 ? CD_SKIP_CHDIR : CD_NORMAL)) {
        !           603:                        rsyserr(FERROR, errno, "change_dir#2 %s failed",
        !           604:                                full_fname(dest_path));
        !           605:                        exit_cleanup(RERR_FILESELECT);
        !           606:                }
        !           607: 
        !           608:                return NULL;
        !           609:        }
        !           610: 
        !           611:        /* Otherwise, we are writing a single file, possibly on top of an
        !           612:         * existing non-directory.  Change to the item's parent directory
        !           613:         * (if it has a path component), return the basename of the
        !           614:         * destination file as the local name, and use mode 2. */
        !           615:        if (!cp)
        !           616:                return dest_path;
        !           617: 
        !           618:        if (cp == dest_path)
        !           619:                dest_path = "/";
        !           620: 
        !           621:        *cp = '\0';
        !           622:        if (!change_dir(dest_path, CD_NORMAL)) {
        !           623:                rsyserr(FERROR, errno, "change_dir#3 %s failed",
        !           624:                        full_fname(dest_path));
        !           625:                exit_cleanup(RERR_FILESELECT);
        !           626:        }
        !           627:        *cp = '/';
        !           628: 
        !           629:        return cp + 1;
        !           630: }
        !           631: 
        !           632: /* This function checks on our alternate-basis directories.  If we're in
        !           633:  * dry-run mode and the destination dir does not yet exist, we'll try to
        !           634:  * tweak any dest-relative paths to make them work for a dry-run (the
        !           635:  * destination dir must be in curr_dir[] when this function is called).
        !           636:  * We also warn about any arg that is non-existent or not a directory. */
        !           637: static void check_alt_basis_dirs(void)
        !           638: {
        !           639:        STRUCT_STAT st;
        !           640:        char **dir_p, *slash = strrchr(curr_dir, '/');
        !           641: 
        !           642:        for (dir_p = basis_dir; *dir_p; dir_p++) {
        !           643:                if (dry_run > 1 && **dir_p != '/') {
        !           644:                        int len = curr_dir_len + 1 + strlen(*dir_p) + 1;
        !           645:                        char *new = new_array(char, len);
        !           646:                        if (!new)
        !           647:                                out_of_memory("check_alt_basis_dirs");
        !           648:                        if (slash && strncmp(*dir_p, "../", 3) == 0) {
        !           649:                            /* We want to remove only one leading "../" prefix for
        !           650:                             * the directory we couldn't create in dry-run mode:
        !           651:                             * this ensures that any other ".." references get
        !           652:                             * evaluated the same as they would for a live copy. */
        !           653:                            *slash = '\0';
        !           654:                            pathjoin(new, len, curr_dir, *dir_p + 3);
        !           655:                            *slash = '/';
        !           656:                        } else
        !           657:                            pathjoin(new, len, curr_dir, *dir_p);
        !           658:                        *dir_p = new;
        !           659:                }
        !           660:                if (do_stat(*dir_p, &st) < 0) {
        !           661:                        rprintf(FWARNING, "%s arg does not exist: %s\n",
        !           662:                                dest_option, *dir_p);
        !           663:                } else if (!S_ISDIR(st.st_mode)) {
        !           664:                        rprintf(FWARNING, "%s arg is not a dir: %s\n",
        !           665:                                dest_option, *dir_p);
        !           666:                }
        !           667:        }
        !           668: }
        !           669: 
        !           670: /* This is only called by the sender. */
        !           671: static void read_final_goodbye(int f_in)
        !           672: {
        !           673:        int i, iflags, xlen;
        !           674:        uchar fnamecmp_type;
        !           675:        char xname[MAXPATHLEN];
        !           676: 
        !           677:        if (protocol_version < 29)
        !           678:                i = read_int(f_in);
        !           679:        else {
        !           680:                i = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
        !           681:                                       xname, &xlen);
        !           682:        }
        !           683: 
        !           684:        if (i != NDX_DONE) {
        !           685:                rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n",
        !           686:                        i, who_am_i());
        !           687:                exit_cleanup(RERR_PROTOCOL);
        !           688:        }
        !           689: }
        !           690: 
        !           691: static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
        !           692: {
        !           693:        struct file_list *flist;
        !           694:        char *dir = argv[0];
        !           695: 
        !           696:        if (verbose > 2) {
        !           697:                rprintf(FINFO, "server_sender starting pid=%ld\n",
        !           698:                        (long)getpid());
        !           699:        }
        !           700: 
        !           701:        if (am_daemon && lp_write_only(module_id)) {
        !           702:                rprintf(FERROR, "ERROR: module is write only\n");
        !           703:                exit_cleanup(RERR_SYNTAX);
        !           704:                return;
        !           705:        }
        !           706:        if (am_daemon && lp_read_only(module_id) && remove_source_files) {
        !           707:                rprintf(FERROR,
        !           708:                    "ERROR: --remove-%s-files cannot be used with a read-only module\n",
        !           709:                    remove_source_files == 1 ? "source" : "sent");
        !           710:                exit_cleanup(RERR_SYNTAX);
        !           711:                return;
        !           712:        }
        !           713: 
        !           714:        if (!relative_paths) {
        !           715:                if (!change_dir(dir, CD_NORMAL)) {
        !           716:                        rsyserr(FERROR, errno, "change_dir#3 %s failed",
        !           717:                                full_fname(dir));
        !           718:                        exit_cleanup(RERR_FILESELECT);
        !           719:                }
        !           720:        }
        !           721:        argc--;
        !           722:        argv++;
        !           723: 
        !           724:        if (argc == 0 && (recurse || xfer_dirs || list_only)) {
        !           725:                argc = 1;
        !           726:                argv--;
        !           727:                argv[0] = ".";
        !           728:        }
        !           729: 
        !           730:        flist = send_file_list(f_out,argc,argv);
        !           731:        if (!flist || flist->used == 0)
        !           732:                exit_cleanup(0);
        !           733: 
        !           734:        io_start_buffering_in(f_in);
        !           735: 
        !           736:        send_files(f_in, f_out);
        !           737:        io_flush(FULL_FLUSH);
        !           738:        handle_stats(f_out);
        !           739:        if (protocol_version >= 24)
        !           740:                read_final_goodbye(f_in);
        !           741:        io_flush(FULL_FLUSH);
        !           742:        exit_cleanup(0);
        !           743: }
        !           744: 
        !           745: 
        !           746: static int do_recv(int f_in, int f_out, char *local_name)
        !           747: {
        !           748:        int pid;
        !           749:        int exit_code = 0;
        !           750:        int error_pipe[2];
        !           751: 
        !           752:        /* The receiving side mustn't obey this, or an existing symlink that
        !           753:         * points to an identical file won't be replaced by the referent. */
        !           754:        copy_links = copy_dirlinks = copy_unsafe_links = 0;
        !           755: 
        !           756: #ifdef SUPPORT_HARD_LINKS
        !           757:        if (preserve_hard_links && !inc_recurse)
        !           758:                match_hard_links(first_flist);
        !           759: #endif
        !           760: 
        !           761:        if (fd_pair(error_pipe) < 0) {
        !           762:                rsyserr(FERROR, errno, "pipe failed in do_recv");
        !           763:                exit_cleanup(RERR_IPC);
        !           764:        }
        !           765: 
        !           766:        io_flush(NORMAL_FLUSH);
        !           767: 
        !           768:        if ((pid = do_fork()) == -1) {
        !           769:                rsyserr(FERROR, errno, "fork failed in do_recv");
        !           770:                exit_cleanup(RERR_IPC);
        !           771:        }
        !           772: 
        !           773:        if (pid == 0) {
        !           774:                am_receiver = 1;
        !           775: 
        !           776:                close(error_pipe[0]);
        !           777:                if (f_in != f_out)
        !           778:                        close(f_out);
        !           779: 
        !           780:                /* we can't let two processes write to the socket at one time */
        !           781:                io_end_multiplex_out();
        !           782: 
        !           783:                /* set place to send errors */
        !           784:                set_msg_fd_out(error_pipe[1]);
        !           785:                io_start_buffering_out(error_pipe[1]);
        !           786: 
        !           787:                recv_files(f_in, local_name);
        !           788:                io_flush(FULL_FLUSH);
        !           789:                handle_stats(f_in);
        !           790: 
        !           791:                send_msg(MSG_DONE, "", 1, 0);
        !           792:                write_varlong(error_pipe[1], stats.total_read, 3);
        !           793:                io_flush(FULL_FLUSH);
        !           794: 
        !           795:                /* Handle any keep-alive packets from the post-processing work
        !           796:                 * that the generator does. */
        !           797:                if (protocol_version >= 29) {
        !           798:                        int iflags, xlen;
        !           799:                        uchar fnamecmp_type;
        !           800:                        char xname[MAXPATHLEN];
        !           801: 
        !           802:                        kluge_around_eof = -1;
        !           803: 
        !           804:                        /* This should only get stopped via a USR2 signal. */
        !           805:                        read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
        !           806:                                           xname, &xlen);
        !           807: 
        !           808:                        rprintf(FERROR, "Invalid packet at end of run [%s]\n",
        !           809:                                who_am_i());
        !           810:                        exit_cleanup(RERR_PROTOCOL);
        !           811:                }
        !           812: 
        !           813:                /* Finally, we go to sleep until our parent kills us with a
        !           814:                 * USR2 signal.  We sleep for a short time, as on some OSes
        !           815:                 * a signal won't interrupt a sleep! */
        !           816:                while (1)
        !           817:                        msleep(20);
        !           818:        }
        !           819: 
        !           820:        am_generator = 1;
        !           821: 
        !           822:        io_end_multiplex_in();
        !           823:        if (write_batch && !am_server)
        !           824:                stop_write_batch();
        !           825: 
        !           826:        close(error_pipe[1]);
        !           827:        if (f_in != f_out)
        !           828:                close(f_in);
        !           829: 
        !           830:        io_start_buffering_out(f_out);
        !           831: 
        !           832:        set_msg_fd_in(error_pipe[0]);
        !           833:        io_start_buffering_in(error_pipe[0]);
        !           834: 
        !           835: #ifdef SUPPORT_HARD_LINKS
        !           836:        if (preserve_hard_links && inc_recurse) {
        !           837:                struct file_list *flist;
        !           838:                for (flist = first_flist; flist; flist = flist->next)
        !           839:                        match_hard_links(flist);
        !           840:        }
        !           841: #endif
        !           842: 
        !           843:        generate_files(f_out, local_name);
        !           844: 
        !           845:        handle_stats(-1);
        !           846:        io_flush(FULL_FLUSH);
        !           847:        if (protocol_version >= 24) {
        !           848:                /* send a final goodbye message */
        !           849:                write_ndx(f_out, NDX_DONE);
        !           850:        }
        !           851:        io_flush(FULL_FLUSH);
        !           852: 
        !           853:        set_msg_fd_in(-1);
        !           854:        kill(pid, SIGUSR2);
        !           855:        wait_process_with_flush(pid, &exit_code);
        !           856:        return exit_code;
        !           857: }
        !           858: 
        !           859: static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
        !           860: {
        !           861:        int exit_code;
        !           862:        struct file_list *flist;
        !           863:        char *local_name = NULL;
        !           864:        int save_verbose = verbose;
        !           865: 
        !           866:        if (filesfrom_fd >= 0) {
        !           867:                /* We can't mix messages with files-from data on the socket,
        !           868:                 * so temporarily turn off verbose messages. */
        !           869:                verbose = 0;
        !           870:        }
        !           871: 
        !           872:        if (verbose > 2) {
        !           873:                rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
        !           874:                        argc, (long)getpid());
        !           875:        }
        !           876: 
        !           877:        if (am_daemon && lp_read_only(module_id)) {
        !           878:                rprintf(FERROR,"ERROR: module is read only\n");
        !           879:                exit_cleanup(RERR_SYNTAX);
        !           880:                return;
        !           881:        }
        !           882: 
        !           883:        if (argc > 0) {
        !           884:                char *dir = argv[0];
        !           885:                argc--;
        !           886:                argv++;
        !           887:                if (!am_daemon && !change_dir(dir, CD_NORMAL)) {
        !           888:                        rsyserr(FERROR, errno, "change_dir#4 %s failed",
        !           889:                                full_fname(dir));
        !           890:                        exit_cleanup(RERR_FILESELECT);
        !           891:                }
        !           892:        }
        !           893: 
        !           894:        if (protocol_version >= 30)
        !           895:                io_start_multiplex_in();
        !           896:        else
        !           897:                io_start_buffering_in(f_in);
        !           898:        recv_filter_list(f_in);
        !           899: 
        !           900:        if (filesfrom_fd >= 0) {
        !           901:                /* We need to send the files-from names to the sender at the
        !           902:                 * same time that we receive the file-list from them, so we
        !           903:                 * need the IO routines to automatically write out the names
        !           904:                 * onto our f_out socket as we read the file-list.  This
        !           905:                 * avoids both deadlock and extra delays/buffers. */
        !           906:                io_set_filesfrom_fds(filesfrom_fd, f_out);
        !           907:                filesfrom_fd = -1;
        !           908:        }
        !           909: 
        !           910:        flist = recv_file_list(f_in);
        !           911:        if (!flist) {
        !           912:                rprintf(FERROR,"server_recv: recv_file_list error\n");
        !           913:                exit_cleanup(RERR_FILESELECT);
        !           914:        }
        !           915:        if (inc_recurse && file_total == 1)
        !           916:                recv_additional_file_list(f_in);
        !           917:        verbose = save_verbose;
        !           918: 
        !           919:        if (argc > 0)
        !           920:                local_name = get_local_name(flist,argv[0]);
        !           921: 
        !           922:        /* Now that we know what our destination directory turned out to be,
        !           923:         * we can sanitize the --link-/copy-/compare-dest args correctly. */
        !           924:        if (sanitize_paths) {
        !           925:                char **dir_p;
        !           926:                for (dir_p = basis_dir; *dir_p; dir_p++)
        !           927:                        *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT);
        !           928:                if (partial_dir)
        !           929:                        partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT);
        !           930:        }
        !           931:        check_alt_basis_dirs();
        !           932: 
        !           933:        if (daemon_filter_list.head) {
        !           934:                char **dir_p;
        !           935:                struct filter_list_struct *elp = &daemon_filter_list;
        !           936: 
        !           937:                for (dir_p = basis_dir; *dir_p; dir_p++) {
        !           938:                        char *dir = *dir_p;
        !           939:                        if (*dir == '/')
        !           940:                                dir += module_dirlen;
        !           941:                        if (check_filter(elp, FLOG, dir, 1) < 0)
        !           942:                                goto options_rejected;
        !           943:                }
        !           944:                if (partial_dir && *partial_dir == '/'
        !           945:                 && check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) {
        !           946:                    options_rejected:
        !           947:                        rprintf(FERROR,
        !           948:                                "Your options have been rejected by the server.\n");
        !           949:                        exit_cleanup(RERR_SYNTAX);
        !           950:                }
        !           951:        }
        !           952: 
        !           953:        exit_code = do_recv(f_in, f_out, local_name);
        !           954:        exit_cleanup(exit_code);
        !           955: }
        !           956: 
        !           957: 
        !           958: int child_main(int argc, char *argv[])
        !           959: {
        !           960:        start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
        !           961:        return 0;
        !           962: }
        !           963: 
        !           964: 
        !           965: void start_server(int f_in, int f_out, int argc, char *argv[])
        !           966: {
        !           967:        set_nonblocking(f_in);
        !           968:        set_nonblocking(f_out);
        !           969: 
        !           970:        io_set_sock_fds(f_in, f_out);
        !           971:        setup_protocol(f_out, f_in);
        !           972: 
        !           973:        if (protocol_version >= 23)
        !           974:                io_start_multiplex_out();
        !           975: 
        !           976:        if (am_sender) {
        !           977:                keep_dirlinks = 0; /* Must be disabled on the sender. */
        !           978:                if (need_messages_from_generator)
        !           979:                        io_start_multiplex_in();
        !           980:                recv_filter_list(f_in);
        !           981:                do_server_sender(f_in, f_out, argc, argv);
        !           982:        } else
        !           983:                do_server_recv(f_in, f_out, argc, argv);
        !           984:        exit_cleanup(0);
        !           985: }
        !           986: 
        !           987: 
        !           988: /*
        !           989:  * This is called once the connection has been negotiated.  It is used
        !           990:  * for rsyncd, remote-shell, and local connections.
        !           991:  */
        !           992: int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
        !           993: {
        !           994:        struct file_list *flist = NULL;
        !           995:        int exit_code = 0, exit_code2 = 0;
        !           996:        char *local_name = NULL;
        !           997: 
        !           998:        cleanup_child_pid = pid;
        !           999:        if (!read_batch) {
        !          1000:                set_nonblocking(f_in);
        !          1001:                set_nonblocking(f_out);
        !          1002:        }
        !          1003: 
        !          1004:        io_set_sock_fds(f_in, f_out);
        !          1005:        setup_protocol(f_out,f_in);
        !          1006: 
        !          1007:        /* We set our stderr file handle to blocking because ssh might have
        !          1008:         * set it to non-blocking.  This can be particularly troublesome if
        !          1009:         * stderr is a clone of stdout, because ssh would have set our stdout
        !          1010:         * to non-blocking at the same time (which can easily cause us to lose
        !          1011:         * output from our print statements).  This kluge shouldn't cause ssh
        !          1012:         * any problems for how we use it.  Note also that we delayed setting
        !          1013:         * this until after the above protocol setup so that we know for sure
        !          1014:         * that ssh is done twiddling its file descriptors.  */
        !          1015:        set_blocking(STDERR_FILENO);
        !          1016: 
        !          1017:        if (am_sender) {
        !          1018:                keep_dirlinks = 0; /* Must be disabled on the sender. */
        !          1019:                if (protocol_version >= 30)
        !          1020:                        io_start_multiplex_out();
        !          1021:                else
        !          1022:                        io_start_buffering_out(f_out);
        !          1023:                if (!filesfrom_host)
        !          1024:                        set_msg_fd_in(f_in);
        !          1025:                send_filter_list(f_out);
        !          1026:                if (filesfrom_host)
        !          1027:                        filesfrom_fd = f_in;
        !          1028: 
        !          1029:                if (write_batch && !am_server)
        !          1030:                        start_write_batch(f_out);
        !          1031:                flist = send_file_list(f_out, argc, argv);
        !          1032:                if (verbose > 3)
        !          1033:                        rprintf(FINFO,"file list sent\n");
        !          1034: 
        !          1035:                if (protocol_version >= 23)
        !          1036:                        io_start_multiplex_in();
        !          1037: 
        !          1038:                io_flush(NORMAL_FLUSH);
        !          1039:                send_files(f_in, f_out);
        !          1040:                io_flush(FULL_FLUSH);
        !          1041:                handle_stats(-1);
        !          1042:                if (protocol_version >= 24)
        !          1043:                        read_final_goodbye(f_in);
        !          1044:                if (pid != -1) {
        !          1045:                        if (verbose > 3)
        !          1046:                                rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
        !          1047:                        io_flush(FULL_FLUSH);
        !          1048:                        wait_process_with_flush(pid, &exit_code);
        !          1049:                }
        !          1050:                output_summary();
        !          1051:                io_flush(FULL_FLUSH);
        !          1052:                exit_cleanup(exit_code);
        !          1053:        }
        !          1054: 
        !          1055:        if (!read_batch) {
        !          1056:                if (protocol_version >= 23)
        !          1057:                        io_start_multiplex_in();
        !          1058:                if (need_messages_from_generator)
        !          1059:                        io_start_multiplex_out();
        !          1060:        }
        !          1061: 
        !          1062:        send_filter_list(read_batch ? -1 : f_out);
        !          1063: 
        !          1064:        if (filesfrom_fd >= 0) {
        !          1065:                io_set_filesfrom_fds(filesfrom_fd, f_out);
        !          1066:                filesfrom_fd = -1;
        !          1067:        }
        !          1068: 
        !          1069:        if (write_batch && !am_server)
        !          1070:                start_write_batch(f_in);
        !          1071:        flist = recv_file_list(f_in);
        !          1072:        if (inc_recurse && file_total == 1)
        !          1073:                recv_additional_file_list(f_in);
        !          1074: 
        !          1075:        if (flist && flist->used > 0) {
        !          1076:                local_name = get_local_name(flist, argv[0]);
        !          1077: 
        !          1078:                check_alt_basis_dirs();
        !          1079: 
        !          1080:                exit_code2 = do_recv(f_in, f_out, local_name);
        !          1081:        } else {
        !          1082:                handle_stats(-1);
        !          1083:                output_summary();
        !          1084:        }
        !          1085: 
        !          1086:        if (pid != -1) {
        !          1087:                if (verbose > 3)
        !          1088:                        rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
        !          1089:                io_flush(FULL_FLUSH);
        !          1090:                wait_process_with_flush(pid, &exit_code);
        !          1091:        }
        !          1092: 
        !          1093:        return MAX(exit_code, exit_code2);
        !          1094: }
        !          1095: 
        !          1096: static int copy_argv(char *argv[])
        !          1097: {
        !          1098:        int i;
        !          1099: 
        !          1100:        for (i = 0; argv[i]; i++) {
        !          1101:                if (!(argv[i] = strdup(argv[i]))) {
        !          1102:                        rprintf (FERROR, "out of memory at %s(%d)\n",
        !          1103:                                 __FILE__, __LINE__);
        !          1104:                        return RERR_MALLOC;
        !          1105:                }
        !          1106:        }
        !          1107: 
        !          1108:        return 0;
        !          1109: }
        !          1110: 
        !          1111: 
        !          1112: /**
        !          1113:  * Start a client for either type of remote connection.  Work out
        !          1114:  * whether the arguments request a remote shell or rsyncd connection,
        !          1115:  * and call the appropriate connection function, then run_client.
        !          1116:  *
        !          1117:  * Calls either start_socket_client (for sockets) or do_cmd and
        !          1118:  * client_run (for ssh).
        !          1119:  **/
        !          1120: static int start_client(int argc, char *argv[])
        !          1121: {
        !          1122:        char *p, *shell_machine = NULL, *shell_user = NULL;
        !          1123:        char **remote_argv;
        !          1124:        int remote_argc;
        !          1125:        int f_in, f_out;
        !          1126:        int ret;
        !          1127:        pid_t pid;
        !          1128: 
        !          1129:        /* Don't clobber argv[] so that ps(1) can still show the right
        !          1130:         * command line. */
        !          1131:        if ((ret = copy_argv(argv)) != 0)
        !          1132:                return ret;
        !          1133: 
        !          1134:        if (!read_batch) { /* for read_batch, NO source is specified */
        !          1135:                char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
        !          1136:                if (path) { /* source is remote */
        !          1137:                        char *dummy_host;
        !          1138:                        int dummy_port = 0;
        !          1139:                        *argv = path;
        !          1140:                        remote_argv = argv;
        !          1141:                        remote_argc = argc;
        !          1142:                        argv += argc - 1;
        !          1143:                        if (argc == 1 || **argv == ':')
        !          1144:                                argc = 0; /* no dest arg */
        !          1145:                        else if (check_for_hostspec(*argv, &dummy_host, &dummy_port)) {
        !          1146:                                rprintf(FERROR,
        !          1147:                                        "The source and destination cannot both be remote.\n");
        !          1148:                                exit_cleanup(RERR_SYNTAX);
        !          1149:                        } else {
        !          1150:                                remote_argc--; /* don't count dest */
        !          1151:                                argc = 1;
        !          1152:                        }
        !          1153:                        if (filesfrom_host && *filesfrom_host
        !          1154:                            && strcmp(filesfrom_host, shell_machine) != 0) {
        !          1155:                                rprintf(FERROR,
        !          1156:                                        "--files-from hostname is not the same as the transfer hostname\n");
        !          1157:                                exit_cleanup(RERR_SYNTAX);
        !          1158:                        }
        !          1159:                        am_sender = 0;
        !          1160:                        if (rsync_port)
        !          1161:                                daemon_over_rsh = shell_cmd ? 1 : -1;
        !          1162:                } else { /* source is local, check dest arg */
        !          1163:                        am_sender = 1;
        !          1164: 
        !          1165:                        if (argc > 1) {
        !          1166:                                p = argv[--argc];
        !          1167:                                remote_argv = argv + argc;
        !          1168:                        } else {
        !          1169:                                static char *dotarg[1] = { "." };
        !          1170:                                p = dotarg[0];
        !          1171:                                remote_argv = dotarg;
        !          1172:                        }
        !          1173:                        remote_argc = 1;
        !          1174: 
        !          1175:                        path = check_for_hostspec(p, &shell_machine, &rsync_port);
        !          1176:                        if (path && filesfrom_host && *filesfrom_host
        !          1177:                            && strcmp(filesfrom_host, shell_machine) != 0) {
        !          1178:                                rprintf(FERROR,
        !          1179:                                        "--files-from hostname is not the same as the transfer hostname\n");
        !          1180:                                exit_cleanup(RERR_SYNTAX);
        !          1181:                        }
        !          1182:                        if (!path) { /* no hostspec found, so src & dest are local */
        !          1183:                                local_server = 1;
        !          1184:                                if (filesfrom_host) {
        !          1185:                                        rprintf(FERROR,
        !          1186:                                                "--files-from cannot be remote when the transfer is local\n");
        !          1187:                                        exit_cleanup(RERR_SYNTAX);
        !          1188:                                }
        !          1189:                                shell_machine = NULL;
        !          1190:                        } else { /* hostspec was found, so dest is remote */
        !          1191:                                argv[argc] = path;
        !          1192:                                if (rsync_port)
        !          1193:                                        daemon_over_rsh = shell_cmd ? 1 : -1;
        !          1194:                        }
        !          1195:                }
        !          1196:        } else {  /* read_batch */
        !          1197:                local_server = 1;
        !          1198:                if (check_for_hostspec(argv[argc-1], &shell_machine, &rsync_port)) {
        !          1199:                        rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
        !          1200:                        exit_cleanup(RERR_SYNTAX);
        !          1201:                }
        !          1202:                remote_argv = argv += argc - 1;
        !          1203:                remote_argc = argc = 1;
        !          1204:        }
        !          1205: 
        !          1206:        if (am_sender) {
        !          1207:                char *dummy_host;
        !          1208:                int dummy_port = rsync_port;
        !          1209:                int i;
        !          1210:                /* For local source, extra source args must not have hostspec. */
        !          1211:                for (i = 1; i < argc; i++) {
        !          1212:                        if (check_for_hostspec(argv[i], &dummy_host, &dummy_port)) {
        !          1213:                                rprintf(FERROR, "Unexpected remote arg: %s\n", argv[i]);
        !          1214:                                exit_cleanup(RERR_SYNTAX);
        !          1215:                        }
        !          1216:                }
        !          1217:        } else {
        !          1218:                char *dummy_host;
        !          1219:                int dummy_port = rsync_port;
        !          1220:                int i;
        !          1221:                /* For remote source, any extra source args must have either
        !          1222:                 * the same hostname or an empty hostname. */
        !          1223:                for (i = 1; i < remote_argc; i++) {
        !          1224:                        char *arg = check_for_hostspec(remote_argv[i], &dummy_host, &dummy_port);
        !          1225:                        if (!arg) {
        !          1226:                                rprintf(FERROR, "Unexpected local arg: %s\n", remote_argv[i]);
        !          1227:                                rprintf(FERROR, "If arg is a remote file/dir, prefix it with a colon (:).\n");
        !          1228:                                exit_cleanup(RERR_SYNTAX);
        !          1229:                        }
        !          1230:                        if (*dummy_host && strcmp(dummy_host, shell_machine) != 0) {
        !          1231:                                rprintf(FERROR, "All source args must come from the same machine.\n");
        !          1232:                                exit_cleanup(RERR_SYNTAX);
        !          1233:                        }
        !          1234:                        if (rsync_port != dummy_port) {
        !          1235:                                if (!rsync_port || !dummy_port)
        !          1236:                                        rprintf(FERROR, "All source args must use the same hostspec format.\n");
        !          1237:                                else
        !          1238:                                        rprintf(FERROR, "All source args must use the same port number.\n");
        !          1239:                                exit_cleanup(RERR_SYNTAX);
        !          1240:                        }
        !          1241:                        remote_argv[i] = arg;
        !          1242:                }
        !          1243:        }
        !          1244: 
        !          1245:        if (daemon_over_rsh < 0)
        !          1246:                return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv);
        !          1247: 
        !          1248:        if (password_file && !daemon_over_rsh) {
        !          1249:                rprintf(FERROR, "The --password-file option may only be "
        !          1250:                                "used when accessing an rsync daemon.\n");
        !          1251:                exit_cleanup(RERR_SYNTAX);
        !          1252:        }
        !          1253: 
        !          1254:        if (connect_timeout) {
        !          1255:                rprintf(FERROR, "The --contimeout option may only be "
        !          1256:                                "used when connecting to an rsync daemon.\n");
        !          1257:                exit_cleanup(RERR_SYNTAX);
        !          1258:        }
        !          1259: 
        !          1260:        if (shell_machine) {
        !          1261:                p = strrchr(shell_machine,'@');
        !          1262:                if (p) {
        !          1263:                        *p = 0;
        !          1264:                        shell_user = shell_machine;
        !          1265:                        shell_machine = p+1;
        !          1266:                }
        !          1267:        }
        !          1268: 
        !          1269:        if (verbose > 3) {
        !          1270:                rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
        !          1271:                        NS(shell_cmd), NS(shell_machine), NS(shell_user),
        !          1272:                        remote_argv ? NS(remote_argv[0]) : "");
        !          1273:        }
        !          1274: 
        !          1275:        pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
        !          1276:                     &f_in, &f_out);
        !          1277: 
        !          1278:        /* if we're running an rsync server on the remote host over a
        !          1279:         * remote shell command, we need to do the RSYNCD protocol first */
        !          1280:        if (daemon_over_rsh) {
        !          1281:                int tmpret;
        !          1282:                tmpret = start_inband_exchange(f_in, f_out, shell_user, remote_argc, remote_argv);
        !          1283:                if (tmpret < 0)
        !          1284:                        return tmpret;
        !          1285:        }
        !          1286: 
        !          1287:        ret = client_run(f_in, f_out, pid, argc, argv);
        !          1288: 
        !          1289:        fflush(stdout);
        !          1290:        fflush(stderr);
        !          1291: 
        !          1292:        return ret;
        !          1293: }
        !          1294: 
        !          1295: 
        !          1296: static RETSIGTYPE sigusr1_handler(UNUSED(int val))
        !          1297: {
        !          1298:        exit_cleanup(RERR_SIGNAL1);
        !          1299: }
        !          1300: 
        !          1301: static RETSIGTYPE sigusr2_handler(UNUSED(int val))
        !          1302: {
        !          1303:        if (!am_server)
        !          1304:                output_summary();
        !          1305:        close_all();
        !          1306:        if (got_xfer_error)
        !          1307:                _exit(RERR_PARTIAL);
        !          1308:        _exit(0);
        !          1309: }
        !          1310: 
        !          1311: RETSIGTYPE remember_children(UNUSED(int val))
        !          1312: {
        !          1313: #ifdef WNOHANG
        !          1314:        int cnt, status;
        !          1315:        pid_t pid;
        !          1316:        /* An empty waitpid() loop was put here by Tridge and we could never
        !          1317:         * get him to explain why he put it in, so rather than taking it
        !          1318:         * out we're instead saving the child exit statuses for later use.
        !          1319:         * The waitpid() loop presumably eliminates all possibility of leaving
        !          1320:         * zombie children, maybe that's why he did it. */
        !          1321:        while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        !          1322:                /* save the child's exit status */
        !          1323:                for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
        !          1324:                        if (pid_stat_table[cnt].pid == 0) {
        !          1325:                                pid_stat_table[cnt].pid = pid;
        !          1326:                                pid_stat_table[cnt].status = status;
        !          1327:                                break;
        !          1328:                        }
        !          1329:                }
        !          1330:        }
        !          1331: #endif
        !          1332: #ifndef HAVE_SIGACTION
        !          1333:        signal(SIGCHLD, remember_children);
        !          1334: #endif
        !          1335: }
        !          1336: 
        !          1337: 
        !          1338: /**
        !          1339:  * This routine catches signals and tries to send them to gdb.
        !          1340:  *
        !          1341:  * Because it's called from inside a signal handler it ought not to
        !          1342:  * use too many library routines.
        !          1343:  *
        !          1344:  * @todo Perhaps use "screen -X" instead/as well, to help people
        !          1345:  * debugging without easy access to X.  Perhaps use an environment
        !          1346:  * variable, or just call a script?
        !          1347:  *
        !          1348:  * @todo The /proc/ magic probably only works on Linux (and
        !          1349:  * Solaris?)  Can we be more portable?
        !          1350:  **/
        !          1351: #ifdef MAINTAINER_MODE
        !          1352: const char *get_panic_action(void)
        !          1353: {
        !          1354:        const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
        !          1355: 
        !          1356:        if (cmd_fmt)
        !          1357:                return cmd_fmt;
        !          1358:        else
        !          1359:                return "xterm -display :0 -T Panic -n Panic "
        !          1360:                        "-e gdb /proc/%d/exe %d";
        !          1361: }
        !          1362: 
        !          1363: 
        !          1364: /**
        !          1365:  * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
        !          1366:  *
        !          1367:  * This signal handler is only installed if we were configured with
        !          1368:  * --enable-maintainer-mode.  Perhaps it should always be on and we
        !          1369:  * should just look at the environment variable, but I'm a bit leery
        !          1370:  * of a signal sending us into a busy loop.
        !          1371:  **/
        !          1372: static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
        !          1373: {
        !          1374:        char cmd_buf[300];
        !          1375:        int ret;
        !          1376: 
        !          1377:        snprintf(cmd_buf, sizeof cmd_buf, get_panic_action(),
        !          1378:                 getpid(), getpid());
        !          1379: 
        !          1380:        /* Unless we failed to execute gdb, we allow the process to
        !          1381:         * continue.  I'm not sure if that's right. */
        !          1382:        ret = system(cmd_buf);
        !          1383:        if (ret)
        !          1384:                _exit(ret);
        !          1385: }
        !          1386: #endif
        !          1387: 
        !          1388: 
        !          1389: int main(int argc,char *argv[])
        !          1390: {
        !          1391:        int ret;
        !          1392:        int orig_argc = argc;
        !          1393:        char **orig_argv = argv;
        !          1394: #ifdef HAVE_SIGACTION
        !          1395: # ifdef HAVE_SIGPROCMASK
        !          1396:        sigset_t sigmask;
        !          1397: 
        !          1398:        sigemptyset(&sigmask);
        !          1399: # endif
        !          1400:        sigact.sa_flags = SA_NOCLDSTOP;
        !          1401: #endif
        !          1402:        SIGACTMASK(SIGUSR1, sigusr1_handler);
        !          1403:        SIGACTMASK(SIGUSR2, sigusr2_handler);
        !          1404:        SIGACTMASK(SIGCHLD, remember_children);
        !          1405: #ifdef MAINTAINER_MODE
        !          1406:        SIGACTMASK(SIGSEGV, rsync_panic_handler);
        !          1407:        SIGACTMASK(SIGFPE, rsync_panic_handler);
        !          1408:        SIGACTMASK(SIGABRT, rsync_panic_handler);
        !          1409:        SIGACTMASK(SIGBUS, rsync_panic_handler);
        !          1410: #endif
        !          1411: 
        !          1412:        starttime = time(NULL);
        !          1413:        our_uid = MY_UID();
        !          1414:        am_root = our_uid == 0;
        !          1415: 
        !          1416:        memset(&stats, 0, sizeof(stats));
        !          1417: 
        !          1418:        if (argc < 2) {
        !          1419:                usage(FERROR);
        !          1420:                exit_cleanup(RERR_SYNTAX);
        !          1421:        }
        !          1422: 
        !          1423:        /* we set a 0 umask so that correct file permissions can be
        !          1424:         * carried across */
        !          1425:        orig_umask = umask(0);
        !          1426: 
        !          1427: #if defined CONFIG_LOCALE && defined HAVE_SETLOCALE
        !          1428:        setlocale(LC_CTYPE, "");
        !          1429: #endif
        !          1430: 
        !          1431:        if (!parse_arguments(&argc, (const char ***) &argv)) {
        !          1432:                /* FIXME: We ought to call the same error-handling
        !          1433:                 * code here, rather than relying on getopt. */
        !          1434:                option_error();
        !          1435:                exit_cleanup(RERR_SYNTAX);
        !          1436:        }
        !          1437: 
        !          1438:        SIGACTMASK(SIGINT, sig_int);
        !          1439:        SIGACTMASK(SIGHUP, sig_int);
        !          1440:        SIGACTMASK(SIGTERM, sig_int);
        !          1441: #if defined HAVE_SIGACTION && HAVE_SIGPROCMASK
        !          1442:        sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
        !          1443: #endif
        !          1444: 
        !          1445:        /* Ignore SIGPIPE; we consistently check error codes and will
        !          1446:         * see the EPIPE. */
        !          1447:        SIGACTION(SIGPIPE, SIG_IGN);
        !          1448: #ifdef SIGXFSZ
        !          1449:        SIGACTION(SIGXFSZ, SIG_IGN);
        !          1450: #endif
        !          1451: 
        !          1452:        /* Initialize change_dir() here because on some old systems getcwd
        !          1453:         * (implemented by forking "pwd" and reading its output) doesn't
        !          1454:         * work when there are other child processes.  Also, on all systems
        !          1455:         * that implement getcwd that way "pwd" can't be found after chroot. */
        !          1456:        change_dir(NULL, CD_NORMAL);
        !          1457: 
        !          1458:        init_flist();
        !          1459: 
        !          1460:        if ((write_batch || read_batch) && !am_server) {
        !          1461:                if (write_batch)
        !          1462:                        write_batch_shell_file(orig_argc, orig_argv, argc);
        !          1463: 
        !          1464:                if (read_batch && strcmp(batch_name, "-") == 0)
        !          1465:                        batch_fd = STDIN_FILENO;
        !          1466:                else {
        !          1467:                        batch_fd = do_open(batch_name,
        !          1468:                                   write_batch ? O_WRONLY | O_CREAT | O_TRUNC
        !          1469:                                   : O_RDONLY, S_IRUSR | S_IWUSR);
        !          1470:                }
        !          1471:                if (batch_fd < 0) {
        !          1472:                        rsyserr(FERROR, errno, "Batch file %s open error",
        !          1473:                                full_fname(batch_name));
        !          1474:                        exit_cleanup(RERR_FILEIO);
        !          1475:                }
        !          1476:                if (read_batch)
        !          1477:                        read_stream_flags(batch_fd);
        !          1478:                else
        !          1479:                        write_stream_flags(batch_fd);
        !          1480:        }
        !          1481:        if (write_batch < 0)
        !          1482:                dry_run = 1;
        !          1483: 
        !          1484:        if (am_server) {
        !          1485: #ifdef ICONV_CONST
        !          1486:                setup_iconv();
        !          1487: #endif
        !          1488:        } else if (am_daemon)
        !          1489:                return daemon_main();
        !          1490: 
        !          1491:        if (am_server && protect_args) {
        !          1492:                char buf[MAXPATHLEN];
        !          1493:                protect_args = 2;
        !          1494:                read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL);
        !          1495:                if (!parse_arguments(&argc, (const char ***) &argv)) {
        !          1496:                        option_error();
        !          1497:                        exit_cleanup(RERR_SYNTAX);
        !          1498:                }
        !          1499:        }
        !          1500: 
        !          1501:        if (argc < 1) {
        !          1502:                usage(FERROR);
        !          1503:                exit_cleanup(RERR_SYNTAX);
        !          1504:        }
        !          1505: 
        !          1506:        if (am_server) {
        !          1507:                set_nonblocking(STDIN_FILENO);
        !          1508:                set_nonblocking(STDOUT_FILENO);
        !          1509:                if (am_daemon)
        !          1510:                        return start_daemon(STDIN_FILENO, STDOUT_FILENO);
        !          1511:                start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
        !          1512:        }
        !          1513: 
        !          1514:        ret = start_client(argc, argv);
        !          1515:        if (ret == -1)
        !          1516:                exit_cleanup(RERR_STARTCLIENT);
        !          1517:        else
        !          1518:                exit_cleanup(ret);
        !          1519: 
        !          1520:        return ret;
        !          1521: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>