xinstall.c revision 1.128 1 /* $NetBSD: xinstall.c,v 1.128 2024/05/10 09:14:52 wiz Exp $ */
2
3 /*
4 * Copyright (c) 1987, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. 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.
18 *
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
29 * SUCH DAMAGE.
30 */
31
32 /*-
33 * Copyright (c) 2015 The NetBSD Foundation, Inc.
34 * All rights reserved.
35 *
36 * This code is derived from software contributed to The NetBSD Foundation
37 * by Christos Zoulas.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 * POSSIBILITY OF SUCH DAMAGE.
59 */
60
61 #define __MKTEMP_OK__ /* All uses of mktemp have been checked */
62
63 #if HAVE_NBTOOL_CONFIG_H
64 #include "nbtool_config.h"
65 #else
66 #define HAVE_FUTIMES 1
67 #define HAVE_POSIX_SPAWN 1
68 #define HAVE_STRUCT_STAT_ST_FLAGS 1
69 #endif
70
71 #include <sys/cdefs.h>
72 #if defined(__COPYRIGHT) && !defined(lint)
73 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
74 The Regents of the University of California. All rights reserved.");
75 #endif /* not lint */
76
77 #if defined(__RCSID) && !defined(lint)
78 #if 0
79 static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93";
80 #else
81 __RCSID("$NetBSD: xinstall.c,v 1.128 2024/05/10 09:14:52 wiz Exp $");
82 #endif
83 #endif /* not lint */
84
85 #include <sys/param.h>
86 #include <sys/mman.h>
87 #include <sys/stat.h>
88 #include <sys/wait.h>
89 #include <sys/time.h>
90
91 #include <ctype.h>
92 #include <err.h>
93 #include <errno.h>
94 #include <fcntl.h>
95 #include <grp.h>
96 #include <libgen.h>
97 #include <paths.h>
98 #include <pwd.h>
99 #include <stdio.h>
100 #include <stdlib.h>
101 #include <string.h>
102 #include <unistd.h>
103 #include <util.h>
104 #include <vis.h>
105
106 #ifdef HAVE_POSIX_SPAWN
107 #include <spawn.h>
108 #endif
109
110 #include <md5.h>
111 #include <rmd160.h>
112 #include <sha1.h>
113 #include <sha2.h>
114
115 #include "pathnames.h"
116 #include "mtree.h"
117
118 #define BACKUP_SUFFIX ".old"
119
120 static int dobackup, dodir, dostrip, dolink, dopreserve, dorename, dounpriv;
121 static int haveopt_f, haveopt_g, haveopt_m, haveopt_o;
122 static int numberedbackup;
123 static int verbose;
124 static int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
125 static char pathbuf[MAXPATHLEN];
126 static uid_t uid = -1;
127 static gid_t gid = -1;
128 static char *group, *owner, *fflags, *tags;
129 static FILE *metafp;
130 static char *metafile;
131 static u_long fileflags;
132 static char *stripArgs;
133 static char *afterinstallcmd;
134 static const char *suffix = BACKUP_SUFFIX;
135 static char *destdir;
136
137 enum {
138 DIGEST_NONE = 0,
139 DIGEST_MD5,
140 DIGEST_RMD160,
141 DIGEST_SHA1,
142 DIGEST_SHA256,
143 DIGEST_SHA384,
144 DIGEST_SHA512,
145 } digesttype = DIGEST_NONE;
146
147 static char *digest;
148
149 #define LN_ABSOLUTE 0x01
150 #define LN_RELATIVE 0x02
151 #define LN_HARD 0x04
152 #define LN_SYMBOLIC 0x08
153 #define LN_MIXED 0x10
154
155 #define DIRECTORY 0x01 /* Tell install it's a directory. */
156 #define SETFLAGS 0x02 /* Tell install to set flags. */
157 #define HASUID 0x04 /* Tell install the uid was given */
158 #define HASGID 0x08 /* Tell install the gid was given */
159
160 static void afterinstall(const char *, const char *, int);
161 static void backup(const char *);
162 static char *copy(int, char *, int, char *, off_t);
163 static int do_link(char *, char *);
164 static void do_symlink(char *, char *);
165 static void install(char *, char *, u_int);
166 static void install_dir(char *, u_int);
167 static void makelink(char *, char *);
168 static void metadata_log(const char *, const char *, struct timeval *,
169 const char *, const char *, off_t);
170 static int parseid(char *, id_t *);
171 static void run(const char *, const char *, const char *, int);
172 static void strip(const char *);
173 __dead static void usage(void);
174 static char *xbasename(char *);
175 static char *xdirname(char *);
176 static int needshell(const char *, int);
177
178 int
179 main(int argc, char *argv[])
180 {
181 struct stat from_sb, to_sb;
182 void *set;
183 u_int iflags;
184 int ch, no_target;
185 char *p, *to_name;
186
187 setprogname(argv[0]);
188
189 iflags = 0;
190 while ((ch = getopt(argc, argv, "a:cbB:dD:f:g:h:l:m:M:N:o:prsS:T:Uv"))
191 != -1)
192 switch((char)ch) {
193 case 'a':
194 afterinstallcmd = strdup(optarg);
195 if (afterinstallcmd == NULL)
196 err(EXIT_FAILURE,
197 "Can't allocate after command");
198 break;
199 case 'B':
200 suffix = optarg;
201 numberedbackup = 0;
202 {
203 /* Check if given suffix really generates
204 different suffixes - catch e.g. ".%" */
205 char suffix_expanded0[FILENAME_MAX],
206 suffix_expanded1[FILENAME_MAX];
207 (void)snprintf(suffix_expanded0, FILENAME_MAX,
208 suffix, 0);
209 (void)snprintf(suffix_expanded1, FILENAME_MAX,
210 suffix, 1);
211 if (strcmp(suffix_expanded0, suffix_expanded1)
212 != 0)
213 numberedbackup = 1;
214 }
215 /* fall through; -B implies -b */
216 /*FALLTHROUGH*/
217 case 'b':
218 dobackup = 1;
219 break;
220 case 'c':
221 /* ignored; was "docopy" which is now the default. */
222 break;
223 case 'd':
224 dodir = 1;
225 break;
226 case 'D':
227 destdir = optarg;
228 break;
229 #if ! HAVE_NBTOOL_CONFIG_H
230 case 'f':
231 haveopt_f = 1;
232 fflags = optarg;
233 break;
234 #endif
235 case 'g':
236 haveopt_g = 1;
237 group = optarg;
238 break;
239 case 'h':
240 digest = optarg;
241 break;
242 case 'l':
243 for (p = optarg; *p; p++)
244 switch (*p) {
245 case 's':
246 dolink &= ~(LN_HARD|LN_MIXED);
247 dolink |= LN_SYMBOLIC;
248 break;
249 case 'h':
250 dolink &= ~(LN_SYMBOLIC|LN_MIXED);
251 dolink |= LN_HARD;
252 break;
253 case 'm':
254 dolink &= ~(LN_SYMBOLIC|LN_HARD);
255 dolink |= LN_MIXED;
256 break;
257 case 'a':
258 dolink &= ~LN_RELATIVE;
259 dolink |= LN_ABSOLUTE;
260 break;
261 case 'r':
262 dolink &= ~LN_ABSOLUTE;
263 dolink |= LN_RELATIVE;
264 break;
265 default:
266 errx(EXIT_FAILURE, "%c: invalid link type", *p);
267 /* NOTREACHED */
268 }
269 break;
270 case 'm':
271 haveopt_m = 1;
272 if (!(set = setmode(optarg)))
273 err(EXIT_FAILURE, "Cannot set file mode `%s'", optarg);
274 mode = getmode(set, 0);
275 free(set);
276 break;
277 case 'M':
278 metafile = optarg;
279 break;
280 case 'N':
281 if (! setup_getid(optarg))
282 errx(EXIT_FAILURE,
283 "Unable to use user and group databases in `%s'",
284 optarg);
285 break;
286 case 'o':
287 haveopt_o = 1;
288 owner = optarg;
289 break;
290 case 'p':
291 dopreserve = 1;
292 break;
293 case 'r':
294 dorename = 1;
295 break;
296 case 'S':
297 stripArgs = strdup(optarg);
298 if (stripArgs == NULL)
299 err(EXIT_FAILURE, "Can't allocate options");
300 /* fall through; -S implies -s */
301 /*FALLTHROUGH*/
302 case 's':
303 dostrip = 1;
304 break;
305 case 'T':
306 tags = optarg;
307 break;
308 case 'U':
309 dounpriv = 1;
310 break;
311 case 'v':
312 verbose = 1;
313 break;
314 case '?':
315 default:
316 usage();
317 }
318 argc -= optind;
319 argv += optind;
320
321 /* strip and link options make no sense when creating directories */
322 if ((dostrip || dolink) && dodir)
323 usage();
324
325 /* strip and flags make no sense with links */
326 if ((dostrip || fflags) && dolink)
327 usage();
328
329 /* must have at least two arguments, except when creating directories */
330 if (argc < 2 && !dodir)
331 usage();
332
333 if (digest) {
334 if (0) {
335 } else if (strcmp(digest, "none") == 0) {
336 digesttype = DIGEST_NONE;
337 } else if (strcmp(digest, "md5") == 0) {
338 digesttype = DIGEST_MD5;
339 } else if (strcmp(digest, "rmd160") == 0) {
340 digesttype = DIGEST_RMD160;
341 } else if (strcmp(digest, "sha1") == 0) {
342 digesttype = DIGEST_SHA1;
343 } else if (strcmp(digest, "sha256") == 0) {
344 digesttype = DIGEST_SHA256;
345 } else if (strcmp(digest, "sha384") == 0) {
346 digesttype = DIGEST_SHA384;
347 } else if (strcmp(digest, "sha512") == 0) {
348 digesttype = DIGEST_SHA512;
349 } else {
350 warnx("unknown digest `%s'", digest);
351 usage();
352 }
353 }
354
355 /* get group and owner id's */
356 if (group && !dounpriv) {
357 if (gid_from_group(group, &gid) == -1) {
358 id_t id;
359 if (!parseid(group, &id))
360 errx(EXIT_FAILURE, "unknown group %s", group);
361 gid = id;
362 }
363 iflags |= HASGID;
364 }
365 if (owner && !dounpriv) {
366 if (uid_from_user(owner, &uid) == -1) {
367 id_t id;
368 if (!parseid(owner, &id))
369 errx(EXIT_FAILURE, "unknown user %s", owner);
370 uid = id;
371 }
372 iflags |= HASUID;
373 }
374
375 #if ! HAVE_NBTOOL_CONFIG_H
376 if (fflags && !dounpriv) {
377 if (string_to_flags(&fflags, &fileflags, NULL))
378 errx(EXIT_FAILURE, "%s: invalid flag", fflags);
379 /* restore fflags since string_to_flags() changed it */
380 fflags = flags_to_string(fileflags, "-");
381 iflags |= SETFLAGS;
382 }
383 #endif
384
385 if (metafile) {
386 if ((metafp = fopen(metafile, "a")) == NULL)
387 warn("open %s", metafile);
388 } else
389 digesttype = DIGEST_NONE;
390
391 if (dodir) {
392 for (; *argv != NULL; ++argv)
393 install_dir(*argv, iflags);
394 exit (0);
395 }
396
397 no_target = stat(to_name = argv[argc - 1], &to_sb);
398 if (!no_target && S_ISDIR(to_sb.st_mode)) {
399 for (; *argv != to_name; ++argv)
400 install(*argv, to_name, iflags | DIRECTORY);
401 exit(0);
402 }
403
404 /* can't do file1 file2 directory/file */
405 if (argc != 2) {
406 errx(EXIT_FAILURE, "the last argument (%s) "
407 "must name an existing directory", argv[argc - 1]);
408 /* NOTREACHED */
409 }
410
411 if (!no_target) {
412 /* makelink() handles checks for links */
413 if (!dolink) {
414 if (stat(*argv, &from_sb))
415 err(EXIT_FAILURE, "%s: stat", *argv);
416 if (!S_ISREG(to_sb.st_mode))
417 errx(EXIT_FAILURE, "%s: not a regular file", to_name);
418 if (to_sb.st_dev == from_sb.st_dev &&
419 to_sb.st_ino == from_sb.st_ino)
420 errx(EXIT_FAILURE, "%s and %s are the same file", *argv,
421 to_name);
422 }
423 /*
424 * Unlink now... avoid ETXTBSY errors later. Try and turn
425 * off the append/immutable bits -- if we fail, go ahead,
426 * it might work.
427 */
428 #if ! HAVE_NBTOOL_CONFIG_H
429 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
430 if (to_sb.st_flags & NOCHANGEBITS)
431 (void)chflags(to_name,
432 to_sb.st_flags & ~(NOCHANGEBITS));
433 #endif
434 if (dobackup)
435 backup(to_name);
436 else if (!dorename)
437 (void)unlink(to_name);
438 }
439 install(*argv, to_name, iflags);
440 exit(0);
441 }
442
443 /*
444 * parseid --
445 * parse uid or gid from arg into id, returning non-zero if successful
446 */
447 static int
448 parseid(char *name, id_t *id)
449 {
450 char *ep;
451
452 errno = 0;
453 *id = (id_t)strtoul(name, &ep, 10);
454 if (errno || *ep != '\0')
455 return (0);
456 return (1);
457 }
458
459 /*
460 * do_link --
461 * make a hard link, obeying dorename if set
462 * return -1 on failure
463 */
464 static int
465 do_link(char *from_name, char *to_name)
466 {
467 char tmpl[MAXPATHLEN];
468 int ret;
469
470 if (dorename) {
471 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name);
472 /* This usage is safe. */
473 if (mktemp(tmpl) == NULL)
474 err(EXIT_FAILURE, "%s: mktemp", tmpl);
475 ret = link(from_name, tmpl);
476 if (ret == 0) {
477 ret = rename(tmpl, to_name);
478 /* If rename has posix semantics, then the temporary
479 * file may still exist when from_name and to_name point
480 * to the same file, so unlink it unconditionally.
481 */
482 (void)unlink(tmpl);
483 }
484 } else {
485 ret = link(from_name, to_name);
486 }
487 if (ret == 0 && verbose)
488 (void)printf("install: link %s -> %s\n", from_name, to_name);
489 return ret;
490 }
491
492 /*
493 * do_symlink --
494 * make a symbolic link, obeying dorename if set
495 * exit on failure
496 */
497 static void
498 do_symlink(char *from_name, char *to_name)
499 {
500 char tmpl[MAXPATHLEN];
501
502 if (dorename) {
503 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name);
504 /* This usage is safe. */
505 if (mktemp(tmpl) == NULL)
506 err(EXIT_FAILURE, "%s: mktemp", tmpl);
507
508 if (symlink(from_name, tmpl) == -1)
509 err(EXIT_FAILURE, "symlink %s -> %s", from_name, tmpl);
510 if (rename(tmpl, to_name) == -1) {
511 /* remove temporary link before exiting */
512 (void)unlink(tmpl);
513 err(EXIT_FAILURE, "%s: rename", to_name);
514 }
515 } else {
516 if (symlink(from_name, to_name) == -1)
517 err(EXIT_FAILURE, "symlink %s -> %s", from_name, to_name);
518 }
519 if (verbose)
520 (void)printf("install: symlink %s -> %s\n", from_name, to_name);
521 }
522
523 /*
524 * makelink --
525 * make a link from source to destination
526 */
527 static void
528 makelink(char *from_name, char *to_name)
529 {
530 char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN];
531 struct stat to_sb;
532
533 /* Try hard links first */
534 if (dolink & (LN_HARD|LN_MIXED)) {
535 if (do_link(from_name, to_name) == -1) {
536 if ((dolink & LN_HARD) || errno != EXDEV)
537 err(EXIT_FAILURE, "link %s -> %s", from_name, to_name);
538 } else {
539 if (stat(to_name, &to_sb))
540 err(EXIT_FAILURE, "%s: stat", to_name);
541 if (S_ISREG(to_sb.st_mode)) {
542 /* XXX: hard links to anything
543 * other than plain files are not
544 * metalogged
545 */
546 int omode;
547 char *oowner, *ogroup, *offlags;
548 char *dres;
549
550 /* XXX: use underlying perms,
551 * unless overridden on command line.
552 */
553 omode = mode;
554 if (!haveopt_m)
555 mode = (to_sb.st_mode & 0777);
556 oowner = owner;
557 if (!haveopt_o)
558 owner = NULL;
559 ogroup = group;
560 if (!haveopt_g)
561 group = NULL;
562 offlags = fflags;
563 if (!haveopt_f)
564 fflags = NULL;
565 switch (digesttype) {
566 case DIGEST_MD5:
567 dres = MD5File(from_name, NULL);
568 break;
569 case DIGEST_RMD160:
570 dres = RMD160File(from_name, NULL);
571 break;
572 case DIGEST_SHA1:
573 dres = SHA1File(from_name, NULL);
574 break;
575 case DIGEST_SHA256:
576 dres = SHA256_File(from_name, NULL);
577 break;
578 case DIGEST_SHA384:
579 dres = SHA384_File(from_name, NULL);
580 break;
581 case DIGEST_SHA512:
582 dres = SHA512_File(from_name, NULL);
583 break;
584 default:
585 dres = NULL;
586 }
587 metadata_log(to_name, "file", NULL, NULL,
588 dres, to_sb.st_size);
589 free(dres);
590 mode = omode;
591 owner = oowner;
592 group = ogroup;
593 fflags = offlags;
594 }
595 return;
596 }
597 }
598
599 /* Symbolic links */
600 if (dolink & LN_ABSOLUTE) {
601 /* Convert source path to absolute */
602 if (realpath(from_name, src) == NULL)
603 err(EXIT_FAILURE, "%s: realpath", from_name);
604 do_symlink(src, to_name);
605 /* XXX: src may point outside of destdir */
606 metadata_log(to_name, "link", NULL, src, NULL, 0);
607 return;
608 }
609
610 if (dolink & LN_RELATIVE) {
611 char *cp, *d, *s;
612
613 /* Resolve pathnames */
614 if (realpath(from_name, src) == NULL)
615 err(EXIT_FAILURE, "%s: realpath", from_name);
616
617 /*
618 * The last component of to_name may be a symlink,
619 * so use realpath to resolve only the directory.
620 */
621 cp = xdirname(to_name);
622 if (realpath(cp, dst) == NULL)
623 err(EXIT_FAILURE, "%s: realpath", cp);
624 /* .. and add the last component */
625 if (strcmp(dst, "/") != 0) {
626 if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst))
627 errx(EXIT_FAILURE, "resolved pathname too long");
628 }
629 cp = xbasename(to_name);
630 if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst))
631 errx(EXIT_FAILURE, "resolved pathname too long");
632
633 /* trim common path components */
634 for (s = src, d = dst; *s == *d; s++, d++)
635 continue;
636 while (*s != '/')
637 s--, d--;
638
639 /* count the number of directories we need to backtrack */
640 for (++d, lnk[0] = '\0'; *d; d++)
641 if (*d == '/')
642 (void)strlcat(lnk, "../", sizeof(lnk));
643
644 (void)strlcat(lnk, ++s, sizeof(lnk));
645
646 do_symlink(lnk, to_name);
647 /* XXX: lnk may point outside of destdir */
648 metadata_log(to_name, "link", NULL, lnk, NULL, 0);
649 return;
650 }
651
652 /*
653 * If absolute or relative was not specified,
654 * try the names the user provided
655 */
656 do_symlink(from_name, to_name);
657 /* XXX: from_name may point outside of destdir */
658 metadata_log(to_name, "link", NULL, from_name, NULL, 0);
659 }
660
661 /*
662 * install --
663 * build a path name and install the file
664 */
665 static void
666 install(char *from_name, char *to_name, u_int flags)
667 {
668 struct stat from_sb;
669 struct stat to_sb;
670 struct timeval tv[2];
671 off_t size;
672 int devnull, from_fd, to_fd, serrno, tmpmode;
673 char *p, tmpl[MAXPATHLEN], *oto_name, *digestresult;
674
675 size = -1;
676 if (!dolink) {
677 /* ensure that from_sb & tv are sane if !dolink */
678 if (stat(from_name, &from_sb))
679 err(EXIT_FAILURE, "%s: stat", from_name);
680 size = from_sb.st_size;
681 #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
682 TIMESPEC_TO_TIMEVAL(&tv[0], &from_sb.st_atimespec);
683 TIMESPEC_TO_TIMEVAL(&tv[1], &from_sb.st_mtimespec);
684 #else
685 tv[0].tv_sec = from_sb.st_atime;
686 tv[0].tv_usec = 0;
687 tv[1].tv_sec = from_sb.st_mtime;
688 tv[1].tv_usec = 0;
689 #endif
690 }
691
692 if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL) != 0) {
693 devnull = 0;
694 if (!dolink) {
695 if (!S_ISREG(from_sb.st_mode))
696 errx(EXIT_FAILURE, "%s: not a regular file", from_name);
697 }
698 /* Build the target path. */
699 if (flags & DIRECTORY) {
700 (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
701 to_name,
702 (p = strrchr(from_name, '/')) ? ++p : from_name);
703 to_name = pathbuf;
704 }
705 } else {
706 devnull = 1;
707 size = 0;
708 #if HAVE_STRUCT_STAT_ST_FLAGS
709 from_sb.st_flags = 0; /* XXX */
710 #endif
711 }
712
713 /*
714 * Unlink now... avoid ETXTBSY errors later. Try and turn
715 * off the append/immutable bits -- if we fail, go ahead,
716 * it might work.
717 */
718 #if ! HAVE_NBTOOL_CONFIG_H
719 if (stat(to_name, &to_sb) == 0 &&
720 to_sb.st_flags & (NOCHANGEBITS))
721 (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
722 #endif
723 if (dorename) {
724 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name);
725 oto_name = to_name;
726 to_name = tmpl;
727 } else {
728 oto_name = NULL; /* pacify gcc */
729 if (dobackup)
730 backup(to_name);
731 else
732 (void)unlink(to_name);
733 }
734
735 if (dolink) {
736 makelink(from_name, dorename ? oto_name : to_name);
737 return;
738 }
739
740 /* Create target. */
741 if (dorename) {
742 if ((to_fd = mkstemp(to_name)) == -1)
743 err(EXIT_FAILURE, "%s: mkstemp", to_name);
744 } else {
745 if ((to_fd = open(to_name,
746 O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0)
747 err(EXIT_FAILURE, "%s: open", to_name);
748 }
749 digestresult = NULL;
750 if (!devnull) {
751 if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
752 (void)unlink(to_name);
753 err(EXIT_FAILURE, "%s: open", from_name);
754 }
755 digestresult =
756 copy(from_fd, from_name, to_fd, to_name, from_sb.st_size);
757 (void)close(from_fd);
758 }
759
760 if (dostrip) {
761 strip(to_name);
762
763 /*
764 * Re-open our fd on the target, in case we used a strip
765 * that does not work in-place -- like gnu binutils strip.
766 */
767 close(to_fd);
768 if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
769 err(EXIT_FAILURE, "stripping %s", to_name);
770
771 /*
772 * Recalculate size and digestresult after stripping.
773 */
774 if (fstat(to_fd, &to_sb) != 0)
775 err(EXIT_FAILURE, "%s: fstat", to_name);
776 size = to_sb.st_size;
777 digestresult =
778 copy(to_fd, to_name, -1, NULL, size);
779
780 }
781
782 if (afterinstallcmd != NULL) {
783 afterinstall(afterinstallcmd, to_name, 1);
784
785 /*
786 * Re-open our fd on the target, in case we used an
787 * after-install command that does not work in-place
788 */
789 close(to_fd);
790 if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
791 err(EXIT_FAILURE, "running after install command on %s", to_name);
792 }
793
794 /*
795 * Set owner, group, mode for target; do the chown first,
796 * chown may lose the setuid bits.
797 */
798 if (!dounpriv &&
799 (flags & (HASUID | HASGID)) && fchown(to_fd, uid, gid) == -1) {
800 serrno = errno;
801 (void)unlink(to_name);
802 errc(EXIT_FAILURE, serrno, "%s: chown/chgrp", to_name);
803 }
804 tmpmode = mode;
805 if (dounpriv)
806 tmpmode &= S_IRWXU|S_IRWXG|S_IRWXO;
807 if (fchmod(to_fd, tmpmode) == -1) {
808 serrno = errno;
809 (void)unlink(to_name);
810 errc(EXIT_FAILURE, serrno, "%s: chmod", to_name);
811 }
812
813 /*
814 * Preserve the date of the source file.
815 */
816 if (dopreserve) {
817 #if HAVE_FUTIMES
818 if (futimes(to_fd, tv) == -1)
819 warn("%s: futimes", to_name);
820 #else
821 if (utimes(to_name, tv) == -1)
822 warn("%s: utimes", to_name);
823 #endif
824 }
825
826 (void)close(to_fd);
827
828 if (dorename) {
829 if (rename(to_name, oto_name) == -1)
830 err(EXIT_FAILURE, "%s: rename", to_name);
831 to_name = oto_name;
832 }
833 if (verbose)
834 (void)printf("install: %s -> %s\n", from_name, to_name);
835
836 /*
837 * If provided a set of flags, set them, otherwise, preserve the
838 * flags, except for the dump flag.
839 */
840 #if ! HAVE_NBTOOL_CONFIG_H
841 if (!dounpriv && chflags(to_name,
842 flags & SETFLAGS ? fileflags : from_sb.st_flags & ~UF_NODUMP) == -1)
843 {
844 if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
845 warn("%s: chflags", to_name);
846 }
847 #endif
848
849 metadata_log(to_name, "file", tv, NULL, digestresult, size);
850 free(digestresult);
851 }
852
853 /*
854 * copy --
855 * copy from one file to another, returning a digest.
856 *
857 * If to_fd < 0, just calculate a digest, don't copy.
858 */
859 static char *
860 copy(int from_fd, char *from_name, int to_fd, char *to_name, off_t size)
861 {
862 ssize_t nr, nw;
863 int serrno;
864 u_char *p;
865 u_char buf[MAXBSIZE];
866 MD5_CTX ctxMD5;
867 RMD160_CTX ctxRMD160;
868 SHA1_CTX ctxSHA1;
869 SHA256_CTX ctxSHA256;
870 SHA384_CTX ctxSHA384;
871 SHA512_CTX ctxSHA512;
872
873 switch (digesttype) {
874 case DIGEST_MD5:
875 MD5Init(&ctxMD5);
876 break;
877 case DIGEST_RMD160:
878 RMD160Init(&ctxRMD160);
879 break;
880 case DIGEST_SHA1:
881 SHA1Init(&ctxSHA1);
882 break;
883 case DIGEST_SHA256:
884 SHA256_Init(&ctxSHA256);
885 break;
886 case DIGEST_SHA384:
887 SHA384_Init(&ctxSHA384);
888 break;
889 case DIGEST_SHA512:
890 SHA512_Init(&ctxSHA512);
891 break;
892 case DIGEST_NONE:
893 if (to_fd < 0)
894 return NULL; /* no need to do anything */
895 default:
896 break;
897 }
898 /*
899 * There's no reason to do anything other than close the file
900 * now if it's empty, so let's not bother.
901 */
902 if (size > 0) {
903
904 /*
905 * Mmap and write if less than 8M (the limit is so we
906 * don't totally trash memory on big files). This is
907 * really a minor hack, but it wins some CPU back.
908 */
909
910 if (size <= 8 * 1048576) {
911 if ((p = mmap(NULL, (size_t)size, PROT_READ,
912 MAP_FILE|MAP_SHARED, from_fd, (off_t)0))
913 == MAP_FAILED) {
914 goto mmap_failed;
915 }
916 #if defined(MADV_SEQUENTIAL) && !defined(__APPLE__)
917 if (madvise(p, (size_t)size, MADV_SEQUENTIAL) == -1
918 && errno != EOPNOTSUPP)
919 warn("madvise");
920 #endif
921
922 if (to_fd >= 0 && write(to_fd, p, size) != size) {
923 serrno = errno;
924 (void)unlink(to_name);
925 errc(EXIT_FAILURE, serrno, "%s: write",
926 to_name);
927 }
928 switch (digesttype) {
929 case DIGEST_MD5:
930 MD5Update(&ctxMD5, p, size);
931 break;
932 case DIGEST_RMD160:
933 RMD160Update(&ctxRMD160, p, size);
934 break;
935 case DIGEST_SHA1:
936 SHA1Update(&ctxSHA1, p, size);
937 break;
938 case DIGEST_SHA256:
939 SHA256_Update(&ctxSHA256, p, size);
940 break;
941 case DIGEST_SHA384:
942 SHA384_Update(&ctxSHA384, p, size);
943 break;
944 case DIGEST_SHA512:
945 SHA512_Update(&ctxSHA512, p, size);
946 break;
947 default:
948 break;
949 }
950 (void)munmap(p, size);
951 } else {
952 mmap_failed:
953 while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
954 if (to_fd >= 0 &&
955 (nw = write(to_fd, buf, nr)) != nr) {
956 serrno = errno;
957 (void)unlink(to_name);
958 errc(EXIT_FAILURE,
959 nw > 0 ? EIO : serrno,
960 "%s: write", to_name);
961 }
962 switch (digesttype) {
963 case DIGEST_MD5:
964 MD5Update(&ctxMD5, buf, nr);
965 break;
966 case DIGEST_RMD160:
967 RMD160Update(&ctxRMD160, buf, nr);
968 break;
969 case DIGEST_SHA1:
970 SHA1Update(&ctxSHA1, buf, nr);
971 break;
972 case DIGEST_SHA256:
973 SHA256_Update(&ctxSHA256, buf, nr);
974 break;
975 case DIGEST_SHA384:
976 SHA384_Update(&ctxSHA384, buf, nr);
977 break;
978 case DIGEST_SHA512:
979 SHA512_Update(&ctxSHA512, buf, nr);
980 break;
981 default:
982 break;
983 }
984 }
985 if (nr != 0) {
986 serrno = errno;
987 (void)unlink(to_name);
988 errc(EXIT_FAILURE, serrno, "%s: read",
989 from_name);
990 }
991 }
992 }
993 switch (digesttype) {
994 case DIGEST_MD5:
995 return MD5End(&ctxMD5, NULL);
996 case DIGEST_RMD160:
997 return RMD160End(&ctxRMD160, NULL);
998 case DIGEST_SHA1:
999 return SHA1End(&ctxSHA1, NULL);
1000 case DIGEST_SHA256:
1001 return SHA256_End(&ctxSHA256, NULL);
1002 case DIGEST_SHA384:
1003 return SHA384_End(&ctxSHA384, NULL);
1004 case DIGEST_SHA512:
1005 return SHA512_End(&ctxSHA512, NULL);
1006 default:
1007 return NULL;
1008 }
1009 }
1010
1011 static void
1012 run(const char *command, const char *flags, const char *to_name, int errunlink)
1013 {
1014 char *args[4];
1015 char *cmd;
1016 int status;
1017 int rv;
1018 size_t i;
1019
1020 i = 1;
1021 status = 0;
1022
1023 if (needshell(command, 1)) {
1024 rv = asprintf(&cmd, "%s %s%s%s", command, flags ? flags : "",
1025 flags ? " " : "", to_name);
1026 if (rv < 0) {
1027 warn("Cannot execute %s", command);
1028 goto out;
1029 }
1030 command = _PATH_BSHELL;
1031 flags = "-c";
1032 } else
1033 cmd = __UNCONST(to_name);
1034
1035 args[0] = __UNCONST(command);
1036 if (flags)
1037 args[i++] = __UNCONST(flags);
1038 args[i++] = cmd;
1039 args[i] = NULL;
1040
1041 #ifdef HAVE_POSIX_SPAWN
1042 if (*command == '/')
1043 rv = posix_spawn(NULL, command, NULL, NULL, args, NULL);
1044 else
1045 rv = posix_spawnp(NULL, command, NULL, NULL, args, NULL);
1046 if (rv != 0)
1047 warnc(rv, "Cannot execute %s", command);
1048 /*
1049 * the wait below will fail if we did not create a child it will
1050 * make rv negative.
1051 */
1052 #else
1053 switch (vfork()) {
1054 case -1:
1055 rv = errno;
1056 if (errunlink)
1057 (void)unlink(to_name);
1058 errc(EXIT_FAILURE, rv, "vfork");
1059 /*NOTREACHED*/
1060 case 0:
1061 if (*command == '/')
1062 execv(command, args);
1063 else
1064 execvp(command, args);
1065 rv = errno;
1066 const char *arr[] = {
1067 getprogname(),
1068 ": exec failed for ",
1069 command,
1070 " (",
1071 strerror(rv),
1072 ")\n",
1073 };
1074 for (i = 0; i < __arraycount(arr); i++)
1075 write(STDERR_FILENO, arr[i], strlen(arr[i]));
1076 _exit(1);
1077 /*NOTREACHED*/
1078 default:
1079 break;
1080 }
1081 #endif
1082 rv = wait(&status);
1083 if (cmd != to_name)
1084 free(cmd);
1085 out:
1086 if ((rv < 0 || status) && errunlink)
1087 (void)unlink(to_name);
1088 }
1089
1090 /*
1091 * strip --
1092 * use strip(1) to strip the target file
1093 */
1094 static void
1095 strip(const char *to_name)
1096 {
1097 const char *stripprog;
1098
1099 if ((stripprog = getenv("STRIP")) == NULL || *stripprog == '\0') {
1100 #ifdef TARGET_STRIP
1101 stripprog = TARGET_STRIP;
1102 #else
1103 stripprog = _PATH_STRIP;
1104 #endif
1105 }
1106 run(stripprog, stripArgs, to_name, 1);
1107 }
1108
1109 /*
1110 * afterinstall --
1111 * run provided command on the target file or directory after it's been
1112 * installed and stripped, but before permissions are set or it's renamed
1113 */
1114 static void
1115 afterinstall(const char *command, const char *to_name, int errunlink)
1116 {
1117 run(command, NULL, to_name, errunlink);
1118 }
1119
1120 /*
1121 * backup --
1122 * backup file "to_name" to to_name.suffix
1123 * if suffix contains a "%", it's taken as a printf(3) pattern
1124 * used for a numbered backup.
1125 */
1126 static void
1127 backup(const char *to_name)
1128 {
1129 char bname[FILENAME_MAX];
1130
1131 if (numberedbackup) {
1132 /* Do numbered backup */
1133 int cnt;
1134 char suffix_expanded[FILENAME_MAX];
1135
1136 cnt=0;
1137 do {
1138 (void)snprintf(suffix_expanded, FILENAME_MAX, suffix,
1139 cnt);
1140 (void)snprintf(bname, FILENAME_MAX, "%s%s", to_name,
1141 suffix_expanded);
1142 cnt++;
1143 } while (access(bname, F_OK) == 0);
1144 } else {
1145 /* Do simple backup */
1146 (void)snprintf(bname, FILENAME_MAX, "%s%s", to_name, suffix);
1147 }
1148
1149 if (rename(to_name, bname) == 0) {
1150 if (verbose)
1151 (void)printf("install: %s -> %s\n", to_name, bname);
1152 }
1153 }
1154
1155 /*
1156 * install_dir --
1157 * build directory hierarchy
1158 */
1159 static void
1160 install_dir(char *path, u_int flags)
1161 {
1162 char *p;
1163 struct stat sb;
1164 int ch;
1165
1166 for (p = path;; ++p)
1167 if (!*p || (p != path && *p == '/')) {
1168 ch = *p;
1169 *p = '\0';
1170 if (mkdir(path, 0777) < 0) {
1171 /*
1172 * Can't create; path exists or no perms.
1173 * stat() path to determine what's there now.
1174 */
1175 int sverrno;
1176 sverrno = errno;
1177 if (stat(path, &sb) < 0) {
1178 /* Not there; use mkdir()s error */
1179 errno = sverrno;
1180 err(EXIT_FAILURE, "%s: mkdir", path);
1181 }
1182 if (!S_ISDIR(sb.st_mode)) {
1183 errx(EXIT_FAILURE,
1184 "%s exists but is not a directory",
1185 path);
1186 }
1187 }
1188 if (verbose)
1189 (void)printf("install: mkdir %s\n", path);
1190 if (!(*p = ch))
1191 break;
1192 }
1193
1194 if (afterinstallcmd != NULL)
1195 afterinstall(afterinstallcmd, path, 0);
1196
1197 if (!dounpriv && (
1198 ((flags & (HASUID | HASGID)) && chown(path, uid, gid) == -1)
1199 || chmod(path, mode) == -1 )) {
1200 warn("%s: chown/chmod", path);
1201 }
1202 metadata_log(path, "dir", NULL, NULL, NULL, 0);
1203 }
1204
1205 /*
1206 * metadata_log --
1207 * if metafp is not NULL, output mtree(8) full path name and settings to
1208 * metafp, to allow permissions to be set correctly by other tools,
1209 * or to allow integrity checks to be performed.
1210 */
1211 static void
1212 metadata_log(const char *path, const char *type, struct timeval *tv,
1213 const char *slink, const char *digestresult, off_t size)
1214 {
1215 static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
1216 const char *p;
1217 char *buf;
1218 size_t destlen;
1219 struct flock metalog_lock;
1220
1221 if (!metafp)
1222 return;
1223 buf = malloc(4 * strlen(path) + 1); /* buf for strsvis(3) */
1224 if (buf == NULL) {
1225 warn("Can't allocate metadata");
1226 return;
1227 }
1228 /* lock log file */
1229 metalog_lock.l_start = 0;
1230 metalog_lock.l_len = 0;
1231 metalog_lock.l_whence = SEEK_SET;
1232 metalog_lock.l_type = F_WRLCK;
1233 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) {
1234 warn("can't lock %s", metafile);
1235 free(buf);
1236 return;
1237 }
1238
1239 p = path; /* remove destdir */
1240 if (destdir) {
1241 destlen = strlen(destdir);
1242 if (strncmp(p, destdir, destlen) == 0 &&
1243 (p[destlen] == '/' || p[destlen] == '\0'))
1244 p += destlen;
1245 }
1246 while (*p && *p == '/') /* remove leading /s */
1247 p++;
1248 strsvis(buf, p, VIS_CSTYLE, extra); /* encode name */
1249 p = buf;
1250 /* print details */
1251 fprintf(metafp, ".%s%s type=%s", *p ? "/" : "", p, type);
1252 if (owner)
1253 fprintf(metafp, " uname=%s", owner);
1254 if (group)
1255 fprintf(metafp, " gname=%s", group);
1256 fprintf(metafp, " mode=%#o", mode);
1257 if (slink) {
1258 strsvis(buf, slink, VIS_CSTYLE, extra); /* encode link */
1259 fprintf(metafp, " link=%s", buf);
1260 }
1261 if (*type == 'f') /* type=file */
1262 fprintf(metafp, " size=%lld", (long long)size);
1263 if (tv != NULL && dopreserve)
1264 fprintf(metafp, " time=%lld.%0*lld",
1265 (long long)tv[1].tv_sec,
1266 (tv[1].tv_usec == 0 ? 1 : 9),
1267 (long long)tv[1].tv_usec * 1000);
1268 if (digestresult && digest)
1269 fprintf(metafp, " %s=%s", digest, digestresult);
1270 if (fflags)
1271 fprintf(metafp, " flags=%s", fflags);
1272 if (tags)
1273 fprintf(metafp, " tags=%s", tags);
1274 fputc('\n', metafp);
1275 fflush(metafp); /* flush output */
1276 /* unlock log file */
1277 metalog_lock.l_type = F_UNLCK;
1278 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) {
1279 warn("can't unlock %s", metafile);
1280 }
1281 free(buf);
1282 }
1283
1284 /*
1285 * xbasename --
1286 * libc basename(3) that returns a pointer to a static buffer
1287 * instead of overwriting that passed-in string.
1288 */
1289 static char *
1290 xbasename(char *path)
1291 {
1292 static char tmp[MAXPATHLEN];
1293
1294 (void)strlcpy(tmp, path, sizeof(tmp));
1295 return (basename(tmp));
1296 }
1297
1298 /*
1299 * xdirname --
1300 * libc dirname(3) that returns a pointer to a static buffer
1301 * instead of overwriting that passed-in string.
1302 */
1303 static char *
1304 xdirname(char *path)
1305 {
1306 static char tmp[MAXPATHLEN];
1307
1308 (void)strlcpy(tmp, path, sizeof(tmp));
1309 return (dirname(tmp));
1310 }
1311
1312 /*
1313 * usage --
1314 * print a usage message and die
1315 */
1316 static void
1317 usage(void)
1318 {
1319 const char *prog;
1320
1321 prog = getprogname();
1322
1323 (void)fprintf(stderr,
1324 "usage: %s [-bcprsUv] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1325 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group] \n"
1326 " [-l linkflags] [-h hash] [-S stripflags] file1 file2\n"
1327 " %s [-bcprsUv] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1328 " [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group]\n"
1329 " [-l linkflags] [-h hash] [-S stripflags] file1 ... fileN directory\n"
1330 " %s -d [-pUv] [-M log] [-D dest] [-T tags] [-a aftercmd] [-m mode]\n"
1331 " [-N dbdir] [-o owner] [-g group] directory ...\n",
1332 prog, prog, prog);
1333 exit(1);
1334 }
1335
1336 /*
1337 * The following array is used to make a fast determination of which
1338 * characters are interpreted specially by the shell. If a command
1339 * contains any of these characters, it is executed by the shell, not
1340 * directly by us.
1341 */
1342 static unsigned char _metachar[128] = {
1343 /* nul soh stx etx eot enq ack bel */
1344 1, 0, 0, 0, 0, 0, 0, 0,
1345 /* bs ht nl vt np cr so si */
1346 0, 0, 1, 0, 0, 0, 0, 0,
1347 /* dle dc1 dc2 dc3 dc4 nak syn etb */
1348 0, 0, 0, 0, 0, 0, 0, 0,
1349 /* can em sub esc fs gs rs us */
1350 0, 0, 0, 0, 0, 0, 0, 0,
1351 /* sp ! " # $ % & ' */
1352 0, 1, 1, 1, 1, 0, 1, 1,
1353 /* ( ) * + , - . / */
1354 1, 1, 1, 0, 0, 0, 0, 0,
1355 /* 0 1 2 3 4 5 6 7 */
1356 0, 0, 0, 0, 0, 0, 0, 0,
1357 /* 8 9 : ; < = > ? */
1358 0, 0, 0, 1, 1, 0, 1, 1,
1359 /* @ A B C D E F G */
1360 0, 0, 0, 0, 0, 0, 0, 0,
1361 /* H I J K L M N O */
1362 0, 0, 0, 0, 0, 0, 0, 0,
1363 /* P Q R S T U V W */
1364 0, 0, 0, 0, 0, 0, 0, 0,
1365 /* X Y Z [ \ ] ^ _ */
1366 0, 0, 0, 1, 1, 1, 1, 0,
1367 /* ` a b c d e f g */
1368 1, 0, 0, 0, 0, 0, 0, 0,
1369 /* h i j k l m n o */
1370 0, 0, 0, 0, 0, 0, 0, 0,
1371 /* p q r s t u v w */
1372 0, 0, 0, 0, 0, 0, 0, 0,
1373 /* x y z { | } ~ del */
1374 0, 0, 0, 1, 1, 1, 1, 0,
1375 };
1376
1377 #define ismeta(c) _metachar[(c) & 0x7f]
1378
1379 static int
1380 needshell(const char *cmd, int white)
1381 {
1382 while (!ismeta(*cmd) && *cmd != ':' && *cmd != '=') {
1383 if (white && isspace((unsigned char)*cmd))
1384 break;
1385 cmd++;
1386 }
1387
1388 return *cmd != '\0';
1389 }
1390