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