Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

main.c

Go to the documentation of this file.
00001 /* -*- c-file-style: "linux" -*-
00002    
00003    Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org>
00004    Copyright (C) Paul Mackerras 1996
00005    Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
00006    
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016    
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 */
00021 
00022 #include "rsync.h"
00023 
00024 time_t starttime = 0;
00025 
00026 extern struct stats stats;
00027 extern int verbose;
00028 
00029 static void show_malloc_stats(void);
00030 
00031 /****************************************************************************
00032 wait for a process to exit, calling io_flush while waiting
00033 ****************************************************************************/
00034 void wait_process(pid_t pid, int *status)
00035 {
00036         while (waitpid(pid, status, WNOHANG) == 0) {
00037                 msleep(20);
00038                 io_flush();
00039         }
00040         
00041         /* TODO: If the child exited on a signal, then log an
00042          * appropriate error message.  Perhaps we should also accept a
00043          * message describing the purpose of the child.  Also indicate
00044          * this to the caller so that thhey know something went
00045          * wrong.  */
00046         *status = WEXITSTATUS(*status);
00047 }
00048 
00049 static void report(int f)
00050 {
00051         time_t t = time(NULL);
00052         extern int am_server;
00053         extern int am_sender;
00054         extern int am_daemon;
00055         extern int do_stats;
00056         extern int remote_version;
00057         int send_stats;
00058 
00059         if (do_stats) {
00060                 /* These come out from every process */
00061                 show_malloc_stats();
00062                 show_flist_stats();
00063         }
00064 
00065         if (am_daemon) {
00066                 log_exit(0, __FILE__, __LINE__);
00067                 if (f == -1 || !am_sender) return;
00068         }
00069 
00070         send_stats = verbose || (remote_version >= 20);
00071         if (am_server) {
00072                 if (am_sender && send_stats) {
00073                         int64 w;
00074                         /* store total_written in a temporary
00075                             because write_longint changes it */
00076                         w = stats.total_written;
00077                         write_longint(f,stats.total_read);
00078                         write_longint(f,w);
00079                         write_longint(f,stats.total_size);
00080                 }
00081                 return;
00082         }
00083 
00084         /* this is the client */
00085             
00086         if (!am_sender && send_stats) {
00087                 int64 r;
00088                 stats.total_written = read_longint(f);
00089                 /* store total_read in a temporary, read_longint changes it */
00090                 r = read_longint(f);
00091                 stats.total_size = read_longint(f);
00092                 stats.total_read = r;
00093         }
00094 
00095         if (do_stats) {
00096                 if (!am_sender && !send_stats) {
00097                     /* missing the bytes written by the generator */
00098                     rprintf(FINFO, "\nCannot show stats as receiver because remote protocol version is less than 20\n");
00099                     rprintf(FINFO, "Use --stats -v to show stats\n");
00100                     return;
00101                 }
00102                 rprintf(FINFO,"\nNumber of files: %d\n", stats.num_files);
00103                 rprintf(FINFO,"Number of files transferred: %d\n", 
00104                        stats.num_transferred_files);
00105                 rprintf(FINFO,"Total file size: %.0f bytes\n", 
00106                        (double)stats.total_size);
00107                 rprintf(FINFO,"Total transferred file size: %.0f bytes\n", 
00108                        (double)stats.total_transferred_size);
00109                 rprintf(FINFO,"Literal data: %.0f bytes\n", 
00110                        (double)stats.literal_data);
00111                 rprintf(FINFO,"Matched data: %.0f bytes\n", 
00112                        (double)stats.matched_data);
00113                 rprintf(FINFO,"File list size: %d\n", stats.flist_size);
00114                 rprintf(FINFO,"Total bytes written: %.0f\n", 
00115                        (double)stats.total_written);
00116                 rprintf(FINFO,"Total bytes read: %.0f\n\n", 
00117                        (double)stats.total_read);
00118         }
00119         
00120         if (verbose || do_stats) {
00121                 rprintf(FINFO,"wrote %.0f bytes  read %.0f bytes  %.2f bytes/sec\n",
00122                        (double)stats.total_written,
00123                        (double)stats.total_read,
00124                        (stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
00125                 rprintf(FINFO,"total size is %.0f  speedup is %.2f\n",
00126                        (double)stats.total_size,
00127                        (1.0*stats.total_size)/(stats.total_written+stats.total_read));
00128         }
00129 
00130         fflush(stdout);
00131         fflush(stderr);
00132 }
00133 
00134 
00135 /**
00136  * If our C library can get malloc statistics, then show them to FINFO
00137  **/
00138 static void show_malloc_stats(void)
00139 {
00140 #ifdef HAVE_MALLINFO
00141         struct mallinfo mi;
00142         extern int am_server;
00143         extern int am_sender;
00144         extern int am_daemon;
00145 
00146         mi = mallinfo();
00147 
00148         rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
00149                 getpid(),
00150                 am_server ? "server " : "",
00151                 am_daemon ? "daemon " : "",
00152                 am_sender ? "sender" : "receiver");
00153         rprintf(FINFO, "  arena:     %10d   (bytes from sbrk)\n", mi.arena);
00154         rprintf(FINFO, "  ordblks:   %10d   (chunks not in use)\n", mi.ordblks);
00155         rprintf(FINFO, "  smblks:    %10d\n", mi.smblks);
00156         rprintf(FINFO, "  hblks:     %10d   (chunks from mmap)\n", mi.hblks);
00157         rprintf(FINFO, "  hblkhd:    %10d   (bytes from mmap)\n", mi.hblkhd);
00158         rprintf(FINFO, "  usmblks:   %10d\n", mi.usmblks);
00159         rprintf(FINFO, "  fsmblks:   %10d\n", mi.fsmblks);
00160         rprintf(FINFO, "  uordblks:  %10d   (bytes used)\n", mi.uordblks);
00161         rprintf(FINFO, "  fordblks:  %10d   (bytes free)\n", mi.fordblks);
00162         rprintf(FINFO, "  keepcost:  %10d   (bytes in releasable chunk)\n", mi.keepcost);
00163 #endif /* HAVE_MALLINFO */
00164 }
00165 
00166 
00167 /* Start the remote shell.   cmd may be NULL to use the default. */
00168 static pid_t do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
00169 {
00170         char *args[100];
00171         int i,argc=0;
00172         pid_t ret;
00173         char *tok,*dir=NULL;
00174         extern int local_server;
00175         extern char *rsync_path;
00176         extern int blocking_io;
00177         extern int read_batch;
00178 
00179         if (!read_batch && !local_server) {
00180                 if (!cmd)
00181                         cmd = getenv(RSYNC_RSH_ENV);
00182                 if (!cmd)
00183                         cmd = RSYNC_RSH;
00184                 cmd = strdup(cmd);
00185                 if (!cmd) 
00186                         goto oom;
00187 
00188                 for (tok=strtok(cmd," ");tok;tok=strtok(NULL," ")) {
00189                         args[argc++] = tok;
00190                 }
00191 
00192 #if HAVE_REMSH
00193                 /* remsh (on HPUX) takes the arguments the other way around */
00194                 args[argc++] = machine;
00195                 if (user) {
00196                         args[argc++] = "-l";
00197                         args[argc++] = user;
00198                 }
00199 #else
00200                 if (user) {
00201                         args[argc++] = "-l";
00202                         args[argc++] = user;
00203                 }
00204                 args[argc++] = machine;
00205 #endif
00206 
00207                 args[argc++] = rsync_path;
00208 
00209                 if ((blocking_io == -1) && (strcmp(cmd, RSYNC_RSH) == 0))
00210                         blocking_io = 1;
00211 
00212                 server_options(args,&argc);
00213 
00214         }
00215 
00216         args[argc++] = ".";
00217 
00218         if (path && *path) 
00219                 args[argc++] = path;
00220 
00221         args[argc] = NULL;
00222 
00223         if (verbose > 3) {
00224                 rprintf(FINFO,"cmd=");
00225                 for (i=0;i<argc;i++)
00226                         rprintf(FINFO,"%s ",args[i]);
00227                 rprintf(FINFO,"\n");
00228         }
00229 
00230         if (local_server) {
00231                 if (read_batch)
00232                     create_flist_from_batch(); /* sets batch_flist */
00233                 ret = local_child(argc, args, f_in, f_out, child_main);
00234         } else {
00235                 ret = piped_child(args,f_in,f_out);
00236         }
00237 
00238         if (dir) free(dir);
00239 
00240         return ret;
00241 
00242 oom:
00243         out_of_memory("do_cmd");
00244         return 0; /* not reached */
00245 }
00246 
00247 
00248 
00249 
00250 static char *get_local_name(struct file_list *flist,char *name)
00251 {
00252         STRUCT_STAT st;
00253         extern int orig_umask;
00254 
00255         if (verbose > 2)
00256                 rprintf(FINFO,"get_local_name count=%d %s\n", 
00257                         flist->count, NS(name));
00258 
00259         if (!name) 
00260                 return NULL;
00261 
00262         if (do_stat(name,&st) == 0) {
00263                 if (S_ISDIR(st.st_mode)) {
00264                         if (!push_dir(name, 0)) {
00265                                 rprintf(FERROR,"push_dir %s : %s (1)\n",
00266                                         name,strerror(errno));
00267                                 exit_cleanup(RERR_FILESELECT);
00268                         }
00269                         return NULL;
00270                 }
00271                 if (flist->count > 1) {
00272                         rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n");
00273                         exit_cleanup(RERR_FILESELECT);
00274                 }
00275                 return name;
00276         }
00277 
00278         if (flist->count <= 1)
00279                 return name;
00280 
00281         if (do_mkdir(name,0777 & ~orig_umask) != 0) {
00282                 rprintf(FERROR, RSYNC_NAME ": mkdir %s: %s\n",
00283                         name, strerror(errno));
00284                 exit_cleanup(RERR_FILEIO);
00285         } else {
00286                 if (verbose > 0)
00287                         rprintf(FINFO,"created directory %s\n",name);
00288         }
00289 
00290         if (!push_dir(name, 0)) {
00291                 rprintf(FERROR, RSYNC_NAME ": push_dir %s: %s\n",
00292                         name, strerror(errno));
00293                 exit_cleanup(RERR_FILESELECT);
00294         }
00295 
00296         return NULL;
00297 }
00298 
00299 
00300 
00301 
00302 static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
00303 {
00304         int i;
00305         struct file_list *flist;
00306         char *dir = argv[0];
00307         extern int relative_paths;
00308         extern int recurse;
00309         extern int remote_version;
00310 
00311         if (verbose > 2)
00312                 rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
00313   
00314         if (!relative_paths && !push_dir(dir, 0)) {
00315                 rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
00316                 exit_cleanup(RERR_FILESELECT);
00317         }
00318         argc--;
00319         argv++;
00320   
00321         if (strcmp(dir,".")) {
00322                 int l = strlen(dir);
00323                 if (strcmp(dir,"/") == 0) 
00324                         l = 0;
00325                 for (i=0;i<argc;i++)
00326                         argv[i] += l+1;
00327         }
00328 
00329         if (argc == 0 && recurse) {
00330                 argc=1;
00331                 argv--;
00332                 argv[0] = ".";
00333         }
00334         
00335         flist = send_file_list(f_out,argc,argv);
00336         if (!flist || flist->count == 0) {
00337                 exit_cleanup(0);
00338         }
00339 
00340         send_files(flist,f_out,f_in);
00341         io_flush();
00342         report(f_out);
00343         if (remote_version >= 24) {
00344                 /* final goodbye message */             
00345                 read_int(f_in);
00346         }
00347         io_flush();
00348         exit_cleanup(0);
00349 }
00350 
00351 
00352 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
00353 {
00354         int pid;
00355         int status=0;
00356         int recv_pipe[2];
00357         int error_pipe[2];
00358         extern int preserve_hard_links;
00359         extern int delete_after;
00360         extern int recurse;
00361         extern int delete_mode;
00362         extern int remote_version;
00363 
00364         if (preserve_hard_links)
00365                 init_hard_links(flist);
00366 
00367         if (!delete_after) {
00368                 /* I moved this here from recv_files() to prevent a race condition */
00369                 if (recurse && delete_mode && !local_name && flist->count>0) {
00370                         delete_files(flist);
00371                 }
00372         }
00373 
00374         if (fd_pair(recv_pipe) < 0) {
00375                 rprintf(FERROR,"pipe failed in do_recv\n");
00376                 exit_cleanup(RERR_SOCKETIO);
00377         }
00378 
00379         if (fd_pair(error_pipe) < 0) {
00380                 rprintf(FERROR,"error pipe failed in do_recv\n");
00381                 exit_cleanup(RERR_SOCKETIO);
00382         }
00383   
00384         io_flush();
00385 
00386         if ((pid=do_fork()) == 0) {
00387                 close(recv_pipe[0]);
00388                 close(error_pipe[0]);
00389                 if (f_in != f_out) close(f_out);
00390 
00391                 /* we can't let two processes write to the socket at one time */
00392                 io_multiplexing_close();
00393 
00394                 /* set place to send errors */
00395                 set_error_fd(error_pipe[1]);
00396 
00397                 recv_files(f_in,flist,local_name,recv_pipe[1]);
00398                 io_flush();
00399                 report(f_in);
00400 
00401                 write_int(recv_pipe[1],1);
00402                 close(recv_pipe[1]);
00403                 io_flush();
00404                 /* finally we go to sleep until our parent kills us
00405                    with a USR2 signal. We sleep for a short time as on
00406                    some OSes a signal won't interrupt a sleep! */
00407                 while (msleep(20))
00408                         ;
00409         }
00410 
00411         close(recv_pipe[1]);
00412         close(error_pipe[1]);
00413         if (f_in != f_out) close(f_in);
00414 
00415         io_start_buffering(f_out);
00416 
00417         io_set_error_fd(error_pipe[0]);
00418 
00419         generate_files(f_out,flist,local_name,recv_pipe[0]);
00420 
00421         read_int(recv_pipe[0]);
00422         close(recv_pipe[0]);
00423         if (remote_version >= 24) {
00424                 /* send a final goodbye message */
00425                 write_int(f_out, -1);
00426         }
00427         io_flush();
00428 
00429         kill(pid, SIGUSR2);
00430         wait_process(pid, &status);
00431         return status;
00432 }
00433 
00434 
00435 static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
00436 {
00437         int status;
00438         struct file_list *flist;
00439         char *local_name=NULL;
00440         char *dir = NULL;
00441         extern int delete_mode;
00442         extern int delete_excluded;
00443         extern int am_daemon;
00444         extern int module_id;
00445         extern int am_sender;
00446         extern int read_batch;
00447         extern struct file_list *batch_flist;
00448 
00449         if (verbose > 2)
00450                 rprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
00451 
00452         if (am_daemon && lp_read_only(module_id) && !am_sender) {
00453                 rprintf(FERROR,"ERROR: module is read only\n");
00454                 exit_cleanup(RERR_SYNTAX);
00455                 return;
00456         }
00457 
00458         
00459         if (argc > 0) {
00460                 dir = argv[0];
00461                 argc--;
00462                 argv++;
00463                 if (!am_daemon && !push_dir(dir, 0)) {
00464                         rprintf(FERROR,"push_dir %s : %s (4)\n",
00465                                 dir,strerror(errno));
00466                         exit_cleanup(RERR_FILESELECT);
00467                 }    
00468         }
00469 
00470         if (delete_mode && !delete_excluded)
00471                 recv_exclude_list(f_in);
00472 
00473         if (read_batch)
00474             flist = batch_flist;
00475         else
00476             flist = recv_file_list(f_in);
00477         if (!flist) {
00478                 rprintf(FERROR,"server_recv: recv_file_list error\n");
00479                 exit_cleanup(RERR_FILESELECT);
00480         }
00481         
00482         if (argc > 0) {    
00483                 if (strcmp(dir,".")) {
00484                         argv[0] += strlen(dir);
00485                         if (argv[0][0] == '/') argv[0]++;
00486                 }
00487                 local_name = get_local_name(flist,argv[0]);
00488         }
00489 
00490         status = do_recv(f_in,f_out,flist,local_name);
00491         exit_cleanup(status);
00492 }
00493 
00494 
00495 int child_main(int argc, char *argv[])
00496 {
00497         start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
00498         return 0;
00499 }
00500 
00501 
00502 void start_server(int f_in, int f_out, int argc, char *argv[])
00503 {
00504         extern int cvs_exclude;
00505         extern int am_sender;
00506         extern int remote_version;
00507         extern int read_batch;
00508 
00509         setup_protocol(f_out, f_in);
00510 
00511         set_nonblocking(f_in);
00512         set_nonblocking(f_out);
00513 
00514         if (remote_version >= 23)
00515                 io_start_multiplex_out(f_out);
00516 
00517         if (am_sender) {
00518                 if (!read_batch) {
00519                     recv_exclude_list(f_in);
00520                     if (cvs_exclude)
00521                         add_cvs_excludes();
00522                 }
00523                 do_server_sender(f_in, f_out, argc, argv);
00524         } else {
00525                 do_server_recv(f_in, f_out, argc, argv);
00526         }
00527         exit_cleanup(0);
00528 }
00529 
00530 
00531 /*
00532  * This is called once the connection has been negotiated.  It is used
00533  * for rsyncd, remote-shell, and local connections.
00534  */
00535 int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
00536 {
00537         struct file_list *flist = NULL;
00538         int status = 0, status2 = 0;
00539         char *local_name = NULL;
00540         extern int am_sender;
00541         extern int remote_version;
00542         extern pid_t cleanup_child_pid;
00543         extern int write_batch;
00544         extern int read_batch;
00545         extern struct file_list *batch_flist;
00546 
00547         cleanup_child_pid = pid;
00548         if (read_batch)
00549             flist = batch_flist;
00550 
00551         set_nonblocking(f_in);
00552         set_nonblocking(f_out);
00553 
00554         setup_protocol(f_out,f_in);
00555 
00556         if (remote_version >= 23)
00557                 io_start_multiplex_in(f_in);
00558         
00559         if (am_sender) {
00560                 extern int cvs_exclude;
00561                 extern int delete_mode;
00562                 extern int delete_excluded;
00563                 if (cvs_exclude)
00564                         add_cvs_excludes();
00565                 if (delete_mode && !delete_excluded) 
00566                         send_exclude_list(f_out);
00567                 if (!read_batch) /*  dw -- don't write to pipe */
00568                     flist = send_file_list(f_out,argc,argv);
00569                 if (verbose > 3) 
00570                         rprintf(FINFO,"file list sent\n");
00571 
00572                 send_files(flist,f_out,f_in);
00573                 if (remote_version >= 24) {
00574                         /* final goodbye message */             
00575                         read_int(f_in);
00576                 }
00577                 if (pid != -1) {
00578                         if (verbose > 3)
00579                                 rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
00580                         io_flush();
00581                         wait_process(pid, &status);
00582                 }
00583                 report(-1);
00584                 exit_cleanup(status);
00585         }
00586 
00587         if (argc == 0) {
00588                 extern int list_only;
00589                 list_only = 1;
00590         }
00591         
00592         if (!write_batch)
00593             send_exclude_list(f_out);
00594         
00595         flist = recv_file_list(f_in);
00596         if (!flist || flist->count == 0) {
00597                 rprintf(FINFO, "client: nothing to do: "
00598                         "perhaps you need to specify some filenames or "
00599                         "the --recursive option?\n");
00600                 exit_cleanup(0);
00601         }
00602         
00603         local_name = get_local_name(flist,argv[0]);
00604         
00605         status2 = do_recv(f_in,f_out,flist,local_name);
00606         
00607         if (pid != -1) {
00608                 if (verbose > 3)
00609                         rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
00610                 io_flush();
00611                 wait_process(pid, &status);
00612         }
00613         
00614         return MAX(status, status2);
00615 }
00616 
00617 static char *find_colon(char *s)
00618 {
00619         char *p, *p2;
00620 
00621         p = strchr(s,':');
00622         if (!p) return NULL;
00623         
00624         /* now check to see if there is a / in the string before the : - if there is then
00625            discard the colon on the assumption that the : is part of a filename */
00626         p2 = strchr(s,'/');
00627         if (p2 && p2 < p) return NULL;
00628 
00629         return p;
00630 }
00631 
00632 
00633 static int copy_argv (char *argv[])
00634 {
00635         int i;
00636 
00637         for (i = 0; argv[i]; i++) {
00638                 if (!(argv[i] = strdup(argv[i]))) {
00639                         rprintf (FERROR, "out of memory at %s(%d)\n",
00640                                  __FILE__, __LINE__);
00641                         return RERR_MALLOC;
00642                 }
00643         }
00644 
00645         return 0;
00646 }
00647 
00648 
00649 /**
00650  * Start a client for either type of remote connection.  Work out
00651  * whether the arguments request a remote shell or rsyncd connection,
00652  * and call the appropriate connection function, then run_client.
00653  *
00654  * Calls either start_socket_client (for sockets) or do_cmd and
00655  * client_run (for ssh).
00656  **/
00657 static int start_client(int argc, char *argv[])
00658 {
00659         char *p;
00660         char *shell_machine = NULL;
00661         char *shell_path = NULL;
00662         char *shell_user = NULL;
00663         int ret;
00664         pid_t pid;
00665         int f_in,f_out;
00666         extern int local_server;
00667         extern int am_sender;
00668         extern char *shell_cmd;
00669         extern int rsync_port;
00670         extern int read_batch;
00671         int rc;
00672 
00673         /* Don't clobber argv[] so that ps(1) can still show the right
00674            command line. */
00675         if ((rc = copy_argv (argv)))
00676                 return rc;
00677 
00678         if (strncasecmp(URL_PREFIX, argv[0], strlen(URL_PREFIX)) == 0) {
00679                 char *host, *path;
00680 
00681                 host = argv[0] + strlen(URL_PREFIX);
00682                 p = strchr(host,'/');
00683                 if (p) {
00684                         *p = 0;
00685                         path = p+1;
00686                 } else {
00687                         path="";
00688                 }
00689                 p = strchr(host,':');
00690                 if (p) {
00691                         rsync_port = atoi(p+1);
00692                         *p = 0;
00693                 }
00694                 return start_socket_client(host, path, argc-1, argv+1);
00695         }
00696 
00697         if (!read_batch) {
00698             p = find_colon(argv[0]);
00699 
00700         if (p) {
00701                 if (p[1] == ':') { /* double colon */
00702                         *p = 0;
00703                         return start_socket_client(argv[0], p+2, argc-1, argv+1);
00704                 }
00705 
00706                 if (argc < 1) {
00707                         usage(FERROR);
00708                         exit_cleanup(RERR_SYNTAX);
00709                 }
00710 
00711                 am_sender = 0;
00712                 *p = 0;
00713                 shell_machine = argv[0];
00714                 shell_path = p+1;
00715                 argc--;
00716                 argv++;
00717         } else {
00718                 am_sender = 1;
00719 
00720                 p = find_colon(argv[argc-1]);
00721                 if (!p) {
00722                         local_server = 1;
00723                 } else if (p[1] == ':') {
00724                         *p = 0;
00725                         return start_socket_client(argv[argc-1], p+2, argc-1, argv);
00726                 }
00727 
00728                 if (argc < 2) {
00729                         usage(FERROR);
00730                         exit_cleanup(RERR_SYNTAX);
00731                 }
00732                 
00733                 if (local_server) {
00734                         shell_machine = NULL;
00735                         shell_path = argv[argc-1];
00736                 } else {
00737                         *p = 0;
00738                         shell_machine = argv[argc-1];
00739                         shell_path = p+1;
00740                 }
00741                 argc--;
00742         }
00743         } else {
00744             am_sender = 1;
00745             local_server = 1;
00746             shell_path = argv[argc-1];
00747         }
00748 
00749         if (shell_machine) {
00750                 p = strchr(shell_machine,'@');
00751                 if (p) {
00752                         *p = 0;
00753                         shell_user = shell_machine;
00754                         shell_machine = p+1;
00755                 }
00756         }
00757 
00758         if (verbose > 3) {
00759                 rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
00760                         shell_cmd?shell_cmd:"",
00761                         shell_machine?shell_machine:"",
00762                         shell_user?shell_user:"",
00763                         shell_path?shell_path:"");
00764         }
00765         
00766         if (!am_sender && argc > 1) {
00767                 usage(FERROR);
00768                 exit_cleanup(RERR_SYNTAX);
00769         }
00770 
00771         if (argc == 0 && !am_sender) {
00772                 extern int list_only;
00773                 list_only = 1;
00774         }
00775         
00776         pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
00777         
00778         ret = client_run(f_in, f_out, pid, argc, argv);
00779 
00780         fflush(stdout);
00781         fflush(stderr);
00782 
00783         return ret;
00784 }
00785 
00786 
00787 static RETSIGTYPE sigusr1_handler(int UNUSED(val)) {
00788         exit_cleanup(RERR_SIGNAL);
00789 }
00790 
00791 static RETSIGTYPE sigusr2_handler(int UNUSED(val)) {
00792         extern int log_got_error;
00793         if (log_got_error) _exit(RERR_PARTIAL);
00794         _exit(0);
00795 }
00796 
00797 static RETSIGTYPE sigchld_handler(int UNUSED(val)) {
00798 #ifdef WNOHANG
00799         while (waitpid(-1, NULL, WNOHANG) > 0) ;
00800 #endif
00801 }
00802 
00803 
00804 /**
00805  * This routine catches signals and tries to send them to gdb.
00806  *
00807  * Because it's called from inside a signal handler it ought not to
00808  * use too many library routines.
00809  *
00810  * @todo Perhaps use "screen -X" instead/as well, to help people
00811  * debugging without easy access to X.  Perhaps use an environment
00812  * variable, or just call a script?
00813  *
00814  * @todo The /proc/ magic probably only works on Linux (and
00815  * Solaris?)  Can we be more portable?
00816  **/
00817 #ifdef MAINTAINER_MODE
00818 const char *get_panic_action(void)
00819 {
00820         const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
00821 
00822         if (cmd_fmt)
00823                 return cmd_fmt;
00824         else
00825                 return "xterm -display :0 -T Panic -n Panic "
00826                         "-e gdb /proc/%d/exe %d";
00827 }
00828 
00829 
00830 /**
00831  * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
00832  *
00833  * This signal handler is only installed if we were configured with
00834  * --enable-maintainer-mode.  Perhaps it should always be on and we
00835  * should just look at the environment variable, but I'm a bit leery
00836  * of a signal sending us into a busy loop.
00837  **/
00838 static RETSIGTYPE rsync_panic_handler(int UNUSED(whatsig))
00839 {
00840         char cmd_buf[300];
00841         int ret;
00842 
00843         sprintf(cmd_buf, get_panic_action(),
00844                 getpid(), getpid());
00845 
00846         /* Unless we failed to execute gdb, we allow the process to
00847          * continue.  I'm not sure if that's right. */
00848         ret = system(cmd_buf);
00849         if (ret)
00850                 _exit(ret);
00851 }
00852 #endif
00853 
00854 
00855 int main(int argc,char *argv[])
00856 {       
00857         extern int am_root;
00858         extern int orig_umask;
00859         extern int dry_run;
00860         extern int am_daemon;
00861         extern int am_server;
00862         int ret;
00863         extern int write_batch;
00864         int orig_argc;
00865         char **orig_argv;
00866 
00867         orig_argc = argc;
00868         orig_argv = argv;
00869 
00870         signal(SIGUSR1, sigusr1_handler);
00871         signal(SIGUSR2, sigusr2_handler);
00872         signal(SIGCHLD, sigchld_handler);
00873 #ifdef MAINTAINER_MODE
00874         signal(SIGSEGV, rsync_panic_handler);
00875         signal(SIGFPE, rsync_panic_handler);
00876         signal(SIGABRT, rsync_panic_handler);
00877         signal(SIGBUS, rsync_panic_handler);
00878 #endif /* def MAINTAINER_MODE */
00879 
00880         starttime = time(NULL);
00881         am_root = (getuid() == 0);
00882 
00883         memset(&stats, 0, sizeof(stats));
00884 
00885         if (argc < 2) {
00886                 usage(FERROR);
00887                 exit_cleanup(RERR_SYNTAX);
00888         }
00889 
00890         /* we set a 0 umask so that correct file permissions can be
00891            carried across */
00892         orig_umask = (int)umask(0);
00893 
00894         if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
00895                 /* FIXME: We ought to call the same error-handling
00896                  * code here, rather than relying on getopt. */
00897                 option_error();
00898                 exit_cleanup(RERR_SYNTAX);
00899         }
00900 
00901         signal(SIGINT,SIGNAL_CAST sig_int);
00902         signal(SIGHUP,SIGNAL_CAST sig_int);
00903         signal(SIGTERM,SIGNAL_CAST sig_int);
00904 
00905         /* Ignore SIGPIPE; we consistently check error codes and will
00906          * see the EPIPE. */
00907         signal(SIGPIPE, SIG_IGN);
00908 
00909         /* Initialize push_dir here because on some old systems getcwd
00910            (implemented by forking "pwd" and reading its output) doesn't
00911            work when there are other child processes.  Also, on all systems
00912            that implement getcwd that way "pwd" can't be found after chroot. */
00913         push_dir(NULL,0);
00914 
00915         if (write_batch && !am_server) {
00916             write_batch_argvs_file(orig_argc, orig_argv);
00917         }
00918 
00919         if (am_daemon) {
00920                 return daemon_main();
00921         }
00922 
00923         if (argc < 1) {
00924                 usage(FERROR);
00925                 exit_cleanup(RERR_SYNTAX);
00926         }
00927 
00928         if (dry_run)
00929                 verbose = MAX(verbose,1);
00930 
00931 #ifndef SUPPORT_LINKS
00932         if (!am_server && preserve_links) {
00933                 rprintf(FERROR,"ERROR: symbolic links not supported\n");
00934                 exit_cleanup(RERR_UNSUPPORTED);
00935         }
00936 #endif
00937 
00938         if (am_server) {
00939                 set_nonblocking(STDIN_FILENO);
00940                 set_nonblocking(STDOUT_FILENO);
00941                 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
00942         }
00943 
00944         ret = start_client(argc, argv);
00945         if (ret == -1) 
00946                 exit_cleanup(RERR_STARTCLIENT);
00947         else
00948                 exit_cleanup(ret);
00949 
00950         exit(ret);
00951         /* NOTREACHED */
00952 }

Generated on Tue Apr 16 12:37:36 2002 for rsync by doxygen1.2.15