1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <libgen.h> 29 #include <malloc.h> 30 #include <string.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <fcntl.h> 34 #include <unistd.h> 35 #include <strings.h> 36 #include <sys/mount.h> 37 #include <sys/mnttab.h> 38 #include <sys/dktp/fdisk.h> 39 #include <sys/dkio.h> 40 #include <sys/vtoc.h> 41 42 #include <libintl.h> 43 #include <locale.h> 44 #include "message.h" 45 #include <errno.h> 46 #include <libfdisk.h> 47 48 #ifndef TEXT_DOMAIN 49 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 50 #endif 51 52 #define SECTOR_SIZE 0x200 53 #define STAGE2_MEMADDR 0x8000 /* loading addr of stage2 */ 54 55 #define STAGE1_BPB_OFFSET 0x3 56 #define STAGE1_BPB_SIZE 0x3B 57 #define STAGE1_BOOT_DRIVE 0x40 58 #define STAGE1_FORCE_LBA 0x41 59 #define STAGE1_STAGE2_ADDRESS 0x42 60 #define STAGE1_STAGE2_SECTOR 0x44 61 #define STAGE1_STAGE2_SEGMENT 0x48 62 63 #define STAGE2_BLOCKLIST (SECTOR_SIZE - 0x8) 64 #define STAGE2_INSTALLPART (SECTOR_SIZE + 0x8) 65 #define STAGE2_FORCE_LBA (SECTOR_SIZE + 0x11) 66 #define STAGE2_VER_STRING (SECTOR_SIZE + 0x12) 67 #define STAGE2_BLKOFF 50 /* offset from start of fdisk part */ 68 69 static int nowrite = 0; 70 static int write_mboot = 0; 71 static int force_mboot = 0; 72 static int is_floppy = 0; 73 static int is_bootpar = 0; 74 static int stage2_fd; 75 static int partition, slice = 0xff; 76 static char *device_p0; 77 static uint32_t stage2_first_sector, stage2_second_sector; 78 79 80 static char bpb_sect[SECTOR_SIZE]; 81 static char boot_sect[SECTOR_SIZE]; 82 static char stage1_buffer[SECTOR_SIZE]; 83 static char stage2_buffer[2 * SECTOR_SIZE]; 84 static unsigned int blocklist[SECTOR_SIZE / sizeof (unsigned int)]; 85 86 static int open_device(char *); 87 static void read_bpb_sect(int); 88 static void read_boot_sect(char *); 89 static void write_boot_sect(char *); 90 static void read_stage1_stage2(char *, char *); 91 static void modify_and_write_stage1(int); 92 static void modify_and_write_stage2(int); 93 static unsigned int get_start_sector(int); 94 static void copy_stage2(int, char *); 95 static char *get_raw_partition(char *); 96 static void usage(char *); 97 98 extern int read_stage2_blocklist(int, unsigned int *); 99 100 int 101 main(int argc, char *argv[]) 102 { 103 int dev_fd, opt; 104 char *stage1, *stage2, *device; 105 106 (void) setlocale(LC_ALL, ""); 107 (void) textdomain(TEXT_DOMAIN); 108 109 while ((opt = getopt(argc, argv, "fmn")) != EOF) { 110 switch (opt) { 111 case 'm': 112 write_mboot = 1; 113 break; 114 case 'n': 115 nowrite = 1; 116 break; 117 case 'f': 118 force_mboot = 1; 119 break; 120 default: 121 /* fall through to process non-optional args */ 122 break; 123 } 124 } 125 126 /* check arguments */ 127 if (argc != optind + 3) { 128 usage(argv[0]); 129 } 130 131 if (nowrite) { 132 (void) fprintf(stdout, DRY_RUN); 133 } 134 135 stage1 = strdup(argv[optind]); 136 stage2 = strdup(argv[optind + 1]); 137 device = strdup(argv[optind + 2]); 138 139 if (!stage1 || !stage2 || !device) { 140 usage(argv[0]); 141 } 142 143 /* open and check device type */ 144 dev_fd = open_device(device); 145 146 /* read in stage1 and stage2 into buffer */ 147 read_stage1_stage2(stage1, stage2); 148 149 /* In the pcfs case, write a fresh stage2 */ 150 if (is_floppy || is_bootpar) { 151 copy_stage2(dev_fd, device); 152 read_bpb_sect(dev_fd); 153 } 154 155 /* read in boot sector */ 156 if (!is_floppy) 157 read_boot_sect(device); 158 159 /* modify stage1 based on grub needs */ 160 modify_and_write_stage1(dev_fd); 161 162 /* modify stage2 and write to media */ 163 modify_and_write_stage2(dev_fd); 164 165 if (!is_floppy && write_mboot) 166 write_boot_sect(device); 167 (void) close(dev_fd); 168 169 return (0); 170 } 171 172 static unsigned int 173 get_start_sector(int fd) 174 { 175 static unsigned int start_sect = 0; 176 uint32_t secnum, numsec; 177 int i, pno, rval, ext_sol_part_found = 0; 178 struct mboot *mboot; 179 struct ipart *part; 180 ext_part_t *epp; 181 182 if (start_sect) 183 return (start_sect); 184 185 mboot = (struct mboot *)boot_sect; 186 for (i = 0; i < FD_NUMPART; i++) { 187 part = (struct ipart *)mboot->parts + i; 188 if (is_bootpar) { 189 if (part->systid == 0xbe) 190 break; 191 } 192 } 193 194 /* Read extended partition to find a solaris partition */ 195 if ((rval = libfdisk_init(&epp, device_p0, NULL, FDISK_READ_DISK)) 196 != FDISK_SUCCESS) { 197 switch (rval) { 198 /* 199 * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can 200 * be considered as soft errors and hence 201 * we do not exit 202 */ 203 case FDISK_EBADLOGDRIVE: 204 break; 205 case FDISK_ENOLOGDRIVE: 206 break; 207 case FDISK_ENOVGEOM: 208 fprintf(stderr, "Could not get virtual" 209 " geometry for this device\n"); 210 exit(1); 211 break; 212 case FDISK_ENOPGEOM: 213 fprintf(stderr, "Could not get physical" 214 " geometry for this device\n"); 215 exit(1); 216 break; 217 case FDISK_ENOLGEOM: 218 fprintf(stderr, "Could not get label" 219 " geometry for this device\n"); 220 exit(1); 221 break; 222 default: 223 perror("Failed to initialise libfdisk.\n"); 224 exit(1); 225 break; 226 } 227 } 228 229 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 230 if (rval == FDISK_SUCCESS) { 231 ext_sol_part_found = 1; 232 } 233 libfdisk_fini(&epp); 234 235 /* 236 * If there is no boot partition, find the solaris partition 237 */ 238 239 if (i == FD_NUMPART) { 240 struct part_info dkpi; 241 struct extpart_info edkpi; 242 243 /* 244 * Get the solaris partition information from the device 245 * and compare the offset of S2 with offset of solaris partition 246 * from fdisk partition table. 247 */ 248 if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 249 if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) { 250 (void) fprintf(stderr, PART_FAIL); 251 exit(-1); 252 } else { 253 edkpi.p_start = dkpi.p_start; 254 } 255 } 256 257 for (i = 0; i < FD_NUMPART; i++) { 258 part = (struct ipart *)mboot->parts + i; 259 260 if (part->relsect == 0) { 261 (void) fprintf(stderr, BAD_PART, i); 262 exit(-1); 263 } 264 265 if (fdisk_is_dos_extended(part->systid)) 266 continue; 267 268 if (edkpi.p_start >= part->relsect && 269 edkpi.p_start < (part->relsect + part->numsect)) { 270 /* Found the partition */ 271 break; 272 } 273 } 274 } 275 276 if ((i == FD_NUMPART) && (!ext_sol_part_found)) { 277 (void) fprintf(stderr, BOOTPAR); 278 exit(-1); 279 } 280 281 /* get confirmation for -m */ 282 if (write_mboot && !force_mboot) { 283 (void) fprintf(stdout, MBOOT_PROMPT); 284 if (getchar() != 'y') { 285 write_mboot = 0; 286 (void) fprintf(stdout, MBOOT_NOT_UPDATED); 287 } 288 } 289 290 if ((i == FD_NUMPART) && (ext_sol_part_found)) { 291 start_sect = secnum; 292 partition = pno; 293 } else { 294 start_sect = part->relsect; 295 partition = i; 296 } 297 298 if (part->bootid != 128 && write_mboot == 0) { 299 (void) fprintf(stdout, BOOTPAR_INACTIVE, i + 1); 300 } 301 302 return (start_sect); 303 } 304 305 static void 306 usage(char *progname) 307 { 308 (void) fprintf(stderr, USAGE, basename(progname)); 309 exit(-1); 310 } 311 312 static int 313 open_device(char *device) 314 { 315 int dev_fd; 316 struct stat stat; 317 char *raw_part; 318 319 is_floppy = strncmp(device, "/dev/rdsk", strlen("/dev/rdsk")) && 320 strncmp(device, "/dev/dsk", strlen("/dev/dsk")); 321 322 /* handle boot partition specification */ 323 if (!is_floppy && strstr(device, "p0:boot")) { 324 is_bootpar = 1; 325 } 326 327 raw_part = get_raw_partition(device); 328 329 if (nowrite) 330 dev_fd = open(raw_part, O_RDONLY); 331 else 332 dev_fd = open(raw_part, O_RDWR); 333 334 if (dev_fd == -1 || fstat(dev_fd, &stat) != 0) { 335 (void) fprintf(stderr, OPEN_FAIL, raw_part); 336 exit(-1); 337 } 338 if (S_ISCHR(stat.st_mode) == 0) { 339 (void) fprintf(stderr, NOT_RAW_DEVICE, raw_part); 340 exit(-1); 341 } 342 343 return (dev_fd); 344 } 345 346 static void 347 read_stage1_stage2(char *stage1, char *stage2) 348 { 349 int fd; 350 351 /* read the stage1 file from filesystem */ 352 fd = open(stage1, O_RDONLY); 353 if (fd == -1 || read(fd, stage1_buffer, SECTOR_SIZE) != SECTOR_SIZE) { 354 (void) fprintf(stderr, READ_FAIL_STAGE1, stage1); 355 exit(-1); 356 } 357 (void) close(fd); 358 359 /* read first two blocks of stage 2 from filesystem */ 360 stage2_fd = open(stage2, O_RDONLY); 361 if (stage2_fd == -1 || 362 read(stage2_fd, stage2_buffer, 2 * SECTOR_SIZE) 363 != 2 * SECTOR_SIZE) { 364 (void) fprintf(stderr, READ_FAIL_STAGE2, stage2); 365 exit(-1); 366 } 367 /* leave the stage2 file open for later */ 368 } 369 370 static void 371 read_bpb_sect(int dev_fd) 372 { 373 if (pread(dev_fd, bpb_sect, SECTOR_SIZE, 0) != SECTOR_SIZE) { 374 (void) fprintf(stderr, READ_FAIL_BPB); 375 exit(-1); 376 } 377 } 378 379 static void 380 read_boot_sect(char *device) 381 { 382 static int read_mbr = 0; 383 int i, fd; 384 char save[2]; 385 386 if (read_mbr) 387 return; 388 read_mbr = 1; 389 390 /* get the whole disk (p0) */ 391 i = strlen(device); 392 save[0] = device[i - 2]; 393 save[1] = device[i - 1]; 394 device[i - 2] = 'p'; 395 device[i - 1] = '0'; 396 397 device_p0 = strdup(device); 398 fd = open(device, O_RDONLY); 399 if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) { 400 (void) fprintf(stderr, READ_FAIL_MBR, device); 401 if (fd == -1) 402 perror("open"); 403 else 404 perror("read"); 405 exit(-1); 406 } 407 (void) close(fd); 408 device[i - 2] = save[0]; 409 device[i - 1] = save[1]; 410 } 411 412 static void 413 write_boot_sect(char *device) 414 { 415 int fd, len; 416 char *raw, *end; 417 struct stat stat; 418 419 /* make a copy and chop off ":boot" */ 420 raw = strdup(device); 421 end = strstr(raw, "p0:boot"); 422 if (end) 423 end[2] = 0; 424 425 /* open p0 (whole disk) */ 426 len = strlen(raw); 427 raw[len - 2] = 'p'; 428 raw[len - 1] = '0'; 429 fd = open(raw, O_WRONLY); 430 if (fd == -1 || fstat(fd, &stat) != 0) { 431 (void) fprintf(stderr, OPEN_FAIL, raw); 432 exit(-1); 433 } 434 if (!nowrite && 435 pwrite(fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) { 436 (void) fprintf(stderr, WRITE_FAIL_BOOTSEC); 437 exit(-1); 438 } 439 (void) fprintf(stdout, WRITE_MBOOT); 440 (void) close(fd); 441 } 442 443 static void 444 modify_and_write_stage1(int dev_fd) 445 { 446 if (is_floppy) { 447 stage2_first_sector = blocklist[0]; 448 /* copy bios parameter block (for fat fs) */ 449 bcopy(bpb_sect + STAGE1_BPB_OFFSET, 450 stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE); 451 } else if (is_bootpar) { 452 stage2_first_sector = get_start_sector(dev_fd) + blocklist[0]; 453 /* copy bios parameter block (for fat fs) and MBR */ 454 bcopy(bpb_sect + STAGE1_BPB_OFFSET, 455 stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE); 456 bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ); 457 *((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1; 458 } else { 459 stage2_first_sector = get_start_sector(dev_fd) + STAGE2_BLKOFF; 460 /* copy MBR to stage1 in case of overwriting MBR sector */ 461 bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ); 462 *((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1; 463 } 464 465 /* modify default stage1 file generated by GRUB */ 466 *((ulong_t *)(stage1_buffer + STAGE1_STAGE2_SECTOR)) 467 = stage2_first_sector; 468 *((ushort_t *)(stage1_buffer + STAGE1_STAGE2_ADDRESS)) 469 = STAGE2_MEMADDR; 470 *((ushort_t *)(stage1_buffer + STAGE1_STAGE2_SEGMENT)) 471 = STAGE2_MEMADDR >> 4; 472 473 /* 474 * XXX the default grub distribution also: 475 * - Copy the possible MBR/extended part table 476 * - Set the boot drive of stage1 477 */ 478 479 /* write stage1/pboot to 1st sector */ 480 if (!nowrite && 481 pwrite(dev_fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) { 482 (void) fprintf(stderr, WRITE_FAIL_PBOOT); 483 exit(-1); 484 } 485 486 if (is_floppy) { 487 (void) fprintf(stdout, WRITE_BOOTSEC_FLOPPY); 488 } else { 489 (void) fprintf(stdout, WRITE_PBOOT, 490 partition, get_start_sector(dev_fd)); 491 } 492 } 493 494 #define START_BLOCK(pos) (*(ulong_t *)(pos)) 495 #define NUM_BLOCK(pos) (*(ushort_t *)((pos) + 4)) 496 #define START_SEG(pos) (*(ushort_t *)((pos) + 6)) 497 498 static void 499 modify_and_write_stage2(int dev_fd) 500 { 501 int nrecord; 502 off_t offset; 503 504 if (is_floppy || is_bootpar) { 505 int i = 0; 506 uint32_t partition_offset; 507 uint32_t install_addr = 0x8200; 508 uchar_t *pos = (uchar_t *)stage2_buffer + STAGE2_BLOCKLIST; 509 510 stage2_first_sector = blocklist[0]; 511 512 /* figure out the second sector */ 513 if (blocklist[1] > 1) { 514 blocklist[0]++; 515 blocklist[1]--; 516 } else { 517 i += 2; 518 } 519 stage2_second_sector = blocklist[i]; 520 521 if (is_floppy) 522 partition_offset = 0; 523 else /* solaris boot partition */ 524 partition_offset = get_start_sector(dev_fd); 525 526 /* install the blocklist at the end of stage2_buffer */ 527 while (blocklist[i]) { 528 if (START_BLOCK(pos - 8) != 0 && 529 START_BLOCK(pos - 8) != blocklist[i + 2]) { 530 (void) fprintf(stderr, PCFS_FRAGMENTED); 531 exit(-1); 532 } 533 START_BLOCK(pos) = blocklist[i] + partition_offset; 534 START_SEG(pos) = (ushort_t)(install_addr >> 4); 535 NUM_BLOCK(pos) = blocklist[i + 1]; 536 install_addr += blocklist[i + 1] * SECTOR_SIZE; 537 pos -= 8; 538 i += 2; 539 } 540 541 } else { 542 /* 543 * In a solaris partition, stage2 is written to contiguous 544 * blocks. So we update the starting block only. 545 */ 546 *((ulong_t *)(stage2_buffer + STAGE2_BLOCKLIST)) = 547 stage2_first_sector + 1; 548 } 549 550 if (is_floppy) { 551 /* modify the config file to add (fd0) */ 552 char *config_file = stage2_buffer + STAGE2_VER_STRING; 553 while (*config_file++) 554 ; 555 strcpy(config_file, "(fd0)/boot/grub/menu.lst"); 556 } else { 557 /* force lba and set disk partition */ 558 *((unsigned char *) (stage2_buffer + STAGE2_FORCE_LBA)) = 1; 559 *((long *)(stage2_buffer + STAGE2_INSTALLPART)) 560 = (partition << 16) | (slice << 8) | 0xff; 561 } 562 563 /* modification done, now do the writing */ 564 if (is_floppy || is_bootpar) { 565 /* we rewrite block 0 and 1 and that's it */ 566 if (!nowrite && 567 (pwrite(dev_fd, stage2_buffer, SECTOR_SIZE, 568 stage2_first_sector * SECTOR_SIZE) != SECTOR_SIZE || 569 pwrite(dev_fd, stage2_buffer + SECTOR_SIZE, SECTOR_SIZE, 570 stage2_second_sector * SECTOR_SIZE) != SECTOR_SIZE)) { 571 (void) fprintf(stderr, WRITE_FAIL_STAGE2); 572 exit(-1); 573 } 574 (void) fprintf(stdout, WRITE_STAGE2_PCFS); 575 return; 576 } 577 578 /* for disk, write stage2 starting at STAGE2_BLKOFF sector */ 579 offset = STAGE2_BLKOFF; 580 581 /* write the modified first two sectors */ 582 if (!nowrite && pwrite(dev_fd, stage2_buffer, 2 * SECTOR_SIZE, 583 offset * SECTOR_SIZE) != 2 * SECTOR_SIZE) { 584 (void) fprintf(stderr, WRITE_FAIL_STAGE2); 585 exit(-1); 586 } 587 588 /* write the remaining sectors */ 589 nrecord = 2; 590 offset += 2; 591 for (;;) { 592 int nread, nwrite; 593 nread = pread(stage2_fd, stage2_buffer, SECTOR_SIZE, 594 nrecord * SECTOR_SIZE); 595 if (nread > 0 && !nowrite) 596 nwrite = pwrite(dev_fd, stage2_buffer, SECTOR_SIZE, 597 offset * SECTOR_SIZE); 598 else 599 nwrite = SECTOR_SIZE; 600 if (nread < 0 || nwrite != SECTOR_SIZE) { 601 (void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS, 602 nread, nwrite); 603 break; 604 } 605 if (nread > 0) { 606 nrecord ++; 607 offset ++; 608 } 609 if (nread < SECTOR_SIZE) 610 break; /* end of file */ 611 } 612 (void) fprintf(stdout, WRITE_STAGE2_DISK, 613 partition, nrecord, STAGE2_BLKOFF, stage2_first_sector); 614 } 615 616 static char * 617 get_raw_partition(char *device) 618 { 619 int len; 620 struct mboot *mboot; 621 static char *raw = NULL; 622 623 if (raw) 624 return (raw); 625 raw = strdup(device); 626 627 if (is_floppy) 628 return (raw); 629 630 if (is_bootpar) { 631 int i; 632 char *end = strstr(raw, "p0:boot"); 633 634 end[2] = 0; /* chop off :boot */ 635 read_boot_sect(raw); 636 mboot = (struct mboot *)boot_sect; 637 for (i = 0; i < FD_NUMPART; i++) { 638 struct ipart *part = (struct ipart *)mboot->parts + i; 639 if (part->systid == 0xbe) /* solaris boot part */ 640 break; 641 } 642 643 if (i == FD_NUMPART) { 644 (void) fprintf(stderr, BOOTPAR_NOTFOUND, device); 645 exit(-1); 646 } 647 end[1] = '1' + i; /* set partition name */ 648 return (raw); 649 } 650 651 /* For disk, remember slice and return whole fdisk partition */ 652 len = strlen(raw); 653 if (raw[len - 2] != 's' || raw[len - 1] == '2') { 654 (void) fprintf(stderr, NOT_ROOT_SLICE); 655 exit(-1); 656 } 657 slice = atoi(&raw[len - 1]); 658 659 raw[len - 2] = 's'; 660 raw[len - 1] = '2'; 661 return (raw); 662 } 663 664 #define TMP_MNTPT "/tmp/installgrub_pcfs" 665 static void 666 copy_stage2(int dev_fd, char *device) 667 { 668 FILE *mntfp; 669 int i, pcfs_fp; 670 char buf[SECTOR_SIZE]; 671 char *cp; 672 struct mnttab mp = {0}, mpref = {0}; 673 674 /* convert raw to block device name by removing the first 'r' */ 675 (void) strncpy(buf, device, sizeof (buf)); 676 buf[sizeof (buf) - 1] = 0; 677 cp = strchr(buf, 'r'); 678 if (cp == NULL) { 679 (void) fprintf(stderr, CONVERT_FAIL, device); 680 exit(-1); 681 } 682 do { 683 *cp = *(cp + 1); 684 } while (*(++cp)); 685 686 /* get the mount point, if any */ 687 mntfp = fopen("/etc/mnttab", "r"); 688 if (mntfp == NULL) { 689 (void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab"); 690 exit(-1); 691 } 692 693 mpref.mnt_special = buf; 694 if (getmntany(mntfp, &mp, &mpref) != 0) { 695 char cmd[128]; 696 697 /* not mounted, try remount */ 698 (void) mkdir(TMP_MNTPT, S_IRWXU); 699 (void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s", 700 buf, TMP_MNTPT); 701 (void) system(cmd); 702 rewind(mntfp); 703 bzero(&mp, sizeof (mp)); 704 if (getmntany(mntfp, &mp, &mpref) != 0) { 705 (void) fprintf(stderr, MOUNT_FAIL, buf); 706 exit(-1); 707 } 708 } 709 710 (void) snprintf(buf, sizeof (buf), 711 "%s/boot", mp.mnt_mountp); 712 (void) mkdir(buf, S_IRWXU); 713 (void) strcat(buf, "/grub"); 714 (void) mkdir(buf, S_IRWXU); 715 716 (void) strcat(buf, "/stage2"); 717 pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU); 718 if (pcfs_fp == -1) { 719 (void) fprintf(stderr, OPEN_FAIL_FILE, buf); 720 perror("open:"); 721 (void) umount(TMP_MNTPT); 722 exit(-1); 723 } 724 725 /* write stage2 to pcfs */ 726 for (i = 0; ; i++) { 727 int nread, nwrite; 728 nread = pread(stage2_fd, buf, SECTOR_SIZE, i * SECTOR_SIZE); 729 if (nowrite) 730 nwrite = nread; 731 else 732 nwrite = pwrite(pcfs_fp, buf, nread, i * SECTOR_SIZE); 733 if (nread < 0 || nwrite != nread) { 734 (void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS, 735 nread, nwrite); 736 break; 737 } 738 if (nread < SECTOR_SIZE) 739 break; /* end of file */ 740 } 741 (void) close(pcfs_fp); 742 (void) umount(TMP_MNTPT); 743 744 /* 745 * Now, get the blocklist from the device. 746 */ 747 bzero(blocklist, sizeof (blocklist)); 748 if (read_stage2_blocklist(dev_fd, blocklist) != 0) 749 exit(-1); 750 } 751