Module Name: src Committed By: martin Date: Tue Nov 12 16:33:14 UTC 2019
Modified Files: src/usr.sbin/sysinst: bsddisklabel.c defs.h disklabel.c disks.c gpt.c install.c label.c main.c mbr.c mbr.h msg.mi.de msg.mi.en msg.mi.es msg.mi.fr msg.mi.pl part_edit.c partitions.c partitions.h util.c src/usr.sbin/sysinst/arch/i386: md.c Log Message: Add options to the various partitioning stages that allow cloning of alien partitions (optionally including data). To generate a diff of this commit: cvs rdiff -u -r1.29 -r1.30 src/usr.sbin/sysinst/bsddisklabel.c cvs rdiff -u -r1.45 -r1.46 src/usr.sbin/sysinst/defs.h cvs rdiff -u -r1.14 -r1.15 src/usr.sbin/sysinst/disklabel.c cvs rdiff -u -r1.54 -r1.55 src/usr.sbin/sysinst/disks.c cvs rdiff -u -r1.11 -r1.12 src/usr.sbin/sysinst/gpt.c \ src/usr.sbin/sysinst/install.c cvs rdiff -u -r1.12 -r1.13 src/usr.sbin/sysinst/label.c cvs rdiff -u -r1.17 -r1.18 src/usr.sbin/sysinst/main.c \ src/usr.sbin/sysinst/msg.mi.es cvs rdiff -u -r1.21 -r1.22 src/usr.sbin/sysinst/mbr.c \ src/usr.sbin/sysinst/msg.mi.fr cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/sysinst/mbr.h cvs rdiff -u -r1.16 -r1.17 src/usr.sbin/sysinst/msg.mi.de cvs rdiff -u -r1.23 -r1.24 src/usr.sbin/sysinst/msg.mi.en cvs rdiff -u -r1.24 -r1.25 src/usr.sbin/sysinst/msg.mi.pl cvs rdiff -u -r1.10 -r1.11 src/usr.sbin/sysinst/part_edit.c cvs rdiff -u -r1.4 -r1.5 src/usr.sbin/sysinst/partitions.c cvs rdiff -u -r1.7 -r1.8 src/usr.sbin/sysinst/partitions.h cvs rdiff -u -r1.34 -r1.35 src/usr.sbin/sysinst/util.c cvs rdiff -u -r1.21 -r1.22 src/usr.sbin/sysinst/arch/i386/md.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/sysinst/bsddisklabel.c diff -u src/usr.sbin/sysinst/bsddisklabel.c:1.29 src/usr.sbin/sysinst/bsddisklabel.c:1.30 --- src/usr.sbin/sysinst/bsddisklabel.c:1.29 Fri Oct 25 12:24:34 2019 +++ src/usr.sbin/sysinst/bsddisklabel.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: bsddisklabel.c,v 1.29 2019/10/25 12:24:34 martin Exp $ */ +/* $NetBSD: bsddisklabel.c,v 1.30 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -251,6 +251,11 @@ draw_size_menu_line(menudesc *m, int opt mount = swap; } else if (pset->infos[opt].mount[0]) { mount = pset->infos[opt].mount; + } else if (pset->infos[opt].flags & PUIFLG_CLONE_PARTS) { + snprintf(swap, sizeof swap, "%zu %s", + pset->infos[opt].clone_src->num_sel, + msg_string(MSG_clone_target_disp)); + mount = swap; } else { mount = NULL; if (pset->infos[opt].parts->pscheme->other_partition_identifier @@ -319,7 +324,7 @@ add_other_ptn_size(menudesc *menu, void break; } - m = realloc(pset->menu_opts, (pset->num+4)*sizeof(*pset->menu_opts)); + m = realloc(pset->menu_opts, (pset->num+5)*sizeof(*pset->menu_opts)); if (m == NULL) return 0; p = realloc(pset->infos, (pset->num+1)*sizeof(*pset->infos)); @@ -348,6 +353,84 @@ add_other_ptn_size(menudesc *menu, void return -1; } +static int +inst_ext_clone(menudesc *menu, void *arg) +{ + struct selected_partitions selected; + struct clone_target_menu_data data; + struct partition_usage_set *pset = arg; + struct part_usage_info *p; + menu_ent *men; + int num_men, i; + + if (!select_partitions(&selected, pm->parts)) + return 0; + + num_men = pset->num+1; + men = calloc(num_men, sizeof *men); + if (men == NULL) + return 0; + for (i = 0; i < num_men; i++) + men[i].opt_action = clone_target_select; + men[num_men-1].opt_name = MSG_clone_target_end; + + memset(&data, 0, sizeof data); + data.usage = *pset; + data.res = -1; + + data.usage.menu = new_menu(MSG_clone_target_hdr, + men, num_men, 3, 2, 0, 65, MC_SCROLL, + NULL, draw_size_menu_line, NULL, NULL, MSG_cancel); + process_menu(data.usage.menu, &data); + free_menu(data.usage.menu); + free(men); + + if (data.res < 0) + goto err; + + /* insert clone record */ + men = realloc(pset->menu_opts, (pset->num+5)*sizeof(*pset->menu_opts)); + if (men == NULL) + goto err; + pset->menu_opts = men; + menu->opts = men; + menu->numopts = pset->num+4; + + p = realloc(pset->infos, (pset->num+1)*sizeof(*pset->infos)); + if (p == NULL) + goto err; + pset->infos = p; + + men += data.res; + p += data.res; + memmove(men+1, men, sizeof(*men)*((pset->num+4)-data.res)); + memmove(p+1, p, sizeof(*p)*((pset->num)-data.res)); + memset(men, 0, sizeof(*men)); + memset(p, 0, sizeof(*p)); + p->flags = PUIFLG_CLONE_PARTS; + p->cur_part_id = NO_PART; + p->clone_src = malloc(sizeof(selected)); + if (p->clone_src != NULL) { + *p->clone_src = selected; + p->clone_ndx = ~0U; + p->size = selected_parts_size(&selected); + p->parts = pset->parts; + } else { + p->clone_ndx = 0; + free_selected_partitions(&selected); + } + + menu->cursel = data.res == 0 ? 1 : 0; + pset->num++; + fill_ptn_menu(pset); + + return -1; + +err: + free_selected_partitions(&selected); + return 0; +} + static size_t fill_ptn_menu(struct partition_usage_set *pset) { @@ -357,9 +440,12 @@ fill_ptn_menu(struct partition_usage_set size_t i; daddr_t free_space; - memset(pset->menu_opts, 0, (pset->num+3)*sizeof(*pset->menu_opts)); + memset(pset->menu_opts, 0, (pset->num+4)*sizeof(*pset->menu_opts)); for (m = pset->menu_opts, p = pset->infos, i = 0; i < pset->num; m++, p++, i++) { + if (p->flags & PUIFLG_CLONE_PARTS) + m->opt_flags = OPT_IGNORE|OPT_NOSHORT; + else m->opt_action = set_ptn_size; } @@ -371,6 +457,10 @@ fill_ptn_menu(struct partition_usage_set m->opt_action = add_other_ptn_size; m++; + m->opt_name = MSG_clone_from_elsewhere; + m->opt_action = inst_ext_clone; + m++; + m->opt_name = MSG_askunits; m->opt_menu = MENU_sizechoice; m->opt_flags = OPT_SUB; @@ -552,7 +642,7 @@ get_ptn_sizes(struct partition_usage_set wrefresh(stdscr); if (pset->menu_opts == NULL) - pset->menu_opts = calloc(pset->num+3, sizeof(*pset->menu_opts)); + pset->menu_opts = calloc(pset->num+4, sizeof(*pset->menu_opts)); pset->menu = -1; num = fill_ptn_menu(pset); @@ -1000,7 +1090,7 @@ sort_and_sync_parts(struct partition_usa continue; if (pset->infos[i].flags & PUIFLG_JUST_MOUNTPOINT) continue; - if ((pset->infos[i].flags & (PUIFLG_IS_OUTER|PUIFLAG_ADD_INNER)) + if ((pset->infos[i].flags & (PUIFLG_IS_OUTER|PUIFLG_ADD_INNER)) == PUIFLG_IS_OUTER) continue; if (pno >= pset->parts->num_part) @@ -1046,17 +1136,73 @@ sort_and_sync_parts(struct partition_usa pset->infos = infos; } +/* + * Convert clone entries with more than one source into + * several entries with a single source each. + */ +static void +normalize_clones(struct part_usage_info **infos, size_t *num) +{ + size_t i, j, add_clones; + struct part_usage_info *ui, *src, *target; + struct disk_part_info info; + struct selected_partition *clone; + + for (add_clones = 0, i = 0; i < *num; i++) { + if ((*infos)[i].clone_src != NULL && + (*infos)[i].flags & PUIFLG_CLONE_PARTS && + (*infos)[i].cur_part_id == NO_PART) + add_clones += (*infos)[i].clone_src->num_sel-1; + } + if (add_clones == 0) + return; + + ui = calloc(*num+add_clones, sizeof(**infos)); + if (ui == NULL) + return; /* can not handle this well here, drop some clones */ + + /* walk the list and dedup clones */ + for (src = *infos, target = ui, i = 0; i < *num; i++) { + if (src != target) + *target = *src; + if (target->clone_src != NULL && + (target->flags & PUIFLG_CLONE_PARTS) && + target->cur_part_id == NO_PART) { + for (j = 0; j < src->clone_src->num_sel; j++) { + if (j > 0) { + target++; + *target = *src; + } + target->clone_ndx = j; + clone = &target->clone_src->selection[j]; + clone->parts->pscheme->get_part_info( + clone->parts, clone->id, &info); + target->size = info.size; + } + } + target++; + src++; + } + *num += add_clones; + assert((target-ui) >= 0 && (size_t)(target-ui) == *num); + free(*infos); + *infos = ui; +} + static void apply_settings_to_partitions(struct pm_devs *p, struct disk_partitions *parts, struct partition_usage_set *wanted, daddr_t start, daddr_t size) { size_t i, exp_ndx = ~0U; daddr_t planned_space = 0, nsp, from, align; - struct disk_part_info *infos; + struct disk_part_info *infos, cinfo, srcinfo; struct disk_part_free_space space; struct disk_partitions *ps = NULL; + struct selected_partition *sp; part_id pno, new_part_id; + normalize_clones(&wanted->infos, &wanted->num); + infos = calloc(wanted->num, sizeof(*infos)); if (infos == NULL) { err_msg_win(err_outofmem); @@ -1167,14 +1313,14 @@ apply_settings_to_partitions(struct pm_d new_part_id, &infos[i]); want->cur_part_id = new_part_id; - want->flags |= PUIFLAG_ADD_INNER|PUIFLG_IS_OUTER; + want->flags |= PUIFLG_ADD_INNER|PUIFLG_IS_OUTER; from = rounddown(infos[i].start + infos[i].size+outer_align, outer_align); } } /* - * Now add new inner partitions + * Now add new inner partitions (and cloned partitions) */ for (i = 0; i < wanted->num && from < wanted->parts->disk_size; i++) { struct part_usage_info *want = &wanted->infos[i]; @@ -1183,35 +1329,66 @@ apply_settings_to_partitions(struct pm_d continue; if (want->flags & (PUIFLG_JUST_MOUNTPOINT|PUIFLG_IS_OUTER)) continue; - if (want->size <= 0) - continue; + if ((want->flags & PUIFLG_CLONE_PARTS) && + want->clone_src != NULL && + want->clone_ndx < want->clone_src->num_sel) { + sp = &want->clone_src->selection[want->clone_ndx]; + if (!sp->parts->pscheme->get_part_info( + sp->parts, sp->id, &srcinfo)) + continue; + if (!wanted->parts->pscheme-> + adapt_foreign_part_info(wanted->parts, + &cinfo, sp->parts->pscheme, &srcinfo)) + continue; - size_t cnt = wanted->parts->pscheme->get_free_spaces( - wanted->parts, &space, 1, want->size-align, align, from, - -1); - if (cnt == 0) - cnt = wanted->parts->pscheme->get_free_spaces( - wanted->parts, &space, 1, - want->size-5*align, align, from, -1); - - if (cnt == 0) - continue; /* no free space for this partition */ - - infos[i].start = space.start; - infos[i].size = min(want->size, space.size); - infos[i].nat_type = - wanted->parts->pscheme->get_fs_part_type(want->fs_type, - want->fs_version); - infos[i].last_mounted = want->mount; - infos[i].fs_type = want->fs_type; - infos[i].fs_sub_type = want->fs_version; - if (want->fs_type != FS_UNUSED && want->type != PT_swap) { - want->instflags |= PUIINST_NEWFS; - if (want->mount[0] != 0) - want->instflags |= PUIINST_MOUNT; + /* find space for cinfo and add a partition */ + size_t cnt = wanted->parts->pscheme->get_free_spaces( + wanted->parts, &space, 1, want->size-align, align, + from, -1); + if (cnt == 0) + cnt = wanted->parts->pscheme->get_free_spaces( + wanted->parts, &space, 1, + want->size-5*align, align, from, -1); + + if (cnt == 0) + continue; /* no free space for this clone */ + + infos[i] = cinfo; + infos[i].start = space.start; + new_part_id = wanted->parts->pscheme->add_partition( + wanted->parts, &infos[i], NULL); + } else { + if (want->size <= 0) + continue; + size_t cnt = wanted->parts->pscheme->get_free_spaces( + wanted->parts, &space, 1, want->size-align, align, + from, -1); + if (cnt == 0) + cnt = wanted->parts->pscheme->get_free_spaces( + wanted->parts, &space, 1, + want->size-5*align, align, from, -1); + + if (cnt == 0) + continue; /* no free space for this partition */ + + infos[i].start = space.start; + infos[i].size = min(want->size, space.size); + infos[i].nat_type = + wanted->parts->pscheme->get_fs_part_type( + want->fs_type, want->fs_version); + infos[i].last_mounted = want->mount; + infos[i].fs_type = want->fs_type; + infos[i].fs_sub_type = want->fs_version; + if (want->fs_type != FS_UNUSED && + want->type != PT_swap) { + want->instflags |= PUIINST_NEWFS; + if (want->mount[0] != 0) + want->instflags |= PUIINST_MOUNT; + } + new_part_id = wanted->parts->pscheme->add_partition( + wanted->parts, &infos[i], NULL); } - new_part_id = wanted->parts->pscheme->add_partition( - wanted->parts, &infos[i], NULL); + if (new_part_id == NO_PART) continue; /* failed to add, skip */ @@ -1235,8 +1412,8 @@ apply_settings_to_partitions(struct pm_d if (want->size <= 0) continue; - if ((want->flags & (PUIFLAG_ADD_INNER|PUIFLG_IS_OUTER)) != - (PUIFLAG_ADD_INNER|PUIFLG_IS_OUTER)) + if ((want->flags & (PUIFLG_ADD_INNER|PUIFLG_IS_OUTER)) != + (PUIFLG_ADD_INNER|PUIFLG_IS_OUTER)) continue; infos[i].start = want->cur_start; Index: src/usr.sbin/sysinst/defs.h diff -u src/usr.sbin/sysinst/defs.h:1.45 src/usr.sbin/sysinst/defs.h:1.46 --- src/usr.sbin/sysinst/defs.h:1.45 Wed Oct 2 11:16:04 2019 +++ src/usr.sbin/sysinst/defs.h Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: defs.h,v 1.45 2019/10/02 11:16:04 maya Exp $ */ +/* $NetBSD: defs.h,v 1.46 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -252,8 +252,9 @@ struct part_usage_info { #define PUIFLAG_ADD_OUTER 2 /* Add this partition to the outer * partitions (if available) */ #define PUIFLG_IS_OUTER 4 /* this is an existing outer one */ -#define PUIFLAG_ADD_INNER 8 /* add outer also to inner */ +#define PUIFLG_ADD_INNER 8 /* add outer also to inner */ #define PUIFLG_JUST_MOUNTPOINT 16 /* tmpfs of mfs mountpoints */ +#define PUIFLG_CLONE_PARTS 32 /* clone external partitions */ uint flags; struct disk_partitions *parts; /* Where does this partition live? * We currently only support @@ -282,6 +283,17 @@ struct part_usage_info { unsigned int instflags; /* installer handling flags */ uint fs_type, fs_version; /* e.g. FS_LFS, or FS_BSDFS, * version = 2 for FFSv2 */ + /* + * Only != NULL when PUIFLG_CLONE_PARTS is set, describes the + * source partitions to clone here. + */ + struct selected_partitions *clone_src; + /* + * If clone_src != NULL, this record corresponds to a single + * selected source partition, if clone_ndx is a valid index in clone_src + * (>= 0 && <= clone_src->num_sel, or all of them if clone_ndx = ~0U. + */ + size_t clone_ndx; }; /* @@ -607,6 +619,30 @@ bool is_cdrom_device(const char *dev, bo bool is_bootable_device(const char *dev); bool is_partitionable_device(const char *dev); bool convert_scheme(struct pm_devs *p, bool is_boot_drive, const char **err_msg); +/* a single partition selected for cloning (etc) */ +struct selected_partition { + struct disk_partitions *parts; + part_id id; +}; +struct selected_partitions { + struct selected_partition *selection; + size_t num_sel; + bool with_data; /* partitions and their data selected */ + bool free_parts; /* caller should free parts */ +}; +bool select_partitions(struct selected_partitions *res, + const struct disk_partitions *ignore); +daddr_t selected_parts_size(struct selected_partitions *); +void free_selected_partitions(struct selected_partitions *); + +struct clone_target_menu_data { + struct partition_usage_set usage; + int res; +}; + +int clone_target_select(menudesc *m, void *arg); +bool clone_partition_data(struct disk_partitions *dest_parts, part_id did, + struct disk_partitions *src_parts, part_id sid); struct menudesc; void disp_cur_fspart(int, int); @@ -716,6 +752,7 @@ bool md_parts_use_wholedisk(struct disk_ /* from util.c */ bool root_is_read_only(void); void get_ptn_alignment(const struct disk_partitions *parts, daddr_t *align, daddr_t *p0off); +struct disk_partitions *get_inner_parts(struct disk_partitions *parts); char* str_arg_subst(const char *, size_t, const char **); void msg_display_subst(const char *, size_t, ...); void msg_display_add_subst(const char *, size_t, ...); Index: src/usr.sbin/sysinst/disklabel.c diff -u src/usr.sbin/sysinst/disklabel.c:1.14 src/usr.sbin/sysinst/disklabel.c:1.15 --- src/usr.sbin/sysinst/disklabel.c:1.14 Mon Oct 21 16:09:59 2019 +++ src/usr.sbin/sysinst/disklabel.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: disklabel.c,v 1.14 2019/10/21 16:09:59 martin Exp $ */ +/* $NetBSD: disklabel.c,v 1.15 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 2018 The NetBSD Foundation, Inc. @@ -140,7 +140,7 @@ disklabel_parts_new(const char *dev, dad parts->l.d_secpercyl = geo.dg_nsectors * geo.dg_ntracks; parts->dp.pscheme = &disklabel_parts; - parts->dp.disk = dev; + parts->dp.disk = strdup(dev); parts->dp.disk_start = start; parts->dp.disk_size = parts->dp.free_space = len; disklabel_init_default_alignment(parts, parts->l.d_secpercyl); @@ -216,7 +216,7 @@ disklabel_parts_read(const char *disk, d if (len > disklabel_parts.size_limit) len = disklabel_parts.size_limit; parts->dp.pscheme = scheme; - parts->dp.disk = disk; + parts->dp.disk = strdup(disk); parts->dp.disk_start = start; parts->dp.disk_size = parts->dp.free_space = len; disklabel_init_default_alignment(parts, 0); @@ -582,6 +582,12 @@ disklabel_get_fs_part_type(unsigned fsty } static const struct part_type_desc * +disklabel_create_unknown_part_type(void) +{ + return disklabel_find_type(FS_OTHER, false); +} + +static const struct part_type_desc * disklabel_get_generic_type(enum part_type pt) { size_t nt; @@ -1076,6 +1082,7 @@ disklabel_free(struct disk_partitions *a { assert(arg != NULL); + free(__UNCONST(arg->disk)); free(arg); } @@ -1100,7 +1107,9 @@ disklabel_parts = { .get_generic_part_type = disklabel_get_generic_type, .get_fs_part_type = disklabel_get_fs_part_type, .create_custom_part_type = disklabel_create_custom_part_type, + .create_unknown_part_type = disklabel_create_unknown_part_type, .get_part_alignment = disklabel_get_alignment, + .adapt_foreign_part_info = generic_adapt_foreign_part_info, .get_part_info = disklabel_get_part_info, .can_add_partition = disklabel_can_add_partition, .set_part_info = disklabel_set_part_info, Index: src/usr.sbin/sysinst/disks.c diff -u src/usr.sbin/sysinst/disks.c:1.54 src/usr.sbin/sysinst/disks.c:1.55 --- src/usr.sbin/sysinst/disks.c:1.54 Fri Oct 25 12:49:58 2019 +++ src/usr.sbin/sysinst/disks.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: disks.c,v 1.54 2019/10/25 12:49:58 martin Exp $ */ +/* $NetBSD: disks.c,v 1.55 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -734,7 +734,7 @@ convert_copy(struct disk_partitions *old } if (!new_parts->pscheme->adapt_foreign_part_info(new_parts, - &oinfo, &ninfo)) + &ninfo, old_parts->pscheme, &oinfo)) continue; new_parts->pscheme->add_partition(new_parts, &ninfo, NULL); } @@ -2045,3 +2045,472 @@ get_dkwedges(struct dkwedge_info **dkw, return dkwl.dkwl_nwedges; } + +/* + * Helper structures used in the partition select menu + */ +struct single_partition { + struct disk_partitions *parts; + part_id id; +}; + +struct sel_menu_data { + struct single_partition *partitions; + struct selected_partition result; +}; + +static int +select_single_part(menudesc *m, void *arg) +{ + struct sel_menu_data *data = arg; + + data->result.parts = data->partitions[m->cursel].parts; + data->result.id = data->partitions[m->cursel].id; + + return 1; +} + +static void +display_single_part(menudesc *m, int opt, void *arg) +{ + const struct sel_menu_data *data = arg; + struct disk_part_info info; + struct disk_partitions *parts = data->partitions[opt].parts; + part_id id = data->partitions[opt].id; + int l; + const char *desc = NULL; + char line[MENUSTRSIZE*2]; + + if (!parts->pscheme->get_part_info(parts, id, &info)) + return; + + if (parts->pscheme->other_partition_identifier != NULL) + desc = parts->pscheme->other_partition_identifier( + parts, id); + + daddr_t start = info.start / sizemult; + daddr_t size = info.size / sizemult; + snprintf(line, sizeof line, "%s [%" PRIu64 " @ %" PRIu64 "]", + parts->disk, size, start); + + if (info.nat_type != NULL) { + strlcat(line, " ", sizeof line); + strlcat(line, info.nat_type->description, sizeof line); + } + + if (desc != NULL) { + strlcat(line, ": ", sizeof line); + strlcat(line, desc, sizeof line); + } + + l = strlen(line); + if (l >= (m->w)) + strcpy(line + (m->w-3), "..."); + wprintw(m->mw, "%s", line); +} + +/* + * is the given "test" partitions set used in the selected set? + */ +static bool +selection_has_parts(struct selected_partitions *sel, + const struct disk_partitions *test) +{ + size_t i; + + for (i = 0; i < sel->num_sel; i++) { + if (sel->selection[i].parts == test) + return true; + } + return false; +} + +/* + * is the given "test" partition in the selected set? + */ +static bool +selection_has_partition(struct selected_partitions *sel, + const struct disk_partitions *test, part_id test_id) +{ + size_t i; + + for (i = 0; i < sel->num_sel; i++) { + if (sel->selection[i].parts == test && + sel->selection[i].id == test_id) + return true; + } + return false; +} + +/* + * let the user select a partition, optionally skipping all partitions + * on the "ignore" device + */ +static bool +add_select_partition(struct selected_partitions *res, + struct disk_partitions **all_parts, size_t all_cnt) +{ + struct disk_partitions *ps; + struct disk_part_info info; + part_id id; + struct single_partition *partitions, *pp; + struct menu_ent *part_menu_opts, *menup; + size_t n, part_cnt; + int sel_menu; + + /* + * count how many items our menu will have + */ + part_cnt = 0; + for (n = 0; n < all_cnt; n++) { + ps = all_parts[n]; + for (id = 0; id < ps->num_part; id++) { + if (selection_has_partition(res, ps, id)) + continue; + if (!ps->pscheme->get_part_info(ps, id, &info)) + continue; + if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK| + PTI_PSCHEME_INTERNAL|PTI_RAW_PART)) + continue; + part_cnt++; + } + } + + /* + * create a menu from this and let the user + * select one partition + */ + part_menu_opts = NULL; + partitions = calloc(part_cnt, sizeof *partitions); + if (partitions == NULL) + goto done; + part_menu_opts = calloc(part_cnt, sizeof *part_menu_opts); + if (part_menu_opts == NULL) + goto done; + pp = partitions; + menup = part_menu_opts; + for (n = 0; n < all_cnt; n++) { + ps = all_parts[n]; + for (id = 0; id < ps->num_part; id++) { + if (selection_has_partition(res, ps, id)) + continue; + if (!ps->pscheme->get_part_info(ps, id, &info)) + continue; + if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK| + PTI_PSCHEME_INTERNAL|PTI_RAW_PART)) + continue; + pp->parts = ps; + pp->id = id; + pp++; + menup->opt_action = select_single_part; + menup++; + } + } + sel_menu = new_menu(MSG_select_foreign_part, part_menu_opts, part_cnt, + 3, 3, 0, 60, + MC_SUBMENU | MC_SCROLL | MC_NOCLEAR, + NULL, display_single_part, NULL, + NULL, NULL); + if (sel_menu != -1) { + struct selected_partition *newsels; + struct sel_menu_data data; + + memset(&data, 0, sizeof data); + data.partitions = partitions; + process_menu(sel_menu, &data); + free_menu(sel_menu); + + if (data.result.parts != NULL) { + newsels = realloc(res->selection, + sizeof(*res->selection)*(res->num_sel+1)); + if (newsels != NULL) { + res->selection = newsels; + newsels += res->num_sel++; + newsels->parts = data.result.parts; + newsels->id = data.result.id; + } + } + } + + /* + * Final cleanup + */ +done: + free(part_menu_opts); + free(partitions); + + return res->num_sel > 0; +} + +struct part_selection_and_all_parts { + struct selected_partitions *selection; + struct disk_partitions **all_parts; + size_t all_cnt; + char *title; + bool cancelled; +}; + +static int +toggle_clone_data(struct menudesc *m, void *arg) +{ + struct part_selection_and_all_parts *sel = arg; + + sel->selection->with_data = !sel->selection->with_data; + return 0; +} + +static int +add_another(struct menudesc *m, void *arg) +{ + struct part_selection_and_all_parts *sel = arg; + + add_select_partition(sel->selection, sel->all_parts, sel->all_cnt); + return 0; +} + +static int +cancel_clone(struct menudesc *m, void *arg) +{ + struct part_selection_and_all_parts *sel = arg; + + sel->cancelled = true; + return 1; +} + +static void +update_sel_part_title(struct part_selection_and_all_parts *sel) +{ + struct disk_part_info info; + char *buf, line[MENUSTRSIZE]; + size_t buf_len, i; + + buf_len = MENUSTRSIZE * (1+sel->selection->num_sel); + buf = malloc(buf_len); + if (buf == NULL) + return; + + strcpy(buf, msg_string(MSG_select_source_hdr)); + for (i = 0; i < sel->selection->num_sel; i++) { + struct selected_partition *s = + &sel->selection->selection[i]; + if (!s->parts->pscheme->get_part_info(s->parts, s->id, &info)) + continue; + daddr_t start = info.start / sizemult; + daddr_t size = info.size / sizemult; + sprintf(line, "\n %s [%" PRIu64 " @ %" PRIu64 "] ", + s->parts->disk, size, start); + if (info.nat_type != NULL) + strlcat(line, info.nat_type->description, sizeof(line)); + strlcat(buf, line, buf_len); + } + free(sel->title); + sel->title = buf; +} + +static void +post_sel_part(struct menudesc *m, void *arg) +{ + struct part_selection_and_all_parts *sel = arg; + + if (m->mw == NULL) + return; + update_sel_part_title(sel); + m->title = sel->title; + m->h = 0; + resize_menu_height(m); +} + +static void +fmt_sel_part_line(struct menudesc *m, int i, void *arg) +{ + struct part_selection_and_all_parts *sel = arg; + + wprintw(m->mw, "%s: %s", msg_string(MSG_clone_with_data), + sel->selection->with_data ? + msg_string(MSG_Yes) : + msg_string(MSG_No)); +} + +bool +select_partitions(struct selected_partitions *res, + const struct disk_partitions *ignore) +{ + struct disk_desc disks[MAX_DISKS]; + struct disk_partitions *ps; + struct part_selection_and_all_parts data; + struct pm_devs *i; + size_t j; + int cnt, n, m; + static menu_ent men[] = { + { .opt_name = MSG_select_source_add, + .opt_action = add_another }, + { .opt_action = toggle_clone_data }, + { .opt_name = MSG_cancel, .opt_action = cancel_clone }, + }; + + memset(res, 0, sizeof *res); + memset(&data, 0, sizeof data); + data.selection = res; + + /* + * collect all available partition sets + */ + data.all_cnt = 0; + if (SLIST_EMPTY(&pm_head)) { + cnt = get_disks(disks, false); + if (cnt <= 0) + return false; + + /* + * allocate two slots for each disk (primary/secondary) + */ + data.all_parts = calloc(2*cnt, sizeof *data.all_parts); + if (data.all_parts == NULL) + return false; + + for (n = 0; n < cnt; n++) { + if (ignore != NULL && + strcmp(disks[n].dd_name, ignore->disk) == 0) + continue; + + ps = partitions_read_disk(disks[n].dd_name, + disks[n].dd_totsec, disks[n].dd_no_mbr); + if (ps == NULL) + continue; + data.all_parts[data.all_cnt++] = ps; + ps = get_inner_parts(ps); + if (ps == NULL) + continue; + data.all_parts[data.all_cnt++] = ps; + } + if (data.all_cnt > 0) + res->free_parts = true; + } else { + cnt = 0; + SLIST_FOREACH(i, &pm_head, l) + cnt++; + + data.all_parts = calloc(cnt, sizeof *data.all_parts); + if (data.all_parts == NULL) + return false; + + SLIST_FOREACH(i, &pm_head, l) { + if (i->parts == NULL) + continue; + if (i->parts == ignore) + continue; + data.all_parts[data.all_cnt++] = i->parts; + } + } + + if (!add_select_partition(res, data.all_parts, data.all_cnt)) + goto fail; + + /* loop with menu */ + update_sel_part_title(&data); + m = new_menu(data.title, men, __arraycount(men), 3, 2, 0, 65, MC_SCROLL, + post_sel_part, fmt_sel_part_line, NULL, NULL, + "Source selection OK, proceed to target selection"); + process_menu(m, &data); + free(data.title); + if (res->num_sel == 0) + goto fail; + + /* cleanup */ + if (res->free_parts) { + for (j = 0; j < data.all_cnt; j++) { + if (selection_has_parts(res, data.all_parts[j])) + continue; + if (data.all_parts[j]->parent != NULL) + continue; + data.all_parts[j]->pscheme->free(data.all_parts[j]); + } + } + free(data.all_parts); + return true; + +fail: + if (res->free_parts) { + for (j = 0; j < data.all_cnt; j++) { + if (data.all_parts[j]->parent != NULL) + continue; + data.all_parts[j]->pscheme->free(data.all_parts[j]); + } + } + free(data.all_parts); + return false; +} + +void +free_selected_partitions(struct selected_partitions *selected) +{ + size_t i; + struct disk_partitions *parts; + + if (!selected->free_parts) + return; + + for (i = 0; i < selected->num_sel; i++) { + parts = selected->selection[i].parts; + + /* remove from list before testing for other instances */ + selected->selection[i].parts = NULL; + + /* if this is the secondary partion set, the parent owns it */ + if (parts->parent != NULL) + continue; + + /* only free once (we use the last one) */ + if (selection_has_parts(selected, parts)) + continue; + parts->pscheme->free(parts); + } + free(selected->selection); +} + +daddr_t +selected_parts_size(struct selected_partitions *selected) +{ + struct disk_part_info info; + size_t i; + daddr_t s = 0; + + for (i = 0; i < selected->num_sel; i++) { + if (!selected->selection[i].parts->pscheme->get_part_info( + selected->selection[i].parts, + selected->selection[i].id, &info)) + continue; + s += info.size; + } + + return s; +} + +int +clone_target_select(menudesc *m, void *arg) +{ + struct clone_target_menu_data *data = arg; + + data->res = m->cursel; + return 1; +} + +bool +clone_partition_data(struct disk_partitions *dest_parts, part_id did, + struct disk_partitions *src_parts, part_id sid) +{ + char src_dev[MAXPATHLEN], target_dev[MAXPATHLEN]; + + if (!src_parts->pscheme->get_part_device( + src_parts, sid, src_dev, sizeof src_dev, NULL, + raw_dev_name, true)) + return false; + if (!dest_parts->pscheme->get_part_device( + dest_parts, did, target_dev, sizeof target_dev, NULL, + raw_dev_name, true)) + return false; + + return run_program(RUN_DISPLAY | RUN_PROGRESS, + "progress -f %s -b 1m dd bs=1m of=%s", + src_dev, target_dev) == 0; +} Index: src/usr.sbin/sysinst/gpt.c diff -u src/usr.sbin/sysinst/gpt.c:1.11 src/usr.sbin/sysinst/gpt.c:1.12 --- src/usr.sbin/sysinst/gpt.c:1.11 Mon Aug 26 12:14:06 2019 +++ src/usr.sbin/sysinst/gpt.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: gpt.c,v 1.11 2019/08/26 12:14:06 martin Exp $ */ +/* $NetBSD: gpt.c,v 1.12 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 2018 The NetBSD Foundation, Inc. @@ -32,10 +32,12 @@ #include "md.h" #include "gpt_uuid.h" #include <assert.h> +#include <err.h> #include <paths.h> #include <sys/param.h> #include <sys/ioctl.h> #include <util.h> +#include <uuid.h> bool gpt_parts_check(void); /* check for needed binaries */ @@ -44,7 +46,8 @@ bool gpt_parts_check(void); /* check for /* a GPT based disk_partitions interface */ #define GUID_STR_LEN 40 -#define GPT_PTYPE_MAX 32 /* should be > gpt type -l | wc -l */ +#define GPT_PTYPE_ALLOC 32 /* initial type array allocation, should be > + * gpt type -l | wc -l */ #define GPT_DEV_LEN 16 /* dkNN */ #define GPT_PARTS_PER_SEC 4 /* a 512 byte sector hols 4 entries */ @@ -112,8 +115,11 @@ struct { { .name = "vmresered", .fstype = FS_VMWRESV, .ptype = PT_unknown } }; -static size_t gpt_ptype_cnt; -static struct gpt_ptype_desc gpt_ptype_descs[GPT_PTYPE_MAX]; +static size_t gpt_ptype_cnt = 0, gpt_ptype_alloc = 0; +static struct gpt_ptype_desc *gpt_ptype_descs = NULL; + +/* "well" known types with special handling */ +static const struct part_type_desc *gpt_native_root; /* similar to struct gpt_ent, but matching our needs */ struct gpt_part_entry { @@ -364,7 +370,7 @@ gpt_read_from_disk(const char *dev, dadd } parts->dp.pscheme = scheme; - parts->dp.disk = dev; + parts->dp.disk = strdup(dev); parts->dp.disk_start = start; parts->dp.disk_size = disk_size; parts->dp.free_space = avail_size; @@ -449,7 +455,7 @@ gpt_create_new(const char *disk, daddr_t return NULL; parts->dp.pscheme = &gpt_parts; - parts->dp.disk = disk; + parts->dp.disk = strdup(disk); gpt_md_init(is_boot_drive, &parts->max_num_parts, &parts->prologue, &parts->epilogue); @@ -709,26 +715,6 @@ gpt_get_free_spaces(const struct disk_pa max_num_result, min_space_size, align, start, ignore); } - -static bool -gpt_adapt(const struct disk_partitions *arg, - const struct disk_part_info *src, struct disk_part_info *dest) -{ - /* slightly simplistic, enhance when needed */ - memcpy(dest, src, sizeof(*dest)); - - if (src->nat_type == NULL) - return false; - - dest->nat_type = arg->pscheme->get_generic_part_type( - src->nat_type->generic_ptype); - if (dest->nat_type == NULL) - dest->nat_type = arg->pscheme->get_generic_part_type( - PT_unknown); - - return true; -} - static void gpt_match_ptype(const char *name, struct gpt_ptype_desc *t) { @@ -739,6 +725,11 @@ gpt_match_ptype(const char *name, struct t->gent.generic_ptype = gpt_fs_types[i].ptype; t->fsflags = gpt_fs_types[i].fsflags; t->default_fs_type = gpt_fs_types[i].fstype; + + /* recongnize special entries */ + if (gpt_native_root == NULL && i == 0) + gpt_native_root = &t->gent; + return; } } @@ -751,10 +742,20 @@ gpt_match_ptype(const char *name, struct static void gpt_internal_add_ptype(const char *uid, const char *name, const char *desc) { + if (gpt_ptype_cnt >= gpt_ptype_alloc) { + gpt_ptype_alloc = gpt_ptype_alloc ? 2*gpt_ptype_alloc + : GPT_PTYPE_ALLOC; + struct gpt_ptype_desc *nptypes = realloc(gpt_ptype_descs, + gpt_ptype_alloc*sizeof(*gpt_ptype_descs)); + if (nptypes == 0) + errx(EXIT_FAILURE, "out of memory"); + gpt_ptype_descs = nptypes; + } + strlcpy(gpt_ptype_descs[gpt_ptype_cnt].tid, uid, sizeof(gpt_ptype_descs[gpt_ptype_cnt].tid)); - gpt_ptype_descs[gpt_ptype_cnt].gent.short_desc = name; - gpt_ptype_descs[gpt_ptype_cnt].gent.description = desc; + gpt_ptype_descs[gpt_ptype_cnt].gent.short_desc = strdup(name); + gpt_ptype_descs[gpt_ptype_cnt].gent.description = strdup(desc); gpt_match_ptype(name, &gpt_ptype_descs[gpt_ptype_cnt]); gpt_ptype_cnt++; } @@ -766,6 +767,19 @@ gpt_init_ptypes(void) gpt_uuid_query(gpt_internal_add_ptype); } +static void +gpt_cleanup(void) +{ + /* free all of gpt_ptype_descs */ + for (size_t i = 0; i < gpt_ptype_cnt; i++) { + free(__UNCONST(gpt_ptype_descs[i].gent.short_desc)); + free(__UNCONST(gpt_ptype_descs[i].gent.description)); + } + free(gpt_ptype_descs); + gpt_ptype_descs = NULL; + gpt_ptype_cnt = gpt_ptype_alloc = 0; +} + static size_t gpt_type_count(void) { @@ -793,6 +807,11 @@ gpt_get_generic_type(enum part_type gent if (gpt_ptype_cnt == 0) gpt_init_ptypes(); + if (gent == PT_root) + return gpt_native_root; + if (gent == PT_unknown) + return NULL; + for (size_t i = 0; i < gpt_ptype_cnt; i++) if (gpt_ptype_descs[i].gent.generic_ptype == gent) return &gpt_ptype_descs[i].gent; @@ -863,7 +882,61 @@ gpt_get_fs_part_type(unsigned fstype, un if (fstype == gpt_fs_types[i].fstype) return gpt_find_type(gpt_fs_types[i].name); - return gpt_get_generic_type(PT_root); + return NULL; +} + +static const struct part_type_desc * +gpt_get_uuid_part_type(const uuid_t *id) +{ + char str[GUID_STR_LEN], desc[GUID_STR_LEN + MENUSTRSIZE]; + const struct gpt_ptype_desc *t; + char *guid = NULL; + uint32_t err; + + uuid_to_string(id, &guid, &err); + strlcpy(str, err == uuid_s_ok ? guid : "-", sizeof str); + free(guid); + + t = gpt_find_guid_type(str); + if (t == NULL) { + snprintf(desc, sizeof desc, "%s (%s)", + msg_string(MSG_custom_type), str); + gpt_internal_add_ptype(str, str, desc); + t = gpt_find_guid_type(str); + assert(t != NULL); + } + return &t->gent; +} + +static const struct part_type_desc * +gpt_create_custom_part_type(const char *custom, const char **err_msg) +{ + uuid_t id; + uint32_t err; + + uuid_from_string(custom, &id, &err); + if (err_msg != NULL && + (err == uuid_s_invalid_string_uuid || err == uuid_s_bad_version)) { + *err_msg = MSG_invalid_guid; + return NULL; + } + if (err != uuid_s_ok) + return NULL; + + return gpt_get_uuid_part_type(&id); +} + +static const struct part_type_desc * +gpt_create_unknown_part_type(void) +{ + uuid_t id; + uint32_t err; + + uuid_create(&id, &err); + if (err != uuid_s_ok) + return NULL; + + return gpt_get_uuid_part_type(&id); } static daddr_t @@ -1312,9 +1385,11 @@ gpt_write_to_disk(struct disk_partitions close(fd); /* - * Collect first root and efi partition (if available) + * Collect first root and efi partition (if available), clear + * "have wedge" flags. */ for (pno = 0, p = parts->partitions; p != NULL; p = p->gp_next, pno++) { + p->gp_flags &= ~GPEF_WEDGE; if (root_id == NO_PART && p->gp_type != NULL) { if (p->gp_type->gent.generic_ptype == PT_root && p->gp_start == pm->ptstart) { @@ -1455,6 +1530,7 @@ gpt_free(struct disk_partitions *arg) n = p->gp_next; free(p); } + free(__UNCONST(parts->dp.disk)); free(parts); } @@ -1657,6 +1733,8 @@ gpt_parts = { .get_part_type = gpt_get_ptype, .get_generic_part_type = gpt_get_generic_type, .get_fs_part_type = gpt_get_fs_part_type, + .create_custom_part_type = gpt_create_custom_part_type, + .create_unknown_part_type = gpt_create_unknown_part_type, .get_part_alignment = gpt_get_part_alignment, .read_from_disk = gpt_read_from_disk, .create_new_for_disk = gpt_create_new, @@ -1671,7 +1749,7 @@ gpt_parts = { .get_part_device = gpt_get_part_device, .max_free_space_at = gpt_max_free_space_at, .get_free_spaces = gpt_get_free_spaces, - .adapt_foreign_part_info = gpt_adapt, + .adapt_foreign_part_info = generic_adapt_foreign_part_info, .get_part_info = gpt_get_part_info, .get_part_attr_str = gpt_get_part_attr_str, .set_part_info = gpt_set_part_info, @@ -1680,4 +1758,5 @@ gpt_parts = { .delete_partition = gpt_delete_partition, .write_to_disk = gpt_write_to_disk, .free = gpt_free, + .cleanup = gpt_cleanup, }; Index: src/usr.sbin/sysinst/install.c diff -u src/usr.sbin/sysinst/install.c:1.11 src/usr.sbin/sysinst/install.c:1.12 --- src/usr.sbin/sysinst/install.c:1.11 Sat Aug 17 18:08:06 2019 +++ src/usr.sbin/sysinst/install.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: install.c,v 1.11 2019/08/17 18:08:06 martin Exp $ */ +/* $NetBSD: install.c,v 1.12 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -34,6 +34,7 @@ /* install.c -- system installation. */ +#include <sys/param.h> #include <stdio.h> #include <curses.h> #include "defs.h" @@ -49,6 +50,7 @@ static bool write_all_parts(struct install_partition_desc *install) { struct disk_partitions **allparts, *parts; + struct selected_partition *src; size_t num_parts, i, j; bool found, res; @@ -75,7 +77,7 @@ write_all_parts(struct install_partition allparts[num_parts++] = parts; } - /* do four phases, abort anytime and go out, returning res */ + /* do multiple phases, abort anytime and go out, returning res */ res = true; @@ -98,7 +100,20 @@ write_all_parts(struct install_partition /* phase 3: now we may have a first chance to enable swap space */ set_swap_if_low_ram(install); - /* phase 4: post disklabel (used for updating boot loaders) */ + /* phase 4: copy any cloned partitions data (if requested) */ + for (i = 0; i < install->num; i++) { + if ((install->infos[i].flags & PUIFLG_CLONE_PARTS) == 0 + || install->infos[i].clone_src == NULL + || !install->infos[i].clone_src->with_data) + continue; + src = &install->infos[i].clone_src + ->selection[install->infos[i].clone_ndx]; + clone_partition_data(install->infos[i].parts, + install->infos[i].cur_part_id, + src->parts, src->id); + } + + /* phase 5: post disklabel (used for updating boot loaders) */ for (i = 0; i < num_parts; i++) { if (!md_post_disklabel(install, allparts[i])) { res = false; @@ -217,5 +232,5 @@ do_install(void) hit_enter_to_continue(MSG_instcomplete, NULL); error: - free(install.infos); + free_install_desc(&install); } Index: src/usr.sbin/sysinst/label.c diff -u src/usr.sbin/sysinst/label.c:1.12 src/usr.sbin/sysinst/label.c:1.13 --- src/usr.sbin/sysinst/label.c:1.12 Sun Aug 4 10:29:41 2019 +++ src/usr.sbin/sysinst/label.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: label.c,v 1.12 2019/08/04 10:29:41 martin Exp $ */ +/* $NetBSD: label.c,v 1.13 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Jonathan Stone @@ -36,7 +36,7 @@ #include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: label.c,v 1.12 2019/08/04 10:29:41 martin Exp $"); +__RCSID("$NetBSD: label.c,v 1.13 2019/11/12 16:33:14 martin Exp $"); #endif #include <sys/types.h> @@ -1113,11 +1113,16 @@ fmt_fspart_header(menudesc *menu, void * { struct partition_usage_set *pset = arg; char total[6], free_space[6], scol[13], ecol[13], szcol[13], - sepline[MENUSTRSIZE], *p; + sepline[MENUSTRSIZE], *p, desc[MENUSTRSIZE]; const char *fstype, *flags; int i; - bool with_inst_flag = pset->parts->parent == NULL; + size_t ptn; + bool with_clone, with_inst_flag = pset->parts->parent == NULL; + with_clone = false; + for (ptn = 0; ptn < pset->num && !with_clone; ptn++) + if (pset->infos[ptn].flags & PUIFLG_CLONE_PARTS) + with_clone = true; humanize_number(total, sizeof total, pset->parts->disk_size * 512, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); @@ -1125,14 +1130,19 @@ fmt_fspart_header(menudesc *menu, void * pset->cur_free_space * 512, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + if (with_clone) + strlcpy(desc, msg_string(MSG_clone_flag_desc), sizeof desc); + else + desc[0] = 0; + if (pset->parts->pscheme->part_flag_desc) + strlcat(desc, msg_string(pset->parts->pscheme->part_flag_desc), + sizeof desc); + msg_display_subst(MSG_fspart, 7, pset->parts->disk, msg_string(pset->parts->pscheme->name), msg_string(pset->parts->pscheme->short_name), with_inst_flag ? msg_string(MSG_ptn_instflag_desc) : "", - pset->parts->pscheme->part_flag_desc ? - msg_string(pset->parts->pscheme->part_flag_desc) - : "", - total, free_space); + desc, total, free_space); snprintf(scol, sizeof scol, "%s (%s)", msg_string(MSG_ptnheaders_start), multname); @@ -1177,11 +1187,40 @@ fmt_fspart_row(menudesc *m, int ptn, voi static const char *Yes; char flag_str[MENUSTRSIZE], *fp; unsigned inst_flags; + size_t clone_cnt; bool with_inst_flag = pset->parts->parent == NULL; if (Yes == NULL) Yes = msg_string(MSG_Yes); + if ((pset->infos[ptn].flags & PUIFLG_CLONE_PARTS) && + pset->infos[ptn].cur_part_id == NO_PART) { + psize = pset->infos[ptn].size / sizemult; + if (pset->infos[ptn].clone_ndx < + pset->infos[ptn].clone_src->num_sel) + clone_cnt = 1; + else + clone_cnt = pset->infos[ptn].clone_src->num_sel; + if (pset->infos[ptn].cur_part_id == NO_PART) + wprintw(m->mw, " %12" PRIu64 + " [%zu %s]", psize, clone_cnt, + msg_string(MSG_clone_target_disp)); + else { + poffset = pset->infos[ptn].cur_start / sizemult; + pend = (pset->infos[ptn].cur_start + + pset->infos[ptn].size) / sizemult - 1; + wprintw(m->mw, "%12" PRIu64 " %12" PRIu64 " %12" PRIu64 + " [%zu %s]", + poffset, pend, psize, clone_cnt, + msg_string(MSG_clone_target_disp)); + } + if (m->title == fspart_title) + m->opts[ptn].opt_flags |= OPT_IGNORE; + else + m->opts[ptn].opt_flags &= ~OPT_IGNORE; + return; + } + if (!real_partition(pset, ptn)) return; @@ -1189,11 +1228,22 @@ fmt_fspart_row(menudesc *m, int ptn, voi pset->infos[ptn].cur_part_id, &info)) return; - /* enable / disable this line if it is something like RAW_PART */ - if (info.flags & (PTI_WHOLE_DISK|PTI_PSCHEME_INTERNAL|PTI_RAW_PART)) - m->opts[ptn].opt_flags |= OPT_IGNORE; - else - m->opts[ptn].opt_flags &= ~OPT_IGNORE; + /* + * We use this function in multiple menus, but only want it + * to play with enable/disable in a single one: + */ + if (m->title == fspart_title) { + /* + * Enable / disable this line if it is something + * like RAW_PART + */ + if ((info.flags & + (PTI_WHOLE_DISK|PTI_PSCHEME_INTERNAL|PTI_RAW_PART)) + || (pset->infos[ptn].flags & PUIFLG_CLONE_PARTS)) + m->opts[ptn].opt_flags |= OPT_IGNORE; + else + m->opts[ptn].opt_flags &= ~OPT_IGNORE; + } poffset = info.start / sizemult; psize = info.size / sizemult; @@ -1223,6 +1273,8 @@ fmt_fspart_row(menudesc *m, int ptn, voi } if (inst_flags & PUIINST_NEWFS) *fp++ = msg_string(MSG_newfs_flag)[0]; + if (pset->infos[ptn].flags & PUIFLG_CLONE_PARTS) + *fp++ = msg_string(MSG_clone_flag)[0]; *fp = 0; if (pset->parts->pscheme->get_part_attr_str != NULL) pset->parts->pscheme->get_part_attr_str(pset->parts, @@ -1245,6 +1297,153 @@ fmt_fspart_row(menudesc *m, int ptn, voi } static int +part_ext_clone(menudesc *m, void *arg) +{ + struct selected_partitions selected, *clone_src; + struct clone_target_menu_data data; + struct partition_usage_set *pset = arg; + struct part_usage_info *p; + struct disk_part_info sinfo, cinfo; + struct disk_partitions *csrc; + struct disk_part_free_space space; + menu_ent *men; + daddr_t clone_size, free_size, offset, align; + int num_men, i; + size_t s, clone_cnt; + part_id cid; + struct clone_data { + struct disk_part_info info; + part_id new_id; + size_t ndx; + }; + struct clone_data *clones = NULL; + + if (!select_partitions(&selected, pm->parts)) + return 0; + + clone_size = selected_parts_size(&selected); + num_men = pset->num+1; + men = calloc(num_men, sizeof *men); + if (men == NULL) + return 0; + for (i = 0; i < num_men; i++) { + men[i].opt_action = clone_target_select; + if (i == 0) + free_size = pset->infos[i].cur_start; + else if (i > 0 && (size_t)i < pset->num) + free_size = pset->infos[i].cur_start - + pset->infos[i-1].cur_start - pset->infos[i-1].size; + else + free_size = pset->parts->free_space; + if (free_size < clone_size) + men[i].opt_flags = OPT_IGNORE; + } + men[num_men-1].opt_name = MSG_clone_target_end; + + memset(&data, 0, sizeof data); + data.usage = *pset; + data.res = -1; + + data.usage.menu = new_menu(MSG_clone_target_hdr, + men, num_men, 3, 2, 0, 65, MC_SCROLL, + NULL, fmt_fspart_row, NULL, NULL, MSG_cancel); + process_menu(data.usage.menu, &data); + free_menu(data.usage.menu); + free(men); + + if (data.res < 0) + goto err; + + /* create temporary infos for all clones that work out */ + clone_cnt = 0; + clones = calloc(selected.num_sel, sizeof(*clones)); + if (clones == NULL) + goto err; + + clone_src = malloc(sizeof(selected)); + if (clone_src == NULL) + goto err; + *clone_src = selected; + + /* find selected offset from data.res and insert clones there */ + align = pset->parts->pscheme->get_part_alignment(pset->parts); + offset = -1; + if (data.res > 0) + offset = pset->infos[data.res-1].cur_start + + pset->infos[data.res-1].size; + else + offset = 0; + for (s = 0; s < selected.num_sel; s++) { + csrc = selected.selection[s].parts; + cid = selected.selection[s].id; + csrc->pscheme->get_part_info(csrc, cid, &sinfo); + if (!pset->parts->pscheme->adapt_foreign_part_info( + pset->parts, &cinfo, csrc->pscheme, &sinfo)) + continue; + size_t cnt = pset->parts->pscheme->get_free_spaces( + pset->parts, &space, 1, cinfo.size-align, align, + offset, -1); + if (cnt == 0) + continue; + cinfo.start = space.start; + cid = pset->parts->pscheme->add_partition( + pset->parts, &cinfo, NULL); + if (cid == NO_PART) + continue; + pset->parts->pscheme->get_part_info(pset->parts, cid, &cinfo); + clones[clone_cnt].info = cinfo; + clones[clone_cnt].new_id = cid; + clones[clone_cnt].ndx = s; + clone_cnt++; + offset = rounddown(cinfo.start+cinfo.size+align, align); + } + + /* insert new clone records at offset data.res */ + men = realloc(m->opts, (m->numopts+clone_cnt)*sizeof(*m->opts)); + if (men == NULL) + goto err; + pset->menu_opts = men; + m->opts = men; + m->numopts += clone_cnt; + + p = realloc(pset->infos, (pset->num+clone_cnt)*sizeof(*pset->infos)); + if (p == NULL) + goto err; + pset->infos = p; + + men += data.res; + p += data.res; + memmove(men+clone_cnt, men, + sizeof(*men)*(m->numopts-data.res-clone_cnt)); + if (pset->num > (size_t)data.res) + memmove(p+clone_cnt, p, sizeof(*p)*(pset->num-data.res)); + memset(men, 0, sizeof(*men)*clone_cnt); + memset(p, 0, sizeof(*p)*clone_cnt); + for (s = 0; s < clone_cnt; s++) { + p[s].cur_part_id = clones[s].new_id; + p[s].cur_start = clones[s].info.start; + p[s].size = clones[s].info.size; + p[s].cur_flags = clones[s].info.flags; + p[s].flags = PUIFLG_CLONE_PARTS; + p[s].parts = pset->parts; + p[s].clone_src = clone_src; + p[s].clone_ndx = s; + } + free(clones); + m->cursel = ((size_t)data.res >= pset->num) ? 0 : data.res+clone_cnt; + pset->num += clone_cnt; + m->h = 0; + resize_menu_height(m); + + return -1; + +err: + free(clones); + free_selected_partitions(&selected); + return 0; +} + +static int edit_fspart_pack(menudesc *m, void *arg) { struct partition_usage_set *pset = arg; @@ -1396,7 +1595,7 @@ edit_and_check_label(struct pm_devs *p, pset->parts->pscheme->set_disk_pack_name != NULL; pset->menu_opts = calloc(pset->parts->num_part - +3+may_add+may_edit_pack, + +4+may_add+may_edit_pack, sizeof *pset->menu_opts); if (pset->menu_opts == NULL) return 0; @@ -1432,6 +1631,11 @@ edit_and_check_label(struct pm_devs *p, op->opt_action = edit_fspart_pack; op++; } + + /* add a clone-from-elsewhere option */ + op->opt_name = MSG_clone_from_elsewhere; + op->opt_action = part_ext_clone; + op++; /* and abort option */ op->opt_name = MSG_cancel; @@ -1439,7 +1643,7 @@ edit_and_check_label(struct pm_devs *p, op->opt_action = edit_fspart_abort; op++; cnt = op - pset->menu_opts; - assert(cnt == pset->parts->num_part+3+may_add+may_edit_pack); + assert(cnt == pset->parts->num_part+4+may_add+may_edit_pack); pset->menu = new_menu(fspart_title, pset->menu_opts, cnt, 0, -1, 0, 74, Index: src/usr.sbin/sysinst/main.c diff -u src/usr.sbin/sysinst/main.c:1.17 src/usr.sbin/sysinst/main.c:1.18 --- src/usr.sbin/sysinst/main.c:1.17 Sat Jun 22 20:46:07 2019 +++ src/usr.sbin/sysinst/main.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.17 2019/06/22 20:46:07 christos Exp $ */ +/* $NetBSD: main.c,v 1.18 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -281,6 +281,8 @@ main(int argc, char **argv) pm_destroy_all(); #endif + partitions_cleanup(); + exit_cleanly = 1; return 0; } Index: src/usr.sbin/sysinst/msg.mi.es diff -u src/usr.sbin/sysinst/msg.mi.es:1.17 src/usr.sbin/sysinst/msg.mi.es:1.18 --- src/usr.sbin/sysinst/msg.mi.es:1.17 Wed Oct 2 11:16:04 2019 +++ src/usr.sbin/sysinst/msg.mi.es Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: msg.mi.es,v 1.17 2019/10/02 11:16:04 maya Exp $ */ +/* $NetBSD: msg.mi.es,v 1.18 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -1284,6 +1284,7 @@ message dl_type_invalid {Invalid file sy message cancel {Cancel} message out_of_range {Invalid value} +message invalid_guid {Invalid GUID} message reedit_partitions {Re-edit} message abort_installation {Abort installation} @@ -1446,6 +1447,9 @@ message newfs_flag {N} message ptn_install {instalar} message ptn_instflag_desc {(I)nstalar, } +message clone_flag {C} +message clone_flag_desc {, (C)lone} + message parttype_gpt {Guid Partition Table (GPT)} message parttype_gpt_short {GPT} @@ -1471,3 +1475,15 @@ message size_ptn_not_mounted {(Other: $ message running_system {current system} +message clone_from_elsewhere {Clone external partition(s)} +message select_foreign_part +{Please select an external source partition:} +message select_source_hdr +{Your currently selected source partitions are:} +message clone_with_data {Clone with data} +message select_source_add {Add another partition} +message clone_target_end {Add at end} +message clone_target_hdr +{Insert cloned partitions before:} +message clone_target_disp {cloned partition(s)} + Index: src/usr.sbin/sysinst/mbr.c diff -u src/usr.sbin/sysinst/mbr.c:1.21 src/usr.sbin/sysinst/mbr.c:1.22 --- src/usr.sbin/sysinst/mbr.c:1.21 Tue Aug 27 17:23:24 2019 +++ src/usr.sbin/sysinst/mbr.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: mbr.c,v 1.21 2019/08/27 17:23:24 martin Exp $ */ +/* $NetBSD: mbr.c,v 1.22 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -74,6 +74,8 @@ #include <unistd.h> #include <fcntl.h> #include <util.h> +#include <paths.h> +#include <sys/ioctl.h> #include "defs.h" #include "mbr.h" #include "md.h" @@ -89,6 +91,9 @@ #define MAXSECTOR 63 +#define MBR_UNKNOWN_PTYPE 94 /* arbitrary not widely used value */ + + /* A list of predefined partition types */ const struct { unsigned int ptype; @@ -588,7 +593,7 @@ static int write_mbr(const char *disk, mbr_info_t *mbri, int bsec, int bhead, int bcyl) { char diskpath[MAXPATHLEN]; - int fd, i, ret = 0; + int fd, i, ret = 0, bits = 0; struct mbr_partition *mbrp; u_int32_t pstart, psize; #ifdef BOOTSEL @@ -605,6 +610,10 @@ write_mbr(const char *disk, mbr_info_t * if (fd < 0) return -1; + /* Remove all wedges */ + if (ioctl(fd, DIOCRMWEDGES, &bits) == -1) + return -1; + #ifdef BOOTSEL /* * If the main boot code (appears to) contain the netbsd bootcode, @@ -646,6 +655,7 @@ write_mbr(const char *disk, mbr_info_t * #endif for (ext = mbri; ext != NULL; ext = ext->extended) { + memset(mbri->wedge, 0, sizeof mbri->wedge); sector = ext->sector; mbrsec = ext->mbr; /* copy sector */ mbrp = &mbrsec.mbr_parts[0]; @@ -830,7 +840,7 @@ mbr_create_new(const char *disk, daddr_t return NULL; parts->dp.pscheme = &mbr_parts; - parts->dp.disk = disk; + parts->dp.disk = strdup(disk); if (len > mbr_parts.size_limit) len = mbr_parts.size_limit; parts->dp.disk_start = start; @@ -894,7 +904,7 @@ mbr_read_from_disk(const char *disk, dad return NULL; parts->dp.pscheme = scheme; - parts->dp.disk = disk; + parts->dp.disk = strdup(disk); if (len >= mbr_parts.size_limit) len = mbr_parts.size_limit; parts->dp.disk_start = start; @@ -1127,6 +1137,16 @@ mbr_custom_part_type(const char *custom, } static const struct part_type_desc * +mbr_create_unknown_part_type(void) +{ + + if (mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen.short_desc != NULL) + return &mbr_gen_type_desc[MBR_UNKNOWN_PTYPE].gen; + + return mbr_new_custom_part_type(MBR_UNKNOWN_PTYPE); +} + +static const struct part_type_desc * mbr_get_gen_type_desc(unsigned int pt) { @@ -1231,12 +1251,80 @@ mbr_do_get_part_info(const struct disk_p mbr_partition_to_info(mp, mb->sector, info); if (mb->last_mounted[i] != NULL && mb->last_mounted[i][0] != 0) info->last_mounted = mb->last_mounted[i]; - info->fs_type = mb->fs_type[i]; - info->fs_sub_type = mb->fs_sub_type[i]; + if (mb->fs_type[i] != FS_UNUSED) { + info->fs_type = mb->fs_type[i]; + info->fs_sub_type = mb->fs_sub_type[i]; + } else { + info->fs_sub_type = 0; + switch (mp->mbrp_type) { + case MBR_PTYPE_FAT12: + case MBR_PTYPE_FAT16S: + case MBR_PTYPE_FAT16B: + case MBR_PTYPE_FAT32: + case MBR_PTYPE_FAT32L: + case MBR_PTYPE_FAT16L: + case MBR_PTYPE_OS2_DOS12: + case MBR_PTYPE_OS2_DOS16S: + case MBR_PTYPE_OS2_DOS16B: + case MBR_PTYPE_HID_FAT32: + case MBR_PTYPE_HID_FAT32_LBA: + case MBR_PTYPE_HID_FAT16_LBA: + case MBR_PTYPE_MDOS_FAT12: + case MBR_PTYPE_MDOS_FAT16S: + case MBR_PTYPE_MDOS_EXT: + case MBR_PTYPE_MDOS_FAT16B: + case MBR_PTYPE_SPEEDSTOR_16S: + case MBR_PTYPE_EFI: + info->fs_type = FS_MSDOS; + break; + case MBR_PTYPE_XENIX_ROOT: + case MBR_PTYPE_XENIX_USR: + info->fs_type = FS_SYSV; + break; + case MBR_PTYPE_NTFS: + info->fs_type = FS_NTFS; + break; + case MBR_PTYPE_APPLE_HFS: + info->fs_type = FS_HFS; + break; + case MBR_PTYPE_VMWARE: + info->fs_type = FS_VMFS; + break; + case MBR_PTYPE_AST_SWAP: + case MBR_PTYPE_DRDOS_LSWAP: + case MBR_PTYPE_LNXSWAP: + case MBR_PTYPE_BSDI_SWAP: + case MBR_PTYPE_HID_LNX_SWAP: + case MBR_PTYPE_VMWARE_SWAP: + info->fs_type = FS_SWAP; + break; + } + } return true; } static bool +get_wedge_devname(const struct disk_partitions *arg, part_id id, + const mbr_info_t *mb, int i, bool primary, + const struct mbr_partition *mp, void *cookie) +{ + char **res = cookie; + + if (!res) + return false; + + *res = __UNCONST(mb->wedge[i]); + return true; +} + +static bool +mbr_part_get_wedge(const struct disk_partitions *arg, part_id id, + char **res) +{ + return mbr_part_apply(arg, id, get_wedge_devname, res); +} + +static bool mbr_get_part_info(const struct disk_partitions *arg, part_id id, struct disk_part_info *info) { @@ -2382,17 +2470,49 @@ mbr_can_add_partition(const struct disk_ } static void +mbr_free_wedge(int *fd, const char *disk, const char *wedge) +{ + struct dkwedge_info dkw; + char diskpath[MAXPATHLEN]; + + if (*fd == -1) + *fd = opendisk(disk, O_RDWR, diskpath, + sizeof(diskpath), 0); + if (*fd != -1) { + memset(&dkw, 0, sizeof(dkw)); + strlcpy(dkw.dkw_devname, wedge, + sizeof(dkw.dkw_devname)); + ioctl(*fd, DIOCDWEDGE, &dkw); + } +} + +static void mbr_free(struct disk_partitions *arg) { struct mbr_disk_partitions *parts = (struct mbr_disk_partitions*)arg; + mbr_info_t *m; + int i, fd; assert(parts != NULL); + fd = -1; + m = &parts->mbr; + do { + for (i = 0; i < MBR_PART_COUNT; i++) { + if (m->wedge[i][0] != 0) + mbr_free_wedge(&fd, arg->disk, m->wedge[i]); + } + } while ((m = m->extended)); + + if (fd != -1) + close(fd); + if (parts->dlabel) parts->dlabel->pscheme->free(parts->dlabel); free_mbr_info(parts->mbr.extended); free_last_mounted(&parts->mbr); + free(__UNCONST(parts->dp.disk)); free(parts); } @@ -2677,6 +2797,103 @@ mbr_part_alignment(const struct disk_par } static bool +add_wedge(const char *disk, daddr_t start, daddr_t size, + char *wname, size_t max_len) +{ + struct dkwedge_info dkw; + char diskpath[MAXPATHLEN]; + int fd; + + memset(&dkw, 0, sizeof(dkw)); + dkw.dkw_offset = start; + dkw.dkw_size = size; + snprintf((char*)dkw.dkw_wname, sizeof dkw.dkw_wname, + "%s_%" PRIi64 "@%" PRIi64, (const char*)disk, size, start); + + *wname = 0; + + fd = opendisk(disk, O_RDWR, diskpath, sizeof(diskpath), 0); + if (fd < 0) + return false; + if (ioctl(fd, DIOCAWEDGE, &dkw) == -1) { + close(fd); + return false; + } + close(fd); + strlcpy(wname, dkw.dkw_devname, max_len); + return true; +} + +static bool +mbr_get_part_device(const struct disk_partitions *arg, + part_id ptn, char *devname, size_t max_devname_len, int *part, + enum dev_name_usage usage, bool with_path) +{ + const struct mbr_disk_partitions *parts = + (const struct mbr_disk_partitions*)arg; + struct disk_part_info info, tmp; + part_id dptn; + char *wedge_dev; + + if (!mbr_get_part_info(arg, ptn, &info)) + return false; + + if (!mbr_part_get_wedge(arg, ptn, &wedge_dev) || wedge_dev == NULL) + return false; + + if (wedge_dev[0] == 0) { + /* + * If we have secondary partitions, try to find a match there + * and use that... + */ + if (parts->dlabel != NULL) { + for (dptn = 0; dptn < parts->dlabel->num_part; dptn++) { + if (!parts->dlabel->pscheme->get_part_info( + parts->dlabel, dptn, &tmp)) + continue; + if (tmp.start != info.start || + tmp.size != info.size) + continue; + return parts->dlabel->pscheme->get_part_device( + parts->dlabel, dptn, devname, + max_devname_len, + part, usage, with_path); + } + } + + /* + * Configure a new wedge and remember the name + */ + if (!add_wedge(arg->disk, info.start, info.size, wedge_dev, + MBR_DEV_LEN)) + return false; + } + + assert(wedge_dev[0] != 0); + + switch (usage) { + case logical_name: + case plain_name: + if (with_path) + snprintf(devname, max_devname_len, _PATH_DEV "%s", + wedge_dev); + else + strlcpy(devname, wedge_dev, max_devname_len); + return true; + case raw_dev_name: + if (with_path) + snprintf(devname, max_devname_len, _PATH_DEV "r%s", + wedge_dev); + else + snprintf(devname, max_devname_len, "r%s", + wedge_dev); + return true; + default: + return false; + } +} + +static bool is_custom_attribute_writable(const struct disk_partitions *arg, part_id id, const mbr_info_t *mb, int i, bool primary, const struct mbr_partition *mp, void *cookie) @@ -2766,16 +2983,19 @@ mbr_parts = { .custom_attribute_toggle = mbr_custom_attribute_toggle, .custom_attribute_set_str = mbr_custom_attribute_set_str, .get_part_types_count = mbr_get_part_type_count, + .adapt_foreign_part_info = generic_adapt_foreign_part_info, .get_part_type = mbr_get_part_type, .get_fs_part_type = mbr_get_fs_part_type, .get_generic_part_type = mbr_get_generic_part_type, .create_custom_part_type = mbr_custom_part_type, + .create_unknown_part_type = mbr_create_unknown_part_type, .secondary_partitions = mbr_read_disklabel, .write_to_disk = mbr_write_to_disk, .read_from_disk = mbr_read_from_disk, .create_new_for_disk = mbr_create_new, .guess_disk_geom = mbr_guess_geom, .change_disk_geom = mbr_change_disk_geom, + .get_part_device = mbr_get_part_device, .max_free_space_at = mbr_max_part_size, .get_free_spaces = mbr_get_free_spaces, .set_part_info = mbr_set_part_info, Index: src/usr.sbin/sysinst/msg.mi.fr diff -u src/usr.sbin/sysinst/msg.mi.fr:1.21 src/usr.sbin/sysinst/msg.mi.fr:1.22 --- src/usr.sbin/sysinst/msg.mi.fr:1.21 Thu Oct 17 08:54:50 2019 +++ src/usr.sbin/sysinst/msg.mi.fr Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: msg.mi.fr,v 1.21 2019/10/17 08:54:50 maxv Exp $ */ +/* $NetBSD: msg.mi.fr,v 1.22 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -1336,6 +1336,7 @@ message dl_type_invalid {Invalid file sy message cancel {Annuler} message out_of_range {Invalid value} +message invalid_guid {Invalid GUID} message reedit_partitions {Re-edit} message abort_installation {Abort installation} @@ -1490,6 +1491,8 @@ message newfs_flag {N} message ptn_install {installation} message ptn_instflag_desc {(I)nstallation, } +message clone_flag {C} +message clone_flag_desc {, (C)lone} message parttype_gpt {Guid Partition Table (GPT)} message parttype_gpt_short {GPT} @@ -1516,3 +1519,15 @@ message size_ptn_not_mounted {(Other: $ message running_system {current system} +message clone_from_elsewhere {Clone external partition(s)} +message select_foreign_part +{Please select an external source partition:} +message select_source_hdr +{Your currently selected source partitions are:} +message clone_with_data {Clone with data} +message select_source_add {Add another partition} +message clone_target_end {Add at end} +message clone_target_hdr +{Insert cloned partitions before:} +message clone_target_disp {cloned partition(s)} + Index: src/usr.sbin/sysinst/mbr.h diff -u src/usr.sbin/sysinst/mbr.h:1.3 src/usr.sbin/sysinst/mbr.h:1.4 --- src/usr.sbin/sysinst/mbr.h:1.3 Wed Jun 19 17:32:31 2019 +++ src/usr.sbin/sysinst/mbr.h Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: mbr.h,v 1.3 2019/06/19 17:32:31 martin Exp $ */ +/* $NetBSD: mbr.h,v 1.4 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997, 1988 Piermont Information Systems Inc. @@ -54,6 +54,8 @@ #define MBR_PUT_LSCYL(c) ((c) & 0xff) #define MBR_PUT_MSCYLANDSEC(c,s) (((s) & 0x3f) | (((c) >> 2) & 0xc0)) +#define MBR_DEV_LEN 16 /* for wedge names */ + typedef struct mbr_info_t mbr_info_t; struct mbr_info_t { struct mbr_sector mbr; @@ -69,6 +71,8 @@ struct mbr_info_t { /* only in first item... */ uint bootsec; /* start sector of bootmenu default */ #endif + /* for temporary access */ + char wedge[MBR_PART_COUNT][MBR_DEV_LEN]; }; #ifdef BOOTSEL Index: src/usr.sbin/sysinst/msg.mi.de diff -u src/usr.sbin/sysinst/msg.mi.de:1.16 src/usr.sbin/sysinst/msg.mi.de:1.17 --- src/usr.sbin/sysinst/msg.mi.de:1.16 Wed Oct 2 11:16:04 2019 +++ src/usr.sbin/sysinst/msg.mi.de Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: msg.mi.de,v 1.16 2019/10/02 11:16:04 maya Exp $ */ +/* $NetBSD: msg.mi.de,v 1.17 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -318,7 +318,7 @@ message fspart {Nachfolgend sehen Sie Ihre $2 Partitionen für $0. Dies ist die letzte Chance, diese zu ändern. -Flags: $3(F)ormatieren$4. Gesamtgröße: $5, noch frei: $6} +Flags: $3(F)ormatieren$4. Gesamtgröße: $5, frei: $6} message ptnheaders_start {Start} message ptnheaders_end {Ende} @@ -1302,6 +1302,7 @@ message custom_type {Unbekannt} message cancel {Abbrechen} message out_of_range {Ungültiger Wert} +message invalid_guid {Ungültige GUID} message reedit_partitions {Erneut bearbeiten} message abort_installation {Installation abbrechen} @@ -1459,6 +1460,9 @@ Wählen Sie die Partition, die Sie veränd message ptn_install {Installation} message ptn_instflag_desc {(I)nstalllieren, } +message clone_flag {C} +message clone_flag_desc {, (C)lone} + message parttype_gpt {Guid Partition Table (GPT)} message parttype_gpt_short {GPT} @@ -1483,3 +1487,14 @@ message gpt_flag_desc {, (S)tart} message size_ptn_not_mounted {(Sonstige: $0)} message running_system {aktuelles System} + +message clone_from_elsewhere {Externe Partition(en) duplizieren} +message select_foreign_part {Wählen Sie eine Quellpartition:} +message select_source_hdr +{Zur Zeit ausgwählte Quellpartitionen:} +message clone_with_data {Auch die Inhalte duplizieren} +message select_source_add {Weitere Partition hinzufügen} +message clone_target_end {Als letzte hinzufügen} +message clone_target_hdr +{Einfügen der duplizierten Partitionen vor:} +message clone_target_disp {duplizierte Partition(en)} Index: src/usr.sbin/sysinst/msg.mi.en diff -u src/usr.sbin/sysinst/msg.mi.en:1.23 src/usr.sbin/sysinst/msg.mi.en:1.24 --- src/usr.sbin/sysinst/msg.mi.en:1.23 Thu Oct 17 08:54:50 2019 +++ src/usr.sbin/sysinst/msg.mi.en Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: msg.mi.en,v 1.23 2019/10/17 08:54:50 maxv Exp $ */ +/* $NetBSD: msg.mi.en,v 1.24 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -307,7 +307,7 @@ message fspart {We now have your $2 partitions for $0 below. This is your last chance to change them. -Flags: $3(N)ewfs$4. Total size: $5, free space: $6} +Flags: $3(N)ewfs$4. Total size: $5, free: $6} message ptnheaders_start {Start} message ptnheaders_end {End} @@ -1234,6 +1234,7 @@ message dl_type_invalid {Invalid file sy message cancel {Cancel} message out_of_range {Invalid value} +message invalid_guid {Invalid GUID} message reedit_partitions {Re-edit} message abort_installation {Abort installation} @@ -1395,6 +1396,9 @@ Select the partition you wish to change: message install_flag {I} message newfs_flag {N} +message clone_flag {C} +message clone_flag_desc {, (C)lone} + message ptn_install {install} message ptn_instflag_desc {(I)nstall, } @@ -1423,3 +1427,15 @@ message size_ptn_not_mounted {(Other: $ message running_system {current system} +message clone_from_elsewhere {Clone external partition(s)} +message select_foreign_part +{Please select an external source partition:} +message select_source_hdr +{Your currently selected source partitions are:} +message clone_with_data {Clone with data} +message select_source_add {Add another partition} +message clone_target_end {Add at end} +message clone_target_hdr +{Insert cloned partitions before:} +message clone_target_disp {cloned partition(s)} + Index: src/usr.sbin/sysinst/msg.mi.pl diff -u src/usr.sbin/sysinst/msg.mi.pl:1.24 src/usr.sbin/sysinst/msg.mi.pl:1.25 --- src/usr.sbin/sysinst/msg.mi.pl:1.24 Wed Oct 23 18:08:31 2019 +++ src/usr.sbin/sysinst/msg.mi.pl Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: msg.mi.pl,v 1.24 2019/10/23 18:08:31 kamil Exp $ */ +/* $NetBSD: msg.mi.pl,v 1.25 2019/11/12 16:33:14 martin Exp $ */ /* Based on english version: */ /* NetBSD: msg.mi.pl,v 1.36 2004/04/17 18:55:35 atatat Exp */ @@ -1234,6 +1234,7 @@ message dl_type_invalid {Nieznany typ sy message cancel {Anuluj} message out_of_range {Nieprawidlowa wartosc} +message invalid_guid {Nieprawidlowa GUID} message reedit_partitions {Edytuj ponownie} message abort_installation {Anuluj instalacje} @@ -1385,6 +1386,8 @@ message newfs_flag {N} message ptn_install {do instalacji} message ptn_instflag_desc {(I)nstalacja, } +message clone_flag {C} +message clone_flag_desc {, (C)lone} message parttype_gpt {Guid Partition Table (GPT)} message parttype_gpt_short {GPT} @@ -1411,3 +1414,15 @@ message size_ptn_not_mounted {(Inna: $0 message running_system {current system} +message clone_from_elsewhere {Clone external partition(s)} +message select_foreign_part +{Please select an external source partition:} +message select_source_hdr +{Your currently selected source partitions are:} +message clone_with_data {Clone with data} +message select_source_add {Add another partition} +message clone_target_end {Add at end} +message clone_target_hdr +{Insert cloned partitions before:} +message clone_target_disp {cloned partition(s)} + Index: src/usr.sbin/sysinst/part_edit.c diff -u src/usr.sbin/sysinst/part_edit.c:1.10 src/usr.sbin/sysinst/part_edit.c:1.11 --- src/usr.sbin/sysinst/part_edit.c:1.10 Sat Oct 26 07:32:52 2019 +++ src/usr.sbin/sysinst/part_edit.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: part_edit.c,v 1.10 2019/10/26 07:32:52 martin Exp $ */ +/* $NetBSD: part_edit.c,v 1.11 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright (c) 2019 The NetBSD Foundation, Inc. @@ -57,8 +57,19 @@ struct part_edit_info { bool num_changed; /* number of partitions has changed */ }; +struct single_clone_data { + struct selected_partitions clone_src; + part_id *clone_ids; /* partition IDs in target */ +}; +struct outer_parts_data { + struct arg_rv av; + struct single_clone_data *clones; + size_t num_clone_entries; +}; + static menu_ent *part_menu_opts; /* the currently edited partitions */ static menu_ent *outer_fill_part_menu_opts(const struct disk_partitions *parts, size_t *cnt); +static void draw_outer_part_line(menudesc *m, int opt, void *arg); static char outer_part_sep_line[MENUSTRSIZE], outer_part_title[2*MENUSTRSIZE]; @@ -388,15 +399,16 @@ fill_part_edit_menu_opts(struct disk_par static int edit_part_entry(menudesc *m, void *arg) { - arg_rv *av = arg; - struct part_edit_info data = { .parts = av->arg, .cur_id = m->cursel, + struct outer_parts_data *pdata = arg; + struct part_edit_info data = { .parts = pdata->av.arg, + .cur_id = m->cursel, .first_custom_opt = __arraycount(common_ptn_edit_opts) }; int ptn_menu; const char *err; menu_ent *opts; size_t num_opts; - opts = fill_part_edit_menu_opts(av->arg, true, ptn_edit_opts, + opts = fill_part_edit_menu_opts(data.parts, true, ptn_edit_opts, __arraycount(ptn_edit_opts), &num_opts); if (opts == NULL) return 1; @@ -434,10 +446,120 @@ edit_part_entry(menudesc *m, void *arg) } static int +add_part_clone(menudesc *menu, void *arg) +{ + struct outer_parts_data *pdata = arg; + struct disk_partitions *parts = pdata->av.arg; + struct clone_target_menu_data data; + menu_ent *men; + int num_men, i; + struct disk_part_info sinfo, cinfo; + struct disk_partitions *csrc; + struct disk_part_free_space space; + daddr_t offset, align; + size_t s, clone_cnt; + part_id cid; + struct selected_partitions selected; + struct single_clone_data *new_clones; + + if (!select_partitions(&selected, parts)) + return 0; + + new_clones = realloc(pdata->clones, + sizeof(*pdata->clones)*(pdata->num_clone_entries+1)); + if (new_clones == NULL) + return 0; + pdata->num_clone_entries++; + pdata->clones = new_clones; + new_clones += (pdata->num_clone_entries-1); + memset(new_clones, 0, sizeof *new_clones); + new_clones->clone_src = selected; + + memset(&data, 0, sizeof data); + data.usage.parts = parts; + + /* if we already have partitions, ask for the target position */ + if (parts->num_part > 0) { + data.res = -1; + num_men = parts->num_part+1; + men = calloc(num_men, sizeof *men); + if (men == NULL) + return 0; + for (i = 0; i < num_men; i++) + men[i].opt_action = clone_target_select; + men[num_men-1].opt_name = MSG_clone_target_end; + + data.usage.menu = new_menu(MSG_clone_target_hdr, + men, num_men, 3, 2, 0, 65, MC_SCROLL, + NULL, draw_outer_part_line, NULL, NULL, MSG_cancel); + process_menu(data.usage.menu, &data); + free_menu(data.usage.menu); + free(men); + + if (data.res < 0) + goto err; + } else { + data.res = 0; + } + + /* find selected offset from data.res and insert clones there */ + align = parts->pscheme->get_part_alignment(parts); + offset = -1; + if (data.res > 0) { + for (cid = 0; cid < (size_t)data.res; cid++) { + if (!parts->pscheme->get_part_info(parts, cid, &sinfo)) + continue; + offset = sinfo.start + sinfo.size; + } + } else { + offset = 0; + } + + new_clones->clone_ids = calloc(selected.num_sel, + sizeof(*new_clones->clone_ids)); + if (new_clones->clone_ids == NULL) + goto err; + for (s = 0; s < selected.num_sel; s++) { + csrc = selected.selection[s].parts; + cid = selected.selection[s].id; + csrc->pscheme->get_part_info(csrc, cid, &sinfo); + if (!parts->pscheme->adapt_foreign_part_info( + parts, &cinfo, csrc->pscheme, &sinfo)) + continue; + size_t cnt = parts->pscheme->get_free_spaces( + parts, &space, 1, cinfo.size-align, align, + offset, -1); + if (cnt == 0) + continue; + cinfo.start = space.start; + cid = parts->pscheme->add_partition( + parts, &cinfo, NULL); + new_clones->clone_ids[s] = cid; + if (cid == NO_PART) + continue; + parts->pscheme->get_part_info(parts, cid, &cinfo); + clone_cnt++; + offset = rounddown(cinfo.start+cinfo.size+align, align); + } + + /* reload menu and start again */ + menu_opts_reload(menu, parts); + menu->cursel = parts->num_part+1; + if (parts->num_part == 0) + menu->cursel++; + return -1; + +err: + free_selected_partitions(&selected); + return -1; +} + + +static int add_part_entry(menudesc *m, void *arg) { - arg_rv *av = arg; - struct part_edit_info data = { .parts = av->arg, + struct outer_parts_data *pdata = arg; + struct part_edit_info data = { .parts = pdata->av.arg, .first_custom_opt = PTN_OPTS_COMMON }; int ptn_menu; daddr_t ptn_alignment; @@ -446,7 +568,7 @@ add_part_entry(menudesc *m, void *arg) struct disk_part_free_space space; const char *err; - opts = fill_part_edit_menu_opts(av->arg, false, ptn_add_opts, + opts = fill_part_edit_menu_opts(data.parts, false, ptn_add_opts, __arraycount(ptn_add_opts), &num_opts); if (opts == NULL) return 1; @@ -617,8 +739,8 @@ draw_outer_ptn_header(menudesc *m, void static void draw_outer_part_line(menudesc *m, int opt, void *arg) { - arg_rv *args = arg; - struct disk_partitions *parts = args->arg; + struct outer_parts_data *pdata = arg; + struct disk_partitions *parts = pdata->av.arg; int len; part_id pno = opt; struct disk_part_info info; @@ -677,9 +799,9 @@ draw_outer_part_line(menudesc *m, int op static int part_edit_abort(menudesc *m, void *arg) { - arg_rv *args = arg; + struct outer_parts_data *pdata = arg; - args->rv = -1; + pdata->av.rv = -1; return 0; } @@ -692,7 +814,7 @@ outer_fill_part_menu_opts(const struct d bool may_add; may_add = parts->pscheme->can_add_partition(parts); - num_opts = 3 + parts->num_part; + num_opts = 4 + parts->num_part; if (parts->num_part == 0) num_opts++; if (may_add) @@ -730,6 +852,11 @@ outer_fill_part_menu_opts(const struct d op++; } + /* and a partition cloner */ + op->opt_name = MSG_clone_from_elsewhere; + op->opt_action = add_part_clone; + op++; + /* and unit changer */ op->opt_name = MSG_askunits; op->opt_menu = MENU_sizechoice; @@ -743,6 +870,9 @@ outer_fill_part_menu_opts(const struct d op->opt_action = part_edit_abort; op++; + /* counts are consistent? */ + assert((op - opts) >= 0 && (size_t)(op - opts) == num_opts); + *cnt = num_opts; return opts; } @@ -750,8 +880,8 @@ outer_fill_part_menu_opts(const struct d static void draw_outer_part_header(menudesc *m, void *arg) { - arg_rv *av = arg; - struct disk_partitions *parts = av->arg; + struct outer_parts_data *pdata = arg; + struct disk_partitions *parts = pdata->av.arg; char start[SSTRSIZE], size[SSTRSIZE], col[SSTRSIZE], *disk_info, total[SSTRSIZE], avail[SSTRSIZE]; size_t sep; @@ -1028,8 +1158,8 @@ ask_outer_partsizes(struct disk_partitio { int j; int part_menu; - size_t num_opts; - arg_rv av; + size_t num_opts, i, ci; + struct outer_parts_data data; part_menu_opts = outer_fill_part_menu_opts(parts, &num_opts); part_menu = new_menu(outer_part_title, part_menu_opts, num_opts, @@ -1048,18 +1178,18 @@ ask_outer_partsizes(struct disk_partitio pm->current_cylsize = 16065; /* noone cares nowadays */ pm->ptstart = 0; pm->ptsize = 0; - av.rv = 0; + memset(&data, 0, sizeof data); + data.av.arg = parts; for (;;) { - av.arg = parts; - av.rv = 0; - process_menu(part_menu, &av); - if (av.rv < 0) + data.av.rv = 0; + process_menu(part_menu, &data); + if (data.av.rv < 0) break; j = verify_outer_parts(parts, false); if (j == 0) { - av.rv = -1; + data.av.rv = -1; return false; } else if (j == 1) { continue; @@ -1067,10 +1197,29 @@ ask_outer_partsizes(struct disk_partitio break; } + /* handle cloned partitions content copies now */ + for (i = 0; i < data.num_clone_entries; i++) { + for (ci = 0; ci < data.clones[i].clone_src.num_sel; ci++) { + if (data.clones[i].clone_src.with_data) + clone_partition_data(parts, + data.clones[i].clone_ids[ci], + data.clones[i].clone_src.selection[ci]. + parts, + data.clones[i].clone_src.selection[ci].id); + } + } + + /* free clone data */ + if (data.clones) { + for (i = 0; i < data.num_clone_entries; i++) + free_selected_partitions(&data.clones[i].clone_src); + free(data.clones); + } + free_menu(part_menu); free(part_menu_opts); - return av.rv == 0; + return data.av.rv == 0; } bool Index: src/usr.sbin/sysinst/partitions.c diff -u src/usr.sbin/sysinst/partitions.c:1.4 src/usr.sbin/sysinst/partitions.c:1.5 --- src/usr.sbin/sysinst/partitions.c:1.4 Sat Oct 26 07:32:52 2019 +++ src/usr.sbin/sysinst/partitions.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: partitions.c,v 1.4 2019/10/26 07:32:52 martin Exp $ */ +/* $NetBSD: partitions.c,v 1.5 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 2018 The NetBSD Foundation, Inc. @@ -65,6 +65,34 @@ partitions_read_disk(const char *dev, da return NULL; } +bool +generic_adapt_foreign_part_info(const struct disk_partitions *myself, + struct disk_part_info *dest, + const struct disk_partitioning_scheme *src_scheme, + const struct disk_part_info *src) +{ + *dest = *src; + if (myself->pscheme == src_scheme) + return true; /* no conversion needed */ + + if (src->nat_type == NULL) + return false; + + /* slightly simplistic, enhance when needed */ + dest->nat_type = myself->pscheme->get_fs_part_type(dest->fs_type, + dest->fs_sub_type); + if (dest->nat_type == NULL) + dest->nat_type = myself->pscheme->get_generic_part_type( + src->nat_type->generic_ptype); + if (dest->nat_type == NULL) + dest->nat_type = myself->pscheme->create_unknown_part_type(); + if (dest->nat_type == NULL) + dest->nat_type = myself->pscheme->get_generic_part_type( + PT_unknown); + + return true; +} + /*************** global init ****************************************/ /* * Helper structure to fill our global list of available partitioning @@ -171,3 +199,15 @@ static const struct part_scheme_desc all free(is_available); } + +/* + * Final cleanup + */ +void +partitions_cleanup(void) +{ + for (size_t i = 0; i < num_available_part_schemes; i++) + if (available_part_schemes[i]->cleanup != NULL) + available_part_schemes[i]->cleanup(); + free(available_part_schemes); +} Index: src/usr.sbin/sysinst/partitions.h diff -u src/usr.sbin/sysinst/partitions.h:1.7 src/usr.sbin/sysinst/partitions.h:1.8 --- src/usr.sbin/sysinst/partitions.h:1.7 Fri Oct 25 12:49:58 2019 +++ src/usr.sbin/sysinst/partitions.h Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: partitions.h,v 1.7 2019/10/25 12:49:58 martin Exp $ */ +/* $NetBSD: partitions.h,v 1.8 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 2018 The NetBSD Foundation, Inc. @@ -233,6 +233,15 @@ struct disk_partitioning_scheme { */ const struct part_type_desc * (*create_custom_part_type) (const char *custom, const char **err_msg); + /* + * Return a usable internal partition type representation + * for types that are not otherwise mappable. + * This could be FS_OTHER for disklabel, or a randomly + * created type guid for GPT. This type may or may not be + * in the regular type list. If not, it needs to behave like a + * custom type. + */ + const struct part_type_desc * (*create_unknown_part_type)(void); /* * Global attributes @@ -343,8 +352,10 @@ struct disk_partitioning_scheme { * This mostly adjusts flags and partition type pointers (using * more lose matching than add_partition would do). */ - bool (*adapt_foreign_part_info)(const struct disk_partitions*, - const struct disk_part_info *src, struct disk_part_info *dest); + bool (*adapt_foreign_part_info)( + const struct disk_partitions *myself, struct disk_part_info *dest, + const struct disk_partitioning_scheme *src_scheme, + const struct disk_part_info *src); /* * Update data for an existing partition @@ -491,6 +502,9 @@ struct disk_partitioning_scheme { /* Free all the data */ void (*free)(struct disk_partitions*); + + /* Scheme global cleanup */ + void (*cleanup)(void); }; /* @@ -552,6 +566,16 @@ struct disk_partitions * partitions_read_disk(const char *, daddr_t disk_size, bool no_mbr); /* - * One time initialization + * Generic part info adaption, may be overriden by individual partitionin + * schemes + */ +bool generic_adapt_foreign_part_info( + const struct disk_partitions *myself, struct disk_part_info *dest, + const struct disk_partitioning_scheme *src_scheme, + const struct disk_part_info *src); + +/* + * One time initialization and clenaup */ void partitions_init(void); +void partitions_cleanup(void); Index: src/usr.sbin/sysinst/util.c diff -u src/usr.sbin/sysinst/util.c:1.34 src/usr.sbin/sysinst/util.c:1.35 --- src/usr.sbin/sysinst/util.c:1.34 Fri Oct 4 21:36:02 2019 +++ src/usr.sbin/sysinst/util.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: util.c,v 1.34 2019/10/04 21:36:02 mrg Exp $ */ +/* $NetBSD: util.c,v 1.35 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -2043,42 +2043,48 @@ usage_set_from_parts(struct partition_us return usage_info_list_from_parts(&wanted->infos, &wanted->num, parts); } -bool -install_desc_from_parts(struct install_partition_desc *install, - struct disk_partitions *parts) +struct disk_partitions * +get_inner_parts(struct disk_partitions *parts) { - struct disk_partitions *inner_parts; daddr_t start, size; part_id pno; struct disk_part_info info; - memset(install, 0, sizeof(*install)); + if (parts->pscheme->secondary_scheme == NULL) + return NULL; - if (parts->pscheme->secondary_scheme != NULL) { - start = -1; - size = -1; - if (parts->pscheme->guess_install_target != NULL && - parts->pscheme->guess_install_target(parts, - &start, &size)) { - } else { - for (pno = 0; pno < parts->num_part; pno++) { - if (!parts->pscheme->get_part_info(parts, pno, - &info)) - continue; - if (!(info.flags & PTI_SEC_CONTAINER)) - continue; - start = info.start; - size = info.size; - } - } - if (size > 0) { - inner_parts = parts->pscheme->secondary_partitions( - parts, start, false); - if (inner_parts != NULL) - parts = inner_parts; + start = -1; + size = -1; + if (parts->pscheme->guess_install_target == NULL || + !parts->pscheme->guess_install_target(parts, &start, &size)) { + for (pno = 0; pno < parts->num_part; pno++) { + if (!parts->pscheme->get_part_info(parts, pno, &info)) + continue; + if (!(info.flags & PTI_SEC_CONTAINER)) + continue; + start = info.start; + size = info.size; } } + if (size > 0) + return parts->pscheme->secondary_partitions(parts, start, + false); + + return NULL; +} + +bool +install_desc_from_parts(struct install_partition_desc *install, + struct disk_partitions *parts) +{ + struct disk_partitions *inner_parts; + + memset(install, 0, sizeof(*install)); + inner_parts = get_inner_parts(parts); + if (inner_parts != NULL) + parts = inner_parts; + return usage_info_list_from_parts(&install->infos, &install->num, parts); } @@ -2086,6 +2092,7 @@ install_desc_from_parts(struct install_p void free_usage_set(struct partition_usage_set *wanted) { + /* XXX - free parts? free clone src? */ free(wanted->menu_opts); free(wanted->infos); } @@ -2093,6 +2100,18 @@ free_usage_set(struct partition_usage_se void free_install_desc(struct install_partition_desc *install) { + size_t i, j; + + for (i = 0; i < install->num; i++) { + struct selected_partitions *src = install->infos[i].clone_src; + if (!(install->infos[i].flags & PUIFLG_CLONE_PARTS) || + src == NULL) + continue; + free_selected_partitions(src); + for (j = i+1; j < install->num; j++) + if (install->infos[j].clone_src == src) + install->infos[j].clone_src = NULL; + } free(install->infos); } Index: src/usr.sbin/sysinst/arch/i386/md.c diff -u src/usr.sbin/sysinst/arch/i386/md.c:1.21 src/usr.sbin/sysinst/arch/i386/md.c:1.22 --- src/usr.sbin/sysinst/arch/i386/md.c:1.21 Wed Aug 14 12:55:36 2019 +++ src/usr.sbin/sysinst/arch/i386/md.c Tue Nov 12 16:33:14 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: md.c,v 1.21 2019/08/14 12:55:36 martin Exp $ */ +/* $NetBSD: md.c,v 1.22 2019/11/12 16:33:14 martin Exp $ */ /* * Copyright 1997 Piermont Information Systems Inc. @@ -895,7 +895,7 @@ x86_md_part_defaults(struct pm_devs *cur if (info.nat_type->generic_ptype != boot->type) continue; boot->flags &= ~PUIFLAG_ADD_OUTER; - boot->flags |= PUIFLG_IS_OUTER|PUIFLAG_ADD_INNER; + boot->flags |= PUIFLG_IS_OUTER|PUIFLG_ADD_INNER; boot->size = info.size; boot->cur_start = info.start; boot->cur_flags = info.flags;