preparing for release of 2.5.7
[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(* (unsigned char *) s))
536                         *s = tolower(* (unsigned char *) s);
537                 s++;
538         }
539 }
540
541 void clean_fname(char *name)
542 {
543         char *p;
544         int l;
545         int modified = 1;
546
547         if (!name) return;
548
549         while (modified) {
550                 modified = 0;
551
552                 if ((p=strstr(name,"/./"))) {
553                         modified = 1;
554                         while (*p) {
555                                 p[0] = p[2];
556                                 p++;
557                         }
558                 }
559
560                 if ((p=strstr(name,"//"))) {
561                         modified = 1;
562                         while (*p) {
563                                 p[0] = p[1];
564                                 p++;
565                         }
566                 }
567
568                 if (strncmp(p=name,"./",2) == 0) {      
569                         modified = 1;
570                         do {
571                                 p[0] = p[2];
572                         } while (*p++);
573                 }
574
575                 l = strlen(p=name);
576                 if (l > 1 && p[l-1] == '/') {
577                         modified = 1;
578                         p[l-1] = 0;
579                 }
580         }
581 }
582
583 /**
584  * Make path appear as if a chroot had occurred:
585  *
586  * @li 1. remove leading "/" (or replace with "." if at end)
587  *
588  * @li 2. remove leading ".." components (except those allowed by @p reldir)
589  *
590  * @li 3. delete any other "<dir>/.." (recursively)
591  *
592  * Can only shrink paths, so sanitizes in place.
593  *
594  * While we're at it, remove double slashes and "." components like
595  *   clean_fname() does, but DON'T remove a trailing slash because that
596  *   is sometimes significant on command line arguments.
597  *
598  * If @p reldir is non-null, it is a sanitized directory that the path will be
599  *    relative to, so allow as many ".." at the beginning of the path as
600  *    there are components in reldir.  This is used for symbolic link targets.
601  *    If reldir is non-null and the path began with "/", to be completely like
602  *    a chroot we should add in depth levels of ".." at the beginning of the
603  *    path, but that would blow the assumption that the path doesn't grow and
604  *    it is not likely to end up being a valid symlink anyway, so just do
605  *    the normal removal of the leading "/" instead.
606  *
607  * Contributed by Dave Dykstra <dwd@bell-labs.com>
608  */
609 void sanitize_path(char *p, char *reldir)
610 {
611         char *start, *sanp;
612         int depth = 0;
613         int allowdotdot = 0;
614
615         if (reldir) {
616                 depth++;
617                 while (*reldir) {
618                         if (*reldir++ == '/') {
619                                 depth++;
620                         }
621                 }
622         }
623         start = p;
624         sanp = p;
625         while (*p == '/') {
626                 /* remove leading slashes */
627                 p++;
628         }
629         while (*p != '\0') {
630                 /* this loop iterates once per filename component in p.
631                  * both p (and sanp if the original had a slash) should
632                  * always be left pointing after a slash
633                  */
634                 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
635                         /* skip "." component */
636                         while (*++p == '/') {
637                                 /* skip following slashes */
638                                 ;
639                         }
640                         continue;
641                 }
642                 allowdotdot = 0;
643                 if ((*p == '.') && (*(p+1) == '.') &&
644                             ((*(p+2) == '/') || (*(p+2) == '\0'))) {
645                         /* ".." component followed by slash or end */
646                         if ((depth > 0) && (sanp == start)) {
647                                 /* allow depth levels of .. at the beginning */
648                                 --depth;
649                                 allowdotdot = 1;
650                         } else {
651                                 p += 2;
652                                 if (*p == '/')
653                                         p++;
654                                 if (sanp != start) {
655                                         /* back up sanp one level */
656                                         --sanp; /* now pointing at slash */
657                                         while ((sanp > start) && (*(sanp - 1) != '/')) {
658                                                 /* skip back up to slash */
659                                                 sanp--;
660                                         }
661                                 }
662                                 continue;
663                         }
664                 }
665                 while (1) {
666                         /* copy one component through next slash */
667                         *sanp++ = *p++;
668                         if ((*p == '\0') || (*(p-1) == '/')) {
669                                 while (*p == '/') {
670                                         /* skip multiple slashes */
671                                         p++;
672                                 }
673                                 break;
674                         }
675                 }
676                 if (allowdotdot) {
677                         /* move the virtual beginning to leave the .. alone */
678                         start = sanp;
679                 }
680         }
681         if ((sanp == start) && !allowdotdot) {
682                 /* ended up with nothing, so put in "." component */
683                 /*
684                  * note that the !allowdotdot doesn't prevent this from
685                  *  happening in all allowed ".." situations, but I didn't
686                  *  think it was worth putting in an extra variable to ensure
687                  *  it since an extra "." won't hurt in those situations.
688                  */
689                 *sanp++ = '.';
690         }
691         *sanp = '\0';
692 }
693
694
695 static char curr_dir[MAXPATHLEN];
696
697 /**
698  * Like chdir() but can be reversed with pop_dir() if @p save is set.
699  * It is also much faster as it remembers where we have been.
700  **/
701 char *push_dir(char *dir, int save)
702 {
703         char *ret = curr_dir;
704         static int initialised;
705
706         if (!initialised) {
707                 initialised = 1;
708                 getcwd(curr_dir, sizeof(curr_dir)-1);
709         }
710
711         if (!dir) return NULL; /* this call was probably just to initialize */
712
713         if (chdir(dir)) return NULL;
714
715         if (save) {
716                 ret = strdup(curr_dir);
717         }
718
719         if (*dir == '/') {
720                 strlcpy(curr_dir, dir, sizeof(curr_dir));
721         } else {
722                 strlcat(curr_dir,"/", sizeof(curr_dir));
723                 strlcat(curr_dir,dir, sizeof(curr_dir));
724         }
725
726         clean_fname(curr_dir);
727
728         return ret;
729 }
730
731 /** Reverse a push_dir() call */
732 int pop_dir(char *dir)
733 {
734         int ret;
735
736         ret = chdir(dir);
737         if (ret) {
738                 free(dir);
739                 return ret;
740         }
741
742         strlcpy(curr_dir, dir, sizeof(curr_dir));
743
744         free(dir);
745
746         return 0;
747 }
748
749 /** We need to supply our own strcmp function for file list comparisons
750    to ensure that signed/unsigned usage is consistent between machines. */
751 int u_strcmp(const char *cs1, const char *cs2)
752 {
753         const uchar *s1 = (const uchar *)cs1;
754         const uchar *s2 = (const uchar *)cs2;
755
756         while (*s1 && *s2 && (*s1 == *s2)) {
757                 s1++; s2++;
758         }
759         
760         return (int)*s1 - (int)*s2;
761 }
762
763
764
765 /**
766  * Determine if a symlink points outside the current directory tree.
767  * This is considered "unsafe" because e.g. when mirroring somebody
768  * else's machine it might allow them to establish a symlink to
769  * /etc/passwd, and then read it through a web server.
770  *
771  * Null symlinks and absolute symlinks are always unsafe.
772  *
773  * Basically here we are concerned with symlinks whose target contains
774  * "..", because this might cause us to walk back up out of the
775  * transferred directory.  We are not allowed to go back up and
776  * reenter.
777  *
778  * @param dest Target of the symlink in question.
779  *
780  * @param src Top source directory currently applicable.  Basically this
781  * is the first parameter to rsync in a simple invocation, but it's
782  * modified by flist.c in slightly complex ways.
783  *
784  * @retval True if unsafe
785  * @retval False is unsafe
786  *
787  * @sa t_unsafe.c
788  **/
789 int unsafe_symlink(const char *dest, const char *src)
790 {
791         const char *name, *slash;
792         int depth = 0;
793
794         /* all absolute and null symlinks are unsafe */
795         if (!dest || !*dest || *dest == '/') return 1;
796
797         /* find out what our safety margin is */
798         for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
799                 if (strncmp(name, "../", 3) == 0) {
800                         depth=0;
801                 } else if (strncmp(name, "./", 2) == 0) {
802                         /* nothing */
803                 } else {
804                         depth++;
805                 }
806         }
807         if (strcmp(name, "..") == 0)
808                 depth = 0;
809
810         for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
811                 if (strncmp(name, "../", 3) == 0) {
812                         /* if at any point we go outside the current directory
813                            then stop - it is unsafe */
814                         if (--depth < 0)
815                                 return 1;
816                 } else if (strncmp(name, "./", 2) == 0) {
817                         /* nothing */
818                 } else {
819                         depth++;
820                 }
821         }
822         if (strcmp(name, "..") == 0)
823                 depth--;
824
825         return (depth < 0);
826 }
827
828
829 /**
830  * Return the date and time as a string
831  **/
832 char *timestring(time_t t)
833 {
834         static char TimeBuf[200];
835         struct tm *tm = localtime(&t);
836
837 #ifdef HAVE_STRFTIME
838         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
839 #else
840         strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
841 #endif
842
843         if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
844                 TimeBuf[strlen(TimeBuf)-1] = 0;
845         }
846
847         return(TimeBuf);
848 }
849
850
851 /**
852  * Sleep for a specified number of milliseconds.
853  *
854  * Always returns TRUE.  (In the future it might return FALSE if
855  * interrupted.)
856  **/
857 int msleep(int t)
858 {
859         int tdiff=0;
860         struct timeval tval,t1,t2;  
861
862         gettimeofday(&t1, NULL);
863         gettimeofday(&t2, NULL);
864   
865         while (tdiff < t) {
866                 tval.tv_sec = (t-tdiff)/1000;
867                 tval.tv_usec = 1000*((t-tdiff)%1000);
868  
869                 errno = 0;
870                 select(0,NULL,NULL, NULL, &tval);
871
872                 gettimeofday(&t2, NULL);
873                 tdiff = (t2.tv_sec - t1.tv_sec)*1000 + 
874                         (t2.tv_usec - t1.tv_usec)/1000;
875         }
876
877         return True;
878 }
879
880
881 /**
882  * Determine if two file modification times are equivalent (either
883  * exact or in the modification timestamp window established by
884  * --modify-window).
885  *
886  * @retval 0 if the times should be treated as the same
887  *
888  * @retval +1 if the first is later
889  *
890  * @retval -1 if the 2nd is later
891  **/
892 int cmp_modtime(time_t file1, time_t file2)
893 {
894         extern int modify_window;
895
896         if (file2 > file1) {
897                 if (file2 - file1 <= modify_window) return 0;
898                 return -1;
899         }
900         if (file1 - file2 <= modify_window) return 0;
901         return 1;
902 }
903
904
905 #ifdef __INSURE__XX
906 #include <dlfcn.h>
907
908 /**
909    This routine is a trick to immediately catch errors when debugging
910    with insure. A xterm with a gdb is popped up when insure catches
911    a error. It is Linux specific.
912 **/
913 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
914 {
915         static int (*fn)();
916         int ret;
917         char *cmd;
918
919         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'", 
920                 getpid(), getpid(), getpid());
921
922         if (!fn) {
923                 static void *h;
924                 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
925                 fn = dlsym(h, "_Insure_trap_error");
926         }
927
928         ret = fn(a1, a2, a3, a4, a5, a6);
929
930         system(cmd);
931
932         free(cmd);
933
934         return ret;
935 }
936 #endif
937
938
939 #define MALLOC_MAX 0x40000000
940
941 void *_new_array(unsigned int size, unsigned long num)
942 {
943         if (num >= MALLOC_MAX/size)
944                 return NULL;
945         return malloc(size * num);
946 }
947
948 void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
949 {
950         if (num >= MALLOC_MAX/size)
951                 return NULL;
952         /* No realloc should need this, but just in case... */
953         if (!ptr)
954                 return malloc(size * num);
955         return realloc(ptr, size * num);
956 }