[BACK]Return to util.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / sysinst

Annotation of src/usr.sbin/sysinst/util.c, Revision 1.29.2.5

1.29.2.5! msaitoh     1: /*     $NetBSD: util.c,v 1.29.2.4 2019/11/17 07:04:34 martin Exp $     */
1.1       dholland    2:
                      3: /*
                      4:  * Copyright 1997 Piermont Information Systems Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Written by Philip A. Nelson for Piermont Information Systems Inc.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. The name of Piermont Information Systems Inc. may not be used to endorse
                     18:  *    or promote products derived from this software without specific prior
                     19:  *    written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
                     22:  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
                     25:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     26:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     27:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     28:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     29:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     30:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
                     31:  * THE POSSIBILITY OF SUCH DAMAGE.
                     32:  *
                     33:  */
                     34:
                     35: /* util.c -- routines that don't really fit anywhere else... */
                     36:
1.17      martin     37: #include <assert.h>
                     38: #include <inttypes.h>
1.1       dholland   39: #include <stdio.h>
                     40: #include <stdarg.h>
                     41: #include <string.h>
                     42: #include <unistd.h>
                     43: #include <sys/mount.h>
                     44: #include <sys/dkio.h>
                     45: #include <sys/ioctl.h>
                     46: #include <sys/types.h>
                     47: #include <sys/param.h>
                     48: #include <sys/sysctl.h>
                     49: #include <sys/stat.h>
                     50: #include <sys/statvfs.h>
                     51: #include <isofs/cd9660/iso.h>
                     52: #include <curses.h>
                     53: #include <err.h>
                     54: #include <errno.h>
                     55: #include <dirent.h>
                     56: #include <util.h>
                     57: #include "defs.h"
                     58: #include "md.h"
1.22      martin     59: #include "defsizes.h"
1.1       dholland   60: #include "msg_defs.h"
                     61: #include "menu_defs.h"
                     62:
                     63: #define MAX_CD_DEVS    256     /* how many cd drives do we expect to attach */
                     64: #define ISO_BLKSIZE    ISO_DEFAULT_BLOCK_SIZE
                     65:
                     66: static const char *msg_yes, *msg_no, *msg_all, *msg_some, *msg_none;
                     67: static int select_menu_width;
                     68:
1.11      christos   69: static uint8_t set_status[SET_GROUP_END];
1.1       dholland   70: #define SET_VALID      0x01
                     71: #define SET_SELECTED   0x02
                     72: #define SET_SKIPPED    0x04
                     73: #define SET_INSTALLED  0x08
                     74:
                     75: struct  tarstats {
                     76:        int nselected;
                     77:        int nfound;
                     78:        int nnotfound;
                     79:        int nerror;
                     80:        int nsuccess;
                     81:        int nskipped;
                     82: } tarstats;
                     83:
                     84: distinfo dist_list[] = {
                     85: #ifdef SET_KERNEL_1_NAME
1.12      martin     86:        {SET_KERNEL_1_NAME,     SET_KERNEL_1,           false, MSG_set_kernel_1, NULL},
1.1       dholland   87: #endif
                     88: #ifdef SET_KERNEL_2_NAME
1.12      martin     89:        {SET_KERNEL_2_NAME,     SET_KERNEL_2,           false, MSG_set_kernel_2, NULL},
1.1       dholland   90: #endif
                     91: #ifdef SET_KERNEL_3_NAME
1.12      martin     92:        {SET_KERNEL_3_NAME,     SET_KERNEL_3,           false, MSG_set_kernel_3, NULL},
1.1       dholland   93: #endif
                     94: #ifdef SET_KERNEL_4_NAME
1.12      martin     95:        {SET_KERNEL_4_NAME,     SET_KERNEL_4,           false, MSG_set_kernel_4, NULL},
1.1       dholland   96: #endif
                     97: #ifdef SET_KERNEL_5_NAME
1.12      martin     98:        {SET_KERNEL_5_NAME,     SET_KERNEL_5,           false, MSG_set_kernel_5, NULL},
1.1       dholland   99: #endif
                    100: #ifdef SET_KERNEL_6_NAME
1.12      martin    101:        {SET_KERNEL_6_NAME,     SET_KERNEL_6,           false, MSG_set_kernel_6, NULL},
1.1       dholland  102: #endif
                    103: #ifdef SET_KERNEL_7_NAME
1.12      martin    104:        {SET_KERNEL_7_NAME,     SET_KERNEL_7,           false, MSG_set_kernel_7, NULL},
1.1       dholland  105: #endif
                    106: #ifdef SET_KERNEL_8_NAME
1.12      martin    107:        {SET_KERNEL_8_NAME,     SET_KERNEL_8,           false, MSG_set_kernel_8, NULL},
1.1       dholland  108: #endif
                    109: #ifdef SET_KERNEL_9_NAME
1.12      martin    110:        {SET_KERNEL_9_NAME,     SET_KERNEL_9,           false, MSG_set_kernel_9, NULL},
1.1       dholland  111: #endif
                    112:
1.12      martin    113:        {"modules",             SET_MODULES,            false, MSG_set_modules, NULL},
                    114:        {"base",                SET_BASE,               false, MSG_set_base, NULL},
                    115:        {"etc",                 SET_ETC,                false, MSG_set_system, NULL},
                    116:        {"comp",                SET_COMPILER,           false, MSG_set_compiler, NULL},
                    117:        {"games",               SET_GAMES,              false, MSG_set_games, NULL},
                    118:        {"man",                 SET_MAN_PAGES,          false, MSG_set_man_pages, NULL},
                    119:        {"misc",                SET_MISC,               false, MSG_set_misc, NULL},
1.29.2.4  martin    120:        {"rescue",              SET_RESCUE,             false, MSG_set_rescue, NULL},
1.12      martin    121:        {"tests",               SET_TESTS,              false, MSG_set_tests, NULL},
                    122:        {"text",                SET_TEXT_TOOLS,         false, MSG_set_text_tools, NULL},
                    123:
                    124:        {NULL,                  SET_GROUP,              false, MSG_set_X11, NULL},
                    125:        {"xbase",               SET_X11_BASE,           false, MSG_set_X11_base, NULL},
                    126:        {"xcomp",               SET_X11_PROG,           false, MSG_set_X11_prog, NULL},
                    127:        {"xetc",                SET_X11_ETC,            false, MSG_set_X11_etc, NULL},
                    128:        {"xfont",               SET_X11_FONTS,          false, MSG_set_X11_fonts, NULL},
                    129:        {"xserver",             SET_X11_SERVERS,        false, MSG_set_X11_servers, NULL},
                    130:        {NULL,                  SET_GROUP_END,          false, NULL, NULL},
1.1       dholland  131:
                    132: #ifdef SET_MD_1_NAME
1.12      martin    133:        {SET_MD_1_NAME,         SET_MD_1,               false, MSG_set_md_1, NULL},
1.1       dholland  134: #endif
                    135: #ifdef SET_MD_2_NAME
1.12      martin    136:        {SET_MD_2_NAME,         SET_MD_2,               false, MSG_set_md_2, NULL},
1.1       dholland  137: #endif
                    138: #ifdef SET_MD_3_NAME
1.12      martin    139:        {SET_MD_3_NAME,         SET_MD_3,               false, MSG_set_md_3, NULL},
1.1       dholland  140: #endif
                    141: #ifdef SET_MD_4_NAME
1.12      martin    142:        {SET_MD_4_NAME,         SET_MD_4,               false, MSG_set_md_4, NULL},
1.1       dholland  143: #endif
                    144:
1.12      martin    145:        {NULL,                  SET_GROUP,              true, MSG_set_source, NULL},
                    146:        {"syssrc",              SET_SYSSRC,             true, MSG_set_syssrc, NULL},
                    147:        {"src",                 SET_SRC,                true, MSG_set_src, NULL},
                    148:        {"sharesrc",            SET_SHARESRC,           true, MSG_set_sharesrc, NULL},
                    149:        {"gnusrc",              SET_GNUSRC,             true, MSG_set_gnusrc, NULL},
                    150:        {"xsrc",                SET_XSRC,               true, MSG_set_xsrc, NULL},
                    151:        {"debug",               SET_DEBUG,              false, MSG_set_debug, NULL},
                    152:        {"xdebug",              SET_X11_DEBUG,          false, MSG_set_xdebug, NULL},
                    153:        {NULL,                  SET_GROUP_END,          false, NULL, NULL},
1.1       dholland  154:
1.12      martin    155:        {NULL,                  SET_LAST,               false, NULL, NULL},
1.1       dholland  156: };
                    157:
                    158: #define MAX_CD_INFOS   16      /* how many media can be found? */
                    159: struct cd_info {
                    160:        char device_name[16];
                    161:        char menu[100];
                    162: };
                    163: static struct cd_info cds[MAX_CD_INFOS];
                    164:
1.22      martin    165: /* flags whether to offer the respective options (depending on helper
                    166:    programs available on install media */
                    167: int have_raid, have_vnd, have_cgd, have_lvm, have_gpt, have_dk;
                    168:
1.1       dholland  169: /*
                    170:  * local prototypes
                    171:  */
                    172:
                    173: static int check_for(unsigned int mode, const char *pathname);
                    174: static int get_iso9660_volname(int dev, int sess, char *volname);
                    175: static int get_available_cds(void);
1.22      martin    176: static int binary_available(const char *prog);
1.1       dholland  177:
                    178: void
                    179: init_set_status(int flags)
                    180: {
                    181:        static const uint8_t sets_valid[] = {MD_SETS_VALID};
                    182:        static const uint8_t sets_selected_full[] = {MD_SETS_SELECTED};
                    183:        static const uint8_t sets_selected_minimal[] = {MD_SETS_SELECTED_MINIMAL};
                    184:        static const uint8_t sets_selected_nox[] = {MD_SETS_SELECTED_NOX};
                    185:        static const uint8_t *sets_selected;
                    186:        unsigned int nelem_selected;
                    187:        unsigned int i, len;
                    188:        const char *longest;
                    189:
                    190:        if (flags & SFLAG_MINIMAL) {
                    191:                sets_selected = sets_selected_minimal;
1.22      martin    192:                nelem_selected = __arraycount(sets_selected_minimal);
1.1       dholland  193:        } else if (flags & SFLAG_NOX) {
                    194:                sets_selected = sets_selected_nox;
1.22      martin    195:                nelem_selected = __arraycount(sets_selected_nox);
1.1       dholland  196:        } else {
                    197:                sets_selected = sets_selected_full;
1.22      martin    198:                nelem_selected = __arraycount(sets_selected_full);
1.1       dholland  199:        }
                    200:
1.22      martin    201:        for (i = 0; i < __arraycount(sets_valid); i++)
1.1       dholland  202:                set_status[sets_valid[i]] = SET_VALID;
                    203:        for (i = 0; i < nelem_selected; i++)
                    204:                set_status[sets_selected[i]] |= SET_SELECTED;
                    205:
                    206:        set_status[SET_GROUP] = SET_VALID;
                    207:
                    208:        /* Lookup some strings we need lots of times */
                    209:        msg_yes = msg_string(MSG_Yes);
                    210:        msg_no = msg_string(MSG_No);
                    211:        msg_all = msg_string(MSG_All);
                    212:        msg_some = msg_string(MSG_Some);
                    213:        msg_none = msg_string(MSG_None);
                    214:
                    215:        /* Find longest and use it to determine width of selection menu */
                    216:        len = strlen(msg_no); longest = msg_no;
                    217:        i = strlen(msg_yes); if (i > len) {len = i; longest = msg_yes; }
                    218:        i = strlen(msg_all); if (i > len) {len = i; longest = msg_all; }
                    219:        i = strlen(msg_some); if (i > len) {len = i; longest = msg_some; }
                    220:        i = strlen(msg_none); if (i > len) {len = i; longest = msg_none; }
1.22      martin    221:        select_menu_width = snprintf(NULL, 0, "%-30s %s", "", longest);
1.1       dholland  222:
                    223:        /* Give the md code a chance to choose the right kernel, etc. */
                    224:        md_init_set_status(flags);
                    225: }
                    226:
                    227: int
                    228: dir_exists_p(const char *path)
                    229: {
                    230:
                    231:        return file_mode_match(path, S_IFDIR);
                    232: }
                    233:
                    234: int
                    235: file_exists_p(const char *path)
                    236: {
                    237:
                    238:        return file_mode_match(path, S_IFREG);
                    239: }
                    240:
                    241: int
                    242: file_mode_match(const char *path, unsigned int mode)
                    243: {
                    244:        struct stat st;
                    245:
                    246:        return (stat(path, &st) == 0 && (st.st_mode & S_IFMT) == mode);
                    247: }
                    248:
1.22      martin    249: /* return ram size in MB */
                    250: uint64_t
1.1       dholland  251: get_ramsize(void)
                    252: {
                    253:        uint64_t ramsize;
                    254:        size_t len = sizeof ramsize;
                    255:        int mib[2] = {CTL_HW, HW_PHYSMEM64};
                    256:
                    257:        sysctl(mib, 2, &ramsize, &len, NULL, 0);
                    258:
                    259:        /* Find out how many Megs ... round up. */
                    260:        return (ramsize + MEG - 1) / MEG;
                    261: }
                    262:
                    263: void
                    264: run_makedev(void)
                    265: {
                    266:        char *owd;
                    267:
                    268:        msg_display_add("\n\n");
                    269:        msg_display_add(MSG_makedev);
                    270:
                    271:        owd = getcwd(NULL, 0);
                    272:
                    273:        /* make /dev, in case the user  didn't extract it. */
                    274:        make_target_dir("/dev");
                    275:        target_chdir_or_die("/dev");
                    276:        run_program(0, "/bin/sh MAKEDEV all");
                    277:
                    278:        chdir(owd);
                    279:        free(owd);
                    280: }
                    281:
                    282: /*
                    283:  * Performs in-place replacement of a set of patterns in a file that lives
                    284:  * inside the installed system.  The patterns must be separated by a semicolon.
                    285:  * For example:
                    286:  *
                    287:  * replace("/etc/some-file.conf", "s/prop1=NO/prop1=YES/;s/foo/bar/");
                    288:  */
                    289: void
                    290: replace(const char *path, const char *patterns, ...)
                    291: {
                    292:        char *spatterns;
                    293:        va_list ap;
                    294:
                    295:        va_start(ap, patterns);
                    296:        vasprintf(&spatterns, patterns, ap);
                    297:        va_end(ap);
                    298:        if (spatterns == NULL)
                    299:                err(1, "vasprintf(&spatterns, \"%s\", ...)", patterns);
                    300:
                    301:        run_program(RUN_CHROOT, "sed -an -e '%s;H;$!d;g;w %s' %s", spatterns,
                    302:            path, path);
                    303:
                    304:        free(spatterns);
                    305: }
                    306:
                    307: static int
                    308: floppy_fetch(const char *set_name)
                    309: {
                    310:        char post[4];
                    311:        msg errmsg;
                    312:        int menu;
                    313:        int status;
                    314:        const char *write_mode = ">";
                    315:
                    316:        strcpy(post, "aa");
                    317:
                    318:        errmsg = "";
                    319:        menu = MENU_fdok;
                    320:        for (;;) {
                    321:                umount_mnt2();
                    322:                msg_display(errmsg);
1.24      christos  323:                msg_fmt_display_add(MSG_fdmount, "%s%s", set_name, post);
1.1       dholland  324:                process_menu(menu, &status);
                    325:                if (status != SET_CONTINUE)
                    326:                        return status;
                    327:                menu = MENU_fdremount;
                    328:                errmsg = MSG_fdremount;
                    329:                if (run_program(0, "/sbin/mount -r -t %s %s /mnt2",
                    330:                                                        fd_type, fd_dev))
                    331:                        continue;
                    332:                mnt2_mounted = 1;
                    333:                errmsg = MSG_fdnotfound;
                    334:
                    335:                /* Display this because it might take a while.... */
                    336:                if (run_program(RUN_DISPLAY,
                    337:                            "sh -c '/bin/cat /mnt2/%s.%s %s %s/%s/%s%s'",
                    338:                            set_name, post, write_mode,
1.12      martin    339:                            target_prefix(), xfer_dir, set_name,
                    340:                            set_postfix(set_name)))
1.1       dholland  341:                        /* XXX: a read error will give a corrupt file! */
                    342:                        continue;
                    343:
                    344:                /* We got that file, advance to next fragment */
                    345:                if (post[1] < 'z')
                    346:                        post[1]++;
                    347:                else
                    348:                        post[1] = 'a', post[0]++;
                    349:                write_mode = ">>";
                    350:                errmsg = "";
                    351:                menu = MENU_fdok;
                    352:        }
                    353: }
                    354:
                    355: /*
                    356:  * Load files from floppy.  Requires a /mnt2 directory for mounting them.
                    357:  */
                    358: int
                    359: get_via_floppy(void)
                    360: {
1.6       martin    361:        int rv = -1;
                    362:
                    363:        process_menu(MENU_floppysource, &rv);
                    364:        if (rv == SET_RETRY)
1.2       martin    365:                return SET_RETRY;
1.1       dholland  366:
                    367:        fetch_fn = floppy_fetch;
                    368:
                    369:        /* Set ext_dir for absolute path. */
                    370:        snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", target_prefix(), xfer_dir);
                    371:        snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", target_prefix(), xfer_dir);
                    372:
                    373:        return SET_OK;
                    374: }
                    375:
                    376: /*
                    377:  * Get the volume name of a ISO9660 file system
                    378:  */
                    379: static int
                    380: get_iso9660_volname(int dev, int sess, char *volname)
                    381: {
                    382:        int blkno, error, last;
                    383:        char buf[ISO_BLKSIZE];
                    384:        struct iso_volume_descriptor *vd = NULL;
                    385:        struct iso_primary_descriptor *pd = NULL;
                    386:
                    387:        for (blkno = sess+16; blkno < sess+16+100; blkno++) {
                    388:                error = pread(dev, buf, ISO_BLKSIZE, blkno*ISO_BLKSIZE);
                    389:                if (error == -1)
                    390:                        return -1;
                    391:                vd = (struct iso_volume_descriptor *)&buf;
                    392:                if (memcmp(vd->id, ISO_STANDARD_ID, sizeof(vd->id)) != 0)
                    393:                        return -1;
                    394:                if (isonum_711((const unsigned char *)&vd->type)
                    395:                     == ISO_VD_PRIMARY) {
                    396:                        pd = (struct iso_primary_descriptor*)buf;
                    397:                        strncpy(volname, pd->volume_id, sizeof pd->volume_id);
                    398:                        last = sizeof pd->volume_id-1;
                    399:                        while (last >= 0
                    400:                            && (volname[last] == ' ' || volname[last] == 0))
                    401:                                last--;
                    402:                        volname[last+1] = 0;
                    403:                        return 0;
                    404:                }
                    405:        }
                    406:        return -1;
                    407: }
                    408:
                    409: /*
1.15      martin    410:  * Local state while iterating CDs and collecting volumes
                    411:  */
                    412: struct get_available_cds_state {
                    413:        struct cd_info *info;
                    414:        size_t count;
                    415: };
                    416:
                    417: /*
                    418:  * Callback function: if this is a CD, enumerate all volumes on it
1.1       dholland  419:  */
1.15      martin    420: static bool
                    421: get_available_cds_helper(void *arg, const char *device)
1.1       dholland  422: {
1.15      martin    423:        struct get_available_cds_state *state = arg;
                    424:        char dname[16], volname[80];
1.1       dholland  425:        struct disklabel label;
1.15      martin    426:        int part, dev, error, sess, ready;
                    427:
1.16      martin    428:        if (!is_cdrom_device(device, false))
1.15      martin    429:                return true;
                    430:
                    431:        sprintf(dname, "/dev/r%s%c", device, 'a'+RAW_PART);
                    432:        dev = open(dname, O_RDONLY, 0);
                    433:        if (dev == -1)
                    434:                return true;
                    435:
                    436:        ready = 0;
                    437:        error = ioctl(dev, DIOCTUR, &ready);
                    438:        if (error != 0 || ready == 0) {
                    439:                close(dev);
                    440:                return true;
                    441:        }
                    442:        error = ioctl(dev, DIOCGDINFO, &label);
                    443:        close(dev);
                    444:        if (error != 0)
                    445:                return true;
1.1       dholland  446:
1.15      martin    447:        for (part = 0; part < label.d_npartitions; part++) {
                    448:
                    449:                if (label.d_partitions[part].p_fstype == FS_UNUSED
                    450:                    || label.d_partitions[part].p_size == 0)
                    451:                        continue;
                    452:
                    453:                if (label.d_partitions[part].p_fstype == FS_ISO9660) {
                    454:                        sess = label.d_partitions[part].p_cdsession;
                    455:                        sprintf(dname, "/dev/r%s%c", device, 'a'+part);
1.14      martin    456:                        dev = open(dname, O_RDONLY, 0);
                    457:                        if (dev == -1)
                    458:                                continue;
1.15      martin    459:                        error = get_iso9660_volname(dev, sess, volname);
                    460:                        close(dev);
                    461:                        if (error)
                    462:                                continue;
                    463:                        sprintf(state->info->device_name,
                    464:                            "%s%c", device, 'a'+part);
                    465:                        sprintf(state->info->menu, "%s (%s)",
                    466:                            state->info->device_name, volname);
                    467:                } else {
                    468:                        /*
                    469:                         * All install CDs use partition
                    470:                         * a for the sets.
                    471:                         */
                    472:                        if (part > 0)
1.14      martin    473:                                continue;
1.15      martin    474:                        sprintf(state->info->device_name,
                    475:                            "%s%c", device, 'a'+part);
                    476:                        strcpy(state->info->menu, state->info->device_name);
1.1       dholland  477:                }
1.15      martin    478:                state->info++;
                    479:                if (++state->count >= MAX_CD_INFOS)
                    480:                        return false;
1.1       dholland  481:        }
1.15      martin    482:
                    483:        return true;
                    484: }
                    485:
                    486: /*
                    487:  * Get a list of all available CD media (not drives!), return
                    488:  * the number of entries collected.
                    489:  */
                    490: static int
                    491: get_available_cds(void)
                    492: {
                    493:        struct get_available_cds_state data;
                    494:
                    495:        data.info = cds;
                    496:        data.count = 0;
                    497:
                    498:        enumerate_disks(&data, get_available_cds_helper);
                    499:
                    500:        return data.count;
1.1       dholland  501: }
                    502:
                    503: static int
                    504: cd_has_sets(void)
                    505: {
                    506:        /* Mount it */
                    507:        if (run_program(RUN_SILENT, "/sbin/mount -rt cd9660 /dev/%s /mnt2",
                    508:            cdrom_dev) != 0)
                    509:                return 0;
                    510:
                    511:        mnt2_mounted = 1;
                    512:
                    513:        snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", "/mnt2", set_dir_bin);
                    514:        snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", "/mnt2", set_dir_src);
                    515:        return dir_exists_p(ext_dir_bin);
                    516: }
                    517:
                    518: /*
                    519:  * Check whether we can remove the boot media.
                    520:  * If it is not a local filesystem, return -1.
                    521:  * If we can not decide for sure (can not tell MD content from plain ffs
                    522:  * on hard disk, for example), return 0.
                    523:  * If it is a CD/DVD, return 1.
                    524:  */
                    525: int
                    526: boot_media_still_needed(void)
                    527: {
                    528:        struct statvfs sb;
                    529:
                    530:        if (statvfs("/", &sb) == 0) {
                    531:                if (!(sb.f_flag & ST_LOCAL))
                    532:                        return -1;
                    533:                if (strcmp(sb.f_fstypename, MOUNT_CD9660) == 0
                    534:                           || strcmp(sb.f_fstypename, MOUNT_UDF) == 0)
                    535:                        return 1;
                    536:        }
                    537:
                    538:        return 0;
                    539: }
                    540:
1.29.2.3  msaitoh   541: bool
                    542: root_is_read_only(void)
                    543: {
                    544:        struct statvfs sb;
                    545:
                    546:        if (statvfs("/", &sb) == 0)
                    547:                return sb.f_flag & ST_RDONLY;
                    548:
                    549:        return false;
                    550: }
                    551:
1.1       dholland  552: /*
                    553:  * Get from a CDROM distribution.
                    554:  * Also used on "installation using bootable install media"
                    555:  * as the default option in the "distmedium" menu.
                    556:  */
                    557: int
                    558: get_via_cdrom(void)
                    559: {
                    560:        menu_ent cd_menu[MAX_CD_INFOS];
                    561:        struct stat sb;
1.6       martin    562:        int rv, num_cds, menu_cd, i, selected_cd = 0;
1.1       dholland  563:        bool silent = false;
                    564:        int mib[2];
                    565:        char rootdev[SSTRSIZE] = "";
                    566:        size_t varlen;
                    567:
                    568:        /* If root is not md(4) and we have set dir, skip this step. */
                    569:        mib[0] = CTL_KERN;
                    570:        mib[1] = KERN_ROOT_DEVICE;
                    571:        varlen = sizeof(rootdev);
                    572:        (void)sysctl(mib, 2, rootdev, &varlen, NULL, 0);
                    573:        if (stat(set_dir_bin, &sb) == 0 && S_ISDIR(sb.st_mode) &&
                    574:            strncmp("md", rootdev, 2) != 0) {
                    575:                strlcpy(ext_dir_bin, set_dir_bin, sizeof ext_dir_bin);
                    576:                strlcpy(ext_dir_src, set_dir_src, sizeof ext_dir_src);
                    577:                return SET_OK;
                    578:        }
                    579:
1.25      christos  580:        memset(cd_menu, 0, sizeof(cd_menu));
1.1       dholland  581:        num_cds = get_available_cds();
                    582:        if (num_cds <= 0) {
                    583:                silent = true;
                    584:        } else if (num_cds == 1) {
                    585:                /* single CD found, check for sets on it */
                    586:                strcpy(cdrom_dev, cds[0].device_name);
                    587:                if (cd_has_sets())
                    588:                        return SET_OK;
                    589:        } else {
                    590:                for (i = 0; i< num_cds; i++) {
                    591:                        cd_menu[i].opt_name = cds[i].menu;
                    592:                        cd_menu[i].opt_flags = OPT_EXIT;
1.2       martin    593:                        cd_menu[i].opt_action = set_menu_select;
1.1       dholland  594:                }
                    595:                /* create a menu offering available choices */
                    596:                menu_cd = new_menu(MSG_Available_cds,
                    597:                        cd_menu, num_cds, -1, 4, 0, 0,
                    598:                        MC_SCROLL | MC_NOEXITOPT,
                    599:                        NULL, NULL, NULL, NULL, NULL);
                    600:                if (menu_cd == -1)
                    601:                        return SET_RETRY;
                    602:                msg_display(MSG_ask_cd);
                    603:                process_menu(menu_cd, &selected_cd);
                    604:                free_menu(menu_cd);
                    605:                strcpy(cdrom_dev, cds[selected_cd].device_name);
                    606:                if (cd_has_sets())
                    607:                        return SET_OK;
                    608:        }
                    609:
                    610:        if (silent)
                    611:                msg_display("");
                    612:        else {
                    613:                umount_mnt2();
1.22      martin    614:                hit_enter_to_continue(MSG_cd_path_not_found, NULL);
1.1       dholland  615:        }
                    616:
                    617:        /* ask for paths on the CD */
1.6       martin    618:        rv = -1;
                    619:        process_menu(MENU_cdromsource, &rv);
                    620:        if (rv == SET_RETRY)
1.2       martin    621:                return SET_RETRY;
1.1       dholland  622:
                    623:        if (cd_has_sets())
                    624:                return SET_OK;
                    625:
                    626:        return SET_RETRY;
                    627: }
                    628:
                    629:
                    630: /*
                    631:  * Get from a pathname inside an unmounted local filesystem
                    632:  * (e.g., where sets were preloaded onto a local DOS partition)
                    633:  */
                    634: int
                    635: get_via_localfs(void)
                    636: {
1.6       martin    637:        int rv = -1;
                    638:
1.1       dholland  639:        /* Get device, filesystem, and filepath */
1.6       martin    640:        process_menu (MENU_localfssource, &rv);
                    641:        if (rv == SET_RETRY)
1.2       martin    642:                return SET_RETRY;
1.1       dholland  643:
                    644:        /* Mount it */
                    645:        if (run_program(0, "/sbin/mount -rt %s /dev/%s /mnt2",
                    646:            localfs_fs, localfs_dev))
                    647:                return SET_RETRY;
                    648:
                    649:        mnt2_mounted = 1;
                    650:
                    651:        snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s/%s",
                    652:                "/mnt2", localfs_dir, set_dir_bin);
                    653:        snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s/%s",
                    654:                "/mnt2", localfs_dir, set_dir_src);
                    655:
                    656:        return SET_OK;
                    657: }
                    658:
                    659: /*
                    660:  * Get from an already-mounted pathname.
                    661:  */
                    662:
                    663: int
                    664: get_via_localdir(void)
                    665: {
1.6       martin    666:        int rv = -1;
                    667:
1.1       dholland  668:        /* Get filepath */
1.6       martin    669:        process_menu(MENU_localdirsource, &rv);
                    670:        if (rv == SET_RETRY)
1.2       martin    671:                return SET_RETRY;
1.1       dholland  672:
                    673:        /*
                    674:         * We have to have an absolute path ('cos pax runs in a
                    675:         * different directory), make it so.
                    676:         */
                    677:        snprintf(ext_dir_bin, sizeof ext_dir_bin, "/%s/%s", localfs_dir, set_dir_bin);
                    678:        snprintf(ext_dir_src, sizeof ext_dir_src, "/%s/%s", localfs_dir, set_dir_src);
                    679:
                    680:        return SET_OK;
                    681: }
                    682:
                    683:
                    684: /*
                    685:  * Support for custom distribution fetches / unpacks.
                    686:  */
                    687:
                    688: unsigned int
                    689: set_X11_selected(void)
                    690: {
                    691:        int i;
                    692:
                    693:        for (i = SET_X11_FIRST; ++i < SET_X11_LAST;)
                    694:                if (set_status[i] & SET_SELECTED)
                    695:                        return 1;
                    696:        return 0;
                    697: }
                    698:
                    699: unsigned int
                    700: get_kernel_set(void)
                    701: {
                    702:        int i;
                    703:
                    704:        for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;)
                    705:                if (set_status[i] & SET_SELECTED)
                    706:                        return i;
                    707:        return SET_NONE;
                    708: }
                    709:
                    710: void
                    711: set_kernel_set(unsigned int kernel_set)
                    712: {
                    713:        int i;
                    714:
                    715:        /* only one kernel set is allowed */
                    716:        for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;)
                    717:                set_status[i] &= ~SET_SELECTED;
                    718:        set_status[kernel_set] |= SET_SELECTED;
                    719: }
                    720:
                    721: static int
                    722: set_toggle(menudesc *menu, void *arg)
                    723: {
                    724:        distinfo **distp = arg;
                    725:        int set = distp[menu->cursel]->set;
                    726:
                    727:        if (set > SET_KERNEL_FIRST && set < SET_KERNEL_LAST &&
                    728:            !(set_status[set] & SET_SELECTED))
                    729:                set_kernel_set(set);
                    730:        else
                    731:                set_status[set] ^= SET_SELECTED;
                    732:        return 0;
                    733: }
                    734:
                    735: static int
                    736: set_all_none(menudesc *menu, void *arg, int set, int clr)
                    737: {
                    738:        distinfo **distp = arg;
                    739:        distinfo *dist = *distp;
                    740:        int nested;
                    741:
                    742:        for (nested = 0; dist->set != SET_GROUP_END || nested--; dist++) {
                    743:                if (dist->set == SET_GROUP) {
                    744:                        nested++;
                    745:                        continue;
                    746:                }
                    747:                set_status[dist->set] = (set_status[dist->set] & ~clr) | set;
                    748:        }
                    749:        return 0;
                    750: }
                    751:
                    752: static int
                    753: set_all(menudesc *menu, void *arg)
                    754: {
                    755:        return set_all_none(menu, arg, SET_SELECTED, 0);
                    756: }
                    757:
                    758: static int
                    759: set_none(menudesc *menu, void *arg)
                    760: {
                    761:        return set_all_none(menu, arg, 0, SET_SELECTED);
                    762: }
                    763:
                    764: static void
                    765: set_label(menudesc *menu, int opt, void *arg)
                    766: {
                    767:        distinfo **distp = arg;
                    768:        distinfo *dist = distp[opt];
                    769:        const char *selected;
                    770:        const char *desc;
                    771:        int nested;
                    772:
                    773:        desc = dist->desc;
                    774:
                    775:        if (dist->set != SET_GROUP)
                    776:                selected = set_status[dist->set] & SET_SELECTED ? msg_yes : msg_no;
                    777:        else {
                    778:                /* sub menu - display None/Some/All */
                    779:                nested = 0;
                    780:                selected = "unknown";
                    781:                while ((++dist)->set != SET_GROUP_END || nested--) {
                    782:                        if (dist->set == SET_GROUP) {
                    783:                                nested++;
                    784:                                continue;
                    785:                        }
                    786:                        if (!(set_status[dist->set] & SET_VALID))
                    787:                                continue;
                    788:                        if (set_status[dist->set] & SET_SELECTED) {
                    789:                                if (selected == msg_none) {
                    790:                                        selected = msg_some;
                    791:                                        break;
                    792:                                }
                    793:                                selected = msg_all;
                    794:                        } else {
                    795:                                if (selected == msg_all) {
                    796:                                        selected = msg_some;
                    797:                                        break;
                    798:                                }
                    799:                                selected = msg_none;
                    800:                        }
                    801:                }
                    802:        }
                    803:
1.22      martin    804:        wprintw(menu->mw, "%-30s %s", msg_string(desc), selected);
1.1       dholland  805: }
                    806:
                    807: static int set_sublist(menudesc *menu, void *arg);
                    808:
                    809: static int
                    810: initialise_set_menu(distinfo *dist, menu_ent *me, distinfo **de, int all_none)
                    811: {
                    812:        int set;
                    813:        int sets;
                    814:        int nested;
                    815:
                    816:        for (sets = 0; ; dist++) {
                    817:                set = dist->set;
                    818:                if (set == SET_LAST || set == SET_GROUP_END)
                    819:                        break;
                    820:                if (!(set_status[set] & SET_VALID))
                    821:                        continue;
                    822:                *de = dist;
1.25      christos  823:                memset(me, 0, sizeof(*me));
1.1       dholland  824:                if (set != SET_GROUP)
                    825:                        me->opt_action = set_toggle;
                    826:                else {
                    827:                        /* Collapse sublist */
                    828:                        nested = 0;
                    829:                        while ((++dist)->set != SET_GROUP_END || nested--) {
                    830:                                if (dist->set == SET_GROUP)
                    831:                                        nested++;
                    832:                        }
                    833:                        me->opt_action = set_sublist;
                    834:                }
                    835:                sets++;
                    836:                de++;
                    837:                me++;
                    838:        }
                    839:
                    840:        if (all_none) {
                    841:                me->opt_name = MSG_select_all;
                    842:                me->opt_action = set_all;
                    843:                me++;
                    844:                me->opt_name = MSG_select_none;
                    845:                me->opt_action = set_none;
                    846:                sets += 2;
                    847:        }
                    848:
                    849:        return sets;
                    850: }
                    851:
                    852: static int
                    853: set_sublist(menudesc *menu, void *arg)
                    854: {
                    855:        distinfo *de[SET_LAST];
                    856:        menu_ent me[SET_LAST];
                    857:        distinfo **dist = arg;
                    858:        int menu_no;
                    859:        int sets;
                    860:
1.25      christos  861:        memset(me, 0, sizeof(me));
1.1       dholland  862:        sets = initialise_set_menu(dist[menu->cursel] + 1, me, de, 1);
                    863:
                    864:        menu_no = new_menu(NULL, me, sets, 20, 10, 0, select_menu_width,
                    865:                MC_SUBMENU | MC_SCROLL | MC_DFLTEXIT,
                    866:                NULL, set_label, NULL, NULL,
                    867:                MSG_install_selected_sets);
                    868:
                    869:        process_menu(menu_no, de);
                    870:        free_menu(menu_no);
                    871:
                    872:        return 0;
                    873: }
                    874:
                    875: void
                    876: customise_sets(void)
                    877: {
                    878:        distinfo *de[SET_LAST];
                    879:        menu_ent me[SET_LAST];
                    880:        int sets;
                    881:        int menu_no;
                    882:
                    883:        msg_display(MSG_cur_distsets);
                    884:        msg_table_add(MSG_cur_distsets_header);
                    885:
1.25      christos  886:        memset(me, 0, sizeof(me));
1.1       dholland  887:        sets = initialise_set_menu(dist_list, me, de, 0);
                    888:
                    889:        menu_no = new_menu(NULL, me, sets, 0, 5, 0, select_menu_width,
                    890:                MC_SCROLL | MC_NOBOX | MC_DFLTEXIT | MC_NOCLEAR,
                    891:                NULL, set_label, NULL, NULL,
                    892:                MSG_install_selected_sets);
                    893:
                    894:        process_menu(menu_no, de);
                    895:        free_menu(menu_no);
                    896: }
                    897:
                    898: /*
                    899:  * Extract_file **REQUIRES** an absolute path in ext_dir.  Any code
                    900:  * that sets up xfer_dir for use by extract_file needs to put in the
                    901:  * full path name to the directory.
                    902:  */
                    903:
                    904: int
                    905: extract_file(distinfo *dist, int update)
                    906: {
                    907:        char path[STRSIZE];
                    908:        char *owd;
                    909:        int   rval;
                    910:
                    911:        /* If we might need to tidy up, ensure directory exists */
                    912:        if (fetch_fn != NULL)
                    913:                make_target_dir(xfer_dir);
                    914:
                    915:        (void)snprintf(path, sizeof path, "%s/%s%s",
1.12      martin    916:            ext_dir_for_set(dist->name), dist->name, set_postfix(dist->name));
1.1       dholland  917:
                    918:        owd = getcwd(NULL, 0);
                    919:
                    920:        /* Do we need to fetch the file now? */
                    921:        if (fetch_fn != NULL) {
                    922:                rval = fetch_fn(dist->name);
                    923:                if (rval != SET_OK)
                    924:                        return rval;
                    925:        }
                    926:
                    927:        /* check tarfile exists */
                    928:        if (!file_exists_p(path)) {
                    929:
                    930: #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
1.29.2.1  msaitoh   931:                /*
                    932:                 * Update path to use dist->name truncated to the first eight
                    933:                 * characters and check again
                    934:                 */
                    935:                (void)snprintf(path, sizeof path,
                    936:                    "%s/%.8s%.4s", /* 4 as includes '.' */
                    937:                    ext_dir_for_set(dist->name), dist->name,
                    938:                    set_postfix(dist->name));
                    939:
1.1       dholland  940:                if (!file_exists_p(path)) {
                    941: #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
1.29.2.1  msaitoh   942:                        tarstats.nnotfound++;
1.1       dholland  943:
1.29.2.1  msaitoh   944:                        char *err = str_arg_subst(msg_string(MSG_notarfile),
                    945:                            1, &dist->name);
                    946:                        hit_enter_to_continue(err, NULL);
                    947:                        free(err);
1.29.2.2  msaitoh   948:                        free(owd);
1.29.2.1  msaitoh   949:                        return SET_RETRY;
                    950:                }
1.1       dholland  951: #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
                    952:        }
                    953: #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
                    954:
                    955:        tarstats.nfound++;
                    956:        /* cd to the target root. */
                    957:        if (update && (dist->set == SET_ETC || dist->set == SET_X11_ETC)) {
                    958:                make_target_dir("/.sysinst");
                    959:                target_chdir_or_die("/.sysinst");
                    960:        } else if (dist->set == SET_PKGSRC)
                    961:                target_chdir_or_die("/usr");
                    962:        else
                    963:                target_chdir_or_die("/");
                    964:
                    965:        /*
                    966:         * /usr/X11R7/lib/X11/xkb/symbols/pc was a directory in 5.0
                    967:         * but is a file in 5.1 and beyond, so on upgrades we need to
                    968:         * delete it before extracting the xbase set.
                    969:         */
                    970:        if (update && dist->set == SET_X11_BASE)
                    971:                run_program(0, "rm -rf usr/X11R7/lib/X11/xkb/symbols/pc");
                    972:
                    973:        /* now extract set files into "./". */
                    974:        rval = run_program(RUN_DISPLAY | RUN_PROGRESS,
1.29.2.5! msaitoh   975:                        "progress -zf %s tar --chroot "
        !           976:                        TAR_EXTRACT_FLAGS " -", path);
1.1       dholland  977:
                    978:        chdir(owd);
                    979:        free(owd);
                    980:
                    981:        /* Check rval for errors and give warning. */
                    982:        if (rval != 0) {
                    983:                tarstats.nerror++;
1.24      christos  984:                msg_fmt_display(MSG_tarerror, "%s", path);
1.22      martin    985:                hit_enter_to_continue(NULL, NULL);
1.1       dholland  986:                return SET_RETRY;
                    987:        }
                    988:
                    989:        if (fetch_fn != NULL && clean_xfer_dir) {
                    990:                run_program(0, "rm %s", path);
                    991:                /* Plausibly we should unlink an empty xfer_dir as well */
                    992:        }
                    993:
                    994:        set_status[dist->set] |= SET_INSTALLED;
                    995:        tarstats.nsuccess++;
                    996:        return SET_OK;
                    997: }
                    998:
                    999: static void
                   1000: skip_set(distinfo *dist, int skip_type)
                   1001: {
                   1002:        int nested;
                   1003:        int set;
                   1004:
                   1005:        nested = 0;
                   1006:        while ((++dist)->set != SET_GROUP_END || nested--) {
                   1007:                set = dist->set;
                   1008:                if (set == SET_GROUP) {
                   1009:                        nested++;
                   1010:                        continue;
                   1011:                }
                   1012:                if (set == SET_LAST)
                   1013:                        break;
                   1014:                if (set_status[set] == (SET_SELECTED | SET_VALID))
                   1015:                        set_status[set] |= SET_SKIPPED;
                   1016:                tarstats.nskipped++;
                   1017:        }
                   1018: }
                   1019:
                   1020: /*
                   1021:  * Get and unpack the distribution.
                   1022:  * Show success_msg if installation completes.
                   1023:  * Otherwise show failure_msg and wait for the user to ack it before continuing.
                   1024:  * success_msg and failure_msg must both be 0-adic messages.
                   1025:  */
                   1026: int
                   1027: get_and_unpack_sets(int update, msg setupdone_msg, msg success_msg, msg failure_msg)
                   1028: {
                   1029:        distinfo *dist;
                   1030:        int status;
                   1031:        int set;
                   1032:
                   1033:        /* Ensure mountpoint for distribution files exists in current root. */
                   1034:        (void)mkdir("/mnt2", S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
                   1035:        if (script)
                   1036:                (void)fprintf(script, "mkdir -m 755 /mnt2\n");
                   1037:
                   1038:        /* reset failure/success counters */
                   1039:        memset(&tarstats, 0, sizeof(tarstats));
                   1040:
                   1041:        /* Find out which files to "get" if we get files. */
                   1042:
                   1043:        /* Accurately count selected sets */
                   1044:        for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
1.11      christos 1045:                if (dist->name == NULL)
                   1046:                        continue;
1.1       dholland 1047:                if ((set_status[set] & (SET_VALID | SET_SELECTED))
                   1048:                    == (SET_VALID | SET_SELECTED))
                   1049:                        tarstats.nselected++;
                   1050:        }
                   1051:
                   1052:        status = SET_RETRY;
1.11      christos 1053:        for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
1.1       dholland 1054:                if (dist->name == NULL)
                   1055:                        continue;
                   1056:                if (set_status[set] != (SET_VALID | SET_SELECTED))
                   1057:                        continue;
                   1058:
                   1059:                if (status != SET_OK) {
                   1060:                        /* This might force a redraw.... */
                   1061:                        clearok(curscr, 1);
                   1062:                        touchwin(stdscr);
                   1063:                        wrefresh(stdscr);
                   1064:                        /* Sort out the location of the set files */
                   1065:                        do {
                   1066:                                umount_mnt2();
1.24      christos 1067:                                msg_fmt_display(MSG_distmedium, "%d%d%s",
                   1068:                                    tarstats.nselected,
1.1       dholland 1069:                                    tarstats.nsuccess + tarstats.nskipped,
                   1070:                                    dist->name);
                   1071:                                fetch_fn = NULL;
                   1072:                                process_menu(MENU_distmedium, &status);
                   1073:                        } while (status == SET_RETRY);
                   1074:
                   1075:                        if (status == SET_SKIP) {
                   1076:                                set_status[set] |= SET_SKIPPED;
                   1077:                                tarstats.nskipped++;
                   1078:                                continue;
                   1079:                        }
                   1080:                        if (status == SET_SKIP_GROUP) {
                   1081:                                skip_set(dist, status);
                   1082:                                continue;
                   1083:                        }
                   1084:                        if (status != SET_OK) {
1.22      martin   1085:                                hit_enter_to_continue(failure_msg, NULL);
1.1       dholland 1086:                                return 1;
                   1087:                        }
                   1088:                }
                   1089:
                   1090:                /* Try to extract this set */
                   1091:                status = extract_file(dist, update);
                   1092:                if (status == SET_RETRY)
                   1093:                        dist--;
                   1094:        }
                   1095:
                   1096:        if (tarstats.nerror == 0 && tarstats.nsuccess == tarstats.nselected) {
                   1097:                msg_display(MSG_endtarok);
                   1098:                /* Give user a chance to see the success message */
                   1099:                sleep(1);
                   1100:        } else {
                   1101:                /* We encountered errors. Let the user know. */
1.24      christos 1102:                msg_fmt_display(MSG_endtar, "%d%d%d%d%d%d",
1.1       dholland 1103:                    tarstats.nselected, tarstats.nnotfound, tarstats.nskipped,
                   1104:                    tarstats.nfound, tarstats.nsuccess, tarstats.nerror);
1.22      martin   1105:                hit_enter_to_continue(NULL, NULL);
1.1       dholland 1106:        }
                   1107:
                   1108:        /*
                   1109:         * postinstall needs to be run after extracting all sets, because
                   1110:         * otherwise /var/db/obsolete will only have current information
                   1111:         * from the base, comp, and etc sets.
                   1112:         */
                   1113:        if (update && (set_status[SET_ETC] & SET_INSTALLED)) {
                   1114:                int oldsendmail;
                   1115:                oldsendmail = run_program(RUN_DISPLAY | RUN_CHROOT |
                   1116:                                          RUN_ERROR_OK | RUN_PROGRESS,
                   1117:                                          "/usr/sbin/postinstall -s /.sysinst -d / check mailerconf");
                   1118:                if (oldsendmail == 1) {
                   1119:                        msg_display(MSG_oldsendmail);
1.6       martin   1120:                        if (ask_yesno(NULL)) {
1.1       dholland 1121:                                run_program(RUN_DISPLAY | RUN_CHROOT,
                   1122:                                            "/usr/sbin/postinstall -s /.sysinst -d / fix mailerconf");
                   1123:                        }
                   1124:                }
                   1125:                run_program(RUN_DISPLAY | RUN_CHROOT,
                   1126:                        "/usr/sbin/postinstall -s /.sysinst -d / fix");
1.3       tls      1127:
                   1128:                /* Don't discard the system's old entropy if any */
                   1129:                run_program(RUN_CHROOT | RUN_SILENT,
                   1130:                            "/etc/rc.d/random_seed start");
1.1       dholland 1131:        }
                   1132:
                   1133:        /* Configure the system */
                   1134:        if (set_status[SET_BASE] & SET_INSTALLED)
                   1135:                run_makedev();
                   1136:
                   1137:        if (!update) {
1.3       tls      1138:                struct stat sb1, sb2;
                   1139:
1.4       martin   1140:                if (stat(target_expand("/"), &sb1) == 0
                   1141:                    && stat(target_expand("/var"), &sb2) == 0
                   1142:                    && sb1.st_dev != sb2.st_dev) {
1.3       tls      1143:                        add_rc_conf("random_file=/etc/entropy-file\n");
                   1144:                        if (target_file_exists_p("/boot.cfg")) {
                   1145:                                run_program(RUN_CHROOT|RUN_FATAL,
                   1146:                                            "sh -c 'sed -e s./var/db/./etc/. "
                   1147:                                            "< /boot.cfg "
                   1148:                                            "> /tmp/boot.cfg.tmp'");
                   1149:                                mv_within_target_or_die("/tmp/boot.cfg.tmp",
                   1150:                                                        "/boot.cfg");
1.29.2.5! msaitoh  1151:
1.3       tls      1152:                        }
                   1153:                }
                   1154:
1.29.2.5! msaitoh  1155: #ifdef MD_BOOT_CFG_FINALIZE
        !          1156:                if (target_file_exists_p("/boot.cfg")) {
        !          1157:                        MD_BOOT_CFG_FINALIZE("/boot.cfg");
        !          1158:                }
        !          1159: #endif
        !          1160:
1.3       tls      1161:                /* Save keyboard type */
1.1       dholland 1162:                save_kb_encoding();
                   1163:
                   1164:                /* Other configuration. */
                   1165:                mnt_net_config();
                   1166:        }
                   1167:
                   1168:        /* Mounted dist dir? */
                   1169:        umount_mnt2();
                   1170:
1.3       tls      1171:        /* Save entropy -- on some systems it's ~all we'll ever get */
                   1172:        run_program(RUN_DISPLAY | RUN_CHROOT | RUN_FATAL | RUN_PROGRESS,
                   1173:                    "/etc/rc.d/random_seed stop");
1.1       dholland 1174:        /* Install/Upgrade complete ... reboot or exit to script */
1.22      martin   1175:        hit_enter_to_continue(success_msg, NULL);
1.1       dholland 1176:        return 0;
                   1177: }
                   1178:
                   1179: void
                   1180: umount_mnt2(void)
                   1181: {
                   1182:        if (!mnt2_mounted)
                   1183:                return;
                   1184:        run_program(RUN_SILENT, "/sbin/umount /mnt2");
                   1185:        mnt2_mounted = 0;
                   1186: }
                   1187:
                   1188:
                   1189: /*
                   1190:  * Do a quick sanity check that  the target can reboot.
                   1191:  * return 1 if everything OK, 0 if there is a problem.
                   1192:  * Uses a table of files we expect to find after a base install/upgrade.
                   1193:  */
                   1194:
                   1195: /* test flag and pathname to check for after unpacking. */
                   1196: struct check_table { unsigned int mode; const char *path;} checks[] = {
                   1197:   { S_IFREG, "/netbsd" },
                   1198:   { S_IFDIR, "/etc" },
                   1199:   { S_IFREG, "/etc/fstab" },
                   1200:   { S_IFREG, "/sbin/init" },
                   1201:   { S_IFREG, "/bin/sh" },
                   1202:   { S_IFREG, "/etc/rc" },
                   1203:   { S_IFREG, "/etc/rc.subr" },
                   1204:   { S_IFREG, "/etc/rc.conf" },
                   1205:   { S_IFDIR, "/dev" },
                   1206:   { S_IFCHR, "/dev/console" },
                   1207: /* XXX check for rootdev in target /dev? */
                   1208:   { S_IFREG, "/sbin/fsck" },
                   1209:   { S_IFREG, "/sbin/fsck_ffs" },
                   1210:   { S_IFREG, "/sbin/mount" },
                   1211:   { S_IFREG, "/sbin/mount_ffs" },
                   1212:   { S_IFREG, "/sbin/mount_nfs" },
                   1213: #if defined(DEBUG) || defined(DEBUG_CHECK)
                   1214:   { S_IFREG, "/foo/bar" },             /* bad entry to exercise warning */
                   1215: #endif
                   1216:   { 0, 0 }
                   1217:
                   1218: };
                   1219:
                   1220: /*
                   1221:  * Check target for a single file.
                   1222:  */
                   1223: static int
                   1224: check_for(unsigned int mode, const char *pathname)
                   1225: {
                   1226:        int found;
                   1227:
                   1228:        found = (target_test(mode, pathname) == 0);
                   1229:        if (found == 0)
1.24      christos 1230:                msg_fmt_display(MSG_rootmissing, "%s", pathname);
1.1       dholland 1231:        return found;
                   1232: }
                   1233:
                   1234: /*
                   1235:  * Check that all the files in check_table are present in the
                   1236:  * target root. Warn if not found.
                   1237:  */
                   1238: int
                   1239: sanity_check(void)
                   1240: {
                   1241:        int target_ok = 1;
                   1242:        struct check_table *p;
                   1243:
                   1244:        for (p = checks; p->path; p++) {
                   1245:                target_ok = target_ok && check_for(p->mode, p->path);
                   1246:        }
                   1247:        if (target_ok)
                   1248:                return 0;
                   1249:
                   1250:        /* Uh, oh. Something's missing. */
1.22      martin   1251:        hit_enter_to_continue(MSG_badroot, NULL);
1.1       dholland 1252:        return 1;
                   1253: }
                   1254:
                   1255: /*
                   1256:  * Some globals to pass things back from callbacks
                   1257:  */
                   1258: static char zoneinfo_dir[STRSIZE];
                   1259: static int zonerootlen;
                   1260: static char *tz_selected;      /* timezonename (relative to share/zoneinfo */
                   1261: const char *tz_default;                /* UTC, or whatever /etc/localtime points to */
                   1262: static char tz_env[STRSIZE];
                   1263: static int save_cursel, save_topline;
                   1264:
                   1265: /*
                   1266:  * Callback from timezone menu
                   1267:  */
                   1268: static int
                   1269: set_tz_select(menudesc *m, void *arg)
                   1270: {
                   1271:        time_t t;
                   1272:        char *new;
1.5       christos 1273:        struct tm *tm;
1.1       dholland 1274:
                   1275:        if (m && strcmp(tz_selected, m->opts[m->cursel].opt_name) != 0) {
                   1276:                /* Change the displayed timezone */
                   1277:                new = strdup(m->opts[m->cursel].opt_name);
                   1278:                if (new == NULL)
                   1279:                        return 0;
                   1280:                free(tz_selected);
                   1281:                tz_selected = new;
                   1282:                snprintf(tz_env, sizeof tz_env, "%.*s%s",
                   1283:                         zonerootlen, zoneinfo_dir, tz_selected);
                   1284:                setenv("TZ", tz_env, 1);
                   1285:        }
                   1286:        if (m)
                   1287:                /* Warp curser to 'Exit' line on menu */
                   1288:                m->cursel = -1;
                   1289:
                   1290:        /* Update displayed time */
                   1291:        t = time(NULL);
1.5       christos 1292:        tm = localtime(&t);
1.24      christos 1293:        msg_fmt_display(MSG_choose_timezone, "%s%s%s%s",
1.5       christos 1294:                    tz_default, tz_selected, safectime(&t), tm ? tm->tm_zone :
                   1295:                    "?");
1.1       dholland 1296:        return 0;
                   1297: }
                   1298:
                   1299: static int
                   1300: set_tz_back(menudesc *m, void *arg)
                   1301: {
                   1302:
                   1303:        zoneinfo_dir[zonerootlen] = 0;
                   1304:        m->cursel = save_cursel;
                   1305:        m->topline = save_topline;
                   1306:        return 0;
                   1307: }
                   1308:
                   1309: static int
                   1310: set_tz_dir(menudesc *m, void *arg)
                   1311: {
                   1312:
                   1313:        strlcpy(zoneinfo_dir + zonerootlen, m->opts[m->cursel].opt_name,
                   1314:                sizeof zoneinfo_dir - zonerootlen);
                   1315:        save_cursel = m->cursel;
                   1316:        save_topline = m->topline;
                   1317:        m->cursel = 0;
                   1318:        m->topline = 0;
                   1319:        return 0;
                   1320: }
                   1321:
                   1322: /*
                   1323:  * Alarm-handler to update example-display
                   1324:  */
                   1325: static void
                   1326: /*ARGSUSED*/
                   1327: timezone_sig(int sig)
                   1328: {
                   1329:
                   1330:        set_tz_select(NULL, NULL);
                   1331:        alarm(60);
                   1332: }
                   1333:
                   1334: static int
                   1335: tz_sort(const void *a, const void *b)
                   1336: {
                   1337:        return strcmp(((const menu_ent *)a)->opt_name, ((const menu_ent *)b)->opt_name);
                   1338: }
                   1339:
                   1340: static void
                   1341: tzm_set_names(menudesc *m, void *arg)
                   1342: {
                   1343:        DIR *dir;
                   1344:        struct dirent *dp;
                   1345:        static int nfiles;
                   1346:        static int maxfiles = 32;
                   1347:        static menu_ent *tz_menu;
                   1348:        static char **tz_names;
                   1349:        void *p;
                   1350:        int maxfname;
                   1351:        char *fp;
                   1352:        struct stat sb;
                   1353:
                   1354:        if (tz_menu == NULL)
1.25      christos 1355:                tz_menu = calloc(maxfiles, sizeof *tz_menu);
1.1       dholland 1356:        if (tz_names == NULL)
                   1357:                tz_names = malloc(maxfiles * sizeof *tz_names);
                   1358:        if (tz_menu == NULL || tz_names == NULL)
                   1359:                return; /* error - skip timezone setting */
                   1360:        while (nfiles > 0)
                   1361:                free(tz_names[--nfiles]);
                   1362:
                   1363:        dir = opendir(zoneinfo_dir);
                   1364:        fp = strchr(zoneinfo_dir, 0);
                   1365:        if (fp != zoneinfo_dir + zonerootlen) {
                   1366:                tz_names[0] = 0;
                   1367:                tz_menu[0].opt_name = msg_string(MSG_tz_back);
                   1368:                tz_menu[0].opt_action = set_tz_back;
                   1369:                nfiles = 1;
                   1370:        }
                   1371:        maxfname = zoneinfo_dir + sizeof zoneinfo_dir - fp - 1;
                   1372:        if (dir != NULL) {
                   1373:                while ((dp = readdir(dir)) != NULL) {
                   1374:                        if (dp->d_namlen > maxfname || dp->d_name[0] == '.')
                   1375:                                continue;
                   1376:                        strlcpy(fp, dp->d_name, maxfname);
                   1377:                        if (stat(zoneinfo_dir, &sb) == -1)
                   1378:                                continue;
                   1379:                        if (nfiles >= maxfiles) {
1.26      martin   1380:                                p = realloc(tz_menu,
                   1381:                                    2 * maxfiles * sizeof *tz_menu);
1.1       dholland 1382:                                if (p == NULL)
                   1383:                                        break;
                   1384:                                tz_menu = p;
1.26      martin   1385:                                memset(tz_menu + maxfiles, 0,
                   1386:                                    maxfiles * sizeof *tz_menu);
                   1387:                                p = realloc(tz_names,
                   1388:                                    2 * maxfiles * sizeof *tz_names);
1.1       dholland 1389:                                if (p == NULL)
                   1390:                                        break;
                   1391:                                tz_names = p;
1.26      martin   1392:                                memset(tz_names + maxfiles, 0,
                   1393:                                    maxfiles * sizeof *tz_names);
1.1       dholland 1394:                                maxfiles *= 2;
                   1395:                        }
                   1396:                        if (S_ISREG(sb.st_mode))
                   1397:                                tz_menu[nfiles].opt_action = set_tz_select;
                   1398:                        else if (S_ISDIR(sb.st_mode)) {
                   1399:                                tz_menu[nfiles].opt_action = set_tz_dir;
                   1400:                                strlcat(fp, "/",
                   1401:                                    sizeof(zoneinfo_dir) - (fp - zoneinfo_dir));
                   1402:                        } else
                   1403:                                continue;
                   1404:                        tz_names[nfiles] = strdup(zoneinfo_dir + zonerootlen);
                   1405:                        tz_menu[nfiles].opt_name = tz_names[nfiles];
                   1406:                        nfiles++;
                   1407:                }
                   1408:                closedir(dir);
                   1409:        }
                   1410:        *fp = 0;
                   1411:
                   1412:        m->opts = tz_menu;
                   1413:        m->numopts = nfiles;
                   1414:        qsort(tz_menu, nfiles, sizeof *tz_menu, tz_sort);
                   1415: }
                   1416:
                   1417: void
                   1418: get_tz_default(void)
                   1419: {
                   1420:        char localtime_link[STRSIZE];
                   1421:        static char localtime_target[STRSIZE];
                   1422:        int rc;
                   1423:
                   1424:        strlcpy(localtime_link, target_expand("/etc/localtime"),
                   1425:            sizeof localtime_link);
                   1426:
                   1427:        /* Add sanity check that /mnt/usr/share/zoneinfo contains
                   1428:         * something useful
                   1429:         */
                   1430:
                   1431:        rc = readlink(localtime_link, localtime_target,
                   1432:                      sizeof(localtime_target) - 1);
                   1433:        if (rc < 0) {
                   1434:                /* error, default to UTC */
                   1435:                tz_default = "UTC";
                   1436:        } else {
                   1437:                localtime_target[rc] = '\0';
                   1438:                tz_default = strchr(strstr(localtime_target, "zoneinfo"), '/') + 1;
                   1439:        }
                   1440: }
                   1441:
                   1442: /*
                   1443:  * Choose from the files in usr/share/zoneinfo and set etc/localtime
                   1444:  */
                   1445: int
                   1446: set_timezone(void)
                   1447: {
                   1448:        char localtime_link[STRSIZE];
                   1449:        char localtime_target[STRSIZE];
                   1450:        time_t t;
1.5       christos 1451:        struct tm *tm;
1.1       dholland 1452:        int menu_no;
                   1453:
                   1454:        strlcpy(zoneinfo_dir, target_expand("/usr/share/zoneinfo/"),
                   1455:            sizeof zoneinfo_dir - 1);
                   1456:        zonerootlen = strlen(zoneinfo_dir);
                   1457:
                   1458:        get_tz_default();
                   1459:
                   1460:        tz_selected = strdup(tz_default);
                   1461:        snprintf(tz_env, sizeof(tz_env), "%s%s", zoneinfo_dir, tz_selected);
                   1462:        setenv("TZ", tz_env, 1);
                   1463:        t = time(NULL);
1.5       christos 1464:        tm = localtime(&t);
1.24      christos 1465:        msg_fmt_display(MSG_choose_timezone, "%s%s%s%s",
                   1466:            tz_default, tz_selected, safectime(&t), tm ? tm->tm_zone : "?");
1.1       dholland 1467:
                   1468:        signal(SIGALRM, timezone_sig);
                   1469:        alarm(60);
                   1470:
                   1471:        menu_no = new_menu(NULL, NULL, 14, 23, 9,
                   1472:                           12, 32, MC_ALWAYS_SCROLL | MC_NOSHORTCUT,
                   1473:                           tzm_set_names, NULL, NULL,
1.29.2.5! msaitoh  1474:                           "\nPlease consult the install documents.",
        !          1475:                           MSG_exit_menu_generic);
1.1       dholland 1476:        if (menu_no < 0)
                   1477:                goto done;      /* error - skip timezone setting */
                   1478:
                   1479:        process_menu(menu_no, NULL);
                   1480:
                   1481:        free_menu(menu_no);
                   1482:
                   1483:        signal(SIGALRM, SIG_IGN);
                   1484:
                   1485:        snprintf(localtime_target, sizeof(localtime_target),
                   1486:                 "/usr/share/zoneinfo/%s", tz_selected);
                   1487:        strlcpy(localtime_link, target_expand("/etc/localtime"),
                   1488:            sizeof localtime_link);
                   1489:        unlink(localtime_link);
                   1490:        symlink(localtime_target, localtime_link);
                   1491:
                   1492: done:
                   1493:        return 1;
                   1494: }
                   1495:
                   1496: void
                   1497: scripting_vfprintf(FILE *f, const char *fmt, va_list ap)
                   1498: {
1.28      martin   1499:        va_list ap2;
1.1       dholland 1500:
1.28      martin   1501:        va_copy(ap2, ap);
1.1       dholland 1502:        if (f)
                   1503:                (void)vfprintf(f, fmt, ap);
                   1504:        if (script)
1.28      martin   1505:                (void)vfprintf(script, fmt, ap2);
1.1       dholland 1506: }
                   1507:
                   1508: void
                   1509: scripting_fprintf(FILE *f, const char *fmt, ...)
                   1510: {
                   1511:        va_list ap;
                   1512:
                   1513:        va_start(ap, fmt);
                   1514:        scripting_vfprintf(f, fmt, ap);
                   1515:        va_end(ap);
                   1516: }
                   1517:
                   1518: void
                   1519: add_rc_conf(const char *fmt, ...)
                   1520: {
                   1521:        FILE *f;
                   1522:        va_list ap;
                   1523:
                   1524:        va_start(ap, fmt);
                   1525:        f = target_fopen("/etc/rc.conf", "a");
                   1526:        if (f != 0) {
                   1527:                scripting_fprintf(NULL, "cat <<EOF >>%s/etc/rc.conf\n",
                   1528:                    target_prefix());
                   1529:                scripting_vfprintf(f, fmt, ap);
                   1530:                fclose(f);
                   1531:                scripting_fprintf(NULL, "EOF\n");
                   1532:        }
                   1533:        va_end(ap);
                   1534: }
                   1535:
                   1536: int
                   1537: del_rc_conf(const char *value)
                   1538: {
                   1539:        FILE *fp, *nfp;
                   1540:        char buf[4096]; /* Ridiculously high, but should be enough in any way */
                   1541:        char *rcconf, *tempname = NULL, *bakname = NULL;
                   1542:        char *cp;
                   1543:        int done = 0;
                   1544:        int fd;
                   1545:        int retval = 0;
                   1546:
                   1547:        /* The paths might seem strange, but using /tmp would require copy instead
                   1548:         * of rename operations. */
                   1549:        if (asprintf(&rcconf, "%s", target_expand("/etc/rc.conf")) < 0
                   1550:                        || asprintf(&tempname, "%s", target_expand("/etc/rc.conf.tmp.XXXXXX")) < 0
                   1551:                        || asprintf(&bakname, "%s", target_expand("/etc/rc.conf.bak.XXXXXX")) < 0) {
                   1552:                if (rcconf)
                   1553:                        free(rcconf);
                   1554:                if (tempname)
                   1555:                        free(tempname);
1.24      christos 1556:                msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
1.22      martin   1557:                hit_enter_to_continue(NULL, NULL);
1.1       dholland 1558:                return -1;
                   1559:        }
                   1560:
                   1561:        if ((fd = mkstemp(bakname)) < 0) {
1.24      christos 1562:                msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
1.22      martin   1563:                hit_enter_to_continue(NULL, NULL);
1.1       dholland 1564:                return -1;
                   1565:        }
                   1566:        close(fd);
                   1567:
                   1568:        if (!(fp = fopen(rcconf, "r+")) || (fd = mkstemp(tempname)) < 0) {
                   1569:                if (fp)
                   1570:                        fclose(fp);
1.24      christos 1571:                msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
1.22      martin   1572:                hit_enter_to_continue(NULL, NULL);
1.1       dholland 1573:                return -1;
                   1574:        }
                   1575:
                   1576:        nfp = fdopen(fd, "w");
                   1577:        if (!nfp) {
                   1578:                fclose(fp);
                   1579:                close(fd);
1.24      christos 1580:                msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
1.22      martin   1581:                hit_enter_to_continue(NULL, NULL);
1.1       dholland 1582:                return -1;
                   1583:        }
                   1584:
                   1585:        while (fgets(buf, sizeof buf, fp) != NULL) {
                   1586:
                   1587:                cp = buf + strspn(buf, " \t"); /* Skip initial spaces */
                   1588:                if (strncmp(cp, value, strlen(value)) == 0) {
                   1589:                        cp += strlen(value);
                   1590:                        if (*cp != '=')
                   1591:                                scripting_fprintf(nfp, "%s", buf);
                   1592:                        else
                   1593:                                done = 1;
                   1594:                } else {
                   1595:                        scripting_fprintf(nfp, "%s", buf);
                   1596:                }
                   1597:        }
                   1598:        fclose(fp);
                   1599:        fclose(nfp);
                   1600:
                   1601:        if (done) {
                   1602:                if (rename(rcconf, bakname)) {
                   1603:                        msg_display(MSG_rcconf_backup_failed);
1.6       martin   1604:                        if (!ask_noyes(NULL)) {
1.1       dholland 1605:                                retval = -1;
                   1606:                                goto done;
                   1607:                        }
                   1608:                }
                   1609:
                   1610:                if (rename(tempname, rcconf)) {
                   1611:                        if (rename(bakname, rcconf)) {
1.22      martin   1612:                                hit_enter_to_continue(MSG_rcconf_restore_failed,
                   1613:                                    NULL);
1.1       dholland 1614:                        } else {
1.22      martin   1615:                                hit_enter_to_continue(MSG_rcconf_delete_failed,
                   1616:                                    NULL);
1.1       dholland 1617:                        }
                   1618:                } else {
                   1619:                        (void)unlink(bakname);
                   1620:                }
                   1621:        }
                   1622:
                   1623: done:
                   1624:        (void)unlink(tempname);
                   1625:        free(rcconf);
                   1626:        free(tempname);
                   1627:        free(bakname);
                   1628:        return retval;
                   1629: }
                   1630:
                   1631: void
                   1632: add_sysctl_conf(const char *fmt, ...)
                   1633: {
                   1634:        FILE *f;
                   1635:        va_list ap;
                   1636:
                   1637:        va_start(ap, fmt);
                   1638:        f = target_fopen("/etc/sysctl.conf", "a");
                   1639:        if (f != 0) {
                   1640:                scripting_fprintf(NULL, "cat <<EOF >>%s/etc/sysctl.conf\n",
                   1641:                    target_prefix());
                   1642:                scripting_vfprintf(f, fmt, ap);
                   1643:                fclose(f);
                   1644:                scripting_fprintf(NULL, "EOF\n");
                   1645:        }
                   1646:        va_end(ap);
                   1647: }
                   1648:
                   1649: void
                   1650: enable_rc_conf(void)
                   1651: {
                   1652:
                   1653:        replace("/etc/rc.conf", "s/^rc_configured=NO/rc_configured=YES/");
                   1654: }
                   1655:
                   1656: int
                   1657: check_lfs_progs(void)
                   1658: {
                   1659:
                   1660: #ifndef NO_LFS
1.2       martin   1661:        return binary_available("fsck_lfs") && binary_available("mount_lfs")
                   1662:            && binary_available("newfs_lfs");
1.1       dholland 1663: #else
                   1664:        return 0;
                   1665: #endif
                   1666: }
                   1667:
                   1668: int
                   1669: set_is_source(const char *set_name) {
                   1670:        int len = strlen(set_name);
                   1671:        return len >= 3 && memcmp(set_name + len - 3, "src", 3) == 0;
                   1672: }
                   1673:
                   1674: const char *
                   1675: set_dir_for_set(const char *set_name) {
                   1676:        if (strcmp(set_name, "pkgsrc") == 0)
                   1677:                return pkgsrc_dir;
                   1678:        return set_is_source(set_name) ? set_dir_src : set_dir_bin;
                   1679: }
                   1680:
                   1681: const char *
                   1682: ext_dir_for_set(const char *set_name) {
                   1683:        if (strcmp(set_name, "pkgsrc") == 0)
                   1684:                return ext_dir_pkgsrc;
                   1685:        return set_is_source(set_name) ? ext_dir_src : ext_dir_bin;
                   1686: }
                   1687:
1.2       martin   1688: void
                   1689: do_coloring(unsigned int fg, unsigned int bg) {
                   1690:        if (bg > COLOR_WHITE)
                   1691:                bg = COLOR_BLUE;
                   1692:        if (fg > COLOR_WHITE)
                   1693:                fg = COLOR_WHITE;
                   1694:        if (fg != bg && has_colors()) {
                   1695:                init_pair(1, fg, bg);
                   1696:                wbkgd(stdscr, COLOR_PAIR(1));
                   1697:                wbkgd(mainwin, COLOR_PAIR(1));
                   1698:                wattrset(stdscr, COLOR_PAIR(1));
                   1699:                wattrset(mainwin, COLOR_PAIR(1));
                   1700:        }
                   1701:        /* redraw screen */
                   1702:        touchwin(stdscr);
                   1703:        touchwin(mainwin);
                   1704:        wrefresh(stdscr);
                   1705:        wrefresh(mainwin);
                   1706:        return;
                   1707: }
                   1708:
                   1709: int
                   1710: set_menu_select(menudesc *m, void *arg)
                   1711: {
                   1712:        *(int *)arg = m->cursel;
                   1713:        return 1;
                   1714: }
                   1715:
                   1716: /*
                   1717:  * check wether a binary is available somewhere in PATH,
                   1718:  * return 1 if found, 0 if not.
                   1719:  */
1.22      martin   1720: static int
1.2       martin   1721: binary_available(const char *prog)
                   1722: {
1.9       kamil    1723:         char *p, tmp[MAXPATHLEN], *path = getenv("PATH"), *opath;
1.2       martin   1724:
                   1725:         if (path == NULL)
                   1726:                 return access(prog, X_OK) == 0;
                   1727:         path = strdup(path);
                   1728:         if (path == NULL)
                   1729:                 return 0;
1.9       kamil    1730:
                   1731:        opath = path;
                   1732:
1.2       martin   1733:         while ((p = strsep(&path, ":")) != NULL) {
                   1734:                 if (strlcpy(tmp, p, MAXPATHLEN) >= MAXPATHLEN)
                   1735:                         continue;
                   1736:                 if (strlcat(tmp, "/", MAXPATHLEN) >= MAXPATHLEN)
                   1737:                         continue;
                   1738:                 if (strlcat(tmp, prog, MAXPATHLEN) >= MAXPATHLEN)
                   1739:                         continue;
                   1740:                 if (access(tmp, X_OK) == 0) {
1.9       kamil    1741:                         free(opath);
1.2       martin   1742:                         return 1;
                   1743:                 }
                   1744:         }
1.9       kamil    1745:         free(opath);
1.2       martin   1746:         return 0;
                   1747: }
                   1748:
1.5       christos 1749: const char *
                   1750: safectime(time_t *t)
                   1751: {
                   1752:        const char *s = ctime(t);
                   1753:        if (s != NULL)
                   1754:                return s;
                   1755:
                   1756:        // Debugging.
                   1757:        fprintf(stderr, "Can't convert to localtime 0x%jx (%s)\n",
                   1758:            (intmax_t)*t, strerror(errno));
                   1759:              /*123456789012345678901234*/
                   1760:        return "preposterous clock time\n";
                   1761: }
1.6       martin   1762:
                   1763: int
1.7       martin   1764: ask_yesno(const char* msgtxt)
1.6       martin   1765: {
                   1766:        arg_rv p;
                   1767:
1.8       joerg    1768:        p.arg = __UNCONST(msgtxt);
1.6       martin   1769:        p.rv = -1;
                   1770:
                   1771:        process_menu(MENU_yesno, &p);
                   1772:        return p.rv;
                   1773: }
                   1774:
                   1775: int
1.7       martin   1776: ask_noyes(const char *msgtxt)
1.6       martin   1777: {
                   1778:        arg_rv p;
                   1779:
1.8       joerg    1780:        p.arg = __UNCONST(msgtxt);
1.6       martin   1781:        p.rv = -1;
                   1782:
                   1783:        process_menu(MENU_noyes, &p);
                   1784:        return p.rv;
                   1785: }
1.12      martin   1786:
1.22      martin   1787: int
                   1788: ask_reedit(const struct disk_partitions *parts)
                   1789: {
                   1790:        const char *args[2];
                   1791:        arg_rep_int arg;
                   1792:
                   1793:        args[0] = msg_string(parts->pscheme->name);
                   1794:        args[1] = msg_string(parts->pscheme->short_name);
                   1795:        arg.args.argv = args;
                   1796:        arg.args.argc = 2;
                   1797:        arg.rv = 0;
                   1798:        process_menu(MENU_reedit, &arg);
                   1799:
                   1800:        return arg.rv;
                   1801: }
                   1802:
1.12      martin   1803: bool
                   1804: use_tgz_for_set(const char *set_name)
                   1805: {
                   1806:        const struct distinfo *dist;
                   1807:
                   1808:        for (dist = dist_list; dist->set != SET_LAST; dist++) {
                   1809:                if (dist->name == NULL)
                   1810:                        continue;
                   1811:                if (strcmp(set_name, dist->name) == 0)
                   1812:                        return dist->force_tgz;
                   1813:        }
                   1814:
1.13      martin   1815:        return true;
1.12      martin   1816: }
                   1817:
                   1818: /* Return the postfix used for a given set */
1.13      martin   1819: const char *
                   1820: set_postfix(const char *set_name)
1.12      martin   1821: {
                   1822:        return use_tgz_for_set(set_name) ? dist_tgz_postfix : dist_postfix;
                   1823: }
                   1824:
1.17      martin   1825: /*
1.18      martin   1826:  * Replace positional arguments (encoded as $0 .. $N) in the string
                   1827:  * passed by the contents of the passed argument array.
                   1828:  * Caller must free() the result string.
1.17      martin   1829:  */
1.18      martin   1830: char*
                   1831: str_arg_subst(const char *src, size_t argc, const char **argv)
1.17      martin   1832: {
1.18      martin   1833:        const char *p, *last;
1.17      martin   1834:        char *out, *t;
                   1835:        size_t len;
                   1836:
                   1837:        len = strlen(src);
                   1838:        for (p = strchr(src, '$'); p; p = strchr(p+1, '$')) {
                   1839:                char *endp = NULL;
                   1840:                size_t n;
                   1841:                int e;
                   1842:
                   1843:                /* $ followed by a correct numeric position? */
                   1844:                n = strtou(p+1, &endp, 10, 0, INT_MAX, &e);
                   1845:                if ((e == 0 || e == ENOTSUP) && n < argc) {
1.18      martin   1846:                        len += strlen(argv[n]);
1.17      martin   1847:                        len -= endp-p;
                   1848:                        p = endp-1;
                   1849:                }
                   1850:        }
                   1851:
                   1852:        out = malloc(len+1);
1.18      martin   1853:        if (out == NULL)
                   1854:                return NULL;
1.17      martin   1855:
                   1856:        t = out;
                   1857:        for (last = src, p = strchr(src, '$'); p; p = strchr(p+1, '$')) {
                   1858:                char *endp = NULL;
                   1859:                size_t n;
                   1860:                int e;
                   1861:
                   1862:                /* $ followed by a correct numeric position? */
                   1863:                n = strtou(p+1, &endp, 10, 0, INT_MAX, &e);
                   1864:                if ((e == 0 || e == ENOTSUP) && n < argc) {
                   1865:                        size_t l = p-last;
                   1866:                        memcpy(t, last, l);
                   1867:                        t += l;
1.18      martin   1868:                        strcpy(t, argv[n]);
                   1869:                        t += strlen(argv[n]);
1.17      martin   1870:                        last = endp;
                   1871:                }
                   1872:        }
                   1873:        if (*last) {
                   1874:                strcpy(t, last);
                   1875:                t += strlen(last);
                   1876:        } else {
                   1877:                *t = 0;
                   1878:        }
                   1879:        assert((size_t)(t-out) == len);
                   1880:
1.18      martin   1881:        return out;
                   1882: }
                   1883:
                   1884: /*
1.22      martin   1885:  * Does this string have any positional args that need expanding?
                   1886:  */
                   1887: bool
                   1888: needs_expanding(const char *src, size_t argc)
                   1889: {
                   1890:        const char *p;
                   1891:
                   1892:        for (p = strchr(src, '$'); p; p = strchr(p+1, '$')) {
                   1893:                char *endp = NULL;
                   1894:                size_t n;
                   1895:                int e;
                   1896:
                   1897:                /* $ followed by a correct numeric position? */
                   1898:                n = strtou(p+1, &endp, 10, 0, INT_MAX, &e);
                   1899:                if ((e == 0 || e == ENOTSUP) && n < argc)
                   1900:                        return true;
                   1901:        }
                   1902:        return false;
                   1903: }
                   1904:
                   1905: /*
1.18      martin   1906:  * Replace positional arguments (encoded as $0 .. $N) in the
1.22      martin   1907:  * message by the strings passed as ... and call outfunc
                   1908:  * with the result.
1.18      martin   1909:  */
1.22      martin   1910: static void
1.24      christos 1911: msg_display_subst_internal(void (*outfunc)(msg),
                   1912:     const char *master, size_t argc, va_list ap)
1.18      martin   1913: {
                   1914:        const char **args, **arg;
                   1915:        char *out;
                   1916:
1.24      christos 1917:        args = calloc(argc, sizeof(*args));
1.18      martin   1918:        if (args == NULL)
                   1919:                return;
                   1920:
                   1921:        arg = args;
                   1922:        for (size_t i = 0; i < argc; i++)
                   1923:                *arg++ = va_arg(ap, const char*);
1.17      martin   1924:
1.18      martin   1925:        out = str_arg_subst(msg_string(master), argc, args);
                   1926:        if (out != NULL) {
1.22      martin   1927:                outfunc(out);
1.18      martin   1928:                free(out);
                   1929:        }
1.17      martin   1930:        free(args);
                   1931: }
                   1932:
1.22      martin   1933: /*
                   1934:  * Replace positional arguments (encoded as $0 .. $N) in the
                   1935:  * message by the strings passed as ...
                   1936:  */
                   1937: void
                   1938: msg_display_subst(const char *master, size_t argc, ...)
                   1939: {
                   1940:        va_list ap;
                   1941:
                   1942:        va_start(ap, argc);
                   1943:        msg_display_subst_internal(msg_display, master, argc, ap);
                   1944:        va_end(ap);
                   1945: }
                   1946:
                   1947: /*
                   1948:  * Same as above, but add to message instead of starting a new one
                   1949:  */
                   1950: void
                   1951: msg_display_add_subst(const char *master, size_t argc, ...)
                   1952: {
                   1953:        va_list ap;
                   1954:
                   1955:        va_start(ap, argc);
                   1956:        msg_display_subst_internal(msg_display_add, master, argc, ap);
                   1957:        va_end(ap);
                   1958: }
                   1959:
                   1960: /* initialize have_* variables */
                   1961: void
                   1962: check_available_binaries()
                   1963: {
                   1964:        static int did_test = false;
                   1965:
                   1966:        if (did_test) return;
                   1967:        did_test = 1;
                   1968:
                   1969:        have_raid = binary_available("raidctl");
                   1970:        have_vnd = binary_available("vndconfig");
                   1971:        have_cgd = binary_available("cgdconfig");
                   1972:        have_lvm = binary_available("lvm");
                   1973:        have_gpt = binary_available("gpt");
                   1974:        have_dk = binary_available("dkctl");
                   1975: }
                   1976:
                   1977: /*
                   1978:  * Wait for enter and immediately clear the screen after user response
                   1979:  * (in case some longer action follows, so the user has instant feedback)
                   1980:  */
                   1981: void
                   1982: hit_enter_to_continue(const char *prompt, const char *title)
                   1983: {
                   1984:        if (prompt != NULL)
                   1985:                msg_display(prompt);
                   1986:         process_menu(MENU_ok, __UNCONST(title));
                   1987:        msg_clear();
                   1988:        wrefresh(mainwin);
                   1989: }
                   1990:
                   1991: /*
                   1992:  * On auto pilot:
                   1993:  * convert an existing set of partitions ot a list of part_usage_info
                   1994:  * so that we "want" exactly what is there already.
                   1995:  */
                   1996: static bool
                   1997: usage_info_list_from_parts(struct part_usage_info **list, size_t *count,
                   1998:     struct disk_partitions *parts)
                   1999: {
                   2000:        struct disk_part_info info;
                   2001:        part_id pno;
                   2002:        size_t no, num;
                   2003:
                   2004:        num = 0;
                   2005:        for (pno = 0; pno < parts->num_part; pno++) {
                   2006:                if (!parts->pscheme->get_part_info(parts, pno, &info))
                   2007:                        continue;
                   2008:                num++;
                   2009:        }
                   2010:
                   2011:        *list = calloc(num, sizeof(**list));
                   2012:        if (*list == NULL)
                   2013:                return false;
                   2014:
                   2015:        *count = num;
                   2016:        for (no = pno = 0; pno < parts->num_part && no < num; pno++) {
                   2017:                if (!parts->pscheme->get_part_info(parts, pno, &info))
                   2018:                        continue;
                   2019:                (*list)[no].size = info.size;
                   2020:                if (info.last_mounted != NULL && *info.last_mounted != 0) {
                   2021:                        strlcpy((*list)[no].mount, info.last_mounted,
                   2022:                            sizeof((*list)[no].mount));
                   2023:                        (*list)[no].instflags |= PUIINST_MOUNT;
                   2024:                }
                   2025:                (*list)[no].parts = parts;
                   2026:                (*list)[no].cur_part_id = pno;
                   2027:                (*list)[no].cur_start = info.start;
                   2028:                (*list)[no].cur_flags = info.flags;
                   2029:                (*list)[no].type = info.nat_type->generic_ptype;
                   2030:                if ((*list)[no].type == PT_swap) {
                   2031:                        (*list)[no].fs_type = FS_SWAP;
                   2032:                        (*list)[no].fs_version = 0;
                   2033:                } else {
                   2034:                        (*list)[no].fs_type = info.fs_type;
                   2035:                        (*list)[no].fs_version = info.fs_sub_type;
                   2036:                }
                   2037:                no++;
                   2038:        }
                   2039:        return true;
                   2040: }
                   2041:
                   2042: bool
                   2043: usage_set_from_parts(struct partition_usage_set *wanted,
                   2044:     struct disk_partitions *parts)
                   2045: {
                   2046:        memset(wanted, 0, sizeof(*wanted));
                   2047:        wanted->parts = parts;
                   2048:
                   2049:        return usage_info_list_from_parts(&wanted->infos, &wanted->num, parts);
                   2050: }
                   2051:
1.29.2.5! msaitoh  2052: struct disk_partitions *
        !          2053: get_inner_parts(struct disk_partitions *parts)
1.22      martin   2054: {
1.23      martin   2055:        daddr_t start, size;
                   2056:        part_id pno;
                   2057:        struct disk_part_info info;
                   2058:
1.29.2.5! msaitoh  2059:        if (parts->pscheme->secondary_scheme == NULL)
        !          2060:                return NULL;
1.22      martin   2061:
1.29.2.5! msaitoh  2062:        start = -1;
        !          2063:        size = -1;
        !          2064:        if (parts->pscheme->guess_install_target == NULL ||
        !          2065:            !parts->pscheme->guess_install_target(parts, &start, &size)) {
        !          2066:                for (pno = 0; pno < parts->num_part; pno++) {
        !          2067:                        if (!parts->pscheme->get_part_info(parts, pno, &info))
        !          2068:                                continue;
        !          2069:                        if (!(info.flags & PTI_SEC_CONTAINER))
        !          2070:                                continue;
        !          2071:                        start = info.start;
        !          2072:                        size = info.size;
1.23      martin   2073:                }
                   2074:        }
                   2075:
1.29.2.5! msaitoh  2076:        if (size > 0)
        !          2077:                return parts->pscheme->secondary_partitions(parts, start,
        !          2078:                    false);
        !          2079:
        !          2080:        return NULL;
        !          2081: }
        !          2082:
        !          2083: bool
        !          2084: install_desc_from_parts(struct install_partition_desc *install,
        !          2085:     struct disk_partitions *parts)
        !          2086: {
        !          2087:        struct disk_partitions *inner_parts;
        !          2088:
        !          2089:        memset(install, 0, sizeof(*install));
        !          2090:        inner_parts = get_inner_parts(parts);
        !          2091:        if (inner_parts != NULL)
        !          2092:                parts = inner_parts;
        !          2093:
1.22      martin   2094:        return usage_info_list_from_parts(&install->infos, &install->num,
                   2095:            parts);
                   2096: }
                   2097:
                   2098: void
                   2099: free_usage_set(struct partition_usage_set *wanted)
                   2100: {
1.29.2.5! msaitoh  2101:        /* XXX - free parts? free clone src? */
1.22      martin   2102:        free(wanted->menu_opts);
                   2103:        free(wanted->infos);
                   2104: }
                   2105:
                   2106: void
                   2107: free_install_desc(struct install_partition_desc *install)
                   2108: {
1.29.2.5! msaitoh  2109: #ifndef NO_CLONES
        !          2110:        size_t i, j;
        !          2111:
        !          2112:        for (i = 0; i < install->num; i++) {
        !          2113:                struct selected_partitions *src = install->infos[i].clone_src;
        !          2114:                if (!(install->infos[i].flags & PUIFLG_CLONE_PARTS) ||
        !          2115:                    src == NULL)
        !          2116:                        continue;
        !          2117:                free_selected_partitions(src);
        !          2118:                for (j = i+1; j < install->num; j++)
        !          2119:                        if (install->infos[j].clone_src == src)
        !          2120:                                install->infos[j].clone_src = NULL;
        !          2121:        }
        !          2122: #endif
1.22      martin   2123:        free(install->infos);
                   2124: }
                   2125:

CVSweb <webmaster@jp.NetBSD.org>