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