1 /* $NetBSD: disks.c,v 1.44 2019/07/25 13:11:15 martin Exp $ */ 2 3 /* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 18 * or promote products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 /* disks.c -- routines to deal with finding disks and labeling disks. */ 36 37 38 #include <assert.h> 39 #include <errno.h> 40 #include <inttypes.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 #include <fcntl.h> 45 #include <fnmatch.h> 46 #include <util.h> 47 #include <uuid.h> 48 #include <paths.h> 49 50 #include <sys/param.h> 51 #include <sys/sysctl.h> 52 #include <sys/swap.h> 53 #include <sys/disklabel_gpt.h> 54 #include <ufs/ufs/dinode.h> 55 #include <ufs/ffs/fs.h> 56 57 #include <dev/scsipi/scsipi_all.h> 58 #include <sys/scsiio.h> 59 60 #include <dev/ata/atareg.h> 61 #include <sys/ataio.h> 62 63 #include "defs.h" 64 #include "md.h" 65 #include "msg_defs.h" 66 #include "menu_defs.h" 67 #include "txtwalk.h" 68 69 /* #define DEBUG_VERBOSE 1 */ 70 71 /* Disk descriptions */ 72 struct disk_desc { 73 char dd_name[SSTRSIZE]; 74 char dd_descr[256]; 75 bool dd_no_mbr, dd_no_part; 76 uint dd_cyl; 77 uint dd_head; 78 uint dd_sec; 79 uint dd_secsize; 80 daddr_t dd_totsec; 81 }; 82 83 /* Local prototypes */ 84 static int foundffs(struct data *, size_t); 85 #ifdef USE_SYSVBFS 86 static int foundsysvbfs(struct data *, size_t); 87 #endif 88 static int fsck_preen(const char *, const char *, bool silent); 89 static void fixsb(const char *, const char *); 90 91 92 static bool tmpfs_on_var_shm(void); 93 94 const char * 95 getfslabelname(uint f, uint f_version) 96 { 97 if (f == FS_TMPFS) 98 return "tmpfs"; 99 else if (f == FS_MFS) 100 return "mfs"; 101 else if (f == FS_BSDFFS && f_version > 0) 102 return f_version == 2 ? 103 msg_string(MSG_fs_type_ffsv2) : msg_string(MSG_fs_type_ffs); 104 else if (f >= __arraycount(fstypenames) || fstypenames[f] == NULL) 105 return "invalid"; 106 return fstypenames[f]; 107 } 108 109 /* 110 * Decide wether we want to mount a tmpfs on /var/shm: we do this always 111 * when the machine has more than 16 MB of user memory. On smaller machines, 112 * shm_open() and friends will not perform well anyway. 113 */ 114 static bool 115 tmpfs_on_var_shm() 116 { 117 uint64_t ram; 118 size_t len; 119 120 len = sizeof(ram); 121 if (sysctlbyname("hw.usermem64", &ram, &len, NULL, 0)) 122 return false; 123 124 return ram > 16 * MEG; 125 } 126 127 /* from src/sbin/atactl/atactl.c 128 * extract_string: copy a block of bytes out of ataparams and make 129 * a proper string out of it, truncating trailing spaces and preserving 130 * strict typing. And also, not doing unaligned accesses. 131 */ 132 static void 133 ata_extract_string(char *buf, size_t bufmax, 134 uint8_t *bytes, unsigned numbytes, 135 int needswap) 136 { 137 unsigned i; 138 size_t j; 139 unsigned char ch1, ch2; 140 141 for (i = 0, j = 0; i < numbytes; i += 2) { 142 ch1 = bytes[i]; 143 ch2 = bytes[i+1]; 144 if (needswap && j < bufmax-1) { 145 buf[j++] = ch2; 146 } 147 if (j < bufmax-1) { 148 buf[j++] = ch1; 149 } 150 if (!needswap && j < bufmax-1) { 151 buf[j++] = ch2; 152 } 153 } 154 while (j > 0 && buf[j-1] == ' ') { 155 j--; 156 } 157 buf[j] = '\0'; 158 } 159 160 /* 161 * from src/sbin/scsictl/scsi_subr.c 162 */ 163 #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377') 164 165 static void 166 scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen) 167 { 168 u_char *dst = (u_char *)sdst; 169 const u_char *src = (const u_char *)ssrc; 170 171 /* Trim leading and trailing blanks and NULs. */ 172 while (slen > 0 && STRVIS_ISWHITE(src[0])) 173 ++src, --slen; 174 while (slen > 0 && STRVIS_ISWHITE(src[slen - 1])) 175 --slen; 176 177 while (slen > 0) { 178 if (*src < 0x20 || *src >= 0x80) { 179 /* non-printable characters */ 180 dlen -= 4; 181 if (dlen < 1) 182 break; 183 *dst++ = '\\'; 184 *dst++ = ((*src & 0300) >> 6) + '0'; 185 *dst++ = ((*src & 0070) >> 3) + '0'; 186 *dst++ = ((*src & 0007) >> 0) + '0'; 187 } else if (*src == '\\') { 188 /* quote characters */ 189 dlen -= 2; 190 if (dlen < 1) 191 break; 192 *dst++ = '\\'; 193 *dst++ = '\\'; 194 } else { 195 /* normal characters */ 196 if (--dlen < 1) 197 break; 198 *dst++ = *src; 199 } 200 ++src, --slen; 201 } 202 203 *dst++ = 0; 204 } 205 206 207 static int 208 get_descr_scsi(struct disk_desc *dd) 209 { 210 struct scsipi_inquiry_data inqbuf; 211 struct scsipi_inquiry cmd; 212 scsireq_t req; 213 /* x4 in case every character is escaped, +1 for NUL. */ 214 char vendor[(sizeof(inqbuf.vendor) * 4) + 1], 215 product[(sizeof(inqbuf.product) * 4) + 1], 216 revision[(sizeof(inqbuf.revision) * 4) + 1]; 217 char size[5]; 218 219 memset(&inqbuf, 0, sizeof(inqbuf)); 220 memset(&cmd, 0, sizeof(cmd)); 221 memset(&req, 0, sizeof(req)); 222 223 cmd.opcode = INQUIRY; 224 cmd.length = sizeof(inqbuf); 225 memcpy(req.cmd, &cmd, sizeof(cmd)); 226 req.cmdlen = sizeof(cmd); 227 req.databuf = &inqbuf; 228 req.datalen = sizeof(inqbuf); 229 req.timeout = 10000; 230 req.flags = SCCMD_READ; 231 req.senselen = SENSEBUFLEN; 232 233 if (!disk_ioctl(dd->dd_name, SCIOCCOMMAND, &req) 234 || req.retsts != SCCMD_OK) 235 return 0; 236 237 scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor, 238 sizeof(inqbuf.vendor)); 239 scsi_strvis(product, sizeof(product), inqbuf.product, 240 sizeof(inqbuf.product)); 241 scsi_strvis(revision, sizeof(revision), inqbuf.revision, 242 sizeof(inqbuf.revision)); 243 244 humanize_number(size, sizeof(size), 245 (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, 246 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 247 248 snprintf(dd->dd_descr, sizeof(dd->dd_descr), 249 "%s (%s, %s %s)", 250 dd->dd_name, size, vendor, product); 251 252 return 1; 253 } 254 255 static int 256 get_descr_ata(struct disk_desc *dd) 257 { 258 struct atareq req; 259 static union { 260 unsigned char inbuf[DEV_BSIZE]; 261 struct ataparams inqbuf; 262 } inbuf; 263 struct ataparams *inqbuf = &inbuf.inqbuf; 264 char model[sizeof(inqbuf->atap_model)+1]; 265 char size[5]; 266 int needswap = 0; 267 268 memset(&inbuf, 0, sizeof(inbuf)); 269 memset(&req, 0, sizeof(req)); 270 271 req.flags = ATACMD_READ; 272 req.command = WDCC_IDENTIFY; 273 req.databuf = (void *)&inbuf; 274 req.datalen = sizeof(inbuf); 275 req.timeout = 1000; 276 277 if (!disk_ioctl(dd->dd_name, ATAIOCCOMMAND, &req) 278 || req.retsts != ATACMD_OK) 279 return 0; 280 281 #if BYTE_ORDER == LITTLE_ENDIAN 282 /* 283 * On little endian machines, we need to shuffle the string 284 * byte order. However, we don't have to do this for NEC or 285 * Mitsumi ATAPI devices 286 */ 287 288 if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC && 289 (inqbuf->atap_config & WDC_CFG_ATAPI) && 290 ((inqbuf->atap_model[0] == 'N' && 291 inqbuf->atap_model[1] == 'E') || 292 (inqbuf->atap_model[0] == 'F' && 293 inqbuf->atap_model[1] == 'X')))) { 294 needswap = 1; 295 } 296 #endif 297 298 ata_extract_string(model, sizeof(model), 299 inqbuf->atap_model, sizeof(inqbuf->atap_model), needswap); 300 humanize_number(size, sizeof(size), 301 (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, 302 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 303 304 snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)", 305 dd->dd_name, size, model); 306 307 return 1; 308 } 309 310 static void 311 get_descr(struct disk_desc *dd) 312 { 313 char size[5]; 314 dd->dd_descr[0] = '\0'; 315 316 /* try ATA */ 317 if (get_descr_ata(dd)) 318 goto done; 319 /* try SCSI */ 320 if (get_descr_scsi(dd)) 321 goto done; 322 323 /* XXX: identify for ld @ NVME or microSD */ 324 325 /* XXX: get description from raid, cgd, vnd... */ 326 done: 327 /* punt, just give some generic info */ 328 humanize_number(size, sizeof(size), 329 (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, 330 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 331 332 snprintf(dd->dd_descr, sizeof(dd->dd_descr), 333 "%s (%s)", dd->dd_name, size); 334 } 335 336 /* 337 * State for helper callback for get_default_cdrom 338 */ 339 struct default_cdrom_data { 340 char *device; 341 size_t max_len; 342 bool found; 343 }; 344 345 /* 346 * Helper function for get_default_cdrom, gets passed a device 347 * name and a void pointer to default_cdrom_data. 348 */ 349 static bool 350 get_default_cdrom_helper(void *state, const char *dev) 351 { 352 struct default_cdrom_data *data = state; 353 354 if (!is_cdrom_device(dev, false)) 355 return true; 356 357 strlcpy(data->device, dev, data->max_len); 358 strlcat(data->device, "a", data->max_len); /* default to partition a */ 359 data->found = true; 360 361 return false; /* one is enough, stop iteration */ 362 } 363 364 /* 365 * Set the argument to the name of the first CD devices actually 366 * available, leave it unmodified otherwise. 367 * Return true if a device has been found. 368 */ 369 bool 370 get_default_cdrom(char *cd, size_t max_len) 371 { 372 struct default_cdrom_data state; 373 374 state.device = cd; 375 state.max_len = max_len; 376 state.found = false; 377 378 if (enumerate_disks(&state, get_default_cdrom_helper)) 379 return state.found; 380 381 return false; 382 } 383 384 static bool 385 get_wedge_descr(struct disk_desc *dd) 386 { 387 struct dkwedge_info dkw; 388 389 if (!get_wedge_info(dd->dd_name, &dkw)) 390 return false; 391 392 snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s@%s)", 393 dkw.dkw_wname, dkw.dkw_devname, dkw.dkw_parent); 394 return true; 395 } 396 397 static bool 398 get_name_and_parent(const char *dev, char *name, char *parent) 399 { 400 struct dkwedge_info dkw; 401 402 if (!get_wedge_info(dev, &dkw)) 403 return false; 404 strcpy(name, (const char *)dkw.dkw_wname); 405 strcpy(parent, dkw.dkw_parent); 406 return true; 407 } 408 409 static bool 410 find_swap_part_on(const char *dev, char *swap_name) 411 { 412 struct dkwedge_list dkwl; 413 struct dkwedge_info *dkw; 414 u_int i; 415 bool res = false; 416 417 if (!get_wedge_list(dev, &dkwl)) 418 return false; 419 420 dkw = dkwl.dkwl_buf; 421 for (i = 0; i < dkwl.dkwl_nwedges; i++) { 422 res = strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) == 0; 423 if (res) { 424 strcpy(swap_name, (const char*)dkw[i].dkw_wname); 425 break; 426 } 427 } 428 free(dkwl.dkwl_buf); 429 430 return res; 431 } 432 433 static bool 434 is_ffs_wedge(const char *dev) 435 { 436 struct dkwedge_info dkw; 437 438 if (!get_wedge_info(dev, &dkw)) 439 return false; 440 441 return strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) == 0; 442 } 443 444 /* 445 * Does this device match an entry in our default CDROM device list? 446 * If looking for install targets, we also flag floopy devices. 447 */ 448 bool 449 is_cdrom_device(const char *dev, bool as_target) 450 { 451 static const char *target_devices[] = { 452 #ifdef CD_NAMES 453 CD_NAMES 454 #endif 455 #if defined(CD_NAMES) && defined(FLOPPY_NAMES) 456 , 457 #endif 458 #ifdef FLOPPY_NAMES 459 FLOPPY_NAMES 460 #endif 461 #if defined(CD_NAMES) || defined(FLOPPY_NAMES) 462 , 463 #endif 464 0 465 }; 466 static const char *src_devices[] = { 467 #ifdef CD_NAMES 468 CD_NAMES , 469 #endif 470 0 471 }; 472 473 for (const char **dev_pat = as_target ? target_devices : src_devices; 474 *dev_pat; dev_pat++) 475 if (fnmatch(*dev_pat, dev, 0) == 0) 476 return true; 477 478 return false; 479 } 480 481 /* does this device match any entry in the driver list? */ 482 static bool 483 dev_in_list(const char *dev, const char **list) 484 { 485 486 for ( ; *list; list++) { 487 488 size_t len = strlen(*list); 489 490 /* start of name matches? */ 491 if (strncmp(dev, *list, len) == 0) { 492 char *endp; 493 int e; 494 495 /* remainder of name is a decimal number? */ 496 strtou(dev+len, &endp, 10, 0, INT_MAX, &e); 497 if (endp && *endp == 0 && e == 0) 498 return true; 499 } 500 } 501 502 return false; 503 } 504 505 bool 506 is_bootable_device(const char *dev) 507 { 508 static const char *non_bootable_devs[] = { 509 "raid", /* bootcode lives outside of raid */ 510 "xbd", /* xen virtual device, can not boot from that */ 511 NULL 512 }; 513 514 return !dev_in_list(dev, non_bootable_devs); 515 } 516 517 bool 518 is_partitionable_device(const char *dev) 519 { 520 static const char *non_partitionable_devs[] = { 521 "dk", /* this is already a partitioned slice */ 522 NULL 523 }; 524 525 return !dev_in_list(dev, non_partitionable_devs); 526 } 527 528 /* 529 * Multi-purpose helper function: 530 * iterate all known disks, invoke a callback for each. 531 * Stop iteration when the callback returns false. 532 * Return true when iteration actually happend, false on error. 533 */ 534 bool 535 enumerate_disks(void *state, bool (*func)(void *state, const char *dev)) 536 { 537 static const int mib[] = { CTL_HW, HW_DISKNAMES }; 538 static const unsigned int miblen = __arraycount(mib); 539 const char *xd; 540 char *disk_names; 541 size_t len; 542 543 if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) 544 return false; 545 546 disk_names = malloc(len); 547 if (disk_names == NULL) 548 return false; 549 550 if (sysctl(mib, miblen, disk_names, &len, NULL, 0) == -1) { 551 free(disk_names); 552 return false; 553 } 554 555 for (xd = strtok(disk_names, " "); xd != NULL; xd = strtok(NULL, " ")) { 556 if (!(*func)(state, xd)) 557 break; 558 } 559 free(disk_names); 560 561 return true; 562 } 563 564 /* 565 * Helper state for get_disks 566 */ 567 struct get_disks_state { 568 int numdisks; 569 struct disk_desc *dd; 570 bool with_non_partitionable; 571 }; 572 573 /* 574 * Helper function for get_disks enumartion 575 */ 576 static bool 577 get_disks_helper(void *arg, const char *dev) 578 { 579 struct get_disks_state *state = arg; 580 struct disk_geom geo; 581 582 /* is this a CD device? */ 583 if (is_cdrom_device(dev, true)) 584 return true; 585 586 memset(state->dd, 0, sizeof(*state->dd)); 587 strlcpy(state->dd->dd_name, dev, sizeof state->dd->dd_name - 2); 588 state->dd->dd_no_mbr = !is_bootable_device(dev); 589 state->dd->dd_no_part = !is_partitionable_device(dev); 590 591 if (state->dd->dd_no_part && !state->with_non_partitionable) 592 return true; 593 594 if (!get_disk_geom(state->dd->dd_name, &geo)) { 595 if (errno == ENOENT) 596 return true; 597 if (errno != ENOTTY || !state->dd->dd_no_part) 598 /* 599 * Allow plain partitions, 600 * like already existing wedges 601 * (like dk0) if marked as 602 * non-partitioning device. 603 * For all other cases, continue 604 * with the next disk. 605 */ 606 return true; 607 if (!is_ffs_wedge(state->dd->dd_name)) 608 return true; 609 } 610 611 /* 612 * Exclude a disk mounted as root partition, 613 * in case of install-image on a USB memstick. 614 */ 615 if (is_active_rootpart(state->dd->dd_name, 616 state->dd->dd_no_part ? -1 : 0)) 617 return true; 618 619 state->dd->dd_cyl = geo.dg_ncylinders; 620 state->dd->dd_head = geo.dg_ntracks; 621 state->dd->dd_sec = geo.dg_nsectors; 622 state->dd->dd_secsize = geo.dg_secsize; 623 state->dd->dd_totsec = geo.dg_secperunit; 624 625 if (!state->dd->dd_no_part || !get_wedge_descr(state->dd)) 626 get_descr(state->dd); 627 state->dd++; 628 state->numdisks++; 629 if (state->numdisks == MAX_DISKS) 630 return false; 631 632 return true; 633 } 634 635 /* 636 * Get all disk devices that are not CDs. 637 * Optionally leave out those that can not be partitioned further. 638 */ 639 static int 640 get_disks(struct disk_desc *dd, bool with_non_partitionable) 641 { 642 struct get_disks_state state; 643 644 /* initialize */ 645 state.numdisks = 0; 646 state.dd = dd; 647 state.with_non_partitionable = with_non_partitionable; 648 649 if (enumerate_disks(&state, get_disks_helper)) 650 return state.numdisks; 651 652 return 0; 653 } 654 655 #ifdef DEBUG_VERBOSE 656 static void 657 dump_parts(const struct disk_partitions *parts) 658 { 659 fprintf(stderr, "%s partitions on %s:\n", 660 MSG_XLAT(parts->pscheme->short_name), parts->disk); 661 662 for (size_t p = 0; p < parts->num_part; p++) { 663 struct disk_part_info info; 664 665 if (parts->pscheme->get_part_info( 666 parts, p, &info)) { 667 fprintf(stderr, " #%zu: start: %" PRIu64 " " 668 "size: %" PRIu64 ", flags: %x\n", 669 p, info.start, info.size, 670 info.flags); 671 if (info.nat_type) 672 fprintf(stderr, "\ttype: %s\n", 673 info.nat_type->description); 674 } else { 675 fprintf(stderr, "failed to get info " 676 "for partition #%zu\n", p); 677 } 678 } 679 fprintf(stderr, "%" PRIu64 " sectors free, disk size %" PRIu64 680 " sectors, %zu partitions used\n", parts->free_space, 681 parts->disk_size, parts->num_part); 682 } 683 #endif 684 685 static bool 686 delete_scheme(struct pm_devs *p) 687 { 688 689 if (!ask_noyes(MSG_removepartswarn)) 690 return false; 691 692 p->parts->pscheme->free(p->parts); 693 p->parts = NULL; 694 return true; 695 } 696 697 698 static void 699 convert_copy(struct disk_partitions *old_parts, 700 struct disk_partitions *new_parts) 701 { 702 struct disk_part_info oinfo, ninfo; 703 part_id i; 704 705 for (i = 0; i < old_parts->num_part; i++) { 706 if (!old_parts->pscheme->get_part_info(old_parts, i, &oinfo)) 707 continue; 708 709 if (oinfo.flags & PTI_PSCHEME_INTERNAL) 710 continue; 711 712 if (oinfo.flags & PTI_SEC_CONTAINER) { 713 if (old_parts->pscheme->secondary_partitions) { 714 struct disk_partitions *sec_part = 715 old_parts->pscheme-> 716 secondary_partitions( 717 old_parts, oinfo.start, false); 718 if (sec_part) 719 convert_copy(sec_part, new_parts); 720 } 721 continue; 722 } 723 724 if (!new_parts->pscheme->adapt_foreign_part_info(new_parts, 725 &oinfo, &ninfo)) 726 continue; 727 new_parts->pscheme->add_partition(new_parts, &ninfo, NULL); 728 } 729 } 730 731 bool 732 convert_scheme(struct pm_devs *p, bool is_boot_drive, const char **err_msg) 733 { 734 struct disk_partitions *old_parts, *new_parts; 735 const struct disk_partitioning_scheme *new_scheme; 736 737 *err_msg = NULL; 738 739 old_parts = p->parts; 740 new_scheme = select_part_scheme(p, old_parts->pscheme, 741 false, MSG_select_other_partscheme); 742 743 if (new_scheme == NULL) 744 return false; 745 746 new_parts = new_scheme->create_new_for_disk(p->diskdev, 747 0, p->dlsize, p->dlsize, is_boot_drive); 748 if (new_parts == NULL) 749 return false; 750 751 convert_copy(old_parts, new_parts); 752 753 if (new_parts->num_part == 0) { 754 /* need to cleanup */ 755 new_parts->pscheme->free(new_parts); 756 return false; 757 } 758 759 old_parts->pscheme->free(old_parts); 760 p->parts = new_parts; 761 return true; 762 } 763 764 static struct pm_devs * 765 dummy_whole_system_pm(void) 766 { 767 static struct pm_devs whole_system = { 768 .diskdev = "/", 769 .no_mbr = true, 770 .no_part = true, 771 .cur_system = true, 772 }; 773 static bool init = false; 774 775 if (!init) { 776 strlcpy(whole_system.diskdev_descr, 777 msg_string(MSG_running_system), 778 sizeof whole_system.diskdev_descr); 779 } 780 781 return &whole_system; 782 } 783 784 int 785 find_disks(const char *doingwhat, bool allow_cur_system) 786 { 787 struct disk_desc disks[MAX_DISKS]; 788 /* need two more menu entries: current system + extended partitioning */ 789 menu_ent dsk_menu[__arraycount(disks) + 2]; 790 struct disk_desc *disk; 791 int i = 0, skipped = 0; 792 int already_found, numdisks, selected_disk = -1; 793 int menu_no; 794 struct pm_devs *pm_i, *pm_last = NULL; 795 796 memset(dsk_menu, 0, sizeof(dsk_menu)); 797 798 /* Find disks. */ 799 numdisks = get_disks(disks, partman_go <= 0); 800 801 /* need a redraw here, kernel messages hose everything */ 802 touchwin(stdscr); 803 refresh(); 804 /* Kill typeahead, it won't be what the user had in mind */ 805 fpurge(stdin); 806 807 /* 808 * partman_go: <0 - we want to see menu with extended partitioning 809 * ==0 - we want to see simple select disk menu 810 * >0 - we do not want to see any menus, just detect 811 * all disks 812 */ 813 if (partman_go <= 0) { 814 if (numdisks == 0 && !allow_cur_system) { 815 /* No disks found! */ 816 hit_enter_to_continue(MSG_nodisk, NULL); 817 /*endwin();*/ 818 return -1; 819 } else { 820 /* One or more disks found or current system allowed */ 821 i = 0; 822 if (allow_cur_system) { 823 dsk_menu[i].opt_name = MSG_running_system; 824 dsk_menu[i].opt_flags = OPT_EXIT; 825 dsk_menu[i].opt_action = set_menu_select; 826 i++; 827 } 828 for (; i < numdisks+allow_cur_system; i++) { 829 dsk_menu[i].opt_name = 830 disks[i-allow_cur_system].dd_descr; 831 dsk_menu[i].opt_flags = OPT_EXIT; 832 dsk_menu[i].opt_action = set_menu_select; 833 } 834 if (partman_go < 0) { 835 dsk_menu[i].opt_name = MSG_partman; 836 dsk_menu[i].opt_flags = OPT_EXIT; 837 dsk_menu[i].opt_action = set_menu_select; 838 i++; 839 } 840 menu_no = new_menu(MSG_Available_disks, 841 dsk_menu, i, -1, 842 4, 0, 0, MC_SCROLL, 843 NULL, NULL, NULL, NULL, NULL); 844 if (menu_no == -1) 845 return -1; 846 msg_fmt_display(MSG_ask_disk, "%s", doingwhat); 847 process_menu(menu_no, &selected_disk); 848 free_menu(menu_no); 849 if (allow_cur_system) { 850 if (selected_disk == 0) { 851 pm = dummy_whole_system_pm(); 852 return 1; 853 } else { 854 selected_disk--; 855 } 856 } 857 } 858 if (partman_go < 0 && selected_disk == numdisks) { 859 partman_go = 1; 860 return -2; 861 } else 862 partman_go = 0; 863 if (selected_disk < 0 || selected_disk >= numdisks) 864 return -1; 865 } 866 867 /* Fill pm struct with device(s) info */ 868 for (i = 0; i < numdisks; i++) { 869 if (! partman_go) 870 disk = disks + selected_disk; 871 else { 872 disk = disks + i; 873 already_found = 0; 874 SLIST_FOREACH(pm_i, &pm_head, l) { 875 pm_last = pm_i; 876 if (strcmp(pm_i->diskdev, disk->dd_name) == 0) { 877 already_found = 1; 878 break; 879 } 880 } 881 if (pm_i != NULL && already_found) { 882 /* 883 * We already added this device, but 884 * partitions might have changed 885 */ 886 if (!pm_i->found) { 887 pm_i->found = true; 888 if (pm_i->parts == NULL) { 889 pm_i->parts = 890 partitions_read_disk( 891 pm_i->diskdev, 892 disk->dd_totsec); 893 } 894 } 895 continue; 896 } 897 } 898 pm = pm_new; 899 pm->found = 1; 900 pm->ptstart = 0; 901 pm->ptsize = 0; 902 pm->bootable = 0; 903 strlcpy(pm->diskdev, disk->dd_name, sizeof pm->diskdev); 904 strlcpy(pm->diskdev_descr, disk->dd_descr, sizeof pm->diskdev_descr); 905 /* Use as a default disk if the user has the sets on a local disk */ 906 strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev); 907 908 /* 909 * Init disk size and geometry 910 */ 911 pm->sectorsize = disk->dd_secsize; 912 pm->dlcyl = disk->dd_cyl; 913 pm->dlhead = disk->dd_head; 914 pm->dlsec = disk->dd_sec; 915 pm->dlsize = disk->dd_totsec; 916 if (pm->dlsize == 0) 917 pm->dlsize = disk->dd_cyl * disk->dd_head 918 * disk->dd_sec; 919 920 pm->parts = partitions_read_disk(pm->diskdev, disk->dd_totsec); 921 922 again: 923 924 #ifdef DEBUG_VERBOSE 925 if (pm->parts) { 926 fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stderr); 927 dump_parts(pm->parts); 928 929 if (pm->parts->pscheme->secondary_partitions) { 930 const struct disk_partitions *sparts = 931 pm->parts->pscheme->secondary_partitions( 932 pm->parts, pm->ptstart, false); 933 if (sparts != NULL) 934 dump_parts(sparts); 935 } 936 } 937 #endif 938 939 pm->no_mbr = disk->dd_no_mbr; 940 pm->no_part = disk->dd_no_part; 941 if (!pm->no_part) { 942 pm->sectorsize = disk->dd_secsize; 943 pm->dlcyl = disk->dd_cyl; 944 pm->dlhead = disk->dd_head; 945 pm->dlsec = disk->dd_sec; 946 pm->dlsize = disk->dd_totsec; 947 if (pm->dlsize == 0) 948 pm->dlsize = disk->dd_cyl * disk->dd_head 949 * disk->dd_sec; 950 951 if (pm->parts && pm->parts->pscheme->size_limit != 0 952 && pm->dlsize > pm->parts->pscheme->size_limit 953 && ! partman_go) { 954 955 char size[5], limit[5]; 956 957 humanize_number(size, sizeof(size), 958 (uint64_t)pm->dlsize * 512U, 959 "", HN_AUTOSCALE, HN_B | HN_NOSPACE 960 | HN_DECIMAL); 961 962 humanize_number(limit, sizeof(limit), 963 (uint64_t)pm->parts->pscheme->size_limit 964 * 512U, 965 "", HN_AUTOSCALE, HN_B | HN_NOSPACE 966 | HN_DECIMAL); 967 968 if (logfp) 969 fprintf(logfp, 970 "disk %s: is too big (%" PRIu64 971 " blocks, %s), will be truncated\n", 972 pm->diskdev, pm->dlsize, 973 size); 974 975 msg_display_subst(MSG_toobigdisklabel, 5, 976 pm->diskdev, 977 msg_string(pm->parts->pscheme->name), 978 msg_string(pm->parts->pscheme->short_name), 979 size, limit); 980 981 int sel = -1; 982 const char *err = NULL; 983 process_menu(MENU_convertscheme, &sel); 984 if (sel == 1) { 985 if (!delete_scheme(pm)) { 986 return -1; 987 } 988 goto again; 989 } else if (sel == 2) { 990 if (!convert_scheme(pm, 991 partman_go < 0, &err)) { 992 if (err != NULL) 993 err_msg_win(err); 994 return -1; 995 } 996 goto again; 997 } else if (sel == 3) { 998 return -1; 999 } 1000 pm->dlsize = pm->parts->pscheme->size_limit; 1001 } 1002 } else { 1003 pm->sectorsize = 0; 1004 pm->dlcyl = 0; 1005 pm->dlhead = 0; 1006 pm->dlsec = 0; 1007 pm->dlsize = 0; 1008 pm->no_mbr = 1; 1009 } 1010 pm->dlcylsize = pm->dlhead * pm->dlsec; 1011 1012 if (partman_go) { 1013 pm_getrefdev(pm_new); 1014 if (SLIST_EMPTY(&pm_head) || pm_last == NULL) 1015 SLIST_INSERT_HEAD(&pm_head, pm_new, l); 1016 else 1017 SLIST_INSERT_AFTER(pm_last, pm_new, l); 1018 pm_new = malloc(sizeof (struct pm_devs)); 1019 memset(pm_new, 0, sizeof *pm_new); 1020 } else 1021 /* We are not in partman and do not want to process 1022 * all devices, exit */ 1023 break; 1024 } 1025 1026 return numdisks-skipped; 1027 } 1028 1029 static int 1030 sort_part_usage_by_mount(const void *a, const void *b) 1031 { 1032 const struct part_usage_info *pa = a, *pb = b; 1033 1034 /* sort all real partitions by mount point */ 1035 if ((pa->instflags & PUIINST_MOUNT) && 1036 (pb->instflags & PUIINST_MOUNT)) 1037 return strcmp(pa->mount, pb->mount); 1038 1039 /* real partitions go first */ 1040 if (pa->instflags & PUIINST_MOUNT) 1041 return -1; 1042 if (pb->instflags & PUIINST_MOUNT) 1043 return 1; 1044 1045 /* arbitrary order for all other partitions */ 1046 if (pa->type == PT_swap) 1047 return -1; 1048 if (pb->type == PT_swap) 1049 return 1; 1050 if (pa->type < pb->type) 1051 return -1; 1052 if (pa->type > pb->type) 1053 return 1; 1054 if (pa->cur_part_id < pb->cur_part_id) 1055 return -1; 1056 if (pa->cur_part_id > pb->cur_part_id) 1057 return 1; 1058 return (uintptr_t)a < (uintptr_t)b ? -1 : 1; 1059 } 1060 1061 int 1062 make_filesystems(struct install_partition_desc *install) 1063 { 1064 int error = 0, partno = -1; 1065 char *newfs = NULL, devdev[PATH_MAX], rdev[PATH_MAX]; 1066 size_t i; 1067 struct part_usage_info *ptn; 1068 struct disk_partitions *parts; 1069 const char *mnt_opts = NULL, *fsname = NULL; 1070 1071 if (pm->cur_system) 1072 return 1; 1073 1074 if (pm->no_part) { 1075 /* check if this target device already has a ffs */ 1076 snprintf(rdev, sizeof rdev, _PATH_DEV "/r%s", pm->diskdev); 1077 error = fsck_preen(rdev, "ffs", true); 1078 if (error) { 1079 if (!ask_noyes(MSG_No_filesystem_newfs)) 1080 return EINVAL; 1081 error = run_program(RUN_DISPLAY | RUN_PROGRESS, 1082 "/sbin/newfs -V2 -O2 %s", rdev); 1083 } 1084 1085 md_pre_mount(install, 0); 1086 1087 make_target_dir("/"); 1088 1089 snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev); 1090 error = target_mount_do("-o async", devdev, "/"); 1091 if (error) { 1092 msg_display_subst(MSG_mountfail, 2, devdev, "/"); 1093 hit_enter_to_continue(NULL, NULL); 1094 } 1095 1096 return error; 1097 } 1098 1099 /* Making new file systems and mounting them */ 1100 1101 /* sort to ensure /usr/local is mounted after /usr (etc) */ 1102 qsort(install->infos, install->num, sizeof(*install->infos), 1103 sort_part_usage_by_mount); 1104 1105 for (i = 0; i < install->num; i++) { 1106 /* 1107 * Newfs all file systems mareked as needing this. 1108 * Mount the ones that have a mountpoint in the target. 1109 */ 1110 ptn = &install->infos[i]; 1111 parts = ptn->parts; 1112 1113 if (ptn->size == 0 || parts == NULL) 1114 continue; 1115 1116 if (parts->pscheme->get_part_device(parts, ptn->cur_part_id, 1117 devdev, sizeof devdev, &partno, parent_device_only, false) 1118 && is_active_rootpart(devdev, partno)) 1119 continue; 1120 1121 if (!(ptn->instflags & PUIINST_NEWFS)) 1122 continue; 1123 1124 parts->pscheme->get_part_device(parts, ptn->cur_part_id, 1125 devdev, sizeof devdev, &partno, plain_name, true); 1126 1127 parts->pscheme->get_part_device(parts, ptn->cur_part_id, 1128 rdev, sizeof rdev, &partno, raw_dev_name, true); 1129 1130 newfs = NULL; 1131 switch (ptn->fs_type) { 1132 case FS_APPLEUFS: 1133 asprintf(&newfs, "/sbin/newfs"); 1134 mnt_opts = "-tffs -o async"; 1135 fsname = "ffs"; 1136 break; 1137 case FS_BSDFFS: 1138 asprintf(&newfs, 1139 "/sbin/newfs -V2 -O %d", 1140 ptn->fs_version == 2 ? 2 : 1); 1141 if (ptn->mountflags & PUIMNT_LOG) 1142 mnt_opts = "-tffs -o log"; 1143 else 1144 mnt_opts = "-tffs -o async"; 1145 fsname = "ffs"; 1146 break; 1147 case FS_BSDLFS: 1148 asprintf(&newfs, "/sbin/newfs_lfs"); 1149 mnt_opts = "-tlfs"; 1150 fsname = "lfs"; 1151 break; 1152 case FS_MSDOS: 1153 asprintf(&newfs, "/sbin/newfs_msdos"); 1154 mnt_opts = "-tmsdos"; 1155 fsname = "msdos"; 1156 break; 1157 #ifdef USE_SYSVBFS 1158 case FS_SYSVBFS: 1159 asprintf(&newfs, "/sbin/newfs_sysvbfs"); 1160 mnt_opts = "-tsysvbfs"; 1161 fsname = "sysvbfs"; 1162 break; 1163 #endif 1164 #ifdef USE_EXT2FS 1165 case FS_EX2FS: 1166 asprintf(&newfs, "/sbin/newfs_ext2fs"); 1167 mnt_opts = "-text2fs"; 1168 fsname = "ext2fs"; 1169 break; 1170 #endif 1171 } 1172 if ((ptn->instflags & PUIINST_NEWFS) && newfs != NULL) { 1173 if (ptn->fs_type == FS_MSDOS) { 1174 /* newfs only if mount fails */ 1175 if (run_program(RUN_SILENT | RUN_ERROR_OK, 1176 "mount -rt msdos %s /mnt2", devdev) != 0) 1177 error = run_program( 1178 RUN_DISPLAY | RUN_PROGRESS, 1179 "%s %s", 1180 newfs, rdev); 1181 else { 1182 run_program(RUN_SILENT | RUN_ERROR_OK, 1183 "umount /mnt2"); 1184 error = 0; 1185 } 1186 } else { 1187 error = run_program(RUN_DISPLAY | RUN_PROGRESS, 1188 "%s %s", newfs, rdev); 1189 } 1190 } else { 1191 /* We'd better check it isn't dirty */ 1192 error = fsck_preen(devdev, fsname, false); 1193 } 1194 free(newfs); 1195 if (error != 0) 1196 return error; 1197 1198 ptn->instflags &= ~PUIINST_NEWFS; 1199 md_pre_mount(install, i); 1200 1201 if (partman_go == 0 && (ptn->instflags & PUIINST_MOUNT) && 1202 mnt_opts != NULL) { 1203 make_target_dir(ptn->mount); 1204 error = target_mount_do(mnt_opts, devdev, 1205 ptn->mount); 1206 if (error) { 1207 msg_display_subst(MSG_mountfail, 2, devdev, 1208 ptn->mount); 1209 hit_enter_to_continue(NULL, NULL); 1210 return error; 1211 } 1212 } 1213 } 1214 return 0; 1215 } 1216 1217 int 1218 make_fstab(struct install_partition_desc *install) 1219 { 1220 FILE *f; 1221 const char *dump_dev = NULL; 1222 const char *dev; 1223 char dev_buf[PATH_MAX], swap_dev[PATH_MAX]; 1224 1225 if (pm->cur_system) 1226 return 1; 1227 1228 swap_dev[0] = 0; 1229 1230 /* Create the fstab. */ 1231 make_target_dir("/etc"); 1232 f = target_fopen("/etc/fstab", "w"); 1233 scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix()); 1234 1235 if (logfp) 1236 (void)fprintf(logfp, 1237 "Making %s/etc/fstab (%s).\n", target_prefix(), 1238 pm->diskdev); 1239 1240 if (f == NULL) { 1241 msg_display(MSG_createfstab); 1242 if (logfp) 1243 (void)fprintf(logfp, "Failed to make /etc/fstab!\n"); 1244 hit_enter_to_continue(NULL, NULL); 1245 #ifndef DEBUG 1246 return 1; 1247 #else 1248 f = stdout; 1249 #endif 1250 } 1251 1252 scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/" 1253 "fstab/ for more examples.\n"); 1254 1255 if (pm->no_part) { 1256 /* single dk? target */ 1257 char buf[200], parent[200], swap[200], *prompt; 1258 int res; 1259 1260 if (!get_name_and_parent(pm->diskdev, buf, parent)) 1261 goto done_with_disks; 1262 scripting_fprintf(f, "NAME=%s\t/\tffs\trw\t\t1 1\n", 1263 buf); 1264 if (!find_swap_part_on(parent, swap)) 1265 goto done_with_disks; 1266 const char *args[] = { parent, swap }; 1267 prompt = str_arg_subst(msg_string(MSG_Auto_add_swap_part), 1268 __arraycount(args), args); 1269 res = ask_yesno(prompt); 1270 free(prompt); 1271 if (res) 1272 scripting_fprintf(f, "NAME=%s\tnone" 1273 "\tswap\tsw,dp\t\t0 0\n", swap); 1274 goto done_with_disks; 1275 } 1276 1277 for (size_t i = 0; i < install->num; i++) { 1278 1279 const struct part_usage_info *ptn = &install->infos[i]; 1280 1281 if (ptn->type != PT_swap && 1282 (ptn->instflags & PUIINST_MOUNT) == 0) 1283 continue; 1284 1285 const char *s = ""; 1286 const char *mp = ptn->mount; 1287 const char *fstype = "ffs"; 1288 int fsck_pass = 0, dump_freq = 0; 1289 1290 if (ptn->parts->pscheme->get_part_device(ptn->parts, 1291 ptn->cur_part_id, dev_buf, sizeof dev_buf, NULL, 1292 logical_name, true)) 1293 dev = dev_buf; 1294 else 1295 dev = NULL; 1296 1297 if (!*mp) { 1298 /* 1299 * No mount point specified, comment out line and 1300 * use /mnt as a placeholder for the mount point. 1301 */ 1302 s = "# "; 1303 mp = "/mnt"; 1304 } 1305 1306 switch (ptn->fs_type) { 1307 case FS_UNUSED: 1308 continue; 1309 case FS_BSDLFS: 1310 /* If there is no LFS, just comment it out. */ 1311 if (!check_lfs_progs()) 1312 s = "# "; 1313 fstype = "lfs"; 1314 /* FALLTHROUGH */ 1315 case FS_BSDFFS: 1316 fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2; 1317 dump_freq = 1; 1318 break; 1319 case FS_MSDOS: 1320 fstype = "msdos"; 1321 break; 1322 case FS_SWAP: 1323 if (swap_dev[0] == 0) { 1324 strncpy(swap_dev, dev, sizeof swap_dev); 1325 dump_dev = ",dp"; 1326 } else { 1327 dump_dev = ""; 1328 } 1329 scripting_fprintf(f, "%s\t\tnone\tswap\tsw%s\t\t 0 0\n", 1330 dev, dump_dev); 1331 continue; 1332 #ifdef USE_SYSVBFS 1333 case FS_SYSVBFS: 1334 fstype = "sysvbfs"; 1335 make_target_dir("/stand"); 1336 break; 1337 #endif 1338 default: 1339 fstype = "???"; 1340 s = "# "; 1341 break; 1342 } 1343 /* The code that remounts root rw doesn't check the partition */ 1344 if (strcmp(mp, "/") == 0 && 1345 (ptn->instflags & PUIINST_MOUNT) == 0) 1346 s = "# "; 1347 1348 scripting_fprintf(f, 1349 "%s%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n", 1350 s, dev, mp, fstype, 1351 ptn->mountflags & PUIMNT_LOG ? ",log" : "", 1352 ptn->mountflags & PUIMNT_NOAUTO ? "" : ",noauto", 1353 ptn->mountflags & PUIMNT_ASYNC ? ",async" : "", 1354 ptn->mountflags & PUIMNT_NOATIME ? ",noatime" : "", 1355 ptn->mountflags & PUIMNT_NODEV ? ",nodev" : "", 1356 ptn->mountflags & PUIMNT_NODEVMTIME ? ",nodevmtime" : "", 1357 ptn->mountflags & PUIMNT_NOEXEC ? ",noexec" : "", 1358 ptn->mountflags & PUIMNT_NOSUID ? ",nosuid" : "", 1359 dump_freq, fsck_pass); 1360 } 1361 1362 done_with_disks: 1363 if (tmp_ramdisk_size > 0) { 1364 #ifdef HAVE_TMPFS 1365 scripting_fprintf(f, "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,-s=%" 1366 PRIu64 "\n", 1367 tmp_ramdisk_size * 512); 1368 #else 1369 if (swap_dev[0] != 0) 1370 scripting_fprintf(f, "%s\t\t/tmp\tmfs\trw,-s=%" 1371 PRIu64 "\n", swap_dev, tmp_ramdisk_size); 1372 else 1373 scripting_fprintf(f, "swap\t\t/tmp\tmfs\trw,-s=%" 1374 PRIu64 "\n", tmp_ramdisk_size); 1375 #endif 1376 } 1377 1378 if (cdrom_dev[0] == 0) 1379 get_default_cdrom(cdrom_dev, sizeof(cdrom_dev)); 1380 1381 /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */ 1382 scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n"); 1383 scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n"); 1384 scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n"); 1385 scripting_fprintf(f, "/dev/%s\t\t/cdrom\tcd9660\tro,noauto\n", 1386 cdrom_dev); 1387 scripting_fprintf(f, "%stmpfs\t\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n", 1388 tmpfs_on_var_shm() ? "" : "#"); 1389 make_target_dir("/kern"); 1390 make_target_dir("/proc"); 1391 make_target_dir("/dev/pts"); 1392 make_target_dir("/cdrom"); 1393 make_target_dir("/var/shm"); 1394 1395 scripting_fprintf(NULL, "EOF\n"); 1396 1397 fclose(f); 1398 fflush(NULL); 1399 return 0; 1400 } 1401 1402 1403 1404 static int 1405 /*ARGSUSED*/ 1406 foundffs(struct data *list, size_t num) 1407 { 1408 int error; 1409 1410 if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 || 1411 strstr(list[2].u.s_val, "noauto") != NULL) 1412 return 0; 1413 1414 error = fsck_preen(list[0].u.s_val, "ffs", false); 1415 if (error != 0) 1416 return error; 1417 1418 error = target_mount("", list[0].u.s_val, list[1].u.s_val); 1419 if (error != 0) { 1420 msg_fmt_display(MSG_mount_failed, "%s", list[0].u.s_val); 1421 if (!ask_noyes(NULL)) 1422 return error; 1423 } 1424 return 0; 1425 } 1426 1427 #ifdef USE_SYSVBFS 1428 static int 1429 /*ARGSUSED*/ 1430 foundsysvbfs(struct data *list, size_t num) 1431 { 1432 int error; 1433 1434 if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 || 1435 strstr(list[2].u.s_val, "noauto") != NULL) 1436 return 0; 1437 1438 error = target_mount("", list[0].u.s_val, list[1].u.s_val); 1439 if (error != 0) 1440 return error; 1441 return 0; 1442 } 1443 #endif 1444 1445 /* 1446 * Do an fsck. On failure, inform the user by showing a warning 1447 * message and doing menu_ok() before proceeding. 1448 * The device passed should be the full qualified path to raw disk 1449 * (e.g. /dev/rwd0a). 1450 * Returns 0 on success, or nonzero return code from fsck() on failure. 1451 */ 1452 static int 1453 fsck_preen(const char *disk, const char *fsname, bool silent) 1454 { 1455 char *prog, err[12]; 1456 int error; 1457 1458 if (fsname == NULL) 1459 return 0; 1460 /* first, check if fsck program exists, if not, assume ok */ 1461 asprintf(&prog, "/sbin/fsck_%s", fsname); 1462 if (prog == NULL) 1463 return 0; 1464 if (access(prog, X_OK) != 0) { 1465 free(prog); 1466 return 0; 1467 } 1468 if (!strcmp(fsname,"ffs")) 1469 fixsb(prog, disk); 1470 error = run_program(silent? RUN_SILENT|RUN_ERROR_OK : 0, "%s -p -q %s", prog, disk); 1471 free(prog); 1472 if (error != 0 && !silent) { 1473 sprintf(err, "%d", error); 1474 msg_display_subst(msg_string(MSG_badfs), 3, 1475 disk, fsname, err); 1476 if (ask_noyes(NULL)) 1477 error = 0; 1478 /* XXX at this point maybe we should run a full fsck? */ 1479 } 1480 return error; 1481 } 1482 1483 /* This performs the same function as the etc/rc.d/fixsb script 1484 * which attempts to correct problems with ffs1 filesystems 1485 * which may have been introduced by booting a netbsd-current kernel 1486 * from between April of 2003 and January 2004. For more information 1487 * This script was developed as a response to NetBSD pr install/25138 1488 * Additional prs regarding the original issue include: 1489 * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926 1490 */ 1491 static void 1492 fixsb(const char *prog, const char *disk) 1493 { 1494 int fd; 1495 int rval; 1496 union { 1497 struct fs fs; 1498 char buf[SBLOCKSIZE]; 1499 } sblk; 1500 struct fs *fs = &sblk.fs; 1501 1502 fd = open(disk, O_RDONLY); 1503 if (fd == -1) 1504 return; 1505 1506 /* Read ffsv1 main superblock */ 1507 rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1); 1508 close(fd); 1509 if (rval != sizeof sblk.buf) 1510 return; 1511 1512 if (fs->fs_magic != FS_UFS1_MAGIC && 1513 fs->fs_magic != FS_UFS1_MAGIC_SWAPPED) 1514 /* Not FFSv1 */ 1515 return; 1516 if (fs->fs_old_flags & FS_FLAGS_UPDATED) 1517 /* properly updated fslevel 4 */ 1518 return; 1519 if (fs->fs_bsize != fs->fs_maxbsize) 1520 /* not messed up */ 1521 return; 1522 1523 /* 1524 * OK we have a munged fs, first 'upgrade' to fslevel 4, 1525 * We specify -b16 in order to stop fsck bleating that the 1526 * sb doesn't match the first alternate. 1527 */ 1528 run_program(RUN_DISPLAY | RUN_PROGRESS, 1529 "%s -p -b 16 -c 4 %s", prog, disk); 1530 /* Then downgrade to fslevel 3 */ 1531 run_program(RUN_DISPLAY | RUN_PROGRESS, 1532 "%s -p -c 3 %s", prog, disk); 1533 } 1534 1535 /* 1536 * fsck and mount the root partition. 1537 * devdev is the fully qualified block device name. 1538 */ 1539 static int 1540 mount_root(const char *devdev, struct install_partition_desc *install) 1541 { 1542 int error; 1543 1544 error = fsck_preen(devdev, "ffs", false); 1545 if (error != 0) 1546 return error; 1547 1548 md_pre_mount(install, 0); 1549 1550 /* Mount devdev on target's "". 1551 * If we pass "" as mount-on, Prefixing will DTRT. 1552 * for now, use no options. 1553 * XXX consider -o remount in case target root is 1554 * current root, still readonly from single-user? 1555 */ 1556 return target_mount("", devdev, ""); 1557 } 1558 1559 /* Get information on the file systems mounted from the root filesystem. 1560 * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD 1561 * inodes. Fsck them. Mount them. 1562 */ 1563 1564 int 1565 mount_disks(struct install_partition_desc *install) 1566 { 1567 char *fstab; 1568 int fstabsize; 1569 int error; 1570 char devdev[PATH_MAX]; 1571 size_t i; 1572 1573 if (install->cur_system) 1574 return 0; 1575 1576 static struct lookfor fstabbuf[] = { 1577 {"/dev/", "/dev/%s %s ffs %s", "c", NULL, 0, 0, foundffs}, 1578 {"/dev/", "/dev/%s %s ufs %s", "c", NULL, 0, 0, foundffs}, 1579 #ifdef USE_SYSVBFS 1580 {"/dev/", "/dev/%s %s sysvbfs %s", "c", NULL, 0, 0, 1581 foundsysvbfs}, 1582 #endif 1583 }; 1584 static size_t numfstabbuf = sizeof(fstabbuf) / sizeof(struct lookfor); 1585 1586 /* First the root device. */ 1587 if (target_already_root()) 1588 /* avoid needing to call target_already_root() again */ 1589 targetroot_mnt[0] = 0; 1590 else { 1591 for (i = 0; i < install->num; i++) { 1592 if (is_root_part_mount(install->infos[i].mount)) 1593 break; 1594 } 1595 1596 if (i >= install->num) { 1597 hit_enter_to_continue(MSG_noroot, NULL); 1598 return -1; 1599 } 1600 1601 if (!install->infos[i].parts->pscheme->get_part_device( 1602 install->infos[i].parts, install->infos[i].cur_part_id, 1603 devdev, sizeof devdev, NULL, plain_name, true)) 1604 return -1; 1605 error = mount_root(devdev, install); 1606 if (error != 0 && error != EBUSY) 1607 return -1; 1608 } 1609 1610 /* Check the target /etc/fstab exists before trying to parse it. */ 1611 if (target_dir_exists_p("/etc") == 0 || 1612 target_file_exists_p("/etc/fstab") == 0) { 1613 msg_fmt_display(MSG_noetcfstab, "%s", pm->diskdev); 1614 hit_enter_to_continue(NULL, NULL); 1615 return -1; 1616 } 1617 1618 1619 /* Get fstab entries from the target-root /etc/fstab. */ 1620 fstabsize = target_collect_file(T_FILE, &fstab, "/etc/fstab"); 1621 if (fstabsize < 0) { 1622 /* error ! */ 1623 msg_fmt_display(MSG_badetcfstab, "%s", pm->diskdev); 1624 hit_enter_to_continue(NULL, NULL); 1625 return -2; 1626 } 1627 error = walk(fstab, (size_t)fstabsize, fstabbuf, numfstabbuf); 1628 free(fstab); 1629 1630 return error; 1631 } 1632 1633 int 1634 set_swap_if_low_ram(struct install_partition_desc *install) 1635 { 1636 if (get_ramsize() <= 32) 1637 return set_swap(install); 1638 return 0; 1639 } 1640 1641 int 1642 set_swap(struct install_partition_desc *install) 1643 { 1644 size_t i; 1645 char dev_buf[PATH_MAX]; 1646 int rval; 1647 1648 for (i = 0; i < install->num; i++) { 1649 if (install->infos[i].type == PT_swap) 1650 break; 1651 } 1652 if (i >= install->num) 1653 return 0; 1654 1655 if (!install->infos[i].parts->pscheme->get_part_device( 1656 install->infos[i].parts, install->infos[i].cur_part_id, dev_buf, 1657 sizeof dev_buf, NULL, plain_name, true)) 1658 return -1; 1659 1660 rval = swapctl(SWAP_ON, dev_buf, 0); 1661 if (rval != 0) 1662 return -1; 1663 1664 return 0; 1665 } 1666 1667 int 1668 check_swap(const char *disk, int remove_swap) 1669 { 1670 struct swapent *swap; 1671 char *cp; 1672 int nswap; 1673 int l; 1674 int rval = 0; 1675 1676 nswap = swapctl(SWAP_NSWAP, 0, 0); 1677 if (nswap <= 0) 1678 return 0; 1679 1680 swap = malloc(nswap * sizeof *swap); 1681 if (swap == NULL) 1682 return -1; 1683 1684 nswap = swapctl(SWAP_STATS, swap, nswap); 1685 if (nswap < 0) 1686 goto bad_swap; 1687 1688 l = strlen(disk); 1689 while (--nswap >= 0) { 1690 /* Should we check the se_dev or se_path? */ 1691 cp = swap[nswap].se_path; 1692 if (memcmp(cp, "/dev/", 5) != 0) 1693 continue; 1694 if (memcmp(cp + 5, disk, l) != 0) 1695 continue; 1696 if (!isalpha(*(unsigned char *)(cp + 5 + l))) 1697 continue; 1698 if (cp[5 + l + 1] != 0) 1699 continue; 1700 /* ok path looks like it is for this device */ 1701 if (!remove_swap) { 1702 /* count active swap areas */ 1703 rval++; 1704 continue; 1705 } 1706 if (swapctl(SWAP_OFF, cp, 0) == -1) 1707 rval = -1; 1708 } 1709 1710 done: 1711 free(swap); 1712 return rval; 1713 1714 bad_swap: 1715 rval = -1; 1716 goto done; 1717 } 1718 1719 #ifdef HAVE_BOOTXX_xFS 1720 char * 1721 bootxx_name(struct install_partition_desc *install) 1722 { 1723 int fstype; 1724 const char *bootxxname; 1725 char *bootxx; 1726 1727 /* check we have boot code for the root partition type */ 1728 fstype = install->infos[0].fs_type; 1729 switch (fstype) { 1730 #if defined(BOOTXX_FFSV1) || defined(BOOTXX_FFSV2) 1731 case FS_BSDFFS: 1732 if (install->infos[0].fs_version == 2) { 1733 #ifdef BOOTXX_FFSV2 1734 bootxxname = BOOTXX_FFSV2; 1735 #else 1736 bootxxname = NULL; 1737 #endif 1738 } else { 1739 #ifdef BOOTXX_FFSV1 1740 bootxxname = BOOTXX_FFSV1; 1741 #else 1742 bootxxname = NULL; 1743 #endif 1744 } 1745 break; 1746 #endif 1747 #ifdef BOOTXX_LFSV2 1748 case FS_BSDLFS: 1749 bootxxname = BOOTXX_LFSV2; 1750 break; 1751 #endif 1752 default: 1753 bootxxname = NULL; 1754 break; 1755 } 1756 1757 if (bootxxname == NULL) 1758 return NULL; 1759 1760 asprintf(&bootxx, "%s/%s", BOOTXXDIR, bootxxname); 1761 return bootxx; 1762 } 1763 #endif 1764 1765 /* from dkctl.c */ 1766 static int 1767 get_dkwedges_sort(const void *a, const void *b) 1768 { 1769 const struct dkwedge_info *dkwa = a, *dkwb = b; 1770 const daddr_t oa = dkwa->dkw_offset, ob = dkwb->dkw_offset; 1771 return (oa < ob) ? -1 : (oa > ob) ? 1 : 0; 1772 } 1773 1774 int 1775 get_dkwedges(struct dkwedge_info **dkw, const char *diskdev) 1776 { 1777 struct dkwedge_list dkwl; 1778 1779 *dkw = NULL; 1780 if (!get_wedge_list(diskdev, &dkwl)) 1781 return -1; 1782 1783 if (dkwl.dkwl_nwedges > 0 && *dkw != NULL) { 1784 qsort(*dkw, dkwl.dkwl_nwedges, sizeof(**dkw), 1785 get_dkwedges_sort); 1786 } 1787 1788 return dkwl.dkwl_nwedges; 1789 } 1790