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