xref: /onnv-gate/usr/src/cmd/fs.d/pcfs/mkfs/mkfs.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1996, 1998-2001 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <ctype.h>
31*0Sstevel@tonic-gate #include <unistd.h>
32*0Sstevel@tonic-gate #include <stdio.h>
33*0Sstevel@tonic-gate #include <stdlib.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <errno.h>
36*0Sstevel@tonic-gate #include <fcntl.h>
37*0Sstevel@tonic-gate #include <libintl.h>
38*0Sstevel@tonic-gate #include <locale.h>
39*0Sstevel@tonic-gate #include <sys/fdio.h>
40*0Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
41*0Sstevel@tonic-gate #include <sys/dkio.h>
42*0Sstevel@tonic-gate #include <sys/sysmacros.h>
43*0Sstevel@tonic-gate #include "mkfs_pcfs.h"
44*0Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
45*0Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
46*0Sstevel@tonic-gate #include <sys/fs/pc_label.h>
47*0Sstevel@tonic-gate #include <macros.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /*
50*0Sstevel@tonic-gate  *	mkfs (for pcfs)
51*0Sstevel@tonic-gate  *
52*0Sstevel@tonic-gate  *	Install a boot block, FAT, and (if desired) the first resident
53*0Sstevel@tonic-gate  *	of the new fs.
54*0Sstevel@tonic-gate  *
55*0Sstevel@tonic-gate  *	XXX -- floppy opens need O_NDELAY?
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate #define	DEFAULT_LABEL "NONAME"
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate static char	*BootBlkFn = NULL;
60*0Sstevel@tonic-gate static char	*DiskName = NULL;
61*0Sstevel@tonic-gate static char	*FirstFn = NULL;
62*0Sstevel@tonic-gate static char	*Label = NULL;
63*0Sstevel@tonic-gate static char	Firstfileattr = 0x20;
64*0Sstevel@tonic-gate static int	Outputtofile = 0;
65*0Sstevel@tonic-gate static int	SunBPBfields = 0;
66*0Sstevel@tonic-gate static int	GetFsParams = 0;
67*0Sstevel@tonic-gate static int	Fatentsize = 0;
68*0Sstevel@tonic-gate static int	Imagesize = 3;
69*0Sstevel@tonic-gate static int	Notreally = 0;
70*0Sstevel@tonic-gate static int	Verbose = 0;
71*0Sstevel@tonic-gate static int	MakeFAT32 = 0;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate /*
74*0Sstevel@tonic-gate  * If there is an FDISK entry for the device where we're about to
75*0Sstevel@tonic-gate  * make the file system, we ought to make a file system that has the
76*0Sstevel@tonic-gate  * same size FAT as the FDISK table claims.  We track the size FDISK
77*0Sstevel@tonic-gate  * thinks in this variable.
78*0Sstevel@tonic-gate  */
79*0Sstevel@tonic-gate static int	FdiskFATsize = 0;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static int	GetSize = 1;	/* Unless we're given as arg, must look it up */
82*0Sstevel@tonic-gate static ulong_t	TotSize;	/* Total size of FS in # of sectors */
83*0Sstevel@tonic-gate static int	GetSPC = 1;	/* Unless we're given as arg, must calculate */
84*0Sstevel@tonic-gate static ulong_t	SecPerClust;	/* # of sectors per cluster */
85*0Sstevel@tonic-gate static int	GetOffset = 1;	/* Unless we're given as arg, must look it up */
86*0Sstevel@tonic-gate static ulong_t	RelOffset;	/* Relative start sector (hidden sectors) */
87*0Sstevel@tonic-gate static int	GetSPT = 1;	/* Unless we're given as arg, must look it up */
88*0Sstevel@tonic-gate static ushort_t	SecPerTrk;	/* # of sectors per track */
89*0Sstevel@tonic-gate static int	GetTPC = 1;	/* Unless we're given as arg, must look it up */
90*0Sstevel@tonic-gate static ushort_t	TrkPerCyl;	/* # of tracks per cylinder */
91*0Sstevel@tonic-gate static int	GetResrvd = 1;	/* Unless we're given as arg, must calculate */
92*0Sstevel@tonic-gate static ushort_t	Resrvd;		/* Number of reserved sectors */
93*0Sstevel@tonic-gate static int	GetBPF = 1;	/* Unless we're given as arg, must calculate */
94*0Sstevel@tonic-gate static int	BitsPerFAT;	/* Total size of FS in # of sectors */
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate static ulong_t	TotalClusters;	/* Computed total number of clusters */
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate /*
99*0Sstevel@tonic-gate  * Unless we are told otherwise, we should use fdisk table for non-diskettes.
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate static int	DontUseFdisk = 0;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate /*
104*0Sstevel@tonic-gate  * Function prototypes
105*0Sstevel@tonic-gate  */
106*0Sstevel@tonic-gate #ifndef i386
107*0Sstevel@tonic-gate static void swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp);
108*0Sstevel@tonic-gate static void swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb);
109*0Sstevel@tonic-gate static void swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb);
110*0Sstevel@tonic-gate static void swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp);
111*0Sstevel@tonic-gate static void swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb);
112*0Sstevel@tonic-gate #endif
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate static uchar_t *build_rootdir(bpb_t *wbpb, char *ffn, int fffd,
115*0Sstevel@tonic-gate 	ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize);
116*0Sstevel@tonic-gate static uchar_t *build_fat(bpb_t *wbpb, struct fat32_boot_fsinfo *fsinfop,
117*0Sstevel@tonic-gate 	ulong_t bootblksize, ulong_t *fatsize, char *ffn, int *fffd,
118*0Sstevel@tonic-gate 	ulong_t *ffsize, pc_cluster32_t *ffstartclust);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate static char *stat_actual_disk(char *diskname, struct stat *info, char **suffix);
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate static void compare_existing_with_computed(int fd, char *suffix,
123*0Sstevel@tonic-gate 	bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect,
124*0Sstevel@tonic-gate 	int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd,
125*0Sstevel@tonic-gate 	int *dashos);
126*0Sstevel@tonic-gate static void print_reproducing_command(int fd, char *actualdisk, char *suffix,
127*0Sstevel@tonic-gate 	bpb_t *wbpb);
128*0Sstevel@tonic-gate static void compute_file_area_size(bpb_t *wbpb);
129*0Sstevel@tonic-gate static void write_fat32_bootstuff(int fd, boot_sector_t *bsp,
130*0Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto);
131*0Sstevel@tonic-gate static void sanity_check_options(int argc, int optind);
132*0Sstevel@tonic-gate static void compute_cluster_size(bpb_t *wbpb);
133*0Sstevel@tonic-gate static void find_fixed_details(int fd, bpb_t *wbpb);
134*0Sstevel@tonic-gate static void dirent_fname_fill(struct pcdir *dep, char *fn);
135*0Sstevel@tonic-gate static void floppy_bpb_fillin(bpb_t *wbpb,
136*0Sstevel@tonic-gate 	int diam, int hds, int spt);
137*0Sstevel@tonic-gate static void read_existing_bpb(int fd, bpb_t *wbpb);
138*0Sstevel@tonic-gate static void warn_funky_fatsize(void);
139*0Sstevel@tonic-gate static void warn_funky_floppy(void);
140*0Sstevel@tonic-gate static void dirent_time_fill(struct pcdir *dep);
141*0Sstevel@tonic-gate static void parse_suboptions(char *optsstr);
142*0Sstevel@tonic-gate static void header_for_dump(void);
143*0Sstevel@tonic-gate static void write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb,
144*0Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto);
145*0Sstevel@tonic-gate static void fill_bpb_sizes(bpb_t *wbpb, struct ipart part[],
146*0Sstevel@tonic-gate 	int partno, off64_t offset);
147*0Sstevel@tonic-gate static void set_fat_string(bpb_t *wbpb, int fatsize);
148*0Sstevel@tonic-gate static void partn_lecture(char *dn);
149*0Sstevel@tonic-gate static void store_16_bits(uchar_t **bp, uint32_t v);
150*0Sstevel@tonic-gate static void store_32_bits(uchar_t **bp, uint32_t v);
151*0Sstevel@tonic-gate static void lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb);
152*0Sstevel@tonic-gate static void label_volume(char *lbl, bpb_t *wbpb);
153*0Sstevel@tonic-gate static void mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum,
154*0Sstevel@tonic-gate 	uint32_t value);
155*0Sstevel@tonic-gate static void missing_arg(char *option);
156*0Sstevel@tonic-gate static void dashm_bail(int fd);
157*0Sstevel@tonic-gate static void dump_bytes(uchar_t *, int);
158*0Sstevel@tonic-gate static void write_rest(bpb_t *wbpb, char *efn,
159*0Sstevel@tonic-gate 	int dfd, int sfd, int remaining);
160*0Sstevel@tonic-gate static void write_fat(int fd, off64_t seekto, char *fn, char *lbl,
161*0Sstevel@tonic-gate 	char *ffn, bpb_t *wbpb);
162*0Sstevel@tonic-gate static void bad_arg(char *option);
163*0Sstevel@tonic-gate static void usage(void);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate static int prepare_image_file(char *fn, bpb_t *wbpb);
166*0Sstevel@tonic-gate static int verify_bootblkfile(char *fn, boot_sector_t *bs,
167*0Sstevel@tonic-gate 	ulong_t *blkfilesize);
168*0Sstevel@tonic-gate static int open_and_examine(char *dn, bpb_t *wbpb);
169*0Sstevel@tonic-gate static int verify_firstfile(char *fn, ulong_t *filesize);
170*0Sstevel@tonic-gate static int lookup_FAT_size(uchar_t partid);
171*0Sstevel@tonic-gate static int powerofx_le_y(int x, int y, int value);
172*0Sstevel@tonic-gate static int open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto);
173*0Sstevel@tonic-gate static int warn_mismatch(char *desc, char *src, int expect, int assigned);
174*0Sstevel@tonic-gate static int copy_bootblk(char *fn, boot_sector_t *bootsect,
175*0Sstevel@tonic-gate 	ulong_t *bootblksize);
176*0Sstevel@tonic-gate static int parse_drvnum(char *pn);
177*0Sstevel@tonic-gate static int seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto);
178*0Sstevel@tonic-gate static int ask_nicely(char *special);
179*0Sstevel@tonic-gate static int seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto);
180*0Sstevel@tonic-gate static int yes(void);
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate /*
183*0Sstevel@tonic-gate  *  usage
184*0Sstevel@tonic-gate  *
185*0Sstevel@tonic-gate  *	Display usage message and exit.
186*0Sstevel@tonic-gate  */
187*0Sstevel@tonic-gate static
188*0Sstevel@tonic-gate void
189*0Sstevel@tonic-gate usage(void)
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	(void) fprintf(stderr,
192*0Sstevel@tonic-gate 	    gettext("pcfs usage: mkfs [-F FSType] [-V] [-m] "
193*0Sstevel@tonic-gate 		"[-o specific_options] special\n"));
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	(void) fprintf(stderr,
196*0Sstevel@tonic-gate 	    gettext(" -V: print this command line and return\n"
197*0Sstevel@tonic-gate 		" -m: dump command line used to create a FAT on this media\n"
198*0Sstevel@tonic-gate 		"\t(other options are ignored if this option is chosen).\n"
199*0Sstevel@tonic-gate 		" -o: pcfs_specific_options:\n"
200*0Sstevel@tonic-gate 		"\t'pcfs_specific_options' is a comma separated list\n"
201*0Sstevel@tonic-gate 		"\tincluding one or more of the following options:\n"
202*0Sstevel@tonic-gate 		"\t    N,v,r,h,s,b=label,B=filename,i=filename,\n"
203*0Sstevel@tonic-gate 		"\t    spc=n,fat=n,nsect=n,ntrack=n,nofdisk,size=n,\n"
204*0Sstevel@tonic-gate 		"\t    reserve=n,hidden=n\n\n"));
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	(void) fprintf(stderr,
207*0Sstevel@tonic-gate 	    gettext("'Special' should specify a raw diskette "
208*0Sstevel@tonic-gate 			"or raw fixed disk device.  \"Fixed\"\n"
209*0Sstevel@tonic-gate 			"disks (which include high-capacity removable "
210*0Sstevel@tonic-gate 			"media such as Zip disks)\n"
211*0Sstevel@tonic-gate 			"may be further qualified with a logical "
212*0Sstevel@tonic-gate 			"drive specifier.\n"
213*0Sstevel@tonic-gate 			"Examples are: /dev/rdiskette and "
214*0Sstevel@tonic-gate 			"/dev/rdsk/c0t0d0p0:c\n"));
215*0Sstevel@tonic-gate 	exit(1);
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate static
219*0Sstevel@tonic-gate int
220*0Sstevel@tonic-gate yes(void)
221*0Sstevel@tonic-gate {
222*0Sstevel@tonic-gate 	char *affirmative = gettext("yY");
223*0Sstevel@tonic-gate 	char *a = affirmative;
224*0Sstevel@tonic-gate 	int b;
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	b = getchar();
227*0Sstevel@tonic-gate 	while (b == '\n' && b != '\0' && b != EOF)
228*0Sstevel@tonic-gate 		b = getchar();
229*0Sstevel@tonic-gate 	while (*a) {
230*0Sstevel@tonic-gate 		if (b == (int)*a)
231*0Sstevel@tonic-gate 			break;
232*0Sstevel@tonic-gate 		a++;
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 	return (*a);
235*0Sstevel@tonic-gate }
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate /*
238*0Sstevel@tonic-gate  * powerofx_le_y
239*0Sstevel@tonic-gate  *	args of x,y, and value to be checked
240*0Sstevel@tonic-gate  *	returns 1 if x**n == value and n >= 0 and value <= y
241*0Sstevel@tonic-gate  *	returns 0 otherwise
242*0Sstevel@tonic-gate  */
243*0Sstevel@tonic-gate static
244*0Sstevel@tonic-gate int
245*0Sstevel@tonic-gate powerofx_le_y(int x, int y, int value)
246*0Sstevel@tonic-gate {
247*0Sstevel@tonic-gate 	int ispower = 0;
248*0Sstevel@tonic-gate 	int pow = 1;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if (value < 1 || value > y)
251*0Sstevel@tonic-gate 		return (ispower);
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	do {
254*0Sstevel@tonic-gate 		if (pow == value) {
255*0Sstevel@tonic-gate 			ispower = 1;
256*0Sstevel@tonic-gate 			break;
257*0Sstevel@tonic-gate 		}
258*0Sstevel@tonic-gate 		pow *= x;
259*0Sstevel@tonic-gate 	} while (pow <= y);
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	return (ispower);
262*0Sstevel@tonic-gate }
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate static
265*0Sstevel@tonic-gate int
266*0Sstevel@tonic-gate ask_nicely(char *special)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	/*
269*0Sstevel@tonic-gate 	 * 4228473 - No way to non-interactively make a pcfs filesystem
270*0Sstevel@tonic-gate 	 *
271*0Sstevel@tonic-gate 	 *	If we don't have an input TTY, or we aren't really doing
272*0Sstevel@tonic-gate 	 *	anything, then don't ask questions.  Assume a yes answer
273*0Sstevel@tonic-gate 	 *	to any questions we would ask.
274*0Sstevel@tonic-gate 	 */
275*0Sstevel@tonic-gate 	if (Notreally || !isatty(fileno(stdin)))
276*0Sstevel@tonic-gate 		return (1);
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	(void) printf(
279*0Sstevel@tonic-gate 	    gettext("Construct a new FAT file system on %s: (y/n)? "), special);
280*0Sstevel@tonic-gate 	(void) fflush(stdout);
281*0Sstevel@tonic-gate 	return (yes());
282*0Sstevel@tonic-gate }
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate /*
285*0Sstevel@tonic-gate  * store_16_bits
286*0Sstevel@tonic-gate  *	Save the lower 16 bits of a 32 bit value (v) into the provided
287*0Sstevel@tonic-gate  *	buffer (pointed at by *bp), and increment the buffer pointer
288*0Sstevel@tonic-gate  *	as well.  This way the routine can be called multiple times in
289*0Sstevel@tonic-gate  *	succession to fill buffers.  The value is stored in little-endian
290*0Sstevel@tonic-gate  *	order.
291*0Sstevel@tonic-gate  */
292*0Sstevel@tonic-gate static
293*0Sstevel@tonic-gate void
294*0Sstevel@tonic-gate store_16_bits(uchar_t **bp, uint32_t v)
295*0Sstevel@tonic-gate {
296*0Sstevel@tonic-gate 	uchar_t *l = *bp;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	*l++ = v & 0xff;
299*0Sstevel@tonic-gate 	*l = (v >> 8) & 0xff;
300*0Sstevel@tonic-gate 	*bp += 2;
301*0Sstevel@tonic-gate }
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate /*
304*0Sstevel@tonic-gate  * store_32_bits
305*0Sstevel@tonic-gate  * 	Save the 32 bit value (v) into the provided buffer (pointed
306*0Sstevel@tonic-gate  *	at by *bp), and increment the buffer pointer as well.  This way
307*0Sstevel@tonic-gate  *	the routine can be called multiple times in succession to fill
308*0Sstevel@tonic-gate  *	buffers.  The value is stored in little-endian order.
309*0Sstevel@tonic-gate  */
310*0Sstevel@tonic-gate static
311*0Sstevel@tonic-gate void
312*0Sstevel@tonic-gate store_32_bits(uchar_t **bp, uint32_t v)
313*0Sstevel@tonic-gate {
314*0Sstevel@tonic-gate 	uchar_t *l = *bp;
315*0Sstevel@tonic-gate 	int b;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	for (b = 0; b < 4; b++) {
318*0Sstevel@tonic-gate 		*l++ = v & 0xff;
319*0Sstevel@tonic-gate 		v = v >> 8;
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate 	*bp += 4;
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate /*
325*0Sstevel@tonic-gate  *  dump_bytes  -- display bytes as hex numbers.
326*0Sstevel@tonic-gate  *		   b is the pointer to the byte buffer
327*0Sstevel@tonic-gate  *		   n is the number of bytes in the buffer
328*0Sstevel@tonic-gate  */
329*0Sstevel@tonic-gate /* Note: BPL = bytes to display per line */
330*0Sstevel@tonic-gate #define	BPL 16
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate static
333*0Sstevel@tonic-gate void
334*0Sstevel@tonic-gate dump_bytes(uchar_t *b, int n)
335*0Sstevel@tonic-gate {
336*0Sstevel@tonic-gate 	int cd = n;
337*0Sstevel@tonic-gate 	int cu = 0;
338*0Sstevel@tonic-gate 	int o = 0;
339*0Sstevel@tonic-gate 	int bl;
340*0Sstevel@tonic-gate 	int ac;
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	/* Display offset, 16 bytes per line, and printable ascii version */
343*0Sstevel@tonic-gate 	while (cd > 0) {
344*0Sstevel@tonic-gate 		ac = 0;
345*0Sstevel@tonic-gate 		(void) printf("\n%06x: ", o);
346*0Sstevel@tonic-gate 		for (bl = 0; bl < BPL; bl++) {
347*0Sstevel@tonic-gate 			if (cu+bl < n) {
348*0Sstevel@tonic-gate 				(void) printf("%02x ", (b[cu+bl] & 0xff));
349*0Sstevel@tonic-gate 				ac++;
350*0Sstevel@tonic-gate 			}
351*0Sstevel@tonic-gate 			else
352*0Sstevel@tonic-gate 				(void) printf("   ");
353*0Sstevel@tonic-gate 		}
354*0Sstevel@tonic-gate 		for (bl = 0; bl < BPL; bl++) {
355*0Sstevel@tonic-gate 			if ((cu+bl < n) &&
356*0Sstevel@tonic-gate 				((b[cu+bl] >= ' ') && (b[cu+bl] <= '~')))
357*0Sstevel@tonic-gate 					(void) printf("%c", b[cu+bl]);
358*0Sstevel@tonic-gate 			else
359*0Sstevel@tonic-gate 				(void) printf(".");
360*0Sstevel@tonic-gate 		}
361*0Sstevel@tonic-gate 		cu += ac; o += ac; cd -= ac;
362*0Sstevel@tonic-gate 	}
363*0Sstevel@tonic-gate 	(void) printf("\n\n");
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate /*
367*0Sstevel@tonic-gate  *  header_for_dump  --  display simple header over what will be output.
368*0Sstevel@tonic-gate  */
369*0Sstevel@tonic-gate static
370*0Sstevel@tonic-gate void
371*0Sstevel@tonic-gate header_for_dump(void)
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate 	int bl;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	(void) printf("\n        ");
376*0Sstevel@tonic-gate 	for (bl = 0; bl < BPL; bl++)
377*0Sstevel@tonic-gate 		(void) printf("%02x ", bl);
378*0Sstevel@tonic-gate 	(void) printf("\n       ");
379*0Sstevel@tonic-gate 	bl = 3*BPL;
380*0Sstevel@tonic-gate 	while (bl-- > 0)
381*0Sstevel@tonic-gate 		(void) printf("-");
382*0Sstevel@tonic-gate }
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate /*
385*0Sstevel@tonic-gate  *  parse_drvnum
386*0Sstevel@tonic-gate  *	Convert a partition name into a drive number.
387*0Sstevel@tonic-gate  */
388*0Sstevel@tonic-gate static
389*0Sstevel@tonic-gate int
390*0Sstevel@tonic-gate parse_drvnum(char *pn)
391*0Sstevel@tonic-gate {
392*0Sstevel@tonic-gate 	int drvnum;
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	/*
395*0Sstevel@tonic-gate 	 * Determine logical drive to seek after.
396*0Sstevel@tonic-gate 	 */
397*0Sstevel@tonic-gate 	if (strlen(pn) == 1 && *pn >= 'c' && *pn <= 'z') {
398*0Sstevel@tonic-gate 		drvnum = *pn - 'c' + 1;
399*0Sstevel@tonic-gate 	} else if (*pn >= '0' && *pn <= '9') {
400*0Sstevel@tonic-gate 		char *d;
401*0Sstevel@tonic-gate 		int v, m, c;
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 		v = 0;
404*0Sstevel@tonic-gate 		d = pn;
405*0Sstevel@tonic-gate 		while (*d && *d >= '0' && *d <= '9') {
406*0Sstevel@tonic-gate 			c = strlen(d);
407*0Sstevel@tonic-gate 			m = 1;
408*0Sstevel@tonic-gate 			while (--c)
409*0Sstevel@tonic-gate 				m *= 10;
410*0Sstevel@tonic-gate 			v += m * (*d - '0');
411*0Sstevel@tonic-gate 			d++;
412*0Sstevel@tonic-gate 		}
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 		if (*d || v > 24) {
415*0Sstevel@tonic-gate 			(void) fprintf(stderr,
416*0Sstevel@tonic-gate 			    gettext("%s: bogus logical drive specification.\n"),
417*0Sstevel@tonic-gate 			    pn);
418*0Sstevel@tonic-gate 			return (-1);
419*0Sstevel@tonic-gate 		}
420*0Sstevel@tonic-gate 		drvnum = v;
421*0Sstevel@tonic-gate 	} else if (strcmp(pn, "boot") == 0) {
422*0Sstevel@tonic-gate 		drvnum = 99;
423*0Sstevel@tonic-gate 	} else {
424*0Sstevel@tonic-gate 		(void) fprintf(stderr,
425*0Sstevel@tonic-gate 		    gettext("%s: bogus logical drive specification.\n"), pn);
426*0Sstevel@tonic-gate 		return (-1);
427*0Sstevel@tonic-gate 	}
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	return (drvnum);
430*0Sstevel@tonic-gate }
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate /*
433*0Sstevel@tonic-gate  *  Define some special logical drives we use.
434*0Sstevel@tonic-gate  */
435*0Sstevel@tonic-gate #define	BOOT_PARTITION_DRIVE	99
436*0Sstevel@tonic-gate #define	PRIMARY_DOS_DRIVE	1
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate /*
439*0Sstevel@tonic-gate  * isDosDrive()
440*0Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
441*0Sstevel@tonic-gate  *	and it decides if that's a systid that describes a DOS drive.  We
442*0Sstevel@tonic-gate  *	use systid values defined in sys/dktp/fdisk.h.
443*0Sstevel@tonic-gate  */
444*0Sstevel@tonic-gate static int
445*0Sstevel@tonic-gate isDosDrive(uchar_t checkMe)
446*0Sstevel@tonic-gate {
447*0Sstevel@tonic-gate 	return ((checkMe == DOSOS12) || (checkMe == DOSOS16) ||
448*0Sstevel@tonic-gate 	    (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) ||
449*0Sstevel@tonic-gate 	    (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) ||
450*0Sstevel@tonic-gate 	    (checkMe == DIAGPART));
451*0Sstevel@tonic-gate }
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate /*
454*0Sstevel@tonic-gate  * isDosExtended()
455*0Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
456*0Sstevel@tonic-gate  *	and it decides if that's a systid that describes an extended DOS
457*0Sstevel@tonic-gate  *	partition.
458*0Sstevel@tonic-gate  */
459*0Sstevel@tonic-gate static int
460*0Sstevel@tonic-gate isDosExtended(uchar_t checkMe)
461*0Sstevel@tonic-gate {
462*0Sstevel@tonic-gate 	return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA));
463*0Sstevel@tonic-gate }
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate /*
466*0Sstevel@tonic-gate  * isBootPart()
467*0Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
468*0Sstevel@tonic-gate  *	and it decides if that's a systid that describes a Solaris boot
469*0Sstevel@tonic-gate  *	partition.
470*0Sstevel@tonic-gate  */
471*0Sstevel@tonic-gate static int
472*0Sstevel@tonic-gate isBootPart(uchar_t checkMe)
473*0Sstevel@tonic-gate {
474*0Sstevel@tonic-gate 	return (checkMe == X86BOOT);
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate static
478*0Sstevel@tonic-gate int
479*0Sstevel@tonic-gate warn_mismatch(char *desc, char *src, int expect, int assigned)
480*0Sstevel@tonic-gate {
481*0Sstevel@tonic-gate 	if (expect == assigned)
482*0Sstevel@tonic-gate 		return (assigned);
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	/*
485*0Sstevel@tonic-gate 	 * 4228473 - No way to non-interactively make a pcfs filesystem
486*0Sstevel@tonic-gate 	 *
487*0Sstevel@tonic-gate 	 *	If we don't have an input TTY, or we aren't really doing
488*0Sstevel@tonic-gate 	 *	anything, then don't ask questions.  Assume a yes answer
489*0Sstevel@tonic-gate 	 *	to any questions we would ask.
490*0Sstevel@tonic-gate 	 */
491*0Sstevel@tonic-gate 	if (Notreally || !isatty(fileno(stdin))) {
492*0Sstevel@tonic-gate 		(void) printf(gettext("WARNING: User supplied %s is %d,"
493*0Sstevel@tonic-gate 			"\nbut value obtained from the %s is %d.\n"
494*0Sstevel@tonic-gate 			"Using user supplied value.\n"),
495*0Sstevel@tonic-gate 			desc, assigned, src, expect);
496*0Sstevel@tonic-gate 		return (assigned);
497*0Sstevel@tonic-gate 	}
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	(void) printf(gettext("User supplied %s is %d."
500*0Sstevel@tonic-gate 		"\nThe value obtained from the %s is %d.\n"),
501*0Sstevel@tonic-gate 		desc, assigned, src, expect);
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	(void) printf(
504*0Sstevel@tonic-gate 	    gettext("Continue with value given on command line (y/n)? "));
505*0Sstevel@tonic-gate 	(void) fflush(stdout);
506*0Sstevel@tonic-gate 	if (yes())
507*0Sstevel@tonic-gate 		return (assigned);
508*0Sstevel@tonic-gate 	else
509*0Sstevel@tonic-gate 		exit(2);
510*0Sstevel@tonic-gate 	/*NOTREACHED*/
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate static
514*0Sstevel@tonic-gate void
515*0Sstevel@tonic-gate fill_fat32_bpb(bpb_t *wbpb)
516*0Sstevel@tonic-gate {
517*0Sstevel@tonic-gate 	/*
518*0Sstevel@tonic-gate 	 * ExtFlags means (according to MSDN BPB (FAT32) document)
519*0Sstevel@tonic-gate 	 *
520*0Sstevel@tonic-gate 	 * Bit 8 indicates info written to the active FAT is written
521*0Sstevel@tonic-gate 	 * to all copies of the FAT.  (I think they mean bit 7, with
522*0Sstevel@tonic-gate 	 * numbering starting at 0)
523*0Sstevel@tonic-gate 	 *
524*0Sstevel@tonic-gate 	 * Lowest 4 bits of field are the 0 based FAT number of the
525*0Sstevel@tonic-gate 	 * Active FAT.  (only meaningful if bit 8 is set)
526*0Sstevel@tonic-gate 	 *
527*0Sstevel@tonic-gate 	 * Field contains combination of these values:
528*0Sstevel@tonic-gate 	 *
529*0Sstevel@tonic-gate 	 *	VALUE				DESCRIPTION
530*0Sstevel@tonic-gate 	 * BGBPB_F_ActiveFATMsk		Mask for low four bits
531*0Sstevel@tonic-gate 	 * (0x000F)
532*0Sstevel@tonic-gate 	 * BGBPB_F_NoFATMirror		If set FAT mirroring disabled.
533*0Sstevel@tonic-gate 	 * (0x0080)			If clear, FAT mirroring enabled.
534*0Sstevel@tonic-gate 	 *
535*0Sstevel@tonic-gate 	 * We set the value based on what I've seen on all the FAT32 drives
536*0Sstevel@tonic-gate 	 * I've seen created by Windows.
537*0Sstevel@tonic-gate 	 *
538*0Sstevel@tonic-gate 	 */
539*0Sstevel@tonic-gate 	wbpb->bpb32.ext_flags = 0x0;
540*0Sstevel@tonic-gate 	/*
541*0Sstevel@tonic-gate 	 * No real explanation of the fs_vers file in the BPB doc.  The
542*0Sstevel@tonic-gate 	 * high byte is supposed to be the major version and the low the
543*0Sstevel@tonic-gate 	 * minor version.  Again I set according to what I've seen on Windows.
544*0Sstevel@tonic-gate 	 */
545*0Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_lo = '\0';
546*0Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_hi = '\0';
547*0Sstevel@tonic-gate 	/*
548*0Sstevel@tonic-gate 	 * The convention appears to be to place the fs info sector
549*0Sstevel@tonic-gate 	 * immediately after the boot sector, and that the backup boot
550*0Sstevel@tonic-gate 	 * sector should be at sector 6. (based on what I see with
551*0Sstevel@tonic-gate 	 * Windows)
552*0Sstevel@tonic-gate 	 */
553*0Sstevel@tonic-gate 	wbpb->bpb32.fsinfosec = 1;
554*0Sstevel@tonic-gate 	wbpb->bpb32.backupboot = 6;
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate static
558*0Sstevel@tonic-gate void
559*0Sstevel@tonic-gate fill_bpb_sizes(bpb_t *wbpb, struct ipart part[], int partno, off64_t offset)
560*0Sstevel@tonic-gate {
561*0Sstevel@tonic-gate 	ulong_t usesize;
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	if (GetFsParams || GetSize) {
564*0Sstevel@tonic-gate 		usesize = ltohi(part[partno].numsect);
565*0Sstevel@tonic-gate 		if (Verbose) {
566*0Sstevel@tonic-gate 		    (void) printf(
567*0Sstevel@tonic-gate 			gettext("Partition size (from FDISK table) "
568*0Sstevel@tonic-gate 			    "= %d sectors.\n"), usesize);
569*0Sstevel@tonic-gate 		}
570*0Sstevel@tonic-gate 	} else {
571*0Sstevel@tonic-gate 		usesize = warn_mismatch(
572*0Sstevel@tonic-gate 		    gettext("length of partition (in sectors)"),
573*0Sstevel@tonic-gate 		    gettext("FDISK table"),
574*0Sstevel@tonic-gate 		    ltohi(part[partno].numsect), TotSize);
575*0Sstevel@tonic-gate 	}
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	if (GetFsParams) {
578*0Sstevel@tonic-gate 		TotSize = usesize;
579*0Sstevel@tonic-gate 	} else {
580*0Sstevel@tonic-gate 		if (usesize > 0xffff)
581*0Sstevel@tonic-gate 			wbpb->bpb.sectors_in_volume = 0;
582*0Sstevel@tonic-gate 		else
583*0Sstevel@tonic-gate 			wbpb->bpb.sectors_in_volume = usesize;
584*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = usesize;
585*0Sstevel@tonic-gate 	}
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = offset;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	if (GetFsParams) {
590*0Sstevel@tonic-gate 		RelOffset = offset;
591*0Sstevel@tonic-gate 	} else {
592*0Sstevel@tonic-gate 		wbpb->sunbpb.bs_offset_high = offset >> 16;
593*0Sstevel@tonic-gate 		wbpb->sunbpb.bs_offset_low = offset & 0xFFFF;
594*0Sstevel@tonic-gate 	}
595*0Sstevel@tonic-gate }
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate /*
598*0Sstevel@tonic-gate  *  lookup_FAT_size
599*0Sstevel@tonic-gate  *
600*0Sstevel@tonic-gate  *	Given the FDISK partition file system identifier, return the
601*0Sstevel@tonic-gate  *	expected FAT size for the partition.
602*0Sstevel@tonic-gate  */
603*0Sstevel@tonic-gate static
604*0Sstevel@tonic-gate int
605*0Sstevel@tonic-gate lookup_FAT_size(uchar_t partid)
606*0Sstevel@tonic-gate {
607*0Sstevel@tonic-gate 	int rval;
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 	switch (partid) {
610*0Sstevel@tonic-gate 	case DOSOS12:
611*0Sstevel@tonic-gate 		rval = 12;
612*0Sstevel@tonic-gate 		break;
613*0Sstevel@tonic-gate 	case DOSOS16:
614*0Sstevel@tonic-gate 	case DOSHUGE:
615*0Sstevel@tonic-gate 	case FDISK_FAT95:
616*0Sstevel@tonic-gate 	case X86BOOT:
617*0Sstevel@tonic-gate 		rval = 16;
618*0Sstevel@tonic-gate 		break;
619*0Sstevel@tonic-gate 	case FDISK_WINDOWS:
620*0Sstevel@tonic-gate 	case FDISK_EXT_WIN:
621*0Sstevel@tonic-gate 		rval = 32;
622*0Sstevel@tonic-gate 		break;
623*0Sstevel@tonic-gate 	case EXTDOS:
624*0Sstevel@tonic-gate 	case FDISK_EXTLBA:
625*0Sstevel@tonic-gate 	default:
626*0Sstevel@tonic-gate 		rval = -1;
627*0Sstevel@tonic-gate 		break;
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	return (rval);
631*0Sstevel@tonic-gate }
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate /*
634*0Sstevel@tonic-gate  *  seek_partn
635*0Sstevel@tonic-gate  *
636*0Sstevel@tonic-gate  *	Seek to the beginning of the partition where we need to install
637*0Sstevel@tonic-gate  *	the new FAT.  Zero return for any error, but print error
638*0Sstevel@tonic-gate  *	messages here.
639*0Sstevel@tonic-gate  */
640*0Sstevel@tonic-gate static
641*0Sstevel@tonic-gate int
642*0Sstevel@tonic-gate seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto)
643*0Sstevel@tonic-gate {
644*0Sstevel@tonic-gate 	struct ipart part[FD_NUMPART];
645*0Sstevel@tonic-gate 	struct mboot extmboot;
646*0Sstevel@tonic-gate 	struct mboot mb;
647*0Sstevel@tonic-gate 	daddr_t xstartsect;
648*0Sstevel@tonic-gate 	off64_t nextseek = 0;
649*0Sstevel@tonic-gate 	off64_t lastseek = 0;
650*0Sstevel@tonic-gate 	int logicalDriveCount = 0;
651*0Sstevel@tonic-gate 	int extendedPart = -1;
652*0Sstevel@tonic-gate 	int primaryPart = -1;
653*0Sstevel@tonic-gate 	int bootPart = -1;
654*0Sstevel@tonic-gate 	int xnumsect = -1;
655*0Sstevel@tonic-gate 	int drvnum;
656*0Sstevel@tonic-gate 	int driveIndex;
657*0Sstevel@tonic-gate 	int i;
658*0Sstevel@tonic-gate 	/*
659*0Sstevel@tonic-gate 	 * Count of drives in the current extended partition's
660*0Sstevel@tonic-gate 	 * FDISK table, and indexes of the drives themselves.
661*0Sstevel@tonic-gate 	 */
662*0Sstevel@tonic-gate 	int extndDrives[FD_NUMPART];
663*0Sstevel@tonic-gate 	int numDrives = 0;
664*0Sstevel@tonic-gate 	/*
665*0Sstevel@tonic-gate 	 * Count of drives (beyond primary) in master boot record's
666*0Sstevel@tonic-gate 	 * FDISK table, and indexes of the drives themselves.
667*0Sstevel@tonic-gate 	 */
668*0Sstevel@tonic-gate 	int extraDrives[FD_NUMPART];
669*0Sstevel@tonic-gate 	int numExtraDrives = 0;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	if ((drvnum = parse_drvnum(pn)) < 0)
672*0Sstevel@tonic-gate 		return (PART_NOT_FOUND);
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	if (read(fd, &mb, sizeof (mb)) != sizeof (mb)) {
675*0Sstevel@tonic-gate 		(void) fprintf(stderr,
676*0Sstevel@tonic-gate 		    gettext("Couldn't read a Master Boot Record?!\n"));
677*0Sstevel@tonic-gate 		return (PART_NOT_FOUND);
678*0Sstevel@tonic-gate 	}
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 	if (ltohs(mb.signature) != BOOTSECSIG) {
681*0Sstevel@tonic-gate 		(void) fprintf(stderr,
682*0Sstevel@tonic-gate 		    gettext("Bad Sig on master boot record!\n"));
683*0Sstevel@tonic-gate 		return (PART_NOT_FOUND);
684*0Sstevel@tonic-gate 	}
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	*seekto = 0;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	/*
689*0Sstevel@tonic-gate 	 * Copy partition table into memory
690*0Sstevel@tonic-gate 	 */
691*0Sstevel@tonic-gate 	(void) memcpy(part, mb.parts, sizeof (part));
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	/*
694*0Sstevel@tonic-gate 	 * Get a summary of what is in the Master FDISK table.
695*0Sstevel@tonic-gate 	 * Normally we expect to find one partition marked as a DOS drive.
696*0Sstevel@tonic-gate 	 * This partition is the one Windows calls the primary dos partition.
697*0Sstevel@tonic-gate 	 * If the machine has any logical drives then we also expect
698*0Sstevel@tonic-gate 	 * to find a partition marked as an extended DOS partition.
699*0Sstevel@tonic-gate 	 *
700*0Sstevel@tonic-gate 	 * Sometimes we'll find multiple partitions marked as DOS drives.
701*0Sstevel@tonic-gate 	 * The Solaris fdisk program allows these partitions
702*0Sstevel@tonic-gate 	 * to be created, but Windows fdisk no longer does.  We still need
703*0Sstevel@tonic-gate 	 * to support these, though, since Windows does.  We also need to fix
704*0Sstevel@tonic-gate 	 * our fdisk to behave like the Windows version.
705*0Sstevel@tonic-gate 	 *
706*0Sstevel@tonic-gate 	 * It turns out that some off-the-shelf media have *only* an
707*0Sstevel@tonic-gate 	 * Extended partition, so we need to deal with that case as
708*0Sstevel@tonic-gate 	 * well.
709*0Sstevel@tonic-gate 	 *
710*0Sstevel@tonic-gate 	 * Only a single (the first) Extended or Boot Partition will
711*0Sstevel@tonic-gate 	 * be recognized.  Any others will be ignored.
712*0Sstevel@tonic-gate 	 */
713*0Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
714*0Sstevel@tonic-gate 		if (isDosDrive(part[i].systid)) {
715*0Sstevel@tonic-gate 			if (primaryPart < 0) {
716*0Sstevel@tonic-gate 				logicalDriveCount++;
717*0Sstevel@tonic-gate 				primaryPart = i;
718*0Sstevel@tonic-gate 			} else {
719*0Sstevel@tonic-gate 				extraDrives[numExtraDrives++] = i;
720*0Sstevel@tonic-gate 			}
721*0Sstevel@tonic-gate 			continue;
722*0Sstevel@tonic-gate 		}
723*0Sstevel@tonic-gate 		if ((extendedPart < 0) && isDosExtended(part[i].systid)) {
724*0Sstevel@tonic-gate 			extendedPart = i;
725*0Sstevel@tonic-gate 			continue;
726*0Sstevel@tonic-gate 		}
727*0Sstevel@tonic-gate 		if ((bootPart < 0) && isBootPart(part[i].systid)) {
728*0Sstevel@tonic-gate 			bootPart = i;
729*0Sstevel@tonic-gate 			continue;
730*0Sstevel@tonic-gate 		}
731*0Sstevel@tonic-gate 	}
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 	if (drvnum == BOOT_PARTITION_DRIVE) {
734*0Sstevel@tonic-gate 		if (bootPart < 0) {
735*0Sstevel@tonic-gate 			(void) fprintf(stderr,
736*0Sstevel@tonic-gate 			    gettext("No boot partition found on drive\n"));
737*0Sstevel@tonic-gate 			return (PART_NOT_FOUND);
738*0Sstevel@tonic-gate 		}
739*0Sstevel@tonic-gate 		if ((*seekto = ltohi(part[bootPart].relsect)) == 0) {
740*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
741*0Sstevel@tonic-gate 			    "A boot partition starting\nat sector 0 would "
742*0Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
743*0Sstevel@tonic-gate 			return (PART_NOT_FOUND);
744*0Sstevel@tonic-gate 		}
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, bootPart, *seekto);
747*0Sstevel@tonic-gate 		*seekto *= BPSEC;
748*0Sstevel@tonic-gate 		FdiskFATsize = lookup_FAT_size(part[bootPart].systid);
749*0Sstevel@tonic-gate 		if (Verbose)
750*0Sstevel@tonic-gate 			(void) printf(gettext("Boot partition's offset: "
751*0Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
752*0Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
753*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Partition %s: "), pn);
754*0Sstevel@tonic-gate 			perror("");
755*0Sstevel@tonic-gate 			return (PART_NOT_FOUND);
756*0Sstevel@tonic-gate 		}
757*0Sstevel@tonic-gate 		return (PART_FOUND);
758*0Sstevel@tonic-gate 	}
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	if (drvnum == PRIMARY_DOS_DRIVE && primaryPart >= 0) {
761*0Sstevel@tonic-gate 		if ((*seekto = ltohi(part[primaryPart].relsect)) == 0) {
762*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
763*0Sstevel@tonic-gate 			    "A partition starting\nat sector 0 would "
764*0Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
765*0Sstevel@tonic-gate 			return (PART_NOT_FOUND);
766*0Sstevel@tonic-gate 		}
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, primaryPart, *seekto);
769*0Sstevel@tonic-gate 		*seekto *= BPSEC;
770*0Sstevel@tonic-gate 		FdiskFATsize = lookup_FAT_size(part[primaryPart].systid);
771*0Sstevel@tonic-gate 		if (Verbose)
772*0Sstevel@tonic-gate 			(void) printf(gettext("Partition's offset: "
773*0Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
774*0Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
775*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Partition %s: "), pn);
776*0Sstevel@tonic-gate 			perror("");
777*0Sstevel@tonic-gate 			return (PART_NOT_FOUND);
778*0Sstevel@tonic-gate 		}
779*0Sstevel@tonic-gate 		return (PART_FOUND);
780*0Sstevel@tonic-gate 	}
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	/*
783*0Sstevel@tonic-gate 	 * We are not looking for the C: drive (or there was no primary
784*0Sstevel@tonic-gate 	 * drive found), so we had better have an extended partition or
785*0Sstevel@tonic-gate 	 * extra drives in the Master FDISK table.
786*0Sstevel@tonic-gate 	 */
787*0Sstevel@tonic-gate 	if ((extendedPart < 0) && (numExtraDrives == 0)) {
788*0Sstevel@tonic-gate 		(void) fprintf(stderr,
789*0Sstevel@tonic-gate 		    gettext("No such logical drive "
790*0Sstevel@tonic-gate 		    "(missing extended partition entry)\n"));
791*0Sstevel@tonic-gate 		return (PART_NOT_FOUND);
792*0Sstevel@tonic-gate 	}
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 	if (extendedPart >= 0) {
795*0Sstevel@tonic-gate 		nextseek = xstartsect = ltohi(part[extendedPart].relsect);
796*0Sstevel@tonic-gate 		xnumsect = ltohi(part[extendedPart].numsect);
797*0Sstevel@tonic-gate 		do {
798*0Sstevel@tonic-gate 			/*
799*0Sstevel@tonic-gate 			 *  If the seek would not cause us to change
800*0Sstevel@tonic-gate 			 *  position on the drive, then we're out of
801*0Sstevel@tonic-gate 			 *  extended partitions to examine.
802*0Sstevel@tonic-gate 			 */
803*0Sstevel@tonic-gate 			if (nextseek == lastseek)
804*0Sstevel@tonic-gate 				break;
805*0Sstevel@tonic-gate 			logicalDriveCount += numDrives;
806*0Sstevel@tonic-gate 			/*
807*0Sstevel@tonic-gate 			 *  Seek the next extended partition, and find
808*0Sstevel@tonic-gate 			 *  logical drives within it.
809*0Sstevel@tonic-gate 			 */
810*0Sstevel@tonic-gate 			if (lseek64(fd, nextseek * BPSEC, SEEK_SET) < 0 ||
811*0Sstevel@tonic-gate 			    read(fd, &extmboot, sizeof (extmboot)) !=
812*0Sstevel@tonic-gate 				sizeof (extmboot)) {
813*0Sstevel@tonic-gate 				perror(gettext("Unable to read extended "
814*0Sstevel@tonic-gate 					"partition record"));
815*0Sstevel@tonic-gate 				return (PART_NOT_FOUND);
816*0Sstevel@tonic-gate 			}
817*0Sstevel@tonic-gate 			(void) memcpy(part, extmboot.parts, sizeof (part));
818*0Sstevel@tonic-gate 			lastseek = nextseek;
819*0Sstevel@tonic-gate 			if (ltohs(extmboot.signature) != MBB_MAGIC) {
820*0Sstevel@tonic-gate 				(void) fprintf(stderr,
821*0Sstevel@tonic-gate 				    gettext("Bad signature on "
822*0Sstevel@tonic-gate 				    "extended partition\n"));
823*0Sstevel@tonic-gate 				return (PART_NOT_FOUND);
824*0Sstevel@tonic-gate 			}
825*0Sstevel@tonic-gate 			/*
826*0Sstevel@tonic-gate 			 *  Count up drives, and track where the next
827*0Sstevel@tonic-gate 			 *  extended partition is in case we need it.  We
828*0Sstevel@tonic-gate 			 *  are expecting only one extended partition.  If
829*0Sstevel@tonic-gate 			 *  there is more than one we'll only go to the
830*0Sstevel@tonic-gate 			 *  first one we see, but warn about ignoring.
831*0Sstevel@tonic-gate 			 */
832*0Sstevel@tonic-gate 			numDrives = 0;
833*0Sstevel@tonic-gate 			for (i = 0; i < FD_NUMPART; i++) {
834*0Sstevel@tonic-gate 				if (isDosDrive(part[i].systid)) {
835*0Sstevel@tonic-gate 					extndDrives[numDrives++] = i;
836*0Sstevel@tonic-gate 					continue;
837*0Sstevel@tonic-gate 				} else if (isDosExtended(part[i].systid)) {
838*0Sstevel@tonic-gate 					if (nextseek != lastseek) {
839*0Sstevel@tonic-gate 						/*
840*0Sstevel@tonic-gate 						 * Already found an extended
841*0Sstevel@tonic-gate 						 * partition in this table.
842*0Sstevel@tonic-gate 						 */
843*0Sstevel@tonic-gate 						(void) fprintf(stderr,
844*0Sstevel@tonic-gate 						    gettext("WARNING: "
845*0Sstevel@tonic-gate 						    "Ignoring unexpected "
846*0Sstevel@tonic-gate 						    "additional extended "
847*0Sstevel@tonic-gate 						    "partition"));
848*0Sstevel@tonic-gate 						continue;
849*0Sstevel@tonic-gate 					}
850*0Sstevel@tonic-gate 					nextseek = xstartsect +
851*0Sstevel@tonic-gate 					    ltohi(part[i].relsect);
852*0Sstevel@tonic-gate 					continue;
853*0Sstevel@tonic-gate 				}
854*0Sstevel@tonic-gate 			}
855*0Sstevel@tonic-gate 		} while (drvnum > logicalDriveCount + numDrives);
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 		if (drvnum <= logicalDriveCount + numDrives) {
858*0Sstevel@tonic-gate 			/*
859*0Sstevel@tonic-gate 			 * The number of logical drives we've found thus
860*0Sstevel@tonic-gate 			 * far is enough to get us to the one we were
861*0Sstevel@tonic-gate 			 * searching for.
862*0Sstevel@tonic-gate 			 */
863*0Sstevel@tonic-gate 			driveIndex = logicalDriveCount + numDrives - drvnum;
864*0Sstevel@tonic-gate 			*seekto =
865*0Sstevel@tonic-gate 			    ltohi(part[extndDrives[driveIndex]].relsect) +
866*0Sstevel@tonic-gate 			    lastseek;
867*0Sstevel@tonic-gate 			if (*seekto == lastseek) {
868*0Sstevel@tonic-gate 				(void) fprintf(stderr,
869*0Sstevel@tonic-gate 				    gettext("Bogus FDISK entry?  A logical "
870*0Sstevel@tonic-gate 				    "drive starting at\nsector 0x%llx would "
871*0Sstevel@tonic-gate 				    "collide with the\nFDISK information in "
872*0Sstevel@tonic-gate 				    "that sector.\n"), *seekto);
873*0Sstevel@tonic-gate 				return (PART_NOT_FOUND);
874*0Sstevel@tonic-gate 			} else if (*seekto <= xstartsect ||
875*0Sstevel@tonic-gate 			    *seekto >= (xstartsect + xnumsect)) {
876*0Sstevel@tonic-gate 				(void) fprintf(stderr,
877*0Sstevel@tonic-gate 				    gettext("Bogus FDISK entry?  "
878*0Sstevel@tonic-gate 				    "Logical drive start sector (0x%llx)\n"
879*0Sstevel@tonic-gate 				    "not within extended partition! "
880*0Sstevel@tonic-gate 				    "(Expected in range 0x%x - 0x%x)\n"),
881*0Sstevel@tonic-gate 				    *seekto, xstartsect + 1,
882*0Sstevel@tonic-gate 				    xstartsect + xnumsect - 1);
883*0Sstevel@tonic-gate 				return (PART_NOT_FOUND);
884*0Sstevel@tonic-gate 			}
885*0Sstevel@tonic-gate 			fill_bpb_sizes(wbpb, part, extndDrives[driveIndex],
886*0Sstevel@tonic-gate 			    *seekto);
887*0Sstevel@tonic-gate 			*seekto *= BPSEC;
888*0Sstevel@tonic-gate 			FdiskFATsize = lookup_FAT_size(
889*0Sstevel@tonic-gate 			    part[extndDrives[driveIndex]].systid);
890*0Sstevel@tonic-gate 			if (Verbose)
891*0Sstevel@tonic-gate 				(void) printf(gettext("Partition's offset: "
892*0Sstevel@tonic-gate 				    "Sector 0x%x.\n"), *seekto/BPSEC);
893*0Sstevel@tonic-gate 			if (lseek64(fd, *seekto, SEEK_SET) < 0) {
894*0Sstevel@tonic-gate 				(void) fprintf(stderr,
895*0Sstevel@tonic-gate 				    gettext("Partition %s: "), pn);
896*0Sstevel@tonic-gate 				perror("");
897*0Sstevel@tonic-gate 				return (PART_NOT_FOUND);
898*0Sstevel@tonic-gate 			}
899*0Sstevel@tonic-gate 			return (PART_FOUND);
900*0Sstevel@tonic-gate 		} else {
901*0Sstevel@tonic-gate 			/*
902*0Sstevel@tonic-gate 			 * We ran out of extended dos partition
903*0Sstevel@tonic-gate 			 * drives.  The only hope now is to go
904*0Sstevel@tonic-gate 			 * back to extra drives defined in the master
905*0Sstevel@tonic-gate 			 * fdisk table.  But we overwrote that table
906*0Sstevel@tonic-gate 			 * already, so we must load it in again.
907*0Sstevel@tonic-gate 			 */
908*0Sstevel@tonic-gate 			logicalDriveCount += numDrives;
909*0Sstevel@tonic-gate 			(void) memcpy(part, mb.parts, sizeof (part));
910*0Sstevel@tonic-gate 		}
911*0Sstevel@tonic-gate 	}
912*0Sstevel@tonic-gate 	/*
913*0Sstevel@tonic-gate 	 *  Still haven't found the drive, is it an extra
914*0Sstevel@tonic-gate 	 *  drive defined in the main FDISK table?
915*0Sstevel@tonic-gate 	 */
916*0Sstevel@tonic-gate 	if (drvnum <= logicalDriveCount + numExtraDrives) {
917*0Sstevel@tonic-gate 		driveIndex = logicalDriveCount + numExtraDrives - drvnum;
918*0Sstevel@tonic-gate 		*seekto = ltohi(part[extraDrives[driveIndex]].relsect);
919*0Sstevel@tonic-gate 		if (*seekto == 0) {
920*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
921*0Sstevel@tonic-gate 			    "A partition starting\nat sector 0 would "
922*0Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
923*0Sstevel@tonic-gate 			return (PART_NOT_FOUND);
924*0Sstevel@tonic-gate 		}
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, extraDrives[driveIndex], *seekto);
927*0Sstevel@tonic-gate 		*seekto *= BPSEC;
928*0Sstevel@tonic-gate 		FdiskFATsize =
929*0Sstevel@tonic-gate 			lookup_FAT_size(part[extraDrives[driveIndex]].systid);
930*0Sstevel@tonic-gate 		if (Verbose)
931*0Sstevel@tonic-gate 			(void) printf(gettext("Partition's offset: "
932*0Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
933*0Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
934*0Sstevel@tonic-gate 			(void) fprintf(stderr,
935*0Sstevel@tonic-gate 			    gettext("Partition %s: "), pn);
936*0Sstevel@tonic-gate 			perror("");
937*0Sstevel@tonic-gate 			return (PART_NOT_FOUND);
938*0Sstevel@tonic-gate 		}
939*0Sstevel@tonic-gate 		return (PART_FOUND);
940*0Sstevel@tonic-gate 	}
941*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("No such logical drive\n"));
942*0Sstevel@tonic-gate 	return (PART_NOT_FOUND);
943*0Sstevel@tonic-gate }
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate /*
946*0Sstevel@tonic-gate  *  seek_nofdisk
947*0Sstevel@tonic-gate  *
948*0Sstevel@tonic-gate  *	User is asking us to trust them that they know best.
949*0Sstevel@tonic-gate  *	We basically won't do much seeking here, the only seeking we'll do
950*0Sstevel@tonic-gate  *	is if the 'hidden' parameter was given.
951*0Sstevel@tonic-gate  */
952*0Sstevel@tonic-gate static
953*0Sstevel@tonic-gate int
954*0Sstevel@tonic-gate seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto)
955*0Sstevel@tonic-gate {
956*0Sstevel@tonic-gate 	if (TotSize > 0xffff)
957*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 0;
958*0Sstevel@tonic-gate 	else
959*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = (short)TotSize;
960*0Sstevel@tonic-gate 	wbpb->bpb.sectors_in_logical_volume = TotSize;
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 	*seekto = RelOffset * BPSEC;
963*0Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = RelOffset;
964*0Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = RelOffset >> 16;
965*0Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = RelOffset & 0xFFFF;
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 	if (Verbose)
968*0Sstevel@tonic-gate 		(void) printf(gettext("Requested offset: Sector %x.\n"),
969*0Sstevel@tonic-gate 		    *seekto/BPSEC);
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	if (lseek64(fd, *seekto, SEEK_SET) < 0) {
972*0Sstevel@tonic-gate 		(void) fprintf(stderr,
973*0Sstevel@tonic-gate 		    gettext("User specified start sector %d"), RelOffset);
974*0Sstevel@tonic-gate 		perror("");
975*0Sstevel@tonic-gate 		return (PART_NOT_FOUND);
976*0Sstevel@tonic-gate 	}
977*0Sstevel@tonic-gate 	return (PART_FOUND);
978*0Sstevel@tonic-gate }
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate /*
981*0Sstevel@tonic-gate  * set_fat_string
982*0Sstevel@tonic-gate  *
983*0Sstevel@tonic-gate  *	Fill in the type string of the FAT
984*0Sstevel@tonic-gate  */
985*0Sstevel@tonic-gate static
986*0Sstevel@tonic-gate void
987*0Sstevel@tonic-gate set_fat_string(bpb_t *wbpb, int fatsize)
988*0Sstevel@tonic-gate {
989*0Sstevel@tonic-gate 	if (fatsize == 12) {
990*0Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT12_TYPE_STRING,
991*0Sstevel@tonic-gate 			strlen(FAT12_TYPE_STRING));
992*0Sstevel@tonic-gate 	} else if (fatsize == 16) {
993*0Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT16_TYPE_STRING,
994*0Sstevel@tonic-gate 			strlen(FAT16_TYPE_STRING));
995*0Sstevel@tonic-gate 	} else {
996*0Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT32_TYPE_STRING,
997*0Sstevel@tonic-gate 			strlen(FAT32_TYPE_STRING));
998*0Sstevel@tonic-gate 	}
999*0Sstevel@tonic-gate }
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate /*
1002*0Sstevel@tonic-gate  *  prepare_image_file
1003*0Sstevel@tonic-gate  *
1004*0Sstevel@tonic-gate  *	Open the file that will hold the image (as opposed to the image
1005*0Sstevel@tonic-gate  *	being written to the boot sector of an actual disk).
1006*0Sstevel@tonic-gate  */
1007*0Sstevel@tonic-gate static
1008*0Sstevel@tonic-gate int
1009*0Sstevel@tonic-gate prepare_image_file(char *fn, bpb_t *wbpb)
1010*0Sstevel@tonic-gate {
1011*0Sstevel@tonic-gate 	int fd;
1012*0Sstevel@tonic-gate 	char zerobyte = '\0';
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate 	if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) {
1015*0Sstevel@tonic-gate 		perror(fn);
1016*0Sstevel@tonic-gate 		exit(2);
1017*0Sstevel@tonic-gate 	}
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 	if (Imagesize == 5) {
1020*0Sstevel@tonic-gate 		/* Disk image of a 1.2M floppy */
1021*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 2 * 80 * 15;
1022*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 15;
1023*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = 15;
1024*0Sstevel@tonic-gate 		wbpb->bpb.heads = 2;
1025*0Sstevel@tonic-gate 		wbpb->bpb.media = 0xF9;
1026*0Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 224;
1027*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_cluster = 1;
1028*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 7;
1029*0Sstevel@tonic-gate 	} else {
1030*0Sstevel@tonic-gate 		/* Disk image of a 1.44M floppy */
1031*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 2 * 80 * 18;
1032*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 18;
1033*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = 18;
1034*0Sstevel@tonic-gate 		wbpb->bpb.heads = 2;
1035*0Sstevel@tonic-gate 		wbpb->bpb.media = 0xF0;
1036*0Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 224;
1037*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_cluster = 1;
1038*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 9;
1039*0Sstevel@tonic-gate 	}
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 	/*
1042*0Sstevel@tonic-gate 	 * Make a holey file, with length the exact
1043*0Sstevel@tonic-gate 	 * size of the floppy image.
1044*0Sstevel@tonic-gate 	 */
1045*0Sstevel@tonic-gate 	if (lseek(fd, (wbpb->bpb.sectors_in_volume * BPSEC)-1, SEEK_SET) < 0) {
1046*0Sstevel@tonic-gate 		(void) close(fd);
1047*0Sstevel@tonic-gate 		perror(fn);
1048*0Sstevel@tonic-gate 		exit(2);
1049*0Sstevel@tonic-gate 	}
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	if (write(fd, &zerobyte, 1) != 1) {
1052*0Sstevel@tonic-gate 		(void) close(fd);
1053*0Sstevel@tonic-gate 		perror(fn);
1054*0Sstevel@tonic-gate 		exit(2);
1055*0Sstevel@tonic-gate 	}
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) < 0) {
1058*0Sstevel@tonic-gate 		(void) close(fd);
1059*0Sstevel@tonic-gate 		perror(fn);
1060*0Sstevel@tonic-gate 		exit(2);
1061*0Sstevel@tonic-gate 	}
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate 	Fatentsize = 12;  /* Size of fat entry in bits */
1064*0Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0;
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = 0;
1069*0Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = 0;
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 	return (fd);
1072*0Sstevel@tonic-gate }
1073*0Sstevel@tonic-gate 
1074*0Sstevel@tonic-gate /*
1075*0Sstevel@tonic-gate  *  partn_lecture
1076*0Sstevel@tonic-gate  *
1077*0Sstevel@tonic-gate  *	Give a brief sermon on dev_name user should pass to
1078*0Sstevel@tonic-gate  *	the program from the command line.
1079*0Sstevel@tonic-gate  *
1080*0Sstevel@tonic-gate  */
1081*0Sstevel@tonic-gate static
1082*0Sstevel@tonic-gate void
1083*0Sstevel@tonic-gate partn_lecture(char *dn)
1084*0Sstevel@tonic-gate {
1085*0Sstevel@tonic-gate 	(void) fprintf(stderr,
1086*0Sstevel@tonic-gate 		gettext("\nDevice %s was assumed to be a diskette.\n"
1087*0Sstevel@tonic-gate 		    "A diskette specific operation failed on this device.\n"
1088*0Sstevel@tonic-gate 		    "If the device is a hard disk, provide the name of "
1089*0Sstevel@tonic-gate 		    "the full physical disk,\n"
1090*0Sstevel@tonic-gate 		    "and qualify that name with a logical drive specifier.\n\n"
1091*0Sstevel@tonic-gate 		    "Hint: the device is usually something similar to\n\n"
1092*0Sstevel@tonic-gate 		    "/dev/rdsk/c0d0p0 or /dev/rdsk/c0t0d0p0 (x86)\n"
1093*0Sstevel@tonic-gate 		    "/dev/rdsk/c0t5d0s2 (sparc)\n\n"
1094*0Sstevel@tonic-gate 		    "The drive specifier is appended to the device name."
1095*0Sstevel@tonic-gate 		    " For example:\n\n"
1096*0Sstevel@tonic-gate 		    "/dev/rdsk/c0t5d0s2:c or /dev/rdsk/c0d0p0:boot\n\n"), dn);
1097*0Sstevel@tonic-gate }
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate static
1100*0Sstevel@tonic-gate void
1101*0Sstevel@tonic-gate warn_funky_floppy(void)
1102*0Sstevel@tonic-gate {
1103*0Sstevel@tonic-gate 	(void) fprintf(stderr,
1104*0Sstevel@tonic-gate 	    gettext("Use the 'nofdisk' option to create file systems\n"
1105*0Sstevel@tonic-gate 		    "on non-standard floppies.\n\n"));
1106*0Sstevel@tonic-gate 	exit(4);
1107*0Sstevel@tonic-gate }
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate static
1110*0Sstevel@tonic-gate void
1111*0Sstevel@tonic-gate warn_funky_fatsize(void)
1112*0Sstevel@tonic-gate {
1113*0Sstevel@tonic-gate 	(void) fprintf(stderr,
1114*0Sstevel@tonic-gate 	    gettext("Non-standard FAT size requested for floppy.\n"
1115*0Sstevel@tonic-gate 		    "The 'nofdisk' option must be used to\n"
1116*0Sstevel@tonic-gate 		    "override the 12 bit floppy default.\n\n"));
1117*0Sstevel@tonic-gate 	exit(4);
1118*0Sstevel@tonic-gate }
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate static
1121*0Sstevel@tonic-gate void
1122*0Sstevel@tonic-gate floppy_bpb_fillin(bpb_t *wbpb, int diam, int hds, int spt)
1123*0Sstevel@tonic-gate {
1124*0Sstevel@tonic-gate 	switch (diam) {
1125*0Sstevel@tonic-gate 	case 3:
1126*0Sstevel@tonic-gate 		switch (hds) {
1127*0Sstevel@tonic-gate 		case 2:
1128*0Sstevel@tonic-gate 			switch (spt) {
1129*0Sstevel@tonic-gate 			case 9:
1130*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xF9;
1131*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
1132*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
1133*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 3;
1134*0Sstevel@tonic-gate 				break;
1135*0Sstevel@tonic-gate 			case 18:
1136*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xF0;
1137*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 224;
1138*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
1139*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 9;
1140*0Sstevel@tonic-gate 				break;
1141*0Sstevel@tonic-gate 			case 36:
1142*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xF0;
1143*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 240;
1144*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
1145*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 9;
1146*0Sstevel@tonic-gate 				break;
1147*0Sstevel@tonic-gate 			default:
1148*0Sstevel@tonic-gate 				(void) fprintf(stderr,
1149*0Sstevel@tonic-gate 				    gettext("Unknown diskette parameters!  "
1150*0Sstevel@tonic-gate 					"3.5'' diskette with %d heads "
1151*0Sstevel@tonic-gate 					"and %d sectors/track.\n"), hds, spt);
1152*0Sstevel@tonic-gate 				warn_funky_floppy();
1153*0Sstevel@tonic-gate 			}
1154*0Sstevel@tonic-gate 			break;
1155*0Sstevel@tonic-gate 		case 1:
1156*0Sstevel@tonic-gate 		default:
1157*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1158*0Sstevel@tonic-gate 			    gettext("Unknown diskette parameters!  "
1159*0Sstevel@tonic-gate 				"3.5'' diskette with %d heads "), hds);
1160*0Sstevel@tonic-gate 			warn_funky_floppy();
1161*0Sstevel@tonic-gate 		}
1162*0Sstevel@tonic-gate 		break;
1163*0Sstevel@tonic-gate 	case 5:
1164*0Sstevel@tonic-gate 		switch (hds) {
1165*0Sstevel@tonic-gate 		case 2:
1166*0Sstevel@tonic-gate 			switch (spt) {
1167*0Sstevel@tonic-gate 			case 15:
1168*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xF9;
1169*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 224;
1170*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
1171*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 7;
1172*0Sstevel@tonic-gate 				break;
1173*0Sstevel@tonic-gate 			case 9:
1174*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xFD;
1175*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
1176*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
1177*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
1178*0Sstevel@tonic-gate 				break;
1179*0Sstevel@tonic-gate 			case 8:
1180*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xFF;
1181*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
1182*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
1183*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
1184*0Sstevel@tonic-gate 				break;
1185*0Sstevel@tonic-gate 			default:
1186*0Sstevel@tonic-gate 				(void) fprintf(stderr,
1187*0Sstevel@tonic-gate 				    gettext("Unknown diskette parameters!  "
1188*0Sstevel@tonic-gate 					"5.25'' diskette with %d heads "
1189*0Sstevel@tonic-gate 					"and %d sectors/track.\n"), hds, spt);
1190*0Sstevel@tonic-gate 				warn_funky_floppy();
1191*0Sstevel@tonic-gate 			}
1192*0Sstevel@tonic-gate 			break;
1193*0Sstevel@tonic-gate 		case 1:
1194*0Sstevel@tonic-gate 			switch (spt) {
1195*0Sstevel@tonic-gate 			case 9:
1196*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xFC;
1197*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 64;
1198*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
1199*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
1200*0Sstevel@tonic-gate 				break;
1201*0Sstevel@tonic-gate 			case 8:
1202*0Sstevel@tonic-gate 				wbpb->bpb.media = 0xFE;
1203*0Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 64;
1204*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
1205*0Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 1;
1206*0Sstevel@tonic-gate 				break;
1207*0Sstevel@tonic-gate 			default:
1208*0Sstevel@tonic-gate 				(void) fprintf(stderr,
1209*0Sstevel@tonic-gate 				    gettext("Unknown diskette parameters! "
1210*0Sstevel@tonic-gate 					"5.25'' diskette with %d heads "
1211*0Sstevel@tonic-gate 					"and %d sectors/track.\n"), hds, spt);
1212*0Sstevel@tonic-gate 				warn_funky_floppy();
1213*0Sstevel@tonic-gate 			}
1214*0Sstevel@tonic-gate 			break;
1215*0Sstevel@tonic-gate 		default:
1216*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1217*0Sstevel@tonic-gate 			    gettext("Unknown diskette parameters! "
1218*0Sstevel@tonic-gate 				"5.25'' diskette with %d heads."), hds);
1219*0Sstevel@tonic-gate 			warn_funky_floppy();
1220*0Sstevel@tonic-gate 		}
1221*0Sstevel@tonic-gate 		break;
1222*0Sstevel@tonic-gate 	default:
1223*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1224*0Sstevel@tonic-gate 		    gettext("\nUnknown diskette type.  Only know about "
1225*0Sstevel@tonic-gate 			"5.25'' and 3.5'' diskettes.\n"));
1226*0Sstevel@tonic-gate 		warn_funky_floppy();
1227*0Sstevel@tonic-gate 	}
1228*0Sstevel@tonic-gate }
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate /*
1231*0Sstevel@tonic-gate  *  lookup_floppy
1232*0Sstevel@tonic-gate  *
1233*0Sstevel@tonic-gate  *	Look up a media descriptor byte and other crucial BPB values
1234*0Sstevel@tonic-gate  *	based on floppy characteristics.
1235*0Sstevel@tonic-gate  */
1236*0Sstevel@tonic-gate static
1237*0Sstevel@tonic-gate void
1238*0Sstevel@tonic-gate lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb)
1239*0Sstevel@tonic-gate {
1240*0Sstevel@tonic-gate 	ulong_t tsize;
1241*0Sstevel@tonic-gate 	ulong_t cyls, spt, hds, diam;
1242*0Sstevel@tonic-gate 
1243*0Sstevel@tonic-gate 	cyls = fdchar->fdc_ncyl;
1244*0Sstevel@tonic-gate 	diam = fdchar->fdc_medium;
1245*0Sstevel@tonic-gate 	spt = fdchar->fdc_secptrack;
1246*0Sstevel@tonic-gate 	hds = fdchar->fdc_nhead;
1247*0Sstevel@tonic-gate 
1248*0Sstevel@tonic-gate 	tsize = cyls * hds * spt;
1249*0Sstevel@tonic-gate 
1250*0Sstevel@tonic-gate 	if (GetFsParams)
1251*0Sstevel@tonic-gate 		TotSize = tsize;
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	if (GetSize) {
1254*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = tsize;
1255*0Sstevel@tonic-gate 	} else {
1256*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume =
1257*0Sstevel@tonic-gate 			warn_mismatch(
1258*0Sstevel@tonic-gate 			    gettext("length of partition (in sectors)"),
1259*0Sstevel@tonic-gate 			    gettext("FDIOGCHAR call"), tsize, TotSize);
1260*0Sstevel@tonic-gate 	}
1261*0Sstevel@tonic-gate 	wbpb->bpb.sectors_in_volume =
1262*0Sstevel@tonic-gate 		(short)wbpb->bpb.sectors_in_logical_volume;
1263*0Sstevel@tonic-gate 
1264*0Sstevel@tonic-gate 	if (GetSPT) {
1265*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = spt;
1266*0Sstevel@tonic-gate 	} else {
1267*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track =
1268*0Sstevel@tonic-gate 			warn_mismatch(
1269*0Sstevel@tonic-gate 			    gettext("sectors per track"),
1270*0Sstevel@tonic-gate 			    gettext("FDIOGCHAR call"), spt, SecPerTrk);
1271*0Sstevel@tonic-gate 		spt = wbpb->bpb.sectors_per_track;
1272*0Sstevel@tonic-gate 	}
1273*0Sstevel@tonic-gate 
1274*0Sstevel@tonic-gate 	if (GetTPC) {
1275*0Sstevel@tonic-gate 		wbpb->bpb.heads = hds;
1276*0Sstevel@tonic-gate 	} else {
1277*0Sstevel@tonic-gate 		wbpb->bpb.heads =
1278*0Sstevel@tonic-gate 			warn_mismatch(
1279*0Sstevel@tonic-gate 			    gettext("number of heads"),
1280*0Sstevel@tonic-gate 			    gettext("FDIOGCHAR call"), hds, TrkPerCyl);
1281*0Sstevel@tonic-gate 		hds = wbpb->bpb.heads;
1282*0Sstevel@tonic-gate 	}
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 	Fatentsize = 12;  /* Size of fat entry in bits */
1285*0Sstevel@tonic-gate 	if (!GetBPF && BitsPerFAT != Fatentsize) {
1286*0Sstevel@tonic-gate 		warn_funky_fatsize();
1287*0Sstevel@tonic-gate 	}
1288*0Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
1289*0Sstevel@tonic-gate 
1290*0Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0;
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = 0;
1293*0Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = 0;
1294*0Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = 0;
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 	floppy_bpb_fillin(wbpb, diam, hds, spt);
1297*0Sstevel@tonic-gate }
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate /*
1300*0Sstevel@tonic-gate  *  compute_cluster_size
1301*0Sstevel@tonic-gate  *
1302*0Sstevel@tonic-gate  *	Compute an acceptable sectors/cluster value.
1303*0Sstevel@tonic-gate  *
1304*0Sstevel@tonic-gate  *	Values taken from a table found on p. 407 of "Windows 98
1305*0Sstevel@tonic-gate  *	Professional Reference", by Bruce A. Hallberg & Joe
1306*0Sstevel@tonic-gate  *	Casad. (ISBN 0-56205-786-3) I believe they've taken their
1307*0Sstevel@tonic-gate  *	table directly from the MSDN docs.
1308*0Sstevel@tonic-gate  *
1309*0Sstevel@tonic-gate  *	FAT32 information taken from "Partition Magic 6.0", User Guide, p67.
1310*0Sstevel@tonic-gate  *	It uses strange values as 8.01, 16.02 and 32.04; the windows support
1311*0Sstevel@tonic-gate  *	site uses 8G and 16G.
1312*0Sstevel@tonic-gate  */
1313*0Sstevel@tonic-gate static
1314*0Sstevel@tonic-gate void
1315*0Sstevel@tonic-gate compute_cluster_size(bpb_t *wbpb)
1316*0Sstevel@tonic-gate {
1317*0Sstevel@tonic-gate 	ulong_t volsize, maxclusters;
1318*0Sstevel@tonic-gate 	ulong_t spc, spf;
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate 	volsize = wbpb->bpb.sectors_in_volume ? wbpb->bpb.sectors_in_volume :
1321*0Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume;
1322*0Sstevel@tonic-gate 	volsize -= wbpb->bpb.resv_sectors;
1323*0Sstevel@tonic-gate 
1324*0Sstevel@tonic-gate 	if (GetSPC) {
1325*0Sstevel@tonic-gate 		if (MakeFAT32) {
1326*0Sstevel@tonic-gate 			if (volsize <= 0x1000000) {		/* 8G */
1327*0Sstevel@tonic-gate 				spc = 8;
1328*0Sstevel@tonic-gate 			} else if (volsize <= 0x2000000) {	/* 16G */
1329*0Sstevel@tonic-gate 				spc = 16;
1330*0Sstevel@tonic-gate 			} else if (volsize <= 0x4000000) {	/* 32G */
1331*0Sstevel@tonic-gate 				spc = 32;
1332*0Sstevel@tonic-gate 			} else {
1333*0Sstevel@tonic-gate 				spc = 64;
1334*0Sstevel@tonic-gate 			}
1335*0Sstevel@tonic-gate 		} else {
1336*0Sstevel@tonic-gate 			if (volsize <= 0x10000) {		/* 32M */
1337*0Sstevel@tonic-gate 				spc = 1;
1338*0Sstevel@tonic-gate 			} else if (volsize <= 0x20000) {	/* 64M */
1339*0Sstevel@tonic-gate 				spc = 2;
1340*0Sstevel@tonic-gate 			} else if (volsize <= 0x40000) {	/* 128M */
1341*0Sstevel@tonic-gate 				spc = 4;
1342*0Sstevel@tonic-gate 			} else if (volsize <= 0x7f800) {	/* 255M */
1343*0Sstevel@tonic-gate 				spc = 8;
1344*0Sstevel@tonic-gate 			} else if (volsize <= 0xff800) {	/* 511M */
1345*0Sstevel@tonic-gate 				spc = 16;
1346*0Sstevel@tonic-gate 			} else if (volsize <= 0x1ff800) {	/* 1023M */
1347*0Sstevel@tonic-gate 				spc = 32;
1348*0Sstevel@tonic-gate 			} else if (volsize <= 0x3ff800) {	/* 2047M */
1349*0Sstevel@tonic-gate 				spc = 64;
1350*0Sstevel@tonic-gate 			} else if (volsize <= 0x7ff800) {	/* 4095M */
1351*0Sstevel@tonic-gate 				spc = 128;
1352*0Sstevel@tonic-gate 			} else {
1353*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1354*0Sstevel@tonic-gate 				    "Partition too large for a FAT!\n"));
1355*0Sstevel@tonic-gate 				exit(4);
1356*0Sstevel@tonic-gate 			}
1357*0Sstevel@tonic-gate 		}
1358*0Sstevel@tonic-gate 	} else {
1359*0Sstevel@tonic-gate 		spc = SecPerClust;
1360*0Sstevel@tonic-gate 	}
1361*0Sstevel@tonic-gate 
1362*0Sstevel@tonic-gate 	if (GetBPF) {
1363*0Sstevel@tonic-gate 		if (MakeFAT32)
1364*0Sstevel@tonic-gate 			Fatentsize = 32;
1365*0Sstevel@tonic-gate 		else
1366*0Sstevel@tonic-gate 			Fatentsize = 16;
1367*0Sstevel@tonic-gate 	} else {
1368*0Sstevel@tonic-gate 		Fatentsize = BitsPerFAT;
1369*0Sstevel@tonic-gate 		if (Fatentsize == 12 && volsize > DOS_F12MAXC * spc) {
1370*0Sstevel@tonic-gate 			/*
1371*0Sstevel@tonic-gate 			 * 4228473 No way to non-interactively make a
1372*0Sstevel@tonic-gate 			 *	   pcfs filesystem
1373*0Sstevel@tonic-gate 			 *
1374*0Sstevel@tonic-gate 			 *	If we don't have an input TTY, or we aren't
1375*0Sstevel@tonic-gate 			 *	really doing anything, then don't ask
1376*0Sstevel@tonic-gate 			 *	questions.  Assume a yes answer to any
1377*0Sstevel@tonic-gate 			 *	questions we would ask.
1378*0Sstevel@tonic-gate 			 */
1379*0Sstevel@tonic-gate 			if (Notreally || !isatty(fileno(stdin))) {
1380*0Sstevel@tonic-gate 			    (void) printf(
1381*0Sstevel@tonic-gate 				gettext("Volume too large for 12 bit FAT,"
1382*0Sstevel@tonic-gate 				" increasing to 16 bit FAT size.\n"));
1383*0Sstevel@tonic-gate 			    (void) fflush(stdout);
1384*0Sstevel@tonic-gate 			    Fatentsize = 16;
1385*0Sstevel@tonic-gate 			} else {
1386*0Sstevel@tonic-gate 			    (void) printf(
1387*0Sstevel@tonic-gate 				gettext("Volume too large for a 12 bit FAT.\n"
1388*0Sstevel@tonic-gate 					"Increase to 16 bit FAT "
1389*0Sstevel@tonic-gate 					"and continue (y/n)? "));
1390*0Sstevel@tonic-gate 			    (void) fflush(stdout);
1391*0Sstevel@tonic-gate 			    if (yes())
1392*0Sstevel@tonic-gate 				Fatentsize = 16;
1393*0Sstevel@tonic-gate 			    else
1394*0Sstevel@tonic-gate 				exit(5);
1395*0Sstevel@tonic-gate 			}
1396*0Sstevel@tonic-gate 		}
1397*0Sstevel@tonic-gate 	}
1398*0Sstevel@tonic-gate 	wbpb->bpb.sectors_per_cluster = spc;
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate 	if (!GetFsParams && FdiskFATsize < 0) {
1401*0Sstevel@tonic-gate 		(void) printf(
1402*0Sstevel@tonic-gate 		    gettext("Cannot verify chosen/computed FAT "
1403*0Sstevel@tonic-gate 			"entry size (%d bits) with FDISK table.\n"
1404*0Sstevel@tonic-gate 			"FDISK table has an unknown file system "
1405*0Sstevel@tonic-gate 			"type for this device.  Giving up...\n"),
1406*0Sstevel@tonic-gate 			Fatentsize, Fatentsize);
1407*0Sstevel@tonic-gate 		exit(6);
1408*0Sstevel@tonic-gate 	} else if (!GetFsParams && FdiskFATsize && FdiskFATsize != Fatentsize) {
1409*0Sstevel@tonic-gate 		(void) printf(
1410*0Sstevel@tonic-gate 		    gettext("Chosen/computed FAT entry size (%d bits) "
1411*0Sstevel@tonic-gate 			"does not match FDISK table (%d bits).\n"),
1412*0Sstevel@tonic-gate 			Fatentsize, FdiskFATsize);
1413*0Sstevel@tonic-gate 		(void) printf(
1414*0Sstevel@tonic-gate 		    gettext("Use -o fat=%d to build a FAT "
1415*0Sstevel@tonic-gate 			"that matches the FDISK entry.\n"), FdiskFATsize);
1416*0Sstevel@tonic-gate 		exit(6);
1417*0Sstevel@tonic-gate 	}
1418*0Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 	/* Compute a sector/fat figure */
1421*0Sstevel@tonic-gate 	switch (Fatentsize) {
1422*0Sstevel@tonic-gate 	case 32:
1423*0Sstevel@tonic-gate 		/*
1424*0Sstevel@tonic-gate 		 *  We arrive at a formula for sectors/fat by simultaneously
1425*0Sstevel@tonic-gate 		 *  solving two equations:
1426*0Sstevel@tonic-gate 		 *
1427*0Sstevel@tonic-gate 		 *	F = size of FAT (in sectors)
1428*0Sstevel@tonic-gate 		 *	V = volume size (in sectors)
1429*0Sstevel@tonic-gate 		 *	X = file area size (in clusters)
1430*0Sstevel@tonic-gate 		 *
1431*0Sstevel@tonic-gate 		 *	X = (V - 2F)/8 <--- always 8 sectors/cluster for FAT32
1432*0Sstevel@tonic-gate 		 *	F = 4(X+2)/512 <--- 4 bytes/cluster-entry,
1433*0Sstevel@tonic-gate 		 *			    512 bytes/sector
1434*0Sstevel@tonic-gate 		 *	and so,
1435*0Sstevel@tonic-gate 		 *		F = 4(((V - 2F)/8)+2)/512
1436*0Sstevel@tonic-gate 		 *			...
1437*0Sstevel@tonic-gate 		 *		F = V + 16 / 1026
1438*0Sstevel@tonic-gate 		 */
1439*0Sstevel@tonic-gate 		spf = idivceil(volsize + 16, 1026);
1440*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 0;
1441*0Sstevel@tonic-gate 		wbpb->bpb32.big_sectors_per_fat = spf;
1442*0Sstevel@tonic-gate 		break;
1443*0Sstevel@tonic-gate 	case 12:
1444*0Sstevel@tonic-gate 		maxclusters = idivceil(volsize, spc) + 2;
1445*0Sstevel@tonic-gate 		spf = idivceil(maxclusters, FAT12_ENTSPERSECT);
1446*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = (ushort_t)spf;
1447*0Sstevel@tonic-gate 		break;
1448*0Sstevel@tonic-gate 	default:	/* 16 bit FAT */
1449*0Sstevel@tonic-gate 		maxclusters = idivceil(volsize, spc) + 2;
1450*0Sstevel@tonic-gate 		spf = idivceil(maxclusters, FAT16_ENTSPERSECT);
1451*0Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = (ushort_t)spf;
1452*0Sstevel@tonic-gate 		break;
1453*0Sstevel@tonic-gate 	}
1454*0Sstevel@tonic-gate }
1455*0Sstevel@tonic-gate 
1456*0Sstevel@tonic-gate static
1457*0Sstevel@tonic-gate void
1458*0Sstevel@tonic-gate find_fixed_details(int fd, bpb_t *wbpb)
1459*0Sstevel@tonic-gate {
1460*0Sstevel@tonic-gate 	struct dk_geom dginfo;
1461*0Sstevel@tonic-gate 
1462*0Sstevel@tonic-gate 	/*
1463*0Sstevel@tonic-gate 	 *  Look up the last remaining bits of info we need
1464*0Sstevel@tonic-gate 	 *  that is specific to the hard drive using a disk ioctl.
1465*0Sstevel@tonic-gate 	 */
1466*0Sstevel@tonic-gate 	if (GetSPT || GetTPC) {
1467*0Sstevel@tonic-gate 		if ((ioctl(fd, DKIOCG_VIRTGEOM, &dginfo)) == -1) {
1468*0Sstevel@tonic-gate 		    if ((ioctl(fd, DKIOCG_PHYGEOM, &dginfo)) == -1) {
1469*0Sstevel@tonic-gate 			if ((ioctl(fd, DKIOCGGEOM, &dginfo)) == -1) {
1470*0Sstevel@tonic-gate 			    (void) close(fd);
1471*0Sstevel@tonic-gate 			    perror(
1472*0Sstevel@tonic-gate 				gettext("Drive geometry lookup (need "
1473*0Sstevel@tonic-gate 				    "tracks/cylinder and/or sectors/track"));
1474*0Sstevel@tonic-gate 			    exit(2);
1475*0Sstevel@tonic-gate 			}
1476*0Sstevel@tonic-gate 		    }
1477*0Sstevel@tonic-gate 		}
1478*0Sstevel@tonic-gate 	}
1479*0Sstevel@tonic-gate 
1480*0Sstevel@tonic-gate 	wbpb->bpb.heads = (GetTPC ? dginfo.dkg_nhead : TrkPerCyl);
1481*0Sstevel@tonic-gate 	wbpb->bpb.sectors_per_track = (GetSPT ? dginfo.dkg_nsect : SecPerTrk);
1482*0Sstevel@tonic-gate 
1483*0Sstevel@tonic-gate 	if (Verbose) {
1484*0Sstevel@tonic-gate 		if (GetTPC) {
1485*0Sstevel@tonic-gate 		    (void) printf(
1486*0Sstevel@tonic-gate 			gettext("DKIOCG determined number of heads = %d\n"),
1487*0Sstevel@tonic-gate 			dginfo.dkg_nhead);
1488*0Sstevel@tonic-gate 		}
1489*0Sstevel@tonic-gate 		if (GetSPT) {
1490*0Sstevel@tonic-gate 		    (void) printf(
1491*0Sstevel@tonic-gate 			gettext("DKIOCG determined sectors per track = %d\n"),
1492*0Sstevel@tonic-gate 			dginfo.dkg_nsect);
1493*0Sstevel@tonic-gate 		}
1494*0Sstevel@tonic-gate 	}
1495*0Sstevel@tonic-gate 
1496*0Sstevel@tonic-gate 	/*
1497*0Sstevel@tonic-gate 	 * XXX - MAY need an additional flag (or flags) to set media
1498*0Sstevel@tonic-gate 	 * and physical drive number fields.  That in the case of weird
1499*0Sstevel@tonic-gate 	 * floppies that have to go through 'nofdisk' route for formatting.
1500*0Sstevel@tonic-gate 	 */
1501*0Sstevel@tonic-gate 	wbpb->bpb.media = 0xF8;
1502*0Sstevel@tonic-gate 	if (MakeFAT32)
1503*0Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 0;
1504*0Sstevel@tonic-gate 	else
1505*0Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 512;
1506*0Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0x80;
1507*0Sstevel@tonic-gate 	compute_cluster_size(wbpb);
1508*0Sstevel@tonic-gate }
1509*0Sstevel@tonic-gate 
1510*0Sstevel@tonic-gate static
1511*0Sstevel@tonic-gate char *
1512*0Sstevel@tonic-gate stat_actual_disk(char *diskname, struct stat *info, char **suffix)
1513*0Sstevel@tonic-gate {
1514*0Sstevel@tonic-gate 	char *actualdisk;
1515*0Sstevel@tonic-gate 
1516*0Sstevel@tonic-gate 	if (stat(diskname, info)) {
1517*0Sstevel@tonic-gate 		/*
1518*0Sstevel@tonic-gate 		 *  Device named on command line doesn't exist.  That
1519*0Sstevel@tonic-gate 		 *  probably means there is a partition-specifying
1520*0Sstevel@tonic-gate 		 *  suffix attached to the actual disk name.
1521*0Sstevel@tonic-gate 		 */
1522*0Sstevel@tonic-gate 		actualdisk = strtok(strdup(diskname), ":");
1523*0Sstevel@tonic-gate 		if (*suffix = strchr(diskname, ':'))
1524*0Sstevel@tonic-gate 			(*suffix)++;
1525*0Sstevel@tonic-gate 
1526*0Sstevel@tonic-gate 		if (stat(actualdisk, info)) {
1527*0Sstevel@tonic-gate 			perror(actualdisk);
1528*0Sstevel@tonic-gate 			exit(2);
1529*0Sstevel@tonic-gate 		}
1530*0Sstevel@tonic-gate 	} else {
1531*0Sstevel@tonic-gate 		actualdisk = strdup(diskname);
1532*0Sstevel@tonic-gate 	}
1533*0Sstevel@tonic-gate 
1534*0Sstevel@tonic-gate 	return (actualdisk);
1535*0Sstevel@tonic-gate }
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate static
1538*0Sstevel@tonic-gate void
1539*0Sstevel@tonic-gate compute_file_area_size(bpb_t *wbpb)
1540*0Sstevel@tonic-gate {
1541*0Sstevel@tonic-gate 	/*
1542*0Sstevel@tonic-gate 	 * First we'll find total number of sectors in the file area...
1543*0Sstevel@tonic-gate 	 */
1544*0Sstevel@tonic-gate 	if (wbpb->bpb.sectors_in_volume > 0)
1545*0Sstevel@tonic-gate 		TotalClusters = wbpb->bpb.sectors_in_volume;
1546*0Sstevel@tonic-gate 	else
1547*0Sstevel@tonic-gate 		TotalClusters = wbpb->bpb.sectors_in_logical_volume;
1548*0Sstevel@tonic-gate 
1549*0Sstevel@tonic-gate 	TotalClusters -= wbpb->bpb.resv_sectors;
1550*0Sstevel@tonic-gate 	TotalClusters -= wbpb->bpb.num_root_entries * sizeof (struct pcdir) /
1551*0Sstevel@tonic-gate 	    BPSEC;
1552*0Sstevel@tonic-gate 
1553*0Sstevel@tonic-gate 	if (wbpb->bpb.sectors_per_fat) {
1554*0Sstevel@tonic-gate 		/*
1555*0Sstevel@tonic-gate 		 * Good old FAT12 or FAT16
1556*0Sstevel@tonic-gate 		 */
1557*0Sstevel@tonic-gate 		TotalClusters -= 2 * wbpb->bpb.sectors_per_fat;
1558*0Sstevel@tonic-gate 	} else {
1559*0Sstevel@tonic-gate 		/*
1560*0Sstevel@tonic-gate 		 *  FAT32
1561*0Sstevel@tonic-gate 		 */
1562*0Sstevel@tonic-gate 		TotalClusters -= 2 * wbpb->bpb32.big_sectors_per_fat;
1563*0Sstevel@tonic-gate 	}
1564*0Sstevel@tonic-gate 
1565*0Sstevel@tonic-gate 	/*
1566*0Sstevel@tonic-gate 	 * Now change sectors to clusters
1567*0Sstevel@tonic-gate 	 */
1568*0Sstevel@tonic-gate 	TotalClusters = TotalClusters / wbpb->bpb.sectors_per_cluster;
1569*0Sstevel@tonic-gate 
1570*0Sstevel@tonic-gate 	if (Verbose)
1571*0Sstevel@tonic-gate 		(void) printf(gettext("Disk has a file area of %d "
1572*0Sstevel@tonic-gate 		    "allocation units,\neach with %d sectors = %d "
1573*0Sstevel@tonic-gate 		    "bytes.\n"), TotalClusters, wbpb->bpb.sectors_per_cluster,
1574*0Sstevel@tonic-gate 		    TotalClusters * wbpb->bpb.sectors_per_cluster * BPSEC);
1575*0Sstevel@tonic-gate }
1576*0Sstevel@tonic-gate 
1577*0Sstevel@tonic-gate #ifndef i386
1578*0Sstevel@tonic-gate /*
1579*0Sstevel@tonic-gate  *  swap_pack_{bpb,bpb32,sebpb}cpy
1580*0Sstevel@tonic-gate  *
1581*0Sstevel@tonic-gate  *	If not on an x86 we assume the structures making up the bpb
1582*0Sstevel@tonic-gate  *	were not packed and that longs and shorts need to be byte swapped
1583*0Sstevel@tonic-gate  *	(we've kept everything in host order up until now).  A new architecture
1584*0Sstevel@tonic-gate  *	might not need to swap or might not need to pack, in which case
1585*0Sstevel@tonic-gate  *	new routines will have to be written.  Of course if an architecture
1586*0Sstevel@tonic-gate  *	supports both packing and little-endian host order, it can follow the
1587*0Sstevel@tonic-gate  *	same path as the x86 code.
1588*0Sstevel@tonic-gate  */
1589*0Sstevel@tonic-gate static
1590*0Sstevel@tonic-gate void
1591*0Sstevel@tonic-gate swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb)
1592*0Sstevel@tonic-gate {
1593*0Sstevel@tonic-gate 	uchar_t *fillp;
1594*0Sstevel@tonic-gate 
1595*0Sstevel@tonic-gate 	fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
1596*0Sstevel@tonic-gate 
1597*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.bytes_sector);
1598*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.sectors_per_cluster;
1599*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.resv_sectors);
1600*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.num_fats;
1601*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.num_root_entries);
1602*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_in_volume);
1603*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.media;
1604*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_fat);
1605*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_track);
1606*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.heads);
1607*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.hidden_sectors);
1608*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume);
1609*0Sstevel@tonic-gate 
1610*0Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.phys_drive_num;
1611*0Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.reserved;
1612*0Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.ext_signature;
1613*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->ebpb.volume_id);
1614*0Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11);
1615*0Sstevel@tonic-gate 	fillp += 11;
1616*0Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8);
1617*0Sstevel@tonic-gate }
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate static
1620*0Sstevel@tonic-gate void
1621*0Sstevel@tonic-gate swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb)
1622*0Sstevel@tonic-gate {
1623*0Sstevel@tonic-gate 	uchar_t *fillp;
1624*0Sstevel@tonic-gate 	int r;
1625*0Sstevel@tonic-gate 
1626*0Sstevel@tonic-gate 	fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
1627*0Sstevel@tonic-gate 
1628*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.bytes_sector);
1629*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.sectors_per_cluster;
1630*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.resv_sectors);
1631*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.num_fats;
1632*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.num_root_entries);
1633*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_in_volume);
1634*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.media;
1635*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_fat);
1636*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_track);
1637*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.heads);
1638*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.hidden_sectors);
1639*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume);
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb32.big_sectors_per_fat);
1642*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.ext_flags);
1643*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb32.fs_vers_lo;
1644*0Sstevel@tonic-gate 	*fillp++ = wbpb->bpb32.fs_vers_hi;
1645*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb32.root_dir_clust);
1646*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.fsinfosec);
1647*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.backupboot);
1648*0Sstevel@tonic-gate 	for (r = 0; r < 6; r++)
1649*0Sstevel@tonic-gate 		store_16_bits(&fillp, wbpb->bpb32.reserved[r]);
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.phys_drive_num;
1652*0Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.reserved;
1653*0Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.ext_signature;
1654*0Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->ebpb.volume_id);
1655*0Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11);
1656*0Sstevel@tonic-gate 	fillp += 11;
1657*0Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8);
1658*0Sstevel@tonic-gate }
1659*0Sstevel@tonic-gate 
1660*0Sstevel@tonic-gate static
1661*0Sstevel@tonic-gate void
1662*0Sstevel@tonic-gate swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb)
1663*0Sstevel@tonic-gate {
1664*0Sstevel@tonic-gate 	uchar_t *fillp;
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 	fillp = bsp->bs_sun_bpb;
1667*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->sunbpb.bs_offset_high);
1668*0Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->sunbpb.bs_offset_low);
1669*0Sstevel@tonic-gate }
1670*0Sstevel@tonic-gate 
1671*0Sstevel@tonic-gate static
1672*0Sstevel@tonic-gate void
1673*0Sstevel@tonic-gate swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp)
1674*0Sstevel@tonic-gate {
1675*0Sstevel@tonic-gate 	uchar_t *grabp;
1676*0Sstevel@tonic-gate 
1677*0Sstevel@tonic-gate 	grabp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
1678*0Sstevel@tonic-gate 
1679*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.bytes_sector))[1] = *grabp++;
1680*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.bytes_sector))[0] = *grabp++;
1681*0Sstevel@tonic-gate 	wbpb->bpb.sectors_per_cluster = *grabp++;
1682*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.resv_sectors))[1] = *grabp++;
1683*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.resv_sectors))[0] = *grabp++;
1684*0Sstevel@tonic-gate 	wbpb->bpb.num_fats = *grabp++;
1685*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.num_root_entries))[1] = *grabp++;
1686*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.num_root_entries))[0] = *grabp++;
1687*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_volume))[1] = *grabp++;
1688*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_volume))[0] = *grabp++;
1689*0Sstevel@tonic-gate 	wbpb->bpb.media = *grabp++;
1690*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_fat))[1] = *grabp++;
1691*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_fat))[0] = *grabp++;
1692*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_track))[1] = *grabp++;
1693*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_track))[0] = *grabp++;
1694*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.heads))[1] = *grabp++;
1695*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.heads))[0] = *grabp++;
1696*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[3] = *grabp++;
1697*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[2] = *grabp++;
1698*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[1] = *grabp++;
1699*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[0] = *grabp++;
1700*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[3] = *grabp++;
1701*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[2] = *grabp++;
1702*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[1] = *grabp++;
1703*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[0] = *grabp++;
1704*0Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = *grabp++;
1705*0Sstevel@tonic-gate 	wbpb->ebpb.reserved = *grabp++;
1706*0Sstevel@tonic-gate 	wbpb->ebpb.ext_signature = *grabp++;
1707*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[3] = *grabp++;
1708*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[2] = *grabp++;
1709*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[1] = *grabp++;
1710*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[0] = *grabp++;
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 	(void) strncpy((char *)wbpb->ebpb.volume_label, (char *)grabp, 11);
1713*0Sstevel@tonic-gate 	grabp += 11;
1714*0Sstevel@tonic-gate 	(void) strncpy((char *)wbpb->ebpb.type, (char *)grabp, 8);
1715*0Sstevel@tonic-gate }
1716*0Sstevel@tonic-gate 
1717*0Sstevel@tonic-gate static
1718*0Sstevel@tonic-gate void
1719*0Sstevel@tonic-gate swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp)
1720*0Sstevel@tonic-gate {
1721*0Sstevel@tonic-gate 	uchar_t *grabp;
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	grabp = bsp->bs_sun_bpb;
1724*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[1] = *grabp++;
1725*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[0] = *grabp++;
1726*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[1] = *grabp++;
1727*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[0] = *grabp++;
1728*0Sstevel@tonic-gate }
1729*0Sstevel@tonic-gate 
1730*0Sstevel@tonic-gate static
1731*0Sstevel@tonic-gate void
1732*0Sstevel@tonic-gate swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp)
1733*0Sstevel@tonic-gate {
1734*0Sstevel@tonic-gate 	uchar_t *grabp;
1735*0Sstevel@tonic-gate 
1736*0Sstevel@tonic-gate 	grabp = (uchar_t *)&(bsp->bs_filler[BPB_32_START_INDEX]);
1737*0Sstevel@tonic-gate 
1738*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[3] = *grabp++;
1739*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[2] = *grabp++;
1740*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[1] = *grabp++;
1741*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[0] = *grabp++;
1742*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.ext_flags))[1] = *grabp++;
1743*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.ext_flags))[0] = *grabp++;
1744*0Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_lo = *grabp++;
1745*0Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_hi = *grabp++;
1746*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[3] = *grabp++;
1747*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[2] = *grabp++;
1748*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[1] = *grabp++;
1749*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[0] = *grabp++;
1750*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.fsinfosec))[1] = *grabp++;
1751*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.fsinfosec))[0] = *grabp++;
1752*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.backupboot))[1] = *grabp++;
1753*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.backupboot))[0] = *grabp++;
1754*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[0]))[1] = *grabp++;
1755*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[0]))[0] = *grabp++;
1756*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[1]))[1] = *grabp++;
1757*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[1]))[0] = *grabp++;
1758*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[2]))[1] = *grabp++;
1759*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[2]))[0] = *grabp++;
1760*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[3]))[1] = *grabp++;
1761*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[3]))[0] = *grabp++;
1762*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[4]))[1] = *grabp++;
1763*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[4]))[0] = *grabp++;
1764*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[5]))[1] = *grabp++;
1765*0Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[5]))[0] = *grabp++;
1766*0Sstevel@tonic-gate }
1767*0Sstevel@tonic-gate #endif	/* ! i386 */
1768*0Sstevel@tonic-gate 
1769*0Sstevel@tonic-gate static
1770*0Sstevel@tonic-gate void
1771*0Sstevel@tonic-gate dashm_bail(int fd)
1772*0Sstevel@tonic-gate {
1773*0Sstevel@tonic-gate 	(void) fprintf(stderr,
1774*0Sstevel@tonic-gate 		gettext("This media does not appear to be "
1775*0Sstevel@tonic-gate 			"formatted with a FAT file system.\n"));
1776*0Sstevel@tonic-gate 	(void) close(fd);
1777*0Sstevel@tonic-gate 	exit(6);
1778*0Sstevel@tonic-gate }
1779*0Sstevel@tonic-gate 
1780*0Sstevel@tonic-gate /*
1781*0Sstevel@tonic-gate  *  read_existing_bpb
1782*0Sstevel@tonic-gate  *
1783*0Sstevel@tonic-gate  *	Grab the first sector, which we think is a bios parameter block.
1784*0Sstevel@tonic-gate  *	If it looks bad, bail.  Otherwise fill in the parameter struct
1785*0Sstevel@tonic-gate  *	fields that matter.
1786*0Sstevel@tonic-gate  */
1787*0Sstevel@tonic-gate static
1788*0Sstevel@tonic-gate void
1789*0Sstevel@tonic-gate read_existing_bpb(int fd, bpb_t *wbpb)
1790*0Sstevel@tonic-gate {
1791*0Sstevel@tonic-gate 	boot_sector_t ubpb;
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 	if (read(fd, ubpb.buf, BPSEC) < BPSEC) {
1794*0Sstevel@tonic-gate 		perror(gettext("Read BIOS parameter block "
1795*0Sstevel@tonic-gate 			"from previously formatted media"));
1796*0Sstevel@tonic-gate 		(void) close(fd);
1797*0Sstevel@tonic-gate 		exit(6);
1798*0Sstevel@tonic-gate 	}
1799*0Sstevel@tonic-gate 
1800*0Sstevel@tonic-gate 	if (ltohs(ubpb.mb.signature) != BOOTSECSIG) {
1801*0Sstevel@tonic-gate 		dashm_bail(fd);
1802*0Sstevel@tonic-gate 	}
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate #ifdef i386
1805*0Sstevel@tonic-gate 	(void) memcpy(&(wbpb->bpb), &(ubpb.bs.bs_front.bs_bpb),
1806*0Sstevel@tonic-gate 		sizeof (wbpb->bpb));
1807*0Sstevel@tonic-gate 	(void) memcpy(&(wbpb->ebpb), &(ubpb.bs.bs_ebpb), sizeof (wbpb->ebpb));
1808*0Sstevel@tonic-gate #else
1809*0Sstevel@tonic-gate 	swap_pack_grabbpb(wbpb, &(ubpb.bs));
1810*0Sstevel@tonic-gate #endif
1811*0Sstevel@tonic-gate 	if (SunBPBfields) {
1812*0Sstevel@tonic-gate #ifdef i386
1813*0Sstevel@tonic-gate 		(void) memcpy(&(wbpb->sunbpb), &(ubpb.bs.bs_sebpb),
1814*0Sstevel@tonic-gate 			sizeof (wbpb->sunbpb));
1815*0Sstevel@tonic-gate #else
1816*0Sstevel@tonic-gate 		swap_pack_grabsebpb(wbpb, &(ubpb.bs));
1817*0Sstevel@tonic-gate #endif
1818*0Sstevel@tonic-gate 	}
1819*0Sstevel@tonic-gate 	if (wbpb->bpb.bytes_sector != BPSEC) {
1820*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1821*0Sstevel@tonic-gate 		    gettext("Bogus bytes per sector value.\n"));
1822*0Sstevel@tonic-gate 		if (!powerofx_le_y(2, BPSEC * 8, wbpb->bpb.bytes_sector)) {
1823*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1824*0Sstevel@tonic-gate 			    gettext("The device name may be missing a "
1825*0Sstevel@tonic-gate 				    "logical drive specifier.\n"));
1826*0Sstevel@tonic-gate 			(void) close(fd);
1827*0Sstevel@tonic-gate 			exit(6);
1828*0Sstevel@tonic-gate 		} else {
1829*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1830*0Sstevel@tonic-gate 			    gettext("Do not know how to build FATs with a\n"
1831*0Sstevel@tonic-gate 				    "non-standard sector size. Standard "
1832*0Sstevel@tonic-gate 				    "size is %d bytes,\nyour sector size "
1833*0Sstevel@tonic-gate 				    "is %d bytes.\n"), BPSEC,
1834*0Sstevel@tonic-gate 				    wbpb->bpb.bytes_sector);
1835*0Sstevel@tonic-gate 			(void) close(fd);
1836*0Sstevel@tonic-gate 			exit(6);
1837*0Sstevel@tonic-gate 		}
1838*0Sstevel@tonic-gate 	}
1839*0Sstevel@tonic-gate 	if (!(powerofx_le_y(2, 128, wbpb->bpb.sectors_per_cluster))) {
1840*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1841*0Sstevel@tonic-gate 		    gettext("Bogus sectors per cluster value.\n"));
1842*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1843*0Sstevel@tonic-gate 		    gettext("The device name may be missing a "
1844*0Sstevel@tonic-gate 			"logical drive specifier.\n"));
1845*0Sstevel@tonic-gate 		(void) close(fd);
1846*0Sstevel@tonic-gate 		exit(6);
1847*0Sstevel@tonic-gate 	}
1848*0Sstevel@tonic-gate 
1849*0Sstevel@tonic-gate 	if (wbpb->bpb.sectors_per_fat == 0) {
1850*0Sstevel@tonic-gate #ifdef i386
1851*0Sstevel@tonic-gate 		(void) memcpy(&(wbpb->bpb32), &(ubpb.bs32.bs_bpb32),
1852*0Sstevel@tonic-gate 			sizeof (wbpb->bpb32));
1853*0Sstevel@tonic-gate #else
1854*0Sstevel@tonic-gate 		swap_pack_grab32bpb(wbpb, &(ubpb.bs));
1855*0Sstevel@tonic-gate #endif
1856*0Sstevel@tonic-gate 		compute_file_area_size(wbpb);
1857*0Sstevel@tonic-gate 		if ((wbpb->bpb32.big_sectors_per_fat * BPSEC / 4) >=
1858*0Sstevel@tonic-gate 		    TotalClusters) {
1859*0Sstevel@tonic-gate 			MakeFAT32 = 1;
1860*0Sstevel@tonic-gate 		} else {
1861*0Sstevel@tonic-gate 			dashm_bail(fd);
1862*0Sstevel@tonic-gate 		}
1863*0Sstevel@tonic-gate 	} else {
1864*0Sstevel@tonic-gate 		compute_file_area_size(wbpb);
1865*0Sstevel@tonic-gate 	}
1866*0Sstevel@tonic-gate }
1867*0Sstevel@tonic-gate 
1868*0Sstevel@tonic-gate /*
1869*0Sstevel@tonic-gate  *  compare_existing_with_computed
1870*0Sstevel@tonic-gate  *
1871*0Sstevel@tonic-gate  *	We use this function when we the user specifies the -m option.
1872*0Sstevel@tonic-gate  *	We compute and look up things like we would if they had asked
1873*0Sstevel@tonic-gate  *	us to make the fs, and compare that to what's already layed down
1874*0Sstevel@tonic-gate  *	in the existing fs.  If there's a difference we can tell them what
1875*0Sstevel@tonic-gate  *	options to specify in order to reproduce their existing layout.
1876*0Sstevel@tonic-gate  *	Note that they still may not get an exact duplicate, because we
1877*0Sstevel@tonic-gate  *	don't, for example, preserve their existing boot code.  We think
1878*0Sstevel@tonic-gate  *	we've got all the fields that matter covered, though.
1879*0Sstevel@tonic-gate  *
1880*0Sstevel@tonic-gate  *	XXX - We're basically ignoring sbpb at this point.  I'm unsure
1881*0Sstevel@tonic-gate  *	if we'll ever care about those fields, in terms of the -m option.
1882*0Sstevel@tonic-gate  */
1883*0Sstevel@tonic-gate static
1884*0Sstevel@tonic-gate void
1885*0Sstevel@tonic-gate compare_existing_with_computed(int fd, char *suffix,
1886*0Sstevel@tonic-gate     bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect,
1887*0Sstevel@tonic-gate     int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd, int *dashos)
1888*0Sstevel@tonic-gate {
1889*0Sstevel@tonic-gate 	struct dk_geom	dginfo;
1890*0Sstevel@tonic-gate 	struct fd_char	fdchar;
1891*0Sstevel@tonic-gate 	bpb_t		compare;
1892*0Sstevel@tonic-gate 	int		fd_ioctl_worked = 0;
1893*0Sstevel@tonic-gate 	int		fatents;
1894*0Sstevel@tonic-gate 
1895*0Sstevel@tonic-gate 	/*
1896*0Sstevel@tonic-gate 	 *  For all non-floppy cases we expect to find a 16-bit FAT
1897*0Sstevel@tonic-gate 	 */
1898*0Sstevel@tonic-gate 	int expectfatsize = 16;
1899*0Sstevel@tonic-gate 
1900*0Sstevel@tonic-gate 	compare = *wbpb;
1901*0Sstevel@tonic-gate 
1902*0Sstevel@tonic-gate 	if (!suffix) {
1903*0Sstevel@tonic-gate 		if (ioctl(fd, FDIOGCHAR, &fdchar) != -1) {
1904*0Sstevel@tonic-gate 			expectfatsize = 12;
1905*0Sstevel@tonic-gate 			fd_ioctl_worked++;
1906*0Sstevel@tonic-gate 		}
1907*0Sstevel@tonic-gate 	}
1908*0Sstevel@tonic-gate 
1909*0Sstevel@tonic-gate 	if (fd_ioctl_worked) {
1910*0Sstevel@tonic-gate #ifdef sparc
1911*0Sstevel@tonic-gate 		fdchar.fdc_medium = 3;
1912*0Sstevel@tonic-gate #endif
1913*0Sstevel@tonic-gate 		GetSize = GetSPT = GetSPC = GetTPC = GetBPF = 1;
1914*0Sstevel@tonic-gate 		lookup_floppy(&fdchar, &compare);
1915*0Sstevel@tonic-gate 		if (compare.bpb.heads != wbpb->bpb.heads) {
1916*0Sstevel@tonic-gate 			(*prtntrk)++;
1917*0Sstevel@tonic-gate 			(*dashos)++;
1918*0Sstevel@tonic-gate 		}
1919*0Sstevel@tonic-gate 		if (compare.bpb.sectors_per_track !=
1920*0Sstevel@tonic-gate 		    wbpb->bpb.sectors_per_track) {
1921*0Sstevel@tonic-gate 			(*prtnsect)++;
1922*0Sstevel@tonic-gate 			(*dashos)++;
1923*0Sstevel@tonic-gate 		}
1924*0Sstevel@tonic-gate 	} else {
1925*0Sstevel@tonic-gate 		int dk_ioctl_worked = 1;
1926*0Sstevel@tonic-gate 
1927*0Sstevel@tonic-gate 		if (!suffix) {
1928*0Sstevel@tonic-gate 			(*prtfdisk)++;
1929*0Sstevel@tonic-gate 			(*prtsize)++;
1930*0Sstevel@tonic-gate 			*dashos += 2;
1931*0Sstevel@tonic-gate 		}
1932*0Sstevel@tonic-gate 		if ((ioctl(fd, DKIOCG_VIRTGEOM, &dginfo)) == -1) {
1933*0Sstevel@tonic-gate 		    if ((ioctl(fd, DKIOCG_PHYGEOM, &dginfo)) == -1) {
1934*0Sstevel@tonic-gate 			if ((ioctl(fd, DKIOCGGEOM, &dginfo)) == -1) {
1935*0Sstevel@tonic-gate 				*prtnsect = *prtntrk = 1;
1936*0Sstevel@tonic-gate 				*dashos += 2;
1937*0Sstevel@tonic-gate 				dk_ioctl_worked = 0;
1938*0Sstevel@tonic-gate 			}
1939*0Sstevel@tonic-gate 		    }
1940*0Sstevel@tonic-gate 		}
1941*0Sstevel@tonic-gate 		if (dk_ioctl_worked) {
1942*0Sstevel@tonic-gate 			if (dginfo.dkg_nhead != wbpb->bpb.heads) {
1943*0Sstevel@tonic-gate 				(*prtntrk)++;
1944*0Sstevel@tonic-gate 				(*dashos)++;
1945*0Sstevel@tonic-gate 			}
1946*0Sstevel@tonic-gate 			if (dginfo.dkg_nsect !=
1947*0Sstevel@tonic-gate 			    wbpb->bpb.sectors_per_track) {
1948*0Sstevel@tonic-gate 				(*prtnsect)++;
1949*0Sstevel@tonic-gate 				(*dashos)++;
1950*0Sstevel@tonic-gate 			}
1951*0Sstevel@tonic-gate 		}
1952*0Sstevel@tonic-gate 		GetBPF = GetSPC = 1;
1953*0Sstevel@tonic-gate 		compute_cluster_size(&compare);
1954*0Sstevel@tonic-gate 	}
1955*0Sstevel@tonic-gate 
1956*0Sstevel@tonic-gate 	if (!*prtfdisk && TotSize != wbpb->bpb.sectors_in_volume &&
1957*0Sstevel@tonic-gate 		TotSize != wbpb->bpb.sectors_in_logical_volume) {
1958*0Sstevel@tonic-gate 		(*dashos)++;
1959*0Sstevel@tonic-gate 		(*prtsize)++;
1960*0Sstevel@tonic-gate 	}
1961*0Sstevel@tonic-gate 
1962*0Sstevel@tonic-gate 	if (compare.bpb.sectors_per_cluster != wbpb->bpb.sectors_per_cluster) {
1963*0Sstevel@tonic-gate 		(*dashos)++;
1964*0Sstevel@tonic-gate 		(*prtspc)++;
1965*0Sstevel@tonic-gate 	}
1966*0Sstevel@tonic-gate 
1967*0Sstevel@tonic-gate 	if (compare.bpb.hidden_sectors != wbpb->bpb.hidden_sectors) {
1968*0Sstevel@tonic-gate 		(*dashos)++;
1969*0Sstevel@tonic-gate 		(*prthidden)++;
1970*0Sstevel@tonic-gate 	}
1971*0Sstevel@tonic-gate 
1972*0Sstevel@tonic-gate 	if (compare.bpb.resv_sectors != wbpb->bpb.resv_sectors) {
1973*0Sstevel@tonic-gate 		(*dashos)++;
1974*0Sstevel@tonic-gate 		(*prtrsrvd)++;
1975*0Sstevel@tonic-gate 	}
1976*0Sstevel@tonic-gate 
1977*0Sstevel@tonic-gate 	/*
1978*0Sstevel@tonic-gate 	 * Compute approximate Fatentsize.  It's approximate because the
1979*0Sstevel@tonic-gate 	 * size of the FAT may not be exactly a multiple of the number of
1980*0Sstevel@tonic-gate 	 * clusters.  It should be close, though.
1981*0Sstevel@tonic-gate 	 */
1982*0Sstevel@tonic-gate 	if (MakeFAT32) {
1983*0Sstevel@tonic-gate 		Fatentsize = 32;
1984*0Sstevel@tonic-gate 		(*dashos)++;
1985*0Sstevel@tonic-gate 		(*prtbpf)++;
1986*0Sstevel@tonic-gate 	} else {
1987*0Sstevel@tonic-gate 		fatents = wbpb->bpb.sectors_per_fat * BPSEC * 2 / 3;
1988*0Sstevel@tonic-gate 		if (fatents >= TotalClusters && wbpb->ebpb.type[4] == '2')
1989*0Sstevel@tonic-gate 			Fatentsize = 12;
1990*0Sstevel@tonic-gate 		else
1991*0Sstevel@tonic-gate 			Fatentsize = 16;
1992*0Sstevel@tonic-gate 		if (Fatentsize != expectfatsize) {
1993*0Sstevel@tonic-gate 			(*dashos)++;
1994*0Sstevel@tonic-gate 			(*prtbpf)++;
1995*0Sstevel@tonic-gate 		}
1996*0Sstevel@tonic-gate 	}
1997*0Sstevel@tonic-gate }
1998*0Sstevel@tonic-gate 
1999*0Sstevel@tonic-gate static
2000*0Sstevel@tonic-gate void
2001*0Sstevel@tonic-gate print_reproducing_command(int fd, char *actualdisk, char *suffix, bpb_t *wbpb)
2002*0Sstevel@tonic-gate {
2003*0Sstevel@tonic-gate 	int needcomma = 0;
2004*0Sstevel@tonic-gate 	int prthidden = 0;
2005*0Sstevel@tonic-gate 	int prtrsrvd = 0;
2006*0Sstevel@tonic-gate 	int prtfdisk = 0;
2007*0Sstevel@tonic-gate 	int prtnsect = 0;
2008*0Sstevel@tonic-gate 	int prtntrk = 0;
2009*0Sstevel@tonic-gate 	int prtsize = 0;
2010*0Sstevel@tonic-gate 	int prtbpf = 0;
2011*0Sstevel@tonic-gate 	int prtspc = 0;
2012*0Sstevel@tonic-gate 	int dashos = 0;
2013*0Sstevel@tonic-gate 	int ll, i;
2014*0Sstevel@tonic-gate 
2015*0Sstevel@tonic-gate 	compare_existing_with_computed(fd, suffix, wbpb,
2016*0Sstevel@tonic-gate 	    &prtsize, &prtspc, &prtbpf, &prtnsect, &prtntrk,
2017*0Sstevel@tonic-gate 	    &prtfdisk, &prthidden, &prtrsrvd, &dashos);
2018*0Sstevel@tonic-gate 
2019*0Sstevel@tonic-gate 	/*
2020*0Sstevel@tonic-gate 	 *  Print out the command line they can use to reproduce the
2021*0Sstevel@tonic-gate 	 *  file system.
2022*0Sstevel@tonic-gate 	 */
2023*0Sstevel@tonic-gate 	(void) printf("mkfs -F pcfs");
2024*0Sstevel@tonic-gate 
2025*0Sstevel@tonic-gate 	ll = min(11, (int)strlen((char *)wbpb->ebpb.volume_label));
2026*0Sstevel@tonic-gate 	/*
2027*0Sstevel@tonic-gate 	 * First, eliminate trailing spaces. Now compare the name against
2028*0Sstevel@tonic-gate 	 * our default label.  If there's a match we don't need to print
2029*0Sstevel@tonic-gate 	 * any label info.
2030*0Sstevel@tonic-gate 	 */
2031*0Sstevel@tonic-gate 	i = ll;
2032*0Sstevel@tonic-gate 	while (wbpb->ebpb.volume_label[--i] == ' ');
2033*0Sstevel@tonic-gate 	ll = i;
2034*0Sstevel@tonic-gate 
2035*0Sstevel@tonic-gate 	if (ll == strlen(DEFAULT_LABEL) - 1) {
2036*0Sstevel@tonic-gate 		char cmpbuf[11];
2037*0Sstevel@tonic-gate 
2038*0Sstevel@tonic-gate 		(void) strcpy(cmpbuf, DEFAULT_LABEL);
2039*0Sstevel@tonic-gate 		for (i = ll; i >= 0; i--) {
2040*0Sstevel@tonic-gate 			if (cmpbuf[i] !=
2041*0Sstevel@tonic-gate 			    toupper((int)(wbpb->ebpb.volume_label[i]))) {
2042*0Sstevel@tonic-gate 				break;
2043*0Sstevel@tonic-gate 			}
2044*0Sstevel@tonic-gate 		}
2045*0Sstevel@tonic-gate 		if (i < 0)
2046*0Sstevel@tonic-gate 			ll = i;
2047*0Sstevel@tonic-gate 	}
2048*0Sstevel@tonic-gate 
2049*0Sstevel@tonic-gate 	if (ll >= 0) {
2050*0Sstevel@tonic-gate 		(void) printf(" -o ");
2051*0Sstevel@tonic-gate 		(void) printf("b=\"");
2052*0Sstevel@tonic-gate 		for (i = 0; i <= ll; i++) {
2053*0Sstevel@tonic-gate 			(void) printf("%c", wbpb->ebpb.volume_label[i]);
2054*0Sstevel@tonic-gate 		}
2055*0Sstevel@tonic-gate 		(void) printf("\"");
2056*0Sstevel@tonic-gate 		needcomma++;
2057*0Sstevel@tonic-gate 	} else if (dashos) {
2058*0Sstevel@tonic-gate 		(void) printf(" -o ");
2059*0Sstevel@tonic-gate 	}
2060*0Sstevel@tonic-gate 
2061*0Sstevel@tonic-gate #define	NEXT_DASH_O	dashos--; needcomma++; continue
2062*0Sstevel@tonic-gate 
2063*0Sstevel@tonic-gate 	while (dashos) {
2064*0Sstevel@tonic-gate 		if (needcomma) {
2065*0Sstevel@tonic-gate 			(void) printf(",");
2066*0Sstevel@tonic-gate 			needcomma = 0;
2067*0Sstevel@tonic-gate 		}
2068*0Sstevel@tonic-gate 		if (prtfdisk) {
2069*0Sstevel@tonic-gate 			(void) printf("nofdisk");
2070*0Sstevel@tonic-gate 			prtfdisk--;
2071*0Sstevel@tonic-gate 			NEXT_DASH_O;
2072*0Sstevel@tonic-gate 		}
2073*0Sstevel@tonic-gate 		if (prtsize) {
2074*0Sstevel@tonic-gate 			(void) printf("size=%u", wbpb->bpb.sectors_in_volume ?
2075*0Sstevel@tonic-gate 			    wbpb->bpb.sectors_in_volume :
2076*0Sstevel@tonic-gate 			    wbpb->bpb.sectors_in_logical_volume);
2077*0Sstevel@tonic-gate 			prtsize--;
2078*0Sstevel@tonic-gate 			NEXT_DASH_O;
2079*0Sstevel@tonic-gate 		}
2080*0Sstevel@tonic-gate 		if (prtnsect) {
2081*0Sstevel@tonic-gate 			(void) printf("nsect=%d", wbpb->bpb.sectors_per_track);
2082*0Sstevel@tonic-gate 			prtnsect--;
2083*0Sstevel@tonic-gate 			NEXT_DASH_O;
2084*0Sstevel@tonic-gate 		}
2085*0Sstevel@tonic-gate 		if (prtspc) {
2086*0Sstevel@tonic-gate 			(void) printf("spc=%d", wbpb->bpb.sectors_per_cluster);
2087*0Sstevel@tonic-gate 			prtspc--;
2088*0Sstevel@tonic-gate 			NEXT_DASH_O;
2089*0Sstevel@tonic-gate 		}
2090*0Sstevel@tonic-gate 		if (prtntrk) {
2091*0Sstevel@tonic-gate 			(void) printf("ntrack=%d", wbpb->bpb.heads);
2092*0Sstevel@tonic-gate 			prtntrk--;
2093*0Sstevel@tonic-gate 			NEXT_DASH_O;
2094*0Sstevel@tonic-gate 		}
2095*0Sstevel@tonic-gate 		if (prtbpf) {
2096*0Sstevel@tonic-gate 			(void) printf("fat=%d", Fatentsize);
2097*0Sstevel@tonic-gate 			prtbpf--;
2098*0Sstevel@tonic-gate 			NEXT_DASH_O;
2099*0Sstevel@tonic-gate 		}
2100*0Sstevel@tonic-gate 		if (prthidden) {
2101*0Sstevel@tonic-gate 			(void) printf("hidden=%u", wbpb->bpb.hidden_sectors);
2102*0Sstevel@tonic-gate 			prthidden--;
2103*0Sstevel@tonic-gate 			NEXT_DASH_O;
2104*0Sstevel@tonic-gate 		}
2105*0Sstevel@tonic-gate 		if (prtrsrvd) {
2106*0Sstevel@tonic-gate 			(void) printf("reserve=%d", wbpb->bpb.resv_sectors);
2107*0Sstevel@tonic-gate 			prtrsrvd--;
2108*0Sstevel@tonic-gate 			NEXT_DASH_O;
2109*0Sstevel@tonic-gate 		}
2110*0Sstevel@tonic-gate 	}
2111*0Sstevel@tonic-gate 
2112*0Sstevel@tonic-gate 	(void) printf(" %s%c%c\n", actualdisk,
2113*0Sstevel@tonic-gate 	    suffix ? ':' : '\0', suffix ? *suffix : '\0');
2114*0Sstevel@tonic-gate }
2115*0Sstevel@tonic-gate 
2116*0Sstevel@tonic-gate /*
2117*0Sstevel@tonic-gate  *  open_and_examine
2118*0Sstevel@tonic-gate  *
2119*0Sstevel@tonic-gate  *	Open the requested 'dev_name'.  Seek to point where
2120*0Sstevel@tonic-gate  *	we'd expect to find boot sectors, etc., based on any ':partition'
2121*0Sstevel@tonic-gate  *	attachments to the dev_name.
2122*0Sstevel@tonic-gate  *
2123*0Sstevel@tonic-gate  *	Examine the fields of any existing boot sector and display best
2124*0Sstevel@tonic-gate  *	approximation of how this fs could be reproduced with this command.
2125*0Sstevel@tonic-gate  */
2126*0Sstevel@tonic-gate static
2127*0Sstevel@tonic-gate int
2128*0Sstevel@tonic-gate open_and_examine(char *dn, bpb_t *wbpb)
2129*0Sstevel@tonic-gate {
2130*0Sstevel@tonic-gate 	struct stat di;
2131*0Sstevel@tonic-gate 	off64_t ignored;
2132*0Sstevel@tonic-gate 	char *actualdisk = NULL;
2133*0Sstevel@tonic-gate 	char *suffix = NULL;
2134*0Sstevel@tonic-gate 	int fd;
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate 	if (Verbose)
2137*0Sstevel@tonic-gate 		(void) printf(gettext("Opening destination device/file.\n"));
2138*0Sstevel@tonic-gate 
2139*0Sstevel@tonic-gate 	actualdisk = stat_actual_disk(dn, &di, &suffix);
2140*0Sstevel@tonic-gate 
2141*0Sstevel@tonic-gate 	/*
2142*0Sstevel@tonic-gate 	 *  Destination exists, now find more about it.
2143*0Sstevel@tonic-gate 	 */
2144*0Sstevel@tonic-gate 	if (!(S_ISCHR(di.st_mode))) {
2145*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2146*0Sstevel@tonic-gate 		    gettext("\n%s: device name must be a "
2147*0Sstevel@tonic-gate 			"character special device.\n"), actualdisk);
2148*0Sstevel@tonic-gate 		exit(2);
2149*0Sstevel@tonic-gate 	} else if ((fd = open(actualdisk, O_RDWR | O_EXCL)) < 0) {
2150*0Sstevel@tonic-gate 		perror(actualdisk);
2151*0Sstevel@tonic-gate 		exit(2);
2152*0Sstevel@tonic-gate 	}
2153*0Sstevel@tonic-gate 
2154*0Sstevel@tonic-gate 	/*
2155*0Sstevel@tonic-gate 	 * Find appropriate partition if we were requested to do so.
2156*0Sstevel@tonic-gate 	 */
2157*0Sstevel@tonic-gate 	if (suffix && !(seek_partn(fd, suffix, wbpb, &ignored))) {
2158*0Sstevel@tonic-gate 		(void) close(fd);
2159*0Sstevel@tonic-gate 		exit(2);
2160*0Sstevel@tonic-gate 	}
2161*0Sstevel@tonic-gate 
2162*0Sstevel@tonic-gate 	read_existing_bpb(fd, wbpb);
2163*0Sstevel@tonic-gate 	print_reproducing_command(fd, actualdisk, suffix, wbpb);
2164*0Sstevel@tonic-gate 
2165*0Sstevel@tonic-gate 	return (fd);
2166*0Sstevel@tonic-gate }
2167*0Sstevel@tonic-gate 
2168*0Sstevel@tonic-gate /*
2169*0Sstevel@tonic-gate  *  open_and_seek
2170*0Sstevel@tonic-gate  *
2171*0Sstevel@tonic-gate  *	Open the requested 'dev_name'.  Seek to point where
2172*0Sstevel@tonic-gate  *	we'll write boot sectors, etc., based on any ':partition'
2173*0Sstevel@tonic-gate  *	attachments to the dev_name.
2174*0Sstevel@tonic-gate  *
2175*0Sstevel@tonic-gate  *	By the time we are finished here, the entire BPB will be
2176*0Sstevel@tonic-gate  *	filled in, excepting the volume label.
2177*0Sstevel@tonic-gate  */
2178*0Sstevel@tonic-gate static
2179*0Sstevel@tonic-gate int
2180*0Sstevel@tonic-gate open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto)
2181*0Sstevel@tonic-gate {
2182*0Sstevel@tonic-gate 	struct fd_char fdchar;
2183*0Sstevel@tonic-gate 	struct stat di;
2184*0Sstevel@tonic-gate 	char *actualdisk = NULL;
2185*0Sstevel@tonic-gate 	char *suffix = NULL;
2186*0Sstevel@tonic-gate 	int fd;
2187*0Sstevel@tonic-gate 
2188*0Sstevel@tonic-gate 	if (Verbose)
2189*0Sstevel@tonic-gate 		(void) printf(gettext("Opening destination device/file.\n"));
2190*0Sstevel@tonic-gate 
2191*0Sstevel@tonic-gate 	/*
2192*0Sstevel@tonic-gate 	 * We hold these truths to be self evident, all BPBs we create
2193*0Sstevel@tonic-gate 	 * will have these values in these fields.
2194*0Sstevel@tonic-gate 	 */
2195*0Sstevel@tonic-gate 	wbpb->bpb.num_fats = 2;
2196*0Sstevel@tonic-gate 	wbpb->bpb.bytes_sector = BPSEC;
2197*0Sstevel@tonic-gate 
2198*0Sstevel@tonic-gate 	/*
2199*0Sstevel@tonic-gate 	 * Assign or use supplied numbers for hidden and
2200*0Sstevel@tonic-gate 	 * reserved sectors in the file system.
2201*0Sstevel@tonic-gate 	 */
2202*0Sstevel@tonic-gate 	if (GetResrvd)
2203*0Sstevel@tonic-gate 		if (MakeFAT32)
2204*0Sstevel@tonic-gate 			wbpb->bpb.resv_sectors = 32;
2205*0Sstevel@tonic-gate 		else
2206*0Sstevel@tonic-gate 			wbpb->bpb.resv_sectors = 1;
2207*0Sstevel@tonic-gate 	else
2208*0Sstevel@tonic-gate 		wbpb->bpb.resv_sectors = Resrvd;
2209*0Sstevel@tonic-gate 
2210*0Sstevel@tonic-gate 	wbpb->ebpb.ext_signature = 0x29; /* Magic number for modern format */
2211*0Sstevel@tonic-gate 	wbpb->ebpb.volume_id = 0;
2212*0Sstevel@tonic-gate 
2213*0Sstevel@tonic-gate 	if (MakeFAT32)
2214*0Sstevel@tonic-gate 		fill_fat32_bpb(wbpb);
2215*0Sstevel@tonic-gate 
2216*0Sstevel@tonic-gate 	/*
2217*0Sstevel@tonic-gate 	 * If all output goes to a simple file, call a routine to setup
2218*0Sstevel@tonic-gate 	 * that scenario. Otherwise, try to find the device.
2219*0Sstevel@tonic-gate 	 */
2220*0Sstevel@tonic-gate 	if (Outputtofile)
2221*0Sstevel@tonic-gate 		return (fd = prepare_image_file(dn, wbpb));
2222*0Sstevel@tonic-gate 
2223*0Sstevel@tonic-gate 	actualdisk = stat_actual_disk(dn, &di, &suffix);
2224*0Sstevel@tonic-gate 
2225*0Sstevel@tonic-gate 	/*
2226*0Sstevel@tonic-gate 	 * Sanity check.  If we've been provided a partition-specifying
2227*0Sstevel@tonic-gate 	 * suffix, we shouldn't also have been told to ignore the
2228*0Sstevel@tonic-gate 	 * fdisk table.
2229*0Sstevel@tonic-gate 	 */
2230*0Sstevel@tonic-gate 	if (DontUseFdisk && suffix) {
2231*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2232*0Sstevel@tonic-gate 		    gettext("Using 'nofdisk' option precludes "
2233*0Sstevel@tonic-gate 			    "appending logical drive\nspecifier "
2234*0Sstevel@tonic-gate 			    "to the device name.\n"));
2235*0Sstevel@tonic-gate 		exit(2);
2236*0Sstevel@tonic-gate 	}
2237*0Sstevel@tonic-gate 
2238*0Sstevel@tonic-gate 	/*
2239*0Sstevel@tonic-gate 	 *  Destination exists, now find more about it.
2240*0Sstevel@tonic-gate 	 */
2241*0Sstevel@tonic-gate 	if (!(S_ISCHR(di.st_mode))) {
2242*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2243*0Sstevel@tonic-gate 		    gettext("\n%s: device name must indicate a "
2244*0Sstevel@tonic-gate 			"character special device.\n"), actualdisk);
2245*0Sstevel@tonic-gate 		exit(2);
2246*0Sstevel@tonic-gate 	} else if ((fd = open(actualdisk, O_RDWR | O_EXCL)) < 0) {
2247*0Sstevel@tonic-gate 		perror(actualdisk);
2248*0Sstevel@tonic-gate 		exit(2);
2249*0Sstevel@tonic-gate 	}
2250*0Sstevel@tonic-gate 
2251*0Sstevel@tonic-gate 	/*
2252*0Sstevel@tonic-gate 	 * Find appropriate partition if we were requested to do so.
2253*0Sstevel@tonic-gate 	 */
2254*0Sstevel@tonic-gate 	if (suffix && !(seek_partn(fd, suffix, wbpb, seekto))) {
2255*0Sstevel@tonic-gate 		(void) close(fd);
2256*0Sstevel@tonic-gate 		exit(2);
2257*0Sstevel@tonic-gate 	}
2258*0Sstevel@tonic-gate 
2259*0Sstevel@tonic-gate 	if (!suffix) {
2260*0Sstevel@tonic-gate 		/*
2261*0Sstevel@tonic-gate 		 * We have one of two possibilities.  Chances are we have
2262*0Sstevel@tonic-gate 		 * a floppy drive.  But the user may be trying to format
2263*0Sstevel@tonic-gate 		 * some weird drive that we don't know about and is supplying
2264*0Sstevel@tonic-gate 		 * all the important values.  In that case, they should have set
2265*0Sstevel@tonic-gate 		 * the 'nofdisk' flag.
2266*0Sstevel@tonic-gate 		 *
2267*0Sstevel@tonic-gate 		 * If 'nofdisk' isn't set, do a floppy-specific ioctl to
2268*0Sstevel@tonic-gate 		 * get the remainder of our info. If the ioctl fails, we have
2269*0Sstevel@tonic-gate 		 * a good idea that they aren't really on a floppy.  In that
2270*0Sstevel@tonic-gate 		 * case, they should have given us a partition specifier.
2271*0Sstevel@tonic-gate 		 */
2272*0Sstevel@tonic-gate 		if (DontUseFdisk) {
2273*0Sstevel@tonic-gate 			if (!(seek_nofdisk(fd, wbpb, seekto))) {
2274*0Sstevel@tonic-gate 				(void) close(fd);
2275*0Sstevel@tonic-gate 				exit(2);
2276*0Sstevel@tonic-gate 			}
2277*0Sstevel@tonic-gate 			find_fixed_details(fd, wbpb);
2278*0Sstevel@tonic-gate 		} else if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) {
2279*0Sstevel@tonic-gate 			if (errno == ENOTTY) {
2280*0Sstevel@tonic-gate 				partn_lecture(actualdisk);
2281*0Sstevel@tonic-gate 				(void) close(fd);
2282*0Sstevel@tonic-gate 				exit(2);
2283*0Sstevel@tonic-gate 			}
2284*0Sstevel@tonic-gate 		} else {
2285*0Sstevel@tonic-gate #ifdef sparc
2286*0Sstevel@tonic-gate 			fdchar.fdc_medium = 3;
2287*0Sstevel@tonic-gate #endif
2288*0Sstevel@tonic-gate 			lookup_floppy(&fdchar, wbpb);
2289*0Sstevel@tonic-gate 		}
2290*0Sstevel@tonic-gate 	} else {
2291*0Sstevel@tonic-gate 		find_fixed_details(fd, wbpb);
2292*0Sstevel@tonic-gate 	}
2293*0Sstevel@tonic-gate 
2294*0Sstevel@tonic-gate 	return (fd);
2295*0Sstevel@tonic-gate }
2296*0Sstevel@tonic-gate 
2297*0Sstevel@tonic-gate /*
2298*0Sstevel@tonic-gate  * The following is a copy of MS-DOS 4.0 boot block.
2299*0Sstevel@tonic-gate  * It consists of the BIOS parameter block, and a disk
2300*0Sstevel@tonic-gate  * bootstrap program.
2301*0Sstevel@tonic-gate  *
2302*0Sstevel@tonic-gate  * The BIOS parameter block contains the right values
2303*0Sstevel@tonic-gate  * for the 3.5" high-density 1.44MB floppy format.
2304*0Sstevel@tonic-gate  *
2305*0Sstevel@tonic-gate  * This will be our default boot sector, if the user
2306*0Sstevel@tonic-gate  * didn't point us at a different one.
2307*0Sstevel@tonic-gate  *
2308*0Sstevel@tonic-gate  */
2309*0Sstevel@tonic-gate static
2310*0Sstevel@tonic-gate uchar_t DefBootSec[512] = {
2311*0Sstevel@tonic-gate 	0xeb, 0x3c, 0x90, 	/* 8086 short jump + displacement + NOP */
2312*0Sstevel@tonic-gate 	'M', 'S', 'D', 'O', 'S', '4', '.', '0',	/* OEM name & version */
2313*0Sstevel@tonic-gate 	0x00, 0x02, 0x01, 0x01, 0x00,
2314*0Sstevel@tonic-gate 	0x02, 0xe0, 0x00, 0x40, 0x0b,
2315*0Sstevel@tonic-gate 	0xf0, 0x09, 0x00, 0x12, 0x00,
2316*0Sstevel@tonic-gate 	0x02, 0x00,
2317*0Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00,
2318*0Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00,
2319*0Sstevel@tonic-gate 	0x00, 0x00,
2320*0Sstevel@tonic-gate 	0x29, 0x00, 0x00, 0x00, 0x00,
2321*0Sstevel@tonic-gate 	'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ',
2322*0Sstevel@tonic-gate 	'F', 'A', 'T', '1', '2', ' ', ' ', ' ',
2323*0Sstevel@tonic-gate 	0xfa, 0x33,
2324*0Sstevel@tonic-gate 	0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07,
2325*0Sstevel@tonic-gate 	0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56,
2326*0Sstevel@tonic-gate 	0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00,
2327*0Sstevel@tonic-gate 	0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe,
2328*0Sstevel@tonic-gate 	0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9,
2329*0Sstevel@tonic-gate 	0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb,
2330*0Sstevel@tonic-gate 	0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06,
2331*0Sstevel@tonic-gate 	0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c,
2332*0Sstevel@tonic-gate 	0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7,
2333*0Sstevel@tonic-gate 	0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13,
2334*0Sstevel@tonic-gate 	0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83,
2335*0Sstevel@tonic-gate 	0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52,
2336*0Sstevel@tonic-gate 	0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c,
2337*0Sstevel@tonic-gate 	0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b,
2338*0Sstevel@tonic-gate 	0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3,
2339*0Sstevel@tonic-gate 	0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c,
2340*0Sstevel@tonic-gate 	0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c,
2341*0Sstevel@tonic-gate 	0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20,
2342*0Sstevel@tonic-gate 	0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b,
2343*0Sstevel@tonic-gate 	0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3,
2344*0Sstevel@tonic-gate 	0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6,
2345*0Sstevel@tonic-gate 	0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18,
2346*0Sstevel@tonic-gate 	0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4,
2347*0Sstevel@tonic-gate 	0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44,
2348*0Sstevel@tonic-gate 	0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8,
2349*0Sstevel@tonic-gate 	0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49,
2350*0Sstevel@tonic-gate 	0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51,
2351*0Sstevel@tonic-gate 	0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8,
2352*0Sstevel@tonic-gate 	0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05,
2353*0Sstevel@tonic-gate 	0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b,
2354*0Sstevel@tonic-gate 	0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a,
2355*0Sstevel@tonic-gate 	0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1,
2356*0Sstevel@tonic-gate 	0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac,
2357*0Sstevel@tonic-gate 	0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07,
2358*0Sstevel@tonic-gate 	0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18,
2359*0Sstevel@tonic-gate 	0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe,
2360*0Sstevel@tonic-gate 	0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7,
2361*0Sstevel@tonic-gate 	0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3,
2362*0Sstevel@tonic-gate 	0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02,
2363*0Sstevel@tonic-gate 	0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6,
2364*0Sstevel@tonic-gate 	0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9,
2365*0Sstevel@tonic-gate 	0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c,
2366*0Sstevel@tonic-gate 	0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e,
2367*0Sstevel@tonic-gate 	0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
2368*0Sstevel@tonic-gate 	0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20,
2369*0Sstevel@tonic-gate 	0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72,
2370*0Sstevel@tonic-gate 	0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c,
2371*0Sstevel@tonic-gate 	0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
2372*0Sstevel@tonic-gate 	0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e,
2373*0Sstevel@tonic-gate 	0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68,
2374*0Sstevel@tonic-gate 	0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79,
2375*0Sstevel@tonic-gate 	0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20,
2376*0Sstevel@tonic-gate 	0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53,
2377*0Sstevel@tonic-gate 	0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59,
2378*0Sstevel@tonic-gate 	0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2379*0Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
2380*0Sstevel@tonic-gate };
2381*0Sstevel@tonic-gate 
2382*0Sstevel@tonic-gate /*
2383*0Sstevel@tonic-gate  *  verify_bootblkfile
2384*0Sstevel@tonic-gate  *
2385*0Sstevel@tonic-gate  *	We were provided with the name of a file containing the bootblk
2386*0Sstevel@tonic-gate  *	to install.  Verify it has a valid boot sector as best we can. Any
2387*0Sstevel@tonic-gate  *	errors and we return a bad file descriptor.  Otherwise we fill up the
2388*0Sstevel@tonic-gate  *	provided buffer with the boot sector, return the file
2389*0Sstevel@tonic-gate  *	descriptor for later use and leave the file pointer just
2390*0Sstevel@tonic-gate  *	past the boot sector part of the boot block file.
2391*0Sstevel@tonic-gate  */
2392*0Sstevel@tonic-gate static
2393*0Sstevel@tonic-gate int
2394*0Sstevel@tonic-gate verify_bootblkfile(char *fn, boot_sector_t *bs, ulong_t *blkfilesize)
2395*0Sstevel@tonic-gate {
2396*0Sstevel@tonic-gate 	struct stat fi;
2397*0Sstevel@tonic-gate 	int bsfd = -1;
2398*0Sstevel@tonic-gate 
2399*0Sstevel@tonic-gate 	if (stat(fn, &fi)) {
2400*0Sstevel@tonic-gate 		perror(fn);
2401*0Sstevel@tonic-gate 	} else if (fi.st_size < BPSEC) {
2402*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2403*0Sstevel@tonic-gate 		    gettext("%s: Too short to be a boot sector.\n"), fn);
2404*0Sstevel@tonic-gate 	} else if ((bsfd = open(fn, O_RDONLY)) < 0) {
2405*0Sstevel@tonic-gate 		perror(fn);
2406*0Sstevel@tonic-gate 	} else if (read(bsfd, bs->buf, BPSEC) < BPSEC) {
2407*0Sstevel@tonic-gate 		(void) close(bsfd);
2408*0Sstevel@tonic-gate 		bsfd = -1;
2409*0Sstevel@tonic-gate 		perror(gettext("Boot block read"));
2410*0Sstevel@tonic-gate 	} else {
2411*0Sstevel@tonic-gate #ifdef i386
2412*0Sstevel@tonic-gate 		if ((bs->bs.bs_front.bs_jump_code[0] != OPCODE1 &&
2413*0Sstevel@tonic-gate 		    bs->bs.bs_front.bs_jump_code[0] != OPCODE2) ||
2414*0Sstevel@tonic-gate #else
2415*0Sstevel@tonic-gate 		if ((bs->bs.bs_jump_code[0] != OPCODE1 &&
2416*0Sstevel@tonic-gate 		    bs->bs.bs_jump_code[0] != OPCODE2) ||
2417*0Sstevel@tonic-gate #endif
2418*0Sstevel@tonic-gate 		    (bs->bs.bs_signature[0] != (BOOTSECSIG & 0xFF) &&
2419*0Sstevel@tonic-gate 		    bs->bs.bs_signature[1] != ((BOOTSECSIG >> 8) & 0xFF))) {
2420*0Sstevel@tonic-gate 			(void) close(bsfd);
2421*0Sstevel@tonic-gate 			bsfd = -1;
2422*0Sstevel@tonic-gate 			(void) fprintf(stderr,
2423*0Sstevel@tonic-gate 			    gettext("Boot block (%s) bogus.\n"), fn);
2424*0Sstevel@tonic-gate 		}
2425*0Sstevel@tonic-gate 		*blkfilesize = fi.st_size;
2426*0Sstevel@tonic-gate 	}
2427*0Sstevel@tonic-gate 	return (bsfd);
2428*0Sstevel@tonic-gate }
2429*0Sstevel@tonic-gate 
2430*0Sstevel@tonic-gate /*
2431*0Sstevel@tonic-gate  *  verify_firstfile
2432*0Sstevel@tonic-gate  *
2433*0Sstevel@tonic-gate  *	We were provided with the name of a file to be the first file
2434*0Sstevel@tonic-gate  *	installed on the disk.  We just need to verify it exists and
2435*0Sstevel@tonic-gate  *	find out how big it is.  If it doesn't exist, we print a warning
2436*0Sstevel@tonic-gate  *	message about how the file wasn't found.  We don't exit fatally,
2437*0Sstevel@tonic-gate  *	though, rather we return a size of 0 and the FAT will be built
2438*0Sstevel@tonic-gate  *	without installing any first file.  They can then presumably
2439*0Sstevel@tonic-gate  *	install the correct first file by hand.
2440*0Sstevel@tonic-gate  */
2441*0Sstevel@tonic-gate static
2442*0Sstevel@tonic-gate int
2443*0Sstevel@tonic-gate verify_firstfile(char *fn, ulong_t *filesize)
2444*0Sstevel@tonic-gate {
2445*0Sstevel@tonic-gate 	struct stat fi;
2446*0Sstevel@tonic-gate 	int fd = -1;
2447*0Sstevel@tonic-gate 
2448*0Sstevel@tonic-gate 	*filesize = 0;
2449*0Sstevel@tonic-gate 	if (stat(fn, &fi) || (fd = open(fn, O_RDONLY)) < 0) {
2450*0Sstevel@tonic-gate 		perror(fn);
2451*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2452*0Sstevel@tonic-gate 		    gettext("Could not access requested file.  It will not\n"
2453*0Sstevel@tonic-gate 			    "be installed in the new file system.\n"));
2454*0Sstevel@tonic-gate 	} else {
2455*0Sstevel@tonic-gate 		*filesize = fi.st_size;
2456*0Sstevel@tonic-gate 	}
2457*0Sstevel@tonic-gate 
2458*0Sstevel@tonic-gate 	return (fd);
2459*0Sstevel@tonic-gate }
2460*0Sstevel@tonic-gate 
2461*0Sstevel@tonic-gate /*
2462*0Sstevel@tonic-gate  *  label_volume
2463*0Sstevel@tonic-gate  *
2464*0Sstevel@tonic-gate  *	Fill in BPB with volume label.
2465*0Sstevel@tonic-gate  */
2466*0Sstevel@tonic-gate static
2467*0Sstevel@tonic-gate void
2468*0Sstevel@tonic-gate label_volume(char *lbl, bpb_t *wbpb)
2469*0Sstevel@tonic-gate {
2470*0Sstevel@tonic-gate 	int ll, i;
2471*0Sstevel@tonic-gate 
2472*0Sstevel@tonic-gate 	/* Put a volume label into our BPB. */
2473*0Sstevel@tonic-gate 	if (!lbl)
2474*0Sstevel@tonic-gate 		lbl = DEFAULT_LABEL;
2475*0Sstevel@tonic-gate 
2476*0Sstevel@tonic-gate 	ll = min(11, (int)strlen(lbl));
2477*0Sstevel@tonic-gate 	for (i = 0; i < ll; i++) {
2478*0Sstevel@tonic-gate 		wbpb->ebpb.volume_label[i] = toupper(lbl[i]);
2479*0Sstevel@tonic-gate 	}
2480*0Sstevel@tonic-gate 	for (; i < 11; i++) {
2481*0Sstevel@tonic-gate 		wbpb->ebpb.volume_label[i] = ' ';
2482*0Sstevel@tonic-gate 	}
2483*0Sstevel@tonic-gate }
2484*0Sstevel@tonic-gate 
2485*0Sstevel@tonic-gate static
2486*0Sstevel@tonic-gate int
2487*0Sstevel@tonic-gate copy_bootblk(char *fn, boot_sector_t *bootsect, ulong_t *bootblksize)
2488*0Sstevel@tonic-gate {
2489*0Sstevel@tonic-gate 	int bsfd = -1;
2490*0Sstevel@tonic-gate 
2491*0Sstevel@tonic-gate 	if (Verbose && fn)
2492*0Sstevel@tonic-gate 		(void) printf(gettext("Request to install boot "
2493*0Sstevel@tonic-gate 		    "block file %s.\n"), fn);
2494*0Sstevel@tonic-gate 	else if (Verbose)
2495*0Sstevel@tonic-gate 		(void) printf(gettext("Request to install DOS boot block.\n"));
2496*0Sstevel@tonic-gate 
2497*0Sstevel@tonic-gate 	/*
2498*0Sstevel@tonic-gate 	 *  If they want to install their own boot block, sanity check
2499*0Sstevel@tonic-gate 	 *  that block.
2500*0Sstevel@tonic-gate 	 */
2501*0Sstevel@tonic-gate 	if (fn) {
2502*0Sstevel@tonic-gate 		bsfd = verify_bootblkfile(fn, bootsect, bootblksize);
2503*0Sstevel@tonic-gate 		if (bsfd < 0) {
2504*0Sstevel@tonic-gate 			exit(3);
2505*0Sstevel@tonic-gate 		}
2506*0Sstevel@tonic-gate 		*bootblksize = roundup(*bootblksize, BPSEC);
2507*0Sstevel@tonic-gate 	} else {
2508*0Sstevel@tonic-gate 		(void) memcpy(bootsect, DefBootSec, BPSEC);
2509*0Sstevel@tonic-gate 		*bootblksize = BPSEC;
2510*0Sstevel@tonic-gate 	}
2511*0Sstevel@tonic-gate 
2512*0Sstevel@tonic-gate 	return (bsfd);
2513*0Sstevel@tonic-gate }
2514*0Sstevel@tonic-gate 
2515*0Sstevel@tonic-gate /*
2516*0Sstevel@tonic-gate  *  mark_cluster
2517*0Sstevel@tonic-gate  *
2518*0Sstevel@tonic-gate  *	This routine fills a FAT entry with the value supplied to it as an
2519*0Sstevel@tonic-gate  *	argument.  The fatp argument is assumed to be a pointer to the FAT's
2520*0Sstevel@tonic-gate  *	0th entry.  The clustnum is the cluster entry that should be updated.
2521*0Sstevel@tonic-gate  *	The value is the new value for the entry.
2522*0Sstevel@tonic-gate  */
2523*0Sstevel@tonic-gate static
2524*0Sstevel@tonic-gate void
2525*0Sstevel@tonic-gate mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, uint32_t value)
2526*0Sstevel@tonic-gate {
2527*0Sstevel@tonic-gate 	uchar_t *ep;
2528*0Sstevel@tonic-gate 	ulong_t idx;
2529*0Sstevel@tonic-gate 
2530*0Sstevel@tonic-gate 	idx = (Fatentsize == 32) ? clustnum * 4 :
2531*0Sstevel@tonic-gate 		(Fatentsize == 16) ? clustnum * 2 : clustnum + clustnum/2;
2532*0Sstevel@tonic-gate 	ep = fatp + idx;
2533*0Sstevel@tonic-gate 
2534*0Sstevel@tonic-gate 	if (Fatentsize == 32) {
2535*0Sstevel@tonic-gate 		store_32_bits(&ep, value);
2536*0Sstevel@tonic-gate 	} else if (Fatentsize == 16) {
2537*0Sstevel@tonic-gate 		store_16_bits(&ep, value);
2538*0Sstevel@tonic-gate 	} else {
2539*0Sstevel@tonic-gate 		if (clustnum & 1) {
2540*0Sstevel@tonic-gate 			*ep = (*ep & 0x0f) | ((value << 4) & 0xf0);
2541*0Sstevel@tonic-gate 			ep++;
2542*0Sstevel@tonic-gate 			*ep = (value >> 4) & 0xff;
2543*0Sstevel@tonic-gate 		} else {
2544*0Sstevel@tonic-gate 			*ep++ = value & 0xff;
2545*0Sstevel@tonic-gate 			*ep = (*ep & 0xf0) | ((value >> 8) & 0x0f);
2546*0Sstevel@tonic-gate 		}
2547*0Sstevel@tonic-gate 	}
2548*0Sstevel@tonic-gate }
2549*0Sstevel@tonic-gate 
2550*0Sstevel@tonic-gate static
2551*0Sstevel@tonic-gate uchar_t *
2552*0Sstevel@tonic-gate build_fat(bpb_t *wbpb, struct fat32_boot_fsinfo *fsinfop, ulong_t bootblksize,
2553*0Sstevel@tonic-gate     ulong_t *fatsize, char *ffn, int *fffd, ulong_t *ffsize,
2554*0Sstevel@tonic-gate     pc_cluster32_t *ffstartclust)
2555*0Sstevel@tonic-gate {
2556*0Sstevel@tonic-gate 	pc_cluster32_t nextfree, ci;
2557*0Sstevel@tonic-gate 	uchar_t *fatp;
2558*0Sstevel@tonic-gate 	ushort_t numclust, numsect;
2559*0Sstevel@tonic-gate 	int  remclust;
2560*0Sstevel@tonic-gate 
2561*0Sstevel@tonic-gate 	/* Alloc space for a FAT and then null it out. */
2562*0Sstevel@tonic-gate 	if (Verbose) {
2563*0Sstevel@tonic-gate 		(void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"),
2564*0Sstevel@tonic-gate 		    wbpb->bpb.sectors_per_fat ? wbpb->bpb.sectors_per_fat :
2565*0Sstevel@tonic-gate 			wbpb->bpb32.big_sectors_per_fat);
2566*0Sstevel@tonic-gate 	}
2567*0Sstevel@tonic-gate 
2568*0Sstevel@tonic-gate 	if (MakeFAT32) {
2569*0Sstevel@tonic-gate 		*fatsize = BPSEC * wbpb->bpb32.big_sectors_per_fat;
2570*0Sstevel@tonic-gate 	} else {
2571*0Sstevel@tonic-gate 		*fatsize = BPSEC * wbpb->bpb.sectors_per_fat;
2572*0Sstevel@tonic-gate 	}
2573*0Sstevel@tonic-gate 	if (!(fatp = (uchar_t *)malloc(*fatsize))) {
2574*0Sstevel@tonic-gate 		perror(gettext("FAT table alloc"));
2575*0Sstevel@tonic-gate 		exit(4);
2576*0Sstevel@tonic-gate 	} else {
2577*0Sstevel@tonic-gate 		(void) memset(fatp, 0, *fatsize);
2578*0Sstevel@tonic-gate 	}
2579*0Sstevel@tonic-gate 
2580*0Sstevel@tonic-gate 	/* Build in-memory FAT */
2581*0Sstevel@tonic-gate 	*fatp = wbpb->bpb.media;
2582*0Sstevel@tonic-gate 	*(fatp + 1) = 0xFF;
2583*0Sstevel@tonic-gate 	*(fatp + 2) = 0xFF;
2584*0Sstevel@tonic-gate 
2585*0Sstevel@tonic-gate 	if (Fatentsize == 16) {
2586*0Sstevel@tonic-gate 		*(fatp + 3) = 0xFF;
2587*0Sstevel@tonic-gate 	} else if (Fatentsize == 32) {
2588*0Sstevel@tonic-gate 		*(fatp + 3) = 0x0F;
2589*0Sstevel@tonic-gate 		*(fatp + 4) = 0xFF;
2590*0Sstevel@tonic-gate 		*(fatp + 5) = 0xFF;
2591*0Sstevel@tonic-gate 		*(fatp + 6) = 0xFF;
2592*0Sstevel@tonic-gate 		*(fatp + 7) = 0x0F;
2593*0Sstevel@tonic-gate 	}
2594*0Sstevel@tonic-gate 
2595*0Sstevel@tonic-gate 	/*
2596*0Sstevel@tonic-gate 	 * Keep track of clusters used.
2597*0Sstevel@tonic-gate 	 */
2598*0Sstevel@tonic-gate 	remclust = TotalClusters;
2599*0Sstevel@tonic-gate 	nextfree = 2;
2600*0Sstevel@tonic-gate 
2601*0Sstevel@tonic-gate 	/*
2602*0Sstevel@tonic-gate 	 * Get info on first file to install, if any.
2603*0Sstevel@tonic-gate 	 */
2604*0Sstevel@tonic-gate 	if (ffn)
2605*0Sstevel@tonic-gate 		*fffd = verify_firstfile(ffn, ffsize);
2606*0Sstevel@tonic-gate 
2607*0Sstevel@tonic-gate 	/*
2608*0Sstevel@tonic-gate 	 * Compute number of clusters to preserve for bootblk overage.
2609*0Sstevel@tonic-gate 	 * Remember that we already wrote the first sector of the boot block.
2610*0Sstevel@tonic-gate 	 * These clusters are marked BAD to prevent them from being deleted
2611*0Sstevel@tonic-gate 	 * or used.  The first available cluster is 2, so we always offset
2612*0Sstevel@tonic-gate 	 * the clusters.
2613*0Sstevel@tonic-gate 	 */
2614*0Sstevel@tonic-gate 	numsect = idivceil((bootblksize - BPSEC), BPSEC);
2615*0Sstevel@tonic-gate 	numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
2616*0Sstevel@tonic-gate 
2617*0Sstevel@tonic-gate 	if (Verbose && numclust)
2618*0Sstevel@tonic-gate 		(void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"),
2619*0Sstevel@tonic-gate 		    numclust);
2620*0Sstevel@tonic-gate 	for (ci = 0; ci < numclust; ci++)
2621*0Sstevel@tonic-gate 		mark_cluster(fatp, nextfree++,
2622*0Sstevel@tonic-gate 			MakeFAT32 ? PCF_BADCLUSTER32 : PCF_BADCLUSTER);
2623*0Sstevel@tonic-gate 	remclust -= numclust;
2624*0Sstevel@tonic-gate 
2625*0Sstevel@tonic-gate 	/*
2626*0Sstevel@tonic-gate 	 * Reserve a cluster for the root directory on a FAT32.
2627*0Sstevel@tonic-gate 	 */
2628*0Sstevel@tonic-gate 	if (MakeFAT32) {
2629*0Sstevel@tonic-gate 		mark_cluster(fatp, nextfree, PCF_LASTCLUSTER32);
2630*0Sstevel@tonic-gate 		wbpb->bpb32.root_dir_clust = nextfree++;
2631*0Sstevel@tonic-gate 		remclust--;
2632*0Sstevel@tonic-gate 	}
2633*0Sstevel@tonic-gate 
2634*0Sstevel@tonic-gate 	/*
2635*0Sstevel@tonic-gate 	 * Compute and preserve number of clusters for first file.
2636*0Sstevel@tonic-gate 	 */
2637*0Sstevel@tonic-gate 	if (*fffd >= 0) {
2638*0Sstevel@tonic-gate 		*ffstartclust = nextfree;
2639*0Sstevel@tonic-gate 		numsect = idivceil(*ffsize, BPSEC);
2640*0Sstevel@tonic-gate 		numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
2641*0Sstevel@tonic-gate 
2642*0Sstevel@tonic-gate 		if (numclust > remclust) {
2643*0Sstevel@tonic-gate 			(void) fprintf(stderr,
2644*0Sstevel@tonic-gate 				gettext("Requested first file too large to be\n"
2645*0Sstevel@tonic-gate 					"installed in the new file system.\n"));
2646*0Sstevel@tonic-gate 			(void) close(*fffd);
2647*0Sstevel@tonic-gate 			*fffd = -1;
2648*0Sstevel@tonic-gate 			goto finish;
2649*0Sstevel@tonic-gate 		}
2650*0Sstevel@tonic-gate 
2651*0Sstevel@tonic-gate 		if (Verbose)
2652*0Sstevel@tonic-gate 			(void) printf(gettext("Reserving %d first file "
2653*0Sstevel@tonic-gate 			    "cluster(s).\n"), numclust);
2654*0Sstevel@tonic-gate 		for (ci = 0; (int)ci < (int)(numclust-1); ci++, nextfree++)
2655*0Sstevel@tonic-gate 			mark_cluster(fatp, nextfree, nextfree + 1);
2656*0Sstevel@tonic-gate 		mark_cluster(fatp, nextfree++,
2657*0Sstevel@tonic-gate 			MakeFAT32 ? PCF_LASTCLUSTER32 : PCF_LASTCLUSTER);
2658*0Sstevel@tonic-gate 		remclust -= numclust;
2659*0Sstevel@tonic-gate 	}
2660*0Sstevel@tonic-gate 
2661*0Sstevel@tonic-gate finish:
2662*0Sstevel@tonic-gate 	if (Verbose) {
2663*0Sstevel@tonic-gate 		(void) printf(gettext("First sector of FAT"));
2664*0Sstevel@tonic-gate 		header_for_dump();
2665*0Sstevel@tonic-gate 		dump_bytes(fatp, BPSEC);
2666*0Sstevel@tonic-gate 	}
2667*0Sstevel@tonic-gate 
2668*0Sstevel@tonic-gate 	fsinfop->fs_signature = FAT32_FS_SIGN;
2669*0Sstevel@tonic-gate 	fsinfop->fs_free_clusters = remclust;
2670*0Sstevel@tonic-gate 	fsinfop->fs_next_cluster = nextfree;
2671*0Sstevel@tonic-gate 	return (fatp);
2672*0Sstevel@tonic-gate }
2673*0Sstevel@tonic-gate 
2674*0Sstevel@tonic-gate static
2675*0Sstevel@tonic-gate void
2676*0Sstevel@tonic-gate dirent_time_fill(struct pcdir *dep)
2677*0Sstevel@tonic-gate {
2678*0Sstevel@tonic-gate 	struct  timeval tv;
2679*0Sstevel@tonic-gate 	struct	tm	*tp;
2680*0Sstevel@tonic-gate 	ushort_t	dostime;
2681*0Sstevel@tonic-gate 	ushort_t	dosday;
2682*0Sstevel@tonic-gate 
2683*0Sstevel@tonic-gate 	(void) gettimeofday(&tv, (struct timezone *)0);
2684*0Sstevel@tonic-gate 	tp = localtime(&tv.tv_sec);
2685*0Sstevel@tonic-gate 	/* get the time & day into DOS format */
2686*0Sstevel@tonic-gate 	dostime = tp->tm_sec / 2;
2687*0Sstevel@tonic-gate 	dostime |= tp->tm_min << 5;
2688*0Sstevel@tonic-gate 	dostime |= tp->tm_hour << 11;
2689*0Sstevel@tonic-gate 	dosday = tp->tm_mday;
2690*0Sstevel@tonic-gate 	dosday |= (tp->tm_mon + 1) << 5;
2691*0Sstevel@tonic-gate 	dosday |= (tp->tm_year - 80) << 9;
2692*0Sstevel@tonic-gate 	dep->pcd_mtime.pct_time = htols(dostime);
2693*0Sstevel@tonic-gate 	dep->pcd_mtime.pct_date = htols(dosday);
2694*0Sstevel@tonic-gate }
2695*0Sstevel@tonic-gate 
2696*0Sstevel@tonic-gate static
2697*0Sstevel@tonic-gate void
2698*0Sstevel@tonic-gate dirent_label_fill(struct pcdir *dep, char *fn)
2699*0Sstevel@tonic-gate {
2700*0Sstevel@tonic-gate 	int nl, i;
2701*0Sstevel@tonic-gate 
2702*0Sstevel@tonic-gate 	/*
2703*0Sstevel@tonic-gate 	 * We spread the volume label across both the NAME and EXT fields
2704*0Sstevel@tonic-gate 	 */
2705*0Sstevel@tonic-gate 	nl = min(PCFNAMESIZE, strlen(fn));
2706*0Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
2707*0Sstevel@tonic-gate 		dep->pcd_filename[i] = toupper(fn[i]);
2708*0Sstevel@tonic-gate 	}
2709*0Sstevel@tonic-gate 	if (i < PCFNAMESIZE) {
2710*0Sstevel@tonic-gate 		for (; i < PCFNAMESIZE; i++)
2711*0Sstevel@tonic-gate 			dep->pcd_filename[i] = ' ';
2712*0Sstevel@tonic-gate 		for (i = 0; i < PCFEXTSIZE; i++)
2713*0Sstevel@tonic-gate 			dep->pcd_ext[i] = ' ';
2714*0Sstevel@tonic-gate 		return;
2715*0Sstevel@tonic-gate 	}
2716*0Sstevel@tonic-gate 	nl = min(PCFEXTSIZE, strlen(fn) - PCFNAMESIZE);
2717*0Sstevel@tonic-gate 	for (i = 0; i < nl; i++)
2718*0Sstevel@tonic-gate 		dep->pcd_ext[i] = toupper(fn[i + PCFNAMESIZE]);
2719*0Sstevel@tonic-gate 	if (i < PCFEXTSIZE) {
2720*0Sstevel@tonic-gate 		for (; i < PCFEXTSIZE; i++)
2721*0Sstevel@tonic-gate 			dep->pcd_ext[i] = ' ';
2722*0Sstevel@tonic-gate 	}
2723*0Sstevel@tonic-gate }
2724*0Sstevel@tonic-gate 
2725*0Sstevel@tonic-gate static
2726*0Sstevel@tonic-gate void
2727*0Sstevel@tonic-gate dirent_fname_fill(struct pcdir *dep, char *fn)
2728*0Sstevel@tonic-gate {
2729*0Sstevel@tonic-gate 	char *fname, *fext;
2730*0Sstevel@tonic-gate 	int nl, i;
2731*0Sstevel@tonic-gate 
2732*0Sstevel@tonic-gate 	if (fname = strrchr(fn, '/')) {
2733*0Sstevel@tonic-gate 		fname++;
2734*0Sstevel@tonic-gate 	} else {
2735*0Sstevel@tonic-gate 		fname = fn;
2736*0Sstevel@tonic-gate 	}
2737*0Sstevel@tonic-gate 
2738*0Sstevel@tonic-gate 	if (fext = strrchr(fname, '.')) {
2739*0Sstevel@tonic-gate 		fext++;
2740*0Sstevel@tonic-gate 	} else {
2741*0Sstevel@tonic-gate 		fext = "";
2742*0Sstevel@tonic-gate 	}
2743*0Sstevel@tonic-gate 
2744*0Sstevel@tonic-gate 	fname = strtok(fname, ".");
2745*0Sstevel@tonic-gate 
2746*0Sstevel@tonic-gate 	nl = min(PCFNAMESIZE, (int)strlen(fname));
2747*0Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
2748*0Sstevel@tonic-gate 		dep->pcd_filename[i] = toupper(fname[i]);
2749*0Sstevel@tonic-gate 	}
2750*0Sstevel@tonic-gate 	for (; i < PCFNAMESIZE; i++) {
2751*0Sstevel@tonic-gate 		dep->pcd_filename[i] = ' ';
2752*0Sstevel@tonic-gate 	}
2753*0Sstevel@tonic-gate 
2754*0Sstevel@tonic-gate 	nl = min(PCFEXTSIZE, (int)strlen(fext));
2755*0Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
2756*0Sstevel@tonic-gate 		dep->pcd_ext[i] = toupper(fext[i]);
2757*0Sstevel@tonic-gate 	}
2758*0Sstevel@tonic-gate 	for (; i < PCFEXTSIZE; i++) {
2759*0Sstevel@tonic-gate 		dep->pcd_ext[i] = ' ';
2760*0Sstevel@tonic-gate 	}
2761*0Sstevel@tonic-gate }
2762*0Sstevel@tonic-gate 
2763*0Sstevel@tonic-gate static
2764*0Sstevel@tonic-gate uchar_t *
2765*0Sstevel@tonic-gate build_rootdir(bpb_t *wbpb, char *ffn, int fffd,
2766*0Sstevel@tonic-gate     ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize)
2767*0Sstevel@tonic-gate {
2768*0Sstevel@tonic-gate 	struct pcdir *rootdirp;
2769*0Sstevel@tonic-gate 	struct pcdir *entry;
2770*0Sstevel@tonic-gate 
2771*0Sstevel@tonic-gate 	/*
2772*0Sstevel@tonic-gate 	 * Build a root directory.  It will have at least one entry,
2773*0Sstevel@tonic-gate 	 * the volume label and a second if the first file was defined.
2774*0Sstevel@tonic-gate 	 */
2775*0Sstevel@tonic-gate 	if (MakeFAT32) {
2776*0Sstevel@tonic-gate 		/*
2777*0Sstevel@tonic-gate 		 * We devote an entire cluster to the root
2778*0Sstevel@tonic-gate 		 * directory on FAT32.
2779*0Sstevel@tonic-gate 		 */
2780*0Sstevel@tonic-gate 		*rdirsize = wbpb->bpb.sectors_per_cluster * BPSEC;
2781*0Sstevel@tonic-gate 	} else {
2782*0Sstevel@tonic-gate 		*rdirsize = wbpb->bpb.num_root_entries * sizeof (struct pcdir);
2783*0Sstevel@tonic-gate 	}
2784*0Sstevel@tonic-gate 	if ((rootdirp = (struct pcdir *)malloc(*rdirsize)) == NULL) {
2785*0Sstevel@tonic-gate 		perror(gettext("Root directory allocation"));
2786*0Sstevel@tonic-gate 		exit(4);
2787*0Sstevel@tonic-gate 	} else {
2788*0Sstevel@tonic-gate 		entry = rootdirp;
2789*0Sstevel@tonic-gate 		(void) memset((char *)rootdirp, 0, *rdirsize);
2790*0Sstevel@tonic-gate 	}
2791*0Sstevel@tonic-gate 
2792*0Sstevel@tonic-gate 	/* Create directory entry for first file, if there is one */
2793*0Sstevel@tonic-gate 	if (fffd >= 0) {
2794*0Sstevel@tonic-gate 		dirent_fname_fill(entry, ffn);
2795*0Sstevel@tonic-gate 		entry->pcd_attr = Firstfileattr;
2796*0Sstevel@tonic-gate 		dirent_time_fill(entry);
2797*0Sstevel@tonic-gate 		entry->pcd_scluster_lo = htols(ffstart);
2798*0Sstevel@tonic-gate 		if (MakeFAT32) {
2799*0Sstevel@tonic-gate 			ffstart = ffstart >> 16;
2800*0Sstevel@tonic-gate 			entry->un.pcd_scluster_hi = htols(ffstart);
2801*0Sstevel@tonic-gate 		}
2802*0Sstevel@tonic-gate 		entry->pcd_size = htoli(ffsize);
2803*0Sstevel@tonic-gate 		entry++;
2804*0Sstevel@tonic-gate 	}
2805*0Sstevel@tonic-gate 
2806*0Sstevel@tonic-gate 	/* Create directory entry for volume label, if there is one */
2807*0Sstevel@tonic-gate 	if (Label != NULL) {
2808*0Sstevel@tonic-gate 		dirent_label_fill(entry, Label);
2809*0Sstevel@tonic-gate 		entry->pcd_attr = PCA_ARCH | PCA_LABEL;
2810*0Sstevel@tonic-gate 		dirent_time_fill(entry);
2811*0Sstevel@tonic-gate 		entry->pcd_scluster_lo = 0;
2812*0Sstevel@tonic-gate 		if (MakeFAT32) {
2813*0Sstevel@tonic-gate 			entry->un.pcd_scluster_hi = 0;
2814*0Sstevel@tonic-gate 		}
2815*0Sstevel@tonic-gate 		entry->pcd_size = 0;
2816*0Sstevel@tonic-gate 		entry++;
2817*0Sstevel@tonic-gate 	}
2818*0Sstevel@tonic-gate 
2819*0Sstevel@tonic-gate 	if (Verbose) {
2820*0Sstevel@tonic-gate 		(void) printf(gettext("First two directory entries"));
2821*0Sstevel@tonic-gate 		header_for_dump();
2822*0Sstevel@tonic-gate 		dump_bytes((uchar_t *)rootdirp, 2 * sizeof (struct pcdir));
2823*0Sstevel@tonic-gate 	}
2824*0Sstevel@tonic-gate 
2825*0Sstevel@tonic-gate 	return ((uchar_t *)rootdirp);
2826*0Sstevel@tonic-gate }
2827*0Sstevel@tonic-gate 
2828*0Sstevel@tonic-gate /*
2829*0Sstevel@tonic-gate  * write_rest
2830*0Sstevel@tonic-gate  *
2831*0Sstevel@tonic-gate  *	Write all the bytes from the current file pointer to end of file
2832*0Sstevel@tonic-gate  *	in the source file out to the destination file.  The writes should
2833*0Sstevel@tonic-gate  *	be padded to whole clusters with 0's if necessary.
2834*0Sstevel@tonic-gate  */
2835*0Sstevel@tonic-gate static
2836*0Sstevel@tonic-gate void
2837*0Sstevel@tonic-gate write_rest(bpb_t *wbpb, char *efn, int dfd, int sfd, int remaining)
2838*0Sstevel@tonic-gate {
2839*0Sstevel@tonic-gate 	char buf[BPSEC];
2840*0Sstevel@tonic-gate 	ushort_t numsect, numclust;
2841*0Sstevel@tonic-gate 	ushort_t wnumsect, s;
2842*0Sstevel@tonic-gate 	int doneread = 0;
2843*0Sstevel@tonic-gate 	int rstat;
2844*0Sstevel@tonic-gate 
2845*0Sstevel@tonic-gate 	/*
2846*0Sstevel@tonic-gate 	 * Compute number of clusters required to contain remaining bytes.
2847*0Sstevel@tonic-gate 	 */
2848*0Sstevel@tonic-gate 	numsect = idivceil(remaining, BPSEC);
2849*0Sstevel@tonic-gate 	numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
2850*0Sstevel@tonic-gate 
2851*0Sstevel@tonic-gate 	wnumsect = numclust * wbpb->bpb.sectors_per_cluster;
2852*0Sstevel@tonic-gate 	for (s = 0; s < wnumsect; s++) {
2853*0Sstevel@tonic-gate 		if (!doneread) {
2854*0Sstevel@tonic-gate 			if ((rstat = read(sfd, buf, BPSEC)) < 0) {
2855*0Sstevel@tonic-gate 				perror(efn);
2856*0Sstevel@tonic-gate 				doneread = 1;
2857*0Sstevel@tonic-gate 				rstat = 0;
2858*0Sstevel@tonic-gate 			} else if (rstat == 0) {
2859*0Sstevel@tonic-gate 				doneread = 1;
2860*0Sstevel@tonic-gate 			}
2861*0Sstevel@tonic-gate 			(void) memset(&(buf[rstat]), 0, BPSEC - rstat);
2862*0Sstevel@tonic-gate 		}
2863*0Sstevel@tonic-gate 		if (write(dfd, buf, BPSEC) != BPSEC) {
2864*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Copying "));
2865*0Sstevel@tonic-gate 			perror(efn);
2866*0Sstevel@tonic-gate 		}
2867*0Sstevel@tonic-gate 	}
2868*0Sstevel@tonic-gate }
2869*0Sstevel@tonic-gate 
2870*0Sstevel@tonic-gate static
2871*0Sstevel@tonic-gate void
2872*0Sstevel@tonic-gate write_fat32_bootstuff(int fd, boot_sector_t *bsp,
2873*0Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto)
2874*0Sstevel@tonic-gate {
2875*0Sstevel@tonic-gate 	uchar_t fsinfobuf[BPSEC];
2876*0Sstevel@tonic-gate 	uchar_t *fp;
2877*0Sstevel@tonic-gate 
2878*0Sstevel@tonic-gate 	/*
2879*0Sstevel@tonic-gate 	 * Construct the fsinfo buf
2880*0Sstevel@tonic-gate 	 */
2881*0Sstevel@tonic-gate 	(void) memset(fsinfobuf, 0, BPSEC);
2882*0Sstevel@tonic-gate 	/*
2883*0Sstevel@tonic-gate 	 * Not sure if this magic signature at the beginning of the
2884*0Sstevel@tonic-gate 	 * sector is necessary for us to create or not.  For now, I'm
2885*0Sstevel@tonic-gate 	 * going to assume it is, since I haven't seen any Windows FAT32s
2886*0Sstevel@tonic-gate 	 * without it.
2887*0Sstevel@tonic-gate 	 */
2888*0Sstevel@tonic-gate 	fsinfobuf[0] = 'R';
2889*0Sstevel@tonic-gate 	fsinfobuf[1] = 'R';
2890*0Sstevel@tonic-gate 	fsinfobuf[2] = 'a';
2891*0Sstevel@tonic-gate 	fsinfobuf[3] = 'A';
2892*0Sstevel@tonic-gate 	/*
2893*0Sstevel@tonic-gate 	 * We also appear to want the magic Boot sector signature at the
2894*0Sstevel@tonic-gate 	 * end of the sector.
2895*0Sstevel@tonic-gate 	 */
2896*0Sstevel@tonic-gate 	fsinfobuf[BPSEC - 2] = BOOTSECSIG & 0xFF;
2897*0Sstevel@tonic-gate 	fsinfobuf[BPSEC - 1] = (BOOTSECSIG >> 8) & 0xFF;
2898*0Sstevel@tonic-gate 
2899*0Sstevel@tonic-gate 	fp = &(fsinfobuf[FAT32_BOOT_FSINFO_OFF]);
2900*0Sstevel@tonic-gate 	fp += 4;	/* skip first reserved field */
2901*0Sstevel@tonic-gate 	store_32_bits(&fp, fsinfop->fs_signature);
2902*0Sstevel@tonic-gate 	store_32_bits(&fp, fsinfop->fs_free_clusters);
2903*0Sstevel@tonic-gate 	store_32_bits(&fp, fsinfop->fs_next_cluster);
2904*0Sstevel@tonic-gate 
2905*0Sstevel@tonic-gate 	if (Verbose) {
2906*0Sstevel@tonic-gate 		(void) printf(gettext("Dump of the fs info sector"));
2907*0Sstevel@tonic-gate 		header_for_dump();
2908*0Sstevel@tonic-gate 		dump_bytes(fsinfobuf, sizeof (fsinfobuf));
2909*0Sstevel@tonic-gate 	}
2910*0Sstevel@tonic-gate 
2911*0Sstevel@tonic-gate 	if (!Notreally) {
2912*0Sstevel@tonic-gate 		/*
2913*0Sstevel@tonic-gate 		 * FAT32's have an FS info sector, then a backup of the boot
2914*0Sstevel@tonic-gate 		 * sector, and a modified backup of the FS Info sector.
2915*0Sstevel@tonic-gate 		 */
2916*0Sstevel@tonic-gate 		if (write(fd, fsinfobuf, sizeof (fsinfobuf)) != BPSEC) {
2917*0Sstevel@tonic-gate 			perror(gettext("FS info sector write"));
2918*0Sstevel@tonic-gate 			exit(4);
2919*0Sstevel@tonic-gate 		}
2920*0Sstevel@tonic-gate 		if (lseek64(fd,	seekto + BKUP_BOOTSECT_OFFSET, SEEK_SET) < 0) {
2921*0Sstevel@tonic-gate 			(void) close(fd);
2922*0Sstevel@tonic-gate 			perror(gettext("Boot sector backup seek"));
2923*0Sstevel@tonic-gate 			exit(4);
2924*0Sstevel@tonic-gate 		}
2925*0Sstevel@tonic-gate 		if (write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) {
2926*0Sstevel@tonic-gate 			perror(gettext("Boot sector backup write"));
2927*0Sstevel@tonic-gate 			exit(4);
2928*0Sstevel@tonic-gate 		}
2929*0Sstevel@tonic-gate 	}
2930*0Sstevel@tonic-gate 
2931*0Sstevel@tonic-gate 	/*
2932*0Sstevel@tonic-gate 	 * Second copy of fs info sector is modified to have "don't know"
2933*0Sstevel@tonic-gate 	 * as the number of free clusters
2934*0Sstevel@tonic-gate 	 */
2935*0Sstevel@tonic-gate 	fp = &(fsinfobuf[FAT32_BOOT_FSINFO_OFF]);
2936*0Sstevel@tonic-gate 	fp += 8;	/* skip first reserved field and signature */
2937*0Sstevel@tonic-gate 	store_32_bits(&fp, -1);
2938*0Sstevel@tonic-gate 
2939*0Sstevel@tonic-gate 	if (Verbose) {
2940*0Sstevel@tonic-gate 		(void) printf(gettext("Dump of the backup fs info sector"));
2941*0Sstevel@tonic-gate 		header_for_dump();
2942*0Sstevel@tonic-gate 		dump_bytes(fsinfobuf, sizeof (fsinfobuf));
2943*0Sstevel@tonic-gate 	}
2944*0Sstevel@tonic-gate 
2945*0Sstevel@tonic-gate 	if (!Notreally) {
2946*0Sstevel@tonic-gate 		if (write(fd, fsinfobuf, sizeof (fsinfobuf)) != BPSEC) {
2947*0Sstevel@tonic-gate 			perror(gettext("FS info sector backup write"));
2948*0Sstevel@tonic-gate 			exit(4);
2949*0Sstevel@tonic-gate 		}
2950*0Sstevel@tonic-gate 	}
2951*0Sstevel@tonic-gate }
2952*0Sstevel@tonic-gate 
2953*0Sstevel@tonic-gate static
2954*0Sstevel@tonic-gate void
2955*0Sstevel@tonic-gate write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb,
2956*0Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto)
2957*0Sstevel@tonic-gate {
2958*0Sstevel@tonic-gate 	if (MakeFAT32) {
2959*0Sstevel@tonic-gate 		/* Copy our BPB into bootsec structure */
2960*0Sstevel@tonic-gate #ifdef i386
2961*0Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_front.bs_bpb), &(wbpb->bpb),
2962*0Sstevel@tonic-gate 			    sizeof (wbpb->bpb));
2963*0Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_bpb32), &(wbpb->bpb32),
2964*0Sstevel@tonic-gate 			    sizeof (wbpb->bpb32));
2965*0Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_ebpb), &(wbpb->ebpb),
2966*0Sstevel@tonic-gate 			    sizeof (wbpb->ebpb));
2967*0Sstevel@tonic-gate #else
2968*0Sstevel@tonic-gate 		swap_pack_bpb32cpy(&(bsp->bs32), wbpb);
2969*0Sstevel@tonic-gate #endif
2970*0Sstevel@tonic-gate 	} else {
2971*0Sstevel@tonic-gate 		/* Copy our BPB into bootsec structure */
2972*0Sstevel@tonic-gate #ifdef i386
2973*0Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs.bs_front.bs_bpb), &(wbpb->bpb),
2974*0Sstevel@tonic-gate 			    sizeof (wbpb->bpb));
2975*0Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs.bs_ebpb), &(wbpb->ebpb),
2976*0Sstevel@tonic-gate 			    sizeof (wbpb->ebpb));
2977*0Sstevel@tonic-gate #else
2978*0Sstevel@tonic-gate 		swap_pack_bpbcpy(&(bsp->bs), wbpb);
2979*0Sstevel@tonic-gate #endif
2980*0Sstevel@tonic-gate 
2981*0Sstevel@tonic-gate 		/* Copy SUN BPB extensions into bootsec structure */
2982*0Sstevel@tonic-gate 		if (SunBPBfields) {
2983*0Sstevel@tonic-gate #ifdef i386
2984*0Sstevel@tonic-gate 			(void) memcpy(&(bsp->bs.bs_sebpb), &(wbpb->sunbpb),
2985*0Sstevel@tonic-gate 				sizeof (wbpb->sunbpb));
2986*0Sstevel@tonic-gate #else
2987*0Sstevel@tonic-gate 			swap_pack_sebpbcpy(&(bsp->bs), wbpb);
2988*0Sstevel@tonic-gate #endif
2989*0Sstevel@tonic-gate 		}
2990*0Sstevel@tonic-gate 	}
2991*0Sstevel@tonic-gate 
2992*0Sstevel@tonic-gate 	/* Write boot sector */
2993*0Sstevel@tonic-gate 	if (!Notreally && write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) {
2994*0Sstevel@tonic-gate 		perror(gettext("Boot sector write"));
2995*0Sstevel@tonic-gate 		exit(4);
2996*0Sstevel@tonic-gate 	}
2997*0Sstevel@tonic-gate 
2998*0Sstevel@tonic-gate 	if (Verbose) {
2999*0Sstevel@tonic-gate 		(void) printf(gettext("Dump of the boot sector"));
3000*0Sstevel@tonic-gate 		header_for_dump();
3001*0Sstevel@tonic-gate 		dump_bytes(bsp->buf, sizeof (bsp->buf));
3002*0Sstevel@tonic-gate 	}
3003*0Sstevel@tonic-gate 
3004*0Sstevel@tonic-gate 	if (MakeFAT32)
3005*0Sstevel@tonic-gate 		write_fat32_bootstuff(fd, bsp, fsinfop, seekto);
3006*0Sstevel@tonic-gate }
3007*0Sstevel@tonic-gate 
3008*0Sstevel@tonic-gate static
3009*0Sstevel@tonic-gate void
3010*0Sstevel@tonic-gate write_fat(int fd, off64_t seekto, char *fn, char *lbl, char *ffn, bpb_t *wbpb)
3011*0Sstevel@tonic-gate {
3012*0Sstevel@tonic-gate 	struct fat32_boot_fsinfo fsinfo;
3013*0Sstevel@tonic-gate 	pc_cluster32_t ffsc;
3014*0Sstevel@tonic-gate 	boot_sector_t bootsect;
3015*0Sstevel@tonic-gate 	uchar_t *fatp, *rdirp;
3016*0Sstevel@tonic-gate 	ulong_t bootblksize, fatsize, rdirsize, ffsize;
3017*0Sstevel@tonic-gate 	int bsfd = -1;
3018*0Sstevel@tonic-gate 	int fffd = -1;
3019*0Sstevel@tonic-gate 
3020*0Sstevel@tonic-gate 	compute_file_area_size(wbpb);
3021*0Sstevel@tonic-gate 
3022*0Sstevel@tonic-gate 	bsfd = copy_bootblk(fn, &bootsect, &bootblksize);
3023*0Sstevel@tonic-gate 	label_volume(lbl, wbpb);
3024*0Sstevel@tonic-gate 
3025*0Sstevel@tonic-gate 	if (Verbose)
3026*0Sstevel@tonic-gate 		(void) printf(gettext("Building FAT.\n"));
3027*0Sstevel@tonic-gate 	fatp = build_fat(wbpb, &fsinfo, bootblksize, &fatsize,
3028*0Sstevel@tonic-gate 	    ffn, &fffd, &ffsize, &ffsc);
3029*0Sstevel@tonic-gate 
3030*0Sstevel@tonic-gate 	write_bootsects(fd, &bootsect, wbpb, &fsinfo, seekto);
3031*0Sstevel@tonic-gate 
3032*0Sstevel@tonic-gate 	if (lseek64(fd,
3033*0Sstevel@tonic-gate 	    seekto + (BPSEC * wbpb->bpb.resv_sectors), SEEK_SET) < 0) {
3034*0Sstevel@tonic-gate 		(void) close(fd);
3035*0Sstevel@tonic-gate 		perror(gettext("Seek to end of reserved sectors"));
3036*0Sstevel@tonic-gate 		exit(4);
3037*0Sstevel@tonic-gate 	}
3038*0Sstevel@tonic-gate 
3039*0Sstevel@tonic-gate 	/* Write FAT */
3040*0Sstevel@tonic-gate 	if (Verbose)
3041*0Sstevel@tonic-gate 		(void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"),
3042*0Sstevel@tonic-gate 		    fatsize, wbpb->bpb.num_fats);
3043*0Sstevel@tonic-gate 	if (!Notreally) {
3044*0Sstevel@tonic-gate 		int nf, wb;
3045*0Sstevel@tonic-gate 		for (nf = 0; nf < (int)wbpb->bpb.num_fats; nf++)
3046*0Sstevel@tonic-gate 			if ((wb = write(fd, fatp, fatsize)) != fatsize) {
3047*0Sstevel@tonic-gate 				perror(gettext("FAT write"));
3048*0Sstevel@tonic-gate 				exit(4);
3049*0Sstevel@tonic-gate 			} else {
3050*0Sstevel@tonic-gate 				if (Verbose)
3051*0Sstevel@tonic-gate 					(void) printf(
3052*0Sstevel@tonic-gate 					    gettext("Wrote %d bytes\n"), wb);
3053*0Sstevel@tonic-gate 			}
3054*0Sstevel@tonic-gate 	}
3055*0Sstevel@tonic-gate 	free(fatp);
3056*0Sstevel@tonic-gate 
3057*0Sstevel@tonic-gate 	if (Verbose)
3058*0Sstevel@tonic-gate 		(void) printf(gettext("Building root directory.\n"));
3059*0Sstevel@tonic-gate 	rdirp = build_rootdir(wbpb, ffn, fffd, ffsize, ffsc, &rdirsize);
3060*0Sstevel@tonic-gate 
3061*0Sstevel@tonic-gate 	/*
3062*0Sstevel@tonic-gate 	 *  In non FAT32, root directory exists outside of the file area
3063*0Sstevel@tonic-gate 	 */
3064*0Sstevel@tonic-gate 	if (!MakeFAT32) {
3065*0Sstevel@tonic-gate 		if (Verbose)
3066*0Sstevel@tonic-gate 		    (void) printf(
3067*0Sstevel@tonic-gate 			gettext("Writing root directory. "
3068*0Sstevel@tonic-gate 				"%d bytes.\n"), rdirsize);
3069*0Sstevel@tonic-gate 		if (!Notreally) {
3070*0Sstevel@tonic-gate 			if (write(fd, rdirp, rdirsize) != rdirsize) {
3071*0Sstevel@tonic-gate 				perror(gettext("Root directory write"));
3072*0Sstevel@tonic-gate 				exit(4);
3073*0Sstevel@tonic-gate 			}
3074*0Sstevel@tonic-gate 		}
3075*0Sstevel@tonic-gate 		free(rdirp);
3076*0Sstevel@tonic-gate 	}
3077*0Sstevel@tonic-gate 
3078*0Sstevel@tonic-gate 	/*
3079*0Sstevel@tonic-gate 	 * Now write anything that needs to be in the file space.
3080*0Sstevel@tonic-gate 	 */
3081*0Sstevel@tonic-gate 	if (bootblksize > BPSEC) {
3082*0Sstevel@tonic-gate 		if (Verbose)
3083*0Sstevel@tonic-gate 			(void) printf(gettext("Writing remainder of "
3084*0Sstevel@tonic-gate 				"boot block.\n"));
3085*0Sstevel@tonic-gate 		if (!Notreally)
3086*0Sstevel@tonic-gate 			write_rest(wbpb, fn, fd, bsfd, bootblksize - BPSEC);
3087*0Sstevel@tonic-gate 	}
3088*0Sstevel@tonic-gate 
3089*0Sstevel@tonic-gate 	if (MakeFAT32) {
3090*0Sstevel@tonic-gate 		if (Verbose)
3091*0Sstevel@tonic-gate 		    (void) printf(
3092*0Sstevel@tonic-gate 			gettext("Writing root directory. "
3093*0Sstevel@tonic-gate 				"%d bytes.\n"), rdirsize);
3094*0Sstevel@tonic-gate 		if (!Notreally) {
3095*0Sstevel@tonic-gate 			if (write(fd, rdirp, rdirsize) != rdirsize) {
3096*0Sstevel@tonic-gate 				perror(gettext("Root directory write"));
3097*0Sstevel@tonic-gate 				exit(4);
3098*0Sstevel@tonic-gate 			}
3099*0Sstevel@tonic-gate 		}
3100*0Sstevel@tonic-gate 		free(rdirp);
3101*0Sstevel@tonic-gate 	}
3102*0Sstevel@tonic-gate 
3103*0Sstevel@tonic-gate 	if (fffd >= 0) {
3104*0Sstevel@tonic-gate 		if (Verbose)
3105*0Sstevel@tonic-gate 			(void) printf(gettext("Writing first file.\n"));
3106*0Sstevel@tonic-gate 		if (!Notreally)
3107*0Sstevel@tonic-gate 			write_rest(wbpb, ffn, fd, fffd, ffsize);
3108*0Sstevel@tonic-gate 	}
3109*0Sstevel@tonic-gate }
3110*0Sstevel@tonic-gate 
3111*0Sstevel@tonic-gate static
3112*0Sstevel@tonic-gate char *LegalOpts[] = {
3113*0Sstevel@tonic-gate #define	NFLAG 0
3114*0Sstevel@tonic-gate 	"N",
3115*0Sstevel@tonic-gate #define	VFLAG 1
3116*0Sstevel@tonic-gate 	"v",
3117*0Sstevel@tonic-gate #define	RFLAG 2
3118*0Sstevel@tonic-gate 	"r",
3119*0Sstevel@tonic-gate #define	HFLAG 3
3120*0Sstevel@tonic-gate 	"h",
3121*0Sstevel@tonic-gate #define	SFLAG 4
3122*0Sstevel@tonic-gate 	"s",
3123*0Sstevel@tonic-gate #define	SUNFLAG 5
3124*0Sstevel@tonic-gate 	"S",
3125*0Sstevel@tonic-gate #define	LABFLAG 6
3126*0Sstevel@tonic-gate 	"b",
3127*0Sstevel@tonic-gate #define	BTRFLAG 7
3128*0Sstevel@tonic-gate 	"B",
3129*0Sstevel@tonic-gate #define	INITFLAG 8
3130*0Sstevel@tonic-gate 	"i",
3131*0Sstevel@tonic-gate #define	SZFLAG 9
3132*0Sstevel@tonic-gate 	"size",
3133*0Sstevel@tonic-gate #define	SECTFLAG 10
3134*0Sstevel@tonic-gate 	"nsect",
3135*0Sstevel@tonic-gate #define	TRKFLAG 11
3136*0Sstevel@tonic-gate 	"ntrack",
3137*0Sstevel@tonic-gate #define	SPCFLAG 12
3138*0Sstevel@tonic-gate 	"spc",
3139*0Sstevel@tonic-gate #define	BPFFLAG 13
3140*0Sstevel@tonic-gate 	"fat",
3141*0Sstevel@tonic-gate #define	FFLAG 14
3142*0Sstevel@tonic-gate 	"f",
3143*0Sstevel@tonic-gate #define	DFLAG 15
3144*0Sstevel@tonic-gate 	"d",
3145*0Sstevel@tonic-gate #define	NOFDISKFLAG 16
3146*0Sstevel@tonic-gate 	"nofdisk",
3147*0Sstevel@tonic-gate #define	RESRVFLAG 17
3148*0Sstevel@tonic-gate 	"reserve",
3149*0Sstevel@tonic-gate #define	HIDDENFLAG 18
3150*0Sstevel@tonic-gate 	"hidden",
3151*0Sstevel@tonic-gate 	NULL
3152*0Sstevel@tonic-gate };
3153*0Sstevel@tonic-gate 
3154*0Sstevel@tonic-gate static
3155*0Sstevel@tonic-gate void
3156*0Sstevel@tonic-gate bad_arg(char *option)
3157*0Sstevel@tonic-gate {
3158*0Sstevel@tonic-gate 	(void) fprintf(stderr,
3159*0Sstevel@tonic-gate 		gettext("Unrecognized option %s.\n"), option);
3160*0Sstevel@tonic-gate 	usage();
3161*0Sstevel@tonic-gate 	exit(2);
3162*0Sstevel@tonic-gate }
3163*0Sstevel@tonic-gate 
3164*0Sstevel@tonic-gate static
3165*0Sstevel@tonic-gate void
3166*0Sstevel@tonic-gate missing_arg(char *option)
3167*0Sstevel@tonic-gate {
3168*0Sstevel@tonic-gate 	(void) fprintf(stderr,
3169*0Sstevel@tonic-gate 		gettext("Option %s requires a value.\n"), option);
3170*0Sstevel@tonic-gate 	usage();
3171*0Sstevel@tonic-gate 	exit(3);
3172*0Sstevel@tonic-gate }
3173*0Sstevel@tonic-gate 
3174*0Sstevel@tonic-gate static
3175*0Sstevel@tonic-gate void
3176*0Sstevel@tonic-gate parse_suboptions(char *optsstr)
3177*0Sstevel@tonic-gate {
3178*0Sstevel@tonic-gate 	char *value;
3179*0Sstevel@tonic-gate 	int c;
3180*0Sstevel@tonic-gate 
3181*0Sstevel@tonic-gate 	while (*optsstr != '\0') {
3182*0Sstevel@tonic-gate 		switch (c = getsubopt(&optsstr, LegalOpts, &value)) {
3183*0Sstevel@tonic-gate 		case NFLAG:
3184*0Sstevel@tonic-gate 			Notreally++;
3185*0Sstevel@tonic-gate 			break;
3186*0Sstevel@tonic-gate 		case VFLAG:
3187*0Sstevel@tonic-gate 			Verbose++;
3188*0Sstevel@tonic-gate 			break;
3189*0Sstevel@tonic-gate 		case RFLAG:
3190*0Sstevel@tonic-gate 			Firstfileattr |= 0x01;
3191*0Sstevel@tonic-gate 			break;
3192*0Sstevel@tonic-gate 		case HFLAG:
3193*0Sstevel@tonic-gate 			Firstfileattr |= 0x02;
3194*0Sstevel@tonic-gate 			break;
3195*0Sstevel@tonic-gate 		case SFLAG:
3196*0Sstevel@tonic-gate 			Firstfileattr |= 0x04;
3197*0Sstevel@tonic-gate 			break;
3198*0Sstevel@tonic-gate 		case SUNFLAG:
3199*0Sstevel@tonic-gate 			SunBPBfields = 1;
3200*0Sstevel@tonic-gate 			break;
3201*0Sstevel@tonic-gate 		case LABFLAG:
3202*0Sstevel@tonic-gate 			if (value == NULL) {
3203*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3204*0Sstevel@tonic-gate 			} else {
3205*0Sstevel@tonic-gate 				Label = value;
3206*0Sstevel@tonic-gate 			}
3207*0Sstevel@tonic-gate 			break;
3208*0Sstevel@tonic-gate 		case BTRFLAG:
3209*0Sstevel@tonic-gate 			if (value == NULL) {
3210*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3211*0Sstevel@tonic-gate 			} else {
3212*0Sstevel@tonic-gate 				BootBlkFn = value;
3213*0Sstevel@tonic-gate 			}
3214*0Sstevel@tonic-gate 			break;
3215*0Sstevel@tonic-gate 		case INITFLAG:
3216*0Sstevel@tonic-gate 			if (value == NULL) {
3217*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3218*0Sstevel@tonic-gate 			} else {
3219*0Sstevel@tonic-gate 				FirstFn = value;
3220*0Sstevel@tonic-gate 			}
3221*0Sstevel@tonic-gate 			break;
3222*0Sstevel@tonic-gate 		case SZFLAG:
3223*0Sstevel@tonic-gate 			if (value == NULL) {
3224*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3225*0Sstevel@tonic-gate 			} else {
3226*0Sstevel@tonic-gate 				TotSize = atoi(value);
3227*0Sstevel@tonic-gate 				GetSize = 0;
3228*0Sstevel@tonic-gate 			}
3229*0Sstevel@tonic-gate 			break;
3230*0Sstevel@tonic-gate 		case SECTFLAG:
3231*0Sstevel@tonic-gate 			if (value == NULL) {
3232*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3233*0Sstevel@tonic-gate 			} else {
3234*0Sstevel@tonic-gate 				SecPerTrk = atoi(value);
3235*0Sstevel@tonic-gate 				GetSPT = 0;
3236*0Sstevel@tonic-gate 			}
3237*0Sstevel@tonic-gate 			break;
3238*0Sstevel@tonic-gate 		case TRKFLAG:
3239*0Sstevel@tonic-gate 			if (value == NULL) {
3240*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3241*0Sstevel@tonic-gate 			} else {
3242*0Sstevel@tonic-gate 				TrkPerCyl = atoi(value);
3243*0Sstevel@tonic-gate 				GetTPC = 0;
3244*0Sstevel@tonic-gate 			}
3245*0Sstevel@tonic-gate 			break;
3246*0Sstevel@tonic-gate 		case SPCFLAG:
3247*0Sstevel@tonic-gate 			if (value == NULL) {
3248*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3249*0Sstevel@tonic-gate 			} else {
3250*0Sstevel@tonic-gate 				SecPerClust = atoi(value);
3251*0Sstevel@tonic-gate 				GetSPC = 0;
3252*0Sstevel@tonic-gate 			}
3253*0Sstevel@tonic-gate 			break;
3254*0Sstevel@tonic-gate 		case BPFFLAG:
3255*0Sstevel@tonic-gate 			if (value == NULL) {
3256*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3257*0Sstevel@tonic-gate 			} else {
3258*0Sstevel@tonic-gate 				BitsPerFAT = atoi(value);
3259*0Sstevel@tonic-gate 				GetBPF = 0;
3260*0Sstevel@tonic-gate 			}
3261*0Sstevel@tonic-gate 			break;
3262*0Sstevel@tonic-gate 		case NOFDISKFLAG:
3263*0Sstevel@tonic-gate 			DontUseFdisk = 1;
3264*0Sstevel@tonic-gate 			break;
3265*0Sstevel@tonic-gate 		case RESRVFLAG:
3266*0Sstevel@tonic-gate 			if (value == NULL) {
3267*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3268*0Sstevel@tonic-gate 			} else {
3269*0Sstevel@tonic-gate 				Resrvd = atoi(value);
3270*0Sstevel@tonic-gate 				GetResrvd = 0;
3271*0Sstevel@tonic-gate 			}
3272*0Sstevel@tonic-gate 			break;
3273*0Sstevel@tonic-gate 		case HIDDENFLAG:
3274*0Sstevel@tonic-gate 			if (value == NULL) {
3275*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3276*0Sstevel@tonic-gate 			} else {
3277*0Sstevel@tonic-gate 				RelOffset = atoi(value);
3278*0Sstevel@tonic-gate 				GetOffset = 0;
3279*0Sstevel@tonic-gate 			}
3280*0Sstevel@tonic-gate 			break;
3281*0Sstevel@tonic-gate 		case FFLAG:
3282*0Sstevel@tonic-gate 			if (value == NULL) {
3283*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3284*0Sstevel@tonic-gate 			} else {
3285*0Sstevel@tonic-gate 				DiskName = value;
3286*0Sstevel@tonic-gate 				Outputtofile = 1;
3287*0Sstevel@tonic-gate 			}
3288*0Sstevel@tonic-gate 			break;
3289*0Sstevel@tonic-gate 		case DFLAG:
3290*0Sstevel@tonic-gate 			if (value == NULL) {
3291*0Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
3292*0Sstevel@tonic-gate 			} else {
3293*0Sstevel@tonic-gate 				Imagesize = atoi(value);
3294*0Sstevel@tonic-gate 			}
3295*0Sstevel@tonic-gate 			break;
3296*0Sstevel@tonic-gate 		default:
3297*0Sstevel@tonic-gate 			bad_arg(value);
3298*0Sstevel@tonic-gate 			break;
3299*0Sstevel@tonic-gate 		}
3300*0Sstevel@tonic-gate 	}
3301*0Sstevel@tonic-gate }
3302*0Sstevel@tonic-gate 
3303*0Sstevel@tonic-gate static
3304*0Sstevel@tonic-gate void
3305*0Sstevel@tonic-gate sanity_check_options(int argc, int optind)
3306*0Sstevel@tonic-gate {
3307*0Sstevel@tonic-gate 	if (GetFsParams) {
3308*0Sstevel@tonic-gate 		if (argc - optind != 1)
3309*0Sstevel@tonic-gate 			usage();
3310*0Sstevel@tonic-gate 		return;
3311*0Sstevel@tonic-gate 	}
3312*0Sstevel@tonic-gate 
3313*0Sstevel@tonic-gate 	if (DontUseFdisk && GetOffset) {
3314*0Sstevel@tonic-gate 		/* Set default relative offset of zero */
3315*0Sstevel@tonic-gate 		RelOffset = 0;
3316*0Sstevel@tonic-gate 	}
3317*0Sstevel@tonic-gate 
3318*0Sstevel@tonic-gate 	if (BitsPerFAT == 32)
3319*0Sstevel@tonic-gate 		MakeFAT32 = 1;
3320*0Sstevel@tonic-gate 
3321*0Sstevel@tonic-gate 	if (Outputtofile && (argc - optind)) {
3322*0Sstevel@tonic-gate 		usage();
3323*0Sstevel@tonic-gate 	} else if (Outputtofile && !DiskName) {
3324*0Sstevel@tonic-gate 		usage();
3325*0Sstevel@tonic-gate 	} else if (!Outputtofile && (argc - optind != 1)) {
3326*0Sstevel@tonic-gate 		usage();
3327*0Sstevel@tonic-gate 	} else if (SunBPBfields && !BootBlkFn) {
3328*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3329*0Sstevel@tonic-gate 		    gettext("Use of the 'S' option requires that\n"
3330*0Sstevel@tonic-gate 			    "the 'B=' option also be used.\n\n"));
3331*0Sstevel@tonic-gate 		usage();
3332*0Sstevel@tonic-gate 	} else if (Firstfileattr != 0x20 && !FirstFn) {
3333*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3334*0Sstevel@tonic-gate 		    gettext("Use of the 'r', 'h', or 's' options requires\n"
3335*0Sstevel@tonic-gate 			    "that the 'i=' option also be used.\n\n"));
3336*0Sstevel@tonic-gate 		usage();
3337*0Sstevel@tonic-gate 	} else if (!GetOffset && !DontUseFdisk) {
3338*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3339*0Sstevel@tonic-gate 		    gettext("Use of the 'hidden' option requires that\n"
3340*0Sstevel@tonic-gate 			    "the 'nofdisk' option also be used.\n\n"));
3341*0Sstevel@tonic-gate 		usage();
3342*0Sstevel@tonic-gate 	} else if (DontUseFdisk && GetSize) {
3343*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3344*0Sstevel@tonic-gate 		    gettext("Use of the 'nofdisk' option requires that\n"
3345*0Sstevel@tonic-gate 			    "the 'size=' option also be used.\n\n"));
3346*0Sstevel@tonic-gate 		usage();
3347*0Sstevel@tonic-gate 	} else if (!GetBPF &&
3348*0Sstevel@tonic-gate 		    BitsPerFAT != 12 && BitsPerFAT != 16 && BitsPerFAT != 32) {
3349*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3350*0Sstevel@tonic-gate 		    gettext("Invalid Bits/Fat value."
3351*0Sstevel@tonic-gate 			    "  Must be 12, 16 or 32.\n"));
3352*0Sstevel@tonic-gate 		exit(2);
3353*0Sstevel@tonic-gate 	} else if (!GetSPC && !powerofx_le_y(2, 128, SecPerClust)) {
3354*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3355*0Sstevel@tonic-gate 		    gettext("Invalid Sectors/Cluster value.  Must be a "
3356*0Sstevel@tonic-gate 			    "power of 2 between 1 and 128.\n"));
3357*0Sstevel@tonic-gate 		exit(2);
3358*0Sstevel@tonic-gate 	} else if (!GetResrvd && (Resrvd < 1 || Resrvd > 0xffff)) {
3359*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3360*0Sstevel@tonic-gate 		    gettext("Invalid number of reserved sectors.  "
3361*0Sstevel@tonic-gate 			"Must be at least 1 but\nno larger than 65535."));
3362*0Sstevel@tonic-gate 		exit(2);
3363*0Sstevel@tonic-gate 	} else if (!GetResrvd && MakeFAT32 &&
3364*0Sstevel@tonic-gate 		    (Resrvd < 32 || Resrvd > 0xffff)) {
3365*0Sstevel@tonic-gate 		(void) fprintf(stderr,
3366*0Sstevel@tonic-gate 		    gettext("Invalid number of reserved sectors.  "
3367*0Sstevel@tonic-gate 			"Must be at least 32 but\nno larger than 65535."));
3368*0Sstevel@tonic-gate 		exit(2);
3369*0Sstevel@tonic-gate 	} else if (Imagesize != 3 && Imagesize != 5) {
3370*0Sstevel@tonic-gate 		usage();
3371*0Sstevel@tonic-gate 	}
3372*0Sstevel@tonic-gate }
3373*0Sstevel@tonic-gate 
3374*0Sstevel@tonic-gate void
3375*0Sstevel@tonic-gate main(int argc, char **argv)
3376*0Sstevel@tonic-gate {
3377*0Sstevel@tonic-gate 	off64_t AbsBootSect = 0;
3378*0Sstevel@tonic-gate 	bpb_t dskparamblk;
3379*0Sstevel@tonic-gate 	char *string;
3380*0Sstevel@tonic-gate 	int  fd;
3381*0Sstevel@tonic-gate 	int  c;
3382*0Sstevel@tonic-gate 
3383*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
3384*0Sstevel@tonic-gate 
3385*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
3386*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
3387*0Sstevel@tonic-gate #endif
3388*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3389*0Sstevel@tonic-gate 
3390*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) {
3391*0Sstevel@tonic-gate 		switch (c) {
3392*0Sstevel@tonic-gate 		case 'F':
3393*0Sstevel@tonic-gate 			string = optarg;
3394*0Sstevel@tonic-gate 			if (strcmp(string, "pcfs") != 0)
3395*0Sstevel@tonic-gate 				usage();
3396*0Sstevel@tonic-gate 			break;
3397*0Sstevel@tonic-gate 		case 'V':
3398*0Sstevel@tonic-gate 			{
3399*0Sstevel@tonic-gate 				char	*opt_text;
3400*0Sstevel@tonic-gate 				int	opt_count;
3401*0Sstevel@tonic-gate 
3402*0Sstevel@tonic-gate 				(void) fprintf(stdout,
3403*0Sstevel@tonic-gate 				    gettext("mkfs -F pcfs "));
3404*0Sstevel@tonic-gate 				for (opt_count = 1; opt_count < argc;
3405*0Sstevel@tonic-gate 								opt_count++) {
3406*0Sstevel@tonic-gate 					opt_text = argv[opt_count];
3407*0Sstevel@tonic-gate 					if (opt_text)
3408*0Sstevel@tonic-gate 					    (void) fprintf(stdout, " %s ",
3409*0Sstevel@tonic-gate 								opt_text);
3410*0Sstevel@tonic-gate 				}
3411*0Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
3412*0Sstevel@tonic-gate 			}
3413*0Sstevel@tonic-gate 			break;
3414*0Sstevel@tonic-gate 		case 'm':
3415*0Sstevel@tonic-gate 			GetFsParams++;
3416*0Sstevel@tonic-gate 			break;
3417*0Sstevel@tonic-gate 		case 'o':
3418*0Sstevel@tonic-gate 			string = optarg;
3419*0Sstevel@tonic-gate 			parse_suboptions(string);
3420*0Sstevel@tonic-gate 			break;
3421*0Sstevel@tonic-gate 		}
3422*0Sstevel@tonic-gate 	}
3423*0Sstevel@tonic-gate 
3424*0Sstevel@tonic-gate 	sanity_check_options(argc, optind);
3425*0Sstevel@tonic-gate 
3426*0Sstevel@tonic-gate 	if (!Outputtofile)
3427*0Sstevel@tonic-gate 		DiskName = argv[optind];
3428*0Sstevel@tonic-gate 
3429*0Sstevel@tonic-gate 	(void) memset(&dskparamblk, 0, sizeof (dskparamblk));
3430*0Sstevel@tonic-gate 
3431*0Sstevel@tonic-gate 	if (GetFsParams) {
3432*0Sstevel@tonic-gate 		fd = open_and_examine(DiskName, &dskparamblk);
3433*0Sstevel@tonic-gate 	} else {
3434*0Sstevel@tonic-gate 		fd = open_and_seek(DiskName, &dskparamblk, &AbsBootSect);
3435*0Sstevel@tonic-gate 		if (ask_nicely(DiskName))
3436*0Sstevel@tonic-gate 			write_fat(fd, AbsBootSect, BootBlkFn, Label,
3437*0Sstevel@tonic-gate 			    FirstFn, &dskparamblk);
3438*0Sstevel@tonic-gate 	}
3439*0Sstevel@tonic-gate 	(void) close(fd);
3440*0Sstevel@tonic-gate 	exit(0);
3441*0Sstevel@tonic-gate }
3442