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