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

Annotation of src/usr.sbin/sysinst/bsddisklabel.c, Revision 1.57

1.57    ! rillig      1: /*     $NetBSD: bsddisklabel.c,v 1.56 2020/10/13 17:26:28 martin Exp $ */
1.1       dholland    2:
                      3: /*
                      4:  * Copyright 1997 Piermont Information Systems Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Based on code written by Philip A. Nelson for Piermont Information
                      8:  * Systems Inc.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. The name of Piermont Information Systems Inc. may not be used to endorse
                     19:  *    or promote products derived from this software without specific prior
                     20:  *    written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
                     23:  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
                     26:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     27:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     28:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     29:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     30:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     31:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
                     32:  * THE POSSIBILITY OF SUCH DAMAGE.
                     33:  */
                     34:
                     35: /* bsddisklabel.c -- generate standard BSD disklabel */
                     36: /* Included by appropriate arch/XXXX/md.c */
                     37:
                     38: #include <sys/param.h>
                     39: #include <sys/sysctl.h>
                     40: #include <sys/exec.h>
                     41: #include <sys/utsname.h>
                     42: #include <sys/types.h>
                     43: #include <sys/stat.h>
                     44: #include <machine/cpu.h>
1.9       martin     45: #include <assert.h>
1.1       dholland   46: #include <stdio.h>
                     47: #include <stddef.h>
                     48: #include <util.h>
                     49: #include <dirent.h>
                     50: #include "defs.h"
                     51: #include "md.h"
1.5       martin     52: #include "defsizes.h"
1.1       dholland   53: #include "endian.h"
                     54: #include "msg_defs.h"
                     55: #include "menu_defs.h"
                     56:
1.9       martin     57: static size_t fill_ptn_menu(struct partition_usage_set *pset);
1.1       dholland   58:
1.9       martin     59: /*
                     60:  * The default partition layout.
                     61:  */
                     62: static const struct part_usage_info
                     63: default_parts_init[] =
                     64: {
                     65:        /*
                     66:         * Pretty complex setup for boot partitions.
                     67:         * This is copy&pasted below, please keep in sync!
                     68:         */
                     69: #ifdef PART_BOOT
                     70:        { .size = PART_BOOT/512,        /* PART_BOOT is in BYTE, not MB! */
                     71: #ifdef PART_BOOT_MOUNT
                     72:          .mount = PART_BOOT_MOUNT,
                     73:          .instflags = PUIINST_MOUNT|PUIINST_BOOT,
                     74: #else
1.18      martin     75:          .instflags = PUIINST_BOOT,
1.9       martin     76: #endif
                     77: #ifdef PART_BOOT_TYPE
                     78:          .fs_type = PART_BOOT_TYPE,
1.45      martin     79: #if (PART_BOOT_TYPE == FS_MSDOS) || (PART_BOOT_TYPE == FS_EX2FS)
1.9       martin     80:          .flags = PUIFLAG_ADD_OUTER,
                     81: #endif
                     82: #endif
                     83: #ifdef PART_BOOT_SUBT
                     84:          .fs_version = PART_BOOT_SUBT,
                     85: #endif
                     86:        },
                     87: #endif
                     88:
                     89:        /*
                     90:         * Two more copies of above for _BOOT1 and _BOOT2, please
                     91:         * keep in sync!
                     92:         */
                     93: #ifdef PART_BOOT1
                     94:        { .size = PART_BOOT1/512,       /* PART_BOOT1 is in BYTE, not MB! */
                     95: #ifdef PART_BOOT1_MOUNT
                     96:          .mount = PART_BOOT1_MOUNT,
                     97:          .instflags = PUIINST_MOUNT|PUIINST_BOOT,
                     98: #else
                     99:          .instflags = PUIINST_MOUNT|PUIINST_BOOT,
                    100: #endif
                    101: #ifdef PART_BOOT1_TYPE
                    102:          .fs_type = PART_BOOT1_TYPE,
1.45      martin    103: #if (PART_BOOT1_TYPE == FS_MSDOS) || (PART_BOOT1_TYPE == FS_EX2FS)
1.9       martin    104:          .flags = PUIFLAG_ADD_OUTER,
                    105: #endif
                    106: #endif
                    107: #ifdef PART_BOOT1_SUBT
                    108:          .fs_version = PART_BOOT1_SUBT,
                    109: #endif
                    110:        },
                    111: #endif
                    112: #ifdef PART_BOOT2
                    113:        { .size = PART_BOOT2/512,       /* PART_BOOT2 is in BYTE, not MB! */
                    114: #ifdef PART_BOOT2_MOUNT
                    115:          .mount = PART_BOOT2_MOUNT,
                    116:          .instflags = PUIINST_MOUNT|PUIINST_BOOT,
                    117: #else
                    118:          .instflags = PUIINST_MOUNT|PUIINST_BOOT,
                    119: #endif
                    120: #ifdef PART_BOOT2_TYPE
                    121:          .fs_type = PART_BOOT2_TYPE,
1.45      martin    122: #if (PART_BOOT2_TYPE == FS_MSDOS) || (PART_BOOT2_TYPE == FS_EX2FS)
1.9       martin    123:          .flags = PUIFLAG_ADD_OUTER,
                    124: #endif
1.1       dholland  125: #endif
1.9       martin    126: #ifdef PART_BOOT2_SUBT
                    127:          .fs_version = PART_BOOT1_SUBT,
1.1       dholland  128: #endif
1.9       martin    129:        },
1.1       dholland  130: #endif
                    131:
1.9       martin    132:        { .size = DEFROOTSIZE*(MEG/512), .mount = "/", .type = PT_root,
                    133:          .flags = PUIFLAG_EXTEND },
                    134:        {
                    135: #if DEFSWAPSIZE > 0
                    136:          .size = DEFSWAPSIZE*(MEG/512),
                    137: #endif
                    138:          .type = PT_swap, .fs_type = FS_SWAP },
                    139: #ifdef HAVE_TMPFS
                    140:        { .type = PT_root, .mount = "/tmp", .fs_type = FS_TMPFS,
                    141:          .flags = PUIFLG_JUST_MOUNTPOINT },
                    142: #else
                    143:        { .type = PT_root, .mount = "/tmp", .fs_type = FS_MFS,
                    144:          .flags = PUIFLG_JUST_MOUNTPOINT },
                    145: #endif
1.40      martin    146:        { .def_size = DEFUSRSIZE*(MEG/512), .mount = "/usr", .type = PT_root,
                    147:          .fs_type = FS_BSDFFS, .fs_version = 2 },
                    148:        { .def_size = DEFVARSIZE*(MEG/512), .mount = "/var", .type = PT_root,
                    149:          .fs_type = FS_BSDFFS, .fs_version = 2 },
1.9       martin    150: };
                    151:
                    152: static const char size_separator[] =
                    153:     "----------------------------------- - --------------------";
                    154: static char size_menu_title[STRSIZE];
                    155: static char size_menu_exit[MENUSTRSIZE];
                    156:
                    157: static void
                    158: set_pset_exit_str(struct partition_usage_set *pset)
                    159: {
                    160:        char *str, num[25];
                    161:        const char *args[2];
                    162:        bool overrun;
                    163:        daddr_t free_space = pset->cur_free_space;
                    164:
                    165:        /* format exit string */
                    166:        overrun = free_space < 0;
                    167:        if (overrun)
                    168:                free_space = -free_space;
                    169:
                    170:        snprintf(num, sizeof(num), "%" PRIu64, free_space / sizemult);
                    171:        args[0] = num;
                    172:        args[1] = multname;
                    173:        str = str_arg_subst(
                    174:            msg_string(overrun ? MSG_fssizesbad : MSG_fssizesok),
                    175:            2, args);
                    176:        strlcpy(size_menu_exit, str, sizeof(size_menu_exit));
                    177:        free(str);
                    178: }
                    179:
                    180: static void
                    181: draw_size_menu_header(menudesc *m, void *arg)
                    182: {
                    183:        struct partition_usage_set *pset = arg;
                    184:        size_t i;
                    185:        char col1[70], desc[MENUSTRSIZE];
                    186:        bool need_ext = false, need_existing = false;
                    187:
                    188:        msg_display(MSG_ptnsizes);
                    189:
                    190:        for (i = 0; i < pset->num; i++) {
                    191:                if (pset->infos[i].flags & PUIFLG_IS_OUTER)
                    192:                        need_ext = true;
                    193:                else if (pset->infos[i].cur_part_id != NO_PART)
                    194:                        need_existing = true;
                    195:        }
                    196:        if (need_ext && need_existing)
                    197:                snprintf(desc, sizeof desc, "%s, %s",
                    198:                    msg_string(MSG_ptnsizes_mark_existing),
                    199:                    msg_string(MSG_ptnsizes_mark_external));
                    200:        else if (need_existing)
                    201:                strlcpy(desc, msg_string(MSG_ptnsizes_mark_existing),
                    202:                    sizeof desc);
                    203:        else if (need_ext)
                    204:                strlcpy(desc, msg_string(MSG_ptnsizes_mark_external),
                    205:                    sizeof desc);
                    206:        if (need_ext || need_existing) {
                    207:                msg_printf("\n");
                    208:                msg_display_add_subst(msg_string(MSG_ptnsizes_markers),
                    209:                    1, &desc);
                    210:        }
                    211:        msg_printf("\n\n");
                    212:
                    213:        /* update menu title */
                    214:        snprintf(col1, sizeof col1, "%s (%s)", msg_string(MSG_ptnheaders_size),
                    215:            multname);
                    216:        snprintf(size_menu_title, sizeof size_menu_title,
                    217:            "   %-37.37s %s\n   %s", col1,
                    218:            msg_string(MSG_ptnheaders_filesystem), size_separator);
1.1       dholland  219: }
                    220:
1.9       martin    221: static void
                    222: draw_size_menu_line(menudesc *m, int opt, void *arg)
1.1       dholland  223: {
1.9       martin    224:        struct partition_usage_set *pset = arg;
1.1       dholland  225:        daddr_t size;
1.9       martin    226:        char psize[38], inc_free[16], flag, swap[40];
                    227:        const char *mount;
                    228:        bool free_mount = false;
1.1       dholland  229:
1.9       martin    230:        if (opt < 0 || (size_t)opt >= pset->num)
1.1       dholland  231:                return;
1.9       martin    232:
                    233:        inc_free[0] = 0;
                    234:        if ((pset->infos[opt].flags & PUIFLAG_EXTEND) &&
                    235:             pset->cur_free_space > 0) {
                    236:                size = pset->infos[opt].size + pset->cur_free_space;
                    237:                snprintf(inc_free, sizeof inc_free, " (%" PRIu64 ")",
                    238:                    size / sizemult);
                    239:        }
                    240:        size = pset->infos[opt].size;
1.35      martin    241:        if (pset->infos[opt].fs_type == FS_TMPFS) {
                    242:                if (pset->infos[opt].size < 0)
                    243:                        snprintf(psize, sizeof psize, "%" PRIu64 "%%", -size);
                    244:                else
                    245:                        snprintf(psize, sizeof psize, "%" PRIu64 " %s", size,
                    246:                            msg_string(MSG_megname));
                    247:        } else {
                    248:                snprintf(psize, sizeof psize, "%" PRIu64 "%s",
                    249:                    size / sizemult, inc_free);
                    250:        }
1.9       martin    251:
                    252:        if (pset->infos[opt].type == PT_swap) {
                    253:                snprintf(swap, sizeof swap, "<%s>",
                    254:                    msg_string(MSG_swap_display));
                    255:                mount = swap;
                    256:        } else if (pset->infos[opt].flags & PUIFLG_JUST_MOUNTPOINT) {
                    257:                snprintf(swap, sizeof swap, "%s (%s)",
                    258:                    pset->infos[opt].mount,
                    259:                    getfslabelname(pset->infos[opt].fs_type,
                    260:                    pset->infos[opt].fs_version));
                    261:                mount = swap;
1.14      christos  262:        } else if (pset->infos[opt].mount[0]) {
1.44      martin    263:                if (pset->infos[opt].instflags & PUIINST_BOOT) {
                    264:                        snprintf(swap, sizeof swap, "%s <%s>",
                    265:                            pset->infos[opt].mount, msg_string(MSG_ptn_boot));
                    266:                        mount = swap;
                    267:                } else {
                    268:                        mount = pset->infos[opt].mount;
                    269:                }
1.31      martin    270: #ifndef NO_CLONES
1.30      martin    271:        } else if (pset->infos[opt].flags & PUIFLG_CLONE_PARTS) {
                    272:                snprintf(swap, sizeof swap, "%zu %s",
                    273:                    pset->infos[opt].clone_src->num_sel,
                    274:                    msg_string(MSG_clone_target_disp));
                    275:                mount = swap;
1.31      martin    276: #endif
1.9       martin    277:        } else {
1.23      martin    278:                mount = NULL;
                    279:                if (pset->infos[opt].parts->pscheme->other_partition_identifier
                    280:                    && pset->infos[opt].cur_part_id != NO_PART)
                    281:                        mount = pset->infos[opt].parts->pscheme->
                    282:                            other_partition_identifier(pset->infos[opt].parts,
                    283:                            pset->infos[opt].cur_part_id);
                    284:                if (mount == NULL)
                    285:                        mount = getfslabelname(pset->infos[opt].fs_type,
                    286:                            pset->infos[opt].fs_version);
1.44      martin    287:                if (pset->infos[opt].instflags & PUIINST_BOOT) {
                    288:                        snprintf(swap, sizeof swap, "%s <%s>",
                    289:                            mount, msg_string(MSG_ptn_boot));
                    290:                        mount = swap;
                    291:                }
1.9       martin    292:                mount = str_arg_subst(msg_string(MSG_size_ptn_not_mounted),
                    293:                    1, &mount);
                    294:                free_mount = true;
                    295:        }
                    296:        flag = ' ';
                    297:        if (pset->infos[opt].flags & PUIFLAG_EXTEND)
                    298:                flag = '+';
                    299:        else if (pset->infos[opt].flags & PUIFLG_IS_OUTER)
                    300:                flag = '@';
                    301:        else if (pset->infos[opt].cur_part_id != NO_PART)
                    302:                flag = '=';
                    303:        wprintw(m->mw, "%-35.35s %c %s", psize, flag, mount);
                    304:        if (free_mount)
                    305:                free(__UNCONST(mount));
                    306:
                    307:        if (opt == 0)
                    308:                set_pset_exit_str(pset);
                    309: }
                    310:
                    311: static int
                    312: add_other_ptn_size(menudesc *menu, void *arg)
                    313: {
                    314:        struct partition_usage_set *pset = arg;
                    315:        struct part_usage_info *p;
                    316:        struct menu_ent *m;
                    317:        char new_mp[MOUNTLEN], *err;
                    318:        const char *args;
                    319:
                    320:        for (;;) {
                    321:                msg_prompt_win(partman_go?MSG_askfsmountadv:MSG_askfsmount,
                    322:                    -1, 18, 0, 0, NULL,  new_mp, sizeof(new_mp));
                    323:                if (new_mp[0] == 0)
                    324:                        return 0;
                    325:                if (new_mp[0] != '/') {
                    326:                        /* we need absolute mount paths */
                    327:                        memmove(new_mp+1, new_mp, sizeof(new_mp)-1);
                    328:                        new_mp[0] = '/';
1.24      martin    329:                }
                    330:
                    331:                /* duplicates? */
                    332:                bool duplicate = false;
                    333:                for (size_t i = 0; i < pset->num; i++) {
                    334:                        if (strcmp(pset->infos[i].mount,
                    335:                            new_mp) == 0) {
                    336:                                args = new_mp;
                    337:                                err = str_arg_subst(
                    338:                                    msg_string(MSG_mp_already_exists),
                    339:                                    1, &args);
                    340:                                err_msg_win(err);
                    341:                                free(err);
                    342:                                duplicate = true;
                    343:                                break;
1.9       martin    344:                        }
                    345:                }
1.24      martin    346:                if (!duplicate)
                    347:                        break;
1.1       dholland  348:        }
1.9       martin    349:
1.30      martin    350:        m = realloc(pset->menu_opts, (pset->num+5)*sizeof(*pset->menu_opts));
1.9       martin    351:        if (m == NULL)
                    352:                return 0;
                    353:        p = realloc(pset->infos, (pset->num+1)*sizeof(*pset->infos));
                    354:        if (p == NULL)
                    355:                return 0;
                    356:
                    357:        pset->infos = p;
                    358:        pset->menu_opts = m;
                    359:        menu->opts = m;
                    360:        menu->numopts = pset->num+4;
                    361:        m += pset->num;
                    362:        p += pset->num;
                    363:        memset(m, 0, sizeof(*m));
                    364:        memset(p, 0, sizeof(*p));
1.25      martin    365:        p->parts = pset->parts;
1.24      martin    366:        p->cur_part_id = NO_PART;
                    367:        p->type = PT_root;
1.25      martin    368:        p->fs_type = FS_BSDFFS;
                    369:        p->fs_version = 2;
1.9       martin    370:        strncpy(p->mount, new_mp, sizeof(p->mount));
                    371:
                    372:        menu->cursel = pset->num;
                    373:        pset->num++;
                    374:        fill_ptn_menu(pset);
                    375:
                    376:        return -1;
1.1       dholland  377: }
                    378:
1.31      martin    379: #ifndef NO_CLONES
1.30      martin    380: static int
                    381: inst_ext_clone(menudesc *menu, void *arg)
                    382: {
                    383:        struct selected_partitions selected;
                    384:        struct clone_target_menu_data data;
                    385:        struct partition_usage_set *pset = arg;
                    386:        struct part_usage_info *p;
                    387:        menu_ent *men;
                    388:        int num_men, i;
1.57    ! rillig    389:
1.30      martin    390:        if (!select_partitions(&selected, pm->parts))
                    391:                return 0;
                    392:
                    393:        num_men = pset->num+1;
                    394:        men = calloc(num_men, sizeof *men);
                    395:        if (men == NULL)
                    396:                return 0;
                    397:        for (i = 0; i < num_men; i++)
                    398:                men[i].opt_action = clone_target_select;
                    399:        men[num_men-1].opt_name = MSG_clone_target_end;
                    400:
                    401:        memset(&data, 0, sizeof data);
                    402:        data.usage = *pset;
                    403:        data.res = -1;
                    404:
                    405:        data.usage.menu = new_menu(MSG_clone_target_hdr,
                    406:            men, num_men, 3, 2, 0, 65, MC_SCROLL,
                    407:            NULL, draw_size_menu_line, NULL, NULL, MSG_cancel);
                    408:        process_menu(data.usage.menu, &data);
                    409:        free_menu(data.usage.menu);
                    410:        free(men);
                    411:
                    412:        if (data.res < 0)
                    413:                goto err;
                    414:
                    415:        /* insert clone record */
                    416:        men = realloc(pset->menu_opts, (pset->num+5)*sizeof(*pset->menu_opts));
                    417:        if (men == NULL)
                    418:                goto err;
                    419:        pset->menu_opts = men;
                    420:        menu->opts = men;
                    421:        menu->numopts = pset->num+4;
                    422:
                    423:        p = realloc(pset->infos, (pset->num+1)*sizeof(*pset->infos));
                    424:        if (p == NULL)
                    425:                goto err;
                    426:        pset->infos = p;
                    427:
                    428:        men += data.res;
                    429:        p += data.res;
                    430:        memmove(men+1, men, sizeof(*men)*((pset->num+4)-data.res));
                    431:        memmove(p+1, p, sizeof(*p)*((pset->num)-data.res));
                    432:        memset(men, 0, sizeof(*men));
                    433:        memset(p, 0, sizeof(*p));
                    434:        p->flags = PUIFLG_CLONE_PARTS;
                    435:        p->cur_part_id = NO_PART;
                    436:        p->clone_src = malloc(sizeof(selected));
                    437:        if (p->clone_src != NULL) {
                    438:                *p->clone_src = selected;
                    439:                p->clone_ndx = ~0U;
                    440:                p->size = selected_parts_size(&selected);
                    441:                p->parts = pset->parts;
                    442:        } else {
                    443:                p->clone_ndx = 0;
                    444:                free_selected_partitions(&selected);
                    445:        }
                    446:
                    447:        menu->cursel = data.res == 0 ? 1 : 0;
                    448:        pset->num++;
                    449:        fill_ptn_menu(pset);
                    450:
                    451:        return -1;
                    452:
                    453: err:
                    454:        free_selected_partitions(&selected);
                    455:        return 0;
                    456: }
1.31      martin    457: #endif
1.30      martin    458:
1.9       martin    459: static size_t
                    460: fill_ptn_menu(struct partition_usage_set *pset)
1.1       dholland  461: {
1.9       martin    462:        struct part_usage_info *p;
                    463:        struct disk_part_info info;
1.1       dholland  464:        menu_ent *m;
1.9       martin    465:        size_t i;
                    466:        daddr_t free_space;
1.1       dholland  467:
1.31      martin    468: #ifdef NO_CLONES
                    469: #define        ADD_ITEMS       3
                    470: #else
                    471: #define        ADD_ITEMS       4
                    472: #endif
                    473:
                    474:        memset(pset->menu_opts, 0, (pset->num+ADD_ITEMS)
                    475:            *sizeof(*pset->menu_opts));
1.9       martin    476:        for (m = pset->menu_opts, p = pset->infos, i = 0; i < pset->num;
                    477:            m++, p++, i++) {
1.30      martin    478:                if (p->flags & PUIFLG_CLONE_PARTS)
                    479:                        m->opt_flags = OPT_IGNORE|OPT_NOSHORT;
                    480:                else
1.1       dholland  481:                m->opt_action = set_ptn_size;
                    482:        }
1.9       martin    483:
                    484:        m->opt_name = size_separator;
                    485:        m->opt_flags = OPT_IGNORE|OPT_NOSHORT;
                    486:        m++;
                    487:
                    488:        m->opt_name = MSG_add_another_ptn;
                    489:        m->opt_action = add_other_ptn_size;
                    490:        m++;
                    491:
1.31      martin    492: #ifndef NO_CLONES
1.30      martin    493:        m->opt_name = MSG_clone_from_elsewhere;
                    494:        m->opt_action = inst_ext_clone;
                    495:        m++;
1.31      martin    496: #endif
1.30      martin    497:
1.1       dholland  498:        m->opt_name = MSG_askunits;
                    499:        m->opt_menu = MENU_sizechoice;
                    500:        m->opt_flags = OPT_SUB;
                    501:        m++;
                    502:
1.9       martin    503:        /* calculate free space */
1.50      martin    504:        free_space = pset->parts->free_space - pset->reserved_space;
1.9       martin    505:        for (i = 0; i < pset->parts->num_part; i++) {
                    506:                if (!pset->parts->pscheme->get_part_info(pset->parts, i,
                    507:                    &info))
                    508:                        continue;
                    509:                if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK|
                    510:                    PTI_PSCHEME_INTERNAL|PTI_RAW_PART))
                    511:                        continue;
                    512:                free_space += info.size;
                    513:        }
                    514:        for (i = 0; i < pset->num; i++) {
                    515:                if (pset->infos[i].flags &
                    516:                    (PUIFLG_IS_OUTER|PUIFLG_JUST_MOUNTPOINT))
                    517:                        continue;
                    518:                free_space -= pset->infos[i].size;
                    519:        }
                    520:        pset->cur_free_space = free_space;
                    521:        set_pset_exit_str(pset);
                    522:
                    523:        if (pset->menu >= 0)
                    524:                set_menu_numopts(pset->menu, m - pset->menu_opts);
                    525:
                    526:        return m - pset->menu_opts;
                    527: }
                    528:
                    529: static part_id
                    530: find_part_at(struct disk_partitions *parts, daddr_t start)
                    531: {
                    532:        size_t i;
                    533:        struct disk_part_info info;
                    534:
                    535:        for (i = 0; i < parts->num_part; i++) {
                    536:                if (!parts->pscheme->get_part_info(parts, i, &info))
                    537:                        continue;
                    538:                if (info.start == start)
                    539:                        return i;
                    540:        }
1.1       dholland  541:
1.9       martin    542:        return NO_PART;
1.1       dholland  543: }
                    544:
1.35      martin    545: static daddr_t
                    546: parse_ram_size(const char *str, bool *is_percent)
                    547: {
                    548:        daddr_t val;
                    549:        char *cp;
                    550:
                    551:        val = strtoull(str, &cp, 10);
                    552:        while (*cp && isspace((unsigned char)*cp))
                    553:                cp++;
                    554:
                    555:        *is_percent = *cp == '%';
                    556:        return val;
                    557: }
                    558:
1.1       dholland  559: int
                    560: set_ptn_size(menudesc *m, void *arg)
                    561: {
1.9       martin    562:        struct partition_usage_set *pset = arg;
                    563:        struct part_usage_info *p = &pset->infos[m->cursel];
                    564:        char answer[16], dflt[16];
                    565:        const char *err_msg;
                    566:        size_t i, root = ~0U;
                    567:        daddr_t size, old_size, new_size_val, mult;
                    568:        int rv;
1.35      martin    569:        bool non_zero, extend, is_ram_size, is_percent = false;
1.1       dholland  570:
1.9       martin    571:        if (pset->cur_free_space == 0 && p->size == 0 &&
                    572:            !(p->flags & PUIFLG_JUST_MOUNTPOINT))
1.1       dholland  573:                /* Don't allow 'free_parts' to go negative */
                    574:                return 0;
                    575:
1.9       martin    576:        if (p->cur_part_id != NO_PART) {
                    577:                rv = 0;
                    578:                process_menu(MENU_ptnsize_replace_existing_partition, &rv);
                    579:                if (rv == 0)
                    580:                        return 0;
                    581:                if (!pset->parts->pscheme->delete_partition(pset->parts,
                    582:                    p->cur_part_id, &err_msg)) {
                    583:                        if (err_msg)
                    584:                                err_msg_win(err_msg);
1.1       dholland  585:                        return 0;
1.9       martin    586:                }
                    587:                p->cur_part_id = NO_PART;
                    588:                /*
                    589:                 * All other part ids are invalid now too - update them!
                    590:                 */
                    591:                for (i = 0; i < pset->num; i++) {
                    592:                        if (pset->infos[i].cur_part_id == NO_PART)
                    593:                                continue;
                    594:                        pset->infos[i].cur_part_id =
                    595:                            find_part_at(pset->parts, pset->infos[i].cur_start);
                    596:                }
1.1       dholland  597:        }
                    598:
1.35      martin    599:        is_ram_size = (p->flags & PUIFLG_JUST_MOUNTPOINT)
                    600:            && p->fs_type == FS_TMPFS;
                    601:
1.1       dholland  602:        size = p->size;
1.35      martin    603:        if (is_ram_size && size < 0) {
                    604:                is_percent = true;
                    605:                size = -size;
                    606:        }
1.1       dholland  607:        old_size = size;
                    608:        if (size == 0)
1.9       martin    609:                size = p->def_size;
1.35      martin    610:        if (!is_ram_size)
                    611:                size /= sizemult;
                    612:
                    613:        if (is_ram_size) {
                    614:                snprintf(dflt, sizeof dflt, "%" PRIu64 "%s",
                    615:                    size, is_percent ? "%" : "");
                    616:        } else {
                    617:                snprintf(dflt, sizeof dflt, "%" PRIu64 "%s",
                    618:                    size, p->flags & PUIFLAG_EXTEND ? "+" : "");
                    619:        }
1.1       dholland  620:
                    621:        for (;;) {
1.13      christos  622:                msg_fmt_prompt_win(MSG_askfssize, -1, 18, 0, 0,
1.35      martin    623:                    dflt, answer, sizeof answer, "%s%s", p->mount,
                    624:                    is_ram_size ? msg_string(MSG_megname) : multname);
1.9       martin    625:
1.35      martin    626:                if (is_ram_size) {
                    627:                        new_size_val = parse_ram_size(answer, &is_percent);
1.57    ! rillig    628:                        if (is_percent &&
1.35      martin    629:                            (new_size_val < 0 || new_size_val > 100))
                    630:                                continue;
                    631:                        if (!is_percent && new_size_val < 0)
                    632:                                continue;
                    633:                        size = new_size_val;
                    634:                        extend = false;
                    635:                        break;
                    636:                }
1.9       martin    637:                mult = sizemult;
1.38      martin    638:                new_size_val = parse_disk_pos(answer, &mult, pm->sectorsize,
1.35      martin    639:                    pm->dlcylsize, &extend);
1.9       martin    640:
                    641:                if (strcmp(answer, dflt) == 0)
                    642:                        non_zero = p->def_size > 0;
                    643:                else
                    644:                        non_zero = new_size_val > 0;
                    645:
1.1       dholland  646:                /* Some special cases when /usr is first given a size */
1.9       martin    647:                if (old_size == 0 && non_zero &&
                    648:                    strcmp(p->mount, "/usr") == 0) {
                    649:                        for (i = 0; i < pset->num; i++) {
                    650:                                if (strcmp(pset->infos[i].mount, "/") == 0) {
                    651:                                        root = i;
                    652:                                        break;
                    653:                                }
                    654:                        }
1.1       dholland  655:                        /* Remove space for /usr from / */
1.9       martin    656:                        if (root < pset->num && pset->infos[i].cur_part_id ==
                    657:                            NO_PART) {
                    658:                                pset->infos[root].size -= p->def_size;
                    659:                                pset->cur_free_space += p->def_size;
1.1       dholland  660:                        }
                    661:                        /* hack to add free space to default sized /usr */
1.9       martin    662:                        if (strcmp(answer, dflt) == 0) {
                    663:                                size = p->def_size;
                    664:                                pset->infos[root].flags &= ~PUIFLAG_EXTEND;
                    665:                                p->flags |= PUIFLAG_EXTEND;
1.1       dholland  666:                                goto adjust_free;
                    667:                        }
                    668:                }
1.9       martin    669:                if (new_size_val < 0)
1.1       dholland  670:                        continue;
1.9       martin    671:                size = new_size_val;
                    672:                break;
1.1       dholland  673:        }
                    674:
1.9       martin    675:        daddr_t align = pset->parts->pscheme->get_part_alignment(pset->parts);
1.35      martin    676:        if (!is_ram_size) {
                    677:                size = NUMSEC(size, mult, align);
                    678:        }
1.9       martin    679:        if (p->flags & PUIFLAG_EXTEND)
                    680:                p->flags &= ~PUIFLAG_EXTEND;
                    681:        if (extend && (p->limit == 0 || p->limit > p->size)) {
1.39      martin    682:                for (size_t k = 0; k < pset->num; k++)
                    683:                        pset->infos[k].flags &= ~PUIFLAG_EXTEND;
1.9       martin    684:                p->flags |= PUIFLAG_EXTEND;
1.1       dholland  685:                if (size == 0)
1.9       martin    686:                        size = align;
1.1       dholland  687:        }
                    688:        if (p->limit != 0 && size > p->limit)
                    689:                size = p->limit;
                    690:     adjust_free:
1.9       martin    691:        if ((p->flags & (PUIFLG_IS_OUTER|PUIFLG_JUST_MOUNTPOINT)) == 0)
                    692:                pset->cur_free_space += p->size - size;
1.35      martin    693:        p->size = is_percent ? -size : size;
1.9       martin    694:        set_pset_exit_str(pset);
1.1       dholland  695:
                    696:        return 0;
                    697: }
                    698:
1.9       martin    699: /*
                    700:  * User interface to edit a "wanted" partition layout "pset" as first
                    701:  * abstract phase (not concrete partitions).
                    702:  * Make sure to have everything (at least theoretically) fit the
                    703:  * available space.
                    704:  * During editing we keep the part_usage_info and the menu_opts
                    705:  * in pset in sync, that is: we always allocate just enough entries
                    706:  * in pset->infos as we have usage infos in the list (pset->num),
                    707:  * and two additional menu entries ("add a partition" and "select units").
                    708:  * The menu exit string changes depending on content, and implies
                    709:  * abort while the partition set is not valid (does not fit).
                    710:  * Return true when the user wants to continue (by editing the concrete
                    711:  * partitions), return false to abort.
                    712:  */
                    713: bool
                    714: get_ptn_sizes(struct partition_usage_set *pset)
                    715: {
                    716:        size_t num;
                    717:
                    718:        wclear(stdscr);
                    719:        wrefresh(stdscr);
                    720:
                    721:        if (pset->menu_opts == NULL)
1.30      martin    722:                pset->menu_opts = calloc(pset->num+4, sizeof(*pset->menu_opts));
1.9       martin    723:
                    724:        pset->menu = -1;
                    725:        num = fill_ptn_menu(pset);
                    726:
                    727:        pset->menu = new_menu(size_menu_title, pset->menu_opts, num,
                    728:                        3, -1, 12, 70,
                    729:                        MC_ALWAYS_SCROLL|MC_NOBOX|MC_NOCLEAR|MC_CONTINUOUS,
                    730:                        draw_size_menu_header, draw_size_menu_line, NULL,
                    731:                        NULL, size_menu_exit);
                    732:
                    733:        if (pset->menu < 0) {
                    734:                free(pset->menu_opts);
                    735:                pset->menu_opts = NULL;
                    736:                return false;
                    737:        }
1.1       dholland  738:
1.9       martin    739:        pset->ok = true;
                    740:        process_menu(pset->menu, pset);
1.1       dholland  741:
1.9       martin    742:        free_menu(pset->menu);
                    743:        free(pset->menu_opts);
                    744:        pset->menu = -1;
                    745:        pset->menu_opts = NULL;
1.1       dholland  746:
1.27      martin    747:        return pset->ok;
1.9       martin    748: }
                    749:
                    750: static int
                    751: set_keep_existing(menudesc *m, void *arg)
                    752: {
                    753:        ((arg_rep_int*)arg)->rv = LY_KEEPEXISTING;
                    754:        return 0;
                    755: }
                    756:
                    757: static int
1.52      martin    758: set_switch_scheme(menudesc *m, void *arg)
                    759: {
                    760:        ((arg_rep_int*)arg)->rv = LY_OTHERSCHEME;
                    761:        return 0;
                    762: }
                    763:
                    764: static int
1.9       martin    765: set_edit_part_sizes(menudesc *m, void *arg)
                    766: {
                    767:        ((arg_rep_int*)arg)->rv = LY_SETSIZES;
                    768:        return 0;
                    769: }
                    770:
                    771: static int
                    772: set_use_default_sizes(menudesc *m, void *arg)
                    773: {
                    774:        ((arg_rep_int*)arg)->rv = LY_USEDEFAULT;
                    775:        return 0;
1.1       dholland  776: }
                    777:
                    778: /*
1.9       martin    779:  * Check if there is a reasonable pre-existing partition for
                    780:  * NetBSD.
                    781:  */
                    782: static bool
                    783: check_existing_netbsd(struct disk_partitions *parts)
                    784: {
                    785:        size_t nbsd_parts;
                    786:        struct disk_part_info info;
                    787:
                    788:        nbsd_parts = 0;
                    789:        for (part_id p = 0; p < parts->num_part; p++) {
1.17      martin    790:                if (!parts->pscheme->get_part_info(parts, p, &info))
                    791:                        continue;
                    792:                if (info.flags & (PTI_PSCHEME_INTERNAL|PTI_RAW_PART))
                    793:                        continue;
                    794:                if (info.nat_type && info.nat_type->generic_ptype == PT_root)
1.9       martin    795:                        nbsd_parts++;
                    796:        }
                    797:
                    798:        return nbsd_parts > 0;
                    799: }
                    800:
                    801: /*
                    802:  * Query a partition layout type (with available options depending on
                    803:  * pre-existing partitions).
1.1       dholland  804:  */
1.9       martin    805: static enum layout_type
                    806: ask_layout(struct disk_partitions *parts, bool have_existing)
                    807: {
                    808:        arg_rep_int ai;
                    809:        const char *args[2];
                    810:        int menu;
                    811:        size_t num_opts;
1.52      martin    812:        menu_ent options[4], *opt;
1.9       martin    813:
                    814:        args[0] = msg_string(parts->pscheme->name);
                    815:        args[1] = msg_string(parts->pscheme->short_name);
                    816:        ai.args.argv = args;
                    817:        ai.args.argc = 2;
1.52      martin    818:        ai.rv = LY_ERROR;
                    819:
1.9       martin    820:        memset(options, 0, sizeof(options));
                    821:        num_opts = 0;
                    822:        opt = &options[0];
                    823:
                    824:        if (have_existing) {
                    825:                opt->opt_name = MSG_Keep_existing_partitions;
                    826:                opt->opt_flags = OPT_EXIT;
                    827:                opt->opt_action = set_keep_existing;
                    828:                opt++;
                    829:                num_opts++;
                    830:        }
                    831:        opt->opt_name = MSG_Set_Sizes;
                    832:        opt->opt_flags = OPT_EXIT;
                    833:        opt->opt_action = set_edit_part_sizes;
                    834:        opt++;
                    835:        num_opts++;
                    836:
                    837:        opt->opt_name = MSG_Use_Default_Parts;
                    838:        opt->opt_flags = OPT_EXIT;
                    839:        opt->opt_action = set_use_default_sizes;
                    840:        opt++;
                    841:        num_opts++;
                    842:
1.53      martin    843:        if (num_available_part_schemes > 1 &&
1.52      martin    844:            parts->parent == NULL) {
                    845:                opt->opt_name = MSG_Use_Different_Part_Scheme;
                    846:                opt->opt_flags = OPT_EXIT;
                    847:                opt->opt_action = set_switch_scheme;
                    848:                opt++;
                    849:                num_opts++;
                    850:        }
                    851:
1.9       martin    852:        menu = new_menu(MSG_Select_your_choice, options, num_opts,
1.52      martin    853:            -1, -10, 0, 0, 0, NULL, NULL, NULL, NULL, MSG_cancel);
1.9       martin    854:        if (menu != -1) {
                    855:                get_menudesc(menu)->expand_act = expand_all_option_texts;
                    856:                process_menu(menu, &ai);
                    857:                free_menu(menu);
                    858:        }
                    859:
                    860:        return ai.rv;
                    861: }
                    862:
                    863: static void
                    864: merge_part_with_wanted(struct disk_partitions *parts, part_id pno,
                    865:     const struct disk_part_info *info, struct partition_usage_set *wanted,
1.22      martin    866:     size_t wanted_num, bool is_outer)
1.1       dholland  867: {
1.9       martin    868:        struct part_usage_info *infos;
1.2       martin    869:
1.9       martin    870:        /*
                    871:         * does this partition match something in the wanted set?
                    872:         */
1.22      martin    873:        for (size_t i = 0; i < wanted_num; i++) {
1.9       martin    874:                if (wanted->infos[i].type != info->nat_type->generic_ptype)
                    875:                        continue;
1.22      martin    876:                if (wanted->infos[i].type == PT_root &&
                    877:                    info->last_mounted != NULL && info->last_mounted[0] != 0 &&
1.9       martin    878:                    strcmp(info->last_mounted, wanted->infos[i].mount) != 0)
                    879:                        continue;
                    880:                if (wanted->infos[i].cur_part_id != NO_PART)
                    881:                        continue;
                    882:                wanted->infos[i].cur_part_id = pno;
                    883:                wanted->infos[i].parts = parts;
                    884:                wanted->infos[i].size = info->size;
                    885:                wanted->infos[i].cur_start = info->start;
                    886:                wanted->infos[i].flags &= ~PUIFLAG_EXTEND;
1.11      martin    887:                if (wanted->infos[i].fs_type != FS_UNUSED &&
1.48      martin    888:                    wanted->infos[i].type != PT_swap &&
                    889:                    info->last_mounted != NULL &&
                    890:                    info->last_mounted[0] != 0)
1.11      martin    891:                        wanted->infos[i].instflags |= PUIINST_MOUNT;
1.9       martin    892:                if (is_outer)
                    893:                        wanted->infos[i].flags |= PUIFLG_IS_OUTER;
1.22      martin    894:                else
                    895:                        wanted->infos[i].flags &= ~PUIFLG_IS_OUTER;
1.9       martin    896:                return;
                    897:        }
1.4       martin    898:
1.9       martin    899:        /*
                    900:         * no match - if this is fromt the outer scheme, we are done.
                    901:         * otherwise it must be inserted into the wanted set.
                    902:         */
                    903:        if (is_outer)
                    904:                return;
1.1       dholland  905:
                    906:        /*
1.9       martin    907:         * create a new entry for this
1.1       dholland  908:         */
1.9       martin    909:        infos = realloc(wanted->infos, sizeof(*infos)*(wanted->num+1));
                    910:        if (infos == NULL)
                    911:                return;
                    912:        wanted->infos = infos;
                    913:        infos += wanted->num;
                    914:        wanted->num++;
                    915:        memset(infos, 0, sizeof(*infos));
                    916:        if (info->last_mounted != NULL && info->last_mounted[0] != 0)
                    917:                strlcpy(infos->mount, info->last_mounted,
                    918:                    sizeof(infos->mount));
                    919:        infos->type = info->nat_type->generic_ptype;
                    920:        infos->cur_part_id = pno;
                    921:        infos->parts = parts;
                    922:        infos->size = info->size;
                    923:        infos->cur_start = info->start;
                    924:        infos->fs_type = info->fs_type;
                    925:        infos->fs_version = info->fs_sub_type;
                    926:        if (is_outer)
                    927:                infos->flags |= PUIFLG_IS_OUTER;
                    928: }
                    929:
                    930: static bool
                    931: have_x11_by_default(void)
                    932: {
                    933:        static const uint8_t def_sets[] = { MD_SETS_SELECTED };
                    934:
                    935:        for (size_t i = 0; i < __arraycount(def_sets); i++)
                    936:                if (def_sets[i] >= SET_X11_FIRST &&
                    937:                    def_sets[i] <= SET_X11_LAST)
                    938:                        return true;
                    939:
                    940:        return false;
                    941: }
1.1       dholland  942:
1.9       martin    943: static void
                    944: fill_defaults(struct partition_usage_set *wanted, struct disk_partitions *parts,
                    945:     daddr_t ptstart, daddr_t ptsize)
                    946: {
1.15      martin    947:        size_t i, root = ~0U, usr = ~0U, swap = ~0U, def_usr = ~0U;
                    948:        daddr_t free_space, dump_space, required;
1.9       martin    949: #if defined(DEFAULT_UFS2) && !defined(HAVE_UFS2_BOOT)
                    950:        size_t boot = ~0U;
                    951: #endif
1.1       dholland  952:
1.9       martin    953:        memset(wanted, 0, sizeof(*wanted));
                    954:        wanted->parts = parts;
1.50      martin    955:        if (ptstart > parts->disk_start)
                    956:                wanted->reserved_space = ptstart - parts->disk_start;
                    957:        if ((ptstart + ptsize) < (parts->disk_start+parts->disk_size))
                    958:                wanted->reserved_space +=
                    959:                    (parts->disk_start+parts->disk_size) -
                    960:                    (ptstart + ptsize);
1.9       martin    961:        wanted->num = __arraycount(default_parts_init);
                    962:        wanted->infos = calloc(wanted->num, sizeof(*wanted->infos));
                    963:        if (wanted->infos == NULL) {
                    964:                err_msg_win(err_outofmem);
                    965:                return;
1.1       dholland  966:        }
                    967:
1.9       martin    968:        memcpy(wanted->infos, default_parts_init, sizeof(default_parts_init));
1.18      martin    969:
1.35      martin    970: #ifdef HAVE_TMPFS
1.37      martin    971:        if (get_ramsize() >= SMALL_RAM_SIZE) {
1.35      martin    972:                for (i = 0; i < wanted->num; i++) {
                    973:                        if (wanted->infos[i].type != PT_root ||
                    974:                            wanted->infos[i].fs_type != FS_TMPFS)
                    975:                                continue;
                    976:                        /* default tmpfs to 1/4 RAM */
                    977:                        wanted->infos[i].size = -25;
                    978:                        wanted->infos[i].def_size = -25;
                    979:                        break;
                    980:                }
                    981:        }
                    982: #endif
                    983:
1.18      martin    984: #ifdef MD_PART_DEFAULTS
                    985:        MD_PART_DEFAULTS(pm, wanted->infos, wanted->num);
                    986: #endif
                    987:
1.9       martin    988:        for (i = 0; i < wanted->num; i++) {
                    989:                wanted->infos[i].parts = parts;
                    990:                wanted->infos[i].cur_part_id = NO_PART;
1.36      martin    991:                if (wanted->infos[i].type == PT_undef &&
                    992:                    wanted->infos[i].fs_type != FS_UNUSED) {
                    993:                        const struct part_type_desc *pt =
                    994:                            parts->pscheme->get_fs_part_type(PT_undef,
                    995:                            wanted->infos[i].fs_type,
                    996:                            wanted->infos[i].fs_version);
                    997:                        if (pt != NULL)
                    998:                                wanted->infos[i].type = pt->generic_ptype;
                    999:                }
                   1000:                if (wanted->parts->parent != NULL &&
1.45      martin   1001:                    (wanted->infos[i].fs_type == FS_MSDOS ||
                   1002:                     wanted->infos[i].fs_type == FS_EX2FS))
1.36      martin   1003:                        wanted->infos[i].flags |=
                   1004:                            PUIFLG_ADD_INNER|PUIFLAG_ADD_OUTER;
1.9       martin   1005:
                   1006: #if DEFSWAPSIZE == -1
1.36      martin   1007:                if (wanted->infos[i].type == PT_swap) {
                   1008: #ifdef MD_MAY_SWAP_TO
                   1009:                        if (MD_MAY_SWAP_TO(wanted->parts->disk))
                   1010: #endif
                   1011:                                wanted->infos[i].size =
                   1012:                                    get_ramsize() * (MEG / 512);
                   1013:                }
1.1       dholland 1014: #endif
1.9       martin   1015:                if (wanted->infos[i].type == PT_swap && swap > wanted->num)
                   1016:                        swap = i;
                   1017: #if defined(DEFAULT_UFS2) && !defined(HAVE_UFS2_BOOT)
                   1018:                if (wanted->infos[i].instflags & PUIINST_BOOT)
                   1019:                        boot = i;
1.1       dholland 1020: #endif
1.15      martin   1021:                if (wanted->infos[i].type == PT_root) {
                   1022:                        if (strcmp(wanted->infos[i].mount, "/") == 0) {
1.9       martin   1023:                                root = i;
1.15      martin   1024:                        } else if (
                   1025:                            strcmp(wanted->infos[i].mount, "/usr") == 0) {
                   1026:                                if (wanted->infos[i].size > 0)
                   1027:                                        usr = i;
                   1028:                                else
                   1029:                                        def_usr = i;
                   1030:                        }
1.21      martin   1031:                        if (wanted->infos[i].fs_type == FS_UNUSED)
                   1032:                                wanted->infos[i].fs_type = FS_BSDFFS;
                   1033:                        if (wanted->infos[i].fs_type == FS_BSDFFS) {
1.9       martin   1034: #ifdef DEFAULT_UFS2
                   1035: #ifndef HAVE_UFS2_BOOT
1.21      martin   1036:                                if (boot < wanted->num || i != root)
1.1       dholland 1037: #endif
1.21      martin   1038:                                        wanted->infos[i].fs_version = 2;
1.1       dholland 1039: #endif
1.21      martin   1040:                        }
1.9       martin   1041:                }
1.1       dholland 1042:        }
                   1043:
1.9       martin   1044:        /*
                   1045:         * Now we have the defaults as if we were installing to an
                   1046:         * empty disk. Merge the partitions in target range that are already
                   1047:         * there (match with wanted) or are there additionaly.
                   1048:         * The only thing outside of target range that we care for
1.45      martin   1049:         * are FAT partitions, EXT2FS partitions, and a potential
                   1050:         * swap partition - we assume one is enough.
1.9       martin   1051:         */
1.22      martin   1052:        size_t num = wanted->num;
1.9       martin   1053:        if (parts->parent) {
                   1054:                for (part_id pno = 0; pno < parts->parent->num_part; pno++) {
                   1055:                        struct disk_part_info info;
1.1       dholland 1056:
1.9       martin   1057:                        if (!parts->parent->pscheme->get_part_info(
                   1058:                            parts->parent, pno, &info))
                   1059:                                continue;
1.36      martin   1060:                        if (info.nat_type->generic_ptype != PT_swap &&
1.45      martin   1061:                            info.fs_type != FS_MSDOS &&
                   1062:                            info.fs_type != FS_EX2FS)
1.1       dholland 1063:                                continue;
1.9       martin   1064:                        merge_part_with_wanted(parts->parent, pno, &info,
1.22      martin   1065:                            wanted, num, true);
1.9       martin   1066:                        break;
                   1067:                }
                   1068:        }
                   1069:        for (part_id pno = 0; pno < parts->num_part; pno++) {
                   1070:                struct disk_part_info info;
                   1071:
                   1072:                if (!parts->pscheme->get_part_info(parts, pno, &info))
                   1073:                        continue;
                   1074:
                   1075:                if (info.flags & PTI_PSCHEME_INTERNAL)
                   1076:                        continue;
                   1077:
                   1078:                if (info.nat_type->generic_ptype != PT_swap &&
                   1079:                    (info.start < ptstart ||
                   1080:                    (info.start + info.size) > (ptstart+ptsize)))
                   1081:                        continue;
                   1082:
                   1083:                merge_part_with_wanted(parts, pno, &info,
1.22      martin   1084:                    wanted, num, false);
1.9       martin   1085:        }
                   1086:
                   1087:        daddr_t align = parts->pscheme->get_part_alignment(parts);
                   1088:
1.10      martin   1089:        if (root < wanted->num && wanted->infos[root].cur_part_id == NO_PART) {
1.9       martin   1090:                daddr_t max_root_size = parts->disk_start + parts->disk_size;
                   1091:                if (root_limit > 0) {
                   1092:                        /* Bah - bios can not read all the disk, limit root */
                   1093:                        max_root_size = root_limit - parts->disk_start;
                   1094:                }
                   1095:                wanted->infos[root].limit = max_root_size;
                   1096:        }
                   1097:
                   1098:        if (have_x11_by_default()) {
                   1099:                daddr_t xsize = XNEEDMB * (MEG / 512);
                   1100:                if (usr < wanted->num) {
1.10      martin   1101:                        if (wanted->infos[usr].cur_part_id == NO_PART) {
                   1102:                                wanted->infos[usr].size += xsize;
                   1103:                                wanted->infos[usr].def_size += xsize;
                   1104:                        }
1.9       martin   1105:                } else if (root < wanted->num &&
1.10      martin   1106:                    wanted->infos[root].cur_part_id == NO_PART &&
                   1107:                    (wanted->infos[root].limit == 0 ||
1.9       martin   1108:                    (wanted->infos[root].size + xsize) <=
1.10      martin   1109:                    wanted->infos[root].limit)) {
1.9       martin   1110:                        wanted->infos[root].size += xsize;
                   1111:                }
                   1112:        }
1.10      martin   1113:        if (wanted->infos[root].limit > 0 &&
                   1114:            wanted->infos[root].size > wanted->infos[root].limit) {
1.9       martin   1115:                if (usr < wanted->num) {
                   1116:                        /* move space from root to usr */
                   1117:                        daddr_t spill = wanted->infos[root].size -
                   1118:                            wanted->infos[root].limit;
                   1119:                        spill = roundup(spill, align);
                   1120:                        wanted->infos[root].size =
                   1121:                            wanted->infos[root].limit;
                   1122:                        wanted->infos[usr].size = spill;
                   1123:                } else {
                   1124:                        wanted->infos[root].size =
                   1125:                            wanted->infos[root].limit;
1.1       dholland 1126:                }
1.9       martin   1127:        }
                   1128:
                   1129:        /*
                   1130:         * Preliminary calc additional space to allocate and how much
                   1131:         * we likely will have left over. Use that to do further
                   1132:         * adjustments, so we don't present the user inherently
                   1133:         * impossible defaults.
                   1134:         */
1.50      martin   1135:        free_space = parts->free_space - wanted->reserved_space;
1.15      martin   1136:        required = 0;
                   1137:        if (root < wanted->num)
                   1138:                required += wanted->infos[root].size;
                   1139:        if (usr < wanted->num)
                   1140:                required += wanted->infos[usr].size;
                   1141:        else if (def_usr < wanted->num)
1.40      martin   1142:                required += wanted->infos[def_usr].def_size;
1.15      martin   1143:        free_space -= required;
1.9       martin   1144:        for (i = 0; i < wanted->num; i++) {
1.15      martin   1145:                if (i == root || i == usr)
                   1146:                        continue;       /* already accounted above */
1.9       martin   1147:                if (wanted->infos[i].cur_part_id != NO_PART)
                   1148:                        continue;
1.15      martin   1149:                if (wanted->infos[i].size == 0)
                   1150:                        continue;
1.9       martin   1151:                if (wanted->infos[i].flags
                   1152:                    & (PUIFLG_IS_OUTER|PUIFLG_JUST_MOUNTPOINT))
                   1153:                        continue;
                   1154:                free_space -= wanted->infos[i].size;
                   1155:        }
                   1156:        if (free_space < 0 && swap < wanted->num) {
                   1157:                /* steel from swap partition */
                   1158:                daddr_t d = wanted->infos[swap].size;
                   1159:                daddr_t inc = roundup(-free_space, align);
                   1160:                if (inc > d)
                   1161:                        inc = d;
                   1162:                free_space += inc;
                   1163:                wanted->infos[swap].size -= inc;
                   1164:        }
                   1165:        if (root < wanted->num) {
                   1166:                /* Add space for 2 system dumps to / (traditional) */
                   1167:                dump_space = get_ramsize() * (MEG/512);
                   1168:                dump_space = roundup(dump_space, align);
                   1169:                if (free_space > dump_space*2)
                   1170:                        dump_space *= 2;
1.41      martin   1171:                if (free_space > dump_space) {
1.9       martin   1172:                        wanted->infos[root].size += dump_space;
1.41      martin   1173:                        free_space -= dump_space;
                   1174:                }
1.9       martin   1175:        }
1.40      martin   1176:        if (wanted->infos[root].limit > 0 &&
1.41      martin   1177:            (wanted->infos[root].cur_start + wanted->infos[root].size >
                   1178:                wanted->infos[root].limit ||
                   1179:            (wanted->infos[root].flags & PUIFLAG_EXTEND &&
                   1180:            (wanted->infos[root].cur_start + wanted->infos[root].size
                   1181:             + free_space > wanted->infos[root].limit)))) {
1.40      martin   1182:                if (usr >= wanted->num && def_usr < wanted->num) {
                   1183:                        usr = def_usr;
                   1184:                        wanted->infos[usr].size = wanted->infos[root].size
                   1185:                            - wanted->infos[root].limit;
1.41      martin   1186:                        if (wanted->infos[usr].size <= 0)
1.42      martin   1187:                                wanted->infos[usr].size = max(1,
                   1188:                                    wanted->infos[usr].def_size);
1.40      martin   1189:                        wanted->infos[root].size =
                   1190:                            wanted->infos[root].limit;
                   1191:                        if (wanted->infos[root].flags & PUIFLAG_EXTEND) {
                   1192:                                wanted->infos[root].flags &= ~PUIFLAG_EXTEND;
                   1193:                                wanted->infos[usr].flags |= PUIFLAG_EXTEND;
                   1194:                        }
                   1195:                } else if (usr < wanted->num) {
                   1196:                        /* move space from root to usr */
                   1197:                        daddr_t spill = wanted->infos[root].size -
                   1198:                            wanted->infos[root].limit;
                   1199:                        spill = roundup(spill, align);
                   1200:                        wanted->infos[root].size =
                   1201:                            wanted->infos[root].limit;
                   1202:                        wanted->infos[usr].size = spill;
                   1203:                } else {
                   1204:                        wanted->infos[root].size =
                   1205:                            wanted->infos[root].limit;
                   1206:                }
                   1207:        }
1.9       martin   1208: }
                   1209:
                   1210: /*
                   1211:  * We sort pset->infos to sync with pset->parts and
                   1212:  * the cur_part_id, to allow using the same index into both
                   1213:  * "array" in later phases. This may include inserting
                   1214:  * dummy  entries (when we do not actually want the
                   1215:  * partition, but it is forced upon us, like RAW_PART in
                   1216:  * disklabel).
                   1217:  */
                   1218: static void
                   1219: sort_and_sync_parts(struct partition_usage_set *pset)
                   1220: {
                   1221:        struct part_usage_info *infos;
                   1222:        size_t i, j, no;
                   1223:        part_id pno;
                   1224:
1.50      martin   1225:        pset->cur_free_space = pset->parts->free_space - pset->reserved_space;
1.9       martin   1226:
                   1227:        /* count non-empty entries that are not in pset->parts */
                   1228:        no = pset->parts->num_part;
                   1229:        for (i = 0; i < pset->num; i++) {
                   1230:                if (pset->infos[i].size == 0)
                   1231:                        continue;
                   1232:                if (pset->infos[i].cur_part_id != NO_PART)
                   1233:                        continue;
                   1234:                no++;
                   1235:        }
                   1236:
                   1237:        /* allocate new infos */
                   1238:        infos = calloc(no, sizeof *infos);
                   1239:        if (infos == NULL)
                   1240:                return;
                   1241:
                   1242:        /* pre-initialize the first entires as dummy entries */
                   1243:        for (i = 0; i < pset->parts->num_part; i++) {
                   1244:                infos[i].cur_part_id = NO_PART;
                   1245:                infos[i].cur_flags = PTI_PSCHEME_INTERNAL;
                   1246:        }
                   1247:        /*
                   1248:         * Now copy over eveything from our old entries that points to
                   1249:         * a real partition.
                   1250:         */
                   1251:        for (i = 0; i < pset->num; i++) {
                   1252:                pno = pset->infos[i].cur_part_id;
                   1253:                if (pno == NO_PART)
                   1254:                        continue;
                   1255:                if (pset->parts != pset->infos[i].parts)
                   1256:                        continue;
1.19      martin   1257:                if (pset->infos[i].flags & PUIFLG_JUST_MOUNTPOINT)
                   1258:                        continue;
1.30      martin   1259:                if ((pset->infos[i].flags & (PUIFLG_IS_OUTER|PUIFLG_ADD_INNER))
1.19      martin   1260:                    == PUIFLG_IS_OUTER)
1.9       martin   1261:                        continue;
                   1262:                if (pno >= pset->parts->num_part)
                   1263:                        continue;
                   1264:                memcpy(infos+pno, pset->infos+i, sizeof(*infos));
                   1265:        }
                   1266:        /* Fill in the infos for real partitions where we had no data */
                   1267:        for (pno = 0; pno < pset->parts->num_part; pno++) {
                   1268:                struct disk_part_info info;
                   1269:
                   1270:                if (infos[pno].cur_part_id != NO_PART)
                   1271:                        continue;
                   1272:
                   1273:                if (!pset->parts->pscheme->get_part_info(pset->parts, pno,
                   1274:                    &info))
                   1275:                        continue;
                   1276:
                   1277:                infos[pno].parts = pset->parts;
                   1278:                infos[pno].cur_part_id = pno;
                   1279:                infos[pno].cur_flags = info.flags;
                   1280:                infos[pno].size = info.size;
                   1281:                infos[pno].type = info.nat_type->generic_ptype;
                   1282:                infos[pno].cur_start = info.start;
                   1283:                infos[pno].fs_type = info.fs_type;
                   1284:                infos[pno].fs_version = info.fs_sub_type;
                   1285:        }
                   1286:        /* Add the non-partition entires after that */
1.35      martin   1287:        j = pset->parts->num_part;
1.9       martin   1288:        for (i = 0; i < pset->num; i++) {
                   1289:                if (j >= no)
                   1290:                        break;
                   1291:                if (pset->infos[i].size == 0)
                   1292:                        continue;
                   1293:                if (pset->infos[i].cur_part_id != NO_PART)
                   1294:                        continue;
                   1295:                memcpy(infos+j, pset->infos+i, sizeof(*infos));
                   1296:                j++;
                   1297:        }
                   1298:
                   1299:        /* done, replace infos */
                   1300:        free(pset->infos);
                   1301:        pset->num = no;
                   1302:        pset->infos = infos;
                   1303: }
                   1304:
1.31      martin   1305: #ifndef NO_CLONES
1.30      martin   1306: /*
                   1307:  * Convert clone entries with more than one source into
                   1308:  * several entries with a single source each.
                   1309:  */
                   1310: static void
                   1311: normalize_clones(struct part_usage_info **infos, size_t *num)
                   1312: {
                   1313:        size_t i, j, add_clones;
                   1314:        struct part_usage_info *ui, *src, *target;
                   1315:        struct disk_part_info info;
                   1316:        struct selected_partition *clone;
                   1317:
                   1318:        for (add_clones = 0, i = 0; i < *num; i++) {
                   1319:                if ((*infos)[i].clone_src != NULL &&
                   1320:                    (*infos)[i].flags & PUIFLG_CLONE_PARTS &&
                   1321:                    (*infos)[i].cur_part_id == NO_PART)
                   1322:                        add_clones += (*infos)[i].clone_src->num_sel-1;
                   1323:        }
                   1324:        if (add_clones == 0)
                   1325:                return;
                   1326:
                   1327:        ui = calloc(*num+add_clones, sizeof(**infos));
                   1328:        if (ui == NULL)
                   1329:                return; /* can not handle this well here, drop some clones */
                   1330:
                   1331:        /* walk the list and dedup clones */
                   1332:        for (src = *infos, target = ui, i = 0; i < *num; i++) {
                   1333:                if (src != target)
                   1334:                        *target = *src;
                   1335:                if (target->clone_src != NULL &&
                   1336:                    (target->flags & PUIFLG_CLONE_PARTS) &&
                   1337:                    target->cur_part_id == NO_PART) {
                   1338:                        for (j = 0; j < src->clone_src->num_sel; j++) {
                   1339:                                if (j > 0) {
                   1340:                                        target++;
                   1341:                                        *target = *src;
                   1342:                                }
                   1343:                                target->clone_ndx = j;
                   1344:                                clone = &target->clone_src->selection[j];
                   1345:                                clone->parts->pscheme->get_part_info(
                   1346:                                    clone->parts, clone->id, &info);
                   1347:                                target->size = info.size;
                   1348:                        }
                   1349:                }
                   1350:                target++;
                   1351:                src++;
                   1352:        }
                   1353:        *num += add_clones;
                   1354:        assert((target-ui) >= 0 && (size_t)(target-ui) == *num);
                   1355:        free(*infos);
                   1356:        *infos = ui;
                   1357: }
1.31      martin   1358: #endif
1.30      martin   1359:
1.9       martin   1360: static void
1.50      martin   1361: apply_settings_to_partitions(struct disk_partitions *parts,
                   1362:     struct partition_usage_set *wanted, daddr_t start, daddr_t xsize)
1.9       martin   1363: {
                   1364:        size_t i, exp_ndx = ~0U;
                   1365:        daddr_t planned_space = 0, nsp, from, align;
1.31      martin   1366:        struct disk_part_info *infos;
                   1367: #ifndef NO_CLONES
                   1368:        struct disk_part_info cinfo, srcinfo;
                   1369:        struct selected_partition *sp;
                   1370: #endif
1.9       martin   1371:        struct disk_part_free_space space;
                   1372:        struct disk_partitions *ps = NULL;
                   1373:        part_id pno, new_part_id;
                   1374:
1.31      martin   1375: #ifndef NO_CLONES
1.30      martin   1376:        normalize_clones(&wanted->infos, &wanted->num);
1.31      martin   1377: #endif
1.30      martin   1378:
1.9       martin   1379:        infos = calloc(wanted->num, sizeof(*infos));
                   1380:        if (infos == NULL) {
                   1381:                err_msg_win(err_outofmem);
                   1382:                return;
                   1383:        }
                   1384:
                   1385:        align = wanted->parts->pscheme->get_part_alignment(wanted->parts);
                   1386:        /*
                   1387:         * Pass one: calculate space available for expanding
                   1388:         * the marked partition.
                   1389:         */
                   1390:        for (i = 0; i < wanted->num; i++) {
                   1391:                if ((wanted->infos[i].flags & PUIFLAG_EXTEND) &&
                   1392:                    exp_ndx == ~0U)
                   1393:                        exp_ndx = i;
1.36      martin   1394:                if (wanted->infos[i].flags & PUIFLG_JUST_MOUNTPOINT)
1.9       martin   1395:                        continue;
                   1396:                nsp = wanted->infos[i].size;
                   1397:                if (wanted->infos[i].cur_part_id != NO_PART) {
                   1398:                        ps = wanted->infos[i].flags & PUIFLG_IS_OUTER ?
                   1399:                            parts->parent : parts;
                   1400:
1.36      martin   1401:                        ps->pscheme->get_part_info(ps,
                   1402:                             wanted->infos[i].cur_part_id, &infos[i]);
                   1403:                        if (!(wanted->infos[i].flags & PUIFLG_IS_OUTER))
1.9       martin   1404:                                nsp -= infos[i].size;
1.1       dholland 1405:                }
1.9       martin   1406:                if (nsp > 0)
                   1407:                        planned_space += roundup(nsp, align);
1.1       dholland 1408:        }
                   1409:
                   1410:        /*
1.9       martin   1411:         * Expand the pool partition (or shrink, if we overran),
1.41      martin   1412:         * but check size limits.
1.1       dholland 1413:         */
1.41      martin   1414:        if (exp_ndx < wanted->num) {
1.50      martin   1415:                daddr_t free_space =
                   1416:                    parts->free_space - roundup(wanted->reserved_space, align);
                   1417:                free_space -= planned_space;
                   1418:                daddr_t new_size = wanted->infos[exp_ndx].size;
                   1419:                if (free_space > 0)
                   1420:                        new_size += free_space;
                   1421:
1.41      martin   1422:                if (wanted->infos[exp_ndx].limit > 0 &&
1.50      martin   1423:                    (new_size + wanted->infos[exp_ndx].cur_start)
                   1424:                     > wanted->infos[exp_ndx].limit) {
1.41      martin   1425:                        wanted->infos[exp_ndx].size =
                   1426:                            wanted->infos[exp_ndx].limit
                   1427:                            - wanted->infos[exp_ndx].cur_start;
                   1428:                } else {
1.50      martin   1429:                        wanted->infos[exp_ndx].size = new_size;
1.41      martin   1430:                }
                   1431:        }
1.9       martin   1432:
                   1433:        /*
                   1434:         * Now it gets tricky: we want the wanted partitions in order
                   1435:         * as defined, but any already existing partitions should not
                   1436:         * be moved. We allow them to change size though.
                   1437:         * To keep it simple, we just assign in order and skip blocked
                   1438:         * spaces. This may shuffle the order of the resulting partitions
                   1439:         * compared to the wanted list.
                   1440:         */
                   1441:
                   1442:        /* Adjust sizes of existing partitions */
                   1443:        for (i = 0; i < wanted->num; i++) {
                   1444:                ps = wanted->infos[i].flags & PUIFLG_IS_OUTER ?
                   1445:                    parts->parent : parts;
                   1446:                const struct part_usage_info *want = &wanted->infos[i];
                   1447:
                   1448:                if (want->cur_part_id == NO_PART)
                   1449:                        continue;
                   1450:                if (i == exp_ndx)       /* the exp. part. can not exist yet */
1.1       dholland 1451:                        continue;
1.9       martin   1452:                daddr_t free_size = ps->pscheme->max_free_space_at(ps,
                   1453:                    infos[i].start);
                   1454:                if (free_size < wanted->infos[i].size)
1.1       dholland 1455:                        continue;
1.36      martin   1456:                if (infos[i].size != wanted->infos[i].size) {
                   1457:                        infos[i].size = wanted->infos[i].size;
                   1458:                        ps->pscheme->set_part_info(ps, want->cur_part_id,
                   1459:                            &infos[i], NULL);
                   1460:                }
1.9       martin   1461:        }
1.19      martin   1462:
1.50      martin   1463:        from = start > 0 ? start : -1;
1.19      martin   1464:        /*
                   1465:         * First add all outer partitions - we need to align those exactly
                   1466:         * with the inner counterpart later.
                   1467:         */
                   1468:        if (parts->parent) {
                   1469:                ps = parts->parent;
                   1470:                daddr_t outer_align = ps->pscheme->get_part_alignment(ps);
                   1471:
                   1472:                for (i = 0; i < wanted->num; i++) {
                   1473:                        struct part_usage_info *want = &wanted->infos[i];
                   1474:
                   1475:                        if (want->cur_part_id != NO_PART)
                   1476:                                continue;
                   1477:                        if (!(want->flags & PUIFLAG_ADD_OUTER))
                   1478:                                continue;
                   1479:                        if (want->size <= 0)
                   1480:                                continue;
                   1481:
                   1482:                        size_t cnt = ps->pscheme->get_free_spaces(ps,
                   1483:                            &space, 1, want->size-2*outer_align,
                   1484:                            outer_align, from, -1);
                   1485:
                   1486:                        if (cnt == 0)   /* no free space for this partition */
                   1487:                                continue;
                   1488:
                   1489:                        infos[i].start = space.start;
                   1490:                        infos[i].size = min(want->size, space.size);
                   1491:                        infos[i].nat_type =
                   1492:                            ps->pscheme->get_fs_part_type(
1.33      martin   1493:                                want->type, want->fs_type, want->fs_version);
1.19      martin   1494:                        infos[i].last_mounted = want->mount;
                   1495:                        infos[i].fs_type = want->fs_type;
                   1496:                        infos[i].fs_sub_type = want->fs_version;
1.56      martin   1497:                        infos[i].fs_opt1 = want->fs_opt1;
                   1498:                        infos[i].fs_opt2 = want->fs_opt2;
                   1499:                        infos[i].fs_opt3 = want->fs_opt3;
1.19      martin   1500:                        new_part_id = ps->pscheme->add_partition(ps,
                   1501:                            &infos[i], NULL);
                   1502:                        if (new_part_id == NO_PART)
                   1503:                                continue;       /* failed to add, skip */
                   1504:
                   1505:                        ps->pscheme->get_part_info(ps,
                   1506:                            new_part_id, &infos[i]);
                   1507:                        want->cur_part_id = new_part_id;
                   1508:
1.30      martin   1509:                        want->flags |= PUIFLG_ADD_INNER|PUIFLG_IS_OUTER;
1.57    ! rillig   1510:                        from = roundup(infos[i].start +
1.50      martin   1511:                            infos[i].size, outer_align);
1.19      martin   1512:                }
                   1513:        }
                   1514:
                   1515:        /*
1.30      martin   1516:         * Now add new inner partitions (and cloned partitions)
1.19      martin   1517:         */
1.50      martin   1518:        for (i = 0; i < wanted->num; i++) {
                   1519:
                   1520:                daddr_t limit = wanted->parts->disk_size + wanted->parts->disk_start;
                   1521:                if (from >= limit)
                   1522:                        break;
                   1523:
1.9       martin   1524:                struct part_usage_info *want = &wanted->infos[i];
                   1525:
                   1526:                if (want->cur_part_id != NO_PART)
                   1527:                        continue;
1.19      martin   1528:                if (want->flags & (PUIFLG_JUST_MOUNTPOINT|PUIFLG_IS_OUTER))
1.9       martin   1529:                        continue;
1.31      martin   1530: #ifndef NO_CLONES
1.30      martin   1531:                if ((want->flags & PUIFLG_CLONE_PARTS) &&
                   1532:                    want->clone_src != NULL &&
                   1533:                    want->clone_ndx < want->clone_src->num_sel) {
                   1534:                        sp = &want->clone_src->selection[want->clone_ndx];
                   1535:                        if (!sp->parts->pscheme->get_part_info(
                   1536:                            sp->parts, sp->id, &srcinfo))
                   1537:                                continue;
                   1538:                        if (!wanted->parts->pscheme->
                   1539:                            adapt_foreign_part_info(wanted->parts,
                   1540:                            &cinfo, sp->parts->pscheme, &srcinfo))
                   1541:                                continue;
                   1542:
                   1543:                        /* find space for cinfo and add a partition */
                   1544:                        size_t cnt = wanted->parts->pscheme->get_free_spaces(
                   1545:                            wanted->parts, &space, 1, want->size-align, align,
                   1546:                            from, -1);
                   1547:                        if (cnt == 0)
                   1548:                                cnt = wanted->parts->pscheme->get_free_spaces(
                   1549:                                    wanted->parts, &space, 1,
                   1550:                                    want->size-5*align, align, from, -1);
                   1551:
                   1552:                        if (cnt == 0)
                   1553:                                continue; /* no free space for this clone */
                   1554:
                   1555:                        infos[i] = cinfo;
                   1556:                        infos[i].start = space.start;
                   1557:                        new_part_id = wanted->parts->pscheme->add_partition(
                   1558:                            wanted->parts, &infos[i], NULL);
                   1559:                } else {
1.31      martin   1560: #else
                   1561:                {
                   1562: #endif
1.30      martin   1563:                        if (want->size <= 0)
                   1564:                                continue;
                   1565:                        size_t cnt = wanted->parts->pscheme->get_free_spaces(
                   1566:                            wanted->parts, &space, 1, want->size-align, align,
                   1567:                            from, -1);
                   1568:                        if (cnt == 0)
                   1569:                                cnt = wanted->parts->pscheme->get_free_spaces(
                   1570:                                    wanted->parts, &space, 1,
                   1571:                                    want->size-5*align, align, from, -1);
                   1572:
                   1573:                        if (cnt == 0)
                   1574:                                continue; /* no free space for this partition */
1.9       martin   1575:
1.30      martin   1576:                        infos[i].start = space.start;
                   1577:                        infos[i].size = min(want->size, space.size);
                   1578:                        infos[i].nat_type =
                   1579:                            wanted->parts->pscheme->get_fs_part_type(
1.33      martin   1580:                            want->type, want->fs_type, want->fs_version);
1.30      martin   1581:                        infos[i].last_mounted = want->mount;
                   1582:                        infos[i].fs_type = want->fs_type;
                   1583:                        infos[i].fs_sub_type = want->fs_version;
1.56      martin   1584:                        infos[i].fs_opt1 = want->fs_opt1;
                   1585:                        infos[i].fs_opt2 = want->fs_opt2;
                   1586:                        infos[i].fs_opt3 = want->fs_opt3;
1.30      martin   1587:                        if (want->fs_type != FS_UNUSED &&
                   1588:                            want->type != PT_swap) {
                   1589:                                want->instflags |= PUIINST_NEWFS;
                   1590:                                if (want->mount[0] != 0)
                   1591:                                        want->instflags |= PUIINST_MOUNT;
                   1592:                        }
                   1593:                        new_part_id = wanted->parts->pscheme->add_partition(
                   1594:                            wanted->parts, &infos[i], NULL);
1.20      martin   1595:                }
1.30      martin   1596:
1.9       martin   1597:                if (new_part_id == NO_PART)
                   1598:                        continue;       /* failed to add, skip */
                   1599:
                   1600:                wanted->parts->pscheme->get_part_info(
                   1601:                    wanted->parts, new_part_id, &infos[i]);
1.50      martin   1602:                from = roundup(infos[i].start+infos[i].size, align);
1.9       martin   1603:        }
                   1604:
1.19      martin   1605:
                   1606:        /*
                   1607:        * If there are any outer partitions that we need as inner ones
                   1608:         * too, add them to the inner partitioning scheme.
                   1609:         */
                   1610:        for (i = 0; i < wanted->num; i++) {
                   1611:                struct part_usage_info *want = &wanted->infos[i];
                   1612:
1.36      martin   1613:                if (want->cur_part_id == NO_PART)
1.19      martin   1614:                        continue;
                   1615:                if (want->flags & PUIFLG_JUST_MOUNTPOINT)
                   1616:                        continue;
                   1617:                if (want->size <= 0)
                   1618:                        continue;
                   1619:
1.30      martin   1620:                if ((want->flags & (PUIFLG_ADD_INNER|PUIFLG_IS_OUTER)) !=
                   1621:                    (PUIFLG_ADD_INNER|PUIFLG_IS_OUTER))
1.19      martin   1622:                        continue;
                   1623:
1.54      martin   1624:                new_part_id = NO_PART;
                   1625:                for (part_id j = 0; new_part_id == NO_PART &&
                   1626:                    j < wanted->parts->num_part; j++) {
                   1627:                        struct disk_part_info test;
                   1628:
                   1629:                        if (!wanted->parts->pscheme->get_part_info(
                   1630:                            wanted->parts, j, &test))
                   1631:                                continue;
                   1632:                        if (test.start == want->cur_start &&
                   1633:                            test.size == want->size)
                   1634:                                new_part_id = j;
                   1635:                }
                   1636:
                   1637:                if (new_part_id == NO_PART) {
                   1638:                        infos[i].start = want->cur_start;
                   1639:                        infos[i].size = want->size;
                   1640:                        infos[i].nat_type = wanted->parts->pscheme->
                   1641:                            get_fs_part_type(want->type, want->fs_type,
                   1642:                            want->fs_version);
                   1643:                        infos[i].last_mounted = want->mount;
                   1644:                        infos[i].fs_type = want->fs_type;
                   1645:                        infos[i].fs_sub_type = want->fs_version;
1.56      martin   1646:                        infos[i].fs_opt1 = want->fs_opt1;
                   1647:                        infos[i].fs_opt2 = want->fs_opt2;
                   1648:                        infos[i].fs_opt3 = want->fs_opt3;
1.54      martin   1649:
                   1650:                        if (wanted->parts->pscheme->add_outer_partition
                   1651:                            != NULL)
                   1652:                                new_part_id = wanted->parts->pscheme->
                   1653:                                    add_outer_partition(
                   1654:                                    wanted->parts, &infos[i], NULL);
                   1655:                        else
                   1656:                                new_part_id = wanted->parts->pscheme->
                   1657:                                    add_partition(
                   1658:                                    wanted->parts, &infos[i], NULL);
1.57    ! rillig   1659:
1.54      martin   1660:                        if (new_part_id == NO_PART)
                   1661:                                continue;       /* failed to add, skip */
                   1662:                }
1.19      martin   1663:
                   1664:                wanted->parts->pscheme->get_part_info(
                   1665:                    wanted->parts, new_part_id, &infos[i]);
1.36      martin   1666:                want->parts = wanted->parts;
                   1667:                if (want->fs_type != FS_UNUSED &&
                   1668:                    want->type != PT_swap) {
                   1669:                        want->instflags |= PUIINST_NEWFS;
                   1670:                        if (want->mount[0] != 0)
                   1671:                                want->instflags |= PUIINST_MOUNT;
                   1672:                }
1.19      martin   1673:        }
                   1674:
1.9       martin   1675:        /*
                   1676:         * Note: all part_ids are invalid now, as we have added things!
                   1677:         */
                   1678:        for (i = 0; i < wanted->num; i++)
                   1679:                wanted->infos[i].cur_part_id = NO_PART;
1.19      martin   1680:        for (pno = 0; pno < parts->num_part; pno++) {
1.9       martin   1681:                struct disk_part_info t;
                   1682:
1.19      martin   1683:                if (!parts->pscheme->get_part_info(parts, pno, &t))
1.9       martin   1684:                        continue;
                   1685:
                   1686:                for (i = 0; i < wanted->num; i++) {
                   1687:                        if (wanted->infos[i].cur_part_id != NO_PART)
                   1688:                                continue;
1.28      martin   1689:                        if (wanted->infos[i].size <= 0)
                   1690:                                continue;
1.9       martin   1691:                        if (t.start == infos[i].start) {
                   1692:                                wanted->infos[i].cur_part_id = pno;
                   1693:                                wanted->infos[i].cur_start = infos[i].start;
                   1694:                                wanted->infos[i].cur_flags = infos[i].flags;
                   1695:                                break;
1.1       dholland 1696:                        }
                   1697:                }
1.9       martin   1698:        }
                   1699:        free(infos);
                   1700:
                   1701:        /* sort, and sync part ids and wanted->infos[] indices */
                   1702:        sort_and_sync_parts(wanted);
                   1703: }
                   1704:
                   1705: static void
1.50      martin   1706: replace_by_default(struct disk_partitions *parts,
1.9       martin   1707:     daddr_t start, daddr_t size, struct partition_usage_set *wanted)
                   1708: {
                   1709:
                   1710:        if (start == 0 && size == parts->disk_size)
                   1711:                parts->pscheme->delete_all_partitions(parts);
                   1712:        else if (parts->pscheme->delete_partitions_in_range != NULL)
                   1713:                parts->pscheme->delete_partitions_in_range(parts, start, size);
                   1714:        else
                   1715:                assert(parts->num_part == 0);
                   1716:
                   1717:        fill_defaults(wanted, parts, start, size);
1.50      martin   1718:        apply_settings_to_partitions(parts, wanted, start, size);
1.9       martin   1719: }
                   1720:
                   1721: static bool
1.50      martin   1722: edit_with_defaults(struct disk_partitions *parts,
1.9       martin   1723:     daddr_t start, daddr_t size, struct partition_usage_set *wanted)
                   1724: {
                   1725:        bool ok;
                   1726:
                   1727:        fill_defaults(wanted, parts, start, size);
                   1728:        ok = get_ptn_sizes(wanted);
                   1729:        if (ok)
1.50      martin   1730:                apply_settings_to_partitions(parts, wanted, start, size);
1.9       martin   1731:        return ok;
                   1732: }
                   1733:
                   1734: /*
                   1735:  * md back-end code for menu-driven BSD disklabel editor.
1.52      martin   1736:  * returns 0 on failure, 1 on success, -1 for restart.
1.9       martin   1737:  * fills the install target with a list for newfs/fstab.
                   1738:  */
1.52      martin   1739: int
1.9       martin   1740: make_bsd_partitions(struct install_partition_desc *install)
                   1741: {
                   1742:        struct disk_partitions *parts = pm->parts;
                   1743:        const struct disk_partitioning_scheme *pscheme;
                   1744:        struct partition_usage_set wanted;
1.51      martin   1745:        daddr_t p_start, p_size;
1.9       martin   1746:        enum layout_type layoutkind = LY_SETSIZES;
                   1747:        bool have_existing;
                   1748:
                   1749:        if (pm && pm->no_part && parts == NULL)
1.52      martin   1750:                return 1;
1.9       martin   1751:        if (parts == NULL) {
1.29      martin   1752:                pscheme = select_part_scheme(pm, NULL, !pm->no_mbr, NULL);
1.9       martin   1753:                if (pscheme == NULL)
1.52      martin   1754:                        return 0;
1.9       martin   1755:                parts = pscheme->create_new_for_disk(pm->diskdev,
1.38      martin   1756:                    0, pm->dlsize, true, NULL);
1.9       martin   1757:                if (parts == NULL)
1.52      martin   1758:                        return 0;
1.9       martin   1759:                pm->parts = parts;
                   1760:        } else {
                   1761:                pscheme = parts->pscheme;
                   1762:        }
                   1763:
                   1764:        if (pscheme->secondary_partitions) {
                   1765:                struct disk_partitions *p;
                   1766:
1.12      martin   1767:                p = pscheme->secondary_partitions(parts, pm->ptstart, false);
1.9       martin   1768:                if (p) {
                   1769:                        parts = p;
                   1770:                        pscheme = parts->pscheme;
                   1771:                }
                   1772:        }
                   1773:
                   1774:        have_existing = check_existing_netbsd(parts);
                   1775:
                   1776:        /*
1.52      martin   1777:         * Make sure the cylinder size multiplier/divisor and disk sieze are
                   1778:         * valid
1.9       martin   1779:         */
                   1780:        if (pm->current_cylsize == 0)
                   1781:                pm->current_cylsize = pm->dlcylsize;
1.52      martin   1782:        if (pm->ptsize == 0)
                   1783:                pm->ptsize = pm->dlsize;
1.9       martin   1784:
                   1785:        /* Ask for layout type -- standard or special */
                   1786:        if (partman_go == 0) {
                   1787:                char bsd_size[6], min_size[6], x_size[6];
                   1788:
                   1789:                humanize_number(bsd_size, sizeof(bsd_size),
                   1790:                    (uint64_t)pm->ptsize*pm->sectorsize,
                   1791:                    "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
                   1792:                humanize_number(min_size, sizeof(min_size),
                   1793:                    (uint64_t)(DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE)*MEG,
                   1794:                    "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
                   1795:                humanize_number(x_size, sizeof(x_size),
                   1796:                    (uint64_t)(DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE
                   1797:                    + XNEEDMB)*MEG,
                   1798:                    "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
                   1799:
                   1800:                msg_display_subst(
                   1801:                    have_existing ? MSG_layout_prologue_existing
                   1802:                    : MSG_layout_prologue_none, 6, pm->diskdev,
                   1803:                    msg_string(parts->pscheme->name),
                   1804:                    msg_string(parts->pscheme->short_name),
                   1805:                    bsd_size, min_size, x_size);
                   1806:                msg_display_add_subst(MSG_layout_main, 6,
                   1807:                    pm->diskdev,
                   1808:                    msg_string(parts->pscheme->name),
                   1809:                    msg_string(parts->pscheme->short_name),
                   1810:                    bsd_size, min_size, x_size);
                   1811:                msg_display_add("\n\n");
                   1812:                layoutkind = ask_layout(parts, have_existing);
1.52      martin   1813:                if (layoutkind == LY_ERROR)
                   1814:                        return 0;
1.9       martin   1815:        }
                   1816:
1.51      martin   1817:        if (layoutkind == LY_USEDEFAULT || layoutkind == LY_SETSIZES) {
                   1818:                /* calc available disk area for the NetBSD partitions */
                   1819:                p_start = pm->ptstart;
                   1820:                p_size = pm->ptsize;
1.57    ! rillig   1821:                if (parts->parent != NULL &&
1.51      martin   1822:                    parts->parent->pscheme->guess_install_target != NULL)
                   1823:                        parts->parent->pscheme->guess_install_target(
                   1824:                            parts->parent, &p_start, &p_size);
                   1825:        }
1.52      martin   1826:        if (layoutkind == LY_OTHERSCHEME) {
                   1827:                parts->pscheme->destroy_part_scheme(parts);
                   1828:                return -1;
1.57    ! rillig   1829:        } else if (layoutkind == LY_USEDEFAULT) {
1.51      martin   1830:                replace_by_default(parts, p_start, p_size,
1.9       martin   1831:                    &wanted);
                   1832:        } else if (layoutkind == LY_SETSIZES) {
1.51      martin   1833:                if (!edit_with_defaults(parts, p_start, p_size,
1.9       martin   1834:                    &wanted)) {
                   1835:                        free_usage_set(&wanted);
1.52      martin   1836:                        return 0;
1.9       martin   1837:                }
                   1838:        } else {
                   1839:                usage_set_from_parts(&wanted, parts);
1.2       martin   1840:        }
1.1       dholland 1841:
                   1842:        /*
1.49      martin   1843:         * Make sure the target root partition is properly marked,
                   1844:         * check for existing EFI boot partition.
1.47      martin   1845:         */
                   1846:        bool have_inst_target = false;
1.49      martin   1847: #ifdef HAVE_EFI_BOOT
                   1848:        daddr_t target_start = -1;
                   1849: #endif
1.47      martin   1850:        for (size_t i = 0; i < wanted.num; i++) {
                   1851:                if (wanted.infos[i].cur_flags & PTI_INSTALL_TARGET) {
                   1852:                        have_inst_target = true;
1.49      martin   1853: #ifdef HAVE_EFI_BOOT
                   1854:                        target_start = wanted.infos[i].cur_start;
                   1855: #endif
1.47      martin   1856:                        break;
                   1857:                 }
                   1858:        }
                   1859:        if (!have_inst_target) {
                   1860:                for (size_t i = 0; i < wanted.num; i++) {
                   1861:                        struct disk_part_info info;
                   1862:
                   1863:                        if (wanted.infos[i].type != PT_root ||
1.57    ! rillig   1864:                            strcmp(wanted.infos[i].mount, "/") != 0)
1.47      martin   1865:                                continue;
                   1866:                        wanted.infos[i].cur_flags |= PTI_INSTALL_TARGET;
                   1867:
                   1868:                        if (!wanted.parts->pscheme->get_part_info(wanted.parts,
                   1869:                            wanted.infos[i].cur_part_id, &info))
                   1870:                                break;
                   1871:                        info.flags |= PTI_INSTALL_TARGET;
                   1872:                        wanted.parts->pscheme->set_part_info(wanted.parts,
                   1873:                            wanted.infos[i].cur_part_id, &info, NULL);
1.49      martin   1874: #ifdef HAVE_EFI_BOOT
                   1875:                        target_start = wanted.infos[i].cur_start;
                   1876: #endif
1.47      martin   1877:                        break;
                   1878:                }
                   1879:        }
1.49      martin   1880: #ifdef HAVE_EFI_BOOT
                   1881:        size_t boot_part = ~0U;
                   1882:        for (part_id i = 0; i < wanted.num; i++) {
                   1883:                if ((wanted.infos[i].cur_flags & PTI_BOOT) != 0 ||
                   1884:                    wanted.infos[i].type ==  PT_EFI_SYSTEM) {
                   1885:                        boot_part = i;
                   1886:                        break;
                   1887:                }
                   1888:        }
                   1889:        if (boot_part == ~0U) {
                   1890:                for (part_id i = 0; i < wanted.num; i++) {
                   1891:                        /*
                   1892:                         * heuristic to recognize existing MBR FAT
                   1893:                         * partitions as EFI without looking for
                   1894:                         * details
                   1895:                         */
                   1896:                        if ((wanted.infos[i].type != PT_FAT &&
                   1897:                            wanted.infos[i].type != PT_EFI_SYSTEM) ||
                   1898:                            wanted.infos[i].fs_type != FS_MSDOS)
                   1899:                                continue;
                   1900:                        daddr_t ps = wanted.infos[i].cur_start;
                   1901:                        daddr_t pe = ps + wanted.infos[i].size;
                   1902:                        if (target_start >= 0 &&
1.57    ! rillig   1903:                           (ps >= target_start || pe >= target_start))
1.49      martin   1904:                                continue;
                   1905:                        boot_part = i;
                   1906:                        break;
                   1907:                }
                   1908:        }
                   1909:        if (boot_part != ~0U) {
                   1910:                struct disk_part_info info;
                   1911:
                   1912:                if (wanted.parts->pscheme->get_part_info(wanted.parts,
                   1913:                    wanted.infos[boot_part].cur_part_id, &info)) {
                   1914:                        info.flags |= PTI_BOOT;
                   1915:                        wanted.parts->pscheme->set_part_info(wanted.parts,
                   1916:                            wanted.infos[boot_part].cur_part_id, &info, NULL);
                   1917:                }
                   1918:                wanted.infos[boot_part].instflags |= PUIINST_BOOT;
                   1919:        }
                   1920: #endif
1.47      martin   1921:
                   1922:        /*
1.1       dholland 1923:         * OK, we have a partition table. Give the user the chance to
                   1924:         * edit it and verify it's OK, or abort altogether.
                   1925:         */
1.9       martin   1926:        for (;;) {
1.34      martin   1927:                int rv = edit_and_check_label(pm, &wanted, true);
1.9       martin   1928:                if (rv == 0) {
                   1929:                        msg_display(MSG_abort_part);
                   1930:                        free_usage_set(&wanted);
1.52      martin   1931:                        return 0;
1.9       martin   1932:                }
                   1933:                /* update install infos */
                   1934:                install->num = wanted.num;
                   1935:                install->infos = wanted.infos;
1.43      martin   1936:                install->write_back = wanted.write_back;
                   1937:                install->num_write_back = wanted.num_write_back;
1.9       martin   1938:                /* and check them */
                   1939:                if (check_partitions(install))
                   1940:                        break;
                   1941:        }
1.1       dholland 1942:
1.9       martin   1943:        /* we moved infos from wanted to install target */
                   1944:        wanted.infos = NULL;
1.43      martin   1945:        wanted.write_back = NULL;
1.9       martin   1946:        free_usage_set(&wanted);
1.1       dholland 1947:
                   1948:        /* Everything looks OK. */
1.52      martin   1949:        return 1;
1.1       dholland 1950: }
                   1951:
1.20      martin   1952: #ifndef MD_NEED_BOOTBLOCK
                   1953: #define MD_NEED_BOOTBLOCK(A)   true
                   1954: #endif
                   1955:
1.1       dholland 1956: /*
                   1957:  * check that there is at least a / somewhere.
                   1958:  */
1.9       martin   1959: bool
                   1960: check_partitions(struct install_partition_desc *install)
1.1       dholland 1961: {
                   1962: #ifdef HAVE_BOOTXX_xFS
1.2       martin   1963:        int rv = 1;
1.1       dholland 1964:        char *bootxx;
                   1965: #endif
                   1966: #ifndef HAVE_UFS2_BOOT
1.9       martin   1967:        size_t i;
1.1       dholland 1968: #endif
                   1969:
                   1970: #ifdef HAVE_BOOTXX_xFS
1.20      martin   1971:        if (MD_NEED_BOOTBLOCK(install)) {
                   1972:                /* check if we have boot code for the root partition type */
                   1973:                bootxx = bootxx_name(install);
                   1974:                if (bootxx != NULL) {
                   1975:                        rv = access(bootxx, R_OK);
                   1976:                        free(bootxx);
                   1977:                } else
                   1978:                        rv = -1;
                   1979:                if (rv != 0) {
                   1980:                        hit_enter_to_continue(NULL, MSG_No_Bootcode);
                   1981:                        return false;
                   1982:                }
1.1       dholland 1983:        }
                   1984: #endif
                   1985: #ifndef HAVE_UFS2_BOOT
1.20      martin   1986:        if (MD_NEED_BOOTBLOCK(install)) {
                   1987:                for (i = 0; i < install->num; i++) {
                   1988:                        if (install->infos[i].type != PT_root)
                   1989:                                continue;
                   1990:                        if (strcmp(install->infos[i].mount, "/") != 0)
                   1991:                                continue;
                   1992:                        if (install->infos[i].fs_type != FS_BSDFFS)
                   1993:                                continue;
                   1994:                        if (install->infos[i].fs_version != 2)
                   1995:                                continue;
                   1996:                        hit_enter_to_continue(NULL, MSG_cannot_ufs2_root);
                   1997:                        return false;
                   1998:                }
1.1       dholland 1999:        }
                   2000: #endif
                   2001:
1.9       martin   2002:        return md_check_partitions(install);
1.1       dholland 2003: }

CVSweb <webmaster@jp.NetBSD.org>