xref: /titanic_51/usr/src/cmd/fs.d/pcfs/mkfs/mkfs.c (revision db92b35af583bf73fcbca649f84420ea778db26b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52d700530Sartem  * Common Development and Distribution License (the "License").
62d700530Sartem  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*db92b35aSGary Mills  * Copyright (c) 2011 Gary Mills
23*db92b35aSGary Mills  *
2465908c77Syu, larry liu - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25c719c59aSjkennedy  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <libintl.h>
377c478bd9Sstevel@tonic-gate #include <locale.h>
387c478bd9Sstevel@tonic-gate #include <sys/fdio.h>
397c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
407c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include "mkfs_pcfs.h"
437c478bd9Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
447c478bd9Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
457c478bd9Sstevel@tonic-gate #include <sys/fs/pc_label.h>
467c478bd9Sstevel@tonic-gate #include <macros.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  *	mkfs (for pcfs)
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  *	Install a boot block, FAT, and (if desired) the first resident
527c478bd9Sstevel@tonic-gate  *	of the new fs.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  *	XXX -- floppy opens need O_NDELAY?
557c478bd9Sstevel@tonic-gate  */
56*db92b35aSGary Mills #define	IN_RANGE(n, x, y) (((n) >= (x)) && ((n) <= (y)))
577c478bd9Sstevel@tonic-gate #define	DEFAULT_LABEL "NONAME"
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static char	*BootBlkFn = NULL;
607c478bd9Sstevel@tonic-gate static char	*DiskName = NULL;
617c478bd9Sstevel@tonic-gate static char	*FirstFn = NULL;
627c478bd9Sstevel@tonic-gate static char	*Label = NULL;
637c478bd9Sstevel@tonic-gate static char	Firstfileattr = 0x20;
647c478bd9Sstevel@tonic-gate static int	Outputtofile = 0;
657c478bd9Sstevel@tonic-gate static int	SunBPBfields = 0;
667c478bd9Sstevel@tonic-gate static int	GetFsParams = 0;
677c478bd9Sstevel@tonic-gate static int	Fatentsize = 0;
687c478bd9Sstevel@tonic-gate static int	Imagesize = 3;
697c478bd9Sstevel@tonic-gate static int	Notreally = 0;
707c478bd9Sstevel@tonic-gate static int	Verbose = 0;
717c478bd9Sstevel@tonic-gate static int	MakeFAT32 = 0;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * If there is an FDISK entry for the device where we're about to
757c478bd9Sstevel@tonic-gate  * make the file system, we ought to make a file system that has the
767c478bd9Sstevel@tonic-gate  * same size FAT as the FDISK table claims.  We track the size FDISK
777c478bd9Sstevel@tonic-gate  * thinks in this variable.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate static int	FdiskFATsize = 0;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static int	GetSize = 1;	/* Unless we're given as arg, must look it up */
827c478bd9Sstevel@tonic-gate static ulong_t	TotSize;	/* Total size of FS in # of sectors */
837c478bd9Sstevel@tonic-gate static int	GetSPC = 1;	/* Unless we're given as arg, must calculate */
847c478bd9Sstevel@tonic-gate static ulong_t	SecPerClust;	/* # of sectors per cluster */
857c478bd9Sstevel@tonic-gate static int	GetOffset = 1;	/* Unless we're given as arg, must look it up */
867c478bd9Sstevel@tonic-gate static ulong_t	RelOffset;	/* Relative start sector (hidden sectors) */
877c478bd9Sstevel@tonic-gate static int	GetSPT = 1;	/* Unless we're given as arg, must look it up */
887c478bd9Sstevel@tonic-gate static ushort_t	SecPerTrk;	/* # of sectors per track */
897c478bd9Sstevel@tonic-gate static int	GetTPC = 1;	/* Unless we're given as arg, must look it up */
907c478bd9Sstevel@tonic-gate static ushort_t	TrkPerCyl;	/* # of tracks per cylinder */
917c478bd9Sstevel@tonic-gate static int	GetResrvd = 1;	/* Unless we're given as arg, must calculate */
92c719c59aSjkennedy static int	Resrvd;		/* Number of reserved sectors */
937c478bd9Sstevel@tonic-gate static int	GetBPF = 1;	/* Unless we're given as arg, must calculate */
947c478bd9Sstevel@tonic-gate static int	BitsPerFAT;	/* Total size of FS in # of sectors */
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static ulong_t	TotalClusters;	/* Computed total number of clusters */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Unless we are told otherwise, we should use fdisk table for non-diskettes.
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate static int	DontUseFdisk = 0;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * Function prototypes
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate #ifndef i386
1077c478bd9Sstevel@tonic-gate static void swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp);
1087c478bd9Sstevel@tonic-gate static void swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb);
1097c478bd9Sstevel@tonic-gate static void swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb);
1107c478bd9Sstevel@tonic-gate static void swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp);
1117c478bd9Sstevel@tonic-gate static void swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb);
1127c478bd9Sstevel@tonic-gate #endif
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static uchar_t *build_rootdir(bpb_t *wbpb, char *ffn, int fffd,
1157c478bd9Sstevel@tonic-gate 	ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize);
116f127cb91Sfrankho static uchar_t *build_fat(bpb_t *wbpb, struct fat_od_fsi *fsinfop,
1177c478bd9Sstevel@tonic-gate 	ulong_t bootblksize, ulong_t *fatsize, char *ffn, int *fffd,
1187c478bd9Sstevel@tonic-gate 	ulong_t *ffsize, pc_cluster32_t *ffstartclust);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static char *stat_actual_disk(char *diskname, struct stat *info, char **suffix);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate static void compare_existing_with_computed(int fd, char *suffix,
1237c478bd9Sstevel@tonic-gate 	bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect,
1247c478bd9Sstevel@tonic-gate 	int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd,
1257c478bd9Sstevel@tonic-gate 	int *dashos);
1267c478bd9Sstevel@tonic-gate static void print_reproducing_command(int fd, char *actualdisk, char *suffix,
1277c478bd9Sstevel@tonic-gate 	bpb_t *wbpb);
1287c478bd9Sstevel@tonic-gate static void compute_file_area_size(bpb_t *wbpb);
1297c478bd9Sstevel@tonic-gate static void write_fat32_bootstuff(int fd, boot_sector_t *bsp,
130f127cb91Sfrankho 	struct fat_od_fsi *fsinfop, off64_t seekto);
1317c478bd9Sstevel@tonic-gate static void sanity_check_options(int argc, int optind);
1327c478bd9Sstevel@tonic-gate static void compute_cluster_size(bpb_t *wbpb);
1337c478bd9Sstevel@tonic-gate static void find_fixed_details(int fd, bpb_t *wbpb);
1347c478bd9Sstevel@tonic-gate static void dirent_fname_fill(struct pcdir *dep, char *fn);
1357c478bd9Sstevel@tonic-gate static void floppy_bpb_fillin(bpb_t *wbpb,
1367c478bd9Sstevel@tonic-gate 	int diam, int hds, int spt);
1377c478bd9Sstevel@tonic-gate static void read_existing_bpb(int fd, bpb_t *wbpb);
1387c478bd9Sstevel@tonic-gate static void warn_funky_fatsize(void);
1397c478bd9Sstevel@tonic-gate static void warn_funky_floppy(void);
1407c478bd9Sstevel@tonic-gate static void dirent_time_fill(struct pcdir *dep);
1417c478bd9Sstevel@tonic-gate static void parse_suboptions(char *optsstr);
1427c478bd9Sstevel@tonic-gate static void header_for_dump(void);
1437c478bd9Sstevel@tonic-gate static void write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb,
144f127cb91Sfrankho 	struct fat_od_fsi *fsinfop, off64_t seekto);
1457c478bd9Sstevel@tonic-gate static void fill_bpb_sizes(bpb_t *wbpb, struct ipart part[],
1467c478bd9Sstevel@tonic-gate 	int partno, off64_t offset);
1477c478bd9Sstevel@tonic-gate static void set_fat_string(bpb_t *wbpb, int fatsize);
1487c478bd9Sstevel@tonic-gate static void partn_lecture(char *dn);
1497c478bd9Sstevel@tonic-gate static void store_16_bits(uchar_t **bp, uint32_t v);
1507c478bd9Sstevel@tonic-gate static void store_32_bits(uchar_t **bp, uint32_t v);
1517c478bd9Sstevel@tonic-gate static void lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb);
1527c478bd9Sstevel@tonic-gate static void label_volume(char *lbl, bpb_t *wbpb);
1537c478bd9Sstevel@tonic-gate static void mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum,
1547c478bd9Sstevel@tonic-gate 	uint32_t value);
1557c478bd9Sstevel@tonic-gate static void missing_arg(char *option);
1567c478bd9Sstevel@tonic-gate static void dashm_bail(int fd);
1577c478bd9Sstevel@tonic-gate static void dump_bytes(uchar_t *, int);
1587c478bd9Sstevel@tonic-gate static void write_rest(bpb_t *wbpb, char *efn,
1597c478bd9Sstevel@tonic-gate 	int dfd, int sfd, int remaining);
1607c478bd9Sstevel@tonic-gate static void write_fat(int fd, off64_t seekto, char *fn, char *lbl,
1617c478bd9Sstevel@tonic-gate 	char *ffn, bpb_t *wbpb);
1627c478bd9Sstevel@tonic-gate static void bad_arg(char *option);
1637c478bd9Sstevel@tonic-gate static void usage(void);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static int prepare_image_file(char *fn, bpb_t *wbpb);
1667c478bd9Sstevel@tonic-gate static int verify_bootblkfile(char *fn, boot_sector_t *bs,
1677c478bd9Sstevel@tonic-gate 	ulong_t *blkfilesize);
1687c478bd9Sstevel@tonic-gate static int open_and_examine(char *dn, bpb_t *wbpb);
1697c478bd9Sstevel@tonic-gate static int verify_firstfile(char *fn, ulong_t *filesize);
1707c478bd9Sstevel@tonic-gate static int lookup_FAT_size(uchar_t partid);
1717c478bd9Sstevel@tonic-gate static int open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto);
1727c478bd9Sstevel@tonic-gate static int warn_mismatch(char *desc, char *src, int expect, int assigned);
1737c478bd9Sstevel@tonic-gate static int copy_bootblk(char *fn, boot_sector_t *bootsect,
1747c478bd9Sstevel@tonic-gate 	ulong_t *bootblksize);
1757c478bd9Sstevel@tonic-gate static int parse_drvnum(char *pn);
1767c478bd9Sstevel@tonic-gate static int seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto);
1777c478bd9Sstevel@tonic-gate static int ask_nicely(char *special);
1787c478bd9Sstevel@tonic-gate static int seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto);
1797c478bd9Sstevel@tonic-gate static int yes(void);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  *  usage
1837c478bd9Sstevel@tonic-gate  *
1847c478bd9Sstevel@tonic-gate  *	Display usage message and exit.
1857c478bd9Sstevel@tonic-gate  */
1867c478bd9Sstevel@tonic-gate static
1877c478bd9Sstevel@tonic-gate void
1887c478bd9Sstevel@tonic-gate usage(void)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
1917c478bd9Sstevel@tonic-gate 	    gettext("pcfs usage: mkfs [-F FSType] [-V] [-m] "
1927c478bd9Sstevel@tonic-gate 	    "[-o specific_options] special\n"));
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
1957c478bd9Sstevel@tonic-gate 	    gettext(" -V: print this command line and return\n"
1967c478bd9Sstevel@tonic-gate 	    " -m: dump command line used to create a FAT on this media\n"
1977c478bd9Sstevel@tonic-gate 	    "\t(other options are ignored if this option is chosen).\n"
1987c478bd9Sstevel@tonic-gate 	    " -o: pcfs_specific_options:\n"
1997c478bd9Sstevel@tonic-gate 	    "\t'pcfs_specific_options' is a comma separated list\n"
2007c478bd9Sstevel@tonic-gate 	    "\tincluding one or more of the following options:\n"
2017c478bd9Sstevel@tonic-gate 	    "\t    N,v,r,h,s,b=label,B=filename,i=filename,\n"
2027c478bd9Sstevel@tonic-gate 	    "\t    spc=n,fat=n,nsect=n,ntrack=n,nofdisk,size=n,\n"
2037c478bd9Sstevel@tonic-gate 	    "\t    reserve=n,hidden=n\n\n"));
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
2067c478bd9Sstevel@tonic-gate 	    gettext("'Special' should specify a raw diskette "
2077c478bd9Sstevel@tonic-gate 	    "or raw fixed disk device.  \"Fixed\"\n"
2087c478bd9Sstevel@tonic-gate 	    "disks (which include high-capacity removable "
2097c478bd9Sstevel@tonic-gate 	    "media such as Zip disks)\n"
2107c478bd9Sstevel@tonic-gate 	    "may be further qualified with a logical "
2117c478bd9Sstevel@tonic-gate 	    "drive specifier.\n"
2127c478bd9Sstevel@tonic-gate 	    "Examples are: /dev/rdiskette and "
2137c478bd9Sstevel@tonic-gate 	    "/dev/rdsk/c0t0d0p0:c\n"));
2147c478bd9Sstevel@tonic-gate 	exit(1);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate static
2187c478bd9Sstevel@tonic-gate int
2197c478bd9Sstevel@tonic-gate yes(void)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	char *affirmative = gettext("yY");
2227c478bd9Sstevel@tonic-gate 	char *a = affirmative;
2237c478bd9Sstevel@tonic-gate 	int b;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	b = getchar();
2267c478bd9Sstevel@tonic-gate 	while (b == '\n' && b != '\0' && b != EOF)
2277c478bd9Sstevel@tonic-gate 		b = getchar();
2287c478bd9Sstevel@tonic-gate 	while (*a) {
2297c478bd9Sstevel@tonic-gate 		if (b == (int)*a)
2307c478bd9Sstevel@tonic-gate 			break;
2317c478bd9Sstevel@tonic-gate 		a++;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	return (*a);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate static
2377c478bd9Sstevel@tonic-gate int
2387c478bd9Sstevel@tonic-gate ask_nicely(char *special)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	/*
2417c478bd9Sstevel@tonic-gate 	 * 4228473 - No way to non-interactively make a pcfs filesystem
2427c478bd9Sstevel@tonic-gate 	 *
2437c478bd9Sstevel@tonic-gate 	 *	If we don't have an input TTY, or we aren't really doing
2447c478bd9Sstevel@tonic-gate 	 *	anything, then don't ask questions.  Assume a yes answer
2457c478bd9Sstevel@tonic-gate 	 *	to any questions we would ask.
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	if (Notreally || !isatty(fileno(stdin)))
2487c478bd9Sstevel@tonic-gate 		return (1);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	(void) printf(
2517c478bd9Sstevel@tonic-gate 	    gettext("Construct a new FAT file system on %s: (y/n)? "), special);
2527c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
2537c478bd9Sstevel@tonic-gate 	return (yes());
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate  * store_16_bits
2587c478bd9Sstevel@tonic-gate  *	Save the lower 16 bits of a 32 bit value (v) into the provided
2597c478bd9Sstevel@tonic-gate  *	buffer (pointed at by *bp), and increment the buffer pointer
2607c478bd9Sstevel@tonic-gate  *	as well.  This way the routine can be called multiple times in
2617c478bd9Sstevel@tonic-gate  *	succession to fill buffers.  The value is stored in little-endian
2627c478bd9Sstevel@tonic-gate  *	order.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate static
2657c478bd9Sstevel@tonic-gate void
2667c478bd9Sstevel@tonic-gate store_16_bits(uchar_t **bp, uint32_t v)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	uchar_t *l = *bp;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	*l++ = v & 0xff;
2717c478bd9Sstevel@tonic-gate 	*l = (v >> 8) & 0xff;
2727c478bd9Sstevel@tonic-gate 	*bp += 2;
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate  * store_32_bits
2777c478bd9Sstevel@tonic-gate  * 	Save the 32 bit value (v) into the provided buffer (pointed
2787c478bd9Sstevel@tonic-gate  *	at by *bp), and increment the buffer pointer as well.  This way
2797c478bd9Sstevel@tonic-gate  *	the routine can be called multiple times in succession to fill
2807c478bd9Sstevel@tonic-gate  *	buffers.  The value is stored in little-endian order.
2817c478bd9Sstevel@tonic-gate  */
2827c478bd9Sstevel@tonic-gate static
2837c478bd9Sstevel@tonic-gate void
2847c478bd9Sstevel@tonic-gate store_32_bits(uchar_t **bp, uint32_t v)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	uchar_t *l = *bp;
2877c478bd9Sstevel@tonic-gate 	int b;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	for (b = 0; b < 4; b++) {
2907c478bd9Sstevel@tonic-gate 		*l++ = v & 0xff;
2917c478bd9Sstevel@tonic-gate 		v = v >> 8;
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 	*bp += 4;
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  *  dump_bytes  -- display bytes as hex numbers.
2987c478bd9Sstevel@tonic-gate  *		   b is the pointer to the byte buffer
2997c478bd9Sstevel@tonic-gate  *		   n is the number of bytes in the buffer
3007c478bd9Sstevel@tonic-gate  */
3017c478bd9Sstevel@tonic-gate /* Note: BPL = bytes to display per line */
3027c478bd9Sstevel@tonic-gate #define	BPL 16
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate static
3057c478bd9Sstevel@tonic-gate void
3067c478bd9Sstevel@tonic-gate dump_bytes(uchar_t *b, int n)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate 	int cd = n;
3097c478bd9Sstevel@tonic-gate 	int cu = 0;
3107c478bd9Sstevel@tonic-gate 	int o = 0;
3117c478bd9Sstevel@tonic-gate 	int bl;
3127c478bd9Sstevel@tonic-gate 	int ac;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/* Display offset, 16 bytes per line, and printable ascii version */
3157c478bd9Sstevel@tonic-gate 	while (cd > 0) {
3167c478bd9Sstevel@tonic-gate 		ac = 0;
3177c478bd9Sstevel@tonic-gate 		(void) printf("\n%06x: ", o);
3187c478bd9Sstevel@tonic-gate 		for (bl = 0; bl < BPL; bl++) {
3197c478bd9Sstevel@tonic-gate 			if (cu+bl < n) {
3207c478bd9Sstevel@tonic-gate 				(void) printf("%02x ", (b[cu+bl] & 0xff));
3217c478bd9Sstevel@tonic-gate 				ac++;
3227c478bd9Sstevel@tonic-gate 			}
3237c478bd9Sstevel@tonic-gate 			else
3247c478bd9Sstevel@tonic-gate 				(void) printf("   ");
3257c478bd9Sstevel@tonic-gate 		}
3267c478bd9Sstevel@tonic-gate 		for (bl = 0; bl < BPL; bl++) {
3277c478bd9Sstevel@tonic-gate 			if ((cu+bl < n) &&
3287c478bd9Sstevel@tonic-gate 			    ((b[cu+bl] >= ' ') && (b[cu+bl] <= '~')))
3297c478bd9Sstevel@tonic-gate 				(void) printf("%c", b[cu+bl]);
3307c478bd9Sstevel@tonic-gate 			else
3317c478bd9Sstevel@tonic-gate 				(void) printf(".");
3327c478bd9Sstevel@tonic-gate 		}
3337c478bd9Sstevel@tonic-gate 		cu += ac; o += ac; cd -= ac;
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 	(void) printf("\n\n");
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  *  header_for_dump  --  display simple header over what will be output.
3407c478bd9Sstevel@tonic-gate  */
3417c478bd9Sstevel@tonic-gate static
3427c478bd9Sstevel@tonic-gate void
3437c478bd9Sstevel@tonic-gate header_for_dump(void)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	int bl;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	(void) printf("\n        ");
3487c478bd9Sstevel@tonic-gate 	for (bl = 0; bl < BPL; bl++)
3497c478bd9Sstevel@tonic-gate 		(void) printf("%02x ", bl);
3507c478bd9Sstevel@tonic-gate 	(void) printf("\n       ");
3517c478bd9Sstevel@tonic-gate 	bl = 3*BPL;
3527c478bd9Sstevel@tonic-gate 	while (bl-- > 0)
3537c478bd9Sstevel@tonic-gate 		(void) printf("-");
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate  *  parse_drvnum
3587c478bd9Sstevel@tonic-gate  *	Convert a partition name into a drive number.
3597c478bd9Sstevel@tonic-gate  */
3607c478bd9Sstevel@tonic-gate static
3617c478bd9Sstevel@tonic-gate int
3627c478bd9Sstevel@tonic-gate parse_drvnum(char *pn)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	int drvnum;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * Determine logical drive to seek after.
3687c478bd9Sstevel@tonic-gate 	 */
3697c478bd9Sstevel@tonic-gate 	if (strlen(pn) == 1 && *pn >= 'c' && *pn <= 'z') {
3707c478bd9Sstevel@tonic-gate 		drvnum = *pn - 'c' + 1;
3717c478bd9Sstevel@tonic-gate 	} else if (*pn >= '0' && *pn <= '9') {
3727c478bd9Sstevel@tonic-gate 		char *d;
3737c478bd9Sstevel@tonic-gate 		int v, m, c;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 		v = 0;
3767c478bd9Sstevel@tonic-gate 		d = pn;
3777c478bd9Sstevel@tonic-gate 		while (*d && *d >= '0' && *d <= '9') {
3787c478bd9Sstevel@tonic-gate 			c = strlen(d);
3797c478bd9Sstevel@tonic-gate 			m = 1;
3807c478bd9Sstevel@tonic-gate 			while (--c)
3817c478bd9Sstevel@tonic-gate 				m *= 10;
3827c478bd9Sstevel@tonic-gate 			v += m * (*d - '0');
3837c478bd9Sstevel@tonic-gate 			d++;
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		if (*d || v > 24) {
3877c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
3887c478bd9Sstevel@tonic-gate 			    gettext("%s: bogus logical drive specification.\n"),
3897c478bd9Sstevel@tonic-gate 			    pn);
3907c478bd9Sstevel@tonic-gate 			return (-1);
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 		drvnum = v;
3937c478bd9Sstevel@tonic-gate 	} else if (strcmp(pn, "boot") == 0) {
3947c478bd9Sstevel@tonic-gate 		drvnum = 99;
3957c478bd9Sstevel@tonic-gate 	} else {
3967c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3977c478bd9Sstevel@tonic-gate 		    gettext("%s: bogus logical drive specification.\n"), pn);
3987c478bd9Sstevel@tonic-gate 		return (-1);
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	return (drvnum);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate /*
4057c478bd9Sstevel@tonic-gate  *  Define some special logical drives we use.
4067c478bd9Sstevel@tonic-gate  */
4077c478bd9Sstevel@tonic-gate #define	BOOT_PARTITION_DRIVE	99
4087c478bd9Sstevel@tonic-gate #define	PRIMARY_DOS_DRIVE	1
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate  * isDosDrive()
4127c478bd9Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
4137c478bd9Sstevel@tonic-gate  *	and it decides if that's a systid that describes a DOS drive.  We
4147c478bd9Sstevel@tonic-gate  *	use systid values defined in sys/dktp/fdisk.h.
4157c478bd9Sstevel@tonic-gate  */
4167c478bd9Sstevel@tonic-gate static int
4177c478bd9Sstevel@tonic-gate isDosDrive(uchar_t checkMe)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	return ((checkMe == DOSOS12) || (checkMe == DOSOS16) ||
4207c478bd9Sstevel@tonic-gate 	    (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) ||
4217c478bd9Sstevel@tonic-gate 	    (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) ||
4227c478bd9Sstevel@tonic-gate 	    (checkMe == DIAGPART));
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  * isDosExtended()
4277c478bd9Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
4287c478bd9Sstevel@tonic-gate  *	and it decides if that's a systid that describes an extended DOS
4297c478bd9Sstevel@tonic-gate  *	partition.
4307c478bd9Sstevel@tonic-gate  */
4317c478bd9Sstevel@tonic-gate static int
4327c478bd9Sstevel@tonic-gate isDosExtended(uchar_t checkMe)
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 	return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA));
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate  * isBootPart()
4397c478bd9Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
4407c478bd9Sstevel@tonic-gate  *	and it decides if that's a systid that describes a Solaris boot
4417c478bd9Sstevel@tonic-gate  *	partition.
4427c478bd9Sstevel@tonic-gate  */
4437c478bd9Sstevel@tonic-gate static int
4447c478bd9Sstevel@tonic-gate isBootPart(uchar_t checkMe)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	return (checkMe == X86BOOT);
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate static
4507c478bd9Sstevel@tonic-gate int
4517c478bd9Sstevel@tonic-gate warn_mismatch(char *desc, char *src, int expect, int assigned)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	if (expect == assigned)
4547c478bd9Sstevel@tonic-gate 		return (assigned);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/*
4577c478bd9Sstevel@tonic-gate 	 * 4228473 - No way to non-interactively make a pcfs filesystem
4587c478bd9Sstevel@tonic-gate 	 *
4597c478bd9Sstevel@tonic-gate 	 *	If we don't have an input TTY, or we aren't really doing
4607c478bd9Sstevel@tonic-gate 	 *	anything, then don't ask questions.  Assume a yes answer
4617c478bd9Sstevel@tonic-gate 	 *	to any questions we would ask.
4627c478bd9Sstevel@tonic-gate 	 */
4637c478bd9Sstevel@tonic-gate 	if (Notreally || !isatty(fileno(stdin))) {
4647c478bd9Sstevel@tonic-gate 		(void) printf(gettext("WARNING: User supplied %s is %d,"
4657c478bd9Sstevel@tonic-gate 		    "\nbut value obtained from the %s is %d.\n"
4667c478bd9Sstevel@tonic-gate 		    "Using user supplied value.\n"),
4677c478bd9Sstevel@tonic-gate 		    desc, assigned, src, expect);
4687c478bd9Sstevel@tonic-gate 		return (assigned);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	(void) printf(gettext("User supplied %s is %d."
4727c478bd9Sstevel@tonic-gate 	    "\nThe value obtained from the %s is %d.\n"),
4737c478bd9Sstevel@tonic-gate 	    desc, assigned, src, expect);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	(void) printf(
4767c478bd9Sstevel@tonic-gate 	    gettext("Continue with value given on command line (y/n)? "));
4777c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
4787c478bd9Sstevel@tonic-gate 	if (yes())
4797c478bd9Sstevel@tonic-gate 		return (assigned);
4807c478bd9Sstevel@tonic-gate 	else
4817c478bd9Sstevel@tonic-gate 		exit(2);
4827c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate static
4867c478bd9Sstevel@tonic-gate void
4877c478bd9Sstevel@tonic-gate fill_fat32_bpb(bpb_t *wbpb)
4887c478bd9Sstevel@tonic-gate {
4897c478bd9Sstevel@tonic-gate 	/*
4907c478bd9Sstevel@tonic-gate 	 * ExtFlags means (according to MSDN BPB (FAT32) document)
4917c478bd9Sstevel@tonic-gate 	 *
4927c478bd9Sstevel@tonic-gate 	 * Bit 8 indicates info written to the active FAT is written
4937c478bd9Sstevel@tonic-gate 	 * to all copies of the FAT.  (I think they mean bit 7, with
4947c478bd9Sstevel@tonic-gate 	 * numbering starting at 0)
4957c478bd9Sstevel@tonic-gate 	 *
4967c478bd9Sstevel@tonic-gate 	 * Lowest 4 bits of field are the 0 based FAT number of the
4977c478bd9Sstevel@tonic-gate 	 * Active FAT.  (only meaningful if bit 8 is set)
4987c478bd9Sstevel@tonic-gate 	 *
4997c478bd9Sstevel@tonic-gate 	 * Field contains combination of these values:
5007c478bd9Sstevel@tonic-gate 	 *
5017c478bd9Sstevel@tonic-gate 	 *	VALUE				DESCRIPTION
5027c478bd9Sstevel@tonic-gate 	 * BGBPB_F_ActiveFATMsk		Mask for low four bits
5037c478bd9Sstevel@tonic-gate 	 * (0x000F)
5047c478bd9Sstevel@tonic-gate 	 * BGBPB_F_NoFATMirror		If set FAT mirroring disabled.
5057c478bd9Sstevel@tonic-gate 	 * (0x0080)			If clear, FAT mirroring enabled.
5067c478bd9Sstevel@tonic-gate 	 *
5077c478bd9Sstevel@tonic-gate 	 * We set the value based on what I've seen on all the FAT32 drives
5087c478bd9Sstevel@tonic-gate 	 * I've seen created by Windows.
5097c478bd9Sstevel@tonic-gate 	 *
5107c478bd9Sstevel@tonic-gate 	 */
5117c478bd9Sstevel@tonic-gate 	wbpb->bpb32.ext_flags = 0x0;
5127c478bd9Sstevel@tonic-gate 	/*
5137c478bd9Sstevel@tonic-gate 	 * No real explanation of the fs_vers file in the BPB doc.  The
5147c478bd9Sstevel@tonic-gate 	 * high byte is supposed to be the major version and the low the
5157c478bd9Sstevel@tonic-gate 	 * minor version.  Again I set according to what I've seen on Windows.
5167c478bd9Sstevel@tonic-gate 	 */
5177c478bd9Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_lo = '\0';
5187c478bd9Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_hi = '\0';
5197c478bd9Sstevel@tonic-gate 	/*
5207c478bd9Sstevel@tonic-gate 	 * The convention appears to be to place the fs info sector
5217c478bd9Sstevel@tonic-gate 	 * immediately after the boot sector, and that the backup boot
5227c478bd9Sstevel@tonic-gate 	 * sector should be at sector 6. (based on what I see with
5237c478bd9Sstevel@tonic-gate 	 * Windows)
5247c478bd9Sstevel@tonic-gate 	 */
5257c478bd9Sstevel@tonic-gate 	wbpb->bpb32.fsinfosec = 1;
5267c478bd9Sstevel@tonic-gate 	wbpb->bpb32.backupboot = 6;
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate static
5307c478bd9Sstevel@tonic-gate void
5317c478bd9Sstevel@tonic-gate fill_bpb_sizes(bpb_t *wbpb, struct ipart part[], int partno, off64_t offset)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	ulong_t usesize;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (GetFsParams || GetSize) {
5367c478bd9Sstevel@tonic-gate 		usesize = ltohi(part[partno].numsect);
5377c478bd9Sstevel@tonic-gate 		if (Verbose) {
5387c478bd9Sstevel@tonic-gate 			(void) printf(
5397c478bd9Sstevel@tonic-gate 			    gettext("Partition size (from FDISK table) "
5407c478bd9Sstevel@tonic-gate 			    "= %d sectors.\n"), usesize);
5417c478bd9Sstevel@tonic-gate 		}
5427c478bd9Sstevel@tonic-gate 	} else {
5437c478bd9Sstevel@tonic-gate 		usesize = warn_mismatch(
5447c478bd9Sstevel@tonic-gate 		    gettext("length of partition (in sectors)"),
5457c478bd9Sstevel@tonic-gate 		    gettext("FDISK table"),
5467c478bd9Sstevel@tonic-gate 		    ltohi(part[partno].numsect), TotSize);
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	if (GetFsParams) {
5507c478bd9Sstevel@tonic-gate 		TotSize = usesize;
5517c478bd9Sstevel@tonic-gate 	} else {
5527c478bd9Sstevel@tonic-gate 		if (usesize > 0xffff)
5537c478bd9Sstevel@tonic-gate 			wbpb->bpb.sectors_in_volume = 0;
5547c478bd9Sstevel@tonic-gate 		else
5557c478bd9Sstevel@tonic-gate 			wbpb->bpb.sectors_in_volume = usesize;
5567c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = usesize;
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = offset;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	if (GetFsParams) {
5627c478bd9Sstevel@tonic-gate 		RelOffset = offset;
5637c478bd9Sstevel@tonic-gate 	} else {
5647c478bd9Sstevel@tonic-gate 		wbpb->sunbpb.bs_offset_high = offset >> 16;
5657c478bd9Sstevel@tonic-gate 		wbpb->sunbpb.bs_offset_low = offset & 0xFFFF;
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate /*
5707c478bd9Sstevel@tonic-gate  *  lookup_FAT_size
5717c478bd9Sstevel@tonic-gate  *
5727c478bd9Sstevel@tonic-gate  *	Given the FDISK partition file system identifier, return the
5737c478bd9Sstevel@tonic-gate  *	expected FAT size for the partition.
5747c478bd9Sstevel@tonic-gate  */
5757c478bd9Sstevel@tonic-gate static
5767c478bd9Sstevel@tonic-gate int
5777c478bd9Sstevel@tonic-gate lookup_FAT_size(uchar_t partid)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	int rval;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	switch (partid) {
5827c478bd9Sstevel@tonic-gate 	case DOSOS12:
5837c478bd9Sstevel@tonic-gate 		rval = 12;
5847c478bd9Sstevel@tonic-gate 		break;
5857c478bd9Sstevel@tonic-gate 	case DOSOS16:
5867c478bd9Sstevel@tonic-gate 	case DOSHUGE:
5877c478bd9Sstevel@tonic-gate 	case FDISK_FAT95:
5887c478bd9Sstevel@tonic-gate 	case X86BOOT:
5897c478bd9Sstevel@tonic-gate 		rval = 16;
5907c478bd9Sstevel@tonic-gate 		break;
5917c478bd9Sstevel@tonic-gate 	case FDISK_WINDOWS:
5927c478bd9Sstevel@tonic-gate 	case FDISK_EXT_WIN:
5937c478bd9Sstevel@tonic-gate 		rval = 32;
5947c478bd9Sstevel@tonic-gate 		break;
5957c478bd9Sstevel@tonic-gate 	case EXTDOS:
5967c478bd9Sstevel@tonic-gate 	case FDISK_EXTLBA:
5977c478bd9Sstevel@tonic-gate 	default:
5987c478bd9Sstevel@tonic-gate 		rval = -1;
5997c478bd9Sstevel@tonic-gate 		break;
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	return (rval);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate  *  seek_partn
6077c478bd9Sstevel@tonic-gate  *
6087c478bd9Sstevel@tonic-gate  *	Seek to the beginning of the partition where we need to install
6097c478bd9Sstevel@tonic-gate  *	the new FAT.  Zero return for any error, but print error
6107c478bd9Sstevel@tonic-gate  *	messages here.
6117c478bd9Sstevel@tonic-gate  */
6127c478bd9Sstevel@tonic-gate static
6137c478bd9Sstevel@tonic-gate int
6147c478bd9Sstevel@tonic-gate seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	struct ipart part[FD_NUMPART];
6177c478bd9Sstevel@tonic-gate 	struct mboot extmboot;
6187c478bd9Sstevel@tonic-gate 	struct mboot mb;
619342440ecSPrasad Singamsetty 	diskaddr_t xstartsect;
6207c478bd9Sstevel@tonic-gate 	off64_t nextseek = 0;
6217c478bd9Sstevel@tonic-gate 	off64_t lastseek = 0;
6227c478bd9Sstevel@tonic-gate 	int logicalDriveCount = 0;
6237c478bd9Sstevel@tonic-gate 	int extendedPart = -1;
6247c478bd9Sstevel@tonic-gate 	int primaryPart = -1;
6257c478bd9Sstevel@tonic-gate 	int bootPart = -1;
626342440ecSPrasad Singamsetty 	uint32_t xnumsect = 0;
6277c478bd9Sstevel@tonic-gate 	int drvnum;
6287c478bd9Sstevel@tonic-gate 	int driveIndex;
6297c478bd9Sstevel@tonic-gate 	int i;
6307c478bd9Sstevel@tonic-gate 	/*
6317c478bd9Sstevel@tonic-gate 	 * Count of drives in the current extended partition's
6327c478bd9Sstevel@tonic-gate 	 * FDISK table, and indexes of the drives themselves.
6337c478bd9Sstevel@tonic-gate 	 */
6347c478bd9Sstevel@tonic-gate 	int extndDrives[FD_NUMPART];
6357c478bd9Sstevel@tonic-gate 	int numDrives = 0;
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * Count of drives (beyond primary) in master boot record's
6387c478bd9Sstevel@tonic-gate 	 * FDISK table, and indexes of the drives themselves.
6397c478bd9Sstevel@tonic-gate 	 */
6407c478bd9Sstevel@tonic-gate 	int extraDrives[FD_NUMPART];
6417c478bd9Sstevel@tonic-gate 	int numExtraDrives = 0;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	if ((drvnum = parse_drvnum(pn)) < 0)
6447c478bd9Sstevel@tonic-gate 		return (PART_NOT_FOUND);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (read(fd, &mb, sizeof (mb)) != sizeof (mb)) {
6477c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
6487c478bd9Sstevel@tonic-gate 		    gettext("Couldn't read a Master Boot Record?!\n"));
6497c478bd9Sstevel@tonic-gate 		return (PART_NOT_FOUND);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	if (ltohs(mb.signature) != BOOTSECSIG) {
6537c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
6547c478bd9Sstevel@tonic-gate 		    gettext("Bad Sig on master boot record!\n"));
6557c478bd9Sstevel@tonic-gate 		return (PART_NOT_FOUND);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	*seekto = 0;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	/*
6617c478bd9Sstevel@tonic-gate 	 * Copy partition table into memory
6627c478bd9Sstevel@tonic-gate 	 */
6637c478bd9Sstevel@tonic-gate 	(void) memcpy(part, mb.parts, sizeof (part));
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/*
6667c478bd9Sstevel@tonic-gate 	 * Get a summary of what is in the Master FDISK table.
6677c478bd9Sstevel@tonic-gate 	 * Normally we expect to find one partition marked as a DOS drive.
6687c478bd9Sstevel@tonic-gate 	 * This partition is the one Windows calls the primary dos partition.
6697c478bd9Sstevel@tonic-gate 	 * If the machine has any logical drives then we also expect
6707c478bd9Sstevel@tonic-gate 	 * to find a partition marked as an extended DOS partition.
6717c478bd9Sstevel@tonic-gate 	 *
6727c478bd9Sstevel@tonic-gate 	 * Sometimes we'll find multiple partitions marked as DOS drives.
6737c478bd9Sstevel@tonic-gate 	 * The Solaris fdisk program allows these partitions
6747c478bd9Sstevel@tonic-gate 	 * to be created, but Windows fdisk no longer does.  We still need
6757c478bd9Sstevel@tonic-gate 	 * to support these, though, since Windows does.  We also need to fix
6767c478bd9Sstevel@tonic-gate 	 * our fdisk to behave like the Windows version.
6777c478bd9Sstevel@tonic-gate 	 *
6787c478bd9Sstevel@tonic-gate 	 * It turns out that some off-the-shelf media have *only* an
6797c478bd9Sstevel@tonic-gate 	 * Extended partition, so we need to deal with that case as
6807c478bd9Sstevel@tonic-gate 	 * well.
6817c478bd9Sstevel@tonic-gate 	 *
6827c478bd9Sstevel@tonic-gate 	 * Only a single (the first) Extended or Boot Partition will
6837c478bd9Sstevel@tonic-gate 	 * be recognized.  Any others will be ignored.
6847c478bd9Sstevel@tonic-gate 	 */
6857c478bd9Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
6867c478bd9Sstevel@tonic-gate 		if (isDosDrive(part[i].systid)) {
6877c478bd9Sstevel@tonic-gate 			if (primaryPart < 0) {
6887c478bd9Sstevel@tonic-gate 				logicalDriveCount++;
6897c478bd9Sstevel@tonic-gate 				primaryPart = i;
6907c478bd9Sstevel@tonic-gate 			} else {
6917c478bd9Sstevel@tonic-gate 				extraDrives[numExtraDrives++] = i;
6927c478bd9Sstevel@tonic-gate 			}
6937c478bd9Sstevel@tonic-gate 			continue;
6947c478bd9Sstevel@tonic-gate 		}
6957c478bd9Sstevel@tonic-gate 		if ((extendedPart < 0) && isDosExtended(part[i].systid)) {
6967c478bd9Sstevel@tonic-gate 			extendedPart = i;
6977c478bd9Sstevel@tonic-gate 			continue;
6987c478bd9Sstevel@tonic-gate 		}
6997c478bd9Sstevel@tonic-gate 		if ((bootPart < 0) && isBootPart(part[i].systid)) {
7007c478bd9Sstevel@tonic-gate 			bootPart = i;
7017c478bd9Sstevel@tonic-gate 			continue;
7027c478bd9Sstevel@tonic-gate 		}
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if (drvnum == BOOT_PARTITION_DRIVE) {
7067c478bd9Sstevel@tonic-gate 		if (bootPart < 0) {
7077c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7087c478bd9Sstevel@tonic-gate 			    gettext("No boot partition found on drive\n"));
7097c478bd9Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7107c478bd9Sstevel@tonic-gate 		}
7117c478bd9Sstevel@tonic-gate 		if ((*seekto = ltohi(part[bootPart].relsect)) == 0) {
7127c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
7137c478bd9Sstevel@tonic-gate 			    "A boot partition starting\nat sector 0 would "
7147c478bd9Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
7157c478bd9Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, bootPart, *seekto);
7197c478bd9Sstevel@tonic-gate 		*seekto *= BPSEC;
7207c478bd9Sstevel@tonic-gate 		FdiskFATsize = lookup_FAT_size(part[bootPart].systid);
7217c478bd9Sstevel@tonic-gate 		if (Verbose)
7227c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Boot partition's offset: "
7237c478bd9Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
7247c478bd9Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
7257c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Partition %s: "), pn);
7267c478bd9Sstevel@tonic-gate 			perror("");
7277c478bd9Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7287c478bd9Sstevel@tonic-gate 		}
7297c478bd9Sstevel@tonic-gate 		return (PART_FOUND);
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (drvnum == PRIMARY_DOS_DRIVE && primaryPart >= 0) {
7337c478bd9Sstevel@tonic-gate 		if ((*seekto = ltohi(part[primaryPart].relsect)) == 0) {
7347c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
7357c478bd9Sstevel@tonic-gate 			    "A partition starting\nat sector 0 would "
7367c478bd9Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
7377c478bd9Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7387c478bd9Sstevel@tonic-gate 		}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, primaryPart, *seekto);
7417c478bd9Sstevel@tonic-gate 		*seekto *= BPSEC;
7427c478bd9Sstevel@tonic-gate 		FdiskFATsize = lookup_FAT_size(part[primaryPart].systid);
7437c478bd9Sstevel@tonic-gate 		if (Verbose)
7447c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Partition's offset: "
7457c478bd9Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
7467c478bd9Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
7477c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Partition %s: "), pn);
7487c478bd9Sstevel@tonic-gate 			perror("");
7497c478bd9Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7507c478bd9Sstevel@tonic-gate 		}
7517c478bd9Sstevel@tonic-gate 		return (PART_FOUND);
7527c478bd9Sstevel@tonic-gate 	}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	/*
7557c478bd9Sstevel@tonic-gate 	 * We are not looking for the C: drive (or there was no primary
7567c478bd9Sstevel@tonic-gate 	 * drive found), so we had better have an extended partition or
7577c478bd9Sstevel@tonic-gate 	 * extra drives in the Master FDISK table.
7587c478bd9Sstevel@tonic-gate 	 */
7597c478bd9Sstevel@tonic-gate 	if ((extendedPart < 0) && (numExtraDrives == 0)) {
7607c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7617c478bd9Sstevel@tonic-gate 		    gettext("No such logical drive "
7627c478bd9Sstevel@tonic-gate 		    "(missing extended partition entry)\n"));
7637c478bd9Sstevel@tonic-gate 		return (PART_NOT_FOUND);
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	if (extendedPart >= 0) {
7677c478bd9Sstevel@tonic-gate 		nextseek = xstartsect = ltohi(part[extendedPart].relsect);
7687c478bd9Sstevel@tonic-gate 		xnumsect = ltohi(part[extendedPart].numsect);
7697c478bd9Sstevel@tonic-gate 		do {
7707c478bd9Sstevel@tonic-gate 			/*
7717c478bd9Sstevel@tonic-gate 			 *  If the seek would not cause us to change
7727c478bd9Sstevel@tonic-gate 			 *  position on the drive, then we're out of
7737c478bd9Sstevel@tonic-gate 			 *  extended partitions to examine.
7747c478bd9Sstevel@tonic-gate 			 */
7757c478bd9Sstevel@tonic-gate 			if (nextseek == lastseek)
7767c478bd9Sstevel@tonic-gate 				break;
7777c478bd9Sstevel@tonic-gate 			logicalDriveCount += numDrives;
7787c478bd9Sstevel@tonic-gate 			/*
7797c478bd9Sstevel@tonic-gate 			 *  Seek the next extended partition, and find
7807c478bd9Sstevel@tonic-gate 			 *  logical drives within it.
7817c478bd9Sstevel@tonic-gate 			 */
7827c478bd9Sstevel@tonic-gate 			if (lseek64(fd, nextseek * BPSEC, SEEK_SET) < 0 ||
7837c478bd9Sstevel@tonic-gate 			    read(fd, &extmboot, sizeof (extmboot)) !=
7847c478bd9Sstevel@tonic-gate 			    sizeof (extmboot)) {
7857c478bd9Sstevel@tonic-gate 				perror(gettext("Unable to read extended "
7867c478bd9Sstevel@tonic-gate 				    "partition record"));
7877c478bd9Sstevel@tonic-gate 				return (PART_NOT_FOUND);
7887c478bd9Sstevel@tonic-gate 			}
7897c478bd9Sstevel@tonic-gate 			(void) memcpy(part, extmboot.parts, sizeof (part));
7907c478bd9Sstevel@tonic-gate 			lastseek = nextseek;
7917c478bd9Sstevel@tonic-gate 			if (ltohs(extmboot.signature) != MBB_MAGIC) {
7927c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
7937c478bd9Sstevel@tonic-gate 				    gettext("Bad signature on "
7947c478bd9Sstevel@tonic-gate 				    "extended partition\n"));
7957c478bd9Sstevel@tonic-gate 				return (PART_NOT_FOUND);
7967c478bd9Sstevel@tonic-gate 			}
7977c478bd9Sstevel@tonic-gate 			/*
7987c478bd9Sstevel@tonic-gate 			 *  Count up drives, and track where the next
7997c478bd9Sstevel@tonic-gate 			 *  extended partition is in case we need it.  We
8007c478bd9Sstevel@tonic-gate 			 *  are expecting only one extended partition.  If
8017c478bd9Sstevel@tonic-gate 			 *  there is more than one we'll only go to the
8027c478bd9Sstevel@tonic-gate 			 *  first one we see, but warn about ignoring.
8037c478bd9Sstevel@tonic-gate 			 */
8047c478bd9Sstevel@tonic-gate 			numDrives = 0;
8057c478bd9Sstevel@tonic-gate 			for (i = 0; i < FD_NUMPART; i++) {
8067c478bd9Sstevel@tonic-gate 				if (isDosDrive(part[i].systid)) {
8077c478bd9Sstevel@tonic-gate 					extndDrives[numDrives++] = i;
8087c478bd9Sstevel@tonic-gate 					continue;
8097c478bd9Sstevel@tonic-gate 				} else if (isDosExtended(part[i].systid)) {
8107c478bd9Sstevel@tonic-gate 					if (nextseek != lastseek) {
8117c478bd9Sstevel@tonic-gate 						/*
8127c478bd9Sstevel@tonic-gate 						 * Already found an extended
8137c478bd9Sstevel@tonic-gate 						 * partition in this table.
8147c478bd9Sstevel@tonic-gate 						 */
8157c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr,
8167c478bd9Sstevel@tonic-gate 						    gettext("WARNING: "
8177c478bd9Sstevel@tonic-gate 						    "Ignoring unexpected "
8187c478bd9Sstevel@tonic-gate 						    "additional extended "
8197c478bd9Sstevel@tonic-gate 						    "partition"));
8207c478bd9Sstevel@tonic-gate 						continue;
8217c478bd9Sstevel@tonic-gate 					}
8227c478bd9Sstevel@tonic-gate 					nextseek = xstartsect +
8237c478bd9Sstevel@tonic-gate 					    ltohi(part[i].relsect);
8247c478bd9Sstevel@tonic-gate 					continue;
8257c478bd9Sstevel@tonic-gate 				}
8267c478bd9Sstevel@tonic-gate 			}
8277c478bd9Sstevel@tonic-gate 		} while (drvnum > logicalDriveCount + numDrives);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 		if (drvnum <= logicalDriveCount + numDrives) {
8307c478bd9Sstevel@tonic-gate 			/*
8317c478bd9Sstevel@tonic-gate 			 * The number of logical drives we've found thus
8327c478bd9Sstevel@tonic-gate 			 * far is enough to get us to the one we were
8337c478bd9Sstevel@tonic-gate 			 * searching for.
8347c478bd9Sstevel@tonic-gate 			 */
8357c478bd9Sstevel@tonic-gate 			driveIndex = logicalDriveCount + numDrives - drvnum;
8367c478bd9Sstevel@tonic-gate 			*seekto =
8377c478bd9Sstevel@tonic-gate 			    ltohi(part[extndDrives[driveIndex]].relsect) +
8387c478bd9Sstevel@tonic-gate 			    lastseek;
8397c478bd9Sstevel@tonic-gate 			if (*seekto == lastseek) {
8407c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
8417c478bd9Sstevel@tonic-gate 				    gettext("Bogus FDISK entry?  A logical "
8427c478bd9Sstevel@tonic-gate 				    "drive starting at\nsector 0x%llx would "
8437c478bd9Sstevel@tonic-gate 				    "collide with the\nFDISK information in "
8447c478bd9Sstevel@tonic-gate 				    "that sector.\n"), *seekto);
8457c478bd9Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8467c478bd9Sstevel@tonic-gate 			} else if (*seekto <= xstartsect ||
8477c478bd9Sstevel@tonic-gate 			    *seekto >= (xstartsect + xnumsect)) {
8487c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
8497c478bd9Sstevel@tonic-gate 				    gettext("Bogus FDISK entry?  "
8507c478bd9Sstevel@tonic-gate 				    "Logical drive start sector (0x%llx)\n"
8517c478bd9Sstevel@tonic-gate 				    "not within extended partition! "
8527c478bd9Sstevel@tonic-gate 				    "(Expected in range 0x%x - 0x%x)\n"),
8537c478bd9Sstevel@tonic-gate 				    *seekto, xstartsect + 1,
8547c478bd9Sstevel@tonic-gate 				    xstartsect + xnumsect - 1);
8557c478bd9Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8567c478bd9Sstevel@tonic-gate 			}
8577c478bd9Sstevel@tonic-gate 			fill_bpb_sizes(wbpb, part, extndDrives[driveIndex],
8587c478bd9Sstevel@tonic-gate 			    *seekto);
8597c478bd9Sstevel@tonic-gate 			*seekto *= BPSEC;
8607c478bd9Sstevel@tonic-gate 			FdiskFATsize = lookup_FAT_size(
8617c478bd9Sstevel@tonic-gate 			    part[extndDrives[driveIndex]].systid);
8627c478bd9Sstevel@tonic-gate 			if (Verbose)
8637c478bd9Sstevel@tonic-gate 				(void) printf(gettext("Partition's offset: "
8647c478bd9Sstevel@tonic-gate 				    "Sector 0x%x.\n"), *seekto/BPSEC);
8657c478bd9Sstevel@tonic-gate 			if (lseek64(fd, *seekto, SEEK_SET) < 0) {
8667c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
8677c478bd9Sstevel@tonic-gate 				    gettext("Partition %s: "), pn);
8687c478bd9Sstevel@tonic-gate 				perror("");
8697c478bd9Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8707c478bd9Sstevel@tonic-gate 			}
8717c478bd9Sstevel@tonic-gate 			return (PART_FOUND);
8727c478bd9Sstevel@tonic-gate 		} else {
8737c478bd9Sstevel@tonic-gate 			/*
8747c478bd9Sstevel@tonic-gate 			 * We ran out of extended dos partition
8757c478bd9Sstevel@tonic-gate 			 * drives.  The only hope now is to go
8767c478bd9Sstevel@tonic-gate 			 * back to extra drives defined in the master
8777c478bd9Sstevel@tonic-gate 			 * fdisk table.  But we overwrote that table
8787c478bd9Sstevel@tonic-gate 			 * already, so we must load it in again.
8797c478bd9Sstevel@tonic-gate 			 */
8807c478bd9Sstevel@tonic-gate 			logicalDriveCount += numDrives;
8817c478bd9Sstevel@tonic-gate 			(void) memcpy(part, mb.parts, sizeof (part));
8827c478bd9Sstevel@tonic-gate 		}
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 	/*
8857c478bd9Sstevel@tonic-gate 	 *  Still haven't found the drive, is it an extra
8867c478bd9Sstevel@tonic-gate 	 *  drive defined in the main FDISK table?
8877c478bd9Sstevel@tonic-gate 	 */
8887c478bd9Sstevel@tonic-gate 	if (drvnum <= logicalDriveCount + numExtraDrives) {
8897c478bd9Sstevel@tonic-gate 		driveIndex = logicalDriveCount + numExtraDrives - drvnum;
8907c478bd9Sstevel@tonic-gate 		*seekto = ltohi(part[extraDrives[driveIndex]].relsect);
8917c478bd9Sstevel@tonic-gate 		if (*seekto == 0) {
8927c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
8937c478bd9Sstevel@tonic-gate 			    "A partition starting\nat sector 0 would "
8947c478bd9Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
8957c478bd9Sstevel@tonic-gate 			return (PART_NOT_FOUND);
8967c478bd9Sstevel@tonic-gate 		}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, extraDrives[driveIndex], *seekto);
8997c478bd9Sstevel@tonic-gate 		*seekto *= BPSEC;
9007c478bd9Sstevel@tonic-gate 		FdiskFATsize =
9017c478bd9Sstevel@tonic-gate 		    lookup_FAT_size(part[extraDrives[driveIndex]].systid);
9027c478bd9Sstevel@tonic-gate 		if (Verbose)
9037c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Partition's offset: "
9047c478bd9Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
9057c478bd9Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
9067c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
9077c478bd9Sstevel@tonic-gate 			    gettext("Partition %s: "), pn);
9087c478bd9Sstevel@tonic-gate 			perror("");
9097c478bd9Sstevel@tonic-gate 			return (PART_NOT_FOUND);
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 		return (PART_FOUND);
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("No such logical drive\n"));
9147c478bd9Sstevel@tonic-gate 	return (PART_NOT_FOUND);
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate /*
9187c478bd9Sstevel@tonic-gate  *  seek_nofdisk
9197c478bd9Sstevel@tonic-gate  *
9207c478bd9Sstevel@tonic-gate  *	User is asking us to trust them that they know best.
9217c478bd9Sstevel@tonic-gate  *	We basically won't do much seeking here, the only seeking we'll do
9227c478bd9Sstevel@tonic-gate  *	is if the 'hidden' parameter was given.
9237c478bd9Sstevel@tonic-gate  */
9247c478bd9Sstevel@tonic-gate static
9257c478bd9Sstevel@tonic-gate int
9267c478bd9Sstevel@tonic-gate seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto)
9277c478bd9Sstevel@tonic-gate {
9287c478bd9Sstevel@tonic-gate 	if (TotSize > 0xffff)
9297c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 0;
9307c478bd9Sstevel@tonic-gate 	else
9317c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = (short)TotSize;
9327c478bd9Sstevel@tonic-gate 	wbpb->bpb.sectors_in_logical_volume = TotSize;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	*seekto = RelOffset * BPSEC;
9357c478bd9Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = RelOffset;
9367c478bd9Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = RelOffset >> 16;
9377c478bd9Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = RelOffset & 0xFFFF;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	if (Verbose)
9407c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Requested offset: Sector %x.\n"),
9417c478bd9Sstevel@tonic-gate 		    *seekto/BPSEC);
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	if (lseek64(fd, *seekto, SEEK_SET) < 0) {
9447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
9457c478bd9Sstevel@tonic-gate 		    gettext("User specified start sector %d"), RelOffset);
9467c478bd9Sstevel@tonic-gate 		perror("");
9477c478bd9Sstevel@tonic-gate 		return (PART_NOT_FOUND);
9487c478bd9Sstevel@tonic-gate 	}
9497c478bd9Sstevel@tonic-gate 	return (PART_FOUND);
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate /*
9537c478bd9Sstevel@tonic-gate  * set_fat_string
9547c478bd9Sstevel@tonic-gate  *
9557c478bd9Sstevel@tonic-gate  *	Fill in the type string of the FAT
9567c478bd9Sstevel@tonic-gate  */
9577c478bd9Sstevel@tonic-gate static
9587c478bd9Sstevel@tonic-gate void
9597c478bd9Sstevel@tonic-gate set_fat_string(bpb_t *wbpb, int fatsize)
9607c478bd9Sstevel@tonic-gate {
9617c478bd9Sstevel@tonic-gate 	if (fatsize == 12) {
9627c478bd9Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT12_TYPE_STRING,
9637c478bd9Sstevel@tonic-gate 		    strlen(FAT12_TYPE_STRING));
9647c478bd9Sstevel@tonic-gate 	} else if (fatsize == 16) {
9657c478bd9Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT16_TYPE_STRING,
9667c478bd9Sstevel@tonic-gate 		    strlen(FAT16_TYPE_STRING));
9677c478bd9Sstevel@tonic-gate 	} else {
9687c478bd9Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT32_TYPE_STRING,
9697c478bd9Sstevel@tonic-gate 		    strlen(FAT32_TYPE_STRING));
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate /*
9747c478bd9Sstevel@tonic-gate  *  prepare_image_file
9757c478bd9Sstevel@tonic-gate  *
9767c478bd9Sstevel@tonic-gate  *	Open the file that will hold the image (as opposed to the image
9777c478bd9Sstevel@tonic-gate  *	being written to the boot sector of an actual disk).
9787c478bd9Sstevel@tonic-gate  */
9797c478bd9Sstevel@tonic-gate static
9807c478bd9Sstevel@tonic-gate int
9817c478bd9Sstevel@tonic-gate prepare_image_file(char *fn, bpb_t *wbpb)
9827c478bd9Sstevel@tonic-gate {
9837c478bd9Sstevel@tonic-gate 	int fd;
9847c478bd9Sstevel@tonic-gate 	char zerobyte = '\0';
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) {
9877c478bd9Sstevel@tonic-gate 		perror(fn);
9887c478bd9Sstevel@tonic-gate 		exit(2);
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	if (Imagesize == 5) {
9927c478bd9Sstevel@tonic-gate 		/* Disk image of a 1.2M floppy */
9937c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 2 * 80 * 15;
9947c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 15;
9957c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = 15;
9967c478bd9Sstevel@tonic-gate 		wbpb->bpb.heads = 2;
9977c478bd9Sstevel@tonic-gate 		wbpb->bpb.media = 0xF9;
9987c478bd9Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 224;
9997c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_cluster = 1;
10007c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 7;
10017c478bd9Sstevel@tonic-gate 	} else {
10027c478bd9Sstevel@tonic-gate 		/* Disk image of a 1.44M floppy */
10037c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 2 * 80 * 18;
10047c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 18;
10057c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = 18;
10067c478bd9Sstevel@tonic-gate 		wbpb->bpb.heads = 2;
10077c478bd9Sstevel@tonic-gate 		wbpb->bpb.media = 0xF0;
10087c478bd9Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 224;
10097c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_cluster = 1;
10107c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 9;
10117c478bd9Sstevel@tonic-gate 	}
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/*
10147c478bd9Sstevel@tonic-gate 	 * Make a holey file, with length the exact
10157c478bd9Sstevel@tonic-gate 	 * size of the floppy image.
10167c478bd9Sstevel@tonic-gate 	 */
10177c478bd9Sstevel@tonic-gate 	if (lseek(fd, (wbpb->bpb.sectors_in_volume * BPSEC)-1, SEEK_SET) < 0) {
10187c478bd9Sstevel@tonic-gate 		(void) close(fd);
10197c478bd9Sstevel@tonic-gate 		perror(fn);
10207c478bd9Sstevel@tonic-gate 		exit(2);
10217c478bd9Sstevel@tonic-gate 	}
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	if (write(fd, &zerobyte, 1) != 1) {
10247c478bd9Sstevel@tonic-gate 		(void) close(fd);
10257c478bd9Sstevel@tonic-gate 		perror(fn);
10267c478bd9Sstevel@tonic-gate 		exit(2);
10277c478bd9Sstevel@tonic-gate 	}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) < 0) {
10307c478bd9Sstevel@tonic-gate 		(void) close(fd);
10317c478bd9Sstevel@tonic-gate 		perror(fn);
10327c478bd9Sstevel@tonic-gate 		exit(2);
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	Fatentsize = 12;  /* Size of fat entry in bits */
10367c478bd9Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = 0;
10417c478bd9Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = 0;
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	return (fd);
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate /*
10477c478bd9Sstevel@tonic-gate  *  partn_lecture
10487c478bd9Sstevel@tonic-gate  *
10497c478bd9Sstevel@tonic-gate  *	Give a brief sermon on dev_name user should pass to
10507c478bd9Sstevel@tonic-gate  *	the program from the command line.
10517c478bd9Sstevel@tonic-gate  *
10527c478bd9Sstevel@tonic-gate  */
10537c478bd9Sstevel@tonic-gate static
10547c478bd9Sstevel@tonic-gate void
10557c478bd9Sstevel@tonic-gate partn_lecture(char *dn)
10567c478bd9Sstevel@tonic-gate {
10577c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
10587c478bd9Sstevel@tonic-gate 	    gettext("\nDevice %s was assumed to be a diskette.\n"
10597c478bd9Sstevel@tonic-gate 	    "A diskette specific operation failed on this device.\n"
10607c478bd9Sstevel@tonic-gate 	    "If the device is a hard disk, provide the name of "
10617c478bd9Sstevel@tonic-gate 	    "the full physical disk,\n"
10627c478bd9Sstevel@tonic-gate 	    "and qualify that name with a logical drive specifier.\n\n"
10637c478bd9Sstevel@tonic-gate 	    "Hint: the device is usually something similar to\n\n"
10647c478bd9Sstevel@tonic-gate 	    "/dev/rdsk/c0d0p0 or /dev/rdsk/c0t0d0p0 (x86)\n"
10657c478bd9Sstevel@tonic-gate 	    "/dev/rdsk/c0t5d0s2 (sparc)\n\n"
10667c478bd9Sstevel@tonic-gate 	    "The drive specifier is appended to the device name."
10677c478bd9Sstevel@tonic-gate 	    " For example:\n\n"
10687c478bd9Sstevel@tonic-gate 	    "/dev/rdsk/c0t5d0s2:c or /dev/rdsk/c0d0p0:boot\n\n"), dn);
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate static
10727c478bd9Sstevel@tonic-gate void
10737c478bd9Sstevel@tonic-gate warn_funky_floppy(void)
10747c478bd9Sstevel@tonic-gate {
10757c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
10767c478bd9Sstevel@tonic-gate 	    gettext("Use the 'nofdisk' option to create file systems\n"
10777c478bd9Sstevel@tonic-gate 	    "on non-standard floppies.\n\n"));
10787c478bd9Sstevel@tonic-gate 	exit(4);
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate static
10827c478bd9Sstevel@tonic-gate void
10837c478bd9Sstevel@tonic-gate warn_funky_fatsize(void)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
10867c478bd9Sstevel@tonic-gate 	    gettext("Non-standard FAT size requested for floppy.\n"
10877c478bd9Sstevel@tonic-gate 	    "The 'nofdisk' option must be used to\n"
10887c478bd9Sstevel@tonic-gate 	    "override the 12 bit floppy default.\n\n"));
10897c478bd9Sstevel@tonic-gate 	exit(4);
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate static
10937c478bd9Sstevel@tonic-gate void
10947c478bd9Sstevel@tonic-gate floppy_bpb_fillin(bpb_t *wbpb, int diam, int hds, int spt)
10957c478bd9Sstevel@tonic-gate {
10967c478bd9Sstevel@tonic-gate 	switch (diam) {
10977c478bd9Sstevel@tonic-gate 	case 3:
10987c478bd9Sstevel@tonic-gate 		switch (hds) {
10997c478bd9Sstevel@tonic-gate 		case 2:
11007c478bd9Sstevel@tonic-gate 			switch (spt) {
11017c478bd9Sstevel@tonic-gate 			case 9:
11027c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xF9;
11037c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
11047c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
11057c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 3;
11067c478bd9Sstevel@tonic-gate 				break;
11077c478bd9Sstevel@tonic-gate 			case 18:
11087c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xF0;
11097c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 224;
11107c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11117c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 9;
11127c478bd9Sstevel@tonic-gate 				break;
11137c478bd9Sstevel@tonic-gate 			case 36:
11147c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xF0;
11157c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 240;
11167c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
11177c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 9;
11187c478bd9Sstevel@tonic-gate 				break;
11197c478bd9Sstevel@tonic-gate 			default:
11207c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
11217c478bd9Sstevel@tonic-gate 				    gettext("Unknown diskette parameters!  "
11227c478bd9Sstevel@tonic-gate 				    "3.5'' diskette with %d heads "
11237c478bd9Sstevel@tonic-gate 				    "and %d sectors/track.\n"), hds, spt);
11247c478bd9Sstevel@tonic-gate 				warn_funky_floppy();
11257c478bd9Sstevel@tonic-gate 			}
11267c478bd9Sstevel@tonic-gate 			break;
11277c478bd9Sstevel@tonic-gate 		case 1:
11287c478bd9Sstevel@tonic-gate 		default:
11297c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
11307c478bd9Sstevel@tonic-gate 			    gettext("Unknown diskette parameters!  "
11317c478bd9Sstevel@tonic-gate 			    "3.5'' diskette with %d heads "), hds);
11327c478bd9Sstevel@tonic-gate 			warn_funky_floppy();
11337c478bd9Sstevel@tonic-gate 		}
11347c478bd9Sstevel@tonic-gate 		break;
11357c478bd9Sstevel@tonic-gate 	case 5:
11367c478bd9Sstevel@tonic-gate 		switch (hds) {
11377c478bd9Sstevel@tonic-gate 		case 2:
11387c478bd9Sstevel@tonic-gate 			switch (spt) {
11397c478bd9Sstevel@tonic-gate 			case 15:
11407c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xF9;
11417c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 224;
11427c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11437c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 7;
11447c478bd9Sstevel@tonic-gate 				break;
11457c478bd9Sstevel@tonic-gate 			case 9:
11467c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xFD;
11477c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
11487c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
11497c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
11507c478bd9Sstevel@tonic-gate 				break;
11517c478bd9Sstevel@tonic-gate 			case 8:
11527c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xFF;
11537c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
11547c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11557c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
11567c478bd9Sstevel@tonic-gate 				break;
11577c478bd9Sstevel@tonic-gate 			default:
11587c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
11597c478bd9Sstevel@tonic-gate 				    gettext("Unknown diskette parameters!  "
11607c478bd9Sstevel@tonic-gate 				    "5.25'' diskette with %d heads "
11617c478bd9Sstevel@tonic-gate 				    "and %d sectors/track.\n"), hds, spt);
11627c478bd9Sstevel@tonic-gate 				warn_funky_floppy();
11637c478bd9Sstevel@tonic-gate 			}
11647c478bd9Sstevel@tonic-gate 			break;
11657c478bd9Sstevel@tonic-gate 		case 1:
11667c478bd9Sstevel@tonic-gate 			switch (spt) {
11677c478bd9Sstevel@tonic-gate 			case 9:
11687c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xFC;
11697c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 64;
11707c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11717c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
11727c478bd9Sstevel@tonic-gate 				break;
11737c478bd9Sstevel@tonic-gate 			case 8:
11747c478bd9Sstevel@tonic-gate 				wbpb->bpb.media = 0xFE;
11757c478bd9Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 64;
11767c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11777c478bd9Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 1;
11787c478bd9Sstevel@tonic-gate 				break;
11797c478bd9Sstevel@tonic-gate 			default:
11807c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
11817c478bd9Sstevel@tonic-gate 				    gettext("Unknown diskette parameters! "
11827c478bd9Sstevel@tonic-gate 				    "5.25'' diskette with %d heads "
11837c478bd9Sstevel@tonic-gate 				    "and %d sectors/track.\n"), hds, spt);
11847c478bd9Sstevel@tonic-gate 				warn_funky_floppy();
11857c478bd9Sstevel@tonic-gate 			}
11867c478bd9Sstevel@tonic-gate 			break;
11877c478bd9Sstevel@tonic-gate 		default:
11887c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
11897c478bd9Sstevel@tonic-gate 			    gettext("Unknown diskette parameters! "
11907c478bd9Sstevel@tonic-gate 			    "5.25'' diskette with %d heads."), hds);
11917c478bd9Sstevel@tonic-gate 			warn_funky_floppy();
11927c478bd9Sstevel@tonic-gate 		}
11937c478bd9Sstevel@tonic-gate 		break;
11947c478bd9Sstevel@tonic-gate 	default:
11957c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
11967c478bd9Sstevel@tonic-gate 		    gettext("\nUnknown diskette type.  Only know about "
11977c478bd9Sstevel@tonic-gate 		    "5.25'' and 3.5'' diskettes.\n"));
11987c478bd9Sstevel@tonic-gate 		warn_funky_floppy();
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate  *  lookup_floppy
12047c478bd9Sstevel@tonic-gate  *
12057c478bd9Sstevel@tonic-gate  *	Look up a media descriptor byte and other crucial BPB values
12067c478bd9Sstevel@tonic-gate  *	based on floppy characteristics.
12077c478bd9Sstevel@tonic-gate  */
12087c478bd9Sstevel@tonic-gate static
12097c478bd9Sstevel@tonic-gate void
12107c478bd9Sstevel@tonic-gate lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate 	ulong_t tsize;
12137c478bd9Sstevel@tonic-gate 	ulong_t cyls, spt, hds, diam;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	cyls = fdchar->fdc_ncyl;
12167c478bd9Sstevel@tonic-gate 	diam = fdchar->fdc_medium;
12177c478bd9Sstevel@tonic-gate 	spt = fdchar->fdc_secptrack;
12187c478bd9Sstevel@tonic-gate 	hds = fdchar->fdc_nhead;
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	tsize = cyls * hds * spt;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	if (GetFsParams)
12237c478bd9Sstevel@tonic-gate 		TotSize = tsize;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	if (GetSize) {
12267c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = tsize;
12277c478bd9Sstevel@tonic-gate 	} else {
12287c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume =
12297c478bd9Sstevel@tonic-gate 		    warn_mismatch(
12307c478bd9Sstevel@tonic-gate 		    gettext("length of partition (in sectors)"),
12317c478bd9Sstevel@tonic-gate 		    gettext("FDIOGCHAR call"), tsize, TotSize);
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 	wbpb->bpb.sectors_in_volume =
12347c478bd9Sstevel@tonic-gate 	    (short)wbpb->bpb.sectors_in_logical_volume;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	if (GetSPT) {
12377c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = spt;
12387c478bd9Sstevel@tonic-gate 	} else {
12397c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track =
12407c478bd9Sstevel@tonic-gate 		    warn_mismatch(
12417c478bd9Sstevel@tonic-gate 		    gettext("sectors per track"),
12427c478bd9Sstevel@tonic-gate 		    gettext("FDIOGCHAR call"), spt, SecPerTrk);
12437c478bd9Sstevel@tonic-gate 		spt = wbpb->bpb.sectors_per_track;
12447c478bd9Sstevel@tonic-gate 	}
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	if (GetTPC) {
12477c478bd9Sstevel@tonic-gate 		wbpb->bpb.heads = hds;
12487c478bd9Sstevel@tonic-gate 	} else {
12497c478bd9Sstevel@tonic-gate 		wbpb->bpb.heads =
12507c478bd9Sstevel@tonic-gate 		    warn_mismatch(
12517c478bd9Sstevel@tonic-gate 		    gettext("number of heads"),
12527c478bd9Sstevel@tonic-gate 		    gettext("FDIOGCHAR call"), hds, TrkPerCyl);
12537c478bd9Sstevel@tonic-gate 		hds = wbpb->bpb.heads;
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	Fatentsize = 12;  /* Size of fat entry in bits */
12577c478bd9Sstevel@tonic-gate 	if (!GetBPF && BitsPerFAT != Fatentsize) {
12587c478bd9Sstevel@tonic-gate 		warn_funky_fatsize();
12597c478bd9Sstevel@tonic-gate 	}
12607c478bd9Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = 0;
12657c478bd9Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = 0;
12667c478bd9Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = 0;
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	floppy_bpb_fillin(wbpb, diam, hds, spt);
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate  *  compute_cluster_size
12737c478bd9Sstevel@tonic-gate  *
12747c478bd9Sstevel@tonic-gate  *	Compute an acceptable sectors/cluster value.
12757c478bd9Sstevel@tonic-gate  *
1276849ee7a1Swyllys  * 	Based on values from the Hardware White Paper
1277849ee7a1Swyllys  *	from Microsoft.
1278849ee7a1Swyllys  *	"Microsoft Extensible Firmware Initiative
1279849ee7a1Swyllys  *	 FAT32 File System Specification
1280849ee7a1Swyllys  *	 FAT: General Overview of On-Disk Format"
12817c478bd9Sstevel@tonic-gate  *
1282849ee7a1Swyllys  *	Version 1.03, December 6, 2000
1283849ee7a1Swyllys  *
12847c478bd9Sstevel@tonic-gate  */
12857c478bd9Sstevel@tonic-gate static
12867c478bd9Sstevel@tonic-gate void
12877c478bd9Sstevel@tonic-gate compute_cluster_size(bpb_t *wbpb)
12887c478bd9Sstevel@tonic-gate {
128957e22c6cSwyllys 	ulong_t volsize;
129057e22c6cSwyllys 	ulong_t spc;
12910576819eSwyllys 	ulong_t rds, tmpval1, tmpval2;
12920576819eSwyllys 	ulong_t fatsz;
1293849ee7a1Swyllys 	int newfat = 16;
1294849ee7a1Swyllys 
1295849ee7a1Swyllys #define	FAT12_MAX_CLUSTERS	0x0FF4
1296849ee7a1Swyllys #define	FAT16_MAX_CLUSTERS	0xFFF4
1297849ee7a1Swyllys #define	FAT32_MAX_CLUSTERS	0x0FFFFFF0
1298849ee7a1Swyllys #define	FAT32_SUGGESTED_NCLUST	0x400000
1299849ee7a1Swyllys 
1300849ee7a1Swyllys 	/* compute volume size in sectors. */
13017c478bd9Sstevel@tonic-gate 	volsize = wbpb->bpb.sectors_in_volume ? wbpb->bpb.sectors_in_volume :
13027c478bd9Sstevel@tonic-gate 	    wbpb->bpb.sectors_in_logical_volume;
13037c478bd9Sstevel@tonic-gate 	volsize -= wbpb->bpb.resv_sectors;
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 	if (GetSPC) {
1306849ee7a1Swyllys 		/*
1307849ee7a1Swyllys 		 * User indicated what sort of FAT to create,
1308849ee7a1Swyllys 		 * make sure it is valid with the given size
1309849ee7a1Swyllys 		 * and compute an SPC value.
1310849ee7a1Swyllys 		 */
1311849ee7a1Swyllys 		if (!MakeFAT32) { /* FAT16 */
1312849ee7a1Swyllys 			/* volsize is in sectors */
1313849ee7a1Swyllys 			if (volsize < FAT12_MAX_CLUSTERS) {
1314849ee7a1Swyllys 				(void) fprintf(stderr,
1315849ee7a1Swyllys 				    gettext("Requested size is too "
1316849ee7a1Swyllys 				    "small for FAT16.\n"));
1317849ee7a1Swyllys 				exit(4);
13187c478bd9Sstevel@tonic-gate 			}
1319849ee7a1Swyllys 			/* SPC must be a power of 2 */
1320849ee7a1Swyllys 			for (spc = 1; spc <= 64; spc = spc * 2) {
1321849ee7a1Swyllys 				if (volsize < spc * FAT16_MAX_CLUSTERS)
1322849ee7a1Swyllys 					break;
1323849ee7a1Swyllys 			}
1324849ee7a1Swyllys 			if (volsize > (spc * FAT16_MAX_CLUSTERS)) {
1325849ee7a1Swyllys 				(void) fprintf(stderr,
1326849ee7a1Swyllys 				    gettext("Requested size is too "
1327849ee7a1Swyllys 				    "large for FAT16.\n"));
1328849ee7a1Swyllys 				exit(4);
1329849ee7a1Swyllys 			}
1330849ee7a1Swyllys 		} else { /* FAT32 */
1331849ee7a1Swyllys 			/* volsize is in sectors */
1332849ee7a1Swyllys 			if (volsize < FAT16_MAX_CLUSTERS) {
1333849ee7a1Swyllys 				(void) fprintf(stderr,
1334849ee7a1Swyllys 				    gettext("Requested size is too "
1335849ee7a1Swyllys 				    "small for FAT32.\n"));
1336849ee7a1Swyllys 				exit(4);
1337849ee7a1Swyllys 			}
1338849ee7a1Swyllys 			/* SPC must be a power of 2 */
1339849ee7a1Swyllys 			for (spc = 1; spc <= 64; spc = spc * 2) {
1340849ee7a1Swyllys 				if (volsize < (spc * FAT32_SUGGESTED_NCLUST))
1341849ee7a1Swyllys 					break;
1342849ee7a1Swyllys 			}
1343849ee7a1Swyllys 			if (volsize > (spc * FAT32_MAX_CLUSTERS)) {
1344849ee7a1Swyllys 				(void) fprintf(stderr,
1345849ee7a1Swyllys 				    gettext("Requested size is too "
1346849ee7a1Swyllys 				    "large for FAT32.\n"));
13477c478bd9Sstevel@tonic-gate 				exit(4);
13487c478bd9Sstevel@tonic-gate 			}
13497c478bd9Sstevel@tonic-gate 		}
13507c478bd9Sstevel@tonic-gate 	} else {
1351849ee7a1Swyllys 		/*
1352849ee7a1Swyllys 		 * User gave the SPC as an explicit option,
1353849ee7a1Swyllys 		 * make sure it will work with the requested
1354849ee7a1Swyllys 		 * volume size.
1355849ee7a1Swyllys 		 */
1356849ee7a1Swyllys 		int nclust;
1357849ee7a1Swyllys 
13587c478bd9Sstevel@tonic-gate 		spc = SecPerClust;
1359849ee7a1Swyllys 		nclust = volsize / spc;
1360849ee7a1Swyllys 
1361849ee7a1Swyllys 		if (nclust <= FAT16_MAX_CLUSTERS && MakeFAT32) {
1362f127cb91Sfrankho 			(void) fprintf(stderr, gettext("Requested size is too "
1363849ee7a1Swyllys 			    "small for FAT32.\n"));
1364849ee7a1Swyllys 			exit(4);
1365849ee7a1Swyllys 		}
1366849ee7a1Swyllys 		if (!MakeFAT32) {
1367849ee7a1Swyllys 			/* Determine if FAT12 or FAT16 */
1368849ee7a1Swyllys 			if (nclust < FAT12_MAX_CLUSTERS)
1369849ee7a1Swyllys 				newfat = 12;
1370849ee7a1Swyllys 			else if (nclust < FAT16_MAX_CLUSTERS)
1371849ee7a1Swyllys 				newfat = 16;
1372849ee7a1Swyllys 			else {
1373849ee7a1Swyllys 				(void) fprintf(stderr,
1374849ee7a1Swyllys 				    gettext("Requested size is too "
1375849ee7a1Swyllys 				    "small for FAT32.\n"));
1376849ee7a1Swyllys 				exit(4);
1377849ee7a1Swyllys 			}
1378849ee7a1Swyllys 		}
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 
13810576819eSwyllys 	/*
13820576819eSwyllys 	 * RootDirSectors = ((BPB_RootEntCnt * 32) +
13830576819eSwyllys 	 *	(BPB_BytsPerSec  1)) / BPB_BytsPerSec;
13840576819eSwyllys 	 */
13850576819eSwyllys 	rds = ((wbpb->bpb.num_root_entries * 32) +
1386f127cb91Sfrankho 	    (wbpb->bpb.bytes_sector - 1)) / wbpb->bpb.bytes_sector;
13870576819eSwyllys 
13887c478bd9Sstevel@tonic-gate 	if (GetBPF) {
13897c478bd9Sstevel@tonic-gate 		if (MakeFAT32)
13907c478bd9Sstevel@tonic-gate 			Fatentsize = 32;
13917c478bd9Sstevel@tonic-gate 		else
1392849ee7a1Swyllys 			Fatentsize = newfat;
13937c478bd9Sstevel@tonic-gate 	} else {
13947c478bd9Sstevel@tonic-gate 		Fatentsize = BitsPerFAT;
13950576819eSwyllys 
13960576819eSwyllys 		if (Fatentsize == 12 &&
13970576819eSwyllys 		    (volsize - rds) >= DOS_F12MAXC * spc) {
13987c478bd9Sstevel@tonic-gate 			/*
13997c478bd9Sstevel@tonic-gate 			 * If we don't have an input TTY, or we aren't
14007c478bd9Sstevel@tonic-gate 			 * really doing anything, then don't ask
14017c478bd9Sstevel@tonic-gate 			 * questions.  Assume a yes answer to any
14027c478bd9Sstevel@tonic-gate 			 * questions we would ask.
14037c478bd9Sstevel@tonic-gate 			 */
14047c478bd9Sstevel@tonic-gate 			if (Notreally || !isatty(fileno(stdin))) {
14057c478bd9Sstevel@tonic-gate 				(void) printf(
14067c478bd9Sstevel@tonic-gate 				gettext("Volume too large for 12 bit FAT,"
14077c478bd9Sstevel@tonic-gate 				    " increasing to 16 bit FAT size.\n"));
14087c478bd9Sstevel@tonic-gate 				(void) fflush(stdout);
14097c478bd9Sstevel@tonic-gate 				Fatentsize = 16;
14107c478bd9Sstevel@tonic-gate 			} else {
14117c478bd9Sstevel@tonic-gate 				(void) printf(
14127c478bd9Sstevel@tonic-gate 				gettext("Volume too large for a 12 bit FAT.\n"
14137c478bd9Sstevel@tonic-gate 				    "Increase to 16 bit FAT "
14147c478bd9Sstevel@tonic-gate 				    "and continue (y/n)? "));
14157c478bd9Sstevel@tonic-gate 				(void) fflush(stdout);
14167c478bd9Sstevel@tonic-gate 				if (yes())
14177c478bd9Sstevel@tonic-gate 					Fatentsize = 16;
14187c478bd9Sstevel@tonic-gate 				else
14197c478bd9Sstevel@tonic-gate 					exit(5);
14207c478bd9Sstevel@tonic-gate 			}
14217c478bd9Sstevel@tonic-gate 		}
14227c478bd9Sstevel@tonic-gate 	}
14237c478bd9Sstevel@tonic-gate 	wbpb->bpb.sectors_per_cluster = spc;
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	if (!GetFsParams && FdiskFATsize < 0) {
14267c478bd9Sstevel@tonic-gate 		(void) printf(
14277c478bd9Sstevel@tonic-gate 		    gettext("Cannot verify chosen/computed FAT "
14287c478bd9Sstevel@tonic-gate 		    "entry size (%d bits) with FDISK table.\n"
14297c478bd9Sstevel@tonic-gate 		    "FDISK table has an unknown file system "
14307c478bd9Sstevel@tonic-gate 		    "type for this device.  Giving up...\n"),
14317c478bd9Sstevel@tonic-gate 		    Fatentsize, Fatentsize);
14327c478bd9Sstevel@tonic-gate 		exit(6);
14337c478bd9Sstevel@tonic-gate 	} else if (!GetFsParams && FdiskFATsize && FdiskFATsize != Fatentsize) {
14347c478bd9Sstevel@tonic-gate 		(void) printf(
14357c478bd9Sstevel@tonic-gate 		    gettext("Chosen/computed FAT entry size (%d bits) "
14367c478bd9Sstevel@tonic-gate 		    "does not match FDISK table (%d bits).\n"),
14377c478bd9Sstevel@tonic-gate 		    Fatentsize, FdiskFATsize);
14387c478bd9Sstevel@tonic-gate 		(void) printf(
14397c478bd9Sstevel@tonic-gate 		    gettext("Use -o fat=%d to build a FAT "
14407c478bd9Sstevel@tonic-gate 		    "that matches the FDISK entry.\n"), FdiskFATsize);
14417c478bd9Sstevel@tonic-gate 		exit(6);
14427c478bd9Sstevel@tonic-gate 	}
14437c478bd9Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
14440576819eSwyllys 	/*
14450576819eSwyllys 	 * Compure the FAT sizes according to algorithm from Microsoft:
14460576819eSwyllys 	 *
14470576819eSwyllys 	 * RootDirSectors = ((BPB_RootEntCnt * 32) +
14480576819eSwyllys 	 *	(BPB_BytsPerSec  1)) / BPB_BytsPerSec;
14490576819eSwyllys 	 * TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors);
14500576819eSwyllys 	 * TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
14510576819eSwyllys 	 * If (FATType == FAT32)
14520576819eSwyllys 	 * 	TmpVal2 = TmpVal2 / 2;
14530576819eSwyllys 	 * FATSz = (TMPVal1 + (TmpVal2  1)) / TmpVal2;
14540576819eSwyllys 	 * If (FATType == FAT32) {
14550576819eSwyllys 	 * 	BPB_FATSz16 = 0;
14560576819eSwyllys 	 *	BPB_FATSz32 = FATSz;
14570576819eSwyllys 	 * } else {
14580576819eSwyllys 	 *	BPB_FATSz16 = LOWORD(FATSz);
14590576819eSwyllys 	 * 	// there is no BPB_FATSz32 in a FAT16 BPB
14600576819eSwyllys 	 * }
14610576819eSwyllys 	 */
14620576819eSwyllys 	tmpval1 = volsize - (wbpb->bpb.resv_sectors + rds);
14630576819eSwyllys 
1464f127cb91Sfrankho 	tmpval2 = (256 * wbpb->bpb.sectors_per_cluster) + wbpb->bpb.num_fats;
14650576819eSwyllys 
14660576819eSwyllys 	if (Fatentsize == 32)
14670576819eSwyllys 		tmpval2 = tmpval2 / 2;
14680576819eSwyllys 
14690576819eSwyllys 	fatsz = (tmpval1 + (tmpval2 - 1)) / tmpval2;
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	/* Compute a sector/fat figure */
14727c478bd9Sstevel@tonic-gate 	switch (Fatentsize) {
14737c478bd9Sstevel@tonic-gate 	case 32:
14747c478bd9Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 0;
14750576819eSwyllys 		wbpb->bpb32.big_sectors_per_fat = fatsz;
14760576819eSwyllys 		if (Verbose)
147757e22c6cSwyllys 			(void) printf("compute_cluster_size: Sectors per "
1478f127cb91Sfrankho 			    "FAT32 = %d\n", wbpb->bpb32.big_sectors_per_fat);
14797c478bd9Sstevel@tonic-gate 		break;
14807c478bd9Sstevel@tonic-gate 	case 12:
14817c478bd9Sstevel@tonic-gate 	default:	/* 16 bit FAT */
14820576819eSwyllys 		wbpb->bpb.sectors_per_fat = (ushort_t)(fatsz & 0x0000FFFF);
14830576819eSwyllys 		if (Verbose)
148457e22c6cSwyllys 			(void) printf("compute_cluster_size: Sectors per "
148557e22c6cSwyllys 			    "FAT16 = %d\n", wbpb->bpb.sectors_per_fat);
14867c478bd9Sstevel@tonic-gate 		break;
14877c478bd9Sstevel@tonic-gate 	}
14887c478bd9Sstevel@tonic-gate }
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate static
14917c478bd9Sstevel@tonic-gate void
14927c478bd9Sstevel@tonic-gate find_fixed_details(int fd, bpb_t *wbpb)
14937c478bd9Sstevel@tonic-gate {
14947c478bd9Sstevel@tonic-gate 	struct dk_geom dginfo;
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	/*
14977c478bd9Sstevel@tonic-gate 	 *  Look up the last remaining bits of info we need
14987c478bd9Sstevel@tonic-gate 	 *  that is specific to the hard drive using a disk ioctl.
14997c478bd9Sstevel@tonic-gate 	 */
15007c478bd9Sstevel@tonic-gate 	if (GetSPT || GetTPC) {
1501f127cb91Sfrankho 		if (ioctl(fd, DKIOCG_VIRTGEOM, &dginfo) == -1 &&
1502f127cb91Sfrankho 		    ioctl(fd, DKIOCG_PHYGEOM, &dginfo) == -1 &&
1503f127cb91Sfrankho 		    ioctl(fd, DKIOCGGEOM, &dginfo) == -1) {
15047c478bd9Sstevel@tonic-gate 			(void) close(fd);
15057c478bd9Sstevel@tonic-gate 			perror(
15067c478bd9Sstevel@tonic-gate 			    gettext("Drive geometry lookup (need "
15077c478bd9Sstevel@tonic-gate 			    "tracks/cylinder and/or sectors/track"));
15087c478bd9Sstevel@tonic-gate 			exit(2);
15097c478bd9Sstevel@tonic-gate 		}
15107c478bd9Sstevel@tonic-gate 	}
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	wbpb->bpb.heads = (GetTPC ? dginfo.dkg_nhead : TrkPerCyl);
15137c478bd9Sstevel@tonic-gate 	wbpb->bpb.sectors_per_track = (GetSPT ? dginfo.dkg_nsect : SecPerTrk);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	if (Verbose) {
15167c478bd9Sstevel@tonic-gate 		if (GetTPC) {
15177c478bd9Sstevel@tonic-gate 			(void) printf(
15187c478bd9Sstevel@tonic-gate 			    gettext("DKIOCG determined number of heads = %d\n"),
15197c478bd9Sstevel@tonic-gate 			    dginfo.dkg_nhead);
15207c478bd9Sstevel@tonic-gate 		}
15217c478bd9Sstevel@tonic-gate 		if (GetSPT) {
15227c478bd9Sstevel@tonic-gate 			(void) printf(
1523f127cb91Sfrankho 			    gettext("DKIOCG determined sectors per track"
1524f127cb91Sfrankho 			    " = %d\n"), dginfo.dkg_nsect);
15257c478bd9Sstevel@tonic-gate 		}
15267c478bd9Sstevel@tonic-gate 	}
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	/*
15297c478bd9Sstevel@tonic-gate 	 * XXX - MAY need an additional flag (or flags) to set media
15307c478bd9Sstevel@tonic-gate 	 * and physical drive number fields.  That in the case of weird
15317c478bd9Sstevel@tonic-gate 	 * floppies that have to go through 'nofdisk' route for formatting.
15327c478bd9Sstevel@tonic-gate 	 */
15337c478bd9Sstevel@tonic-gate 	wbpb->bpb.media = 0xF8;
15347c478bd9Sstevel@tonic-gate 	if (MakeFAT32)
15357c478bd9Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 0;
15367c478bd9Sstevel@tonic-gate 	else
15377c478bd9Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 512;
15387c478bd9Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0x80;
15397c478bd9Sstevel@tonic-gate 	compute_cluster_size(wbpb);
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate static
15437c478bd9Sstevel@tonic-gate char *
15447c478bd9Sstevel@tonic-gate stat_actual_disk(char *diskname, struct stat *info, char **suffix)
15457c478bd9Sstevel@tonic-gate {
15467c478bd9Sstevel@tonic-gate 	char *actualdisk;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	if (stat(diskname, info)) {
15497c478bd9Sstevel@tonic-gate 		/*
15507c478bd9Sstevel@tonic-gate 		 *  Device named on command line doesn't exist.  That
15517c478bd9Sstevel@tonic-gate 		 *  probably means there is a partition-specifying
15527c478bd9Sstevel@tonic-gate 		 *  suffix attached to the actual disk name.
15537c478bd9Sstevel@tonic-gate 		 */
15547c478bd9Sstevel@tonic-gate 		actualdisk = strtok(strdup(diskname), ":");
15557c478bd9Sstevel@tonic-gate 		if (*suffix = strchr(diskname, ':'))
15567c478bd9Sstevel@tonic-gate 			(*suffix)++;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 		if (stat(actualdisk, info)) {
15597c478bd9Sstevel@tonic-gate 			perror(actualdisk);
15607c478bd9Sstevel@tonic-gate 			exit(2);
15617c478bd9Sstevel@tonic-gate 		}
15627c478bd9Sstevel@tonic-gate 	} else {
15637c478bd9Sstevel@tonic-gate 		actualdisk = strdup(diskname);
15647c478bd9Sstevel@tonic-gate 	}
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	return (actualdisk);
15677c478bd9Sstevel@tonic-gate }
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate static
15707c478bd9Sstevel@tonic-gate void
15717c478bd9Sstevel@tonic-gate compute_file_area_size(bpb_t *wbpb)
15727c478bd9Sstevel@tonic-gate {
15730576819eSwyllys 	int FATSz;
15740576819eSwyllys 	int TotSec;
15750576819eSwyllys 	int DataSec;
1576f127cb91Sfrankho 	int RootDirSectors =
1577f127cb91Sfrankho 	    ((wbpb->bpb.num_root_entries * 32) + (wbpb->bpb.bytes_sector - 1)) /
15780576819eSwyllys 	    wbpb->bpb.bytes_sector;
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	if (wbpb->bpb.sectors_per_fat) {
15817c478bd9Sstevel@tonic-gate 		/*
15827c478bd9Sstevel@tonic-gate 		 * Good old FAT12 or FAT16
15837c478bd9Sstevel@tonic-gate 		 */
15840576819eSwyllys 		FATSz = wbpb->bpb.sectors_per_fat;
15850576819eSwyllys 		TotSec = wbpb->bpb.sectors_in_volume;
15867c478bd9Sstevel@tonic-gate 	} else {
15877c478bd9Sstevel@tonic-gate 		/*
15887c478bd9Sstevel@tonic-gate 		 *  FAT32
15897c478bd9Sstevel@tonic-gate 		 */
15900576819eSwyllys 		FATSz = wbpb->bpb32.big_sectors_per_fat;
15910576819eSwyllys 		TotSec = wbpb->bpb.sectors_in_logical_volume;
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 
1594f127cb91Sfrankho 	DataSec = TotSec -
1595f127cb91Sfrankho 	    (wbpb->bpb.resv_sectors + (wbpb->bpb.num_fats * FATSz) +
15960576819eSwyllys 	    RootDirSectors);
15970576819eSwyllys 
15980576819eSwyllys 
15997c478bd9Sstevel@tonic-gate 	/*
16007c478bd9Sstevel@tonic-gate 	 * Now change sectors to clusters
16017c478bd9Sstevel@tonic-gate 	 */
16020576819eSwyllys 	TotalClusters = DataSec / wbpb->bpb.sectors_per_cluster;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	if (Verbose)
16057c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Disk has a file area of %d "
16067c478bd9Sstevel@tonic-gate 		    "allocation units,\neach with %d sectors = %d "
16077c478bd9Sstevel@tonic-gate 		    "bytes.\n"), TotalClusters, wbpb->bpb.sectors_per_cluster,
16087c478bd9Sstevel@tonic-gate 		    TotalClusters * wbpb->bpb.sectors_per_cluster * BPSEC);
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate #ifndef i386
16127c478bd9Sstevel@tonic-gate /*
16137c478bd9Sstevel@tonic-gate  *  swap_pack_{bpb,bpb32,sebpb}cpy
16147c478bd9Sstevel@tonic-gate  *
16157c478bd9Sstevel@tonic-gate  *	If not on an x86 we assume the structures making up the bpb
16167c478bd9Sstevel@tonic-gate  *	were not packed and that longs and shorts need to be byte swapped
16177c478bd9Sstevel@tonic-gate  *	(we've kept everything in host order up until now).  A new architecture
16187c478bd9Sstevel@tonic-gate  *	might not need to swap or might not need to pack, in which case
16197c478bd9Sstevel@tonic-gate  *	new routines will have to be written.  Of course if an architecture
16207c478bd9Sstevel@tonic-gate  *	supports both packing and little-endian host order, it can follow the
16217c478bd9Sstevel@tonic-gate  *	same path as the x86 code.
16227c478bd9Sstevel@tonic-gate  */
16237c478bd9Sstevel@tonic-gate static
16247c478bd9Sstevel@tonic-gate void
16257c478bd9Sstevel@tonic-gate swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb)
16267c478bd9Sstevel@tonic-gate {
16277c478bd9Sstevel@tonic-gate 	uchar_t *fillp;
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.bytes_sector);
16327c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.sectors_per_cluster;
16337c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.resv_sectors);
16347c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.num_fats;
16357c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.num_root_entries);
16367c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_in_volume);
16377c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.media;
16387c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_fat);
16397c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_track);
16407c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.heads);
16417c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.hidden_sectors);
16427c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume);
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.phys_drive_num;
16457c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.reserved;
16467c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.ext_signature;
16477c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->ebpb.volume_id);
16487c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11);
16497c478bd9Sstevel@tonic-gate 	fillp += 11;
16507c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8);
16517c478bd9Sstevel@tonic-gate }
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate static
16547c478bd9Sstevel@tonic-gate void
16557c478bd9Sstevel@tonic-gate swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb)
16567c478bd9Sstevel@tonic-gate {
16577c478bd9Sstevel@tonic-gate 	uchar_t *fillp;
16587c478bd9Sstevel@tonic-gate 	int r;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.bytes_sector);
16637c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.sectors_per_cluster;
16647c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.resv_sectors);
16657c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.num_fats;
16667c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.num_root_entries);
16677c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_in_volume);
16687c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.media;
16697c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_fat);
16707c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_track);
16717c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.heads);
16727c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.hidden_sectors);
16737c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume);
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb32.big_sectors_per_fat);
16767c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.ext_flags);
16777c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb32.fs_vers_lo;
16787c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->bpb32.fs_vers_hi;
16797c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb32.root_dir_clust);
16807c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.fsinfosec);
16817c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.backupboot);
16827c478bd9Sstevel@tonic-gate 	for (r = 0; r < 6; r++)
16837c478bd9Sstevel@tonic-gate 		store_16_bits(&fillp, wbpb->bpb32.reserved[r]);
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.phys_drive_num;
16867c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.reserved;
16877c478bd9Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.ext_signature;
16887c478bd9Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->ebpb.volume_id);
16897c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11);
16907c478bd9Sstevel@tonic-gate 	fillp += 11;
16917c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8);
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate static
16957c478bd9Sstevel@tonic-gate void
16967c478bd9Sstevel@tonic-gate swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb)
16977c478bd9Sstevel@tonic-gate {
16987c478bd9Sstevel@tonic-gate 	uchar_t *fillp;
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	fillp = bsp->bs_sun_bpb;
17017c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->sunbpb.bs_offset_high);
17027c478bd9Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->sunbpb.bs_offset_low);
17037c478bd9Sstevel@tonic-gate }
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate static
17067c478bd9Sstevel@tonic-gate void
17077c478bd9Sstevel@tonic-gate swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp)
17087c478bd9Sstevel@tonic-gate {
17097c478bd9Sstevel@tonic-gate 	uchar_t *grabp;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	grabp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.bytes_sector))[1] = *grabp++;
17147c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.bytes_sector))[0] = *grabp++;
17157c478bd9Sstevel@tonic-gate 	wbpb->bpb.sectors_per_cluster = *grabp++;
17167c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.resv_sectors))[1] = *grabp++;
17177c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.resv_sectors))[0] = *grabp++;
17187c478bd9Sstevel@tonic-gate 	wbpb->bpb.num_fats = *grabp++;
17197c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.num_root_entries))[1] = *grabp++;
17207c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.num_root_entries))[0] = *grabp++;
17217c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_volume))[1] = *grabp++;
17227c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_volume))[0] = *grabp++;
17237c478bd9Sstevel@tonic-gate 	wbpb->bpb.media = *grabp++;
17247c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_fat))[1] = *grabp++;
17257c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_fat))[0] = *grabp++;
17267c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_track))[1] = *grabp++;
17277c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_track))[0] = *grabp++;
17287c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.heads))[1] = *grabp++;
17297c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.heads))[0] = *grabp++;
17307c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[3] = *grabp++;
17317c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[2] = *grabp++;
17327c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[1] = *grabp++;
17337c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[0] = *grabp++;
17347c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[3] = *grabp++;
17357c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[2] = *grabp++;
17367c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[1] = *grabp++;
17377c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[0] = *grabp++;
17387c478bd9Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = *grabp++;
17397c478bd9Sstevel@tonic-gate 	wbpb->ebpb.reserved = *grabp++;
17407c478bd9Sstevel@tonic-gate 	wbpb->ebpb.ext_signature = *grabp++;
17417c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[3] = *grabp++;
17427c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[2] = *grabp++;
17437c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[1] = *grabp++;
17447c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[0] = *grabp++;
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)wbpb->ebpb.volume_label, (char *)grabp, 11);
17477c478bd9Sstevel@tonic-gate 	grabp += 11;
17487c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)wbpb->ebpb.type, (char *)grabp, 8);
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate static
17527c478bd9Sstevel@tonic-gate void
17537c478bd9Sstevel@tonic-gate swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate 	uchar_t *grabp;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	grabp = bsp->bs_sun_bpb;
17587c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[1] = *grabp++;
17597c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[0] = *grabp++;
17607c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[1] = *grabp++;
17617c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[0] = *grabp++;
17627c478bd9Sstevel@tonic-gate }
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate static
17657c478bd9Sstevel@tonic-gate void
17667c478bd9Sstevel@tonic-gate swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp)
17677c478bd9Sstevel@tonic-gate {
17687c478bd9Sstevel@tonic-gate 	uchar_t *grabp;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	grabp = (uchar_t *)&(bsp->bs_filler[BPB_32_START_INDEX]);
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[3] = *grabp++;
17737c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[2] = *grabp++;
17747c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[1] = *grabp++;
17757c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[0] = *grabp++;
17767c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.ext_flags))[1] = *grabp++;
17777c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.ext_flags))[0] = *grabp++;
17787c478bd9Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_lo = *grabp++;
17797c478bd9Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_hi = *grabp++;
17807c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[3] = *grabp++;
17817c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[2] = *grabp++;
17827c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[1] = *grabp++;
17837c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[0] = *grabp++;
17847c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.fsinfosec))[1] = *grabp++;
17857c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.fsinfosec))[0] = *grabp++;
17867c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.backupboot))[1] = *grabp++;
17877c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.backupboot))[0] = *grabp++;
17887c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[0]))[1] = *grabp++;
17897c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[0]))[0] = *grabp++;
17907c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[1]))[1] = *grabp++;
17917c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[1]))[0] = *grabp++;
17927c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[2]))[1] = *grabp++;
17937c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[2]))[0] = *grabp++;
17947c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[3]))[1] = *grabp++;
17957c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[3]))[0] = *grabp++;
17967c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[4]))[1] = *grabp++;
17977c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[4]))[0] = *grabp++;
17987c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[5]))[1] = *grabp++;
17997c478bd9Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[5]))[0] = *grabp++;
18007c478bd9Sstevel@tonic-gate }
18017c478bd9Sstevel@tonic-gate #endif	/* ! i386 */
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate static
18047c478bd9Sstevel@tonic-gate void
18057c478bd9Sstevel@tonic-gate dashm_bail(int fd)
18067c478bd9Sstevel@tonic-gate {
18077c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
18087c478bd9Sstevel@tonic-gate 	    gettext("This media does not appear to be "
18097c478bd9Sstevel@tonic-gate 	    "formatted with a FAT file system.\n"));
18107c478bd9Sstevel@tonic-gate 	(void) close(fd);
18117c478bd9Sstevel@tonic-gate 	exit(6);
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate /*
18157c478bd9Sstevel@tonic-gate  *  read_existing_bpb
18167c478bd9Sstevel@tonic-gate  *
18177c478bd9Sstevel@tonic-gate  *	Grab the first sector, which we think is a bios parameter block.
18187c478bd9Sstevel@tonic-gate  *	If it looks bad, bail.  Otherwise fill in the parameter struct
18197c478bd9Sstevel@tonic-gate  *	fields that matter.
18207c478bd9Sstevel@tonic-gate  */
18217c478bd9Sstevel@tonic-gate static
18227c478bd9Sstevel@tonic-gate void
18237c478bd9Sstevel@tonic-gate read_existing_bpb(int fd, bpb_t *wbpb)
18247c478bd9Sstevel@tonic-gate {
18257c478bd9Sstevel@tonic-gate 	boot_sector_t ubpb;
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	if (read(fd, ubpb.buf, BPSEC) < BPSEC) {
18287c478bd9Sstevel@tonic-gate 		perror(gettext("Read BIOS parameter block "
18297c478bd9Sstevel@tonic-gate 		    "from previously formatted media"));
18307c478bd9Sstevel@tonic-gate 		(void) close(fd);
18317c478bd9Sstevel@tonic-gate 		exit(6);
18327c478bd9Sstevel@tonic-gate 	}
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 	if (ltohs(ubpb.mb.signature) != BOOTSECSIG) {
18357c478bd9Sstevel@tonic-gate 		dashm_bail(fd);
18367c478bd9Sstevel@tonic-gate 	}
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate #ifdef i386
18397c478bd9Sstevel@tonic-gate 	(void) memcpy(&(wbpb->bpb), &(ubpb.bs.bs_front.bs_bpb),
18407c478bd9Sstevel@tonic-gate 	    sizeof (wbpb->bpb));
18417c478bd9Sstevel@tonic-gate 	(void) memcpy(&(wbpb->ebpb), &(ubpb.bs.bs_ebpb), sizeof (wbpb->ebpb));
18427c478bd9Sstevel@tonic-gate #else
18437c478bd9Sstevel@tonic-gate 	swap_pack_grabbpb(wbpb, &(ubpb.bs));
18447c478bd9Sstevel@tonic-gate #endif
18457c478bd9Sstevel@tonic-gate 	if (SunBPBfields) {
18467c478bd9Sstevel@tonic-gate #ifdef i386
18477c478bd9Sstevel@tonic-gate 		(void) memcpy(&(wbpb->sunbpb), &(ubpb.bs.bs_sebpb),
18487c478bd9Sstevel@tonic-gate 		    sizeof (wbpb->sunbpb));
18497c478bd9Sstevel@tonic-gate #else
18507c478bd9Sstevel@tonic-gate 		swap_pack_grabsebpb(wbpb, &(ubpb.bs));
18517c478bd9Sstevel@tonic-gate #endif
18527c478bd9Sstevel@tonic-gate 	}
18537c478bd9Sstevel@tonic-gate 	if (wbpb->bpb.bytes_sector != BPSEC) {
18547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
18557c478bd9Sstevel@tonic-gate 		    gettext("Bogus bytes per sector value.\n"));
1856*db92b35aSGary Mills 		if (!(ISP2(wbpb->bpb.bytes_sector) &&
1857*db92b35aSGary Mills 		    IN_RANGE(wbpb->bpb.bytes_sector, 1, BPSEC * 8))) {
18587c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
18597c478bd9Sstevel@tonic-gate 			    gettext("The device name may be missing a "
18607c478bd9Sstevel@tonic-gate 			    "logical drive specifier.\n"));
18617c478bd9Sstevel@tonic-gate 			(void) close(fd);
18627c478bd9Sstevel@tonic-gate 			exit(6);
18637c478bd9Sstevel@tonic-gate 		} else {
18647c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
18657c478bd9Sstevel@tonic-gate 			    gettext("Do not know how to build FATs with a\n"
18667c478bd9Sstevel@tonic-gate 			    "non-standard sector size. Standard "
18677c478bd9Sstevel@tonic-gate 			    "size is %d bytes,\nyour sector size "
18687c478bd9Sstevel@tonic-gate 			    "is %d bytes.\n"), BPSEC,
18697c478bd9Sstevel@tonic-gate 			    wbpb->bpb.bytes_sector);
18707c478bd9Sstevel@tonic-gate 			(void) close(fd);
18717c478bd9Sstevel@tonic-gate 			exit(6);
18727c478bd9Sstevel@tonic-gate 		}
18737c478bd9Sstevel@tonic-gate 	}
1874*db92b35aSGary Mills 	if (!(ISP2(wbpb->bpb.sectors_per_cluster) &&
1875*db92b35aSGary Mills 	    IN_RANGE(wbpb->bpb.sectors_per_cluster, 1, 128))) {
18767c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
18777c478bd9Sstevel@tonic-gate 		    gettext("Bogus sectors per cluster value.\n"));
18787c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
18797c478bd9Sstevel@tonic-gate 		    gettext("The device name may be missing a "
18807c478bd9Sstevel@tonic-gate 		    "logical drive specifier.\n"));
18817c478bd9Sstevel@tonic-gate 		(void) close(fd);
18827c478bd9Sstevel@tonic-gate 		exit(6);
18837c478bd9Sstevel@tonic-gate 	}
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	if (wbpb->bpb.sectors_per_fat == 0) {
18867c478bd9Sstevel@tonic-gate #ifdef i386
18877c478bd9Sstevel@tonic-gate 		(void) memcpy(&(wbpb->bpb32), &(ubpb.bs32.bs_bpb32),
18887c478bd9Sstevel@tonic-gate 		    sizeof (wbpb->bpb32));
18897c478bd9Sstevel@tonic-gate #else
18907c478bd9Sstevel@tonic-gate 		swap_pack_grab32bpb(wbpb, &(ubpb.bs));
18917c478bd9Sstevel@tonic-gate #endif
18927c478bd9Sstevel@tonic-gate 		compute_file_area_size(wbpb);
18937c478bd9Sstevel@tonic-gate 		if ((wbpb->bpb32.big_sectors_per_fat * BPSEC / 4) >=
18947c478bd9Sstevel@tonic-gate 		    TotalClusters) {
18957c478bd9Sstevel@tonic-gate 			MakeFAT32 = 1;
18967c478bd9Sstevel@tonic-gate 		} else {
18977c478bd9Sstevel@tonic-gate 			dashm_bail(fd);
18987c478bd9Sstevel@tonic-gate 		}
18997c478bd9Sstevel@tonic-gate 	} else {
19007c478bd9Sstevel@tonic-gate 		compute_file_area_size(wbpb);
19017c478bd9Sstevel@tonic-gate 	}
19027c478bd9Sstevel@tonic-gate }
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate /*
19057c478bd9Sstevel@tonic-gate  *  compare_existing_with_computed
19067c478bd9Sstevel@tonic-gate  *
19077c478bd9Sstevel@tonic-gate  *	We use this function when we the user specifies the -m option.
19087c478bd9Sstevel@tonic-gate  *	We compute and look up things like we would if they had asked
19097c478bd9Sstevel@tonic-gate  *	us to make the fs, and compare that to what's already layed down
19107c478bd9Sstevel@tonic-gate  *	in the existing fs.  If there's a difference we can tell them what
19117c478bd9Sstevel@tonic-gate  *	options to specify in order to reproduce their existing layout.
19127c478bd9Sstevel@tonic-gate  *	Note that they still may not get an exact duplicate, because we
19137c478bd9Sstevel@tonic-gate  *	don't, for example, preserve their existing boot code.  We think
19147c478bd9Sstevel@tonic-gate  *	we've got all the fields that matter covered, though.
19157c478bd9Sstevel@tonic-gate  *
19167c478bd9Sstevel@tonic-gate  *	XXX - We're basically ignoring sbpb at this point.  I'm unsure
19177c478bd9Sstevel@tonic-gate  *	if we'll ever care about those fields, in terms of the -m option.
19187c478bd9Sstevel@tonic-gate  */
19197c478bd9Sstevel@tonic-gate static
19207c478bd9Sstevel@tonic-gate void
19217c478bd9Sstevel@tonic-gate compare_existing_with_computed(int fd, char *suffix,
19227c478bd9Sstevel@tonic-gate     bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect,
19237c478bd9Sstevel@tonic-gate     int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd, int *dashos)
19247c478bd9Sstevel@tonic-gate {
19257c478bd9Sstevel@tonic-gate 	struct dk_geom	dginfo;
19267c478bd9Sstevel@tonic-gate 	struct fd_char	fdchar;
19277c478bd9Sstevel@tonic-gate 	bpb_t		compare;
19287c478bd9Sstevel@tonic-gate 	int		fd_ioctl_worked = 0;
19297c478bd9Sstevel@tonic-gate 	int		fatents;
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	/*
19327c478bd9Sstevel@tonic-gate 	 *  For all non-floppy cases we expect to find a 16-bit FAT
19337c478bd9Sstevel@tonic-gate 	 */
19347c478bd9Sstevel@tonic-gate 	int expectfatsize = 16;
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	compare = *wbpb;
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	if (!suffix) {
19397c478bd9Sstevel@tonic-gate 		if (ioctl(fd, FDIOGCHAR, &fdchar) != -1) {
19407c478bd9Sstevel@tonic-gate 			expectfatsize = 12;
19417c478bd9Sstevel@tonic-gate 			fd_ioctl_worked++;
19427c478bd9Sstevel@tonic-gate 		}
19437c478bd9Sstevel@tonic-gate 	}
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	if (fd_ioctl_worked) {
19467c478bd9Sstevel@tonic-gate #ifdef sparc
19477c478bd9Sstevel@tonic-gate 		fdchar.fdc_medium = 3;
19487c478bd9Sstevel@tonic-gate #endif
19497c478bd9Sstevel@tonic-gate 		GetSize = GetSPT = GetSPC = GetTPC = GetBPF = 1;
19507c478bd9Sstevel@tonic-gate 		lookup_floppy(&fdchar, &compare);
19517c478bd9Sstevel@tonic-gate 		if (compare.bpb.heads != wbpb->bpb.heads) {
19527c478bd9Sstevel@tonic-gate 			(*prtntrk)++;
19537c478bd9Sstevel@tonic-gate 			(*dashos)++;
19547c478bd9Sstevel@tonic-gate 		}
19557c478bd9Sstevel@tonic-gate 		if (compare.bpb.sectors_per_track !=
19567c478bd9Sstevel@tonic-gate 		    wbpb->bpb.sectors_per_track) {
19577c478bd9Sstevel@tonic-gate 			(*prtnsect)++;
19587c478bd9Sstevel@tonic-gate 			(*dashos)++;
19597c478bd9Sstevel@tonic-gate 		}
19607c478bd9Sstevel@tonic-gate 	} else {
19617c478bd9Sstevel@tonic-gate 		int dk_ioctl_worked = 1;
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 		if (!suffix) {
19647c478bd9Sstevel@tonic-gate 			(*prtfdisk)++;
19657c478bd9Sstevel@tonic-gate 			(*prtsize)++;
19667c478bd9Sstevel@tonic-gate 			*dashos += 2;
19677c478bd9Sstevel@tonic-gate 		}
1968f127cb91Sfrankho 		if (ioctl(fd, DKIOCG_VIRTGEOM, &dginfo) == -1 &&
1969f127cb91Sfrankho 		    ioctl(fd, DKIOCG_PHYGEOM, &dginfo) == -1 &&
1970f127cb91Sfrankho 		    ioctl(fd, DKIOCGGEOM, &dginfo) == -1) {
19717c478bd9Sstevel@tonic-gate 			*prtnsect = *prtntrk = 1;
19727c478bd9Sstevel@tonic-gate 			*dashos += 2;
19737c478bd9Sstevel@tonic-gate 			dk_ioctl_worked = 0;
19747c478bd9Sstevel@tonic-gate 		}
19757c478bd9Sstevel@tonic-gate 		if (dk_ioctl_worked) {
19767c478bd9Sstevel@tonic-gate 			if (dginfo.dkg_nhead != wbpb->bpb.heads) {
19777c478bd9Sstevel@tonic-gate 				(*prtntrk)++;
19787c478bd9Sstevel@tonic-gate 				(*dashos)++;
19797c478bd9Sstevel@tonic-gate 			}
19807c478bd9Sstevel@tonic-gate 			if (dginfo.dkg_nsect !=
19817c478bd9Sstevel@tonic-gate 			    wbpb->bpb.sectors_per_track) {
19827c478bd9Sstevel@tonic-gate 				(*prtnsect)++;
19837c478bd9Sstevel@tonic-gate 				(*dashos)++;
19847c478bd9Sstevel@tonic-gate 			}
19857c478bd9Sstevel@tonic-gate 		}
19867c478bd9Sstevel@tonic-gate 		GetBPF = GetSPC = 1;
19877c478bd9Sstevel@tonic-gate 		compute_cluster_size(&compare);
19887c478bd9Sstevel@tonic-gate 	}
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 	if (!*prtfdisk && TotSize != wbpb->bpb.sectors_in_volume &&
19917c478bd9Sstevel@tonic-gate 	    TotSize != wbpb->bpb.sectors_in_logical_volume) {
19927c478bd9Sstevel@tonic-gate 		(*dashos)++;
19937c478bd9Sstevel@tonic-gate 		(*prtsize)++;
19947c478bd9Sstevel@tonic-gate 	}
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	if (compare.bpb.sectors_per_cluster != wbpb->bpb.sectors_per_cluster) {
19977c478bd9Sstevel@tonic-gate 		(*dashos)++;
19987c478bd9Sstevel@tonic-gate 		(*prtspc)++;
19997c478bd9Sstevel@tonic-gate 	}
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	if (compare.bpb.hidden_sectors != wbpb->bpb.hidden_sectors) {
20027c478bd9Sstevel@tonic-gate 		(*dashos)++;
20037c478bd9Sstevel@tonic-gate 		(*prthidden)++;
20047c478bd9Sstevel@tonic-gate 	}
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	if (compare.bpb.resv_sectors != wbpb->bpb.resv_sectors) {
20077c478bd9Sstevel@tonic-gate 		(*dashos)++;
20087c478bd9Sstevel@tonic-gate 		(*prtrsrvd)++;
20097c478bd9Sstevel@tonic-gate 	}
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 	/*
20127c478bd9Sstevel@tonic-gate 	 * Compute approximate Fatentsize.  It's approximate because the
20137c478bd9Sstevel@tonic-gate 	 * size of the FAT may not be exactly a multiple of the number of
20147c478bd9Sstevel@tonic-gate 	 * clusters.  It should be close, though.
20157c478bd9Sstevel@tonic-gate 	 */
20167c478bd9Sstevel@tonic-gate 	if (MakeFAT32) {
20177c478bd9Sstevel@tonic-gate 		Fatentsize = 32;
20187c478bd9Sstevel@tonic-gate 		(*dashos)++;
20197c478bd9Sstevel@tonic-gate 		(*prtbpf)++;
20207c478bd9Sstevel@tonic-gate 	} else {
20217c478bd9Sstevel@tonic-gate 		fatents = wbpb->bpb.sectors_per_fat * BPSEC * 2 / 3;
20227c478bd9Sstevel@tonic-gate 		if (fatents >= TotalClusters && wbpb->ebpb.type[4] == '2')
20237c478bd9Sstevel@tonic-gate 			Fatentsize = 12;
20247c478bd9Sstevel@tonic-gate 		else
20257c478bd9Sstevel@tonic-gate 			Fatentsize = 16;
20267c478bd9Sstevel@tonic-gate 		if (Fatentsize != expectfatsize) {
20277c478bd9Sstevel@tonic-gate 			(*dashos)++;
20287c478bd9Sstevel@tonic-gate 			(*prtbpf)++;
20297c478bd9Sstevel@tonic-gate 		}
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate }
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate static
20347c478bd9Sstevel@tonic-gate void
20357c478bd9Sstevel@tonic-gate print_reproducing_command(int fd, char *actualdisk, char *suffix, bpb_t *wbpb)
20367c478bd9Sstevel@tonic-gate {
20377c478bd9Sstevel@tonic-gate 	int needcomma = 0;
20387c478bd9Sstevel@tonic-gate 	int prthidden = 0;
20397c478bd9Sstevel@tonic-gate 	int prtrsrvd = 0;
20407c478bd9Sstevel@tonic-gate 	int prtfdisk = 0;
20417c478bd9Sstevel@tonic-gate 	int prtnsect = 0;
20427c478bd9Sstevel@tonic-gate 	int prtntrk = 0;
20437c478bd9Sstevel@tonic-gate 	int prtsize = 0;
20447c478bd9Sstevel@tonic-gate 	int prtbpf = 0;
20457c478bd9Sstevel@tonic-gate 	int prtspc = 0;
20467c478bd9Sstevel@tonic-gate 	int dashos = 0;
20477c478bd9Sstevel@tonic-gate 	int ll, i;
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	compare_existing_with_computed(fd, suffix, wbpb,
20507c478bd9Sstevel@tonic-gate 	    &prtsize, &prtspc, &prtbpf, &prtnsect, &prtntrk,
20517c478bd9Sstevel@tonic-gate 	    &prtfdisk, &prthidden, &prtrsrvd, &dashos);
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	/*
20547c478bd9Sstevel@tonic-gate 	 *  Print out the command line they can use to reproduce the
20557c478bd9Sstevel@tonic-gate 	 *  file system.
20567c478bd9Sstevel@tonic-gate 	 */
20577c478bd9Sstevel@tonic-gate 	(void) printf("mkfs -F pcfs");
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	ll = min(11, (int)strlen((char *)wbpb->ebpb.volume_label));
20607c478bd9Sstevel@tonic-gate 	/*
20617c478bd9Sstevel@tonic-gate 	 * First, eliminate trailing spaces. Now compare the name against
20627c478bd9Sstevel@tonic-gate 	 * our default label.  If there's a match we don't need to print
20637c478bd9Sstevel@tonic-gate 	 * any label info.
20647c478bd9Sstevel@tonic-gate 	 */
20657c478bd9Sstevel@tonic-gate 	i = ll;
2066f127cb91Sfrankho 	while (wbpb->ebpb.volume_label[--i] == ' ')
2067f127cb91Sfrankho 		;
20687c478bd9Sstevel@tonic-gate 	ll = i;
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	if (ll == strlen(DEFAULT_LABEL) - 1) {
20717c478bd9Sstevel@tonic-gate 		char cmpbuf[11];
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 		(void) strcpy(cmpbuf, DEFAULT_LABEL);
20747c478bd9Sstevel@tonic-gate 		for (i = ll; i >= 0; i--) {
20757c478bd9Sstevel@tonic-gate 			if (cmpbuf[i] !=
20767c478bd9Sstevel@tonic-gate 			    toupper((int)(wbpb->ebpb.volume_label[i]))) {
20777c478bd9Sstevel@tonic-gate 				break;
20787c478bd9Sstevel@tonic-gate 			}
20797c478bd9Sstevel@tonic-gate 		}
20807c478bd9Sstevel@tonic-gate 		if (i < 0)
20817c478bd9Sstevel@tonic-gate 			ll = i;
20827c478bd9Sstevel@tonic-gate 	}
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	if (ll >= 0) {
20857c478bd9Sstevel@tonic-gate 		(void) printf(" -o ");
20867c478bd9Sstevel@tonic-gate 		(void) printf("b=\"");
20877c478bd9Sstevel@tonic-gate 		for (i = 0; i <= ll; i++) {
20887c478bd9Sstevel@tonic-gate 			(void) printf("%c", wbpb->ebpb.volume_label[i]);
20897c478bd9Sstevel@tonic-gate 		}
20907c478bd9Sstevel@tonic-gate 		(void) printf("\"");
20917c478bd9Sstevel@tonic-gate 		needcomma++;
20927c478bd9Sstevel@tonic-gate 	} else if (dashos) {
20937c478bd9Sstevel@tonic-gate 		(void) printf(" -o ");
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate #define	NEXT_DASH_O	dashos--; needcomma++; continue
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	while (dashos) {
20997c478bd9Sstevel@tonic-gate 		if (needcomma) {
21007c478bd9Sstevel@tonic-gate 			(void) printf(",");
21017c478bd9Sstevel@tonic-gate 			needcomma = 0;
21027c478bd9Sstevel@tonic-gate 		}
21037c478bd9Sstevel@tonic-gate 		if (prtfdisk) {
21047c478bd9Sstevel@tonic-gate 			(void) printf("nofdisk");
21057c478bd9Sstevel@tonic-gate 			prtfdisk--;
21067c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21077c478bd9Sstevel@tonic-gate 		}
21087c478bd9Sstevel@tonic-gate 		if (prtsize) {
21097c478bd9Sstevel@tonic-gate 			(void) printf("size=%u", wbpb->bpb.sectors_in_volume ?
21107c478bd9Sstevel@tonic-gate 			    wbpb->bpb.sectors_in_volume :
21117c478bd9Sstevel@tonic-gate 			    wbpb->bpb.sectors_in_logical_volume);
21127c478bd9Sstevel@tonic-gate 			prtsize--;
21137c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21147c478bd9Sstevel@tonic-gate 		}
21157c478bd9Sstevel@tonic-gate 		if (prtnsect) {
21167c478bd9Sstevel@tonic-gate 			(void) printf("nsect=%d", wbpb->bpb.sectors_per_track);
21177c478bd9Sstevel@tonic-gate 			prtnsect--;
21187c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21197c478bd9Sstevel@tonic-gate 		}
21207c478bd9Sstevel@tonic-gate 		if (prtspc) {
21217c478bd9Sstevel@tonic-gate 			(void) printf("spc=%d", wbpb->bpb.sectors_per_cluster);
21227c478bd9Sstevel@tonic-gate 			prtspc--;
21237c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21247c478bd9Sstevel@tonic-gate 		}
21257c478bd9Sstevel@tonic-gate 		if (prtntrk) {
21267c478bd9Sstevel@tonic-gate 			(void) printf("ntrack=%d", wbpb->bpb.heads);
21277c478bd9Sstevel@tonic-gate 			prtntrk--;
21287c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21297c478bd9Sstevel@tonic-gate 		}
21307c478bd9Sstevel@tonic-gate 		if (prtbpf) {
21317c478bd9Sstevel@tonic-gate 			(void) printf("fat=%d", Fatentsize);
21327c478bd9Sstevel@tonic-gate 			prtbpf--;
21337c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21347c478bd9Sstevel@tonic-gate 		}
21357c478bd9Sstevel@tonic-gate 		if (prthidden) {
21367c478bd9Sstevel@tonic-gate 			(void) printf("hidden=%u", wbpb->bpb.hidden_sectors);
21377c478bd9Sstevel@tonic-gate 			prthidden--;
21387c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21397c478bd9Sstevel@tonic-gate 		}
21407c478bd9Sstevel@tonic-gate 		if (prtrsrvd) {
21417c478bd9Sstevel@tonic-gate 			(void) printf("reserve=%d", wbpb->bpb.resv_sectors);
21427c478bd9Sstevel@tonic-gate 			prtrsrvd--;
21437c478bd9Sstevel@tonic-gate 			NEXT_DASH_O;
21447c478bd9Sstevel@tonic-gate 		}
21457c478bd9Sstevel@tonic-gate 	}
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate 	(void) printf(" %s%c%c\n", actualdisk,
21487c478bd9Sstevel@tonic-gate 	    suffix ? ':' : '\0', suffix ? *suffix : '\0');
21497c478bd9Sstevel@tonic-gate }
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate /*
21527c478bd9Sstevel@tonic-gate  *  open_and_examine
21537c478bd9Sstevel@tonic-gate  *
21547c478bd9Sstevel@tonic-gate  *	Open the requested 'dev_name'.  Seek to point where
21557c478bd9Sstevel@tonic-gate  *	we'd expect to find boot sectors, etc., based on any ':partition'
21567c478bd9Sstevel@tonic-gate  *	attachments to the dev_name.
21577c478bd9Sstevel@tonic-gate  *
21587c478bd9Sstevel@tonic-gate  *	Examine the fields of any existing boot sector and display best
21597c478bd9Sstevel@tonic-gate  *	approximation of how this fs could be reproduced with this command.
21607c478bd9Sstevel@tonic-gate  */
21617c478bd9Sstevel@tonic-gate static
21627c478bd9Sstevel@tonic-gate int
21637c478bd9Sstevel@tonic-gate open_and_examine(char *dn, bpb_t *wbpb)
21647c478bd9Sstevel@tonic-gate {
21657c478bd9Sstevel@tonic-gate 	struct stat di;
21667c478bd9Sstevel@tonic-gate 	off64_t ignored;
21677c478bd9Sstevel@tonic-gate 	char *actualdisk = NULL;
21687c478bd9Sstevel@tonic-gate 	char *suffix = NULL;
21697c478bd9Sstevel@tonic-gate 	int fd;
217065908c77Syu, larry liu - Sun Microsystems - Beijing China 	struct dk_minfo dkminfo;
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	if (Verbose)
21737c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Opening destination device/file.\n"));
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	actualdisk = stat_actual_disk(dn, &di, &suffix);
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 	/*
21787c478bd9Sstevel@tonic-gate 	 *  Destination exists, now find more about it.
21797c478bd9Sstevel@tonic-gate 	 */
21807c478bd9Sstevel@tonic-gate 	if (!(S_ISCHR(di.st_mode))) {
21817c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
21827c478bd9Sstevel@tonic-gate 		    gettext("\n%s: device name must be a "
21837c478bd9Sstevel@tonic-gate 		    "character special device.\n"), actualdisk);
21847c478bd9Sstevel@tonic-gate 		exit(2);
21852d700530Sartem 	} else if ((fd = open(actualdisk, O_RDWR)) < 0) {
21867c478bd9Sstevel@tonic-gate 		perror(actualdisk);
21877c478bd9Sstevel@tonic-gate 		exit(2);
21887c478bd9Sstevel@tonic-gate 	}
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 	/*
219165908c77Syu, larry liu - Sun Microsystems - Beijing China 	 * Check the media sector size
219265908c77Syu, larry liu - Sun Microsystems - Beijing China 	 */
219365908c77Syu, larry liu - Sun Microsystems - Beijing China 	if (ioctl(fd, DKIOCGMEDIAINFO, &dkminfo) != -1) {
219465908c77Syu, larry liu - Sun Microsystems - Beijing China 		if (dkminfo.dki_lbsize != 0 &&
219565908c77Syu, larry liu - Sun Microsystems - Beijing China 		    ISP2(dkminfo.dki_lbsize / DEV_BSIZE) &&
219665908c77Syu, larry liu - Sun Microsystems - Beijing China 		    dkminfo.dki_lbsize != DEV_BSIZE) {
219765908c77Syu, larry liu - Sun Microsystems - Beijing China 			(void) fprintf(stderr,
219865908c77Syu, larry liu - Sun Microsystems - Beijing China 			    gettext("The device sector size %u is not "
219965908c77Syu, larry liu - Sun Microsystems - Beijing China 			    "supported by pcfs!\n"), dkminfo.dki_lbsize);
220065908c77Syu, larry liu - Sun Microsystems - Beijing China 			(void) close(fd);
220165908c77Syu, larry liu - Sun Microsystems - Beijing China 			exit(1);
220265908c77Syu, larry liu - Sun Microsystems - Beijing China 		}
220365908c77Syu, larry liu - Sun Microsystems - Beijing China 	}
220465908c77Syu, larry liu - Sun Microsystems - Beijing China 
220565908c77Syu, larry liu - Sun Microsystems - Beijing China 	/*
22067c478bd9Sstevel@tonic-gate 	 * Find appropriate partition if we were requested to do so.
22077c478bd9Sstevel@tonic-gate 	 */
22087c478bd9Sstevel@tonic-gate 	if (suffix && !(seek_partn(fd, suffix, wbpb, &ignored))) {
22097c478bd9Sstevel@tonic-gate 		(void) close(fd);
22107c478bd9Sstevel@tonic-gate 		exit(2);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	read_existing_bpb(fd, wbpb);
22147c478bd9Sstevel@tonic-gate 	print_reproducing_command(fd, actualdisk, suffix, wbpb);
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	return (fd);
22177c478bd9Sstevel@tonic-gate }
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate /*
22207c478bd9Sstevel@tonic-gate  *  open_and_seek
22217c478bd9Sstevel@tonic-gate  *
22227c478bd9Sstevel@tonic-gate  *	Open the requested 'dev_name'.  Seek to point where
22237c478bd9Sstevel@tonic-gate  *	we'll write boot sectors, etc., based on any ':partition'
22247c478bd9Sstevel@tonic-gate  *	attachments to the dev_name.
22257c478bd9Sstevel@tonic-gate  *
22267c478bd9Sstevel@tonic-gate  *	By the time we are finished here, the entire BPB will be
22277c478bd9Sstevel@tonic-gate  *	filled in, excepting the volume label.
22287c478bd9Sstevel@tonic-gate  */
22297c478bd9Sstevel@tonic-gate static
22307c478bd9Sstevel@tonic-gate int
22317c478bd9Sstevel@tonic-gate open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto)
22327c478bd9Sstevel@tonic-gate {
22337c478bd9Sstevel@tonic-gate 	struct fd_char fdchar;
2234f69e9be8Sps156622 	struct dk_geom dg;
22357c478bd9Sstevel@tonic-gate 	struct stat di;
223665908c77Syu, larry liu - Sun Microsystems - Beijing China 	struct dk_minfo	dkminfo;
22377c478bd9Sstevel@tonic-gate 	char *actualdisk = NULL;
22387c478bd9Sstevel@tonic-gate 	char *suffix = NULL;
22397c478bd9Sstevel@tonic-gate 	int fd;
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	if (Verbose)
22427c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Opening destination device/file.\n"));
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	/*
22457c478bd9Sstevel@tonic-gate 	 * We hold these truths to be self evident, all BPBs we create
22467c478bd9Sstevel@tonic-gate 	 * will have these values in these fields.
22477c478bd9Sstevel@tonic-gate 	 */
22487c478bd9Sstevel@tonic-gate 	wbpb->bpb.num_fats = 2;
22497c478bd9Sstevel@tonic-gate 	wbpb->bpb.bytes_sector = BPSEC;
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	/*
22527c478bd9Sstevel@tonic-gate 	 * Assign or use supplied numbers for hidden and
22537c478bd9Sstevel@tonic-gate 	 * reserved sectors in the file system.
22547c478bd9Sstevel@tonic-gate 	 */
22557c478bd9Sstevel@tonic-gate 	if (GetResrvd)
22567c478bd9Sstevel@tonic-gate 		if (MakeFAT32)
22577c478bd9Sstevel@tonic-gate 			wbpb->bpb.resv_sectors = 32;
22587c478bd9Sstevel@tonic-gate 		else
22597c478bd9Sstevel@tonic-gate 			wbpb->bpb.resv_sectors = 1;
22607c478bd9Sstevel@tonic-gate 	else
22617c478bd9Sstevel@tonic-gate 		wbpb->bpb.resv_sectors = Resrvd;
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	wbpb->ebpb.ext_signature = 0x29; /* Magic number for modern format */
22647c478bd9Sstevel@tonic-gate 	wbpb->ebpb.volume_id = 0;
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 	if (MakeFAT32)
22677c478bd9Sstevel@tonic-gate 		fill_fat32_bpb(wbpb);
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	/*
22707c478bd9Sstevel@tonic-gate 	 * If all output goes to a simple file, call a routine to setup
22717c478bd9Sstevel@tonic-gate 	 * that scenario. Otherwise, try to find the device.
22727c478bd9Sstevel@tonic-gate 	 */
22737c478bd9Sstevel@tonic-gate 	if (Outputtofile)
22747c478bd9Sstevel@tonic-gate 		return (fd = prepare_image_file(dn, wbpb));
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 	actualdisk = stat_actual_disk(dn, &di, &suffix);
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate 	/*
22797c478bd9Sstevel@tonic-gate 	 * Sanity check.  If we've been provided a partition-specifying
22807c478bd9Sstevel@tonic-gate 	 * suffix, we shouldn't also have been told to ignore the
22817c478bd9Sstevel@tonic-gate 	 * fdisk table.
22827c478bd9Sstevel@tonic-gate 	 */
22837c478bd9Sstevel@tonic-gate 	if (DontUseFdisk && suffix) {
22847c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
22857c478bd9Sstevel@tonic-gate 		    gettext("Using 'nofdisk' option precludes "
22867c478bd9Sstevel@tonic-gate 		    "appending logical drive\nspecifier "
22877c478bd9Sstevel@tonic-gate 		    "to the device name.\n"));
22887c478bd9Sstevel@tonic-gate 		exit(2);
22897c478bd9Sstevel@tonic-gate 	}
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	/*
22927c478bd9Sstevel@tonic-gate 	 *  Destination exists, now find more about it.
22937c478bd9Sstevel@tonic-gate 	 */
22947c478bd9Sstevel@tonic-gate 	if (!(S_ISCHR(di.st_mode))) {
22957c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
22967c478bd9Sstevel@tonic-gate 		    gettext("\n%s: device name must indicate a "
22977c478bd9Sstevel@tonic-gate 		    "character special device.\n"), actualdisk);
22987c478bd9Sstevel@tonic-gate 		exit(2);
22992d700530Sartem 	} else if ((fd = open(actualdisk, O_RDWR)) < 0) {
23007c478bd9Sstevel@tonic-gate 		perror(actualdisk);
23017c478bd9Sstevel@tonic-gate 		exit(2);
23027c478bd9Sstevel@tonic-gate 	}
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 	/*
230565908c77Syu, larry liu - Sun Microsystems - Beijing China 	 * Check the media sector size
230665908c77Syu, larry liu - Sun Microsystems - Beijing China 	 */
230765908c77Syu, larry liu - Sun Microsystems - Beijing China 	if (ioctl(fd, DKIOCGMEDIAINFO, &dkminfo) != -1) {
230865908c77Syu, larry liu - Sun Microsystems - Beijing China 		if (dkminfo.dki_lbsize != 0 &&
230965908c77Syu, larry liu - Sun Microsystems - Beijing China 		    ISP2(dkminfo.dki_lbsize / DEV_BSIZE) &&
231065908c77Syu, larry liu - Sun Microsystems - Beijing China 		    dkminfo.dki_lbsize != DEV_BSIZE) {
231165908c77Syu, larry liu - Sun Microsystems - Beijing China 			(void) fprintf(stderr,
231265908c77Syu, larry liu - Sun Microsystems - Beijing China 			    gettext("The device sector size %u is not "
231365908c77Syu, larry liu - Sun Microsystems - Beijing China 			    "supported by pcfs!\n"), dkminfo.dki_lbsize);
231465908c77Syu, larry liu - Sun Microsystems - Beijing China 			(void) close(fd);
231565908c77Syu, larry liu - Sun Microsystems - Beijing China 			exit(1);
231665908c77Syu, larry liu - Sun Microsystems - Beijing China 		}
231765908c77Syu, larry liu - Sun Microsystems - Beijing China 	}
231865908c77Syu, larry liu - Sun Microsystems - Beijing China 
231965908c77Syu, larry liu - Sun Microsystems - Beijing China 	/*
23207c478bd9Sstevel@tonic-gate 	 * Find appropriate partition if we were requested to do so.
23217c478bd9Sstevel@tonic-gate 	 */
23227c478bd9Sstevel@tonic-gate 	if (suffix && !(seek_partn(fd, suffix, wbpb, seekto))) {
23237c478bd9Sstevel@tonic-gate 		(void) close(fd);
23247c478bd9Sstevel@tonic-gate 		exit(2);
23257c478bd9Sstevel@tonic-gate 	}
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	if (!suffix) {
23287c478bd9Sstevel@tonic-gate 		/*
23297c478bd9Sstevel@tonic-gate 		 * We have one of two possibilities.  Chances are we have
23307c478bd9Sstevel@tonic-gate 		 * a floppy drive.  But the user may be trying to format
23317c478bd9Sstevel@tonic-gate 		 * some weird drive that we don't know about and is supplying
23327c478bd9Sstevel@tonic-gate 		 * all the important values.  In that case, they should have set
23337c478bd9Sstevel@tonic-gate 		 * the 'nofdisk' flag.
23347c478bd9Sstevel@tonic-gate 		 *
23357c478bd9Sstevel@tonic-gate 		 * If 'nofdisk' isn't set, do a floppy-specific ioctl to
23367c478bd9Sstevel@tonic-gate 		 * get the remainder of our info. If the ioctl fails, we have
23377c478bd9Sstevel@tonic-gate 		 * a good idea that they aren't really on a floppy.  In that
23387c478bd9Sstevel@tonic-gate 		 * case, they should have given us a partition specifier.
23397c478bd9Sstevel@tonic-gate 		 */
23407c478bd9Sstevel@tonic-gate 		if (DontUseFdisk) {
23417c478bd9Sstevel@tonic-gate 			if (!(seek_nofdisk(fd, wbpb, seekto))) {
23427c478bd9Sstevel@tonic-gate 				(void) close(fd);
23437c478bd9Sstevel@tonic-gate 				exit(2);
23447c478bd9Sstevel@tonic-gate 			}
23457c478bd9Sstevel@tonic-gate 			find_fixed_details(fd, wbpb);
23467c478bd9Sstevel@tonic-gate 		} else if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) {
2347f69e9be8Sps156622 			/*
2348f69e9be8Sps156622 			 * It is possible that we are trying to use floppy
2349f69e9be8Sps156622 			 * specific FDIOGCHAR ioctl on USB floppy. Since sd
2350f69e9be8Sps156622 			 * driver, by which USB floppy is handled, doesn't
2351f69e9be8Sps156622 			 * support it, we can try to use disk DKIOCGGEOM ioctl
2352f69e9be8Sps156622 			 * to retrieve data we need. sd driver itself
2353f69e9be8Sps156622 			 * determines floppy disk by number of blocks
2354f69e9be8Sps156622 			 * (<=0x1000), then it sets geometry to 80 cylinders,
2355f69e9be8Sps156622 			 * 2 heads.
2356f69e9be8Sps156622 			 *
2357f69e9be8Sps156622 			 * Note that DKIOCGGEOM cannot supply us with type
2358f69e9be8Sps156622 			 * of media (e.g. 3.5" or 5.25"). We will set it to
2359f69e9be8Sps156622 			 * 3 (3.5") which is most probable value.
2360f69e9be8Sps156622 			 */
23617c478bd9Sstevel@tonic-gate 			if (errno == ENOTTY) {
2362f69e9be8Sps156622 				if (ioctl(fd, DKIOCGGEOM, &dg) != -1 &&
2363f69e9be8Sps156622 				    dg.dkg_ncyl == 80 && dg.dkg_nhead == 2) {
2364f69e9be8Sps156622 					fdchar.fdc_ncyl = dg.dkg_ncyl;
2365f69e9be8Sps156622 					fdchar.fdc_medium = 3;
2366f69e9be8Sps156622 					fdchar.fdc_secptrack = dg.dkg_nsect;
2367f69e9be8Sps156622 					fdchar.fdc_nhead = dg.dkg_nhead;
2368f69e9be8Sps156622 					lookup_floppy(&fdchar, wbpb);
2369f69e9be8Sps156622 				} else {
23707c478bd9Sstevel@tonic-gate 					partn_lecture(actualdisk);
23717c478bd9Sstevel@tonic-gate 					(void) close(fd);
23727c478bd9Sstevel@tonic-gate 					exit(2);
23737c478bd9Sstevel@tonic-gate 				}
2374f69e9be8Sps156622 			}
23757c478bd9Sstevel@tonic-gate 		} else {
23767c478bd9Sstevel@tonic-gate #ifdef sparc
23777c478bd9Sstevel@tonic-gate 			fdchar.fdc_medium = 3;
23787c478bd9Sstevel@tonic-gate #endif
23797c478bd9Sstevel@tonic-gate 			lookup_floppy(&fdchar, wbpb);
23807c478bd9Sstevel@tonic-gate 		}
23817c478bd9Sstevel@tonic-gate 	} else {
23827c478bd9Sstevel@tonic-gate 		find_fixed_details(fd, wbpb);
23837c478bd9Sstevel@tonic-gate 	}
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 	return (fd);
23867c478bd9Sstevel@tonic-gate }
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate /*
23897c478bd9Sstevel@tonic-gate  * The following is a copy of MS-DOS 4.0 boot block.
23907c478bd9Sstevel@tonic-gate  * It consists of the BIOS parameter block, and a disk
23917c478bd9Sstevel@tonic-gate  * bootstrap program.
23927c478bd9Sstevel@tonic-gate  *
23937c478bd9Sstevel@tonic-gate  * The BIOS parameter block contains the right values
23947c478bd9Sstevel@tonic-gate  * for the 3.5" high-density 1.44MB floppy format.
23957c478bd9Sstevel@tonic-gate  *
23967c478bd9Sstevel@tonic-gate  * This will be our default boot sector, if the user
23977c478bd9Sstevel@tonic-gate  * didn't point us at a different one.
23987c478bd9Sstevel@tonic-gate  *
23997c478bd9Sstevel@tonic-gate  */
24007c478bd9Sstevel@tonic-gate static
24017c478bd9Sstevel@tonic-gate uchar_t DefBootSec[512] = {
24027c478bd9Sstevel@tonic-gate 	0xeb, 0x3c, 0x90, 	/* 8086 short jump + displacement + NOP */
24037c478bd9Sstevel@tonic-gate 	'M', 'S', 'D', 'O', 'S', '4', '.', '0',	/* OEM name & version */
24047c478bd9Sstevel@tonic-gate 	0x00, 0x02, 0x01, 0x01, 0x00,
24057c478bd9Sstevel@tonic-gate 	0x02, 0xe0, 0x00, 0x40, 0x0b,
24067c478bd9Sstevel@tonic-gate 	0xf0, 0x09, 0x00, 0x12, 0x00,
24077c478bd9Sstevel@tonic-gate 	0x02, 0x00,
24087c478bd9Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00,
24097c478bd9Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00,
24107c478bd9Sstevel@tonic-gate 	0x00, 0x00,
24117c478bd9Sstevel@tonic-gate 	0x29, 0x00, 0x00, 0x00, 0x00,
24127c478bd9Sstevel@tonic-gate 	'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ',
24137c478bd9Sstevel@tonic-gate 	'F', 'A', 'T', '1', '2', ' ', ' ', ' ',
24147c478bd9Sstevel@tonic-gate 	0xfa, 0x33,
24157c478bd9Sstevel@tonic-gate 	0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07,
24167c478bd9Sstevel@tonic-gate 	0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56,
24177c478bd9Sstevel@tonic-gate 	0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00,
24187c478bd9Sstevel@tonic-gate 	0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe,
24197c478bd9Sstevel@tonic-gate 	0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9,
24207c478bd9Sstevel@tonic-gate 	0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb,
24217c478bd9Sstevel@tonic-gate 	0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06,
24227c478bd9Sstevel@tonic-gate 	0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c,
24237c478bd9Sstevel@tonic-gate 	0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7,
24247c478bd9Sstevel@tonic-gate 	0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13,
24257c478bd9Sstevel@tonic-gate 	0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83,
24267c478bd9Sstevel@tonic-gate 	0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52,
24277c478bd9Sstevel@tonic-gate 	0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c,
24287c478bd9Sstevel@tonic-gate 	0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b,
24297c478bd9Sstevel@tonic-gate 	0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3,
24307c478bd9Sstevel@tonic-gate 	0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c,
24317c478bd9Sstevel@tonic-gate 	0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c,
24327c478bd9Sstevel@tonic-gate 	0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20,
24337c478bd9Sstevel@tonic-gate 	0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b,
24347c478bd9Sstevel@tonic-gate 	0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3,
24357c478bd9Sstevel@tonic-gate 	0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6,
24367c478bd9Sstevel@tonic-gate 	0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18,
24377c478bd9Sstevel@tonic-gate 	0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4,
24387c478bd9Sstevel@tonic-gate 	0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44,
24397c478bd9Sstevel@tonic-gate 	0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8,
24407c478bd9Sstevel@tonic-gate 	0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49,
24417c478bd9Sstevel@tonic-gate 	0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51,
24427c478bd9Sstevel@tonic-gate 	0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8,
24437c478bd9Sstevel@tonic-gate 	0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05,
24447c478bd9Sstevel@tonic-gate 	0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b,
24457c478bd9Sstevel@tonic-gate 	0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a,
24467c478bd9Sstevel@tonic-gate 	0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1,
24477c478bd9Sstevel@tonic-gate 	0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac,
24487c478bd9Sstevel@tonic-gate 	0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07,
24497c478bd9Sstevel@tonic-gate 	0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18,
24507c478bd9Sstevel@tonic-gate 	0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe,
24517c478bd9Sstevel@tonic-gate 	0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7,
24527c478bd9Sstevel@tonic-gate 	0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3,
24537c478bd9Sstevel@tonic-gate 	0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02,
24547c478bd9Sstevel@tonic-gate 	0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6,
24557c478bd9Sstevel@tonic-gate 	0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9,
24567c478bd9Sstevel@tonic-gate 	0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c,
24577c478bd9Sstevel@tonic-gate 	0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e,
24587c478bd9Sstevel@tonic-gate 	0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
24597c478bd9Sstevel@tonic-gate 	0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20,
24607c478bd9Sstevel@tonic-gate 	0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72,
24617c478bd9Sstevel@tonic-gate 	0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c,
24627c478bd9Sstevel@tonic-gate 	0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
24637c478bd9Sstevel@tonic-gate 	0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e,
24647c478bd9Sstevel@tonic-gate 	0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68,
24657c478bd9Sstevel@tonic-gate 	0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79,
24667c478bd9Sstevel@tonic-gate 	0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20,
24677c478bd9Sstevel@tonic-gate 	0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53,
24687c478bd9Sstevel@tonic-gate 	0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59,
24697c478bd9Sstevel@tonic-gate 	0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24707c478bd9Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
24717c478bd9Sstevel@tonic-gate };
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate /*
24747c478bd9Sstevel@tonic-gate  *  verify_bootblkfile
24757c478bd9Sstevel@tonic-gate  *
24767c478bd9Sstevel@tonic-gate  *	We were provided with the name of a file containing the bootblk
24777c478bd9Sstevel@tonic-gate  *	to install.  Verify it has a valid boot sector as best we can. Any
24787c478bd9Sstevel@tonic-gate  *	errors and we return a bad file descriptor.  Otherwise we fill up the
24797c478bd9Sstevel@tonic-gate  *	provided buffer with the boot sector, return the file
24807c478bd9Sstevel@tonic-gate  *	descriptor for later use and leave the file pointer just
24817c478bd9Sstevel@tonic-gate  *	past the boot sector part of the boot block file.
24827c478bd9Sstevel@tonic-gate  */
24837c478bd9Sstevel@tonic-gate static
24847c478bd9Sstevel@tonic-gate int
24857c478bd9Sstevel@tonic-gate verify_bootblkfile(char *fn, boot_sector_t *bs, ulong_t *blkfilesize)
24867c478bd9Sstevel@tonic-gate {
24877c478bd9Sstevel@tonic-gate 	struct stat fi;
24887c478bd9Sstevel@tonic-gate 	int bsfd = -1;
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 	if (stat(fn, &fi)) {
24917c478bd9Sstevel@tonic-gate 		perror(fn);
24927c478bd9Sstevel@tonic-gate 	} else if (fi.st_size < BPSEC) {
24937c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
24947c478bd9Sstevel@tonic-gate 		    gettext("%s: Too short to be a boot sector.\n"), fn);
24957c478bd9Sstevel@tonic-gate 	} else if ((bsfd = open(fn, O_RDONLY)) < 0) {
24967c478bd9Sstevel@tonic-gate 		perror(fn);
24977c478bd9Sstevel@tonic-gate 	} else if (read(bsfd, bs->buf, BPSEC) < BPSEC) {
24987c478bd9Sstevel@tonic-gate 		(void) close(bsfd);
24997c478bd9Sstevel@tonic-gate 		bsfd = -1;
25007c478bd9Sstevel@tonic-gate 		perror(gettext("Boot block read"));
25017c478bd9Sstevel@tonic-gate 	} else {
2502f127cb91Sfrankho 		if ((bs->bs.bs_signature[0] != (BOOTSECSIG & 0xFF) &&
2503f127cb91Sfrankho 		    bs->bs.bs_signature[1] != ((BOOTSECSIG >> 8) & 0xFF)) ||
25047c478bd9Sstevel@tonic-gate #ifdef i386
2505f127cb91Sfrankho 		    (bs->bs.bs_front.bs_jump_code[0] != OPCODE1 &&
2506f127cb91Sfrankho 		    bs->bs.bs_front.bs_jump_code[0] != OPCODE2)
25077c478bd9Sstevel@tonic-gate #else
2508f127cb91Sfrankho 		    (bs->bs.bs_jump_code[0] != OPCODE1 &&
2509f127cb91Sfrankho 		    bs->bs.bs_jump_code[0] != OPCODE2)
25107c478bd9Sstevel@tonic-gate #endif
2511a9fcfb29Sfrankho 		    /* CSTYLED */
2512f127cb91Sfrankho 		    ) {
25137c478bd9Sstevel@tonic-gate 			(void) close(bsfd);
25147c478bd9Sstevel@tonic-gate 			bsfd = -1;
25157c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
25167c478bd9Sstevel@tonic-gate 			    gettext("Boot block (%s) bogus.\n"), fn);
25177c478bd9Sstevel@tonic-gate 		}
25187c478bd9Sstevel@tonic-gate 		*blkfilesize = fi.st_size;
25197c478bd9Sstevel@tonic-gate 	}
25207c478bd9Sstevel@tonic-gate 	return (bsfd);
25217c478bd9Sstevel@tonic-gate }
25227c478bd9Sstevel@tonic-gate 
25237c478bd9Sstevel@tonic-gate /*
25247c478bd9Sstevel@tonic-gate  *  verify_firstfile
25257c478bd9Sstevel@tonic-gate  *
25267c478bd9Sstevel@tonic-gate  *	We were provided with the name of a file to be the first file
25277c478bd9Sstevel@tonic-gate  *	installed on the disk.  We just need to verify it exists and
25287c478bd9Sstevel@tonic-gate  *	find out how big it is.  If it doesn't exist, we print a warning
25297c478bd9Sstevel@tonic-gate  *	message about how the file wasn't found.  We don't exit fatally,
25307c478bd9Sstevel@tonic-gate  *	though, rather we return a size of 0 and the FAT will be built
25317c478bd9Sstevel@tonic-gate  *	without installing any first file.  They can then presumably
25327c478bd9Sstevel@tonic-gate  *	install the correct first file by hand.
25337c478bd9Sstevel@tonic-gate  */
25347c478bd9Sstevel@tonic-gate static
25357c478bd9Sstevel@tonic-gate int
25367c478bd9Sstevel@tonic-gate verify_firstfile(char *fn, ulong_t *filesize)
25377c478bd9Sstevel@tonic-gate {
25387c478bd9Sstevel@tonic-gate 	struct stat fi;
25397c478bd9Sstevel@tonic-gate 	int fd = -1;
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 	*filesize = 0;
25427c478bd9Sstevel@tonic-gate 	if (stat(fn, &fi) || (fd = open(fn, O_RDONLY)) < 0) {
25437c478bd9Sstevel@tonic-gate 		perror(fn);
25447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
25457c478bd9Sstevel@tonic-gate 		    gettext("Could not access requested file.  It will not\n"
25467c478bd9Sstevel@tonic-gate 		    "be installed in the new file system.\n"));
25477c478bd9Sstevel@tonic-gate 	} else {
25487c478bd9Sstevel@tonic-gate 		*filesize = fi.st_size;
25497c478bd9Sstevel@tonic-gate 	}
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 	return (fd);
25527c478bd9Sstevel@tonic-gate }
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate /*
25557c478bd9Sstevel@tonic-gate  *  label_volume
25567c478bd9Sstevel@tonic-gate  *
25577c478bd9Sstevel@tonic-gate  *	Fill in BPB with volume label.
25587c478bd9Sstevel@tonic-gate  */
25597c478bd9Sstevel@tonic-gate static
25607c478bd9Sstevel@tonic-gate void
25617c478bd9Sstevel@tonic-gate label_volume(char *lbl, bpb_t *wbpb)
25627c478bd9Sstevel@tonic-gate {
25637c478bd9Sstevel@tonic-gate 	int ll, i;
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 	/* Put a volume label into our BPB. */
25667c478bd9Sstevel@tonic-gate 	if (!lbl)
25677c478bd9Sstevel@tonic-gate 		lbl = DEFAULT_LABEL;
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	ll = min(11, (int)strlen(lbl));
25707c478bd9Sstevel@tonic-gate 	for (i = 0; i < ll; i++) {
25717c478bd9Sstevel@tonic-gate 		wbpb->ebpb.volume_label[i] = toupper(lbl[i]);
25727c478bd9Sstevel@tonic-gate 	}
25737c478bd9Sstevel@tonic-gate 	for (; i < 11; i++) {
25747c478bd9Sstevel@tonic-gate 		wbpb->ebpb.volume_label[i] = ' ';
25757c478bd9Sstevel@tonic-gate 	}
25767c478bd9Sstevel@tonic-gate }
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate static
25797c478bd9Sstevel@tonic-gate int
25807c478bd9Sstevel@tonic-gate copy_bootblk(char *fn, boot_sector_t *bootsect, ulong_t *bootblksize)
25817c478bd9Sstevel@tonic-gate {
25827c478bd9Sstevel@tonic-gate 	int bsfd = -1;
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 	if (Verbose && fn)
25857c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Request to install boot "
25867c478bd9Sstevel@tonic-gate 		    "block file %s.\n"), fn);
25877c478bd9Sstevel@tonic-gate 	else if (Verbose)
25887c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Request to install DOS boot block.\n"));
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 	/*
25917c478bd9Sstevel@tonic-gate 	 *  If they want to install their own boot block, sanity check
25927c478bd9Sstevel@tonic-gate 	 *  that block.
25937c478bd9Sstevel@tonic-gate 	 */
25947c478bd9Sstevel@tonic-gate 	if (fn) {
25957c478bd9Sstevel@tonic-gate 		bsfd = verify_bootblkfile(fn, bootsect, bootblksize);
25967c478bd9Sstevel@tonic-gate 		if (bsfd < 0) {
25977c478bd9Sstevel@tonic-gate 			exit(3);
25987c478bd9Sstevel@tonic-gate 		}
25997c478bd9Sstevel@tonic-gate 		*bootblksize = roundup(*bootblksize, BPSEC);
26007c478bd9Sstevel@tonic-gate 	} else {
26017c478bd9Sstevel@tonic-gate 		(void) memcpy(bootsect, DefBootSec, BPSEC);
26027c478bd9Sstevel@tonic-gate 		*bootblksize = BPSEC;
26037c478bd9Sstevel@tonic-gate 	}
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate 	return (bsfd);
26067c478bd9Sstevel@tonic-gate }
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate /*
26097c478bd9Sstevel@tonic-gate  *  mark_cluster
26107c478bd9Sstevel@tonic-gate  *
26117c478bd9Sstevel@tonic-gate  *	This routine fills a FAT entry with the value supplied to it as an
26127c478bd9Sstevel@tonic-gate  *	argument.  The fatp argument is assumed to be a pointer to the FAT's
26137c478bd9Sstevel@tonic-gate  *	0th entry.  The clustnum is the cluster entry that should be updated.
26147c478bd9Sstevel@tonic-gate  *	The value is the new value for the entry.
26157c478bd9Sstevel@tonic-gate  */
26167c478bd9Sstevel@tonic-gate static
26177c478bd9Sstevel@tonic-gate void
26187c478bd9Sstevel@tonic-gate mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, uint32_t value)
26197c478bd9Sstevel@tonic-gate {
26207c478bd9Sstevel@tonic-gate 	uchar_t *ep;
26217c478bd9Sstevel@tonic-gate 	ulong_t idx;
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	idx = (Fatentsize == 32) ? clustnum * 4 :
26247c478bd9Sstevel@tonic-gate 	    (Fatentsize == 16) ? clustnum * 2 : clustnum + clustnum/2;
26257c478bd9Sstevel@tonic-gate 	ep = fatp + idx;
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 	if (Fatentsize == 32) {
26287c478bd9Sstevel@tonic-gate 		store_32_bits(&ep, value);
26297c478bd9Sstevel@tonic-gate 	} else if (Fatentsize == 16) {
26307c478bd9Sstevel@tonic-gate 		store_16_bits(&ep, value);
26317c478bd9Sstevel@tonic-gate 	} else {
26327c478bd9Sstevel@tonic-gate 		if (clustnum & 1) {
26337c478bd9Sstevel@tonic-gate 			*ep = (*ep & 0x0f) | ((value << 4) & 0xf0);
26347c478bd9Sstevel@tonic-gate 			ep++;
26357c478bd9Sstevel@tonic-gate 			*ep = (value >> 4) & 0xff;
26367c478bd9Sstevel@tonic-gate 		} else {
26377c478bd9Sstevel@tonic-gate 			*ep++ = value & 0xff;
26387c478bd9Sstevel@tonic-gate 			*ep = (*ep & 0xf0) | ((value >> 8) & 0x0f);
26397c478bd9Sstevel@tonic-gate 		}
26407c478bd9Sstevel@tonic-gate 	}
26417c478bd9Sstevel@tonic-gate }
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate static
26447c478bd9Sstevel@tonic-gate uchar_t *
2645f127cb91Sfrankho build_fat(bpb_t *wbpb, struct fat_od_fsi *fsinfop, ulong_t bootblksize,
26467c478bd9Sstevel@tonic-gate     ulong_t *fatsize, char *ffn, int *fffd, ulong_t *ffsize,
26477c478bd9Sstevel@tonic-gate     pc_cluster32_t *ffstartclust)
26487c478bd9Sstevel@tonic-gate {
26497c478bd9Sstevel@tonic-gate 	pc_cluster32_t nextfree, ci;
26507c478bd9Sstevel@tonic-gate 	uchar_t *fatp;
26517c478bd9Sstevel@tonic-gate 	ushort_t numclust, numsect;
26527c478bd9Sstevel@tonic-gate 	int  remclust;
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 	/* Alloc space for a FAT and then null it out. */
26557c478bd9Sstevel@tonic-gate 	if (Verbose) {
26567c478bd9Sstevel@tonic-gate 		(void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"),
26577c478bd9Sstevel@tonic-gate 		    wbpb->bpb.sectors_per_fat ? wbpb->bpb.sectors_per_fat :
26587c478bd9Sstevel@tonic-gate 		    wbpb->bpb32.big_sectors_per_fat);
26597c478bd9Sstevel@tonic-gate 	}
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 	if (MakeFAT32) {
26627c478bd9Sstevel@tonic-gate 		*fatsize = BPSEC * wbpb->bpb32.big_sectors_per_fat;
26637c478bd9Sstevel@tonic-gate 	} else {
26647c478bd9Sstevel@tonic-gate 		*fatsize = BPSEC * wbpb->bpb.sectors_per_fat;
26657c478bd9Sstevel@tonic-gate 	}
26660576819eSwyllys 
26677c478bd9Sstevel@tonic-gate 	if (!(fatp = (uchar_t *)malloc(*fatsize))) {
26687c478bd9Sstevel@tonic-gate 		perror(gettext("FAT table alloc"));
26697c478bd9Sstevel@tonic-gate 		exit(4);
26707c478bd9Sstevel@tonic-gate 	} else {
26717c478bd9Sstevel@tonic-gate 		(void) memset(fatp, 0, *fatsize);
26727c478bd9Sstevel@tonic-gate 	}
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 	/* Build in-memory FAT */
26757c478bd9Sstevel@tonic-gate 	*fatp = wbpb->bpb.media;
26767c478bd9Sstevel@tonic-gate 	*(fatp + 1) = 0xFF;
26777c478bd9Sstevel@tonic-gate 	*(fatp + 2) = 0xFF;
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 	if (Fatentsize == 16) {
26807c478bd9Sstevel@tonic-gate 		*(fatp + 3) = 0xFF;
26817c478bd9Sstevel@tonic-gate 	} else if (Fatentsize == 32) {
26827c478bd9Sstevel@tonic-gate 		*(fatp + 3) = 0x0F;
26837c478bd9Sstevel@tonic-gate 		*(fatp + 4) = 0xFF;
26847c478bd9Sstevel@tonic-gate 		*(fatp + 5) = 0xFF;
26857c478bd9Sstevel@tonic-gate 		*(fatp + 6) = 0xFF;
26867c478bd9Sstevel@tonic-gate 		*(fatp + 7) = 0x0F;
26877c478bd9Sstevel@tonic-gate 	}
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate 	/*
26907c478bd9Sstevel@tonic-gate 	 * Keep track of clusters used.
26917c478bd9Sstevel@tonic-gate 	 */
26927c478bd9Sstevel@tonic-gate 	remclust = TotalClusters;
26937c478bd9Sstevel@tonic-gate 	nextfree = 2;
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 	/*
26967c478bd9Sstevel@tonic-gate 	 * Get info on first file to install, if any.
26977c478bd9Sstevel@tonic-gate 	 */
26987c478bd9Sstevel@tonic-gate 	if (ffn)
26997c478bd9Sstevel@tonic-gate 		*fffd = verify_firstfile(ffn, ffsize);
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 	/*
27027c478bd9Sstevel@tonic-gate 	 * Compute number of clusters to preserve for bootblk overage.
27037c478bd9Sstevel@tonic-gate 	 * Remember that we already wrote the first sector of the boot block.
27047c478bd9Sstevel@tonic-gate 	 * These clusters are marked BAD to prevent them from being deleted
27057c478bd9Sstevel@tonic-gate 	 * or used.  The first available cluster is 2, so we always offset
27067c478bd9Sstevel@tonic-gate 	 * the clusters.
27077c478bd9Sstevel@tonic-gate 	 */
27087c478bd9Sstevel@tonic-gate 	numsect = idivceil((bootblksize - BPSEC), BPSEC);
27097c478bd9Sstevel@tonic-gate 	numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
27107c478bd9Sstevel@tonic-gate 
27117c478bd9Sstevel@tonic-gate 	if (Verbose && numclust)
27127c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"),
27137c478bd9Sstevel@tonic-gate 		    numclust);
27147c478bd9Sstevel@tonic-gate 	for (ci = 0; ci < numclust; ci++)
27157c478bd9Sstevel@tonic-gate 		mark_cluster(fatp, nextfree++,
27167c478bd9Sstevel@tonic-gate 		    MakeFAT32 ? PCF_BADCLUSTER32 : PCF_BADCLUSTER);
27177c478bd9Sstevel@tonic-gate 	remclust -= numclust;
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate 	/*
27207c478bd9Sstevel@tonic-gate 	 * Reserve a cluster for the root directory on a FAT32.
27217c478bd9Sstevel@tonic-gate 	 */
27227c478bd9Sstevel@tonic-gate 	if (MakeFAT32) {
27237c478bd9Sstevel@tonic-gate 		mark_cluster(fatp, nextfree, PCF_LASTCLUSTER32);
27247c478bd9Sstevel@tonic-gate 		wbpb->bpb32.root_dir_clust = nextfree++;
27257c478bd9Sstevel@tonic-gate 		remclust--;
27267c478bd9Sstevel@tonic-gate 	}
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	/*
27297c478bd9Sstevel@tonic-gate 	 * Compute and preserve number of clusters for first file.
27307c478bd9Sstevel@tonic-gate 	 */
27317c478bd9Sstevel@tonic-gate 	if (*fffd >= 0) {
27327c478bd9Sstevel@tonic-gate 		*ffstartclust = nextfree;
27337c478bd9Sstevel@tonic-gate 		numsect = idivceil(*ffsize, BPSEC);
27347c478bd9Sstevel@tonic-gate 		numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 		if (numclust > remclust) {
27377c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
27387c478bd9Sstevel@tonic-gate 			    gettext("Requested first file too large to be\n"
27397c478bd9Sstevel@tonic-gate 			    "installed in the new file system.\n"));
27407c478bd9Sstevel@tonic-gate 			(void) close(*fffd);
27417c478bd9Sstevel@tonic-gate 			*fffd = -1;
27427c478bd9Sstevel@tonic-gate 			goto finish;
27437c478bd9Sstevel@tonic-gate 		}
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 		if (Verbose)
27467c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reserving %d first file "
27477c478bd9Sstevel@tonic-gate 			    "cluster(s).\n"), numclust);
27487c478bd9Sstevel@tonic-gate 		for (ci = 0; (int)ci < (int)(numclust-1); ci++, nextfree++)
27497c478bd9Sstevel@tonic-gate 			mark_cluster(fatp, nextfree, nextfree + 1);
27507c478bd9Sstevel@tonic-gate 		mark_cluster(fatp, nextfree++,
27517c478bd9Sstevel@tonic-gate 		    MakeFAT32 ? PCF_LASTCLUSTER32 : PCF_LASTCLUSTER);
27527c478bd9Sstevel@tonic-gate 		remclust -= numclust;
27537c478bd9Sstevel@tonic-gate 	}
27547c478bd9Sstevel@tonic-gate 
27557c478bd9Sstevel@tonic-gate finish:
27567c478bd9Sstevel@tonic-gate 	if (Verbose) {
27577c478bd9Sstevel@tonic-gate 		(void) printf(gettext("First sector of FAT"));
27587c478bd9Sstevel@tonic-gate 		header_for_dump();
27597c478bd9Sstevel@tonic-gate 		dump_bytes(fatp, BPSEC);
27607c478bd9Sstevel@tonic-gate 	}
27617c478bd9Sstevel@tonic-gate 
2762f127cb91Sfrankho 	(void) memset(fsinfop, 0, sizeof (*fsinfop));
2763f127cb91Sfrankho 	fsinfop->fsi_leadsig = LE_32(FSI_LEADSIG);
2764f127cb91Sfrankho 	fsinfop->fsi_strucsig = LE_32(FSI_STRUCSIG);
2765f127cb91Sfrankho 	fsinfop->fsi_trailsig = LE_32(FSI_TRAILSIG);
2766f127cb91Sfrankho 	fsinfop->fsi_incore.fs_free_clusters = LE_32(remclust);
2767f127cb91Sfrankho 	fsinfop->fsi_incore.fs_next_free = LE_32(nextfree);
27687c478bd9Sstevel@tonic-gate 	return (fatp);
27697c478bd9Sstevel@tonic-gate }
27707c478bd9Sstevel@tonic-gate 
27717c478bd9Sstevel@tonic-gate static
27727c478bd9Sstevel@tonic-gate void
27737c478bd9Sstevel@tonic-gate dirent_time_fill(struct pcdir *dep)
27747c478bd9Sstevel@tonic-gate {
27757c478bd9Sstevel@tonic-gate 	struct  timeval tv;
27767c478bd9Sstevel@tonic-gate 	struct	tm	*tp;
27777c478bd9Sstevel@tonic-gate 	ushort_t	dostime;
27787c478bd9Sstevel@tonic-gate 	ushort_t	dosday;
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&tv, (struct timezone *)0);
27817c478bd9Sstevel@tonic-gate 	tp = localtime(&tv.tv_sec);
27827c478bd9Sstevel@tonic-gate 	/* get the time & day into DOS format */
27837c478bd9Sstevel@tonic-gate 	dostime = tp->tm_sec / 2;
27847c478bd9Sstevel@tonic-gate 	dostime |= tp->tm_min << 5;
27857c478bd9Sstevel@tonic-gate 	dostime |= tp->tm_hour << 11;
27867c478bd9Sstevel@tonic-gate 	dosday = tp->tm_mday;
27877c478bd9Sstevel@tonic-gate 	dosday |= (tp->tm_mon + 1) << 5;
27887c478bd9Sstevel@tonic-gate 	dosday |= (tp->tm_year - 80) << 9;
27897c478bd9Sstevel@tonic-gate 	dep->pcd_mtime.pct_time = htols(dostime);
27907c478bd9Sstevel@tonic-gate 	dep->pcd_mtime.pct_date = htols(dosday);
27917c478bd9Sstevel@tonic-gate }
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate static
27947c478bd9Sstevel@tonic-gate void
27957c478bd9Sstevel@tonic-gate dirent_label_fill(struct pcdir *dep, char *fn)
27967c478bd9Sstevel@tonic-gate {
27977c478bd9Sstevel@tonic-gate 	int nl, i;
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 	/*
28007c478bd9Sstevel@tonic-gate 	 * We spread the volume label across both the NAME and EXT fields
28017c478bd9Sstevel@tonic-gate 	 */
28027c478bd9Sstevel@tonic-gate 	nl = min(PCFNAMESIZE, strlen(fn));
28037c478bd9Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
28047c478bd9Sstevel@tonic-gate 		dep->pcd_filename[i] = toupper(fn[i]);
28057c478bd9Sstevel@tonic-gate 	}
28067c478bd9Sstevel@tonic-gate 	if (i < PCFNAMESIZE) {
28077c478bd9Sstevel@tonic-gate 		for (; i < PCFNAMESIZE; i++)
28087c478bd9Sstevel@tonic-gate 			dep->pcd_filename[i] = ' ';
28097c478bd9Sstevel@tonic-gate 		for (i = 0; i < PCFEXTSIZE; i++)
28107c478bd9Sstevel@tonic-gate 			dep->pcd_ext[i] = ' ';
28117c478bd9Sstevel@tonic-gate 		return;
28127c478bd9Sstevel@tonic-gate 	}
28137c478bd9Sstevel@tonic-gate 	nl = min(PCFEXTSIZE, strlen(fn) - PCFNAMESIZE);
28147c478bd9Sstevel@tonic-gate 	for (i = 0; i < nl; i++)
28157c478bd9Sstevel@tonic-gate 		dep->pcd_ext[i] = toupper(fn[i + PCFNAMESIZE]);
28167c478bd9Sstevel@tonic-gate 	if (i < PCFEXTSIZE) {
28177c478bd9Sstevel@tonic-gate 		for (; i < PCFEXTSIZE; i++)
28187c478bd9Sstevel@tonic-gate 			dep->pcd_ext[i] = ' ';
28197c478bd9Sstevel@tonic-gate 	}
28207c478bd9Sstevel@tonic-gate }
28217c478bd9Sstevel@tonic-gate 
28227c478bd9Sstevel@tonic-gate static
28237c478bd9Sstevel@tonic-gate void
28247c478bd9Sstevel@tonic-gate dirent_fname_fill(struct pcdir *dep, char *fn)
28257c478bd9Sstevel@tonic-gate {
28267c478bd9Sstevel@tonic-gate 	char *fname, *fext;
28277c478bd9Sstevel@tonic-gate 	int nl, i;
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate 	if (fname = strrchr(fn, '/')) {
28307c478bd9Sstevel@tonic-gate 		fname++;
28317c478bd9Sstevel@tonic-gate 	} else {
28327c478bd9Sstevel@tonic-gate 		fname = fn;
28337c478bd9Sstevel@tonic-gate 	}
28347c478bd9Sstevel@tonic-gate 
28357c478bd9Sstevel@tonic-gate 	if (fext = strrchr(fname, '.')) {
28367c478bd9Sstevel@tonic-gate 		fext++;
28377c478bd9Sstevel@tonic-gate 	} else {
28387c478bd9Sstevel@tonic-gate 		fext = "";
28397c478bd9Sstevel@tonic-gate 	}
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate 	fname = strtok(fname, ".");
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 	nl = min(PCFNAMESIZE, (int)strlen(fname));
28447c478bd9Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
28457c478bd9Sstevel@tonic-gate 		dep->pcd_filename[i] = toupper(fname[i]);
28467c478bd9Sstevel@tonic-gate 	}
28477c478bd9Sstevel@tonic-gate 	for (; i < PCFNAMESIZE; i++) {
28487c478bd9Sstevel@tonic-gate 		dep->pcd_filename[i] = ' ';
28497c478bd9Sstevel@tonic-gate 	}
28507c478bd9Sstevel@tonic-gate 
28517c478bd9Sstevel@tonic-gate 	nl = min(PCFEXTSIZE, (int)strlen(fext));
28527c478bd9Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
28537c478bd9Sstevel@tonic-gate 		dep->pcd_ext[i] = toupper(fext[i]);
28547c478bd9Sstevel@tonic-gate 	}
28557c478bd9Sstevel@tonic-gate 	for (; i < PCFEXTSIZE; i++) {
28567c478bd9Sstevel@tonic-gate 		dep->pcd_ext[i] = ' ';
28577c478bd9Sstevel@tonic-gate 	}
28587c478bd9Sstevel@tonic-gate }
28597c478bd9Sstevel@tonic-gate 
28607c478bd9Sstevel@tonic-gate static
28617c478bd9Sstevel@tonic-gate uchar_t *
28627c478bd9Sstevel@tonic-gate build_rootdir(bpb_t *wbpb, char *ffn, int fffd,
28637c478bd9Sstevel@tonic-gate     ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize)
28647c478bd9Sstevel@tonic-gate {
28657c478bd9Sstevel@tonic-gate 	struct pcdir *rootdirp;
28667c478bd9Sstevel@tonic-gate 	struct pcdir *entry;
28677c478bd9Sstevel@tonic-gate 
28687c478bd9Sstevel@tonic-gate 	/*
28697c478bd9Sstevel@tonic-gate 	 * Build a root directory.  It will have at least one entry,
28707c478bd9Sstevel@tonic-gate 	 * the volume label and a second if the first file was defined.
28717c478bd9Sstevel@tonic-gate 	 */
28727c478bd9Sstevel@tonic-gate 	if (MakeFAT32) {
28737c478bd9Sstevel@tonic-gate 		/*
28747c478bd9Sstevel@tonic-gate 		 * We devote an entire cluster to the root
28757c478bd9Sstevel@tonic-gate 		 * directory on FAT32.
28767c478bd9Sstevel@tonic-gate 		 */
28777c478bd9Sstevel@tonic-gate 		*rdirsize = wbpb->bpb.sectors_per_cluster * BPSEC;
28787c478bd9Sstevel@tonic-gate 	} else {
28797c478bd9Sstevel@tonic-gate 		*rdirsize = wbpb->bpb.num_root_entries * sizeof (struct pcdir);
28807c478bd9Sstevel@tonic-gate 	}
28817c478bd9Sstevel@tonic-gate 	if ((rootdirp = (struct pcdir *)malloc(*rdirsize)) == NULL) {
28827c478bd9Sstevel@tonic-gate 		perror(gettext("Root directory allocation"));
28837c478bd9Sstevel@tonic-gate 		exit(4);
28847c478bd9Sstevel@tonic-gate 	} else {
28857c478bd9Sstevel@tonic-gate 		entry = rootdirp;
28867c478bd9Sstevel@tonic-gate 		(void) memset((char *)rootdirp, 0, *rdirsize);
28877c478bd9Sstevel@tonic-gate 	}
28887c478bd9Sstevel@tonic-gate 
28897c478bd9Sstevel@tonic-gate 	/* Create directory entry for first file, if there is one */
28907c478bd9Sstevel@tonic-gate 	if (fffd >= 0) {
28917c478bd9Sstevel@tonic-gate 		dirent_fname_fill(entry, ffn);
28927c478bd9Sstevel@tonic-gate 		entry->pcd_attr = Firstfileattr;
28937c478bd9Sstevel@tonic-gate 		dirent_time_fill(entry);
28947c478bd9Sstevel@tonic-gate 		entry->pcd_scluster_lo = htols(ffstart);
28957c478bd9Sstevel@tonic-gate 		if (MakeFAT32) {
28967c478bd9Sstevel@tonic-gate 			ffstart = ffstart >> 16;
28977c478bd9Sstevel@tonic-gate 			entry->un.pcd_scluster_hi = htols(ffstart);
28987c478bd9Sstevel@tonic-gate 		}
28997c478bd9Sstevel@tonic-gate 		entry->pcd_size = htoli(ffsize);
29007c478bd9Sstevel@tonic-gate 		entry++;
29017c478bd9Sstevel@tonic-gate 	}
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	/* Create directory entry for volume label, if there is one */
29047c478bd9Sstevel@tonic-gate 	if (Label != NULL) {
29057c478bd9Sstevel@tonic-gate 		dirent_label_fill(entry, Label);
29067c478bd9Sstevel@tonic-gate 		entry->pcd_attr = PCA_ARCH | PCA_LABEL;
29077c478bd9Sstevel@tonic-gate 		dirent_time_fill(entry);
29087c478bd9Sstevel@tonic-gate 		entry->pcd_scluster_lo = 0;
29097c478bd9Sstevel@tonic-gate 		if (MakeFAT32) {
29107c478bd9Sstevel@tonic-gate 			entry->un.pcd_scluster_hi = 0;
29117c478bd9Sstevel@tonic-gate 		}
29127c478bd9Sstevel@tonic-gate 		entry->pcd_size = 0;
29137c478bd9Sstevel@tonic-gate 		entry++;
29147c478bd9Sstevel@tonic-gate 	}
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	if (Verbose) {
29177c478bd9Sstevel@tonic-gate 		(void) printf(gettext("First two directory entries"));
29187c478bd9Sstevel@tonic-gate 		header_for_dump();
29197c478bd9Sstevel@tonic-gate 		dump_bytes((uchar_t *)rootdirp, 2 * sizeof (struct pcdir));
29207c478bd9Sstevel@tonic-gate 	}
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate 	return ((uchar_t *)rootdirp);
29237c478bd9Sstevel@tonic-gate }
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate /*
29267c478bd9Sstevel@tonic-gate  * write_rest
29277c478bd9Sstevel@tonic-gate  *
29287c478bd9Sstevel@tonic-gate  *	Write all the bytes from the current file pointer to end of file
29297c478bd9Sstevel@tonic-gate  *	in the source file out to the destination file.  The writes should
29307c478bd9Sstevel@tonic-gate  *	be padded to whole clusters with 0's if necessary.
29317c478bd9Sstevel@tonic-gate  */
29327c478bd9Sstevel@tonic-gate static
29337c478bd9Sstevel@tonic-gate void
29347c478bd9Sstevel@tonic-gate write_rest(bpb_t *wbpb, char *efn, int dfd, int sfd, int remaining)
29357c478bd9Sstevel@tonic-gate {
29367c478bd9Sstevel@tonic-gate 	char buf[BPSEC];
29377c478bd9Sstevel@tonic-gate 	ushort_t numsect, numclust;
29387c478bd9Sstevel@tonic-gate 	ushort_t wnumsect, s;
29397c478bd9Sstevel@tonic-gate 	int doneread = 0;
29407c478bd9Sstevel@tonic-gate 	int rstat;
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 	/*
29437c478bd9Sstevel@tonic-gate 	 * Compute number of clusters required to contain remaining bytes.
29447c478bd9Sstevel@tonic-gate 	 */
29457c478bd9Sstevel@tonic-gate 	numsect = idivceil(remaining, BPSEC);
29467c478bd9Sstevel@tonic-gate 	numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
29477c478bd9Sstevel@tonic-gate 
29487c478bd9Sstevel@tonic-gate 	wnumsect = numclust * wbpb->bpb.sectors_per_cluster;
29497c478bd9Sstevel@tonic-gate 	for (s = 0; s < wnumsect; s++) {
29507c478bd9Sstevel@tonic-gate 		if (!doneread) {
29517c478bd9Sstevel@tonic-gate 			if ((rstat = read(sfd, buf, BPSEC)) < 0) {
29527c478bd9Sstevel@tonic-gate 				perror(efn);
29537c478bd9Sstevel@tonic-gate 				doneread = 1;
29547c478bd9Sstevel@tonic-gate 				rstat = 0;
29557c478bd9Sstevel@tonic-gate 			} else if (rstat == 0) {
29567c478bd9Sstevel@tonic-gate 				doneread = 1;
29577c478bd9Sstevel@tonic-gate 			}
29587c478bd9Sstevel@tonic-gate 			(void) memset(&(buf[rstat]), 0, BPSEC - rstat);
29597c478bd9Sstevel@tonic-gate 		}
29607c478bd9Sstevel@tonic-gate 		if (write(dfd, buf, BPSEC) != BPSEC) {
29617c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Copying "));
29627c478bd9Sstevel@tonic-gate 			perror(efn);
29637c478bd9Sstevel@tonic-gate 		}
29647c478bd9Sstevel@tonic-gate 	}
29657c478bd9Sstevel@tonic-gate }
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate static
29687c478bd9Sstevel@tonic-gate void
29697c478bd9Sstevel@tonic-gate write_fat32_bootstuff(int fd, boot_sector_t *bsp,
2970f127cb91Sfrankho 	struct fat_od_fsi *fsinfop, off64_t seekto)
29717c478bd9Sstevel@tonic-gate {
29727c478bd9Sstevel@tonic-gate 	if (Verbose) {
29737c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Dump of the fs info sector"));
29747c478bd9Sstevel@tonic-gate 		header_for_dump();
2975f127cb91Sfrankho 		dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop));
29767c478bd9Sstevel@tonic-gate 	}
29777c478bd9Sstevel@tonic-gate 
29787c478bd9Sstevel@tonic-gate 	if (!Notreally) {
29797c478bd9Sstevel@tonic-gate 		/*
29807c478bd9Sstevel@tonic-gate 		 * FAT32's have an FS info sector, then a backup of the boot
29817c478bd9Sstevel@tonic-gate 		 * sector, and a modified backup of the FS Info sector.
29827c478bd9Sstevel@tonic-gate 		 */
2983f127cb91Sfrankho 		if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) {
29847c478bd9Sstevel@tonic-gate 			perror(gettext("FS info sector write"));
29857c478bd9Sstevel@tonic-gate 			exit(4);
29867c478bd9Sstevel@tonic-gate 		}
29877c478bd9Sstevel@tonic-gate 		if (lseek64(fd,	seekto + BKUP_BOOTSECT_OFFSET, SEEK_SET) < 0) {
29887c478bd9Sstevel@tonic-gate 			(void) close(fd);
29897c478bd9Sstevel@tonic-gate 			perror(gettext("Boot sector backup seek"));
29907c478bd9Sstevel@tonic-gate 			exit(4);
29917c478bd9Sstevel@tonic-gate 		}
29927c478bd9Sstevel@tonic-gate 		if (write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) {
29937c478bd9Sstevel@tonic-gate 			perror(gettext("Boot sector backup write"));
29947c478bd9Sstevel@tonic-gate 			exit(4);
29957c478bd9Sstevel@tonic-gate 		}
29967c478bd9Sstevel@tonic-gate 	}
29977c478bd9Sstevel@tonic-gate 
29987c478bd9Sstevel@tonic-gate 	/*
29997c478bd9Sstevel@tonic-gate 	 * Second copy of fs info sector is modified to have "don't know"
30007c478bd9Sstevel@tonic-gate 	 * as the number of free clusters
30017c478bd9Sstevel@tonic-gate 	 */
3002f127cb91Sfrankho 	fsinfop->fsi_incore.fs_next_free = LE_32(FSINFO_UNKNOWN);
30037c478bd9Sstevel@tonic-gate 
30047c478bd9Sstevel@tonic-gate 	if (Verbose) {
30057c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Dump of the backup fs info sector"));
30067c478bd9Sstevel@tonic-gate 		header_for_dump();
3007f127cb91Sfrankho 		dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop));
30087c478bd9Sstevel@tonic-gate 	}
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	if (!Notreally) {
3011f127cb91Sfrankho 		if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) {
30127c478bd9Sstevel@tonic-gate 			perror(gettext("FS info sector backup write"));
30137c478bd9Sstevel@tonic-gate 			exit(4);
30147c478bd9Sstevel@tonic-gate 		}
30157c478bd9Sstevel@tonic-gate 	}
30167c478bd9Sstevel@tonic-gate }
30177c478bd9Sstevel@tonic-gate 
30187c478bd9Sstevel@tonic-gate static
30197c478bd9Sstevel@tonic-gate void
30207c478bd9Sstevel@tonic-gate write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb,
3021f127cb91Sfrankho 	struct fat_od_fsi *fsinfop, off64_t seekto)
30227c478bd9Sstevel@tonic-gate {
30237c478bd9Sstevel@tonic-gate 	if (MakeFAT32) {
30247c478bd9Sstevel@tonic-gate 		/* Copy our BPB into bootsec structure */
30257c478bd9Sstevel@tonic-gate #ifdef i386
30267c478bd9Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_front.bs_bpb), &(wbpb->bpb),
30277c478bd9Sstevel@tonic-gate 		    sizeof (wbpb->bpb));
30287c478bd9Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_bpb32), &(wbpb->bpb32),
30297c478bd9Sstevel@tonic-gate 		    sizeof (wbpb->bpb32));
30307c478bd9Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_ebpb), &(wbpb->ebpb),
30317c478bd9Sstevel@tonic-gate 		    sizeof (wbpb->ebpb));
30327c478bd9Sstevel@tonic-gate #else
30337c478bd9Sstevel@tonic-gate 		swap_pack_bpb32cpy(&(bsp->bs32), wbpb);
30347c478bd9Sstevel@tonic-gate #endif
30357c478bd9Sstevel@tonic-gate 	} else {
30367c478bd9Sstevel@tonic-gate 		/* Copy our BPB into bootsec structure */
30377c478bd9Sstevel@tonic-gate #ifdef i386
30387c478bd9Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs.bs_front.bs_bpb), &(wbpb->bpb),
30397c478bd9Sstevel@tonic-gate 		    sizeof (wbpb->bpb));
30407c478bd9Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs.bs_ebpb), &(wbpb->ebpb),
30417c478bd9Sstevel@tonic-gate 		    sizeof (wbpb->ebpb));
30427c478bd9Sstevel@tonic-gate #else
30437c478bd9Sstevel@tonic-gate 		swap_pack_bpbcpy(&(bsp->bs), wbpb);
30447c478bd9Sstevel@tonic-gate #endif
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate 		/* Copy SUN BPB extensions into bootsec structure */
30477c478bd9Sstevel@tonic-gate 		if (SunBPBfields) {
30487c478bd9Sstevel@tonic-gate #ifdef i386
30497c478bd9Sstevel@tonic-gate 			(void) memcpy(&(bsp->bs.bs_sebpb), &(wbpb->sunbpb),
30507c478bd9Sstevel@tonic-gate 			    sizeof (wbpb->sunbpb));
30517c478bd9Sstevel@tonic-gate #else
30527c478bd9Sstevel@tonic-gate 			swap_pack_sebpbcpy(&(bsp->bs), wbpb);
30537c478bd9Sstevel@tonic-gate #endif
30547c478bd9Sstevel@tonic-gate 		}
30557c478bd9Sstevel@tonic-gate 	}
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate 	/* Write boot sector */
30587c478bd9Sstevel@tonic-gate 	if (!Notreally && write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) {
30597c478bd9Sstevel@tonic-gate 		perror(gettext("Boot sector write"));
30607c478bd9Sstevel@tonic-gate 		exit(4);
30617c478bd9Sstevel@tonic-gate 	}
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 	if (Verbose) {
30647c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Dump of the boot sector"));
30657c478bd9Sstevel@tonic-gate 		header_for_dump();
30667c478bd9Sstevel@tonic-gate 		dump_bytes(bsp->buf, sizeof (bsp->buf));
30677c478bd9Sstevel@tonic-gate 	}
30687c478bd9Sstevel@tonic-gate 
30697c478bd9Sstevel@tonic-gate 	if (MakeFAT32)
30707c478bd9Sstevel@tonic-gate 		write_fat32_bootstuff(fd, bsp, fsinfop, seekto);
30717c478bd9Sstevel@tonic-gate }
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate static
30747c478bd9Sstevel@tonic-gate void
30757c478bd9Sstevel@tonic-gate write_fat(int fd, off64_t seekto, char *fn, char *lbl, char *ffn, bpb_t *wbpb)
30767c478bd9Sstevel@tonic-gate {
3077f127cb91Sfrankho 	struct fat_od_fsi fsinfo;
30787c478bd9Sstevel@tonic-gate 	pc_cluster32_t ffsc;
30797c478bd9Sstevel@tonic-gate 	boot_sector_t bootsect;
30807c478bd9Sstevel@tonic-gate 	uchar_t *fatp, *rdirp;
30817c478bd9Sstevel@tonic-gate 	ulong_t bootblksize, fatsize, rdirsize, ffsize;
30827c478bd9Sstevel@tonic-gate 	int bsfd = -1;
30837c478bd9Sstevel@tonic-gate 	int fffd = -1;
30847c478bd9Sstevel@tonic-gate 
30857c478bd9Sstevel@tonic-gate 	compute_file_area_size(wbpb);
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate 	bsfd = copy_bootblk(fn, &bootsect, &bootblksize);
30887c478bd9Sstevel@tonic-gate 	label_volume(lbl, wbpb);
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate 	if (Verbose)
30917c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Building FAT.\n"));
30927c478bd9Sstevel@tonic-gate 	fatp = build_fat(wbpb, &fsinfo, bootblksize, &fatsize,
30937c478bd9Sstevel@tonic-gate 	    ffn, &fffd, &ffsize, &ffsc);
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate 	write_bootsects(fd, &bootsect, wbpb, &fsinfo, seekto);
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 	if (lseek64(fd,
30987c478bd9Sstevel@tonic-gate 	    seekto + (BPSEC * wbpb->bpb.resv_sectors), SEEK_SET) < 0) {
30997c478bd9Sstevel@tonic-gate 		(void) close(fd);
31007c478bd9Sstevel@tonic-gate 		perror(gettext("Seek to end of reserved sectors"));
31017c478bd9Sstevel@tonic-gate 		exit(4);
31027c478bd9Sstevel@tonic-gate 	}
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 	/* Write FAT */
31057c478bd9Sstevel@tonic-gate 	if (Verbose)
31067c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"),
31077c478bd9Sstevel@tonic-gate 		    fatsize, wbpb->bpb.num_fats);
31087c478bd9Sstevel@tonic-gate 	if (!Notreally) {
31097c478bd9Sstevel@tonic-gate 		int nf, wb;
31107c478bd9Sstevel@tonic-gate 		for (nf = 0; nf < (int)wbpb->bpb.num_fats; nf++)
31117c478bd9Sstevel@tonic-gate 			if ((wb = write(fd, fatp, fatsize)) != fatsize) {
31127c478bd9Sstevel@tonic-gate 				perror(gettext("FAT write"));
31137c478bd9Sstevel@tonic-gate 				exit(4);
31147c478bd9Sstevel@tonic-gate 			} else {
31157c478bd9Sstevel@tonic-gate 				if (Verbose)
31167c478bd9Sstevel@tonic-gate 					(void) printf(
31177c478bd9Sstevel@tonic-gate 					    gettext("Wrote %d bytes\n"), wb);
31187c478bd9Sstevel@tonic-gate 			}
31197c478bd9Sstevel@tonic-gate 	}
31207c478bd9Sstevel@tonic-gate 	free(fatp);
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 	if (Verbose)
31237c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Building root directory.\n"));
31247c478bd9Sstevel@tonic-gate 	rdirp = build_rootdir(wbpb, ffn, fffd, ffsize, ffsc, &rdirsize);
31257c478bd9Sstevel@tonic-gate 
31267c478bd9Sstevel@tonic-gate 	/*
31277c478bd9Sstevel@tonic-gate 	 *  In non FAT32, root directory exists outside of the file area
31287c478bd9Sstevel@tonic-gate 	 */
31297c478bd9Sstevel@tonic-gate 	if (!MakeFAT32) {
31307c478bd9Sstevel@tonic-gate 		if (Verbose)
3131f127cb91Sfrankho 			(void) printf(gettext("Writing root directory. "
31327c478bd9Sstevel@tonic-gate 			    "%d bytes.\n"), rdirsize);
31337c478bd9Sstevel@tonic-gate 		if (!Notreally) {
31347c478bd9Sstevel@tonic-gate 			if (write(fd, rdirp, rdirsize) != rdirsize) {
31357c478bd9Sstevel@tonic-gate 				perror(gettext("Root directory write"));
31367c478bd9Sstevel@tonic-gate 				exit(4);
31377c478bd9Sstevel@tonic-gate 			}
31387c478bd9Sstevel@tonic-gate 		}
31397c478bd9Sstevel@tonic-gate 		free(rdirp);
31407c478bd9Sstevel@tonic-gate 	}
31417c478bd9Sstevel@tonic-gate 
31427c478bd9Sstevel@tonic-gate 	/*
31437c478bd9Sstevel@tonic-gate 	 * Now write anything that needs to be in the file space.
31447c478bd9Sstevel@tonic-gate 	 */
31457c478bd9Sstevel@tonic-gate 	if (bootblksize > BPSEC) {
31467c478bd9Sstevel@tonic-gate 		if (Verbose)
31477c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Writing remainder of "
31487c478bd9Sstevel@tonic-gate 			    "boot block.\n"));
31497c478bd9Sstevel@tonic-gate 		if (!Notreally)
31507c478bd9Sstevel@tonic-gate 			write_rest(wbpb, fn, fd, bsfd, bootblksize - BPSEC);
31517c478bd9Sstevel@tonic-gate 	}
31527c478bd9Sstevel@tonic-gate 
31537c478bd9Sstevel@tonic-gate 	if (MakeFAT32) {
31547c478bd9Sstevel@tonic-gate 		if (Verbose)
3155f127cb91Sfrankho 			(void) printf(gettext("Writing root directory. "
31567c478bd9Sstevel@tonic-gate 			    "%d bytes.\n"), rdirsize);
31577c478bd9Sstevel@tonic-gate 		if (!Notreally) {
31587c478bd9Sstevel@tonic-gate 			if (write(fd, rdirp, rdirsize) != rdirsize) {
31597c478bd9Sstevel@tonic-gate 				perror(gettext("Root directory write"));
31607c478bd9Sstevel@tonic-gate 				exit(4);
31617c478bd9Sstevel@tonic-gate 			}
31627c478bd9Sstevel@tonic-gate 		}
31637c478bd9Sstevel@tonic-gate 		free(rdirp);
31647c478bd9Sstevel@tonic-gate 	}
31657c478bd9Sstevel@tonic-gate 
31667c478bd9Sstevel@tonic-gate 	if (fffd >= 0) {
31677c478bd9Sstevel@tonic-gate 		if (Verbose)
31687c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Writing first file.\n"));
31697c478bd9Sstevel@tonic-gate 		if (!Notreally)
31707c478bd9Sstevel@tonic-gate 			write_rest(wbpb, ffn, fd, fffd, ffsize);
31717c478bd9Sstevel@tonic-gate 	}
31727c478bd9Sstevel@tonic-gate }
31737c478bd9Sstevel@tonic-gate 
31747c478bd9Sstevel@tonic-gate static
31757c478bd9Sstevel@tonic-gate char *LegalOpts[] = {
31767c478bd9Sstevel@tonic-gate #define	NFLAG 0
31777c478bd9Sstevel@tonic-gate 	"N",
31787c478bd9Sstevel@tonic-gate #define	VFLAG 1
31797c478bd9Sstevel@tonic-gate 	"v",
31807c478bd9Sstevel@tonic-gate #define	RFLAG 2
31817c478bd9Sstevel@tonic-gate 	"r",
31827c478bd9Sstevel@tonic-gate #define	HFLAG 3
31837c478bd9Sstevel@tonic-gate 	"h",
31847c478bd9Sstevel@tonic-gate #define	SFLAG 4
31857c478bd9Sstevel@tonic-gate 	"s",
31867c478bd9Sstevel@tonic-gate #define	SUNFLAG 5
31877c478bd9Sstevel@tonic-gate 	"S",
31887c478bd9Sstevel@tonic-gate #define	LABFLAG 6
31897c478bd9Sstevel@tonic-gate 	"b",
31907c478bd9Sstevel@tonic-gate #define	BTRFLAG 7
31917c478bd9Sstevel@tonic-gate 	"B",
31927c478bd9Sstevel@tonic-gate #define	INITFLAG 8
31937c478bd9Sstevel@tonic-gate 	"i",
31947c478bd9Sstevel@tonic-gate #define	SZFLAG 9
31957c478bd9Sstevel@tonic-gate 	"size",
31967c478bd9Sstevel@tonic-gate #define	SECTFLAG 10
31977c478bd9Sstevel@tonic-gate 	"nsect",
31987c478bd9Sstevel@tonic-gate #define	TRKFLAG 11
31997c478bd9Sstevel@tonic-gate 	"ntrack",
32007c478bd9Sstevel@tonic-gate #define	SPCFLAG 12
32017c478bd9Sstevel@tonic-gate 	"spc",
32027c478bd9Sstevel@tonic-gate #define	BPFFLAG 13
32037c478bd9Sstevel@tonic-gate 	"fat",
32047c478bd9Sstevel@tonic-gate #define	FFLAG 14
32057c478bd9Sstevel@tonic-gate 	"f",
32067c478bd9Sstevel@tonic-gate #define	DFLAG 15
32077c478bd9Sstevel@tonic-gate 	"d",
32087c478bd9Sstevel@tonic-gate #define	NOFDISKFLAG 16
32097c478bd9Sstevel@tonic-gate 	"nofdisk",
32107c478bd9Sstevel@tonic-gate #define	RESRVFLAG 17
32117c478bd9Sstevel@tonic-gate 	"reserve",
32127c478bd9Sstevel@tonic-gate #define	HIDDENFLAG 18
32137c478bd9Sstevel@tonic-gate 	"hidden",
32147c478bd9Sstevel@tonic-gate 	NULL
32157c478bd9Sstevel@tonic-gate };
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate static
32187c478bd9Sstevel@tonic-gate void
32197c478bd9Sstevel@tonic-gate bad_arg(char *option)
32207c478bd9Sstevel@tonic-gate {
32217c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
32227c478bd9Sstevel@tonic-gate 	    gettext("Unrecognized option %s.\n"), option);
32237c478bd9Sstevel@tonic-gate 	usage();
32247c478bd9Sstevel@tonic-gate 	exit(2);
32257c478bd9Sstevel@tonic-gate }
32267c478bd9Sstevel@tonic-gate 
32277c478bd9Sstevel@tonic-gate static
32287c478bd9Sstevel@tonic-gate void
32297c478bd9Sstevel@tonic-gate missing_arg(char *option)
32307c478bd9Sstevel@tonic-gate {
32317c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
32327c478bd9Sstevel@tonic-gate 	    gettext("Option %s requires a value.\n"), option);
32337c478bd9Sstevel@tonic-gate 	usage();
32347c478bd9Sstevel@tonic-gate 	exit(3);
32357c478bd9Sstevel@tonic-gate }
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate static
32387c478bd9Sstevel@tonic-gate void
32397c478bd9Sstevel@tonic-gate parse_suboptions(char *optsstr)
32407c478bd9Sstevel@tonic-gate {
32417c478bd9Sstevel@tonic-gate 	char *value;
32427c478bd9Sstevel@tonic-gate 	int c;
32437c478bd9Sstevel@tonic-gate 
32447c478bd9Sstevel@tonic-gate 	while (*optsstr != '\0') {
32457c478bd9Sstevel@tonic-gate 		switch (c = getsubopt(&optsstr, LegalOpts, &value)) {
32467c478bd9Sstevel@tonic-gate 		case NFLAG:
32477c478bd9Sstevel@tonic-gate 			Notreally++;
32487c478bd9Sstevel@tonic-gate 			break;
32497c478bd9Sstevel@tonic-gate 		case VFLAG:
32507c478bd9Sstevel@tonic-gate 			Verbose++;
32517c478bd9Sstevel@tonic-gate 			break;
32527c478bd9Sstevel@tonic-gate 		case RFLAG:
32537c478bd9Sstevel@tonic-gate 			Firstfileattr |= 0x01;
32547c478bd9Sstevel@tonic-gate 			break;
32557c478bd9Sstevel@tonic-gate 		case HFLAG:
32567c478bd9Sstevel@tonic-gate 			Firstfileattr |= 0x02;
32577c478bd9Sstevel@tonic-gate 			break;
32587c478bd9Sstevel@tonic-gate 		case SFLAG:
32597c478bd9Sstevel@tonic-gate 			Firstfileattr |= 0x04;
32607c478bd9Sstevel@tonic-gate 			break;
32617c478bd9Sstevel@tonic-gate 		case SUNFLAG:
32627c478bd9Sstevel@tonic-gate 			SunBPBfields = 1;
32637c478bd9Sstevel@tonic-gate 			break;
32647c478bd9Sstevel@tonic-gate 		case LABFLAG:
32657c478bd9Sstevel@tonic-gate 			if (value == NULL) {
32667c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32677c478bd9Sstevel@tonic-gate 			} else {
32687c478bd9Sstevel@tonic-gate 				Label = value;
32697c478bd9Sstevel@tonic-gate 			}
32707c478bd9Sstevel@tonic-gate 			break;
32717c478bd9Sstevel@tonic-gate 		case BTRFLAG:
32727c478bd9Sstevel@tonic-gate 			if (value == NULL) {
32737c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32747c478bd9Sstevel@tonic-gate 			} else {
32757c478bd9Sstevel@tonic-gate 				BootBlkFn = value;
32767c478bd9Sstevel@tonic-gate 			}
32777c478bd9Sstevel@tonic-gate 			break;
32787c478bd9Sstevel@tonic-gate 		case INITFLAG:
32797c478bd9Sstevel@tonic-gate 			if (value == NULL) {
32807c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32817c478bd9Sstevel@tonic-gate 			} else {
32827c478bd9Sstevel@tonic-gate 				FirstFn = value;
32837c478bd9Sstevel@tonic-gate 			}
32847c478bd9Sstevel@tonic-gate 			break;
32857c478bd9Sstevel@tonic-gate 		case SZFLAG:
32867c478bd9Sstevel@tonic-gate 			if (value == NULL) {
32877c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32887c478bd9Sstevel@tonic-gate 			} else {
32897c478bd9Sstevel@tonic-gate 				TotSize = atoi(value);
32907c478bd9Sstevel@tonic-gate 				GetSize = 0;
32917c478bd9Sstevel@tonic-gate 			}
32927c478bd9Sstevel@tonic-gate 			break;
32937c478bd9Sstevel@tonic-gate 		case SECTFLAG:
32947c478bd9Sstevel@tonic-gate 			if (value == NULL) {
32957c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32967c478bd9Sstevel@tonic-gate 			} else {
32977c478bd9Sstevel@tonic-gate 				SecPerTrk = atoi(value);
32987c478bd9Sstevel@tonic-gate 				GetSPT = 0;
32997c478bd9Sstevel@tonic-gate 			}
33007c478bd9Sstevel@tonic-gate 			break;
33017c478bd9Sstevel@tonic-gate 		case TRKFLAG:
33027c478bd9Sstevel@tonic-gate 			if (value == NULL) {
33037c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
33047c478bd9Sstevel@tonic-gate 			} else {
33057c478bd9Sstevel@tonic-gate 				TrkPerCyl = atoi(value);
33067c478bd9Sstevel@tonic-gate 				GetTPC = 0;
33077c478bd9Sstevel@tonic-gate 			}
33087c478bd9Sstevel@tonic-gate 			break;
33097c478bd9Sstevel@tonic-gate 		case SPCFLAG:
33107c478bd9Sstevel@tonic-gate 			if (value == NULL) {
33117c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
33127c478bd9Sstevel@tonic-gate 			} else {
33137c478bd9Sstevel@tonic-gate 				SecPerClust = atoi(value);
33147c478bd9Sstevel@tonic-gate 				GetSPC = 0;
33157c478bd9Sstevel@tonic-gate 			}
33167c478bd9Sstevel@tonic-gate 			break;
33177c478bd9Sstevel@tonic-gate 		case BPFFLAG:
33187c478bd9Sstevel@tonic-gate 			if (value == NULL) {
33197c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
33207c478bd9Sstevel@tonic-gate 			} else {
33217c478bd9Sstevel@tonic-gate 				BitsPerFAT = atoi(value);
33227c478bd9Sstevel@tonic-gate 				GetBPF = 0;
33237c478bd9Sstevel@tonic-gate 			}
33247c478bd9Sstevel@tonic-gate 			break;
33257c478bd9Sstevel@tonic-gate 		case NOFDISKFLAG:
33267c478bd9Sstevel@tonic-gate 			DontUseFdisk = 1;
33277c478bd9Sstevel@tonic-gate 			break;
33287c478bd9Sstevel@tonic-gate 		case RESRVFLAG:
33297c478bd9Sstevel@tonic-gate 			if (value == NULL) {
33307c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
33317c478bd9Sstevel@tonic-gate 			} else {
33327c478bd9Sstevel@tonic-gate 				Resrvd = atoi(value);
33337c478bd9Sstevel@tonic-gate 				GetResrvd = 0;
33347c478bd9Sstevel@tonic-gate 			}
33357c478bd9Sstevel@tonic-gate 			break;
33367c478bd9Sstevel@tonic-gate 		case HIDDENFLAG:
33377c478bd9Sstevel@tonic-gate 			if (value == NULL) {
33387c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
33397c478bd9Sstevel@tonic-gate 			} else {
33407c478bd9Sstevel@tonic-gate 				RelOffset = atoi(value);
33417c478bd9Sstevel@tonic-gate 				GetOffset = 0;
33427c478bd9Sstevel@tonic-gate 			}
33437c478bd9Sstevel@tonic-gate 			break;
33447c478bd9Sstevel@tonic-gate 		case FFLAG:
33457c478bd9Sstevel@tonic-gate 			if (value == NULL) {
33467c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
33477c478bd9Sstevel@tonic-gate 			} else {
33487c478bd9Sstevel@tonic-gate 				DiskName = value;
33497c478bd9Sstevel@tonic-gate 				Outputtofile = 1;
33507c478bd9Sstevel@tonic-gate 			}
33517c478bd9Sstevel@tonic-gate 			break;
33527c478bd9Sstevel@tonic-gate 		case DFLAG:
33537c478bd9Sstevel@tonic-gate 			if (value == NULL) {
33547c478bd9Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
33557c478bd9Sstevel@tonic-gate 			} else {
33567c478bd9Sstevel@tonic-gate 				Imagesize = atoi(value);
33577c478bd9Sstevel@tonic-gate 			}
33587c478bd9Sstevel@tonic-gate 			break;
33597c478bd9Sstevel@tonic-gate 		default:
33607c478bd9Sstevel@tonic-gate 			bad_arg(value);
33617c478bd9Sstevel@tonic-gate 			break;
33627c478bd9Sstevel@tonic-gate 		}
33637c478bd9Sstevel@tonic-gate 	}
33647c478bd9Sstevel@tonic-gate }
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate static
33677c478bd9Sstevel@tonic-gate void
33687c478bd9Sstevel@tonic-gate sanity_check_options(int argc, int optind)
33697c478bd9Sstevel@tonic-gate {
33707c478bd9Sstevel@tonic-gate 	if (GetFsParams) {
33717c478bd9Sstevel@tonic-gate 		if (argc - optind != 1)
33727c478bd9Sstevel@tonic-gate 			usage();
33737c478bd9Sstevel@tonic-gate 		return;
33747c478bd9Sstevel@tonic-gate 	}
33757c478bd9Sstevel@tonic-gate 
33767c478bd9Sstevel@tonic-gate 	if (DontUseFdisk && GetOffset) {
33777c478bd9Sstevel@tonic-gate 		/* Set default relative offset of zero */
33787c478bd9Sstevel@tonic-gate 		RelOffset = 0;
33797c478bd9Sstevel@tonic-gate 	}
33807c478bd9Sstevel@tonic-gate 
33817c478bd9Sstevel@tonic-gate 	if (BitsPerFAT == 32)
33827c478bd9Sstevel@tonic-gate 		MakeFAT32 = 1;
33837c478bd9Sstevel@tonic-gate 
33847c478bd9Sstevel@tonic-gate 	if (Outputtofile && (argc - optind)) {
33857c478bd9Sstevel@tonic-gate 		usage();
33867c478bd9Sstevel@tonic-gate 	} else if (Outputtofile && !DiskName) {
33877c478bd9Sstevel@tonic-gate 		usage();
33887c478bd9Sstevel@tonic-gate 	} else if (!Outputtofile && (argc - optind != 1)) {
33897c478bd9Sstevel@tonic-gate 		usage();
33907c478bd9Sstevel@tonic-gate 	} else if (SunBPBfields && !BootBlkFn) {
33917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
33927c478bd9Sstevel@tonic-gate 		    gettext("Use of the 'S' option requires that\n"
33937c478bd9Sstevel@tonic-gate 		    "the 'B=' option also be used.\n\n"));
33947c478bd9Sstevel@tonic-gate 		usage();
33957c478bd9Sstevel@tonic-gate 	} else if (Firstfileattr != 0x20 && !FirstFn) {
33967c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
33977c478bd9Sstevel@tonic-gate 		    gettext("Use of the 'r', 'h', or 's' options requires\n"
33987c478bd9Sstevel@tonic-gate 		    "that the 'i=' option also be used.\n\n"));
33997c478bd9Sstevel@tonic-gate 		usage();
34007c478bd9Sstevel@tonic-gate 	} else if (!GetOffset && !DontUseFdisk) {
34017c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
34027c478bd9Sstevel@tonic-gate 		    gettext("Use of the 'hidden' option requires that\n"
34037c478bd9Sstevel@tonic-gate 		    "the 'nofdisk' option also be used.\n\n"));
34047c478bd9Sstevel@tonic-gate 		usage();
34057c478bd9Sstevel@tonic-gate 	} else if (DontUseFdisk && GetSize) {
34067c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
34077c478bd9Sstevel@tonic-gate 		    gettext("Use of the 'nofdisk' option requires that\n"
34087c478bd9Sstevel@tonic-gate 		    "the 'size=' option also be used.\n\n"));
34097c478bd9Sstevel@tonic-gate 		usage();
34107c478bd9Sstevel@tonic-gate 	} else if (!GetBPF &&
34117c478bd9Sstevel@tonic-gate 	    BitsPerFAT != 12 && BitsPerFAT != 16 && BitsPerFAT != 32) {
3412f127cb91Sfrankho 		(void) fprintf(stderr, gettext("Invalid Bits/Fat value."
34137c478bd9Sstevel@tonic-gate 		    " Must be 12, 16 or 32.\n"));
34147c478bd9Sstevel@tonic-gate 		exit(2);
3415*db92b35aSGary Mills 	} else if (!GetSPC && !(ISP2(SecPerClust) &&
3416*db92b35aSGary Mills 	    IN_RANGE(SecPerClust, 1, 128))) {
34177c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
34187c478bd9Sstevel@tonic-gate 		    gettext("Invalid Sectors/Cluster value.  Must be a "
34197c478bd9Sstevel@tonic-gate 		    "power of 2 between 1 and 128.\n"));
34207c478bd9Sstevel@tonic-gate 		exit(2);
34217c478bd9Sstevel@tonic-gate 	} else if (!GetResrvd && (Resrvd < 1 || Resrvd > 0xffff)) {
34227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
34237c478bd9Sstevel@tonic-gate 		    gettext("Invalid number of reserved sectors.  "
34247c478bd9Sstevel@tonic-gate 		    "Must be at least 1 but\nno larger than 65535."));
34257c478bd9Sstevel@tonic-gate 		exit(2);
34267c478bd9Sstevel@tonic-gate 	} else if (!GetResrvd && MakeFAT32 &&
34277c478bd9Sstevel@tonic-gate 	    (Resrvd < 32 || Resrvd > 0xffff)) {
34287c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
34297c478bd9Sstevel@tonic-gate 		    gettext("Invalid number of reserved sectors.  "
34307c478bd9Sstevel@tonic-gate 		    "Must be at least 32 but\nno larger than 65535."));
34317c478bd9Sstevel@tonic-gate 		exit(2);
34327c478bd9Sstevel@tonic-gate 	} else if (Imagesize != 3 && Imagesize != 5) {
34337c478bd9Sstevel@tonic-gate 		usage();
34347c478bd9Sstevel@tonic-gate 	}
34357c478bd9Sstevel@tonic-gate }
34367c478bd9Sstevel@tonic-gate 
3437c719c59aSjkennedy int
34387c478bd9Sstevel@tonic-gate main(int argc, char **argv)
34397c478bd9Sstevel@tonic-gate {
34407c478bd9Sstevel@tonic-gate 	off64_t AbsBootSect = 0;
34417c478bd9Sstevel@tonic-gate 	bpb_t dskparamblk;
34427c478bd9Sstevel@tonic-gate 	char *string;
34437c478bd9Sstevel@tonic-gate 	int  fd;
34447c478bd9Sstevel@tonic-gate 	int  c;
34457c478bd9Sstevel@tonic-gate 
34467c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
34477c478bd9Sstevel@tonic-gate 
34487c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
34497c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
34507c478bd9Sstevel@tonic-gate #endif
34517c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) {
34547c478bd9Sstevel@tonic-gate 		switch (c) {
34557c478bd9Sstevel@tonic-gate 		case 'F':
34567c478bd9Sstevel@tonic-gate 			string = optarg;
34577c478bd9Sstevel@tonic-gate 			if (strcmp(string, "pcfs") != 0)
34587c478bd9Sstevel@tonic-gate 				usage();
34597c478bd9Sstevel@tonic-gate 			break;
34607c478bd9Sstevel@tonic-gate 		case 'V':
34617c478bd9Sstevel@tonic-gate 			{
34627c478bd9Sstevel@tonic-gate 				char	*opt_text;
34637c478bd9Sstevel@tonic-gate 				int	opt_count;
34647c478bd9Sstevel@tonic-gate 
34657c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout,
34667c478bd9Sstevel@tonic-gate 				    gettext("mkfs -F pcfs "));
34677c478bd9Sstevel@tonic-gate 				for (opt_count = 1; opt_count < argc;
34687c478bd9Sstevel@tonic-gate 				    opt_count++) {
34697c478bd9Sstevel@tonic-gate 					opt_text = argv[opt_count];
34707c478bd9Sstevel@tonic-gate 					if (opt_text)
3471f127cb91Sfrankho 						(void) fprintf(stdout,
3472f127cb91Sfrankho 						    " %s ", opt_text);
34737c478bd9Sstevel@tonic-gate 				}
34747c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
34757c478bd9Sstevel@tonic-gate 			}
34767c478bd9Sstevel@tonic-gate 			break;
34777c478bd9Sstevel@tonic-gate 		case 'm':
34787c478bd9Sstevel@tonic-gate 			GetFsParams++;
34797c478bd9Sstevel@tonic-gate 			break;
34807c478bd9Sstevel@tonic-gate 		case 'o':
34817c478bd9Sstevel@tonic-gate 			string = optarg;
34827c478bd9Sstevel@tonic-gate 			parse_suboptions(string);
34837c478bd9Sstevel@tonic-gate 			break;
34847c478bd9Sstevel@tonic-gate 		}
34857c478bd9Sstevel@tonic-gate 	}
34867c478bd9Sstevel@tonic-gate 
34877c478bd9Sstevel@tonic-gate 	sanity_check_options(argc, optind);
34887c478bd9Sstevel@tonic-gate 
34897c478bd9Sstevel@tonic-gate 	if (!Outputtofile)
34907c478bd9Sstevel@tonic-gate 		DiskName = argv[optind];
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate 	(void) memset(&dskparamblk, 0, sizeof (dskparamblk));
34937c478bd9Sstevel@tonic-gate 
34947c478bd9Sstevel@tonic-gate 	if (GetFsParams) {
34957c478bd9Sstevel@tonic-gate 		fd = open_and_examine(DiskName, &dskparamblk);
34967c478bd9Sstevel@tonic-gate 	} else {
34977c478bd9Sstevel@tonic-gate 		fd = open_and_seek(DiskName, &dskparamblk, &AbsBootSect);
34987c478bd9Sstevel@tonic-gate 		if (ask_nicely(DiskName))
34997c478bd9Sstevel@tonic-gate 			write_fat(fd, AbsBootSect, BootBlkFn, Label,
35007c478bd9Sstevel@tonic-gate 			    FirstFn, &dskparamblk);
35017c478bd9Sstevel@tonic-gate 	}
35027c478bd9Sstevel@tonic-gate 	(void) close(fd);
3503c719c59aSjkennedy 	return (0);
35047c478bd9Sstevel@tonic-gate }
3505