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