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