1 /* $NetBSD: label.c,v 1.2 2014/08/03 16:09:38 martin 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.2 2014/08/03 16:09:38 martin 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 * 1024 * (1024 / 512))) 237 p->pi_fsize = 512; 238 else if (p->pi_size < (1000 * 1024 * (1024 / 512))) 239 p->pi_fsize = 1024; 240 else if (p->pi_size < (128 * 1024 * 1024 * (1024 / 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 {NULL, MENU_selfskind, OPT_SUB, NULL}, 378 #define PTN_MENU_START 1 379 {NULL, OPT_NOMENU, 0, edit_fs_start}, 380 #define PTN_MENU_SIZE 2 381 {NULL, OPT_NOMENU, 0, edit_fs_size}, 382 #define PTN_MENU_END 3 383 {NULL, OPT_NOMENU, OPT_IGNORE, NULL}, /* displays 'end' */ 384 #define PTN_MENU_NEWFS 4 385 {NULL, OPT_NOMENU, 0, edit_fs_preserve}, 386 #define PTN_MENU_ISIZE 5 387 {NULL, OPT_NOMENU, 0, edit_fs_isize}, 388 #define PTN_MENU_BSIZE 6 389 {NULL, MENU_selbsize, OPT_SUB, NULL}, 390 #define PTN_MENU_FSIZE 7 391 {NULL, MENU_selfsize, OPT_SUB, NULL}, 392 #define PTN_MENU_MOUNT 8 393 {NULL, OPT_NOMENU, 0, edit_fs_mount}, 394 #define PTN_MENU_MOUNTOPT 9 395 {NULL, MENU_mountoptions, OPT_SUB, NULL}, 396 #define PTN_MENU_MOUNTPT 10 397 {NULL, OPT_NOMENU, 0, edit_fs_mountpt}, 398 {MSG_askunits, MENU_sizechoice, OPT_SUB, NULL}, 399 {MSG_restore, OPT_NOMENU, 0, edit_restore}, 400 }; 401 static int fspart_menu = -1; 402 static menu_ent all_fstypes[FSMAXTYPES]; 403 partinfo *p, p_save; 404 unsigned int i; 405 406 if (fspart_menu == -1) { 407 fspart_menu = new_menu(NULL, fs_fields, nelem(fs_fields), 408 0, -1, 0, 70, 409 MC_NOBOX | MC_NOCLEAR | MC_SCROLL, 410 set_ptn_header, set_ptn_label, NULL, 411 NULL, MSG_partition_sizes_ok); 412 } 413 414 if (all_fstype_menu == -1) { 415 for (i = 0; i < nelem(all_fstypes); i++) { 416 all_fstypes[i].opt_name = getfslabelname(i); 417 all_fstypes[i].opt_menu = OPT_NOMENU; 418 all_fstypes[i].opt_flags = 0; 419 all_fstypes[i].opt_action = set_fstype; 420 } 421 all_fstype_menu = new_menu(MSG_Select_the_type, 422 all_fstypes, nelem(all_fstypes), 423 30, 6, 10, 0, MC_SUBMENU | MC_SCROLL, 424 get_fstype, NULL, NULL, NULL, MSG_unchanged); 425 } 426 427 p = pm->bsdlabel + menu->cursel; 428 p->pi_flags &= ~PIF_RESET; 429 p_save = *p; 430 for (;;) { 431 process_menu(fspart_menu, p); 432 if (!(p->pi_flags & PIF_RESET)) 433 break; 434 *p = p_save; 435 } 436 437 return 0; 438 } 439 440 static void 441 set_ptn_header(menudesc *m, void *arg) 442 { 443 partinfo *p = arg; 444 int i; 445 int t; 446 447 msg_clear(); 448 msg_table_add(MSG_edfspart, 'a' + (p - pm->bsdlabel)); 449 450 /* Determine which of the properties can be changed */ 451 for (i = PTN_MENU_START; i <= PTN_MENU_MOUNTPT; i++) { 452 /* Default to disabled... */ 453 m->opts[i].opt_flags |= OPT_IGNORE; 454 t = p->pi_fstype; 455 if (i == PTN_MENU_END) 456 /* The 'end address' is calculated from the size */ 457 continue; 458 if (t == FS_UNUSED || (t == FS_SWAP && i > PTN_MENU_END)) { 459 /* Nothing after 'size' can be set for swap/unused */ 460 p->pi_flags &= ~(PIF_NEWFS | PIF_MOUNT); 461 p->pi_mount[0] = 0; 462 continue; 463 } 464 if (i == PTN_MENU_NEWFS && t != FS_BSDFFS && t != FS_BSDLFS 465 && t != FS_APPLEUFS) { 466 /* Can only newfs UFS and LFS filesystems */ 467 p->pi_flags &= ~PIF_NEWFS; 468 continue; 469 } 470 if (i >= PTN_MENU_ISIZE && i <= PTN_MENU_FSIZE) { 471 /* Parameters for newfs... */ 472 if (!(p->pi_flags & PIF_NEWFS)) 473 /* Not if we aren't going to run newfs */ 474 continue; 475 if (t == FS_APPLEUFS && i != PTN_MENU_ISIZE) 476 /* Can only set # inodes for appleufs */ 477 continue; 478 if (t == FS_BSDLFS && i != PTN_MENU_BSIZE) 479 /* LFS doesn't have fragments */ 480 continue; 481 } 482 /* Ok: we want this one */ 483 m->opts[i].opt_flags &= ~OPT_IGNORE; 484 } 485 } 486 487 static void 488 disp_sector_count(menudesc *m, msg fmt, uint s) 489 { 490 uint ms = MEG / pm->sectorsize; 491 492 wprintw(m->mw, msg_string(fmt), 493 s / ms, s / pm->dlcylsize, s % pm->dlcylsize ? '*' : ' ', s ); 494 } 495 496 static void 497 set_ptn_label(menudesc *m, int opt, void *arg) 498 { 499 partinfo *p = arg; 500 const char *c; 501 502 if (m->opts[opt].opt_flags & OPT_IGNORE 503 && (opt != PTN_MENU_END || p->pi_fstype == FS_UNUSED)) { 504 wprintw(m->mw, " -"); 505 return; 506 } 507 508 switch (opt) { 509 case PTN_MENU_FSKIND: 510 if (p->pi_fstype == FS_BSDFFS) 511 if (p->pi_flags & PIF_FFSv2) 512 c = "FFSv2"; 513 else 514 c = "FFSv1"; 515 else 516 c = getfslabelname(p->pi_fstype); 517 wprintw(m->mw, msg_string(MSG_fstype_fmt), c); 518 break; 519 case PTN_MENU_START: 520 disp_sector_count(m, MSG_start_fmt, p->pi_offset); 521 break; 522 case PTN_MENU_SIZE: 523 disp_sector_count(m, MSG_size_fmt, p->pi_size); 524 break; 525 case PTN_MENU_END: 526 disp_sector_count(m, MSG_end_fmt, p->pi_offset + p->pi_size); 527 break; 528 case PTN_MENU_NEWFS: 529 wprintw(m->mw, msg_string(MSG_newfs_fmt), 530 msg_string(p->pi_flags & PIF_NEWFS ? MSG_Yes : MSG_No)); 531 break; 532 case PTN_MENU_ISIZE: 533 wprintw(m->mw, msg_string(p->pi_isize > 0 ? 534 MSG_isize_fmt : MSG_isize_fmt_dflt), p->pi_isize); 535 break; 536 case PTN_MENU_BSIZE: 537 wprintw(m->mw, msg_string(MSG_bsize_fmt), 538 p->pi_fsize * p->pi_frag); 539 break; 540 case PTN_MENU_FSIZE: 541 wprintw(m->mw, msg_string(MSG_fsize_fmt), p->pi_fsize); 542 break; 543 case PTN_MENU_MOUNT: 544 wprintw(m->mw, msg_string(MSG_mount_fmt), 545 msg_string(p->pi_flags & PIF_MOUNT ? MSG_Yes : MSG_No)); 546 break; 547 case PTN_MENU_MOUNTOPT: 548 wprintw(m->mw, "%s", msg_string(MSG_mount_options_fmt)); 549 if (p->pi_flags & PIF_ASYNC) 550 wprintw(m->mw, "async "); 551 if (p->pi_flags & PIF_NOATIME) 552 wprintw(m->mw, "noatime "); 553 if (p->pi_flags & PIF_NODEV) 554 wprintw(m->mw, "nodev "); 555 if (p->pi_flags & PIF_NODEVMTIME) 556 wprintw(m->mw, "nodevmtime "); 557 if (p->pi_flags & PIF_NOEXEC) 558 wprintw(m->mw, "noexec "); 559 if (p->pi_flags & PIF_NOSUID) 560 wprintw(m->mw, "nosuid "); 561 if (p->pi_flags & PIF_LOG) 562 wprintw(m->mw, "log "); 563 break; 564 case PTN_MENU_MOUNTPT: 565 wprintw(m->mw, msg_string(MSG_mountpt_fmt), p->pi_mount); 566 break; 567 } 568 } 569 570 static int 571 show_all_unused(menudesc *m, void *arg) 572 { 573 struct ptn_menu_info *pi = arg; 574 575 pi->flags |= PIF_SHOW_UNUSED; 576 return 0; 577 } 578 579 static void 580 set_label_texts(menudesc *menu, void *arg) 581 { 582 struct ptn_menu_info *pi = arg; 583 menu_ent *m; 584 int ptn, show_unused_ptn; 585 int rawptn = getrawpartition(); 586 int maxpart = getmaxpartitions(); 587 588 msg_display(MSG_fspart); 589 msg_table_add(MSG_fspart_header, multname, multname, multname); 590 591 for (show_unused_ptn = 0, ptn = 0; ptn < maxpart; ptn++) { 592 m = &menu->opts[ptn]; 593 m->opt_menu = OPT_NOMENU; 594 m->opt_name = NULL; 595 m->opt_action = edit_ptn; 596 if (ptn == rawptn 597 #ifdef PART_BOOT 598 || ptn == PART_BOOT 599 #endif 600 || ptn == PART_C) { 601 m->opt_flags = OPT_IGNORE; 602 } else { 603 m->opt_flags = 0; 604 if (pm->bsdlabel[ptn].pi_fstype == FS_UNUSED) 605 continue; 606 } 607 show_unused_ptn = ptn + 2; 608 } 609 610 if (!(pi->flags & PIF_SHOW_UNUSED) && ptn > show_unused_ptn) { 611 ptn = show_unused_ptn; 612 m = &menu->opts[ptn]; 613 m->opt_name = MSG_show_all_unused_partitions; 614 m->opt_action = show_all_unused; 615 ptn++; 616 } 617 618 m = &menu->opts[ptn]; 619 m->opt_menu = MENU_sizechoice; 620 m->opt_flags = OPT_SUB; 621 m->opt_action = NULL; 622 m->opt_name = MSG_askunits; 623 624 menu->numopts = ptn + 1; 625 } 626 627 /* 628 * Check a disklabel. 629 * If there are overlapping active partitions, 630 * Ask the user if they want to edit the partition or give up. 631 */ 632 int 633 edit_and_check_label(partinfo *lp, int nparts, int rawpart, int bsdpart) 634 { 635 static struct menu_ent *menu; 636 static int menu_no = -1; 637 static struct ptn_menu_info pi; 638 int maxpart = getmaxpartitions(); 639 640 if (menu == NULL) { 641 menu = malloc((maxpart + 1) * sizeof *menu); 642 if (!menu) 643 return 1; 644 } 645 646 if (menu_no == -1) { 647 menu_no = new_menu(NULL, menu, maxpart + 1, 648 0, -1, maxpart + 2, 74, 649 MC_ALWAYS_SCROLL | MC_NOBOX | MC_DFLTEXIT, 650 set_label_texts, fmt_fspart, NULL, NULL, 651 MSG_partition_sizes_ok); 652 } 653 654 if (menu_no < 0) 655 return 1; 656 657 pi.flags = 0; 658 pm->current_cylsize = pm->dlcylsize; 659 660 for (;;) { 661 /* first give the user the option to edit the label... */ 662 process_menu(menu_no, &pi); 663 664 /* User thinks the label is OK. */ 665 /* check we have a single root fs */ 666 if (check_one_root(lp, nparts) == 0 && partman_go == 0) 667 msg_display(MSG_must_be_one_root); 668 else 669 /* Check for overlaps */ 670 if (checkoverlap(lp, nparts, rawpart, bsdpart) == 0) 671 return 1; 672 673 /*XXX ???*/ 674 msg_display_add(MSG_edit_partitions_again); 675 process_menu(MENU_yesno, NULL); 676 if (!yesno) 677 return(0); 678 } 679 680 /*NOTREACHED*/ 681 } 682 683 /* 684 * Read a label from disk into a sysinst label structure. 685 */ 686 int 687 incorelabel(const char *dkname, partinfo *lp) 688 { 689 struct disklabel lab; 690 int i, maxpart; 691 struct partition *pp; 692 int fd; 693 char buf[64]; 694 695 if (get_real_geom(dkname, &lab) == 0) 696 return -1; 697 698 touchwin(stdscr); 699 maxpart = getmaxpartitions(); 700 if (maxpart > MAXPARTITIONS) 701 maxpart = MAXPARTITIONS; 702 if (maxpart > lab.d_npartitions) 703 maxpart = lab.d_npartitions; 704 705 /* 706 * Historically sysinst writes the name to d_typename rather 707 * than d_diskname. Who knows why, but pull the value back here. 708 */ 709 if (lab.d_typename[0] != 0 && strcmp(lab.d_typename, "unknown") != 0) 710 strlcpy(pm->bsddiskname, lab.d_typename, sizeof pm->bsddiskname); 711 712 fd = opendisk(dkname, O_RDONLY, buf, sizeof buf, 0); 713 pp = &lab.d_partitions[0]; 714 for (i = 0; i < maxpart; lp++, pp++, i++) { 715 lp->pi_partition = *pp; 716 if (lp->pi_fstype >= FSMAXTYPES) 717 lp->pi_fstype = FS_OTHER; 718 strlcpy(lp->pi_mount, get_last_mounted(fd, pp->p_offset, lp), 719 sizeof lp->pi_mount); 720 } 721 if (fd != -1) 722 close(fd); 723 724 return 0; 725 } 726 727 /* 728 * Try to get 'last mounted on' (or equiv) from fs superblock. 729 */ 730 const char * 731 get_last_mounted(int fd, int partstart, partinfo *lp) 732 { 733 static char sblk[SBLOCKSIZE]; /* is this enough? */ 734 struct fs *SB = (struct fs *)sblk; 735 static const int sblocks[] = SBLOCKSEARCH; 736 const int *sbp; 737 char *cp; 738 const char *mnt = NULL; 739 int len; 740 741 if (fd == -1) 742 return ""; 743 744 /* Check UFS1/2 (and hence LFS) superblock */ 745 for (sbp = sblocks; mnt == NULL && *sbp != -1; sbp++) { 746 if (pread(fd, sblk, sizeof sblk, 747 partstart * (off_t)512 + *sbp) != sizeof sblk) 748 continue; 749 /* Maybe we should validate the checksum??? */ 750 switch (SB->fs_magic) { 751 case FS_UFS1_MAGIC: 752 case FS_UFS1_MAGIC_SWAPPED: 753 if (!(SB->fs_old_flags & FS_FLAGS_UPDATED)) { 754 if (*sbp == SBLOCK_UFS1) 755 mnt = (const char *)SB->fs_fsmnt; 756 } else { 757 /* Check we have the main superblock */ 758 if (SB->fs_sblockloc == *sbp) 759 mnt = (const char *)SB->fs_fsmnt; 760 } 761 continue; 762 case FS_UFS2_MAGIC: 763 case FS_UFS2_MAGIC_SWAPPED: 764 /* Check we have the main superblock */ 765 if (SB->fs_sblockloc == *sbp) { 766 mnt = (const char *)SB->fs_fsmnt; 767 if (lp != NULL) 768 lp->pi_flags |= PIF_FFSv2; 769 } 770 continue; 771 } 772 773 #if 0 /* Requires fs/ext2fs/ext2fs.h which collides badly... */ 774 if ((struct ext2fs *)sblk)->e2fs_magic == E2FS_MAGIC) { 775 mnt = ((struct ext2fs *)sblk)->e2fs_fsmnt; 776 continue; 777 } 778 #endif 779 if (*sbp != 0) 780 continue; 781 782 /* If start of partition check for other fs types */ 783 if (sblk[0x42] == 0x29 && memcmp(sblk + 0x52, "FAT", 3) == 0) { 784 /* Probably a FAT filesystem, report volume name */ 785 cp = strchr(sblk + 0x47, ' '); 786 if (cp == NULL || cp - (sblk + 0x47) > 11) 787 cp = sblk + 0x47 + 11; 788 *cp = 0; 789 return sblk + 0x47; 790 } 791 } 792 793 if (mnt == NULL) 794 return ""; 795 796 /* If sysinst mounted this last then strip prefix */ 797 len = strlen(targetroot_mnt); 798 if (memcmp(mnt, targetroot_mnt, len) == 0) { 799 if (mnt[len] == 0) 800 return "/"; 801 if (mnt[len] == '/') 802 return mnt + len; 803 } 804 return mnt; 805 #undef SB 806 } 807 808 /* Ask for a partition offset, check bounds and do the needed roundups */ 809 static uint32_t 810 getpartoff(uint32_t defpartstart) 811 { 812 char defsize[20], isize[20], maxpartc; 813 uint32_t i; 814 uint32_t localsizemult; 815 int partn; 816 const char *errmsg = "\n"; 817 818 maxpartc = 'a' + getmaxpartitions() - 1; 819 for (;;) { 820 snprintf(defsize, sizeof defsize, "%d", defpartstart/sizemult); 821 msg_prompt_win(MSG_label_offset, -1, 13, 70, 9, 822 (defpartstart > 0) ? defsize : NULL, isize, sizeof isize, 823 errmsg, maxpartc, maxpartc, multname); 824 if (strcmp(defsize, isize) == 0) 825 /* Don't do rounding if default accepted */ 826 return defpartstart; 827 if (isize[1] == '\0' && isize[0] >= 'a' && 828 isize[0] <= maxpartc) { 829 partn = isize[0] - 'a'; 830 i = pm->bsdlabel[partn].pi_size + pm->bsdlabel[partn].pi_offset; 831 localsizemult = 1; 832 } else if (atoi(isize) == -1) { 833 i = pm->ptstart; 834 localsizemult = 1; 835 } else { 836 if (atofsb(isize, &i, &localsizemult)) { 837 errmsg = msg_string(MSG_invalid_sector_number); 838 continue; 839 } 840 } 841 /* round to cylinder size if localsizemult != 1 */ 842 i = NUMSEC(i/localsizemult, localsizemult, pm->dlcylsize); 843 /* Adjust to start of slice if needed */ 844 if ((i < pm->ptstart && (pm->ptstart - i) < localsizemult) || 845 (i > pm->ptstart && (i - pm->ptstart) < localsizemult)) { 846 i = pm->ptstart; 847 } 848 if (i <= pm->dlsize) 849 break; 850 errmsg = msg_string(MSG_startoutsidedisk); 851 } 852 return i; 853 } 854 855 856 /* Ask for a partition size, check bounds and do the needed roundups */ 857 static uint32_t 858 getpartsize(uint32_t partstart, uint32_t defpartsize) 859 { 860 char dsize[20], isize[20], maxpartc; 861 const char *errmsg = "\n"; 862 uint32_t i, partend, localsizemult; 863 uint32_t fsptend = pm->ptstart + pm->ptsize; 864 int partn; 865 866 maxpartc = 'a' + getmaxpartitions() - 1; 867 for (;;) { 868 snprintf(dsize, sizeof dsize, "%d", defpartsize/sizemult); 869 msg_prompt_win(MSG_label_size, -1, 12, 70, 9, 870 (defpartsize != 0) ? dsize : 0, isize, sizeof isize, 871 errmsg, maxpartc, multname); 872 if (strcmp(isize, dsize) == 0) 873 return defpartsize; 874 if (isize[1] == '\0' && isize[0] >= 'a' && 875 isize[0] <= maxpartc) { 876 partn = isize[0] - 'a'; 877 i = pm->bsdlabel[partn].pi_offset - partstart; 878 localsizemult = 1; 879 } else if (atoi(isize) == -1) { 880 i = fsptend - partstart; 881 localsizemult = 1; 882 } else { 883 if (atofsb(isize, &i, &localsizemult)) { 884 errmsg = msg_string(MSG_invalid_sector_number); 885 continue; 886 } 887 } 888 /* 889 * partend is aligned to a cylinder if localsizemult 890 * is not 1 sector 891 */ 892 partend = NUMSEC((partstart + i) / localsizemult, 893 localsizemult, pm->dlcylsize); 894 /* Align to end-of-disk or end-of-slice if close enough */ 895 if (partend > (pm->dlsize - localsizemult) 896 && partend < (pm->dlsize + localsizemult)) 897 partend = pm->dlsize; 898 if (partend > (fsptend - localsizemult) 899 && partend < (fsptend + localsizemult)) 900 partend = fsptend; 901 /* sanity checks */ 902 if (partend > pm->dlsize) { 903 partend = pm->dlsize; 904 msg_prompt_win(MSG_endoutsidedisk, -1, 13, 70, 6, 905 NULL, isize, 1, 906 (partend - partstart) / sizemult, multname); 907 } 908 if (partend < partstart) 909 return 0; 910 return (partend - partstart); 911 } 912 /* NOTREACHED */ 913 } 914 915 /* 916 * convert a string to a number of sectors, with a possible unit 917 * 150M = 150 Megabytes 918 * 2000c = 2000 cylinders 919 * 150256s = 150256 sectors 920 * Without units, use the default (sizemult) 921 * returns the number of sectors, and the unit used (for roundups). 922 */ 923 924 static int 925 atofsb(const char *str, uint32_t *p_val, uint32_t *localsizemult) 926 { 927 int i; 928 uint32_t val; 929 930 *localsizemult = sizemult; 931 if (str[0] == '\0') { 932 return 1; 933 } 934 val = 0; 935 for (i = 0; str[i] != '\0'; i++) { 936 if (str[i] >= '0' && str[i] <= '9') { 937 val = val * 10 + str[i] - '0'; 938 continue; 939 } 940 if (str[i + 1] != '\0') { 941 /* A non-digit caracter, not at the end */ 942 return 1; 943 } 944 if (str[i] == 'G' || str[i] == 'g') { 945 val *= 1024; 946 *localsizemult = MEG / pm->sectorsize; 947 break; 948 } 949 if (str[i] == 'M' || str[i] == 'm') { 950 *localsizemult = MEG / pm->sectorsize; 951 break; 952 } 953 if (str[i] == 'c') { 954 *localsizemult = pm->dlcylsize; 955 break; 956 } 957 if (str[i] == 's') { 958 *localsizemult = 1; 959 break; 960 } 961 /* not a known unit */ 962 return 1; 963 } 964 *p_val = val * (*localsizemult); 965 return 0; 966 } 967