print_child_argv can be static.
[rsync/rsync.git] / util.c
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
29 extern int verbose;
30
31
32 /****************************************************************************
33 Set a fd into nonblocking mode
34 ****************************************************************************/
35 void 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 /****************************************************************************
48 Set a fd into blocking mode
49 ****************************************************************************/
50 void 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  */
68 int 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 static 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  */
117 pid_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
176 pid_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
229 void out_of_memory(char *str)
230 {
231   rprintf(FERROR,"ERROR: out of memory in %s\n",str);
232   exit_cleanup(RERR_MALLOC);
233 }
234
235 void overflow(char *str)
236 {
237   rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
238   exit_cleanup(RERR_MALLOC);
239 }
240
241
242
243 int 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 /****************************************************************************
279 create any necessary directories in fname. Unfortunately we don't know
280 what perms to give the directory when this is called so we need to rely
281 on the umask
282 ****************************************************************************/
283 int 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 */
307 static 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. */
333 static 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 */
353 int 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
415 int 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
463 int 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
478 static pid_t all_pids[10];
479 static int num_pids;
480
481 /* fork and record the pid of the child */
482 pid_t do_fork(void)
483 {
484         pid_t newpid = fork();
485         
486         if (newpid) {
487                 all_pids[num_pids++] = newpid;
488         }
489         return newpid;
490 }
491
492 /* kill all children */
493 void kill_all(int sig)
494 {
495         int i;
496         for (i=0;i<num_pids;i++) {
497                 if (all_pids[i] != getpid())
498                         kill(all_pids[i], sig);
499         }
500 }
501
502 /* turn a user name into a uid */
503 int name_to_uid(char *name, uid_t *uid)
504 {
505         struct passwd *pass;
506         if (!name || !*name) return 0;
507         pass = getpwnam(name);
508         if (pass) {
509                 *uid = pass->pw_uid;
510                 return 1;
511         }
512         return 0;
513 }
514
515 /* turn a group name into a gid */
516 int name_to_gid(char *name, gid_t *gid)
517 {
518         struct group *grp;
519         if (!name || !*name) return 0;
520         grp = getgrnam(name);
521         if (grp) {
522                 *gid = grp->gr_gid;
523                 return 1;
524         }
525         return 0;
526 }
527
528
529 /* lock a byte range in a open file */
530 int lock_range(int fd, int offset, int len)
531 {
532         struct flock lock;
533
534         lock.l_type = F_WRLCK;
535         lock.l_whence = SEEK_SET;
536         lock.l_start = offset;
537         lock.l_len = len;
538         lock.l_pid = 0;
539         
540         return fcntl(fd,F_SETLK,&lock) == 0;
541 }
542
543
544 static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
545 {
546 #if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
547         if (!*s) s = ".";
548         argv[*argc] = strdup(s);
549         (*argc)++;
550         return;
551 #else
552         extern int sanitize_paths;
553         glob_t globbuf;
554         int i;
555
556         if (!*s) s = ".";
557
558         argv[*argc] = strdup(s);
559         if (sanitize_paths) {
560                 sanitize_path(argv[*argc], NULL);
561         }
562
563         memset(&globbuf, 0, sizeof(globbuf));
564         glob(argv[*argc], 0, NULL, &globbuf);
565         if (globbuf.gl_pathc == 0) {
566                 (*argc)++;
567                 globfree(&globbuf);
568                 return;
569         }
570         for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
571                 if (i == 0) free(argv[*argc]);
572                 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
573                 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
574         }
575         globfree(&globbuf);
576         (*argc) += i;
577 #endif
578 }
579
580 void glob_expand(char *base1, char **argv, int *argc, int maxargs)
581 {
582         char *s = argv[*argc];
583         char *p, *q;
584         char *base = base1;
585
586         if (!s || !*s) return;
587
588         if (strncmp(s, base, strlen(base)) == 0) {
589                 s += strlen(base);
590         }
591
592         s = strdup(s);
593         if (!s) out_of_memory("glob_expand");
594
595         if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
596
597         q = s;
598         while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
599                 /* split it at this point */
600                 *p = 0;
601                 glob_expand_one(q, argv, argc, maxargs);
602                 q = p+strlen(base);
603         }
604
605         if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
606
607         free(s);
608         free(base);
609 }
610
611 /*******************************************************************
612   convert a string to lower case
613 ********************************************************************/
614 void strlower(char *s)
615 {
616         while (*s) {
617                 if (isupper(*s)) *s = tolower(*s);
618                 s++;
619         }
620 }
621
622 void *Realloc(void *p, int size)
623 {
624         if (!p) return (void *)malloc(size);
625         return (void *)realloc(p, size);
626 }
627
628
629 void clean_fname(char *name)
630 {
631         char *p;
632         int l;
633         int modified = 1;
634
635         if (!name) return;
636
637         while (modified) {
638                 modified = 0;
639
640                 if ((p=strstr(name,"/./"))) {
641                         modified = 1;
642                         while (*p) {
643                                 p[0] = p[2];
644                                 p++;
645                         }
646                 }
647
648                 if ((p=strstr(name,"//"))) {
649                         modified = 1;
650                         while (*p) {
651                                 p[0] = p[1];
652                                 p++;
653                         }
654                 }
655
656                 if (strncmp(p=name,"./",2) == 0) {      
657                         modified = 1;
658                         do {
659                                 p[0] = p[2];
660                         } while (*p++);
661                 }
662
663                 l = strlen(p=name);
664                 if (l > 1 && p[l-1] == '/') {
665                         modified = 1;
666                         p[l-1] = 0;
667                 }
668         }
669 }
670
671 /*
672  * Make path appear as if a chroot had occurred:
673  *    1. remove leading "/" (or replace with "." if at end)
674  *    2. remove leading ".." components (except those allowed by "reldir")
675  *    3. delete any other "<dir>/.." (recursively)
676  * Can only shrink paths, so sanitizes in place.
677  * While we're at it, remove double slashes and "." components like
678  *   clean_fname does(), but DON'T remove a trailing slash because that
679  *   is sometimes significant on command line arguments.
680  * If "reldir" is non-null, it is a sanitized directory that the path will be
681  *    relative to, so allow as many ".." at the beginning of the path as
682  *    there are components in reldir.  This is used for symbolic link targets.
683  *    If reldir is non-null and the path began with "/", to be completely like
684  *    a chroot we should add in depth levels of ".." at the beginning of the
685  *    path, but that would blow the assumption that the path doesn't grow and
686  *    it is not likely to end up being a valid symlink anyway, so just do
687  *    the normal removal of the leading "/" instead.
688  * Contributed by Dave Dykstra <dwd@bell-labs.com>
689  */
690
691 void sanitize_path(char *p, char *reldir)
692 {
693         char *start, *sanp;
694         int depth = 0;
695         int allowdotdot = 0;
696
697         if (reldir) {
698                 depth++;
699                 while (*reldir) {
700                         if (*reldir++ == '/') {
701                                 depth++;
702                         }
703                 }
704         }
705         start = p;
706         sanp = p;
707         while (*p == '/') {
708                 /* remove leading slashes */
709                 p++;
710         }
711         while (*p != '\0') {
712                 /* this loop iterates once per filename component in p.
713                  * both p (and sanp if the original had a slash) should
714                  * always be left pointing after a slash
715                  */
716                 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
717                         /* skip "." component */
718                         while (*++p == '/') {
719                                 /* skip following slashes */
720                                 ;
721                         }
722                         continue;
723                 }
724                 allowdotdot = 0;
725                 if ((*p == '.') && (*(p+1) == '.') &&
726                             ((*(p+2) == '/') || (*(p+2) == '\0'))) {
727                         /* ".." component followed by slash or end */
728                         if ((depth > 0) && (sanp == start)) {
729                                 /* allow depth levels of .. at the beginning */
730                                 --depth;
731                                 allowdotdot = 1;
732                         } else {
733                                 p += 2;
734                                 if (*p == '/')
735                                         p++;
736                                 if (sanp != start) {
737                                         /* back up sanp one level */
738                                         --sanp; /* now pointing at slash */
739                                         while ((sanp > start) && (*(sanp - 1) != '/')) {
740                                                 /* skip back up to slash */
741                                                 sanp--;
742                                         }
743                                 }
744                                 continue;
745                         }
746                 }
747                 while (1) {
748                         /* copy one component through next slash */
749                         *sanp++ = *p++;
750                         if ((*p == '\0') || (*(p-1) == '/')) {
751                                 while (*p == '/') {
752                                         /* skip multiple slashes */
753                                         p++;
754                                 }
755                                 break;
756                         }
757                 }
758                 if (allowdotdot) {
759                         /* move the virtual beginning to leave the .. alone */
760                         start = sanp;
761                 }
762         }
763         if ((sanp == start) && !allowdotdot) {
764                 /* ended up with nothing, so put in "." component */
765                 /*
766                  * note that the !allowdotdot doesn't prevent this from
767                  *  happening in all allowed ".." situations, but I didn't
768                  *  think it was worth putting in an extra variable to ensure
769                  *  it since an extra "." won't hurt in those situations.
770                  */
771                 *sanp++ = '.';
772         }
773         *sanp = '\0';
774 }
775
776
777 static char curr_dir[MAXPATHLEN];
778
779 /* like chdir() but can be reversed with pop_dir() if save is set. It
780    is also much faster as it remembers where we have been */
781 char *push_dir(char *dir, int save)
782 {
783         char *ret = curr_dir;
784         static int initialised;
785
786         if (!initialised) {
787                 initialised = 1;
788                 getcwd(curr_dir, sizeof(curr_dir)-1);
789         }
790
791         if (!dir) return NULL; /* this call was probably just to initialize */
792
793         if (chdir(dir)) return NULL;
794
795         if (save) {
796                 ret = strdup(curr_dir);
797         }
798
799         if (*dir == '/') {
800                 strlcpy(curr_dir, dir, sizeof(curr_dir));
801         } else {
802                 strlcat(curr_dir,"/", sizeof(curr_dir));
803                 strlcat(curr_dir,dir, sizeof(curr_dir));
804         }
805
806         clean_fname(curr_dir);
807
808         return ret;
809 }
810
811 /* reverse a push_dir call */
812 int pop_dir(char *dir)
813 {
814         int ret;
815
816         ret = chdir(dir);
817         if (ret) {
818                 free(dir);
819                 return ret;
820         }
821
822         strlcpy(curr_dir, dir, sizeof(curr_dir));
823
824         free(dir);
825
826         return 0;
827 }
828
829 /* we need to supply our own strcmp function for file list comparisons
830    to ensure that signed/unsigned usage is consistent between machines. */
831 int u_strcmp(const char *cs1, const char *cs2)
832 {
833         const uchar *s1 = (const uchar *)cs1;
834         const uchar *s2 = (const uchar *)cs2;
835
836         while (*s1 && *s2 && (*s1 == *s2)) {
837                 s1++; s2++;
838         }
839         
840         return (int)*s1 - (int)*s2;
841 }
842
843 static OFF_T  last_ofs;
844 static struct timeval print_time;
845 static struct timeval start_time;
846 static OFF_T  start_ofs;
847
848 static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
849 {
850     return (t2->tv_sec - t1->tv_sec) * 1000
851         + (t2->tv_usec - t1->tv_usec) / 1000;
852 }
853
854
855 /**
856  * @param ofs Current position in file
857  * @param size Total size of file
858  * @param is_last True if this is the last time progress will be
859  * printed for this file, so we should output a newline.  (Not
860  * necessarily the same as all bytes being received.)
861  **/
862 static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
863                             int is_last)
864 {
865     int           pct  = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
866     unsigned long diff = msdiff(&start_time, now);
867     double        rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
868     const char    *units;
869     double        remain = rate ? (double) (size-ofs) / rate / 1000.0: 0.0;
870     int           remain_h, remain_m, remain_s;
871
872     if (rate > 1024*1024) {
873             rate /= 1024.0 * 1024.0;
874             units = "GB/s";
875     } else if (rate > 1024) {
876             rate /= 1024.0;
877             units = "MB/s";
878     } else {
879             units = "kB/s";
880     }
881
882     remain_s = (int) remain % 60;
883     remain_m = (int) (remain / 60.0) % 60;
884     remain_h = (int) (remain / 3600.0);
885     
886     rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
887             (double) ofs, pct, rate, units,
888             remain_h, remain_m, remain_s,
889             is_last ? "\n" : "\r");
890 }
891
892 void end_progress(OFF_T size)
893 {
894         extern int do_progress, am_server;
895
896         if (do_progress && !am_server) {
897                 struct timeval now;
898                 gettimeofday(&now, NULL);
899                 rprint_progress(size, size, &now, True);
900         }
901         last_ofs   = 0;
902         start_ofs  = 0;
903         print_time.tv_sec  = print_time.tv_usec  = 0;
904         start_time.tv_sec  = start_time.tv_usec  = 0;
905 }
906
907 void show_progress(OFF_T ofs, OFF_T size)
908 {
909         extern int do_progress, am_server;
910         struct timeval now;
911
912         gettimeofday(&now, NULL);
913
914         if (!start_time.tv_sec && !start_time.tv_usec) {
915                 start_time.tv_sec  = now.tv_sec;
916                 start_time.tv_usec = now.tv_usec;
917                 start_ofs          = ofs;
918         }
919
920         if (do_progress
921             && !am_server
922             && ofs > last_ofs + 1000
923             && msdiff(&print_time, &now) > 250) {
924                 rprint_progress(ofs, size, &now, False);
925                 last_ofs = ofs;
926                 print_time.tv_sec  = now.tv_sec;
927                 print_time.tv_usec = now.tv_usec;
928         }
929 }
930
931 /* determine if a symlink points outside the current directory tree */
932 int unsafe_symlink(char *dest, char *src)
933 {
934         char *tok;
935         int depth = 0;
936
937         /* all absolute and null symlinks are unsafe */
938         if (!dest || !(*dest) || (*dest == '/')) return 1;
939
940         src = strdup(src);
941         if (!src) out_of_memory("unsafe_symlink");
942
943         /* find out what our safety margin is */
944         for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
945                 if (strcmp(tok,"..") == 0) {
946                         depth=0;
947                 } else if (strcmp(tok,".") == 0) {
948                         /* nothing */
949                 } else {
950                         depth++;
951                 }
952         }
953         free(src);
954
955         /* drop by one to account for the filename portion */
956         depth--;
957
958         dest = strdup(dest);
959         if (!dest) out_of_memory("unsafe_symlink");
960
961         for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
962                 if (strcmp(tok,"..") == 0) {
963                         depth--;
964                 } else if (strcmp(tok,".") == 0) {
965                         /* nothing */
966                 } else {
967                         depth++;
968                 }
969                 /* if at any point we go outside the current directory then
970                    stop - it is unsafe */
971                 if (depth < 0) break;
972         }
973
974         free(dest);
975         return (depth < 0);
976 }
977
978
979 /****************************************************************************
980   return the date and time as a string
981 ****************************************************************************/
982 char *timestring(time_t t)
983 {
984         static char TimeBuf[200];
985         struct tm *tm = localtime(&t);
986
987 #ifdef HAVE_STRFTIME
988         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
989 #else
990         strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
991 #endif
992
993         if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
994                 TimeBuf[strlen(TimeBuf)-1] = 0;
995         }
996
997         return(TimeBuf);
998 }
999
1000
1001 /**
1002  * Sleep for a specified number of milliseconds.
1003  *
1004  * Always returns TRUE.  (In the future it might return FALSE if
1005  * interrupted.)
1006  **/
1007 int msleep(int t)
1008 {
1009         int tdiff=0;
1010         struct timeval tval,t1,t2;  
1011
1012         gettimeofday(&t1, NULL);
1013         gettimeofday(&t2, NULL);
1014   
1015         while (tdiff < t) {
1016                 tval.tv_sec = (t-tdiff)/1000;
1017                 tval.tv_usec = 1000*((t-tdiff)%1000);
1018  
1019                 errno = 0;
1020                 select(0,NULL,NULL, NULL, &tval);
1021
1022                 gettimeofday(&t2, NULL);
1023                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 + 
1024                         (t2.tv_usec - t1.tv_usec)/1000;
1025         }
1026
1027         return True;
1028 }
1029
1030
1031 /*******************************************************************
1032  Determine if two file modification times are equivalent (either exact 
1033  or in the modification timestamp window established by --modify-window) 
1034  Returns 0 if the times should be treated as the same, 1 if the 
1035  first is later and -1 if the 2nd is later
1036  *******************************************************************/
1037 int cmp_modtime(time_t file1, time_t file2)
1038 {
1039         extern int modify_window;
1040
1041         if (file2 > file1) {
1042                 if (file2 - file1 <= modify_window) return 0;
1043                 return -1;
1044         }
1045         if (file1 - file2 <= modify_window) return 0;
1046         return 1;
1047 }
1048
1049
1050 #ifdef __INSURE__XX
1051 #include <dlfcn.h>
1052
1053 /*******************************************************************
1054 This routine is a trick to immediately catch errors when debugging
1055 with insure. A xterm with a gdb is popped up when insure catches
1056 a error. It is Linux specific.
1057 ********************************************************************/
1058 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1059 {
1060         static int (*fn)();
1061         int ret;
1062         char *cmd;
1063
1064         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'", 
1065                 getpid(), getpid(), getpid());
1066
1067         if (!fn) {
1068                 static void *h;
1069                 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1070                 fn = dlsym(h, "_Insure_trap_error");
1071         }
1072
1073         ret = fn(a1, a2, a3, a4, a5, a6);
1074
1075         system(cmd);
1076
1077         free(cmd);
1078
1079         return ret;
1080 }
1081 #endif