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