1 /* $NetBSD: xinstall.c,v 1.124 2015/06/19 17:20:02 christos 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.124 2015/06/19 17:20:02 christos Exp $");
53 #define __MKTEMP_OK__ /* All uses of mktemp have been checked */
54 #include <sys/param.h>
75 #ifdef HAVE_POSIX_SPAWN
84 #include "pathnames.h"
88 #define BACKUP_SUFFIX ".old"
90 static int dobackup
, dodir
, dostrip
, dolink
, dopreserve
, dorename
, dounpriv
;
91 static int haveopt_f
, haveopt_g
, haveopt_m
, haveopt_o
;
92 static int numberedbackup
;
93 static int mode
= S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
94 static char pathbuf
[MAXPATHLEN
];
95 static uid_t uid
= -1;
96 static gid_t gid
= -1;
97 static char *group
, *owner
, *fflags
, *tags
;
99 static char *metafile
;
100 static u_long fileflags
;
101 static char *stripArgs
;
102 static char *afterinstallcmd
;
103 static const char *suffix
= BACKUP_SUFFIX
;
104 static char *destdir
;
114 } digesttype
= DIGEST_NONE
;
118 #define LN_ABSOLUTE 0x01
119 #define LN_RELATIVE 0x02
121 #define LN_SYMBOLIC 0x08
122 #define LN_MIXED 0x10
124 #define DIRECTORY 0x01 /* Tell install it's a directory. */
125 #define SETFLAGS 0x02 /* Tell install to set flags. */
126 #define HASUID 0x04 /* Tell install the uid was given */
127 #define HASGID 0x08 /* Tell install the gid was given */
129 static void afterinstall(const char *, const char *, int);
130 static void backup(const char *);
131 static char *copy(int, char *, int, char *, off_t
);
132 static int do_link(char *, char *);
133 static void do_symlink(char *, char *);
134 static void install(char *, char *, u_int
);
135 static void install_dir(char *, u_int
);
136 static void makelink(char *, char *);
137 static void metadata_log(const char *, const char *, struct timeval
*,
138 const char *, const char *, off_t
);
139 static int parseid(char *, id_t
*);
140 static void run(const char *, const char *, const char *, int);
141 static void strip(const char *);
142 __dead
static void usage(void);
143 static char *xbasename(char *);
144 static char *xdirname(char *);
147 main(int argc
, char *argv
[])
149 struct stat from_sb
, to_sb
;
155 setprogname(argv
[0]);
158 while ((ch
= getopt(argc
, argv
, "a:cbB:dD:f:g:h:l:m:M:N:o:prsS:T:U"))
162 afterinstallcmd
= strdup(optarg
);
163 if (afterinstallcmd
== NULL
)
165 "Can't allocate after command");
171 /* Check if given suffix really generates
172 different suffixes - catch e.g. ".%" */
173 char suffix_expanded0
[FILENAME_MAX
],
174 suffix_expanded1
[FILENAME_MAX
];
175 (void)snprintf(suffix_expanded0
, FILENAME_MAX
,
177 (void)snprintf(suffix_expanded1
, FILENAME_MAX
,
179 if (strcmp(suffix_expanded0
, suffix_expanded1
)
183 /* fall through; -B implies -b */
189 /* ignored; was "docopy" which is now the default. */
197 #if ! HAVE_NBTOOL_CONFIG_H
211 for (p
= optarg
; *p
; p
++)
214 dolink
&= ~(LN_HARD
|LN_MIXED
);
215 dolink
|= LN_SYMBOLIC
;
218 dolink
&= ~(LN_SYMBOLIC
|LN_MIXED
);
222 dolink
&= ~(LN_SYMBOLIC
|LN_HARD
);
226 dolink
&= ~LN_RELATIVE
;
227 dolink
|= LN_ABSOLUTE
;
230 dolink
&= ~LN_ABSOLUTE
;
231 dolink
|= LN_RELATIVE
;
234 errx(EXIT_FAILURE
, "%c: invalid link type", *p
);
240 if (!(set
= setmode(optarg
)))
241 err(EXIT_FAILURE
, "Cannot set file mode `%s'", optarg
);
242 mode
= getmode(set
, 0);
249 if (! setup_getid(optarg
))
251 "Unable to use user and group databases in `%s'",
265 stripArgs
= strdup(optarg
);
266 if (stripArgs
== NULL
)
267 err(EXIT_FAILURE
, "Can't allocate options");
268 /* fall through; -S implies -s */
286 /* strip and link options make no sense when creating directories */
287 if ((dostrip
|| dolink
) && dodir
)
290 /* strip and flags make no sense with links */
291 if ((dostrip
|| fflags
) && dolink
)
294 /* must have at least two arguments, except when creating directories */
295 if (argc
< 2 && !dodir
)
300 } else if (strcmp(digest
, "none") == 0) {
301 digesttype
= DIGEST_NONE
;
302 } else if (strcmp(digest
, "md5") == 0) {
303 digesttype
= DIGEST_MD5
;
304 } else if (strcmp(digest
, "rmd160") == 0) {
305 digesttype
= DIGEST_RMD160
;
306 } else if (strcmp(digest
, "sha1") == 0) {
307 digesttype
= DIGEST_SHA1
;
308 } else if (strcmp(digest
, "sha256") == 0) {
309 digesttype
= DIGEST_SHA256
;
310 } else if (strcmp(digest
, "sha384") == 0) {
311 digesttype
= DIGEST_SHA384
;
312 } else if (strcmp(digest
, "sha512") == 0) {
313 digesttype
= DIGEST_SHA512
;
315 warnx("unknown digest `%s'", digest
);
320 /* get group and owner id's */
321 if (group
&& !dounpriv
) {
322 if (gid_from_group(group
, &gid
) == -1) {
324 if (!parseid(group
, &id
))
325 errx(EXIT_FAILURE
, "unknown group %s", group
);
330 if (owner
&& !dounpriv
) {
331 if (uid_from_user(owner
, &uid
) == -1) {
333 if (!parseid(owner
, &id
))
334 errx(EXIT_FAILURE
, "unknown user %s", owner
);
340 #if ! HAVE_NBTOOL_CONFIG_H
341 if (fflags
&& !dounpriv
) {
342 if (string_to_flags(&fflags
, &fileflags
, NULL
))
343 errx(EXIT_FAILURE
, "%s: invalid flag", fflags
);
344 /* restore fflags since string_to_flags() changed it */
345 fflags
= flags_to_string(fileflags
, "-");
351 if ((metafp
= fopen(metafile
, "a")) == NULL
)
352 warn("open %s", metafile
);
354 digesttype
= DIGEST_NONE
;
357 for (; *argv
!= NULL
; ++argv
)
358 install_dir(*argv
, iflags
);
362 no_target
= stat(to_name
= argv
[argc
- 1], &to_sb
);
363 if (!no_target
&& S_ISDIR(to_sb
.st_mode
)) {
364 for (; *argv
!= to_name
; ++argv
)
365 install(*argv
, to_name
, iflags
| DIRECTORY
);
369 /* can't do file1 file2 directory/file */
371 errx(EXIT_FAILURE
, "the last argument (%s) "
372 "must name an existing directory", argv
[argc
- 1]);
377 /* makelink() handles checks for links */
379 if (stat(*argv
, &from_sb
))
380 err(EXIT_FAILURE
, "%s: stat", *argv
);
381 if (!S_ISREG(to_sb
.st_mode
))
382 errx(EXIT_FAILURE
, "%s: not a regular file", to_name
);
383 if (to_sb
.st_dev
== from_sb
.st_dev
&&
384 to_sb
.st_ino
== from_sb
.st_ino
)
385 errx(EXIT_FAILURE
, "%s and %s are the same file", *argv
,
389 * Unlink now... avoid ETXTBSY errors later. Try and turn
390 * off the append/immutable bits -- if we fail, go ahead,
393 #if !defined(__minix)
394 #if ! HAVE_NBTOOL_CONFIG_H
395 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
396 if (to_sb
.st_flags
& NOCHANGEBITS
)
397 (void)chflags(to_name
,
398 to_sb
.st_flags
& ~(NOCHANGEBITS
));
400 #endif /* !defined(__minix) */
404 (void)unlink(to_name
);
406 install(*argv
, to_name
, iflags
);
412 * parse uid or gid from arg into id, returning non-zero if successful
415 parseid(char *name
, id_t
*id
)
420 *id
= (id_t
)strtoul(name
, &ep
, 10);
421 if (errno
|| *ep
!= '\0')
428 * make a hard link, obeying dorename if set
429 * return -1 on failure
432 do_link(char *from_name
, char *to_name
)
434 char tmpl
[MAXPATHLEN
];
438 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
439 /* This usage is safe. */
440 if (mktemp(tmpl
) == NULL
)
441 err(EXIT_FAILURE
, "%s: mktemp", tmpl
);
442 ret
= link(from_name
, tmpl
);
444 ret
= rename(tmpl
, to_name
);
445 /* If rename has posix semantics, then the temporary
446 * file may still exist when from_name and to_name point
447 * to the same file, so unlink it unconditionally.
453 return (link(from_name
, to_name
));
458 * make a symbolic link, obeying dorename if set
462 do_symlink(char *from_name
, char *to_name
)
464 char tmpl
[MAXPATHLEN
];
467 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
468 /* This usage is safe. */
469 if (mktemp(tmpl
) == NULL
)
470 err(EXIT_FAILURE
, "%s: mktemp", tmpl
);
472 if (symlink(from_name
, tmpl
) == -1)
473 err(EXIT_FAILURE
, "symlink %s -> %s", from_name
, tmpl
);
474 if (rename(tmpl
, to_name
) == -1) {
475 /* remove temporary link before exiting */
477 err(EXIT_FAILURE
, "%s: rename", to_name
);
480 if (symlink(from_name
, to_name
) == -1)
481 err(EXIT_FAILURE
, "symlink %s -> %s", from_name
, to_name
);
487 * make a link from source to destination
490 makelink(char *from_name
, char *to_name
)
492 char src
[MAXPATHLEN
], dst
[MAXPATHLEN
], lnk
[MAXPATHLEN
];
495 /* Try hard links first */
496 if (dolink
& (LN_HARD
|LN_MIXED
)) {
497 if (do_link(from_name
, to_name
) == -1) {
498 if ((dolink
& LN_HARD
) || errno
!= EXDEV
)
499 err(EXIT_FAILURE
, "link %s -> %s", from_name
, to_name
);
501 if (stat(to_name
, &to_sb
))
502 err(EXIT_FAILURE
, "%s: stat", to_name
);
503 if (S_ISREG(to_sb
.st_mode
)) {
504 /* XXX: hard links to anything
505 * other than plain files are not
509 char *oowner
, *ogroup
, *offlags
;
512 /* XXX: use underlying perms,
513 * unless overridden on command line.
517 mode
= (to_sb
.st_mode
& 0777);
527 switch (digesttype
) {
529 dres
= MD5File(from_name
, NULL
);
532 dres
= RMD160File(from_name
, NULL
);
535 dres
= SHA1File(from_name
, NULL
);
538 dres
= SHA256_File(from_name
, NULL
);
541 dres
= SHA384_File(from_name
, NULL
);
544 dres
= SHA512_File(from_name
, NULL
);
549 metadata_log(to_name
, "file", NULL
, NULL
,
550 dres
, to_sb
.st_size
);
562 if (dolink
& LN_ABSOLUTE
) {
563 /* Convert source path to absolute */
564 if (realpath(from_name
, src
) == NULL
)
565 err(EXIT_FAILURE
, "%s: realpath", from_name
);
566 do_symlink(src
, to_name
);
567 /* XXX: src may point outside of destdir */
568 metadata_log(to_name
, "link", NULL
, src
, NULL
, 0);
572 if (dolink
& LN_RELATIVE
) {
575 /* Resolve pathnames */
576 if (realpath(from_name
, src
) == NULL
)
577 err(EXIT_FAILURE
, "%s: realpath", from_name
);
580 * The last component of to_name may be a symlink,
581 * so use realpath to resolve only the directory.
583 cp
= xdirname(to_name
);
584 if (realpath(cp
, dst
) == NULL
)
585 err(EXIT_FAILURE
, "%s: realpath", cp
);
586 /* .. and add the last component */
587 if (strcmp(dst
, "/") != 0) {
588 if (strlcat(dst
, "/", sizeof(dst
)) > sizeof(dst
))
589 errx(EXIT_FAILURE
, "resolved pathname too long");
591 cp
= xbasename(to_name
);
592 if (strlcat(dst
, cp
, sizeof(dst
)) > sizeof(dst
))
593 errx(EXIT_FAILURE
, "resolved pathname too long");
595 /* trim common path components */
596 for (s
= src
, d
= dst
; *s
== *d
; s
++, d
++)
601 /* count the number of directories we need to backtrack */
602 for (++d
, lnk
[0] = '\0'; *d
; d
++)
604 (void)strlcat(lnk
, "../", sizeof(lnk
));
606 (void)strlcat(lnk
, ++s
, sizeof(lnk
));
608 do_symlink(lnk
, to_name
);
609 /* XXX: lnk may point outside of destdir */
610 metadata_log(to_name
, "link", NULL
, lnk
, NULL
, 0);
615 * If absolute or relative was not specified,
616 * try the names the user provided
618 do_symlink(from_name
, to_name
);
619 /* XXX: from_name may point outside of destdir */
620 metadata_log(to_name
, "link", NULL
, from_name
, NULL
, 0);
625 * build a path name and install the file
628 install(char *from_name
, char *to_name
, u_int flags
)
632 struct timeval tv
[2];
634 int devnull
, from_fd
, to_fd
, serrno
, tmpmode
;
635 char *p
, tmpl
[MAXPATHLEN
], *oto_name
, *digestresult
;
639 /* ensure that from_sb & tv are sane if !dolink */
640 if (stat(from_name
, &from_sb
))
641 err(EXIT_FAILURE
, "%s: stat", from_name
);
642 size
= from_sb
.st_size
;
643 #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
644 TIMESPEC_TO_TIMEVAL(&tv
[0], &from_sb
.st_atimespec
);
645 TIMESPEC_TO_TIMEVAL(&tv
[1], &from_sb
.st_mtimespec
);
647 tv
[0].tv_sec
= from_sb
.st_atime
;
649 tv
[1].tv_sec
= from_sb
.st_mtime
;
654 if (flags
& DIRECTORY
|| strcmp(from_name
, _PATH_DEVNULL
) != 0) {
657 if (!S_ISREG(from_sb
.st_mode
))
658 errx(EXIT_FAILURE
, "%s: not a regular file", from_name
);
660 /* Build the target path. */
661 if (flags
& DIRECTORY
) {
662 (void)snprintf(pathbuf
, sizeof(pathbuf
), "%s/%s",
664 (p
= strrchr(from_name
, '/')) ? ++p
: from_name
);
670 #if HAVE_STRUCT_STAT_ST_FLAGS
671 from_sb
.st_flags
= 0; /* XXX */
676 * Unlink now... avoid ETXTBSY errors later. Try and turn
677 * off the append/immutable bits -- if we fail, go ahead,
680 #if !defined(__minix)
681 #if ! HAVE_NBTOOL_CONFIG_H
682 if (stat(to_name
, &to_sb
) == 0 &&
683 to_sb
.st_flags
& (NOCHANGEBITS
))
684 (void)chflags(to_name
, to_sb
.st_flags
& ~(NOCHANGEBITS
));
686 #endif /* !defined(__minix) */
688 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
692 oto_name
= NULL
; /* pacify gcc */
696 (void)unlink(to_name
);
700 makelink(from_name
, dorename
? oto_name
: to_name
);
706 if ((to_fd
= mkstemp(to_name
)) == -1)
707 err(EXIT_FAILURE
, "%s: mkstemp", to_name
);
709 if ((to_fd
= open(to_name
,
710 O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
)) < 0)
711 err(EXIT_FAILURE
, "%s: open", to_name
);
715 if ((from_fd
= open(from_name
, O_RDONLY
, 0)) < 0) {
716 (void)unlink(to_name
);
717 err(EXIT_FAILURE
, "%s: open", from_name
);
720 copy(from_fd
, from_name
, to_fd
, to_name
, from_sb
.st_size
);
721 (void)close(from_fd
);
728 * Re-open our fd on the target, in case we used a strip
729 * that does not work in-place -- like gnu binutils strip.
732 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
733 err(EXIT_FAILURE
, "stripping %s", to_name
);
736 * Recalculate size and digestresult after stripping.
738 if (fstat(to_fd
, &to_sb
) != 0)
739 err(EXIT_FAILURE
, "%s: fstat", to_name
);
740 size
= to_sb
.st_size
;
742 copy(to_fd
, to_name
, -1, NULL
, size
);
746 if (afterinstallcmd
!= NULL
) {
747 afterinstall(afterinstallcmd
, to_name
, 1);
750 * Re-open our fd on the target, in case we used an
751 * after-install command that does not work in-place
754 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
755 err(EXIT_FAILURE
, "running after install command on %s", to_name
);
759 * Set owner, group, mode for target; do the chown first,
760 * chown may lose the setuid bits.
763 (flags
& (HASUID
| HASGID
)) && fchown(to_fd
, uid
, gid
) == -1) {
765 (void)unlink(to_name
);
766 errc(EXIT_FAILURE
, serrno
, "%s: chown/chgrp", to_name
);
770 tmpmode
&= S_IRWXU
|S_IRWXG
|S_IRWXO
;
771 if (fchmod(to_fd
, tmpmode
) == -1) {
773 (void)unlink(to_name
);
774 errc(EXIT_FAILURE
, serrno
, "%s: chmod", to_name
);
778 * Preserve the date of the source file.
782 if (futimes(to_fd
, tv
) == -1)
783 warn("%s: futimes", to_name
);
785 if (utimes(to_name
, tv
) == -1)
786 warn("%s: utimes", to_name
);
793 if (rename(to_name
, oto_name
) == -1)
794 err(EXIT_FAILURE
, "%s: rename", to_name
);
799 * If provided a set of flags, set them, otherwise, preserve the
800 * flags, except for the dump flag.
802 #if !defined(__minix)
803 #if ! HAVE_NBTOOL_CONFIG_H
804 if (!dounpriv
&& chflags(to_name
,
805 flags
& SETFLAGS
? fileflags
: from_sb
.st_flags
& ~UF_NODUMP
) == -1)
807 if (errno
!= EOPNOTSUPP
|| (from_sb
.st_flags
& ~UF_NODUMP
) != 0)
808 warn("%s: chflags", to_name
);
811 #endif /* !defined(__minix) */
813 metadata_log(to_name
, "file", tv
, NULL
, digestresult
, size
);
819 * copy from one file to another, returning a digest.
821 * If to_fd < 0, just calculate a digest, don't copy.
824 copy(int from_fd
, char *from_name
, int to_fd
, char *to_name
, off_t size
)
829 u_char buf
[MAXBSIZE
];
831 RMD160_CTX ctxRMD160
;
833 SHA256_CTX ctxSHA256
;
834 SHA384_CTX ctxSHA384
;
835 SHA512_CTX ctxSHA512
;
837 switch (digesttype
) {
842 RMD160Init(&ctxRMD160
);
848 SHA256_Init(&ctxSHA256
);
851 SHA384_Init(&ctxSHA384
);
854 SHA512_Init(&ctxSHA512
);
858 return NULL
; /* no need to do anything */
863 * There's no reason to do anything other than close the file
864 * now if it's empty, so let's not bother.
869 * Mmap and write if less than 8M (the limit is so we
870 * don't totally trash memory on big files). This is
871 * really a minor hack, but it wins some CPU back.
874 if (size
<= 8 * 1048576) {
875 if ((p
= mmap(NULL
, (size_t)size
, PROT_READ
,
876 MAP_FILE
|MAP_SHARED
, from_fd
, (off_t
)0))
880 #if defined(MADV_SEQUENTIAL) && !defined(__APPLE__) && !defined(__minix)
881 if (madvise(p
, (size_t)size
, MADV_SEQUENTIAL
) == -1
882 && errno
!= EOPNOTSUPP
)
886 if (to_fd
>= 0 && write(to_fd
, p
, size
) != size
) {
888 (void)unlink(to_name
);
889 errc(EXIT_FAILURE
, serrno
, "%s: write",
892 switch (digesttype
) {
894 MD5Update(&ctxMD5
, p
, size
);
897 RMD160Update(&ctxRMD160
, p
, size
);
900 SHA1Update(&ctxSHA1
, p
, size
);
903 SHA256_Update(&ctxSHA256
, p
, size
);
906 SHA384_Update(&ctxSHA384
, p
, size
);
909 SHA512_Update(&ctxSHA512
, p
, size
);
914 (void)munmap(p
, size
);
917 while ((nr
= read(from_fd
, buf
, sizeof(buf
))) > 0) {
919 (nw
= write(to_fd
, buf
, nr
)) != nr
) {
921 (void)unlink(to_name
);
923 nw
> 0 ? EIO
: serrno
,
924 "%s: write", to_name
);
926 switch (digesttype
) {
928 MD5Update(&ctxMD5
, buf
, nr
);
931 RMD160Update(&ctxRMD160
, buf
, nr
);
934 SHA1Update(&ctxSHA1
, buf
, nr
);
937 SHA256_Update(&ctxSHA256
, buf
, nr
);
940 SHA384_Update(&ctxSHA384
, buf
, nr
);
943 SHA512_Update(&ctxSHA512
, buf
, nr
);
951 (void)unlink(to_name
);
952 errc(EXIT_FAILURE
, serrno
, "%s: read",
957 switch (digesttype
) {
959 return MD5End(&ctxMD5
, NULL
);
961 return RMD160End(&ctxRMD160
, NULL
);
963 return SHA1End(&ctxSHA1
, NULL
);
965 return SHA256_End(&ctxSHA256
, NULL
);
967 return SHA384_End(&ctxSHA384
, NULL
);
969 return SHA512_End(&ctxSHA512
, NULL
);
976 run(const char *command
, const char *flags
, const char *to_name
, int errunlink
)
987 if (needshell(command
, 1)) {
988 rv
= asprintf(&cmd
, "%s %s%s%s", command
, flags
? flags
: "",
989 flags
? " " : "", to_name
);
991 warn("Cannot execute %s", command
);
994 command
= _PATH_BSHELL
;
997 cmd
= __UNCONST(to_name
);
999 args
[0] = __UNCONST(command
);
1001 args
[i
++] = __UNCONST(flags
);
1005 #ifdef HAVE_POSIX_SPAWN
1006 if (*command
== '/')
1007 rv
= posix_spawn(NULL
, command
, NULL
, NULL
, args
, NULL
);
1009 rv
= posix_spawnp(NULL
, command
, NULL
, NULL
, args
, NULL
);
1011 warnc(rv
, "Cannot execute %s", command
);
1013 * the wait below will fail if we did not create a child it will
1021 (void)unlink(to_name
);
1022 errc(EXIT_FAILURE
, rv
, "vfork");
1025 if (*command
== '/')
1026 execv(command
, args
);
1028 execvp(command
, args
);
1030 const char *arr
[] = {
1032 ": exec failed for ",
1038 for (i
= 0; i
< __arraycount(arr
); i
++)
1039 write(STDERR_FILENO
, arr
[i
], strlen(arr
[i
]));
1050 if ((rv
< 0 || status
) && errunlink
)
1051 (void)unlink(to_name
);
1056 * use strip(1) to strip the target file
1059 strip(const char *to_name
)
1061 const char *stripprog
;
1063 if ((stripprog
= getenv("STRIP")) == NULL
|| *stripprog
== '\0') {
1065 stripprog
= TARGET_STRIP
;
1067 stripprog
= _PATH_STRIP
;
1070 run(stripprog
, stripArgs
, to_name
, 1);
1075 * run provided command on the target file or directory after it's been
1076 * installed and stripped, but before permissions are set or it's renamed
1079 afterinstall(const char *command
, const char *to_name
, int errunlink
)
1081 run(command
, NULL
, to_name
, errunlink
);
1086 * backup file "to_name" to to_name.suffix
1087 * if suffix contains a "%", it's taken as a printf(3) pattern
1088 * used for a numbered backup.
1091 backup(const char *to_name
)
1093 char bname
[FILENAME_MAX
];
1095 if (numberedbackup
) {
1096 /* Do numbered backup */
1098 char suffix_expanded
[FILENAME_MAX
];
1102 (void)snprintf(suffix_expanded
, FILENAME_MAX
, suffix
,
1104 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
,
1107 } while (access(bname
, F_OK
) == 0);
1109 /* Do simple backup */
1110 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
, suffix
);
1113 (void)rename(to_name
, bname
);
1118 * build directory hierarchy
1121 install_dir(char *path
, u_int flags
)
1127 for (p
= path
;; ++p
)
1128 if (!*p
|| (p
!= path
&& *p
== '/')) {
1131 if (mkdir(path
, 0777) < 0) {
1133 * Can't create; path exists or no perms.
1134 * stat() path to determine what's there now.
1138 if (stat(path
, &sb
) < 0) {
1139 /* Not there; use mkdir()s error */
1141 err(EXIT_FAILURE
, "%s: mkdir", path
);
1143 if (!S_ISDIR(sb
.st_mode
)) {
1145 "%s exists but is not a directory",
1153 if (afterinstallcmd
!= NULL
)
1154 afterinstall(afterinstallcmd
, path
, 0);
1157 ((flags
& (HASUID
| HASGID
)) && chown(path
, uid
, gid
) == -1)
1158 || chmod(path
, mode
) == -1 )) {
1159 warn("%s: chown/chmod", path
);
1161 metadata_log(path
, "dir", NULL
, NULL
, NULL
, 0);
1166 * if metafp is not NULL, output mtree(8) full path name and settings to
1167 * metafp, to allow permissions to be set correctly by other tools,
1168 * or to allow integrity checks to be performed.
1171 metadata_log(const char *path
, const char *type
, struct timeval
*tv
,
1172 const char *slink
, const char *digestresult
, off_t size
)
1174 static const char extra
[] = { ' ', '\t', '\n', '\\', '#', '\0' };
1178 struct flock metalog_lock
;
1182 buf
= malloc(4 * strlen(path
) + 1); /* buf for strsvis(3) */
1184 warn("Can't allocate metadata");
1188 metalog_lock
.l_start
= 0;
1189 metalog_lock
.l_len
= 0;
1190 metalog_lock
.l_whence
= SEEK_SET
;
1191 metalog_lock
.l_type
= F_WRLCK
;
1192 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1193 warn("can't lock %s", metafile
);
1198 p
= path
; /* remove destdir */
1200 destlen
= strlen(destdir
);
1201 if (strncmp(p
, destdir
, destlen
) == 0 &&
1202 (p
[destlen
] == '/' || p
[destlen
] == '\0'))
1205 while (*p
&& *p
== '/') /* remove leading /s */
1207 strsvis(buf
, p
, VIS_CSTYLE
, extra
); /* encode name */
1210 fprintf(metafp
, ".%s%s type=%s", *p
? "/" : "", p
, type
);
1212 fprintf(metafp
, " uname=%s", owner
);
1214 fprintf(metafp
, " gname=%s", group
);
1215 fprintf(metafp
, " mode=%#o", mode
);
1217 strsvis(buf
, slink
, VIS_CSTYLE
, extra
); /* encode link */
1218 fprintf(metafp
, " link=%s", buf
);
1220 if (*type
== 'f') /* type=file */
1221 fprintf(metafp
, " size=%lld", (long long)size
);
1222 if (tv
!= NULL
&& dopreserve
)
1223 fprintf(metafp
, " time=%lld.%0*lld",
1224 (long long)tv
[1].tv_sec
,
1225 (tv
[1].tv_usec
== 0 ? 1 : 9),
1226 (long long)tv
[1].tv_usec
* 1000);
1227 if (digestresult
&& digest
)
1228 fprintf(metafp
, " %s=%s", digest
, digestresult
);
1230 fprintf(metafp
, " flags=%s", fflags
);
1232 fprintf(metafp
, " tags=%s", tags
);
1233 fputc('\n', metafp
);
1234 fflush(metafp
); /* flush output */
1235 /* unlock log file */
1236 metalog_lock
.l_type
= F_UNLCK
;
1237 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1238 warn("can't unlock %s", metafile
);
1245 * libc basename(3) that returns a pointer to a static buffer
1246 * instead of overwriting that passed-in string.
1249 xbasename(char *path
)
1251 static char tmp
[MAXPATHLEN
];
1253 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1254 return (basename(tmp
));
1259 * libc dirname(3) that returns a pointer to a static buffer
1260 * instead of overwriting that passed-in string.
1263 xdirname(char *path
)
1265 static char tmp
[MAXPATHLEN
];
1267 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1268 return (dirname(tmp
));
1273 * print a usage message and die
1280 prog
= getprogname();
1282 (void)fprintf(stderr
,
1283 "usage: %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1284 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group] \n"
1285 " [-l linkflags] [-h hash] [-S stripflags] file1 file2\n"
1286 " %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1287 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group]\n"
1288 " [-l linkflags] [-h hash] [-S stripflags] file1 ... fileN directory\n"
1289 " %s -d [-Up] [-M log] [-D dest] [-T tags] [-a aftercmd] [-m mode]\n"
1290 " [-N dbdir] [-o owner] [-g group] directory ...\n",