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