Clean up comments for Doxygen.
[rsync/rsync.git] / util.c
CommitLineData
1960e228
MP
1/* -*- c-file-style: "linux" -*-
2
3 Copyright (C) 1996-2000 by Andrew Tridgell
4 Copyright (C) Paul Mackerras 1996
a9b31409 5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
c627d613
AT
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
ac13ad10
MP
22/**
23 *
24 * @file util.c
25 *
26 * Utilities used in rsync
27 **/
c627d613 28
c627d613
AT
29#include "rsync.h"
30
c7c11a0d
DD
31extern int verbose;
32
f0359dd0 33
ac13ad10
MP
34/**
35 Set a fd into nonblocking mode
36**/
f0359dd0
AT
37void set_nonblocking(int fd)
38{
39 int val;
40
41 if((val = fcntl(fd, F_GETFL, 0)) == -1)
42 return;
43 if (!(val & NONBLOCK_FLAG)) {
44 val |= NONBLOCK_FLAG;
45 fcntl(fd, F_SETFL, val);
46 }
47}
48
ac13ad10 49/**
36349ea0 50Set a fd into blocking mode
ac13ad10 51*/
36349ea0
AT
52void set_blocking(int fd)
53{
54 int val;
55
56 if((val = fcntl(fd, F_GETFL, 0)) == -1)
57 return;
58 if (val & NONBLOCK_FLAG) {
59 val &= ~NONBLOCK_FLAG;
60 fcntl(fd, F_SETFL, val);
61 }
62}
63
f0359dd0 64
ac13ad10
MP
65/**
66 Create a file descriptor pair - like pipe() but use socketpair if
67 possible (because of blocking issues on pipes).
f0359dd0 68
ac13ad10 69 Always set non-blocking.
f0359dd0 70 */
08f15335
AT
71int fd_pair(int fd[2])
72{
f0359dd0
AT
73 int ret;
74
08f15335 75#if HAVE_SOCKETPAIR
f0359dd0 76 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
08f15335 77#else
f0359dd0 78 ret = pipe(fd);
08f15335 79#endif
f0359dd0
AT
80
81 if (ret == 0) {
82 set_nonblocking(fd[0]);
83 set_nonblocking(fd[1]);
84 }
85
86 return ret;
08f15335
AT
87}
88
89
6dd41b67 90static void print_child_argv(char **cmd)
5ad0e46f 91{
1bbd10fe 92 rprintf(FINFO, "opening connection using ");
5ad0e46f
MP
93 for (; *cmd; cmd++) {
94 /* Look for characters that ought to be quoted. This
95 * is not a great quoting algorithm, but it's
96 * sufficient for a log message. */
97 if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz"
98 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
99 "0123456789"
100 ",.-_=+@/") != strlen(*cmd)) {
101 rprintf(FINFO, "\"%s\" ", *cmd);
102 } else {
103 rprintf(FINFO, "%s ", *cmd);
104 }
105 }
106 rprintf(FINFO, "\n");
107}
108
109
ac13ad10
MP
110/**
111 * Create a child connected to use on stdin/stdout.
112 *
113 * This is derived from CVS code
114 *
115 * Note that in the child STDIN is set to blocking and STDOUT
116 * is set to non-blocking. This is necessary as rsh relies on stdin being blocking
117 * and ssh relies on stdout being non-blocking
118 *
119 * If blocking_io is set then use blocking io on both fds. That can be
120 * used to cope with badly broken rsh implementations like the one on
121 * Solaris.
122 **/
1b5814e3 123pid_t piped_child(char **command, int *f_in, int *f_out)
c627d613 124{
1b5814e3
MP
125 pid_t pid;
126 int to_child_pipe[2];
127 int from_child_pipe[2];
128 extern int blocking_io;
5ad0e46f 129
0b1ffe27 130 if (verbose >= 2) {
5ad0e46f
MP
131 print_child_argv(command);
132 }
1b5814e3
MP
133
134 if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
135 rprintf(FERROR, "pipe: %s\n", strerror(errno));
136 exit_cleanup(RERR_IPC);
137 }
138
139
140 pid = do_fork();
141 if (pid == -1) {
142 rprintf(FERROR, "fork: %s\n", strerror(errno));
143 exit_cleanup(RERR_IPC);
144 }
145
146 if (pid == 0) {
147 extern int orig_umask;
148 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
149 close(to_child_pipe[1]) < 0 ||
150 close(from_child_pipe[0]) < 0 ||
151 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
152 rprintf(FERROR, "Failed to dup/close : %s\n",
153 strerror(errno));
154 exit_cleanup(RERR_IPC);
155 }
156 if (to_child_pipe[0] != STDIN_FILENO)
157 close(to_child_pipe[0]);
158 if (from_child_pipe[1] != STDOUT_FILENO)
159 close(from_child_pipe[1]);
160 umask(orig_umask);
161 set_blocking(STDIN_FILENO);
162 if (blocking_io) {
163 set_blocking(STDOUT_FILENO);
164 }
165 execvp(command[0], command);
166 rprintf(FERROR, "Failed to exec %s : %s\n",
167 command[0], strerror(errno));
168 exit_cleanup(RERR_IPC);
169 }
170
171 if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
172 rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
173 exit_cleanup(RERR_IPC);
174 }
175
176 *f_in = from_child_pipe[0];
177 *f_out = to_child_pipe[1];
178
179 return pid;
c627d613
AT
180}
181
19b27a48 182pid_t local_child(int argc, char **argv,int *f_in,int *f_out)
366345fe 183{
19b27a48 184 pid_t pid;
366345fe
AT
185 int to_child_pipe[2];
186 int from_child_pipe[2];
6902ed17 187 extern int read_batch; /* dw */
366345fe 188
08f15335
AT
189 if (fd_pair(to_child_pipe) < 0 ||
190 fd_pair(from_child_pipe) < 0) {
9486289c 191 rprintf(FERROR,"pipe: %s\n",strerror(errno));
65417579 192 exit_cleanup(RERR_IPC);
366345fe
AT
193 }
194
195
196 pid = do_fork();
19b27a48 197 if (pid == -1) {
9486289c 198 rprintf(FERROR,"fork: %s\n",strerror(errno));
65417579 199 exit_cleanup(RERR_IPC);
366345fe
AT
200 }
201
202 if (pid == 0) {
203 extern int am_sender;
204 extern int am_server;
205
76f79ba7 206 am_sender = read_batch ? 0 : !am_sender;
366345fe
AT
207 am_server = 1;
208
209 if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
210 close(to_child_pipe[1]) < 0 ||
211 close(from_child_pipe[0]) < 0 ||
212 dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
9486289c 213 rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
65417579 214 exit_cleanup(RERR_IPC);
366345fe
AT
215 }
216 if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
217 if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
9486289c 218 start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
366345fe
AT
219 }
220
221 if (close(from_child_pipe[1]) < 0 ||
222 close(to_child_pipe[0]) < 0) {
9486289c 223 rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
65417579 224 exit_cleanup(RERR_IPC);
366345fe
AT
225 }
226
227 *f_in = from_child_pipe[0];
228 *f_out = to_child_pipe[1];
229
230 return pid;
231}
232
233
c627d613
AT
234
235void out_of_memory(char *str)
236{
9486289c 237 rprintf(FERROR,"ERROR: out of memory in %s\n",str);
65417579 238 exit_cleanup(RERR_MALLOC);
575f2fca
AT
239}
240
241void overflow(char *str)
242{
9486289c 243 rprintf(FERROR,"ERROR: buffer overflow in %s\n",str);
65417579 244 exit_cleanup(RERR_MALLOC);
c627d613
AT
245}
246
247
c627d613 248
404e813c 249int set_modtime(char *fname, time_t modtime)
c627d613 250{
31e12522 251 extern int dry_run;
404e813c
MP
252 if (dry_run)
253 return 0;
254
255 if (verbose > 2) {
256 rprintf(FINFO, "set modtime of %s to (%ld) %s",
257 fname, (long) modtime,
258 asctime(localtime(&modtime)));
259 }
260
31e12522 261 {
1e9f155a 262#ifdef HAVE_UTIMBUF
31e12522
AT
263 struct utimbuf tbuf;
264 tbuf.actime = time(NULL);
265 tbuf.modtime = modtime;
266 return utime(fname,&tbuf);
c627d613 267#elif defined(HAVE_UTIME)
31e12522
AT
268 time_t t[2];
269 t[0] = time(NULL);
270 t[1] = modtime;
271 return utime(fname,t);
c627d613 272#else
31e12522
AT
273 struct timeval t[2];
274 t[0].tv_sec = time(NULL);
275 t[0].tv_usec = 0;
276 t[1].tv_sec = modtime;
277 t[1].tv_usec = 0;
278 return utimes(fname,t);
c627d613 279#endif
31e12522 280 }
c627d613 281}
94481d91 282
720b47f2 283
ac13ad10
MP
284/**
285 Create any necessary directories in fname. Unfortunately we don't know
286 what perms to give the directory when this is called so we need to rely
287 on the umask
288**/
6574b4f7
AT
289int create_directory_path(char *fname)
290{
291 extern int orig_umask;
292 char *p;
293
294 while (*fname == '/') fname++;
295 while (strncmp(fname,"./",2)==0) fname += 2;
296
297 p = fname;
298 while ((p=strchr(p,'/'))) {
299 *p = 0;
1b2d733a 300 do_mkdir(fname,0777 & ~orig_umask);
6574b4f7
AT
301 *p = '/';
302 p++;
303 }
304 return 0;
305}
950ab32d
AT
306
307
ac13ad10
MP
308/**
309 * Write @p len bytes at @p ptr to descriptor @p desc, retrying if
310 * interrupted.
311 *
312 * @retval len upon success
313 *
314 * @retval <0 write's (negative) error code
315 *
316 * Derived from GNU C's cccp.c.
317 */
9dd891bb 318static int full_write(int desc, char *ptr, size_t len)
950ab32d
AT
319{
320 int total_written;
321
322 total_written = 0;
323 while (len > 0) {
324 int written = write (desc, ptr, len);
325 if (written < 0) {
326#ifdef EINTR
327 if (errno == EINTR)
328 continue;
329#endif
330 return written;
331 }
332 total_written += written;
333 ptr += written;
334 len -= written;
335 }
336 return total_written;
337}
338
950ab32d 339
ac13ad10
MP
340/**
341 * Read @p len bytes at @p ptr from descriptor @p desc, retrying if
342 * interrupted.
343 *
344 * @retval >0 the actual number of bytes read
345 *
346 * @retval 0 for EOF
347 *
348 * @retval <0 for an error.
349 *
350 * Derived from GNU C's cccp.c. */
9dd891bb 351static int safe_read(int desc, char *ptr, size_t len)
950ab32d
AT
352{
353 int n_chars;
354
9dd891bb 355 if (len == 0)
950ab32d
AT
356 return len;
357
358#ifdef EINTR
359 do {
360 n_chars = read(desc, ptr, len);
361 } while (n_chars < 0 && errno == EINTR);
362#else
363 n_chars = read(desc, ptr, len);
364#endif
365
366 return n_chars;
367}
368
369
ac13ad10
MP
370/** Copy a file.
371 *
372 * This is used in conjunction with the --temp-dir option */
950ab32d
AT
373int copy_file(char *source, char *dest, mode_t mode)
374{
375 int ifd;
376 int ofd;
377 char buf[1024 * 8];
378 int len; /* Number of bytes read into `buf'. */
379
8c9fd200 380 ifd = do_open(source, O_RDONLY, 0);
950ab32d 381 if (ifd == -1) {
9486289c 382 rprintf(FERROR,"open %s: %s\n",
950ab32d
AT
383 source,strerror(errno));
384 return -1;
385 }
386
c7c11a0d 387 if (robust_unlink(dest) && errno != ENOENT) {
9486289c 388 rprintf(FERROR,"unlink %s: %s\n",
950ab32d
AT
389 dest,strerror(errno));
390 return -1;
391 }
392
31e12522 393 ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
c46ded46 394 if (ofd == -1) {
9486289c 395 rprintf(FERROR,"open %s: %s\n",
950ab32d
AT
396 dest,strerror(errno));
397 close(ifd);
398 return -1;
399 }
400
401 while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
402 if (full_write(ofd, buf, len) < 0) {
9486289c 403 rprintf(FERROR,"write %s: %s\n",
950ab32d
AT
404 dest,strerror(errno));
405 close(ifd);
406 close(ofd);
407 return -1;
408 }
409 }
410
411 close(ifd);
412 close(ofd);
413
414 if (len < 0) {
9486289c 415 rprintf(FERROR,"read %s: %s\n",
950ab32d
AT
416 source,strerror(errno));
417 return -1;
418 }
419
420 return 0;
421}
feaa89c4 422
c7c11a0d
DD
423/* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */
424#define MAX_RENAMES_DIGITS 3
425#define MAX_RENAMES 1000
426
ac13ad10
MP
427/**
428 *
429 Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so
430 rename to <path>/.rsyncNNN instead.
431
432 Note that successive rsync runs will shuffle the filenames around a
433 bit as long as the file is still busy; this is because this function
434 does not know if the unlink call is due to a new file coming in, or
435 --delete trying to remove old .rsyncNNN files, hence it renames it
436 each time.
437*/
c7c11a0d
DD
438int robust_unlink(char *fname)
439{
440#ifndef ETXTBSY
441 return do_unlink(fname);
442#else
443 static int counter = 1;
444 int rc, pos, start;
445 char path[MAXPATHLEN];
446
447 rc = do_unlink(fname);
448 if ((rc == 0) || (errno != ETXTBSY))
449 return rc;
450
451 strlcpy(path, fname, MAXPATHLEN);
452
453 pos = strlen(path);
454 while((path[--pos] != '/') && (pos >= 0))
455 ;
456 ++pos;
457 strlcpy(&path[pos], ".rsync", MAXPATHLEN-pos);
458 pos += sizeof(".rsync")-1;
459
460 if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) {
461 errno = ETXTBSY;
462 return -1;
463 }
464
465 /* start where the last one left off to reduce chance of clashes */
466 start = counter;
467 do {
468 sprintf(&path[pos], "%03d", counter);
469 if (++counter >= MAX_RENAMES)
470 counter = 1;
471 } while (((rc = access(path, 0)) == 0) && (counter != start));
472
473 if (verbose > 0)
474 rprintf(FINFO,"renaming %s to %s because of text busy\n",
475 fname, path);
476
477 /* maybe we should return rename()'s exit status? Nah. */
478 if (do_rename(fname, path) != 0) {
479 errno = ETXTBSY;
480 return -1;
481 }
482 return 0;
483#endif
484}
485
486int robust_rename(char *from, char *to)
487{
488#ifndef ETXTBSY
489 return do_rename(from, to);
490#else
491 int rc = do_rename(from, to);
492 if ((rc == 0) || (errno != ETXTBSY))
493 return rc;
494 if (robust_unlink(to) != 0)
495 return -1;
496 return do_rename(from, to);
497#endif
feaa89c4 498}
3ba62a83
AT
499
500
501static pid_t all_pids[10];
502static int num_pids;
503
4cf64834 504/** Fork and record the pid of the child. **/
3ba62a83
AT
505pid_t do_fork(void)
506{
507 pid_t newpid = fork();
508
4cf64834 509 if (newpid != 0 && newpid != -1) {
3ba62a83
AT
510 all_pids[num_pids++] = newpid;
511 }
512 return newpid;
513}
514
4cf64834
MP
515/**
516 * Kill all children.
517 *
518 * @todo It would be kind of nice to make sure that they are actually
519 * all our children before we kill them, because their pids may have
520 * been recycled by some other process. Perhaps when we wait for a
521 * child, we should remove it from this array. Alternatively we could
522 * perhaps use process groups, but I think that would not work on
523 * ancient Unix versions that don't support them.
524 **/
3ba62a83
AT
525void kill_all(int sig)
526{
527 int i;
4cf64834
MP
528
529 for (i = 0; i < num_pids; i++) {
530 /* Let's just be a little careful where we
531 * point that gun, hey? See kill(2) for the
532 * magic caused by negative values. */
533 pid_t p = all_pids[i];
534
535 if (p == getpid())
536 continue;
537 if (p <= 0)
538 continue;
539
540 kill(p, sig);
3ba62a83
AT
541 }
542}
9486289c 543
4cf64834 544
ac13ad10 545/** Turn a user name into a uid */
8ef4ffd6
AT
546int name_to_uid(char *name, uid_t *uid)
547{
548 struct passwd *pass;
549 if (!name || !*name) return 0;
550 pass = getpwnam(name);
551 if (pass) {
552 *uid = pass->pw_uid;
553 return 1;
554 }
555 return 0;
556}
557
ac13ad10 558/** Turn a group name into a gid */
8ef4ffd6
AT
559int name_to_gid(char *name, gid_t *gid)
560{
561 struct group *grp;
562 if (!name || !*name) return 0;
563 grp = getgrnam(name);
564 if (grp) {
565 *gid = grp->gr_gid;
566 return 1;
567 }
568 return 0;
569}
570
ff8b29b8 571
ac13ad10 572/** Lock a byte range in a open file */
31593dd6 573int lock_range(int fd, int offset, int len)
0c515f17 574{
31593dd6 575 struct flock lock;
0c515f17 576
31593dd6
AT
577 lock.l_type = F_WRLCK;
578 lock.l_whence = SEEK_SET;
579 lock.l_start = offset;
580 lock.l_len = len;
581 lock.l_pid = 0;
582
583 return fcntl(fd,F_SETLK,&lock) == 0;
0c515f17 584}
874895d5
AT
585
586
cb13abfe 587static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
874895d5 588{
932be9aa 589#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
e42c9458 590 if (!*s) s = ".";
087bf010 591 argv[*argc] = strdup(s);
874895d5
AT
592 (*argc)++;
593 return;
594#else
cb13abfe 595 extern int sanitize_paths;
874895d5
AT
596 glob_t globbuf;
597 int i;
598
e42c9458
AT
599 if (!*s) s = ".";
600
cb13abfe
DD
601 argv[*argc] = strdup(s);
602 if (sanitize_paths) {
603 sanitize_path(argv[*argc], NULL);
604 }
087bf010 605
874895d5
AT
606 memset(&globbuf, 0, sizeof(globbuf));
607 glob(argv[*argc], 0, NULL, &globbuf);
608 if (globbuf.gl_pathc == 0) {
609 (*argc)++;
610 globfree(&globbuf);
611 return;
612 }
a261989c 613 for (i=0; i<(maxargs - (*argc)) && i < (int) globbuf.gl_pathc;i++) {
874895d5
AT
614 if (i == 0) free(argv[*argc]);
615 argv[(*argc) + i] = strdup(globbuf.gl_pathv[i]);
616 if (!argv[(*argc) + i]) out_of_memory("glob_expand");
617 }
618 globfree(&globbuf);
619 (*argc) += i;
620#endif
621}
5a96ee05 622
cb13abfe 623void glob_expand(char *base1, char **argv, int *argc, int maxargs)
087bf010
AT
624{
625 char *s = argv[*argc];
626 char *p, *q;
ba5e128d 627 char *base = base1;
087bf010
AT
628
629 if (!s || !*s) return;
630
e42c9458
AT
631 if (strncmp(s, base, strlen(base)) == 0) {
632 s += strlen(base);
633 }
634
087bf010
AT
635 s = strdup(s);
636 if (!s) out_of_memory("glob_expand");
637
8950ac03 638 if (asprintf(&base," %s/", base1) <= 0) out_of_memory("glob_expand");
ba5e128d 639
087bf010
AT
640 q = s;
641 while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
ba5e128d
AT
642 /* split it at this point */
643 *p = 0;
cb13abfe 644 glob_expand_one(q, argv, argc, maxargs);
ba5e128d 645 q = p+strlen(base);
087bf010
AT
646 }
647
cb13abfe 648 if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
087bf010
AT
649
650 free(s);
ba5e128d 651 free(base);
087bf010 652}
5a96ee05 653
ac13ad10
MP
654/**
655 * Convert a string to lower case
656 **/
5a96ee05
AT
657void strlower(char *s)
658{
659 while (*s) {
660 if (isupper(*s)) *s = tolower(*s);
661 s++;
662 }
663}
e42c9458 664
fe8c0a98
AT
665void *Realloc(void *p, int size)
666{
667 if (!p) return (void *)malloc(size);
668 return (void *)realloc(p, size);
669}
5243c216
AT
670
671
672void clean_fname(char *name)
673{
674 char *p;
675 int l;
676 int modified = 1;
677
678 if (!name) return;
679
680 while (modified) {
681 modified = 0;
682
683 if ((p=strstr(name,"/./"))) {
684 modified = 1;
685 while (*p) {
686 p[0] = p[2];
687 p++;
688 }
689 }
690
691 if ((p=strstr(name,"//"))) {
692 modified = 1;
693 while (*p) {
694 p[0] = p[1];
695 p++;
696 }
697 }
698
699 if (strncmp(p=name,"./",2) == 0) {
700 modified = 1;
701 do {
702 p[0] = p[2];
703 } while (*p++);
704 }
705
706 l = strlen(p=name);
707 if (l > 1 && p[l-1] == '/') {
708 modified = 1;
709 p[l-1] = 0;
710 }
711 }
712}
713
ac13ad10 714/**
1b8e662a 715 * Make path appear as if a chroot had occurred:
ac13ad10 716 *
1b8e662a 717 * 1. remove leading "/" (or replace with "." if at end)
cb13abfe 718 * 2. remove leading ".." components (except those allowed by "reldir")
1b8e662a 719 * 3. delete any other "<dir>/.." (recursively)
ac13ad10 720 *
79452d46 721 * Can only shrink paths, so sanitizes in place.
ac13ad10 722 *
b5f9e67d
DD
723 * While we're at it, remove double slashes and "." components like
724 * clean_fname does(), but DON'T remove a trailing slash because that
725 * is sometimes significant on command line arguments.
ac13ad10 726 *
79452d46
DD
727 * If "reldir" is non-null, it is a sanitized directory that the path will be
728 * relative to, so allow as many ".." at the beginning of the path as
729 * there are components in reldir. This is used for symbolic link targets.
730 * If reldir is non-null and the path began with "/", to be completely like
731 * a chroot we should add in depth levels of ".." at the beginning of the
732 * path, but that would blow the assumption that the path doesn't grow and
733 * it is not likely to end up being a valid symlink anyway, so just do
734 * the normal removal of the leading "/" instead.
ac13ad10 735 *
1b8e662a
DD
736 * Contributed by Dave Dykstra <dwd@bell-labs.com>
737 */
cb13abfe 738void sanitize_path(char *p, char *reldir)
1b8e662a 739{
44e2e578 740 char *start, *sanp;
cb13abfe
DD
741 int depth = 0;
742 int allowdotdot = 0;
743
744 if (reldir) {
745 depth++;
746 while (*reldir) {
747 if (*reldir++ == '/') {
748 depth++;
749 }
750 }
751 }
44e2e578
DD
752 start = p;
753 sanp = p;
b5f9e67d
DD
754 while (*p == '/') {
755 /* remove leading slashes */
756 p++;
757 }
1b8e662a 758 while (*p != '\0') {
b5f9e67d 759 /* this loop iterates once per filename component in p.
44e2e578 760 * both p (and sanp if the original had a slash) should
b5f9e67d
DD
761 * always be left pointing after a slash
762 */
763 if ((*p == '.') && ((*(p+1) == '/') || (*(p+1) == '\0'))) {
764 /* skip "." component */
765 while (*++p == '/') {
766 /* skip following slashes */
767 ;
768 }
cb13abfe
DD
769 continue;
770 }
771 allowdotdot = 0;
772 if ((*p == '.') && (*(p+1) == '.') &&
1b8e662a 773 ((*(p+2) == '/') || (*(p+2) == '\0'))) {
cb13abfe
DD
774 /* ".." component followed by slash or end */
775 if ((depth > 0) && (sanp == start)) {
776 /* allow depth levels of .. at the beginning */
777 --depth;
778 allowdotdot = 1;
779 } else {
780 p += 2;
781 if (*p == '/')
782 p++;
783 if (sanp != start) {
784 /* back up sanp one level */
785 --sanp; /* now pointing at slash */
786 while ((sanp > start) && (*(sanp - 1) != '/')) {
787 /* skip back up to slash */
788 sanp--;
789 }
b5f9e67d 790 }
cb13abfe 791 continue;
1b8e662a 792 }
cb13abfe
DD
793 }
794 while (1) {
795 /* copy one component through next slash */
796 *sanp++ = *p++;
797 if ((*p == '\0') || (*(p-1) == '/')) {
798 while (*p == '/') {
799 /* skip multiple slashes */
800 p++;
b5f9e67d 801 }
cb13abfe 802 break;
1b8e662a
DD
803 }
804 }
cb13abfe
DD
805 if (allowdotdot) {
806 /* move the virtual beginning to leave the .. alone */
807 start = sanp;
808 }
1b8e662a 809 }
cb13abfe 810 if ((sanp == start) && !allowdotdot) {
b5f9e67d 811 /* ended up with nothing, so put in "." component */
79452d46
DD
812 /*
813 * note that the !allowdotdot doesn't prevent this from
814 * happening in all allowed ".." situations, but I didn't
815 * think it was worth putting in an extra variable to ensure
816 * it since an extra "." won't hurt in those situations.
817 */
44e2e578 818 *sanp++ = '.';
b5f9e67d 819 }
44e2e578 820 *sanp = '\0';
1b8e662a
DD
821}
822
5243c216
AT
823
824static char curr_dir[MAXPATHLEN];
825
ac13ad10 826/** like chdir() but can be reversed with pop_dir() if save is set. It
5243c216
AT
827 is also much faster as it remembers where we have been */
828char *push_dir(char *dir, int save)
829{
830 char *ret = curr_dir;
831 static int initialised;
832
833 if (!initialised) {
834 initialised = 1;
835 getcwd(curr_dir, sizeof(curr_dir)-1);
836 }
837
c226b7c2
DD
838 if (!dir) return NULL; /* this call was probably just to initialize */
839
5243c216
AT
840 if (chdir(dir)) return NULL;
841
842 if (save) {
843 ret = strdup(curr_dir);
844 }
845
846 if (*dir == '/') {
37f9805d 847 strlcpy(curr_dir, dir, sizeof(curr_dir));
5243c216 848 } else {
37f9805d
AT
849 strlcat(curr_dir,"/", sizeof(curr_dir));
850 strlcat(curr_dir,dir, sizeof(curr_dir));
5243c216
AT
851 }
852
853 clean_fname(curr_dir);
854
855 return ret;
856}
857
ac13ad10 858/** Reverse a push_dir call */
5243c216
AT
859int pop_dir(char *dir)
860{
861 int ret;
862
863 ret = chdir(dir);
864 if (ret) {
865 free(dir);
866 return ret;
867 }
868
37f9805d 869 strlcpy(curr_dir, dir, sizeof(curr_dir));
5243c216
AT
870
871 free(dir);
872
873 return 0;
874}
aa9b77a5 875
ac13ad10 876/** We need to supply our own strcmp function for file list comparisons
aa9b77a5
AT
877 to ensure that signed/unsigned usage is consistent between machines. */
878int u_strcmp(const char *cs1, const char *cs2)
879{
5a788ade
AT
880 const uchar *s1 = (const uchar *)cs1;
881 const uchar *s2 = (const uchar *)cs2;
aa9b77a5
AT
882
883 while (*s1 && *s2 && (*s1 == *s2)) {
884 s1++; s2++;
885 }
886
887 return (int)*s1 - (int)*s2;
888}
eb86d661 889
47f1218d
MP
890static OFF_T last_ofs;
891static struct timeval print_time;
892static struct timeval start_time;
893static OFF_T start_ofs;
894
895static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
896{
897 return (t2->tv_sec - t1->tv_sec) * 1000
898 + (t2->tv_usec - t1->tv_usec) / 1000;
899}
900
901
902/**
6066594b
MP
903 * @param ofs Current position in file
904 * @param size Total size of file
47f1218d
MP
905 * @param is_last True if this is the last time progress will be
906 * printed for this file, so we should output a newline. (Not
907 * necessarily the same as all bytes being received.)
908 **/
909static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
910 int is_last)
911{
62791bdf 912 int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
47f1218d 913 unsigned long diff = msdiff(&start_time, now);
f9c3005b 914 double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
a9b31409 915 const char *units;
c579310a
MP
916 /* If we've finished transferring this file, show the time taken;
917 * otherwise show expected time to complete. That's kind of
918 * inconsistent, but people can probably cope. Hopefully we'll
919 * get more consistent and complete progress reporting soon. --
920 * mbp */
921 double remain = is_last
922 ? (double) diff / 1000.0
923 : rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
7007bdda 924 int remain_h, remain_m, remain_s;
47f1218d 925
47f1218d
MP
926 if (rate > 1024*1024) {
927 rate /= 1024.0 * 1024.0;
928 units = "GB/s";
929 } else if (rate > 1024) {
930 rate /= 1024.0;
931 units = "MB/s";
932 } else {
933 units = "kB/s";
934 }
62791bdf 935
7007bdda
MP
936 remain_s = (int) remain % 60;
937 remain_m = (int) (remain / 60.0) % 60;
938 remain_h = (int) (remain / 3600.0);
47f1218d 939
7007bdda 940 rprintf(FINFO, "%12.0f %3d%% %7.2f%s %4d:%02d:%02d%s",
47f1218d 941 (double) ofs, pct, rate, units,
7007bdda 942 remain_h, remain_m, remain_s,
47f1218d
MP
943 is_last ? "\n" : "\r");
944}
eb86d661 945
166aa723 946void end_progress(OFF_T size)
eb86d661
AT
947{
948 extern int do_progress, am_server;
949
950 if (do_progress && !am_server) {
47f1218d
MP
951 struct timeval now;
952 gettimeofday(&now, NULL);
953 rprint_progress(size, size, &now, True);
954 }
955 last_ofs = 0;
956 start_ofs = 0;
957 print_time.tv_sec = print_time.tv_usec = 0;
958 start_time.tv_sec = start_time.tv_usec = 0;
eb86d661
AT
959}
960
961void show_progress(OFF_T ofs, OFF_T size)
962{
963 extern int do_progress, am_server;
47f1218d
MP
964 struct timeval now;
965
966 gettimeofday(&now, NULL);
967
968 if (!start_time.tv_sec && !start_time.tv_usec) {
969 start_time.tv_sec = now.tv_sec;
970 start_time.tv_usec = now.tv_usec;
971 start_ofs = ofs;
972 }
973
974 if (do_progress
975 && !am_server
976 && ofs > last_ofs + 1000
977 && msdiff(&print_time, &now) > 250) {
978 rprint_progress(ofs, size, &now, False);
979 last_ofs = ofs;
980 print_time.tv_sec = now.tv_sec;
981 print_time.tv_usec = now.tv_usec;
eb86d661
AT
982 }
983}
4b957c22 984
ac13ad10
MP
985
986/**
987 * Determine if a symlink points outside the current directory tree.
988 **/
4b957c22
AT
989int unsafe_symlink(char *dest, char *src)
990{
991 char *tok;
992 int depth = 0;
993
994 /* all absolute and null symlinks are unsafe */
995 if (!dest || !(*dest) || (*dest == '/')) return 1;
996
997 src = strdup(src);
998 if (!src) out_of_memory("unsafe_symlink");
999
1000 /* find out what our safety margin is */
1001 for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
1002 if (strcmp(tok,"..") == 0) {
1003 depth=0;
1004 } else if (strcmp(tok,".") == 0) {
1005 /* nothing */
1006 } else {
1007 depth++;
1008 }
1009 }
1010 free(src);
1011
1012 /* drop by one to account for the filename portion */
1013 depth--;
1014
1015 dest = strdup(dest);
1016 if (!dest) out_of_memory("unsafe_symlink");
1017
1018 for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
1019 if (strcmp(tok,"..") == 0) {
1020 depth--;
1021 } else if (strcmp(tok,".") == 0) {
1022 /* nothing */
1023 } else {
1024 depth++;
1025 }
1026 /* if at any point we go outside the current directory then
1027 stop - it is unsafe */
1028 if (depth < 0) break;
1029 }
1030
1031 free(dest);
1032 return (depth < 0);
1033}
375a4556 1034
f7632fc6 1035
ac13ad10
MP
1036/**
1037 Return the date and time as a string
1038*/
f7632fc6
AT
1039char *timestring(time_t t)
1040{
1041 static char TimeBuf[200];
1042 struct tm *tm = localtime(&t);
1043
1044#ifdef HAVE_STRFTIME
1045 strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %T",tm);
1046#else
37f9805d 1047 strlcpy(TimeBuf, asctime(tm), sizeof(TimeBuf));
f7632fc6
AT
1048#endif
1049
1050 if (TimeBuf[strlen(TimeBuf)-1] == '\n') {
1051 TimeBuf[strlen(TimeBuf)-1] = 0;
1052 }
1053
1054 return(TimeBuf);
1055}
1056
9ec16c83 1057
e1bd49d6
MP
1058/**
1059 * Sleep for a specified number of milliseconds.
1060 *
1061 * Always returns TRUE. (In the future it might return FALSE if
1062 * interrupted.)
1063 **/
1064int msleep(int t)
9ec16c83
AT
1065{
1066 int tdiff=0;
1067 struct timeval tval,t1,t2;
1068
1069 gettimeofday(&t1, NULL);
1070 gettimeofday(&t2, NULL);
1071
1072 while (tdiff < t) {
1073 tval.tv_sec = (t-tdiff)/1000;
1074 tval.tv_usec = 1000*((t-tdiff)%1000);
1075
1076 errno = 0;
1077 select(0,NULL,NULL, NULL, &tval);
1078
1079 gettimeofday(&t2, NULL);
1080 tdiff = (t2.tv_sec - t1.tv_sec)*1000 +
1081 (t2.tv_usec - t1.tv_usec)/1000;
1082 }
e1bd49d6
MP
1083
1084 return True;
9ec16c83
AT
1085}
1086
1087
ac13ad10
MP
1088/**
1089 * Determine if two file modification times are equivalent (either
1090 * exact or in the modification timestamp window established by
1091 * --modify-window).
1092 *
1093 * @retval 0 if the times should be treated as the same
1094 *
1095 * @retval +1 if the first is later
1096 *
1097 * @retval -1 if the 2nd is later
1098 **/
5b56cc19
AT
1099int cmp_modtime(time_t file1, time_t file2)
1100{
5b56cc19
AT
1101 extern int modify_window;
1102
1103 if (file2 > file1) {
1104 if (file2 - file1 <= modify_window) return 0;
1105 return -1;
1106 }
1107 if (file1 - file2 <= modify_window) return 0;
1108 return 1;
1109}
1110
1111
1112#ifdef __INSURE__XX
0f8f98c8
AT
1113#include <dlfcn.h>
1114
ac13ad10
MP
1115/**
1116 This routine is a trick to immediately catch errors when debugging
1117 with insure. A xterm with a gdb is popped up when insure catches
1118 a error. It is Linux specific.
1119**/
0f8f98c8
AT
1120int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
1121{
1122 static int (*fn)();
1123 int ret;
8950ac03 1124 char *cmd;
0f8f98c8 1125
8950ac03 1126 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'",
0f8f98c8
AT
1127 getpid(), getpid(), getpid());
1128
1129 if (!fn) {
1130 static void *h;
1131 h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY);
1132 fn = dlsym(h, "_Insure_trap_error");
1133 }
1134
1135 ret = fn(a1, a2, a3, a4, a5, a6);
1136
1137 system(cmd);
1138
8950ac03
AT
1139 free(cmd);
1140
0f8f98c8
AT
1141 return ret;
1142}
1143#endif