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