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'",
256 "Minix lacks support for futimes(3)/utimes(2)");
263 stripArgs
= strdup(optarg
);
264 if (stripArgs
== NULL
)
265 errx(1, "%s", strerror(ENOMEM
));
266 /* fall through; -S implies -s */
284 /* strip and link options make no sense when creating directories */
285 if ((dostrip
|| dolink
) && dodir
)
288 /* strip and flags make no sense with links */
289 if ((dostrip
|| fflags
) && dolink
)
292 /* must have at least two arguments, except when creating directories */
293 if (argc
< 2 && !dodir
)
298 } else if (strcmp(digest
, "none") == 0) {
299 digesttype
= DIGEST_NONE
;
300 } else if (strcmp(digest
, "md5") == 0) {
301 digesttype
= DIGEST_MD5
;
302 } else if (strcmp(digest
, "rmd160") == 0) {
303 digesttype
= DIGEST_RMD160
;
304 } else if (strcmp(digest
, "sha1") == 0) {
305 digesttype
= DIGEST_SHA1
;
306 } else if (strcmp(digest
, "sha256") == 0) {
307 digesttype
= DIGEST_SHA256
;
308 } else if (strcmp(digest
, "sha384") == 0) {
309 digesttype
= DIGEST_SHA384
;
310 } else if (strcmp(digest
, "sha512") == 0) {
311 digesttype
= DIGEST_SHA512
;
313 warnx("unknown digest `%s'", digest
);
318 /* get group and owner id's */
319 if (group
&& !dounpriv
) {
320 if (gid_from_group(group
, &gid
) == -1) {
322 if (!parseid(group
, &id
))
323 errx(1, "unknown group %s", group
);
328 if (owner
&& !dounpriv
) {
329 if (uid_from_user(owner
, &uid
) == -1) {
331 if (!parseid(owner
, &id
))
332 errx(1, "unknown user %s", owner
);
338 #if ! HAVE_NBTOOL_CONFIG_H
339 if (fflags
&& !dounpriv
) {
340 if (string_to_flags(&fflags
, &fileflags
, NULL
))
341 errx(1, "%s: invalid flag", fflags
);
342 /* restore fflags since string_to_flags() changed it */
343 fflags
= flags_to_string(fileflags
, "-");
349 if ((metafp
= fopen(metafile
, "a")) == NULL
)
350 warn("open %s", metafile
);
352 digesttype
= DIGEST_NONE
;
355 for (; *argv
!= NULL
; ++argv
)
356 install_dir(*argv
, iflags
);
360 no_target
= stat(to_name
= argv
[argc
- 1], &to_sb
);
361 if (!no_target
&& S_ISDIR(to_sb
.st_mode
)) {
362 for (; *argv
!= to_name
; ++argv
)
363 install(*argv
, to_name
, iflags
| DIRECTORY
);
367 /* can't do file1 file2 directory/file */
369 errx(EXIT_FAILURE
, "the last argument (%s) "
370 "must name an existing directory", argv
[argc
- 1]);
375 /* makelink() handles checks for links */
377 if (stat(*argv
, &from_sb
))
378 err(1, "%s: stat", *argv
);
379 if (!S_ISREG(to_sb
.st_mode
))
380 errx(1, "%s: not a regular file", to_name
);
381 if (to_sb
.st_dev
== from_sb
.st_dev
&&
382 to_sb
.st_ino
== from_sb
.st_ino
)
383 errx(1, "%s and %s are the same file", *argv
,
387 * Unlink now... avoid ETXTBSY errors later. Try and turn
388 * off the append/immutable bits -- if we fail, go ahead,
392 #if ! HAVE_NBTOOL_CONFIG_H
393 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
394 if (to_sb
.st_flags
& NOCHANGEBITS
)
395 (void)chflags(to_name
,
396 to_sb
.st_flags
& ~(NOCHANGEBITS
));
402 (void)unlink(to_name
);
404 install(*argv
, to_name
, iflags
);
410 * parse uid or gid from arg into id, returning non-zero if successful
413 parseid(char *name
, id_t
*id
)
418 *id
= (id_t
)strtoul(name
, &ep
, 10);
419 if (errno
|| *ep
!= '\0')
426 * make a hard link, obeying dorename if set
427 * return -1 on failure
430 do_link(char *from_name
, char *to_name
)
432 char tmpl
[MAXPATHLEN
];
436 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
437 /* This usage is safe. */
438 if (mktemp(tmpl
) == NULL
)
439 err(1, "%s: mktemp", tmpl
);
440 ret
= link(from_name
, tmpl
);
442 ret
= rename(tmpl
, to_name
);
443 /* If rename has posix semantics, then the temporary
444 * file may still exist when from_name and to_name point
445 * to the same file, so unlink it unconditionally.
451 return (link(from_name
, to_name
));
456 * make a symbolic link, obeying dorename if set
460 do_symlink(char *from_name
, char *to_name
)
462 char tmpl
[MAXPATHLEN
];
465 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
466 /* This usage is safe. */
467 if (mktemp(tmpl
) == NULL
)
468 err(1, "%s: mktemp", tmpl
);
470 if (symlink(from_name
, tmpl
) == -1)
471 err(1, "symlink %s -> %s", from_name
, tmpl
);
472 if (rename(tmpl
, to_name
) == -1) {
473 /* remove temporary link before exiting */
475 err(1, "%s: rename", to_name
);
478 if (symlink(from_name
, to_name
) == -1)
479 err(1, "symlink %s -> %s", from_name
, to_name
);
485 * make a link from source to destination
488 makelink(char *from_name
, char *to_name
)
490 char src
[MAXPATHLEN
], dst
[MAXPATHLEN
], lnk
[MAXPATHLEN
];
493 /* Try hard links first */
494 if (dolink
& (LN_HARD
|LN_MIXED
)) {
495 if (do_link(from_name
, to_name
) == -1) {
496 if ((dolink
& LN_HARD
) || errno
!= EXDEV
)
497 err(1, "link %s -> %s", from_name
, to_name
);
499 if (stat(to_name
, &to_sb
))
500 err(1, "%s: stat", to_name
);
501 if (S_ISREG(to_sb
.st_mode
)) {
502 /* XXX: hard links to anything
503 * other than plain files are not
507 char *oowner
, *ogroup
, *offlags
;
510 /* XXX: use underlying perms,
511 * unless overridden on command line.
515 mode
= (to_sb
.st_mode
& 0777);
525 switch (digesttype
) {
527 dres
= MD5File(from_name
, NULL
);
530 dres
= RMD160File(from_name
, NULL
);
533 dres
= SHA1File(from_name
, NULL
);
536 dres
= SHA256_File(from_name
, NULL
);
539 dres
= SHA384_File(from_name
, NULL
);
542 dres
= SHA512_File(from_name
, NULL
);
547 metadata_log(to_name
, "file", NULL
, NULL
,
548 dres
, to_sb
.st_size
);
560 if (dolink
& LN_ABSOLUTE
) {
561 /* Convert source path to absolute */
562 if (realpath(from_name
, src
) == NULL
)
563 err(1, "%s: realpath", from_name
);
564 do_symlink(src
, to_name
);
565 /* XXX: src may point outside of destdir */
566 metadata_log(to_name
, "link", NULL
, src
, NULL
, 0);
570 if (dolink
& LN_RELATIVE
) {
573 /* Resolve pathnames */
574 if (realpath(from_name
, src
) == NULL
)
575 err(1, "%s: realpath", from_name
);
578 * The last component of to_name may be a symlink,
579 * so use realpath to resolve only the directory.
581 cp
= xdirname(to_name
);
582 if (realpath(cp
, dst
) == NULL
)
583 err(1, "%s: realpath", cp
);
584 /* .. and add the last component */
585 if (strcmp(dst
, "/") != 0) {
586 if (strlcat(dst
, "/", sizeof(dst
)) > sizeof(dst
))
587 errx(1, "resolved pathname too long");
589 cp
= xbasename(to_name
);
590 if (strlcat(dst
, cp
, sizeof(dst
)) > sizeof(dst
))
591 errx(1, "resolved pathname too long");
593 /* trim common path components */
594 for (s
= src
, d
= dst
; *s
== *d
; s
++, d
++)
599 /* count the number of directories we need to backtrack */
600 for (++d
, lnk
[0] = '\0'; *d
; d
++)
602 (void)strlcat(lnk
, "../", sizeof(lnk
));
604 (void)strlcat(lnk
, ++s
, sizeof(lnk
));
606 do_symlink(lnk
, to_name
);
607 /* XXX: lnk may point outside of destdir */
608 metadata_log(to_name
, "link", NULL
, lnk
, NULL
, 0);
613 * If absolute or relative was not specified,
614 * try the names the user provided
616 do_symlink(from_name
, to_name
);
617 /* XXX: from_name may point outside of destdir */
618 metadata_log(to_name
, "link", NULL
, from_name
, NULL
, 0);
623 * build a path name and install the file
626 install(char *from_name
, char *to_name
, u_int flags
)
630 struct timeval tv
[2];
632 int devnull
, from_fd
, to_fd
, serrno
, tmpmode
;
633 char *p
, tmpl
[MAXPATHLEN
], *oto_name
, *digestresult
;
637 /* ensure that from_sb & tv are sane if !dolink */
638 if (stat(from_name
, &from_sb
))
639 err(1, "%s: stat", from_name
);
640 size
= from_sb
.st_size
;
641 #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
642 TIMESPEC_TO_TIMEVAL(&tv
[0], &from_sb
.st_atimespec
);
643 TIMESPEC_TO_TIMEVAL(&tv
[1], &from_sb
.st_mtimespec
);
645 tv
[0].tv_sec
= from_sb
.st_atime
;
647 tv
[1].tv_sec
= from_sb
.st_mtime
;
652 if (flags
& DIRECTORY
|| strcmp(from_name
, _PATH_DEVNULL
) != 0) {
655 if (!S_ISREG(from_sb
.st_mode
))
656 errx(1, "%s: not a regular file", from_name
);
658 /* Build the target path. */
659 if (flags
& DIRECTORY
) {
660 (void)snprintf(pathbuf
, sizeof(pathbuf
), "%s/%s",
662 (p
= strrchr(from_name
, '/')) ? ++p
: from_name
);
668 #if HAVE_STRUCT_STAT_ST_FLAGS
669 from_sb
.st_flags
= 0; /* XXX */
674 * Unlink now... avoid ETXTBSY errors later. Try and turn
675 * off the append/immutable bits -- if we fail, go ahead,
679 #if ! HAVE_NBTOOL_CONFIG_H
680 if (stat(to_name
, &to_sb
) == 0 &&
681 to_sb
.st_flags
& (NOCHANGEBITS
))
682 (void)chflags(to_name
, to_sb
.st_flags
& ~(NOCHANGEBITS
));
686 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
690 oto_name
= NULL
; /* pacify gcc */
694 (void)unlink(to_name
);
698 makelink(from_name
, dorename
? oto_name
: to_name
);
704 if ((to_fd
= mkstemp(to_name
)) == -1)
705 err(1, "%s: mkstemp", to_name
);
707 if ((to_fd
= open(to_name
,
708 O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
)) < 0)
709 err(1, "%s: open", to_name
);
713 if ((from_fd
= open(from_name
, O_RDONLY
, 0)) < 0) {
714 (void)unlink(to_name
);
715 err(1, "%s: open", from_name
);
718 copy(from_fd
, from_name
, to_fd
, to_name
, from_sb
.st_size
);
719 (void)close(from_fd
);
726 * Re-open our fd on the target, in case we used a strip
727 * that does not work in-place -- like gnu binutils strip.
730 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
731 err(1, "stripping %s", to_name
);
734 * Recalculate size and digestresult after stripping.
736 if (fstat(to_fd
, &to_sb
) != 0)
737 err(1, "%s: fstat", to_name
);
738 size
= to_sb
.st_size
;
740 copy(to_fd
, to_name
, -1, NULL
, size
);
744 if (afterinstallcmd
!= NULL
) {
745 afterinstall(afterinstallcmd
, to_name
, 1);
748 * Re-open our fd on the target, in case we used an
749 * after-install command that does not work in-place
752 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
753 err(1, "running after install command on %s", to_name
);
757 * Set owner, group, mode for target; do the chown first,
758 * chown may lose the setuid bits.
761 (flags
& (HASUID
| HASGID
)) && fchown(to_fd
, uid
, gid
) == -1) {
763 (void)unlink(to_name
);
764 errx(1, "%s: chown/chgrp: %s", to_name
, strerror(serrno
));
768 tmpmode
&= S_IRWXU
|S_IRWXG
|S_IRWXO
;
769 if (fchmod(to_fd
, tmpmode
) == -1) {
771 (void)unlink(to_name
);
772 errx(1, "%s: chmod: %s", to_name
, strerror(serrno
));
776 * Preserve the date of the source file.
781 if (futimes(to_fd
, tv
) == -1)
782 warn("%s: futimes", to_name
);
784 if (utimes(to_name
, tv
) == -1)
785 warn("%s: utimes", to_name
);
793 if (rename(to_name
, oto_name
) == -1)
794 err(1, "%s: rename", to_name
);
799 * If provided a set of flags, set them, otherwise, preserve the
800 * flags, except for the dump flag.
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
);
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) {
878 if ((p
= mmap(NULL
, (size_t)size
, PROT_READ
,
879 MAP_FILE
|MAP_SHARED
, from_fd
, (off_t
)0))
883 #if defined(MADV_SEQUENTIAL) && !defined(__APPLE__)
884 if (madvise(p
, (size_t)size
, MADV_SEQUENTIAL
) == -1
885 && errno
!= EOPNOTSUPP
)
886 warnx("madvise: %s", strerror(errno
));
889 if (to_fd
>= 0 && write(to_fd
, p
, size
) != size
) {
891 (void)unlink(to_name
);
892 errx(1, "%s: write: %s",
893 to_name
, strerror(serrno
));
895 switch (digesttype
) {
897 MD5Update(&ctxMD5
, p
, size
);
900 RMD160Update(&ctxRMD160
, p
, size
);
903 SHA1Update(&ctxSHA1
, p
, size
);
906 SHA256_Update(&ctxSHA256
, p
, size
);
909 SHA384_Update(&ctxSHA384
, p
, size
);
912 SHA512_Update(&ctxSHA512
, p
, size
);
917 (void)munmap(p
, size
);
921 while ((nr
= read(from_fd
, buf
, sizeof(buf
))) > 0) {
923 (nw
= write(to_fd
, buf
, nr
)) != nr
) {
925 (void)unlink(to_name
);
926 errx(1, "%s: write: %s", to_name
,
927 strerror(nw
> 0 ? EIO
: serrno
));
929 switch (digesttype
) {
931 MD5Update(&ctxMD5
, buf
, nr
);
934 RMD160Update(&ctxRMD160
, buf
, nr
);
937 SHA1Update(&ctxSHA1
, buf
, nr
);
940 SHA256_Update(&ctxSHA256
, buf
, nr
);
943 SHA384_Update(&ctxSHA384
, buf
, nr
);
946 SHA512_Update(&ctxSHA512
, buf
, nr
);
954 (void)unlink(to_name
);
955 errx(1, "%s: read: %s", from_name
, strerror(serrno
));
959 switch (digesttype
) {
961 return MD5End(&ctxMD5
, NULL
);
963 return RMD160End(&ctxRMD160
, NULL
);
965 return SHA1End(&ctxSHA1
, NULL
);
967 return SHA256_End(&ctxSHA256
, NULL
);
969 return SHA384_End(&ctxSHA384
, NULL
);
971 return SHA512_End(&ctxSHA512
, NULL
);
979 * use strip(1) to strip the target file
984 static const char exec_failure
[] = ": exec of strip failed: ";
986 const char * volatile stripprog
, *progname
;
989 if ((stripprog
= getenv("STRIP")) == NULL
|| *stripprog
== '\0') {
991 stripprog
= TARGET_STRIP
;
993 stripprog
= _PATH_STRIP
;
1001 * Build up a command line and let /bin/sh
1002 * parse the arguments.
1004 int ret
= asprintf(&cmd
, "%s %s %s", stripprog
, stripArgs
,
1007 if (ret
== -1 || cmd
== NULL
)
1008 err(1, "asprintf failed");
1014 (void)unlink(to_name
);
1015 errx(1, "vfork: %s", strerror(serrno
));
1020 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1022 execlp(stripprog
, "strip", to_name
, NULL
);
1024 progname
= getprogname();
1025 write(STDERR_FILENO
, progname
, strlen(progname
));
1026 write(STDERR_FILENO
, exec_failure
, strlen(exec_failure
));
1027 write(STDERR_FILENO
, stripprog
, strlen(stripprog
));
1028 write(STDERR_FILENO
, "\n", 1);
1032 if (wait(&status
) == -1 || status
)
1033 (void)unlink(to_name
);
1041 * run provided command on the target file or directory after it's been
1042 * installed and stripped, but before permissions are set or it's renamed
1045 afterinstall(const char *command
, const char *to_name
, int errunlink
)
1054 (void)unlink(to_name
);
1055 errx(1, "vfork: %s", strerror(serrno
));
1059 * build up a command line and let /bin/sh
1060 * parse the arguments
1062 cmd
= (char*)malloc(sizeof(char)*
1067 errx(1, "%s", strerror(ENOMEM
));
1069 sprintf(cmd
, "%s %s", command
, to_name
);
1071 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1073 warn("%s: exec of after install command", command
);
1077 if ((wait(&status
) == -1 || status
) && errunlink
)
1078 (void)unlink(to_name
);
1084 * backup file "to_name" to to_name.suffix
1085 * if suffix contains a "%", it's taken as a printf(3) pattern
1086 * used for a numbered backup.
1089 backup(const char *to_name
)
1091 char bname
[FILENAME_MAX
];
1093 if (numberedbackup
) {
1094 /* Do numbered backup */
1096 char suffix_expanded
[FILENAME_MAX
];
1100 (void)snprintf(suffix_expanded
, FILENAME_MAX
, suffix
,
1102 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
,
1105 } while (access(bname
, F_OK
) == 0);
1107 /* Do simple backup */
1108 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
, suffix
);
1111 (void)rename(to_name
, bname
);
1116 * build directory hierarchy
1119 install_dir(char *path
, u_int flags
)
1125 for (p
= path
;; ++p
)
1126 if (!*p
|| (p
!= path
&& *p
== '/')) {
1129 if (mkdir(path
, 0777) < 0) {
1131 * Can't create; path exists or no perms.
1132 * stat() path to determine what's there now.
1136 if (stat(path
, &sb
) < 0) {
1137 /* Not there; use mkdir()s error */
1139 err(1, "%s: mkdir", path
);
1141 if (!S_ISDIR(sb
.st_mode
)) {
1143 "%s exists but is not a directory",
1151 if (afterinstallcmd
!= NULL
)
1152 afterinstall(afterinstallcmd
, path
, 0);
1155 ((flags
& (HASUID
| HASGID
)) && chown(path
, uid
, gid
) == -1)
1156 || chmod(path
, mode
) == -1 )) {
1157 warn("%s: chown/chmod", path
);
1159 metadata_log(path
, "dir", NULL
, NULL
, NULL
, 0);
1164 * if metafp is not NULL, output mtree(8) full path name and settings to
1165 * metafp, to allow permissions to be set correctly by other tools,
1166 * or to allow integrity checks to be performed.
1169 metadata_log(const char *path
, const char *type
, struct timeval
*tv
,
1170 const char *slink
, const char *digestresult
, off_t size
)
1172 static const char extra
[] = { ' ', '\t', '\n', '\\', '#', '\0' };
1176 struct flock metalog_lock
;
1180 buf
= (char *)malloc(4 * strlen(path
) + 1); /* buf for strsvis(3) */
1182 warnx("%s", strerror(ENOMEM
));
1186 metalog_lock
.l_start
= 0;
1187 metalog_lock
.l_len
= 0;
1188 metalog_lock
.l_whence
= SEEK_SET
;
1189 metalog_lock
.l_type
= F_WRLCK
;
1190 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1191 warn("can't lock %s", metafile
);
1196 p
= path
; /* remove destdir */
1198 destlen
= strlen(destdir
);
1199 if (strncmp(p
, destdir
, destlen
) == 0 &&
1200 (p
[destlen
] == '/' || p
[destlen
] == '\0'))
1203 while (*p
&& *p
== '/') /* remove leading /s */
1205 strsvis(buf
, p
, VIS_CSTYLE
, extra
); /* encode name */
1208 fprintf(metafp
, ".%s%s type=%s", *p
? "/" : "", p
, type
);
1210 fprintf(metafp
, " uname=%s", owner
);
1212 fprintf(metafp
, " gname=%s", group
);
1213 fprintf(metafp
, " mode=%#o", mode
);
1215 strsvis(buf
, slink
, VIS_CSTYLE
, extra
); /* encode link */
1216 fprintf(metafp
, " link=%s", buf
);
1218 if (*type
== 'f') /* type=file */
1219 fprintf(metafp
, " size=%lld", (long long)size
);
1220 if (tv
!= NULL
&& dopreserve
)
1221 fprintf(metafp
, " time=%lld.%ld",
1222 (long long)tv
[1].tv_sec
, (long)tv
[1].tv_usec
);
1223 if (digestresult
&& digest
)
1224 fprintf(metafp
, " %s=%s", digest
, digestresult
);
1226 fprintf(metafp
, " flags=%s", fflags
);
1228 fprintf(metafp
, " tags=%s", tags
);
1229 fputc('\n', metafp
);
1230 fflush(metafp
); /* flush output */
1231 /* unlock log file */
1232 metalog_lock
.l_type
= F_UNLCK
;
1233 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1234 warn("can't unlock %s", metafile
);
1241 * libc basename(3) that returns a pointer to a static buffer
1242 * instead of overwriting that passed-in string.
1245 xbasename(char *path
)
1247 static char tmp
[MAXPATHLEN
];
1249 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1250 return (basename(tmp
));
1255 * libc dirname(3) that returns a pointer to a static buffer
1256 * instead of overwriting that passed-in string.
1259 xdirname(char *path
)
1261 static char tmp
[MAXPATHLEN
];
1263 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1264 return (dirname(tmp
));
1269 * print a usage message and die
1276 prog
= getprogname();
1278 (void)fprintf(stderr
,
1279 "usage: %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1280 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group] \n"
1281 " [-l linkflags] [-h hash] [-S stripflags] file1 file2\n"
1282 " %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1283 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group]\n"
1284 " [-l linkflags] [-h hash] [-S stripflags] file1 ... fileN directory\n"
1285 " %s -d [-Up] [-M log] [-D dest] [-T tags] [-a aftercmd] [-m mode]\n"
1286 " [-N dbdir] [-o owner] [-g group] directory ...\n",