Annotation of src/distrib/utils/sysinst/target.c, Revision 1.2.2.5
1.2.2.5 ! phil 1: /* $NetBSD: target.c,v 1.2.2.4 1997/11/13 17:28:28 phil Exp $ */
1.2.2.2 mellon 2:
3: /*
4: * Copyright 1997 Jonathan Stone
5: * All rights reserved.
6: *
7:
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software develooped for the NetBSD Project by
19: * Jonathan Stone.
20: * 4. The name of Jonathan Stone may not be used to endorse
21: * or promote products derived from this software without specific prior
22: * written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY JONATHAN STONE ``AS IS''
25: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
28: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34: * THE POSSIBILITY OF SUCH DAMAGE.
35: *
36: */
37:
38: #include <sys/cdefs.h>
39: #if defined(LIBC_SCCS) && !defined(lint)
1.2.2.5 ! phil 40: __RCSID("$NetBSD: target.c,v 1.2.2.4 1997/11/13 17:28:28 phil Exp $");
1.2.2.2 mellon 41: #endif
42:
43:
44: /*
45: * target.c -- path-prefixing routines to access the target installation
46: * filesystems. Makes the install tools more ndependent of whether
47: * we're installing into a separate filesystem hierarchy mounted under /mnt,
48: * or into the currently active root mounted on /.
49: */
50:
51: #include <sys/param.h> /* XXX vm_param.h always defines TRUE*/
1.2.2.3 thorpej 52: #include <sys/types.h>
1.2.2.2 mellon 53: #include <sys/sysctl.h>
1.2.2.3 thorpej 54: #include <sys/stat.h> /* stat() */
55: #include <sys/mount.h> /* statfs() */
1.2.2.2 mellon 56:
57: #include <stdio.h>
58: #include <stdarg.h>
59: #include <unistd.h>
60: #include <curses.h> /* defines TRUE, but checks */
61: #include <errno.h>
62:
63:
64: #include "defs.h"
65: #include "md.h"
66: #include "msg_defs.h"
67: #include "menu_defs.h"
68:
69:
70: /*
71: * local prototypes
72: */
1.2.2.3 thorpej 73: static const char* get_rootdev __P((void));
74: static const char* mounted_rootpart __P((void));
75: int target_on_current_disk __P((void));
76: int must_mount_root __P((void));
77:
1.2.2.2 mellon 78: static void make_prefixed_dir __P((const char *prefix, const char *path));
79: const char* target_prefix __P((void));
80: static int do_target_chdir __P((const char *dir, int flag));
81: static const char* concat_paths __P((const char *prefix, const char *suffix));
82: int target_test(const char *test, const char *path);
83:
1.2.2.3 thorpej 84: void backtowin(void);
85:
86: /* turn on what-is-root? debugging. */
87: /*#define DEBUG_ROOT*/
1.2.2.2 mellon 88:
1.2.2.3 thorpej 89: /*
90: * debugging helper. curses...
91: */
92: void backtowin(void)
93: {
94:
95: fflush(stdout); /* curses does not leave stdout linebuffered. */
96:
97: getchar(); /* wait for user to press return */
98:
99: puts (CL);
100: wrefresh(stdscr);
101: }
102:
103: /*
104: * Get name of current root device from kernel via sysctl.
105: * On NetBSD-1.3_ALPHA, this just returns the name of a
106: * device (e.g., "sd0"), not a specific partition -- like "sd0a",
107: * or "sd0b" for root-in-swap.
108: */
109: static const char*
110: get_rootdev()
1.2.2.2 mellon 111: {
112: int mib[2];
1.2.2.3 thorpej 113: static char rootdev[STRSIZE];
1.2.2.2 mellon 114: size_t varlen;
115:
116: mib[0] = CTL_KERN;
117: mib[1] = KERN_ROOT_DEVICE;
1.2.2.3 thorpej 118: varlen = sizeof(rootdev);
119: if (sysctl(mib, 2, rootdev, &varlen, NULL, 0) < 0)
1.2.2.2 mellon 120: return (NULL);
121:
122: #ifdef DEBUG
1.2.2.3 thorpej 123: printf("get_rootdev(): sysctl returns %s\n", rootdev);
1.2.2.2 mellon 124: #endif
1.2.2.3 thorpej 125: return (rootdev);
1.2.2.2 mellon 126: }
127:
1.2.2.3 thorpej 128:
1.2.2.2 mellon 129: /*
1.2.2.3 thorpej 130: * Check if current root and target are on the same
131: * device (e.g., both on "sd0") or on different devices
132: * e.g., target is "sd0" and root is "le0" (nfs).
133: */
134: int
135: target_on_current_disk(void)
136: {
137: int same;
138: same = (strcmp(diskdev, get_rootdev()) == 0);
139: return (same);
140: }
141:
142: /*
143: * must_mount_root -- check to see if the current root
144: * partition and the target root partition are on the same
145: * device. If they are, we need to have the root mounted read/write
146: * in order to find out whether they're the same partition.
147: * (this is arguably a bug in the kernel API.)
148: *
149: * check to see if they're
150: */
151: int must_mount_root(void)
152: {
153: int result;
154:
155: #if defined(DEBUG) || defined(DEBUG_ROOT)
156: endwin();
157: printf("must_mount_root\n");
158: backtowin();
159: #endif
160:
161: /* if they're on different devices, we're OK. */
162: if (target_on_current_disk() == 0) {
163: #if defined(DEBUG) || defined(DEBUG_ROOT)
164: endwin();
165: printf("must_mount_root: %s and %s, no?\n",
166: diskdev, get_rootdev());
167: fflush(stdout);
168: backtowin();
169: #endif
170: return (0);
171: }
172:
173:
174: /* If they're on the same device, and root not mounted, yell. */
175: result = (strcmp(mounted_rootpart(), "root_device") == 0);
176:
177: #if defined(DEBUG) || defined(DEBUG_ROOT)
178: endwin();
179: printf("must_mount_root %s and root_device gives %d\n",
180: mounted_rootpart(), result);
181: fflush(stdout);
182: backtowin();
183: #endif
184:
185: return (result);
186: }
187:
188: /*
189: * Is the root pattion we're running from the same as the root
190: * which the user has selected to install/upgrade?
191: * Uses global variable "diskdev" to find the selected device for
192: * install/upgrade.
193: * FIXME -- disklabel-editing code assumes that partition 'a' is always root.
1.2.2.2 mellon 194: */
195: int target_already_root()
196: {
197: register int result;
1.2.2.3 thorpej 198: char diskdevroot[STRSIZE];
199:
200:
201: /* if they're on different devices, we're OK. */
202: if (target_on_current_disk() == 0)
203: return (0);
204:
205: /*
206: * otherwise, install() or upgrade() should already did
207: * have forced the user to explicitly mount the root,
208: * so we can find out via statfs(). Abort if not.
209: */
1.2.2.2 mellon 210:
1.2.2.3 thorpej 211: /* append 'a' to the partitionless target disk device name. */
212: snprintf(diskdevroot, STRSIZE, "%s%c", diskdev, 'a');
213: result = is_active_rootpart(diskdevroot);
1.2.2.2 mellon 214: return(result);
215: }
216:
217:
1.2.2.3 thorpej 218:
219: /*
220: * ask the kernel what the current root is.
221: * If it's "root_device", we should jsut give up now.
222: * (Why won't the kernel tell us? If we booted with "n",
223: * or an explicit bootpath, the operator told *it* ....)
224: *
225: * Don't cache the answer in case the user suspnnds and remounts.
226: */
227: static const char*
228: mounted_rootpart(void)
229: {
230: struct statfs statfsbuf;
231: int result;
232:
233: static char statrootstr[STRSIZE];
234: bzero(&statfsbuf, sizeof(statfsbuf));
235: result = statfs("/", &statfsbuf);
236: if (result < 0) {
237: endwin();
238: fprintf(stderr, "Help! statfs() can't find root: %s\n",
239: strerror(errno));
240: fflush(stderr);
241: exit(errno);
242: return(0);
243: }
244: #if defined(DEBUG)
245: endwin();
246: printf("mounted_rootpart: got %s on %s\n",
247: statfsbuf.f_mntonname, statfsbuf.f_mntfromname);
248: fflush(stdout);
249: backtowin();
250: #endif
251:
252: /*
253: * Check for unmounted root. We can't tell which partition
254: */
255: strncpy(statrootstr, statfsbuf.f_mntfromname, STRSIZE);
256: return(statrootstr);
257: }
258:
259:
260: /*
261: * Is this device partition (e.g., "sd0a") mounted as root?
262: * Note difference from target_on_current_disk()!
263: */
264: int
265: is_active_rootpart(const char *devpart)
1.2.2.2 mellon 266: {
1.2.2.3 thorpej 267: const char *root = 0;
1.2.2.2 mellon 268: int result;
269:
1.2.2.3 thorpej 270: /* check to see if the devices match? */
271:
272: /* this changes on mounts, so don't cache it. */
273: root = mounted_rootpart();
1.2.2.2 mellon 274:
1.2.2.3 thorpej 275: result = (strcmp(devpart, root) == 0);
276:
277: #if defined(DEBUG) || defined(DEBUG_ROOT)
278: endwin();
279: printf("is_active_rootpart: root devpart = %s, query=%s, answer=%d\n",
280: root, devpart, result);
281: fflush(stdout);
282: backtowin();
1.2.2.2 mellon 283: #endif
1.2.2.3 thorpej 284:
1.2.2.2 mellon 285: return(result);
286: }
287:
1.2.2.3 thorpej 288:
289:
1.2.2.2 mellon 290: /*
291: * Pathname prefixing glue to support installation either
292: * from in-ramdisk miniroots or on-disk diskimages.
293: * If our root is on the target disk, the install target is mounted
294: * on /mnt and we need to prefix installed pathnames with /mnt.
295: * otherwise we are installing to the currently-active root and
296: * no prefix is needed.
297: */
298:
299: const char* target_prefix(void)
300: {
301: /*
302: * XXX fetch sysctl variable for current root, and compare
303: * to the devicename of the instllal target disk.
304: */
305: return(target_already_root() ? "" : "/mnt");
306: }
307:
308:
309: /*
310: * concatenate two pathnames.
311: * XXX returns either input args or result in a static buffer.
312: * The caller must copy if it wants to use the pathname past the
313: * next call to a target-prefixing function, or to modify the inputs..
314: * Used only internally so this is probably safe.
315: */
316: static const char*
317: concat_paths(const char* prefix, const char *suffix)
318: {
319: static char realpath[STRSIZE];
320:
321: /* absolute prefix and null suffix? */
322: if (prefix[0] == '/' && suffix[0] == 0)
323: return prefix;
324:
325: /* null prefix and absolute suffix? */
326: if (prefix[0] == 0 && suffix[0] == '/')
327: return suffix;
328:
329: /* avoid "//" */
330: if (suffix[0] == '/' || suffix[0] == 0)
331: snprintf(realpath, STRSIZE, "%s%s", prefix, suffix);
332: else
333: snprintf(realpath, STRSIZE, "%s/%s", prefix, suffix);
334: return realpath;
335: }
336:
337:
338:
339: /*
340: * Do target prefix expansion on a pathname.
341: * XXX uses concat_paths and so returns result in a static buffer.
342: * The caller must copy if it wants to use the pathname past the
343: * next call to a target-prefixing function, or to modify the inputs..
344: * Used only internally so this is probably safe.
345: *
346: * Not static so other functions can generate target related file names.
347: */
348: const char*
349: target_expand(const char *tgtpath)
350: {
351: return concat_paths(target_prefix(), tgtpath);
352: }
353:
354:
355: /* Make a directory, with a prefix like "/mnt" or possibly just "". */
356: static void
357: make_prefixed_dir(const char *prefix, const char *path)
358: {
359: run_prog_or_continue("/bin/mkdir -p %s", concat_paths(prefix, path));
360: }
361:
362:
363:
364: /* Make a directory with a pathname relative to the insatllation target. */
365: void
366: make_target_dir(const char *path)
367: {
368: make_prefixed_dir(target_prefix(), path);
369: }
370:
371:
372: /* Make a directory with a pathname in the currently-mounted root. */
373: void
374: make_ramdisk_dir(const char *path)
375: {
376: make_prefixed_dir(path, "");
377: }
378:
379:
380: /*
381: *
382: * Append |string| to the filename |path|, where |path| is
383: * relative to the root of the install target.
384: * for example,
385: * echo_to_target_file( "Newbie.NetBSD.ORG", "/etc/myname");
386: * would set the default hostname at the next reboot of the installed-on disk.
387: */
388: void
389: append_to_target_file(const char *path, const char *string)
390: {
391: run_prog_or_die("echo %s >> %s", string, target_expand(path));
392: }
393:
394: /*
395: * As append_to_target_file, but with ftrunc semantics.
396: */
397: void
398: echo_to_target_file(const char *path, const char *string)
399: {
400: trunc_target_file(path);
401: append_to_target_file(path, string);
402: }
403:
404: void
405: sprintf_to_target_file(const char *path, const char *format, ...)
406: {
407: char lines[STRSIZE];
408: va_list ap;
409:
410: trunc_target_file(path);
411:
1.2.2.5 ! phil 412: va_start(ap, format);
1.2.2.2 mellon 413: vsnprintf(lines, STRSIZE, format, ap);
414: va_end(ap);
415:
416: append_to_target_file(path, lines);
417: }
418:
419:
420: void
421: trunc_target_file(const char *path)
422: {
423: run_prog_or_die("cat < /dev/null > %s", target_expand(path));
424: }
425:
426: static int do_target_chdir(const char *dir, int must_succeed)
427: {
428: const char *tgt_dir;
1.2.2.4 phil 429: int error;
1.2.2.2 mellon 430:
1.2.2.4 phil 431: error = 0;
1.2.2.2 mellon 432: tgt_dir = target_expand(dir);
433:
434: #ifndef DEBUG
435: /* chdir returns -1 on error and sets errno. */
436: if (chdir(tgt_dir) < 0) {
437: error = errno;
438: }
439: if (error && must_succeed) {
440: endwin();
441: fprintf(stderr, msg_string(MSG_realdir),
442: target_prefix(), strerror(error));
443: exit(1);
444: }
445: return (error);
446: #else
447: printf("target_chdir (%s)\n", tgt_dir);
448: return (0);
449: #endif
450: }
451:
452: void target_chdir_or_die(const char *dir)
453: {
454: (void) do_target_chdir(dir, 1);
455: }
456:
457: int target_chdir(const char *dir)
458: {
459: return(do_target_chdir(dir, 0));
460: }
461:
462: /*
463: * Duplicate a file from the current root to the same pathname
464: * in the target system. Pathname must be an absolute pathname.
465: * If we're running in the target, do nothing.
466: */
467: void dup_file_into_target(const char *filename)
468: {
469: if (!target_already_root()) {
470: const char *realpath = target_expand(filename);
471: run_prog ("/bin/cp %s %s", filename, realpath);
472: }
473: }
474:
475:
476: /* Do a mv where both pathnames are within the target filesystem. */
477: void mv_within_target_or_die(const char *frompath, const char *topath)
478: {
479: char realfrom[STRSIZE];
480: char realto[STRSIZE];
481:
482: strncpy(realfrom, target_expand(frompath), STRSIZE);
483: strncpy(realto, target_expand(topath), STRSIZE);
484:
485: run_prog_or_die("mv %s %s", realfrom, realto);
486: }
487:
488: /* Do a cp where both pathnames are within the target filesystem. */
489: int cp_within_target(const char *frompath, const char *topath)
490: {
491: char realfrom[STRSIZE];
492: char realto[STRSIZE];
493:
494: strncpy(realfrom, target_expand(frompath), STRSIZE);
495: strncpy(realto, target_expand(topath), STRSIZE);
496:
497: return (run_prog("cp -p %s %s", realfrom, realto));
498: }
499:
500: /* fopen a pathname in the target. */
501: FILE* target_fopen (const char *filename, const char *type)
502: {
503: return fopen(target_expand(filename), type);
504: }
505:
506: /*
507: * Do a mount onto a moutpoint in the install target.
508: * NB: does not prefix mount-from, which probably breaks nullfs mounts.
509: */
510: int target_mount(const char *fstype, const char *from, const char *on)
511: {
512: int error;
513: const char *realmount = target_expand(on);
514:
515: error = run_prog("/sbin/mount %s %s %s", fstype, from, realmount);
516: return (error);
517: }
518:
519:
520: int target_collect_file(int kind, char **buffer, char *name)
521: {
522: register const char *realname =target_expand(name);
523:
524: #ifdef DEBUG
525: printf("collect real name %s\n", realname);
526: #endif
527: return collect(kind, buffer, realname);
528: }
529:
530: /*
531: * Verify a pathname already exists in the target root filesystem,
532: * by running test "testflag" on the expanded target pathname.
533: */
534:
535: int target_test(const char *test, const char *path)
536: {
537: const char *realpath = target_expand(path);
538: register int result;
539:
540: result = run_prog ("test %s %s", test, realpath);
541:
542: #if defined(DEBUG)
543: printf("target_test(%s %s) returning %d\n",
544: test, realpath, result);
545: #endif
546: return result;
547: }
548:
549: /*
550: * Verify a directory already exists in the target root
551: * filesystem. Do not create the directory if it doesn't exist.
552: * Assumes that sysinst has already mounted the target root.
553: */
554: int target_verify_dir(const char *path)
555: {
556: return target_test("-d", path);
557: }
558:
559: /*
560: * Verify an ordinary file already exists in the target root
561: * filesystem. Do not create the directory if it doesn't exist.
562: * Assumes that sysinst has already mounted the target root.
563: */
564: int target_verify_file(const char *path)
565: {
566: return target_test("-f", path);
567: }
CVSweb <webmaster@jp.NetBSD.org>