Test harness for unsafe_symlink: just passes in argv[].
[rsync/rsync.git] / util.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux" -*-
2
3 Copyright (C) 1996-2000 by Andrew Tridgell
4 Copyright (C) Paul Mackerras 1996
5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/**
23 *
24 * @file util.c
25 *
26 * Utilities used in rsync
27 **/
28
29#include "rsync.h"
30
31extern int verbose;
32
33
34/**
35 Set a fd into nonblocking mode
36**/
37void set_nonblocking(int fd)
38{
39 int val;
40
41 if((val = fcntl(fd, F_GETFL, 0)) == -1)
42 return;
43 if (!(val & NONBLOCK_FLAG)) {
44 val |= NONBLOCK_FLAG;
45 fcntl(fd, F_SETFL, val);
46 }
47}
48
49/**
50Set a fd into blocking mode
51*/
52void set_blocking(int fd)
53{
54 int val;
55
56 if((val = fcntl(fd, F_GETFL, 0)) == -1)
57 return;
58 if (val & NONBLOCK_FLAG) {
59 val &= ~NONBLOCK_FLAG;
60 fcntl(fd, F_SETFL, val);
61 }
62}
63
64
65/**
66 Create a file descriptor pair - like pipe() but use socketpair if
67 possible (because of blocking issues on pipes).
68
69 Always set non-blocking.
70 */
71int fd_pair(int fd[2])
72{
73 int ret;
74
75#if HAVE_SOCKETPAIR
76 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
77#else
78 ret = pipe(fd);
79#endif
80
81 if (ret == 0) {
82 set_nonblocking(fd[0]);
83 set_nonblocking(fd[1]);
84 }
85
86 return ret;
87}
88
89
90static void print_child_argv(char **cmd)
91{
92 rprintf(FINFO, "opening connection using ");
93 for (; *cmd; cmd++) {
94 /* Look for characters that ought to be quoted. This
95 * is not a great quoting algorithm, but it's
96 * sufficient for a log message. */
97 if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
98 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
99 "0123456789"
100 ",.-_=+@/") != strlen(*cmd)) {
101 rprintf(FINFO, "\"%s\" ", *cmd);
102 } else {
103 rprintf(FINFO, "%s ", *cmd);
104 }
105 }
106 rprintf(FINFO, "\n");
107}
108
109
110/**
111 * Create a child connected to use on stdin/stdout.
112 *
113 * This is derived from CVS code
114 *
115 * Note that in the child STDIN is set to blocking and STDOUT
116 * is set to non-blocking. This is necessary as rsh relies on stdin being blocking
117 * and ssh relies on stdout being non-blocking
118 *
119 * If blocking_io is set then use blocking io on both fds. That can be
120 * used to cope with badly broken rsh implementations like the one on
121 * Solaris.
122 **/
123pid_t piped_child(char **command, int *f_in, int *f_out)
124{
125 pid_t pid;
126 int to_child_pipe[2];
127 int from_child_pipe[2];
128 extern int blocking_io;
129
130 if (verbose >= 2) {
131 print_child_argv(command);
132 }
133
134 if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
135 rprintf(FERROR, "pipe: %s\n", strerror(errno));
136 exit_cleanup(RERR_IPC);
137 }
138
139
140 pid = do_fork();
141 if (pid == -1) {
142 rprintf(FERROR, "fork: %s\n", strerror(errno));
143 exit_cleanup(RERR_IPC);
144 }
145
146 if (pid == 0) {
147 extern int orig_umask;
148 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
149 close(to_child_pipe[1]) < 0 ||
150 close(from_child_pipe[0]) < 0 ||
151 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
152 rprintf(FERROR, "Failed to dup/close : %s\n",
153 strerror(errno));
154 exit_cleanup(RERR_IPC);
155 }
156 if (to_child_pipe[0] != STDIN_FILENO)
157 close(to_child_pipe[0]);
158 if (from_child_pipe[1] != STDOUT_FILENO)
159 close(from_child_pipe[1]);
160 umask(orig_umask);
161 set_blocking(STDIN_FILENO);
162 if (blocking_io) {
163 set_blocking(STDOUT_FILENO);
164 }
165 execvp(command[0], command);
166 rprintf(FERROR, "Failed to exec %s : %s\n",
167 command[0], strerror(errno));
168 exit_cleanup(RERR_IPC);
169 }
170
171 if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
172 rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
173 exit_cleanup(RERR_IPC);
174 }
175
176 *f_in = from_child_pipe[0];
177 *f_out = to_child_pipe[1];
178
179 return pid;
180}
181
182pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
183 int (*child_main)(int, char **))
184{
185 pid_t pid;
186 int to_child_pipe[2];
187 int from_child_pipe[2];
188 extern int read_batch; /* dw */
189
190 if (fd_pair(to_child_pipe) < 0 ||
191 fd_pair(from_child_pipe) < 0) {
192 rprintf(FERROR,"pipe: %s\n",strerror(errno));
193 exit_cleanup(RERR_IPC);
194 }
195
196
197 pid = do_fork();
198 if (pid == -1) {
199 rprintf(FERROR,"fork: %s\n",strerror(errno));
200 exit_cleanup(RERR_IPC);
201 }
202
203 if (pid == 0) {
204 extern int am_sender;
205 extern int am_server;
206
207 am_sender = read_batch ? 0 : !am_sender;
208 am_server = 1;
209
210 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
211 close(to_child_pipe[1]) < 0 ||
212 close(from_child_pipe[0]) < 0 ||
213 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
214 rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
215 exit_cleanup(RERR_IPC);
216 }
217 if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
218 if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
219 child_main(argc, argv);
220 }
221
222 if (close(from_child_pipe[1]) < 0 ||
223 close(to_child_pipe[0]) < 0) {
224 rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
225 exit_cleanup(RERR_IPC);
226 }
227
228 *f_in = from_child_pipe[0];
229 *f_out = to_child_pipe[1];
230
231 return pid;
232}
233
234
235
236void out_of_memory(char *str)
237{
238 rprintf(FERROR,"ERROR: out of memory in %s\n",str);
239 exit_cleanup(RERR_MALLOC);
240}
241
242void overflow(char *str)
243{
244 rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
245 exit_cleanup(RERR_MALLOC);
246}
247
248
249
250int set_modtime(char *fname, time_t modtime)
251{
252 extern int dry_run;
253 if (dry_run)
254 return 0;
255
256 if (verbose > 2) {
257 rprintf(FINFO, "set modtime of %s to (%ld) %s",
258 fname, (long) modtime,
259 asctime(localtime(&modtime)));
260 }
261
262 {
263#ifdef HAVE_UTIMBUF
264 struct utimbuf tbuf;
265 tbuf.actime = time(NULL);
266 tbuf.modtime = modtime;
267 return utime(fname,&tbuf);
268#elif defined(HAVE_UTIME)
269 time_t t[2];
270 t[0] = time(NULL);
271 t[1] = modtime;
272 return utime(fname,t);
273#else
274 struct timeval t[2];
275 t[0].tv_sec = time(NULL);
276 t[0].tv_usec = 0;
277 t[1].tv_sec = modtime;
278 t[1].tv_usec = 0;
279 return utimes(fname,t);
280#endif
281 }
282}
283
284
285/**
286 Create any necessary directories in fname. Unfortunately we don't know
287 what perms to give the directory when this is called so we need to rely
288 on the umask
289**/
290int create_directory_path(char *fname)
291{
292 extern int orig_umask;
293 char *p;
294
295 while (*fname == '/') fname++;
296 while (strncmp(fname,"./",2)==0) fname += 2;
297
298 p = fname;
299 while ((p=strchr(p,'/'))) {
300 *p = 0;
301 do_mkdir(fname,0777 & ~orig_umask);
302 *p = '/';
303 p++;
304 }
305 return 0;
306}
307
308
309/**
310 * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
311 * interrupted.
312 *
313 * @retval len upon success
314 *
315 * @retval <0 write's (negative) error code
316 *
317 * Derived from GNU C's cccp.c.
318 */
319static int full_write(int desc, char *ptr, size_t len)
320{
321 int total_written;
322
323 total_written = 0;
324 while (len > 0) {
325 int written = write (desc, ptr, len);
326 if (written < 0) {
327#ifdef EINTR
328 if (errno == EINTR)
329 continue;
330#endif
331 return written;
332 }
333 total_written += written;
334 ptr += written;
335 len -= written;
336 }
337 return total_written;
338}
339
340
341/**
342 * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
343 * interrupted.
344 *
345 * @retval >0 the actual number of bytes read
346 *
347 * @retval 0 for EOF
348 *
349 * @retval <0 for an error.
350 *
351 * Derived from GNU C's cccp.c. */
352static int safe_read(int desc, char *ptr, size_t len)
353{
354 int n_chars;
355
356 if (len == 0)
357 return len;
358
359#ifdef EINTR
360 do {
361 n_chars = read(desc, ptr, len);
362 } while (n_chars < 0 && errno == EINTR);
363#else
364 n_chars = read(desc, ptr, len);
365#endif
366
367 return n_chars;
368}
369
370
371/** Copy a file.
372 *
373 * This is used in conjunction with the --temp-dir option */
374int copy_file(char *source, char *dest, mode_t mode)
375{
376 int ifd;
377 int ofd;
378 char buf[1024 * 8];
379 int len; /* Number of bytes read into `buf'. */
380
381 ifd = do_open(source, O_RDONLY, 0);
382 if (ifd == -1) {
383 rprintf(FERROR,"open %s: %s\n",
384 source,strerror(errno));
385 return -1;
386 }
387
388 if (robust_unlink(dest) && errno != ENOENT) {
389 rprintf(FERROR,"unlink %s: %s\n",
390 dest,strerror(errno));
391 return -1;
392 }
393
394 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
395 if (ofd == -1) {
396 rprintf(FERROR,"open %s: %s\n",
397 dest,strerror(errno));
398 close(ifd);
399 return -1;
400 }
401
402 while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
403 if (full_write(ofd, buf, len) < 0) {
404 rprintf(FERROR,"write %s: %s\n",
405 dest,strerror(errno));
406 close(ifd);
407 close(ofd);
408 return -1;
409 }
410 }
411
412 close(ifd);
413 close(ofd);
414
415 if (len < 0) {
416 rprintf(FERROR,"read %s: %s\n",
417 source,strerror(errno));
418 return -1;
419 }
420
421 return 0;
422}
423
424/* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
425#define MAX_RENAMES_DIGITS 3
426#define MAX_RENAMES 1000
427
428/**
429 *
430 Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
431 rename to <path>/.rsyncNNN instead.
432
433 Note that successive rsync runs will shuffle the filenames around a
434 bit as long as the file is still busy; this is because this function
435 does not know if the unlink call is due to a new file coming in, or
436 --delete trying to remove old .rsyncNNN files, hence it renames it
437 each time.
438*/
439int robust_unlink(char *fname)
440{
441#ifndef ETXTBSY
442 return do_unlink(fname);
443#else
444 static int counter = 1;
445 int rc, pos, start;
446 char path[MAXPATHLEN];
447
448 rc = do_unlink(fname);
449 if ((rc == 0) || (errno != ETXTBSY))
450 return rc;
451
452 strlcpy(path, fname, MAXPATHLEN);
453
454 pos = strlen(path);
455 while((path[--pos] != '/') && (pos >= 0))
456 ;
457 ++pos;
458 strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
459 pos += sizeof(".rsync")-1;
460
461 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
462 errno = ETXTBSY;
463 return -1;
464 }
465
466 /* start where the last one left off to reduce chance of clashes */
467 start = counter;
468 do {
469 sprintf(&path[pos], "%03d", counter);
470 if (++counter >= MAX_RENAMES)
471 counter = 1;
472 } while (((rc = access(path, 0)) == 0) && (counter != start));
473
474 if (verbose > 0)
475 rprintf(FINFO,"renaming %s to %s because of text busy\n",
476 fname, path);
477
478 /* maybe we should return rename()'s exit status? Nah. */
479 if (do_rename(fname, path) != 0) {
480 errno = ETXTBSY;
481 return -1;
482 }
483 return 0;
484#endif
485}
486
487int robust_rename(char *from, char *to)
488{
489#ifndef ETXTBSY
490 return do_rename(from, to);
491#else
492 int rc = do_rename(from, to);
493 if ((rc == 0) || (errno != ETXTBSY))
494 return rc;
495 if (robust_unlink(to) != 0)
496 return -1;
497 return do_rename(from, to);
498#endif
499}
500
501
502static pid_t all_pids[10];
503static int num_pids;
504
505/** Fork and record the pid of the child. **/
506pid_t do_fork(void)
507{
508 pid_t newpid = fork();
509
510 if (newpid != 0 && newpid != -1) {
511 all_pids[num_pids++] = newpid;
512 }
513 return newpid;
514}
515
516/**
517 * Kill all children.
518 *
519 * @todo It would be kind of nice to make sure that they are actually
520 * all our children before we kill them, because their pids may have
521 * been recycled by some other process. Perhaps when we wait for a
522 * child, we should remove it from this array. Alternatively we could
523 * perhaps use process groups, but I think that would not work on
524 * ancient Unix versions that don't support them.
525 **/
526void kill_all(int sig)
527{
528 int i;
529
530 for (i = 0; i < num_pids; i++) {
531 /* Let's just be a little careful where we
532 * point that gun, hey? See kill(2) for the
533 * magic caused by negative values. */
534 pid_t p = all_pids[i];
535
536 if (p == getpid())
537 continue;
538 if (p <= 0)
539 continue;
540
541 kill(p, sig);
542 }
543}
544
545
546/** Turn a user name into a uid */
547int name_to_uid(char *name, uid_t *uid)
548{
549 struct passwd *pass;
550 if (!name || !*name) return 0;
551 pass = getpwnam(name);
552 if (pass) {
553 *uid = pass->pw_uid;
554 return 1;
555 }
556 return 0;
557}
558
559/** Turn a group name into a gid */
560int name_to_gid(char *name, gid_t *gid)
561{
562 struct group *grp;
563 if (!name || !*name) return 0;
564 grp = getgrnam(name);
565 if (grp) {
566 *gid = grp->gr_gid;
567 return 1;
568 }
569 return 0;
570}
571
572
573/** Lock a byte range in a open file */
574int lock_range(int fd, int offset, int len)
575{
576 struct flock lock;
577
578 lock.l_type = F_WRLCK;
579 lock.l_whence = SEEK_SET;
580 lock.l_start = offset;
581 lock.l_len = len;
582 lock.l_pid = 0;
583
584 return fcntl(fd,F_SETLK,&lock) == 0;
585}
586
587
588static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
589{
590#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
591 if (!*s) s = ".";
592 argv[*argc] = strdup(s);
593 (*argc)++;
594 return;
595#else
596 extern int sanitize_paths;
597 glob_t globbuf;
598 int i;
599
600 if (!*s) s = ".";
601
602 argv[*argc] = strdup(s);
603 if (sanitize_paths) {
604 sanitize_path(argv[*argc], NULL);
605 }
606
607 memset(&globbuf, 0, sizeof(globbuf));
608 glob(argv[*argc], 0, NULL, &globbuf);
609 if (globbuf.gl_pathc == 0) {
610 (*argc)++;
611 globfree(&globbuf);
612 return;
613 }
614 for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
615 if (i == 0) free(argv[*argc]);
616 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
617 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
618 }
619 globfree(&globbuf);
620 (*argc) += i;
621#endif
622}
623
624void glob_expand(char *base1, char **argv, int *argc, int maxargs)
625{
626 char *s = argv[*argc];
627 char *p, *q;
628 char *base = base1;
629
630 if (!s || !*s) return;
631
632 if (strncmp(s, base, strlen(base)) == 0) {
633 s += strlen(base);
634 }
635
636 s = strdup(s);
637 if (!s) out_of_memory("glob_expand");
638
639 if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
640
641 q = s;
642 while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
643 /* split it at this point */
644 *p = 0;
645 glob_expand_one(q, argv, argc, maxargs);
646 q = p+strlen(base);
647 }
648
649 if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
650
651 free(s);
652 free(base);
653}
654
655/**
656 * Convert a string to lower case
657 **/
658void strlower(char *s)
659{
660 while (*s) {
661 if (isupper(*s)) *s = tolower(*s);
662 s++;
663 }
664}
665
666void *Realloc(void *p, int size)
667{
668 if (!p) return (void *)malloc(size);
669 return (void *)realloc(p, size);
670}
671
672
673void clean_fname(char *name)
674{
675 char *p;
676 int l;
677 int modified = 1;
678
679 if (!name) return;
680
681 while (modified) {
682 modified = 0;
683
684 if ((p=strstr(name,"/./"))) {
685 modified = 1;
686 while (*p) {
687 p[0] = p[2];
688 p++;
689 }
690 }
691
692 if ((p=strstr(name,"//"))) {
693 modified = 1;
694 while (*p) {
695 p[0] = p[1];
696 p++;
697 }
698 }
699
700 if (strncmp(p=name,"./",2) == 0) {
701 modified = 1;
702 do {
703 p[0] = p[2];
704 } while (*p++);
705 }
706
707 l = strlen(p=name);
708 if (l > 1 && p[l-1] == '/') {
709 modified = 1;
710 p[l-1] = 0;
711 }
712 }
713}
714
715/**
716 * Make path appear as if a chroot had occurred:
717 *
718 * 1. remove leading "/" (or replace with "." if at end)
719 * 2. remove leading ".." components (except those allowed by "reldir")
720 * 3. delete any other "<dir>/.." (recursively)
721 *
722 * Can only shrink paths, so sanitizes in place.
723 *
724 * While we're at it, remove double slashes and "." components like
725 * clean_fname does(), but DON'T remove a trailing slash because that
726 * is sometimes significant on command line arguments.
727 *
728 * If "reldir" is non-null, it is a sanitized directory that the path will be
729 * relative to, so allow as many ".." at the beginning of the path as
730 * there are components in reldir. This is used for symbolic link targets.
731 * If reldir is non-null and the path began with "/", to be completely like
732 * a chroot we should add in depth levels of ".." at the beginning of the
733 * path, but that would blow the assumption that the path doesn't grow and
734 * it is not likely to end up being a valid symlink anyway, so just do
735 * the normal removal of the leading "/" instead.
736 *
737 * Contributed by Dave Dykstra <dwd@bell-labs.com>
738 */
739void sanitize_path(char *p, char *reldir)
740{
741 char *start, *sanp;
742 int depth = 0;
743 int allowdotdot = 0;
744
745 if (reldir) {
746 depth++;
747 while (*reldir) {
748 if (*reldir++ == '/') {
749 depth++;
750 }
751 }
752 }
753 start = p;
754 sanp = p;
755 while (*p == '/') {
756 /* remove leading slashes */
757 p++;
758 }
759 while (*p != '\0') {
760 /* this loop iterates once per filename component in p.
761 * both p (and sanp if the original had a slash) should
762 * always be left pointing after a slash
763 */
764 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
765 /* skip "." component */
766 while (*++p == '/') {
767 /* skip following slashes */
768 ;
769 }
770 continue;
771 }
772 allowdotdot = 0;
773 if ((*p == '.') && (*(p+1) == '.') &&
774 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
775 /* ".." component followed by slash or end */
776 if ((depth > 0) && (sanp == start)) {
777 /* allow depth levels of .. at the beginning */
778 --depth;
779 allowdotdot = 1;
780 } else {
781 p += 2;
782 if (*p == '/')
783 p++;
784 if (sanp != start) {
785 /* back up sanp one level */
786 --sanp; /* now pointing at slash */
787 while ((sanp > start) && (*(sanp - 1) != '/')) {
788 /* skip back up to slash */
789 sanp--;
790 }
791 }
792 continue;
793 }
794 }
795 while (1) {
796 /* copy one component through next slash */
797 *sanp++ = *p++;
798 if ((*p == '\0') || (*(p-1) == '/')) {
799 while (*p == '/') {
800 /* skip multiple slashes */
801 p++;
802 }
803 break;
804 }
805 }
806 if (allowdotdot) {
807 /* move the virtual beginning to leave the .. alone */
808 start = sanp;
809 }
810 }
811 if ((sanp == start) && !allowdotdot) {
812 /* ended up with nothing, so put in "." component */
813 /*
814 * note that the !allowdotdot doesn't prevent this from
815 * happening in all allowed ".." situations, but I didn't
816 * think it was worth putting in an extra variable to ensure
817 * it since an extra "." won't hurt in those situations.
818 */
819 *sanp++ = '.';
820 }
821 *sanp = '\0';
822}
823
824
825static char curr_dir[MAXPATHLEN];
826
827/** like chdir() but can be reversed with pop_dir() if save is set. It
828 is also much faster as it remembers where we have been */
829char *push_dir(char *dir, int save)
830{
831 char *ret = curr_dir;
832 static int initialised;
833
834 if (!initialised) {
835 initialised = 1;
836 getcwd(curr_dir, sizeof(curr_dir)-1);
837 }
838
839 if (!dir) return NULL; /* this call was probably just to initialize */
840
841 if (chdir(dir)) return NULL;
842
843 if (save) {
844 ret = strdup(curr_dir);
845 }
846
847 if (*dir == '/') {
848 strlcpy(curr_dir, dir, sizeof(curr_dir));
849 } else {
850 strlcat(curr_dir,"/", sizeof(curr_dir));
851 strlcat(curr_dir,dir, sizeof(curr_dir));
852 }
853
854 clean_fname(curr_dir);
855
856 return ret;
857}
858
859/** Reverse a push_dir call */
860int pop_dir(char *dir)
861{
862 int ret;
863
864 ret = chdir(dir);
865 if (ret) {
866 free(dir);
867 return ret;
868 }
869
870 strlcpy(curr_dir, dir, sizeof(curr_dir));
871
872 free(dir);
873
874 return 0;
875}
876
877/** We need to supply our own strcmp function for file list comparisons
878 to ensure that signed/unsigned usage is consistent between machines. */
879int u_strcmp(const char *cs1, const char *cs2)
880{
881 const uchar *s1 = (const uchar *)cs1;
882 const uchar *s2 = (const uchar *)cs2;
883
884 while (*s1 && *s2 && (*s1 == *s2)) {
885 s1++; s2++;
886 }
887
888 return (int)*s1 - (int)*s2;
889}
890
891static OFF_T last_ofs;
892static struct timeval print_time;
893static struct timeval start_time;
894static OFF_T start_ofs;
895
896static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
897{
898 return (t2->tv_sec - t1->tv_sec) * 1000
899 + (t2->tv_usec - t1->tv_usec) / 1000;
900}
901
902
903/**
904 * @param ofs Current position in file
905 * @param size Total size of file
906 * @param is_last True if this is the last time progress will be
907 * printed for this file, so we should output a newline. (Not
908 * necessarily the same as all bytes being received.)
909 **/
910static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
911 int is_last)
912{
913 int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
914 unsigned long diff = msdiff(&start_time, now);
915 double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
916 const char *units;
917 /* If we've finished transferring this file, show the time taken;
918 * otherwise show expected time to complete. That's kind of
919 * inconsistent, but people can probably cope. Hopefully we'll
920 * get more consistent and complete progress reporting soon. --
921 * mbp */
922 double remain = is_last
923 ? (double) diff / 1000.0
924 : rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
925 int remain_h, remain_m, remain_s;
926
927 if (rate > 1024*1024) {
928 rate /= 1024.0 * 1024.0;
929 units = "GB/s";
930 } else if (rate > 1024) {
931 rate /= 1024.0;
932 units = "MB/s";
933 } else {
934 units = "kB/s";
935 }
936
937 remain_s = (int) remain % 60;
938 remain_m = (int) (remain / 60.0) % 60;
939 remain_h = (int) (remain / 3600.0);
940
941 rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
942 (double) ofs, pct, rate, units,
943 remain_h, remain_m, remain_s,
944 is_last ? "\n" : "\r");
945}
946
947void end_progress(OFF_T size)
948{
949 extern int do_progress, am_server;
950
951 if (do_progress && !am_server) {
952 struct timeval now;
953 gettimeofday(&now, NULL);
954 rprint_progress(size, size, &now, True);
955 }
956 last_ofs = 0;
957 start_ofs = 0;
958 print_time.tv_sec = print_time.tv_usec = 0;
959 start_time.tv_sec = start_time.tv_usec = 0;
960}
961
962void show_progress(OFF_T ofs, OFF_T size)
963{
964 extern int do_progress, am_server;
965 struct timeval now;
966
967 gettimeofday(&now, NULL);
968
969 if (!start_time.tv_sec && !start_time.tv_usec) {
970 start_time.tv_sec = now.tv_sec;
971 start_time.tv_usec = now.tv_usec;
972 start_ofs = ofs;
973 }
974
975 if (do_progress
976 && !am_server
977 && ofs > last_ofs + 1000
978 && msdiff(&print_time, &now) > 250) {
979 rprint_progress(ofs, size, &now, False);
980 last_ofs = ofs;
981 print_time.tv_sec = now.tv_sec;
982 print_time.tv_usec = now.tv_usec;
983 }
984}
985
986
987/**
988 * Determine if a symlink points outside the current directory tree.
989 * This is considered "unsafe" because e.g. when mirroring somebody
990 * else's machine it might allow them to establish a symlink to
991 * /etc/passwd, and then read it through a web server.
992 *
993 * @param dest Target of the symlink in question.
994 *
995 * @param src Top source directory currently applicable. Basically this
996 * is the first parameter to rsync in a simple invocation, but it's
997 * modified by flist.c in slightly complex ways.
998 *
999 * @retval True if unsafe
1000 * @retval False is unsafe
1001 **/
1002int unsafe_symlink(char *dest, char *src)
1003{
1004 char *tok;
1005 int depth = 0;
1006
1007 /* all absolute and null symlinks are unsafe */
1008 if (!dest || !(*dest) || (*dest == '/')) return 1;
1009
1010 src = strdup(src);
1011 if (!src) out_of_memory("unsafe_symlink");
1012
1013 /* find out what our safety margin is */
1014 for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
1015 if (strcmp(tok,"..") == 0) {
1016 depth=0;
1017 } else if (strcmp(tok,".") == 0) {
1018 /* nothing */
1019 } else {
1020 depth++;
1021 }
1022 }
1023 free(src);
1024
1025 /* drop by one to account for the filename portion */
1026 depth--;
1027
1028 dest = strdup(dest);
1029 if (!dest) out_of_memory("unsafe_symlink");
1030
1031 for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
1032 if (strcmp(tok,"..") == 0) {
1033 depth--;
1034 } else if (strcmp(tok,".") == 0) {
1035 /* nothing */
1036 } else {
1037 depth++;
1038 }
1039 /* if at any point we go outside the current directory then
1040 stop - it is unsafe */
1041 if (depth < 0) break;
1042 }
1043
1044 free(dest);
1045 return (depth < 0);
1046}
1047
1048
1049/**
1050 Return the date and time as a string
1051*/
1052char *timestring(time_t t)
1053{
1054 static char TimeBuf[200];
1055 struct tm *tm = localtime(&t);
1056
1057#ifdef HAVE_STRFTIME
1058 strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
1059#else
1060 strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
1061#endif
1062
1063 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
1064 TimeBuf[strlen(TimeBuf)-1] = 0;
1065 }
1066
1067 return(TimeBuf);
1068}
1069
1070
1071/**
1072 * Sleep for a specified number of milliseconds.
1073 *
1074 * Always returns TRUE. (In the future it might return FALSE if
1075 * interrupted.)
1076 **/
1077int msleep(int t)
1078{
1079 int tdiff=0;
1080 struct timeval tval,t1,t2;
1081
1082 gettimeofday(&t1, NULL);
1083 gettimeofday(&t2, NULL);
1084
1085 while (tdiff < t) {
1086 tval.tv_sec = (t-tdiff)/1000;
1087 tval.tv_usec = 1000*((t-tdiff)%1000);
1088
1089 errno = 0;
1090 select(0,NULL,NULL, NULL, &tval);
1091
1092 gettimeofday(&t2, NULL);
1093 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
1094 (t2.tv_usec - t1.tv_usec)/1000;
1095 }
1096
1097 return True;
1098}
1099
1100
1101/**
1102 * Determine if two file modification times are equivalent (either
1103 * exact or in the modification timestamp window established by
1104 * --modify-window).
1105 *
1106 * @retval 0 if the times should be treated as the same
1107 *
1108 * @retval +1 if the first is later
1109 *
1110 * @retval -1 if the 2nd is later
1111 **/
1112int cmp_modtime(time_t file1, time_t file2)
1113{
1114 extern int modify_window;
1115
1116 if (file2 > file1) {
1117 if (file2 - file1 <= modify_window) return 0;
1118 return -1;
1119 }
1120 if (file1 - file2 <= modify_window) return 0;
1121 return 1;
1122}
1123
1124
1125#ifdef __INSURE__XX
1126#include <dlfcn.h>
1127
1128/**
1129 This routine is a trick to immediately catch errors when debugging
1130 with insure. A xterm with a gdb is popped up when insure catches
1131 a error. It is Linux specific.
1132**/
1133int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1134{
1135 static int (*fn)();
1136 int ret;
1137 char *cmd;
1138
1139 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'",
1140 getpid(), getpid(), getpid());
1141
1142 if (!fn) {
1143 static void *h;
1144 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1145 fn = dlsym(h, "_Insure_trap_error");
1146 }
1147
1148 ret = fn(a1, a2, a3, a4, a5, a6);
1149
1150 system(cmd);
1151
1152 free(cmd);
1153
1154 return ret;
1155}
1156#endif