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