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