Annotation of src/distrib/utils/sysinst/target.c, Revision 1.37
1.37 ! dsl 1: /* $NetBSD: target.c,v 1.36 2003/06/25 15:45:22 dsl Exp $ */
1.1 jonathan 2:
3: /*
1.2 jonathan 4: * Copyright 1997 Jonathan Stone
1.1 jonathan 5: * 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. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
1.22 cgd 17: * This product includes software developed for the NetBSD Project by
1.2 jonathan 18: * Jonathan Stone.
19: * 4. The name of Jonathan Stone may not be used to endorse
1.1 jonathan 20: * or promote products derived from this software without specific prior
21: * written permission.
22: *
1.2 jonathan 23: * THIS SOFTWARE IS PROVIDED BY JONATHAN STONE ``AS IS''
1.1 jonathan 24: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
27: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33: * THE POSSIBILITY OF SUCH DAMAGE.
34: *
35: */
36:
1.26 fvdl 37: /* Copyright below applies to the realpath() code */
38:
39: /*
40: * Copyright (c) 1989, 1991, 1993, 1995
41: * The Regents of the University of California. All rights reserved.
42: *
43: * This code is derived from software contributed to Berkeley by
44: * Jan-Simon Pendry.
45: *
46: * Redistribution and use in source and binary forms, with or without
47: * modification, are permitted provided that the following conditions
48: * are met:
49: * 1. Redistributions of source code must retain the above copyright
50: * notice, this list of conditions and the following disclaimer.
51: * 2. Redistributions in binary form must reproduce the above copyright
52: * notice, this list of conditions and the following disclaimer in the
53: * documentation and/or other materials provided with the distribution.
54: * 3. All advertising materials mentioning features or use of this software
55: * must display the following acknowledgement:
56: * This product includes software developed by the University of
57: * California, Berkeley and its contributors.
58: * 4. Neither the name of the University nor the names of its contributors
59: * may be used to endorse or promote products derived from this software
60: * without specific prior written permission.
61: *
62: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72: * SUCH DAMAGE.
73: */
74:
75:
1.5 jonathan 76: #include <sys/cdefs.h>
77: #if defined(LIBC_SCCS) && !defined(lint)
1.37 ! dsl 78: __RCSID("$NetBSD: target.c,v 1.36 2003/06/25 15:45:22 dsl Exp $");
1.5 jonathan 79: #endif
80:
81: /*
82: * target.c -- path-prefixing routines to access the target installation
1.29 wiz 83: * filesystems. Makes the install tools more independent of whether
1.37 ! dsl 84: * we're installing into a separate filesystem hierarchy mounted under
! 85: * /targetroot, or into the currently active root mounted on /.
1.5 jonathan 86: */
87:
88: #include <sys/param.h> /* XXX vm_param.h always defines TRUE*/
1.8 jonathan 89: #include <sys/types.h>
1.5 jonathan 90: #include <sys/sysctl.h>
1.8 jonathan 91: #include <sys/stat.h> /* stat() */
92: #include <sys/mount.h> /* statfs() */
1.1 jonathan 93:
1.28 pk 94: #include <fcntl.h>
1.1 jonathan 95: #include <stdio.h>
96: #include <stdarg.h>
97: #include <unistd.h>
1.5 jonathan 98: #include <curses.h> /* defines TRUE, but checks */
1.7 jonathan 99: #include <errno.h>
1.5 jonathan 100:
101:
1.1 jonathan 102: #include "defs.h"
103: #include "md.h"
104: #include "msg_defs.h"
105: #include "menu_defs.h"
106:
107: /*
108: * local prototypes
109: */
1.30 mrg 110: static const char* get_rootdev (void);
111: static const char* mounted_rootpart (void);
112: int target_on_current_disk (void);
113: int must_mount_root (void);
1.8 jonathan 114:
1.30 mrg 115: static void make_prefixed_dir (const char *prefix, const char *path);
116: static int do_target_chdir (const char *dir, int flag);
1.25 fvdl 117: int target_test(unsigned int mode, const char *path);
1.30 mrg 118: int target_test_dir (const char *path); /* deprecated */
119: int target_test_file (const char *path); /* deprecated */
120: int target_test_symlink (const char *path); /* deprecated */
1.1 jonathan 121:
1.8 jonathan 122: void backtowin(void);
123:
1.30 mrg 124: void unwind_mounts (void);
125: int mount_with_unwind (const char *fstype, const char *from, const char *on);
1.13 jonathan 126:
127: /* Record a mount for later unwinding of target mounts. */
128: struct unwind_mount {
129: struct unwind_mount *um_prev;
130: char um_mountpoint[STRSIZE];
131: };
132:
133: /* Unwind-mount stack */
1.16 mrg 134: struct unwind_mount *unwind_mountlist = NULL;
1.13 jonathan 135:
136: /*
137: * Debugging options
138: */
139: /*#define DEBUG_ROOT*/ /* turn on what-is-root? debugging. */
140: /*#define DEBUG_UNWIND*/ /* turn on unwind-target-mount debugging. */
141:
1.8 jonathan 142: /*
143: * debugging helper. curses...
144: */
1.34 christos 145: #if defined(DEBUG) || defined(DEBUG_ROOT)
1.16 mrg 146: void
1.35 dsl 147: backtowin(void)
1.8 jonathan 148: {
149:
150: fflush(stdout); /* curses does not leave stdout linebuffered. */
151: getchar(); /* wait for user to press return */
152: wrefresh(stdscr);
153: }
1.34 christos 154: #endif
1.8 jonathan 155:
156: /*
157: * Get name of current root device from kernel via sysctl.
158: * On NetBSD-1.3_ALPHA, this just returns the name of a
159: * device (e.g., "sd0"), not a specific partition -- like "sd0a",
160: * or "sd0b" for root-in-swap.
1.16 mrg 161: */
162: static const char *
1.35 dsl 163: get_rootdev(void)
1.5 jonathan 164: {
165: int mib[2];
1.8 jonathan 166: static char rootdev[STRSIZE];
1.5 jonathan 167: size_t varlen;
168:
169: mib[0] = CTL_KERN;
170: mib[1] = KERN_ROOT_DEVICE;
1.8 jonathan 171: varlen = sizeof(rootdev);
172: if (sysctl(mib, 2, rootdev, &varlen, NULL, 0) < 0)
1.5 jonathan 173: return (NULL);
174:
175: #ifdef DEBUG
1.8 jonathan 176: printf("get_rootdev(): sysctl returns %s\n", rootdev);
1.5 jonathan 177: #endif
1.8 jonathan 178: return (rootdev);
1.5 jonathan 179: }
180:
1.8 jonathan 181:
1.5 jonathan 182: /*
1.8 jonathan 183: * Check if current root and target are on the same
184: * device (e.g., both on "sd0") or on different devices
185: * e.g., target is "sd0" and root is "le0" (nfs).
186: */
187: int
1.35 dsl 188: target_on_current_disk(void)
1.8 jonathan 189: {
190: int same;
1.16 mrg 191:
1.24 hubertf 192: if (strcmp(diskdev, "") == 0) /* nothing selected yet */
193: same = 1; /* bad assumption: this is a live system */
194: else
195: same = (strcmp(diskdev, get_rootdev()) == 0);
1.8 jonathan 196: return (same);
197: }
198:
199: /*
200: * must_mount_root -- check to see if the current root
201: * partition and the target root partition are on the same
202: * device. If they are, we need to have the root mounted read/write
203: * in order to find out whether they're the same partition.
204: * (this is arguably a bug in the kernel API.)
205: *
206: * check to see if they're
207: */
1.16 mrg 208: int
1.35 dsl 209: must_mount_root(void)
1.8 jonathan 210: {
211: int result;
212:
213: #if defined(DEBUG) || defined(DEBUG_ROOT)
1.16 mrg 214: endwin();
215: printf("must_mount_root\n");
216: backtowin();
1.8 jonathan 217: #endif
218:
219: /* if they're on different devices, we're OK. */
220: if (target_on_current_disk() == 0) {
221: #if defined(DEBUG) || defined(DEBUG_ROOT)
222: endwin();
223: printf("must_mount_root: %s and %s, no?\n",
1.16 mrg 224: diskdev, get_rootdev());
1.8 jonathan 225: fflush(stdout);
226: backtowin();
227: #endif
228: return (0);
229: }
230:
231: /* If they're on the same device, and root not mounted, yell. */
232: result = (strcmp(mounted_rootpart(), "root_device") == 0);
233:
234: #if defined(DEBUG) || defined(DEBUG_ROOT)
235: endwin();
236: printf("must_mount_root %s and root_device gives %d\n",
1.16 mrg 237: mounted_rootpart(), result);
1.8 jonathan 238: fflush(stdout);
239: backtowin();
240: #endif
241:
242: return (result);
243: }
244:
245: /*
1.29 wiz 246: * Is the root partition we're running from the same as the root
247: * which the user has selected to install/upgrade?
1.8 jonathan 248: * Uses global variable "diskdev" to find the selected device for
249: * install/upgrade.
250: * FIXME -- disklabel-editing code assumes that partition 'a' is always root.
1.5 jonathan 251: */
1.16 mrg 252: int
1.35 dsl 253: target_already_root(void)
1.5 jonathan 254: {
255: register int result;
1.8 jonathan 256: char diskdevroot[STRSIZE];
257:
258: /* if they're on different devices, we're OK. */
259: if (target_on_current_disk() == 0)
260: return (0);
261:
262: /*
263: * otherwise, install() or upgrade() should already did
264: * have forced the user to explicitly mount the root,
265: * so we can find out via statfs(). Abort if not.
266: */
267:
1.24 hubertf 268: if (strcmp(diskdev, "") == 0) {
269: /* no root partition was ever selected. Assume that
270: * the currently mounted one should be used */
271: result = 1;
272: } else {
273: /* append 'a' to the partitionless target disk device name. */
274: snprintf(diskdevroot, STRSIZE, "%s%c", diskdev, 'a');
275: result = is_active_rootpart(diskdevroot);
276: }
1.16 mrg 277: return (result);
1.5 jonathan 278: }
279:
280:
1.8 jonathan 281:
282: /*
283: * ask the kernel what the current root is.
1.29 wiz 284: * If it's "root_device", we should just give up now.
1.8 jonathan 285: * (Why won't the kernel tell us? If we booted with "n",
286: * or an explicit bootpath, the operator told *it* ....)
287: *
1.29 wiz 288: * Don't cache the answer in case the user suspends and remounts.
1.8 jonathan 289: */
1.16 mrg 290: static const char *
1.35 dsl 291: mounted_rootpart(void)
1.8 jonathan 292: {
293: struct statfs statfsbuf;
294: int result;
295:
296: static char statrootstr[STRSIZE];
1.17 perry 297: memset(&statfsbuf, 0, sizeof(statfsbuf));
1.8 jonathan 298: result = statfs("/", &statfsbuf);
299: if (result < 0) {
300: fprintf(stderr, "Help! statfs() can't find root: %s\n",
1.16 mrg 301: strerror(errno));
1.8 jonathan 302: fflush(stderr);
1.18 garbled 303: if (logging)
1.33 fvdl 304: fprintf(logfp, "Help! statfs() can't find root: %s\n",
1.18 garbled 305: strerror(errno));
1.8 jonathan 306: exit(errno);
307: return(0);
308: }
309: #if defined(DEBUG)
310: endwin();
311: printf("mounted_rootpart: got %s on %s\n",
1.16 mrg 312: statfsbuf.f_mntonname, statfsbuf.f_mntfromname);
1.8 jonathan 313: fflush(stdout);
314: backtowin();
315: #endif
316:
317: /*
318: * Check for unmounted root. We can't tell which partition
319: */
320: strncpy(statrootstr, statfsbuf.f_mntfromname, STRSIZE);
1.16 mrg 321: return (statrootstr);
1.8 jonathan 322: }
323:
324: /*
325: * Is this device partition (e.g., "sd0a") mounted as root?
326: * Note difference from target_on_current_disk()!
327: */
328: int
1.35 dsl 329: is_active_rootpart(const char *devpart)
1.5 jonathan 330: {
1.8 jonathan 331: const char *root = 0;
1.5 jonathan 332: int result;
1.12 jonathan 333: static char devdirdevpart[STRSIZE];
1.5 jonathan 334:
1.8 jonathan 335: /* check to see if the devices match? */
336:
337: /* this changes on mounts, so don't cache it. */
338: root = mounted_rootpart();
339:
1.12 jonathan 340: /* prepend /dev. */
341: /* XXX post-1.3, use strstr to strip "/dev" from input. */
342: snprintf(devdirdevpart, STRSIZE, "/dev/%s", devpart);
343:
344: result = (strcmp(devdirdevpart, root) == 0);
345:
1.8 jonathan 346: #if defined(DEBUG) || defined(DEBUG_ROOT)
347: endwin();
1.12 jonathan 348: printf("is_active_rootpart: activeroot = %s, query=%s, mung=%s, answer=%d\n",
1.16 mrg 349: root, devpart, devdirdevpart, result);
1.8 jonathan 350: fflush(stdout);
351: backtowin();
1.5 jonathan 352: #endif
1.8 jonathan 353:
1.16 mrg 354: return (result);
1.5 jonathan 355: }
1.8 jonathan 356:
1.1 jonathan 357: /*
358: * Pathname prefixing glue to support installation either
359: * from in-ramdisk miniroots or on-disk diskimages.
360: * If our root is on the target disk, the install target is mounted
1.37 ! dsl 361: * on /targetroot and we need to prefix installed pathnames with /targetroot.
1.1 jonathan 362: * otherwise we are installing to the currently-active root and
363: * no prefix is needed.
364: */
1.16 mrg 365: const char *
1.35 dsl 366: target_prefix(void)
1.1 jonathan 367: {
368: /*
369: * XXX fetch sysctl variable for current root, and compare
1.16 mrg 370: * to the devicename of the install target disk.
1.1 jonathan 371: */
1.37 ! dsl 372: return(target_already_root() ? "" : targetroot_mnt);
1.1 jonathan 373: }
374:
1.4 jonathan 375: /*
376: * concatenate two pathnames.
377: * XXX returns either input args or result in a static buffer.
378: * The caller must copy if it wants to use the pathname past the
379: * next call to a target-prefixing function, or to modify the inputs..
380: * Used only internally so this is probably safe.
381: */
1.35 dsl 382: const char *
383: concat_paths(const char *prefix, const char *suffix)
1.4 jonathan 384: {
1.34 christos 385: static char real_path[MAXPATHLEN];
1.4 jonathan 386:
387: /* absolute prefix and null suffix? */
388: if (prefix[0] == '/' && suffix[0] == 0)
389: return prefix;
390:
391: /* null prefix and absolute suffix? */
392: if (prefix[0] == 0 && suffix[0] == '/')
393: return suffix;
394:
395: /* avoid "//" */
396: if (suffix[0] == '/' || suffix[0] == 0)
1.34 christos 397: snprintf(real_path, sizeof(real_path), "%s%s", prefix, suffix);
1.4 jonathan 398: else
1.34 christos 399: snprintf(real_path, sizeof(real_path), "%s/%s",
400: prefix, suffix);
401: return (real_path);
1.4 jonathan 402: }
403:
404: /*
405: * Do target prefix expansion on a pathname.
406: * XXX uses concat_paths and so returns result in a static buffer.
407: * The caller must copy if it wants to use the pathname past the
408: * next call to a target-prefixing function, or to modify the inputs..
409: * Used only internally so this is probably safe.
1.6 phil 410: *
411: * Not static so other functions can generate target related file names.
1.4 jonathan 412: */
1.16 mrg 413: const char *
1.35 dsl 414: target_expand(const char *tgtpath)
1.4 jonathan 415: {
1.16 mrg 416:
1.4 jonathan 417: return concat_paths(target_prefix(), tgtpath);
418: }
419:
1.37 ! dsl 420: /* Make a directory, with a prefix like "/targetroot" or possibly just "". */
1.1 jonathan 421: static void
1.35 dsl 422: make_prefixed_dir(const char *prefix, const char *path)
1.1 jonathan 423: {
1.16 mrg 424:
1.27 fvdl 425: run_prog(0, NULL, "/bin/mkdir -p %s", concat_paths(prefix, path));
1.1 jonathan 426: }
427:
1.29 wiz 428: /* Make a directory with a pathname relative to the installation target. */
1.1 jonathan 429: void
1.35 dsl 430: make_target_dir(const char *path)
1.1 jonathan 431: {
1.16 mrg 432:
1.1 jonathan 433: make_prefixed_dir(target_prefix(), path);
434: }
435:
1.34 christos 436: #ifdef notdef
1.16 mrg 437: /* Make a directory with a pathname in the currently-mounted root. */
1.1 jonathan 438: void
1.35 dsl 439: make_ramdisk_dir(const char *path)
1.1 jonathan 440: {
1.16 mrg 441:
1.1 jonathan 442: make_prefixed_dir(path, "");
443: }
444:
1.19 garbled 445: /* unused, will not work with new run.c */
1.1 jonathan 446: /*
447: *
448: * Append |string| to the filename |path|, where |path| is
449: * relative to the root of the install target.
450: * for example,
451: * echo_to_target_file( "Newbie.NetBSD.ORG", "/etc/myname");
452: * would set the default hostname at the next reboot of the installed-on disk.
453: */
454: void
1.35 dsl 455: append_to_target_file(const char *path, const char *string)
1.1 jonathan 456: {
1.16 mrg 457:
1.27 fvdl 458: run_prog(RUN_FATAL, NULL, "echo %s >> %s", string, target_expand(path));
1.1 jonathan 459: }
460:
461: /*
462: * As append_to_target_file, but with ftrunc semantics.
463: */
464: void
1.35 dsl 465: echo_to_target_file(const char *path, const char *string)
1.1 jonathan 466: {
467: trunc_target_file(path);
468: append_to_target_file(path, string);
469: }
470:
471: void
472: sprintf_to_target_file(const char *path, const char *format, ...)
473: {
474: char lines[STRSIZE];
475: va_list ap;
476:
477: trunc_target_file(path);
478:
1.10 phil 479: va_start(ap, format);
1.1 jonathan 480: vsnprintf(lines, STRSIZE, format, ap);
481: va_end(ap);
482:
483: append_to_target_file(path, lines);
484: }
485:
486:
487: void
1.35 dsl 488: trunc_target_file(const char *path)
1.1 jonathan 489: {
1.16 mrg 490:
1.27 fvdl 491: run_prog(RUN_FATAL, NULL, "cat < /dev/null > %s", target_expand(path));
1.1 jonathan 492: }
1.19 garbled 493: #endif /* if 0 */
1.1 jonathan 494:
1.16 mrg 495: static int
1.35 dsl 496: do_target_chdir(const char *dir, int must_succeed)
1.1 jonathan 497: {
1.4 jonathan 498: const char *tgt_dir;
1.9 phil 499: int error;
1.1 jonathan 500:
1.9 phil 501: error = 0;
1.4 jonathan 502: tgt_dir = target_expand(dir);
1.1 jonathan 503:
504: #ifndef DEBUG
1.7 jonathan 505: /* chdir returns -1 on error and sets errno. */
1.16 mrg 506: if (chdir(tgt_dir) < 0)
1.7 jonathan 507: error = errno;
1.18 garbled 508: if (logging) {
1.33 fvdl 509: fprintf(logfp, "cd to %s\n", tgt_dir);
510: fflush(logfp);
1.18 garbled 511: }
512: if (scripting) {
1.31 mrg 513: scripting_fprintf(NULL, "cd %s\n", tgt_dir);
1.18 garbled 514: fflush(script);
515: }
1.16 mrg 516:
1.1 jonathan 517: if (error && must_succeed) {
1.7 jonathan 518: fprintf(stderr, msg_string(MSG_realdir),
519: target_prefix(), strerror(error));
1.18 garbled 520: if (logging)
1.33 fvdl 521: fprintf(logfp, msg_string(MSG_realdir),
1.18 garbled 522: target_prefix(), strerror(error));
1.1 jonathan 523: exit(1);
524: }
525: return (error);
526: #else
527: printf("target_chdir (%s)\n", tgt_dir);
528: return (0);
529: #endif
530: }
531:
1.16 mrg 532: void
1.35 dsl 533: target_chdir_or_die(const char *dir)
1.1 jonathan 534: {
1.16 mrg 535:
1.35 dsl 536: (void)do_target_chdir(dir, 1);
1.1 jonathan 537: }
538:
1.34 christos 539: #ifdef notdef
1.16 mrg 540: int
1.35 dsl 541: target_chdir(const char *dir)
1.1 jonathan 542: {
1.16 mrg 543:
1.35 dsl 544: return do_target_chdir(dir, 0);
1.3 jonathan 545: }
1.34 christos 546: #endif
1.3 jonathan 547:
548: /*
1.15 jonathan 549: * Copy a file from the current root into the target system,
550: * where the destination pathname is relative to the target root.
551: * Does not check for copy-to-self when target is current root.
552: */
1.20 bouyer 553: int
1.35 dsl 554: cp_to_target(const char *srcpath, const char *tgt_path)
1.15 jonathan 555: {
1.34 christos 556: const char *real_path = target_expand(tgt_path);
1.16 mrg 557:
1.34 christos 558: return run_prog(0, NULL, "/bin/cp %s %s", srcpath, real_path);
1.15 jonathan 559: }
560:
561: /*
1.3 jonathan 562: * Duplicate a file from the current root to the same pathname
1.15 jonathan 563: * in the target system. Pathname must be an absolute pathname.
1.3 jonathan 564: * If we're running in the target, do nothing.
565: */
1.16 mrg 566: void
1.35 dsl 567: dup_file_into_target(const char *filename)
1.3 jonathan 568: {
1.16 mrg 569:
570: if (!target_already_root())
1.15 jonathan 571: cp_to_target(filename, filename);
1.3 jonathan 572: }
573:
574:
1.16 mrg 575: /*
576: * Do a mv where both pathnames are within the target filesystem.
577: */
1.23 hubertf 578: void
1.35 dsl 579: mv_within_target_or_die(const char *frompath, const char *topath)
1.4 jonathan 580: {
581: char realfrom[STRSIZE];
582: char realto[STRSIZE];
583:
584: strncpy(realfrom, target_expand(frompath), STRSIZE);
585: strncpy(realto, target_expand(topath), STRSIZE);
586:
1.27 fvdl 587: run_prog(RUN_FATAL, NULL, "mv %s %s", realfrom, realto);
1.4 jonathan 588: }
589:
1.7 jonathan 590: /* Do a cp where both pathnames are within the target filesystem. */
1.36 dsl 591: int
592: cp_within_target(const char *frompath, const char *topath)
1.7 jonathan 593: {
594: char realfrom[STRSIZE];
595: char realto[STRSIZE];
596:
597: strncpy(realfrom, target_expand(frompath), STRSIZE);
598: strncpy(realto, target_expand(topath), STRSIZE);
599:
1.27 fvdl 600: return (run_prog(0, NULL, "cp -p %s %s", realfrom, realto));
1.7 jonathan 601: }
602:
1.4 jonathan 603: /* fopen a pathname in the target. */
1.16 mrg 604: FILE *
1.35 dsl 605: target_fopen(const char *filename, const char *type)
1.4 jonathan 606: {
1.16 mrg 607:
1.4 jonathan 608: return fopen(target_expand(filename), type);
609: }
610:
611: /*
1.13 jonathan 612: * Do a mount and record the mountpoint in a list of mounts to
613: * unwind after completing or aborting a mount.
614: */
615: int
1.35 dsl 616: mount_with_unwind(const char *fstype, const char *from, const char *on)
1.13 jonathan 617: {
618: int error;
619: struct unwind_mount * m;
620:
621: m = malloc(sizeof(*m));
622: if (m == 0)
623: return (ENOMEM); /* XXX */
624:
625: strncpy(m->um_mountpoint, on, STRSIZE);
626: m->um_prev = unwind_mountlist;
627: unwind_mountlist = m;
628:
629: #ifdef DEBUG_UNWIND
630: endwin();
631: fprintf(stderr, "mounting %s with unwind\n", on);
632: backtowin();
633: #endif
634:
1.27 fvdl 635: error = run_prog(0, NULL, "/sbin/mount %s %s %s", fstype, from, on);
1.13 jonathan 636: return (error);
637: }
638:
639: /*
1.29 wiz 640: * unwind the mount stack, unmounting mounted filesystems.
1.13 jonathan 641: * For now, ignore any errors in unmount.
642: * (Why would we be unable to unmount? The user has suspended
643: * us and forked shell sitting somewhere in the target root?)
644: */
645: void
1.35 dsl 646: unwind_mounts(void)
1.13 jonathan 647: {
1.34 christos 648: struct unwind_mount *m;
1.14 jonathan 649: volatile static int unwind_in_progress = 0;
650:
651: /* signal safety */
652: if (unwind_in_progress)
653: return;
654: unwind_in_progress = 1;
1.13 jonathan 655:
656: for (m = unwind_mountlist; m; ) {
657: struct unwind_mount *prev;
658: #ifdef DEBUG_UNWIND
659: endwin();
660: fprintf(stderr, "unmounting %s\n", m->um_mountpoint);
661: backtowin();
662: #endif
1.27 fvdl 663: run_prog(0, NULL, "/sbin/umount %s", m->um_mountpoint);
1.13 jonathan 664: prev = m->um_prev;
665: free(m);
666: m = prev;
667: }
668: unwind_mountlist = NULL;
1.14 jonathan 669: unwind_in_progress = 0;
1.13 jonathan 670: }
671:
672: /*
1.29 wiz 673: * Do a mount onto a mountpoint in the install target.
1.4 jonathan 674: * NB: does not prefix mount-from, which probably breaks nullfs mounts.
675: */
1.16 mrg 676: int
1.35 dsl 677: target_mount(const char *fstype, const char *from, const char *on)
1.4 jonathan 678: {
679: int error;
680: const char *realmount = target_expand(on);
681:
1.29 wiz 682: /* mount and record for unmounting when done. */
1.13 jonathan 683: error = mount_with_unwind(fstype, from, realmount);
684:
1.4 jonathan 685: return (error);
686: }
687:
1.16 mrg 688: int
1.35 dsl 689: target_collect_file(int kind, char **buffer, char *name)
1.3 jonathan 690: {
1.35 dsl 691: const char *realname = target_expand(name);
1.5 jonathan 692:
693: #ifdef DEBUG
694: printf("collect real name %s\n", realname);
695: #endif
696: return collect(kind, buffer, realname);
1.7 jonathan 697: }
698:
699: /*
700: * Verify a pathname already exists in the target root filesystem,
701: * by running test "testflag" on the expanded target pathname.
702: */
1.16 mrg 703: int
1.35 dsl 704: target_test(unsigned int mode, const char *path)
1.7 jonathan 705: {
1.34 christos 706: const char *real_path = target_expand(path);
1.7 jonathan 707: register int result;
708:
1.34 christos 709: result = !file_mode_match(real_path, mode);
710: scripting_fprintf(NULL, "if [ $? != 0 ]; then echo \"%s does not exist!\"; fi\n", real_path);
1.7 jonathan 711:
712: #if defined(DEBUG)
1.34 christos 713: printf("target_test(%s %s) returning %d\n", test, real_path, result);
1.7 jonathan 714: #endif
1.16 mrg 715: return (result);
1.7 jonathan 716: }
717:
718: /*
719: * Verify a directory already exists in the target root
720: * filesystem. Do not create the directory if it doesn't exist.
721: * Assumes that sysinst has already mounted the target root.
722: */
1.16 mrg 723: int
1.35 dsl 724: target_test_dir(const char *path)
1.7 jonathan 725: {
1.16 mrg 726:
1.25 fvdl 727: return target_test(S_IFDIR, path);
1.7 jonathan 728: }
729:
730: /*
731: * Verify an ordinary file already exists in the target root
732: * filesystem. Do not create the directory if it doesn't exist.
733: * Assumes that sysinst has already mounted the target root.
734: */
1.16 mrg 735: int
1.35 dsl 736: target_test_file(const char *path)
1.7 jonathan 737: {
1.16 mrg 738:
1.25 fvdl 739: return target_test(S_IFREG, path);
1.1 jonathan 740: }
1.14 jonathan 741:
1.23 hubertf 742: int
1.35 dsl 743: target_test_symlink(const char *path)
1.23 hubertf 744: {
745:
1.25 fvdl 746: return target_test(S_IFLNK, path);
1.23 hubertf 747: }
748:
1.35 dsl 749: int
750: target_file_exists_p(const char *path)
1.14 jonathan 751: {
1.16 mrg 752:
1.14 jonathan 753: return (target_test_file(path) == 0);
754: }
755:
1.35 dsl 756: int
757: target_dir_exists_p(const char *path)
1.14 jonathan 758: {
1.16 mrg 759:
1.14 jonathan 760: return (target_test_dir(path) == 0);
1.23 hubertf 761: }
762:
1.35 dsl 763: int
764: target_symlink_exists_p(const char *path)
1.23 hubertf 765: {
766:
767: return (target_test_symlink(path) == 0);
1.26 fvdl 768: }
769:
770: /*
1.37 ! dsl 771: * XXXX had to include this to deal with symlinks in some places.
! 772: * When the target * disk is mounted under /targetroot, absolute symlinks
! 773: * on it don't work right.
! 774: * This function will resolve them using the mountpoint as prefix.
! 775: * Copied verbatim from libc, with added prefix handling.
1.26 fvdl 776: *
777: * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
778: *
779: * Find the real name of path, by removing all ".", ".." and symlink
780: * components. Returns (resolved) on success, or (NULL) on failure,
781: * in which case the path which caused trouble is left in (resolved).
782: */
783: char *
784: target_realpath(const char *path, char *resolved)
785: {
786: struct stat sb;
787: int fd, n, rootd, serrno, nlnk = 0;
788: char *p, *q, wbuf[MAXPATHLEN];
789:
790: /* Save the starting point. */
791: if ((fd = open(".", O_RDONLY)) < 0) {
792: (void)strcpy(resolved, ".");
793: return (NULL);
794: }
795:
796: /*
797: * Find the dirname and basename from the path to be resolved.
798: * Change directory to the dirname component.
799: * lstat the basename part.
800: * if it is a symlink, read in the value and loop.
801: * if it is a directory, then change to that directory.
802: * get the current directory name and append the basename.
803: */
804: if (target_prefix() != NULL && strcmp(target_prefix(), "") != 0)
805: snprintf(resolved, MAXPATHLEN, "%s/%s", target_prefix(), path);
806: else {
807: (void)strncpy(resolved, path, MAXPATHLEN - 1);
808: resolved[MAXPATHLEN - 1] = '\0';
809: }
810: loop:
811: q = strrchr(resolved, '/');
812: if (q != NULL) {
813: p = q + 1;
814: if (q == resolved)
815: q = "/";
816: else {
817: do {
818: --q;
819: } while (q > resolved && *q == '/');
820: q[1] = '\0';
821: q = resolved;
822: }
823: if (chdir(q) < 0)
824: goto err1;
825: } else
826: p = resolved;
827:
828: /* Deal with the last component. */
829: if (lstat(p, &sb) == 0) {
830: if (S_ISLNK(sb.st_mode)) {
831: if (nlnk++ >= MAXSYMLINKS) {
832: errno = ELOOP;
833: goto err1;
834: }
1.32 provos 835: n = readlink(p, wbuf, MAXPATHLEN - 1);
1.26 fvdl 836: if (n < 0)
837: goto err1;
838: wbuf[n] = '\0';
839: if (wbuf[0] == '/')
840: snprintf(resolved, MAXPATHLEN, "%s%s", target_prefix(),
841: wbuf);
842: else
843: strcpy(resolved, wbuf);
844: goto loop;
845: }
846: if (S_ISDIR(sb.st_mode)) {
847: if (chdir(p) < 0)
848: goto err1;
849: p = "";
850: }
851: }
852:
853: /*
854: * Save the last component name and get the full pathname of
855: * the current directory.
856: */
857: (void)strncpy(wbuf, p, (sizeof(wbuf) - 1));
858:
859: /*
1.29 wiz 860: * Call the internal internal version of getcwd which
1.26 fvdl 861: * does a physical search rather than using the $PWD short-cut
862: */
863: if (getcwd(resolved, MAXPATHLEN) == 0)
864: goto err1;
865:
866: /*
867: * Join the two strings together, ensuring that the right thing
868: * happens if the last component is empty, or the dirname is root.
869: */
870: if (resolved[0] == '/' && resolved[1] == '\0')
871: rootd = 1;
872: else
873: rootd = 0;
874:
875: if (*wbuf) {
876: if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
877: errno = ENAMETOOLONG;
878: goto err1;
879: }
880: if (rootd == 0)
881: (void)strcat(resolved, "/"); /* XXX: strcat is safe */
882: (void)strcat(resolved, wbuf); /* XXX: strcat is safe */
883: }
884:
885: /* Go back to where we came from. */
886: if (fchdir(fd) < 0) {
887: serrno = errno;
888: goto err2;
889: }
890:
891: /* It's okay if the close fails, what's an fd more or less? */
892: (void)close(fd);
893: return (resolved);
894:
895: err1: serrno = errno;
896: (void)fchdir(fd);
897: err2: (void)close(fd);
898: errno = serrno;
899: return (NULL);
1.14 jonathan 900: }
CVSweb <webmaster@jp.NetBSD.org>