xref: /titanic_50/usr/src/cmd/boot/installgrub/installgrub.c (revision 6e0414acac7fe81ff262fb9d3d83c0700fe9b695)
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