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