1 1.18 martin /* $NetBSD: target.c,v 1.18 2022/02/10 16:11:41 martin Exp $ */ 2 1.1 dholland 3 1.1 dholland /* 4 1.1 dholland * Copyright 1997 Jonathan Stone 5 1.1 dholland * All rights reserved. 6 1.1 dholland * 7 1.1 dholland * Redistribution and use in source and binary forms, with or without 8 1.1 dholland * modification, are permitted provided that the following conditions 9 1.1 dholland * are met: 10 1.1 dholland * 1. Redistributions of source code must retain the above copyright 11 1.1 dholland * notice, this list of conditions and the following disclaimer. 12 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer in the 14 1.1 dholland * documentation and/or other materials provided with the distribution. 15 1.1 dholland * 3. All advertising materials mentioning features or use of this software 16 1.1 dholland * must display the following acknowledgement: 17 1.1 dholland * This product includes software developed for the NetBSD Project by 18 1.1 dholland * Jonathan Stone. 19 1.1 dholland * 4. The name of Jonathan Stone may not be used to endorse 20 1.1 dholland * or promote products derived from this software without specific prior 21 1.1 dholland * written permission. 22 1.1 dholland * 23 1.1 dholland * THIS SOFTWARE IS PROVIDED BY JONATHAN STONE ``AS IS'' 24 1.1 dholland * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.15 rillig * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 27 1.15 rillig * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 1.15 rillig * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 1.15 rillig * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33 1.1 dholland * THE POSSIBILITY OF SUCH DAMAGE. 34 1.1 dholland * 35 1.1 dholland */ 36 1.1 dholland 37 1.1 dholland /* Copyright below applies to the realpath() code */ 38 1.1 dholland 39 1.1 dholland /* 40 1.1 dholland * Copyright (c) 1989, 1991, 1993, 1995 41 1.1 dholland * The Regents of the University of California. All rights reserved. 42 1.15 rillig * 43 1.1 dholland * This code is derived from software contributed to Berkeley by 44 1.1 dholland * Jan-Simon Pendry. 45 1.1 dholland * 46 1.1 dholland * Redistribution and use in source and binary forms, with or without 47 1.1 dholland * modification, are permitted provided that the following conditions 48 1.1 dholland * are met: 49 1.1 dholland * 1. Redistributions of source code must retain the above copyright 50 1.1 dholland * notice, this list of conditions and the following disclaimer. 51 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 52 1.1 dholland * notice, this list of conditions and the following disclaimer in the 53 1.1 dholland * documentation and/or other materials provided with the distribution. 54 1.1 dholland * 3. Neither the name of the University nor the names of its contributors 55 1.1 dholland * may be used to endorse or promote products derived from this software 56 1.15 rillig * without specific prior written permission. 57 1.15 rillig * 58 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 1.1 dholland * SUCH DAMAGE. 69 1.15 rillig */ 70 1.1 dholland 71 1.1 dholland 72 1.1 dholland #include <sys/cdefs.h> 73 1.1 dholland #if defined(LIBC_SCCS) && !defined(lint) 74 1.18 martin __RCSID("$NetBSD: target.c,v 1.18 2022/02/10 16:11:41 martin Exp $"); 75 1.1 dholland #endif 76 1.1 dholland 77 1.1 dholland /* 78 1.1 dholland * target.c -- path-prefixing routines to access the target installation 79 1.1 dholland * filesystems. Makes the install tools more independent of whether 80 1.1 dholland * we're installing into a separate filesystem hierarchy mounted under 81 1.1 dholland * /targetroot, or into the currently active root mounted on /. 82 1.1 dholland */ 83 1.1 dholland 84 1.1 dholland #include <sys/param.h> /* XXX vm_param.h always defines TRUE*/ 85 1.1 dholland #include <sys/types.h> 86 1.16 martin #include <sys/ioctl.h> 87 1.1 dholland #include <sys/sysctl.h> 88 1.1 dholland #include <sys/stat.h> /* stat() */ 89 1.1 dholland #include <sys/mount.h> /* statfs() */ 90 1.1 dholland 91 1.1 dholland #include <fcntl.h> 92 1.1 dholland #include <stdio.h> 93 1.1 dholland #include <stdarg.h> 94 1.1 dholland #include <unistd.h> 95 1.1 dholland #include <curses.h> /* defines TRUE, but checks */ 96 1.1 dholland #include <errno.h> 97 1.16 martin #include <util.h> 98 1.1 dholland 99 1.1 dholland #include "defs.h" 100 1.1 dholland #include "md.h" 101 1.1 dholland #include "msg_defs.h" 102 1.1 dholland #include "menu_defs.h" 103 1.1 dholland 104 1.1 dholland /* 105 1.15 rillig * local prototypes 106 1.1 dholland */ 107 1.1 dholland 108 1.1 dholland static void make_prefixed_dir (const char *prefix, const char *path); 109 1.1 dholland static int do_target_chdir (const char *dir, int flag); 110 1.1 dholland int target_test(unsigned int mode, const char *path); 111 1.1 dholland int target_test_dir (const char *path); /* deprecated */ 112 1.1 dholland int target_test_file (const char *path); /* deprecated */ 113 1.1 dholland int target_test_symlink (const char *path); /* deprecated */ 114 1.1 dholland 115 1.1 dholland void unwind_mounts(void); 116 1.1 dholland 117 1.1 dholland /* Record a mount for later unwinding of target mounts. */ 118 1.1 dholland struct unwind_mount { 119 1.1 dholland struct unwind_mount *um_prev; 120 1.1 dholland char um_mountpoint[4]; /* Allocated longer... */ 121 1.1 dholland }; 122 1.1 dholland 123 1.16 martin /* Record a wedge for later deletion after all file systems have been unmounted */ 124 1.16 martin struct umount_delwedge { 125 1.16 martin struct umount_delwedge *next; 126 1.17 martin char disk[DISKNAMESIZE], wedge[DISKNAMESIZE]; 127 1.16 martin }; 128 1.16 martin struct umount_delwedge *post_umount_dwlist = NULL; 129 1.16 martin 130 1.1 dholland /* Unwind-mount stack */ 131 1.1 dholland struct unwind_mount *unwind_mountlist = NULL; 132 1.1 dholland 133 1.1 dholland /* 134 1.1 dholland * Debugging options 135 1.1 dholland */ 136 1.1 dholland /*#define DEBUG_ROOT*/ /* turn on what-is-root? debugging. */ 137 1.1 dholland /*#define DEBUG_UNWIND*/ /* turn on unwind-target-mount debugging. */ 138 1.1 dholland 139 1.1 dholland /* 140 1.1 dholland * debugging helper. curses... 141 1.1 dholland */ 142 1.1 dholland #if defined(DEBUG) || defined(DEBUG_ROOT) 143 1.1 dholland void 144 1.1 dholland backtowin(void) 145 1.1 dholland { 146 1.1 dholland 147 1.1 dholland fflush(stdout); /* curses does not leave stdout linebuffered. */ 148 1.1 dholland getchar(); /* wait for user to press return */ 149 1.1 dholland wrefresh(stdscr); 150 1.1 dholland } 151 1.1 dholland #endif 152 1.1 dholland 153 1.1 dholland 154 1.1 dholland /* 155 1.15 rillig * Is the root partition we're running from the same as the root 156 1.1 dholland * which the user has selected to install/upgrade? 157 1.2 martin * Uses global variable "pm->diskdev" to find the selected device for 158 1.1 dholland * install/upgrade. 159 1.1 dholland */ 160 1.1 dholland int 161 1.1 dholland target_already_root(void) 162 1.1 dholland { 163 1.5 martin char dev[PATH_MAX]; 164 1.5 martin int rootpart = -1; 165 1.5 martin static struct pm_devs *last_pm; 166 1.5 martin static int last_res; 167 1.5 martin part_id ptn; 168 1.12 martin struct disk_partitions *parts, *inner; 169 1.5 martin struct disk_part_info info; 170 1.5 martin 171 1.14 martin if (pm == NULL) 172 1.14 martin return 1; 173 1.14 martin 174 1.5 martin if (pm == last_pm) 175 1.5 martin return last_res; 176 1.5 martin 177 1.8 martin if (pm->cur_system) 178 1.8 martin return 1; 179 1.8 martin 180 1.5 martin last_pm = pm; 181 1.7 martin last_res = 0; 182 1.5 martin 183 1.5 martin parts = pm->parts; 184 1.7 martin if (parts == NULL) { 185 1.5 martin last_res = 0; 186 1.5 martin return 0; 187 1.5 martin } 188 1.7 martin 189 1.7 martin if (pm->no_part) { 190 1.7 martin last_res = is_active_rootpart(pm->diskdev, -1); 191 1.7 martin return last_res; 192 1.7 martin } 193 1.7 martin 194 1.12 martin if (pm->parts->pscheme->secondary_partitions != NULL) { 195 1.12 martin inner = pm->parts->pscheme->secondary_partitions(parts, 196 1.6 martin pm->ptstart, false); 197 1.12 martin if (inner != NULL) 198 1.12 martin parts = inner; 199 1.12 martin } 200 1.5 martin 201 1.5 martin for (ptn = 0; ptn < parts->num_part; ptn++) { 202 1.5 martin if (!parts->pscheme->get_part_info(parts, ptn, &info)) 203 1.5 martin continue; 204 1.5 martin if (info.nat_type->generic_ptype != PT_root) 205 1.5 martin continue; 206 1.7 martin if (!is_root_part_mount(info.last_mounted)) 207 1.5 martin continue; 208 1.5 martin if (!parts->pscheme->get_part_device(parts, ptn, 209 1.11 martin dev, sizeof dev, &rootpart, plain_name, false, true)) 210 1.5 martin continue; 211 1.1 dholland 212 1.5 martin last_res = is_active_rootpart(dev, rootpart); 213 1.7 martin break; 214 1.7 martin } 215 1.3 martin 216 1.7 martin return last_res; 217 1.1 dholland } 218 1.1 dholland 219 1.7 martin /* 220 1.7 martin * Could something with this "last mounted on" information be a potential 221 1.7 martin * root partition? 222 1.7 martin */ 223 1.7 martin bool 224 1.7 martin is_root_part_mount(const char *last_mounted) 225 1.7 martin { 226 1.9 martin if (last_mounted == NULL) 227 1.9 martin return false; 228 1.9 martin 229 1.7 martin return strcmp(last_mounted, "/") == 0 || 230 1.7 martin strcmp(last_mounted, "/targetroot") == 0 || 231 1.7 martin strcmp(last_mounted, "/altroot") == 0; 232 1.7 martin } 233 1.1 dholland 234 1.1 dholland /* 235 1.15 rillig * Is this device partition (e.g., "sd0a") mounted as root? 236 1.1 dholland */ 237 1.1 dholland int 238 1.1 dholland is_active_rootpart(const char *dev, int ptn) 239 1.1 dholland { 240 1.1 dholland int mib[2]; 241 1.1 dholland char rootdev[SSTRSIZE]; 242 1.1 dholland int rootptn; 243 1.1 dholland size_t varlen; 244 1.1 dholland 245 1.1 dholland mib[0] = CTL_KERN; 246 1.1 dholland mib[1] = KERN_ROOT_DEVICE; 247 1.1 dholland varlen = sizeof(rootdev); 248 1.1 dholland if (sysctl(mib, 2, rootdev, &varlen, NULL, 0) < 0) 249 1.1 dholland return 1; 250 1.1 dholland 251 1.1 dholland if (strcmp(dev, rootdev) != 0) 252 1.1 dholland return 0; 253 1.1 dholland 254 1.4 martin if (ptn < 0) 255 1.4 martin return 1; /* device only check, or wedge */ 256 1.4 martin 257 1.1 dholland mib[1] = KERN_ROOT_PARTITION; 258 1.1 dholland varlen = sizeof rootptn; 259 1.4 martin rootptn = -1; 260 1.1 dholland if (sysctl(mib, 2, &rootptn, &varlen, NULL, 0) < 0) 261 1.1 dholland return 1; 262 1.1 dholland 263 1.1 dholland return ptn == rootptn; 264 1.1 dholland } 265 1.1 dholland 266 1.1 dholland /* 267 1.15 rillig * Pathname prefixing glue to support installation either 268 1.1 dholland * from in-ramdisk miniroots or on-disk diskimages. 269 1.1 dholland * If our root is on the target disk, the install target is mounted 270 1.1 dholland * on /targetroot and we need to prefix installed pathnames with /targetroot. 271 1.1 dholland * otherwise we are installing to the currently-active root and 272 1.1 dholland * no prefix is needed. 273 1.1 dholland */ 274 1.1 dholland const char * 275 1.1 dholland target_prefix(void) 276 1.1 dholland { 277 1.1 dholland /* 278 1.15 rillig * XXX fetch sysctl variable for current root, and compare 279 1.1 dholland * to the devicename of the install target disk. 280 1.1 dholland */ 281 1.1 dholland return(target_already_root() ? "" : targetroot_mnt); 282 1.1 dholland } 283 1.1 dholland 284 1.1 dholland /* 285 1.1 dholland * concatenate two pathnames. 286 1.1 dholland * XXX returns either input args or result in a static buffer. 287 1.15 rillig * The caller must copy if it wants to use the pathname past the 288 1.15 rillig * next call to a target-prefixing function, or to modify the inputs. 289 1.15 rillig * Used only internally so this is probably safe. 290 1.1 dholland */ 291 1.15 rillig const char * 292 1.1 dholland concat_paths(const char *prefix, const char *suffix) 293 1.1 dholland { 294 1.1 dholland static char real_path[MAXPATHLEN]; 295 1.1 dholland 296 1.1 dholland /* absolute prefix and null suffix? */ 297 1.1 dholland if (prefix[0] == '/' && suffix[0] == 0) 298 1.1 dholland return prefix; 299 1.1 dholland 300 1.1 dholland /* null prefix and absolute suffix? */ 301 1.1 dholland if (prefix[0] == 0 && suffix[0] == '/') 302 1.1 dholland return suffix; 303 1.1 dholland 304 1.1 dholland /* avoid "//" */ 305 1.1 dholland if (suffix[0] == '/' || suffix[0] == 0) 306 1.1 dholland snprintf(real_path, sizeof(real_path), "%s%s", prefix, suffix); 307 1.1 dholland else 308 1.15 rillig snprintf(real_path, sizeof(real_path), "%s/%s", 309 1.1 dholland prefix, suffix); 310 1.1 dholland return (real_path); 311 1.1 dholland } 312 1.1 dholland 313 1.1 dholland /* 314 1.1 dholland * Do target prefix expansion on a pathname. 315 1.1 dholland * XXX uses concat_paths and so returns result in a static buffer. 316 1.15 rillig * The caller must copy if it wants to use the pathname past the 317 1.15 rillig * next call to a target-prefixing function, or to modify the inputs. 318 1.15 rillig * Used only internally so this is probably safe. 319 1.1 dholland * 320 1.1 dholland * Not static so other functions can generate target related file names. 321 1.1 dholland */ 322 1.1 dholland const char * 323 1.1 dholland target_expand(const char *tgtpath) 324 1.1 dholland { 325 1.1 dholland 326 1.1 dholland return concat_paths(target_prefix(), tgtpath); 327 1.1 dholland } 328 1.1 dholland 329 1.1 dholland /* Make a directory, with a prefix like "/targetroot" or possibly just "". */ 330 1.15 rillig static void 331 1.1 dholland make_prefixed_dir(const char *prefix, const char *path) 332 1.1 dholland { 333 1.1 dholland 334 1.1 dholland run_program(0, "/bin/mkdir -p %s", concat_paths(prefix, path)); 335 1.1 dholland } 336 1.1 dholland 337 1.1 dholland /* Make a directory with a pathname relative to the installation target. */ 338 1.1 dholland void 339 1.1 dholland make_target_dir(const char *path) 340 1.1 dholland { 341 1.1 dholland 342 1.1 dholland make_prefixed_dir(target_prefix(), path); 343 1.1 dholland } 344 1.1 dholland 345 1.1 dholland 346 1.1 dholland static int 347 1.1 dholland do_target_chdir(const char *dir, int must_succeed) 348 1.1 dholland { 349 1.1 dholland const char *tgt_dir; 350 1.1 dholland int error; 351 1.1 dholland 352 1.1 dholland error = 0; 353 1.1 dholland tgt_dir = target_expand(dir); 354 1.1 dholland 355 1.2 martin #ifdef DEBUG 356 1.2 martin printf("target_chdir (%s)\n", tgt_dir); 357 1.2 martin //return (0); 358 1.2 martin #endif 359 1.1 dholland /* chdir returns -1 on error and sets errno. */ 360 1.1 dholland if (chdir(tgt_dir) < 0) 361 1.1 dholland error = errno; 362 1.1 dholland if (logfp) { 363 1.1 dholland fprintf(logfp, "cd to %s\n", tgt_dir); 364 1.1 dholland fflush(logfp); 365 1.1 dholland } 366 1.1 dholland if (script) { 367 1.1 dholland scripting_fprintf(NULL, "cd %s\n", tgt_dir); 368 1.1 dholland fflush(script); 369 1.1 dholland } 370 1.1 dholland 371 1.1 dholland if (error && must_succeed) { 372 1.5 martin const char *args[] = { target_prefix(), strerror(error) }; 373 1.5 martin char *err = str_arg_subst(msg_string(MSG_realdir), 374 1.5 martin __arraycount(args), args); 375 1.5 martin fprintf(stderr, "%s\n", err); 376 1.1 dholland if (logfp) 377 1.5 martin fprintf(logfp, "%s\n", err); 378 1.5 martin free(err); 379 1.1 dholland exit(1); 380 1.1 dholland } 381 1.1 dholland errno = error; 382 1.1 dholland return (error); 383 1.1 dholland } 384 1.1 dholland 385 1.1 dholland void 386 1.1 dholland target_chdir_or_die(const char *dir) 387 1.1 dholland { 388 1.1 dholland 389 1.1 dholland (void)do_target_chdir(dir, 1); 390 1.1 dholland } 391 1.1 dholland 392 1.1 dholland #ifdef notdef 393 1.1 dholland int 394 1.1 dholland target_chdir(const char *dir) 395 1.1 dholland { 396 1.1 dholland 397 1.1 dholland return do_target_chdir(dir, 0); 398 1.1 dholland } 399 1.1 dholland #endif 400 1.1 dholland 401 1.1 dholland /* 402 1.1 dholland * Copy a file from the current root into the target system, 403 1.1 dholland * where the destination pathname is relative to the target root. 404 1.1 dholland * Does not check for copy-to-self when target is current root. 405 1.1 dholland */ 406 1.1 dholland int 407 1.1 dholland cp_to_target(const char *srcpath, const char *tgt_path) 408 1.1 dholland { 409 1.1 dholland const char *real_path = target_expand(tgt_path); 410 1.1 dholland 411 1.1 dholland return run_program(0, "/bin/cp %s %s", srcpath, real_path); 412 1.1 dholland } 413 1.1 dholland 414 1.1 dholland /* 415 1.1 dholland * Duplicate a file from the current root to the same pathname 416 1.1 dholland * in the target system. Pathname must be an absolute pathname. 417 1.15 rillig * If we're running in the target, do nothing. 418 1.1 dholland */ 419 1.1 dholland void 420 1.1 dholland dup_file_into_target(const char *filename) 421 1.1 dholland { 422 1.1 dholland 423 1.1 dholland if (!target_already_root()) 424 1.1 dholland cp_to_target(filename, filename); 425 1.1 dholland } 426 1.1 dholland 427 1.1 dholland 428 1.1 dholland /* 429 1.1 dholland * Do a mv where both pathnames are within the target filesystem. 430 1.1 dholland */ 431 1.1 dholland void 432 1.1 dholland mv_within_target_or_die(const char *frompath, const char *topath) 433 1.1 dholland { 434 1.1 dholland char realfrom[STRSIZE]; 435 1.1 dholland char realto[STRSIZE]; 436 1.1 dholland 437 1.1 dholland strlcpy(realfrom, target_expand(frompath), sizeof realfrom); 438 1.1 dholland strlcpy(realto, target_expand(topath), sizeof realto); 439 1.1 dholland 440 1.1 dholland run_program(RUN_FATAL, "mv %s %s", realfrom, realto); 441 1.1 dholland } 442 1.1 dholland 443 1.1 dholland /* Do a cp where both pathnames are within the target filesystem. */ 444 1.1 dholland int 445 1.1 dholland cp_within_target(const char *frompath, const char *topath, int optional) 446 1.1 dholland { 447 1.1 dholland char realfrom[STRSIZE]; 448 1.1 dholland char realto[STRSIZE]; 449 1.1 dholland 450 1.13 martin strlcpy(realfrom, target_expand(frompath), sizeof realfrom); 451 1.13 martin strlcpy(realto, target_expand(topath), sizeof realto); 452 1.1 dholland 453 1.1 dholland if (access(realfrom, R_OK) == -1 && optional) 454 1.1 dholland return 0; 455 1.1 dholland return (run_program(0, "cp -p %s %s", realfrom, realto)); 456 1.1 dholland } 457 1.1 dholland 458 1.1 dholland /* fopen a pathname in the target. */ 459 1.1 dholland FILE * 460 1.1 dholland target_fopen(const char *filename, const char *type) 461 1.1 dholland { 462 1.1 dholland 463 1.1 dholland return fopen(target_expand(filename), type); 464 1.1 dholland } 465 1.1 dholland 466 1.1 dholland /* 467 1.1 dholland * Do a mount onto a mountpoint in the install target. 468 1.1 dholland * Record mountpoint so we can unmount when finished. 469 1.1 dholland * NB: does not prefix mount-from, which probably breaks nullfs mounts. 470 1.1 dholland */ 471 1.1 dholland int 472 1.2 martin target_mount_do(const char *opts, const char *from, const char *on) 473 1.1 dholland { 474 1.1 dholland struct unwind_mount *m; 475 1.1 dholland int error; 476 1.1 dholland int len; 477 1.1 dholland 478 1.1 dholland len = strlen(on); 479 1.1 dholland m = malloc(sizeof *m + len); 480 1.1 dholland if (m == 0) 481 1.1 dholland return (ENOMEM); /* XXX */ 482 1.1 dholland 483 1.1 dholland memcpy(m->um_mountpoint, on, len + 1); 484 1.1 dholland 485 1.1 dholland #ifdef DEBUG_UNWIND 486 1.1 dholland endwin(); 487 1.1 dholland fprintf(stderr, "mounting %s with unwind\n", on); 488 1.1 dholland backtowin(); 489 1.1 dholland #endif 490 1.1 dholland 491 1.2 martin error = run_program(0, "/sbin/mount %s %s %s%s", 492 1.2 martin opts, from, target_prefix(), on); 493 1.1 dholland if (error) { 494 1.1 dholland free(m); 495 1.1 dholland return error; 496 1.1 dholland } 497 1.1 dholland m->um_prev = unwind_mountlist; 498 1.1 dholland unwind_mountlist = m; 499 1.1 dholland return 0; 500 1.1 dholland } 501 1.1 dholland 502 1.10 martin /* 503 1.10 martin * Special case - we have mounted the target / readonly 504 1.10 martin * to peek at etc/fstab, and now want it undone. 505 1.10 martin */ 506 1.10 martin void 507 1.10 martin umount_root(void) 508 1.10 martin { 509 1.10 martin 510 1.10 martin /* verify this is the only mount */ 511 1.10 martin if (unwind_mountlist == NULL) 512 1.10 martin return; 513 1.10 martin if (unwind_mountlist->um_prev != NULL) 514 1.10 martin return; 515 1.10 martin 516 1.10 martin if (run_program(0, "/sbin/umount %s", target_prefix()) != 0) 517 1.10 martin return; 518 1.10 martin 519 1.10 martin free(unwind_mountlist); 520 1.10 martin unwind_mountlist = NULL; 521 1.10 martin } 522 1.10 martin 523 1.10 martin 524 1.2 martin int 525 1.5 martin target_mount(const char *opts, const char *from, const char *on) 526 1.2 martin { 527 1.5 martin return target_mount_do(opts, from, on); 528 1.2 martin } 529 1.2 martin 530 1.18 martin int 531 1.18 martin target_unmount(const char *mount_point) 532 1.18 martin { 533 1.18 martin struct unwind_mount *m, *prev = NULL; 534 1.18 martin int error; 535 1.18 martin 536 1.18 martin for (m = unwind_mountlist; m != NULL; prev = m, m = m->um_prev) 537 1.18 martin if (strcmp(m->um_mountpoint, mount_point) == 0) 538 1.18 martin break; 539 1.18 martin 540 1.18 martin if (m == NULL) 541 1.18 martin return ENOTDIR; 542 1.18 martin 543 1.18 martin error = run_program(0, "/sbin/umount %s%s", 544 1.18 martin target_prefix(), m->um_mountpoint); 545 1.18 martin if (error) 546 1.18 martin return error; 547 1.18 martin 548 1.18 martin if (m == unwind_mountlist) 549 1.18 martin unwind_mountlist = m->um_prev; 550 1.18 martin else 551 1.18 martin prev->um_prev = m->um_prev; 552 1.18 martin free(m); 553 1.18 martin 554 1.18 martin return 0; 555 1.18 martin } 556 1.18 martin 557 1.16 martin static bool 558 1.16 martin delete_wedge(const char *disk, const char *wedge) 559 1.16 martin { 560 1.16 martin struct dkwedge_info dkw; 561 1.16 martin char diskpath[MAXPATHLEN]; 562 1.16 martin int fd, error; 563 1.16 martin 564 1.16 martin fd = opendisk(disk, O_RDWR, diskpath, sizeof(diskpath), 0); 565 1.16 martin if (fd < 0) 566 1.16 martin return false; 567 1.16 martin memset(&dkw, 0, sizeof(dkw)); 568 1.16 martin strlcpy(dkw.dkw_devname, wedge, sizeof(dkw.dkw_devname)); 569 1.16 martin error = ioctl(fd, DIOCDWEDGE, &dkw); 570 1.16 martin close(fd); 571 1.16 martin return error == 0; 572 1.16 martin } 573 1.16 martin 574 1.16 martin void 575 1.16 martin register_post_umount_delwedge(const char *disk, const char *wedge) 576 1.16 martin { 577 1.16 martin struct umount_delwedge *dw; 578 1.16 martin 579 1.17 martin if (unwind_mountlist == NULL) { 580 1.17 martin /* we have nothing mounted, can delete it right now */ 581 1.17 martin delete_wedge(disk, wedge); 582 1.17 martin return; 583 1.17 martin } 584 1.17 martin 585 1.16 martin dw = calloc(1, sizeof(*dw)); 586 1.16 martin dw->next = post_umount_dwlist; 587 1.16 martin strlcpy(dw->disk, disk, sizeof(dw->disk)); 588 1.16 martin strlcpy(dw->wedge, wedge, sizeof(dw->wedge)); 589 1.16 martin post_umount_dwlist = dw; 590 1.16 martin } 591 1.16 martin 592 1.1 dholland /* 593 1.1 dholland * unwind the mount stack, unmounting mounted filesystems. 594 1.15 rillig * For now, ignore any errors in unmount. 595 1.1 dholland * (Why would we be unable to unmount? The user has suspended 596 1.1 dholland * us and forked shell sitting somewhere in the target root?) 597 1.1 dholland */ 598 1.1 dholland void 599 1.1 dholland unwind_mounts(void) 600 1.1 dholland { 601 1.1 dholland struct unwind_mount *m; 602 1.16 martin struct umount_delwedge *dw; 603 1.1 dholland static volatile int unwind_in_progress = 0; 604 1.1 dholland 605 1.1 dholland /* signal safety */ 606 1.1 dholland if (unwind_in_progress) 607 1.1 dholland return; 608 1.1 dholland unwind_in_progress = 1; 609 1.1 dholland 610 1.1 dholland while ((m = unwind_mountlist) != NULL) { 611 1.1 dholland unwind_mountlist = m->um_prev; 612 1.1 dholland #ifdef DEBUG_UNWIND 613 1.1 dholland endwin(); 614 1.1 dholland fprintf(stderr, "unmounting %s\n", m->um_mountpoint); 615 1.1 dholland backtowin(); 616 1.1 dholland #endif 617 1.1 dholland run_program(0, "/sbin/umount %s%s", 618 1.1 dholland target_prefix(), m->um_mountpoint); 619 1.1 dholland free(m); 620 1.1 dholland } 621 1.16 martin while ((dw = post_umount_dwlist) != NULL) { 622 1.16 martin post_umount_dwlist = dw->next; 623 1.16 martin delete_wedge(dw->disk, dw->wedge); 624 1.16 martin free(dw); 625 1.16 martin } 626 1.1 dholland unwind_in_progress = 0; 627 1.1 dholland } 628 1.1 dholland 629 1.1 dholland int 630 1.1 dholland target_collect_file(int kind, char **buffer, const char *name) 631 1.1 dholland { 632 1.1 dholland const char *realname = target_expand(name); 633 1.1 dholland 634 1.1 dholland #ifdef DEBUG 635 1.1 dholland printf("collect real name %s\n", realname); 636 1.1 dholland #endif 637 1.1 dholland return collect(kind, buffer, "%s", realname); 638 1.1 dholland } 639 1.1 dholland 640 1.1 dholland /* 641 1.1 dholland * Verify a pathname already exists in the target root filesystem, 642 1.1 dholland * by running test "testflag" on the expanded target pathname. 643 1.1 dholland */ 644 1.1 dholland int 645 1.1 dholland target_test(unsigned int mode, const char *path) 646 1.1 dholland { 647 1.1 dholland const char *real_path = target_expand(path); 648 1.1 dholland register int result; 649 1.1 dholland 650 1.1 dholland result = !file_mode_match(real_path, mode); 651 1.1 dholland scripting_fprintf(NULL, "if [ $? != 0 ]; then echo \"%s does not exist!\"; fi\n", real_path); 652 1.1 dholland 653 1.1 dholland #if defined(DEBUG) 654 1.1 dholland printf("target_test(%o, %s) returning %d\n", mode, real_path, result); 655 1.1 dholland #endif 656 1.1 dholland return (result); 657 1.1 dholland } 658 1.1 dholland 659 1.1 dholland /* 660 1.15 rillig * Verify a directory already exists in the target root 661 1.1 dholland * filesystem. Do not create the directory if it doesn't exist. 662 1.1 dholland * Assumes that sysinst has already mounted the target root. 663 1.1 dholland */ 664 1.1 dholland int 665 1.1 dholland target_test_dir(const char *path) 666 1.1 dholland { 667 1.1 dholland 668 1.1 dholland return target_test(S_IFDIR, path); 669 1.1 dholland } 670 1.1 dholland 671 1.1 dholland /* 672 1.15 rillig * Verify an ordinary file already exists in the target root 673 1.1 dholland * filesystem. Do not create the directory if it doesn't exist. 674 1.1 dholland * Assumes that sysinst has already mounted the target root. 675 1.1 dholland */ 676 1.1 dholland int 677 1.1 dholland target_test_file(const char *path) 678 1.1 dholland { 679 1.1 dholland 680 1.1 dholland return target_test(S_IFREG, path); 681 1.1 dholland } 682 1.1 dholland 683 1.1 dholland int 684 1.1 dholland target_test_symlink(const char *path) 685 1.1 dholland { 686 1.1 dholland 687 1.1 dholland return target_test(S_IFLNK, path); 688 1.1 dholland } 689 1.1 dholland 690 1.1 dholland int 691 1.1 dholland target_file_exists_p(const char *path) 692 1.1 dholland { 693 1.1 dholland 694 1.1 dholland return (target_test_file(path) == 0); 695 1.1 dholland } 696 1.1 dholland 697 1.1 dholland int 698 1.1 dholland target_dir_exists_p(const char *path) 699 1.1 dholland { 700 1.1 dholland 701 1.1 dholland return (target_test_dir(path) == 0); 702 1.1 dholland } 703 1.1 dholland 704 1.1 dholland int 705 1.1 dholland target_symlink_exists_p(const char *path) 706 1.1 dholland { 707 1.1 dholland 708 1.1 dholland return (target_test_symlink(path) == 0); 709 1.1 dholland } 710 1.1 dholland 711 1.1 dholland int 712 1.1 dholland target_mounted(void) 713 1.1 dholland { 714 1.1 dholland return (unwind_mountlist != NULL); 715 1.1 dholland } 716