Try to get test scripts to run properly.
[rsync.git] / util.c
blobada404653e3b615135f4c8e5a5a01fd6cfaa61ed
1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1996-2000 by Andrew Tridgell
4 Copyright (C) Paul Mackerras 1996
5 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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.
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.
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.
23 Utilities used in rsync
25 tridge, June 1996
27 #include "rsync.h"
29 extern int verbose;
32 /****************************************************************************
33 Set a fd into nonblocking mode
34 ****************************************************************************/
35 void set_nonblocking(int fd)
37 int val;
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);
47 /****************************************************************************
48 Set a fd into blocking mode
49 ****************************************************************************/
50 void set_blocking(int fd)
52 int val;
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);
63 /* create a file descriptor pair - like pipe() but use socketpair if
64 possible (because of blocking issues on pipes)
66 always set non-blocking
68 int fd_pair(int fd[2])
70 int ret;
72 #if HAVE_SOCKETPAIR
73 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
74 #else
75 ret = pipe(fd);
76 #endif
78 if (ret == 0) {
79 set_nonblocking(fd[0]);
80 set_nonblocking(fd[1]);
83 return ret;
87 /* this is derived from CVS code
89 note that in the child STDIN is set to blocking and STDOUT
90 is set to non-blocking. This is necessary as rsh relies on stdin being blocking
91 and ssh relies on stdout being non-blocking
93 if blocking_io is set then use blocking io on both fds. That can be
94 used to cope with badly broken rsh implementations like the one on
95 solaris.
97 pid_t piped_child(char **command,int *f_in,int *f_out)
99 pid_t pid;
100 int to_child_pipe[2];
101 int from_child_pipe[2];
102 extern int blocking_io;
104 if (fd_pair(to_child_pipe) < 0 ||
105 fd_pair(from_child_pipe) < 0) {
106 rprintf(FERROR,"pipe: %s\n",strerror(errno));
107 exit_cleanup(RERR_IPC);
111 pid = do_fork();
112 if (pid == -1) {
113 rprintf(FERROR,"fork: %s\n",strerror(errno));
114 exit_cleanup(RERR_IPC);
117 if (pid == 0)
119 extern int orig_umask;
120 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
121 close(to_child_pipe[1]) < 0 ||
122 close(from_child_pipe[0]) < 0 ||
123 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
124 rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
125 exit_cleanup(RERR_IPC);
127 if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
128 if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
129 umask(orig_umask);
130 set_blocking(STDIN_FILENO);
131 if (blocking_io) {
132 set_blocking(STDOUT_FILENO);
134 execvp(command[0], command);
135 rprintf(FERROR,"Failed to exec %s : %s\n",
136 command[0],strerror(errno));
137 exit_cleanup(RERR_IPC);
140 if (close(from_child_pipe[1]) < 0 ||
141 close(to_child_pipe[0]) < 0) {
142 rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
143 exit_cleanup(RERR_IPC);
146 *f_in = from_child_pipe[0];
147 *f_out = to_child_pipe[1];
149 return pid;
152 pid_t local_child(int argc, char **argv,int *f_in,int *f_out)
154 pid_t pid;
155 int to_child_pipe[2];
156 int from_child_pipe[2];
157 extern int read_batch; /* dw */
159 if (fd_pair(to_child_pipe) < 0 ||
160 fd_pair(from_child_pipe) < 0) {
161 rprintf(FERROR,"pipe: %s\n",strerror(errno));
162 exit_cleanup(RERR_IPC);
166 pid = do_fork();
167 if (pid == -1) {
168 rprintf(FERROR,"fork: %s\n",strerror(errno));
169 exit_cleanup(RERR_IPC);
172 if (pid == 0) {
173 extern int am_sender;
174 extern int am_server;
176 if (read_batch)
177 am_sender = 0;
178 else
179 am_sender = !am_sender;
180 am_server = 1;
182 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
183 close(to_child_pipe[1]) < 0 ||
184 close(from_child_pipe[0]) < 0 ||
185 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
186 rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
187 exit_cleanup(RERR_IPC);
189 if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
190 if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
191 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
194 if (close(from_child_pipe[1]) < 0 ||
195 close(to_child_pipe[0]) < 0) {
196 rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
197 exit_cleanup(RERR_IPC);
200 *f_in = from_child_pipe[0];
201 *f_out = to_child_pipe[1];
203 return pid;
208 void out_of_memory(char *str)
210 rprintf(FERROR,"ERROR: out of memory in %s\n",str);
211 exit_cleanup(RERR_MALLOC);
214 void overflow(char *str)
216 rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
217 exit_cleanup(RERR_MALLOC);
222 int set_modtime(char *fname,time_t modtime)
224 extern int dry_run;
225 if (dry_run) return 0;
227 #ifdef HAVE_UTIMBUF
228 struct utimbuf tbuf;
229 tbuf.actime = time(NULL);
230 tbuf.modtime = modtime;
231 return utime(fname,&tbuf);
232 #elif defined(HAVE_UTIME)
233 time_t t[2];
234 t[0] = time(NULL);
235 t[1] = modtime;
236 return utime(fname,t);
237 #else
238 struct timeval t[2];
239 t[0].tv_sec = time(NULL);
240 t[0].tv_usec = 0;
241 t[1].tv_sec = modtime;
242 t[1].tv_usec = 0;
243 return utimes(fname,t);
244 #endif
249 /****************************************************************************
250 create any necessary directories in fname. Unfortunately we don't know
251 what perms to give the directory when this is called so we need to rely
252 on the umask
253 ****************************************************************************/
254 int create_directory_path(char *fname)
256 extern int orig_umask;
257 char *p;
259 while (*fname == '/') fname++;
260 while (strncmp(fname,"./",2)==0) fname += 2;
262 p = fname;
263 while ((p=strchr(p,'/'))) {
264 *p = 0;
265 do_mkdir(fname,0777 & ~orig_umask);
266 *p = '/';
267 p++;
269 return 0;
273 /* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
274 Return LEN upon success, write's (negative) error code otherwise.
276 derived from GNU C's cccp.c.
278 static int full_write(int desc, char *ptr, int len)
280 int total_written;
282 total_written = 0;
283 while (len > 0) {
284 int written = write (desc, ptr, len);
285 if (written < 0) {
286 #ifdef EINTR
287 if (errno == EINTR)
288 continue;
289 #endif
290 return written;
292 total_written += written;
293 ptr += written;
294 len -= written;
296 return total_written;
299 /* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
300 Return the actual number of bytes read, zero for EOF, or negative
301 for an error.
303 derived from GNU C's cccp.c. */
304 static int safe_read(int desc, char *ptr, int len)
306 int n_chars;
308 if (len <= 0)
309 return len;
311 #ifdef EINTR
312 do {
313 n_chars = read(desc, ptr, len);
314 } while (n_chars < 0 && errno == EINTR);
315 #else
316 n_chars = read(desc, ptr, len);
317 #endif
319 return n_chars;
323 /* copy a file - this is used in conjunction with the --temp-dir option */
324 int copy_file(char *source, char *dest, mode_t mode)
326 int ifd;
327 int ofd;
328 char buf[1024 * 8];
329 int len; /* Number of bytes read into `buf'. */
331 ifd = do_open(source, O_RDONLY, 0);
332 if (ifd == -1) {
333 rprintf(FERROR,"open %s: %s\n",
334 source,strerror(errno));
335 return -1;
338 if (robust_unlink(dest) && errno != ENOENT) {
339 rprintf(FERROR,"unlink %s: %s\n",
340 dest,strerror(errno));
341 return -1;
344 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
345 if (ofd == -1) {
346 rprintf(FERROR,"open %s: %s\n",
347 dest,strerror(errno));
348 close(ifd);
349 return -1;
352 while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
353 if (full_write(ofd, buf, len) < 0) {
354 rprintf(FERROR,"write %s: %s\n",
355 dest,strerror(errno));
356 close(ifd);
357 close(ofd);
358 return -1;
362 close(ifd);
363 close(ofd);
365 if (len < 0) {
366 rprintf(FERROR,"read %s: %s\n",
367 source,strerror(errno));
368 return -1;
371 return 0;
375 Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
376 rename to <path>/.rsyncNNN instead. Note that successive rsync runs
377 will shuffle the filenames around a bit as long as the file is still
378 busy; this is because this function does not know if the unlink call
379 is due to a new file coming in, or --delete trying to remove old
380 .rsyncNNN files, hence it renames it each time.
382 /* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
383 #define MAX_RENAMES_DIGITS 3
384 #define MAX_RENAMES 1000
386 int robust_unlink(char *fname)
388 #ifndef ETXTBSY
389 return do_unlink(fname);
390 #else
391 static int counter = 1;
392 int rc, pos, start;
393 char path[MAXPATHLEN];
395 rc = do_unlink(fname);
396 if ((rc == 0) || (errno != ETXTBSY))
397 return rc;
399 strlcpy(path, fname, MAXPATHLEN);
401 pos = strlen(path);
402 while((path[--pos] != '/') && (pos >= 0))
404 ++pos;
405 strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
406 pos += sizeof(".rsync")-1;
408 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
409 errno = ETXTBSY;
410 return -1;
413 /* start where the last one left off to reduce chance of clashes */
414 start = counter;
415 do {
416 sprintf(&path[pos], "%03d", counter);
417 if (++counter >= MAX_RENAMES)
418 counter = 1;
419 } while (((rc = access(path, 0)) == 0) && (counter != start));
421 if (verbose > 0)
422 rprintf(FINFO,"renaming %s to %s because of text busy\n",
423 fname, path);
425 /* maybe we should return rename()'s exit status? Nah. */
426 if (do_rename(fname, path) != 0) {
427 errno = ETXTBSY;
428 return -1;
430 return 0;
431 #endif
434 int robust_rename(char *from, char *to)
436 #ifndef ETXTBSY
437 return do_rename(from, to);
438 #else
439 int rc = do_rename(from, to);
440 if ((rc == 0) || (errno != ETXTBSY))
441 return rc;
442 if (robust_unlink(to) != 0)
443 return -1;
444 return do_rename(from, to);
445 #endif
449 static pid_t all_pids[10];
450 static int num_pids;
452 /* fork and record the pid of the child */
453 pid_t do_fork(void)
455 pid_t newpid = fork();
457 if (newpid) {
458 all_pids[num_pids++] = newpid;
460 return newpid;
463 /* kill all children */
464 void kill_all(int sig)
466 int i;
467 for (i=0;i<num_pids;i++) {
468 if (all_pids[i] != getpid())
469 kill(all_pids[i], sig);
473 /* turn a user name into a uid */
474 int name_to_uid(char *name, uid_t *uid)
476 struct passwd *pass;
477 if (!name || !*name) return 0;
478 pass = getpwnam(name);
479 if (pass) {
480 *uid = pass->pw_uid;
481 return 1;
483 return 0;
486 /* turn a group name into a gid */
487 int name_to_gid(char *name, gid_t *gid)
489 struct group *grp;
490 if (!name || !*name) return 0;
491 grp = getgrnam(name);
492 if (grp) {
493 *gid = grp->gr_gid;
494 return 1;
496 return 0;
500 /* lock a byte range in a open file */
501 int lock_range(int fd, int offset, int len)
503 struct flock lock;
505 lock.l_type = F_WRLCK;
506 lock.l_whence = SEEK_SET;
507 lock.l_start = offset;
508 lock.l_len = len;
509 lock.l_pid = 0;
511 return fcntl(fd,F_SETLK,&lock) == 0;
515 static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
517 #if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
518 if (!*s) s = ".";
519 argv[*argc] = strdup(s);
520 (*argc)++;
521 return;
522 #else
523 extern int sanitize_paths;
524 glob_t globbuf;
525 int i;
527 if (!*s) s = ".";
529 argv[*argc] = strdup(s);
530 if (sanitize_paths) {
531 sanitize_path(argv[*argc], NULL);
534 memset(&globbuf, 0, sizeof(globbuf));
535 glob(argv[*argc], 0, NULL, &globbuf);
536 if (globbuf.gl_pathc == 0) {
537 (*argc)++;
538 globfree(&globbuf);
539 return;
541 for (i=0; i<(maxargs - (*argc)) && i<globbuf.gl_pathc;i++) {
542 if (i == 0) free(argv[*argc]);
543 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
544 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
546 globfree(&globbuf);
547 (*argc) += i;
548 #endif
551 void glob_expand(char *base1, char **argv, int *argc, int maxargs)
553 char *s = argv[*argc];
554 char *p, *q;
555 char *base = base1;
557 if (!s || !*s) return;
559 if (strncmp(s, base, strlen(base)) == 0) {
560 s += strlen(base);
563 s = strdup(s);
564 if (!s) out_of_memory("glob_expand");
566 if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
568 q = s;
569 while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
570 /* split it at this point */
571 *p = 0;
572 glob_expand_one(q, argv, argc, maxargs);
573 q = p+strlen(base);
576 if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
578 free(s);
579 free(base);
582 /*******************************************************************
583 convert a string to lower case
584 ********************************************************************/
585 void strlower(char *s)
587 while (*s) {
588 if (isupper(*s)) *s = tolower(*s);
589 s++;
593 void *Realloc(void *p, int size)
595 if (!p) return (void *)malloc(size);
596 return (void *)realloc(p, size);
600 void clean_fname(char *name)
602 char *p;
603 int l;
604 int modified = 1;
606 if (!name) return;
608 while (modified) {
609 modified = 0;
611 if ((p=strstr(name,"/./"))) {
612 modified = 1;
613 while (*p) {
614 p[0] = p[2];
615 p++;
619 if ((p=strstr(name,"//"))) {
620 modified = 1;
621 while (*p) {
622 p[0] = p[1];
623 p++;
627 if (strncmp(p=name,"./",2) == 0) {
628 modified = 1;
629 do {
630 p[0] = p[2];
631 } while (*p++);
634 l = strlen(p=name);
635 if (l > 1 && p[l-1] == '/') {
636 modified = 1;
637 p[l-1] = 0;
643 * Make path appear as if a chroot had occurred:
644 * 1. remove leading "/" (or replace with "." if at end)
645 * 2. remove leading ".." components (except those allowed by "reldir")
646 * 3. delete any other "<dir>/.." (recursively)
647 * Can only shrink paths, so sanitizes in place.
648 * While we're at it, remove double slashes and "." components like
649 * clean_fname does(), but DON'T remove a trailing slash because that
650 * is sometimes significant on command line arguments.
651 * If "reldir" is non-null, it is a sanitized directory that the path will be
652 * relative to, so allow as many ".." at the beginning of the path as
653 * there are components in reldir. This is used for symbolic link targets.
654 * If reldir is non-null and the path began with "/", to be completely like
655 * a chroot we should add in depth levels of ".." at the beginning of the
656 * path, but that would blow the assumption that the path doesn't grow and
657 * it is not likely to end up being a valid symlink anyway, so just do
658 * the normal removal of the leading "/" instead.
659 * Contributed by Dave Dykstra <dwd@bell-labs.com>
662 void sanitize_path(char *p, char *reldir)
664 char *start, *sanp;
665 int depth = 0;
666 int allowdotdot = 0;
668 if (reldir) {
669 depth++;
670 while (*reldir) {
671 if (*reldir++ == '/') {
672 depth++;
676 start = p;
677 sanp = p;
678 while (*p == '/') {
679 /* remove leading slashes */
680 p++;
682 while (*p != '\0') {
683 /* this loop iterates once per filename component in p.
684 * both p (and sanp if the original had a slash) should
685 * always be left pointing after a slash
687 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
688 /* skip "." component */
689 while (*++p == '/') {
690 /* skip following slashes */
693 continue;
695 allowdotdot = 0;
696 if ((*p == '.') && (*(p+1) == '.') &&
697 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
698 /* ".." component followed by slash or end */
699 if ((depth > 0) && (sanp == start)) {
700 /* allow depth levels of .. at the beginning */
701 --depth;
702 allowdotdot = 1;
703 } else {
704 p += 2;
705 if (*p == '/')
706 p++;
707 if (sanp != start) {
708 /* back up sanp one level */
709 --sanp; /* now pointing at slash */
710 while ((sanp > start) && (*(sanp - 1) != '/')) {
711 /* skip back up to slash */
712 sanp--;
715 continue;
718 while (1) {
719 /* copy one component through next slash */
720 *sanp++ = *p++;
721 if ((*p == '\0') || (*(p-1) == '/')) {
722 while (*p == '/') {
723 /* skip multiple slashes */
724 p++;
726 break;
729 if (allowdotdot) {
730 /* move the virtual beginning to leave the .. alone */
731 start = sanp;
734 if ((sanp == start) && !allowdotdot) {
735 /* ended up with nothing, so put in "." component */
737 * note that the !allowdotdot doesn't prevent this from
738 * happening in all allowed ".." situations, but I didn't
739 * think it was worth putting in an extra variable to ensure
740 * it since an extra "." won't hurt in those situations.
742 *sanp++ = '.';
744 *sanp = '\0';
748 static char curr_dir[MAXPATHLEN];
750 /* like chdir() but can be reversed with pop_dir() if save is set. It
751 is also much faster as it remembers where we have been */
752 char *push_dir(char *dir, int save)
754 char *ret = curr_dir;
755 static int initialised;
757 if (!initialised) {
758 initialised = 1;
759 getcwd(curr_dir, sizeof(curr_dir)-1);
762 if (!dir) return NULL; /* this call was probably just to initialize */
764 if (chdir(dir)) return NULL;
766 if (save) {
767 ret = strdup(curr_dir);
770 if (*dir == '/') {
771 strlcpy(curr_dir, dir, sizeof(curr_dir));
772 } else {
773 strlcat(curr_dir,"/", sizeof(curr_dir));
774 strlcat(curr_dir,dir, sizeof(curr_dir));
777 clean_fname(curr_dir);
779 return ret;
782 /* reverse a push_dir call */
783 int pop_dir(char *dir)
785 int ret;
787 ret = chdir(dir);
788 if (ret) {
789 free(dir);
790 return ret;
793 strlcpy(curr_dir, dir, sizeof(curr_dir));
795 free(dir);
797 return 0;
800 /* we need to supply our own strcmp function for file list comparisons
801 to ensure that signed/unsigned usage is consistent between machines. */
802 int u_strcmp(const char *cs1, const char *cs2)
804 const uchar *s1 = (const uchar *)cs1;
805 const uchar *s2 = (const uchar *)cs2;
807 while (*s1 && *s2 && (*s1 == *s2)) {
808 s1++; s2++;
811 return (int)*s1 - (int)*s2;
814 static OFF_T last_ofs;
816 void end_progress(OFF_T size)
818 extern int do_progress, am_server;
820 if (do_progress && !am_server) {
821 rprintf(FINFO,"%.0f (100%%)\n", (double)size);
823 last_ofs = 0;
826 void show_progress(OFF_T ofs, OFF_T size)
828 extern int do_progress, am_server;
830 if (do_progress && !am_server) {
831 if (ofs > last_ofs + 1000) {
832 int pct = (int)((100.0*ofs)/size);
833 rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct);
834 last_ofs = ofs;
839 /* determine if a symlink points outside the current directory tree */
840 int unsafe_symlink(char *dest, char *src)
842 char *tok;
843 int depth = 0;
845 /* all absolute and null symlinks are unsafe */
846 if (!dest || !(*dest) || (*dest == '/')) return 1;
848 src = strdup(src);
849 if (!src) out_of_memory("unsafe_symlink");
851 /* find out what our safety margin is */
852 for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
853 if (strcmp(tok,"..") == 0) {
854 depth=0;
855 } else if (strcmp(tok,".") == 0) {
856 /* nothing */
857 } else {
858 depth++;
861 free(src);
863 /* drop by one to account for the filename portion */
864 depth--;
866 dest = strdup(dest);
867 if (!dest) out_of_memory("unsafe_symlink");
869 for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
870 if (strcmp(tok,"..") == 0) {
871 depth--;
872 } else if (strcmp(tok,".") == 0) {
873 /* nothing */
874 } else {
875 depth++;
877 /* if at any point we go outside the current directory then
878 stop - it is unsafe */
879 if (depth < 0) break;
882 free(dest);
883 return (depth < 0);
887 /****************************************************************************
888 return the date and time as a string
889 ****************************************************************************/
890 char *timestring(time_t t)
892 static char TimeBuf[200];
893 struct tm *tm = localtime(&t);
895 #ifdef HAVE_STRFTIME
896 strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
897 #else
898 strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
899 #endif
901 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
902 TimeBuf[strlen(TimeBuf)-1] = 0;
905 return(TimeBuf);
910 * Sleep for a specified number of milliseconds.
912 * Always returns TRUE. (In the future it might return FALSE if
913 * interrupted.)
915 int msleep(int t)
917 int tdiff=0;
918 struct timeval tval,t1,t2;
920 gettimeofday(&t1, NULL);
921 gettimeofday(&t2, NULL);
923 while (tdiff < t) {
924 tval.tv_sec = (t-tdiff)/1000;
925 tval.tv_usec = 1000*((t-tdiff)%1000);
927 errno = 0;
928 select(0,NULL,NULL, NULL, &tval);
930 gettimeofday(&t2, NULL);
931 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
932 (t2.tv_usec - t1.tv_usec)/1000;
935 return True;
939 /*******************************************************************
940 Determine if two file modification times are equivalent (either exact
941 or in the modification timestamp window established by --modify-window)
942 Returns 0 if the times should be treated as the same, 1 if the
943 first is later and -1 if the 2nd is later
944 *******************************************************************/
945 int cmp_modtime(time_t file1, time_t file2)
947 extern int modify_window;
949 if (file2 > file1) {
950 if (file2 - file1 <= modify_window) return 0;
951 return -1;
953 if (file1 - file2 <= modify_window) return 0;
954 return 1;
958 #ifdef __INSURE__XX
959 #include <dlfcn.h>
961 /*******************************************************************
962 This routine is a trick to immediately catch errors when debugging
963 with insure. A xterm with a gdb is popped up when insure catches
964 a error. It is Linux specific.
965 ********************************************************************/
966 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
968 static int (*fn)();
969 int ret;
970 char *cmd;
972 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'",
973 getpid(), getpid(), getpid());
975 if (!fn) {
976 static void *h;
977 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
978 fn = dlsym(h, "_Insure_trap_error");
981 ret = fn(a1, a2, a3, a4, a5, a6);
983 system(cmd);
985 free(cmd);
987 return ret;
989 #endif