[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.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>