diff options
author | Martin Pool <mbp@samba.org> | 2002-01-25 00:56:35 +0000 |
---|---|---|
committer | Martin Pool <mbp@samba.org> | 2002-01-25 00:56:35 +0000 |
commit | 5c6e0ee27cddc273db7f9afa3b3aedf58827e749 (patch) | |
tree | 84914ba1063050c380ea769feb5ff993f0499713 | |
parent | 0d9582499579ffc8507e56d60b28f0efc44f5f65 (diff) | |
download | rsync-5c6e0ee27cddc273db7f9afa3b3aedf58827e749.tar.gz |
Signedness security patch from Sebastian Krahmer <krahmer@suse.de> --v2.4.7pre1
in some cases we were not sufficiently careful about reading integers
from the network.
-rw-r--r-- | NEWS | 29 | ||||
-rw-r--r-- | exclude.c | 74 | ||||
-rw-r--r-- | flist.c | 170 | ||||
-rw-r--r-- | io.c | 233 | ||||
-rw-r--r-- | log.c | 294 | ||||
-rw-r--r-- | receiver.c | 50 | ||||
-rw-r--r-- | rsync.h | 143 | ||||
-rw-r--r-- | util.c | 276 | ||||
-rw-r--r-- | version.h | 1 |
9 files changed, 343 insertions, 927 deletions
@@ -1,34 +1,7 @@ -rsync 2.5.2 (???) +rsync 2.4.7 (???) SECURITY FIXES: * Signedness security patch from Sebastian Krahmer <krahmer@suse.de> -- in some cases we were not sufficiently careful about reading integers from the network. - - BUG FIXES: - - * Fix possible string mangling in log files. - - * Fix for setting local address of outgoing sockets. - - * Better handling of hardlinks and devices on platforms with - 64-bit dev_t or ino_t. - - * Name resolution on machines supporting IPv6 is improved. - - ENHANCEMENTS: - - * With -v, rsync now shows the command used to initiate an ssh/rsh - connection. - - * --statistics now shows memory heap usage on platforms that - support mallinfo(). - - * "The Ted T'so school of program optimization": make progress - visible and people will think it's faster. (With --progress, - rsync will show you how many files it has seen as it builds the - file_list, giving some indication that it has not hung.) - - * Improvements to batch mode support. This is still experimental - but testing would be welcome. (Jos Backus) @@ -1,7 +1,6 @@ -/* -*- c-file-style: "linux" -*- - - Copyright (C) 1996-2001 by Andrew Tridgell <tridge@samba.org> - Copyright (C) 1996 by Paul Mackerras +/* + Copyright (C) Andrew Tridgell 1996 + Copyright (C) Paul Mackerras 1996 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,8 +20,6 @@ /* a lot of this stuff was originally derived from GNU tar, although it has now changed so much that it is hard to tell :) */ -/* include/exclude cluestick added by Martin Pool <mbp@samba.org> */ - #include "rsync.h" extern int verbose; @@ -31,7 +28,7 @@ extern int delete_mode; static struct exclude_struct **exclude_list; /* build an exclude structure given a exclude pattern */ -static struct exclude_struct *make_exclude(const char *pattern, int include) +static struct exclude_struct *make_exclude(char *pattern, int include) { struct exclude_struct *ret; @@ -87,8 +84,8 @@ static void free_exclude(struct exclude_struct *ex) free(ex); } -static int check_one_exclude(char *name, struct exclude_struct *ex, - STRUCT_STAT *st) +static int check_one_exclude(char *name,struct exclude_struct *ex, + STRUCT_STAT *st) { char *p; int match_start=0; @@ -124,62 +121,32 @@ static int check_one_exclude(char *name, struct exclude_struct *ex, } -static void report_exclude_result(char const *name, - struct exclude_struct const *ent, - STRUCT_STAT const *st) -{ - /* If a trailing slash is present to match only directories, - * then it is stripped out by make_exclude. So as a special - * case we add it back in here. */ - - if (verbose >= 2) - rprintf(FINFO, "%s %s %s because of pattern %s%s\n", - ent->include ? "including" : "excluding", - S_ISDIR(st->st_mode) ? "directory" : "file", - name, ent->pattern, - ent->directory ? "/" : ""); -} - - -/* - * Return true if file NAME is defined to be excluded by either - * LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST. - */ -int check_exclude(char *name, struct exclude_struct **local_exclude_list, +int check_exclude(char *name,struct exclude_struct **local_exclude_list, STRUCT_STAT *st) { int n; - struct exclude_struct *ent; if (name && (name[0] == '.') && !name[1]) /* never exclude '.', even if somebody does --exclude '*' */ return 0; if (exclude_list) { - for (n=0; exclude_list[n]; n++) { - ent = exclude_list[n]; - if (check_one_exclude(name, ent, st)) { - report_exclude_result(name, ent, st); - return !ent->include; - } - } + for (n=0; exclude_list[n]; n++) + if (check_one_exclude(name,exclude_list[n],st)) + return !exclude_list[n]->include; } if (local_exclude_list) { - for (n=0; local_exclude_list[n]; n++) { - ent = local_exclude_list[n]; - if (check_one_exclude(name, ent, st)) { - report_exclude_result(name, ent, st); - return !ent->include; - } - } + for (n=0; local_exclude_list[n]; n++) + if (check_one_exclude(name,local_exclude_list[n],st)) + return !local_exclude_list[n]->include; } return 0; } -void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include) +void add_exclude_list(char *pattern,struct exclude_struct ***list, int include) { int len=0; if (list && *list) @@ -207,12 +174,12 @@ void add_exclude_list(const char *pattern, struct exclude_struct ***list, int in (*list)[len+1] = NULL; } -void add_exclude(const char *pattern, int include) +void add_exclude(char *pattern, int include) { add_exclude_list(pattern,&exclude_list, include); } -struct exclude_struct **make_exclude_list(const char *fname, +struct exclude_struct **make_exclude_list(char *fname, struct exclude_struct **list1, int fatal, int include) { @@ -221,10 +188,7 @@ struct exclude_struct **make_exclude_list(const char *fname, char line[MAXPATHLEN]; if (!f) { if (fatal) { - rsyserr(FERROR, errno, - "failed to open %s file %s", - include ? "include" : "exclude", - fname); + rprintf(FERROR,"%s : %s\n",fname,strerror(errno)); exit_cleanup(RERR_FILEIO); } return list; @@ -246,7 +210,7 @@ struct exclude_struct **make_exclude_list(const char *fname, } -void add_exclude_file(const char *fname, int fatal, int include) +void add_exclude_file(char *fname,int fatal,int include) { if (!fname || !*fname) return; @@ -399,7 +363,7 @@ void add_cvs_excludes(void) add_exclude(cvs_ignore_list[i], 0); if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) { - snprintf(fname,sizeof(fname), "%s/.cvsignore",p); + slprintf(fname,sizeof(fname), "%s/.cvsignore",p); add_exclude_file(fname,0,0); } @@ -1,7 +1,6 @@ /* Copyright (C) Andrew Tridgell 1996 Copyright (C) Paul Mackerras 1996 - Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,14 +17,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/** @file flist.c - * Generate and receive file lists - * - * @todo Get rid of the string_area optimization. Efficiently - * allocating blocks is the responsibility of the system's malloc - * library, not of rsync. - * - **/ +/* generate and receive file lists */ #include "rsync.h" @@ -55,9 +47,6 @@ extern int remote_version; extern int io_error; extern int sanitize_paths; -extern int read_batch; -extern int write_batch; - static char topsrcname[MAXPATHLEN]; static struct exclude_struct **local_exclude_list; @@ -66,35 +55,6 @@ static struct file_struct null_file; static void clean_flist(struct file_list *flist, int strip_root); - -static int show_build_progress_p(void) -{ - extern int do_progress; - - return do_progress && verbose && recurse && !am_server; -} - -/** - * True if we're local, etc, and should emit progress emssages. - **/ -static void emit_build_progress(const struct file_list *flist) -{ - rprintf(FINFO, - " %d files...\r", - flist->count); -} - - -static void finish_build_progress(const struct file_list *flist) -{ - if (verbose && recurse && !am_server) { - /* This overwrites the progress line, if any. */ - rprintf(FINFO, RSYNC_NAME ": %d files to consider.\n", - flist->count); - } -} - - static struct string_area *string_area_new(int size) { struct string_area *a; @@ -148,14 +108,24 @@ static char *string_area_strdup(struct string_area **ap, const char *src) static void list_file_entry(struct file_struct *f) { - char perms[11]; + char perms[11] = "----------"; + char *perm_map = "rwxrwxrwx"; + int i; if (!f->basename) /* this can happen if duplicate names were removed */ return; - permstring(perms, f->mode); - + for (i=0;i<9;i++) { + if (f->mode & (1<<i)) perms[9-i] = perm_map[8-i]; + } + if (S_ISLNK(f->mode)) perms[0] = 'l'; + if (S_ISDIR(f->mode)) perms[0] = 'd'; + if (S_ISBLK(f->mode)) perms[0] = 'b'; + if (S_ISCHR(f->mode)) perms[0] = 'c'; + if (S_ISSOCK(f->mode)) perms[0] = 's'; + if (S_ISFIFO(f->mode)) perms[0] = 'p'; + if (preserve_links && S_ISLNK(f->mode)) { rprintf(FINFO,"%s %11.0f %s %s -> %s\n", perms, @@ -180,7 +150,7 @@ int readlink_stat(const char *Path, STRUCT_STAT *Buffer, char *Linkbuf) } if (S_ISLNK(Buffer->st_mode)) { int l; - if ((l = readlink((char *) Path, Linkbuf, MAXPATHLEN-1))== -1) { + if ((l = readlink(Path,Linkbuf,MAXPATHLEN-1)) == -1) { return -1; } Linkbuf[l] = 0; @@ -212,18 +182,14 @@ int link_stat(const char *Path, STRUCT_STAT *Buffer) This function is used to check if a file should be included/excluded from the list of files based on its name and type etc */ -static int check_exclude_file(int f,char *fname,STRUCT_STAT *st) +static int match_file_name(char *fname,STRUCT_STAT *st) { - extern int delete_excluded; - - /* f is set to -1 when calculating deletion file list */ - if ((f == -1) && delete_excluded) { - return 0; - } - if (check_exclude(fname,local_exclude_list,st)) { - return 1; - } - return 0; + if (check_exclude(fname,local_exclude_list,st)) { + if (verbose > 2) + rprintf(FINFO,"excluding file %s\n",fname); + return 0; + } + return 1; } /* used by the one_file_system code */ @@ -239,7 +205,7 @@ static void set_filesystem(char *fname) static int to_wire_mode(mode_t mode) { - if (S_ISLNK(mode) && (_S_IFLNK != 0120000)) { + if (S_ISLNK(mode) && (S_IFLNK != 0120000)) { return (mode & ~(_S_IFMT)) | 0120000; } return (int)mode; @@ -247,8 +213,8 @@ static int to_wire_mode(mode_t mode) static mode_t from_wire_mode(int mode) { - if ((mode & (_S_IFMT)) == 0120000 && (_S_IFLNK != 0120000)) { - return (mode & ~(_S_IFMT)) | _S_IFLNK; + if ((mode & (_S_IFMT)) == 0120000 && (S_IFLNK != 0120000)) { + return (mode & ~(_S_IFMT)) | S_IFLNK; } return (mode_t)mode; } @@ -333,15 +299,8 @@ static void send_file_entry(struct file_struct *file,int f,unsigned base_flags) #if SUPPORT_HARD_LINKS if (preserve_hard_links && S_ISREG(file->mode)) { - if (remote_version < 26) { - /* 32-bit dev_t and ino_t */ - write_int(f,(int)file->dev); - write_int(f,(int)file->inode); - } else { - /* 64-bit dev_t and ino_t */ - write_longint(f, file->dev); - write_longint(f, file->inode); - } + write_int(f,(int)file->dev); + write_int(f,(int)file->inode); } #endif @@ -456,13 +415,8 @@ static void receive_file_entry(struct file_struct **fptr, #if SUPPORT_HARD_LINKS if (preserve_hard_links && S_ISREG(file->mode)) { - if (remote_version < 26) { - file->dev = read_int(f); - file->inode = read_int(f); - } else { - file->dev = read_longint(f); - file->inode = read_longint(f); - } + file->dev = read_int(f); + file->inode = read_int(f); } #endif @@ -516,8 +470,7 @@ static int skip_filesystem(char *fname, STRUCT_STAT *st) } #define STRDUP(ap, p) (ap ? string_area_strdup(ap, p) : strdup(p)) -/* IRIX cc cares that the operands to the ternary have the same type. */ -#define MALLOC(ap, i) (ap ? (void*) string_area_malloc(ap, i) : malloc(i)) +#define MALLOC(ap, i) (ap ? string_area_malloc(ap, i) : malloc(i)) /* create a file_struct for a named file */ struct file_struct *make_file(int f, char *fname, struct string_area **ap, @@ -529,6 +482,7 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap, char *p; char cleaned_name[MAXPATHLEN]; char linkbuf[MAXPATHLEN]; + extern int delete_excluded; extern int module_id; strlcpy(cleaned_name, fname, MAXPATHLEN); @@ -542,18 +496,9 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap, memset(sum,0,SUM_LENGTH); if (readlink_stat(fname,&st,linkbuf) != 0) { - int save_errno = errno; - if ((errno == ENOENT) && copy_links && !noexcludes) { - /* symlink pointing nowhere, see if excluded */ - memset((char *)&st, 0, sizeof(st)); - if (check_exclude_file(f,fname,&st)) { - /* file is excluded anyway, ignore silently */ - return NULL; - } - } io_error = 1; rprintf(FERROR,"readlink %s: %s\n", - fname,strerror(save_errno)); + fname,strerror(errno)); return NULL; } @@ -570,7 +515,8 @@ struct file_struct *make_file(int f, char *fname, struct string_area **ap, return NULL; } - if (check_exclude_file(f,fname,&st)) + /* f is set to -1 when calculating deletion file list */ + if (((f != -1) || !delete_excluded) && !match_file_name(fname,&st)) return NULL; @@ -659,10 +605,7 @@ void send_file_name(int f,struct file_list *flist,char *fname, file = make_file(f,fname, &flist->string_area, 0); - if (!file) return; - - if (show_build_progress_p() & !(flist->count % 100)) - emit_build_progress(flist); + if (!file) return; if (flist->count >= flist->malloced) { if (flist->malloced < 1000) @@ -676,9 +619,6 @@ void send_file_name(int f,struct file_list *flist,char *fname, out_of_memory("send_file_name"); } - if (write_batch) /* dw */ - file->flags = FLAG_DELETE; - if (strcmp(file->basename,"")) { flist->files[flist->count++] = file; send_file_entry(file,f,base_flags); @@ -753,11 +693,6 @@ static void send_directory(int f,struct file_list *flist,char *dir) } -/* - * - * I *think* f==-1 means that the list should just be built in memory - * and not transmitted. But who can tell? -- mbp - */ struct file_list *send_file_list(int f,int argc,char *argv[]) { int i,l; @@ -768,9 +703,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) int64 start_write; if (verbose && recurse && !am_server && f != -1) { - rprintf(FINFO, RSYNC_NAME ": building file list...\n"); - if (verbose > 1) - rprintf(FINFO, "\n"); + rprintf(FINFO,"building file list ... "); rflush(FINFO); } @@ -891,7 +824,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) send_file_entry(NULL,f,0); } - finish_build_progress(flist); + if (verbose && recurse && !am_server && f != -1) + rprintf(FINFO,"done\n"); clean_flist(flist, 0); @@ -911,8 +845,6 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) io_end_buffering(f); stats.flist_size = stats.total_written - start_write; stats.num_files = flist->count; - if (write_batch) /* dw */ - write_batch_flist_info(flist->count, flist->files); } if (verbose > 2) @@ -990,7 +922,7 @@ struct file_list *recv_file_list(int f) } /* if protocol version is >= 17 then recv the io_error flag */ - if (f != -1 && remote_version >= 17 && !read_batch) { /* dw-added readbatch */ + if (f != -1 && remote_version >= 17) { extern int module_id; extern int ignore_errors; if (lp_ignore_errors(module_id) || ignore_errors) { @@ -1022,10 +954,6 @@ oom: } -/* - * XXX: This is currently the hottest function while building the file - * list, because building f_name()s every time is expensive. - **/ int file_compare(struct file_struct **f1,struct file_struct **f2) { if (!(*f1)->basename && !(*f2)->basename) return 0; @@ -1148,10 +1076,6 @@ static void clean_flist(struct file_list *flist, int strip_root) } } - /* FIXME: There is a bug here when filenames are repeated more - * than once, because we don't handle freed files when doing - * the comparison. */ - if (strip_root) { /* we need to strip off the root directory in the case of relative paths, but this must be done _after_ @@ -1176,10 +1100,10 @@ static void clean_flist(struct file_list *flist, int strip_root) for (i=0;i<flist->count;i++) { rprintf(FINFO,"[%d] i=%d %s %s mode=0%o len=%.0f\n", - (int) getpid(), i, + getpid(), i, NS(flist->files[i]->dirname), NS(flist->files[i]->basename), - (int) flist->files[i]->mode, + flist->files[i]->mode, (double)flist->files[i]->length); } } @@ -1187,10 +1111,6 @@ static void clean_flist(struct file_list *flist, int strip_root) /* * return the full filename of a flist entry - * - * This function is too expensive at the moment, because it copies - * strings when often we only want to compare them. In any case, - * using strlcat is silly because it will walk the string repeatedly. */ char *f_name(struct file_struct *f) { @@ -1203,11 +1123,9 @@ char *f_name(struct file_struct *f) n = (n+1)%10; if (f->dirname) { - int off; - - off = strlcpy(p, f->dirname, MAXPATHLEN); - off += strlcpy(p+off, "/", MAXPATHLEN-off); - off += strlcpy(p+off, f->basename, MAXPATHLEN-off); + strlcpy(p, f->dirname, MAXPATHLEN); + strlcat(p, "/", MAXPATHLEN); + strlcat(p, f->basename, MAXPATHLEN); } else { strlcpy(p, f->basename, MAXPATHLEN); } @@ -1,8 +1,6 @@ -/* -*- c-file-style: "linux" -*- - - Copyright (C) 1996-2001 by Andrew Tridgell +/* + Copyright (C) Andrew Tridgell 1996 Copyright (C) Paul Mackerras 1996 - Copyright (C) 2001 by Martin Pool <mbp@samba.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,24 +27,18 @@ /* if no timeout is specified then use a 60 second select timeout */ #define SELECT_TIMEOUT 60 +extern int bwlimit; + static int io_multiplexing_out; static int io_multiplexing_in; static int multiplex_in_fd; static int multiplex_out_fd; static time_t last_io; -static int no_flush; - -extern int bwlimit; +static int eof_error=1; extern int verbose; extern int io_timeout; extern struct stats stats; - -/** Ignore EOF errors while reading a module listing if the remote - version is 24 or less. */ -int kludge_around_eof = False; - - static int io_error_fd = -1; static void read_loop(int fd, char *buf, size_t len); @@ -55,8 +47,6 @@ static void check_timeout(void) { extern int am_server, am_daemon; time_t t; - - err_list_push(); if (!io_timeout) return; @@ -69,7 +59,7 @@ static void check_timeout(void) if (last_io && io_timeout && (t-last_io) >= io_timeout) { if (!am_server && !am_daemon) { - rprintf(FERROR,"io timeout after %d seconds - exiting\n", + rprintf(FERROR,"io timeout after %d second - exiting\n", (int)(t-last_io)); } exit_cleanup(RERR_TIMEOUT); @@ -86,12 +76,10 @@ void io_set_error_fd(int fd) static void read_error_fd(void) { char buf[200]; - size_t n; + int n; int fd = io_error_fd; int tag, len; - /* io_error_fd is temporarily disabled -- is this meant to - * prevent indefinite recursion? */ io_error_fd = -1; read_loop(fd, buf, 4); @@ -103,8 +91,7 @@ static void read_error_fd(void) while (len) { n = len; - if (n > (sizeof(buf)-1)) - n = sizeof(buf)-1; + if (n > (sizeof(buf)-1)) n = sizeof(buf)-1; read_loop(fd, buf, n); rwrite((enum logcode)tag, buf, n); len -= n; @@ -114,68 +101,21 @@ static void read_error_fd(void) } -static void whine_about_eof (void) -{ - /** - It's almost always an error to get an EOF when we're trying - to read from the network, because the protocol is - self-terminating. - - However, there is one unfortunate cases where it is not, - which is rsync <2.4.6 sending a list of modules on a - server, since the list is terminated by closing the socket. - So, for the section of the program where that is a problem - (start_socket_client), kludge_around_eof is True and we - just exit. - */ - - if (kludge_around_eof) - exit_cleanup (0); - else { - rprintf (FERROR, - "%s: connection unexpectedly closed " - "(%.0f bytes read so far)\n", - RSYNC_NAME, (double)stats.total_read); - - exit_cleanup (RERR_STREAMIO); - } -} - - -static void die_from_readerr (int err) -{ - /* this prevents us trying to write errors on a dead socket */ - io_multiplexing_close(); - - rprintf(FERROR, "%s: read error: %s\n", - RSYNC_NAME, strerror (err)); - exit_cleanup(RERR_STREAMIO); -} - +static int no_flush; -/*! - * Read from a socket with IO timeout. return the number of bytes - * read. If no bytes can be read then exit, never return a number <= 0. - * - * TODO: If the remote shell connection fails, then current versions - * actually report an "unexpected EOF" error here. Since it's a - * fairly common mistake to try to use rsh when ssh is required, we - * should trap that: if we fail to read any data at all, we should - * give a better explanation. We can tell whether the connection has - * started by looking e.g. at whether the remote version is known yet. - */ -static int read_timeout (int fd, char *buf, size_t len) +/* read from a socket with IO timeout. return the number of + bytes read. If no bytes can be read then exit, never return + a number <= 0 */ +static int read_timeout(int fd, char *buf, size_t len) { int n, ret=0; io_flush(); while (ret == 0) { - /* until we manage to read *something* */ fd_set fds; struct timeval tv; int fd_count = fd+1; - int count; FD_ZERO(&fds); FD_SET(fd, &fds); @@ -189,16 +129,11 @@ static int read_timeout (int fd, char *buf, size_t len) errno = 0; - count = select(fd_count, &fds, NULL, NULL, &tv); - - if (count == 0) { - check_timeout(); - } - - if (count <= 0) { + if (select(fd_count, &fds, NULL, NULL, &tv) < 1) { if (errno == EBADF) { exit_cleanup(RERR_SOCKETIO); } + check_timeout(); continue; } @@ -217,27 +152,38 @@ static int read_timeout (int fd, char *buf, size_t len) if (io_timeout) last_io = time(NULL); continue; - } else if (n == 0) { - whine_about_eof (); - return -1; /* doesn't return */ - } else if (n == -1) { - if (errno == EINTR || errno == EWOULDBLOCK || - errno == EAGAIN) - continue; - else - die_from_readerr (errno); } - } - return ret; -} + if (n == -1 && errno == EINTR) { + continue; + } + + if (n == -1 && + (errno == EWOULDBLOCK || errno == EAGAIN)) { + continue; + } + if (n == 0) { + if (eof_error) { + rprintf(FERROR,"unexpected EOF in read_timeout\n"); + } + exit_cleanup(RERR_STREAMIO); + } + /* this prevents us trying to write errors on a dead socket */ + io_multiplexing_close(); + + rprintf(FERROR,"read error: %s\n", strerror(errno)); + exit_cleanup(RERR_STREAMIO); + } -/*! Continue trying to read len bytes - don't return until len has - been read. */ -static void read_loop (int fd, char *buf, size_t len) + return ret; +} + +/* continue trying to read len bytes - don't return until len + has been read */ +static void read_loop(int fd, char *buf, size_t len) { while (len) { int n = read_timeout(fd, buf, len); @@ -247,20 +193,16 @@ static void read_loop (int fd, char *buf, size_t len) } } - -/** - * Read from the file descriptor handling multiplexing - return number - * of bytes read. - * - * Never returns <= 0. - */ +/* read from the file descriptor handling multiplexing - + return number of bytes read + never return <= 0 */ static int read_unbuffered(int fd, char *buf, size_t len) { - static size_t remaining; - int tag, ret = 0; + static int remaining; + int tag, ret=0; char line[1024]; - if (!io_multiplexing_in || fd != multiplex_in_fd) + if (!io_multiplexing_in || fd != multiplex_in_fd) return read_timeout(fd, buf, len); while (ret == 0) { @@ -278,18 +220,17 @@ static int read_unbuffered(int fd, char *buf, size_t len) remaining = tag & 0xFFFFFF; tag = tag >> 24; - if (tag == MPLEX_BASE) - continue; + if (tag == MPLEX_BASE) continue; tag -= MPLEX_BASE; if (tag != FERROR && tag != FINFO) { - rprintf(FERROR, "unexpected tag %d\n", tag); + rprintf(FERROR,"unexpected tag %d\n", tag); exit_cleanup(RERR_STREAMIO); } - if (remaining > sizeof(line) - 1) { - rprintf(FERROR, "multiplexing overflow %d\n\n", + if (remaining > sizeof(line)-1) { + rprintf(FERROR,"multiplexing overflow %d\n\n", remaining); exit_cleanup(RERR_STREAMIO); } @@ -297,7 +238,7 @@ static int read_unbuffered(int fd, char *buf, size_t len) read_loop(fd, line, remaining); line[remaining] = 0; - rprintf((enum logcode) tag, "%s", line); + rprintf((enum logcode)tag,"%s", line); remaining = 0; } @@ -305,18 +246,17 @@ static int read_unbuffered(int fd, char *buf, size_t len) } - /* do a buffered read from fd. don't return until all N bytes have been read. If all N can't be read then exit with an error */ -static void readfd (int fd, char *buffer, size_t N) +static void readfd(int fd,char *buffer,size_t N) { int ret; - size_t total=0; + int total=0; while (total < N) { io_flush(); - ret = read_unbuffered (fd, buffer + total, N-total); + ret = read_unbuffered(fd,buffer + total,N-total); total += ret; } @@ -366,27 +306,25 @@ void read_buf(int f,char *buf,size_t len) void read_sbuf(int f,char *buf,size_t len) { - read_buf (f,buf,len); + read_buf(f,buf,len); buf[len] = 0; } unsigned char read_byte(int f) { unsigned char c; - read_buf (f, (char *)&c, 1); + read_buf(f,(char *)&c,1); return c; } /* write len bytes to fd */ static void writefd_unbuffered(int fd,char *buf,size_t len) { - size_t total = 0; + int total = 0; fd_set w_fds, r_fds; int fd_count, count; struct timeval tv; - err_list_push(); - no_flush++; while (total < len) { @@ -411,14 +349,11 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) &w_fds,NULL, &tv); - if (count == 0) { - check_timeout(); - } - if (count <= 0) { if (errno == EBADF) { exit_cleanup(RERR_SOCKETIO); } + check_timeout(); continue; } @@ -427,8 +362,8 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) } if (FD_ISSET(fd, &w_fds)) { - int ret; - size_t n = len-total; + int ret, n = len-total; + ret = write(fd,buf+total,n); if (ret == -1 && errno == EINTR) { @@ -442,10 +377,7 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) } if (ret <= 0) { - rprintf(FERROR, - "error writing %d unbuffered bytes" - " - exiting: %s\n", len, - strerror(errno)); + rprintf(FERROR,"erroring writing %d bytes - exiting\n", len); exit_cleanup(RERR_STREAMIO); } @@ -490,7 +422,7 @@ void io_start_buffering(int fd) static void mplex_write(int fd, enum logcode code, char *buf, size_t len) { char buffer[4096]; - size_t n = len; + int n = len; SIVAL(buffer, 0, ((MPLEX_BASE + (int)code)<<24) + len); @@ -513,9 +445,6 @@ static void mplex_write(int fd, enum logcode code, char *buf, size_t len) void io_flush(void) { int fd = multiplex_out_fd; - - err_list_push(); - if (!io_buffer_count || no_flush) return; if (io_multiplexing_out) { @@ -526,8 +455,6 @@ void io_flush(void) io_buffer_count = 0; } - -/* XXX: fd is ignored, which seems a little strange. */ void io_end_buffering(int fd) { io_flush(); @@ -537,12 +464,21 @@ void io_end_buffering(int fd) } } +/* some OSes have a bug where an exit causes the pending writes on + a socket to be flushed. Do an explicit shutdown to try to prevent this */ +void io_shutdown(void) +{ + if (multiplex_out_fd != -1) close(multiplex_out_fd); + if (io_error_fd != -1) close(io_error_fd); + multiplex_out_fd = -1; + io_error_fd = -1; +} + + static void writefd(int fd,char *buf,size_t len) { stats.total_written += len; - err_list_push(); - if (!io_buffer || fd != multiplex_out_fd) { writefd_unbuffered(fd, buf, len); return; @@ -569,11 +505,6 @@ void write_int(int f,int32 x) writefd(f,b,4); } - -/* - * Note: int64 may actually be a 32-bit type if ./configure couldn't find any - * 64-bit types on this platform. - */ void write_longint(int f, int64 x) { extern int remote_version; @@ -608,10 +539,10 @@ void write_byte(int f,unsigned char c) write_buf(f,(char *)&c,1); } - - int read_line(int f, char *buf, size_t maxlen) { + eof_error = 0; + while (maxlen) { buf[0] = 0; read_buf(f, buf, 1); @@ -630,6 +561,8 @@ int read_line(int f, char *buf, size_t maxlen) return 0; } + eof_error = 1; + return 1; } @@ -641,7 +574,7 @@ void io_printf(int fd, const char *format, ...) int len; va_start(ap, format); - len = vsnprintf(buf, sizeof(buf), format, ap); + len = vslprintf(buf, sizeof(buf), format, ap); va_end(ap); if (len < 0) exit_cleanup(RERR_STREAMIO); @@ -678,6 +611,14 @@ int io_multiplex_write(enum logcode code, char *buf, size_t len) return 1; } +/* write a message to the special error fd */ +int io_error_write(int f, enum logcode code, char *buf, size_t len) +{ + if (f == -1) return 0; + mplex_write(f, code, buf, len); + return 1; +} + /* stop output multiplexing */ void io_multiplexing_close(void) { @@ -1,7 +1,5 @@ -/* -*- c-file-style: "linux"; -*- - - Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org> - Copyright (C) 2000-2001 by Martin Pool <mbp@samba.org> +/* + Copyright (C) Andrew Tridgell 1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,121 +17,18 @@ */ /* - Logging and utility functions. - tridge, May 1998 + logging and utility functions - Mapping to human-readable messages added by Martin Pool - <mbp@samba.org>, Oct 2000. + tridge, May 1998 */ #include "rsync.h" -static char *logfname; static FILE *logfile; static int log_error_fd = -1; -int log_got_error=0; - -struct { - int code; - char const *name; -} const rerr_names[] = { - { RERR_SYNTAX , "syntax or usage error" }, - { RERR_PROTOCOL , "protocol incompatibility" }, - { RERR_FILESELECT , "errors selecting input/output files, dirs" }, - { RERR_UNSUPPORTED, "requested action not supported" }, - { RERR_SOCKETIO , "error in socket IO" }, - { RERR_FILEIO , "error in file IO" }, - { RERR_STREAMIO , "error in rsync protocol data stream" }, - { RERR_MESSAGEIO , "errors with program diagnostics" }, - { RERR_IPC , "error in IPC code" }, - { RERR_SIGNAL , "received SIGUSR1 or SIGINT" }, - { RERR_WAITCHILD , "some error returned by waitpid()" }, - { RERR_MALLOC , "error allocating core memory buffers" }, - { RERR_PARTIAL , "partial transfer" }, - { RERR_TIMEOUT , "timeout in data send/receive" }, - { RERR_CMD_FAILED , "remote shell failed" }, - { RERR_CMD_KILLED , "remote shell killed" }, - { RERR_CMD_RUN, "remote command could not be run" }, - { RERR_CMD_NOTFOUND, "remote command not found" }, - { 0, NULL } -}; - - - -/* - * Map from rsync error code to name, or return NULL. - */ -static char const *rerr_name(int code) -{ - int i; - for (i = 0; rerr_names[i].name; i++) { - if (rerr_names[i].code == code) - return rerr_names[i].name; - } - return NULL; -} - -struct err_list { - struct err_list *next; - char *buf; - int len; - int written; /* how many bytes we have written so far */ -}; - -static struct err_list *err_list_head; -static struct err_list *err_list_tail; - -/* add an error message to the pending error list */ -static void err_list_add(int code, char *buf, int len) -{ - struct err_list *el; - el = (struct err_list *)malloc(sizeof(*el)); - if (!el) exit_cleanup(RERR_MALLOC); - el->next = NULL; - el->buf = malloc(len+4); - if (!el->buf) exit_cleanup(RERR_MALLOC); - memcpy(el->buf+4, buf, len); - SIVAL(el->buf, 0, ((code+MPLEX_BASE)<<24) | len); - el->len = len+4; - el->written = 0; - if (err_list_tail) { - err_list_tail->next = el; - } else { - err_list_head = el; - } - err_list_tail = el; -} - - -/* try to push errors off the error list onto the wire */ -void err_list_push(void) -{ - if (log_error_fd == -1) return; - - while (err_list_head) { - struct err_list *el = err_list_head; - int n = write(log_error_fd, el->buf+el->written, el->len - el->written); - /* don't check for an error if the best way of handling the error is - to ignore it */ - if (n == -1) break; - if (n > 0) { - el->written += n; - } - if (el->written == el->len) { - free(el->buf); - err_list_head = el->next; - if (!err_list_head) err_list_tail = NULL; - free(el); - } - } -} - - static void logit(int priority, char *buf) { - if (logfname) { - if (!logfile) - log_open(); + if (logfile) { fprintf(logfile,"%s [%d] %s", timestring(time(NULL)), (int)getpid(), buf); fflush(logfile); @@ -142,11 +37,12 @@ static void logit(int priority, char *buf) } } -void log_init(void) +void log_open(void) { static int initialised; int options = LOG_PID; time_t t; + char *logf; if (initialised) return; initialised = 1; @@ -158,13 +54,13 @@ void log_init(void) localtime(&t); /* optionally use a log file instead of syslog */ - logfname = lp_log_file(); - if (logfname) { - if (*logfname) { - log_open(); - return; - } - logfname = NULL; + logf = lp_log_file(); + if (logf && *logf) { + extern int orig_umask; + int old_umask = umask(022 | orig_umask); + logfile = fopen(logf, "a"); + umask(old_umask); + return; } #ifdef LOG_NDELAY @@ -182,30 +78,11 @@ void log_init(void) #endif } -void log_open() -{ - if (logfname && !logfile) { - extern int orig_umask; - int old_umask = umask(022 | orig_umask); - logfile = fopen(logfname, "a"); - umask(old_umask); - } -} - -void log_close() -{ - if (logfile) { - fclose(logfile); - logfile = NULL; - } -} - /* setup the error file descriptor - used when we are a server that is receiving files */ void set_error_fd(int fd) { log_error_fd = fd; - set_nonblocking(log_error_fd); } /* this is the underlying (unformatted) rsync debugging function. Call @@ -229,14 +106,12 @@ void rwrite(enum logcode code, char *buf, int len) return; } - /* first try to pass it off to our sibling */ - if (am_server && log_error_fd != -1) { - err_list_add(code, buf, len); - err_list_push(); + /* first try to pass it off the our sibling */ + if (am_server && io_error_write(log_error_fd, code, buf, len)) { return; } - /* if that fails, try to pass it to the other end */ + /* then try to pass it to the other end */ if (am_server && io_multiplex_write(code, buf, len)) { return; } @@ -250,7 +125,7 @@ void rwrite(enum logcode code, char *buf, int len) depth++; - log_init(); + log_open(); logit(priority, buf); depth--; @@ -258,7 +133,6 @@ void rwrite(enum logcode code, char *buf, int len) } if (code == FERROR) { - log_got_error = 1; f = stderr; } @@ -277,90 +151,22 @@ void rwrite(enum logcode code, char *buf, int len) } -/* This is the rsync debugging function. Call it with FINFO, FERROR or - * FLOG. */ -void rprintf(enum logcode code, const char *format, ...) -{ - va_list ap; - char buf[1024]; - int len; - - va_start(ap, format); - /* Note: might return -1 */ - len = vsnprintf(buf, sizeof(buf), format, ap); - va_end(ap); - - /* Deal with buffer overruns. Instead of panicking, just - * truncate the resulting string. Note that some vsnprintf()s - * return -1 on truncation, e.g., glibc 2.0.6 and earlier. */ - if ((size_t) len > sizeof(buf)-1 || len < 0) { - const char ellipsis[] = "[...]"; - - /* Reset length, and zero-terminate the end of our buffer */ - len = sizeof(buf)-1; - buf[len] = '\0'; - - /* Copy the ellipsis to the end of the string, but give - * us one extra character: - * - * v--- null byte at buf[sizeof(buf)-1] - * abcdefghij0 - * -> abcd[...]00 <-- now two null bytes at end - * - * If the input format string has a trailing newline, - * we copy it into that extra null; if it doesn't, well, - * all we lose is one byte. */ - strncpy(buf+len-sizeof(ellipsis), ellipsis, sizeof(ellipsis)); - if (format[strlen(format)-1] == '\n') { - buf[len-1] = '\n'; - } - } - - rwrite(code, buf, len); -} - - -/* This is like rprintf, but it also tries to print some - * representation of the error code. Normally errcode = errno. - * - * Unlike rprintf, this always adds a newline and there should not be - * one in the format string. - * - * Note that since strerror might involve dynamically loading a - * message catalog we need to call it once before chroot-ing. */ -void rsyserr(enum logcode code, int errcode, const char *format, ...) +/* this is the rsync debugging function. Call it with FINFO, FERROR or FLOG */ + void rprintf(enum logcode code, const char *format, ...) { va_list ap; char buf[1024]; int len; - size_t sys_len; - char *sysmsg; va_start(ap, format); - /* Note: might return <0 */ - len = vsnprintf(buf, sizeof(buf), format, ap); + len = vslprintf(buf, sizeof(buf), format, ap); va_end(ap); - if ((size_t) len > sizeof(buf)-1) - exit_cleanup(RERR_MESSAGEIO); - - sysmsg = strerror(errcode); - sys_len = strlen(sysmsg); - if ((size_t) len + 3 + sys_len > sizeof(buf) - 1) - exit_cleanup(RERR_MESSAGEIO); - - strcpy(buf + len, ": "); - len += 2; - strcpy(buf + len, sysmsg); - len += sys_len; - strcpy(buf + len, "\n"); - len++; + if (len > sizeof(buf)-1) exit_cleanup(RERR_MESSAGEIO); rwrite(code, buf, len); } - - void rflush(enum logcode code) { FILE *f = NULL; @@ -403,18 +209,14 @@ static void log_formatted(enum logcode code, char buf[1024]; char buf2[1024]; char *p, *s, *n; - size_t l; + int l; extern struct stats stats; extern int am_sender; extern int am_daemon; int64 b; - /* We expand % codes one by one in place in buf. We don't - * copy in the terminating nul of the inserted strings, but - * rather keep going until we reach the nul of the format. - * Just to make sure we don't clobber that nul and therefore - * accidentally keep going, we zero the buffer now. */ - memset(buf, 0, sizeof buf); + memset(buf,0,sizeof(buf)); + strlcpy(buf, format, sizeof(buf)); for (s=&buf[0]; @@ -426,18 +228,18 @@ static void log_formatted(enum logcode code, case 'h': if (am_daemon) n = client_name(0); break; case 'a': if (am_daemon) n = client_addr(0); break; case 'l': - snprintf(buf2,sizeof(buf2),"%.0f", + slprintf(buf2,sizeof(buf2),"%.0f", (double)file->length); n = buf2; break; case 'p': - snprintf(buf2,sizeof(buf2),"%d", + slprintf(buf2,sizeof(buf2),"%d", (int)getpid()); n = buf2; break; case 'o': n = op; break; case 'f': - snprintf(buf2, sizeof(buf2), "%s/%s", + slprintf(buf2, sizeof(buf2), "%s/%s", file->basedir?file->basedir:"", f_name(file)); clean_fname(buf2); @@ -456,7 +258,7 @@ static void log_formatted(enum logcode code, b = stats.total_read - initial_stats->total_read; } - snprintf(buf2,sizeof(buf2),"%.0f", (double)b); + slprintf(buf2,sizeof(buf2),"%.0f", (double)b); n = buf2; break; case 'c': @@ -467,35 +269,26 @@ static void log_formatted(enum logcode code, b = stats.total_read - initial_stats->total_read; } - snprintf(buf2,sizeof(buf2),"%.0f", (double)b); + slprintf(buf2,sizeof(buf2),"%.0f", (double)b); n = buf2; break; } - /* n is the string to be inserted in place of this % - * code; l is its length not including the trailing - * NUL */ - if (!n) - continue; + if (!n) continue; l = strlen(n); - if (l + ((int)(s - &buf[0])) >= sizeof(buf)) { + if (l + ((int)(s - &buf[0])) > sizeof(buf)) { rprintf(FERROR,"buffer overflow expanding %%%c - exiting\n", p[0]); exit_cleanup(RERR_MESSAGEIO); } - /* Shuffle the rest of the string along to make space for n */ if (l != 2) { memmove(s+(l-1), s+1, strlen(s+1)+1); } - - /* Copy in n but NOT its nul, because the format sting - * probably continues after this. */ memcpy(p, n, l); - /* Skip over inserted string; continue looking */ s = p+l; } @@ -530,15 +323,7 @@ void log_recv(struct file_struct *file, struct stats *initial_stats) } } - - - -/* - * Called when the transfer is interrupted for some reason. - * - * Code is one of the RERR_* codes from errcode.h, or terminating - * successfully. - */ +/* called when the transfer is interrupted for some reason */ void log_exit(int code, const char *file, int line) { if (code == 0) { @@ -548,20 +333,11 @@ void log_exit(int code, const char *file, int line) (double)stats.total_read, (double)stats.total_size); } else { - const char *name; - - name = rerr_name(code); - if (!name) - name = "unexplained error"; - - rprintf(FERROR,"rsync error: %s (code %d) at %s(%d)\n", - name, code, file, line); + rprintf(FLOG,"transfer interrupted (code %d) at %s(%d)\n", + code, file, line); } } - - - /* log the incoming transfer of a file for interactive use, this will be called at the end where the client was run @@ -1,6 +1,5 @@ -/* -*- c-file-style: "linux" -*- - - Copyright (C) 1996-2000 by Andrew Tridgell +/* + Copyright (C) Andrew Tridgell 1996 Copyright (C) Paul Mackerras 1996 This program is free software; you can redistribute it and/or modify @@ -38,8 +37,8 @@ extern int make_backups; extern char *backup_suffix; static struct delete_list { - DEV64_T dev; - INO64_T inode; + dev_t dev; + INO_T inode; } *delete_list; static int dlist_len, dlist_alloc_len; @@ -83,15 +82,14 @@ static void delete_one(struct file_struct *f) { if (!S_ISDIR(f->mode)) { if (robust_unlink(f_name(f)) != 0) { - rprintf(FERROR,"delete_one: unlink %s: %s\n",f_name(f),strerror(errno)); + rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno)); } else if (verbose) { rprintf(FINFO,"deleting %s\n",f_name(f)); } } else { if (do_rmdir(f_name(f)) != 0) { if (errno != ENOTEMPTY && errno != EEXIST) - rprintf(FERROR,"delete_one: rmdir %s: %s\n", - f_name(f), strerror(errno)); + rprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno)); } else if (verbose) { rprintf(FINFO,"deleting directory %s\n",f_name(f)); } @@ -179,7 +177,7 @@ static int get_tmpname(char *fnametmp, char *fname) rprintf(FERROR,"filename too long\n"); return 0; } - snprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f); + slprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f); return 1; } @@ -192,11 +190,11 @@ static int get_tmpname(char *fnametmp, char *fname) if (f) { *f = 0; - snprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX", + slprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX", fname,f+1); *f = '/'; } else { - snprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname); + slprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname); } return 1; @@ -305,7 +303,6 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) int fd1,fd2; STRUCT_STAT st; char *fname; - char template[MAXPATHLEN]; char fnametmp[MAXPATHLEN]; char *fnamecmp; char fnamecmpbuf[MAXPATHLEN]; @@ -373,7 +370,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) if ((fd1 == -1) && (compare_dest != NULL)) { /* try the file at compare_dest instead */ - snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s", + slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s", compare_dest,fname); fnamecmp = fnamecmpbuf; fd1 = do_open(fnamecmp, O_RDONLY, 0); @@ -414,7 +411,17 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) continue; } - strlcpy(template, fnametmp, sizeof(template)); + /* mktemp is deliberately used here instead of mkstemp. + because O_EXCL is used on the open, the race condition + is not a problem or a security hole, and we want to + control the access permissions on the created file. */ + if (NULL == do_mktemp(fnametmp)) { + rprintf(FERROR,"mktemp %s failed\n",fnametmp); + receive_data(f_in,buf,-1,NULL,file->length); + if (buf) unmap_file(buf); + if (fd1 != -1) close(fd1); + continue; + } /* we initially set the perms without the setuid/setgid bits to ensure that there is no race @@ -422,21 +429,16 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) the lchown. Thanks to snabb@epipe.fi for pointing this out. We also set it initially without group access because of a similar race condition. */ - fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS); - if (fd2 == -1) { - rprintf(FERROR,"mkstemp %s failed\n",fnametmp); - receive_data(f_in,buf,-1,NULL,file->length); - if (buf) unmap_file(buf); - continue; - } + fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL, + file->mode & INITACCESSPERMS); /* in most cases parent directories will already exist because their information should have been previously transferred, but that may not be the case with -R */ if (fd2 == -1 && relative_paths && errno == ENOENT && create_directory_path(fnametmp) == 0) { - strlcpy(fnametmp, template, sizeof(fnametmp)); - fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS); + fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL, + file->mode & INITACCESSPERMS); } if (fd2 == -1) { rprintf(FERROR,"cannot create %s : %s\n",fnametmp,strerror(errno)); @@ -489,7 +491,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) } if (preserve_hard_links) - do_hard_links(); + do_hard_links(flist); /* now we need to fix any directory permissions that were modified during the transfer */ @@ -1,7 +1,6 @@ /* - Copyright (C) by Andrew Tridgell 1996, 2000 + Copyright (C) Andrew Tridgell 1996 Copyright (C) Paul Mackerras 1996 - Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,7 +17,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #define False 0 #define True 1 @@ -49,18 +47,7 @@ #define SAME_TIME (1<<7) /* update this if you make incompatible changes */ -#define PROTOCOL_VERSION 26 - -/* We refuse to interoperate with versions that are not in this range. - * Note that we assume we'll work with later versions: the onus is on - * people writing them to make sure that they don't send us anything - * we won't understand. - * - * There are two possible explanations for the limit at thirty: either - * to allow new major-rev versions that do not interoperate with us, - * and (more likely) so that we can detect an attempt to connect rsync - * to a non-rsync server, which is unlikely to begin by sending a byte - * between 15 and 30. */ +#define PROTOCOL_VERSION 24 #define MIN_PROTOCOL_VERSION 15 #define MAX_PROTOCOL_VERSION 30 @@ -76,10 +63,7 @@ #define MPLEX_BASE 7 -/* Log values. I *think* what these mean is: FLOG goes to the server - * logfile; FERROR and FINFO try to end up on the client, with - * different levels of filtering. */ -enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 }; +enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3}; #include "errcode.h" @@ -93,6 +77,12 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 }; #include <sys/types.h> +#ifdef HAVE_GETOPT_LONG +#include <getopt.h> +#else +#include "lib/getopt.h" +#endif + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -185,10 +175,6 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 }; #include <glob.h> #endif -#ifdef HAVE_MALLOC_H -# include <malloc.h> -#endif - /* these are needed for the uid/gid mapping code */ #include <pwd.h> #include <grp.h> @@ -267,44 +253,15 @@ enum logcode {FNONE=0, FERROR=1, FINFO=2, FLOG=3 }; #elif HAVE_LONGLONG #define int64 long long #else -/* As long as it gets... */ #define int64 off_t #define NO_INT64 #endif -/* Starting from protocol version 26, we always use 64-bit - * ino_t and dev_t internally, even if this platform does not - * allow files to have 64-bit inums. That's because the - * receiver needs to find duplicate (dev,ino) tuples to detect - * hardlinks, and it might have files coming from a platform - * that has 64-bit inums. - * - * The only exception is if we're on a platform with no 64-bit type at - * all. - * - * Because we use read_longint() to get these off the wire, if you - * transfer devices or hardlinks with dev or inum > 2**32 to a machine - * with no 64-bit types then you will get an overflow error. Probably - * not many people have that combination of machines, and you can - * avoid it by not preserving hardlinks or not transferring device - * nodes. It's not clear that any other behaviour is better. - * - * Note that if you transfer devices from a 64-bit-devt machine (say, - * Solaris) to a 32-bit-devt machine (say, Linux-2.2/x86) then the - * device numbers will be truncated. But it's a kind of silly thing - * to do anyhow. - * - * FIXME: In future, we should probable split the device number into - * major/minor, and transfer the two parts as 32-bit ints. That gives - * you somewhat more of a chance that they'll come from a big machine - * to a little one in a useful way. - * - * FIXME: Really we need an unsigned type, and we perhaps ought to - * cope with platforms on which this is an unsigned int or even a - * struct. Later. - */ -#define INO64_T int64 -#define DEV64_T int64 +#if HAVE_SHORT_INO_T +#define INO_T uint32 +#else +#define INO_T ino_t +#endif #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) @@ -335,13 +292,9 @@ struct file_struct { time_t modtime; OFF_T length; mode_t mode; - - INO64_T inode; - /** Device this file lives upon */ - DEV64_T dev; - - /** If this is a device node, the device number. */ - DEV64_T rdev; + INO_T inode; + dev_t dev; + dev_t rdev; uid_t uid; gid_t gid; char *basename; @@ -377,11 +330,11 @@ struct sum_buf { }; struct sum_struct { - OFF_T flength; /* total file length */ - size_t count; /* how many chunks */ - size_t remainder; /* flength % block_length */ - size_t n; /* block_length */ - struct sum_buf *sums; /* points to info for each chunk */ + OFF_T flength; /* total file length */ + size_t count; /* how many chunks */ + size_t remainder; /* flength % block_length */ + size_t n; /* block_length */ + struct sum_buf *sums; /* points to info for each chunk */ }; struct map_struct { @@ -391,6 +344,7 @@ struct map_struct { }; struct exclude_struct { + char *orig; char *pattern; int regular_exp; int fnmatch_flags; @@ -422,29 +376,9 @@ static inline int flist_up(struct file_list *flist, int i) } #include "byteorder.h" -#include "lib/mdfour.h" -#include "lib/permstring.h" -#include "lib/addrinfo.h" - +#include "version.h" #include "proto.h" - -/* We have replacement versions of these if they're missing. */ -#ifndef HAVE_ASPRINTF -int asprintf(char **ptr, const char *format, ...); -#endif - -#ifndef HAVE_VASPRINTF -int vasprintf(char **ptr, const char *format, va_list ap); -#endif - -#if !defined(HAVE_VSNPRINTF) && !defined(HAVE_C99_VSNPRINTF) -int vsnprintf (char *str, size_t count, const char *fmt, va_list args); -#endif - -#if !defined(HAVE_SNPRINTF) && !defined(HAVE_C99_VSNPRINTF) -int snprintf(char *str,size_t count,const char *fmt,...); -#endif - +#include "lib/mdfour.h" #if !HAVE_STRERROR extern char *sys_errlist[]; @@ -542,13 +476,6 @@ extern int errno; # define NONBLOCK_FLAG FNDELAY #endif -#ifndef INADDR_LOOPBACK -#define INADDR_LOOPBACK 0x7f000001 -#endif - -#ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff -#endif #define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode)) @@ -570,14 +497,6 @@ extern int errno; #endif ; -/* This is just like rprintf, but it also tries to print some - * representation of the error code. Normally errcode = errno. */ -void rsyserr(enum logcode, int, const char *, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 3, 4))) -#endif - ; - #ifdef REPLACE_INET_NTOA #define inet_ntoa rep_inet_ntoa #endif @@ -596,15 +515,3 @@ size_t strlcat(char *d, const char *s, size_t bufsize); #endif #define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__) - - -extern int verbose; - -#ifndef HAVE_INET_NTOP -const char * -inet_ntop(int af, const void *src, char *dst, size_t size); -#endif /* !HAVE_INET_NTOP */ - -#ifndef HAVE_INET_PTON -int isc_net_pton(int af, const char *src, void *dst); -#endif @@ -1,8 +1,6 @@ -/* -*- c-file-style: "linux" -*- - - Copyright (C) 1996-2000 by Andrew Tridgell - Copyright (C) Paul Mackerras 1996 - Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org> +/* + Copyright (C) Andrew Tridgell 1996 + Copyright (C) Paul Mackerras 1996 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -84,26 +82,6 @@ int fd_pair(int fd[2]) } -void print_child_argv(char **cmd) -{ - rprintf(FINFO, RSYNC_NAME ": open connection using "); - for (; *cmd; cmd++) { - /* Look for characters that ought to be quoted. This - * is not a great quoting algorithm, but it's - * sufficient for a log message. */ - if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789" - ",.-_=+@/") != strlen(*cmd)) { - rprintf(FINFO, "\"%s\" ", *cmd); - } else { - rprintf(FINFO, "%s ", *cmd); - } - } - rprintf(FINFO, "\n"); -} - - /* this is derived from CVS code note that in the child STDIN is set to blocking and STDOUT @@ -114,71 +92,66 @@ void print_child_argv(char **cmd) used to cope with badly broken rsh implementations like the one on solaris. */ -pid_t piped_child(char **command, int *f_in, int *f_out) -{ - pid_t pid; - int to_child_pipe[2]; - int from_child_pipe[2]; - extern int blocking_io; - - if (verbose > 0) { - print_child_argv(command); - } - - if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) { - rprintf(FERROR, "pipe: %s\n", strerror(errno)); - exit_cleanup(RERR_IPC); - } - - - pid = do_fork(); - if (pid == -1) { - rprintf(FERROR, "fork: %s\n", strerror(errno)); - exit_cleanup(RERR_IPC); - } - - if (pid == 0) { - extern int orig_umask; - if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || - close(to_child_pipe[1]) < 0 || - close(from_child_pipe[0]) < 0 || - dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { - rprintf(FERROR, "Failed to dup/close : %s\n", - strerror(errno)); - exit_cleanup(RERR_IPC); - } - if (to_child_pipe[0] != STDIN_FILENO) - close(to_child_pipe[0]); - if (from_child_pipe[1] != STDOUT_FILENO) - close(from_child_pipe[1]); - umask(orig_umask); - set_blocking(STDIN_FILENO); - if (blocking_io) { - set_blocking(STDOUT_FILENO); - } - execvp(command[0], command); - rprintf(FERROR, "Failed to exec %s : %s\n", - command[0], strerror(errno)); - exit_cleanup(RERR_IPC); - } +int piped_child(char **command,int *f_in,int *f_out) +{ + int pid; + int to_child_pipe[2]; + int from_child_pipe[2]; + extern int blocking_io; + + if (fd_pair(to_child_pipe) < 0 || + fd_pair(from_child_pipe) < 0) { + rprintf(FERROR,"pipe: %s\n",strerror(errno)); + exit_cleanup(RERR_IPC); + } + + + pid = do_fork(); + if (pid < 0) { + rprintf(FERROR,"fork: %s\n",strerror(errno)); + exit_cleanup(RERR_IPC); + } + + if (pid == 0) + { + extern int orig_umask; + if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || + close(to_child_pipe[1]) < 0 || + close(from_child_pipe[0]) < 0 || + dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { + rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno)); + exit_cleanup(RERR_IPC); + } + if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]); + if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]); + umask(orig_umask); + set_blocking(STDIN_FILENO); + if (blocking_io) { + set_blocking(STDOUT_FILENO); + } + execvp(command[0], command); + rprintf(FERROR,"Failed to exec %s : %s\n", + command[0],strerror(errno)); + exit_cleanup(RERR_IPC); + } - if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) { - rprintf(FERROR, "Failed to close : %s\n", strerror(errno)); - exit_cleanup(RERR_IPC); - } + if (close(from_child_pipe[1]) < 0 || + close(to_child_pipe[0]) < 0) { + rprintf(FERROR,"Failed to close : %s\n",strerror(errno)); + exit_cleanup(RERR_IPC); + } - *f_in = from_child_pipe[0]; - *f_out = to_child_pipe[1]; + *f_in = from_child_pipe[0]; + *f_out = to_child_pipe[1]; - return pid; + return pid; } -pid_t local_child(int argc, char **argv,int *f_in,int *f_out) +int local_child(int argc, char **argv,int *f_in,int *f_out) { - pid_t pid; + int pid; int to_child_pipe[2]; int from_child_pipe[2]; - extern int read_batch; /* dw */ if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) { @@ -188,7 +161,7 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out) pid = do_fork(); - if (pid == -1) { + if (pid < 0) { rprintf(FERROR,"fork: %s\n",strerror(errno)); exit_cleanup(RERR_IPC); } @@ -197,7 +170,7 @@ pid_t local_child(int argc, char **argv,int *f_in,int *f_out) extern int am_sender; extern int am_server; - am_sender = read_batch ? 0 : !am_sender; + am_sender = !am_sender; am_server = 1; if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || @@ -584,7 +557,10 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs) s = strdup(s); if (!s) out_of_memory("glob_expand"); - if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand"); + base = (char *)malloc(strlen(base1)+3); + if (!base) out_of_memory("glob_expand"); + + sprintf(base," %s/", base1); q = s; while ((p = strstr(q,base)) && ((*argc) < maxargs)) { @@ -611,6 +587,33 @@ void strlower(char *s) } } +/* this is like vsnprintf but it always null terminates, so you + can fit at most n-1 chars in */ +int vslprintf(char *str, int n, const char *format, va_list ap) +{ + int ret = vsnprintf(str, n, format, ap); + if (ret >= n || ret < 0) { + str[n-1] = 0; + return -1; + } + str[ret] = 0; + return ret; +} + + +/* like snprintf but always null terminates */ +int slprintf(char *str, int n, char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = vslprintf(str,n,format,ap); + va_end(ap); + return ret; +} + + void *Realloc(void *p, int size) { if (!p) return (void *)malloc(size); @@ -832,91 +835,28 @@ int u_strcmp(const char *cs1, const char *cs2) return (int)*s1 - (int)*s2; } -static OFF_T last_ofs; -static struct timeval print_time; -static struct timeval start_time; -static OFF_T start_ofs; - -static unsigned long msdiff(struct timeval *t1, struct timeval *t2) -{ - return (t2->tv_sec - t1->tv_sec) * 1000 - + (t2->tv_usec - t1->tv_usec) / 1000; -} - - -/** - * @param ofs Current position in file - * @param size Total size of file - * @param is_last True if this is the last time progress will be - * printed for this file, so we should output a newline. (Not - * necessarily the same as all bytes being received.) - **/ -static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now, - int is_last) -{ - int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size); - unsigned long diff = msdiff(&start_time, now); - double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0; - const char *units; - double remain = rate ? (double) (size-ofs) / rate / 1000.0: 0.0; - int remain_h, remain_m, remain_s; - - if (rate > 1024*1024) { - rate /= 1024.0 * 1024.0; - units = "GB/s"; - } else if (rate > 1024) { - rate /= 1024.0; - units = "MB/s"; - } else { - units = "kB/s"; - } - - remain_s = (int) remain % 60; - remain_m = (int) (remain / 60.0) % 60; - remain_h = (int) (remain / 3600.0); - - rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s", - (double) ofs, pct, rate, units, - remain_h, remain_m, remain_s, - is_last ? "\n" : "\r"); -} +static OFF_T last_ofs; void end_progress(OFF_T size) { extern int do_progress, am_server; if (do_progress && !am_server) { - struct timeval now; - gettimeofday(&now, NULL); - rprint_progress(size, size, &now, True); + rprintf(FINFO,"%.0f (100%%)\n", (double)size); } - last_ofs = 0; - start_ofs = 0; - print_time.tv_sec = print_time.tv_usec = 0; - start_time.tv_sec = start_time.tv_usec = 0; + last_ofs = 0; } void show_progress(OFF_T ofs, OFF_T size) { extern int do_progress, am_server; - struct timeval now; - - gettimeofday(&now, NULL); - - if (!start_time.tv_sec && !start_time.tv_usec) { - start_time.tv_sec = now.tv_sec; - start_time.tv_usec = now.tv_usec; - start_ofs = ofs; - } - - if (do_progress - && !am_server - && ofs > last_ofs + 1000 - && msdiff(&print_time, &now) > 250) { - rprint_progress(ofs, size, &now, False); - last_ofs = ofs; - print_time.tv_sec = now.tv_sec; - print_time.tv_usec = now.tv_usec; + + if (do_progress && !am_server) { + if (ofs > last_ofs + 1000) { + int pct = (int)((100.0*ofs)/size); + rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct); + last_ofs = ofs; + } } } @@ -990,13 +930,10 @@ char *timestring(time_t t) } -/** - * Sleep for a specified number of milliseconds. - * - * Always returns TRUE. (In the future it might return FALSE if - * interrupted.) - **/ -int msleep(int t) +/******************************************************************* +sleep for a specified number of milliseconds +********************************************************************/ +void msleep(int t) { int tdiff=0; struct timeval tval,t1,t2; @@ -1015,8 +952,6 @@ int msleep(int t) tdiff = (t2.tv_sec - t1.tv_sec)*1000 + (t2.tv_usec - t1.tv_usec)/1000; } - - return True; } @@ -1028,6 +963,7 @@ int msleep(int t) *******************************************************************/ int cmp_modtime(time_t file1, time_t file2) { + time_t diff; extern int modify_window; if (file2 > file1) { @@ -1051,9 +987,9 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) { static int (*fn)(); int ret; - char *cmd; + char cmd[1024]; - asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'", + sprintf(cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'", getpid(), getpid(), getpid()); if (!fn) { @@ -1066,8 +1002,6 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) system(cmd); - free(cmd); - return ret; } #endif diff --git a/version.h b/version.h new file mode 100644 index 00000000..ba452e92 --- /dev/null +++ b/version.h @@ -0,0 +1 @@ +#define VERSION "2.4.7pre1" |