Annotation of src/distrib/utils/sysinst/target.c, Revision 1.31.2.1
1.31.2.1! msaitoh 1: /* $NetBSD: target.c,v 1.31 2001/01/14 02:38:15 mrg 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.31.2.1! msaitoh 78: __RCSID("$NetBSD: target.c,v 1.31 2001/01/14 02:38:15 mrg 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.5 jonathan 84: * we're installing into a separate filesystem hierarchy mounted under /mnt,
85: * or into the currently active root mounted on /.
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.16 mrg 145: void
146: backtowin()
1.8 jonathan 147: {
148:
149: fflush(stdout); /* curses does not leave stdout linebuffered. */
150: getchar(); /* wait for user to press return */
151: wrefresh(stdscr);
152: }
153:
154: /*
155: * Get name of current root device from kernel via sysctl.
156: * On NetBSD-1.3_ALPHA, this just returns the name of a
157: * device (e.g., "sd0"), not a specific partition -- like "sd0a",
158: * or "sd0b" for root-in-swap.
1.16 mrg 159: */
160: static const char *
1.8 jonathan 161: get_rootdev()
1.5 jonathan 162: {
163: int mib[2];
1.8 jonathan 164: static char rootdev[STRSIZE];
1.5 jonathan 165: size_t varlen;
166:
167: mib[0] = CTL_KERN;
168: mib[1] = KERN_ROOT_DEVICE;
1.8 jonathan 169: varlen = sizeof(rootdev);
170: if (sysctl(mib, 2, rootdev, &varlen, NULL, 0) < 0)
1.5 jonathan 171: return (NULL);
172:
173: #ifdef DEBUG
1.8 jonathan 174: printf("get_rootdev(): sysctl returns %s\n", rootdev);
1.5 jonathan 175: #endif
1.8 jonathan 176: return (rootdev);
1.5 jonathan 177: }
178:
1.8 jonathan 179:
1.5 jonathan 180: /*
1.8 jonathan 181: * Check if current root and target are on the same
182: * device (e.g., both on "sd0") or on different devices
183: * e.g., target is "sd0" and root is "le0" (nfs).
184: */
185: int
1.16 mrg 186: target_on_current_disk()
1.8 jonathan 187: {
188: int same;
1.16 mrg 189:
1.24 hubertf 190: if (strcmp(diskdev, "") == 0) /* nothing selected yet */
191: same = 1; /* bad assumption: this is a live system */
192: else
193: same = (strcmp(diskdev, get_rootdev()) == 0);
1.8 jonathan 194: return (same);
195: }
196:
197: /*
198: * must_mount_root -- check to see if the current root
199: * partition and the target root partition are on the same
200: * device. If they are, we need to have the root mounted read/write
201: * in order to find out whether they're the same partition.
202: * (this is arguably a bug in the kernel API.)
203: *
204: * check to see if they're
205: */
1.16 mrg 206: int
207: must_mount_root()
1.8 jonathan 208: {
209: int result;
210:
211: #if defined(DEBUG) || defined(DEBUG_ROOT)
1.16 mrg 212: endwin();
213: printf("must_mount_root\n");
214: backtowin();
1.8 jonathan 215: #endif
216:
217: /* if they're on different devices, we're OK. */
218: if (target_on_current_disk() == 0) {
219: #if defined(DEBUG) || defined(DEBUG_ROOT)
220: endwin();
221: printf("must_mount_root: %s and %s, no?\n",
1.16 mrg 222: diskdev, get_rootdev());
1.8 jonathan 223: fflush(stdout);
224: backtowin();
225: #endif
226: return (0);
227: }
228:
229: /* If they're on the same device, and root not mounted, yell. */
230: result = (strcmp(mounted_rootpart(), "root_device") == 0);
231:
232: #if defined(DEBUG) || defined(DEBUG_ROOT)
233: endwin();
234: printf("must_mount_root %s and root_device gives %d\n",
1.16 mrg 235: mounted_rootpart(), result);
1.8 jonathan 236: fflush(stdout);
237: backtowin();
238: #endif
239:
240: return (result);
241: }
242:
243: /*
1.29 wiz 244: * Is the root partition we're running from the same as the root
245: * which the user has selected to install/upgrade?
1.8 jonathan 246: * Uses global variable "diskdev" to find the selected device for
247: * install/upgrade.
248: * FIXME -- disklabel-editing code assumes that partition 'a' is always root.
1.5 jonathan 249: */
1.16 mrg 250: int
251: target_already_root()
1.5 jonathan 252: {
253: register int result;
1.8 jonathan 254: char diskdevroot[STRSIZE];
255:
256: /* if they're on different devices, we're OK. */
257: if (target_on_current_disk() == 0)
258: return (0);
259:
260: /*
261: * otherwise, install() or upgrade() should already did
262: * have forced the user to explicitly mount the root,
263: * so we can find out via statfs(). Abort if not.
264: */
265:
1.24 hubertf 266: if (strcmp(diskdev, "") == 0) {
267: /* no root partition was ever selected. Assume that
268: * the currently mounted one should be used */
269: result = 1;
270: } else {
271: /* append 'a' to the partitionless target disk device name. */
272: snprintf(diskdevroot, STRSIZE, "%s%c", diskdev, 'a');
273: result = is_active_rootpart(diskdevroot);
274: }
1.16 mrg 275: return (result);
1.5 jonathan 276: }
277:
278:
1.8 jonathan 279:
280: /*
281: * ask the kernel what the current root is.
1.29 wiz 282: * If it's "root_device", we should just give up now.
1.8 jonathan 283: * (Why won't the kernel tell us? If we booted with "n",
284: * or an explicit bootpath, the operator told *it* ....)
285: *
1.29 wiz 286: * Don't cache the answer in case the user suspends and remounts.
1.8 jonathan 287: */
1.16 mrg 288: static const char *
289: mounted_rootpart()
1.8 jonathan 290: {
291: struct statfs statfsbuf;
292: int result;
293:
294: static char statrootstr[STRSIZE];
1.17 perry 295: memset(&statfsbuf, 0, sizeof(statfsbuf));
1.8 jonathan 296: result = statfs("/", &statfsbuf);
297: if (result < 0) {
298: fprintf(stderr, "Help! statfs() can't find root: %s\n",
1.16 mrg 299: strerror(errno));
1.8 jonathan 300: fflush(stderr);
1.18 garbled 301: if (logging)
302: fprintf(log, "Help! statfs() can't find root: %s\n",
303: strerror(errno));
1.8 jonathan 304: exit(errno);
305: return(0);
306: }
307: #if defined(DEBUG)
308: endwin();
309: printf("mounted_rootpart: got %s on %s\n",
1.16 mrg 310: statfsbuf.f_mntonname, statfsbuf.f_mntfromname);
1.8 jonathan 311: fflush(stdout);
312: backtowin();
313: #endif
314:
315: /*
316: * Check for unmounted root. We can't tell which partition
317: */
318: strncpy(statrootstr, statfsbuf.f_mntfromname, STRSIZE);
1.16 mrg 319: return (statrootstr);
1.8 jonathan 320: }
321:
322: /*
323: * Is this device partition (e.g., "sd0a") mounted as root?
324: * Note difference from target_on_current_disk()!
325: */
326: int
1.16 mrg 327: is_active_rootpart(devpart)
328: const char *devpart;
1.5 jonathan 329: {
1.8 jonathan 330: const char *root = 0;
1.5 jonathan 331: int result;
1.12 jonathan 332: static char devdirdevpart[STRSIZE];
1.5 jonathan 333:
1.8 jonathan 334: /* check to see if the devices match? */
335:
336: /* this changes on mounts, so don't cache it. */
337: root = mounted_rootpart();
338:
1.12 jonathan 339: /* prepend /dev. */
340: /* XXX post-1.3, use strstr to strip "/dev" from input. */
341: snprintf(devdirdevpart, STRSIZE, "/dev/%s", devpart);
342:
343: result = (strcmp(devdirdevpart, root) == 0);
344:
1.8 jonathan 345: #if defined(DEBUG) || defined(DEBUG_ROOT)
346: endwin();
1.12 jonathan 347: printf("is_active_rootpart: activeroot = %s, query=%s, mung=%s, answer=%d\n",
1.16 mrg 348: root, devpart, devdirdevpart, result);
1.8 jonathan 349: fflush(stdout);
350: backtowin();
1.5 jonathan 351: #endif
1.8 jonathan 352:
1.16 mrg 353: return (result);
1.5 jonathan 354: }
1.8 jonathan 355:
1.1 jonathan 356: /*
357: * Pathname prefixing glue to support installation either
358: * from in-ramdisk miniroots or on-disk diskimages.
359: * If our root is on the target disk, the install target is mounted
360: * on /mnt and we need to prefix installed pathnames with /mnt.
361: * otherwise we are installing to the currently-active root and
362: * no prefix is needed.
363: */
1.16 mrg 364: const char *
365: target_prefix()
1.1 jonathan 366: {
367: /*
368: * XXX fetch sysctl variable for current root, and compare
1.16 mrg 369: * to the devicename of the install target disk.
1.1 jonathan 370: */
1.5 jonathan 371: return(target_already_root() ? "" : "/mnt");
1.1 jonathan 372: }
373:
1.4 jonathan 374: /*
375: * concatenate two pathnames.
376: * XXX returns either input args or result in a static buffer.
377: * The caller must copy if it wants to use the pathname past the
378: * next call to a target-prefixing function, or to modify the inputs..
379: * Used only internally so this is probably safe.
380: */
1.26 fvdl 381: const char*
1.16 mrg 382: concat_paths(prefix, suffix)
383: const char* prefix;
384: const char *suffix;
1.4 jonathan 385: {
1.26 fvdl 386: static char realpath[MAXPATHLEN];
1.4 jonathan 387:
388: /* absolute prefix and null suffix? */
389: if (prefix[0] == '/' && suffix[0] == 0)
390: return prefix;
391:
392: /* null prefix and absolute suffix? */
393: if (prefix[0] == 0 && suffix[0] == '/')
394: return suffix;
395:
396: /* avoid "//" */
397: if (suffix[0] == '/' || suffix[0] == 0)
1.26 fvdl 398: snprintf(realpath, MAXPATHLEN, "%s%s", prefix, suffix);
1.4 jonathan 399: else
1.26 fvdl 400: snprintf(realpath, MAXPATHLEN, "%s/%s", prefix, suffix);
1.16 mrg 401: return (realpath);
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 *
414: target_expand(tgtpath)
415: const char *tgtpath;
1.4 jonathan 416: {
1.16 mrg 417:
1.4 jonathan 418: return concat_paths(target_prefix(), tgtpath);
419: }
420:
1.1 jonathan 421: /* Make a directory, with a prefix like "/mnt" or possibly just "". */
422: static void
1.16 mrg 423: make_prefixed_dir(prefix, path)
424: const char *prefix;
425: const char *path;
1.1 jonathan 426: {
1.16 mrg 427:
1.27 fvdl 428: run_prog(0, NULL, "/bin/mkdir -p %s", concat_paths(prefix, path));
1.1 jonathan 429: }
430:
1.29 wiz 431: /* Make a directory with a pathname relative to the installation target. */
1.1 jonathan 432: void
1.16 mrg 433: make_target_dir(path)
434: const char *path;
1.1 jonathan 435: {
1.16 mrg 436:
1.1 jonathan 437: make_prefixed_dir(target_prefix(), path);
438: }
439:
1.16 mrg 440: /* Make a directory with a pathname in the currently-mounted root. */
1.1 jonathan 441: void
1.16 mrg 442: make_ramdisk_dir(path)
443: const char *path;
1.1 jonathan 444: {
1.16 mrg 445:
1.1 jonathan 446: make_prefixed_dir(path, "");
447: }
448:
1.19 garbled 449: #if 0
450: /* unused, will not work with new run.c */
1.1 jonathan 451: /*
452: *
453: * Append |string| to the filename |path|, where |path| is
454: * relative to the root of the install target.
455: * for example,
456: * echo_to_target_file( "Newbie.NetBSD.ORG", "/etc/myname");
457: * would set the default hostname at the next reboot of the installed-on disk.
458: */
459: void
1.16 mrg 460: append_to_target_file(path, string)
461: const char *path;
462: const char *string;
1.1 jonathan 463: {
1.16 mrg 464:
1.27 fvdl 465: run_prog(RUN_FATAL, NULL, "echo %s >> %s", string, target_expand(path));
1.1 jonathan 466: }
467:
468: /*
469: * As append_to_target_file, but with ftrunc semantics.
470: */
471: void
1.16 mrg 472: echo_to_target_file(path, string)
473: const char *path;
474: const char *string;
1.1 jonathan 475: {
476: trunc_target_file(path);
477: append_to_target_file(path, string);
478: }
479:
480: void
481: sprintf_to_target_file(const char *path, const char *format, ...)
482: {
483: char lines[STRSIZE];
484: va_list ap;
485:
486: trunc_target_file(path);
487:
1.10 phil 488: va_start(ap, format);
1.1 jonathan 489: vsnprintf(lines, STRSIZE, format, ap);
490: va_end(ap);
491:
492: append_to_target_file(path, lines);
493: }
494:
495:
496: void
1.16 mrg 497: trunc_target_file(path)
498: const char *path;
1.1 jonathan 499: {
1.16 mrg 500:
1.27 fvdl 501: run_prog(RUN_FATAL, NULL, "cat < /dev/null > %s", target_expand(path));
1.1 jonathan 502: }
1.19 garbled 503: #endif /* if 0 */
1.1 jonathan 504:
1.16 mrg 505: static int
506: do_target_chdir(dir, must_succeed)
507: const char *dir;
508: int must_succeed;
1.1 jonathan 509: {
1.4 jonathan 510: const char *tgt_dir;
1.9 phil 511: int error;
1.1 jonathan 512:
1.9 phil 513: error = 0;
1.4 jonathan 514: tgt_dir = target_expand(dir);
1.1 jonathan 515:
516: #ifndef DEBUG
1.7 jonathan 517: /* chdir returns -1 on error and sets errno. */
1.16 mrg 518: if (chdir(tgt_dir) < 0)
1.7 jonathan 519: error = errno;
1.18 garbled 520: if (logging) {
521: fprintf(log, "cd to %s\n", tgt_dir);
522: fflush(log);
523: }
524: if (scripting) {
1.31 mrg 525: scripting_fprintf(NULL, "cd %s\n", tgt_dir);
1.18 garbled 526: fflush(script);
527: }
1.16 mrg 528:
1.1 jonathan 529: if (error && must_succeed) {
1.7 jonathan 530: fprintf(stderr, msg_string(MSG_realdir),
531: target_prefix(), strerror(error));
1.18 garbled 532: if (logging)
533: fprintf(log, msg_string(MSG_realdir),
534: target_prefix(), strerror(error));
1.1 jonathan 535: exit(1);
536: }
537: return (error);
538: #else
539: printf("target_chdir (%s)\n", tgt_dir);
540: return (0);
541: #endif
542: }
543:
1.16 mrg 544: void
545: target_chdir_or_die(dir)
546: const char *dir;
1.1 jonathan 547: {
1.16 mrg 548:
1.1 jonathan 549: (void) do_target_chdir(dir, 1);
550: }
551:
1.16 mrg 552: int
553: target_chdir(dir)
554: const char *dir;
1.1 jonathan 555: {
1.16 mrg 556:
1.1 jonathan 557: return(do_target_chdir(dir, 0));
1.3 jonathan 558: }
559:
560: /*
1.15 jonathan 561: * Copy a file from the current root into the target system,
562: * where the destination pathname is relative to the target root.
563: * Does not check for copy-to-self when target is current root.
564: */
1.20 bouyer 565: int
1.16 mrg 566: cp_to_target(srcpath, tgt_path)
567: const char *srcpath;
568: const char *tgt_path;
1.15 jonathan 569: {
570: const char *realpath = target_expand(tgt_path);
1.16 mrg 571:
1.27 fvdl 572: return run_prog(0, NULL, "/bin/cp %s %s", srcpath, realpath);
1.15 jonathan 573: }
574:
575: /*
1.3 jonathan 576: * Duplicate a file from the current root to the same pathname
1.15 jonathan 577: * in the target system. Pathname must be an absolute pathname.
1.3 jonathan 578: * If we're running in the target, do nothing.
579: */
1.16 mrg 580: void
581: dup_file_into_target(filename)
582: const char *filename;
1.3 jonathan 583: {
1.16 mrg 584:
585: if (!target_already_root())
1.15 jonathan 586: cp_to_target(filename, filename);
1.3 jonathan 587: }
588:
589:
1.16 mrg 590: /*
591: * Do a mv where both pathnames are within the target filesystem.
592: */
1.23 hubertf 593: void
594: mv_within_target_or_die(frompath, topath)
1.16 mrg 595: const char *frompath;
596: const char *topath;
1.4 jonathan 597: {
598: char realfrom[STRSIZE];
599: char realto[STRSIZE];
600:
601: strncpy(realfrom, target_expand(frompath), STRSIZE);
602: strncpy(realto, target_expand(topath), STRSIZE);
603:
1.27 fvdl 604: run_prog(RUN_FATAL, NULL, "mv %s %s", realfrom, realto);
1.4 jonathan 605: }
606:
1.7 jonathan 607: /* Do a cp where both pathnames are within the target filesystem. */
1.16 mrg 608: int cp_within_target(frompath, topath)
609: const char *frompath;
610: const char *topath;
1.7 jonathan 611: {
612: char realfrom[STRSIZE];
613: char realto[STRSIZE];
614:
615: strncpy(realfrom, target_expand(frompath), STRSIZE);
616: strncpy(realto, target_expand(topath), STRSIZE);
617:
1.27 fvdl 618: return (run_prog(0, NULL, "cp -p %s %s", realfrom, realto));
1.7 jonathan 619: }
620:
1.4 jonathan 621: /* fopen a pathname in the target. */
1.16 mrg 622: FILE *
623: target_fopen(filename, type)
624: const char *filename;
625: const char *type;
1.4 jonathan 626: {
1.16 mrg 627:
1.4 jonathan 628: return fopen(target_expand(filename), type);
629: }
630:
631: /*
1.13 jonathan 632: * Do a mount and record the mountpoint in a list of mounts to
633: * unwind after completing or aborting a mount.
634: */
635: int
1.16 mrg 636: mount_with_unwind(fstype, from, on)
637: const char *fstype;
638: const char *from;
639: const char *on;
1.13 jonathan 640: {
641: int error;
642: struct unwind_mount * m;
643:
644: m = malloc(sizeof(*m));
645: if (m == 0)
646: return (ENOMEM); /* XXX */
647:
648: strncpy(m->um_mountpoint, on, STRSIZE);
649: m->um_prev = unwind_mountlist;
650: unwind_mountlist = m;
651:
652: #ifdef DEBUG_UNWIND
653: endwin();
654: fprintf(stderr, "mounting %s with unwind\n", on);
655: backtowin();
656: #endif
657:
1.27 fvdl 658: error = run_prog(0, NULL, "/sbin/mount %s %s %s", fstype, from, on);
1.13 jonathan 659: return (error);
660: }
661:
662: /*
1.29 wiz 663: * unwind the mount stack, unmounting mounted filesystems.
1.13 jonathan 664: * For now, ignore any errors in unmount.
665: * (Why would we be unable to unmount? The user has suspended
666: * us and forked shell sitting somewhere in the target root?)
667: */
668: void
669: unwind_mounts()
670: {
671: struct unwind_mount *m, *prev;
1.14 jonathan 672: volatile static int unwind_in_progress = 0;
673:
674: /* signal safety */
675: if (unwind_in_progress)
676: return;
677: unwind_in_progress = 1;
1.13 jonathan 678:
679: prev = NULL;
680: for (m = unwind_mountlist; m; ) {
681: struct unwind_mount *prev;
682: #ifdef DEBUG_UNWIND
683: endwin();
684: fprintf(stderr, "unmounting %s\n", m->um_mountpoint);
685: backtowin();
686: #endif
1.27 fvdl 687: run_prog(0, NULL, "/sbin/umount %s", m->um_mountpoint);
1.13 jonathan 688: prev = m->um_prev;
689: free(m);
690: m = prev;
691: }
692: unwind_mountlist = NULL;
1.14 jonathan 693: unwind_in_progress = 0;
1.13 jonathan 694: }
695:
696: /*
1.29 wiz 697: * Do a mount onto a mountpoint in the install target.
1.4 jonathan 698: * NB: does not prefix mount-from, which probably breaks nullfs mounts.
699: */
1.16 mrg 700: int
701: target_mount(fstype, from, on)
702: const char *fstype;
703: const char *from;
704: const char *on;
1.4 jonathan 705: {
706: int error;
707: const char *realmount = target_expand(on);
708:
1.29 wiz 709: /* mount and record for unmounting when done. */
1.13 jonathan 710: error = mount_with_unwind(fstype, from, realmount);
711:
1.4 jonathan 712: return (error);
713: }
714:
1.16 mrg 715: int
716: target_collect_file(kind, buffer, name)
717: int kind;
718: char **buffer;
719: char *name;
1.3 jonathan 720: {
1.16 mrg 721: const char *realname =target_expand(name);
1.5 jonathan 722:
723: #ifdef DEBUG
724: printf("collect real name %s\n", realname);
725: #endif
726: return collect(kind, buffer, realname);
1.7 jonathan 727: }
728:
729: /*
730: * Verify a pathname already exists in the target root filesystem,
731: * by running test "testflag" on the expanded target pathname.
732: */
1.16 mrg 733: int
1.25 fvdl 734: target_test(mode, path)
735: unsigned int mode;
1.16 mrg 736: const char *path;
1.7 jonathan 737: {
738: const char *realpath = target_expand(path);
739: register int result;
740:
1.25 fvdl 741: result = !file_mode_match(realpath, mode);
1.31 mrg 742: scripting_fprintf(NULL, "if [ $? != 0 ]; then echo \"%s does not exist!\"; fi\n", realpath);
1.7 jonathan 743:
744: #if defined(DEBUG)
1.16 mrg 745: printf("target_test(%s %s) returning %d\n", test, realpath, result);
1.7 jonathan 746: #endif
1.16 mrg 747: return (result);
1.7 jonathan 748: }
749:
750: /*
751: * Verify a directory already exists in the target root
752: * filesystem. Do not create the directory if it doesn't exist.
753: * Assumes that sysinst has already mounted the target root.
754: */
1.16 mrg 755: int
756: target_test_dir(path)
757: const char *path;
1.7 jonathan 758: {
1.16 mrg 759:
1.25 fvdl 760: return target_test(S_IFDIR, path);
1.7 jonathan 761: }
762:
763: /*
764: * Verify an ordinary file already exists in the target root
765: * filesystem. Do not create the directory if it doesn't exist.
766: * Assumes that sysinst has already mounted the target root.
767: */
1.16 mrg 768: int
769: target_test_file(path)
770: const char *path;
1.7 jonathan 771: {
1.16 mrg 772:
1.25 fvdl 773: return target_test(S_IFREG, path);
1.1 jonathan 774: }
1.14 jonathan 775:
1.23 hubertf 776: int
777: target_test_symlink(path)
778: const char *path;
779: {
780:
1.25 fvdl 781: return target_test(S_IFLNK, path);
1.23 hubertf 782: }
783:
1.16 mrg 784: int target_file_exists_p(path)
785: const char *path;
1.14 jonathan 786: {
1.16 mrg 787:
1.14 jonathan 788: return (target_test_file(path) == 0);
789: }
790:
1.16 mrg 791: int target_dir_exists_p(path)
792: const char *path;
1.14 jonathan 793: {
1.16 mrg 794:
1.14 jonathan 795: return (target_test_dir(path) == 0);
1.23 hubertf 796: }
797:
798: int target_symlink_exists_p(path)
799: const char *path;
800: {
801:
802: return (target_test_symlink(path) == 0);
1.26 fvdl 803: }
804:
805: /*
806: * XXXX had to include this to deal with symlinks in some places. When the target
807: * disk is mounted under /mnt, absolute symlinks on it don't work right. This
808: * function will resolve them using the mountpoint as prefix. Copied verbatim
809: * from libc, with added prefix handling.
810: *
811: * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
812: *
813: * Find the real name of path, by removing all ".", ".." and symlink
814: * components. Returns (resolved) on success, or (NULL) on failure,
815: * in which case the path which caused trouble is left in (resolved).
816: */
817: char *
818: target_realpath(const char *path, char *resolved)
819: {
820: struct stat sb;
821: int fd, n, rootd, serrno, nlnk = 0;
822: char *p, *q, wbuf[MAXPATHLEN];
823:
824: /* Save the starting point. */
825: if ((fd = open(".", O_RDONLY)) < 0) {
826: (void)strcpy(resolved, ".");
827: return (NULL);
828: }
829:
830: /*
831: * Find the dirname and basename from the path to be resolved.
832: * Change directory to the dirname component.
833: * lstat the basename part.
834: * if it is a symlink, read in the value and loop.
835: * if it is a directory, then change to that directory.
836: * get the current directory name and append the basename.
837: */
838: if (target_prefix() != NULL && strcmp(target_prefix(), "") != 0)
839: snprintf(resolved, MAXPATHLEN, "%s/%s", target_prefix(), path);
840: else {
841: (void)strncpy(resolved, path, MAXPATHLEN - 1);
842: resolved[MAXPATHLEN - 1] = '\0';
843: }
844: loop:
845: q = strrchr(resolved, '/');
846: if (q != NULL) {
847: p = q + 1;
848: if (q == resolved)
849: q = "/";
850: else {
851: do {
852: --q;
853: } while (q > resolved && *q == '/');
854: q[1] = '\0';
855: q = resolved;
856: }
857: if (chdir(q) < 0)
858: goto err1;
859: } else
860: p = resolved;
861:
862: /* Deal with the last component. */
863: if (lstat(p, &sb) == 0) {
864: if (S_ISLNK(sb.st_mode)) {
865: if (nlnk++ >= MAXSYMLINKS) {
866: errno = ELOOP;
867: goto err1;
868: }
869: n = readlink(p, wbuf, MAXPATHLEN);
870: if (n < 0)
871: goto err1;
872: wbuf[n] = '\0';
873: if (wbuf[0] == '/')
874: snprintf(resolved, MAXPATHLEN, "%s%s", target_prefix(),
875: wbuf);
876: else
877: strcpy(resolved, wbuf);
878: goto loop;
879: }
880: if (S_ISDIR(sb.st_mode)) {
881: if (chdir(p) < 0)
882: goto err1;
883: p = "";
884: }
885: }
886:
887: /*
888: * Save the last component name and get the full pathname of
889: * the current directory.
890: */
891: (void)strncpy(wbuf, p, (sizeof(wbuf) - 1));
892:
893: /*
1.29 wiz 894: * Call the internal internal version of getcwd which
1.26 fvdl 895: * does a physical search rather than using the $PWD short-cut
896: */
897: if (getcwd(resolved, MAXPATHLEN) == 0)
898: goto err1;
899:
900: /*
901: * Join the two strings together, ensuring that the right thing
902: * happens if the last component is empty, or the dirname is root.
903: */
904: if (resolved[0] == '/' && resolved[1] == '\0')
905: rootd = 1;
906: else
907: rootd = 0;
908:
909: if (*wbuf) {
1.31.2.1! msaitoh 910: if (strlen(resolved) + strlen(wbuf) + (rootd ? 0 : 1) + 1 >
! 911: MAXPATHLEN) {
1.26 fvdl 912: errno = ENAMETOOLONG;
913: goto err1;
914: }
915: if (rootd == 0)
916: (void)strcat(resolved, "/"); /* XXX: strcat is safe */
917: (void)strcat(resolved, wbuf); /* XXX: strcat is safe */
918: }
919:
920: /* Go back to where we came from. */
921: if (fchdir(fd) < 0) {
922: serrno = errno;
923: goto err2;
924: }
925:
926: /* It's okay if the close fails, what's an fd more or less? */
927: (void)close(fd);
928: return (resolved);
929:
930: err1: serrno = errno;
931: (void)fchdir(fd);
932: err2: (void)close(fd);
933: errno = serrno;
934: return (NULL);
1.14 jonathan 935: }
CVSweb <webmaster@jp.NetBSD.org>