xref: /onnv-gate/usr/src/cmd/fs.d/pcfs/mkfs/mkfs.c (revision 452:bdf9a95e8caa)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*452Sjkennedy  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*452Sjkennedy  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <ctype.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <errno.h>
360Sstevel@tonic-gate #include <fcntl.h>
370Sstevel@tonic-gate #include <libintl.h>
380Sstevel@tonic-gate #include <locale.h>
390Sstevel@tonic-gate #include <sys/fdio.h>
400Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
410Sstevel@tonic-gate #include <sys/dkio.h>
420Sstevel@tonic-gate #include <sys/sysmacros.h>
430Sstevel@tonic-gate #include "mkfs_pcfs.h"
440Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
450Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
460Sstevel@tonic-gate #include <sys/fs/pc_label.h>
470Sstevel@tonic-gate #include <macros.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  *	mkfs (for pcfs)
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  *	Install a boot block, FAT, and (if desired) the first resident
530Sstevel@tonic-gate  *	of the new fs.
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  *	XXX -- floppy opens need O_NDELAY?
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate #define	DEFAULT_LABEL "NONAME"
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static char	*BootBlkFn = NULL;
600Sstevel@tonic-gate static char	*DiskName = NULL;
610Sstevel@tonic-gate static char	*FirstFn = NULL;
620Sstevel@tonic-gate static char	*Label = NULL;
630Sstevel@tonic-gate static char	Firstfileattr = 0x20;
640Sstevel@tonic-gate static int	Outputtofile = 0;
650Sstevel@tonic-gate static int	SunBPBfields = 0;
660Sstevel@tonic-gate static int	GetFsParams = 0;
670Sstevel@tonic-gate static int	Fatentsize = 0;
680Sstevel@tonic-gate static int	Imagesize = 3;
690Sstevel@tonic-gate static int	Notreally = 0;
700Sstevel@tonic-gate static int	Verbose = 0;
710Sstevel@tonic-gate static int	MakeFAT32 = 0;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * If there is an FDISK entry for the device where we're about to
750Sstevel@tonic-gate  * make the file system, we ought to make a file system that has the
760Sstevel@tonic-gate  * same size FAT as the FDISK table claims.  We track the size FDISK
770Sstevel@tonic-gate  * thinks in this variable.
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate static int	FdiskFATsize = 0;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static int	GetSize = 1;	/* Unless we're given as arg, must look it up */
820Sstevel@tonic-gate static ulong_t	TotSize;	/* Total size of FS in # of sectors */
830Sstevel@tonic-gate static int	GetSPC = 1;	/* Unless we're given as arg, must calculate */
840Sstevel@tonic-gate static ulong_t	SecPerClust;	/* # of sectors per cluster */
850Sstevel@tonic-gate static int	GetOffset = 1;	/* Unless we're given as arg, must look it up */
860Sstevel@tonic-gate static ulong_t	RelOffset;	/* Relative start sector (hidden sectors) */
870Sstevel@tonic-gate static int	GetSPT = 1;	/* Unless we're given as arg, must look it up */
880Sstevel@tonic-gate static ushort_t	SecPerTrk;	/* # of sectors per track */
890Sstevel@tonic-gate static int	GetTPC = 1;	/* Unless we're given as arg, must look it up */
900Sstevel@tonic-gate static ushort_t	TrkPerCyl;	/* # of tracks per cylinder */
910Sstevel@tonic-gate static int	GetResrvd = 1;	/* Unless we're given as arg, must calculate */
92*452Sjkennedy static int	Resrvd;		/* Number of reserved sectors */
930Sstevel@tonic-gate static int	GetBPF = 1;	/* Unless we're given as arg, must calculate */
940Sstevel@tonic-gate static int	BitsPerFAT;	/* Total size of FS in # of sectors */
950Sstevel@tonic-gate 
960Sstevel@tonic-gate static ulong_t	TotalClusters;	/* Computed total number of clusters */
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * Unless we are told otherwise, we should use fdisk table for non-diskettes.
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate static int	DontUseFdisk = 0;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate  * Function prototypes
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate #ifndef i386
1070Sstevel@tonic-gate static void swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp);
1080Sstevel@tonic-gate static void swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb);
1090Sstevel@tonic-gate static void swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb);
1100Sstevel@tonic-gate static void swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp);
1110Sstevel@tonic-gate static void swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb);
1120Sstevel@tonic-gate #endif
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate static uchar_t *build_rootdir(bpb_t *wbpb, char *ffn, int fffd,
1150Sstevel@tonic-gate 	ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize);
1160Sstevel@tonic-gate static uchar_t *build_fat(bpb_t *wbpb, struct fat32_boot_fsinfo *fsinfop,
1170Sstevel@tonic-gate 	ulong_t bootblksize, ulong_t *fatsize, char *ffn, int *fffd,
1180Sstevel@tonic-gate 	ulong_t *ffsize, pc_cluster32_t *ffstartclust);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static char *stat_actual_disk(char *diskname, struct stat *info, char **suffix);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static void compare_existing_with_computed(int fd, char *suffix,
1230Sstevel@tonic-gate 	bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect,
1240Sstevel@tonic-gate 	int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd,
1250Sstevel@tonic-gate 	int *dashos);
1260Sstevel@tonic-gate static void print_reproducing_command(int fd, char *actualdisk, char *suffix,
1270Sstevel@tonic-gate 	bpb_t *wbpb);
1280Sstevel@tonic-gate static void compute_file_area_size(bpb_t *wbpb);
1290Sstevel@tonic-gate static void write_fat32_bootstuff(int fd, boot_sector_t *bsp,
1300Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto);
1310Sstevel@tonic-gate static void sanity_check_options(int argc, int optind);
1320Sstevel@tonic-gate static void compute_cluster_size(bpb_t *wbpb);
1330Sstevel@tonic-gate static void find_fixed_details(int fd, bpb_t *wbpb);
1340Sstevel@tonic-gate static void dirent_fname_fill(struct pcdir *dep, char *fn);
1350Sstevel@tonic-gate static void floppy_bpb_fillin(bpb_t *wbpb,
1360Sstevel@tonic-gate 	int diam, int hds, int spt);
1370Sstevel@tonic-gate static void read_existing_bpb(int fd, bpb_t *wbpb);
1380Sstevel@tonic-gate static void warn_funky_fatsize(void);
1390Sstevel@tonic-gate static void warn_funky_floppy(void);
1400Sstevel@tonic-gate static void dirent_time_fill(struct pcdir *dep);
1410Sstevel@tonic-gate static void parse_suboptions(char *optsstr);
1420Sstevel@tonic-gate static void header_for_dump(void);
1430Sstevel@tonic-gate static void write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb,
1440Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto);
1450Sstevel@tonic-gate static void fill_bpb_sizes(bpb_t *wbpb, struct ipart part[],
1460Sstevel@tonic-gate 	int partno, off64_t offset);
1470Sstevel@tonic-gate static void set_fat_string(bpb_t *wbpb, int fatsize);
1480Sstevel@tonic-gate static void partn_lecture(char *dn);
1490Sstevel@tonic-gate static void store_16_bits(uchar_t **bp, uint32_t v);
1500Sstevel@tonic-gate static void store_32_bits(uchar_t **bp, uint32_t v);
1510Sstevel@tonic-gate static void lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb);
1520Sstevel@tonic-gate static void label_volume(char *lbl, bpb_t *wbpb);
1530Sstevel@tonic-gate static void mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum,
1540Sstevel@tonic-gate 	uint32_t value);
1550Sstevel@tonic-gate static void missing_arg(char *option);
1560Sstevel@tonic-gate static void dashm_bail(int fd);
1570Sstevel@tonic-gate static void dump_bytes(uchar_t *, int);
1580Sstevel@tonic-gate static void write_rest(bpb_t *wbpb, char *efn,
1590Sstevel@tonic-gate 	int dfd, int sfd, int remaining);
1600Sstevel@tonic-gate static void write_fat(int fd, off64_t seekto, char *fn, char *lbl,
1610Sstevel@tonic-gate 	char *ffn, bpb_t *wbpb);
1620Sstevel@tonic-gate static void bad_arg(char *option);
1630Sstevel@tonic-gate static void usage(void);
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate static int prepare_image_file(char *fn, bpb_t *wbpb);
1660Sstevel@tonic-gate static int verify_bootblkfile(char *fn, boot_sector_t *bs,
1670Sstevel@tonic-gate 	ulong_t *blkfilesize);
1680Sstevel@tonic-gate static int open_and_examine(char *dn, bpb_t *wbpb);
1690Sstevel@tonic-gate static int verify_firstfile(char *fn, ulong_t *filesize);
1700Sstevel@tonic-gate static int lookup_FAT_size(uchar_t partid);
1710Sstevel@tonic-gate static int powerofx_le_y(int x, int y, int value);
1720Sstevel@tonic-gate static int open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto);
1730Sstevel@tonic-gate static int warn_mismatch(char *desc, char *src, int expect, int assigned);
1740Sstevel@tonic-gate static int copy_bootblk(char *fn, boot_sector_t *bootsect,
1750Sstevel@tonic-gate 	ulong_t *bootblksize);
1760Sstevel@tonic-gate static int parse_drvnum(char *pn);
1770Sstevel@tonic-gate static int seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto);
1780Sstevel@tonic-gate static int ask_nicely(char *special);
1790Sstevel@tonic-gate static int seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto);
1800Sstevel@tonic-gate static int yes(void);
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate  *  usage
1840Sstevel@tonic-gate  *
1850Sstevel@tonic-gate  *	Display usage message and exit.
1860Sstevel@tonic-gate  */
1870Sstevel@tonic-gate static
1880Sstevel@tonic-gate void
1890Sstevel@tonic-gate usage(void)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate 	(void) fprintf(stderr,
1920Sstevel@tonic-gate 	    gettext("pcfs usage: mkfs [-F FSType] [-V] [-m] "
1930Sstevel@tonic-gate 		"[-o specific_options] special\n"));
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	(void) fprintf(stderr,
1960Sstevel@tonic-gate 	    gettext(" -V: print this command line and return\n"
1970Sstevel@tonic-gate 		" -m: dump command line used to create a FAT on this media\n"
1980Sstevel@tonic-gate 		"\t(other options are ignored if this option is chosen).\n"
1990Sstevel@tonic-gate 		" -o: pcfs_specific_options:\n"
2000Sstevel@tonic-gate 		"\t'pcfs_specific_options' is a comma separated list\n"
2010Sstevel@tonic-gate 		"\tincluding one or more of the following options:\n"
2020Sstevel@tonic-gate 		"\t    N,v,r,h,s,b=label,B=filename,i=filename,\n"
2030Sstevel@tonic-gate 		"\t    spc=n,fat=n,nsect=n,ntrack=n,nofdisk,size=n,\n"
2040Sstevel@tonic-gate 		"\t    reserve=n,hidden=n\n\n"));
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	(void) fprintf(stderr,
2070Sstevel@tonic-gate 	    gettext("'Special' should specify a raw diskette "
2080Sstevel@tonic-gate 			"or raw fixed disk device.  \"Fixed\"\n"
2090Sstevel@tonic-gate 			"disks (which include high-capacity removable "
2100Sstevel@tonic-gate 			"media such as Zip disks)\n"
2110Sstevel@tonic-gate 			"may be further qualified with a logical "
2120Sstevel@tonic-gate 			"drive specifier.\n"
2130Sstevel@tonic-gate 			"Examples are: /dev/rdiskette and "
2140Sstevel@tonic-gate 			"/dev/rdsk/c0t0d0p0:c\n"));
2150Sstevel@tonic-gate 	exit(1);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate static
2190Sstevel@tonic-gate int
2200Sstevel@tonic-gate yes(void)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	char *affirmative = gettext("yY");
2230Sstevel@tonic-gate 	char *a = affirmative;
2240Sstevel@tonic-gate 	int b;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	b = getchar();
2270Sstevel@tonic-gate 	while (b == '\n' && b != '\0' && b != EOF)
2280Sstevel@tonic-gate 		b = getchar();
2290Sstevel@tonic-gate 	while (*a) {
2300Sstevel@tonic-gate 		if (b == (int)*a)
2310Sstevel@tonic-gate 			break;
2320Sstevel@tonic-gate 		a++;
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 	return (*a);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  * powerofx_le_y
2390Sstevel@tonic-gate  *	args of x,y, and value to be checked
2400Sstevel@tonic-gate  *	returns 1 if x**n == value and n >= 0 and value <= y
2410Sstevel@tonic-gate  *	returns 0 otherwise
2420Sstevel@tonic-gate  */
2430Sstevel@tonic-gate static
2440Sstevel@tonic-gate int
2450Sstevel@tonic-gate powerofx_le_y(int x, int y, int value)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	int ispower = 0;
2480Sstevel@tonic-gate 	int pow = 1;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	if (value < 1 || value > y)
2510Sstevel@tonic-gate 		return (ispower);
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	do {
2540Sstevel@tonic-gate 		if (pow == value) {
2550Sstevel@tonic-gate 			ispower = 1;
2560Sstevel@tonic-gate 			break;
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 		pow *= x;
2590Sstevel@tonic-gate 	} while (pow <= y);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	return (ispower);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate static
2650Sstevel@tonic-gate int
2660Sstevel@tonic-gate ask_nicely(char *special)
2670Sstevel@tonic-gate {
2680Sstevel@tonic-gate 	/*
2690Sstevel@tonic-gate 	 * 4228473 - No way to non-interactively make a pcfs filesystem
2700Sstevel@tonic-gate 	 *
2710Sstevel@tonic-gate 	 *	If we don't have an input TTY, or we aren't really doing
2720Sstevel@tonic-gate 	 *	anything, then don't ask questions.  Assume a yes answer
2730Sstevel@tonic-gate 	 *	to any questions we would ask.
2740Sstevel@tonic-gate 	 */
2750Sstevel@tonic-gate 	if (Notreally || !isatty(fileno(stdin)))
2760Sstevel@tonic-gate 		return (1);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	(void) printf(
2790Sstevel@tonic-gate 	    gettext("Construct a new FAT file system on %s: (y/n)? "), special);
2800Sstevel@tonic-gate 	(void) fflush(stdout);
2810Sstevel@tonic-gate 	return (yes());
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate  * store_16_bits
2860Sstevel@tonic-gate  *	Save the lower 16 bits of a 32 bit value (v) into the provided
2870Sstevel@tonic-gate  *	buffer (pointed at by *bp), and increment the buffer pointer
2880Sstevel@tonic-gate  *	as well.  This way the routine can be called multiple times in
2890Sstevel@tonic-gate  *	succession to fill buffers.  The value is stored in little-endian
2900Sstevel@tonic-gate  *	order.
2910Sstevel@tonic-gate  */
2920Sstevel@tonic-gate static
2930Sstevel@tonic-gate void
2940Sstevel@tonic-gate store_16_bits(uchar_t **bp, uint32_t v)
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate 	uchar_t *l = *bp;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	*l++ = v & 0xff;
2990Sstevel@tonic-gate 	*l = (v >> 8) & 0xff;
3000Sstevel@tonic-gate 	*bp += 2;
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate /*
3040Sstevel@tonic-gate  * store_32_bits
3050Sstevel@tonic-gate  * 	Save the 32 bit value (v) into the provided buffer (pointed
3060Sstevel@tonic-gate  *	at by *bp), and increment the buffer pointer as well.  This way
3070Sstevel@tonic-gate  *	the routine can be called multiple times in succession to fill
3080Sstevel@tonic-gate  *	buffers.  The value is stored in little-endian order.
3090Sstevel@tonic-gate  */
3100Sstevel@tonic-gate static
3110Sstevel@tonic-gate void
3120Sstevel@tonic-gate store_32_bits(uchar_t **bp, uint32_t v)
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate 	uchar_t *l = *bp;
3150Sstevel@tonic-gate 	int b;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	for (b = 0; b < 4; b++) {
3180Sstevel@tonic-gate 		*l++ = v & 0xff;
3190Sstevel@tonic-gate 		v = v >> 8;
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 	*bp += 4;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate  *  dump_bytes  -- display bytes as hex numbers.
3260Sstevel@tonic-gate  *		   b is the pointer to the byte buffer
3270Sstevel@tonic-gate  *		   n is the number of bytes in the buffer
3280Sstevel@tonic-gate  */
3290Sstevel@tonic-gate /* Note: BPL = bytes to display per line */
3300Sstevel@tonic-gate #define	BPL 16
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate static
3330Sstevel@tonic-gate void
3340Sstevel@tonic-gate dump_bytes(uchar_t *b, int n)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	int cd = n;
3370Sstevel@tonic-gate 	int cu = 0;
3380Sstevel@tonic-gate 	int o = 0;
3390Sstevel@tonic-gate 	int bl;
3400Sstevel@tonic-gate 	int ac;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	/* Display offset, 16 bytes per line, and printable ascii version */
3430Sstevel@tonic-gate 	while (cd > 0) {
3440Sstevel@tonic-gate 		ac = 0;
3450Sstevel@tonic-gate 		(void) printf("\n%06x: ", o);
3460Sstevel@tonic-gate 		for (bl = 0; bl < BPL; bl++) {
3470Sstevel@tonic-gate 			if (cu+bl < n) {
3480Sstevel@tonic-gate 				(void) printf("%02x ", (b[cu+bl] & 0xff));
3490Sstevel@tonic-gate 				ac++;
3500Sstevel@tonic-gate 			}
3510Sstevel@tonic-gate 			else
3520Sstevel@tonic-gate 				(void) printf("   ");
3530Sstevel@tonic-gate 		}
3540Sstevel@tonic-gate 		for (bl = 0; bl < BPL; bl++) {
3550Sstevel@tonic-gate 			if ((cu+bl < n) &&
3560Sstevel@tonic-gate 				((b[cu+bl] >= ' ') && (b[cu+bl] <= '~')))
3570Sstevel@tonic-gate 					(void) printf("%c", b[cu+bl]);
3580Sstevel@tonic-gate 			else
3590Sstevel@tonic-gate 				(void) printf(".");
3600Sstevel@tonic-gate 		}
3610Sstevel@tonic-gate 		cu += ac; o += ac; cd -= ac;
3620Sstevel@tonic-gate 	}
3630Sstevel@tonic-gate 	(void) printf("\n\n");
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate /*
3670Sstevel@tonic-gate  *  header_for_dump  --  display simple header over what will be output.
3680Sstevel@tonic-gate  */
3690Sstevel@tonic-gate static
3700Sstevel@tonic-gate void
3710Sstevel@tonic-gate header_for_dump(void)
3720Sstevel@tonic-gate {
3730Sstevel@tonic-gate 	int bl;
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	(void) printf("\n        ");
3760Sstevel@tonic-gate 	for (bl = 0; bl < BPL; bl++)
3770Sstevel@tonic-gate 		(void) printf("%02x ", bl);
3780Sstevel@tonic-gate 	(void) printf("\n       ");
3790Sstevel@tonic-gate 	bl = 3*BPL;
3800Sstevel@tonic-gate 	while (bl-- > 0)
3810Sstevel@tonic-gate 		(void) printf("-");
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate  *  parse_drvnum
3860Sstevel@tonic-gate  *	Convert a partition name into a drive number.
3870Sstevel@tonic-gate  */
3880Sstevel@tonic-gate static
3890Sstevel@tonic-gate int
3900Sstevel@tonic-gate parse_drvnum(char *pn)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	int drvnum;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	/*
3950Sstevel@tonic-gate 	 * Determine logical drive to seek after.
3960Sstevel@tonic-gate 	 */
3970Sstevel@tonic-gate 	if (strlen(pn) == 1 && *pn >= 'c' && *pn <= 'z') {
3980Sstevel@tonic-gate 		drvnum = *pn - 'c' + 1;
3990Sstevel@tonic-gate 	} else if (*pn >= '0' && *pn <= '9') {
4000Sstevel@tonic-gate 		char *d;
4010Sstevel@tonic-gate 		int v, m, c;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		v = 0;
4040Sstevel@tonic-gate 		d = pn;
4050Sstevel@tonic-gate 		while (*d && *d >= '0' && *d <= '9') {
4060Sstevel@tonic-gate 			c = strlen(d);
4070Sstevel@tonic-gate 			m = 1;
4080Sstevel@tonic-gate 			while (--c)
4090Sstevel@tonic-gate 				m *= 10;
4100Sstevel@tonic-gate 			v += m * (*d - '0');
4110Sstevel@tonic-gate 			d++;
4120Sstevel@tonic-gate 		}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 		if (*d || v > 24) {
4150Sstevel@tonic-gate 			(void) fprintf(stderr,
4160Sstevel@tonic-gate 			    gettext("%s: bogus logical drive specification.\n"),
4170Sstevel@tonic-gate 			    pn);
4180Sstevel@tonic-gate 			return (-1);
4190Sstevel@tonic-gate 		}
4200Sstevel@tonic-gate 		drvnum = v;
4210Sstevel@tonic-gate 	} else if (strcmp(pn, "boot") == 0) {
4220Sstevel@tonic-gate 		drvnum = 99;
4230Sstevel@tonic-gate 	} else {
4240Sstevel@tonic-gate 		(void) fprintf(stderr,
4250Sstevel@tonic-gate 		    gettext("%s: bogus logical drive specification.\n"), pn);
4260Sstevel@tonic-gate 		return (-1);
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	return (drvnum);
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate /*
4330Sstevel@tonic-gate  *  Define some special logical drives we use.
4340Sstevel@tonic-gate  */
4350Sstevel@tonic-gate #define	BOOT_PARTITION_DRIVE	99
4360Sstevel@tonic-gate #define	PRIMARY_DOS_DRIVE	1
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate /*
4390Sstevel@tonic-gate  * isDosDrive()
4400Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
4410Sstevel@tonic-gate  *	and it decides if that's a systid that describes a DOS drive.  We
4420Sstevel@tonic-gate  *	use systid values defined in sys/dktp/fdisk.h.
4430Sstevel@tonic-gate  */
4440Sstevel@tonic-gate static int
4450Sstevel@tonic-gate isDosDrive(uchar_t checkMe)
4460Sstevel@tonic-gate {
4470Sstevel@tonic-gate 	return ((checkMe == DOSOS12) || (checkMe == DOSOS16) ||
4480Sstevel@tonic-gate 	    (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) ||
4490Sstevel@tonic-gate 	    (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) ||
4500Sstevel@tonic-gate 	    (checkMe == DIAGPART));
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate /*
4540Sstevel@tonic-gate  * isDosExtended()
4550Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
4560Sstevel@tonic-gate  *	and it decides if that's a systid that describes an extended DOS
4570Sstevel@tonic-gate  *	partition.
4580Sstevel@tonic-gate  */
4590Sstevel@tonic-gate static int
4600Sstevel@tonic-gate isDosExtended(uchar_t checkMe)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate 	return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA));
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate /*
4660Sstevel@tonic-gate  * isBootPart()
4670Sstevel@tonic-gate  *	Boolean function.  Give it the systid field for an fdisk partition
4680Sstevel@tonic-gate  *	and it decides if that's a systid that describes a Solaris boot
4690Sstevel@tonic-gate  *	partition.
4700Sstevel@tonic-gate  */
4710Sstevel@tonic-gate static int
4720Sstevel@tonic-gate isBootPart(uchar_t checkMe)
4730Sstevel@tonic-gate {
4740Sstevel@tonic-gate 	return (checkMe == X86BOOT);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate static
4780Sstevel@tonic-gate int
4790Sstevel@tonic-gate warn_mismatch(char *desc, char *src, int expect, int assigned)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	if (expect == assigned)
4820Sstevel@tonic-gate 		return (assigned);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * 4228473 - No way to non-interactively make a pcfs filesystem
4860Sstevel@tonic-gate 	 *
4870Sstevel@tonic-gate 	 *	If we don't have an input TTY, or we aren't really doing
4880Sstevel@tonic-gate 	 *	anything, then don't ask questions.  Assume a yes answer
4890Sstevel@tonic-gate 	 *	to any questions we would ask.
4900Sstevel@tonic-gate 	 */
4910Sstevel@tonic-gate 	if (Notreally || !isatty(fileno(stdin))) {
4920Sstevel@tonic-gate 		(void) printf(gettext("WARNING: User supplied %s is %d,"
4930Sstevel@tonic-gate 			"\nbut value obtained from the %s is %d.\n"
4940Sstevel@tonic-gate 			"Using user supplied value.\n"),
4950Sstevel@tonic-gate 			desc, assigned, src, expect);
4960Sstevel@tonic-gate 		return (assigned);
4970Sstevel@tonic-gate 	}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	(void) printf(gettext("User supplied %s is %d."
5000Sstevel@tonic-gate 		"\nThe value obtained from the %s is %d.\n"),
5010Sstevel@tonic-gate 		desc, assigned, src, expect);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	(void) printf(
5040Sstevel@tonic-gate 	    gettext("Continue with value given on command line (y/n)? "));
5050Sstevel@tonic-gate 	(void) fflush(stdout);
5060Sstevel@tonic-gate 	if (yes())
5070Sstevel@tonic-gate 		return (assigned);
5080Sstevel@tonic-gate 	else
5090Sstevel@tonic-gate 		exit(2);
5100Sstevel@tonic-gate 	/*NOTREACHED*/
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate static
5140Sstevel@tonic-gate void
5150Sstevel@tonic-gate fill_fat32_bpb(bpb_t *wbpb)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate 	/*
5180Sstevel@tonic-gate 	 * ExtFlags means (according to MSDN BPB (FAT32) document)
5190Sstevel@tonic-gate 	 *
5200Sstevel@tonic-gate 	 * Bit 8 indicates info written to the active FAT is written
5210Sstevel@tonic-gate 	 * to all copies of the FAT.  (I think they mean bit 7, with
5220Sstevel@tonic-gate 	 * numbering starting at 0)
5230Sstevel@tonic-gate 	 *
5240Sstevel@tonic-gate 	 * Lowest 4 bits of field are the 0 based FAT number of the
5250Sstevel@tonic-gate 	 * Active FAT.  (only meaningful if bit 8 is set)
5260Sstevel@tonic-gate 	 *
5270Sstevel@tonic-gate 	 * Field contains combination of these values:
5280Sstevel@tonic-gate 	 *
5290Sstevel@tonic-gate 	 *	VALUE				DESCRIPTION
5300Sstevel@tonic-gate 	 * BGBPB_F_ActiveFATMsk		Mask for low four bits
5310Sstevel@tonic-gate 	 * (0x000F)
5320Sstevel@tonic-gate 	 * BGBPB_F_NoFATMirror		If set FAT mirroring disabled.
5330Sstevel@tonic-gate 	 * (0x0080)			If clear, FAT mirroring enabled.
5340Sstevel@tonic-gate 	 *
5350Sstevel@tonic-gate 	 * We set the value based on what I've seen on all the FAT32 drives
5360Sstevel@tonic-gate 	 * I've seen created by Windows.
5370Sstevel@tonic-gate 	 *
5380Sstevel@tonic-gate 	 */
5390Sstevel@tonic-gate 	wbpb->bpb32.ext_flags = 0x0;
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * No real explanation of the fs_vers file in the BPB doc.  The
5420Sstevel@tonic-gate 	 * high byte is supposed to be the major version and the low the
5430Sstevel@tonic-gate 	 * minor version.  Again I set according to what I've seen on Windows.
5440Sstevel@tonic-gate 	 */
5450Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_lo = '\0';
5460Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_hi = '\0';
5470Sstevel@tonic-gate 	/*
5480Sstevel@tonic-gate 	 * The convention appears to be to place the fs info sector
5490Sstevel@tonic-gate 	 * immediately after the boot sector, and that the backup boot
5500Sstevel@tonic-gate 	 * sector should be at sector 6. (based on what I see with
5510Sstevel@tonic-gate 	 * Windows)
5520Sstevel@tonic-gate 	 */
5530Sstevel@tonic-gate 	wbpb->bpb32.fsinfosec = 1;
5540Sstevel@tonic-gate 	wbpb->bpb32.backupboot = 6;
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate static
5580Sstevel@tonic-gate void
5590Sstevel@tonic-gate fill_bpb_sizes(bpb_t *wbpb, struct ipart part[], int partno, off64_t offset)
5600Sstevel@tonic-gate {
5610Sstevel@tonic-gate 	ulong_t usesize;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if (GetFsParams || GetSize) {
5640Sstevel@tonic-gate 		usesize = ltohi(part[partno].numsect);
5650Sstevel@tonic-gate 		if (Verbose) {
5660Sstevel@tonic-gate 		    (void) printf(
5670Sstevel@tonic-gate 			gettext("Partition size (from FDISK table) "
5680Sstevel@tonic-gate 			    "= %d sectors.\n"), usesize);
5690Sstevel@tonic-gate 		}
5700Sstevel@tonic-gate 	} else {
5710Sstevel@tonic-gate 		usesize = warn_mismatch(
5720Sstevel@tonic-gate 		    gettext("length of partition (in sectors)"),
5730Sstevel@tonic-gate 		    gettext("FDISK table"),
5740Sstevel@tonic-gate 		    ltohi(part[partno].numsect), TotSize);
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	if (GetFsParams) {
5780Sstevel@tonic-gate 		TotSize = usesize;
5790Sstevel@tonic-gate 	} else {
5800Sstevel@tonic-gate 		if (usesize > 0xffff)
5810Sstevel@tonic-gate 			wbpb->bpb.sectors_in_volume = 0;
5820Sstevel@tonic-gate 		else
5830Sstevel@tonic-gate 			wbpb->bpb.sectors_in_volume = usesize;
5840Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = usesize;
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = offset;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	if (GetFsParams) {
5900Sstevel@tonic-gate 		RelOffset = offset;
5910Sstevel@tonic-gate 	} else {
5920Sstevel@tonic-gate 		wbpb->sunbpb.bs_offset_high = offset >> 16;
5930Sstevel@tonic-gate 		wbpb->sunbpb.bs_offset_low = offset & 0xFFFF;
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate /*
5980Sstevel@tonic-gate  *  lookup_FAT_size
5990Sstevel@tonic-gate  *
6000Sstevel@tonic-gate  *	Given the FDISK partition file system identifier, return the
6010Sstevel@tonic-gate  *	expected FAT size for the partition.
6020Sstevel@tonic-gate  */
6030Sstevel@tonic-gate static
6040Sstevel@tonic-gate int
6050Sstevel@tonic-gate lookup_FAT_size(uchar_t partid)
6060Sstevel@tonic-gate {
6070Sstevel@tonic-gate 	int rval;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	switch (partid) {
6100Sstevel@tonic-gate 	case DOSOS12:
6110Sstevel@tonic-gate 		rval = 12;
6120Sstevel@tonic-gate 		break;
6130Sstevel@tonic-gate 	case DOSOS16:
6140Sstevel@tonic-gate 	case DOSHUGE:
6150Sstevel@tonic-gate 	case FDISK_FAT95:
6160Sstevel@tonic-gate 	case X86BOOT:
6170Sstevel@tonic-gate 		rval = 16;
6180Sstevel@tonic-gate 		break;
6190Sstevel@tonic-gate 	case FDISK_WINDOWS:
6200Sstevel@tonic-gate 	case FDISK_EXT_WIN:
6210Sstevel@tonic-gate 		rval = 32;
6220Sstevel@tonic-gate 		break;
6230Sstevel@tonic-gate 	case EXTDOS:
6240Sstevel@tonic-gate 	case FDISK_EXTLBA:
6250Sstevel@tonic-gate 	default:
6260Sstevel@tonic-gate 		rval = -1;
6270Sstevel@tonic-gate 		break;
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	return (rval);
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate /*
6340Sstevel@tonic-gate  *  seek_partn
6350Sstevel@tonic-gate  *
6360Sstevel@tonic-gate  *	Seek to the beginning of the partition where we need to install
6370Sstevel@tonic-gate  *	the new FAT.  Zero return for any error, but print error
6380Sstevel@tonic-gate  *	messages here.
6390Sstevel@tonic-gate  */
6400Sstevel@tonic-gate static
6410Sstevel@tonic-gate int
6420Sstevel@tonic-gate seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto)
6430Sstevel@tonic-gate {
6440Sstevel@tonic-gate 	struct ipart part[FD_NUMPART];
6450Sstevel@tonic-gate 	struct mboot extmboot;
6460Sstevel@tonic-gate 	struct mboot mb;
6470Sstevel@tonic-gate 	daddr_t xstartsect;
6480Sstevel@tonic-gate 	off64_t nextseek = 0;
6490Sstevel@tonic-gate 	off64_t lastseek = 0;
6500Sstevel@tonic-gate 	int logicalDriveCount = 0;
6510Sstevel@tonic-gate 	int extendedPart = -1;
6520Sstevel@tonic-gate 	int primaryPart = -1;
6530Sstevel@tonic-gate 	int bootPart = -1;
6540Sstevel@tonic-gate 	int xnumsect = -1;
6550Sstevel@tonic-gate 	int drvnum;
6560Sstevel@tonic-gate 	int driveIndex;
6570Sstevel@tonic-gate 	int i;
6580Sstevel@tonic-gate 	/*
6590Sstevel@tonic-gate 	 * Count of drives in the current extended partition's
6600Sstevel@tonic-gate 	 * FDISK table, and indexes of the drives themselves.
6610Sstevel@tonic-gate 	 */
6620Sstevel@tonic-gate 	int extndDrives[FD_NUMPART];
6630Sstevel@tonic-gate 	int numDrives = 0;
6640Sstevel@tonic-gate 	/*
6650Sstevel@tonic-gate 	 * Count of drives (beyond primary) in master boot record's
6660Sstevel@tonic-gate 	 * FDISK table, and indexes of the drives themselves.
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	int extraDrives[FD_NUMPART];
6690Sstevel@tonic-gate 	int numExtraDrives = 0;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	if ((drvnum = parse_drvnum(pn)) < 0)
6720Sstevel@tonic-gate 		return (PART_NOT_FOUND);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	if (read(fd, &mb, sizeof (mb)) != sizeof (mb)) {
6750Sstevel@tonic-gate 		(void) fprintf(stderr,
6760Sstevel@tonic-gate 		    gettext("Couldn't read a Master Boot Record?!\n"));
6770Sstevel@tonic-gate 		return (PART_NOT_FOUND);
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	if (ltohs(mb.signature) != BOOTSECSIG) {
6810Sstevel@tonic-gate 		(void) fprintf(stderr,
6820Sstevel@tonic-gate 		    gettext("Bad Sig on master boot record!\n"));
6830Sstevel@tonic-gate 		return (PART_NOT_FOUND);
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	*seekto = 0;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/*
6890Sstevel@tonic-gate 	 * Copy partition table into memory
6900Sstevel@tonic-gate 	 */
6910Sstevel@tonic-gate 	(void) memcpy(part, mb.parts, sizeof (part));
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/*
6940Sstevel@tonic-gate 	 * Get a summary of what is in the Master FDISK table.
6950Sstevel@tonic-gate 	 * Normally we expect to find one partition marked as a DOS drive.
6960Sstevel@tonic-gate 	 * This partition is the one Windows calls the primary dos partition.
6970Sstevel@tonic-gate 	 * If the machine has any logical drives then we also expect
6980Sstevel@tonic-gate 	 * to find a partition marked as an extended DOS partition.
6990Sstevel@tonic-gate 	 *
7000Sstevel@tonic-gate 	 * Sometimes we'll find multiple partitions marked as DOS drives.
7010Sstevel@tonic-gate 	 * The Solaris fdisk program allows these partitions
7020Sstevel@tonic-gate 	 * to be created, but Windows fdisk no longer does.  We still need
7030Sstevel@tonic-gate 	 * to support these, though, since Windows does.  We also need to fix
7040Sstevel@tonic-gate 	 * our fdisk to behave like the Windows version.
7050Sstevel@tonic-gate 	 *
7060Sstevel@tonic-gate 	 * It turns out that some off-the-shelf media have *only* an
7070Sstevel@tonic-gate 	 * Extended partition, so we need to deal with that case as
7080Sstevel@tonic-gate 	 * well.
7090Sstevel@tonic-gate 	 *
7100Sstevel@tonic-gate 	 * Only a single (the first) Extended or Boot Partition will
7110Sstevel@tonic-gate 	 * be recognized.  Any others will be ignored.
7120Sstevel@tonic-gate 	 */
7130Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
7140Sstevel@tonic-gate 		if (isDosDrive(part[i].systid)) {
7150Sstevel@tonic-gate 			if (primaryPart < 0) {
7160Sstevel@tonic-gate 				logicalDriveCount++;
7170Sstevel@tonic-gate 				primaryPart = i;
7180Sstevel@tonic-gate 			} else {
7190Sstevel@tonic-gate 				extraDrives[numExtraDrives++] = i;
7200Sstevel@tonic-gate 			}
7210Sstevel@tonic-gate 			continue;
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 		if ((extendedPart < 0) && isDosExtended(part[i].systid)) {
7240Sstevel@tonic-gate 			extendedPart = i;
7250Sstevel@tonic-gate 			continue;
7260Sstevel@tonic-gate 		}
7270Sstevel@tonic-gate 		if ((bootPart < 0) && isBootPart(part[i].systid)) {
7280Sstevel@tonic-gate 			bootPart = i;
7290Sstevel@tonic-gate 			continue;
7300Sstevel@tonic-gate 		}
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	if (drvnum == BOOT_PARTITION_DRIVE) {
7340Sstevel@tonic-gate 		if (bootPart < 0) {
7350Sstevel@tonic-gate 			(void) fprintf(stderr,
7360Sstevel@tonic-gate 			    gettext("No boot partition found on drive\n"));
7370Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7380Sstevel@tonic-gate 		}
7390Sstevel@tonic-gate 		if ((*seekto = ltohi(part[bootPart].relsect)) == 0) {
7400Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
7410Sstevel@tonic-gate 			    "A boot partition starting\nat sector 0 would "
7420Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
7430Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, bootPart, *seekto);
7470Sstevel@tonic-gate 		*seekto *= BPSEC;
7480Sstevel@tonic-gate 		FdiskFATsize = lookup_FAT_size(part[bootPart].systid);
7490Sstevel@tonic-gate 		if (Verbose)
7500Sstevel@tonic-gate 			(void) printf(gettext("Boot partition's offset: "
7510Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
7520Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
7530Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Partition %s: "), pn);
7540Sstevel@tonic-gate 			perror("");
7550Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7560Sstevel@tonic-gate 		}
7570Sstevel@tonic-gate 		return (PART_FOUND);
7580Sstevel@tonic-gate 	}
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	if (drvnum == PRIMARY_DOS_DRIVE && primaryPart >= 0) {
7610Sstevel@tonic-gate 		if ((*seekto = ltohi(part[primaryPart].relsect)) == 0) {
7620Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
7630Sstevel@tonic-gate 			    "A partition starting\nat sector 0 would "
7640Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
7650Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7660Sstevel@tonic-gate 		}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, primaryPart, *seekto);
7690Sstevel@tonic-gate 		*seekto *= BPSEC;
7700Sstevel@tonic-gate 		FdiskFATsize = lookup_FAT_size(part[primaryPart].systid);
7710Sstevel@tonic-gate 		if (Verbose)
7720Sstevel@tonic-gate 			(void) printf(gettext("Partition's offset: "
7730Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
7740Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
7750Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Partition %s: "), pn);
7760Sstevel@tonic-gate 			perror("");
7770Sstevel@tonic-gate 			return (PART_NOT_FOUND);
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 		return (PART_FOUND);
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/*
7830Sstevel@tonic-gate 	 * We are not looking for the C: drive (or there was no primary
7840Sstevel@tonic-gate 	 * drive found), so we had better have an extended partition or
7850Sstevel@tonic-gate 	 * extra drives in the Master FDISK table.
7860Sstevel@tonic-gate 	 */
7870Sstevel@tonic-gate 	if ((extendedPart < 0) && (numExtraDrives == 0)) {
7880Sstevel@tonic-gate 		(void) fprintf(stderr,
7890Sstevel@tonic-gate 		    gettext("No such logical drive "
7900Sstevel@tonic-gate 		    "(missing extended partition entry)\n"));
7910Sstevel@tonic-gate 		return (PART_NOT_FOUND);
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if (extendedPart >= 0) {
7950Sstevel@tonic-gate 		nextseek = xstartsect = ltohi(part[extendedPart].relsect);
7960Sstevel@tonic-gate 		xnumsect = ltohi(part[extendedPart].numsect);
7970Sstevel@tonic-gate 		do {
7980Sstevel@tonic-gate 			/*
7990Sstevel@tonic-gate 			 *  If the seek would not cause us to change
8000Sstevel@tonic-gate 			 *  position on the drive, then we're out of
8010Sstevel@tonic-gate 			 *  extended partitions to examine.
8020Sstevel@tonic-gate 			 */
8030Sstevel@tonic-gate 			if (nextseek == lastseek)
8040Sstevel@tonic-gate 				break;
8050Sstevel@tonic-gate 			logicalDriveCount += numDrives;
8060Sstevel@tonic-gate 			/*
8070Sstevel@tonic-gate 			 *  Seek the next extended partition, and find
8080Sstevel@tonic-gate 			 *  logical drives within it.
8090Sstevel@tonic-gate 			 */
8100Sstevel@tonic-gate 			if (lseek64(fd, nextseek * BPSEC, SEEK_SET) < 0 ||
8110Sstevel@tonic-gate 			    read(fd, &extmboot, sizeof (extmboot)) !=
8120Sstevel@tonic-gate 				sizeof (extmboot)) {
8130Sstevel@tonic-gate 				perror(gettext("Unable to read extended "
8140Sstevel@tonic-gate 					"partition record"));
8150Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8160Sstevel@tonic-gate 			}
8170Sstevel@tonic-gate 			(void) memcpy(part, extmboot.parts, sizeof (part));
8180Sstevel@tonic-gate 			lastseek = nextseek;
8190Sstevel@tonic-gate 			if (ltohs(extmboot.signature) != MBB_MAGIC) {
8200Sstevel@tonic-gate 				(void) fprintf(stderr,
8210Sstevel@tonic-gate 				    gettext("Bad signature on "
8220Sstevel@tonic-gate 				    "extended partition\n"));
8230Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8240Sstevel@tonic-gate 			}
8250Sstevel@tonic-gate 			/*
8260Sstevel@tonic-gate 			 *  Count up drives, and track where the next
8270Sstevel@tonic-gate 			 *  extended partition is in case we need it.  We
8280Sstevel@tonic-gate 			 *  are expecting only one extended partition.  If
8290Sstevel@tonic-gate 			 *  there is more than one we'll only go to the
8300Sstevel@tonic-gate 			 *  first one we see, but warn about ignoring.
8310Sstevel@tonic-gate 			 */
8320Sstevel@tonic-gate 			numDrives = 0;
8330Sstevel@tonic-gate 			for (i = 0; i < FD_NUMPART; i++) {
8340Sstevel@tonic-gate 				if (isDosDrive(part[i].systid)) {
8350Sstevel@tonic-gate 					extndDrives[numDrives++] = i;
8360Sstevel@tonic-gate 					continue;
8370Sstevel@tonic-gate 				} else if (isDosExtended(part[i].systid)) {
8380Sstevel@tonic-gate 					if (nextseek != lastseek) {
8390Sstevel@tonic-gate 						/*
8400Sstevel@tonic-gate 						 * Already found an extended
8410Sstevel@tonic-gate 						 * partition in this table.
8420Sstevel@tonic-gate 						 */
8430Sstevel@tonic-gate 						(void) fprintf(stderr,
8440Sstevel@tonic-gate 						    gettext("WARNING: "
8450Sstevel@tonic-gate 						    "Ignoring unexpected "
8460Sstevel@tonic-gate 						    "additional extended "
8470Sstevel@tonic-gate 						    "partition"));
8480Sstevel@tonic-gate 						continue;
8490Sstevel@tonic-gate 					}
8500Sstevel@tonic-gate 					nextseek = xstartsect +
8510Sstevel@tonic-gate 					    ltohi(part[i].relsect);
8520Sstevel@tonic-gate 					continue;
8530Sstevel@tonic-gate 				}
8540Sstevel@tonic-gate 			}
8550Sstevel@tonic-gate 		} while (drvnum > logicalDriveCount + numDrives);
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 		if (drvnum <= logicalDriveCount + numDrives) {
8580Sstevel@tonic-gate 			/*
8590Sstevel@tonic-gate 			 * The number of logical drives we've found thus
8600Sstevel@tonic-gate 			 * far is enough to get us to the one we were
8610Sstevel@tonic-gate 			 * searching for.
8620Sstevel@tonic-gate 			 */
8630Sstevel@tonic-gate 			driveIndex = logicalDriveCount + numDrives - drvnum;
8640Sstevel@tonic-gate 			*seekto =
8650Sstevel@tonic-gate 			    ltohi(part[extndDrives[driveIndex]].relsect) +
8660Sstevel@tonic-gate 			    lastseek;
8670Sstevel@tonic-gate 			if (*seekto == lastseek) {
8680Sstevel@tonic-gate 				(void) fprintf(stderr,
8690Sstevel@tonic-gate 				    gettext("Bogus FDISK entry?  A logical "
8700Sstevel@tonic-gate 				    "drive starting at\nsector 0x%llx would "
8710Sstevel@tonic-gate 				    "collide with the\nFDISK information in "
8720Sstevel@tonic-gate 				    "that sector.\n"), *seekto);
8730Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8740Sstevel@tonic-gate 			} else if (*seekto <= xstartsect ||
8750Sstevel@tonic-gate 			    *seekto >= (xstartsect + xnumsect)) {
8760Sstevel@tonic-gate 				(void) fprintf(stderr,
8770Sstevel@tonic-gate 				    gettext("Bogus FDISK entry?  "
8780Sstevel@tonic-gate 				    "Logical drive start sector (0x%llx)\n"
8790Sstevel@tonic-gate 				    "not within extended partition! "
8800Sstevel@tonic-gate 				    "(Expected in range 0x%x - 0x%x)\n"),
8810Sstevel@tonic-gate 				    *seekto, xstartsect + 1,
8820Sstevel@tonic-gate 				    xstartsect + xnumsect - 1);
8830Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8840Sstevel@tonic-gate 			}
8850Sstevel@tonic-gate 			fill_bpb_sizes(wbpb, part, extndDrives[driveIndex],
8860Sstevel@tonic-gate 			    *seekto);
8870Sstevel@tonic-gate 			*seekto *= BPSEC;
8880Sstevel@tonic-gate 			FdiskFATsize = lookup_FAT_size(
8890Sstevel@tonic-gate 			    part[extndDrives[driveIndex]].systid);
8900Sstevel@tonic-gate 			if (Verbose)
8910Sstevel@tonic-gate 				(void) printf(gettext("Partition's offset: "
8920Sstevel@tonic-gate 				    "Sector 0x%x.\n"), *seekto/BPSEC);
8930Sstevel@tonic-gate 			if (lseek64(fd, *seekto, SEEK_SET) < 0) {
8940Sstevel@tonic-gate 				(void) fprintf(stderr,
8950Sstevel@tonic-gate 				    gettext("Partition %s: "), pn);
8960Sstevel@tonic-gate 				perror("");
8970Sstevel@tonic-gate 				return (PART_NOT_FOUND);
8980Sstevel@tonic-gate 			}
8990Sstevel@tonic-gate 			return (PART_FOUND);
9000Sstevel@tonic-gate 		} else {
9010Sstevel@tonic-gate 			/*
9020Sstevel@tonic-gate 			 * We ran out of extended dos partition
9030Sstevel@tonic-gate 			 * drives.  The only hope now is to go
9040Sstevel@tonic-gate 			 * back to extra drives defined in the master
9050Sstevel@tonic-gate 			 * fdisk table.  But we overwrote that table
9060Sstevel@tonic-gate 			 * already, so we must load it in again.
9070Sstevel@tonic-gate 			 */
9080Sstevel@tonic-gate 			logicalDriveCount += numDrives;
9090Sstevel@tonic-gate 			(void) memcpy(part, mb.parts, sizeof (part));
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 	}
9120Sstevel@tonic-gate 	/*
9130Sstevel@tonic-gate 	 *  Still haven't found the drive, is it an extra
9140Sstevel@tonic-gate 	 *  drive defined in the main FDISK table?
9150Sstevel@tonic-gate 	 */
9160Sstevel@tonic-gate 	if (drvnum <= logicalDriveCount + numExtraDrives) {
9170Sstevel@tonic-gate 		driveIndex = logicalDriveCount + numExtraDrives - drvnum;
9180Sstevel@tonic-gate 		*seekto = ltohi(part[extraDrives[driveIndex]].relsect);
9190Sstevel@tonic-gate 		if (*seekto == 0) {
9200Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Bogus FDISK entry? "
9210Sstevel@tonic-gate 			    "A partition starting\nat sector 0 would "
9220Sstevel@tonic-gate 			    "collide with the FDISK table!\n"));
9230Sstevel@tonic-gate 			return (PART_NOT_FOUND);
9240Sstevel@tonic-gate 		}
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 		fill_bpb_sizes(wbpb, part, extraDrives[driveIndex], *seekto);
9270Sstevel@tonic-gate 		*seekto *= BPSEC;
9280Sstevel@tonic-gate 		FdiskFATsize =
9290Sstevel@tonic-gate 			lookup_FAT_size(part[extraDrives[driveIndex]].systid);
9300Sstevel@tonic-gate 		if (Verbose)
9310Sstevel@tonic-gate 			(void) printf(gettext("Partition's offset: "
9320Sstevel@tonic-gate 			    "Sector %x.\n"), *seekto/BPSEC);
9330Sstevel@tonic-gate 		if (lseek64(fd, *seekto, SEEK_SET) < 0) {
9340Sstevel@tonic-gate 			(void) fprintf(stderr,
9350Sstevel@tonic-gate 			    gettext("Partition %s: "), pn);
9360Sstevel@tonic-gate 			perror("");
9370Sstevel@tonic-gate 			return (PART_NOT_FOUND);
9380Sstevel@tonic-gate 		}
9390Sstevel@tonic-gate 		return (PART_FOUND);
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("No such logical drive\n"));
9420Sstevel@tonic-gate 	return (PART_NOT_FOUND);
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate /*
9460Sstevel@tonic-gate  *  seek_nofdisk
9470Sstevel@tonic-gate  *
9480Sstevel@tonic-gate  *	User is asking us to trust them that they know best.
9490Sstevel@tonic-gate  *	We basically won't do much seeking here, the only seeking we'll do
9500Sstevel@tonic-gate  *	is if the 'hidden' parameter was given.
9510Sstevel@tonic-gate  */
9520Sstevel@tonic-gate static
9530Sstevel@tonic-gate int
9540Sstevel@tonic-gate seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto)
9550Sstevel@tonic-gate {
9560Sstevel@tonic-gate 	if (TotSize > 0xffff)
9570Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 0;
9580Sstevel@tonic-gate 	else
9590Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = (short)TotSize;
9600Sstevel@tonic-gate 	wbpb->bpb.sectors_in_logical_volume = TotSize;
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	*seekto = RelOffset * BPSEC;
9630Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = RelOffset;
9640Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = RelOffset >> 16;
9650Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = RelOffset & 0xFFFF;
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	if (Verbose)
9680Sstevel@tonic-gate 		(void) printf(gettext("Requested offset: Sector %x.\n"),
9690Sstevel@tonic-gate 		    *seekto/BPSEC);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	if (lseek64(fd, *seekto, SEEK_SET) < 0) {
9720Sstevel@tonic-gate 		(void) fprintf(stderr,
9730Sstevel@tonic-gate 		    gettext("User specified start sector %d"), RelOffset);
9740Sstevel@tonic-gate 		perror("");
9750Sstevel@tonic-gate 		return (PART_NOT_FOUND);
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 	return (PART_FOUND);
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate /*
9810Sstevel@tonic-gate  * set_fat_string
9820Sstevel@tonic-gate  *
9830Sstevel@tonic-gate  *	Fill in the type string of the FAT
9840Sstevel@tonic-gate  */
9850Sstevel@tonic-gate static
9860Sstevel@tonic-gate void
9870Sstevel@tonic-gate set_fat_string(bpb_t *wbpb, int fatsize)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	if (fatsize == 12) {
9900Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT12_TYPE_STRING,
9910Sstevel@tonic-gate 			strlen(FAT12_TYPE_STRING));
9920Sstevel@tonic-gate 	} else if (fatsize == 16) {
9930Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT16_TYPE_STRING,
9940Sstevel@tonic-gate 			strlen(FAT16_TYPE_STRING));
9950Sstevel@tonic-gate 	} else {
9960Sstevel@tonic-gate 		(void) strncpy((char *)wbpb->ebpb.type, FAT32_TYPE_STRING,
9970Sstevel@tonic-gate 			strlen(FAT32_TYPE_STRING));
9980Sstevel@tonic-gate 	}
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate /*
10020Sstevel@tonic-gate  *  prepare_image_file
10030Sstevel@tonic-gate  *
10040Sstevel@tonic-gate  *	Open the file that will hold the image (as opposed to the image
10050Sstevel@tonic-gate  *	being written to the boot sector of an actual disk).
10060Sstevel@tonic-gate  */
10070Sstevel@tonic-gate static
10080Sstevel@tonic-gate int
10090Sstevel@tonic-gate prepare_image_file(char *fn, bpb_t *wbpb)
10100Sstevel@tonic-gate {
10110Sstevel@tonic-gate 	int fd;
10120Sstevel@tonic-gate 	char zerobyte = '\0';
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) {
10150Sstevel@tonic-gate 		perror(fn);
10160Sstevel@tonic-gate 		exit(2);
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	if (Imagesize == 5) {
10200Sstevel@tonic-gate 		/* Disk image of a 1.2M floppy */
10210Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 2 * 80 * 15;
10220Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 15;
10230Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = 15;
10240Sstevel@tonic-gate 		wbpb->bpb.heads = 2;
10250Sstevel@tonic-gate 		wbpb->bpb.media = 0xF9;
10260Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 224;
10270Sstevel@tonic-gate 		wbpb->bpb.sectors_per_cluster = 1;
10280Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 7;
10290Sstevel@tonic-gate 	} else {
10300Sstevel@tonic-gate 		/* Disk image of a 1.44M floppy */
10310Sstevel@tonic-gate 		wbpb->bpb.sectors_in_volume = 2 * 80 * 18;
10320Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 18;
10330Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = 18;
10340Sstevel@tonic-gate 		wbpb->bpb.heads = 2;
10350Sstevel@tonic-gate 		wbpb->bpb.media = 0xF0;
10360Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 224;
10370Sstevel@tonic-gate 		wbpb->bpb.sectors_per_cluster = 1;
10380Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 9;
10390Sstevel@tonic-gate 	}
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	/*
10420Sstevel@tonic-gate 	 * Make a holey file, with length the exact
10430Sstevel@tonic-gate 	 * size of the floppy image.
10440Sstevel@tonic-gate 	 */
10450Sstevel@tonic-gate 	if (lseek(fd, (wbpb->bpb.sectors_in_volume * BPSEC)-1, SEEK_SET) < 0) {
10460Sstevel@tonic-gate 		(void) close(fd);
10470Sstevel@tonic-gate 		perror(fn);
10480Sstevel@tonic-gate 		exit(2);
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	if (write(fd, &zerobyte, 1) != 1) {
10520Sstevel@tonic-gate 		(void) close(fd);
10530Sstevel@tonic-gate 		perror(fn);
10540Sstevel@tonic-gate 		exit(2);
10550Sstevel@tonic-gate 	}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) < 0) {
10580Sstevel@tonic-gate 		(void) close(fd);
10590Sstevel@tonic-gate 		perror(fn);
10600Sstevel@tonic-gate 		exit(2);
10610Sstevel@tonic-gate 	}
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	Fatentsize = 12;  /* Size of fat entry in bits */
10640Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = 0;
10690Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = 0;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	return (fd);
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate /*
10750Sstevel@tonic-gate  *  partn_lecture
10760Sstevel@tonic-gate  *
10770Sstevel@tonic-gate  *	Give a brief sermon on dev_name user should pass to
10780Sstevel@tonic-gate  *	the program from the command line.
10790Sstevel@tonic-gate  *
10800Sstevel@tonic-gate  */
10810Sstevel@tonic-gate static
10820Sstevel@tonic-gate void
10830Sstevel@tonic-gate partn_lecture(char *dn)
10840Sstevel@tonic-gate {
10850Sstevel@tonic-gate 	(void) fprintf(stderr,
10860Sstevel@tonic-gate 		gettext("\nDevice %s was assumed to be a diskette.\n"
10870Sstevel@tonic-gate 		    "A diskette specific operation failed on this device.\n"
10880Sstevel@tonic-gate 		    "If the device is a hard disk, provide the name of "
10890Sstevel@tonic-gate 		    "the full physical disk,\n"
10900Sstevel@tonic-gate 		    "and qualify that name with a logical drive specifier.\n\n"
10910Sstevel@tonic-gate 		    "Hint: the device is usually something similar to\n\n"
10920Sstevel@tonic-gate 		    "/dev/rdsk/c0d0p0 or /dev/rdsk/c0t0d0p0 (x86)\n"
10930Sstevel@tonic-gate 		    "/dev/rdsk/c0t5d0s2 (sparc)\n\n"
10940Sstevel@tonic-gate 		    "The drive specifier is appended to the device name."
10950Sstevel@tonic-gate 		    " For example:\n\n"
10960Sstevel@tonic-gate 		    "/dev/rdsk/c0t5d0s2:c or /dev/rdsk/c0d0p0:boot\n\n"), dn);
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate static
11000Sstevel@tonic-gate void
11010Sstevel@tonic-gate warn_funky_floppy(void)
11020Sstevel@tonic-gate {
11030Sstevel@tonic-gate 	(void) fprintf(stderr,
11040Sstevel@tonic-gate 	    gettext("Use the 'nofdisk' option to create file systems\n"
11050Sstevel@tonic-gate 		    "on non-standard floppies.\n\n"));
11060Sstevel@tonic-gate 	exit(4);
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate static
11100Sstevel@tonic-gate void
11110Sstevel@tonic-gate warn_funky_fatsize(void)
11120Sstevel@tonic-gate {
11130Sstevel@tonic-gate 	(void) fprintf(stderr,
11140Sstevel@tonic-gate 	    gettext("Non-standard FAT size requested for floppy.\n"
11150Sstevel@tonic-gate 		    "The 'nofdisk' option must be used to\n"
11160Sstevel@tonic-gate 		    "override the 12 bit floppy default.\n\n"));
11170Sstevel@tonic-gate 	exit(4);
11180Sstevel@tonic-gate }
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate static
11210Sstevel@tonic-gate void
11220Sstevel@tonic-gate floppy_bpb_fillin(bpb_t *wbpb, int diam, int hds, int spt)
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate 	switch (diam) {
11250Sstevel@tonic-gate 	case 3:
11260Sstevel@tonic-gate 		switch (hds) {
11270Sstevel@tonic-gate 		case 2:
11280Sstevel@tonic-gate 			switch (spt) {
11290Sstevel@tonic-gate 			case 9:
11300Sstevel@tonic-gate 				wbpb->bpb.media = 0xF9;
11310Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
11320Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
11330Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 3;
11340Sstevel@tonic-gate 				break;
11350Sstevel@tonic-gate 			case 18:
11360Sstevel@tonic-gate 				wbpb->bpb.media = 0xF0;
11370Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 224;
11380Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11390Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 9;
11400Sstevel@tonic-gate 				break;
11410Sstevel@tonic-gate 			case 36:
11420Sstevel@tonic-gate 				wbpb->bpb.media = 0xF0;
11430Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 240;
11440Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
11450Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 9;
11460Sstevel@tonic-gate 				break;
11470Sstevel@tonic-gate 			default:
11480Sstevel@tonic-gate 				(void) fprintf(stderr,
11490Sstevel@tonic-gate 				    gettext("Unknown diskette parameters!  "
11500Sstevel@tonic-gate 					"3.5'' diskette with %d heads "
11510Sstevel@tonic-gate 					"and %d sectors/track.\n"), hds, spt);
11520Sstevel@tonic-gate 				warn_funky_floppy();
11530Sstevel@tonic-gate 			}
11540Sstevel@tonic-gate 			break;
11550Sstevel@tonic-gate 		case 1:
11560Sstevel@tonic-gate 		default:
11570Sstevel@tonic-gate 			(void) fprintf(stderr,
11580Sstevel@tonic-gate 			    gettext("Unknown diskette parameters!  "
11590Sstevel@tonic-gate 				"3.5'' diskette with %d heads "), hds);
11600Sstevel@tonic-gate 			warn_funky_floppy();
11610Sstevel@tonic-gate 		}
11620Sstevel@tonic-gate 		break;
11630Sstevel@tonic-gate 	case 5:
11640Sstevel@tonic-gate 		switch (hds) {
11650Sstevel@tonic-gate 		case 2:
11660Sstevel@tonic-gate 			switch (spt) {
11670Sstevel@tonic-gate 			case 15:
11680Sstevel@tonic-gate 				wbpb->bpb.media = 0xF9;
11690Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 224;
11700Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11710Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 7;
11720Sstevel@tonic-gate 				break;
11730Sstevel@tonic-gate 			case 9:
11740Sstevel@tonic-gate 				wbpb->bpb.media = 0xFD;
11750Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
11760Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 2;
11770Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
11780Sstevel@tonic-gate 				break;
11790Sstevel@tonic-gate 			case 8:
11800Sstevel@tonic-gate 				wbpb->bpb.media = 0xFF;
11810Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 112;
11820Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11830Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
11840Sstevel@tonic-gate 				break;
11850Sstevel@tonic-gate 			default:
11860Sstevel@tonic-gate 				(void) fprintf(stderr,
11870Sstevel@tonic-gate 				    gettext("Unknown diskette parameters!  "
11880Sstevel@tonic-gate 					"5.25'' diskette with %d heads "
11890Sstevel@tonic-gate 					"and %d sectors/track.\n"), hds, spt);
11900Sstevel@tonic-gate 				warn_funky_floppy();
11910Sstevel@tonic-gate 			}
11920Sstevel@tonic-gate 			break;
11930Sstevel@tonic-gate 		case 1:
11940Sstevel@tonic-gate 			switch (spt) {
11950Sstevel@tonic-gate 			case 9:
11960Sstevel@tonic-gate 				wbpb->bpb.media = 0xFC;
11970Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 64;
11980Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
11990Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 2;
12000Sstevel@tonic-gate 				break;
12010Sstevel@tonic-gate 			case 8:
12020Sstevel@tonic-gate 				wbpb->bpb.media = 0xFE;
12030Sstevel@tonic-gate 				wbpb->bpb.num_root_entries = 64;
12040Sstevel@tonic-gate 				wbpb->bpb.sectors_per_cluster = 1;
12050Sstevel@tonic-gate 				wbpb->bpb.sectors_per_fat = 1;
12060Sstevel@tonic-gate 				break;
12070Sstevel@tonic-gate 			default:
12080Sstevel@tonic-gate 				(void) fprintf(stderr,
12090Sstevel@tonic-gate 				    gettext("Unknown diskette parameters! "
12100Sstevel@tonic-gate 					"5.25'' diskette with %d heads "
12110Sstevel@tonic-gate 					"and %d sectors/track.\n"), hds, spt);
12120Sstevel@tonic-gate 				warn_funky_floppy();
12130Sstevel@tonic-gate 			}
12140Sstevel@tonic-gate 			break;
12150Sstevel@tonic-gate 		default:
12160Sstevel@tonic-gate 			(void) fprintf(stderr,
12170Sstevel@tonic-gate 			    gettext("Unknown diskette parameters! "
12180Sstevel@tonic-gate 				"5.25'' diskette with %d heads."), hds);
12190Sstevel@tonic-gate 			warn_funky_floppy();
12200Sstevel@tonic-gate 		}
12210Sstevel@tonic-gate 		break;
12220Sstevel@tonic-gate 	default:
12230Sstevel@tonic-gate 		(void) fprintf(stderr,
12240Sstevel@tonic-gate 		    gettext("\nUnknown diskette type.  Only know about "
12250Sstevel@tonic-gate 			"5.25'' and 3.5'' diskettes.\n"));
12260Sstevel@tonic-gate 		warn_funky_floppy();
12270Sstevel@tonic-gate 	}
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate /*
12310Sstevel@tonic-gate  *  lookup_floppy
12320Sstevel@tonic-gate  *
12330Sstevel@tonic-gate  *	Look up a media descriptor byte and other crucial BPB values
12340Sstevel@tonic-gate  *	based on floppy characteristics.
12350Sstevel@tonic-gate  */
12360Sstevel@tonic-gate static
12370Sstevel@tonic-gate void
12380Sstevel@tonic-gate lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb)
12390Sstevel@tonic-gate {
12400Sstevel@tonic-gate 	ulong_t tsize;
12410Sstevel@tonic-gate 	ulong_t cyls, spt, hds, diam;
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	cyls = fdchar->fdc_ncyl;
12440Sstevel@tonic-gate 	diam = fdchar->fdc_medium;
12450Sstevel@tonic-gate 	spt = fdchar->fdc_secptrack;
12460Sstevel@tonic-gate 	hds = fdchar->fdc_nhead;
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	tsize = cyls * hds * spt;
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	if (GetFsParams)
12510Sstevel@tonic-gate 		TotSize = tsize;
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	if (GetSize) {
12540Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume = tsize;
12550Sstevel@tonic-gate 	} else {
12560Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume =
12570Sstevel@tonic-gate 			warn_mismatch(
12580Sstevel@tonic-gate 			    gettext("length of partition (in sectors)"),
12590Sstevel@tonic-gate 			    gettext("FDIOGCHAR call"), tsize, TotSize);
12600Sstevel@tonic-gate 	}
12610Sstevel@tonic-gate 	wbpb->bpb.sectors_in_volume =
12620Sstevel@tonic-gate 		(short)wbpb->bpb.sectors_in_logical_volume;
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	if (GetSPT) {
12650Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track = spt;
12660Sstevel@tonic-gate 	} else {
12670Sstevel@tonic-gate 		wbpb->bpb.sectors_per_track =
12680Sstevel@tonic-gate 			warn_mismatch(
12690Sstevel@tonic-gate 			    gettext("sectors per track"),
12700Sstevel@tonic-gate 			    gettext("FDIOGCHAR call"), spt, SecPerTrk);
12710Sstevel@tonic-gate 		spt = wbpb->bpb.sectors_per_track;
12720Sstevel@tonic-gate 	}
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	if (GetTPC) {
12750Sstevel@tonic-gate 		wbpb->bpb.heads = hds;
12760Sstevel@tonic-gate 	} else {
12770Sstevel@tonic-gate 		wbpb->bpb.heads =
12780Sstevel@tonic-gate 			warn_mismatch(
12790Sstevel@tonic-gate 			    gettext("number of heads"),
12800Sstevel@tonic-gate 			    gettext("FDIOGCHAR call"), hds, TrkPerCyl);
12810Sstevel@tonic-gate 		hds = wbpb->bpb.heads;
12820Sstevel@tonic-gate 	}
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	Fatentsize = 12;  /* Size of fat entry in bits */
12850Sstevel@tonic-gate 	if (!GetBPF && BitsPerFAT != Fatentsize) {
12860Sstevel@tonic-gate 		warn_funky_fatsize();
12870Sstevel@tonic-gate 	}
12880Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0;
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	wbpb->bpb.hidden_sectors = 0;
12930Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_high = 0;
12940Sstevel@tonic-gate 	wbpb->sunbpb.bs_offset_low = 0;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	floppy_bpb_fillin(wbpb, diam, hds, spt);
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate /*
13000Sstevel@tonic-gate  *  compute_cluster_size
13010Sstevel@tonic-gate  *
13020Sstevel@tonic-gate  *	Compute an acceptable sectors/cluster value.
13030Sstevel@tonic-gate  *
13040Sstevel@tonic-gate  *	Values taken from a table found on p. 407 of "Windows 98
13050Sstevel@tonic-gate  *	Professional Reference", by Bruce A. Hallberg & Joe
13060Sstevel@tonic-gate  *	Casad. (ISBN 0-56205-786-3) I believe they've taken their
13070Sstevel@tonic-gate  *	table directly from the MSDN docs.
13080Sstevel@tonic-gate  *
13090Sstevel@tonic-gate  *	FAT32 information taken from "Partition Magic 6.0", User Guide, p67.
13100Sstevel@tonic-gate  *	It uses strange values as 8.01, 16.02 and 32.04; the windows support
13110Sstevel@tonic-gate  *	site uses 8G and 16G.
13120Sstevel@tonic-gate  */
13130Sstevel@tonic-gate static
13140Sstevel@tonic-gate void
13150Sstevel@tonic-gate compute_cluster_size(bpb_t *wbpb)
13160Sstevel@tonic-gate {
13170Sstevel@tonic-gate 	ulong_t volsize, maxclusters;
13180Sstevel@tonic-gate 	ulong_t spc, spf;
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	volsize = wbpb->bpb.sectors_in_volume ? wbpb->bpb.sectors_in_volume :
13210Sstevel@tonic-gate 		wbpb->bpb.sectors_in_logical_volume;
13220Sstevel@tonic-gate 	volsize -= wbpb->bpb.resv_sectors;
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	if (GetSPC) {
13250Sstevel@tonic-gate 		if (MakeFAT32) {
13260Sstevel@tonic-gate 			if (volsize <= 0x1000000) {		/* 8G */
13270Sstevel@tonic-gate 				spc = 8;
13280Sstevel@tonic-gate 			} else if (volsize <= 0x2000000) {	/* 16G */
13290Sstevel@tonic-gate 				spc = 16;
13300Sstevel@tonic-gate 			} else if (volsize <= 0x4000000) {	/* 32G */
13310Sstevel@tonic-gate 				spc = 32;
13320Sstevel@tonic-gate 			} else {
13330Sstevel@tonic-gate 				spc = 64;
13340Sstevel@tonic-gate 			}
13350Sstevel@tonic-gate 		} else {
13360Sstevel@tonic-gate 			if (volsize <= 0x10000) {		/* 32M */
13370Sstevel@tonic-gate 				spc = 1;
13380Sstevel@tonic-gate 			} else if (volsize <= 0x20000) {	/* 64M */
13390Sstevel@tonic-gate 				spc = 2;
13400Sstevel@tonic-gate 			} else if (volsize <= 0x40000) {	/* 128M */
13410Sstevel@tonic-gate 				spc = 4;
13420Sstevel@tonic-gate 			} else if (volsize <= 0x7f800) {	/* 255M */
13430Sstevel@tonic-gate 				spc = 8;
13440Sstevel@tonic-gate 			} else if (volsize <= 0xff800) {	/* 511M */
13450Sstevel@tonic-gate 				spc = 16;
13460Sstevel@tonic-gate 			} else if (volsize <= 0x1ff800) {	/* 1023M */
13470Sstevel@tonic-gate 				spc = 32;
13480Sstevel@tonic-gate 			} else if (volsize <= 0x3ff800) {	/* 2047M */
13490Sstevel@tonic-gate 				spc = 64;
13500Sstevel@tonic-gate 			} else if (volsize <= 0x7ff800) {	/* 4095M */
13510Sstevel@tonic-gate 				spc = 128;
13520Sstevel@tonic-gate 			} else {
13530Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
13540Sstevel@tonic-gate 				    "Partition too large for a FAT!\n"));
13550Sstevel@tonic-gate 				exit(4);
13560Sstevel@tonic-gate 			}
13570Sstevel@tonic-gate 		}
13580Sstevel@tonic-gate 	} else {
13590Sstevel@tonic-gate 		spc = SecPerClust;
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	if (GetBPF) {
13630Sstevel@tonic-gate 		if (MakeFAT32)
13640Sstevel@tonic-gate 			Fatentsize = 32;
13650Sstevel@tonic-gate 		else
13660Sstevel@tonic-gate 			Fatentsize = 16;
13670Sstevel@tonic-gate 	} else {
13680Sstevel@tonic-gate 		Fatentsize = BitsPerFAT;
13690Sstevel@tonic-gate 		if (Fatentsize == 12 && volsize > DOS_F12MAXC * spc) {
13700Sstevel@tonic-gate 			/*
13710Sstevel@tonic-gate 			 * 4228473 No way to non-interactively make a
13720Sstevel@tonic-gate 			 *	   pcfs filesystem
13730Sstevel@tonic-gate 			 *
13740Sstevel@tonic-gate 			 *	If we don't have an input TTY, or we aren't
13750Sstevel@tonic-gate 			 *	really doing anything, then don't ask
13760Sstevel@tonic-gate 			 *	questions.  Assume a yes answer to any
13770Sstevel@tonic-gate 			 *	questions we would ask.
13780Sstevel@tonic-gate 			 */
13790Sstevel@tonic-gate 			if (Notreally || !isatty(fileno(stdin))) {
13800Sstevel@tonic-gate 			    (void) printf(
13810Sstevel@tonic-gate 				gettext("Volume too large for 12 bit FAT,"
13820Sstevel@tonic-gate 				" increasing to 16 bit FAT size.\n"));
13830Sstevel@tonic-gate 			    (void) fflush(stdout);
13840Sstevel@tonic-gate 			    Fatentsize = 16;
13850Sstevel@tonic-gate 			} else {
13860Sstevel@tonic-gate 			    (void) printf(
13870Sstevel@tonic-gate 				gettext("Volume too large for a 12 bit FAT.\n"
13880Sstevel@tonic-gate 					"Increase to 16 bit FAT "
13890Sstevel@tonic-gate 					"and continue (y/n)? "));
13900Sstevel@tonic-gate 			    (void) fflush(stdout);
13910Sstevel@tonic-gate 			    if (yes())
13920Sstevel@tonic-gate 				Fatentsize = 16;
13930Sstevel@tonic-gate 			    else
13940Sstevel@tonic-gate 				exit(5);
13950Sstevel@tonic-gate 			}
13960Sstevel@tonic-gate 		}
13970Sstevel@tonic-gate 	}
13980Sstevel@tonic-gate 	wbpb->bpb.sectors_per_cluster = spc;
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	if (!GetFsParams && FdiskFATsize < 0) {
14010Sstevel@tonic-gate 		(void) printf(
14020Sstevel@tonic-gate 		    gettext("Cannot verify chosen/computed FAT "
14030Sstevel@tonic-gate 			"entry size (%d bits) with FDISK table.\n"
14040Sstevel@tonic-gate 			"FDISK table has an unknown file system "
14050Sstevel@tonic-gate 			"type for this device.  Giving up...\n"),
14060Sstevel@tonic-gate 			Fatentsize, Fatentsize);
14070Sstevel@tonic-gate 		exit(6);
14080Sstevel@tonic-gate 	} else if (!GetFsParams && FdiskFATsize && FdiskFATsize != Fatentsize) {
14090Sstevel@tonic-gate 		(void) printf(
14100Sstevel@tonic-gate 		    gettext("Chosen/computed FAT entry size (%d bits) "
14110Sstevel@tonic-gate 			"does not match FDISK table (%d bits).\n"),
14120Sstevel@tonic-gate 			Fatentsize, FdiskFATsize);
14130Sstevel@tonic-gate 		(void) printf(
14140Sstevel@tonic-gate 		    gettext("Use -o fat=%d to build a FAT "
14150Sstevel@tonic-gate 			"that matches the FDISK entry.\n"), FdiskFATsize);
14160Sstevel@tonic-gate 		exit(6);
14170Sstevel@tonic-gate 	}
14180Sstevel@tonic-gate 	set_fat_string(wbpb, Fatentsize);
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	/* Compute a sector/fat figure */
14210Sstevel@tonic-gate 	switch (Fatentsize) {
14220Sstevel@tonic-gate 	case 32:
14230Sstevel@tonic-gate 		/*
14240Sstevel@tonic-gate 		 *  We arrive at a formula for sectors/fat by simultaneously
14250Sstevel@tonic-gate 		 *  solving two equations:
14260Sstevel@tonic-gate 		 *
14270Sstevel@tonic-gate 		 *	F = size of FAT (in sectors)
14280Sstevel@tonic-gate 		 *	V = volume size (in sectors)
14290Sstevel@tonic-gate 		 *	X = file area size (in clusters)
14300Sstevel@tonic-gate 		 *
14310Sstevel@tonic-gate 		 *	X = (V - 2F)/8 <--- always 8 sectors/cluster for FAT32
14320Sstevel@tonic-gate 		 *	F = 4(X+2)/512 <--- 4 bytes/cluster-entry,
14330Sstevel@tonic-gate 		 *			    512 bytes/sector
14340Sstevel@tonic-gate 		 *	and so,
14350Sstevel@tonic-gate 		 *		F = 4(((V - 2F)/8)+2)/512
14360Sstevel@tonic-gate 		 *			...
14370Sstevel@tonic-gate 		 *		F = V + 16 / 1026
14380Sstevel@tonic-gate 		 */
14390Sstevel@tonic-gate 		spf = idivceil(volsize + 16, 1026);
14400Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = 0;
14410Sstevel@tonic-gate 		wbpb->bpb32.big_sectors_per_fat = spf;
14420Sstevel@tonic-gate 		break;
14430Sstevel@tonic-gate 	case 12:
14440Sstevel@tonic-gate 		maxclusters = idivceil(volsize, spc) + 2;
14450Sstevel@tonic-gate 		spf = idivceil(maxclusters, FAT12_ENTSPERSECT);
14460Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = (ushort_t)spf;
14470Sstevel@tonic-gate 		break;
14480Sstevel@tonic-gate 	default:	/* 16 bit FAT */
14490Sstevel@tonic-gate 		maxclusters = idivceil(volsize, spc) + 2;
14500Sstevel@tonic-gate 		spf = idivceil(maxclusters, FAT16_ENTSPERSECT);
14510Sstevel@tonic-gate 		wbpb->bpb.sectors_per_fat = (ushort_t)spf;
14520Sstevel@tonic-gate 		break;
14530Sstevel@tonic-gate 	}
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate static
14570Sstevel@tonic-gate void
14580Sstevel@tonic-gate find_fixed_details(int fd, bpb_t *wbpb)
14590Sstevel@tonic-gate {
14600Sstevel@tonic-gate 	struct dk_geom dginfo;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	/*
14630Sstevel@tonic-gate 	 *  Look up the last remaining bits of info we need
14640Sstevel@tonic-gate 	 *  that is specific to the hard drive using a disk ioctl.
14650Sstevel@tonic-gate 	 */
14660Sstevel@tonic-gate 	if (GetSPT || GetTPC) {
14670Sstevel@tonic-gate 		if ((ioctl(fd, DKIOCG_VIRTGEOM, &dginfo)) == -1) {
14680Sstevel@tonic-gate 		    if ((ioctl(fd, DKIOCG_PHYGEOM, &dginfo)) == -1) {
14690Sstevel@tonic-gate 			if ((ioctl(fd, DKIOCGGEOM, &dginfo)) == -1) {
14700Sstevel@tonic-gate 			    (void) close(fd);
14710Sstevel@tonic-gate 			    perror(
14720Sstevel@tonic-gate 				gettext("Drive geometry lookup (need "
14730Sstevel@tonic-gate 				    "tracks/cylinder and/or sectors/track"));
14740Sstevel@tonic-gate 			    exit(2);
14750Sstevel@tonic-gate 			}
14760Sstevel@tonic-gate 		    }
14770Sstevel@tonic-gate 		}
14780Sstevel@tonic-gate 	}
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	wbpb->bpb.heads = (GetTPC ? dginfo.dkg_nhead : TrkPerCyl);
14810Sstevel@tonic-gate 	wbpb->bpb.sectors_per_track = (GetSPT ? dginfo.dkg_nsect : SecPerTrk);
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	if (Verbose) {
14840Sstevel@tonic-gate 		if (GetTPC) {
14850Sstevel@tonic-gate 		    (void) printf(
14860Sstevel@tonic-gate 			gettext("DKIOCG determined number of heads = %d\n"),
14870Sstevel@tonic-gate 			dginfo.dkg_nhead);
14880Sstevel@tonic-gate 		}
14890Sstevel@tonic-gate 		if (GetSPT) {
14900Sstevel@tonic-gate 		    (void) printf(
14910Sstevel@tonic-gate 			gettext("DKIOCG determined sectors per track = %d\n"),
14920Sstevel@tonic-gate 			dginfo.dkg_nsect);
14930Sstevel@tonic-gate 		}
14940Sstevel@tonic-gate 	}
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	/*
14970Sstevel@tonic-gate 	 * XXX - MAY need an additional flag (or flags) to set media
14980Sstevel@tonic-gate 	 * and physical drive number fields.  That in the case of weird
14990Sstevel@tonic-gate 	 * floppies that have to go through 'nofdisk' route for formatting.
15000Sstevel@tonic-gate 	 */
15010Sstevel@tonic-gate 	wbpb->bpb.media = 0xF8;
15020Sstevel@tonic-gate 	if (MakeFAT32)
15030Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 0;
15040Sstevel@tonic-gate 	else
15050Sstevel@tonic-gate 		wbpb->bpb.num_root_entries = 512;
15060Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = 0x80;
15070Sstevel@tonic-gate 	compute_cluster_size(wbpb);
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate static
15110Sstevel@tonic-gate char *
15120Sstevel@tonic-gate stat_actual_disk(char *diskname, struct stat *info, char **suffix)
15130Sstevel@tonic-gate {
15140Sstevel@tonic-gate 	char *actualdisk;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	if (stat(diskname, info)) {
15170Sstevel@tonic-gate 		/*
15180Sstevel@tonic-gate 		 *  Device named on command line doesn't exist.  That
15190Sstevel@tonic-gate 		 *  probably means there is a partition-specifying
15200Sstevel@tonic-gate 		 *  suffix attached to the actual disk name.
15210Sstevel@tonic-gate 		 */
15220Sstevel@tonic-gate 		actualdisk = strtok(strdup(diskname), ":");
15230Sstevel@tonic-gate 		if (*suffix = strchr(diskname, ':'))
15240Sstevel@tonic-gate 			(*suffix)++;
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 		if (stat(actualdisk, info)) {
15270Sstevel@tonic-gate 			perror(actualdisk);
15280Sstevel@tonic-gate 			exit(2);
15290Sstevel@tonic-gate 		}
15300Sstevel@tonic-gate 	} else {
15310Sstevel@tonic-gate 		actualdisk = strdup(diskname);
15320Sstevel@tonic-gate 	}
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	return (actualdisk);
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate static
15380Sstevel@tonic-gate void
15390Sstevel@tonic-gate compute_file_area_size(bpb_t *wbpb)
15400Sstevel@tonic-gate {
15410Sstevel@tonic-gate 	/*
15420Sstevel@tonic-gate 	 * First we'll find total number of sectors in the file area...
15430Sstevel@tonic-gate 	 */
15440Sstevel@tonic-gate 	if (wbpb->bpb.sectors_in_volume > 0)
15450Sstevel@tonic-gate 		TotalClusters = wbpb->bpb.sectors_in_volume;
15460Sstevel@tonic-gate 	else
15470Sstevel@tonic-gate 		TotalClusters = wbpb->bpb.sectors_in_logical_volume;
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 	TotalClusters -= wbpb->bpb.resv_sectors;
15500Sstevel@tonic-gate 	TotalClusters -= wbpb->bpb.num_root_entries * sizeof (struct pcdir) /
15510Sstevel@tonic-gate 	    BPSEC;
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 	if (wbpb->bpb.sectors_per_fat) {
15540Sstevel@tonic-gate 		/*
15550Sstevel@tonic-gate 		 * Good old FAT12 or FAT16
15560Sstevel@tonic-gate 		 */
15570Sstevel@tonic-gate 		TotalClusters -= 2 * wbpb->bpb.sectors_per_fat;
15580Sstevel@tonic-gate 	} else {
15590Sstevel@tonic-gate 		/*
15600Sstevel@tonic-gate 		 *  FAT32
15610Sstevel@tonic-gate 		 */
15620Sstevel@tonic-gate 		TotalClusters -= 2 * wbpb->bpb32.big_sectors_per_fat;
15630Sstevel@tonic-gate 	}
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	/*
15660Sstevel@tonic-gate 	 * Now change sectors to clusters
15670Sstevel@tonic-gate 	 */
15680Sstevel@tonic-gate 	TotalClusters = TotalClusters / wbpb->bpb.sectors_per_cluster;
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	if (Verbose)
15710Sstevel@tonic-gate 		(void) printf(gettext("Disk has a file area of %d "
15720Sstevel@tonic-gate 		    "allocation units,\neach with %d sectors = %d "
15730Sstevel@tonic-gate 		    "bytes.\n"), TotalClusters, wbpb->bpb.sectors_per_cluster,
15740Sstevel@tonic-gate 		    TotalClusters * wbpb->bpb.sectors_per_cluster * BPSEC);
15750Sstevel@tonic-gate }
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate #ifndef i386
15780Sstevel@tonic-gate /*
15790Sstevel@tonic-gate  *  swap_pack_{bpb,bpb32,sebpb}cpy
15800Sstevel@tonic-gate  *
15810Sstevel@tonic-gate  *	If not on an x86 we assume the structures making up the bpb
15820Sstevel@tonic-gate  *	were not packed and that longs and shorts need to be byte swapped
15830Sstevel@tonic-gate  *	(we've kept everything in host order up until now).  A new architecture
15840Sstevel@tonic-gate  *	might not need to swap or might not need to pack, in which case
15850Sstevel@tonic-gate  *	new routines will have to be written.  Of course if an architecture
15860Sstevel@tonic-gate  *	supports both packing and little-endian host order, it can follow the
15870Sstevel@tonic-gate  *	same path as the x86 code.
15880Sstevel@tonic-gate  */
15890Sstevel@tonic-gate static
15900Sstevel@tonic-gate void
15910Sstevel@tonic-gate swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb)
15920Sstevel@tonic-gate {
15930Sstevel@tonic-gate 	uchar_t *fillp;
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.bytes_sector);
15980Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.sectors_per_cluster;
15990Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.resv_sectors);
16000Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.num_fats;
16010Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.num_root_entries);
16020Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_in_volume);
16030Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.media;
16040Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_fat);
16050Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_track);
16060Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.heads);
16070Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.hidden_sectors);
16080Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume);
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.phys_drive_num;
16110Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.reserved;
16120Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.ext_signature;
16130Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->ebpb.volume_id);
16140Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11);
16150Sstevel@tonic-gate 	fillp += 11;
16160Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8);
16170Sstevel@tonic-gate }
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate static
16200Sstevel@tonic-gate void
16210Sstevel@tonic-gate swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb)
16220Sstevel@tonic-gate {
16230Sstevel@tonic-gate 	uchar_t *fillp;
16240Sstevel@tonic-gate 	int r;
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.bytes_sector);
16290Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.sectors_per_cluster;
16300Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.resv_sectors);
16310Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.num_fats;
16320Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.num_root_entries);
16330Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_in_volume);
16340Sstevel@tonic-gate 	*fillp++ = wbpb->bpb.media;
16350Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_fat);
16360Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.sectors_per_track);
16370Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb.heads);
16380Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.hidden_sectors);
16390Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume);
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb32.big_sectors_per_fat);
16420Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.ext_flags);
16430Sstevel@tonic-gate 	*fillp++ = wbpb->bpb32.fs_vers_lo;
16440Sstevel@tonic-gate 	*fillp++ = wbpb->bpb32.fs_vers_hi;
16450Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->bpb32.root_dir_clust);
16460Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.fsinfosec);
16470Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->bpb32.backupboot);
16480Sstevel@tonic-gate 	for (r = 0; r < 6; r++)
16490Sstevel@tonic-gate 		store_16_bits(&fillp, wbpb->bpb32.reserved[r]);
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.phys_drive_num;
16520Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.reserved;
16530Sstevel@tonic-gate 	*fillp++ = wbpb->ebpb.ext_signature;
16540Sstevel@tonic-gate 	store_32_bits(&fillp, wbpb->ebpb.volume_id);
16550Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11);
16560Sstevel@tonic-gate 	fillp += 11;
16570Sstevel@tonic-gate 	(void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8);
16580Sstevel@tonic-gate }
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate static
16610Sstevel@tonic-gate void
16620Sstevel@tonic-gate swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb)
16630Sstevel@tonic-gate {
16640Sstevel@tonic-gate 	uchar_t *fillp;
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 	fillp = bsp->bs_sun_bpb;
16670Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->sunbpb.bs_offset_high);
16680Sstevel@tonic-gate 	store_16_bits(&fillp, wbpb->sunbpb.bs_offset_low);
16690Sstevel@tonic-gate }
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate static
16720Sstevel@tonic-gate void
16730Sstevel@tonic-gate swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp)
16740Sstevel@tonic-gate {
16750Sstevel@tonic-gate 	uchar_t *grabp;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	grabp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.bytes_sector))[1] = *grabp++;
16800Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.bytes_sector))[0] = *grabp++;
16810Sstevel@tonic-gate 	wbpb->bpb.sectors_per_cluster = *grabp++;
16820Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.resv_sectors))[1] = *grabp++;
16830Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.resv_sectors))[0] = *grabp++;
16840Sstevel@tonic-gate 	wbpb->bpb.num_fats = *grabp++;
16850Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.num_root_entries))[1] = *grabp++;
16860Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.num_root_entries))[0] = *grabp++;
16870Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_volume))[1] = *grabp++;
16880Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_volume))[0] = *grabp++;
16890Sstevel@tonic-gate 	wbpb->bpb.media = *grabp++;
16900Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_fat))[1] = *grabp++;
16910Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_fat))[0] = *grabp++;
16920Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_track))[1] = *grabp++;
16930Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_per_track))[0] = *grabp++;
16940Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.heads))[1] = *grabp++;
16950Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.heads))[0] = *grabp++;
16960Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[3] = *grabp++;
16970Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[2] = *grabp++;
16980Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[1] = *grabp++;
16990Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.hidden_sectors))[0] = *grabp++;
17000Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[3] = *grabp++;
17010Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[2] = *grabp++;
17020Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[1] = *grabp++;
17030Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[0] = *grabp++;
17040Sstevel@tonic-gate 	wbpb->ebpb.phys_drive_num = *grabp++;
17050Sstevel@tonic-gate 	wbpb->ebpb.reserved = *grabp++;
17060Sstevel@tonic-gate 	wbpb->ebpb.ext_signature = *grabp++;
17070Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[3] = *grabp++;
17080Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[2] = *grabp++;
17090Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[1] = *grabp++;
17100Sstevel@tonic-gate 	((uchar_t *)&(wbpb->ebpb.volume_id))[0] = *grabp++;
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	(void) strncpy((char *)wbpb->ebpb.volume_label, (char *)grabp, 11);
17130Sstevel@tonic-gate 	grabp += 11;
17140Sstevel@tonic-gate 	(void) strncpy((char *)wbpb->ebpb.type, (char *)grabp, 8);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate static
17180Sstevel@tonic-gate void
17190Sstevel@tonic-gate swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp)
17200Sstevel@tonic-gate {
17210Sstevel@tonic-gate 	uchar_t *grabp;
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	grabp = bsp->bs_sun_bpb;
17240Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[1] = *grabp++;
17250Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[0] = *grabp++;
17260Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[1] = *grabp++;
17270Sstevel@tonic-gate 	((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[0] = *grabp++;
17280Sstevel@tonic-gate }
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate static
17310Sstevel@tonic-gate void
17320Sstevel@tonic-gate swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp)
17330Sstevel@tonic-gate {
17340Sstevel@tonic-gate 	uchar_t *grabp;
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	grabp = (uchar_t *)&(bsp->bs_filler[BPB_32_START_INDEX]);
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[3] = *grabp++;
17390Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[2] = *grabp++;
17400Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[1] = *grabp++;
17410Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[0] = *grabp++;
17420Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.ext_flags))[1] = *grabp++;
17430Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.ext_flags))[0] = *grabp++;
17440Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_lo = *grabp++;
17450Sstevel@tonic-gate 	wbpb->bpb32.fs_vers_hi = *grabp++;
17460Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[3] = *grabp++;
17470Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[2] = *grabp++;
17480Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[1] = *grabp++;
17490Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.root_dir_clust))[0] = *grabp++;
17500Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.fsinfosec))[1] = *grabp++;
17510Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.fsinfosec))[0] = *grabp++;
17520Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.backupboot))[1] = *grabp++;
17530Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.backupboot))[0] = *grabp++;
17540Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[0]))[1] = *grabp++;
17550Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[0]))[0] = *grabp++;
17560Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[1]))[1] = *grabp++;
17570Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[1]))[0] = *grabp++;
17580Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[2]))[1] = *grabp++;
17590Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[2]))[0] = *grabp++;
17600Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[3]))[1] = *grabp++;
17610Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[3]))[0] = *grabp++;
17620Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[4]))[1] = *grabp++;
17630Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[4]))[0] = *grabp++;
17640Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[5]))[1] = *grabp++;
17650Sstevel@tonic-gate 	((uchar_t *)&(wbpb->bpb32.reserved[5]))[0] = *grabp++;
17660Sstevel@tonic-gate }
17670Sstevel@tonic-gate #endif	/* ! i386 */
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate static
17700Sstevel@tonic-gate void
17710Sstevel@tonic-gate dashm_bail(int fd)
17720Sstevel@tonic-gate {
17730Sstevel@tonic-gate 	(void) fprintf(stderr,
17740Sstevel@tonic-gate 		gettext("This media does not appear to be "
17750Sstevel@tonic-gate 			"formatted with a FAT file system.\n"));
17760Sstevel@tonic-gate 	(void) close(fd);
17770Sstevel@tonic-gate 	exit(6);
17780Sstevel@tonic-gate }
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate /*
17810Sstevel@tonic-gate  *  read_existing_bpb
17820Sstevel@tonic-gate  *
17830Sstevel@tonic-gate  *	Grab the first sector, which we think is a bios parameter block.
17840Sstevel@tonic-gate  *	If it looks bad, bail.  Otherwise fill in the parameter struct
17850Sstevel@tonic-gate  *	fields that matter.
17860Sstevel@tonic-gate  */
17870Sstevel@tonic-gate static
17880Sstevel@tonic-gate void
17890Sstevel@tonic-gate read_existing_bpb(int fd, bpb_t *wbpb)
17900Sstevel@tonic-gate {
17910Sstevel@tonic-gate 	boot_sector_t ubpb;
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	if (read(fd, ubpb.buf, BPSEC) < BPSEC) {
17940Sstevel@tonic-gate 		perror(gettext("Read BIOS parameter block "
17950Sstevel@tonic-gate 			"from previously formatted media"));
17960Sstevel@tonic-gate 		(void) close(fd);
17970Sstevel@tonic-gate 		exit(6);
17980Sstevel@tonic-gate 	}
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	if (ltohs(ubpb.mb.signature) != BOOTSECSIG) {
18010Sstevel@tonic-gate 		dashm_bail(fd);
18020Sstevel@tonic-gate 	}
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate #ifdef i386
18050Sstevel@tonic-gate 	(void) memcpy(&(wbpb->bpb), &(ubpb.bs.bs_front.bs_bpb),
18060Sstevel@tonic-gate 		sizeof (wbpb->bpb));
18070Sstevel@tonic-gate 	(void) memcpy(&(wbpb->ebpb), &(ubpb.bs.bs_ebpb), sizeof (wbpb->ebpb));
18080Sstevel@tonic-gate #else
18090Sstevel@tonic-gate 	swap_pack_grabbpb(wbpb, &(ubpb.bs));
18100Sstevel@tonic-gate #endif
18110Sstevel@tonic-gate 	if (SunBPBfields) {
18120Sstevel@tonic-gate #ifdef i386
18130Sstevel@tonic-gate 		(void) memcpy(&(wbpb->sunbpb), &(ubpb.bs.bs_sebpb),
18140Sstevel@tonic-gate 			sizeof (wbpb->sunbpb));
18150Sstevel@tonic-gate #else
18160Sstevel@tonic-gate 		swap_pack_grabsebpb(wbpb, &(ubpb.bs));
18170Sstevel@tonic-gate #endif
18180Sstevel@tonic-gate 	}
18190Sstevel@tonic-gate 	if (wbpb->bpb.bytes_sector != BPSEC) {
18200Sstevel@tonic-gate 		(void) fprintf(stderr,
18210Sstevel@tonic-gate 		    gettext("Bogus bytes per sector value.\n"));
18220Sstevel@tonic-gate 		if (!powerofx_le_y(2, BPSEC * 8, wbpb->bpb.bytes_sector)) {
18230Sstevel@tonic-gate 			(void) fprintf(stderr,
18240Sstevel@tonic-gate 			    gettext("The device name may be missing a "
18250Sstevel@tonic-gate 				    "logical drive specifier.\n"));
18260Sstevel@tonic-gate 			(void) close(fd);
18270Sstevel@tonic-gate 			exit(6);
18280Sstevel@tonic-gate 		} else {
18290Sstevel@tonic-gate 			(void) fprintf(stderr,
18300Sstevel@tonic-gate 			    gettext("Do not know how to build FATs with a\n"
18310Sstevel@tonic-gate 				    "non-standard sector size. Standard "
18320Sstevel@tonic-gate 				    "size is %d bytes,\nyour sector size "
18330Sstevel@tonic-gate 				    "is %d bytes.\n"), BPSEC,
18340Sstevel@tonic-gate 				    wbpb->bpb.bytes_sector);
18350Sstevel@tonic-gate 			(void) close(fd);
18360Sstevel@tonic-gate 			exit(6);
18370Sstevel@tonic-gate 		}
18380Sstevel@tonic-gate 	}
18390Sstevel@tonic-gate 	if (!(powerofx_le_y(2, 128, wbpb->bpb.sectors_per_cluster))) {
18400Sstevel@tonic-gate 		(void) fprintf(stderr,
18410Sstevel@tonic-gate 		    gettext("Bogus sectors per cluster value.\n"));
18420Sstevel@tonic-gate 		(void) fprintf(stderr,
18430Sstevel@tonic-gate 		    gettext("The device name may be missing a "
18440Sstevel@tonic-gate 			"logical drive specifier.\n"));
18450Sstevel@tonic-gate 		(void) close(fd);
18460Sstevel@tonic-gate 		exit(6);
18470Sstevel@tonic-gate 	}
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	if (wbpb->bpb.sectors_per_fat == 0) {
18500Sstevel@tonic-gate #ifdef i386
18510Sstevel@tonic-gate 		(void) memcpy(&(wbpb->bpb32), &(ubpb.bs32.bs_bpb32),
18520Sstevel@tonic-gate 			sizeof (wbpb->bpb32));
18530Sstevel@tonic-gate #else
18540Sstevel@tonic-gate 		swap_pack_grab32bpb(wbpb, &(ubpb.bs));
18550Sstevel@tonic-gate #endif
18560Sstevel@tonic-gate 		compute_file_area_size(wbpb);
18570Sstevel@tonic-gate 		if ((wbpb->bpb32.big_sectors_per_fat * BPSEC / 4) >=
18580Sstevel@tonic-gate 		    TotalClusters) {
18590Sstevel@tonic-gate 			MakeFAT32 = 1;
18600Sstevel@tonic-gate 		} else {
18610Sstevel@tonic-gate 			dashm_bail(fd);
18620Sstevel@tonic-gate 		}
18630Sstevel@tonic-gate 	} else {
18640Sstevel@tonic-gate 		compute_file_area_size(wbpb);
18650Sstevel@tonic-gate 	}
18660Sstevel@tonic-gate }
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate /*
18690Sstevel@tonic-gate  *  compare_existing_with_computed
18700Sstevel@tonic-gate  *
18710Sstevel@tonic-gate  *	We use this function when we the user specifies the -m option.
18720Sstevel@tonic-gate  *	We compute and look up things like we would if they had asked
18730Sstevel@tonic-gate  *	us to make the fs, and compare that to what's already layed down
18740Sstevel@tonic-gate  *	in the existing fs.  If there's a difference we can tell them what
18750Sstevel@tonic-gate  *	options to specify in order to reproduce their existing layout.
18760Sstevel@tonic-gate  *	Note that they still may not get an exact duplicate, because we
18770Sstevel@tonic-gate  *	don't, for example, preserve their existing boot code.  We think
18780Sstevel@tonic-gate  *	we've got all the fields that matter covered, though.
18790Sstevel@tonic-gate  *
18800Sstevel@tonic-gate  *	XXX - We're basically ignoring sbpb at this point.  I'm unsure
18810Sstevel@tonic-gate  *	if we'll ever care about those fields, in terms of the -m option.
18820Sstevel@tonic-gate  */
18830Sstevel@tonic-gate static
18840Sstevel@tonic-gate void
18850Sstevel@tonic-gate compare_existing_with_computed(int fd, char *suffix,
18860Sstevel@tonic-gate     bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect,
18870Sstevel@tonic-gate     int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd, int *dashos)
18880Sstevel@tonic-gate {
18890Sstevel@tonic-gate 	struct dk_geom	dginfo;
18900Sstevel@tonic-gate 	struct fd_char	fdchar;
18910Sstevel@tonic-gate 	bpb_t		compare;
18920Sstevel@tonic-gate 	int		fd_ioctl_worked = 0;
18930Sstevel@tonic-gate 	int		fatents;
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	/*
18960Sstevel@tonic-gate 	 *  For all non-floppy cases we expect to find a 16-bit FAT
18970Sstevel@tonic-gate 	 */
18980Sstevel@tonic-gate 	int expectfatsize = 16;
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	compare = *wbpb;
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	if (!suffix) {
19030Sstevel@tonic-gate 		if (ioctl(fd, FDIOGCHAR, &fdchar) != -1) {
19040Sstevel@tonic-gate 			expectfatsize = 12;
19050Sstevel@tonic-gate 			fd_ioctl_worked++;
19060Sstevel@tonic-gate 		}
19070Sstevel@tonic-gate 	}
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	if (fd_ioctl_worked) {
19100Sstevel@tonic-gate #ifdef sparc
19110Sstevel@tonic-gate 		fdchar.fdc_medium = 3;
19120Sstevel@tonic-gate #endif
19130Sstevel@tonic-gate 		GetSize = GetSPT = GetSPC = GetTPC = GetBPF = 1;
19140Sstevel@tonic-gate 		lookup_floppy(&fdchar, &compare);
19150Sstevel@tonic-gate 		if (compare.bpb.heads != wbpb->bpb.heads) {
19160Sstevel@tonic-gate 			(*prtntrk)++;
19170Sstevel@tonic-gate 			(*dashos)++;
19180Sstevel@tonic-gate 		}
19190Sstevel@tonic-gate 		if (compare.bpb.sectors_per_track !=
19200Sstevel@tonic-gate 		    wbpb->bpb.sectors_per_track) {
19210Sstevel@tonic-gate 			(*prtnsect)++;
19220Sstevel@tonic-gate 			(*dashos)++;
19230Sstevel@tonic-gate 		}
19240Sstevel@tonic-gate 	} else {
19250Sstevel@tonic-gate 		int dk_ioctl_worked = 1;
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 		if (!suffix) {
19280Sstevel@tonic-gate 			(*prtfdisk)++;
19290Sstevel@tonic-gate 			(*prtsize)++;
19300Sstevel@tonic-gate 			*dashos += 2;
19310Sstevel@tonic-gate 		}
19320Sstevel@tonic-gate 		if ((ioctl(fd, DKIOCG_VIRTGEOM, &dginfo)) == -1) {
19330Sstevel@tonic-gate 		    if ((ioctl(fd, DKIOCG_PHYGEOM, &dginfo)) == -1) {
19340Sstevel@tonic-gate 			if ((ioctl(fd, DKIOCGGEOM, &dginfo)) == -1) {
19350Sstevel@tonic-gate 				*prtnsect = *prtntrk = 1;
19360Sstevel@tonic-gate 				*dashos += 2;
19370Sstevel@tonic-gate 				dk_ioctl_worked = 0;
19380Sstevel@tonic-gate 			}
19390Sstevel@tonic-gate 		    }
19400Sstevel@tonic-gate 		}
19410Sstevel@tonic-gate 		if (dk_ioctl_worked) {
19420Sstevel@tonic-gate 			if (dginfo.dkg_nhead != wbpb->bpb.heads) {
19430Sstevel@tonic-gate 				(*prtntrk)++;
19440Sstevel@tonic-gate 				(*dashos)++;
19450Sstevel@tonic-gate 			}
19460Sstevel@tonic-gate 			if (dginfo.dkg_nsect !=
19470Sstevel@tonic-gate 			    wbpb->bpb.sectors_per_track) {
19480Sstevel@tonic-gate 				(*prtnsect)++;
19490Sstevel@tonic-gate 				(*dashos)++;
19500Sstevel@tonic-gate 			}
19510Sstevel@tonic-gate 		}
19520Sstevel@tonic-gate 		GetBPF = GetSPC = 1;
19530Sstevel@tonic-gate 		compute_cluster_size(&compare);
19540Sstevel@tonic-gate 	}
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	if (!*prtfdisk && TotSize != wbpb->bpb.sectors_in_volume &&
19570Sstevel@tonic-gate 		TotSize != wbpb->bpb.sectors_in_logical_volume) {
19580Sstevel@tonic-gate 		(*dashos)++;
19590Sstevel@tonic-gate 		(*prtsize)++;
19600Sstevel@tonic-gate 	}
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 	if (compare.bpb.sectors_per_cluster != wbpb->bpb.sectors_per_cluster) {
19630Sstevel@tonic-gate 		(*dashos)++;
19640Sstevel@tonic-gate 		(*prtspc)++;
19650Sstevel@tonic-gate 	}
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	if (compare.bpb.hidden_sectors != wbpb->bpb.hidden_sectors) {
19680Sstevel@tonic-gate 		(*dashos)++;
19690Sstevel@tonic-gate 		(*prthidden)++;
19700Sstevel@tonic-gate 	}
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 	if (compare.bpb.resv_sectors != wbpb->bpb.resv_sectors) {
19730Sstevel@tonic-gate 		(*dashos)++;
19740Sstevel@tonic-gate 		(*prtrsrvd)++;
19750Sstevel@tonic-gate 	}
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	/*
19780Sstevel@tonic-gate 	 * Compute approximate Fatentsize.  It's approximate because the
19790Sstevel@tonic-gate 	 * size of the FAT may not be exactly a multiple of the number of
19800Sstevel@tonic-gate 	 * clusters.  It should be close, though.
19810Sstevel@tonic-gate 	 */
19820Sstevel@tonic-gate 	if (MakeFAT32) {
19830Sstevel@tonic-gate 		Fatentsize = 32;
19840Sstevel@tonic-gate 		(*dashos)++;
19850Sstevel@tonic-gate 		(*prtbpf)++;
19860Sstevel@tonic-gate 	} else {
19870Sstevel@tonic-gate 		fatents = wbpb->bpb.sectors_per_fat * BPSEC * 2 / 3;
19880Sstevel@tonic-gate 		if (fatents >= TotalClusters && wbpb->ebpb.type[4] == '2')
19890Sstevel@tonic-gate 			Fatentsize = 12;
19900Sstevel@tonic-gate 		else
19910Sstevel@tonic-gate 			Fatentsize = 16;
19920Sstevel@tonic-gate 		if (Fatentsize != expectfatsize) {
19930Sstevel@tonic-gate 			(*dashos)++;
19940Sstevel@tonic-gate 			(*prtbpf)++;
19950Sstevel@tonic-gate 		}
19960Sstevel@tonic-gate 	}
19970Sstevel@tonic-gate }
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate static
20000Sstevel@tonic-gate void
20010Sstevel@tonic-gate print_reproducing_command(int fd, char *actualdisk, char *suffix, bpb_t *wbpb)
20020Sstevel@tonic-gate {
20030Sstevel@tonic-gate 	int needcomma = 0;
20040Sstevel@tonic-gate 	int prthidden = 0;
20050Sstevel@tonic-gate 	int prtrsrvd = 0;
20060Sstevel@tonic-gate 	int prtfdisk = 0;
20070Sstevel@tonic-gate 	int prtnsect = 0;
20080Sstevel@tonic-gate 	int prtntrk = 0;
20090Sstevel@tonic-gate 	int prtsize = 0;
20100Sstevel@tonic-gate 	int prtbpf = 0;
20110Sstevel@tonic-gate 	int prtspc = 0;
20120Sstevel@tonic-gate 	int dashos = 0;
20130Sstevel@tonic-gate 	int ll, i;
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	compare_existing_with_computed(fd, suffix, wbpb,
20160Sstevel@tonic-gate 	    &prtsize, &prtspc, &prtbpf, &prtnsect, &prtntrk,
20170Sstevel@tonic-gate 	    &prtfdisk, &prthidden, &prtrsrvd, &dashos);
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 	/*
20200Sstevel@tonic-gate 	 *  Print out the command line they can use to reproduce the
20210Sstevel@tonic-gate 	 *  file system.
20220Sstevel@tonic-gate 	 */
20230Sstevel@tonic-gate 	(void) printf("mkfs -F pcfs");
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate 	ll = min(11, (int)strlen((char *)wbpb->ebpb.volume_label));
20260Sstevel@tonic-gate 	/*
20270Sstevel@tonic-gate 	 * First, eliminate trailing spaces. Now compare the name against
20280Sstevel@tonic-gate 	 * our default label.  If there's a match we don't need to print
20290Sstevel@tonic-gate 	 * any label info.
20300Sstevel@tonic-gate 	 */
20310Sstevel@tonic-gate 	i = ll;
20320Sstevel@tonic-gate 	while (wbpb->ebpb.volume_label[--i] == ' ');
20330Sstevel@tonic-gate 	ll = i;
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	if (ll == strlen(DEFAULT_LABEL) - 1) {
20360Sstevel@tonic-gate 		char cmpbuf[11];
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 		(void) strcpy(cmpbuf, DEFAULT_LABEL);
20390Sstevel@tonic-gate 		for (i = ll; i >= 0; i--) {
20400Sstevel@tonic-gate 			if (cmpbuf[i] !=
20410Sstevel@tonic-gate 			    toupper((int)(wbpb->ebpb.volume_label[i]))) {
20420Sstevel@tonic-gate 				break;
20430Sstevel@tonic-gate 			}
20440Sstevel@tonic-gate 		}
20450Sstevel@tonic-gate 		if (i < 0)
20460Sstevel@tonic-gate 			ll = i;
20470Sstevel@tonic-gate 	}
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 	if (ll >= 0) {
20500Sstevel@tonic-gate 		(void) printf(" -o ");
20510Sstevel@tonic-gate 		(void) printf("b=\"");
20520Sstevel@tonic-gate 		for (i = 0; i <= ll; i++) {
20530Sstevel@tonic-gate 			(void) printf("%c", wbpb->ebpb.volume_label[i]);
20540Sstevel@tonic-gate 		}
20550Sstevel@tonic-gate 		(void) printf("\"");
20560Sstevel@tonic-gate 		needcomma++;
20570Sstevel@tonic-gate 	} else if (dashos) {
20580Sstevel@tonic-gate 		(void) printf(" -o ");
20590Sstevel@tonic-gate 	}
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate #define	NEXT_DASH_O	dashos--; needcomma++; continue
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	while (dashos) {
20640Sstevel@tonic-gate 		if (needcomma) {
20650Sstevel@tonic-gate 			(void) printf(",");
20660Sstevel@tonic-gate 			needcomma = 0;
20670Sstevel@tonic-gate 		}
20680Sstevel@tonic-gate 		if (prtfdisk) {
20690Sstevel@tonic-gate 			(void) printf("nofdisk");
20700Sstevel@tonic-gate 			prtfdisk--;
20710Sstevel@tonic-gate 			NEXT_DASH_O;
20720Sstevel@tonic-gate 		}
20730Sstevel@tonic-gate 		if (prtsize) {
20740Sstevel@tonic-gate 			(void) printf("size=%u", wbpb->bpb.sectors_in_volume ?
20750Sstevel@tonic-gate 			    wbpb->bpb.sectors_in_volume :
20760Sstevel@tonic-gate 			    wbpb->bpb.sectors_in_logical_volume);
20770Sstevel@tonic-gate 			prtsize--;
20780Sstevel@tonic-gate 			NEXT_DASH_O;
20790Sstevel@tonic-gate 		}
20800Sstevel@tonic-gate 		if (prtnsect) {
20810Sstevel@tonic-gate 			(void) printf("nsect=%d", wbpb->bpb.sectors_per_track);
20820Sstevel@tonic-gate 			prtnsect--;
20830Sstevel@tonic-gate 			NEXT_DASH_O;
20840Sstevel@tonic-gate 		}
20850Sstevel@tonic-gate 		if (prtspc) {
20860Sstevel@tonic-gate 			(void) printf("spc=%d", wbpb->bpb.sectors_per_cluster);
20870Sstevel@tonic-gate 			prtspc--;
20880Sstevel@tonic-gate 			NEXT_DASH_O;
20890Sstevel@tonic-gate 		}
20900Sstevel@tonic-gate 		if (prtntrk) {
20910Sstevel@tonic-gate 			(void) printf("ntrack=%d", wbpb->bpb.heads);
20920Sstevel@tonic-gate 			prtntrk--;
20930Sstevel@tonic-gate 			NEXT_DASH_O;
20940Sstevel@tonic-gate 		}
20950Sstevel@tonic-gate 		if (prtbpf) {
20960Sstevel@tonic-gate 			(void) printf("fat=%d", Fatentsize);
20970Sstevel@tonic-gate 			prtbpf--;
20980Sstevel@tonic-gate 			NEXT_DASH_O;
20990Sstevel@tonic-gate 		}
21000Sstevel@tonic-gate 		if (prthidden) {
21010Sstevel@tonic-gate 			(void) printf("hidden=%u", wbpb->bpb.hidden_sectors);
21020Sstevel@tonic-gate 			prthidden--;
21030Sstevel@tonic-gate 			NEXT_DASH_O;
21040Sstevel@tonic-gate 		}
21050Sstevel@tonic-gate 		if (prtrsrvd) {
21060Sstevel@tonic-gate 			(void) printf("reserve=%d", wbpb->bpb.resv_sectors);
21070Sstevel@tonic-gate 			prtrsrvd--;
21080Sstevel@tonic-gate 			NEXT_DASH_O;
21090Sstevel@tonic-gate 		}
21100Sstevel@tonic-gate 	}
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 	(void) printf(" %s%c%c\n", actualdisk,
21130Sstevel@tonic-gate 	    suffix ? ':' : '\0', suffix ? *suffix : '\0');
21140Sstevel@tonic-gate }
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate /*
21170Sstevel@tonic-gate  *  open_and_examine
21180Sstevel@tonic-gate  *
21190Sstevel@tonic-gate  *	Open the requested 'dev_name'.  Seek to point where
21200Sstevel@tonic-gate  *	we'd expect to find boot sectors, etc., based on any ':partition'
21210Sstevel@tonic-gate  *	attachments to the dev_name.
21220Sstevel@tonic-gate  *
21230Sstevel@tonic-gate  *	Examine the fields of any existing boot sector and display best
21240Sstevel@tonic-gate  *	approximation of how this fs could be reproduced with this command.
21250Sstevel@tonic-gate  */
21260Sstevel@tonic-gate static
21270Sstevel@tonic-gate int
21280Sstevel@tonic-gate open_and_examine(char *dn, bpb_t *wbpb)
21290Sstevel@tonic-gate {
21300Sstevel@tonic-gate 	struct stat di;
21310Sstevel@tonic-gate 	off64_t ignored;
21320Sstevel@tonic-gate 	char *actualdisk = NULL;
21330Sstevel@tonic-gate 	char *suffix = NULL;
21340Sstevel@tonic-gate 	int fd;
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 	if (Verbose)
21370Sstevel@tonic-gate 		(void) printf(gettext("Opening destination device/file.\n"));
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	actualdisk = stat_actual_disk(dn, &di, &suffix);
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 	/*
21420Sstevel@tonic-gate 	 *  Destination exists, now find more about it.
21430Sstevel@tonic-gate 	 */
21440Sstevel@tonic-gate 	if (!(S_ISCHR(di.st_mode))) {
21450Sstevel@tonic-gate 		(void) fprintf(stderr,
21460Sstevel@tonic-gate 		    gettext("\n%s: device name must be a "
21470Sstevel@tonic-gate 			"character special device.\n"), actualdisk);
21480Sstevel@tonic-gate 		exit(2);
21490Sstevel@tonic-gate 	} else if ((fd = open(actualdisk, O_RDWR | O_EXCL)) < 0) {
21500Sstevel@tonic-gate 		perror(actualdisk);
21510Sstevel@tonic-gate 		exit(2);
21520Sstevel@tonic-gate 	}
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate 	/*
21550Sstevel@tonic-gate 	 * Find appropriate partition if we were requested to do so.
21560Sstevel@tonic-gate 	 */
21570Sstevel@tonic-gate 	if (suffix && !(seek_partn(fd, suffix, wbpb, &ignored))) {
21580Sstevel@tonic-gate 		(void) close(fd);
21590Sstevel@tonic-gate 		exit(2);
21600Sstevel@tonic-gate 	}
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 	read_existing_bpb(fd, wbpb);
21630Sstevel@tonic-gate 	print_reproducing_command(fd, actualdisk, suffix, wbpb);
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	return (fd);
21660Sstevel@tonic-gate }
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate /*
21690Sstevel@tonic-gate  *  open_and_seek
21700Sstevel@tonic-gate  *
21710Sstevel@tonic-gate  *	Open the requested 'dev_name'.  Seek to point where
21720Sstevel@tonic-gate  *	we'll write boot sectors, etc., based on any ':partition'
21730Sstevel@tonic-gate  *	attachments to the dev_name.
21740Sstevel@tonic-gate  *
21750Sstevel@tonic-gate  *	By the time we are finished here, the entire BPB will be
21760Sstevel@tonic-gate  *	filled in, excepting the volume label.
21770Sstevel@tonic-gate  */
21780Sstevel@tonic-gate static
21790Sstevel@tonic-gate int
21800Sstevel@tonic-gate open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto)
21810Sstevel@tonic-gate {
21820Sstevel@tonic-gate 	struct fd_char fdchar;
21830Sstevel@tonic-gate 	struct stat di;
21840Sstevel@tonic-gate 	char *actualdisk = NULL;
21850Sstevel@tonic-gate 	char *suffix = NULL;
21860Sstevel@tonic-gate 	int fd;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	if (Verbose)
21890Sstevel@tonic-gate 		(void) printf(gettext("Opening destination device/file.\n"));
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate 	/*
21920Sstevel@tonic-gate 	 * We hold these truths to be self evident, all BPBs we create
21930Sstevel@tonic-gate 	 * will have these values in these fields.
21940Sstevel@tonic-gate 	 */
21950Sstevel@tonic-gate 	wbpb->bpb.num_fats = 2;
21960Sstevel@tonic-gate 	wbpb->bpb.bytes_sector = BPSEC;
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 	/*
21990Sstevel@tonic-gate 	 * Assign or use supplied numbers for hidden and
22000Sstevel@tonic-gate 	 * reserved sectors in the file system.
22010Sstevel@tonic-gate 	 */
22020Sstevel@tonic-gate 	if (GetResrvd)
22030Sstevel@tonic-gate 		if (MakeFAT32)
22040Sstevel@tonic-gate 			wbpb->bpb.resv_sectors = 32;
22050Sstevel@tonic-gate 		else
22060Sstevel@tonic-gate 			wbpb->bpb.resv_sectors = 1;
22070Sstevel@tonic-gate 	else
22080Sstevel@tonic-gate 		wbpb->bpb.resv_sectors = Resrvd;
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	wbpb->ebpb.ext_signature = 0x29; /* Magic number for modern format */
22110Sstevel@tonic-gate 	wbpb->ebpb.volume_id = 0;
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	if (MakeFAT32)
22140Sstevel@tonic-gate 		fill_fat32_bpb(wbpb);
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	/*
22170Sstevel@tonic-gate 	 * If all output goes to a simple file, call a routine to setup
22180Sstevel@tonic-gate 	 * that scenario. Otherwise, try to find the device.
22190Sstevel@tonic-gate 	 */
22200Sstevel@tonic-gate 	if (Outputtofile)
22210Sstevel@tonic-gate 		return (fd = prepare_image_file(dn, wbpb));
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 	actualdisk = stat_actual_disk(dn, &di, &suffix);
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 	/*
22260Sstevel@tonic-gate 	 * Sanity check.  If we've been provided a partition-specifying
22270Sstevel@tonic-gate 	 * suffix, we shouldn't also have been told to ignore the
22280Sstevel@tonic-gate 	 * fdisk table.
22290Sstevel@tonic-gate 	 */
22300Sstevel@tonic-gate 	if (DontUseFdisk && suffix) {
22310Sstevel@tonic-gate 		(void) fprintf(stderr,
22320Sstevel@tonic-gate 		    gettext("Using 'nofdisk' option precludes "
22330Sstevel@tonic-gate 			    "appending logical drive\nspecifier "
22340Sstevel@tonic-gate 			    "to the device name.\n"));
22350Sstevel@tonic-gate 		exit(2);
22360Sstevel@tonic-gate 	}
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate 	/*
22390Sstevel@tonic-gate 	 *  Destination exists, now find more about it.
22400Sstevel@tonic-gate 	 */
22410Sstevel@tonic-gate 	if (!(S_ISCHR(di.st_mode))) {
22420Sstevel@tonic-gate 		(void) fprintf(stderr,
22430Sstevel@tonic-gate 		    gettext("\n%s: device name must indicate a "
22440Sstevel@tonic-gate 			"character special device.\n"), actualdisk);
22450Sstevel@tonic-gate 		exit(2);
22460Sstevel@tonic-gate 	} else if ((fd = open(actualdisk, O_RDWR | O_EXCL)) < 0) {
22470Sstevel@tonic-gate 		perror(actualdisk);
22480Sstevel@tonic-gate 		exit(2);
22490Sstevel@tonic-gate 	}
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate 	/*
22520Sstevel@tonic-gate 	 * Find appropriate partition if we were requested to do so.
22530Sstevel@tonic-gate 	 */
22540Sstevel@tonic-gate 	if (suffix && !(seek_partn(fd, suffix, wbpb, seekto))) {
22550Sstevel@tonic-gate 		(void) close(fd);
22560Sstevel@tonic-gate 		exit(2);
22570Sstevel@tonic-gate 	}
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate 	if (!suffix) {
22600Sstevel@tonic-gate 		/*
22610Sstevel@tonic-gate 		 * We have one of two possibilities.  Chances are we have
22620Sstevel@tonic-gate 		 * a floppy drive.  But the user may be trying to format
22630Sstevel@tonic-gate 		 * some weird drive that we don't know about and is supplying
22640Sstevel@tonic-gate 		 * all the important values.  In that case, they should have set
22650Sstevel@tonic-gate 		 * the 'nofdisk' flag.
22660Sstevel@tonic-gate 		 *
22670Sstevel@tonic-gate 		 * If 'nofdisk' isn't set, do a floppy-specific ioctl to
22680Sstevel@tonic-gate 		 * get the remainder of our info. If the ioctl fails, we have
22690Sstevel@tonic-gate 		 * a good idea that they aren't really on a floppy.  In that
22700Sstevel@tonic-gate 		 * case, they should have given us a partition specifier.
22710Sstevel@tonic-gate 		 */
22720Sstevel@tonic-gate 		if (DontUseFdisk) {
22730Sstevel@tonic-gate 			if (!(seek_nofdisk(fd, wbpb, seekto))) {
22740Sstevel@tonic-gate 				(void) close(fd);
22750Sstevel@tonic-gate 				exit(2);
22760Sstevel@tonic-gate 			}
22770Sstevel@tonic-gate 			find_fixed_details(fd, wbpb);
22780Sstevel@tonic-gate 		} else if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) {
22790Sstevel@tonic-gate 			if (errno == ENOTTY) {
22800Sstevel@tonic-gate 				partn_lecture(actualdisk);
22810Sstevel@tonic-gate 				(void) close(fd);
22820Sstevel@tonic-gate 				exit(2);
22830Sstevel@tonic-gate 			}
22840Sstevel@tonic-gate 		} else {
22850Sstevel@tonic-gate #ifdef sparc
22860Sstevel@tonic-gate 			fdchar.fdc_medium = 3;
22870Sstevel@tonic-gate #endif
22880Sstevel@tonic-gate 			lookup_floppy(&fdchar, wbpb);
22890Sstevel@tonic-gate 		}
22900Sstevel@tonic-gate 	} else {
22910Sstevel@tonic-gate 		find_fixed_details(fd, wbpb);
22920Sstevel@tonic-gate 	}
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 	return (fd);
22950Sstevel@tonic-gate }
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate /*
22980Sstevel@tonic-gate  * The following is a copy of MS-DOS 4.0 boot block.
22990Sstevel@tonic-gate  * It consists of the BIOS parameter block, and a disk
23000Sstevel@tonic-gate  * bootstrap program.
23010Sstevel@tonic-gate  *
23020Sstevel@tonic-gate  * The BIOS parameter block contains the right values
23030Sstevel@tonic-gate  * for the 3.5" high-density 1.44MB floppy format.
23040Sstevel@tonic-gate  *
23050Sstevel@tonic-gate  * This will be our default boot sector, if the user
23060Sstevel@tonic-gate  * didn't point us at a different one.
23070Sstevel@tonic-gate  *
23080Sstevel@tonic-gate  */
23090Sstevel@tonic-gate static
23100Sstevel@tonic-gate uchar_t DefBootSec[512] = {
23110Sstevel@tonic-gate 	0xeb, 0x3c, 0x90, 	/* 8086 short jump + displacement + NOP */
23120Sstevel@tonic-gate 	'M', 'S', 'D', 'O', 'S', '4', '.', '0',	/* OEM name & version */
23130Sstevel@tonic-gate 	0x00, 0x02, 0x01, 0x01, 0x00,
23140Sstevel@tonic-gate 	0x02, 0xe0, 0x00, 0x40, 0x0b,
23150Sstevel@tonic-gate 	0xf0, 0x09, 0x00, 0x12, 0x00,
23160Sstevel@tonic-gate 	0x02, 0x00,
23170Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00,
23180Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00,
23190Sstevel@tonic-gate 	0x00, 0x00,
23200Sstevel@tonic-gate 	0x29, 0x00, 0x00, 0x00, 0x00,
23210Sstevel@tonic-gate 	'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ',
23220Sstevel@tonic-gate 	'F', 'A', 'T', '1', '2', ' ', ' ', ' ',
23230Sstevel@tonic-gate 	0xfa, 0x33,
23240Sstevel@tonic-gate 	0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07,
23250Sstevel@tonic-gate 	0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56,
23260Sstevel@tonic-gate 	0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00,
23270Sstevel@tonic-gate 	0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe,
23280Sstevel@tonic-gate 	0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9,
23290Sstevel@tonic-gate 	0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb,
23300Sstevel@tonic-gate 	0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06,
23310Sstevel@tonic-gate 	0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c,
23320Sstevel@tonic-gate 	0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7,
23330Sstevel@tonic-gate 	0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13,
23340Sstevel@tonic-gate 	0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83,
23350Sstevel@tonic-gate 	0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52,
23360Sstevel@tonic-gate 	0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c,
23370Sstevel@tonic-gate 	0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b,
23380Sstevel@tonic-gate 	0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3,
23390Sstevel@tonic-gate 	0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c,
23400Sstevel@tonic-gate 	0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c,
23410Sstevel@tonic-gate 	0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20,
23420Sstevel@tonic-gate 	0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b,
23430Sstevel@tonic-gate 	0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3,
23440Sstevel@tonic-gate 	0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6,
23450Sstevel@tonic-gate 	0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18,
23460Sstevel@tonic-gate 	0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4,
23470Sstevel@tonic-gate 	0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44,
23480Sstevel@tonic-gate 	0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8,
23490Sstevel@tonic-gate 	0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49,
23500Sstevel@tonic-gate 	0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51,
23510Sstevel@tonic-gate 	0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8,
23520Sstevel@tonic-gate 	0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05,
23530Sstevel@tonic-gate 	0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b,
23540Sstevel@tonic-gate 	0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a,
23550Sstevel@tonic-gate 	0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1,
23560Sstevel@tonic-gate 	0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac,
23570Sstevel@tonic-gate 	0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07,
23580Sstevel@tonic-gate 	0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18,
23590Sstevel@tonic-gate 	0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe,
23600Sstevel@tonic-gate 	0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7,
23610Sstevel@tonic-gate 	0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3,
23620Sstevel@tonic-gate 	0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02,
23630Sstevel@tonic-gate 	0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6,
23640Sstevel@tonic-gate 	0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9,
23650Sstevel@tonic-gate 	0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c,
23660Sstevel@tonic-gate 	0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e,
23670Sstevel@tonic-gate 	0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
23680Sstevel@tonic-gate 	0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20,
23690Sstevel@tonic-gate 	0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72,
23700Sstevel@tonic-gate 	0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c,
23710Sstevel@tonic-gate 	0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
23720Sstevel@tonic-gate 	0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e,
23730Sstevel@tonic-gate 	0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68,
23740Sstevel@tonic-gate 	0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79,
23750Sstevel@tonic-gate 	0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20,
23760Sstevel@tonic-gate 	0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53,
23770Sstevel@tonic-gate 	0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59,
23780Sstevel@tonic-gate 	0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23790Sstevel@tonic-gate 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
23800Sstevel@tonic-gate };
23810Sstevel@tonic-gate 
23820Sstevel@tonic-gate /*
23830Sstevel@tonic-gate  *  verify_bootblkfile
23840Sstevel@tonic-gate  *
23850Sstevel@tonic-gate  *	We were provided with the name of a file containing the bootblk
23860Sstevel@tonic-gate  *	to install.  Verify it has a valid boot sector as best we can. Any
23870Sstevel@tonic-gate  *	errors and we return a bad file descriptor.  Otherwise we fill up the
23880Sstevel@tonic-gate  *	provided buffer with the boot sector, return the file
23890Sstevel@tonic-gate  *	descriptor for later use and leave the file pointer just
23900Sstevel@tonic-gate  *	past the boot sector part of the boot block file.
23910Sstevel@tonic-gate  */
23920Sstevel@tonic-gate static
23930Sstevel@tonic-gate int
23940Sstevel@tonic-gate verify_bootblkfile(char *fn, boot_sector_t *bs, ulong_t *blkfilesize)
23950Sstevel@tonic-gate {
23960Sstevel@tonic-gate 	struct stat fi;
23970Sstevel@tonic-gate 	int bsfd = -1;
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate 	if (stat(fn, &fi)) {
24000Sstevel@tonic-gate 		perror(fn);
24010Sstevel@tonic-gate 	} else if (fi.st_size < BPSEC) {
24020Sstevel@tonic-gate 		(void) fprintf(stderr,
24030Sstevel@tonic-gate 		    gettext("%s: Too short to be a boot sector.\n"), fn);
24040Sstevel@tonic-gate 	} else if ((bsfd = open(fn, O_RDONLY)) < 0) {
24050Sstevel@tonic-gate 		perror(fn);
24060Sstevel@tonic-gate 	} else if (read(bsfd, bs->buf, BPSEC) < BPSEC) {
24070Sstevel@tonic-gate 		(void) close(bsfd);
24080Sstevel@tonic-gate 		bsfd = -1;
24090Sstevel@tonic-gate 		perror(gettext("Boot block read"));
24100Sstevel@tonic-gate 	} else {
24110Sstevel@tonic-gate #ifdef i386
24120Sstevel@tonic-gate 		if ((bs->bs.bs_front.bs_jump_code[0] != OPCODE1 &&
24130Sstevel@tonic-gate 		    bs->bs.bs_front.bs_jump_code[0] != OPCODE2) ||
24140Sstevel@tonic-gate #else
24150Sstevel@tonic-gate 		if ((bs->bs.bs_jump_code[0] != OPCODE1 &&
24160Sstevel@tonic-gate 		    bs->bs.bs_jump_code[0] != OPCODE2) ||
24170Sstevel@tonic-gate #endif
24180Sstevel@tonic-gate 		    (bs->bs.bs_signature[0] != (BOOTSECSIG & 0xFF) &&
24190Sstevel@tonic-gate 		    bs->bs.bs_signature[1] != ((BOOTSECSIG >> 8) & 0xFF))) {
24200Sstevel@tonic-gate 			(void) close(bsfd);
24210Sstevel@tonic-gate 			bsfd = -1;
24220Sstevel@tonic-gate 			(void) fprintf(stderr,
24230Sstevel@tonic-gate 			    gettext("Boot block (%s) bogus.\n"), fn);
24240Sstevel@tonic-gate 		}
24250Sstevel@tonic-gate 		*blkfilesize = fi.st_size;
24260Sstevel@tonic-gate 	}
24270Sstevel@tonic-gate 	return (bsfd);
24280Sstevel@tonic-gate }
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate /*
24310Sstevel@tonic-gate  *  verify_firstfile
24320Sstevel@tonic-gate  *
24330Sstevel@tonic-gate  *	We were provided with the name of a file to be the first file
24340Sstevel@tonic-gate  *	installed on the disk.  We just need to verify it exists and
24350Sstevel@tonic-gate  *	find out how big it is.  If it doesn't exist, we print a warning
24360Sstevel@tonic-gate  *	message about how the file wasn't found.  We don't exit fatally,
24370Sstevel@tonic-gate  *	though, rather we return a size of 0 and the FAT will be built
24380Sstevel@tonic-gate  *	without installing any first file.  They can then presumably
24390Sstevel@tonic-gate  *	install the correct first file by hand.
24400Sstevel@tonic-gate  */
24410Sstevel@tonic-gate static
24420Sstevel@tonic-gate int
24430Sstevel@tonic-gate verify_firstfile(char *fn, ulong_t *filesize)
24440Sstevel@tonic-gate {
24450Sstevel@tonic-gate 	struct stat fi;
24460Sstevel@tonic-gate 	int fd = -1;
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate 	*filesize = 0;
24490Sstevel@tonic-gate 	if (stat(fn, &fi) || (fd = open(fn, O_RDONLY)) < 0) {
24500Sstevel@tonic-gate 		perror(fn);
24510Sstevel@tonic-gate 		(void) fprintf(stderr,
24520Sstevel@tonic-gate 		    gettext("Could not access requested file.  It will not\n"
24530Sstevel@tonic-gate 			    "be installed in the new file system.\n"));
24540Sstevel@tonic-gate 	} else {
24550Sstevel@tonic-gate 		*filesize = fi.st_size;
24560Sstevel@tonic-gate 	}
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 	return (fd);
24590Sstevel@tonic-gate }
24600Sstevel@tonic-gate 
24610Sstevel@tonic-gate /*
24620Sstevel@tonic-gate  *  label_volume
24630Sstevel@tonic-gate  *
24640Sstevel@tonic-gate  *	Fill in BPB with volume label.
24650Sstevel@tonic-gate  */
24660Sstevel@tonic-gate static
24670Sstevel@tonic-gate void
24680Sstevel@tonic-gate label_volume(char *lbl, bpb_t *wbpb)
24690Sstevel@tonic-gate {
24700Sstevel@tonic-gate 	int ll, i;
24710Sstevel@tonic-gate 
24720Sstevel@tonic-gate 	/* Put a volume label into our BPB. */
24730Sstevel@tonic-gate 	if (!lbl)
24740Sstevel@tonic-gate 		lbl = DEFAULT_LABEL;
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 	ll = min(11, (int)strlen(lbl));
24770Sstevel@tonic-gate 	for (i = 0; i < ll; i++) {
24780Sstevel@tonic-gate 		wbpb->ebpb.volume_label[i] = toupper(lbl[i]);
24790Sstevel@tonic-gate 	}
24800Sstevel@tonic-gate 	for (; i < 11; i++) {
24810Sstevel@tonic-gate 		wbpb->ebpb.volume_label[i] = ' ';
24820Sstevel@tonic-gate 	}
24830Sstevel@tonic-gate }
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate static
24860Sstevel@tonic-gate int
24870Sstevel@tonic-gate copy_bootblk(char *fn, boot_sector_t *bootsect, ulong_t *bootblksize)
24880Sstevel@tonic-gate {
24890Sstevel@tonic-gate 	int bsfd = -1;
24900Sstevel@tonic-gate 
24910Sstevel@tonic-gate 	if (Verbose && fn)
24920Sstevel@tonic-gate 		(void) printf(gettext("Request to install boot "
24930Sstevel@tonic-gate 		    "block file %s.\n"), fn);
24940Sstevel@tonic-gate 	else if (Verbose)
24950Sstevel@tonic-gate 		(void) printf(gettext("Request to install DOS boot block.\n"));
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	/*
24980Sstevel@tonic-gate 	 *  If they want to install their own boot block, sanity check
24990Sstevel@tonic-gate 	 *  that block.
25000Sstevel@tonic-gate 	 */
25010Sstevel@tonic-gate 	if (fn) {
25020Sstevel@tonic-gate 		bsfd = verify_bootblkfile(fn, bootsect, bootblksize);
25030Sstevel@tonic-gate 		if (bsfd < 0) {
25040Sstevel@tonic-gate 			exit(3);
25050Sstevel@tonic-gate 		}
25060Sstevel@tonic-gate 		*bootblksize = roundup(*bootblksize, BPSEC);
25070Sstevel@tonic-gate 	} else {
25080Sstevel@tonic-gate 		(void) memcpy(bootsect, DefBootSec, BPSEC);
25090Sstevel@tonic-gate 		*bootblksize = BPSEC;
25100Sstevel@tonic-gate 	}
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	return (bsfd);
25130Sstevel@tonic-gate }
25140Sstevel@tonic-gate 
25150Sstevel@tonic-gate /*
25160Sstevel@tonic-gate  *  mark_cluster
25170Sstevel@tonic-gate  *
25180Sstevel@tonic-gate  *	This routine fills a FAT entry with the value supplied to it as an
25190Sstevel@tonic-gate  *	argument.  The fatp argument is assumed to be a pointer to the FAT's
25200Sstevel@tonic-gate  *	0th entry.  The clustnum is the cluster entry that should be updated.
25210Sstevel@tonic-gate  *	The value is the new value for the entry.
25220Sstevel@tonic-gate  */
25230Sstevel@tonic-gate static
25240Sstevel@tonic-gate void
25250Sstevel@tonic-gate mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, uint32_t value)
25260Sstevel@tonic-gate {
25270Sstevel@tonic-gate 	uchar_t *ep;
25280Sstevel@tonic-gate 	ulong_t idx;
25290Sstevel@tonic-gate 
25300Sstevel@tonic-gate 	idx = (Fatentsize == 32) ? clustnum * 4 :
25310Sstevel@tonic-gate 		(Fatentsize == 16) ? clustnum * 2 : clustnum + clustnum/2;
25320Sstevel@tonic-gate 	ep = fatp + idx;
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 	if (Fatentsize == 32) {
25350Sstevel@tonic-gate 		store_32_bits(&ep, value);
25360Sstevel@tonic-gate 	} else if (Fatentsize == 16) {
25370Sstevel@tonic-gate 		store_16_bits(&ep, value);
25380Sstevel@tonic-gate 	} else {
25390Sstevel@tonic-gate 		if (clustnum & 1) {
25400Sstevel@tonic-gate 			*ep = (*ep & 0x0f) | ((value << 4) & 0xf0);
25410Sstevel@tonic-gate 			ep++;
25420Sstevel@tonic-gate 			*ep = (value >> 4) & 0xff;
25430Sstevel@tonic-gate 		} else {
25440Sstevel@tonic-gate 			*ep++ = value & 0xff;
25450Sstevel@tonic-gate 			*ep = (*ep & 0xf0) | ((value >> 8) & 0x0f);
25460Sstevel@tonic-gate 		}
25470Sstevel@tonic-gate 	}
25480Sstevel@tonic-gate }
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate static
25510Sstevel@tonic-gate uchar_t *
25520Sstevel@tonic-gate build_fat(bpb_t *wbpb, struct fat32_boot_fsinfo *fsinfop, ulong_t bootblksize,
25530Sstevel@tonic-gate     ulong_t *fatsize, char *ffn, int *fffd, ulong_t *ffsize,
25540Sstevel@tonic-gate     pc_cluster32_t *ffstartclust)
25550Sstevel@tonic-gate {
25560Sstevel@tonic-gate 	pc_cluster32_t nextfree, ci;
25570Sstevel@tonic-gate 	uchar_t *fatp;
25580Sstevel@tonic-gate 	ushort_t numclust, numsect;
25590Sstevel@tonic-gate 	int  remclust;
25600Sstevel@tonic-gate 
25610Sstevel@tonic-gate 	/* Alloc space for a FAT and then null it out. */
25620Sstevel@tonic-gate 	if (Verbose) {
25630Sstevel@tonic-gate 		(void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"),
25640Sstevel@tonic-gate 		    wbpb->bpb.sectors_per_fat ? wbpb->bpb.sectors_per_fat :
25650Sstevel@tonic-gate 			wbpb->bpb32.big_sectors_per_fat);
25660Sstevel@tonic-gate 	}
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	if (MakeFAT32) {
25690Sstevel@tonic-gate 		*fatsize = BPSEC * wbpb->bpb32.big_sectors_per_fat;
25700Sstevel@tonic-gate 	} else {
25710Sstevel@tonic-gate 		*fatsize = BPSEC * wbpb->bpb.sectors_per_fat;
25720Sstevel@tonic-gate 	}
25730Sstevel@tonic-gate 	if (!(fatp = (uchar_t *)malloc(*fatsize))) {
25740Sstevel@tonic-gate 		perror(gettext("FAT table alloc"));
25750Sstevel@tonic-gate 		exit(4);
25760Sstevel@tonic-gate 	} else {
25770Sstevel@tonic-gate 		(void) memset(fatp, 0, *fatsize);
25780Sstevel@tonic-gate 	}
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 	/* Build in-memory FAT */
25810Sstevel@tonic-gate 	*fatp = wbpb->bpb.media;
25820Sstevel@tonic-gate 	*(fatp + 1) = 0xFF;
25830Sstevel@tonic-gate 	*(fatp + 2) = 0xFF;
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 	if (Fatentsize == 16) {
25860Sstevel@tonic-gate 		*(fatp + 3) = 0xFF;
25870Sstevel@tonic-gate 	} else if (Fatentsize == 32) {
25880Sstevel@tonic-gate 		*(fatp + 3) = 0x0F;
25890Sstevel@tonic-gate 		*(fatp + 4) = 0xFF;
25900Sstevel@tonic-gate 		*(fatp + 5) = 0xFF;
25910Sstevel@tonic-gate 		*(fatp + 6) = 0xFF;
25920Sstevel@tonic-gate 		*(fatp + 7) = 0x0F;
25930Sstevel@tonic-gate 	}
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate 	/*
25960Sstevel@tonic-gate 	 * Keep track of clusters used.
25970Sstevel@tonic-gate 	 */
25980Sstevel@tonic-gate 	remclust = TotalClusters;
25990Sstevel@tonic-gate 	nextfree = 2;
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 	/*
26020Sstevel@tonic-gate 	 * Get info on first file to install, if any.
26030Sstevel@tonic-gate 	 */
26040Sstevel@tonic-gate 	if (ffn)
26050Sstevel@tonic-gate 		*fffd = verify_firstfile(ffn, ffsize);
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 	/*
26080Sstevel@tonic-gate 	 * Compute number of clusters to preserve for bootblk overage.
26090Sstevel@tonic-gate 	 * Remember that we already wrote the first sector of the boot block.
26100Sstevel@tonic-gate 	 * These clusters are marked BAD to prevent them from being deleted
26110Sstevel@tonic-gate 	 * or used.  The first available cluster is 2, so we always offset
26120Sstevel@tonic-gate 	 * the clusters.
26130Sstevel@tonic-gate 	 */
26140Sstevel@tonic-gate 	numsect = idivceil((bootblksize - BPSEC), BPSEC);
26150Sstevel@tonic-gate 	numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate 	if (Verbose && numclust)
26180Sstevel@tonic-gate 		(void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"),
26190Sstevel@tonic-gate 		    numclust);
26200Sstevel@tonic-gate 	for (ci = 0; ci < numclust; ci++)
26210Sstevel@tonic-gate 		mark_cluster(fatp, nextfree++,
26220Sstevel@tonic-gate 			MakeFAT32 ? PCF_BADCLUSTER32 : PCF_BADCLUSTER);
26230Sstevel@tonic-gate 	remclust -= numclust;
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate 	/*
26260Sstevel@tonic-gate 	 * Reserve a cluster for the root directory on a FAT32.
26270Sstevel@tonic-gate 	 */
26280Sstevel@tonic-gate 	if (MakeFAT32) {
26290Sstevel@tonic-gate 		mark_cluster(fatp, nextfree, PCF_LASTCLUSTER32);
26300Sstevel@tonic-gate 		wbpb->bpb32.root_dir_clust = nextfree++;
26310Sstevel@tonic-gate 		remclust--;
26320Sstevel@tonic-gate 	}
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 	/*
26350Sstevel@tonic-gate 	 * Compute and preserve number of clusters for first file.
26360Sstevel@tonic-gate 	 */
26370Sstevel@tonic-gate 	if (*fffd >= 0) {
26380Sstevel@tonic-gate 		*ffstartclust = nextfree;
26390Sstevel@tonic-gate 		numsect = idivceil(*ffsize, BPSEC);
26400Sstevel@tonic-gate 		numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
26410Sstevel@tonic-gate 
26420Sstevel@tonic-gate 		if (numclust > remclust) {
26430Sstevel@tonic-gate 			(void) fprintf(stderr,
26440Sstevel@tonic-gate 				gettext("Requested first file too large to be\n"
26450Sstevel@tonic-gate 					"installed in the new file system.\n"));
26460Sstevel@tonic-gate 			(void) close(*fffd);
26470Sstevel@tonic-gate 			*fffd = -1;
26480Sstevel@tonic-gate 			goto finish;
26490Sstevel@tonic-gate 		}
26500Sstevel@tonic-gate 
26510Sstevel@tonic-gate 		if (Verbose)
26520Sstevel@tonic-gate 			(void) printf(gettext("Reserving %d first file "
26530Sstevel@tonic-gate 			    "cluster(s).\n"), numclust);
26540Sstevel@tonic-gate 		for (ci = 0; (int)ci < (int)(numclust-1); ci++, nextfree++)
26550Sstevel@tonic-gate 			mark_cluster(fatp, nextfree, nextfree + 1);
26560Sstevel@tonic-gate 		mark_cluster(fatp, nextfree++,
26570Sstevel@tonic-gate 			MakeFAT32 ? PCF_LASTCLUSTER32 : PCF_LASTCLUSTER);
26580Sstevel@tonic-gate 		remclust -= numclust;
26590Sstevel@tonic-gate 	}
26600Sstevel@tonic-gate 
26610Sstevel@tonic-gate finish:
26620Sstevel@tonic-gate 	if (Verbose) {
26630Sstevel@tonic-gate 		(void) printf(gettext("First sector of FAT"));
26640Sstevel@tonic-gate 		header_for_dump();
26650Sstevel@tonic-gate 		dump_bytes(fatp, BPSEC);
26660Sstevel@tonic-gate 	}
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 	fsinfop->fs_signature = FAT32_FS_SIGN;
26690Sstevel@tonic-gate 	fsinfop->fs_free_clusters = remclust;
26700Sstevel@tonic-gate 	fsinfop->fs_next_cluster = nextfree;
26710Sstevel@tonic-gate 	return (fatp);
26720Sstevel@tonic-gate }
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate static
26750Sstevel@tonic-gate void
26760Sstevel@tonic-gate dirent_time_fill(struct pcdir *dep)
26770Sstevel@tonic-gate {
26780Sstevel@tonic-gate 	struct  timeval tv;
26790Sstevel@tonic-gate 	struct	tm	*tp;
26800Sstevel@tonic-gate 	ushort_t	dostime;
26810Sstevel@tonic-gate 	ushort_t	dosday;
26820Sstevel@tonic-gate 
26830Sstevel@tonic-gate 	(void) gettimeofday(&tv, (struct timezone *)0);
26840Sstevel@tonic-gate 	tp = localtime(&tv.tv_sec);
26850Sstevel@tonic-gate 	/* get the time & day into DOS format */
26860Sstevel@tonic-gate 	dostime = tp->tm_sec / 2;
26870Sstevel@tonic-gate 	dostime |= tp->tm_min << 5;
26880Sstevel@tonic-gate 	dostime |= tp->tm_hour << 11;
26890Sstevel@tonic-gate 	dosday = tp->tm_mday;
26900Sstevel@tonic-gate 	dosday |= (tp->tm_mon + 1) << 5;
26910Sstevel@tonic-gate 	dosday |= (tp->tm_year - 80) << 9;
26920Sstevel@tonic-gate 	dep->pcd_mtime.pct_time = htols(dostime);
26930Sstevel@tonic-gate 	dep->pcd_mtime.pct_date = htols(dosday);
26940Sstevel@tonic-gate }
26950Sstevel@tonic-gate 
26960Sstevel@tonic-gate static
26970Sstevel@tonic-gate void
26980Sstevel@tonic-gate dirent_label_fill(struct pcdir *dep, char *fn)
26990Sstevel@tonic-gate {
27000Sstevel@tonic-gate 	int nl, i;
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate 	/*
27030Sstevel@tonic-gate 	 * We spread the volume label across both the NAME and EXT fields
27040Sstevel@tonic-gate 	 */
27050Sstevel@tonic-gate 	nl = min(PCFNAMESIZE, strlen(fn));
27060Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
27070Sstevel@tonic-gate 		dep->pcd_filename[i] = toupper(fn[i]);
27080Sstevel@tonic-gate 	}
27090Sstevel@tonic-gate 	if (i < PCFNAMESIZE) {
27100Sstevel@tonic-gate 		for (; i < PCFNAMESIZE; i++)
27110Sstevel@tonic-gate 			dep->pcd_filename[i] = ' ';
27120Sstevel@tonic-gate 		for (i = 0; i < PCFEXTSIZE; i++)
27130Sstevel@tonic-gate 			dep->pcd_ext[i] = ' ';
27140Sstevel@tonic-gate 		return;
27150Sstevel@tonic-gate 	}
27160Sstevel@tonic-gate 	nl = min(PCFEXTSIZE, strlen(fn) - PCFNAMESIZE);
27170Sstevel@tonic-gate 	for (i = 0; i < nl; i++)
27180Sstevel@tonic-gate 		dep->pcd_ext[i] = toupper(fn[i + PCFNAMESIZE]);
27190Sstevel@tonic-gate 	if (i < PCFEXTSIZE) {
27200Sstevel@tonic-gate 		for (; i < PCFEXTSIZE; i++)
27210Sstevel@tonic-gate 			dep->pcd_ext[i] = ' ';
27220Sstevel@tonic-gate 	}
27230Sstevel@tonic-gate }
27240Sstevel@tonic-gate 
27250Sstevel@tonic-gate static
27260Sstevel@tonic-gate void
27270Sstevel@tonic-gate dirent_fname_fill(struct pcdir *dep, char *fn)
27280Sstevel@tonic-gate {
27290Sstevel@tonic-gate 	char *fname, *fext;
27300Sstevel@tonic-gate 	int nl, i;
27310Sstevel@tonic-gate 
27320Sstevel@tonic-gate 	if (fname = strrchr(fn, '/')) {
27330Sstevel@tonic-gate 		fname++;
27340Sstevel@tonic-gate 	} else {
27350Sstevel@tonic-gate 		fname = fn;
27360Sstevel@tonic-gate 	}
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 	if (fext = strrchr(fname, '.')) {
27390Sstevel@tonic-gate 		fext++;
27400Sstevel@tonic-gate 	} else {
27410Sstevel@tonic-gate 		fext = "";
27420Sstevel@tonic-gate 	}
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	fname = strtok(fname, ".");
27450Sstevel@tonic-gate 
27460Sstevel@tonic-gate 	nl = min(PCFNAMESIZE, (int)strlen(fname));
27470Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
27480Sstevel@tonic-gate 		dep->pcd_filename[i] = toupper(fname[i]);
27490Sstevel@tonic-gate 	}
27500Sstevel@tonic-gate 	for (; i < PCFNAMESIZE; i++) {
27510Sstevel@tonic-gate 		dep->pcd_filename[i] = ' ';
27520Sstevel@tonic-gate 	}
27530Sstevel@tonic-gate 
27540Sstevel@tonic-gate 	nl = min(PCFEXTSIZE, (int)strlen(fext));
27550Sstevel@tonic-gate 	for (i = 0; i < nl; i++) {
27560Sstevel@tonic-gate 		dep->pcd_ext[i] = toupper(fext[i]);
27570Sstevel@tonic-gate 	}
27580Sstevel@tonic-gate 	for (; i < PCFEXTSIZE; i++) {
27590Sstevel@tonic-gate 		dep->pcd_ext[i] = ' ';
27600Sstevel@tonic-gate 	}
27610Sstevel@tonic-gate }
27620Sstevel@tonic-gate 
27630Sstevel@tonic-gate static
27640Sstevel@tonic-gate uchar_t *
27650Sstevel@tonic-gate build_rootdir(bpb_t *wbpb, char *ffn, int fffd,
27660Sstevel@tonic-gate     ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize)
27670Sstevel@tonic-gate {
27680Sstevel@tonic-gate 	struct pcdir *rootdirp;
27690Sstevel@tonic-gate 	struct pcdir *entry;
27700Sstevel@tonic-gate 
27710Sstevel@tonic-gate 	/*
27720Sstevel@tonic-gate 	 * Build a root directory.  It will have at least one entry,
27730Sstevel@tonic-gate 	 * the volume label and a second if the first file was defined.
27740Sstevel@tonic-gate 	 */
27750Sstevel@tonic-gate 	if (MakeFAT32) {
27760Sstevel@tonic-gate 		/*
27770Sstevel@tonic-gate 		 * We devote an entire cluster to the root
27780Sstevel@tonic-gate 		 * directory on FAT32.
27790Sstevel@tonic-gate 		 */
27800Sstevel@tonic-gate 		*rdirsize = wbpb->bpb.sectors_per_cluster * BPSEC;
27810Sstevel@tonic-gate 	} else {
27820Sstevel@tonic-gate 		*rdirsize = wbpb->bpb.num_root_entries * sizeof (struct pcdir);
27830Sstevel@tonic-gate 	}
27840Sstevel@tonic-gate 	if ((rootdirp = (struct pcdir *)malloc(*rdirsize)) == NULL) {
27850Sstevel@tonic-gate 		perror(gettext("Root directory allocation"));
27860Sstevel@tonic-gate 		exit(4);
27870Sstevel@tonic-gate 	} else {
27880Sstevel@tonic-gate 		entry = rootdirp;
27890Sstevel@tonic-gate 		(void) memset((char *)rootdirp, 0, *rdirsize);
27900Sstevel@tonic-gate 	}
27910Sstevel@tonic-gate 
27920Sstevel@tonic-gate 	/* Create directory entry for first file, if there is one */
27930Sstevel@tonic-gate 	if (fffd >= 0) {
27940Sstevel@tonic-gate 		dirent_fname_fill(entry, ffn);
27950Sstevel@tonic-gate 		entry->pcd_attr = Firstfileattr;
27960Sstevel@tonic-gate 		dirent_time_fill(entry);
27970Sstevel@tonic-gate 		entry->pcd_scluster_lo = htols(ffstart);
27980Sstevel@tonic-gate 		if (MakeFAT32) {
27990Sstevel@tonic-gate 			ffstart = ffstart >> 16;
28000Sstevel@tonic-gate 			entry->un.pcd_scluster_hi = htols(ffstart);
28010Sstevel@tonic-gate 		}
28020Sstevel@tonic-gate 		entry->pcd_size = htoli(ffsize);
28030Sstevel@tonic-gate 		entry++;
28040Sstevel@tonic-gate 	}
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate 	/* Create directory entry for volume label, if there is one */
28070Sstevel@tonic-gate 	if (Label != NULL) {
28080Sstevel@tonic-gate 		dirent_label_fill(entry, Label);
28090Sstevel@tonic-gate 		entry->pcd_attr = PCA_ARCH | PCA_LABEL;
28100Sstevel@tonic-gate 		dirent_time_fill(entry);
28110Sstevel@tonic-gate 		entry->pcd_scluster_lo = 0;
28120Sstevel@tonic-gate 		if (MakeFAT32) {
28130Sstevel@tonic-gate 			entry->un.pcd_scluster_hi = 0;
28140Sstevel@tonic-gate 		}
28150Sstevel@tonic-gate 		entry->pcd_size = 0;
28160Sstevel@tonic-gate 		entry++;
28170Sstevel@tonic-gate 	}
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate 	if (Verbose) {
28200Sstevel@tonic-gate 		(void) printf(gettext("First two directory entries"));
28210Sstevel@tonic-gate 		header_for_dump();
28220Sstevel@tonic-gate 		dump_bytes((uchar_t *)rootdirp, 2 * sizeof (struct pcdir));
28230Sstevel@tonic-gate 	}
28240Sstevel@tonic-gate 
28250Sstevel@tonic-gate 	return ((uchar_t *)rootdirp);
28260Sstevel@tonic-gate }
28270Sstevel@tonic-gate 
28280Sstevel@tonic-gate /*
28290Sstevel@tonic-gate  * write_rest
28300Sstevel@tonic-gate  *
28310Sstevel@tonic-gate  *	Write all the bytes from the current file pointer to end of file
28320Sstevel@tonic-gate  *	in the source file out to the destination file.  The writes should
28330Sstevel@tonic-gate  *	be padded to whole clusters with 0's if necessary.
28340Sstevel@tonic-gate  */
28350Sstevel@tonic-gate static
28360Sstevel@tonic-gate void
28370Sstevel@tonic-gate write_rest(bpb_t *wbpb, char *efn, int dfd, int sfd, int remaining)
28380Sstevel@tonic-gate {
28390Sstevel@tonic-gate 	char buf[BPSEC];
28400Sstevel@tonic-gate 	ushort_t numsect, numclust;
28410Sstevel@tonic-gate 	ushort_t wnumsect, s;
28420Sstevel@tonic-gate 	int doneread = 0;
28430Sstevel@tonic-gate 	int rstat;
28440Sstevel@tonic-gate 
28450Sstevel@tonic-gate 	/*
28460Sstevel@tonic-gate 	 * Compute number of clusters required to contain remaining bytes.
28470Sstevel@tonic-gate 	 */
28480Sstevel@tonic-gate 	numsect = idivceil(remaining, BPSEC);
28490Sstevel@tonic-gate 	numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster);
28500Sstevel@tonic-gate 
28510Sstevel@tonic-gate 	wnumsect = numclust * wbpb->bpb.sectors_per_cluster;
28520Sstevel@tonic-gate 	for (s = 0; s < wnumsect; s++) {
28530Sstevel@tonic-gate 		if (!doneread) {
28540Sstevel@tonic-gate 			if ((rstat = read(sfd, buf, BPSEC)) < 0) {
28550Sstevel@tonic-gate 				perror(efn);
28560Sstevel@tonic-gate 				doneread = 1;
28570Sstevel@tonic-gate 				rstat = 0;
28580Sstevel@tonic-gate 			} else if (rstat == 0) {
28590Sstevel@tonic-gate 				doneread = 1;
28600Sstevel@tonic-gate 			}
28610Sstevel@tonic-gate 			(void) memset(&(buf[rstat]), 0, BPSEC - rstat);
28620Sstevel@tonic-gate 		}
28630Sstevel@tonic-gate 		if (write(dfd, buf, BPSEC) != BPSEC) {
28640Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Copying "));
28650Sstevel@tonic-gate 			perror(efn);
28660Sstevel@tonic-gate 		}
28670Sstevel@tonic-gate 	}
28680Sstevel@tonic-gate }
28690Sstevel@tonic-gate 
28700Sstevel@tonic-gate static
28710Sstevel@tonic-gate void
28720Sstevel@tonic-gate write_fat32_bootstuff(int fd, boot_sector_t *bsp,
28730Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto)
28740Sstevel@tonic-gate {
28750Sstevel@tonic-gate 	uchar_t fsinfobuf[BPSEC];
28760Sstevel@tonic-gate 	uchar_t *fp;
28770Sstevel@tonic-gate 
28780Sstevel@tonic-gate 	/*
28790Sstevel@tonic-gate 	 * Construct the fsinfo buf
28800Sstevel@tonic-gate 	 */
28810Sstevel@tonic-gate 	(void) memset(fsinfobuf, 0, BPSEC);
28820Sstevel@tonic-gate 	/*
28830Sstevel@tonic-gate 	 * Not sure if this magic signature at the beginning of the
28840Sstevel@tonic-gate 	 * sector is necessary for us to create or not.  For now, I'm
28850Sstevel@tonic-gate 	 * going to assume it is, since I haven't seen any Windows FAT32s
28860Sstevel@tonic-gate 	 * without it.
28870Sstevel@tonic-gate 	 */
28880Sstevel@tonic-gate 	fsinfobuf[0] = 'R';
28890Sstevel@tonic-gate 	fsinfobuf[1] = 'R';
28900Sstevel@tonic-gate 	fsinfobuf[2] = 'a';
28910Sstevel@tonic-gate 	fsinfobuf[3] = 'A';
28920Sstevel@tonic-gate 	/*
28930Sstevel@tonic-gate 	 * We also appear to want the magic Boot sector signature at the
28940Sstevel@tonic-gate 	 * end of the sector.
28950Sstevel@tonic-gate 	 */
28960Sstevel@tonic-gate 	fsinfobuf[BPSEC - 2] = BOOTSECSIG & 0xFF;
28970Sstevel@tonic-gate 	fsinfobuf[BPSEC - 1] = (BOOTSECSIG >> 8) & 0xFF;
28980Sstevel@tonic-gate 
28990Sstevel@tonic-gate 	fp = &(fsinfobuf[FAT32_BOOT_FSINFO_OFF]);
29000Sstevel@tonic-gate 	fp += 4;	/* skip first reserved field */
29010Sstevel@tonic-gate 	store_32_bits(&fp, fsinfop->fs_signature);
29020Sstevel@tonic-gate 	store_32_bits(&fp, fsinfop->fs_free_clusters);
29030Sstevel@tonic-gate 	store_32_bits(&fp, fsinfop->fs_next_cluster);
29040Sstevel@tonic-gate 
29050Sstevel@tonic-gate 	if (Verbose) {
29060Sstevel@tonic-gate 		(void) printf(gettext("Dump of the fs info sector"));
29070Sstevel@tonic-gate 		header_for_dump();
29080Sstevel@tonic-gate 		dump_bytes(fsinfobuf, sizeof (fsinfobuf));
29090Sstevel@tonic-gate 	}
29100Sstevel@tonic-gate 
29110Sstevel@tonic-gate 	if (!Notreally) {
29120Sstevel@tonic-gate 		/*
29130Sstevel@tonic-gate 		 * FAT32's have an FS info sector, then a backup of the boot
29140Sstevel@tonic-gate 		 * sector, and a modified backup of the FS Info sector.
29150Sstevel@tonic-gate 		 */
29160Sstevel@tonic-gate 		if (write(fd, fsinfobuf, sizeof (fsinfobuf)) != BPSEC) {
29170Sstevel@tonic-gate 			perror(gettext("FS info sector write"));
29180Sstevel@tonic-gate 			exit(4);
29190Sstevel@tonic-gate 		}
29200Sstevel@tonic-gate 		if (lseek64(fd,	seekto + BKUP_BOOTSECT_OFFSET, SEEK_SET) < 0) {
29210Sstevel@tonic-gate 			(void) close(fd);
29220Sstevel@tonic-gate 			perror(gettext("Boot sector backup seek"));
29230Sstevel@tonic-gate 			exit(4);
29240Sstevel@tonic-gate 		}
29250Sstevel@tonic-gate 		if (write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) {
29260Sstevel@tonic-gate 			perror(gettext("Boot sector backup write"));
29270Sstevel@tonic-gate 			exit(4);
29280Sstevel@tonic-gate 		}
29290Sstevel@tonic-gate 	}
29300Sstevel@tonic-gate 
29310Sstevel@tonic-gate 	/*
29320Sstevel@tonic-gate 	 * Second copy of fs info sector is modified to have "don't know"
29330Sstevel@tonic-gate 	 * as the number of free clusters
29340Sstevel@tonic-gate 	 */
29350Sstevel@tonic-gate 	fp = &(fsinfobuf[FAT32_BOOT_FSINFO_OFF]);
29360Sstevel@tonic-gate 	fp += 8;	/* skip first reserved field and signature */
29370Sstevel@tonic-gate 	store_32_bits(&fp, -1);
29380Sstevel@tonic-gate 
29390Sstevel@tonic-gate 	if (Verbose) {
29400Sstevel@tonic-gate 		(void) printf(gettext("Dump of the backup fs info sector"));
29410Sstevel@tonic-gate 		header_for_dump();
29420Sstevel@tonic-gate 		dump_bytes(fsinfobuf, sizeof (fsinfobuf));
29430Sstevel@tonic-gate 	}
29440Sstevel@tonic-gate 
29450Sstevel@tonic-gate 	if (!Notreally) {
29460Sstevel@tonic-gate 		if (write(fd, fsinfobuf, sizeof (fsinfobuf)) != BPSEC) {
29470Sstevel@tonic-gate 			perror(gettext("FS info sector backup write"));
29480Sstevel@tonic-gate 			exit(4);
29490Sstevel@tonic-gate 		}
29500Sstevel@tonic-gate 	}
29510Sstevel@tonic-gate }
29520Sstevel@tonic-gate 
29530Sstevel@tonic-gate static
29540Sstevel@tonic-gate void
29550Sstevel@tonic-gate write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb,
29560Sstevel@tonic-gate 	struct fat32_boot_fsinfo *fsinfop, off64_t seekto)
29570Sstevel@tonic-gate {
29580Sstevel@tonic-gate 	if (MakeFAT32) {
29590Sstevel@tonic-gate 		/* Copy our BPB into bootsec structure */
29600Sstevel@tonic-gate #ifdef i386
29610Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_front.bs_bpb), &(wbpb->bpb),
29620Sstevel@tonic-gate 			    sizeof (wbpb->bpb));
29630Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_bpb32), &(wbpb->bpb32),
29640Sstevel@tonic-gate 			    sizeof (wbpb->bpb32));
29650Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs32.bs_ebpb), &(wbpb->ebpb),
29660Sstevel@tonic-gate 			    sizeof (wbpb->ebpb));
29670Sstevel@tonic-gate #else
29680Sstevel@tonic-gate 		swap_pack_bpb32cpy(&(bsp->bs32), wbpb);
29690Sstevel@tonic-gate #endif
29700Sstevel@tonic-gate 	} else {
29710Sstevel@tonic-gate 		/* Copy our BPB into bootsec structure */
29720Sstevel@tonic-gate #ifdef i386
29730Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs.bs_front.bs_bpb), &(wbpb->bpb),
29740Sstevel@tonic-gate 			    sizeof (wbpb->bpb));
29750Sstevel@tonic-gate 		(void) memcpy(&(bsp->bs.bs_ebpb), &(wbpb->ebpb),
29760Sstevel@tonic-gate 			    sizeof (wbpb->ebpb));
29770Sstevel@tonic-gate #else
29780Sstevel@tonic-gate 		swap_pack_bpbcpy(&(bsp->bs), wbpb);
29790Sstevel@tonic-gate #endif
29800Sstevel@tonic-gate 
29810Sstevel@tonic-gate 		/* Copy SUN BPB extensions into bootsec structure */
29820Sstevel@tonic-gate 		if (SunBPBfields) {
29830Sstevel@tonic-gate #ifdef i386
29840Sstevel@tonic-gate 			(void) memcpy(&(bsp->bs.bs_sebpb), &(wbpb->sunbpb),
29850Sstevel@tonic-gate 				sizeof (wbpb->sunbpb));
29860Sstevel@tonic-gate #else
29870Sstevel@tonic-gate 			swap_pack_sebpbcpy(&(bsp->bs), wbpb);
29880Sstevel@tonic-gate #endif
29890Sstevel@tonic-gate 		}
29900Sstevel@tonic-gate 	}
29910Sstevel@tonic-gate 
29920Sstevel@tonic-gate 	/* Write boot sector */
29930Sstevel@tonic-gate 	if (!Notreally && write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) {
29940Sstevel@tonic-gate 		perror(gettext("Boot sector write"));
29950Sstevel@tonic-gate 		exit(4);
29960Sstevel@tonic-gate 	}
29970Sstevel@tonic-gate 
29980Sstevel@tonic-gate 	if (Verbose) {
29990Sstevel@tonic-gate 		(void) printf(gettext("Dump of the boot sector"));
30000Sstevel@tonic-gate 		header_for_dump();
30010Sstevel@tonic-gate 		dump_bytes(bsp->buf, sizeof (bsp->buf));
30020Sstevel@tonic-gate 	}
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 	if (MakeFAT32)
30050Sstevel@tonic-gate 		write_fat32_bootstuff(fd, bsp, fsinfop, seekto);
30060Sstevel@tonic-gate }
30070Sstevel@tonic-gate 
30080Sstevel@tonic-gate static
30090Sstevel@tonic-gate void
30100Sstevel@tonic-gate write_fat(int fd, off64_t seekto, char *fn, char *lbl, char *ffn, bpb_t *wbpb)
30110Sstevel@tonic-gate {
30120Sstevel@tonic-gate 	struct fat32_boot_fsinfo fsinfo;
30130Sstevel@tonic-gate 	pc_cluster32_t ffsc;
30140Sstevel@tonic-gate 	boot_sector_t bootsect;
30150Sstevel@tonic-gate 	uchar_t *fatp, *rdirp;
30160Sstevel@tonic-gate 	ulong_t bootblksize, fatsize, rdirsize, ffsize;
30170Sstevel@tonic-gate 	int bsfd = -1;
30180Sstevel@tonic-gate 	int fffd = -1;
30190Sstevel@tonic-gate 
30200Sstevel@tonic-gate 	compute_file_area_size(wbpb);
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 	bsfd = copy_bootblk(fn, &bootsect, &bootblksize);
30230Sstevel@tonic-gate 	label_volume(lbl, wbpb);
30240Sstevel@tonic-gate 
30250Sstevel@tonic-gate 	if (Verbose)
30260Sstevel@tonic-gate 		(void) printf(gettext("Building FAT.\n"));
30270Sstevel@tonic-gate 	fatp = build_fat(wbpb, &fsinfo, bootblksize, &fatsize,
30280Sstevel@tonic-gate 	    ffn, &fffd, &ffsize, &ffsc);
30290Sstevel@tonic-gate 
30300Sstevel@tonic-gate 	write_bootsects(fd, &bootsect, wbpb, &fsinfo, seekto);
30310Sstevel@tonic-gate 
30320Sstevel@tonic-gate 	if (lseek64(fd,
30330Sstevel@tonic-gate 	    seekto + (BPSEC * wbpb->bpb.resv_sectors), SEEK_SET) < 0) {
30340Sstevel@tonic-gate 		(void) close(fd);
30350Sstevel@tonic-gate 		perror(gettext("Seek to end of reserved sectors"));
30360Sstevel@tonic-gate 		exit(4);
30370Sstevel@tonic-gate 	}
30380Sstevel@tonic-gate 
30390Sstevel@tonic-gate 	/* Write FAT */
30400Sstevel@tonic-gate 	if (Verbose)
30410Sstevel@tonic-gate 		(void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"),
30420Sstevel@tonic-gate 		    fatsize, wbpb->bpb.num_fats);
30430Sstevel@tonic-gate 	if (!Notreally) {
30440Sstevel@tonic-gate 		int nf, wb;
30450Sstevel@tonic-gate 		for (nf = 0; nf < (int)wbpb->bpb.num_fats; nf++)
30460Sstevel@tonic-gate 			if ((wb = write(fd, fatp, fatsize)) != fatsize) {
30470Sstevel@tonic-gate 				perror(gettext("FAT write"));
30480Sstevel@tonic-gate 				exit(4);
30490Sstevel@tonic-gate 			} else {
30500Sstevel@tonic-gate 				if (Verbose)
30510Sstevel@tonic-gate 					(void) printf(
30520Sstevel@tonic-gate 					    gettext("Wrote %d bytes\n"), wb);
30530Sstevel@tonic-gate 			}
30540Sstevel@tonic-gate 	}
30550Sstevel@tonic-gate 	free(fatp);
30560Sstevel@tonic-gate 
30570Sstevel@tonic-gate 	if (Verbose)
30580Sstevel@tonic-gate 		(void) printf(gettext("Building root directory.\n"));
30590Sstevel@tonic-gate 	rdirp = build_rootdir(wbpb, ffn, fffd, ffsize, ffsc, &rdirsize);
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	/*
30620Sstevel@tonic-gate 	 *  In non FAT32, root directory exists outside of the file area
30630Sstevel@tonic-gate 	 */
30640Sstevel@tonic-gate 	if (!MakeFAT32) {
30650Sstevel@tonic-gate 		if (Verbose)
30660Sstevel@tonic-gate 		    (void) printf(
30670Sstevel@tonic-gate 			gettext("Writing root directory. "
30680Sstevel@tonic-gate 				"%d bytes.\n"), rdirsize);
30690Sstevel@tonic-gate 		if (!Notreally) {
30700Sstevel@tonic-gate 			if (write(fd, rdirp, rdirsize) != rdirsize) {
30710Sstevel@tonic-gate 				perror(gettext("Root directory write"));
30720Sstevel@tonic-gate 				exit(4);
30730Sstevel@tonic-gate 			}
30740Sstevel@tonic-gate 		}
30750Sstevel@tonic-gate 		free(rdirp);
30760Sstevel@tonic-gate 	}
30770Sstevel@tonic-gate 
30780Sstevel@tonic-gate 	/*
30790Sstevel@tonic-gate 	 * Now write anything that needs to be in the file space.
30800Sstevel@tonic-gate 	 */
30810Sstevel@tonic-gate 	if (bootblksize > BPSEC) {
30820Sstevel@tonic-gate 		if (Verbose)
30830Sstevel@tonic-gate 			(void) printf(gettext("Writing remainder of "
30840Sstevel@tonic-gate 				"boot block.\n"));
30850Sstevel@tonic-gate 		if (!Notreally)
30860Sstevel@tonic-gate 			write_rest(wbpb, fn, fd, bsfd, bootblksize - BPSEC);
30870Sstevel@tonic-gate 	}
30880Sstevel@tonic-gate 
30890Sstevel@tonic-gate 	if (MakeFAT32) {
30900Sstevel@tonic-gate 		if (Verbose)
30910Sstevel@tonic-gate 		    (void) printf(
30920Sstevel@tonic-gate 			gettext("Writing root directory. "
30930Sstevel@tonic-gate 				"%d bytes.\n"), rdirsize);
30940Sstevel@tonic-gate 		if (!Notreally) {
30950Sstevel@tonic-gate 			if (write(fd, rdirp, rdirsize) != rdirsize) {
30960Sstevel@tonic-gate 				perror(gettext("Root directory write"));
30970Sstevel@tonic-gate 				exit(4);
30980Sstevel@tonic-gate 			}
30990Sstevel@tonic-gate 		}
31000Sstevel@tonic-gate 		free(rdirp);
31010Sstevel@tonic-gate 	}
31020Sstevel@tonic-gate 
31030Sstevel@tonic-gate 	if (fffd >= 0) {
31040Sstevel@tonic-gate 		if (Verbose)
31050Sstevel@tonic-gate 			(void) printf(gettext("Writing first file.\n"));
31060Sstevel@tonic-gate 		if (!Notreally)
31070Sstevel@tonic-gate 			write_rest(wbpb, ffn, fd, fffd, ffsize);
31080Sstevel@tonic-gate 	}
31090Sstevel@tonic-gate }
31100Sstevel@tonic-gate 
31110Sstevel@tonic-gate static
31120Sstevel@tonic-gate char *LegalOpts[] = {
31130Sstevel@tonic-gate #define	NFLAG 0
31140Sstevel@tonic-gate 	"N",
31150Sstevel@tonic-gate #define	VFLAG 1
31160Sstevel@tonic-gate 	"v",
31170Sstevel@tonic-gate #define	RFLAG 2
31180Sstevel@tonic-gate 	"r",
31190Sstevel@tonic-gate #define	HFLAG 3
31200Sstevel@tonic-gate 	"h",
31210Sstevel@tonic-gate #define	SFLAG 4
31220Sstevel@tonic-gate 	"s",
31230Sstevel@tonic-gate #define	SUNFLAG 5
31240Sstevel@tonic-gate 	"S",
31250Sstevel@tonic-gate #define	LABFLAG 6
31260Sstevel@tonic-gate 	"b",
31270Sstevel@tonic-gate #define	BTRFLAG 7
31280Sstevel@tonic-gate 	"B",
31290Sstevel@tonic-gate #define	INITFLAG 8
31300Sstevel@tonic-gate 	"i",
31310Sstevel@tonic-gate #define	SZFLAG 9
31320Sstevel@tonic-gate 	"size",
31330Sstevel@tonic-gate #define	SECTFLAG 10
31340Sstevel@tonic-gate 	"nsect",
31350Sstevel@tonic-gate #define	TRKFLAG 11
31360Sstevel@tonic-gate 	"ntrack",
31370Sstevel@tonic-gate #define	SPCFLAG 12
31380Sstevel@tonic-gate 	"spc",
31390Sstevel@tonic-gate #define	BPFFLAG 13
31400Sstevel@tonic-gate 	"fat",
31410Sstevel@tonic-gate #define	FFLAG 14
31420Sstevel@tonic-gate 	"f",
31430Sstevel@tonic-gate #define	DFLAG 15
31440Sstevel@tonic-gate 	"d",
31450Sstevel@tonic-gate #define	NOFDISKFLAG 16
31460Sstevel@tonic-gate 	"nofdisk",
31470Sstevel@tonic-gate #define	RESRVFLAG 17
31480Sstevel@tonic-gate 	"reserve",
31490Sstevel@tonic-gate #define	HIDDENFLAG 18
31500Sstevel@tonic-gate 	"hidden",
31510Sstevel@tonic-gate 	NULL
31520Sstevel@tonic-gate };
31530Sstevel@tonic-gate 
31540Sstevel@tonic-gate static
31550Sstevel@tonic-gate void
31560Sstevel@tonic-gate bad_arg(char *option)
31570Sstevel@tonic-gate {
31580Sstevel@tonic-gate 	(void) fprintf(stderr,
31590Sstevel@tonic-gate 		gettext("Unrecognized option %s.\n"), option);
31600Sstevel@tonic-gate 	usage();
31610Sstevel@tonic-gate 	exit(2);
31620Sstevel@tonic-gate }
31630Sstevel@tonic-gate 
31640Sstevel@tonic-gate static
31650Sstevel@tonic-gate void
31660Sstevel@tonic-gate missing_arg(char *option)
31670Sstevel@tonic-gate {
31680Sstevel@tonic-gate 	(void) fprintf(stderr,
31690Sstevel@tonic-gate 		gettext("Option %s requires a value.\n"), option);
31700Sstevel@tonic-gate 	usage();
31710Sstevel@tonic-gate 	exit(3);
31720Sstevel@tonic-gate }
31730Sstevel@tonic-gate 
31740Sstevel@tonic-gate static
31750Sstevel@tonic-gate void
31760Sstevel@tonic-gate parse_suboptions(char *optsstr)
31770Sstevel@tonic-gate {
31780Sstevel@tonic-gate 	char *value;
31790Sstevel@tonic-gate 	int c;
31800Sstevel@tonic-gate 
31810Sstevel@tonic-gate 	while (*optsstr != '\0') {
31820Sstevel@tonic-gate 		switch (c = getsubopt(&optsstr, LegalOpts, &value)) {
31830Sstevel@tonic-gate 		case NFLAG:
31840Sstevel@tonic-gate 			Notreally++;
31850Sstevel@tonic-gate 			break;
31860Sstevel@tonic-gate 		case VFLAG:
31870Sstevel@tonic-gate 			Verbose++;
31880Sstevel@tonic-gate 			break;
31890Sstevel@tonic-gate 		case RFLAG:
31900Sstevel@tonic-gate 			Firstfileattr |= 0x01;
31910Sstevel@tonic-gate 			break;
31920Sstevel@tonic-gate 		case HFLAG:
31930Sstevel@tonic-gate 			Firstfileattr |= 0x02;
31940Sstevel@tonic-gate 			break;
31950Sstevel@tonic-gate 		case SFLAG:
31960Sstevel@tonic-gate 			Firstfileattr |= 0x04;
31970Sstevel@tonic-gate 			break;
31980Sstevel@tonic-gate 		case SUNFLAG:
31990Sstevel@tonic-gate 			SunBPBfields = 1;
32000Sstevel@tonic-gate 			break;
32010Sstevel@tonic-gate 		case LABFLAG:
32020Sstevel@tonic-gate 			if (value == NULL) {
32030Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32040Sstevel@tonic-gate 			} else {
32050Sstevel@tonic-gate 				Label = value;
32060Sstevel@tonic-gate 			}
32070Sstevel@tonic-gate 			break;
32080Sstevel@tonic-gate 		case BTRFLAG:
32090Sstevel@tonic-gate 			if (value == NULL) {
32100Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32110Sstevel@tonic-gate 			} else {
32120Sstevel@tonic-gate 				BootBlkFn = value;
32130Sstevel@tonic-gate 			}
32140Sstevel@tonic-gate 			break;
32150Sstevel@tonic-gate 		case INITFLAG:
32160Sstevel@tonic-gate 			if (value == NULL) {
32170Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32180Sstevel@tonic-gate 			} else {
32190Sstevel@tonic-gate 				FirstFn = value;
32200Sstevel@tonic-gate 			}
32210Sstevel@tonic-gate 			break;
32220Sstevel@tonic-gate 		case SZFLAG:
32230Sstevel@tonic-gate 			if (value == NULL) {
32240Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32250Sstevel@tonic-gate 			} else {
32260Sstevel@tonic-gate 				TotSize = atoi(value);
32270Sstevel@tonic-gate 				GetSize = 0;
32280Sstevel@tonic-gate 			}
32290Sstevel@tonic-gate 			break;
32300Sstevel@tonic-gate 		case SECTFLAG:
32310Sstevel@tonic-gate 			if (value == NULL) {
32320Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32330Sstevel@tonic-gate 			} else {
32340Sstevel@tonic-gate 				SecPerTrk = atoi(value);
32350Sstevel@tonic-gate 				GetSPT = 0;
32360Sstevel@tonic-gate 			}
32370Sstevel@tonic-gate 			break;
32380Sstevel@tonic-gate 		case TRKFLAG:
32390Sstevel@tonic-gate 			if (value == NULL) {
32400Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32410Sstevel@tonic-gate 			} else {
32420Sstevel@tonic-gate 				TrkPerCyl = atoi(value);
32430Sstevel@tonic-gate 				GetTPC = 0;
32440Sstevel@tonic-gate 			}
32450Sstevel@tonic-gate 			break;
32460Sstevel@tonic-gate 		case SPCFLAG:
32470Sstevel@tonic-gate 			if (value == NULL) {
32480Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32490Sstevel@tonic-gate 			} else {
32500Sstevel@tonic-gate 				SecPerClust = atoi(value);
32510Sstevel@tonic-gate 				GetSPC = 0;
32520Sstevel@tonic-gate 			}
32530Sstevel@tonic-gate 			break;
32540Sstevel@tonic-gate 		case BPFFLAG:
32550Sstevel@tonic-gate 			if (value == NULL) {
32560Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32570Sstevel@tonic-gate 			} else {
32580Sstevel@tonic-gate 				BitsPerFAT = atoi(value);
32590Sstevel@tonic-gate 				GetBPF = 0;
32600Sstevel@tonic-gate 			}
32610Sstevel@tonic-gate 			break;
32620Sstevel@tonic-gate 		case NOFDISKFLAG:
32630Sstevel@tonic-gate 			DontUseFdisk = 1;
32640Sstevel@tonic-gate 			break;
32650Sstevel@tonic-gate 		case RESRVFLAG:
32660Sstevel@tonic-gate 			if (value == NULL) {
32670Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32680Sstevel@tonic-gate 			} else {
32690Sstevel@tonic-gate 				Resrvd = atoi(value);
32700Sstevel@tonic-gate 				GetResrvd = 0;
32710Sstevel@tonic-gate 			}
32720Sstevel@tonic-gate 			break;
32730Sstevel@tonic-gate 		case HIDDENFLAG:
32740Sstevel@tonic-gate 			if (value == NULL) {
32750Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32760Sstevel@tonic-gate 			} else {
32770Sstevel@tonic-gate 				RelOffset = atoi(value);
32780Sstevel@tonic-gate 				GetOffset = 0;
32790Sstevel@tonic-gate 			}
32800Sstevel@tonic-gate 			break;
32810Sstevel@tonic-gate 		case FFLAG:
32820Sstevel@tonic-gate 			if (value == NULL) {
32830Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32840Sstevel@tonic-gate 			} else {
32850Sstevel@tonic-gate 				DiskName = value;
32860Sstevel@tonic-gate 				Outputtofile = 1;
32870Sstevel@tonic-gate 			}
32880Sstevel@tonic-gate 			break;
32890Sstevel@tonic-gate 		case DFLAG:
32900Sstevel@tonic-gate 			if (value == NULL) {
32910Sstevel@tonic-gate 				missing_arg(LegalOpts[c]);
32920Sstevel@tonic-gate 			} else {
32930Sstevel@tonic-gate 				Imagesize = atoi(value);
32940Sstevel@tonic-gate 			}
32950Sstevel@tonic-gate 			break;
32960Sstevel@tonic-gate 		default:
32970Sstevel@tonic-gate 			bad_arg(value);
32980Sstevel@tonic-gate 			break;
32990Sstevel@tonic-gate 		}
33000Sstevel@tonic-gate 	}
33010Sstevel@tonic-gate }
33020Sstevel@tonic-gate 
33030Sstevel@tonic-gate static
33040Sstevel@tonic-gate void
33050Sstevel@tonic-gate sanity_check_options(int argc, int optind)
33060Sstevel@tonic-gate {
33070Sstevel@tonic-gate 	if (GetFsParams) {
33080Sstevel@tonic-gate 		if (argc - optind != 1)
33090Sstevel@tonic-gate 			usage();
33100Sstevel@tonic-gate 		return;
33110Sstevel@tonic-gate 	}
33120Sstevel@tonic-gate 
33130Sstevel@tonic-gate 	if (DontUseFdisk && GetOffset) {
33140Sstevel@tonic-gate 		/* Set default relative offset of zero */
33150Sstevel@tonic-gate 		RelOffset = 0;
33160Sstevel@tonic-gate 	}
33170Sstevel@tonic-gate 
33180Sstevel@tonic-gate 	if (BitsPerFAT == 32)
33190Sstevel@tonic-gate 		MakeFAT32 = 1;
33200Sstevel@tonic-gate 
33210Sstevel@tonic-gate 	if (Outputtofile && (argc - optind)) {
33220Sstevel@tonic-gate 		usage();
33230Sstevel@tonic-gate 	} else if (Outputtofile && !DiskName) {
33240Sstevel@tonic-gate 		usage();
33250Sstevel@tonic-gate 	} else if (!Outputtofile && (argc - optind != 1)) {
33260Sstevel@tonic-gate 		usage();
33270Sstevel@tonic-gate 	} else if (SunBPBfields && !BootBlkFn) {
33280Sstevel@tonic-gate 		(void) fprintf(stderr,
33290Sstevel@tonic-gate 		    gettext("Use of the 'S' option requires that\n"
33300Sstevel@tonic-gate 			    "the 'B=' option also be used.\n\n"));
33310Sstevel@tonic-gate 		usage();
33320Sstevel@tonic-gate 	} else if (Firstfileattr != 0x20 && !FirstFn) {
33330Sstevel@tonic-gate 		(void) fprintf(stderr,
33340Sstevel@tonic-gate 		    gettext("Use of the 'r', 'h', or 's' options requires\n"
33350Sstevel@tonic-gate 			    "that the 'i=' option also be used.\n\n"));
33360Sstevel@tonic-gate 		usage();
33370Sstevel@tonic-gate 	} else if (!GetOffset && !DontUseFdisk) {
33380Sstevel@tonic-gate 		(void) fprintf(stderr,
33390Sstevel@tonic-gate 		    gettext("Use of the 'hidden' option requires that\n"
33400Sstevel@tonic-gate 			    "the 'nofdisk' option also be used.\n\n"));
33410Sstevel@tonic-gate 		usage();
33420Sstevel@tonic-gate 	} else if (DontUseFdisk && GetSize) {
33430Sstevel@tonic-gate 		(void) fprintf(stderr,
33440Sstevel@tonic-gate 		    gettext("Use of the 'nofdisk' option requires that\n"
33450Sstevel@tonic-gate 			    "the 'size=' option also be used.\n\n"));
33460Sstevel@tonic-gate 		usage();
33470Sstevel@tonic-gate 	} else if (!GetBPF &&
33480Sstevel@tonic-gate 		    BitsPerFAT != 12 && BitsPerFAT != 16 && BitsPerFAT != 32) {
33490Sstevel@tonic-gate 		(void) fprintf(stderr,
33500Sstevel@tonic-gate 		    gettext("Invalid Bits/Fat value."
33510Sstevel@tonic-gate 			    "  Must be 12, 16 or 32.\n"));
33520Sstevel@tonic-gate 		exit(2);
33530Sstevel@tonic-gate 	} else if (!GetSPC && !powerofx_le_y(2, 128, SecPerClust)) {
33540Sstevel@tonic-gate 		(void) fprintf(stderr,
33550Sstevel@tonic-gate 		    gettext("Invalid Sectors/Cluster value.  Must be a "
33560Sstevel@tonic-gate 			    "power of 2 between 1 and 128.\n"));
33570Sstevel@tonic-gate 		exit(2);
33580Sstevel@tonic-gate 	} else if (!GetResrvd && (Resrvd < 1 || Resrvd > 0xffff)) {
33590Sstevel@tonic-gate 		(void) fprintf(stderr,
33600Sstevel@tonic-gate 		    gettext("Invalid number of reserved sectors.  "
33610Sstevel@tonic-gate 			"Must be at least 1 but\nno larger than 65535."));
33620Sstevel@tonic-gate 		exit(2);
33630Sstevel@tonic-gate 	} else if (!GetResrvd && MakeFAT32 &&
33640Sstevel@tonic-gate 		    (Resrvd < 32 || Resrvd > 0xffff)) {
33650Sstevel@tonic-gate 		(void) fprintf(stderr,
33660Sstevel@tonic-gate 		    gettext("Invalid number of reserved sectors.  "
33670Sstevel@tonic-gate 			"Must be at least 32 but\nno larger than 65535."));
33680Sstevel@tonic-gate 		exit(2);
33690Sstevel@tonic-gate 	} else if (Imagesize != 3 && Imagesize != 5) {
33700Sstevel@tonic-gate 		usage();
33710Sstevel@tonic-gate 	}
33720Sstevel@tonic-gate }
33730Sstevel@tonic-gate 
3374*452Sjkennedy int
33750Sstevel@tonic-gate main(int argc, char **argv)
33760Sstevel@tonic-gate {
33770Sstevel@tonic-gate 	off64_t AbsBootSect = 0;
33780Sstevel@tonic-gate 	bpb_t dskparamblk;
33790Sstevel@tonic-gate 	char *string;
33800Sstevel@tonic-gate 	int  fd;
33810Sstevel@tonic-gate 	int  c;
33820Sstevel@tonic-gate 
33830Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
33840Sstevel@tonic-gate 
33850Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
33860Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
33870Sstevel@tonic-gate #endif
33880Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
33890Sstevel@tonic-gate 
33900Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) {
33910Sstevel@tonic-gate 		switch (c) {
33920Sstevel@tonic-gate 		case 'F':
33930Sstevel@tonic-gate 			string = optarg;
33940Sstevel@tonic-gate 			if (strcmp(string, "pcfs") != 0)
33950Sstevel@tonic-gate 				usage();
33960Sstevel@tonic-gate 			break;
33970Sstevel@tonic-gate 		case 'V':
33980Sstevel@tonic-gate 			{
33990Sstevel@tonic-gate 				char	*opt_text;
34000Sstevel@tonic-gate 				int	opt_count;
34010Sstevel@tonic-gate 
34020Sstevel@tonic-gate 				(void) fprintf(stdout,
34030Sstevel@tonic-gate 				    gettext("mkfs -F pcfs "));
34040Sstevel@tonic-gate 				for (opt_count = 1; opt_count < argc;
34050Sstevel@tonic-gate 								opt_count++) {
34060Sstevel@tonic-gate 					opt_text = argv[opt_count];
34070Sstevel@tonic-gate 					if (opt_text)
34080Sstevel@tonic-gate 					    (void) fprintf(stdout, " %s ",
34090Sstevel@tonic-gate 								opt_text);
34100Sstevel@tonic-gate 				}
34110Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
34120Sstevel@tonic-gate 			}
34130Sstevel@tonic-gate 			break;
34140Sstevel@tonic-gate 		case 'm':
34150Sstevel@tonic-gate 			GetFsParams++;
34160Sstevel@tonic-gate 			break;
34170Sstevel@tonic-gate 		case 'o':
34180Sstevel@tonic-gate 			string = optarg;
34190Sstevel@tonic-gate 			parse_suboptions(string);
34200Sstevel@tonic-gate 			break;
34210Sstevel@tonic-gate 		}
34220Sstevel@tonic-gate 	}
34230Sstevel@tonic-gate 
34240Sstevel@tonic-gate 	sanity_check_options(argc, optind);
34250Sstevel@tonic-gate 
34260Sstevel@tonic-gate 	if (!Outputtofile)
34270Sstevel@tonic-gate 		DiskName = argv[optind];
34280Sstevel@tonic-gate 
34290Sstevel@tonic-gate 	(void) memset(&dskparamblk, 0, sizeof (dskparamblk));
34300Sstevel@tonic-gate 
34310Sstevel@tonic-gate 	if (GetFsParams) {
34320Sstevel@tonic-gate 		fd = open_and_examine(DiskName, &dskparamblk);
34330Sstevel@tonic-gate 	} else {
34340Sstevel@tonic-gate 		fd = open_and_seek(DiskName, &dskparamblk, &AbsBootSect);
34350Sstevel@tonic-gate 		if (ask_nicely(DiskName))
34360Sstevel@tonic-gate 			write_fat(fd, AbsBootSect, BootBlkFn, Label,
34370Sstevel@tonic-gate 			    FirstFn, &dskparamblk);
34380Sstevel@tonic-gate 	}
34390Sstevel@tonic-gate 	(void) close(fd);
3440*452Sjkennedy 	return (0);
34410Sstevel@tonic-gate }
3442