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