1 /* $NetBSD: disks.c,v 1.42 2019/07/24 02:38:29 msaitoh 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; 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 (!already_found && 877 strcmp(pm_i->diskdev, disk->dd_name) == 0) { 878 pm_i->found = 1; 879 break; 880 } 881 } 882 if (pm_i != NULL && pm_i->found) 883 /* We already added this device, skipping */ 884 continue; 885 } 886 pm = pm_new; 887 pm->found = 1; 888 pm->ptstart = 0; 889 pm->ptsize = 0; 890 pm->bootable = 0; 891 strlcpy(pm->diskdev, disk->dd_name, sizeof pm->diskdev); 892 strlcpy(pm->diskdev_descr, disk->dd_descr, sizeof pm->diskdev_descr); 893 /* Use as a default disk if the user has the sets on a local disk */ 894 strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev); 895 896 /* 897 * Init disk size and geometry 898 */ 899 pm->sectorsize = disk->dd_secsize; 900 pm->dlcyl = disk->dd_cyl; 901 pm->dlhead = disk->dd_head; 902 pm->dlsec = disk->dd_sec; 903 pm->dlsize = disk->dd_totsec; 904 if (pm->dlsize == 0) 905 pm->dlsize = disk->dd_cyl * disk->dd_head 906 * disk->dd_sec; 907 908 pm->parts = partitions_read_disk(pm->diskdev, disk->dd_totsec); 909 910 again: 911 912 #ifdef DEBUG_VERBOSE 913 if (pm->parts) { 914 fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stderr); 915 dump_parts(pm->parts); 916 917 if (pm->parts->pscheme->secondary_partitions) { 918 const struct disk_partitions *sparts = 919 pm->parts->pscheme->secondary_partitions( 920 pm->parts, pm->ptstart, false); 921 if (sparts != NULL) 922 dump_parts(sparts); 923 } 924 } 925 #endif 926 927 pm->no_mbr = disk->dd_no_mbr; 928 pm->no_part = disk->dd_no_part; 929 if (!pm->no_part) { 930 pm->sectorsize = disk->dd_secsize; 931 pm->dlcyl = disk->dd_cyl; 932 pm->dlhead = disk->dd_head; 933 pm->dlsec = disk->dd_sec; 934 pm->dlsize = disk->dd_totsec; 935 if (pm->dlsize == 0) 936 pm->dlsize = disk->dd_cyl * disk->dd_head 937 * disk->dd_sec; 938 939 if (pm->parts && pm->parts->pscheme->size_limit != 0 940 && pm->dlsize > pm->parts->pscheme->size_limit 941 && ! partman_go) { 942 943 char size[5], limit[5]; 944 945 humanize_number(size, sizeof(size), 946 (uint64_t)pm->dlsize * 512U, 947 "", HN_AUTOSCALE, HN_B | HN_NOSPACE 948 | HN_DECIMAL); 949 950 humanize_number(limit, sizeof(limit), 951 (uint64_t)pm->parts->pscheme->size_limit 952 * 512U, 953 "", HN_AUTOSCALE, HN_B | HN_NOSPACE 954 | HN_DECIMAL); 955 956 if (logfp) 957 fprintf(logfp, 958 "disk %s: is too big (%" PRIu64 959 " blocks, %s), will be truncated\n", 960 pm->diskdev, pm->dlsize, 961 size); 962 963 msg_display_subst(MSG_toobigdisklabel, 5, 964 pm->diskdev, 965 msg_string(pm->parts->pscheme->name), 966 msg_string(pm->parts->pscheme->short_name), 967 size, limit); 968 969 int sel = -1; 970 const char *err = NULL; 971 process_menu(MENU_convertscheme, &sel); 972 if (sel == 1) { 973 if (!delete_scheme(pm)) { 974 return -1; 975 } 976 goto again; 977 } else if (sel == 2) { 978 if (!convert_scheme(pm, 979 partman_go < 0, &err)) { 980 if (err != NULL) 981 err_msg_win(err); 982 return -1; 983 } 984 goto again; 985 } else if (sel == 3) { 986 return -1; 987 } 988 pm->dlsize = pm->parts->pscheme->size_limit; 989 } 990 } else { 991 pm->sectorsize = 0; 992 pm->dlcyl = 0; 993 pm->dlhead = 0; 994 pm->dlsec = 0; 995 pm->dlsize = 0; 996 pm->no_mbr = 1; 997 } 998 pm->dlcylsize = pm->dlhead * pm->dlsec; 999 1000 if (partman_go) { 1001 pm_getrefdev(pm_new); 1002 if (SLIST_EMPTY(&pm_head) || pm_last == NULL) 1003 SLIST_INSERT_HEAD(&pm_head, pm_new, l); 1004 else 1005 SLIST_INSERT_AFTER(pm_last, pm_new, l); 1006 pm_new = malloc(sizeof (struct pm_devs)); 1007 memset(pm_new, 0, sizeof *pm_new); 1008 } else 1009 /* We are not in partman and do not want to process 1010 * all devices, exit */ 1011 break; 1012 } 1013 1014 return numdisks-skipped; 1015 } 1016 1017 static int 1018 sort_part_usage_by_mount(const void *a, const void *b) 1019 { 1020 const struct part_usage_info *pa = a, *pb = b; 1021 1022 /* sort all real partitions by mount point */ 1023 if ((pa->instflags & PUIINST_MOUNT) && 1024 (pb->instflags & PUIINST_MOUNT)) 1025 return strcmp(pa->mount, pb->mount); 1026 1027 /* real partitions go first */ 1028 if (pa->instflags & PUIINST_MOUNT) 1029 return -1; 1030 if (pb->instflags & PUIINST_MOUNT) 1031 return 1; 1032 1033 /* arbitrary order for all other partitions */ 1034 if (pa->type == PT_swap) 1035 return -1; 1036 if (pb->type == PT_swap) 1037 return 1; 1038 if (pa->type < pb->type) 1039 return -1; 1040 if (pa->type > pb->type) 1041 return 1; 1042 if (pa->cur_part_id < pb->cur_part_id) 1043 return -1; 1044 if (pa->cur_part_id > pb->cur_part_id) 1045 return 1; 1046 return (uintptr_t)a < (uintptr_t)b ? -1 : 1; 1047 } 1048 1049 int 1050 make_filesystems(struct install_partition_desc *install) 1051 { 1052 int error = 0, partno = -1; 1053 char *newfs = NULL, devdev[PATH_MAX], rdev[PATH_MAX]; 1054 size_t i; 1055 struct part_usage_info *ptn; 1056 struct disk_partitions *parts; 1057 const char *mnt_opts = NULL, *fsname = NULL; 1058 1059 if (pm->cur_system) 1060 return 1; 1061 1062 if (pm->no_part) { 1063 /* check if this target device already has a ffs */ 1064 snprintf(rdev, sizeof rdev, _PATH_DEV "/r%s", pm->diskdev); 1065 error = fsck_preen(rdev, "ffs", true); 1066 if (error) { 1067 if (!ask_noyes(MSG_No_filesystem_newfs)) 1068 return EINVAL; 1069 error = run_program(RUN_DISPLAY | RUN_PROGRESS, 1070 "/sbin/newfs -V2 -O2 %s", rdev); 1071 } 1072 1073 md_pre_mount(install, 0); 1074 1075 make_target_dir("/"); 1076 1077 snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev); 1078 error = target_mount_do("-o async", devdev, "/"); 1079 if (error) { 1080 msg_display_subst(MSG_mountfail, 2, devdev, "/"); 1081 hit_enter_to_continue(NULL, NULL); 1082 } 1083 1084 return error; 1085 } 1086 1087 /* Making new file systems and mounting them */ 1088 1089 /* sort to ensure /usr/local is mounted after /usr (etc) */ 1090 qsort(install->infos, install->num, sizeof(*install->infos), 1091 sort_part_usage_by_mount); 1092 1093 for (i = 0; i < install->num; i++) { 1094 /* 1095 * Newfs all file systems mareked as needing this. 1096 * Mount the ones that have a mountpoint in the target. 1097 */ 1098 ptn = &install->infos[i]; 1099 parts = ptn->parts; 1100 1101 if (ptn->size == 0 || parts == NULL) 1102 continue; 1103 1104 if (parts->pscheme->get_part_device(parts, ptn->cur_part_id, 1105 devdev, sizeof devdev, &partno, parent_device_only, false) 1106 && is_active_rootpart(devdev, partno)) 1107 continue; 1108 1109 if (!(ptn->instflags & PUIINST_NEWFS)) 1110 continue; 1111 1112 parts->pscheme->get_part_device(parts, ptn->cur_part_id, 1113 devdev, sizeof devdev, &partno, plain_name, true); 1114 1115 parts->pscheme->get_part_device(parts, ptn->cur_part_id, 1116 rdev, sizeof rdev, &partno, raw_dev_name, true); 1117 1118 newfs = NULL; 1119 switch (ptn->fs_type) { 1120 case FS_APPLEUFS: 1121 asprintf(&newfs, "/sbin/newfs"); 1122 mnt_opts = "-tffs -o async"; 1123 fsname = "ffs"; 1124 break; 1125 case FS_BSDFFS: 1126 asprintf(&newfs, 1127 "/sbin/newfs -V2 -O %d", 1128 ptn->fs_version == 2 ? 2 : 1); 1129 if (ptn->mountflags & PUIMNT_LOG) 1130 mnt_opts = "-tffs -o log"; 1131 else 1132 mnt_opts = "-tffs -o async"; 1133 fsname = "ffs"; 1134 break; 1135 case FS_BSDLFS: 1136 asprintf(&newfs, "/sbin/newfs_lfs"); 1137 mnt_opts = "-tlfs"; 1138 fsname = "lfs"; 1139 break; 1140 case FS_MSDOS: 1141 asprintf(&newfs, "/sbin/newfs_msdos"); 1142 mnt_opts = "-tmsdos"; 1143 fsname = "msdos"; 1144 break; 1145 #ifdef USE_SYSVBFS 1146 case FS_SYSVBFS: 1147 asprintf(&newfs, "/sbin/newfs_sysvbfs"); 1148 mnt_opts = "-tsysvbfs"; 1149 fsname = "sysvbfs"; 1150 break; 1151 #endif 1152 #ifdef USE_EXT2FS 1153 case FS_EX2FS: 1154 asprintf(&newfs, "/sbin/newfs_ext2fs"); 1155 mnt_opts = "-text2fs"; 1156 fsname = "ext2fs"; 1157 break; 1158 #endif 1159 } 1160 if ((ptn->instflags & PUIINST_NEWFS) && newfs != NULL) { 1161 if (ptn->fs_type == FS_MSDOS) { 1162 /* newfs only if mount fails */ 1163 if (run_program(RUN_SILENT | RUN_ERROR_OK, 1164 "mount -rt msdos %s /mnt2", devdev) != 0) 1165 error = run_program( 1166 RUN_DISPLAY | RUN_PROGRESS, 1167 "%s %s", 1168 newfs, rdev); 1169 else { 1170 run_program(RUN_SILENT | RUN_ERROR_OK, 1171 "umount /mnt2"); 1172 error = 0; 1173 } 1174 } else { 1175 error = run_program(RUN_DISPLAY | RUN_PROGRESS, 1176 "%s %s", newfs, rdev); 1177 } 1178 } else { 1179 /* We'd better check it isn't dirty */ 1180 error = fsck_preen(devdev, fsname, false); 1181 } 1182 free(newfs); 1183 if (error != 0) 1184 return error; 1185 1186 ptn->instflags &= ~PUIINST_NEWFS; 1187 md_pre_mount(install, i); 1188 1189 if (partman_go == 0 && (ptn->instflags & PUIINST_MOUNT) && 1190 mnt_opts != NULL) { 1191 make_target_dir(ptn->mount); 1192 error = target_mount_do(mnt_opts, devdev, 1193 ptn->mount); 1194 if (error) { 1195 msg_display_subst(MSG_mountfail, 2, devdev, 1196 ptn->mount); 1197 hit_enter_to_continue(NULL, NULL); 1198 return error; 1199 } 1200 } 1201 } 1202 return 0; 1203 } 1204 1205 int 1206 make_fstab(struct install_partition_desc *install) 1207 { 1208 FILE *f; 1209 const char *dump_dev = NULL; 1210 const char *dev; 1211 char dev_buf[PATH_MAX], swap_dev[PATH_MAX]; 1212 1213 if (pm->cur_system) 1214 return 1; 1215 1216 swap_dev[0] = 0; 1217 1218 /* Create the fstab. */ 1219 make_target_dir("/etc"); 1220 f = target_fopen("/etc/fstab", "w"); 1221 scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix()); 1222 1223 if (logfp) 1224 (void)fprintf(logfp, 1225 "Making %s/etc/fstab (%s).\n", target_prefix(), 1226 pm->diskdev); 1227 1228 if (f == NULL) { 1229 msg_display(MSG_createfstab); 1230 if (logfp) 1231 (void)fprintf(logfp, "Failed to make /etc/fstab!\n"); 1232 hit_enter_to_continue(NULL, NULL); 1233 #ifndef DEBUG 1234 return 1; 1235 #else 1236 f = stdout; 1237 #endif 1238 } 1239 1240 scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/" 1241 "fstab/ for more examples.\n"); 1242 1243 if (pm->no_part) { 1244 /* single dk? target */ 1245 char buf[200], parent[200], swap[200], *prompt; 1246 int res; 1247 1248 if (!get_name_and_parent(pm->diskdev, buf, parent)) 1249 goto done_with_disks; 1250 scripting_fprintf(f, "NAME=%s\t/\tffs\trw\t\t1 1\n", 1251 buf); 1252 if (!find_swap_part_on(parent, swap)) 1253 goto done_with_disks; 1254 const char *args[] = { parent, swap }; 1255 prompt = str_arg_subst(msg_string(MSG_Auto_add_swap_part), 1256 __arraycount(args), args); 1257 res = ask_yesno(prompt); 1258 free(prompt); 1259 if (res) 1260 scripting_fprintf(f, "NAME=%s\tnone" 1261 "\tswap\tsw,dp\t\t0 0\n", swap); 1262 goto done_with_disks; 1263 } 1264 1265 for (size_t i = 0; i < install->num; i++) { 1266 1267 const struct part_usage_info *ptn = &install->infos[i]; 1268 1269 if (ptn->type != PT_swap && 1270 (ptn->instflags & PUIINST_MOUNT) == 0) 1271 continue; 1272 1273 const char *s = ""; 1274 const char *mp = ptn->mount; 1275 const char *fstype = "ffs"; 1276 int fsck_pass = 0, dump_freq = 0; 1277 1278 if (ptn->parts->pscheme->get_part_device(ptn->parts, 1279 ptn->cur_part_id, dev_buf, sizeof dev_buf, NULL, 1280 logical_name, true)) 1281 dev = dev_buf; 1282 else 1283 dev = NULL; 1284 1285 if (!*mp) { 1286 /* 1287 * No mount point specified, comment out line and 1288 * use /mnt as a placeholder for the mount point. 1289 */ 1290 s = "# "; 1291 mp = "/mnt"; 1292 } 1293 1294 switch (ptn->fs_type) { 1295 case FS_UNUSED: 1296 continue; 1297 case FS_BSDLFS: 1298 /* If there is no LFS, just comment it out. */ 1299 if (!check_lfs_progs()) 1300 s = "# "; 1301 fstype = "lfs"; 1302 /* FALLTHROUGH */ 1303 case FS_BSDFFS: 1304 fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2; 1305 dump_freq = 1; 1306 break; 1307 case FS_MSDOS: 1308 fstype = "msdos"; 1309 break; 1310 case FS_SWAP: 1311 if (swap_dev[0] == 0) { 1312 strncpy(swap_dev, dev, sizeof swap_dev); 1313 dump_dev = ",dp"; 1314 } else { 1315 dump_dev = ""; 1316 } 1317 scripting_fprintf(f, "%s\t\tnone\tswap\tsw%s\t\t 0 0\n", 1318 dev, dump_dev); 1319 continue; 1320 #ifdef USE_SYSVBFS 1321 case FS_SYSVBFS: 1322 fstype = "sysvbfs"; 1323 make_target_dir("/stand"); 1324 break; 1325 #endif 1326 default: 1327 fstype = "???"; 1328 s = "# "; 1329 break; 1330 } 1331 /* The code that remounts root rw doesn't check the partition */ 1332 if (strcmp(mp, "/") == 0 && 1333 (ptn->instflags & PUIINST_MOUNT) == 0) 1334 s = "# "; 1335 1336 scripting_fprintf(f, 1337 "%s%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n", 1338 s, dev, mp, fstype, 1339 ptn->mountflags & PUIMNT_LOG ? ",log" : "", 1340 ptn->mountflags & PUIMNT_NOAUTO ? "" : ",noauto", 1341 ptn->mountflags & PUIMNT_ASYNC ? ",async" : "", 1342 ptn->mountflags & PUIMNT_NOATIME ? ",noatime" : "", 1343 ptn->mountflags & PUIMNT_NODEV ? ",nodev" : "", 1344 ptn->mountflags & PUIMNT_NODEVMTIME ? ",nodevmtime" : "", 1345 ptn->mountflags & PUIMNT_NOEXEC ? ",noexec" : "", 1346 ptn->mountflags & PUIMNT_NOSUID ? ",nosuid" : "", 1347 dump_freq, fsck_pass); 1348 } 1349 1350 done_with_disks: 1351 if (tmp_ramdisk_size > 0) { 1352 #ifdef HAVE_TMPFS 1353 scripting_fprintf(f, "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,-s=%" 1354 PRIu64 "\n", 1355 tmp_ramdisk_size * 512); 1356 #else 1357 if (swap_dev[0] != 0) 1358 scripting_fprintf(f, "%s\t\t/tmp\tmfs\trw,-s=%" 1359 PRIu64 "\n", swap_dev, tmp_ramdisk_size); 1360 else 1361 scripting_fprintf(f, "swap\t\t/tmp\tmfs\trw,-s=%" 1362 PRIu64 "\n", tmp_ramdisk_size); 1363 #endif 1364 } 1365 1366 if (cdrom_dev[0] == 0) 1367 get_default_cdrom(cdrom_dev, sizeof(cdrom_dev)); 1368 1369 /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */ 1370 scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n"); 1371 scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n"); 1372 scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n"); 1373 scripting_fprintf(f, "/dev/%s\t\t/cdrom\tcd9660\tro,noauto\n", 1374 cdrom_dev); 1375 scripting_fprintf(f, "%stmpfs\t\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n", 1376 tmpfs_on_var_shm() ? "" : "#"); 1377 make_target_dir("/kern"); 1378 make_target_dir("/proc"); 1379 make_target_dir("/dev/pts"); 1380 make_target_dir("/cdrom"); 1381 make_target_dir("/var/shm"); 1382 1383 scripting_fprintf(NULL, "EOF\n"); 1384 1385 fclose(f); 1386 fflush(NULL); 1387 return 0; 1388 } 1389 1390 1391 1392 static int 1393 /*ARGSUSED*/ 1394 foundffs(struct data *list, size_t num) 1395 { 1396 int error; 1397 1398 if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 || 1399 strstr(list[2].u.s_val, "noauto") != NULL) 1400 return 0; 1401 1402 error = fsck_preen(list[0].u.s_val, "ffs", false); 1403 if (error != 0) 1404 return error; 1405 1406 error = target_mount("", list[0].u.s_val, list[1].u.s_val); 1407 if (error != 0) { 1408 msg_fmt_display(MSG_mount_failed, "%s", list[0].u.s_val); 1409 if (!ask_noyes(NULL)) 1410 return error; 1411 } 1412 return 0; 1413 } 1414 1415 #ifdef USE_SYSVBFS 1416 static int 1417 /*ARGSUSED*/ 1418 foundsysvbfs(struct data *list, size_t num) 1419 { 1420 int error; 1421 1422 if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 || 1423 strstr(list[2].u.s_val, "noauto") != NULL) 1424 return 0; 1425 1426 error = target_mount("", list[0].u.s_val, list[1].u.s_val); 1427 if (error != 0) 1428 return error; 1429 return 0; 1430 } 1431 #endif 1432 1433 /* 1434 * Do an fsck. On failure, inform the user by showing a warning 1435 * message and doing menu_ok() before proceeding. 1436 * The device passed should be the full qualified path to raw disk 1437 * (e.g. /dev/rwd0a). 1438 * Returns 0 on success, or nonzero return code from fsck() on failure. 1439 */ 1440 static int 1441 fsck_preen(const char *disk, const char *fsname, bool silent) 1442 { 1443 char *prog, err[12]; 1444 int error; 1445 1446 if (fsname == NULL) 1447 return 0; 1448 /* first, check if fsck program exists, if not, assume ok */ 1449 asprintf(&prog, "/sbin/fsck_%s", fsname); 1450 if (prog == NULL) 1451 return 0; 1452 if (access(prog, X_OK) != 0) { 1453 free(prog); 1454 return 0; 1455 } 1456 if (!strcmp(fsname,"ffs")) 1457 fixsb(prog, disk); 1458 error = run_program(silent? RUN_SILENT|RUN_ERROR_OK : 0, "%s -p -q %s", prog, disk); 1459 free(prog); 1460 if (error != 0 && !silent) { 1461 sprintf(err, "%d", error); 1462 msg_display_subst(msg_string(MSG_badfs), 3, 1463 disk, fsname, err); 1464 if (ask_noyes(NULL)) 1465 error = 0; 1466 /* XXX at this point maybe we should run a full fsck? */ 1467 } 1468 return error; 1469 } 1470 1471 /* This performs the same function as the etc/rc.d/fixsb script 1472 * which attempts to correct problems with ffs1 filesystems 1473 * which may have been introduced by booting a netbsd-current kernel 1474 * from between April of 2003 and January 2004. For more information 1475 * This script was developed as a response to NetBSD pr install/25138 1476 * Additional prs regarding the original issue include: 1477 * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926 1478 */ 1479 static void 1480 fixsb(const char *prog, const char *disk) 1481 { 1482 int fd; 1483 int rval; 1484 union { 1485 struct fs fs; 1486 char buf[SBLOCKSIZE]; 1487 } sblk; 1488 struct fs *fs = &sblk.fs; 1489 1490 fd = open(disk, O_RDONLY); 1491 if (fd == -1) 1492 return; 1493 1494 /* Read ffsv1 main superblock */ 1495 rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1); 1496 close(fd); 1497 if (rval != sizeof sblk.buf) 1498 return; 1499 1500 if (fs->fs_magic != FS_UFS1_MAGIC && 1501 fs->fs_magic != FS_UFS1_MAGIC_SWAPPED) 1502 /* Not FFSv1 */ 1503 return; 1504 if (fs->fs_old_flags & FS_FLAGS_UPDATED) 1505 /* properly updated fslevel 4 */ 1506 return; 1507 if (fs->fs_bsize != fs->fs_maxbsize) 1508 /* not messed up */ 1509 return; 1510 1511 /* 1512 * OK we have a munged fs, first 'upgrade' to fslevel 4, 1513 * We specify -b16 in order to stop fsck bleating that the 1514 * sb doesn't match the first alternate. 1515 */ 1516 run_program(RUN_DISPLAY | RUN_PROGRESS, 1517 "%s -p -b 16 -c 4 %s", prog, disk); 1518 /* Then downgrade to fslevel 3 */ 1519 run_program(RUN_DISPLAY | RUN_PROGRESS, 1520 "%s -p -c 3 %s", prog, disk); 1521 } 1522 1523 /* 1524 * fsck and mount the root partition. 1525 * devdev is the fully qualified block device name. 1526 */ 1527 static int 1528 mount_root(const char *devdev, struct install_partition_desc *install) 1529 { 1530 int error; 1531 1532 error = fsck_preen(devdev, "ffs", false); 1533 if (error != 0) 1534 return error; 1535 1536 md_pre_mount(install, 0); 1537 1538 /* Mount devdev on target's "". 1539 * If we pass "" as mount-on, Prefixing will DTRT. 1540 * for now, use no options. 1541 * XXX consider -o remount in case target root is 1542 * current root, still readonly from single-user? 1543 */ 1544 return target_mount("", devdev, ""); 1545 } 1546 1547 /* Get information on the file systems mounted from the root filesystem. 1548 * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD 1549 * inodes. Fsck them. Mount them. 1550 */ 1551 1552 int 1553 mount_disks(struct install_partition_desc *install) 1554 { 1555 char *fstab; 1556 int fstabsize; 1557 int error; 1558 char devdev[PATH_MAX]; 1559 size_t i; 1560 1561 if (install->cur_system) 1562 return 0; 1563 1564 static struct lookfor fstabbuf[] = { 1565 {"/dev/", "/dev/%s %s ffs %s", "c", NULL, 0, 0, foundffs}, 1566 {"/dev/", "/dev/%s %s ufs %s", "c", NULL, 0, 0, foundffs}, 1567 #ifdef USE_SYSVBFS 1568 {"/dev/", "/dev/%s %s sysvbfs %s", "c", NULL, 0, 0, 1569 foundsysvbfs}, 1570 #endif 1571 }; 1572 static size_t numfstabbuf = sizeof(fstabbuf) / sizeof(struct lookfor); 1573 1574 /* First the root device. */ 1575 if (target_already_root()) 1576 /* avoid needing to call target_already_root() again */ 1577 targetroot_mnt[0] = 0; 1578 else { 1579 for (i = 0; i < install->num; i++) { 1580 if (is_root_part_mount(install->infos[i].mount)) 1581 break; 1582 } 1583 1584 if (i >= install->num) { 1585 hit_enter_to_continue(MSG_noroot, NULL); 1586 return -1; 1587 } 1588 1589 if (!install->infos[i].parts->pscheme->get_part_device( 1590 install->infos[i].parts, install->infos[i].cur_part_id, 1591 devdev, sizeof devdev, NULL, plain_name, true)) 1592 return -1; 1593 error = mount_root(devdev, install); 1594 if (error != 0 && error != EBUSY) 1595 return -1; 1596 } 1597 1598 /* Check the target /etc/fstab exists before trying to parse it. */ 1599 if (target_dir_exists_p("/etc") == 0 || 1600 target_file_exists_p("/etc/fstab") == 0) { 1601 msg_fmt_display(MSG_noetcfstab, "%s", pm->diskdev); 1602 hit_enter_to_continue(NULL, NULL); 1603 return -1; 1604 } 1605 1606 1607 /* Get fstab entries from the target-root /etc/fstab. */ 1608 fstabsize = target_collect_file(T_FILE, &fstab, "/etc/fstab"); 1609 if (fstabsize < 0) { 1610 /* error ! */ 1611 msg_fmt_display(MSG_badetcfstab, "%s", pm->diskdev); 1612 hit_enter_to_continue(NULL, NULL); 1613 return -2; 1614 } 1615 error = walk(fstab, (size_t)fstabsize, fstabbuf, numfstabbuf); 1616 free(fstab); 1617 1618 return error; 1619 } 1620 1621 int 1622 set_swap_if_low_ram(struct install_partition_desc *install) 1623 { 1624 if (get_ramsize() <= 32) 1625 return set_swap(install); 1626 return 0; 1627 } 1628 1629 int 1630 set_swap(struct install_partition_desc *install) 1631 { 1632 size_t i; 1633 char dev_buf[PATH_MAX]; 1634 int rval; 1635 1636 for (i = 0; i < install->num; i++) { 1637 if (install->infos[i].type == PT_swap) 1638 break; 1639 } 1640 if (i >= install->num) 1641 return 0; 1642 1643 if (!install->infos[i].parts->pscheme->get_part_device( 1644 install->infos[i].parts, install->infos[i].cur_part_id, dev_buf, 1645 sizeof dev_buf, NULL, plain_name, true)) 1646 return -1; 1647 1648 rval = swapctl(SWAP_ON, dev_buf, 0); 1649 if (rval != 0) 1650 return -1; 1651 1652 return 0; 1653 } 1654 1655 int 1656 check_swap(const char *disk, int remove_swap) 1657 { 1658 struct swapent *swap; 1659 char *cp; 1660 int nswap; 1661 int l; 1662 int rval = 0; 1663 1664 nswap = swapctl(SWAP_NSWAP, 0, 0); 1665 if (nswap <= 0) 1666 return 0; 1667 1668 swap = malloc(nswap * sizeof *swap); 1669 if (swap == NULL) 1670 return -1; 1671 1672 nswap = swapctl(SWAP_STATS, swap, nswap); 1673 if (nswap < 0) 1674 goto bad_swap; 1675 1676 l = strlen(disk); 1677 while (--nswap >= 0) { 1678 /* Should we check the se_dev or se_path? */ 1679 cp = swap[nswap].se_path; 1680 if (memcmp(cp, "/dev/", 5) != 0) 1681 continue; 1682 if (memcmp(cp + 5, disk, l) != 0) 1683 continue; 1684 if (!isalpha(*(unsigned char *)(cp + 5 + l))) 1685 continue; 1686 if (cp[5 + l + 1] != 0) 1687 continue; 1688 /* ok path looks like it is for this device */ 1689 if (!remove_swap) { 1690 /* count active swap areas */ 1691 rval++; 1692 continue; 1693 } 1694 if (swapctl(SWAP_OFF, cp, 0) == -1) 1695 rval = -1; 1696 } 1697 1698 done: 1699 free(swap); 1700 return rval; 1701 1702 bad_swap: 1703 rval = -1; 1704 goto done; 1705 } 1706 1707 #ifdef HAVE_BOOTXX_xFS 1708 char * 1709 bootxx_name(struct install_partition_desc *install) 1710 { 1711 int fstype; 1712 const char *bootxxname; 1713 char *bootxx; 1714 1715 /* check we have boot code for the root partition type */ 1716 fstype = install->infos[0].fs_type; 1717 switch (fstype) { 1718 #if defined(BOOTXX_FFSV1) || defined(BOOTXX_FFSV2) 1719 case FS_BSDFFS: 1720 if (install->infos[0].fs_version == 2) { 1721 #ifdef BOOTXX_FFSV2 1722 bootxxname = BOOTXX_FFSV2; 1723 #else 1724 bootxxname = NULL; 1725 #endif 1726 } else { 1727 #ifdef BOOTXX_FFSV1 1728 bootxxname = BOOTXX_FFSV1; 1729 #else 1730 bootxxname = NULL; 1731 #endif 1732 } 1733 break; 1734 #endif 1735 #ifdef BOOTXX_LFSV2 1736 case FS_BSDLFS: 1737 bootxxname = BOOTXX_LFSV2; 1738 break; 1739 #endif 1740 default: 1741 bootxxname = NULL; 1742 break; 1743 } 1744 1745 if (bootxxname == NULL) 1746 return NULL; 1747 1748 asprintf(&bootxx, "%s/%s", BOOTXXDIR, bootxxname); 1749 return bootxx; 1750 } 1751 #endif 1752 1753 /* from dkctl.c */ 1754 static int 1755 get_dkwedges_sort(const void *a, const void *b) 1756 { 1757 const struct dkwedge_info *dkwa = a, *dkwb = b; 1758 const daddr_t oa = dkwa->dkw_offset, ob = dkwb->dkw_offset; 1759 return (oa < ob) ? -1 : (oa > ob) ? 1 : 0; 1760 } 1761 1762 int 1763 get_dkwedges(struct dkwedge_info **dkw, const char *diskdev) 1764 { 1765 struct dkwedge_list dkwl; 1766 1767 *dkw = NULL; 1768 if (!get_wedge_list(diskdev, &dkwl)) 1769 return -1; 1770 1771 if (dkwl.dkwl_nwedges > 0 && *dkw != NULL) { 1772 qsort(*dkw, dkwl.dkwl_nwedges, sizeof(**dkw), 1773 get_dkwedges_sort); 1774 } 1775 1776 return dkwl.dkwl_nwedges; 1777 } 1778