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