[BACK]Return to target.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / distrib / utils / sysinst

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>