Annotation of src/usr.sbin/sysinst/bsddisklabel.c, Revision 1.15
1.15 ! martin 1: /* $NetBSD: bsddisklabel.c,v 1.14 2019/06/20 15:52:07 christos 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
75: .instflags = PUIINST_MOUNT|PUIINST_BOOT,
76: #endif
77: #ifdef PART_BOOT_TYPE
78: .fs_type = PART_BOOT_TYPE,
79: #if PART_BOOT_TYPE == FS_MSDOS
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,
103: #if PART_BOOT1_TYPE == FS_MSDOS
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,
122: #if PART_BOOT2_TYPE == FS_MSDOS
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
146: { .def_size = DEFUSRSIZE*(MEG/512), .mount = "/usr", .type = PT_root },
147: { .def_size = DEFVARSIZE*(MEG/512), .mount = "/var", .type = PT_root },
148: };
149:
150: #if 0 // XXX
151: static int
1.1 dholland 152: save_ptn(int ptn, daddr_t start, daddr_t size, int fstype, const char *mountpt)
153: {
154: static int maxptn;
155: partinfo *p;
156: int pp;
1.2 martin 157: char *buf;
1.1 dholland 158:
159: if (maxptn == 0)
160: maxptn = getmaxpartitions();
161:
1.9 martin 162: if (ptn < 0 || PI_FSTYPE(&pm->bsdlabel[ptn]) != FS_UNUSED) {
1.1 dholland 163: ptn = getrawpartition() + 1;
164: #ifdef PART_FIRST_FREE
165: if (ptn < PART_FIRST_FREE)
166: ptn = PART_FIRST_FREE;
167: #endif
168: for (;; ptn++) {
169: if (ptn >= maxptn)
170: return -1;
1.9 martin 171: // XXX if (ptn == PART_USR)
172: // continue;
173: if (PI_FSTYPE(&pm->bsdlabel[ptn]) == FS_UNUSED)
1.1 dholland 174: break;
175: }
176: }
177:
178: if (fstype == FS_UNUSED)
179: return ptn;
180:
1.2 martin 181: p = pm->bsdlabel + ptn;
1.9 martin 182: PI_SET_OFFSET(p, start);
183: PI_SET_SIZE(p, size);
1.1 dholland 184: set_ptype(p, fstype, mountpt ? PIF_NEWFS : 0);
185:
1.2 martin 186: /* Hack because we does not have something like FS_LVMPV */
187: p->lvmpv = 0;
188: if (mountpt != NULL && strcmp(mountpt, "lvm") == 0)
189: p->lvmpv = 1;
190: else if (mountpt != NULL) {
1.1 dholland 191: for (pp = 0; pp < maxptn; pp++) {
1.2 martin 192: if (strcmp(pm->bsdlabel[pp].pi_mount, mountpt) == 0)
193: pm->bsdlabel[pp].pi_flags &= ~PIF_MOUNT;
1.1 dholland 194: }
1.2 martin 195: if (mountpt[0] != '/')
196: asprintf(&buf, "/%s", mountpt);
197: else
198: asprintf(&buf, "%s", mountpt);
199: strlcpy(p->pi_mount, buf, sizeof p->pi_mount);
1.1 dholland 200: p->pi_flags |= PIF_MOUNT;
201: /* Default to UFS2. */
1.9 martin 202: if (PI_FSTYPE(p) == FS_BSDFFS) {
1.1 dholland 203: #ifdef DEFAULT_UFS2
204: #ifndef HAVE_UFS2_BOOT
205: if (strcmp(mountpt, "/") != 0)
206: #endif
207: p->pi_flags |= PIF_FFSv2;
208: #endif
209: }
1.2 martin 210: free(buf);
1.1 dholland 211: }
1.9 martin 212: return ptn;
213: }
214: #endif
215:
1.1 dholland 216:
1.9 martin 217: static const char size_separator[] =
218: "----------------------------------- - --------------------";
219: static char size_menu_title[STRSIZE];
220: static char size_menu_exit[MENUSTRSIZE];
221:
222: static void
223: set_pset_exit_str(struct partition_usage_set *pset)
224: {
225: char *str, num[25];
226: const char *args[2];
227: bool overrun;
228: daddr_t free_space = pset->cur_free_space;
229:
230: /* format exit string */
231: overrun = free_space < 0;
232: if (overrun)
233: free_space = -free_space;
234:
235: snprintf(num, sizeof(num), "%" PRIu64, free_space / sizemult);
236: args[0] = num;
237: args[1] = multname;
238: str = str_arg_subst(
239: msg_string(overrun ? MSG_fssizesbad : MSG_fssizesok),
240: 2, args);
241: strlcpy(size_menu_exit, str, sizeof(size_menu_exit));
242: free(str);
243: }
244:
245: static void
246: draw_size_menu_header(menudesc *m, void *arg)
247: {
248: struct partition_usage_set *pset = arg;
249: size_t i;
250: char col1[70], desc[MENUSTRSIZE];
251: bool need_ext = false, need_existing = false;
252:
253: msg_display(MSG_ptnsizes);
254:
255: for (i = 0; i < pset->num; i++) {
256: if (pset->infos[i].flags & PUIFLG_IS_OUTER)
257: need_ext = true;
258: else if (pset->infos[i].cur_part_id != NO_PART)
259: need_existing = true;
260: }
261: if (need_ext && need_existing)
262: snprintf(desc, sizeof desc, "%s, %s",
263: msg_string(MSG_ptnsizes_mark_existing),
264: msg_string(MSG_ptnsizes_mark_external));
265: else if (need_existing)
266: strlcpy(desc, msg_string(MSG_ptnsizes_mark_existing),
267: sizeof desc);
268: else if (need_ext)
269: strlcpy(desc, msg_string(MSG_ptnsizes_mark_external),
270: sizeof desc);
271: if (need_ext || need_existing) {
272: msg_printf("\n");
273: msg_display_add_subst(msg_string(MSG_ptnsizes_markers),
274: 1, &desc);
275: }
276: msg_printf("\n\n");
277:
278: /* update menu title */
279: snprintf(col1, sizeof col1, "%s (%s)", msg_string(MSG_ptnheaders_size),
280: multname);
281: snprintf(size_menu_title, sizeof size_menu_title,
282: " %-37.37s %s\n %s", col1,
283: msg_string(MSG_ptnheaders_filesystem), size_separator);
1.1 dholland 284: }
285:
1.9 martin 286: static void
287: draw_size_menu_line(menudesc *m, int opt, void *arg)
1.1 dholland 288: {
1.9 martin 289: struct partition_usage_set *pset = arg;
1.1 dholland 290: daddr_t size;
1.9 martin 291: char psize[38], inc_free[16], flag, swap[40];
292: const char *mount;
293: bool free_mount = false;
1.1 dholland 294:
1.9 martin 295: if (opt < 0 || (size_t)opt >= pset->num)
1.1 dholland 296: return;
1.9 martin 297:
298: inc_free[0] = 0;
299: if ((pset->infos[opt].flags & PUIFLAG_EXTEND) &&
300: pset->cur_free_space > 0) {
301: size = pset->infos[opt].size + pset->cur_free_space;
302: snprintf(inc_free, sizeof inc_free, " (%" PRIu64 ")",
303: size / sizemult);
304: }
305: size = pset->infos[opt].size;
306: snprintf(psize, sizeof psize, "%" PRIu64 "%s",
307: size / sizemult, inc_free);
308:
309: if (pset->infos[opt].type == PT_swap) {
310: snprintf(swap, sizeof swap, "<%s>",
311: msg_string(MSG_swap_display));
312: mount = swap;
313: } else if (pset->infos[opt].flags & PUIFLG_JUST_MOUNTPOINT) {
314: snprintf(swap, sizeof swap, "%s (%s)",
315: pset->infos[opt].mount,
316: getfslabelname(pset->infos[opt].fs_type,
317: pset->infos[opt].fs_version));
318: mount = swap;
1.14 christos 319: } else if (pset->infos[opt].mount[0]) {
1.9 martin 320: mount = pset->infos[opt].mount;
321: } else {
322: mount = getfslabelname(pset->infos[opt].fs_type,
323: pset->infos[opt].fs_version);
324: mount = str_arg_subst(msg_string(MSG_size_ptn_not_mounted),
325: 1, &mount);
326: free_mount = true;
327: }
328: flag = ' ';
329: if (pset->infos[opt].flags & PUIFLAG_EXTEND)
330: flag = '+';
331: else if (pset->infos[opt].flags & PUIFLG_IS_OUTER)
332: flag = '@';
333: else if (pset->infos[opt].cur_part_id != NO_PART)
334: flag = '=';
335: wprintw(m->mw, "%-35.35s %c %s", psize, flag, mount);
336: if (free_mount)
337: free(__UNCONST(mount));
338:
339: if (opt == 0)
340: set_pset_exit_str(pset);
341: }
342:
343: static int
344: add_other_ptn_size(menudesc *menu, void *arg)
345: {
346: struct partition_usage_set *pset = arg;
347: struct part_usage_info *p;
348: struct menu_ent *m;
349: char new_mp[MOUNTLEN], *err;
350: const char *args;
351:
352: for (;;) {
353: msg_prompt_win(partman_go?MSG_askfsmountadv:MSG_askfsmount,
354: -1, 18, 0, 0, NULL, new_mp, sizeof(new_mp));
355: if (new_mp[0] == 0)
356: return 0;
357: if (new_mp[0] != '/') {
358: /* we need absolute mount paths */
359: memmove(new_mp+1, new_mp, sizeof(new_mp)-1);
360: new_mp[0] = '/';
361: /* duplicates? */
362: bool duplicate = false;
363: for (size_t i = 0; i < pset->num; i++) {
364: if (strcmp(pset->infos[i].mount,
365: new_mp) == 0) {
366: args = new_mp;
367: err = str_arg_subst(
368: msg_string(MSG_mp_already_exists),
369: 1, &args);
370: err_msg_win(err);
371: free(err);
372: duplicate = true;
373: break;
374: }
375: }
376: if (!duplicate)
377: break;
378: }
1.1 dholland 379: }
1.9 martin 380:
381: m = realloc(pset->menu_opts, (pset->num+4)*sizeof(*pset->menu_opts));
382: if (m == NULL)
383: return 0;
384: p = realloc(pset->infos, (pset->num+1)*sizeof(*pset->infos));
385: if (p == NULL)
386: return 0;
387:
388: pset->infos = p;
389: pset->menu_opts = m;
390: menu->opts = m;
391: menu->numopts = pset->num+4;
392: m += pset->num;
393: p += pset->num;
394: memset(m, 0, sizeof(*m));
395: memset(p, 0, sizeof(*p));
396: strncpy(p->mount, new_mp, sizeof(p->mount));
397:
398: menu->cursel = pset->num;
399: pset->num++;
400: fill_ptn_menu(pset);
401:
402: return -1;
1.1 dholland 403: }
404:
1.9 martin 405: static size_t
406: fill_ptn_menu(struct partition_usage_set *pset)
1.1 dholland 407: {
1.9 martin 408: struct part_usage_info *p;
409: struct disk_part_info info;
1.1 dholland 410: menu_ent *m;
1.9 martin 411: size_t i;
412: daddr_t free_space;
1.1 dholland 413:
1.9 martin 414: memset(pset->menu_opts, 0, (pset->num+3)*sizeof(*pset->menu_opts));
415: for (m = pset->menu_opts, p = pset->infos, i = 0; i < pset->num;
416: m++, p++, i++) {
1.1 dholland 417: m->opt_menu = OPT_NOMENU;
418: m->opt_action = set_ptn_size;
419: }
1.9 martin 420:
421: m->opt_name = size_separator;
422: m->opt_menu = OPT_NOMENU;
423: m->opt_flags = OPT_IGNORE|OPT_NOSHORT;
424: m++;
425:
426: m->opt_name = MSG_add_another_ptn;
427: m->opt_menu = OPT_NOMENU;
428: m->opt_action = add_other_ptn_size;
429: m++;
430:
1.1 dholland 431: m->opt_name = MSG_askunits;
432: m->opt_menu = MENU_sizechoice;
433: m->opt_flags = OPT_SUB;
434: m++;
435:
1.9 martin 436: /* calculate free space */
437: free_space = pset->parts->free_space;
438: for (i = 0; i < pset->parts->num_part; i++) {
439: if (!pset->parts->pscheme->get_part_info(pset->parts, i,
440: &info))
441: continue;
442: if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK|
443: PTI_PSCHEME_INTERNAL|PTI_RAW_PART))
444: continue;
445: free_space += info.size;
446: }
447: for (i = 0; i < pset->num; i++) {
448: if (pset->infos[i].flags &
449: (PUIFLG_IS_OUTER|PUIFLG_JUST_MOUNTPOINT))
450: continue;
451: free_space -= pset->infos[i].size;
452: }
453: pset->cur_free_space = free_space;
454: set_pset_exit_str(pset);
455:
456: if (pset->menu >= 0)
457: set_menu_numopts(pset->menu, m - pset->menu_opts);
458:
459: return m - pset->menu_opts;
460: }
461:
462: static part_id
463: find_part_at(struct disk_partitions *parts, daddr_t start)
464: {
465: size_t i;
466: struct disk_part_info info;
467:
468: for (i = 0; i < parts->num_part; i++) {
469: if (!parts->pscheme->get_part_info(parts, i, &info))
470: continue;
471: if (info.start == start)
472: return i;
473: }
1.1 dholland 474:
1.9 martin 475: return NO_PART;
1.1 dholland 476: }
477:
478: int
479: set_ptn_size(menudesc *m, void *arg)
480: {
1.9 martin 481: struct partition_usage_set *pset = arg;
482: struct part_usage_info *p = &pset->infos[m->cursel];
483: char answer[16], dflt[16];
484: const char *err_msg;
485: size_t i, root = ~0U;
486: daddr_t size, old_size, new_size_val, mult;
487: int rv;
488: bool non_zero, extend;
1.1 dholland 489:
1.9 martin 490: if (pset->cur_free_space == 0 && p->size == 0 &&
491: !(p->flags & PUIFLG_JUST_MOUNTPOINT))
1.1 dholland 492: /* Don't allow 'free_parts' to go negative */
493: return 0;
494:
1.9 martin 495: if (p->cur_part_id != NO_PART) {
496: rv = 0;
497: process_menu(MENU_ptnsize_replace_existing_partition, &rv);
498: if (rv == 0)
499: return 0;
500: if (!pset->parts->pscheme->delete_partition(pset->parts,
501: p->cur_part_id, &err_msg)) {
502: if (err_msg)
503: err_msg_win(err_msg);
1.1 dholland 504: return 0;
1.9 martin 505: }
506: p->cur_part_id = NO_PART;
507: /*
508: * All other part ids are invalid now too - update them!
509: */
510: for (i = 0; i < pset->num; i++) {
511: if (pset->infos[i].cur_part_id == NO_PART)
512: continue;
513: pset->infos[i].cur_part_id =
514: find_part_at(pset->parts, pset->infos[i].cur_start);
515: }
1.1 dholland 516: }
517:
518: size = p->size;
519: old_size = size;
520: if (size == 0)
1.9 martin 521: size = p->def_size;
1.1 dholland 522: size /= sizemult;
1.9 martin 523: snprintf(dflt, sizeof dflt, "%" PRIu64 "%s",
524: size, p->flags & PUIFLAG_EXTEND ? "+" : "");
1.1 dholland 525:
526: for (;;) {
1.13 christos 527: msg_fmt_prompt_win(MSG_askfssize, -1, 18, 0, 0,
528: dflt, answer, sizeof answer, "%s%s", p->mount, multname);
1.9 martin 529:
530: /* cp will be checked below */
531: mult = sizemult;
532: new_size_val = parse_disk_pos(answer, &mult, pm->dlcylsize,
533: &extend);
534:
535: if (strcmp(answer, dflt) == 0)
536: non_zero = p->def_size > 0;
537: else
538: non_zero = new_size_val > 0;
539:
1.1 dholland 540: /* Some special cases when /usr is first given a size */
1.9 martin 541: if (old_size == 0 && non_zero &&
542: strcmp(p->mount, "/usr") == 0) {
543: for (i = 0; i < pset->num; i++) {
544: if (strcmp(pset->infos[i].mount, "/") == 0) {
545: root = i;
546: break;
547: }
548: }
1.1 dholland 549: /* Remove space for /usr from / */
1.9 martin 550: if (root < pset->num && pset->infos[i].cur_part_id ==
551: NO_PART) {
552: pset->infos[root].size -= p->def_size;
553: pset->cur_free_space += p->def_size;
1.1 dholland 554: }
555: /* hack to add free space to default sized /usr */
1.9 martin 556: if (strcmp(answer, dflt) == 0) {
557: size = p->def_size;
558: pset->infos[root].flags &= ~PUIFLAG_EXTEND;
559: p->flags |= PUIFLAG_EXTEND;
1.1 dholland 560: goto adjust_free;
561: }
562: }
1.9 martin 563: if (new_size_val < 0)
1.1 dholland 564: continue;
1.9 martin 565: size = new_size_val;
566: break;
1.1 dholland 567: }
568:
1.9 martin 569: daddr_t align = pset->parts->pscheme->get_part_alignment(pset->parts);
570: size = NUMSEC(size, mult, align);
571: if (p->flags & PUIFLAG_EXTEND)
572: p->flags &= ~PUIFLAG_EXTEND;
573: if (extend && (p->limit == 0 || p->limit > p->size)) {
574: p->flags |= PUIFLAG_EXTEND;
1.1 dholland 575: if (size == 0)
1.9 martin 576: size = align;
1.1 dholland 577: }
578: if (p->limit != 0 && size > p->limit)
579: size = p->limit;
580: adjust_free:
1.9 martin 581: if ((p->flags & (PUIFLG_IS_OUTER|PUIFLG_JUST_MOUNTPOINT)) == 0)
582: pset->cur_free_space += p->size - size;
1.1 dholland 583: p->size = size;
1.9 martin 584: set_pset_exit_str(pset);
1.1 dholland 585:
586: return 0;
587: }
588:
1.9 martin 589: /*
590: * User interface to edit a "wanted" partition layout "pset" as first
591: * abstract phase (not concrete partitions).
592: * Make sure to have everything (at least theoretically) fit the
593: * available space.
594: * During editing we keep the part_usage_info and the menu_opts
595: * in pset in sync, that is: we always allocate just enough entries
596: * in pset->infos as we have usage infos in the list (pset->num),
597: * and two additional menu entries ("add a partition" and "select units").
598: * The menu exit string changes depending on content, and implies
599: * abort while the partition set is not valid (does not fit).
600: * Return true when the user wants to continue (by editing the concrete
601: * partitions), return false to abort.
602: */
603: bool
604: get_ptn_sizes(struct partition_usage_set *pset)
605: {
606: size_t num;
607:
608: wclear(stdscr);
609: wrefresh(stdscr);
610:
611: if (pset->menu_opts == NULL)
612: pset->menu_opts = calloc(pset->num+3, sizeof(*pset->menu_opts));
613:
614: pset->menu = -1;
615: num = fill_ptn_menu(pset);
616:
617: pset->menu = new_menu(size_menu_title, pset->menu_opts, num,
618: 3, -1, 12, 70,
619: MC_ALWAYS_SCROLL|MC_NOBOX|MC_NOCLEAR|MC_CONTINUOUS,
620: draw_size_menu_header, draw_size_menu_line, NULL,
621: NULL, size_menu_exit);
622:
623: if (pset->menu < 0) {
624: free(pset->menu_opts);
625: pset->menu_opts = NULL;
626: return false;
627: }
1.1 dholland 628:
1.9 martin 629: pset->ok = true;
630: process_menu(pset->menu, pset);
1.1 dholland 631:
1.9 martin 632: free_menu(pset->menu);
633: free(pset->menu_opts);
634: pset->menu = -1;
635: pset->menu_opts = NULL;
1.1 dholland 636:
1.9 martin 637: if (!pset->ok)
638: return false;
1.1 dholland 639:
1.9 martin 640: #if 0
641: if (cur_ptns.menu_no < 0) {
1.1 dholland 642: /* If there is a swap partition elsewhere, don't add one here.*/
1.2 martin 643: if (no_swap || (swap_created && partman_go)) {
1.9 martin 644: cur_ptns.ptn_sizes[PI_SWAP].size = 0;
1.1 dholland 645: } else {
646: #if DEFSWAPSIZE == -1
647: /* Dynamic swap size. */
1.9 martin 648: cur_ptns.ptn_sizes[PI_SWAP].dflt_size = get_ramsize();
649: cur_ptns.ptn_sizes[PI_SWAP].size =
650: cur_ptns.ptn_sizes[PI_SWAP].dflt_size;
1.1 dholland 651: #endif
652: }
653:
654: /* If installing X increase default size of /usr */
655: if (set_X11_selected())
1.9 martin 656: cur_ptns.ptn_sizes[PI_USR].dflt_size += XNEEDMB;
1.1 dholland 657:
658: /* Start of planning to give free space to / */
1.9 martin 659: cur_ptns.pool_part = &cur_ptns.ptn_sizes[PI_ROOT];
1.1 dholland 660: /* Make size of root include default size of /usr */
1.9 martin 661: cur_ptns.ptn_sizes[PI_ROOT].size += cur_ptns.ptn_sizes[PI_USR].dflt_size;
1.1 dholland 662:
1.2 martin 663: sm = MEG / pm->sectorsize;
1.1 dholland 664:
665: if (root_limit != 0) {
666: /* Bah - bios can not read all the disk, limit root */
1.9 martin 667: cur_ptns.ptn_sizes[PI_ROOT].limit = root_limit -
668: part_start;
1.1 dholland 669: /* Allocate a /usr partition if bios can't read
670: * everything except swap.
671: */
1.9 martin 672: if (cur_ptns.ptn_sizes[PI_ROOT].limit
673: < sectors - cur_ptns.ptn_sizes[PI_SWAP].size * sm) {
1.1 dholland 674: /* Root won't be able to access all the space */
675: /* Claw back space for /usr */
1.9 martin 676: cur_ptns.ptn_sizes[PI_USR].size =
677: cur_ptns.ptn_sizes[PI_USR].dflt_size;
678: cur_ptns.ptn_sizes[PI_ROOT].size -=
679: cur_ptns.ptn_sizes[PI_USR].dflt_size;
680: cur_ptns.ptn_sizes[PI_ROOT].changed = 1;
1.1 dholland 681: /* Give free space to /usr */
1.9 martin 682: cur_ptns.pool_part = &cur_ptns.ptn_sizes[PI_USR];
1.1 dholland 683: }
684: }
685:
686: /* Change preset sizes from MB to sectors */
1.9 martin 687: cur_ptns.free_space = sectors;
688: for (p = cur_ptns.ptn_sizes; p->mount[0]; p++) {
1.2 martin 689: p->size = NUMSEC(p->size, sm, pm->dlcylsize);
690: p->dflt_size = NUMSEC(p->dflt_size, sm, pm->dlcylsize);
1.9 martin 691: cur_ptns.free_space -= p->size;
1.1 dholland 692: }
693:
694: /* Steal space from swap to make things fit.. */
1.9 martin 695: if (cur_ptns.free_space < 0) {
696: i = roundup(-cur_ptns.free_space, pm->dlcylsize);
697: if (i > cur_ptns.ptn_sizes[PI_SWAP].size)
698: i = cur_ptns.ptn_sizes[PI_SWAP].size;
699: cur_ptns.ptn_sizes[PI_SWAP].size -= i;
700: cur_ptns.free_space += i;
1.1 dholland 701: }
702:
703: /* Add space for 2 system dumps to / (traditional) */
704: i = get_ramsize() * sm;
1.2 martin 705: i = roundup(i, pm->dlcylsize);
1.9 martin 706: if (cur_ptns.free_space > i * 2)
1.1 dholland 707: i *= 2;
1.9 martin 708: if (cur_ptns.free_space > i) {
709: cur_ptns.ptn_sizes[PI_ROOT].size += i;
710: cur_ptns.free_space -= i;
1.2 martin 711: }
712:
713: if (root_created && partman_go) {
1.9 martin 714: cur_ptns.ptn_sizes[PI_ROOT].size = 0;
715: cur_ptns.pool_part = 0;
1.1 dholland 716: }
717:
718: /* Ensure all of / is readable by the system boot code */
1.9 martin 719: i = cur_ptns.ptn_sizes[PI_ROOT].limit;
720: if (i != 0 && (i -= cur_ptns.ptn_sizes[PI_ROOT].size) < 0) {
721: cur_ptns.ptn_sizes[PI_ROOT].size += i;
722: cur_ptns.free_space -= i;
1.1 dholland 723: }
724:
725: /* Count free partition slots */
1.9 martin 726: cur_ptns.free_parts = 0;
727: #if 0 // XXX
1.1 dholland 728: for (i = 0; i < maxpart; i++) {
1.2 martin 729: if (pm->bsdlabel[i].pi_size == 0)
1.9 martin 730: cur_ptns.free_parts++;
1.1 dholland 731: }
1.9 martin 732: #endif
1.1 dholland 733: for (i = 0; i < MAXPARTITIONS; i++) {
1.9 martin 734: p = &cur_ptns.ptn_sizes[i];
735: if (i != 0 && p->use == 0)
736: p->use = PART_EXTRA;
1.1 dholland 737: if (p->size != 0)
1.9 martin 738: cur_ptns.free_parts--;
1.1 dholland 739: }
740:
1.9 martin 741: cur_ptns.menu_no = new_menu(0, cur_ptns.ptn_menus,
742: __arraycount(cur_ptns.ptn_menus),
1.1 dholland 743: 3, -1, 12, 70,
744: MC_ALWAYS_SCROLL | MC_NOBOX | MC_NOCLEAR,
745: NULL, set_ptn_titles, NULL,
1.9 martin 746: "help", cur_ptns.exit_msg);
1.1 dholland 747:
1.9 martin 748: if (cur_ptns.menu_no < 0)
1.1 dholland 749: return;
750: }
751:
752: do {
1.9 martin 753: set_ptn_menu(&cur_ptns);
1.2 martin 754: pm->current_cylsize = pm->dlcylsize;
1.9 martin 755: process_menu(cur_ptns.menu_no, &cur_ptns);
756: } while (cur_ptns.free_space < 0 || cur_ptns.free_parts < 0);
1.1 dholland 757:
758: /* Give any cylinder fragment to last partition */
1.9 martin 759: if (cur_ptns.pool_part != NULL || cur_ptns.free_space < pm->dlcylsize) {
760: for (p = cur_ptns.ptn_sizes + __arraycount(cur_ptns.ptn_sizes) - 1; ;p--) {
1.1 dholland 761: if (p->size == 0) {
1.9 martin 762: if (p == cur_ptns.ptn_sizes)
1.1 dholland 763: break;
764: continue;
765: }
1.9 martin 766: if (p->use == PART_TMP_RAMDISK)
1.1 dholland 767: continue;
1.9 martin 768: p->size += cur_ptns.free_space % pm->dlcylsize;
769: cur_ptns.free_space -= cur_ptns.free_space % pm->dlcylsize;
1.1 dholland 770: break;
771: }
772: }
773:
1.9 martin 774: for (p = cur_ptns.ptn_sizes; p->mount[0]; p++, part_start += size) {
1.1 dholland 775: size = p->size;
1.9 martin 776: if (p == cur_ptns.pool_part) {
777: size += rounddown(cur_ptns.free_space, pm->dlcylsize);
1.1 dholland 778: if (p->limit != 0 && size > p->limit)
779: size = p->limit;
780: }
1.9 martin 781: i = p->use;
1.1 dholland 782: if (i == PART_TMP_RAMDISK) {
783: tmp_ramdisk_size = size;
784: size = 0;
785: continue;
786: }
787: if (size == 0)
788: continue;
1.2 martin 789: if (i == PART_ROOT && size > 0)
790: root_created = 1;
1.1 dholland 791: if (i == PART_SWAP) {
1.2 martin 792: if (size > 0)
793: swap_created = 1;
1.1 dholland 794: save_ptn(i, part_start, size, FS_SWAP, NULL);
795: continue;
796: }
1.2 martin 797: if (!strcmp(p->mount, "raid")) {
798: save_ptn(i, part_start, size, FS_RAID, NULL);
799: continue;
800: } else if (!strcmp(p->mount, "cgd")) {
801: save_ptn(i, part_start, size, FS_CGD, NULL);
802: continue;
803: }
1.1 dholland 804: save_ptn(i, part_start, size, FS_BSDFFS, p->mount);
805: }
1.9 martin 806: #endif
807: return true;
808: }
809:
810: static int
811: set_keep_existing(menudesc *m, void *arg)
812: {
813: ((arg_rep_int*)arg)->rv = LY_KEEPEXISTING;
814: return 0;
815: }
816:
817: static int
818: set_edit_part_sizes(menudesc *m, void *arg)
819: {
820: ((arg_rep_int*)arg)->rv = LY_SETSIZES;
821: return 0;
822: }
823:
824: static int
825: set_use_default_sizes(menudesc *m, void *arg)
826: {
827: ((arg_rep_int*)arg)->rv = LY_USEDEFAULT;
828: return 0;
1.1 dholland 829: }
830:
831: /*
1.9 martin 832: * Check if there is a reasonable pre-existing partition for
833: * NetBSD.
834: */
835:
836: static bool
837: check_existing_netbsd(struct disk_partitions *parts)
838: {
839: size_t nbsd_parts;
840: struct disk_part_info info;
841:
842: nbsd_parts = 0;
843: for (part_id p = 0; p < parts->num_part; p++) {
844: if (parts->pscheme->get_part_info(parts, p, &info) &&
845: info.nat_type && info.nat_type->generic_ptype == PT_root)
846: nbsd_parts++;
847: }
848:
849: return nbsd_parts > 0;
850: }
851:
852: /*
853: * Query a partition layout type (with available options depending on
854: * pre-existing partitions).
1.1 dholland 855: */
1.9 martin 856: static enum layout_type
857: ask_layout(struct disk_partitions *parts, bool have_existing)
858: {
859: arg_rep_int ai;
860: const char *args[2];
861: int menu;
862: size_t num_opts;
863: menu_ent options[3], *opt;
864:
865: args[0] = msg_string(parts->pscheme->name);
866: args[1] = msg_string(parts->pscheme->short_name);
867: ai.args.argv = args;
868: ai.args.argc = 2;
869: ai.rv = LY_SETSIZES;
870:
871: memset(options, 0, sizeof(options));
872: num_opts = 0;
873: opt = &options[0];
874:
875: if (have_existing) {
876: opt->opt_name = MSG_Keep_existing_partitions;
877: opt->opt_exp_name = NULL;
878: opt->opt_menu = OPT_NOMENU;
879: opt->opt_flags = OPT_EXIT;
880: opt->opt_action = set_keep_existing;
881: opt++;
882: num_opts++;
883: }
884: opt->opt_name = MSG_Set_Sizes;
885: opt->opt_exp_name = NULL;
886: opt->opt_menu = OPT_NOMENU;
887: opt->opt_flags = OPT_EXIT;
888: opt->opt_action = set_edit_part_sizes;
889: opt++;
890: num_opts++;
891:
892: opt->opt_name = MSG_Use_Default_Parts;
893: opt->opt_exp_name = NULL;
894: opt->opt_menu = OPT_NOMENU;
895: opt->opt_flags = OPT_EXIT;
896: opt->opt_action = set_use_default_sizes;
897: opt++;
898: num_opts++;
899:
900: menu = new_menu(MSG_Select_your_choice, options, num_opts,
901: -1, -10, 0, 0, MC_NOEXITOPT, NULL, NULL, NULL, NULL, NULL);
902: if (menu != -1) {
903: get_menudesc(menu)->expand_act = expand_all_option_texts;
904: process_menu(menu, &ai);
905: free_menu(menu);
906: }
907:
908: return ai.rv;
909: }
910:
911: static void
912: merge_part_with_wanted(struct disk_partitions *parts, part_id pno,
913: const struct disk_part_info *info, struct partition_usage_set *wanted,
914: bool is_outer)
1.1 dholland 915: {
1.9 martin 916: struct part_usage_info *infos;
1.2 martin 917:
1.9 martin 918: /*
919: * does this partition match something in the wanted set?
920: */
921: for (size_t i = 0; i < wanted->num; i++) {
922: if (wanted->infos[i].type != info->nat_type->generic_ptype)
923: continue;
924: if (info->last_mounted != NULL && info->last_mounted[0] != 0 &&
925: strcmp(info->last_mounted, wanted->infos[i].mount) != 0)
926: continue;
927: if (wanted->infos[i].cur_part_id != NO_PART)
928: continue;
929: wanted->infos[i].cur_part_id = pno;
930: wanted->infos[i].parts = parts;
931: wanted->infos[i].size = info->size;
932: wanted->infos[i].cur_start = info->start;
933: wanted->infos[i].flags &= ~PUIFLAG_EXTEND;
1.11 martin 934: if (wanted->infos[i].fs_type != FS_UNUSED &&
935: wanted->infos[i].type != PT_swap)
936: wanted->infos[i].instflags |= PUIINST_MOUNT;
1.9 martin 937: if (is_outer)
938: wanted->infos[i].flags |= PUIFLG_IS_OUTER;
939: return;
940: }
1.4 martin 941:
1.9 martin 942: /*
943: * no match - if this is fromt the outer scheme, we are done.
944: * otherwise it must be inserted into the wanted set.
945: */
946: if (is_outer)
947: return;
1.1 dholland 948:
949: /*
1.9 martin 950: * create a new entry for this
1.1 dholland 951: */
1.9 martin 952: infos = realloc(wanted->infos, sizeof(*infos)*(wanted->num+1));
953: if (infos == NULL)
954: return;
955: wanted->infos = infos;
956: infos += wanted->num;
957: wanted->num++;
958: memset(infos, 0, sizeof(*infos));
959: if (info->last_mounted != NULL && info->last_mounted[0] != 0)
960: strlcpy(infos->mount, info->last_mounted,
961: sizeof(infos->mount));
962: infos->type = info->nat_type->generic_ptype;
963: infos->cur_part_id = pno;
964: infos->parts = parts;
965: infos->size = info->size;
966: infos->cur_start = info->start;
967: infos->fs_type = info->fs_type;
968: infos->fs_version = info->fs_sub_type;
969: if (is_outer)
970: infos->flags |= PUIFLG_IS_OUTER;
971: }
972:
973: static bool
974: have_x11_by_default(void)
975: {
976: static const uint8_t def_sets[] = { MD_SETS_SELECTED };
977:
978: for (size_t i = 0; i < __arraycount(def_sets); i++)
979: if (def_sets[i] >= SET_X11_FIRST &&
980: def_sets[i] <= SET_X11_LAST)
981: return true;
982:
983: return false;
984: }
1.1 dholland 985:
1.9 martin 986: static void
987: fill_defaults(struct partition_usage_set *wanted, struct disk_partitions *parts,
988: daddr_t ptstart, daddr_t ptsize)
989: {
1.15 ! martin 990: size_t i, root = ~0U, usr = ~0U, swap = ~0U, def_usr = ~0U;
! 991: daddr_t free_space, dump_space, required;
1.9 martin 992: #if defined(DEFAULT_UFS2) && !defined(HAVE_UFS2_BOOT)
993: size_t boot = ~0U;
994: #endif
1.1 dholland 995:
1.9 martin 996: memset(wanted, 0, sizeof(*wanted));
997: wanted->parts = parts;
998: wanted->num = __arraycount(default_parts_init);
999: wanted->infos = calloc(wanted->num, sizeof(*wanted->infos));
1000: if (wanted->infos == NULL) {
1001: err_msg_win(err_outofmem);
1002: return;
1.1 dholland 1003: }
1004:
1.9 martin 1005: memcpy(wanted->infos, default_parts_init, sizeof(default_parts_init));
1006: for (i = 0; i < wanted->num; i++) {
1007: wanted->infos[i].parts = parts;
1008: wanted->infos[i].cur_part_id = NO_PART;
1009:
1010: #if DEFSWAPSIZE == -1
1011: if (wanted->infos[i].type == PT_swap)
1012: wanted->infos[i].size = get_ramsize() * (MEG / 512);
1.1 dholland 1013: #endif
1.9 martin 1014: if (wanted->infos[i].type == PT_swap && swap > wanted->num)
1015: swap = i;
1016: #if defined(DEFAULT_UFS2) && !defined(HAVE_UFS2_BOOT)
1017: if (wanted->infos[i].instflags & PUIINST_BOOT)
1018: boot = i;
1.1 dholland 1019: #endif
1.15 ! martin 1020: if (wanted->infos[i].type == PT_root) {
! 1021: if (strcmp(wanted->infos[i].mount, "/") == 0) {
1.9 martin 1022: root = i;
1.15 ! martin 1023: } else if (
! 1024: strcmp(wanted->infos[i].mount, "/usr") == 0) {
! 1025: if (wanted->infos[i].size > 0)
! 1026: usr = i;
! 1027: else
! 1028: def_usr = i;
! 1029: }
1.9 martin 1030: wanted->infos[i].fs_type = FS_BSDFFS;
1031: #ifdef DEFAULT_UFS2
1032: #ifndef HAVE_UFS2_BOOT
1033: if (boot < wanted->num || i != root)
1.1 dholland 1034: #endif
1.9 martin 1035: wanted->infos[i].fs_version = 2;
1.1 dholland 1036: #endif
1.9 martin 1037: }
1038: if ((wanted->infos[i].flags & PUIFLG_JUST_MOUNTPOINT) &&
1039: wanted->infos[i].size == 0)
1040: /* default tmpfs to 1/4 RAM */
1041: wanted->infos[i].def_size =
1042: get_ramsize() * (MEG/512/4);
1.1 dholland 1043: }
1044:
1.9 martin 1045: #ifdef MD_PART_DEFAULTS
1046: MD_PART_DEFAULTS(pm, wanted->infos[i].parts, wanted->num);
1.1 dholland 1047: #endif
1048:
1.9 martin 1049: /*
1050: * Now we have the defaults as if we were installing to an
1051: * empty disk. Merge the partitions in target range that are already
1052: * there (match with wanted) or are there additionaly.
1053: * The only thing outside of target range that we care for
1054: * is a potential swap partition - we assume one is enough.
1055: */
1056: if (parts->parent) {
1057: for (part_id pno = 0; pno < parts->parent->num_part; pno++) {
1058: struct disk_part_info info;
1.1 dholland 1059:
1.9 martin 1060: if (!parts->parent->pscheme->get_part_info(
1061: parts->parent, pno, &info))
1062: continue;
1063: if (info.nat_type->generic_ptype != PT_swap)
1.1 dholland 1064: continue;
1.9 martin 1065: merge_part_with_wanted(parts->parent, pno, &info,
1066: wanted, true);
1067: break;
1068: }
1069: }
1070: for (part_id pno = 0; pno < parts->num_part; pno++) {
1071: struct disk_part_info info;
1072:
1073: if (!parts->pscheme->get_part_info(parts, pno, &info))
1074: continue;
1075:
1076: if (info.flags & PTI_PSCHEME_INTERNAL)
1077: continue;
1078:
1079: if (info.nat_type->generic_ptype != PT_swap &&
1080: (info.start < ptstart ||
1081: (info.start + info.size) > (ptstart+ptsize)))
1082: continue;
1083:
1084: merge_part_with_wanted(parts, pno, &info,
1085: wanted, false);
1086: }
1087:
1088: daddr_t align = parts->pscheme->get_part_alignment(parts);
1089:
1.10 martin 1090: if (root < wanted->num && wanted->infos[root].cur_part_id == NO_PART) {
1.9 martin 1091: daddr_t max_root_size = parts->disk_start + parts->disk_size;
1092: if (root_limit > 0) {
1093: /* Bah - bios can not read all the disk, limit root */
1094: max_root_size = root_limit - parts->disk_start;
1095: }
1096: wanted->infos[root].limit = max_root_size;
1097: }
1098:
1099: if (have_x11_by_default()) {
1100: daddr_t xsize = XNEEDMB * (MEG / 512);
1101: if (usr < wanted->num) {
1.10 martin 1102: if (wanted->infos[usr].cur_part_id == NO_PART) {
1103: wanted->infos[usr].size += xsize;
1104: wanted->infos[usr].def_size += xsize;
1105: }
1.9 martin 1106: } else if (root < wanted->num &&
1.10 martin 1107: wanted->infos[root].cur_part_id == NO_PART &&
1108: (wanted->infos[root].limit == 0 ||
1.9 martin 1109: (wanted->infos[root].size + xsize) <=
1.10 martin 1110: wanted->infos[root].limit)) {
1.9 martin 1111: wanted->infos[root].size += xsize;
1112: }
1113: }
1.10 martin 1114: if (wanted->infos[root].limit > 0 &&
1115: wanted->infos[root].size > wanted->infos[root].limit) {
1.9 martin 1116: if (usr < wanted->num) {
1117: /* move space from root to usr */
1118: daddr_t spill = wanted->infos[root].size -
1119: wanted->infos[root].limit;
1120: spill = roundup(spill, align);
1121: wanted->infos[root].size =
1122: wanted->infos[root].limit;
1123: wanted->infos[usr].size = spill;
1124: } else {
1125: wanted->infos[root].size =
1126: wanted->infos[root].limit;
1.1 dholland 1127: }
1.9 martin 1128: }
1129:
1130: /*
1131: * Preliminary calc additional space to allocate and how much
1132: * we likely will have left over. Use that to do further
1133: * adjustments, so we don't present the user inherently
1134: * impossible defaults.
1135: */
1136: free_space = parts->free_space;
1.15 ! martin 1137: required = 0;
! 1138: if (root < wanted->num)
! 1139: required += wanted->infos[root].size;
! 1140: if (usr < wanted->num)
! 1141: required += wanted->infos[usr].size;
! 1142: else if (def_usr < wanted->num)
! 1143: required += wanted->infos[def_usr].def_size;
! 1144: free_space -= required;
1.9 martin 1145: for (i = 0; i < wanted->num; i++) {
1.15 ! martin 1146: if (i == root || i == usr)
! 1147: continue; /* already accounted above */
1.9 martin 1148: if (wanted->infos[i].cur_part_id != NO_PART)
1149: continue;
1.15 ! martin 1150: if (wanted->infos[i].size == 0)
! 1151: continue;
1.9 martin 1152: if (wanted->infos[i].flags
1153: & (PUIFLG_IS_OUTER|PUIFLG_JUST_MOUNTPOINT))
1154: continue;
1155: free_space -= wanted->infos[i].size;
1156: }
1157: if (free_space < 0 && swap < wanted->num) {
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;
1172: if (free_space > dump_space)
1173: wanted->infos[root].size += dump_space;
1174: }
1175: }
1176:
1177: /*
1178: * We sort pset->infos to sync with pset->parts and
1179: * the cur_part_id, to allow using the same index into both
1180: * "array" in later phases. This may include inserting
1181: * dummy entries (when we do not actually want the
1182: * partition, but it is forced upon us, like RAW_PART in
1183: * disklabel).
1184: */
1185: static void
1186: sort_and_sync_parts(struct partition_usage_set *pset)
1187: {
1188: struct part_usage_info *infos;
1189: size_t i, j, no;
1190: part_id pno;
1191:
1192: pset->cur_free_space = pset->parts->free_space;
1193:
1194: /* count non-empty entries that are not in pset->parts */
1195: no = pset->parts->num_part;
1196: for (i = 0; i < pset->num; i++) {
1197: if (pset->infos[i].size == 0)
1198: continue;
1199: if (pset->infos[i].cur_part_id != NO_PART)
1200: continue;
1201: no++;
1202: }
1203:
1204: /* allocate new infos */
1205: infos = calloc(no, sizeof *infos);
1206: if (infos == NULL)
1207: return;
1208:
1209: /* pre-initialize the first entires as dummy entries */
1210: for (i = 0; i < pset->parts->num_part; i++) {
1211: infos[i].cur_part_id = NO_PART;
1212: infos[i].cur_flags = PTI_PSCHEME_INTERNAL;
1213: }
1214: /*
1215: * Now copy over eveything from our old entries that points to
1216: * a real partition.
1217: */
1218: for (i = 0; i < pset->num; i++) {
1219: pno = pset->infos[i].cur_part_id;
1220: if (pno == NO_PART)
1221: continue;
1222: if (pset->parts != pset->infos[i].parts)
1223: continue;
1224: if (pset->infos[i].flags &
1225: (PUIFLG_IS_OUTER|PUIFLG_JUST_MOUNTPOINT))
1226: continue;
1227: if (pno >= pset->parts->num_part)
1228: continue;
1229: memcpy(infos+pno, pset->infos+i, sizeof(*infos));
1230: }
1231: /* Fill in the infos for real partitions where we had no data */
1232: for (pno = 0; pno < pset->parts->num_part; pno++) {
1233: struct disk_part_info info;
1234:
1235: if (infos[pno].cur_part_id != NO_PART)
1236: continue;
1237:
1238: if (!pset->parts->pscheme->get_part_info(pset->parts, pno,
1239: &info))
1240: continue;
1241:
1242: infos[pno].parts = pset->parts;
1243: infos[pno].cur_part_id = pno;
1244: infos[pno].cur_flags = info.flags;
1245: infos[pno].size = info.size;
1246: infos[pno].type = info.nat_type->generic_ptype;
1247: infos[pno].cur_start = info.start;
1248: infos[pno].fs_type = info.fs_type;
1249: infos[pno].fs_version = info.fs_sub_type;
1250: }
1251: /* Add the non-partition entires after that */
1252: j = pset->num;
1253: for (i = 0; i < pset->num; i++) {
1254: if (j >= no)
1255: break;
1256: if (pset->infos[i].size == 0)
1257: continue;
1258: if (pset->infos[i].cur_part_id != NO_PART)
1259: continue;
1260: memcpy(infos+j, pset->infos+i, sizeof(*infos));
1261: j++;
1262: }
1263:
1264: /* done, replace infos */
1265: free(pset->infos);
1266: pset->num = no;
1267: pset->infos = infos;
1268: }
1269:
1270: static void
1271: apply_settings_to_partitions(struct pm_devs *p, struct disk_partitions *parts,
1272: struct partition_usage_set *wanted, daddr_t start, daddr_t size)
1273: {
1274: size_t i, exp_ndx = ~0U;
1275: daddr_t planned_space = 0, nsp, from, align;
1276: struct disk_part_info *infos;
1277: struct disk_part_free_space space;
1278: struct disk_partitions *ps = NULL;
1279: part_id pno, new_part_id;
1280:
1281: infos = calloc(wanted->num, sizeof(*infos));
1282: if (infos == NULL) {
1283: err_msg_win(err_outofmem);
1284: return;
1285: }
1286:
1287: align = wanted->parts->pscheme->get_part_alignment(wanted->parts);
1288:
1289: /*
1290: * Pass one: calculate space available for expanding
1291: * the marked partition.
1292: */
1293: for (i = 0; i < wanted->num; i++) {
1294: if ((wanted->infos[i].flags & PUIFLAG_EXTEND) &&
1295: exp_ndx == ~0U)
1296: exp_ndx = i;
1297: if (wanted->infos[i].flags & PUIFLG_JUST_MOUNTPOINT)
1298: continue;
1299: nsp = wanted->infos[i].size;
1300: if (wanted->infos[i].cur_part_id != NO_PART) {
1301: ps = wanted->infos[i].flags & PUIFLG_IS_OUTER ?
1302: parts->parent : parts;
1303:
1304: if (ps->pscheme->get_part_info(ps,
1305: wanted->infos[i].cur_part_id, &infos[i]))
1306: nsp -= infos[i].size;
1.1 dholland 1307: }
1.9 martin 1308: if (nsp > 0)
1309: planned_space += roundup(nsp, align);
1.1 dholland 1310: }
1311:
1312: /*
1.9 martin 1313: * Expand the pool partition (or shrink, if we overran),
1.1 dholland 1314: */
1.9 martin 1315: if (exp_ndx < wanted->num)
1316: wanted->infos[exp_ndx].size +=
1317: parts->free_space - planned_space;
1318:
1319: /*
1320: * Now it gets tricky: we want the wanted partitions in order
1321: * as defined, but any already existing partitions should not
1322: * be moved. We allow them to change size though.
1323: * To keep it simple, we just assign in order and skip blocked
1324: * spaces. This may shuffle the order of the resulting partitions
1325: * compared to the wanted list.
1326: */
1327:
1328: /* Adjust sizes of existing partitions */
1329: for (i = 0; i < wanted->num; i++) {
1330: ps = wanted->infos[i].flags & PUIFLG_IS_OUTER ?
1331: parts->parent : parts;
1332: const struct part_usage_info *want = &wanted->infos[i];
1333:
1334: if (want->cur_part_id == NO_PART)
1335: continue;
1336: if (i == exp_ndx) /* the exp. part. can not exist yet */
1.1 dholland 1337: continue;
1.9 martin 1338: daddr_t free_size = ps->pscheme->max_free_space_at(ps,
1339: infos[i].start);
1340: if (free_size < wanted->infos[i].size)
1.1 dholland 1341: continue;
1.9 martin 1342: infos[i].size = wanted->infos[i].size;
1343: ps->pscheme->set_part_info(ps, want->cur_part_id,
1344: &infos[i], NULL);
1345: }
1346: /* Now add new partitions */
1347: from = -1;
1348: for (i = 0; i < wanted->num && from < wanted->parts->disk_size; i++) {
1349: struct part_usage_info *want = &wanted->infos[i];
1350:
1351: if (want->cur_part_id != NO_PART)
1352: continue;
1353: if (want->flags & PUIFLG_JUST_MOUNTPOINT)
1354: continue;
1355: if (want->size <= 0)
1356: continue;
1357:
1358: size_t cnt = wanted->parts->pscheme->get_free_spaces(
1359: wanted->parts, &space, 1, want->size-2*align, align, from,
1360: -1);
1361:
1362: if (cnt == 0)
1363: continue; /* no free space for this partition */
1364:
1365: infos[i].start = space.start;
1366: infos[i].size = min(want->size, space.size);
1367: infos[i].nat_type =
1368: wanted->parts->pscheme->get_fs_part_type(want->fs_type,
1369: want->fs_version);
1370: infos[i].last_mounted = want->mount;
1371: infos[i].fs_type = want->fs_type;
1372: infos[i].fs_sub_type = want->fs_version;
1373: if (want->fs_type != FS_UNUSED && want->type != PT_swap)
1374: want->instflags |= PUIINST_NEWFS|PUIINST_MOUNT;
1375: new_part_id = wanted->parts->pscheme->add_partition(
1376: wanted->parts, &infos[i], NULL);
1377: if (new_part_id == NO_PART)
1378: continue; /* failed to add, skip */
1379:
1380: wanted->parts->pscheme->get_part_info(
1381: wanted->parts, new_part_id, &infos[i]);
1382: from = rounddown(infos[i].start+infos[i].size+align, align);
1383: }
1384:
1385: /*
1386: * Note: all part_ids are invalid now, as we have added things!
1387: */
1388: for (i = 0; i < wanted->num; i++)
1389: wanted->infos[i].cur_part_id = NO_PART;
1390: for (pno = 0; pno < ps->num_part; pno++) {
1391: struct disk_part_info t;
1392:
1393: if (!ps->pscheme->get_part_info(ps, pno, &t))
1394: continue;
1395:
1396: for (i = 0; i < wanted->num; i++) {
1397: if (wanted->infos[i].cur_part_id != NO_PART)
1398: continue;
1399: if (t.start == infos[i].start) {
1400: wanted->infos[i].cur_part_id = pno;
1401: wanted->infos[i].cur_start = infos[i].start;
1402: wanted->infos[i].cur_flags = infos[i].flags;
1403: break;
1.1 dholland 1404: }
1405: }
1.9 martin 1406: }
1407: free(infos);
1408:
1409: /* sort, and sync part ids and wanted->infos[] indices */
1410: sort_and_sync_parts(wanted);
1411: }
1412:
1413: static void
1414: replace_by_default(struct pm_devs *p, struct disk_partitions *parts,
1415: daddr_t start, daddr_t size, struct partition_usage_set *wanted)
1416: {
1417:
1418: if (start == 0 && size == parts->disk_size)
1419: parts->pscheme->delete_all_partitions(parts);
1420: else if (parts->pscheme->delete_partitions_in_range != NULL)
1421: parts->pscheme->delete_partitions_in_range(parts, start, size);
1422: else
1423: assert(parts->num_part == 0);
1424:
1425: fill_defaults(wanted, parts, start, size);
1426: apply_settings_to_partitions(p, parts, wanted, start, size);
1427: }
1428:
1429: static bool
1430: edit_with_defaults(struct pm_devs *p, struct disk_partitions *parts,
1431: daddr_t start, daddr_t size, struct partition_usage_set *wanted)
1432: {
1433: bool ok;
1434:
1435: fill_defaults(wanted, parts, start, size);
1436: ok = get_ptn_sizes(wanted);
1437: if (ok)
1438: apply_settings_to_partitions(p, parts, wanted, start, size);
1439: return ok;
1440: }
1441:
1442: /*
1443: * md back-end code for menu-driven BSD disklabel editor.
1444: * returns 0 on failure, 1 on success.
1445: * fills the install target with a list for newfs/fstab.
1446: */
1447: bool
1448: make_bsd_partitions(struct install_partition_desc *install)
1449: {
1450: struct disk_partitions *parts = pm->parts;
1451: const struct disk_partitioning_scheme *pscheme;
1452: struct partition_usage_set wanted;
1453: enum layout_type layoutkind = LY_SETSIZES;
1454: bool have_existing;
1455:
1456: if (pm && pm->no_part && parts == NULL)
1457: return true;
1458:
1459: if (parts == NULL) {
1460: pscheme = select_part_scheme(pm, NULL, true, NULL);
1461: if (pscheme == NULL)
1462: return false;
1463: parts = pscheme->create_new_for_disk(pm->diskdev,
1464: 0, pm->dlsize, pm->dlsize, true);
1465: if (parts == NULL)
1466: return false;
1467: pm->parts = parts;
1468: } else {
1469: pscheme = parts->pscheme;
1470: }
1471:
1472: if (pscheme->secondary_partitions) {
1473: struct disk_partitions *p;
1474:
1.12 martin 1475: p = pscheme->secondary_partitions(parts, pm->ptstart, false);
1.9 martin 1476: if (p) {
1477: parts = p;
1478: pscheme = parts->pscheme;
1479: }
1480: }
1481:
1482: have_existing = check_existing_netbsd(parts);
1483:
1484: /*
1485: * Initialize global variables that track space used on this disk.
1486: */
1487: if (pm->ptsize == 0)
1488: pm->ptsize = pm->dlsize - pm->ptstart;
1489: if (pm->dlsize == 0)
1490: pm->dlsize = pm->ptstart + pm->ptsize;
1.1 dholland 1491:
1.9 martin 1492: if (logfp) fprintf(logfp, "dlsize=%" PRId64 " ptsize=%" PRId64
1493: " ptstart=%" PRId64 "\n",
1494: pm->dlsize, pm->ptsize, pm->ptstart);
1495:
1496: if (pm->current_cylsize == 0)
1497: pm->current_cylsize = pm->dlcylsize;
1498:
1499: /* Ask for layout type -- standard or special */
1500: if (partman_go == 0) {
1501: char bsd_size[6], min_size[6], x_size[6];
1502:
1503: humanize_number(bsd_size, sizeof(bsd_size),
1504: (uint64_t)pm->ptsize*pm->sectorsize,
1505: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1506: humanize_number(min_size, sizeof(min_size),
1507: (uint64_t)(DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE)*MEG,
1508: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1509: humanize_number(x_size, sizeof(x_size),
1510: (uint64_t)(DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE
1511: + XNEEDMB)*MEG,
1512: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
1513:
1514: msg_display_subst(
1515: have_existing ? MSG_layout_prologue_existing
1516: : MSG_layout_prologue_none, 6, pm->diskdev,
1517: msg_string(parts->pscheme->name),
1518: msg_string(parts->pscheme->short_name),
1519: bsd_size, min_size, x_size);
1520: msg_display_add_subst(MSG_layout_main, 6,
1521: pm->diskdev,
1522: msg_string(parts->pscheme->name),
1523: msg_string(parts->pscheme->short_name),
1524: bsd_size, min_size, x_size);
1525: msg_display_add("\n\n");
1526: layoutkind = ask_layout(parts, have_existing);
1527: }
1528:
1529: if (layoutkind == LY_USEDEFAULT) {
1530: replace_by_default(pm, parts, pm->ptstart, pm->ptsize,
1531: &wanted);
1532: } else if (layoutkind == LY_SETSIZES) {
1533: if (!edit_with_defaults(pm, parts, pm->ptstart, pm->ptsize,
1534: &wanted)) {
1535: free_usage_set(&wanted);
1536: return false;
1537: }
1538: } else {
1539: usage_set_from_parts(&wanted, parts);
1.2 martin 1540: }
1.1 dholland 1541:
1542: /*
1543: * OK, we have a partition table. Give the user the chance to
1544: * edit it and verify it's OK, or abort altogether.
1545: */
1.9 martin 1546: for (;;) {
1547: int rv = edit_and_check_label(pm, &wanted);
1548: if (rv == 0) {
1549: msg_display(MSG_abort_part);
1550: free_usage_set(&wanted);
1551: return false;
1552: }
1553: /* update install infos */
1554: install->num = wanted.num;
1555: install->infos = wanted.infos;
1556: /* and check them */
1557: if (check_partitions(install))
1558: break;
1559: }
1.1 dholland 1560:
1.9 martin 1561: /* we moved infos from wanted to install target */
1562: wanted.infos = NULL;
1563: free_usage_set(&wanted);
1.1 dholland 1564:
1565: /* Everything looks OK. */
1.9 martin 1566: return true;
1.1 dholland 1567: }
1568:
1569: /*
1570: * check that there is at least a / somewhere.
1571: */
1.9 martin 1572: bool
1573: check_partitions(struct install_partition_desc *install)
1.1 dholland 1574: {
1575: #ifdef HAVE_BOOTXX_xFS
1.2 martin 1576: int rv = 1;
1.1 dholland 1577: char *bootxx;
1578: #endif
1579: #ifndef HAVE_UFS2_BOOT
1.9 martin 1580: size_t i;
1.1 dholland 1581: #endif
1582:
1583: #ifdef HAVE_BOOTXX_xFS
1584: /* check if we have boot code for the root partition type */
1.9 martin 1585: bootxx = bootxx_name(install);
1.1 dholland 1586: if (bootxx != NULL) {
1587: rv = access(bootxx, R_OK);
1588: free(bootxx);
1589: } else
1590: rv = -1;
1591: if (rv != 0) {
1.9 martin 1592: hit_enter_to_continue(NULL, MSG_No_Bootcode);
1593: return false;
1.1 dholland 1594: }
1595: #endif
1596: #ifndef HAVE_UFS2_BOOT
1.9 martin 1597: for (i = 0; i < install->num; i++) {
1598: if (install->infos[i].type != PT_root)
1599: continue;
1600: if (strcmp(install->infos[i].mount, "/") != 0)
1601: continue;
1602: if (install->infos[i].fs_type != FS_BSDFFS)
1603: continue;
1604: if (install->infos[i].fs_version != 2)
1605: continue;
1606: hit_enter_to_continue(NULL, MSG_cannot_ufs2_root);
1607: return false;
1.1 dholland 1608: }
1609: #endif
1610:
1.9 martin 1611: return md_check_partitions(install);
1.1 dholland 1612: }
CVSweb <webmaster@jp.NetBSD.org>