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