xinstall.c revision 1.66 1 /* $NetBSD: xinstall.c,v 1.66 2002/01/28 19:44:03 tv Exp $ */
2
3 /*
4 * Copyright (c) 1987, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #if HAVE_CONFIG_H
37 #include "config.h"
38 #else
39 #define HAVE_ERR_H 1
40 #define HAVE_FUTIMES 1
41 #define HAVE_LIBGEN_H 1
42 #define HAVE_STRUCT_STAT_ST_FLAGS 1
43 #define HAVE_VIS_H 1
44 #endif
45
46 #include <sys/cdefs.h>
47 #ifndef lint
48 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
49 The Regents of the University of California. All rights reserved.\n");
50 #endif /* not lint */
51
52 #ifndef lint
53 #if 0
54 static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
55 #else
56 __RCSID("$NetBSD: xinstall.c,v 1.66 2002/01/28 19:44:03 tv Exp $");
57 #endif
58 #endif /* not lint */
59
60 #include <sys/param.h>
61 #include <sys/mman.h>
62 #include <sys/stat.h>
63 #include <sys/wait.h>
64
65 #include <ctype.h>
66 #include <errno.h>
67 #include <fcntl.h>
68 #include <grp.h>
69 #include <paths.h>
70 #include <pwd.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75
76 #if HAVE_ERR_H
77 #include <err.h>
78 #endif
79 #if HAVE_LIBGEN_H
80 #include <libgen.h>
81 #endif
82 #if HAVE_VIS_H
83 #include <vis.h>
84 #endif
85
86 #include "pathnames.h"
87 #include "stat_flags.h"
88
89 #define STRIP_ARGS_MAX 32
90 #define BACKUP_SUFFIX ".old"
91
92 int dobackup, docopy, dodir, dostrip, dolink, dopreserve, dorename,
93 dounpriv;
94 int numberedbackup;
95 int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
96 char pathbuf[MAXPATHLEN];
97 id_t uid, gid;
98 char *group, *owner, *fflags, *tags;
99 FILE *metafp;
100 char *metafile;
101 u_long fileflags;
102 char *stripArgs;
103 char *suffix = BACKUP_SUFFIX;
104
105 #define LN_ABSOLUTE 0x01
106 #define LN_RELATIVE 0x02
107 #define LN_HARD 0x04
108 #define LN_SYMBOLIC 0x08
109 #define LN_MIXED 0x10
110
111 #define DIRECTORY 0x01 /* Tell install it's a directory. */
112 #define SETFLAGS 0x02 /* Tell install to set flags. */
113 #define HASUID 0x04 /* Tell install the uid was given */
114 #define HASGID 0x08 /* Tell install the gid was given */
115
116 void backup(const char *);
117 void copy(int, char *, int, char *, off_t);
118 int do_link(char *, char *);
119 void do_symlink(char *, char *);
120 void install(char *, char *, u_int);
121 void install_dir(char *, u_int);
122 int main(int, char *[]);
123 void makelink(char *, char *);
124 void metadata_log(const char *, const char *, struct timeval *, const char *);
125 int parseid(char *, id_t *);
126 void strip(char *);
127 void usage(void);
128 char *xbasename(char *);
129 char *xdirname(char *);
130
131 int
132 main(int argc, char *argv[])
133 {
134 struct stat from_sb, to_sb;
135 void *set;
136 u_int iflags;
137 int ch, no_target;
138 char *p, *to_name;
139
140 setprogname(argv[0]);
141
142 iflags = 0;
143 while ((ch = getopt(argc, argv, "cbB:df:g:l:m:M:o:prsS:T:U")) != -1)
144 switch((char)ch) {
145 case 'B':
146 suffix = optarg;
147 numberedbackup = 0;
148 {
149 /* Check if given suffix really generates
150 different suffixes - catch e.g. ".%" */
151 char suffix_expanded0[FILENAME_MAX],
152 suffix_expanded1[FILENAME_MAX];
153 (void)snprintf(suffix_expanded0, FILENAME_MAX,
154 suffix, 0);
155 (void)snprintf(suffix_expanded1, FILENAME_MAX,
156 suffix, 1);
157 if (strcmp(suffix_expanded0, suffix_expanded1)
158 != 0)
159 numberedbackup = 1;
160 }
161 /* fall through; -B implies -b */
162 /*FALLTHROUGH*/
163 case 'b':
164 dobackup = 1;
165 break;
166 case 'c':
167 docopy = 1;
168 break;
169 case 'd':
170 dodir = 1;
171 break;
172 #if !HAVE_CONFIG_H
173 case 'f':
174 fflags = optarg;
175 break;
176 #endif
177 case 'g':
178 group = optarg;
179 break;
180 case 'l':
181 for (p = optarg; *p; p++)
182 switch (*p) {
183 case 's':
184 dolink &= ~(LN_HARD|LN_MIXED);
185 dolink |= LN_SYMBOLIC;
186 break;
187 case 'h':
188 dolink &= ~(LN_SYMBOLIC|LN_MIXED);
189 dolink |= LN_HARD;
190 break;
191 case 'm':
192 dolink &= ~(LN_SYMBOLIC|LN_HARD);
193 dolink |= LN_MIXED;
194 break;
195 case 'a':
196 dolink &= ~LN_RELATIVE;
197 dolink |= LN_ABSOLUTE;
198 break;
199 case 'r':
200 dolink &= ~LN_ABSOLUTE;
201 dolink |= LN_RELATIVE;
202 break;
203 default:
204 errx(1, "%c: invalid link type", *p);
205 /* NOTREACHED */
206 }
207 break;
208 case 'm':
209 if (!(set = setmode(optarg)))
210 errx(1, "%s: invalid file mode", optarg);
211 mode = getmode(set, 0);
212 free(set);
213 break;
214 case 'M':
215 metafile = optarg;
216 break;
217 case 'o':
218 owner = optarg;
219 break;
220 case 'p':
221 dopreserve = 1;
222 break;
223 case 'r':
224 dorename = 1;
225 break;
226 case 'S':
227 stripArgs = strdup(optarg);
228 if (stripArgs == NULL)
229 errx(1, "%s", strerror(ENOMEM));
230 /* fall through; -S implies -s */
231 /*FALLTHROUGH*/
232 case 's':
233 dostrip = 1;
234 break;
235 case 'T':
236 tags = optarg;
237 break;
238 case 'U':
239 dounpriv = 1;
240 break;
241 case '?':
242 default:
243 usage();
244 }
245 argc -= optind;
246 argv += optind;
247
248 /* strip and link options make no sense when creating directories */
249 if ((dostrip || dolink) && dodir)
250 usage();
251
252 /* strip and flags make no sense with links */
253 if ((dostrip || fflags) && dolink)
254 usage();
255
256 /* must have at least two arguments, except when creating directories */
257 if (argc < 2 && !dodir)
258 usage();
259
260 /* get group and owner id's */
261 if (group && !dounpriv) {
262 struct group *gp;
263
264 if ((gp = getgrnam(group)) != NULL)
265 gid = gp->gr_gid;
266 else if (! parseid(group, &gid))
267 errx(1, "unknown group %s", group);
268 iflags |= HASGID;
269 }
270 if (owner && !dounpriv) {
271 struct passwd *pp;
272
273 if ((pp = getpwnam(owner)) != NULL)
274 uid = pp->pw_uid;
275 else if (! parseid(owner, &uid))
276 errx(1, "unknown user %s", owner);
277 iflags |= HASUID;
278 }
279
280 #if !HAVE_CONFIG_H
281 if (fflags && !dounpriv) {
282 if (string_to_flags(&fflags, &fileflags, NULL))
283 errx(1, "%s: invalid flag", fflags);
284 iflags |= SETFLAGS;
285 }
286 #endif
287
288 if (metafile) {
289 if ((metafp = fopen(metafile, "a")) == NULL)
290 warn("open %s", metafile);
291 }
292
293 if (dodir) {
294 for (; *argv != NULL; ++argv)
295 install_dir(*argv, iflags);
296 exit (0);
297 }
298
299 no_target = stat(to_name = argv[argc - 1], &to_sb);
300 if (!no_target && S_ISDIR(to_sb.st_mode)) {
301 for (; *argv != to_name; ++argv)
302 install(*argv, to_name, iflags | DIRECTORY);
303 exit(0);
304 }
305
306 /* can't do file1 file2 directory/file */
307 if (argc != 2)
308 usage();
309
310 if (!no_target) {
311 /* makelink() handles checks for links */
312 if (!dolink) {
313 if (stat(*argv, &from_sb))
314 err(1, "%s: stat", *argv);
315 if (!S_ISREG(to_sb.st_mode))
316 errx(1, "%s: not a regular file", to_name);
317 if (to_sb.st_dev == from_sb.st_dev &&
318 to_sb.st_ino == from_sb.st_ino)
319 errx(1, "%s and %s are the same file", *argv,
320 to_name);
321 }
322 /*
323 * Unlink now... avoid ETXTBSY errors later. Try and turn
324 * off the append/immutable bits -- if we fail, go ahead,
325 * it might work.
326 */
327 #if !HAVE_CONFIG_H
328 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
329 if (to_sb.st_flags & NOCHANGEBITS)
330 (void)chflags(to_name,
331 to_sb.st_flags & ~(NOCHANGEBITS));
332 #endif
333 if (dobackup)
334 backup(to_name);
335 else if (!dorename)
336 (void)unlink(to_name);
337 }
338 install(*argv, to_name, iflags);
339 exit(0);
340 }
341
342 /*
343 * parseid --
344 * parse uid or gid from arg into id, returning non-zero if successful
345 */
346 int
347 parseid(char *name, id_t *id)
348 {
349 char *ep;
350
351 errno = 0;
352 *id = (id_t)strtoul(name, &ep, 10);
353 if (errno || *ep != '\0')
354 return (0);
355 return (1);
356 }
357
358 /*
359 * do_link --
360 * make a hard link, obeying dorename if set
361 * return -1 on failure
362 */
363 int
364 do_link(char *from_name, char *to_name)
365 {
366 char tmpl[MAXPATHLEN];
367 int ret;
368
369 if (dorename) {
370 (void)snprintf(tmpl, sizeof(tmpl), "%s/inst.XXXXXX",
371 xdirname(to_name));
372 /* This usage is safe. The linker will bitch anyway. */
373 if (mktemp(tmpl) == NULL)
374 err(1, "%s: mktemp", tmpl);
375 ret = link(from_name, tmpl);
376 if (ret == 0) {
377 ret = rename(tmpl, to_name);
378 if (ret < 0)
379 /* remove temporary link before exiting */
380 (void)unlink(tmpl);
381 }
382 return (ret);
383 } else
384 return (link(from_name, to_name));
385 }
386
387 /*
388 * do_symlink --
389 * make a symbolic link, obeying dorename if set
390 * exit on failure
391 */
392 void
393 do_symlink(char *from_name, char *to_name)
394 {
395 char tmpl[MAXPATHLEN];
396
397 if (dorename) {
398 (void)snprintf(tmpl, sizeof(tmpl), "%s/inst.XXXXXX",
399 xdirname(to_name));
400 /* This usage is safe. The linker will bitch anyway. */
401 if (mktemp(tmpl) == NULL)
402 err(1, "%s: mktemp", tmpl);
403
404 if (symlink(from_name, tmpl) == -1)
405 err(1, "symlink %s -> %s", from_name, tmpl);
406 if (rename(tmpl, to_name) == -1) {
407 /* remove temporary link before exiting */
408 (void)unlink(tmpl);
409 err(1, "%s: rename", to_name);
410 }
411 } else {
412 if (symlink(from_name, to_name) == -1)
413 err(1, "symlink %s -> %s", from_name, to_name);
414 }
415 }
416
417 /*
418 * makelink --
419 * make a link from source to destination
420 */
421 void
422 makelink(char *from_name, char *to_name)
423 {
424 char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN];
425
426 /* Try hard links first */
427 if (dolink & (LN_HARD|LN_MIXED)) {
428 if (do_link(from_name, to_name) == -1) {
429 if ((dolink & LN_HARD) || errno != EXDEV)
430 err(1, "link %s -> %s", from_name, to_name);
431 }
432 else {
433 metadata_log(to_name, "hlink", NULL, from_name);
434 return;
435 }
436 }
437
438 /* Symbolic links */
439 if (dolink & LN_ABSOLUTE) {
440 /* Convert source path to absolute */
441 if (realpath(from_name, src) == NULL)
442 err(1, "%s: realpath", from_name);
443 do_symlink(src, to_name);
444 metadata_log(to_name, "link", NULL, src);
445 return;
446 }
447
448 if (dolink & LN_RELATIVE) {
449 char *cp, *d, *s;
450
451 /* Resolve pathnames */
452 if (realpath(from_name, src) == NULL)
453 err(1, "%s: realpath", from_name);
454
455 /*
456 * The last component of to_name may be a symlink,
457 * so use realpath to resolve only the directory.
458 */
459 cp = xdirname(to_name);
460 if (realpath(cp, dst) == NULL)
461 err(1, "%s: realpath", cp);
462 /* .. and add the last component */
463 if (strcmp(dst, "/") != 0) {
464 if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst))
465 errx(1, "resolved pathname too long");
466 }
467 cp = xbasename(to_name);
468 if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst))
469 errx(1, "resolved pathname too long");
470
471 /* trim common path components */
472 for (s = src, d = dst; *s == *d; s++, d++)
473 continue;
474 while (*s != '/')
475 s--, d--;
476
477 /* count the number of directories we need to backtrack */
478 for (++d, lnk[0] = '\0'; *d; d++)
479 if (*d == '/')
480 (void)strcat(lnk, "../");
481
482 (void)strcat(lnk, ++s);
483
484 do_symlink(lnk, dst);
485 metadata_log(dst, "link", NULL, lnk);
486 return;
487 }
488
489 /*
490 * If absolute or relative was not specified,
491 * try the names the user provided
492 */
493 do_symlink(from_name, to_name);
494 metadata_log(to_name, "link", NULL, from_name);
495 }
496
497 /*
498 * install --
499 * build a path name and install the file
500 */
501 void
502 install(char *from_name, char *to_name, u_int flags)
503 {
504 struct stat from_sb;
505 #if !HAVE_CONFIG_H
506 struct stat to_sb;
507 #endif
508 struct timeval tv[2];
509 int devnull, from_fd, to_fd, serrno, tmpmode;
510 char *p, tmpl[MAXPATHLEN], *oto_name;
511
512 if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
513 if (!dolink) {
514 if (stat(from_name, &from_sb))
515 err(1, "%s: stat", from_name);
516 if (!S_ISREG(from_sb.st_mode))
517 errx(1, "%s: not a regular file", from_name);
518 }
519 /* Build the target path. */
520 if (flags & DIRECTORY) {
521 (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
522 to_name,
523 (p = strrchr(from_name, '/')) ? ++p : from_name);
524 to_name = pathbuf;
525 }
526 devnull = 0;
527 } else {
528 #if HAVE_STRUCT_STAT_ST_FLAGS
529 from_sb.st_flags = 0; /* XXX */
530 #endif
531 devnull = 1;
532 }
533
534 /*
535 * Unlink now... avoid ETXTBSY errors later. Try and turn
536 * off the append/immutable bits -- if we fail, go ahead,
537 * it might work.
538 */
539 #if !HAVE_CONFIG_H
540 if (stat(to_name, &to_sb) == 0 &&
541 to_sb.st_flags & (NOCHANGEBITS))
542 (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
543 #endif
544 if (dorename) {
545 (void)snprintf(tmpl, sizeof(tmpl), "%s/inst.XXXXXX",
546 xdirname(to_name));
547 oto_name = to_name;
548 to_name = tmpl;
549 } else {
550 oto_name = NULL; /* pacify gcc */
551 if (dobackup)
552 backup(to_name);
553 else
554 (void)unlink(to_name);
555 }
556
557 if (dolink) {
558 makelink(from_name, dorename ? oto_name : to_name);
559 return;
560 }
561
562 /* Create target. */
563 if (dorename) {
564 if ((to_fd = mkstemp(to_name)) == -1)
565 err(1, "%s: mkstemp", to_name);
566 } else {
567 if ((to_fd = open(to_name,
568 O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0)
569 err(1, "%s: open", to_name);
570 }
571 if (!devnull) {
572 if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
573 (void)unlink(to_name);
574 err(1, "%s: open", from_name);
575 }
576 copy(from_fd, from_name, to_fd, to_name, from_sb.st_size);
577 (void)close(from_fd);
578 }
579
580 if (dostrip) {
581 strip(to_name);
582
583 /*
584 * Re-open our fd on the target, in case we used a strip
585 * that does not work in-place -- like gnu binutils strip.
586 */
587 close(to_fd);
588 if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
589 err(1, "stripping %s", to_name);
590 }
591
592 /*
593 * Set owner, group, mode for target; do the chown first,
594 * chown may lose the setuid bits.
595 */
596 if (!dounpriv &&
597 (flags & (HASUID | HASGID)) && fchown(to_fd, uid, gid) == -1) {
598 serrno = errno;
599 (void)unlink(to_name);
600 errx(1, "%s: chown/chgrp: %s", to_name, strerror(serrno));
601 }
602 tmpmode = mode;
603 if (dounpriv)
604 tmpmode &= S_IRWXU|S_IRWXG|S_IRWXO;
605 if (fchmod(to_fd, tmpmode) == -1) {
606 serrno = errno;
607 (void)unlink(to_name);
608 errx(1, "%s: chmod: %s", to_name, strerror(serrno));
609 }
610
611 /*
612 * Preserve the date of the source file.
613 */
614 if (dopreserve) {
615 #ifdef BSD4_4
616 TIMESPEC_TO_TIMEVAL(&tv[0], &from_sb.st_atimespec);
617 TIMESPEC_TO_TIMEVAL(&tv[1], &from_sb.st_mtimespec);
618 #else
619 tv[0].tv_sec = from_sb.st_atime;
620 tv[0].tv_usec = 0;
621 tv[1].tv_sec = from_sb.st_mtime;
622 tv[1].tv_usec = 0;
623 #endif
624 #if HAVE_FUTIMES
625 if (futimes(to_fd, tv) == -1)
626 warn("%s: futimes", to_name);
627 #else
628 if (utimes(to_name, tv) == -1)
629 warn("%s: utimes", to_name);
630 #endif
631 }
632
633 (void)close(to_fd);
634
635 if (dorename) {
636 if (rename(to_name, oto_name) == -1)
637 err(1, "%s: rename", to_name);
638 to_name = oto_name;
639 }
640
641 if (!docopy && !devnull && unlink(from_name))
642 err(1, "%s: unlink", from_name);
643
644 /*
645 * If provided a set of flags, set them, otherwise, preserve the
646 * flags, except for the dump flag.
647 */
648 #if !HAVE_CONFIG_H
649 if (!dounpriv && chflags(to_name,
650 flags & SETFLAGS ? fileflags : from_sb.st_flags & ~UF_NODUMP) == -1)
651 {
652 if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
653 warn("%s: chflags", to_name);
654 }
655 #endif
656
657 metadata_log(to_name, "file", tv, NULL);
658 }
659
660 /*
661 * copy --
662 * copy from one file to another
663 */
664 void
665 copy(int from_fd, char *from_name, int to_fd, char *to_name, off_t size)
666 {
667 ssize_t nr, nw;
668 int serrno;
669 char *p;
670 char buf[MAXBSIZE];
671
672 /*
673 * There's no reason to do anything other than close the file
674 * now if it's empty, so let's not bother.
675 */
676 if (size > 0) {
677
678 /*
679 * Mmap and write if less than 8M (the limit is so we
680 * don't totally trash memory on big files). This is
681 * really a minor hack, but it wins some CPU back.
682 */
683
684 if (size <= 8 * 1048576) {
685 if ((p = mmap(NULL, (size_t)size, PROT_READ,
686 MAP_FILE|MAP_SHARED, from_fd, (off_t)0))
687 == MAP_FAILED) {
688 goto mmap_failed;
689 }
690 #ifdef MADV_SEQUENTIAL
691 if (madvise(p, (size_t)size, MADV_SEQUENTIAL) == -1
692 && errno != EOPNOTSUPP)
693 warnx("madvise: %s", strerror(errno));
694 #endif
695
696 if (write(to_fd, p, size) != size) {
697 serrno = errno;
698 (void)unlink(to_name);
699 errx(1, "%s: write: %s",
700 to_name, strerror(serrno));
701 }
702 } else {
703 mmap_failed:
704 while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
705 if ((nw = write(to_fd, buf, nr)) != nr) {
706 serrno = errno;
707 (void)unlink(to_name);
708 errx(1, "%s: write: %s", to_name,
709 strerror(nw > 0 ? EIO : serrno));
710 }
711 }
712 if (nr != 0) {
713 serrno = errno;
714 (void)unlink(to_name);
715 errx(1, "%s: read: %s", from_name, strerror(serrno));
716 }
717 }
718 }
719 }
720
721 /*
722 * strip --
723 * use strip(1) to strip the target file
724 */
725 void
726 strip(char *to_name)
727 {
728 int serrno, status;
729 char *stripprog;
730
731 switch (vfork()) {
732 case -1:
733 serrno = errno;
734 (void)unlink(to_name);
735 errx(1, "vfork: %s", strerror(serrno));
736 /*NOTREACHED*/
737 case 0:
738 stripprog = getenv("STRIP");
739 if (stripprog == NULL)
740 stripprog = _PATH_STRIP;
741
742 if (stripArgs) {
743 /*
744 * build up a command line and let /bin/sh
745 * parse the arguments
746 */
747 char* cmd = (char*)malloc(sizeof(char)*
748 (3+strlen(stripprog)+
749 strlen(stripArgs)+
750 strlen(to_name)));
751
752 if (cmd == NULL)
753 errx(1, "%s", strerror(ENOMEM));
754
755 sprintf(cmd, "%s %s %s", stripprog, stripArgs, to_name);
756
757 execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
758 } else
759 execlp(stripprog, "strip", to_name, NULL);
760
761 warn("%s: exec of strip", stripprog);
762 _exit(1);
763 /*NOTREACHED*/
764 default:
765 if (wait(&status) == -1 || status)
766 (void)unlink(to_name);
767 }
768 }
769
770 /*
771 * backup --
772 * backup file "to_name" to to_name.suffix
773 * if suffix contains a "%", it's taken as a printf(3) pattern
774 * used for a numbered backup.
775 */
776 void
777 backup(const char *to_name)
778 {
779 char bname[FILENAME_MAX];
780
781 if (numberedbackup) {
782 /* Do numbered backup */
783 int cnt;
784 char suffix_expanded[FILENAME_MAX];
785
786 cnt=0;
787 do {
788 (void)snprintf(suffix_expanded, FILENAME_MAX, suffix,
789 cnt);
790 (void)snprintf(bname, FILENAME_MAX, "%s%s", to_name,
791 suffix_expanded);
792 cnt++;
793 } while (access(bname, F_OK) == 0);
794 } else {
795 /* Do simple backup */
796 (void)snprintf(bname, FILENAME_MAX, "%s%s", to_name, suffix);
797 }
798
799 (void)rename(to_name, bname);
800 }
801
802 /*
803 * install_dir --
804 * build directory hierarchy
805 */
806 void
807 install_dir(char *path, u_int flags)
808 {
809 char *p;
810 struct stat sb;
811 int ch;
812
813 for (p = path;; ++p)
814 if (!*p || (p != path && *p == '/')) {
815 ch = *p;
816 *p = '\0';
817 if (stat(path, &sb)) {
818 if (errno != ENOENT || mkdir(path, 0777) < 0) {
819 err(1, "%s: mkdir", path);
820 }
821 }
822 if (!(*p = ch))
823 break;
824 }
825
826 if (!dounpriv && (
827 ((flags & (HASUID | HASGID)) && chown(path, uid, gid) == -1)
828 || chmod(path, mode) == -1 )) {
829 warn("%s: chown/chmod", path);
830 }
831 metadata_log(path, "dir", NULL, NULL);
832 }
833
834 /*
835 * metadata_log --
836 * if metafp is not NULL, output mtree(8) full path name and settings to
837 * metafp, to allow permissions to be set correctly by other tools.
838 */
839 void
840 metadata_log(const char *path, const char *type, struct timeval *tv,
841 const char *link)
842 {
843 const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
844 char *buf;
845
846 if (!metafp)
847 return;
848 buf = (char *)malloc(4 * strlen(path) + 1); /* buf for strsvis(3) */
849 if (buf == NULL) {
850 warnx("%s", strerror(ENOMEM));
851 return;
852 }
853 if (flock(fileno(metafp), LOCK_EX) == -1) { /* lock log file */
854 warn("can't lock %s", metafile);
855 return;
856 }
857
858 strsvis(buf, path, VIS_CSTYLE, extra); /* encode name */
859 fprintf(metafp, ".%s%s type=%s mode=%#o", /* print details */
860 buf[0] == '/' ? "" : "/", buf, type, mode);
861 if (link)
862 fprintf(metafp, " link=%s", link);
863 if (owner)
864 fprintf(metafp, " uname=%s", owner);
865 if (group)
866 fprintf(metafp, " gname=%s", group);
867 if (fflags)
868 fprintf(metafp, " flags=%s", fflags);
869 if (tags)
870 fprintf(metafp, " tags=%s", tags);
871 if (tv != NULL && dopreserve)
872 fprintf(metafp, " time=%ld.%ld", tv[1].tv_sec, tv[1].tv_usec);
873 fputc('\n', metafp);
874 fflush(metafp); /* flush output */
875 if (flock(fileno(metafp), LOCK_UN) == -1) { /* unlock log file */
876 warn("can't unlock %s", metafile);
877 }
878 free(buf);
879 }
880
881 /*
882 * xbasename --
883 * libc basename(3) that returns a pointer to a static buffer
884 * instead of overwriting that passed-in string.
885 */
886 char *
887 xbasename(char *path)
888 {
889 static char tmp[MAXPATHLEN];
890
891 (void)strlcpy(tmp, path, sizeof(tmp));
892 return (basename(tmp));
893 }
894
895 /*
896 * xdirname --
897 * libc dirname(3) that returns a pointer to a static buffer
898 * instead of overwriting that passed-in string.
899 */
900 char *
901 xdirname(char *path)
902 {
903 static char tmp[MAXPATHLEN];
904
905 (void)strlcpy(tmp, path, sizeof(tmp));
906 return (dirname(tmp));
907 }
908
909 /*
910 * usage --
911 * print a usage message and die
912 */
913 void
914 usage(void)
915 {
916
917 (void)fprintf(stderr, "\
918 usage: install [-Ubcprs] [-M log] [-T tags] [-B suffix] [-f flags] [-m mode]\n\
919 [-o owner] [-g group] [-l linkflags] [-S stripflags] file1 file2\n\
920 install [-Ubcprs] [-M log] [-T tags] [-B suffix] [-f flags] [-m mode]\n\
921 [-o owner] [-g group] [-l linkflags] [-S stripflags]\n\
922 file1 ... fileN directory\n\
923 install [-Up] [-M log] [-T tags] -d [-m mode]\n\
924 [-o owner] [-g group] directory ...\n");
925 exit(1);
926 }
927