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

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

CVSweb <webmaster@jp.NetBSD.org>