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