1 /* $NetBSD: xinstall.c,v 1.115 2011/09/06 18:50:32 joerg Exp $ */
4 * Copyright (c) 1987, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
35 #define HAVE_FUTIMES 1
36 #define HAVE_STRUCT_STAT_ST_FLAGS 1
39 #include <sys/cdefs.h>
40 #if defined(__COPYRIGHT) && !defined(lint)
41 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
42 The Regents of the University of California. All rights reserved.");
45 #if defined(__RCSID) && !defined(lint)
47 static char sccsid
[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
49 __RCSID("$NetBSD: xinstall.c,v 1.115 2011/09/06 18:50:32 joerg Exp $");
53 #define __MKTEMP_OK__ /* All uses of mktemp have been checked */
54 #include <sys/param.h>
80 #include "pathnames.h"
83 #define STRIP_ARGS_MAX 32
84 #define BACKUP_SUFFIX ".old"
86 static int dobackup
, dodir
, dostrip
, dolink
, dopreserve
, dorename
, dounpriv
;
87 static int haveopt_f
, haveopt_g
, haveopt_m
, haveopt_o
;
88 static int numberedbackup
;
89 static int mode
= S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
90 static char pathbuf
[MAXPATHLEN
];
91 static uid_t uid
= -1;
92 static gid_t gid
= -1;
93 static char *group
, *owner
, *fflags
, *tags
;
95 static char *metafile
;
96 static u_long fileflags
;
97 static char *stripArgs
;
98 static char *afterinstallcmd
;
99 static const char *suffix
= BACKUP_SUFFIX
;
100 static char *destdir
;
110 } digesttype
= DIGEST_NONE
;
114 #define LN_ABSOLUTE 0x01
115 #define LN_RELATIVE 0x02
117 #define LN_SYMBOLIC 0x08
118 #define LN_MIXED 0x10
120 #define DIRECTORY 0x01 /* Tell install it's a directory. */
121 #define SETFLAGS 0x02 /* Tell install to set flags. */
122 #define HASUID 0x04 /* Tell install the uid was given */
123 #define HASGID 0x08 /* Tell install the gid was given */
125 static void afterinstall(const char *, const char *, int);
126 static void backup(const char *);
127 static char *copy(int, char *, int, char *, off_t
);
128 static int do_link(char *, char *);
129 static void do_symlink(char *, char *);
130 static void install(char *, char *, u_int
);
131 static void install_dir(char *, u_int
);
132 static void makelink(char *, char *);
133 static void metadata_log(const char *, const char *, struct timeval
*,
134 const char *, const char *, off_t
);
135 static int parseid(char *, id_t
*);
136 static void strip(char *);
137 __dead
static void usage(void);
138 static char *xbasename(char *);
139 static char *xdirname(char *);
142 main(int argc
, char *argv
[])
144 struct stat from_sb
, to_sb
;
150 setprogname(argv
[0]);
153 while ((ch
= getopt(argc
, argv
, "a:cbB:dD:f:g:h:l:m:M:N:o:prsS:T:U"))
157 afterinstallcmd
= strdup(optarg
);
158 if (afterinstallcmd
== NULL
)
159 errx(1, "%s", strerror(ENOMEM
));
165 /* Check if given suffix really generates
166 different suffixes - catch e.g. ".%" */
167 char suffix_expanded0
[FILENAME_MAX
],
168 suffix_expanded1
[FILENAME_MAX
];
169 (void)snprintf(suffix_expanded0
, FILENAME_MAX
,
171 (void)snprintf(suffix_expanded1
, FILENAME_MAX
,
173 if (strcmp(suffix_expanded0
, suffix_expanded1
)
177 /* fall through; -B implies -b */
183 /* ignored; was "docopy" which is now the default. */
191 #if ! HAVE_NBTOOL_CONFIG_H
205 for (p
= optarg
; *p
; p
++)
208 dolink
&= ~(LN_HARD
|LN_MIXED
);
209 dolink
|= LN_SYMBOLIC
;
212 dolink
&= ~(LN_SYMBOLIC
|LN_MIXED
);
216 dolink
&= ~(LN_SYMBOLIC
|LN_HARD
);
220 dolink
&= ~LN_RELATIVE
;
221 dolink
|= LN_ABSOLUTE
;
224 dolink
&= ~LN_ABSOLUTE
;
225 dolink
|= LN_RELATIVE
;
228 errx(1, "%c: invalid link type", *p
);
234 if (!(set
= setmode(optarg
)))
235 err(1, "Cannot set file mode `%s'", optarg
);
236 mode
= getmode(set
, 0);
243 if (! setup_getid(optarg
))
245 "Unable to use user and group databases in `%s'",
259 stripArgs
= strdup(optarg
);
260 if (stripArgs
== NULL
)
261 errx(1, "%s", strerror(ENOMEM
));
262 /* fall through; -S implies -s */
280 /* strip and link options make no sense when creating directories */
281 if ((dostrip
|| dolink
) && dodir
)
284 /* strip and flags make no sense with links */
285 if ((dostrip
|| fflags
) && dolink
)
288 /* must have at least two arguments, except when creating directories */
289 if (argc
< 2 && !dodir
)
294 } else if (strcmp(digest
, "none") == 0) {
295 digesttype
= DIGEST_NONE
;
296 } else if (strcmp(digest
, "md5") == 0) {
297 digesttype
= DIGEST_MD5
;
298 } else if (strcmp(digest
, "rmd160") == 0) {
299 digesttype
= DIGEST_RMD160
;
300 } else if (strcmp(digest
, "sha1") == 0) {
301 digesttype
= DIGEST_SHA1
;
302 } else if (strcmp(digest
, "sha256") == 0) {
303 digesttype
= DIGEST_SHA256
;
304 } else if (strcmp(digest
, "sha384") == 0) {
305 digesttype
= DIGEST_SHA384
;
306 } else if (strcmp(digest
, "sha512") == 0) {
307 digesttype
= DIGEST_SHA512
;
309 warnx("unknown digest `%s'", digest
);
314 /* get group and owner id's */
315 if (group
&& !dounpriv
) {
316 if (gid_from_group(group
, &gid
) == -1) {
318 if (!parseid(group
, &id
))
319 errx(1, "unknown group %s", group
);
324 if (owner
&& !dounpriv
) {
325 if (uid_from_user(owner
, &uid
) == -1) {
327 if (!parseid(owner
, &id
))
328 errx(1, "unknown user %s", owner
);
334 #if ! HAVE_NBTOOL_CONFIG_H
335 if (fflags
&& !dounpriv
) {
336 if (string_to_flags(&fflags
, &fileflags
, NULL
))
337 errx(1, "%s: invalid flag", fflags
);
338 /* restore fflags since string_to_flags() changed it */
339 fflags
= flags_to_string(fileflags
, "-");
345 if ((metafp
= fopen(metafile
, "a")) == NULL
)
346 warn("open %s", metafile
);
348 digesttype
= DIGEST_NONE
;
351 for (; *argv
!= NULL
; ++argv
)
352 install_dir(*argv
, iflags
);
356 no_target
= stat(to_name
= argv
[argc
- 1], &to_sb
);
357 if (!no_target
&& S_ISDIR(to_sb
.st_mode
)) {
358 for (; *argv
!= to_name
; ++argv
)
359 install(*argv
, to_name
, iflags
| DIRECTORY
);
363 /* can't do file1 file2 directory/file */
365 errx(EXIT_FAILURE
, "the last argument (%s) "
366 "must name an existing directory", argv
[argc
- 1]);
371 /* makelink() handles checks for links */
373 if (stat(*argv
, &from_sb
))
374 err(1, "%s: stat", *argv
);
375 if (!S_ISREG(to_sb
.st_mode
))
376 errx(1, "%s: not a regular file", to_name
);
377 if (to_sb
.st_dev
== from_sb
.st_dev
&&
378 to_sb
.st_ino
== from_sb
.st_ino
)
379 errx(1, "%s and %s are the same file", *argv
,
383 * Unlink now... avoid ETXTBSY errors later. Try and turn
384 * off the append/immutable bits -- if we fail, go ahead,
387 #if !defined(__minix)
388 #if ! HAVE_NBTOOL_CONFIG_H
389 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
390 if (to_sb
.st_flags
& NOCHANGEBITS
)
391 (void)chflags(to_name
,
392 to_sb
.st_flags
& ~(NOCHANGEBITS
));
394 #endif /* !defined(__minix) */
398 (void)unlink(to_name
);
400 install(*argv
, to_name
, iflags
);
406 * parse uid or gid from arg into id, returning non-zero if successful
409 parseid(char *name
, id_t
*id
)
414 *id
= (id_t
)strtoul(name
, &ep
, 10);
415 if (errno
|| *ep
!= '\0')
422 * make a hard link, obeying dorename if set
423 * return -1 on failure
426 do_link(char *from_name
, char *to_name
)
428 char tmpl
[MAXPATHLEN
];
432 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
433 /* This usage is safe. */
434 if (mktemp(tmpl
) == NULL
)
435 err(1, "%s: mktemp", tmpl
);
436 ret
= link(from_name
, tmpl
);
438 ret
= rename(tmpl
, to_name
);
439 /* If rename has posix semantics, then the temporary
440 * file may still exist when from_name and to_name point
441 * to the same file, so unlink it unconditionally.
447 return (link(from_name
, to_name
));
452 * make a symbolic link, obeying dorename if set
456 do_symlink(char *from_name
, char *to_name
)
458 char tmpl
[MAXPATHLEN
];
461 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
462 /* This usage is safe. */
463 if (mktemp(tmpl
) == NULL
)
464 err(1, "%s: mktemp", tmpl
);
466 if (symlink(from_name
, tmpl
) == -1)
467 err(1, "symlink %s -> %s", from_name
, tmpl
);
468 if (rename(tmpl
, to_name
) == -1) {
469 /* remove temporary link before exiting */
471 err(1, "%s: rename", to_name
);
474 if (symlink(from_name
, to_name
) == -1)
475 err(1, "symlink %s -> %s", from_name
, to_name
);
481 * make a link from source to destination
484 makelink(char *from_name
, char *to_name
)
486 char src
[MAXPATHLEN
], dst
[MAXPATHLEN
], lnk
[MAXPATHLEN
];
489 /* Try hard links first */
490 if (dolink
& (LN_HARD
|LN_MIXED
)) {
491 if (do_link(from_name
, to_name
) == -1) {
492 if ((dolink
& LN_HARD
) || errno
!= EXDEV
)
493 err(1, "link %s -> %s", from_name
, to_name
);
495 if (stat(to_name
, &to_sb
))
496 err(1, "%s: stat", to_name
);
497 if (S_ISREG(to_sb
.st_mode
)) {
498 /* XXX: hard links to anything
499 * other than plain files are not
503 char *oowner
, *ogroup
, *offlags
;
506 /* XXX: use underlying perms,
507 * unless overridden on command line.
511 mode
= (to_sb
.st_mode
& 0777);
521 switch (digesttype
) {
523 dres
= MD5File(from_name
, NULL
);
526 dres
= RMD160File(from_name
, NULL
);
529 dres
= SHA1File(from_name
, NULL
);
532 dres
= SHA256_File(from_name
, NULL
);
535 dres
= SHA384_File(from_name
, NULL
);
538 dres
= SHA512_File(from_name
, NULL
);
543 metadata_log(to_name
, "file", NULL
, NULL
,
544 dres
, to_sb
.st_size
);
556 if (dolink
& LN_ABSOLUTE
) {
557 /* Convert source path to absolute */
558 if (realpath(from_name
, src
) == NULL
)
559 err(1, "%s: realpath", from_name
);
560 do_symlink(src
, to_name
);
561 /* XXX: src may point outside of destdir */
562 metadata_log(to_name
, "link", NULL
, src
, NULL
, 0);
566 if (dolink
& LN_RELATIVE
) {
569 /* Resolve pathnames */
570 if (realpath(from_name
, src
) == NULL
)
571 err(1, "%s: realpath", from_name
);
574 * The last component of to_name may be a symlink,
575 * so use realpath to resolve only the directory.
577 cp
= xdirname(to_name
);
578 if (realpath(cp
, dst
) == NULL
)
579 err(1, "%s: realpath", cp
);
580 /* .. and add the last component */
581 if (strcmp(dst
, "/") != 0) {
582 if (strlcat(dst
, "/", sizeof(dst
)) > sizeof(dst
))
583 errx(1, "resolved pathname too long");
585 cp
= xbasename(to_name
);
586 if (strlcat(dst
, cp
, sizeof(dst
)) > sizeof(dst
))
587 errx(1, "resolved pathname too long");
589 /* trim common path components */
590 for (s
= src
, d
= dst
; *s
== *d
; s
++, d
++)
595 /* count the number of directories we need to backtrack */
596 for (++d
, lnk
[0] = '\0'; *d
; d
++)
598 (void)strlcat(lnk
, "../", sizeof(lnk
));
600 (void)strlcat(lnk
, ++s
, sizeof(lnk
));
602 do_symlink(lnk
, to_name
);
603 /* XXX: lnk may point outside of destdir */
604 metadata_log(to_name
, "link", NULL
, lnk
, NULL
, 0);
609 * If absolute or relative was not specified,
610 * try the names the user provided
612 do_symlink(from_name
, to_name
);
613 /* XXX: from_name may point outside of destdir */
614 metadata_log(to_name
, "link", NULL
, from_name
, NULL
, 0);
619 * build a path name and install the file
622 install(char *from_name
, char *to_name
, u_int flags
)
626 struct timeval tv
[2];
628 int devnull
, from_fd
, to_fd
, serrno
, tmpmode
;
629 char *p
, tmpl
[MAXPATHLEN
], *oto_name
, *digestresult
;
633 /* ensure that from_sb & tv are sane if !dolink */
634 if (stat(from_name
, &from_sb
))
635 err(1, "%s: stat", from_name
);
636 size
= from_sb
.st_size
;
637 #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
638 TIMESPEC_TO_TIMEVAL(&tv
[0], &from_sb
.st_atimespec
);
639 TIMESPEC_TO_TIMEVAL(&tv
[1], &from_sb
.st_mtimespec
);
641 tv
[0].tv_sec
= from_sb
.st_atime
;
643 tv
[1].tv_sec
= from_sb
.st_mtime
;
648 if (flags
& DIRECTORY
|| strcmp(from_name
, _PATH_DEVNULL
) != 0) {
651 if (!S_ISREG(from_sb
.st_mode
))
652 errx(1, "%s: not a regular file", from_name
);
654 /* Build the target path. */
655 if (flags
& DIRECTORY
) {
656 (void)snprintf(pathbuf
, sizeof(pathbuf
), "%s/%s",
658 (p
= strrchr(from_name
, '/')) ? ++p
: from_name
);
664 #if HAVE_STRUCT_STAT_ST_FLAGS
665 from_sb
.st_flags
= 0; /* XXX */
670 * Unlink now... avoid ETXTBSY errors later. Try and turn
671 * off the append/immutable bits -- if we fail, go ahead,
674 #if !defined(__minix)
675 #if ! HAVE_NBTOOL_CONFIG_H
676 if (stat(to_name
, &to_sb
) == 0 &&
677 to_sb
.st_flags
& (NOCHANGEBITS
))
678 (void)chflags(to_name
, to_sb
.st_flags
& ~(NOCHANGEBITS
));
680 #endif /* !defined(__minix) */
682 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
686 oto_name
= NULL
; /* pacify gcc */
690 (void)unlink(to_name
);
694 makelink(from_name
, dorename
? oto_name
: to_name
);
700 if ((to_fd
= mkstemp(to_name
)) == -1)
701 err(1, "%s: mkstemp", to_name
);
703 if ((to_fd
= open(to_name
,
704 O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
)) < 0)
705 err(1, "%s: open", to_name
);
709 if ((from_fd
= open(from_name
, O_RDONLY
, 0)) < 0) {
710 (void)unlink(to_name
);
711 err(1, "%s: open", from_name
);
714 copy(from_fd
, from_name
, to_fd
, to_name
, from_sb
.st_size
);
715 (void)close(from_fd
);
722 * Re-open our fd on the target, in case we used a strip
723 * that does not work in-place -- like gnu binutils strip.
726 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
727 err(1, "stripping %s", to_name
);
730 * Recalculate size and digestresult after stripping.
732 if (fstat(to_fd
, &to_sb
) != 0)
733 err(1, "%s: fstat", to_name
);
734 size
= to_sb
.st_size
;
736 copy(to_fd
, to_name
, -1, NULL
, size
);
740 if (afterinstallcmd
!= NULL
) {
741 afterinstall(afterinstallcmd
, to_name
, 1);
744 * Re-open our fd on the target, in case we used an
745 * after-install command that does not work in-place
748 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
749 err(1, "running after install command on %s", to_name
);
753 * Set owner, group, mode for target; do the chown first,
754 * chown may lose the setuid bits.
757 (flags
& (HASUID
| HASGID
)) && fchown(to_fd
, uid
, gid
) == -1) {
759 (void)unlink(to_name
);
760 errx(1, "%s: chown/chgrp: %s", to_name
, strerror(serrno
));
764 tmpmode
&= S_IRWXU
|S_IRWXG
|S_IRWXO
;
765 if (fchmod(to_fd
, tmpmode
) == -1) {
767 (void)unlink(to_name
);
768 errx(1, "%s: chmod: %s", to_name
, strerror(serrno
));
772 * Preserve the date of the source file.
776 if (futimes(to_fd
, tv
) == -1)
777 warn("%s: futimes", to_name
);
779 if (utimes(to_name
, tv
) == -1)
780 warn("%s: utimes", to_name
);
787 if (rename(to_name
, oto_name
) == -1)
788 err(1, "%s: rename", to_name
);
793 * If provided a set of flags, set them, otherwise, preserve the
794 * flags, except for the dump flag.
796 #if !defined(__minix)
797 #if ! HAVE_NBTOOL_CONFIG_H
798 if (!dounpriv
&& chflags(to_name
,
799 flags
& SETFLAGS
? fileflags
: from_sb
.st_flags
& ~UF_NODUMP
) == -1)
801 if (errno
!= EOPNOTSUPP
|| (from_sb
.st_flags
& ~UF_NODUMP
) != 0)
802 warn("%s: chflags", to_name
);
805 #endif /* !defined(__minix) */
807 metadata_log(to_name
, "file", tv
, NULL
, digestresult
, size
);
813 * copy from one file to another, returning a digest.
815 * If to_fd < 0, just calculate a digest, don't copy.
818 copy(int from_fd
, char *from_name
, int to_fd
, char *to_name
, off_t size
)
823 u_char buf
[MAXBSIZE
];
825 RMD160_CTX ctxRMD160
;
827 SHA256_CTX ctxSHA256
;
828 SHA384_CTX ctxSHA384
;
829 SHA512_CTX ctxSHA512
;
831 switch (digesttype
) {
836 RMD160Init(&ctxRMD160
);
842 SHA256_Init(&ctxSHA256
);
845 SHA384_Init(&ctxSHA384
);
848 SHA512_Init(&ctxSHA512
);
852 return NULL
; /* no need to do anything */
857 * There's no reason to do anything other than close the file
858 * now if it's empty, so let's not bother.
863 * Mmap and write if less than 8M (the limit is so we
864 * don't totally trash memory on big files). This is
865 * really a minor hack, but it wins some CPU back.
868 if (size
<= 8 * 1048576) {
869 if ((p
= mmap(NULL
, (size_t)size
, PROT_READ
,
870 MAP_FILE
|MAP_SHARED
, from_fd
, (off_t
)0))
874 #if defined(MADV_SEQUENTIAL) && !defined(__APPLE__) && !defined(__minix)
875 if (madvise(p
, (size_t)size
, MADV_SEQUENTIAL
) == -1
876 && errno
!= EOPNOTSUPP
)
877 warnx("madvise: %s", strerror(errno
));
880 if (to_fd
>= 0 && write(to_fd
, p
, size
) != size
) {
882 (void)unlink(to_name
);
883 errx(1, "%s: write: %s",
884 to_name
, strerror(serrno
));
886 switch (digesttype
) {
888 MD5Update(&ctxMD5
, p
, size
);
891 RMD160Update(&ctxRMD160
, p
, size
);
894 SHA1Update(&ctxSHA1
, p
, size
);
897 SHA256_Update(&ctxSHA256
, p
, size
);
900 SHA384_Update(&ctxSHA384
, p
, size
);
903 SHA512_Update(&ctxSHA512
, p
, size
);
908 (void)munmap(p
, size
);
911 while ((nr
= read(from_fd
, buf
, sizeof(buf
))) > 0) {
913 (nw
= write(to_fd
, buf
, nr
)) != nr
) {
915 (void)unlink(to_name
);
916 errx(1, "%s: write: %s", to_name
,
917 strerror(nw
> 0 ? EIO
: serrno
));
919 switch (digesttype
) {
921 MD5Update(&ctxMD5
, buf
, nr
);
924 RMD160Update(&ctxRMD160
, buf
, nr
);
927 SHA1Update(&ctxSHA1
, buf
, nr
);
930 SHA256_Update(&ctxSHA256
, buf
, nr
);
933 SHA384_Update(&ctxSHA384
, buf
, nr
);
936 SHA512_Update(&ctxSHA512
, buf
, nr
);
944 (void)unlink(to_name
);
945 errx(1, "%s: read: %s", from_name
, strerror(serrno
));
949 switch (digesttype
) {
951 return MD5End(&ctxMD5
, NULL
);
953 return RMD160End(&ctxRMD160
, NULL
);
955 return SHA1End(&ctxSHA1
, NULL
);
957 return SHA256_End(&ctxSHA256
, NULL
);
959 return SHA384_End(&ctxSHA384
, NULL
);
961 return SHA512_End(&ctxSHA512
, NULL
);
969 * use strip(1) to strip the target file
974 static const char exec_failure
[] = ": exec of strip failed: ";
976 const char * volatile stripprog
, *progname
;
979 if ((stripprog
= getenv("STRIP")) == NULL
|| *stripprog
== '\0') {
981 stripprog
= TARGET_STRIP
;
983 stripprog
= _PATH_STRIP
;
991 * Build up a command line and let /bin/sh
992 * parse the arguments.
994 int ret
= asprintf(&cmd
, "%s %s %s", stripprog
, stripArgs
,
997 if (ret
== -1 || cmd
== NULL
)
998 err(1, "asprintf failed");
1004 (void)unlink(to_name
);
1005 errx(1, "vfork: %s", strerror(serrno
));
1010 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1012 execlp(stripprog
, "strip", to_name
, NULL
);
1014 progname
= getprogname();
1015 write(STDERR_FILENO
, progname
, strlen(progname
));
1016 write(STDERR_FILENO
, exec_failure
, strlen(exec_failure
));
1017 write(STDERR_FILENO
, stripprog
, strlen(stripprog
));
1018 write(STDERR_FILENO
, "\n", 1);
1022 if (wait(&status
) == -1 || status
)
1023 (void)unlink(to_name
);
1031 * run provided command on the target file or directory after it's been
1032 * installed and stripped, but before permissions are set or it's renamed
1035 afterinstall(const char *command
, const char *to_name
, int errunlink
)
1044 (void)unlink(to_name
);
1045 errx(1, "vfork: %s", strerror(serrno
));
1049 * build up a command line and let /bin/sh
1050 * parse the arguments
1052 cmd
= (char*)malloc(sizeof(char)*
1057 errx(1, "%s", strerror(ENOMEM
));
1059 sprintf(cmd
, "%s %s", command
, to_name
);
1061 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1063 warn("%s: exec of after install command", command
);
1067 if ((wait(&status
) == -1 || status
) && errunlink
)
1068 (void)unlink(to_name
);
1074 * backup file "to_name" to to_name.suffix
1075 * if suffix contains a "%", it's taken as a printf(3) pattern
1076 * used for a numbered backup.
1079 backup(const char *to_name
)
1081 char bname
[FILENAME_MAX
];
1083 if (numberedbackup
) {
1084 /* Do numbered backup */
1086 char suffix_expanded
[FILENAME_MAX
];
1090 (void)snprintf(suffix_expanded
, FILENAME_MAX
, suffix
,
1092 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
,
1095 } while (access(bname
, F_OK
) == 0);
1097 /* Do simple backup */
1098 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
, suffix
);
1101 (void)rename(to_name
, bname
);
1106 * build directory hierarchy
1109 install_dir(char *path
, u_int flags
)
1115 for (p
= path
;; ++p
)
1116 if (!*p
|| (p
!= path
&& *p
== '/')) {
1119 if (mkdir(path
, 0777) < 0) {
1121 * Can't create; path exists or no perms.
1122 * stat() path to determine what's there now.
1126 if (stat(path
, &sb
) < 0) {
1127 /* Not there; use mkdir()s error */
1129 err(1, "%s: mkdir", path
);
1131 if (!S_ISDIR(sb
.st_mode
)) {
1133 "%s exists but is not a directory",
1141 if (afterinstallcmd
!= NULL
)
1142 afterinstall(afterinstallcmd
, path
, 0);
1145 ((flags
& (HASUID
| HASGID
)) && chown(path
, uid
, gid
) == -1)
1146 || chmod(path
, mode
) == -1 )) {
1147 warn("%s: chown/chmod", path
);
1149 metadata_log(path
, "dir", NULL
, NULL
, NULL
, 0);
1154 * if metafp is not NULL, output mtree(8) full path name and settings to
1155 * metafp, to allow permissions to be set correctly by other tools,
1156 * or to allow integrity checks to be performed.
1159 metadata_log(const char *path
, const char *type
, struct timeval
*tv
,
1160 const char *slink
, const char *digestresult
, off_t size
)
1162 static const char extra
[] = { ' ', '\t', '\n', '\\', '#', '\0' };
1166 struct flock metalog_lock
;
1170 buf
= (char *)malloc(4 * strlen(path
) + 1); /* buf for strsvis(3) */
1172 warnx("%s", strerror(ENOMEM
));
1176 metalog_lock
.l_start
= 0;
1177 metalog_lock
.l_len
= 0;
1178 metalog_lock
.l_whence
= SEEK_SET
;
1179 metalog_lock
.l_type
= F_WRLCK
;
1180 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1181 warn("can't lock %s", metafile
);
1186 p
= path
; /* remove destdir */
1188 destlen
= strlen(destdir
);
1189 if (strncmp(p
, destdir
, destlen
) == 0 &&
1190 (p
[destlen
] == '/' || p
[destlen
] == '\0'))
1193 while (*p
&& *p
== '/') /* remove leading /s */
1195 strsvis(buf
, p
, VIS_CSTYLE
, extra
); /* encode name */
1198 fprintf(metafp
, ".%s%s type=%s", *p
? "/" : "", p
, type
);
1200 fprintf(metafp
, " uname=%s", owner
);
1202 fprintf(metafp
, " gname=%s", group
);
1203 fprintf(metafp
, " mode=%#o", mode
);
1205 strsvis(buf
, slink
, VIS_CSTYLE
, extra
); /* encode link */
1206 fprintf(metafp
, " link=%s", buf
);
1208 if (*type
== 'f') /* type=file */
1209 fprintf(metafp
, " size=%lld", (long long)size
);
1210 if (tv
!= NULL
&& dopreserve
)
1211 fprintf(metafp
, " time=%lld.%ld",
1212 (long long)tv
[1].tv_sec
, (long)tv
[1].tv_usec
);
1213 if (digestresult
&& digest
)
1214 fprintf(metafp
, " %s=%s", digest
, digestresult
);
1216 fprintf(metafp
, " flags=%s", fflags
);
1218 fprintf(metafp
, " tags=%s", tags
);
1219 fputc('\n', metafp
);
1220 fflush(metafp
); /* flush output */
1221 /* unlock log file */
1222 metalog_lock
.l_type
= F_UNLCK
;
1223 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1224 warn("can't unlock %s", metafile
);
1231 * libc basename(3) that returns a pointer to a static buffer
1232 * instead of overwriting that passed-in string.
1235 xbasename(char *path
)
1237 static char tmp
[MAXPATHLEN
];
1239 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1240 return (basename(tmp
));
1245 * libc dirname(3) that returns a pointer to a static buffer
1246 * instead of overwriting that passed-in string.
1249 xdirname(char *path
)
1251 static char tmp
[MAXPATHLEN
];
1253 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1254 return (dirname(tmp
));
1259 * print a usage message and die
1266 prog
= getprogname();
1268 (void)fprintf(stderr
,
1269 "usage: %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1270 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group] \n"
1271 " [-l linkflags] [-h hash] [-S stripflags] file1 file2\n"
1272 " %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1273 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group]\n"
1274 " [-l linkflags] [-h hash] [-S stripflags] file1 ... fileN directory\n"
1275 " %s -d [-Up] [-M log] [-D dest] [-T tags] [-a aftercmd] [-m mode]\n"
1276 " [-N dbdir] [-o owner] [-g group] directory ...\n",