1 /* $NetBSD: label.c,v 1.6 2018/11/28 00:44:08 kre Exp $ */ 2 3 /* 4 * Copyright 1997 Jonathan Stone 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project by 18 * Jonathan Stone. 19 * 4. The name of Jonathan Stone may not be used to endorse 20 * or promote products derived from this software without specific prior 21 * written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY JONATHAN STONE ``AS IS'' 24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33 * THE POSSIBILITY OF SUCH DAMAGE. 34 * 35 */ 36 37 #include <sys/cdefs.h> 38 #if defined(LIBC_SCCS) && !defined(lint) 39 __RCSID("$NetBSD: label.c,v 1.6 2018/11/28 00:44:08 kre Exp $"); 40 #endif 41 42 #include <sys/types.h> 43 #include <stddef.h> 44 #include <errno.h> 45 #include <stdio.h> 46 #include <fcntl.h> 47 #include <util.h> 48 #include <unistd.h> 49 #include <sys/dkio.h> 50 #include <sys/param.h> 51 #include <ufs/ffs/fs.h> 52 53 #include "defs.h" 54 #include "msg_defs.h" 55 #include "menu_defs.h" 56 57 struct ptn_menu_info { 58 int flags; 59 #define PIF_SHOW_UNUSED 1 60 }; 61 62 /* 63 * local prototypes 64 */ 65 static int boringpart(partinfo *, int, int, int); 66 static uint32_t getpartoff(uint32_t); 67 static uint32_t getpartsize(uint32_t, uint32_t); 68 69 static int checklabel(partinfo *, int, int, int, int *, int *); 70 static int atofsb(const char *, uint32_t *, uint32_t *); 71 72 73 /* 74 * Return 1 if partition i in lp should be ignored when checking 75 * for overlapping partitions. 76 */ 77 static int 78 boringpart(partinfo *lp, int i, int rawpart, int bsdpart) 79 { 80 81 if (i == rawpart || i == bsdpart || 82 lp[i].pi_fstype == FS_UNUSED || lp[i].pi_size == 0) 83 return 1; 84 return 0; 85 } 86 87 88 89 /* 90 * Check a sysinst label structure for overlapping partitions. 91 * Returns 0 if no overlapping partition found, nonzero otherwise. 92 * Sets reference arguments ovly1 and ovly2 to the indices of 93 * overlapping partitions if any are found. 94 */ 95 static int 96 checklabel(partinfo *lp, int nparts, int rawpart, int bsdpart, 97 int *ovly1, int *ovly2) 98 { 99 int i; 100 int j; 101 102 *ovly1 = -1; 103 *ovly2 = -1; 104 105 for (i = 0; i < nparts - 1; i ++ ) { 106 partinfo *ip = &lp[i]; 107 uint32_t istart, istop; 108 109 /* skip unused or reserved partitions */ 110 if (boringpart(lp, i, rawpart, bsdpart)) 111 continue; 112 113 /* 114 * check succeeding partitions for overlap. 115 * O(n^2), but n is small (currently <= 16). 116 */ 117 istart = ip->pi_offset; 118 istop = istart + ip->pi_size; 119 120 for (j = i+1; j < nparts; j++) { 121 partinfo *jp = &lp[j]; 122 uint32_t jstart, jstop; 123 124 /* skip unused or reserved partitions */ 125 if (boringpart(lp, j, rawpart, bsdpart)) 126 continue; 127 128 jstart = jp->pi_offset; 129 jstop = jstart + jp->pi_size; 130 131 /* overlap? */ 132 if ((istart <= jstart && jstart < istop) || 133 (jstart <= istart && istart < jstop)) { 134 *ovly1 = i; 135 *ovly2 = j; 136 return (1); 137 } 138 } 139 } 140 141 return (0); 142 } 143 144 int 145 checkoverlap(partinfo *lp, int nparts, int rawpart, int bsdpart) 146 { 147 int i, j; 148 if (checklabel(lp, nparts, rawpart, bsdpart, &i, &j)) { 149 msg_display(MSG_partitions_overlap,'a'+i,'a'+j); 150 return 1; 151 } 152 return 0; 153 } 154 155 static int 156 check_one_root(partinfo *lp, int nparts) 157 { 158 int part; 159 int foundroot = 0; 160 161 for (part = 0; part < nparts; lp++, part++) { 162 #if 0 163 if (!PI_ISBSDFS(lp)) 164 continue; 165 #endif 166 if (!(lp->pi_flags & PIF_MOUNT)) 167 continue; 168 if (strcmp(lp->pi_mount, "/") != 0) 169 continue; 170 if (foundroot) 171 /* Duplicate */ 172 return 0; 173 foundroot = 1; 174 /* Save partition number, a few things need to know it */ 175 pm->rootpart = part; 176 } 177 return foundroot; 178 } 179 180 static int 181 edit_fs_start(menudesc *m, void *arg) 182 { 183 partinfo *p = arg; 184 uint32_t start, end; 185 186 start = getpartoff(p->pi_offset); 187 if (p->pi_size != 0) { 188 /* Try to keep end in the same place */ 189 end = p->pi_offset + p->pi_size; 190 if (end < start) 191 p->pi_size = 0; 192 else 193 p->pi_size = end - start; 194 } 195 p->pi_offset = start; 196 return 0; 197 } 198 199 static int 200 edit_fs_size(menudesc *m, void *arg) 201 { 202 partinfo *p = arg; 203 uint32_t size; 204 205 size = getpartsize(p->pi_offset, p->pi_size); 206 if (size == ~0u) 207 size = pm->dlsize - p->pi_offset; 208 p->pi_size = size; 209 if (size == 0) { 210 p->pi_offset = 0; 211 p->pi_fstype = FS_UNUSED; 212 } 213 return 0; 214 } 215 216 void 217 set_ptype(partinfo *p, int fstype, int flag) 218 { 219 p->pi_flags = (p->pi_flags & ~PIF_FFSv2) | flag; 220 221 if (p->pi_fstype == fstype) 222 return; 223 224 p->pi_fstype = fstype; 225 if (fstype == FS_BSDFFS || fstype == FS_BSDLFS) { 226 p->pi_frag = 8; 227 /* 228 * match newfs defaults for fragments size: 229 * fs size frag size 230 * < 20 MB 0.5 KB 231 * < 1000 MB 1 KB 232 * < 128 GB 2 KB 233 * >= 128 GB 4 KB 234 */ 235 /* note pi_size is uint32_t so we have to avoid overflow */ 236 if (p->pi_size < (20 * MEG / 512)) 237 p->pi_fsize = 512; 238 else if (p->pi_size < (1000 * MEG / 512)) 239 p->pi_fsize = 1024; 240 else if (p->pi_size < (128 * (GIG / 512))) 241 p->pi_fsize = 2048; 242 else 243 p->pi_fsize = 4096; 244 } else { 245 /* zero - fields not used */ 246 p->pi_frag = 0; 247 p->pi_fsize = 0; 248 } 249 } 250 251 void 252 set_bsize(partinfo *p, int size) 253 { 254 int frags, sz; 255 256 sz = p->pi_fsize; 257 if (sz <= 0) 258 sz = 512; 259 frags = size / sz; 260 if (frags > 8) 261 frags = 8; 262 if (frags <= 0) 263 frags = 1; 264 265 p->pi_frag = frags; 266 p->pi_fsize = size / frags; 267 } 268 269 void 270 set_fsize(partinfo *p, int fsize) 271 { 272 int bsz = p->pi_fsize * p->pi_frag; 273 int frags = bsz / fsize; 274 275 if (frags > 8) 276 frags = 8; 277 if (frags <= 0) 278 frags = 1; 279 280 p->pi_fsize = fsize; 281 p->pi_frag = frags; 282 } 283 284 static int 285 edit_fs_isize(menudesc *m, void *arg) 286 { 287 partinfo *p = arg; 288 char answer[12]; 289 290 snprintf(answer, sizeof answer, "%u", p->pi_isize); 291 msg_prompt_win(MSG_fs_isize, -1, 18, 0, 0, 292 answer, answer, sizeof answer); 293 p->pi_isize = atol(answer); 294 return 0; 295 } 296 297 298 static int 299 edit_fs_preserve(menudesc *m, void *arg) 300 { 301 partinfo *p = arg; 302 303 p->pi_flags ^= PIF_NEWFS; 304 return 0; 305 } 306 307 static int 308 edit_fs_mount(menudesc *m, void *arg) 309 { 310 partinfo *p = arg; 311 312 p->pi_flags ^= PIF_MOUNT; 313 return 0; 314 } 315 316 static int 317 edit_fs_mountpt(menudesc *m, void *arg) 318 { 319 partinfo *p = arg; 320 321 msg_prompt_win(MSG_mountpoint, -1, 18, 0, 0, 322 p->pi_mount, p->pi_mount, sizeof p->pi_mount); 323 324 if (p->pi_mount[0] == ' ' || strcmp(p->pi_mount, "none") == 0) { 325 p->pi_mount[0] = 0; 326 return 0; 327 } 328 329 if (p->pi_mount[0] != '/') { 330 memmove(p->pi_mount + 1, p->pi_mount, 331 sizeof p->pi_mount - 1); 332 p->pi_mount[sizeof p->pi_mount - 1] = 0; 333 p->pi_mount[0] = '/'; 334 } 335 336 return 0; 337 } 338 339 static int 340 edit_restore(menudesc *m, void *arg) 341 { 342 partinfo *p = arg; 343 344 p->pi_flags |= PIF_RESET; 345 return 1; 346 } 347 348 static int 349 set_fstype(menudesc *m, void *arg) 350 { 351 partinfo *p = arg; 352 353 if (m->cursel == FS_UNUSED) 354 memset(p, 0, sizeof *p); 355 else 356 p->pi_fstype = m->cursel; 357 return 1; 358 } 359 360 static void 361 get_fstype(menudesc *m, void *arg) 362 { 363 partinfo *p = arg; 364 365 m->cursel = p->pi_fstype; 366 } 367 368 static void set_ptn_header(menudesc *m, void *arg); 369 static void set_ptn_label(menudesc *m, int opt, void *arg); 370 int all_fstype_menu = -1; 371 372 int 373 edit_ptn(menudesc *menu, void *arg) 374 { 375 static menu_ent fs_fields[] = { 376 #define PTN_MENU_FSKIND 0 377 { .opt_menu=MENU_selfskind, .opt_flags=OPT_SUB }, 378 #define PTN_MENU_START 1 379 { .opt_menu=OPT_NOMENU, .opt_action=edit_fs_start }, 380 #define PTN_MENU_SIZE 2 381 { .opt_menu=OPT_NOMENU, .opt_action=edit_fs_size }, 382 #define PTN_MENU_END 3 383 { .opt_menu=OPT_NOMENU, .opt_flags=OPT_IGNORE }, /* displays 'end' */ 384 #define PTN_MENU_NEWFS 4 385 { .opt_menu=OPT_NOMENU, .opt_action=edit_fs_preserve }, 386 #define PTN_MENU_ISIZE 5 387 { .opt_menu=OPT_NOMENU, .opt_action=edit_fs_isize }, 388 #define PTN_MENU_BSIZE 6 389 { .opt_menu=MENU_selbsize, .opt_flags=OPT_SUB }, 390 #define PTN_MENU_FSIZE 7 391 { .opt_menu=MENU_selfsize, .opt_flags=OPT_SUB }, 392 #define PTN_MENU_MOUNT 8 393 { .opt_menu=OPT_NOMENU, .opt_action=edit_fs_mount }, 394 #define PTN_MENU_MOUNTOPT 9 395 { .opt_menu=MENU_mountoptions, .opt_flags=OPT_SUB }, 396 #define PTN_MENU_MOUNTPT 10 397 { .opt_menu=OPT_NOMENU, .opt_action=edit_fs_mountpt }, 398 { .opt_name=MSG_askunits, .opt_menu=MENU_sizechoice, 399 .opt_flags=OPT_SUB }, 400 { .opt_name=MSG_restore, .opt_menu=OPT_NOMENU, 401 .opt_action=edit_restore}, 402 }; 403 static int fspart_menu = -1; 404 static menu_ent all_fstypes[FSMAXTYPES]; 405 partinfo *p, p_save; 406 unsigned int i; 407 408 if (fspart_menu == -1) { 409 fspart_menu = new_menu(NULL, fs_fields, nelem(fs_fields), 410 0, -1, 0, 70, 411 MC_NOBOX | MC_NOCLEAR | MC_SCROLL, 412 set_ptn_header, set_ptn_label, NULL, 413 NULL, MSG_partition_sizes_ok); 414 } 415 416 if (all_fstype_menu == -1) { 417 for (i = 0; i < nelem(all_fstypes); i++) { 418 all_fstypes[i].opt_name = getfslabelname(i); 419 all_fstypes[i].opt_menu = OPT_NOMENU; 420 all_fstypes[i].opt_flags = 0; 421 all_fstypes[i].opt_action = set_fstype; 422 } 423 all_fstype_menu = new_menu(MSG_Select_the_type, 424 all_fstypes, nelem(all_fstypes), 425 30, 6, 10, 0, MC_SUBMENU | MC_SCROLL, 426 get_fstype, NULL, NULL, NULL, MSG_unchanged); 427 } 428 429 p = pm->bsdlabel + menu->cursel; 430 p->pi_flags &= ~PIF_RESET; 431 p_save = *p; 432 for (;;) { 433 process_menu(fspart_menu, p); 434 if (!(p->pi_flags & PIF_RESET)) 435 break; 436 *p = p_save; 437 } 438 439 return 0; 440 } 441 442 static void 443 set_ptn_header(menudesc *m, void *arg) 444 { 445 partinfo *p = arg; 446 int i; 447 int t; 448 449 msg_clear(); 450 msg_table_add(MSG_edfspart, 'a' + (p - pm->bsdlabel)); 451 452 /* Determine which of the properties can be changed */ 453 for (i = PTN_MENU_START; i <= PTN_MENU_MOUNTPT; i++) { 454 /* Default to disabled... */ 455 m->opts[i].opt_flags |= OPT_IGNORE; 456 t = p->pi_fstype; 457 if (i == PTN_MENU_END) 458 /* The 'end address' is calculated from the size */ 459 continue; 460 if (t == FS_UNUSED || (t == FS_SWAP && i > PTN_MENU_END)) { 461 /* Nothing after 'size' can be set for swap/unused */ 462 p->pi_flags &= ~(PIF_NEWFS | PIF_MOUNT); 463 p->pi_mount[0] = 0; 464 continue; 465 } 466 if (i == PTN_MENU_NEWFS && t != FS_BSDFFS && t != FS_BSDLFS 467 && t != FS_APPLEUFS) { 468 /* Can only newfs UFS and LFS filesystems */ 469 p->pi_flags &= ~PIF_NEWFS; 470 continue; 471 } 472 if (i >= PTN_MENU_ISIZE && i <= PTN_MENU_FSIZE) { 473 /* Parameters for newfs... */ 474 if (!(p->pi_flags & PIF_NEWFS)) 475 /* Not if we aren't going to run newfs */ 476 continue; 477 if (t == FS_APPLEUFS && i != PTN_MENU_ISIZE) 478 /* Can only set # inodes for appleufs */ 479 continue; 480 if (t == FS_BSDLFS && i != PTN_MENU_BSIZE) 481 /* LFS doesn't have fragments */ 482 continue; 483 } 484 /* Ok: we want this one */ 485 m->opts[i].opt_flags &= ~OPT_IGNORE; 486 } 487 } 488 489 static void 490 disp_sector_count(menudesc *m, msg fmt, uint s) 491 { 492 uint ms = MEG / pm->sectorsize; 493 494 wprintw(m->mw, msg_string(fmt), 495 s / ms, s / pm->dlcylsize, s % pm->dlcylsize ? '*' : ' ', s ); 496 } 497 498 static void 499 set_ptn_label(menudesc *m, int opt, void *arg) 500 { 501 partinfo *p = arg; 502 const char *c; 503 504 if (m->opts[opt].opt_flags & OPT_IGNORE 505 && (opt != PTN_MENU_END || p->pi_fstype == FS_UNUSED)) { 506 wprintw(m->mw, " -"); 507 return; 508 } 509 510 switch (opt) { 511 case PTN_MENU_FSKIND: 512 if (p->pi_fstype == FS_BSDFFS) 513 if (p->pi_flags & PIF_FFSv2) 514 c = "FFSv2"; 515 else 516 c = "FFSv1"; 517 else 518 c = getfslabelname(p->pi_fstype); 519 wprintw(m->mw, msg_string(MSG_fstype_fmt), c); 520 break; 521 case PTN_MENU_START: 522 disp_sector_count(m, MSG_start_fmt, p->pi_offset); 523 break; 524 case PTN_MENU_SIZE: 525 disp_sector_count(m, MSG_size_fmt, p->pi_size); 526 break; 527 case PTN_MENU_END: 528 disp_sector_count(m, MSG_end_fmt, p->pi_offset + p->pi_size); 529 break; 530 case PTN_MENU_NEWFS: 531 wprintw(m->mw, msg_string(MSG_newfs_fmt), 532 msg_string(p->pi_flags & PIF_NEWFS ? MSG_Yes : MSG_No)); 533 break; 534 case PTN_MENU_ISIZE: 535 wprintw(m->mw, msg_string(p->pi_isize > 0 ? 536 MSG_isize_fmt : MSG_isize_fmt_dflt), p->pi_isize); 537 break; 538 case PTN_MENU_BSIZE: 539 wprintw(m->mw, msg_string(MSG_bsize_fmt), 540 p->pi_fsize * p->pi_frag); 541 break; 542 case PTN_MENU_FSIZE: 543 wprintw(m->mw, msg_string(MSG_fsize_fmt), p->pi_fsize); 544 break; 545 case PTN_MENU_MOUNT: 546 wprintw(m->mw, msg_string(MSG_mount_fmt), 547 msg_string(p->pi_flags & PIF_MOUNT ? MSG_Yes : MSG_No)); 548 break; 549 case PTN_MENU_MOUNTOPT: 550 wprintw(m->mw, "%s", msg_string(MSG_mount_options_fmt)); 551 if (p->pi_flags & PIF_ASYNC) 552 wprintw(m->mw, "async "); 553 if (p->pi_flags & PIF_NOATIME) 554 wprintw(m->mw, "noatime "); 555 if (p->pi_flags & PIF_NODEV) 556 wprintw(m->mw, "nodev "); 557 if (p->pi_flags & PIF_NODEVMTIME) 558 wprintw(m->mw, "nodevmtime "); 559 if (p->pi_flags & PIF_NOEXEC) 560 wprintw(m->mw, "noexec "); 561 if (p->pi_flags & PIF_NOSUID) 562 wprintw(m->mw, "nosuid "); 563 if (p->pi_flags & PIF_LOG) 564 wprintw(m->mw, "log "); 565 break; 566 case PTN_MENU_MOUNTPT: 567 wprintw(m->mw, msg_string(MSG_mountpt_fmt), p->pi_mount); 568 break; 569 } 570 } 571 572 static int 573 show_all_unused(menudesc *m, void *arg) 574 { 575 struct ptn_menu_info *pi = arg; 576 577 pi->flags |= PIF_SHOW_UNUSED; 578 return 0; 579 } 580 581 static void 582 set_label_texts(menudesc *menu, void *arg) 583 { 584 struct ptn_menu_info *pi = arg; 585 menu_ent *m; 586 int ptn, show_unused_ptn; 587 int rawptn = getrawpartition(); 588 int maxpart = getmaxpartitions(); 589 590 msg_display(MSG_fspart); 591 msg_table_add(MSG_fspart_header, multname, multname, multname); 592 593 for (show_unused_ptn = 0, ptn = 0; ptn < maxpart; ptn++) { 594 m = &menu->opts[ptn]; 595 m->opt_menu = OPT_NOMENU; 596 m->opt_name = NULL; 597 m->opt_action = edit_ptn; 598 if (ptn == rawptn 599 #ifdef PART_BOOT 600 || ptn == PART_BOOT 601 #endif 602 || ptn == PART_C) { 603 m->opt_flags = OPT_IGNORE; 604 } else { 605 m->opt_flags = 0; 606 if (pm->bsdlabel[ptn].pi_fstype == FS_UNUSED) 607 continue; 608 } 609 show_unused_ptn = ptn + 2; 610 } 611 612 if (!(pi->flags & PIF_SHOW_UNUSED) && ptn > show_unused_ptn) { 613 ptn = show_unused_ptn; 614 m = &menu->opts[ptn]; 615 m->opt_name = MSG_show_all_unused_partitions; 616 m->opt_action = show_all_unused; 617 ptn++; 618 } 619 620 m = &menu->opts[ptn]; 621 m->opt_menu = MENU_sizechoice; 622 m->opt_flags = OPT_SUB; 623 m->opt_action = NULL; 624 m->opt_name = MSG_askunits; 625 626 menu->numopts = ptn + 1; 627 } 628 629 /* 630 * Check a disklabel. 631 * If there are overlapping active partitions, 632 * Ask the user if they want to edit the partition or give up. 633 */ 634 int 635 edit_and_check_label(partinfo *lp, int nparts, int rawpart, int bsdpart) 636 { 637 static struct menu_ent *menu; 638 static int menu_no = -1; 639 static struct ptn_menu_info pi; 640 int maxpart = getmaxpartitions(); 641 642 if (menu == NULL) { 643 menu = malloc((maxpart + 1) * sizeof *menu); 644 if (!menu) 645 return 1; 646 } 647 648 if (menu_no == -1) { 649 menu_no = new_menu(NULL, menu, maxpart + 1, 650 0, -1, maxpart + 2, 74, 651 MC_ALWAYS_SCROLL | MC_NOBOX | MC_DFLTEXIT, 652 set_label_texts, fmt_fspart, NULL, NULL, 653 MSG_partition_sizes_ok); 654 } 655 656 if (menu_no < 0) 657 return 1; 658 659 pi.flags = 0; 660 pm->current_cylsize = pm->dlcylsize; 661 662 for (;;) { 663 /* first give the user the option to edit the label... */ 664 process_menu(menu_no, &pi); 665 666 /* User thinks the label is OK. */ 667 /* check we have a single root fs */ 668 if (check_one_root(lp, nparts) == 0 && partman_go == 0) 669 msg_display(MSG_must_be_one_root); 670 else 671 /* Check for overlaps */ 672 if (checkoverlap(lp, nparts, rawpart, bsdpart) == 0) 673 return 1; 674 675 /*XXX ???*/ 676 msg_display_add(MSG_edit_partitions_again); 677 if (!ask_yesno(NULL)) 678 return(0); 679 } 680 681 /*NOTREACHED*/ 682 } 683 684 /* 685 * Read a label from disk into a sysinst label structure. 686 */ 687 int 688 incorelabel(const char *dkname, partinfo *lp) 689 { 690 struct disklabel lab; 691 int i, maxpart; 692 struct partition *pp; 693 int fd; 694 char buf[64]; 695 696 if (get_real_geom(dkname, &lab) == 0) 697 return -1; 698 699 touchwin(stdscr); 700 maxpart = getmaxpartitions(); 701 if (maxpart > MAXPARTITIONS) 702 maxpart = MAXPARTITIONS; 703 if (maxpart > lab.d_npartitions) 704 maxpart = lab.d_npartitions; 705 706 /* 707 * Historically sysinst writes the name to d_typename rather 708 * than d_diskname. Who knows why, but pull the value back here. 709 */ 710 if (lab.d_typename[0] != 0 && strcmp(lab.d_typename, "unknown") != 0) 711 strlcpy(pm->bsddiskname, lab.d_typename, sizeof pm->bsddiskname); 712 713 fd = opendisk(dkname, O_RDONLY, buf, sizeof buf, 0); 714 pp = &lab.d_partitions[0]; 715 for (i = 0; i < maxpart; lp++, pp++, i++) { 716 lp->pi_partition = *pp; 717 if (lp->pi_fstype >= FSMAXTYPES) 718 lp->pi_fstype = FS_OTHER; 719 strlcpy(lp->pi_mount, get_last_mounted(fd, pp->p_offset, lp), 720 sizeof lp->pi_mount); 721 } 722 if (fd != -1) 723 close(fd); 724 725 return 0; 726 } 727 728 /* 729 * Try to get 'last mounted on' (or equiv) from fs superblock. 730 */ 731 const char * 732 get_last_mounted(int fd, int partstart, partinfo *lp) 733 { 734 static char sblk[SBLOCKSIZE]; /* is this enough? */ 735 struct fs *SB = (struct fs *)sblk; 736 static const int sblocks[] = SBLOCKSEARCH; 737 const int *sbp; 738 char *cp; 739 const char *mnt = NULL; 740 int len; 741 742 if (fd == -1) 743 return ""; 744 745 /* Check UFS1/2 (and hence LFS) superblock */ 746 for (sbp = sblocks; mnt == NULL && *sbp != -1; sbp++) { 747 if (pread(fd, sblk, sizeof sblk, 748 partstart * (off_t)512 + *sbp) != sizeof sblk) 749 continue; 750 /* Maybe we should validate the checksum??? */ 751 switch (SB->fs_magic) { 752 case FS_UFS1_MAGIC: 753 case FS_UFS1_MAGIC_SWAPPED: 754 if (!(SB->fs_old_flags & FS_FLAGS_UPDATED)) { 755 if (*sbp == SBLOCK_UFS1) 756 mnt = (const char *)SB->fs_fsmnt; 757 } else { 758 /* Check we have the main superblock */ 759 if (SB->fs_sblockloc == *sbp) 760 mnt = (const char *)SB->fs_fsmnt; 761 } 762 continue; 763 case FS_UFS2_MAGIC: 764 case FS_UFS2_MAGIC_SWAPPED: 765 /* Check we have the main superblock */ 766 if (SB->fs_sblockloc == *sbp) { 767 mnt = (const char *)SB->fs_fsmnt; 768 if (lp != NULL) 769 lp->pi_flags |= PIF_FFSv2; 770 } 771 continue; 772 } 773 774 #if 0 /* Requires fs/ext2fs/ext2fs.h which collides badly... */ 775 if ((struct ext2fs *)sblk)->e2fs_magic == E2FS_MAGIC) { 776 mnt = ((struct ext2fs *)sblk)->e2fs_fsmnt; 777 continue; 778 } 779 #endif 780 if (*sbp != 0) 781 continue; 782 783 /* If start of partition check for other fs types */ 784 if (sblk[0x42] == 0x29 && memcmp(sblk + 0x52, "FAT", 3) == 0) { 785 /* Probably a FAT filesystem, report volume name */ 786 cp = strchr(sblk + 0x47, ' '); 787 if (cp == NULL || cp - (sblk + 0x47) > 11) 788 cp = sblk + 0x47 + 11; 789 *cp = 0; 790 return sblk + 0x47; 791 } 792 } 793 794 if (mnt == NULL) 795 return ""; 796 797 /* If sysinst mounted this last then strip prefix */ 798 len = strlen(targetroot_mnt); 799 if (memcmp(mnt, targetroot_mnt, len) == 0) { 800 if (mnt[len] == 0) 801 return "/"; 802 if (mnt[len] == '/') 803 return mnt + len; 804 } 805 return mnt; 806 #undef SB 807 } 808 809 /* Ask for a partition offset, check bounds and do the needed roundups */ 810 static uint32_t 811 getpartoff(uint32_t defpartstart) 812 { 813 char defsize[20], isize[20], maxpartc; 814 uint32_t i; 815 uint32_t localsizemult; 816 int partn; 817 const char *errmsg = "\n"; 818 819 maxpartc = 'a' + getmaxpartitions() - 1; 820 for (;;) { 821 snprintf(defsize, sizeof defsize, "%d", defpartstart/sizemult); 822 msg_prompt_win(MSG_label_offset, -1, 13, 70, 9, 823 (defpartstart > 0) ? defsize : NULL, isize, sizeof isize, 824 errmsg, maxpartc, maxpartc, multname); 825 if (strcmp(defsize, isize) == 0) 826 /* Don't do rounding if default accepted */ 827 return defpartstart; 828 if (isize[1] == '\0' && isize[0] >= 'a' && 829 isize[0] <= maxpartc) { 830 partn = isize[0] - 'a'; 831 i = pm->bsdlabel[partn].pi_size + pm->bsdlabel[partn].pi_offset; 832 localsizemult = 1; 833 } else if (atoi(isize) == -1) { 834 i = pm->ptstart; 835 localsizemult = 1; 836 } else { 837 if (atofsb(isize, &i, &localsizemult)) { 838 errmsg = msg_string(MSG_invalid_sector_number); 839 continue; 840 } 841 } 842 /* round to cylinder size if localsizemult != 1 */ 843 i = NUMSEC(i/localsizemult, localsizemult, pm->dlcylsize); 844 /* Adjust to start of slice if needed */ 845 if ((i < pm->ptstart && (pm->ptstart - i) < localsizemult) || 846 (i > pm->ptstart && (i - pm->ptstart) < localsizemult)) { 847 i = pm->ptstart; 848 } 849 if (i <= pm->dlsize) 850 break; 851 errmsg = msg_string(MSG_startoutsidedisk); 852 } 853 return i; 854 } 855 856 857 /* Ask for a partition size, check bounds and do the needed roundups */ 858 static uint32_t 859 getpartsize(uint32_t partstart, uint32_t defpartsize) 860 { 861 char dsize[20], isize[20], maxpartc; 862 const char *errmsg = "\n"; 863 uint32_t i, partend, localsizemult; 864 uint32_t fsptend = pm->ptstart + pm->ptsize; 865 int partn; 866 867 maxpartc = 'a' + getmaxpartitions() - 1; 868 for (;;) { 869 snprintf(dsize, sizeof dsize, "%d", defpartsize/sizemult); 870 msg_prompt_win(MSG_label_size, -1, 12, 70, 9, 871 (defpartsize != 0) ? dsize : 0, isize, sizeof isize, 872 errmsg, maxpartc, multname); 873 if (strcmp(isize, dsize) == 0) 874 return defpartsize; 875 if (isize[1] == '\0' && isize[0] >= 'a' && 876 isize[0] <= maxpartc) { 877 partn = isize[0] - 'a'; 878 i = pm->bsdlabel[partn].pi_offset - partstart; 879 localsizemult = 1; 880 } else if (atoi(isize) == -1) { 881 i = fsptend - partstart; 882 localsizemult = 1; 883 } else { 884 if (atofsb(isize, &i, &localsizemult)) { 885 errmsg = msg_string(MSG_invalid_sector_number); 886 continue; 887 } 888 } 889 /* 890 * partend is aligned to a cylinder if localsizemult 891 * is not 1 sector 892 */ 893 partend = NUMSEC((partstart + i) / localsizemult, 894 localsizemult, pm->dlcylsize); 895 /* Align to end-of-disk or end-of-slice if close enough */ 896 if (partend > (pm->dlsize - localsizemult) 897 && partend < (pm->dlsize + localsizemult)) 898 partend = pm->dlsize; 899 if (partend > (fsptend - localsizemult) 900 && partend < (fsptend + localsizemult)) 901 partend = fsptend; 902 /* sanity checks */ 903 if (partend > pm->dlsize) { 904 partend = pm->dlsize; 905 msg_prompt_win(MSG_endoutsidedisk, -1, 13, 70, 6, 906 NULL, isize, 1, 907 (partend - partstart) / sizemult, multname); 908 } 909 if (partend < partstart) 910 return 0; 911 return (partend - partstart); 912 } 913 /* NOTREACHED */ 914 } 915 916 /* 917 * convert a string to a number of sectors, with a possible unit 918 * 150M = 150 Megabytes 919 * 2000c = 2000 cylinders 920 * 150256s = 150256 sectors 921 * Without units, use the default (sizemult) 922 * returns the number of sectors, and the unit used (for roundups). 923 */ 924 925 static int 926 atofsb(const char *str, uint32_t *p_val, uint32_t *localsizemult) 927 { 928 int i; 929 uint32_t val; 930 931 *localsizemult = sizemult; 932 if (str[0] == '\0') { 933 return 1; 934 } 935 val = 0; 936 for (i = 0; str[i] != '\0'; i++) { 937 if (str[i] >= '0' && str[i] <= '9') { 938 val = val * 10 + str[i] - '0'; 939 continue; 940 } 941 if (str[i + 1] != '\0') { 942 /* A non-digit caracter, not at the end */ 943 return 1; 944 } 945 if (str[i] == 'G' || str[i] == 'g') { 946 val *= 1024; 947 *localsizemult = MEG / pm->sectorsize; 948 break; 949 } 950 if (str[i] == 'M' || str[i] == 'm') { 951 *localsizemult = MEG / pm->sectorsize; 952 break; 953 } 954 if (str[i] == 'c') { 955 *localsizemult = pm->dlcylsize; 956 break; 957 } 958 if (str[i] == 's') { 959 *localsizemult = 1; 960 break; 961 } 962 /* not a known unit */ 963 return 1; 964 } 965 *p_val = val * (*localsizemult); 966 return 0; 967 } 968