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