xref: /netbsd-src/usr.sbin/sysinst/partman.c (revision 6cf6fe02a981b55727c49c3d37b0d8191a98c0ee)
1 /*	$NetBSD: partman.c,v 1.6 2014/08/19 13:44:31 martin Exp $ */
2 
3 /*
4  * Copyright 2012 Eugene Lozovoy
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of Eugene Lozovoy may not be used to endorse
16  *    or promote products derived from this software without specific prior
17  *    written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29  * THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /* partman.c - extended partitioning */
34 
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <libgen.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <util.h>
42 
43 #include "defs.h"
44 #include "msg_defs.h"
45 #include "menu_defs.h"
46 
47 /* flags whether to offer the respective options (depending on helper
48    programs available on install media */
49 static int have_raid, have_vnd, have_cgd, have_lvm, have_gpt, have_dk;
50 
51 /* XXX: replace all MAX_* defines with vars that depend on kernel settings */
52 #define MAX_ENTRIES 96
53 
54 #define MAX_RAID 8
55 #define MAX_IN_RAID 48
56 typedef struct raids_t {
57 	int enabled;
58 	int blocked;
59 	int node;
60 	char pm_name[MAX_IN_RAID][SSTRSIZE];
61 	int pm_part[MAX_IN_RAID];
62 	int pm_is_spare[MAX_IN_RAID];
63 	int numRow, numCol, numSpare;
64 	int sectPerSU, SUsPerParityUnit, SUsPerReconUnit, raid_level;
65 	uint total_size;
66 	pm_devs_t *pm[MAX_IN_RAID];
67 } raids_t;
68 raids_t raids[MAX_RAID];
69 
70 #define MAX_VND 4
71 typedef struct vnds_t {
72 	int enabled;
73 	int blocked;
74 	int node;
75 	char filepath[STRSIZE];
76 	int size;
77 	int readonly;
78 	int is_exist;
79 	int manual_geom;
80 	int secsize, nsectors, ntracks, ncylinders;
81 	int pm_part;    /* Used only for */
82 	pm_devs_t *pm;  /* referring device */
83 } vnds_t;
84 vnds_t vnds[MAX_VND];
85 
86 #define MAX_CGD 4
87 typedef struct cgds_t {
88 	int enabled;
89 	int blocked;
90 	int node;
91 	pm_devs_t *pm;
92 	char pm_name[SSTRSIZE];
93 	int pm_part;
94 	const char *keygen_type;
95 	const char *verify_type;
96 	const char *enc_type;
97 	const char *iv_type;
98 	int key_size;
99 } cgds_t;
100 cgds_t cgds[MAX_CGD];
101 
102 #define MAX_LVM_VG 16
103 #define MAX_LVM_PV 255
104 #define MAX_LVM_LV 255
105 typedef struct pv_t {
106 	pm_devs_t *pm;
107 	char pm_name[SSTRSIZE];
108 	int pm_part;
109 	int metadatasize;
110 	int metadatacopies;
111 	int labelsector;
112 	int setphysicalvolumesize;
113 } pv_t;
114 typedef struct lv_t {
115 	int blocked;
116 	int size;
117 	char name[SSTRSIZE];
118 	int readonly;
119 	int contiguous;
120 	char extents[SSTRSIZE];
121 	int minor;
122 	int mirrors;
123 	int regionsize;
124 	int persistent;
125 	int readahead;
126 	int stripes;
127 	int stripesize;
128 	int zero;
129 } lv_t;
130 typedef struct lvms_t {
131 	int enabled;
132 	int blocked;
133 	char name[SSTRSIZE];
134 	int maxlogicalvolumes;
135 	int maxphysicalvolumes;
136 	int physicalextentsize;
137 	uint total_size;
138 	pv_t pv[MAX_LVM_PV];
139 	lv_t lv[MAX_LVM_LV];
140 } lvms_t;
141 lvms_t lvms[MAX_LVM_VG];
142 
143 typedef struct structinfo_t {
144 	int max;
145 	uint entry_size;
146 	uint parent_size;
147 	void *entry_first;
148 	void *entry_enabled;
149 	void *entry_blocked;
150 	void *entry_node;
151 } structinfo_t;
152 structinfo_t raids_t_info, vnds_t_info, cgds_t_info, lvms_t_info, lv_t_info;
153 
154 typedef struct pm_upddevlist_adv_t {
155 	const char *create_msg;
156 	int pe_type;
157 	structinfo_t *s;
158 	int sub_num;
159 	struct pm_upddevlist_adv_t *sub;
160 } pm_upddevlist_adv_t;
161 
162 #define MAX_MNTS 48
163 struct {
164     char dev[STRSIZE];
165     const char *mnt_opts, *on;
166 } mnts[MAX_MNTS];
167 
168 int cursel; /* Number of selected entry in main menu */
169 int changed; /* flag indicating that we have unsaved changes */
170 int raid_curspare; /* XXX: replace by true way */
171 
172 enum { /* RAIDframe menu enum */
173 	PMR_MENU_DEVS, PMR_MENU_DEVSSPARE, PMR_MENU_RAIDLEVEL, PMR_MENU_NUMROW,
174 	PMR_MENU_NUMCOL, PMR_MENU_NUMSPARE,	PMR_MENU_SECTPERSU,	PMR_MENU_SUSPERPARITYUNIT,
175 	PMR_MENU_SUSPERRECONUNIT, PMR_MENU_REMOVE, PMR_MENU_END
176 };
177 
178 enum { /* VND menu enum */
179 	PMV_MENU_FILEPATH, PMV_MENU_EXIST, PMV_MENU_SIZE, PMV_MENU_RO, PMV_MENU_MGEOM,
180 	PMV_MENU_SECSIZE, PMV_MENU_NSECTORS, PMV_MENU_NTRACKS, PMV_MENU_NCYLINDERS,
181 	PMV_MENU_REMOVE, PMV_MENU_END
182 };
183 
184 enum { /* CGD menu enum */
185 	PMC_MENU_DEV, PMC_MENU_ENCTYPE, PMC_MENU_KEYSIZE, PMC_MENU_IVTYPE,
186 	PMC_MENU_KEYGENTYPE, PMC_MENU_VERIFYTYPE, PMC_MENU_REMOVE, PMC_MENU_END
187 };
188 
189 enum { /* LVM menu enum */
190 	PML_MENU_PV, PML_MENU_NAME, PML_MENU_MAXLOGICALVOLUMES,
191 	PML_MENU_MAXPHYSICALVOLUMES, PML_MENU_PHYSICALEXTENTSIZE,
192 	PML_MENU_REMOVE, PML_MENU_END
193 };
194 
195 enum { /* LVM submenu (logical volumes) enum */
196 	PMLV_MENU_NAME, PMLV_MENU_SIZE, PMLV_MENU_READONLY, PMLV_MENU_CONTIGUOUS,
197 	PMLV_MENU_EXTENTS, PMLV_MENU_MINOR, PMLV_MENU_PERSISTENT,
198 	PMLV_MENU_MIRRORS, PMLV_MENU_REGIONSIZE, PMLV_MENU_READAHEAD,
199 	PMLV_MENU_STRIPES, PMLV_MENU_STRIPESIZE, PMLV_MENU_ZERO,
200 	PMLV_MENU_REMOVE, PMLV_MENU_END
201 };
202 
203 part_entry_t pm_dev_list(int);
204 static int pm_raid_disk_add(menudesc *, void *);
205 static int pm_raid_disk_del(menudesc *, void *);
206 static int pm_cgd_disk_set(cgds_t *, part_entry_t *);
207 static int pm_mount(pm_devs_t *, int);
208 static int pm_upddevlist(menudesc *, void *);
209 static void pm_select(pm_devs_t *);
210 
211 /* Universal menu for RAID/VND/CGD/LVM entry edit */
212 static int
213 pm_edit(int menu_entries_count, void (*menu_fmt)(menudesc *, int, void *),
214 	int (*action)(menudesc *, void *), int (*check_fun)(void *),
215 	void (*entry_init)(void *, void *),	void *entry_init_arg,
216 	void *dev_ptr, int dev_ptr_delta, structinfo_t *s)
217 {
218 	int i, ok = 0;
219 
220 	if (dev_ptr == NULL) {
221 		/* We should create new device */
222 		for (i = 0; i < s->max && !ok; i++)
223 			if (*(int*)((char*)s->entry_enabled + dev_ptr_delta + s->entry_size * i) == 0) {
224 				dev_ptr = (char*)s->entry_first + dev_ptr_delta + s->entry_size * i;
225 				entry_init(dev_ptr, entry_init_arg);
226 				ok = 1;
227 			}
228 		if (!ok) {
229 			/* We do not have free device slots */
230 			process_menu(MENU_ok, deconst(MSG_limitcount));
231 			return -1;
232 		}
233 	}
234 
235 	menu_ent menu_entries[menu_entries_count];
236 	for (i = 0; i < menu_entries_count - 1; i++)
237 		menu_entries[i] = (menu_ent) {NULL, OPT_NOMENU, 0, action};
238 	menu_entries[i] = (menu_ent) {MSG_fremove, OPT_NOMENU, OPT_EXIT, action};
239 
240 	int menu_no = -1;
241 	menu_no = new_menu(NULL, menu_entries, menu_entries_count,
242 		-1, -1, 0, 40, MC_NOCLEAR | MC_SCROLL,
243 		NULL, menu_fmt, NULL, NULL, MSG_DONE);
244 
245 	process_menu(menu_no, dev_ptr);
246 	free_menu(menu_no);
247 
248 	return check_fun(dev_ptr);
249 }
250 
251 static void
252 pm_getdevstring(char *buf, int len, pm_devs_t *pm_cur, int num)
253 {
254 	int i;
255 
256 	if (pm_cur->isspecial)
257 		snprintf(buf, len, "%s", pm_cur->diskdev);
258 	else if (num + 'a' < 'a' || num + 'a' > 'a' + MAXPARTITIONS)
259 		snprintf(buf, len, "%sd", pm_cur->diskdev);
260 	else if (pm_cur->gpt) {
261 		for (i = 0; i < MAX_WEDGES; i++)
262 			if (wedges[i].pm == pm_cur &&
263 				wedges[i].ptn == num)
264 				snprintf(buf, len, "dk%d", i); // XXX: xxx
265 	} else
266 		snprintf(buf, len, "%s%c", pm_cur->diskdev, num + 'a');
267 
268 	return;
269 }
270 
271 /* Show filtered partitions menu */
272 part_entry_t
273 pm_dev_list(int type)
274 {
275 	int dev_num = -1, num_devs = 0;
276 	int i, ok;
277 	int menu_no;
278 	menu_ent menu_entries[MAX_DISKS*MAXPARTITIONS];
279 	part_entry_t disk_entries[MAX_DISKS*MAXPARTITIONS];
280 	pm_devs_t *pm_i;
281 
282 	SLIST_FOREACH(pm_i, &pm_head, l)
283 		for (i = 0; i < MAXPARTITIONS; i++) {
284 			ok = 0;
285 			switch (type) {
286 				case PM_RAID_T:
287 					if (pm_i->bsdlabel[i].pi_fstype == FS_RAID)
288 						ok = 1;
289 					break;
290 				case PM_CGD_T:
291 					if (pm_i->bsdlabel[i].pi_fstype == FS_CGD)
292 						ok = 1;
293 					break;
294 				case PM_LVM_T:
295 					if (pm_i->bsdlabel[i].lvmpv)
296 						ok = 1;
297 					break;
298 			}
299 			if (ok && pm_partusage(pm_i, i, 0) == 0) {
300 				disk_entries[num_devs].dev_ptr = pm_i;
301 				disk_entries[num_devs].dev_num = i;
302 				pm_getdevstring(disk_entries[num_devs].fullname, SSTRSIZE, pm_i, i);
303 
304 				menu_entries[num_devs] = (struct menu_ent) {
305 					.opt_name = disk_entries[num_devs].fullname,
306 					.opt_action = set_menu_select,
307 					.opt_menu = OPT_NOMENU,
308 					.opt_flags = OPT_EXIT,
309 				};
310 				num_devs++;
311 			}
312 		}
313 
314 	menu_no = new_menu(MSG_avdisks,
315 		menu_entries, num_devs, -1, -1, (num_devs+1<3)?3:num_devs+1, 13,
316 		MC_SCROLL | MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
317 	if (menu_no == -1)
318 		return (part_entry_t) { .retvalue = -1, };
319 	process_menu(menu_no, &dev_num);
320 	free_menu(menu_no);
321 
322 	if (dev_num < 0 || dev_num >= num_devs)
323 		return (part_entry_t) { .retvalue = -1, };
324 
325 	disk_entries[dev_num].retvalue = dev_num;
326 	return disk_entries[dev_num];
327 }
328 
329 /* Get unused raid*, cgd* or vnd* device */
330 static int
331 pm_manage_getfreenode(void *node, const char *d, structinfo_t *s)
332 {
333 	int i, ii, ok;
334 	char buf[SSTRSIZE];
335 	pm_devs_t *pm_i;
336 
337 	*(int*)node = -1;
338 	for (i = 0; i < s->max; i++) {
339 		ok = 1;
340 		/* Check that node is not already reserved */
341 		for (ii = 0; ii < s->max; ii++)
342 			if (*(int*)((char*)s->entry_node + s->entry_size * ii) == i) {
343 				ok = 0;
344 				break;
345 			}
346 		if (! ok)
347 			continue;
348 		/* Check that node is not in the device list */
349 		snprintf(buf, SSTRSIZE, "%s%d", d, i);
350 		SLIST_FOREACH(pm_i, &pm_head, l)
351 			if (! strcmp(pm_i->diskdev, buf)) {
352 				ok = 0;
353 				break;
354 			}
355 		if (ok) {
356 			*(int*)node = i;
357 			return i;
358 		}
359 	}
360 	process_menu(MENU_ok, deconst(MSG_nofreedev));
361 	return -1;
362 }
363 
364 /***
365  RAIDs
366  ***/
367 
368 static void
369 pm_raid_menufmt(menudesc *m, int opt, void *arg)
370 {
371 	int i, ok = 0;
372 	char buf[STRSIZE]; buf[0] = '\0';
373 	raids_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
374 
375 	if (dev_ptr->enabled == 0)
376 		return;
377 	for (i = 0; i < MAX_IN_RAID; i++)
378 		if (dev_ptr->pm[i] != NULL) {
379 			strncat(buf, dev_ptr->pm_name[i], STRSIZE);
380 			strncat(buf, " ", STRSIZE);
381 			ok = 1;
382 		}
383 	if (ok)
384 		wprintw(m->mw, msg_string(MSG_raid_menufmt), dev_ptr->node,
385 			dev_ptr->raid_level, buf, dev_ptr->total_size);
386 	else
387 		wprintw(m->mw, "%s", msg_string(MSG_raid_err_menufmt));
388 	return;
389 }
390 
391 static void
392 pm_raid_edit_menufmt(menudesc *m, int opt, void *arg)
393 {
394 	int i;
395 	char buf[STRSIZE]; buf[0] = '\0';
396 	raids_t *dev_ptr = arg;
397 
398 	switch (opt) {
399 		case PMR_MENU_DEVS:
400 			for (i = 0; i < MAX_IN_RAID; i++)
401 				if (dev_ptr->pm[i] != NULL && dev_ptr->pm_is_spare[i] == 0)
402 					snprintf(buf, STRSIZE, "%s %s", buf, dev_ptr->pm_name[i]);
403 			wprintw(m->mw, msg_string(MSG_raid_disks_fmt), buf);
404 			break;
405 		case PMR_MENU_DEVSSPARE:
406 			for (i = 0; i < MAX_IN_RAID; i++)
407 				if (dev_ptr->pm[i] != NULL && dev_ptr->pm_is_spare[i] != 0)
408 					snprintf(buf, STRSIZE, "%s %s", buf, dev_ptr->pm_name[i]);
409 			wprintw(m->mw, msg_string(MSG_raid_spares_fmt), buf);
410 			break;
411 		case PMR_MENU_RAIDLEVEL:
412 			wprintw(m->mw, msg_string(MSG_raid_level_fmt), dev_ptr->raid_level);
413 			break;
414 		case PMR_MENU_NUMROW:
415 			wprintw(m->mw, msg_string(MSG_raid_numrow_fmt), dev_ptr->numRow);
416 			break;
417 		case PMR_MENU_NUMCOL:
418 			wprintw(m->mw, msg_string(MSG_raid_numcol_fmt), dev_ptr->numCol);
419 			break;
420 		case PMR_MENU_NUMSPARE:
421 			wprintw(m->mw, msg_string(MSG_raid_numspare_fmt), dev_ptr->numSpare);
422 			break;
423 		case PMR_MENU_SECTPERSU:
424 			wprintw(m->mw, msg_string(MSG_raid_sectpersu_fmt), dev_ptr->sectPerSU);
425 			break;
426 		case PMR_MENU_SUSPERPARITYUNIT:
427 			wprintw(m->mw, msg_string(MSG_raid_superpar_fmt), dev_ptr->SUsPerParityUnit);
428 			break;
429 		case PMR_MENU_SUSPERRECONUNIT:
430 			wprintw(m->mw, msg_string(MSG_raid_superrec_fmt), dev_ptr->SUsPerReconUnit);
431 			break;
432 	}
433 	return;
434 }
435 
436 static int
437 pm_raid_set_value(menudesc *m, void *arg)
438 {
439 	int retvalue = -1;
440 	int *out_var = NULL;
441 	char buf[SSTRSIZE];
442 	const char *msg_to_show = NULL;
443 	raids_t *dev_ptr = arg;
444 
445 	static menu_ent menuent_disk_adddel[] = {
446 	    {MSG_add, OPT_NOMENU, OPT_EXIT, pm_raid_disk_add},
447 	    {MSG_remove, OPT_NOMENU, OPT_EXIT, pm_raid_disk_del}
448 	};
449 	static int menu_disk_adddel = -1;
450 	if (menu_disk_adddel == -1) {
451 		menu_disk_adddel = new_menu(NULL, menuent_disk_adddel, nelem(menuent_disk_adddel),
452 			-1, -1, 0, 10, MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
453 	}
454 
455 	switch (m->cursel) {
456 		case PMR_MENU_DEVS:
457 			raid_curspare = 0;
458 			process_menu(menu_disk_adddel, dev_ptr);
459 			return 0;
460 		case PMR_MENU_DEVSSPARE:
461 			raid_curspare = 1;
462 			process_menu(menu_disk_adddel, dev_ptr);
463 			return 0;
464 		case PMR_MENU_RAIDLEVEL:
465 			process_menu(MENU_raidlevel, &retvalue);
466 			if (retvalue >= 0)
467 				dev_ptr->raid_level = retvalue;
468 			return 0;
469 		case PMR_MENU_NUMROW:
470 			process_menu(MENU_ok, deconst(MSG_raid_nomultidim));
471 			return 0;
472 			msg_to_show = MSG_raid_numrow_ask;
473 			out_var = &(dev_ptr->numRow);
474 			break;
475 		case PMR_MENU_NUMCOL:
476 			msg_to_show = MSG_raid_numcol_ask;
477 			out_var = &(dev_ptr->numCol);
478 			break;
479 		case PMR_MENU_NUMSPARE:
480 			msg_to_show = MSG_raid_numspare_ask;
481 			out_var = &(dev_ptr->numSpare);
482 			break;
483 		case PMR_MENU_SECTPERSU:
484 			msg_to_show = MSG_raid_sectpersu_ask;
485 			out_var = &(dev_ptr->sectPerSU);
486 			break;
487 		case PMR_MENU_SUSPERPARITYUNIT:
488 			msg_to_show = MSG_raid_superpar_ask;
489 			out_var = &(dev_ptr->SUsPerParityUnit);
490 			break;
491 		case PMR_MENU_SUSPERRECONUNIT:
492 			msg_to_show = MSG_raid_superrec_ask;
493 			out_var = &(dev_ptr->SUsPerReconUnit);
494 			break;
495 		case PMR_MENU_REMOVE:
496 			dev_ptr->enabled = 0;
497 			return 0;
498 	}
499 	if (out_var == NULL || msg_to_show == NULL)
500 		return -1;
501 	snprintf(buf, SSTRSIZE, "%d", *out_var);
502 	msg_prompt_win(msg_to_show, -1, 18, 0, 0, buf, buf, SSTRSIZE);
503 	if (atoi(buf) >= 0)
504 		*out_var = atoi(buf);
505 	return 0;
506 }
507 
508 static void
509 pm_raid_init(void *arg, void *none)
510 {
511 	raids_t *dev_ptr = arg;
512 	memset(dev_ptr, 0, sizeof(*dev_ptr));
513 	*dev_ptr = (struct raids_t) {
514 		.enabled = 1,
515 		.blocked = 0,
516 		.sectPerSU = 32,
517 		.SUsPerParityUnit = 1,
518 		.SUsPerReconUnit = 1,
519 	};
520 	return;
521 }
522 
523 static int
524 pm_raid_check(void *arg)
525 {
526 	int i, dev_num = 0, min_size = 0, cur_size = 0;
527 	raids_t *dev_ptr = arg;
528 
529 	if (dev_ptr->blocked)
530 		return 0;
531 	for (i = 0; i < MAX_IN_RAID; i++)
532 		if (dev_ptr->pm[i] != NULL) {
533 			cur_size = dev_ptr->pm[i]->bsdlabel[dev_ptr->pm_part[i]].pi_size /
534 						(MEG / dev_ptr->pm[i]->sectorsize);
535 			if (cur_size < min_size || dev_num == 0)
536 				min_size = cur_size;
537 			if (!dev_ptr->pm_is_spare[i])
538 				dev_num++;
539 		}
540 	/* Calculate sum of available space */
541 	if (dev_num > 0) {
542 		switch (dev_ptr->raid_level) {
543 			case 0:
544 				dev_ptr->total_size = min_size * dev_num;
545 				break;
546 			case 1:
547 				dev_ptr->total_size = min_size;
548 				break;
549 			case 4:
550 			case 5:
551 				dev_ptr->total_size = min_size * (dev_num - 1);
552 				break;
553 		}
554 		pm_manage_getfreenode(&(dev_ptr->node), "raid", &raids_t_info);
555 		if (dev_ptr->node < 0)
556 			dev_ptr->enabled = 0;
557 	}
558 	else
559 		dev_ptr->enabled = 0;
560 	return dev_ptr->enabled;
561 }
562 
563 static int
564 pm_raid_disk_add(menudesc *m, void *arg)
565 {
566 	int i;
567 	raids_t *dev_ptr = arg;
568 	part_entry_t disk_entrie = pm_dev_list(PM_RAID_T);
569 	if (disk_entrie.retvalue < 0)
570 		return disk_entrie.retvalue;
571 
572 	for (i = 0; i < MAX_IN_RAID; i++)
573 		if (dev_ptr->pm[i] == NULL) {
574 			dev_ptr->pm[i] = disk_entrie.dev_ptr;
575 			dev_ptr->pm_part[i] = disk_entrie.dev_num;
576 			dev_ptr->pm_is_spare[i] = raid_curspare;
577 			strlcpy(dev_ptr->pm_name[i], disk_entrie.fullname, SSTRSIZE);
578 			if (raid_curspare)
579 				dev_ptr->numSpare++;
580 			else
581 				dev_ptr->numCol++;
582 			dev_ptr->numRow = 1;
583 			break;
584 		}
585 	return 0;
586 }
587 
588 static int
589 pm_raid_disk_del(menudesc *m, void *arg)
590 {
591 	int retvalue = -1, num_devs = 0;
592 	int i, pm_cur;
593 	int menu_no;
594 	raids_t *dev_ptr = arg;
595 	menu_ent menu_entries[MAX_IN_RAID];
596 	part_entry_t submenu_args[MAX_IN_RAID];
597 
598 	for (i = 0; i < MAX_IN_RAID; i++) {
599 		if (dev_ptr->pm[i] == NULL ||
600 			dev_ptr->pm_is_spare[i] != raid_curspare)
601 			continue;
602 		menu_entries[num_devs] = (struct menu_ent) {
603 			.opt_name = dev_ptr->pm_name[i],
604 			.opt_action = set_menu_select,
605 			.opt_menu = OPT_NOMENU,
606 			.opt_flags = OPT_EXIT,
607 		};
608 		submenu_args[num_devs].dev_num = i;
609 		num_devs++;
610 	}
611 
612 	menu_no = new_menu(MSG_raid_disks,
613 		menu_entries, num_devs, -1, -1, (num_devs+1<3)?3:num_devs+1, 13,
614 		MC_SCROLL | MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
615 	if (menu_no == -1)
616 		return -1;
617 	process_menu(menu_no, &retvalue);
618 	free_menu(menu_no);
619 
620 	if (retvalue < 0 || retvalue >= num_devs)
621 		return -1;
622 
623 	pm_cur = submenu_args[retvalue].dev_num;
624 
625 	if (dev_ptr->pm_is_spare[pm_cur])
626 		dev_ptr->numSpare--;
627 	else
628 		dev_ptr->numCol--;
629 	dev_ptr->numRow = (dev_ptr->numCol)?1:0;
630 	dev_ptr->pm[pm_cur] = NULL;
631 
632 	return 0;
633 }
634 
635 static int
636 pm_raid_commit(void)
637 {
638 	int i, ii;
639 	FILE *f;
640 	char f_name[STRSIZE];
641 
642 	for (i = 0; i < MAX_RAID; i++) {
643 		if (! pm_raid_check(&raids[i]))
644 			continue;
645 
646 		/* Generating configure file for our raid */
647 		snprintf(f_name, SSTRSIZE, "/tmp/raid.%d.conf", raids[i].node);
648 		f = fopen(f_name, "w");
649 		if (f == NULL) {
650 			endwin();
651 			(void)fprintf(stderr, "Could not open %s for writing\n", f_name);
652 			if (logfp)
653 				(void)fprintf(logfp, "Could not open %s for writing\n", f_name);
654 			return 1;
655 		}
656 		scripting_fprintf(NULL, "cat <<EOF >%s\n", f_name);
657 		scripting_fprintf(f, "START array\n%d %d %d\n", raids[i].numRow,
658 							raids[i].numCol, raids[i].numSpare);
659 
660 		scripting_fprintf(f, "\nSTART disks\n");
661 		for (ii = 0; ii < MAX_IN_RAID; ii++)
662 			if (raids[i].pm[ii] != NULL && raids[i].pm_is_spare[ii] == 0) {
663 				scripting_fprintf(f,  "/dev/%s\n", raids[i].pm_name[ii]);
664 			}
665 
666 		scripting_fprintf(f, "\nSTART spare\n");
667 		for (ii = 0; ii < MAX_IN_RAID; ii++)
668 			if (raids[i].pm[ii] != NULL && raids[i].pm_is_spare[ii] != 0) {
669 				scripting_fprintf(f,  "/dev/%s\n", raids[i].pm_name[ii]);
670 			}
671 
672 		scripting_fprintf(f, "\nSTART layout\n%d %d %d %d\n", raids[i].sectPerSU,
673 						raids[i].SUsPerParityUnit, raids[i].SUsPerReconUnit,
674 						raids[i].raid_level);
675 
676 		scripting_fprintf(f, "\nSTART queue\nfifo 100\n\n");
677 		scripting_fprintf(NULL, "EOF\n");
678 		fclose (f);
679 		fflush(NULL);
680 
681 		/* Raid initialization */
682 		if (
683 			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -C %s raid%d",
684 							f_name, raids[i].node) == 0 &&
685 			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -I %d raid%d",
686 							rand(), raids[i].node) == 0 &&
687 			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -vi raid%d",
688 							raids[i].node) == 0 &&
689 			run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -v -A yes raid%d",
690 							raids[i].node) == 0
691 			) {
692 			raids[i].blocked = 1; /* RAID creation done, remove it from list to
693 									 prevent it's repeated reinitialization */
694 			for (ii = 0; ii < MAX_IN_RAID; ii++)
695 				if (raids[i].pm[ii] != NULL)
696 					raids[i].pm[ii]->blocked++;
697 		}
698 	}
699 	return 0;
700 }
701 
702 /***
703  VND
704  ***/
705 
706 static void
707 pm_vnd_menufmt(menudesc *m, int opt, void *arg)
708 {
709 	vnds_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
710 
711 	if (dev_ptr->enabled == 0)
712 		return;
713 	if (strlen(dev_ptr->filepath) < 1)
714 		wprintw(m->mw, "%s", msg_string(MSG_vnd_err_menufmt));
715 	else if (dev_ptr->is_exist)
716 		wprintw(m->mw, msg_string(MSG_vnd_assgn_menufmt),
717 			dev_ptr->node, dev_ptr->filepath);
718 	else
719 		wprintw(m->mw, msg_string(MSG_vnd_menufmt),
720 			dev_ptr->node, dev_ptr->filepath, dev_ptr->size);
721 	return;
722 }
723 
724 static void
725 pm_vnd_edit_menufmt(menudesc *m, int opt, void *arg)
726 {
727 	vnds_t *dev_ptr = arg;
728 	char buf[SSTRSIZE];
729 	strcpy(buf, "-");
730 
731 	switch (opt) {
732 		case PMV_MENU_FILEPATH:
733 			wprintw(m->mw, msg_string(MSG_vnd_path_fmt), dev_ptr->filepath);
734 			break;
735 		case PMV_MENU_EXIST:
736 			wprintw(m->mw, msg_string(MSG_vnd_assgn_fmt),
737 				dev_ptr->is_exist? msg_string(MSG_Yes) : msg_string(MSG_No));
738 			break;
739 		case PMV_MENU_SIZE:
740 			if (!dev_ptr->is_exist)
741 				snprintf(buf, SSTRSIZE, "%d", dev_ptr->size);
742 			wprintw(m->mw, msg_string(MSG_vnd_size_fmt), buf);
743 			break;
744 		case PMV_MENU_RO:
745 			wprintw(m->mw, msg_string(MSG_vnd_ro_fmt),
746 				dev_ptr->readonly? msg_string(MSG_Yes) : msg_string(MSG_No));
747 			break;
748 		case PMV_MENU_MGEOM:
749 			if (!dev_ptr->is_exist)
750 				snprintf(buf, SSTRSIZE, "%s",
751 					dev_ptr->manual_geom? msg_string(MSG_Yes) : msg_string(MSG_No));
752 			wprintw(m->mw, msg_string(MSG_vnd_geom_fmt), buf);
753 			break;
754 		case PMV_MENU_SECSIZE:
755 			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
756 				snprintf(buf, SSTRSIZE, "%d", dev_ptr->secsize);
757 			wprintw(m->mw, msg_string(MSG_vnd_bps_fmt), buf);
758 			break;
759 		case PMV_MENU_NSECTORS:
760 			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
761 				snprintf(buf, SSTRSIZE, "%d", dev_ptr->nsectors);
762 			wprintw(m->mw, msg_string(MSG_vnd_spt_fmt), buf);
763 			break;
764 		case PMV_MENU_NTRACKS:
765 			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
766 				snprintf(buf, SSTRSIZE, "%d", dev_ptr->ntracks);
767 			wprintw(m->mw, msg_string(MSG_vnd_tpc_fmt), buf);
768 			break;
769 		case PMV_MENU_NCYLINDERS:
770 			if (dev_ptr->manual_geom && !dev_ptr->is_exist)
771 				snprintf(buf, SSTRSIZE, "%d", dev_ptr->ncylinders);
772 			wprintw(m->mw, msg_string(MSG_vnd_cyl_fmt), buf);
773 			break;
774 	}
775 	return;
776 }
777 
778 static int
779 pm_vnd_set_value(menudesc *m, void *arg)
780 {
781 	vnds_t *dev_ptr = arg;
782 	char buf[STRSIZE];
783 	const char *msg_to_show = NULL;
784 	int *out_var = NULL;
785 
786 	switch (m->cursel) {
787 		case PMV_MENU_FILEPATH:
788 			msg_prompt_win(MSG_vnd_path_ask, -1, 18, 0, 0, dev_ptr->filepath,
789 				dev_ptr->filepath, STRSIZE);
790 			if (dev_ptr->filepath[0] != '/') {
791 				strlcpy(buf, dev_ptr->filepath, MOUNTLEN);
792 				snprintf(dev_ptr->filepath, MOUNTLEN, "/%s", buf);
793 			}
794 			if (dev_ptr->filepath[strlen(dev_ptr->filepath) - 1] == '/')
795 				dev_ptr->filepath[strlen(dev_ptr->filepath) - 1] = '\0';
796 			return 0;
797 		case PMV_MENU_EXIST:
798 			dev_ptr->is_exist = !dev_ptr->is_exist;
799 			return 0;
800 		case PMV_MENU_SIZE:
801 			if (dev_ptr->is_exist)
802 				return 0;
803 			msg_to_show = MSG_vnd_size_ask;
804 			out_var = &(dev_ptr->size);
805 			break;
806 		case PMV_MENU_RO:
807 			dev_ptr->readonly = !dev_ptr->readonly;
808 			return 0;
809 		case PMV_MENU_MGEOM:
810 			if (dev_ptr->is_exist)
811 				return 0;
812 			dev_ptr->manual_geom = !dev_ptr->manual_geom;
813 			return 0;
814 		case PMV_MENU_SECSIZE:
815 			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
816 				return 0;
817 			msg_to_show = MSG_vnd_bps_ask;
818 			out_var = &(dev_ptr->secsize);
819 			break;
820 		case PMV_MENU_NSECTORS:
821 			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
822 				return 0;
823 			msg_to_show = MSG_vnd_spt_ask;
824 			out_var = &(dev_ptr->nsectors);
825 			break;
826 		case PMV_MENU_NTRACKS:
827 			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
828 				return 0;
829 			msg_to_show = MSG_vnd_tpc_ask;
830 			out_var = &(dev_ptr->ntracks);
831 			break;
832 		case PMV_MENU_NCYLINDERS:
833 			if (!dev_ptr->manual_geom || dev_ptr->is_exist)
834 				return 0;
835 			msg_to_show = MSG_vnd_cyl_ask;
836 			out_var = &(dev_ptr->ncylinders);
837 			break;
838 		case PMV_MENU_REMOVE:
839 			dev_ptr->enabled = 0;
840 			return 0;
841 	}
842 	if (out_var == NULL || msg_to_show == NULL)
843 		return -1;
844 	snprintf(buf, SSTRSIZE, "%d", *out_var);
845 	msg_prompt_win(msg_to_show, -1, 18, 0, 0, buf, buf, SSTRSIZE);
846 	if (atoi(buf) >= 0)
847 		*out_var = atoi(buf);
848 	return 0;
849 }
850 
851 static void
852 pm_vnd_init(void *arg, void *none)
853 {
854 	vnds_t *dev_ptr = arg;
855 	memset(dev_ptr, 0, sizeof(*dev_ptr));
856 	*dev_ptr = (struct vnds_t) {
857 		.enabled = 1,
858 		.blocked = 0,
859 		.filepath[0] = '\0',
860 		.is_exist = 0,
861 		.size = 1024,
862 		.readonly = 0,
863 		.manual_geom = 0,
864 		.secsize = 512,
865 		.nsectors = 18,
866 		.ntracks = 2,
867 		.ncylinders = 80
868 	};
869 	return;
870 }
871 
872 static int
873 pm_vnd_check(void *arg)
874 {
875 	vnds_t *dev_ptr = arg;
876 
877 	if (dev_ptr->blocked)
878 		return 0;
879 	if (strlen(dev_ptr->filepath) < 1 ||
880 			dev_ptr->size < 1)
881 		dev_ptr->enabled = 0;
882 	else {
883 		pm_manage_getfreenode(&(dev_ptr->node), "vnd", &vnds_t_info);
884 		if (dev_ptr->node < 0)
885 			dev_ptr->enabled = 0;
886 	}
887 	return dev_ptr->enabled;
888 }
889 
890 /* XXX: vnconfig always return 0? */
891 static int
892 pm_vnd_commit(void)
893 {
894 	int i, ii, error, part_suit = -1;
895 	char r_o[3], buf[MOUNTLEN+3], resultpath[STRSIZE];
896 	pm_devs_t *pm_i, *pm_suit = NULL;
897 
898 	for (i = 0; i < MAX_VND; i++) {
899 		error = 0;
900 		if (! pm_vnd_check(&vnds[i]))
901 			continue;
902 
903 		/* Trying to assign target device */
904 		SLIST_FOREACH(pm_i, &pm_head, l)
905 			for (ii = 0; ii < 6; ii++) {
906 				strcpy(buf, pm_i->bsdlabel[ii].pi_mount);
907 				if (buf[strlen(buf)-1] != '/')
908 					sprintf(buf,"%s/", buf);
909 				printf("%s\n",buf);
910 				if (strstr(vnds[i].filepath, buf) == vnds[i].filepath)
911 					if (part_suit < 0 || pm_suit == NULL ||
912 						strlen(buf) > strlen(pm_suit->bsdlabel[part_suit].pi_mount)) {
913 						part_suit = ii;
914 						pm_suit = pm_i;
915 					}
916 			}
917 		if (part_suit < 0 || pm_suit == NULL ||
918 			pm_suit->bsdlabel[part_suit].mnt_opts == NULL ||
919 			! (pm_suit->bsdlabel[part_suit].pi_flags & PIF_MOUNT))
920 			continue;
921 
922 		/* Mounting assigned partition and try to get real file path*/
923 		if (pm_mount(pm_suit, part_suit) != 0)
924 			continue;
925 		snprintf(resultpath, STRSIZE, "%s/%s",
926 			pm_suit->bsdlabel[part_suit].mounted,
927 			&(vnds[i].filepath[strlen(pm_suit->bsdlabel[part_suit].pi_mount)]));
928 
929 		strcpy(r_o, vnds[i].readonly?"-r":"");
930 		/* If this is a new image */
931 		if (!vnds[i].is_exist) {
932 			run_program(RUN_DISPLAY | RUN_PROGRESS, "mkdir -p %s ", dirname(resultpath));
933 			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
934 						"dd if=/dev/zero of=%s bs=1m count=%d progress=100 msgfmt=human",
935 						resultpath, vnds[i].size);
936 		}
937 		if (error)
938 			continue;
939 		/* If this is a new image with manual geometry */
940 		if (!vnds[i].is_exist && vnds[i].manual_geom)
941 			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
942 						"vnconfig %s vnd%d %s %d %d %d %d", r_o, vnds[i].node,
943 						resultpath, vnds[i].secsize, vnds[i].nsectors,
944 						vnds[i].ntracks, vnds[i].ncylinders);
945 		/* If this is a existing image or image without manual geometry */
946 		else
947 			error += run_program(RUN_DISPLAY | RUN_PROGRESS, "vnconfig %s vnd%d %s",
948 						r_o, vnds[i].node, resultpath);
949 
950 		if (! error) {
951 			vnds[i].blocked = 1;
952 			vnds[i].pm_part = part_suit;
953 			vnds[i].pm = pm_suit;
954 			vnds[i].pm->blocked++;
955 		}
956 	}
957 	return 0;
958 }
959 
960 /***
961  CGD
962  ***/
963 
964 static void
965 pm_cgd_menufmt(menudesc *m, int opt, void *arg)
966 {
967 	cgds_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
968 	char desc[STRSIZE];
969 
970 	if (dev_ptr->enabled == 0)
971 		return;
972 	if (dev_ptr->pm == NULL)
973 		wprintw(m->mw, "%s", msg_string(MSG_cgd_err_menufmt));
974 	else {
975 		snprintf(desc, STRSIZE, "(%s-%d) on %s", dev_ptr->enc_type,
976 			dev_ptr->key_size, dev_ptr->pm_name);
977 		wprintw(m->mw, msg_string(MSG_cgd_menufmt), dev_ptr->node, desc,
978 			dev_ptr->pm->bsdlabel[dev_ptr->pm_part].pi_size /
979 							(MEG / dev_ptr->pm->sectorsize));
980 	}
981 	return;
982 }
983 
984 static void
985 pm_cgd_edit_menufmt(menudesc *m, int opt, void *arg)
986 {
987 	cgds_t *dev_ptr = arg;
988 	switch (opt) {
989 		case PMC_MENU_DEV:
990 			wprintw(m->mw, msg_string(MSG_cgd_dev_fmt), dev_ptr->pm_name);
991 			break;
992 		case PMC_MENU_ENCTYPE:
993 			wprintw(m->mw, msg_string(MSG_cgd_enc_fmt), dev_ptr->enc_type);
994 			break;
995 		case PMC_MENU_KEYSIZE:
996 			wprintw(m->mw, msg_string(MSG_cgd_key_fmt), dev_ptr->key_size);
997 			break;
998 		case PMC_MENU_IVTYPE:
999 			wprintw(m->mw, msg_string(MSG_cgd_iv_fmt), dev_ptr->iv_type);
1000 			break;
1001 		case PMC_MENU_KEYGENTYPE:
1002 			wprintw(m->mw, msg_string(MSG_cgd_keygen_fmt), dev_ptr->keygen_type);
1003 			break;
1004 		case PMC_MENU_VERIFYTYPE:
1005 			wprintw(m->mw, msg_string(MSG_cgd_verif_fmt), dev_ptr->verify_type);
1006 			break;
1007 	}
1008 	return;
1009 }
1010 
1011 static int
1012 pm_cgd_set_value(menudesc *m, void *arg)
1013 {
1014 	char *retstring;
1015 	cgds_t *dev_ptr = arg;
1016 
1017 	switch (m->cursel) {
1018 		case PMC_MENU_DEV:
1019 			pm_cgd_disk_set(dev_ptr, NULL);
1020 			return 0;
1021 		case PMC_MENU_ENCTYPE:
1022 			process_menu(MENU_cgd_enctype, &retstring);
1023 			dev_ptr->enc_type = retstring;
1024 			if (! strcmp(retstring, "blowfish-cbc"))
1025 				dev_ptr->key_size = 128;
1026 			if (! strcmp(retstring, "3des-cbc"))
1027 				dev_ptr->key_size = 192;
1028 			return 0;
1029 		case PMC_MENU_KEYSIZE:
1030 			if (! strcmp(dev_ptr->enc_type, "aes-cbc"))
1031 				dev_ptr->key_size +=
1032 					(dev_ptr->key_size < 256)? 64 : -128;
1033 			if (! strcmp(dev_ptr->enc_type, "blowfish-cbc"))
1034 				dev_ptr->key_size = 128;
1035 			if (! strcmp(dev_ptr->enc_type, "3des-cbc"))
1036 				dev_ptr->key_size = 192;
1037 			return 0;
1038 		case PMC_MENU_IVTYPE:
1039 			process_menu(MENU_cgd_ivtype, &retstring);
1040 			dev_ptr->iv_type = retstring;
1041 			return 0;
1042 		case PMC_MENU_KEYGENTYPE:
1043 			process_menu(MENU_cgd_keygentype, &retstring);
1044 			dev_ptr->keygen_type = retstring;
1045 			return 0;
1046 		case PMC_MENU_VERIFYTYPE:
1047 			process_menu(MENU_cgd_verifytype, &retstring);
1048 			dev_ptr->verify_type = retstring;
1049 			return 0;
1050 		case PMC_MENU_REMOVE:
1051 			dev_ptr->enabled = 0;
1052 			return 0;
1053 	}
1054 	return -1;
1055 }
1056 
1057 static void
1058 pm_cgd_init(void *arg1, void *arg2)
1059 {
1060 	cgds_t *dev_ptr = arg1;
1061 	part_entry_t *disk_entrie = arg2;
1062 
1063 	memset(dev_ptr, 0, sizeof(*dev_ptr));
1064 	*dev_ptr = (struct cgds_t) {
1065 		.enabled = 1,
1066 		.blocked = 0,
1067 		.pm = NULL,
1068 		.pm_name[0] = '\0',
1069 		.pm_part = 0,
1070 		.keygen_type = "pkcs5_pbkdf2/sha1",
1071 		.verify_type = "disklabel",
1072 		.enc_type = "aes-cbc",
1073 		.iv_type = "encblkno1",
1074 		.key_size = 192,
1075 	};
1076 	if (disk_entrie != NULL) {
1077 		pm_getdevstring(disk_entrie->fullname, SSTRSIZE,
1078 			disk_entrie->dev_ptr, disk_entrie->dev_num);
1079 		pm_cgd_disk_set(dev_ptr, disk_entrie);
1080 	}
1081 	return;
1082 }
1083 
1084 static int
1085 pm_cgd_check(void *arg)
1086 {
1087 	cgds_t *dev_ptr = arg;
1088 
1089 	if (dev_ptr->blocked)
1090 		return 0;
1091 	if (dev_ptr->pm == NULL)
1092 		dev_ptr->enabled = 0;
1093 	else
1094 		pm_manage_getfreenode(&(dev_ptr->node), "cgd", &cgds_t_info);
1095 		if (dev_ptr->node < 0)
1096 			dev_ptr->enabled = 0;
1097 	return dev_ptr->enabled;
1098 }
1099 
1100 static int
1101 pm_cgd_disk_set(cgds_t *dev_ptr, part_entry_t *disk_entrie)
1102 {
1103 	int alloc_disk_entrie = 0;
1104 	if (disk_entrie == NULL) {
1105 		alloc_disk_entrie = 1;
1106 		disk_entrie = malloc (sizeof(part_entry_t));
1107 		if (disk_entrie == NULL)
1108 			return -2;
1109 		*disk_entrie = pm_dev_list(PM_CGD_T);
1110 		if (disk_entrie->retvalue < 0) {
1111 			free(disk_entrie);
1112 			return -1;
1113 		}
1114 	}
1115 	dev_ptr->pm = disk_entrie->dev_ptr;
1116 	dev_ptr->pm_part = disk_entrie->dev_num;
1117 	strlcpy(dev_ptr->pm_name, disk_entrie->fullname, SSTRSIZE);
1118 
1119 	if (alloc_disk_entrie)
1120 		free(disk_entrie);
1121 	return 0;
1122 }
1123 
1124 int
1125 pm_cgd_edit(void *dev_ptr, part_entry_t *disk_entrie)
1126 {
1127 	if (disk_entrie != NULL)
1128 		dev_ptr = NULL;
1129 	return pm_edit(PMC_MENU_END, pm_cgd_edit_menufmt,
1130 		pm_cgd_set_value, pm_cgd_check, pm_cgd_init,
1131 		disk_entrie, dev_ptr, 0, &cgds_t_info);
1132 }
1133 
1134 static int
1135 pm_cgd_commit(void)
1136 {
1137 	int i, error = 0;
1138 	for (i = 0; i < MAX_CGD; i++) {
1139 		if (! pm_cgd_check(&cgds[i]))
1140 			continue;
1141 		if (run_program(RUN_DISPLAY | RUN_PROGRESS,
1142 			"cgdconfig -g -i %s -k %s -o /tmp/cgd.%d.conf %s %d",
1143 			cgds[i].iv_type, cgds[i].keygen_type, cgds[i].node,
1144 			cgds[i].enc_type, cgds[i].key_size) != 0) {
1145 			error++;
1146 			continue;
1147 		}
1148 		if (run_program(RUN_DISPLAY | RUN_PROGRESS,
1149 			"cgdconfig -V re-enter cgd%d /dev/%s /tmp/cgd.%d.conf",
1150 			cgds[i].node, cgds[i].pm_name, cgds[i].node) != 0) {
1151 			error++;
1152 			continue;
1153 		}
1154 		cgds[i].pm->blocked++;
1155 		cgds[i].blocked = 1;
1156 	}
1157 	return error;
1158 }
1159 
1160 /***
1161  LVM
1162  ***/
1163 
1164 /* Add lvm logical volumes to pm list */
1165 /* XXX: rewrite */
1166 static int
1167 pm_lvm_find(void)
1168 {
1169 	int i, ii, already_found;
1170 	char dev[STRSIZE];
1171 	pm_devs_t *pm_i;
1172 
1173 	for (i = 0; i < MAX_LVM_VG; i++) {
1174 		if (! lvms[i].blocked)
1175 			continue;
1176 		for (ii = 0; ii < MAX_LVM_LV; ii++) {
1177 			if (! lvms[i].lv[ii].blocked || lvms[i].lv[ii].size < 1)
1178 				continue;
1179 			snprintf(dev, STRSIZE, "%s/%s", lvms[i].name, lvms[i].lv[ii].name);
1180 			already_found = 0;
1181 			SLIST_FOREACH(pm_i, &pm_head, l)
1182 				if (!already_found && strcmp(pm_i->diskdev, dev) == 0) {
1183 					pm_i->found = 1;
1184 					already_found = 1;
1185 				}
1186 			if (already_found)
1187 				/* We already added this device, skipping */
1188 				continue;
1189 			pm_new->found = 1;
1190 			pm_new->isspecial = 1;
1191 			pm_new->refdev = &lvms[i].lv[ii];
1192 			pm_new->sectorsize = 1;
1193 			pm_new->dlcylsize = MEG;
1194 			pm_new->bsdlabel[0].pi_size = MEG * lvms[i].lv[ii].size;
1195 			strlcpy(pm_new->diskdev, dev, SSTRSIZE);
1196 			strlcpy(pm_new->diskdev_descr, dev, STRSIZE);
1197 
1198 			if (SLIST_EMPTY(&pm_head))
1199 				 SLIST_INSERT_HEAD(&pm_head, pm_new, l);
1200 			else
1201 				 SLIST_INSERT_AFTER(pm_i, pm_new, l);
1202 			pm_new = malloc(sizeof (pm_devs_t));
1203 			memset(pm_new, 0, sizeof *pm_new);
1204 		}
1205 	}
1206 	return 0;
1207 }
1208 
1209 static int
1210 pm_lvm_disk_add(menudesc *m, void *arg)
1211 {
1212 	int i;
1213 	lvms_t *dev_ptr = arg;
1214 	part_entry_t disk_entrie = pm_dev_list(PM_LVM_T);
1215 	if (disk_entrie.retvalue < 0)
1216 		return disk_entrie.retvalue;
1217 
1218 	for (i = 0; i < MAX_LVM_PV; i++)
1219 		if (dev_ptr->pv[i].pm == NULL) {
1220 			dev_ptr->pv[i].pm = disk_entrie.dev_ptr;
1221 			dev_ptr->pv[i].pm_part = disk_entrie.dev_num;
1222 			strlcpy(dev_ptr->pv[i].pm_name, disk_entrie.fullname, SSTRSIZE);
1223 			break;
1224 		}
1225 	return 0;
1226 }
1227 
1228 static int
1229 pm_lvm_disk_del(menudesc *m, void *arg)
1230 {
1231 	int i, retvalue = -1, num_devs = 0;
1232 	int menu_no;
1233 	lvms_t *dev_ptr = arg;
1234 	menu_ent menu_entries[MAX_LVM_PV];
1235 	part_entry_t submenu_args[MAX_LVM_PV];
1236 
1237 	for (i = 0; i < MAX_LVM_PV; i++) {
1238 		if (dev_ptr->pv[i].pm == NULL)
1239 			continue;
1240 		menu_entries[num_devs] = (struct menu_ent) {
1241 			.opt_name = dev_ptr->pv[i].pm_name,
1242 			.opt_action = set_menu_select,
1243 			.opt_menu = OPT_NOMENU,
1244 			.opt_flags = OPT_EXIT,
1245 		};
1246 		submenu_args[num_devs].dev_num = i;
1247 		num_devs++;
1248 	}
1249 
1250 	menu_no = new_menu(MSG_lvm_disks,
1251 		menu_entries, num_devs, -1, -1, (num_devs+1<3)?3:num_devs+1, 13,
1252 		MC_SCROLL | MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
1253 	if (menu_no == -1)
1254 		return -1;
1255 	process_menu(menu_no, &retvalue);
1256 	free_menu(menu_no);
1257 
1258 	if (retvalue < 0 || retvalue >= num_devs)
1259 		return -1;
1260 
1261 	dev_ptr->pv[submenu_args[retvalue].dev_num].pm = NULL;
1262 
1263 	return 0;
1264 }
1265 
1266 static void
1267 pm_lvm_menufmt(menudesc *m, int opt, void *arg)
1268 {
1269 	int i, ok = 0, used_size = 0;
1270 	char buf1[STRSIZE]; buf1[0] = '\0';
1271 	char buf2[STRSIZE]; buf2[0] = '\0';
1272 	lvms_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
1273 
1274 	if (dev_ptr->enabled == 0)
1275 		return;
1276 	snprintf(buf1, STRSIZE, "VG '%s' on ", dev_ptr->name);
1277 	for (i = 0; i < MAX_LVM_PV; i++)
1278 		if (dev_ptr->pv[i].pm != NULL) {
1279 			strncat(buf1, dev_ptr->pv[i].pm_name, STRSIZE);
1280 			strncat(buf1, " ", STRSIZE);
1281 			ok = 1;
1282 		}
1283 	for (i = 0; i < MAX_LVM_LV; i++)
1284 		used_size += dev_ptr->lv[i].size;
1285 	if (ok) {
1286 		snprintf(buf2, STRSIZE, "%d/%u",
1287 			dev_ptr->total_size - used_size, dev_ptr->total_size);
1288 		wprintw(m->mw, msg_string(MSG_lvm_menufmt), buf1, buf2);
1289 	} else
1290 		wprintw(m->mw, "%s", msg_string(MSG_lvm_err_menufmt));
1291 	return;
1292 }
1293 
1294 static void
1295 pm_lvm_edit_menufmt(menudesc *m, int opt, void *arg)
1296 {
1297 	int i;
1298 	char buf[STRSIZE];
1299 	lvms_t *dev_ptr = arg;
1300 	strlcpy(buf, msg_string(MSG_auto), STRSIZE);
1301 
1302 	switch (opt) {
1303 		case PML_MENU_PV:
1304 			buf[0] = '\0';
1305 			for (i = 0; i < MAX_LVM_PV; i++)
1306 				if (dev_ptr->pv[i].pm != NULL)
1307 					snprintf(buf, STRSIZE, "%s %s", buf, dev_ptr->pv[i].pm_name);
1308 			wprintw(m->mw, msg_string(MSG_lvm_disks_fmt), buf);
1309 			break;
1310 		case PML_MENU_NAME:
1311 			wprintw(m->mw, msg_string(MSG_lvm_name_fmt), dev_ptr->name);
1312 			break;
1313 		case PML_MENU_MAXLOGICALVOLUMES:
1314 			if (dev_ptr->maxlogicalvolumes > 0)
1315 				snprintf(buf, STRSIZE, "%d", dev_ptr->maxlogicalvolumes);
1316 			wprintw(m->mw, msg_string(MSG_lvm_maxlv_fmt), buf);
1317 			break;
1318 		case PML_MENU_MAXPHYSICALVOLUMES:
1319 			if (dev_ptr->maxphysicalvolumes > 0)
1320 				snprintf(buf, STRSIZE, "%d", dev_ptr->maxphysicalvolumes);
1321 			wprintw(m->mw, msg_string(MSG_lvm_maxpv_fmt), buf);
1322 			break;
1323 		case PML_MENU_PHYSICALEXTENTSIZE:
1324 			if (dev_ptr->physicalextentsize > 0)
1325 				snprintf(buf, STRSIZE, "%dM", dev_ptr->physicalextentsize);
1326 			wprintw(m->mw, msg_string(MSG_lvm_extsiz_fmt), buf);
1327 			break;
1328 	}
1329 	return;
1330 }
1331 
1332 static int
1333 pm_lvm_set_value(menudesc *m, void *arg)
1334 {
1335 	char buf[STRSIZE];
1336 	const char *msg_to_show = NULL;
1337 	int *out_var = NULL;
1338 	lvms_t *dev_ptr = arg;
1339 
1340 	static menu_ent menuent_disk_adddel[] = {
1341 	    {MSG_add, OPT_NOMENU, OPT_EXIT, pm_lvm_disk_add},
1342 	    {MSG_remove, OPT_NOMENU, OPT_EXIT, pm_lvm_disk_del}
1343 	};
1344 	static int menu_disk_adddel = -1;
1345 	if (menu_disk_adddel == -1) {
1346 		menu_disk_adddel = new_menu(NULL, menuent_disk_adddel, nelem(menuent_disk_adddel),
1347 			-1, -1, 0, 10, MC_NOCLEAR, NULL, NULL, NULL, NULL, NULL);
1348 	}
1349 
1350 	switch (m->cursel) {
1351 		case PML_MENU_PV:
1352 			process_menu(menu_disk_adddel, arg);
1353 			return 0;
1354 		case PML_MENU_NAME:
1355 			msg_prompt_win(MSG_lvm_name_ask, -1, 18, 0, 0, dev_ptr->name, dev_ptr->name, SSTRSIZE);
1356 			return 0;
1357 		case PML_MENU_MAXLOGICALVOLUMES:
1358 			msg_to_show = MSG_lvm_maxlv_ask;
1359 			out_var = &(dev_ptr->maxlogicalvolumes);
1360 			break;
1361 		case PML_MENU_MAXPHYSICALVOLUMES:
1362 			msg_to_show = MSG_lvm_maxpv_ask;
1363 			out_var = &(dev_ptr->maxphysicalvolumes);
1364 			break;
1365 		case PML_MENU_PHYSICALEXTENTSIZE:
1366 			msg_to_show = MSG_lvm_extsiz_ask;
1367 			out_var = &(dev_ptr->physicalextentsize);
1368 			break;
1369 		case PML_MENU_REMOVE:
1370 			dev_ptr->enabled = 0;
1371 			return 0;
1372 	}
1373 	if (out_var == NULL || msg_to_show == NULL)
1374 		return -1;
1375 	snprintf(buf, SSTRSIZE, "%d", *out_var);
1376 	msg_prompt_win(msg_to_show, -1, 18, 0, 0, buf, buf, SSTRSIZE);
1377 	if (atoi(buf) >= 0)
1378 		*out_var = atoi(buf);
1379 	return 0;
1380 }
1381 
1382 static void
1383 pm_lvm_init(void *arg, void* none)
1384 {
1385 	lvms_t *dev_ptr = arg;
1386 
1387 	memset(dev_ptr, 0, sizeof *dev_ptr);
1388 	*dev_ptr = (struct lvms_t) {
1389 		.enabled = 1,
1390 		.blocked = 0,
1391 		.maxlogicalvolumes = MAX_LVM_PV,
1392 		.maxphysicalvolumes = MAX_LVM_LV,
1393 		.physicalextentsize = -1,
1394 	};
1395 	sprintf(dev_ptr->name, "vg%.2d", rand()%100);
1396 	return;
1397 }
1398 
1399 static int
1400 pm_lvm_check(void *arg)
1401 {
1402 	int i, ok = 0;
1403 	lvms_t *dev_ptr = arg;
1404 	dev_ptr->total_size = 0;
1405 
1406 	for (i = 0; i < MAX_LVM_PV; i++)
1407 		if (dev_ptr->pv[i].pm != NULL) {
1408 			ok = 1;
1409 			dev_ptr->total_size += dev_ptr->pv[i].pm->
1410 						bsdlabel[dev_ptr->pv[i].pm_part].pi_size /
1411 						(MEG / dev_ptr->pv[i].pm->sectorsize);
1412 		}
1413 	if (! ok)
1414 		dev_ptr->enabled = 0;
1415 	return dev_ptr->enabled;
1416 }
1417 
1418 static void
1419 pm_lvmlv_menufmt(menudesc *m, int opt, void *arg)
1420 {
1421 	char buf[STRSIZE];
1422 	lv_t *dev_ptr = ((part_entry_t *)arg)[opt].dev_ptr;
1423 
1424 	if (dev_ptr->size > 0) {
1425 		snprintf(buf, STRSIZE, "'%s'", dev_ptr->name);
1426 		wprintw(m->mw, msg_string(MSG_lvmlv_menufmt), buf, dev_ptr->size);
1427 	}
1428 	return;
1429 }
1430 
1431 static void
1432 pm_lvmlv_edit_menufmt(menudesc *m, int opt, void *arg)
1433 {
1434 
1435 	lv_t *dev_ptr = arg;
1436 	char buf[STRSIZE];
1437 	strlcpy(buf, msg_string(MSG_auto), STRSIZE);
1438 
1439 	switch (opt) {
1440 		case PMLV_MENU_NAME:
1441 			wprintw(m->mw, msg_string(MSG_lvmlv_name_fmt), dev_ptr->name);
1442 			break;
1443 		case PMLV_MENU_SIZE:
1444 			wprintw(m->mw, msg_string(MSG_lvmlv_size_fmt), dev_ptr->size);
1445 			break;
1446 		case PMLV_MENU_READONLY:
1447 			wprintw(m->mw, msg_string(MSG_lvmlv_ro_fmt),
1448 				dev_ptr->readonly? msg_string(MSG_Yes) : msg_string(MSG_No));
1449 			break;
1450 		case PMLV_MENU_CONTIGUOUS:
1451 			wprintw(m->mw, msg_string(MSG_lvmlv_cont_fmt),
1452 				dev_ptr->contiguous? msg_string(MSG_Yes) : msg_string(MSG_No));
1453 			break;
1454 		case PMLV_MENU_EXTENTS:
1455 			wprintw(m->mw, msg_string(MSG_lvmlv_extnum_fmt),
1456 				(strlen(dev_ptr->extents) > 0)? dev_ptr->extents : msg_string(MSG_auto));
1457 			break;
1458 		case PMLV_MENU_MINOR:
1459 			if (dev_ptr->minor > 0)
1460 				snprintf(buf, STRSIZE, "%dK", dev_ptr->minor);
1461 			wprintw(m->mw, msg_string(MSG_lvmlv_minor_fmt), buf);
1462 			break;
1463 		case PMLV_MENU_MIRRORS:
1464 			wprintw(m->mw, msg_string(MSG_lvmlv_mirrors_fmt), dev_ptr->mirrors);
1465 			break;
1466 		case PMLV_MENU_REGIONSIZE:
1467 			if (dev_ptr->regionsize > 0)
1468 				snprintf(buf, STRSIZE, "%dM", dev_ptr->regionsize);
1469 			wprintw(m->mw, msg_string(MSG_lvmlv_regsiz_fmt), buf);
1470 			break;
1471 		case PMLV_MENU_PERSISTENT:
1472 			wprintw(m->mw, msg_string(MSG_lvmlv_pers_fmt),
1473 				dev_ptr->persistent ? msg_string(MSG_Yes) : msg_string(MSG_No));
1474 			break;
1475 		case PMLV_MENU_READAHEAD:
1476 			if (dev_ptr->readahead > 0)
1477 				snprintf(buf, STRSIZE, "%d", dev_ptr->readahead);
1478 			wprintw(m->mw, msg_string(MSG_lvmlv_readahsect_fmt), buf);
1479 			break;
1480 		case PMLV_MENU_STRIPES:
1481 			if (dev_ptr->stripes > 0)
1482 				snprintf(buf, STRSIZE, "%d", dev_ptr->stripes);
1483 			wprintw(m->mw, msg_string(MSG_lvmlv_stripes_fmt), buf);
1484 			break;
1485 		case PMLV_MENU_STRIPESIZE:
1486 			if (dev_ptr->stripesize > 0)
1487 				snprintf(buf, STRSIZE, "%dK", dev_ptr->stripesize);
1488 			wprintw(m->mw, msg_string(MSG_lvmlv_stripesiz_fmt), buf);
1489 			break;
1490 		case PMLV_MENU_ZERO:
1491 			wprintw(m->mw, msg_string(MSG_lvmlv_zero_fmt),
1492 				dev_ptr->zero? msg_string(MSG_Yes) : msg_string(MSG_No));
1493 			break;
1494 	}
1495 	return;
1496 }
1497 
1498 static int
1499 pm_lvmlv_set_value(menudesc *m, void *arg)
1500 {
1501 	char buf[STRSIZE];
1502 	const char *msg_to_show = NULL;
1503 	int *out_var = NULL;
1504 	lv_t *dev_ptr = arg;
1505 
1506 	switch (m->cursel) {
1507 		case PMLV_MENU_NAME:
1508 			msg_prompt_win(MSG_lvmlv_name_ask, -1, 18, 0, 0, dev_ptr->name, dev_ptr->name,
1509 				SSTRSIZE);
1510 			return 0;
1511 		case PMLV_MENU_SIZE:
1512 			msg_to_show = MSG_lvmlv_size_ask;
1513 			out_var = &(dev_ptr->size);
1514 			break;
1515 		case PMLV_MENU_READONLY:
1516 			dev_ptr->readonly = !dev_ptr->readonly;
1517 			return 0;
1518 		case PMLV_MENU_CONTIGUOUS:
1519 			dev_ptr->contiguous = !dev_ptr->contiguous;
1520 			return 0;
1521 		case PMLV_MENU_EXTENTS:
1522 			msg_prompt_win(MSG_lvmlv_extnum_ask, -1, 18, 0, 0,
1523 				dev_ptr->extents, dev_ptr->extents, SSTRSIZE);
1524 			return 0;
1525 		case PMLV_MENU_MINOR:
1526 			msg_to_show = MSG_lvmlv_minor_ask;
1527 			out_var = &(dev_ptr->minor);
1528 			break;
1529 		case PMLV_MENU_MIRRORS:
1530 			msg_to_show = MSG_lvmlv_mirrors_ask;
1531 			out_var = &(dev_ptr->mirrors);
1532 			break;
1533 		case PMLV_MENU_REGIONSIZE:
1534 			msg_to_show = MSG_lvmlv_regsiz_ask;
1535 			out_var = &(dev_ptr->regionsize);
1536 			break;
1537 		case PMLV_MENU_PERSISTENT:
1538 			dev_ptr->persistent = !dev_ptr->persistent;
1539 			return 0;
1540 		case PMLV_MENU_READAHEAD:
1541 			msg_to_show = MSG_lvmlv_readahsect_ask;
1542 			out_var = &(dev_ptr->readahead);
1543 			break;
1544 		case PMLV_MENU_STRIPES:
1545 			msg_to_show = MSG_lvmlv_stripes_ask;
1546 			out_var = &(dev_ptr->stripes);
1547 			break;
1548 		case PMLV_MENU_STRIPESIZE:
1549 			if (dev_ptr->stripesize << 1 > 512)
1550 				dev_ptr->stripesize = 4;
1551 			else
1552 				dev_ptr->stripesize <<= 1;
1553 			return 0;
1554 		case PMLV_MENU_ZERO:
1555 			dev_ptr->zero = !dev_ptr->zero;
1556 			return 0;
1557 		case PMLV_MENU_REMOVE:
1558 			dev_ptr->size = 0;
1559 			return 0;
1560 	}
1561 	if (out_var == NULL || msg_to_show == NULL)
1562 		return -1;
1563 	snprintf(buf, SSTRSIZE, "%d", *out_var);
1564 	msg_prompt_win(msg_to_show, -1, 18, 0, 0, buf, buf, SSTRSIZE);
1565 	if (atoi(buf) >= 0)
1566 		*out_var = atoi(buf);
1567 	return 0;
1568 }
1569 
1570 static void
1571 pm_lvmlv_init(void *arg, void *none)
1572 {
1573 	lv_t *dev_ptr = arg;
1574 	memset(dev_ptr, 0, sizeof *(dev_ptr));
1575 	*dev_ptr = (struct lv_t) {
1576 		.blocked = 0,
1577 		.size = 1024,
1578 		.stripesize = 64,
1579 	};
1580 	sprintf (dev_ptr->name, "lvol%.2d", rand()%100);
1581 	return;
1582 }
1583 
1584 static int
1585 pm_lvmlv_check(void *arg)
1586 {
1587 	lv_t *dev_ptr = arg;
1588 	if (dev_ptr->size > 0 && strlen(dev_ptr->name) > 0)
1589 		return 1;
1590 	else {
1591 		dev_ptr->size = 0;
1592 		return 0;
1593 	}
1594 }
1595 
1596 static int
1597 pm_lvm_commit(void)
1598 {
1599 	int i, ii, error;
1600 	uint used_size = 0;
1601 	char params[STRSIZE*3];
1602 	char devs[STRSIZE*3];
1603 
1604 	for (i = 0; i < MAX_LVM_VG; i++) {
1605 		/* Stage 0: checks */
1606 		if (! pm_lvm_check(&lvms[i]))
1607 			continue;
1608 		for (ii = 0; ii < MAX_LVM_LV; ii++)
1609 			used_size += lvms[i].lv[ii].size;
1610 		if (used_size > lvms[i].total_size)
1611 			continue;
1612 
1613 		params[0] = '\0';
1614 		devs[0] = '\0';
1615 		error = 0;
1616 		/* Stage 1: creating Physical Volumes (PV's) */
1617 		for (ii = 0; ii < MAX_LVM_PV && ! error; ii++)
1618 			if (lvms[i].pv[ii].pm != NULL) {
1619 				run_program(RUN_SILENT | RUN_ERROR_OK,
1620 										"lvm pvremove -ffy /dev/r%s",
1621 										(char*)lvms[i].pv[ii].pm_name);
1622 				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
1623 										"lvm pvcreate -ffy /dev/r%s",
1624 										(char*)lvms[i].pv[ii].pm_name);
1625 				if (error)
1626 					break;
1627 				snprintf(devs, STRSIZE*3, "%s /dev/r%s", devs, (char*)lvms[i].pv[ii].pm_name);
1628 			}
1629 		if (error)
1630 			continue;
1631 		/* Stage 2: creating Volume Groups (VG's) */
1632 		if (lvms[i].maxlogicalvolumes > 0)
1633 			snprintf(params, STRSIZE*3, "%s -l %d", params, lvms[i].maxlogicalvolumes);
1634 		if (lvms[i].maxphysicalvolumes > 0)
1635 			snprintf(params, STRSIZE*3, "%s -p %d", params, lvms[i].maxphysicalvolumes);
1636 		if (lvms[i].physicalextentsize > 0)
1637 			snprintf(params, STRSIZE*3, "%s -s %d", params, lvms[i].physicalextentsize);
1638 		error += run_program(RUN_DISPLAY | RUN_PROGRESS, "lvm vgcreate %s %s %s",
1639 							params, lvms[i].name, devs);
1640 		if (error)
1641 			continue;
1642 		/* Stage 3: creating Logical Volumes (LV's) */
1643 		for (ii = 0; ii < MAX_LVM_LV; ii++) {
1644 			if (lvms[i].lv[ii].size <= 0)
1645 				continue;
1646 
1647 			params[0] = '\0';
1648 			snprintf(params, STRSIZE*3, "%s -C %c", params, lvms[i].lv[ii].contiguous?'y':'n');
1649 			snprintf(params, STRSIZE*3, "%s -M %c", params, lvms[i].lv[ii].persistent?'y':'n');
1650 			snprintf(params, STRSIZE*3, "%s -p %s", params, lvms[i].lv[ii].readonly?"r":"rw");
1651 			snprintf(params, STRSIZE*3, "%s -Z %c", params, lvms[i].lv[ii].zero?'y':'n');
1652 			if (strlen(lvms[i].lv[ii].name) > 0)
1653 				snprintf(params, STRSIZE*3, "%s -n %s", params, lvms[i].lv[ii].name);
1654 			if (strlen(lvms[i].lv[ii].extents) > 0)
1655 				snprintf(params, STRSIZE*3, "%s -l %s", params, lvms[i].lv[ii].extents);
1656 			if (lvms[i].lv[ii].minor > 0)
1657 				snprintf(params, STRSIZE*3, "%s --minor %d", params, lvms[i].lv[ii].minor);
1658 			if (lvms[i].lv[ii].mirrors > 0) {
1659 				snprintf(params, STRSIZE*3, "%s -m %d", params, lvms[i].lv[ii].mirrors);
1660 				if (lvms[i].lv[ii].regionsize > 0)
1661 					snprintf(params, STRSIZE*3, "%s -R %d", params, lvms[i].lv[ii].regionsize);
1662 			}
1663 			if (lvms[i].lv[ii].readahead > 0)
1664 				snprintf(params, STRSIZE*3, "%s -r %d", params, lvms[i].lv[ii].readahead);
1665 			if (lvms[i].lv[ii].stripes > 0) {
1666 				snprintf(params, STRSIZE*3, "%s -i %d", params, lvms[i].lv[ii].stripes);
1667 				if (lvms[i].lv[ii].stripesize > 0)
1668 					snprintf(params, STRSIZE*3, "%s -I %d", params, lvms[i].lv[ii].stripesize);
1669 			}
1670 			snprintf(params, STRSIZE*3, "%s -L %uM", params, lvms[i].lv[ii].size);
1671 			error += run_program(RUN_DISPLAY | RUN_PROGRESS, "lvm lvcreate %s %s",
1672 									params, lvms[i].name);
1673 		}
1674 		if (! error) {
1675 			lvms[i].blocked = 1;
1676 			for (ii = 0; ii < MAX_LVM_PV; ii++)
1677 				if (lvms[i].pv[ii].pm != NULL)
1678 					lvms[i].pv[ii].pm->blocked++;
1679 			for (ii = 0; ii < MAX_LVM_LV; ii++)
1680 				if (lvms[i].lv[ii].size > 0)
1681 					lvms[i].lv[ii].blocked = 1;
1682 		}
1683 	}
1684 
1685 	return 0;
1686 }
1687 
1688 /***
1689  GPT
1690  ***/
1691 
1692 int
1693 pm_gpt_convert(pm_devs_t *pm_cur)
1694 {
1695 	int i, error = 0;
1696 
1697 	msg_display(MSG_removepartswarn);
1698 	process_menu(MENU_noyes, NULL);
1699 	if (! yesno)
1700 		return -1;
1701 
1702 	if (! pm_cur->gpt)
1703 		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "gpt create -f %s",
1704 				pm_cur->diskdev);
1705 	else {
1706 		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "gpt destroy %s",
1707 				pm_cur->diskdev);
1708 		for (i = 0; i < MAX_WEDGES; i++)
1709 			if (wedges[i].pm == pm_cur)
1710 				wedges[i].pm = NULL;
1711 	}
1712 	if (!error) {
1713 		pm_cur->gpt = !pm_cur->gpt;
1714 		pm_select(pm_cur);
1715 		label_read();
1716 	}
1717 	return error;
1718 }
1719 
1720 static int
1721 pm_wedge_getfree(void)
1722 {
1723 	int i;
1724 	for (i = 0; i < MAX_WEDGES; i++)
1725 		if (! wedges[i].allocated && wedges[i].pm == NULL)
1726 			return i;
1727 	return -1;
1728 }
1729 
1730 void
1731 pm_wedges_fill(pm_devs_t *pm_cur)
1732 {
1733 	int i, current;
1734 
1735 	for (i = 0; i < MAX_WEDGES; i++)
1736 		if (wedges[i].pm == pm_cur && ! wedges[i].allocated)
1737 			wedges[i].pm = NULL;
1738 
1739 	for (i = 0; i < min(MAXPARTITIONS,MAX_WEDGES); i++)
1740 		if (pm_cur->bsdlabel[i].pi_fstype != FS_UNUSED) {
1741 			current = pm_wedge_getfree();
1742 			if (current < 0) {
1743 				process_menu(MENU_ok, deconst(MSG_limitcount));
1744 				return;
1745 			}
1746 			wedges[current].pm = pm_cur;
1747 			wedges[current].ptn = i;
1748 		}
1749 	return;
1750 }
1751 
1752 static int
1753 pm_wedge_create(int num, pm_devs_t **pm_dk)
1754 {
1755 	int i, ii, hackerr, error;
1756 	partinfo *p = &(wedges[num].pm->bsdlabel[wedges[num].ptn]);
1757 
1758 	if (num > MAX_WEDGES)
1759 		return -1;
1760 
1761 	/* There is no ability to use required dkX device, so that's a hack */
1762 	for (i = 0; i < num; i++)
1763 		if (! wedges[i].allocated) {
1764 			hackerr = 1;
1765 			for (ii = 0; hackerr && ii < 3; ii++)
1766 				hackerr = run_program(RUN_SILENT | RUN_ERROR_OK,
1767 					"dkctl %s addwedge HACK%d %d %d unused",
1768 					wedges[num].pm->diskdev,
1769 					rand()%33, rand()%33, 0);
1770 			wedges[i].todel = 1;
1771 		}
1772 
1773 	run_program(RUN_SILENT | RUN_ERROR_OK,
1774 					"dkctl %s listwedges", wedges[num].pm->diskdev);
1775 
1776 	error = run_program(RUN_DISPLAY | RUN_PROGRESS,
1777 			"dkctl %s addwedge dk%d %u %u %s",
1778 			wedges[num].pm->diskdev,
1779 			num,
1780 			p->pi_offset,
1781 			p->pi_size,
1782 			getfstypename(p->pi_fstype));
1783 	if (!error) {
1784 		wedges[num].allocated = 1;
1785 		wedges[num].pm->blocked++;
1786 		if (pm_dk != NULL) {
1787 			*pm_dk = malloc(sizeof(pm_devs_t));
1788 			memset(*pm_dk, 0, sizeof **pm_dk);
1789 			memcpy(&(*pm_dk)->bsdlabel[0], p, sizeof (*pm_dk)->bsdlabel[0]);
1790 			(*pm_dk)->found = -1;
1791 			(*pm_dk)->isspecial = 1;
1792 			(*pm_dk)->sectorsize = 512; /* XXX: xxx */
1793 			(*pm_dk)->dlcylsize = MEG;
1794 			(*pm_dk)->refdev = wedges[num].pm;
1795 			snprintf((*pm_dk)->diskdev, SSTRSIZE, "dk%d", num);
1796 			snprintf((*pm_dk)->diskdev_descr, STRSIZE, "   %s (%s)",
1797 				(*pm_dk)->diskdev, getfstypename(p->pi_fstype));
1798 		}
1799 	} else
1800 		if (logfp)
1801 			fprintf(logfp, "Cannot create wedge dk%d for %s.\n",
1802 				num, wedges[num].pm->diskdev);
1803 
1804 	/* Hack, see above */
1805 	for (i = 0; i < num; i ++)
1806 		if (! wedges[i].allocated && wedges[i].todel) {
1807 			hackerr = run_program(RUN_SILENT | RUN_ERROR_OK,
1808 				"dkctl %s delwedge dk%d", wedges[num].pm->diskdev, i);
1809 			wedges[i].todel = 0;
1810 		}
1811 
1812 	return error;
1813 }
1814 
1815 static int
1816 pm_gpt_commit(void)
1817 {
1818 	uint i, error;
1819 	pm_devs_t *pm_i, *pm_dk = NULL;
1820 	char fstype[STRSIZE]; fstype[0] = '\0';
1821 	partinfo *p;
1822 
1823 	SLIST_FOREACH(pm_i, &pm_head, l)
1824 		if (pm_i->gpt && pm_i->unsaved)
1825 			run_program(RUN_DISPLAY | RUN_PROGRESS,
1826 				"gpt remove -a %s",
1827 				pm_i->diskdev);
1828 
1829 	for (i = 0; i < MAX_WEDGES; i++) {
1830 		if (wedges[i].pm == NULL ||
1831 			! wedges[i].pm->unsaved ||
1832 			wedges[i].ptn < 0)
1833 			continue;
1834 		error = 0;
1835 		p = &(wedges[i].pm->bsdlabel[wedges[i].ptn]);
1836 		if (wedges[i].pm->gpt) {
1837 			if (get_gptfs_by_id(p->pi_fstype) != NULL)
1838 				snprintf(fstype, STRSIZE, "-t %s", get_gptfs_by_id(p->pi_fstype));
1839 			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
1840 				"gpt add -i %u -b %u -s %u %s %s",
1841 				wedges[i].ptn + 1,
1842 				p->pi_offset, p->pi_size,
1843 				fstype, wedges[i].pm->diskdev);
1844 		}
1845 
1846 		if (error || wedges[i].allocated) {
1847 			if (logfp && error)
1848 				fprintf(logfp, "Cannot create GPT partition #%d on %s\n",
1849 					i, wedges[i].pm->diskdev);
1850 			continue;
1851 		}
1852 
1853 		error += pm_wedge_create(i, &pm_dk);
1854 		if (pm_dk != NULL) {
1855 			/* Create file system on wedge and add it to list */
1856 			pm_select(pm_dk);
1857 			make_filesystems();
1858 			SLIST_INSERT_AFTER(wedges[i].pm, pm_dk, l);
1859 			memset(p, 0, sizeof *p);
1860 			if (error)
1861 				return -1;
1862 		}
1863 	}
1864 
1865 	SLIST_FOREACH(pm_i, &pm_head, l)
1866 		if (pm_i->gpt && pm_i->unsaved)
1867 			pm_i->unsaved = 0;
1868 
1869 	return 0;
1870 }
1871 
1872 /***
1873  Partman generic functions
1874  ***/
1875 
1876 int
1877 pm_getrefdev(pm_devs_t *pm_cur)
1878 {
1879 	int i, ii, dev_num, num_devs, num_devs_s;
1880 	char dev[SSTRSIZE]; dev[0] = '\0';
1881 
1882 	pm_cur->refdev = NULL;
1883 	if (! strncmp(pm_cur->diskdev, "cgd", 3)) {
1884 		dev_num = pm_cur->diskdev[3] - '0';
1885 		for (i = 0; i < MAX_CGD; i++)
1886 			if (cgds[i].blocked && cgds[i].node == dev_num) {
1887 				pm_cur->refdev = &cgds[i];
1888 
1889 				snprintf(pm_cur->diskdev_descr, STRSIZE, "%s (%s, %s-%d)",
1890 					pm_cur->diskdev_descr, cgds[i].pm_name,
1891 					cgds[i].enc_type, cgds[i].key_size);
1892 				break;
1893 			}
1894  	} else if (! strncmp(pm_cur->diskdev, "vnd", 3)) {
1895  		dev_num = pm_cur->diskdev[3] - '0';
1896  		for (i = 0; i < MAX_VND; i++)
1897 			if (vnds[i].blocked && vnds[i].node == dev_num) {
1898 				pm_cur->refdev = &vnds[i];
1899 				pm_getdevstring(dev, SSTRSIZE, vnds[i].pm, vnds[i].pm_part);
1900 				snprintf(pm_cur->diskdev_descr, STRSIZE, "%s (%s, %s)",
1901 					pm_cur->diskdev_descr, dev, vnds[i].filepath);
1902 				break;
1903 			}
1904 	} else if (! strncmp(pm_cur->diskdev, "raid", 4)) {
1905 		dev_num = pm_cur->diskdev[4] - '0';
1906  		for (i = 0; i < MAX_RAID; i++)
1907 			if (raids[i].blocked && raids[i].node == dev_num) {
1908 				pm_cur->refdev = &raids[i];
1909 				num_devs = 0; num_devs_s = 0;
1910 				for (ii = 0; ii < MAX_IN_RAID; ii++)
1911 					if (raids[i].pm[ii] != NULL) {
1912 						if(raids[i].pm_is_spare[ii])
1913 							num_devs_s++;
1914 						else
1915 							num_devs++;
1916 					}
1917 				snprintf(pm_cur->diskdev_descr, STRSIZE,
1918 					"%s (lvl %d, %d disks, %d spare)", pm_cur->diskdev_descr,
1919 					raids[i].raid_level, num_devs, num_devs_s);
1920 				break;
1921 			}
1922 	} else
1923 		return -1;
1924 	return 0;
1925 }
1926 
1927 /* Detect that partition is in use */
1928 int
1929 pm_partusage(pm_devs_t *pm_cur, int part_num, int do_del)
1930 {
1931 	int i, ii, retvalue = 0;
1932 
1933 	if (part_num < 0) {
1934 		/* Check all partitions on device */
1935 		for (i = 0; i < MAXPARTITIONS; i++)
1936 			retvalue += pm_partusage(pm_cur, i, do_del);
1937 		return retvalue;
1938 	}
1939 
1940 	for (i = 0; i < MAX_CGD; i++)
1941 		if (cgds[i].enabled &&
1942 			cgds[i].pm == pm_cur &&
1943 			cgds[i].pm_part == part_num) {
1944 			if (do_del) {
1945 				cgds[i].pm = NULL;
1946 				strcpy(cgds[i].pm_name, "");
1947 			}
1948 			return 1;
1949 		}
1950 	for (i = 0; i < MAX_RAID; i++)
1951 		for (ii = 0; ii < MAX_IN_RAID; ii++)
1952 			if (raids[i].enabled &&
1953 				raids[i].pm[ii] == pm_cur &&
1954 				raids[i].pm_part[ii] == part_num) {
1955 					if (do_del)
1956 						raids[i].pm[ii] = NULL;
1957 					return 1;
1958 			}
1959 	for (i = 0; i < MAX_LVM_VG; i++)
1960 		for (ii = 0; ii < MAX_LVM_PV; ii++)
1961 			if (lvms[i].enabled &&
1962 				lvms[i].pv[ii].pm == pm_cur &&
1963 				lvms[i].pv[ii].pm_part == part_num) {
1964 					if (do_del)
1965 						lvms[i].pv[ii].pm = NULL;
1966 					return 1;
1967 			}
1968 
1969 	return 0;
1970 }
1971 
1972 /* Clean up removed devices */
1973 static int
1974 pm_clean(void)
1975 {
1976 	int count = 0;
1977 	pm_devs_t *pm_i;
1978 
1979 	SLIST_FOREACH(pm_i, &pm_head, l)
1980 		if (! pm_i->found) {
1981 			count++;
1982 			SLIST_REMOVE(&pm_head, pm_i, pm_devs_t, l);
1983 			free(pm_i);
1984 		}
1985 	return count;
1986 }
1987 
1988 void
1989 pm_make_bsd_partitions(pm_devs_t *pm_cur)
1990 {
1991 	int i;
1992 	partinfo baklabel[MAXPARTITIONS];
1993 	memcpy(baklabel, &pm_cur->bsdlabel, sizeof baklabel);
1994 
1995 	pm_cur->unsaved = 1;
1996 	layoutkind = LY_SETNEW;
1997 	md_make_bsd_partitions();
1998 	pm_cur->bootable = (pm_cur->bsdlabel[pm_cur->rootpart].pi_flags & PIF_MOUNT) ?
1999 		1 : 0;
2000 	for (i = 0; i < MAXPARTITIONS; i++)
2001 		if (pm_cur->bsdlabel[i].pi_fstype != baklabel[i].pi_fstype ||
2002 				pm_cur->bsdlabel[i].lvmpv != baklabel[i].lvmpv)
2003 			pm_partusage(pm_cur, i, 1);
2004 }
2005 
2006 void
2007 pm_setfstype(pm_devs_t *pm_cur, int part_num, int fstype)
2008 {
2009 	pm_cur->bsdlabel[part_num].pi_mount[0] = '\0';
2010 	pm_cur->bsdlabel[part_num].pi_flags = 0;
2011 	pm_cur->bsdlabel[part_num].lvmpv = 0;
2012 	pm_cur->bsdlabel[part_num].pi_fstype = fstype;
2013 	return;
2014 }
2015 
2016 static void
2017 pm_select(pm_devs_t *pm_devs_in)
2018 {
2019 	pm = pm_devs_in;
2020 	if (logfp)
2021 		(void)fprintf(logfp, "Partman device: %s\n", pm->diskdev);
2022 	return;
2023 }
2024 
2025 void
2026 pm_rename(pm_devs_t *pm_cur)
2027 {
2028 	pm_select(pm_cur);
2029 	msg_prompt_win(MSG_packname, -1, 18, 0, 0, pm_cur->bsddiskname,
2030 		pm_cur->bsddiskname, sizeof pm_cur->bsddiskname);
2031 #ifndef NO_DISKLABEL
2032 	(void) savenewlabel(pm_cur->bsdlabel, MAXPARTITIONS);
2033 #endif
2034 	return;
2035 }
2036 
2037 int
2038 pm_editpart(int part_num)
2039 {
2040 	partinfo backup = pm->bsdlabel[part_num];
2041 
2042 	edit_ptn(&(struct menudesc){.cursel = part_num}, NULL);
2043 	if (checkoverlap(pm->bsdlabel, MAXPARTITIONS, PART_D, PART_C)) {
2044 		msg_display_add(MSG_cantsave);
2045 		process_menu(MENU_ok, NULL);
2046 		pm->bsdlabel[part_num] = backup;
2047 		return -1;
2048 	}
2049 	pm->unsaved = 1;
2050 	return 0;
2051 }
2052 
2053 /* Safe erase of disk */
2054 int
2055 pm_shred(pm_devs_t *pm_cur, int part, int shredtype)
2056 {
2057 	int error = -1;
2058 	char dev[SSTRSIZE];
2059 
2060 	pm_getdevstring(dev, SSTRSIZE, pm_cur, part);
2061 	switch(shredtype) {
2062 		case SHRED_ZEROS:
2063 			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
2064 				"dd of=/dev/%s if=/dev/zero bs=1m progress=100 msgfmt=human",
2065 				dev);
2066 			break;
2067 		case SHRED_RANDOM:
2068 			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
2069 				"dd of=/dev/%s if=/dev/urandom bs=1m progress=100 msgfmt=human",
2070 				dev);
2071 			break;
2072 		case SHRED_CRYPTO:
2073 			error += run_program(RUN_DISPLAY | RUN_PROGRESS,
2074 				"sh -c 'cgdconfig -s cgd0 /dev/%s aes-cbc 128 < /dev/urandom'",
2075 				dev); /* XXX: cgd0?! */
2076 			if (! error) {
2077 				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
2078 					"dd of=/dev/rcgd0d if=/dev/urandom bs=1m progress=100 msgfmt=human");
2079 				error += run_program(RUN_DISPLAY | RUN_PROGRESS,
2080 					"cgdconfig -u cgd0");
2081 			}
2082 			break;
2083 		default:
2084 			return -1;
2085 	}
2086 	pm_partusage(pm_cur, -1, 1);
2087 	memset(&pm_cur->oldlabel, 0, sizeof pm_cur->oldlabel);
2088 	memset(&pm_cur->bsdlabel, 0, sizeof pm_cur->bsdlabel);
2089 	return error;
2090 }
2091 
2092 static int
2093 pm_mountall_sort(const void *a, const void *b)
2094 {
2095 	return strcmp(mnts[*(const int *)a].on, mnts[*(const int *)b].on);
2096 }
2097 
2098 /* Mount all available partitions */
2099 static int
2100 pm_mountall(void)
2101 {
2102 	int num_devs = 0;
2103 	int mnts_order[MAX_MNTS];
2104 	int i, ii, error, ok;
2105 	char dev[SSTRSIZE]; dev[0] = '\0';
2106 	pm_devs_t *pm_i;
2107 
2108 	localfs_dev[0] = '\0';
2109 	memset(&mnts, 0, sizeof mnts);
2110 
2111 	SLIST_FOREACH(pm_i, &pm_head, l) {
2112 		ok = 0;
2113 		for (i = 0; i < MAXPARTITIONS; i++) {
2114 			if (!(pm_i->bsdlabel[i].pi_flags & PIF_MOUNT &&
2115 					pm_i->bsdlabel[i].mnt_opts != NULL))
2116 				continue;
2117 			mnts[num_devs].mnt_opts = pm_i->bsdlabel[i].mnt_opts;
2118 			if (strlen(pm_i->bsdlabel[i].mounted) > 0) {
2119 				/* Device is already mounted. So, doing mount_null */
2120 				strlcpy(mnts[num_devs].dev, pm_i->bsdlabel[i].mounted, MOUNTLEN);
2121 				mnts[num_devs].mnt_opts = "-t null";
2122 			} else {
2123 				pm_getdevstring(dev, SSTRSIZE, pm_i, i);
2124 				snprintf(mnts[num_devs].dev, STRSIZE, "/dev/%s", dev);
2125 			}
2126 			mnts[num_devs].on = pm_i->bsdlabel[i].pi_mount;
2127 			if (strcmp(pm_i->bsdlabel[i].pi_mount, "/") == 0) {
2128 				if (pm_i->isspecial)
2129 					pm_i->bootable = 1;
2130 				/* Use disk with / as a default if the user has
2131 				the sets on a local disk */
2132 				strlcpy(localfs_dev, pm_i->diskdev, SSTRSIZE);
2133 			}
2134 			num_devs++;
2135 			ok = 1;
2136 		}
2137 		if (ok)
2138 			md_pre_mount();
2139 	}
2140 	if (strlen(localfs_dev) < 1) {
2141 		msg_display(MSG_noroot);
2142 		process_menu(MENU_ok, NULL);
2143 		return -1;
2144 	}
2145 	for (i = 0; i < num_devs; i++)
2146 		mnts_order[i] = i;
2147 	qsort(mnts_order, num_devs, sizeof mnts_order[0], pm_mountall_sort);
2148 
2149 	for (i = 0; i < num_devs; i++) {
2150 		ii = mnts_order[i];
2151 		make_target_dir(mnts[ii].on);
2152 		error = target_mount_do(mnts[ii].mnt_opts, mnts[ii].dev, mnts[ii].on);
2153 		if (error)
2154 			return error;
2155 	}
2156 	return 0;
2157 }
2158 
2159 /* Mount partition bypassing ordinary order */
2160 static int
2161 pm_mount(pm_devs_t *pm_cur, int part_num)
2162 {
2163 	int error = 0;
2164 	char buf[MOUNTLEN];
2165 
2166 	if (strlen(pm_cur->bsdlabel[part_num].mounted) > 0)
2167 		return 0;
2168 
2169 	snprintf(buf, MOUNTLEN, "/tmp/%s%c", pm_cur->diskdev, part_num + 'a');
2170 	if (! dir_exists_p(buf))
2171 		run_program(RUN_DISPLAY | RUN_PROGRESS, "/bin/mkdir -p %s", buf);
2172 	if (pm_cur->bsdlabel[part_num].pi_flags & PIF_MOUNT &&
2173 		pm_cur->bsdlabel[part_num].mnt_opts != NULL &&
2174 		strlen(pm_cur->bsdlabel[part_num].mounted) < 1)
2175 		error += run_program(RUN_DISPLAY | RUN_PROGRESS, "/sbin/mount %s /dev/%s%c %s",
2176 				pm_cur->bsdlabel[part_num].mnt_opts,
2177 				pm_cur->diskdev, part_num + 'a', buf);
2178 
2179 	if (error)
2180 		pm_cur->bsdlabel[part_num].mounted[0] = '\0';
2181 	else {
2182 		strlcpy(pm_cur->bsdlabel[part_num].mounted, buf, MOUNTLEN);
2183 		pm_cur->blocked++;
2184 	}
2185 	return error;
2186 }
2187 
2188 void
2189 pm_umount(pm_devs_t *pm_cur, int part_num)
2190 {
2191 	char buf[SSTRSIZE]; buf[0] = '\0';
2192 	pm_getdevstring(buf, SSTRSIZE, pm_cur, part_num);
2193 
2194 	if (run_program(RUN_DISPLAY | RUN_PROGRESS,
2195 			"umount -f /dev/%s", buf) == 0) {
2196 		pm_cur->bsdlabel[part_num].mounted[0] = '\0';
2197 		if (pm_cur->blocked > 0)
2198 			pm_cur->blocked--;
2199 	}
2200 	return;
2201 }
2202 
2203 int
2204 pm_unconfigure(pm_devs_t *pm_cur)
2205 {
2206 	int i, error = 0, num = 0;
2207 	if (! strncmp(pm_cur->diskdev, "cgd", 3)) {
2208  		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "cgdconfig -u %s", pm_cur->diskdev);
2209  		if (! error && pm_cur->refdev != NULL) {
2210 			((cgds_t*)pm_cur->refdev)->pm->blocked--;
2211 			((cgds_t*)pm_cur->refdev)->blocked = 0;
2212  		}
2213  	} else if (! strncmp(pm_cur->diskdev, "vnd", 3)) {
2214 		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "vnconfig -u %s", pm_cur->diskdev);
2215  		if (! error && pm_cur->refdev != NULL) {
2216 			((vnds_t*)pm_cur->refdev)->pm->blocked--;
2217 			((vnds_t*)pm_cur->refdev)->blocked = 0;
2218  		}
2219 	} else if (! strncmp(pm_cur->diskdev, "raid", 4)) {
2220 		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "raidctl -u %s", pm_cur->diskdev);
2221 		if (! error && pm_cur->refdev != NULL) {
2222 			((raids_t*)pm_cur->refdev)->blocked = 0;
2223 			for (i = 0; i < MAX_IN_RAID; i++)
2224 				if (((raids_t*)pm_cur->refdev)->pm[i] != NULL)
2225 					((raids_t*)pm_cur->refdev)->pm[i]->blocked--;
2226 		}
2227 	} else if (! strncmp(pm_cur->diskdev, "dk", 2)) {
2228 		if (pm_cur->refdev == NULL)
2229 			return -2;
2230 		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "dkctl %s delwedge %s",
2231 			((pm_devs_t*)pm_cur->refdev)->diskdev, pm_cur->diskdev);
2232 		if (! error) {
2233 			if (pm_cur->refdev != NULL && ((pm_devs_t*)pm_cur->refdev)->blocked > 0)
2234 				((pm_devs_t*)pm_cur->refdev)->blocked--;
2235 			sscanf(pm_cur->diskdev, "dk%d", &num);
2236 			if (num >= 0 && num < MAX_WEDGES)
2237 				wedges[num].allocated = 0;
2238 		}
2239 	} /* XXX: lvm */
2240 	else
2241 		error = run_program(RUN_DISPLAY | RUN_PROGRESS, "eject -t disk /dev/%sd",
2242 			pm_cur->diskdev);
2243 	if (!error)
2244 		pm_cur->found = 0;
2245 	return error;
2246 }
2247 
2248 /* Last checks before leaving partition manager */
2249 static int
2250 pm_lastcheck(void)
2251 {
2252 	FILE *file_tmp = fopen(concat_paths(targetroot_mnt, "/etc/fstab"), "r");
2253 	if (file_tmp == NULL)
2254 		return 1;
2255 	fclose(file_tmp);
2256 	return 0;
2257 }
2258 
2259 /* Are there unsaved changes? */
2260 static int
2261 pm_needsave(void)
2262 {
2263 	pm_devs_t *pm_i;
2264 	SLIST_FOREACH(pm_i, &pm_head, l)
2265 		if (pm_i->unsaved) {
2266 			/* Oops, we have unsaved changes */
2267 			changed = 1;
2268 			msg_display(MSG_saveprompt);
2269 			process_menu(MENU_yesno, NULL);
2270 			return (yesno);
2271 		}
2272 	return 0;
2273 }
2274 
2275 /* Write all changes to disk */
2276 static int
2277 pm_commit(menudesc *m, void *arg)
2278 {
2279 	int retcode;
2280 	pm_devs_t *pm_i;
2281 	if (m != NULL && arg != NULL)
2282 		((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
2283 
2284 	pm_gpt_commit();
2285 
2286 	SLIST_FOREACH(pm_i, &pm_head, l) {
2287 		if (! pm_i->unsaved)
2288 			continue;
2289 		pm_select(pm_i);
2290 
2291 		if (pm_i->isspecial) {
2292 			if (make_filesystems() != 0) {
2293 				if (logfp)
2294 					fprintf(logfp, "Special disk %s preparing error\n", pm_i->diskdev);
2295 				continue;
2296 			}
2297 			pm_i->unsaved = 0;
2298 		} else if (! pm_i->gpt) {
2299 #ifndef NO_DISKLABEL
2300 			savenewlabel(pm_i->bsdlabel, MAXPARTITIONS);
2301 #endif
2302 			if (
2303 				write_disklabel() != 0   || /* Write slices table (disklabel) */
2304 				md_post_disklabel() != 0 || /* Enable swap and check badblock */
2305 				make_filesystems() != 0     /* Create filesystems with newfs */
2306 			) {
2307 				/* Oops, something failed... */
2308 				if (logfp)
2309 					fprintf(logfp, "Disk %s preparing error\n", pm_i->diskdev);
2310 				continue;
2311 			}
2312 			pm_i->unsaved = 0;
2313 		}
2314 	}
2315 
2316 	/* Call all functions that may create new devices */
2317 	if ((retcode = pm_raid_commit()) != 0) {
2318 		if (logfp)
2319 			fprintf(logfp, "RAIDframe configuring error #%d\n", retcode);
2320 		return -1;
2321 	}
2322 	if ((retcode = pm_cgd_commit()) != 0) {
2323 		if (logfp)
2324 			fprintf(logfp, "CGD configuring error #%d\n", retcode);
2325 		return -1;
2326 	}
2327 	if ((retcode = pm_lvm_commit()) != 0) {
2328 		if (logfp)
2329 			fprintf(logfp, "LVM configuring error #%d\n", retcode);
2330 		return -1;
2331 	}
2332 	if ((retcode = pm_vnd_commit()) != 0) {
2333 		if (logfp)
2334 			fprintf(logfp, "VND configuring error #%d\n", retcode);
2335 		return -1;
2336 	}
2337 	if (m != NULL && arg != NULL)
2338 		pm_upddevlist(m, arg);
2339 	if (logfp)
2340 		fflush (logfp);
2341     return 0;
2342 }
2343 
2344 static int
2345 pm_savebootsector(void)
2346 {
2347 	pm_devs_t *pm_i;
2348 	SLIST_FOREACH(pm_i, &pm_head, l)
2349 		if (pm_i->bootable) {
2350 			if (! strncmp("raid", pm_i->diskdev, 4))
2351 				if (run_program(RUN_DISPLAY | RUN_PROGRESS,
2352 					"raidctl -v -A root %s", pm_i->diskdev) != 0) {
2353 					if (logfp)
2354 						fprintf(logfp, "Error writting RAID bootsector to %s\n",
2355 							pm_i->diskdev);
2356 					continue;
2357 				}
2358 			if (pm_i->gpt && ! pm_i->isspecial) {
2359 				if (pm_i->rootpart < 0 ||
2360 					run_program(RUN_DISPLAY | RUN_PROGRESS,
2361 					"gpt biosboot -i %d %s",
2362 					pm_i->rootpart + 1, pm_i->diskdev) != 0) {
2363 			 		if (logfp)
2364 						fprintf(logfp, "Error writting GPT bootsector to %s\n",
2365 							pm_i->diskdev);
2366 					continue;
2367 				}
2368 			} else {
2369 				pm_select(pm_i);
2370 			 	if (
2371 #ifndef NO_DISKLABEL
2372 				    check_partitions() == 0 ||
2373 #endif
2374 				    md_post_newfs() != 0) {
2375 		 			if (logfp)
2376 						fprintf(logfp, "Error writting bootsector to %s\n",
2377 							pm_i->diskdev);
2378 					continue;
2379 				}
2380 			}
2381 		}
2382 	return 0;
2383 }
2384 
2385 /* Function for 'Enter'-menu */
2386 static int
2387 pm_submenu(menudesc *m, void *arg)
2388 {
2389 	int part_num = -1;
2390 	pm_devs_t *pm_cur = NULL;
2391 	((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
2392 
2393 	switch (((part_entry_t *)arg)[m->cursel].type) {
2394 		case PM_DISK_T:
2395 		case PM_WEDGE_T:
2396 		case PM_PART_T:
2397 		case PM_SPEC_T:
2398 			if (((part_entry_t *)arg)[m->cursel].dev_ptr != NULL) {
2399 				pm_cur = ((part_entry_t *)arg)[m->cursel].dev_ptr;
2400 				if (pm_cur == NULL)
2401 					return -1;
2402 				if (pm_cur->blocked) {
2403 					msg_display(MSG_wannaunblock);
2404 					process_menu(MENU_noyes, NULL);
2405 					if (!yesno)
2406 						return -2;
2407 					pm_cur->blocked = 0;
2408 				}
2409 				pm_select(pm_cur);
2410 			}
2411 		default:
2412 			break;
2413 	}
2414 
2415 	switch (((part_entry_t *)arg)[m->cursel].type) {
2416 		case PM_DISK_T:
2417 			if (pm_cur != NULL && pm_cur->gpt) {
2418 				process_menu(MENU_pmgptentry, &part_num);
2419 				pm_wedges_fill(pm_cur);
2420 			} else {
2421 				process_menu(MENU_pmdiskentry, &part_num);
2422 			}
2423 			break;
2424 		case PM_WEDGE_T:
2425 		case PM_PART_T:
2426 			part_num = ((part_entry_t *)arg)[m->cursel].dev_num;
2427 			process_menu(MENU_pmpartentry, &part_num);
2428 			if (pm_cur != NULL && pm_cur->gpt)
2429 				pm_wedges_fill(pm_cur);
2430 			break;
2431 		case PM_SPEC_T:
2432 			part_num = 0;
2433 			process_menu(MENU_pmpartentry, &part_num);
2434 			break;
2435 		case PM_RAID_T:
2436 			return pm_edit(PMR_MENU_END, pm_raid_edit_menufmt,
2437 				pm_raid_set_value, pm_raid_check, pm_raid_init,
2438 				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr, 0, &raids_t_info);
2439 		case PM_VND_T:
2440 			return pm_edit(PMV_MENU_END, pm_vnd_edit_menufmt,
2441 				pm_vnd_set_value, pm_vnd_check, pm_vnd_init,
2442 				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr, 0, &vnds_t_info);
2443 		case PM_CGD_T:
2444 			return pm_cgd_edit(((part_entry_t *)arg)[m->cursel].dev_ptr,
2445 				NULL);
2446 		case PM_LVM_T:
2447 			return pm_edit(PML_MENU_END, pm_lvm_edit_menufmt,
2448 				pm_lvm_set_value, pm_lvm_check, pm_lvm_init,
2449 				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr, 0, &lvms_t_info);
2450 		case PM_LVMLV_T:
2451 			return pm_edit(PMLV_MENU_END, pm_lvmlv_edit_menufmt,
2452 				pm_lvmlv_set_value, pm_lvmlv_check, pm_lvmlv_init,
2453 				NULL, ((part_entry_t *)arg)[m->cursel].dev_ptr,
2454 				((part_entry_t *)arg)[m->cursel].dev_ptr_delta, &lv_t_info);
2455 	}
2456 	return 0;
2457 }
2458 
2459 /* Functions that generate menu entries text */
2460 static void
2461 pm_menufmt(menudesc *m, int opt, void *arg)
2462 {
2463 	const char *dev_status = "";
2464 	char buf[STRSIZE];
2465 	int part_num = ((part_entry_t *)arg)[opt].dev_num;
2466 	pm_devs_t *pm_cur = ((part_entry_t *)arg)[opt].dev_ptr;
2467 
2468 	switch (((part_entry_t *)arg)[opt].type) {
2469 		case PM_DISK_T:
2470 			if (pm_cur->blocked)
2471 				dev_status = msg_string(MSG_pmblocked);
2472 			else if (! pm_cur->unsaved)
2473 				dev_status = msg_string(MSG_pmunchanged);
2474 			else if (pm_cur->bootable)
2475 				dev_status = msg_string(MSG_pmsetboot);
2476 			else
2477 				dev_status = msg_string(MSG_pmused);
2478 			wprintw(m->mw, "%-33.32s %-22.21s %12.12s",
2479 				pm_cur->diskdev_descr,
2480 				(pm_cur->gpt) ?
2481 					msg_string(MSG_pmgptdisk) :
2482 					pm_cur->bsddiskname,
2483 				dev_status);
2484 			break;
2485 		case PM_WEDGE_T:
2486 			part_num = ((part_entry_t *)arg)[opt].wedge_num;
2487 			snprintf(buf, STRSIZE, "dk%d: %s",
2488 				part_num,
2489 				wedges[part_num].pm->bsdlabel[wedges[part_num].ptn].pi_mount);
2490 			wprintw(m->mw, "   %-30.29s %-22.21s %11uM",
2491 				buf,
2492 				(wedges[part_num].pm->bsdlabel[wedges[part_num].ptn].lvmpv) ?
2493 					"lvm pv" :
2494 					getfslabelname(wedges[part_num].pm->bsdlabel[wedges[part_num].
2495 						ptn].pi_fstype),
2496 				wedges[part_num].pm->bsdlabel[wedges[part_num].ptn].pi_size /
2497 					(MEG / pm_cur->sectorsize));
2498 			break;
2499 		case PM_PART_T:
2500 			snprintf(buf, STRSIZE, "%s%c: %s %s",
2501 				pm_cur->diskdev,
2502 				'a' + part_num,
2503 				pm_cur->bsdlabel[part_num].pi_mount,
2504 				(strlen(pm_cur->bsdlabel[part_num].mounted) > 0) ? msg_string(MSG_pmmounted) :
2505 					(part_num == PART_B ||
2506 						strlen (pm_cur->bsdlabel[part_num].pi_mount ) < 1 ||
2507 						pm_cur->bsdlabel[part_num].pi_flags & PIF_MOUNT) ?
2508 						"" : msg_string(MSG_pmunused));
2509 			wprintw(m->mw, "   %-30.29s %-22.21s %11uM",
2510 				buf,
2511 				(pm_cur->bsdlabel[part_num].lvmpv) ?
2512 					"lvm pv" :
2513 					getfslabelname(pm_cur->bsdlabel[part_num].pi_fstype),
2514 				pm_cur->bsdlabel[part_num].pi_size / (MEG / pm_cur->sectorsize));
2515 			break;
2516 		case PM_SPEC_T:
2517 			snprintf(buf, STRSIZE, "%s: %s",
2518 				pm_cur->diskdev_descr, pm_cur->bsdlabel[0].pi_mount);
2519 			wprintw(m->mw, "%-33.32s %-22.21s %11uM", buf,
2520 				getfslabelname(pm_cur->bsdlabel[0].pi_fstype),
2521 				pm_cur->bsdlabel[0].pi_size / (MEG / pm_cur->sectorsize));
2522 			break;
2523 		case PM_RAID_T:
2524 			pm_raid_menufmt(m, opt, arg);
2525 			break;
2526 		case PM_VND_T:
2527 			pm_vnd_menufmt(m, opt, arg);
2528 			break;
2529 		case PM_CGD_T:
2530 			pm_cgd_menufmt(m, opt, arg);
2531 			break;
2532 		case PM_LVM_T:
2533 			pm_lvm_menufmt(m, opt, arg);
2534 			break;
2535 		case PM_LVMLV_T:
2536 			pm_lvmlv_menufmt(m, opt, arg);
2537 			break;
2538 	}
2539 	return;
2540 }
2541 
2542 /* Submenu for RAID/LVM/CGD/VND */
2543 static void
2544 pm_upddevlist_adv(menudesc *m, void *arg, int *i,
2545 	pm_upddevlist_adv_t *d)
2546 {
2547 	int ii;
2548 	if (d->create_msg != NULL) {
2549 		/* We want to have menu entry that creates a new device */
2550 		((part_entry_t *)arg)[*i].type = d->pe_type;
2551 		((part_entry_t *)arg)[*i].dev_ptr = NULL;
2552 		((part_entry_t *)arg)[*i].dev_ptr_delta = d->s->parent_size * d->sub_num;
2553 		m->opts[(*i)++] = (struct menu_ent) {
2554 			.opt_name = d->create_msg,
2555 			.opt_action = pm_submenu,
2556 		};
2557 	}
2558 	for (ii = 0; ii < d->s->max; ii++) {
2559 		if (d->s->entry_enabled == NULL ||
2560 			d->s->entry_blocked == NULL ||
2561 			*(int*)((char*)d->s->entry_enabled + d->s->entry_size * ii +
2562 				d->s->parent_size * d->sub_num) == 0 ||
2563 			*(int*)((char*)d->s->entry_blocked + d->s->entry_size * ii +
2564 				d->s->parent_size * d->sub_num) != 0)
2565 			continue;
2566 		/* We have a entry for displaying */
2567 		changed = 1;
2568 		m->opts[*i] = (struct menu_ent) {
2569 			.opt_name = NULL,
2570 			.opt_action = pm_submenu,
2571 		};
2572 		((part_entry_t *)arg)[*i].type = d->pe_type;
2573 		((part_entry_t *)arg)[*i].dev_ptr = (char*)d->s->entry_first +
2574 			d->s->entry_size * ii + d->s->parent_size * d->sub_num;
2575 		(*i)++;
2576 		/* We should show submenu for current entry */
2577 		if (d->sub != NULL) {
2578 			d->sub->sub_num = ii;
2579 			pm_upddevlist_adv(m, arg, i, d->sub);
2580 		}
2581 	}
2582 	return;
2583 }
2584 
2585 /* Update partman main menu with devices list */
2586 static int
2587 pm_upddevlist(menudesc *m, void *arg)
2588 {
2589 	int i = 0, ii;
2590 	pm_devs_t *pm_i;
2591 
2592 	if (arg != NULL)
2593 		((part_entry_t *)arg)[0].retvalue = m->cursel + 1;
2594 
2595 	changed = 0;
2596 	/* Mark all devices as not found */
2597 	SLIST_FOREACH(pm_i, &pm_head, l)
2598 		if (pm_i->found > 0)
2599 			pm_i->found = 0;
2600 	/* Detect all present devices */
2601 	(void)find_disks("partman");
2602 	pm_lvm_find();
2603 	pm_clean();
2604 
2605 	if (m == NULL || arg == NULL)
2606 		return -1;
2607 
2608 	SLIST_FOREACH(pm_i, &pm_head, l) {
2609 		m->opts[i].opt_name = NULL;
2610 		m->opts[i].opt_action = pm_submenu;
2611 		((part_entry_t *)arg)[i].dev_ptr = pm_i;
2612 		((part_entry_t *)arg)[i].dev_num = -1;
2613 		if (pm_i->isspecial)
2614 			((part_entry_t *)arg)[i].type = PM_SPEC_T;
2615 		else {
2616 			((part_entry_t *)arg)[i].type = PM_DISK_T;
2617 			if (pm_i->gpt) {
2618 				pm_wedges_fill(pm_i);
2619 				for (ii = 0; ii < MAX_WEDGES; ii++)
2620 					if (wedges[ii].pm == pm_i) {
2621 						i++;
2622 						m->opts[i].opt_name = NULL;
2623 						m->opts[i].opt_action = pm_submenu;
2624 						((part_entry_t *)arg)[i].dev_ptr = pm_i;
2625 						((part_entry_t *)arg)[i].dev_num = wedges[ii].ptn;
2626 						((part_entry_t *)arg)[i].wedge_num = ii;
2627 						((part_entry_t *)arg)[i].type = PM_WEDGE_T;
2628 					}
2629 			} else {
2630 				for (ii = 0; ii < MAXPARTITIONS; ii++)
2631 					if (pm_i->bsdlabel[ii].pi_fstype != FS_UNUSED) {
2632 						i++;
2633 						m->opts[i].opt_name = NULL;
2634 						m->opts[i].opt_action = pm_submenu;
2635 						((part_entry_t *)arg)[i].dev_ptr = pm_i;
2636 						((part_entry_t *)arg)[i].dev_num = ii;
2637 						((part_entry_t *)arg)[i].type = PM_PART_T;
2638 					}
2639 			}
2640 		}
2641 		i++;
2642 	}
2643 	if (have_cgd) {
2644 		pm_upddevlist_adv(m, arg, &i,
2645 		    &(pm_upddevlist_adv_t) {MSG_create_cgd, PM_CGD_T, &cgds_t_info, 0, NULL});
2646 	}
2647 	if (have_lvm) {
2648 		pm_upddevlist_adv(m, arg, &i,
2649 		    &(pm_upddevlist_adv_t) {MSG_create_cnd, PM_VND_T, &vnds_t_info, 0, NULL});
2650 		pm_upddevlist_adv(m, arg, &i,
2651 		    &(pm_upddevlist_adv_t) {MSG_create_vg, PM_LVM_T, &lvms_t_info, 0,
2652 		    &(pm_upddevlist_adv_t) {MSG_create_lv, PM_LVMLV_T, &lv_t_info, 0, NULL}});
2653 	}
2654 	if (have_raid) {
2655 		pm_upddevlist_adv(m, arg, &i,
2656 		    &(pm_upddevlist_adv_t) {MSG_create_raid, PM_RAID_T, &raids_t_info, 0, NULL});
2657 	}
2658 
2659 	m->opts[i++] = (struct menu_ent) {
2660 		.opt_name = MSG_updpmlist,
2661 		.opt_action = pm_upddevlist,
2662 	};
2663 	m->opts[i  ] = (struct menu_ent) {
2664 		.opt_name = MSG_savepm,
2665 		.opt_action = pm_commit,
2666 	};
2667 	for (ii = 0; ii <= i; ii++) {
2668 		m->opts[ii].opt_menu = OPT_NOMENU;
2669 		m->opts[ii].opt_flags = OPT_EXIT;
2670 	}
2671 
2672 	if (((part_entry_t *)arg)[0].retvalue >= 0)
2673 		m->cursel = ((part_entry_t *)arg)[0].retvalue - 1;
2674 	return i;
2675 }
2676 
2677 static void
2678 pm_menuin(menudesc *m, void *arg)
2679 {
2680 	if (cursel > m->numopts)
2681 		m->cursel = m->numopts;
2682 	else if (cursel < 0)
2683 		m->cursel = 0;
2684 	else
2685 		m->cursel = cursel;
2686 }
2687 
2688 static void
2689 pm_menuout(menudesc *m, void *arg)
2690 {
2691 	cursel = m->cursel;
2692 }
2693 
2694 /* Main partman function */
2695 int
2696 partman(void)
2697 {
2698 	int menu_no, menu_num_entries;
2699 	static int firstrun = 1;
2700 	menu_ent menu_entries[MAX_ENTRIES+6];
2701 	part_entry_t args[MAX_ENTRIES];
2702 
2703 	if (firstrun) {
2704 		have_raid = binary_available("raidctl");
2705 		have_vnd = binary_available("vnconfig");
2706 		have_cgd = binary_available("cgdconfig");
2707 		have_lvm = binary_available("lvm");
2708 		have_gpt = binary_available("gpt");
2709 		have_dk = binary_available("dkctl");
2710 
2711 		if (!have_raid)
2712 			remove_raid_options();
2713 		if (!have_lvm)
2714 			remove_lvm_options();
2715 		if (!have_gpt)
2716 			remove_gpt_options();
2717 		if (!have_cgd)
2718 			remove_cgd_options();
2719 
2720 		raids_t_info = (structinfo_t) {
2721 			.max = MAX_RAID,
2722 			.entry_size = sizeof raids[0],
2723 			.entry_first = &raids[0],
2724 			.entry_enabled = &(raids[0].enabled),
2725 			.entry_blocked = &(raids[0].blocked),
2726 			.entry_node = &(raids[0].node),
2727 		};
2728 		vnds_t_info = (structinfo_t) {
2729 			.max = MAX_VND,
2730 			.entry_size = sizeof vnds[0],
2731 			.entry_first = &vnds[0],
2732 			.entry_enabled = &(vnds[0].enabled),
2733 			.entry_blocked = &(vnds[0].blocked),
2734 			.entry_node = &(vnds[0].node),
2735 		};
2736 		cgds_t_info = (structinfo_t) {
2737 			.max = MAX_CGD,
2738 			.entry_size = sizeof cgds[0],
2739 			.entry_first = &cgds[0],
2740 			.entry_enabled = &(cgds[0].enabled),
2741 			.entry_blocked = &(cgds[0].blocked),
2742 			.entry_node = &(cgds[0].node),
2743 		};
2744 		lvms_t_info = (structinfo_t) {
2745 			.max = MAX_LVM_VG,
2746 			.entry_size = sizeof lvms[0],
2747 			.entry_first = &lvms[0],
2748 			.entry_enabled = &(lvms[0].enabled),
2749 			.entry_blocked = &(lvms[0].blocked),
2750 			.entry_node = NULL,
2751 		};
2752 		lv_t_info = (structinfo_t) {
2753 			.max = MAX_LVM_LV,
2754 			.entry_size = sizeof lvms[0].lv[0],
2755 			.entry_first = &lvms[0].lv[0],
2756 			.entry_enabled = &(lvms[0].lv[0].size),
2757 			.entry_blocked = &(lvms[0].lv[0].blocked),
2758 			.parent_size = sizeof lvms[0],
2759 		};
2760 
2761 		memset(&raids, 0, sizeof raids);
2762 		memset(&cgds, 0, sizeof cgds);
2763 		memset(&vnds, 0, sizeof vnds);
2764 		memset(&lvms, 0, sizeof lvms);
2765 		cursel = 0;
2766 		changed = 0;
2767 		firstrun = 0;
2768 	}
2769 
2770 	do {
2771 		menu_num_entries = pm_upddevlist(&(menudesc){.opts = menu_entries}, args);
2772 		menu_no = new_menu(MSG_partman_header,
2773 			menu_entries, menu_num_entries+1, 1, 1, 0, 75, /* Fixed width */
2774 			MC_ALWAYS_SCROLL | MC_NOBOX | MC_NOCLEAR,
2775 			pm_menuin, pm_menufmt, pm_menuout, NULL, MSG_finishpm);
2776 		if (menu_no == -1)
2777 			args[0].retvalue = -1;
2778 		else {
2779 			args[0].retvalue = 0;
2780 			clear();
2781 			refresh();
2782 			process_menu(menu_no, &args);
2783 			free_menu(menu_no);
2784 		}
2785 
2786 		if (args[0].retvalue == 0) {
2787 			if (pm_needsave())
2788 				pm_commit(NULL, NULL);
2789 			if (pm_mountall() != 0 ||
2790 				make_fstab() != 0 ||
2791 				pm_lastcheck() != 0 ||
2792 				pm_savebootsector() != 0) {
2793 					msg_display(MSG_wannatry);
2794 					process_menu(MENU_yesno, NULL);
2795 					args[0].retvalue = (yesno) ? 1:-1;
2796 			}
2797 		}
2798 	} while (args[0].retvalue > 0);
2799 
2800 	/* retvalue <0 - error, retvalue ==0 - user quits, retvalue >0 - all ok */
2801 	return (args[0].retvalue >= 0)?0:-1;
2802 }
2803