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