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