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