1 /* $NetBSD: xinstall.c,v 1.113 2009/10/30 20:57:30 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.113 2009/10/30 20:57:30 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 int dobackup
, dodir
, dostrip
, dolink
, dopreserve
, dorename
, dounpriv
;
87 int haveopt_f
, haveopt_g
, haveopt_m
, haveopt_o
;
89 int mode
= S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
90 char pathbuf
[MAXPATHLEN
];
93 char *group
, *owner
, *fflags
, *tags
;
98 char *afterinstallcmd
;
99 const char *suffix
= BACKUP_SUFFIX
;
110 } digesttype
= DIGEST_NONE
;
113 #define LN_ABSOLUTE 0x01
114 #define LN_RELATIVE 0x02
116 #define LN_SYMBOLIC 0x08
117 #define LN_MIXED 0x10
119 #define DIRECTORY 0x01 /* Tell install it's a directory. */
120 #define SETFLAGS 0x02 /* Tell install to set flags. */
121 #define HASUID 0x04 /* Tell install the uid was given */
122 #define HASGID 0x08 /* Tell install the gid was given */
124 void afterinstall(const char *, const char *, int);
125 void backup(const char *);
126 char *copy(int, char *, int, char *, off_t
);
127 int do_link(char *, char *);
128 void do_symlink(char *, char *);
129 void install(char *, char *, u_int
);
130 void install_dir(char *, u_int
);
131 int main(int, char *[]);
132 void makelink(char *, char *);
133 void metadata_log(const char *, const char *, struct timeval
*,
134 const char *, const char *, off_t
);
135 int parseid(char *, id_t
*);
138 char *xbasename(char *);
139 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 ! HAVE_NBTOOL_CONFIG_H
388 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
389 if (to_sb
.st_flags
& NOCHANGEBITS
)
390 (void)chflags(to_name
,
391 to_sb
.st_flags
& ~(NOCHANGEBITS
));
396 (void)unlink(to_name
);
398 install(*argv
, to_name
, iflags
);
404 * parse uid or gid from arg into id, returning non-zero if successful
407 parseid(char *name
, id_t
*id
)
412 *id
= (id_t
)strtoul(name
, &ep
, 10);
413 if (errno
|| *ep
!= '\0')
420 * make a hard link, obeying dorename if set
421 * return -1 on failure
424 do_link(char *from_name
, char *to_name
)
426 char tmpl
[MAXPATHLEN
];
430 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
431 /* This usage is safe. */
432 if (mktemp(tmpl
) == NULL
)
433 err(1, "%s: mktemp", tmpl
);
434 ret
= link(from_name
, tmpl
);
436 ret
= rename(tmpl
, to_name
);
437 /* If rename has posix semantics, then the temporary
438 * file may still exist when from_name and to_name point
439 * to the same file, so unlink it unconditionally.
445 return (link(from_name
, to_name
));
450 * make a symbolic link, obeying dorename if set
454 do_symlink(char *from_name
, char *to_name
)
456 char tmpl
[MAXPATHLEN
];
459 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
460 /* This usage is safe. */
461 if (mktemp(tmpl
) == NULL
)
462 err(1, "%s: mktemp", tmpl
);
464 if (symlink(from_name
, tmpl
) == -1)
465 err(1, "symlink %s -> %s", from_name
, tmpl
);
466 if (rename(tmpl
, to_name
) == -1) {
467 /* remove temporary link before exiting */
469 err(1, "%s: rename", to_name
);
472 if (symlink(from_name
, to_name
) == -1)
473 err(1, "symlink %s -> %s", from_name
, to_name
);
479 * make a link from source to destination
482 makelink(char *from_name
, char *to_name
)
484 char src
[MAXPATHLEN
], dst
[MAXPATHLEN
], lnk
[MAXPATHLEN
];
487 /* Try hard links first */
488 if (dolink
& (LN_HARD
|LN_MIXED
)) {
489 if (do_link(from_name
, to_name
) == -1) {
490 if ((dolink
& LN_HARD
) || errno
!= EXDEV
)
491 err(1, "link %s -> %s", from_name
, to_name
);
493 if (stat(to_name
, &to_sb
))
494 err(1, "%s: stat", to_name
);
495 if (S_ISREG(to_sb
.st_mode
)) {
496 /* XXX: hard links to anything
497 * other than plain files are not
501 char *oowner
, *ogroup
, *offlags
;
504 /* XXX: use underlying perms,
505 * unless overridden on command line.
509 mode
= (to_sb
.st_mode
& 0777);
519 switch (digesttype
) {
521 dres
= MD5File(from_name
, NULL
);
524 dres
= RMD160File(from_name
, NULL
);
527 dres
= SHA1File(from_name
, NULL
);
530 dres
= SHA256_File(from_name
, NULL
);
533 dres
= SHA384_File(from_name
, NULL
);
536 dres
= SHA512_File(from_name
, NULL
);
541 metadata_log(to_name
, "file", NULL
, NULL
,
542 dres
, to_sb
.st_size
);
554 if (dolink
& LN_ABSOLUTE
) {
555 /* Convert source path to absolute */
556 if (realpath(from_name
, src
) == NULL
)
557 err(1, "%s: realpath", from_name
);
558 do_symlink(src
, to_name
);
559 /* XXX: src may point outside of destdir */
560 metadata_log(to_name
, "link", NULL
, src
, NULL
, 0);
564 if (dolink
& LN_RELATIVE
) {
567 /* Resolve pathnames */
568 if (realpath(from_name
, src
) == NULL
)
569 err(1, "%s: realpath", from_name
);
572 * The last component of to_name may be a symlink,
573 * so use realpath to resolve only the directory.
575 cp
= xdirname(to_name
);
576 if (realpath(cp
, dst
) == NULL
)
577 err(1, "%s: realpath", cp
);
578 /* .. and add the last component */
579 if (strcmp(dst
, "/") != 0) {
580 if (strlcat(dst
, "/", sizeof(dst
)) > sizeof(dst
))
581 errx(1, "resolved pathname too long");
583 cp
= xbasename(to_name
);
584 if (strlcat(dst
, cp
, sizeof(dst
)) > sizeof(dst
))
585 errx(1, "resolved pathname too long");
587 /* trim common path components */
588 for (s
= src
, d
= dst
; *s
== *d
; s
++, d
++)
593 /* count the number of directories we need to backtrack */
594 for (++d
, lnk
[0] = '\0'; *d
; d
++)
596 (void)strlcat(lnk
, "../", sizeof(lnk
));
598 (void)strlcat(lnk
, ++s
, sizeof(lnk
));
600 do_symlink(lnk
, to_name
);
601 /* XXX: lnk may point outside of destdir */
602 metadata_log(to_name
, "link", NULL
, lnk
, NULL
, 0);
607 * If absolute or relative was not specified,
608 * try the names the user provided
610 do_symlink(from_name
, to_name
);
611 /* XXX: from_name may point outside of destdir */
612 metadata_log(to_name
, "link", NULL
, from_name
, NULL
, 0);
617 * build a path name and install the file
620 install(char *from_name
, char *to_name
, u_int flags
)
624 struct timeval tv
[2];
626 int devnull
, from_fd
, to_fd
, serrno
, tmpmode
;
627 char *p
, tmpl
[MAXPATHLEN
], *oto_name
, *digestresult
;
631 /* ensure that from_sb & tv are sane if !dolink */
632 if (stat(from_name
, &from_sb
))
633 err(1, "%s: stat", from_name
);
634 size
= from_sb
.st_size
;
635 #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
636 TIMESPEC_TO_TIMEVAL(&tv
[0], &from_sb
.st_atimespec
);
637 TIMESPEC_TO_TIMEVAL(&tv
[1], &from_sb
.st_mtimespec
);
639 tv
[0].tv_sec
= from_sb
.st_atime
;
641 tv
[1].tv_sec
= from_sb
.st_mtime
;
646 if (flags
& DIRECTORY
|| strcmp(from_name
, _PATH_DEVNULL
) != 0) {
649 if (!S_ISREG(from_sb
.st_mode
))
650 errx(1, "%s: not a regular file", from_name
);
652 /* Build the target path. */
653 if (flags
& DIRECTORY
) {
654 (void)snprintf(pathbuf
, sizeof(pathbuf
), "%s/%s",
656 (p
= strrchr(from_name
, '/')) ? ++p
: from_name
);
662 #if HAVE_STRUCT_STAT_ST_FLAGS
663 from_sb
.st_flags
= 0; /* XXX */
668 * Unlink now... avoid ETXTBSY errors later. Try and turn
669 * off the append/immutable bits -- if we fail, go ahead,
672 #if ! HAVE_NBTOOL_CONFIG_H
673 if (stat(to_name
, &to_sb
) == 0 &&
674 to_sb
.st_flags
& (NOCHANGEBITS
))
675 (void)chflags(to_name
, to_sb
.st_flags
& ~(NOCHANGEBITS
));
678 (void)snprintf(tmpl
, sizeof(tmpl
), "%s.inst.XXXXXX", to_name
);
682 oto_name
= NULL
; /* pacify gcc */
686 (void)unlink(to_name
);
690 makelink(from_name
, dorename
? oto_name
: to_name
);
696 if ((to_fd
= mkstemp(to_name
)) == -1)
697 err(1, "%s: mkstemp", to_name
);
699 if ((to_fd
= open(to_name
,
700 O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
)) < 0)
701 err(1, "%s: open", to_name
);
705 if ((from_fd
= open(from_name
, O_RDONLY
, 0)) < 0) {
706 (void)unlink(to_name
);
707 err(1, "%s: open", from_name
);
710 copy(from_fd
, from_name
, to_fd
, to_name
, from_sb
.st_size
);
711 (void)close(from_fd
);
718 * Re-open our fd on the target, in case we used a strip
719 * that does not work in-place -- like gnu binutils strip.
722 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
723 err(1, "stripping %s", to_name
);
726 * Recalculate size and digestresult after stripping.
728 if (fstat(to_fd
, &to_sb
) != 0)
729 err(1, "%s: fstat", to_name
);
730 size
= to_sb
.st_size
;
732 copy(to_fd
, to_name
, -1, NULL
, size
);
736 if (afterinstallcmd
!= NULL
) {
737 afterinstall(afterinstallcmd
, to_name
, 1);
740 * Re-open our fd on the target, in case we used an
741 * after-install command that does not work in-place
744 if ((to_fd
= open(to_name
, O_RDONLY
, S_IRUSR
| S_IWUSR
)) < 0)
745 err(1, "running after install command on %s", to_name
);
749 * Set owner, group, mode for target; do the chown first,
750 * chown may lose the setuid bits.
753 (flags
& (HASUID
| HASGID
)) && fchown(to_fd
, uid
, gid
) == -1) {
755 (void)unlink(to_name
);
756 errx(1, "%s: chown/chgrp: %s", to_name
, strerror(serrno
));
760 tmpmode
&= S_IRWXU
|S_IRWXG
|S_IRWXO
;
761 if (fchmod(to_fd
, tmpmode
) == -1) {
763 (void)unlink(to_name
);
764 errx(1, "%s: chmod: %s", to_name
, strerror(serrno
));
768 * Preserve the date of the source file.
772 if (futimes(to_fd
, tv
) == -1)
773 warn("%s: futimes", to_name
);
775 if (utimes(to_name
, tv
) == -1)
776 warn("%s: utimes", to_name
);
783 if (rename(to_name
, oto_name
) == -1)
784 err(1, "%s: rename", to_name
);
789 * If provided a set of flags, set them, otherwise, preserve the
790 * flags, except for the dump flag.
792 #if ! HAVE_NBTOOL_CONFIG_H
793 if (!dounpriv
&& chflags(to_name
,
794 flags
& SETFLAGS
? fileflags
: from_sb
.st_flags
& ~UF_NODUMP
) == -1)
796 if (errno
!= EOPNOTSUPP
|| (from_sb
.st_flags
& ~UF_NODUMP
) != 0)
797 warn("%s: chflags", to_name
);
801 metadata_log(to_name
, "file", tv
, NULL
, digestresult
, size
);
807 * copy from one file to another, returning a digest.
809 * If to_fd < 0, just calculate a digest, don't copy.
812 copy(int from_fd
, char *from_name
, int to_fd
, char *to_name
, off_t size
)
817 u_char buf
[MAXBSIZE
];
819 RMD160_CTX ctxRMD160
;
821 SHA256_CTX ctxSHA256
;
822 SHA384_CTX ctxSHA384
;
823 SHA512_CTX ctxSHA512
;
825 switch (digesttype
) {
830 RMD160Init(&ctxRMD160
);
836 SHA256_Init(&ctxSHA256
);
839 SHA384_Init(&ctxSHA384
);
842 SHA512_Init(&ctxSHA512
);
846 return NULL
; /* no need to do anything */
851 * There's no reason to do anything other than close the file
852 * now if it's empty, so let's not bother.
857 * Mmap and write if less than 8M (the limit is so we
858 * don't totally trash memory on big files). This is
859 * really a minor hack, but it wins some CPU back.
862 if (size
<= 8 * 1048576) {
863 if ((p
= mmap(NULL
, (size_t)size
, PROT_READ
,
864 MAP_FILE
|MAP_SHARED
, from_fd
, (off_t
)0))
868 #if defined(MADV_SEQUENTIAL) && !defined(__APPLE__)
869 if (madvise(p
, (size_t)size
, MADV_SEQUENTIAL
) == -1
870 && errno
!= EOPNOTSUPP
)
871 warnx("madvise: %s", strerror(errno
));
874 if (to_fd
>= 0 && write(to_fd
, p
, size
) != size
) {
876 (void)unlink(to_name
);
877 errx(1, "%s: write: %s",
878 to_name
, strerror(serrno
));
880 switch (digesttype
) {
882 MD5Update(&ctxMD5
, p
, size
);
885 RMD160Update(&ctxRMD160
, p
, size
);
888 SHA1Update(&ctxSHA1
, p
, size
);
891 SHA256_Update(&ctxSHA256
, p
, size
);
894 SHA384_Update(&ctxSHA384
, p
, size
);
897 SHA512_Update(&ctxSHA512
, p
, size
);
902 (void)munmap(p
, size
);
905 while ((nr
= read(from_fd
, buf
, sizeof(buf
))) > 0) {
907 (nw
= write(to_fd
, buf
, nr
)) != nr
) {
909 (void)unlink(to_name
);
910 errx(1, "%s: write: %s", to_name
,
911 strerror(nw
> 0 ? EIO
: serrno
));
913 switch (digesttype
) {
915 MD5Update(&ctxMD5
, buf
, nr
);
918 RMD160Update(&ctxRMD160
, buf
, nr
);
921 SHA1Update(&ctxSHA1
, buf
, nr
);
924 SHA256_Update(&ctxSHA256
, buf
, nr
);
927 SHA384_Update(&ctxSHA384
, buf
, nr
);
930 SHA512_Update(&ctxSHA512
, buf
, nr
);
938 (void)unlink(to_name
);
939 errx(1, "%s: read: %s", from_name
, strerror(serrno
));
943 switch (digesttype
) {
945 return MD5End(&ctxMD5
, NULL
);
947 return RMD160End(&ctxRMD160
, NULL
);
949 return SHA1End(&ctxSHA1
, NULL
);
951 return SHA256_End(&ctxSHA256
, NULL
);
953 return SHA384_End(&ctxSHA384
, NULL
);
955 return SHA512_End(&ctxSHA512
, NULL
);
963 * use strip(1) to strip the target file
968 static const char exec_failure
[] = ": exec of strip failed: ";
970 const char * volatile stripprog
, *progname
;
973 if ((stripprog
= getenv("STRIP")) == NULL
|| *stripprog
== '\0') {
975 stripprog
= TARGET_STRIP
;
977 stripprog
= _PATH_STRIP
;
985 * Build up a command line and let /bin/sh
986 * parse the arguments.
988 int ret
= asprintf(&cmd
, "%s %s %s", stripprog
, stripArgs
,
991 if (ret
== -1 || cmd
== NULL
)
992 err(1, "asprintf failed");
998 (void)unlink(to_name
);
999 errx(1, "vfork: %s", strerror(serrno
));
1004 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1006 execlp(stripprog
, "strip", to_name
, NULL
);
1008 progname
= getprogname();
1009 write(STDERR_FILENO
, progname
, strlen(progname
));
1010 write(STDERR_FILENO
, exec_failure
, strlen(exec_failure
));
1011 write(STDERR_FILENO
, stripprog
, strlen(stripprog
));
1012 write(STDERR_FILENO
, "\n", 1);
1016 if (wait(&status
) == -1 || status
)
1017 (void)unlink(to_name
);
1025 * run provided command on the target file or directory after it's been
1026 * installed and stripped, but before permissions are set or it's renamed
1029 afterinstall(const char *command
, const char *to_name
, int errunlink
)
1038 (void)unlink(to_name
);
1039 errx(1, "vfork: %s", strerror(serrno
));
1043 * build up a command line and let /bin/sh
1044 * parse the arguments
1046 cmd
= (char*)malloc(sizeof(char)*
1051 errx(1, "%s", strerror(ENOMEM
));
1053 sprintf(cmd
, "%s %s", command
, to_name
);
1055 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1057 warn("%s: exec of after install command", command
);
1061 if ((wait(&status
) == -1 || status
) && errunlink
)
1062 (void)unlink(to_name
);
1068 * backup file "to_name" to to_name.suffix
1069 * if suffix contains a "%", it's taken as a printf(3) pattern
1070 * used for a numbered backup.
1073 backup(const char *to_name
)
1075 char bname
[FILENAME_MAX
];
1077 if (numberedbackup
) {
1078 /* Do numbered backup */
1080 char suffix_expanded
[FILENAME_MAX
];
1084 (void)snprintf(suffix_expanded
, FILENAME_MAX
, suffix
,
1086 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
,
1089 } while (access(bname
, F_OK
) == 0);
1091 /* Do simple backup */
1092 (void)snprintf(bname
, FILENAME_MAX
, "%s%s", to_name
, suffix
);
1095 (void)rename(to_name
, bname
);
1100 * build directory hierarchy
1103 install_dir(char *path
, u_int flags
)
1109 for (p
= path
;; ++p
)
1110 if (!*p
|| (p
!= path
&& *p
== '/')) {
1113 if (mkdir(path
, 0777) < 0) {
1115 * Can't create; path exists or no perms.
1116 * stat() path to determine what's there now.
1120 if (stat(path
, &sb
) < 0) {
1121 /* Not there; use mkdir()s error */
1123 err(1, "%s: mkdir", path
);
1125 if (!S_ISDIR(sb
.st_mode
)) {
1127 "%s exists but is not a directory",
1135 if (afterinstallcmd
!= NULL
)
1136 afterinstall(afterinstallcmd
, path
, 0);
1139 ((flags
& (HASUID
| HASGID
)) && chown(path
, uid
, gid
) == -1)
1140 || chmod(path
, mode
) == -1 )) {
1141 warn("%s: chown/chmod", path
);
1143 metadata_log(path
, "dir", NULL
, NULL
, NULL
, 0);
1148 * if metafp is not NULL, output mtree(8) full path name and settings to
1149 * metafp, to allow permissions to be set correctly by other tools,
1150 * or to allow integrity checks to be performed.
1153 metadata_log(const char *path
, const char *type
, struct timeval
*tv
,
1154 const char *slink
, const char *digestresult
, off_t size
)
1156 static const char extra
[] = { ' ', '\t', '\n', '\\', '#', '\0' };
1160 struct flock metalog_lock
;
1164 buf
= (char *)malloc(4 * strlen(path
) + 1); /* buf for strsvis(3) */
1166 warnx("%s", strerror(ENOMEM
));
1170 metalog_lock
.l_start
= 0;
1171 metalog_lock
.l_len
= 0;
1172 metalog_lock
.l_whence
= SEEK_SET
;
1173 metalog_lock
.l_type
= F_WRLCK
;
1174 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1175 warn("can't lock %s", metafile
);
1180 p
= path
; /* remove destdir */
1182 destlen
= strlen(destdir
);
1183 if (strncmp(p
, destdir
, destlen
) == 0 &&
1184 (p
[destlen
] == '/' || p
[destlen
] == '\0'))
1187 while (*p
&& *p
== '/') /* remove leading /s */
1189 strsvis(buf
, p
, VIS_CSTYLE
, extra
); /* encode name */
1192 fprintf(metafp
, ".%s%s type=%s", *p
? "/" : "", p
, type
);
1194 fprintf(metafp
, " uname=%s", owner
);
1196 fprintf(metafp
, " gname=%s", group
);
1197 fprintf(metafp
, " mode=%#o", mode
);
1199 strsvis(buf
, slink
, VIS_CSTYLE
, extra
); /* encode link */
1200 fprintf(metafp
, " link=%s", buf
);
1202 if (*type
== 'f') /* type=file */
1203 fprintf(metafp
, " size=%lld", (long long)size
);
1204 if (tv
!= NULL
&& dopreserve
)
1205 fprintf(metafp
, " time=%lld.%ld",
1206 (long long)tv
[1].tv_sec
, (long)tv
[1].tv_usec
);
1207 if (digestresult
&& digest
)
1208 fprintf(metafp
, " %s=%s", digest
, digestresult
);
1210 fprintf(metafp
, " flags=%s", fflags
);
1212 fprintf(metafp
, " tags=%s", tags
);
1213 fputc('\n', metafp
);
1214 fflush(metafp
); /* flush output */
1215 /* unlock log file */
1216 metalog_lock
.l_type
= F_UNLCK
;
1217 if (fcntl(fileno(metafp
), F_SETLKW
, &metalog_lock
) == -1) {
1218 warn("can't unlock %s", metafile
);
1225 * libc basename(3) that returns a pointer to a static buffer
1226 * instead of overwriting that passed-in string.
1229 xbasename(char *path
)
1231 static char tmp
[MAXPATHLEN
];
1233 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1234 return (basename(tmp
));
1239 * libc dirname(3) that returns a pointer to a static buffer
1240 * instead of overwriting that passed-in string.
1243 xdirname(char *path
)
1245 static char tmp
[MAXPATHLEN
];
1247 (void)strlcpy(tmp
, path
, sizeof(tmp
));
1248 return (dirname(tmp
));
1253 * print a usage message and die
1260 prog
= getprogname();
1262 (void)fprintf(stderr
,
1263 "usage: %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1264 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group] \n"
1265 " [-l linkflags] [-h hash] [-S stripflags] file1 file2\n"
1266 " %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1267 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group]\n"
1268 " [-l linkflags] [-h hash] [-S stripflags] file1 ... fileN directory\n"
1269 " %s -d [-Up] [-M log] [-D dest] [-T tags] [-a aftercmd] [-m mode]\n"
1270 " [-N dbdir] [-o owner] [-g group] directory ...\n",