4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2011 Gary Mills
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #include <sys/types.h>
39 #include <sys/dktp/fdisk.h>
42 #include <sys/efi_partition.h>
43 #include <sys/sysmacros.h>
44 #include "mkfs_pcfs.h"
45 #include <sys/fs/pc_fs.h>
46 #include <sys/fs/pc_dir.h>
47 #include <sys/fs/pc_label.h>
53 * Install a boot block, FAT, and (if desired) the first resident
56 * XXX -- floppy opens need O_NDELAY?
58 #define IN_RANGE(n, x, y) (((n) >= (x)) && ((n) <= (y)))
59 #define DEFAULT_LABEL "NONAME"
61 static char *BootBlkFn
= NULL
;
62 static char *DiskName
= NULL
;
63 static char *FirstFn
= NULL
;
64 static char *Label
= NULL
;
65 static char Firstfileattr
= 0x20;
66 static int Outputtofile
= 0;
67 static int SunBPBfields
= 0;
68 static int GetFsParams
= 0;
69 static int Fatentsize
= 0;
70 static int Imagesize
= 3;
71 static int Notreally
= 0;
72 static int Verbose
= 0;
73 static int MakeFAT32
= 0;
76 * If there is an FDISK entry for the device where we're about to
77 * make the file system, we ought to make a file system that has the
78 * same size FAT as the FDISK table claims. We track the size FDISK
79 * thinks in this variable.
81 static int FdiskFATsize
= 0;
83 static int GetSize
= 1; /* Unless we're given as arg, must look it up */
84 static ulong_t TotSize
; /* Total size of FS in # of sectors */
85 static int GetSPC
= 1; /* Unless we're given as arg, must calculate */
86 static ulong_t SecPerClust
; /* # of sectors per cluster */
87 static int GetOffset
= 1; /* Unless we're given as arg, must look it up */
88 static ulong_t RelOffset
; /* Relative start sector (hidden sectors) */
89 static int GetSPT
= 1; /* Unless we're given as arg, must look it up */
90 static ushort_t SecPerTrk
; /* # of sectors per track */
91 static int GetTPC
= 1; /* Unless we're given as arg, must look it up */
92 static ushort_t TrkPerCyl
; /* # of tracks per cylinder */
93 static int GetResrvd
= 1; /* Unless we're given as arg, must calculate */
94 static int Resrvd
; /* Number of reserved sectors */
95 static int GetBPF
= 1; /* Unless we're given as arg, must calculate */
96 static int BitsPerFAT
; /* Total size of FS in # of sectors */
98 static ulong_t TotalClusters
; /* Computed total number of clusters */
101 * Unless we are told otherwise, we should use fdisk table for non-diskettes.
103 static int DontUseFdisk
= 0;
106 * Function prototypes
109 static void swap_pack_grabsebpb(bpb_t
*wbpb
, struct _boot_sector
*bsp
);
110 static void swap_pack_bpb32cpy(struct _boot_sector32
*bsp
, bpb_t
*wbpb
);
111 static void swap_pack_sebpbcpy(struct _boot_sector
*bsp
, bpb_t
*wbpb
);
112 static void swap_pack_grabbpb(bpb_t
*wbpb
, struct _boot_sector
*bsp
);
113 static void swap_pack_bpbcpy(struct _boot_sector
*bsp
, bpb_t
*wbpb
);
116 static uchar_t
*build_rootdir(bpb_t
*wbpb
, char *ffn
, int fffd
,
117 ulong_t ffsize
, pc_cluster32_t ffstart
, ulong_t
*rdirsize
);
118 static uchar_t
*build_fat(bpb_t
*wbpb
, struct fat_od_fsi
*fsinfop
,
119 ulong_t bootblksize
, ulong_t
*fatsize
, char *ffn
, int *fffd
,
120 ulong_t
*ffsize
, pc_cluster32_t
*ffstartclust
);
122 static char *stat_actual_disk(char *diskname
, struct stat
*info
, char **suffix
);
124 static void compare_existing_with_computed(int fd
, char *suffix
,
125 bpb_t
*wbpb
, int *prtsize
, int *prtspc
, int *prtbpf
, int *prtnsect
,
126 int *prtntrk
, int *prtfdisk
, int *prthidden
, int *prtrsrvd
,
128 static void print_reproducing_command(int fd
, char *actualdisk
, char *suffix
,
130 static void compute_file_area_size(bpb_t
*wbpb
);
131 static void write_fat32_bootstuff(int fd
, boot_sector_t
*bsp
,
132 struct fat_od_fsi
*fsinfop
, off64_t seekto
);
133 static void sanity_check_options(int argc
, int optind
);
134 static void compute_cluster_size(bpb_t
*wbpb
);
135 static void find_fixed_details(int fd
, bpb_t
*wbpb
);
136 static void dirent_fname_fill(struct pcdir
*dep
, char *fn
);
137 static void floppy_bpb_fillin(bpb_t
*wbpb
,
138 int diam
, int hds
, int spt
);
139 static void read_existing_bpb(int fd
, bpb_t
*wbpb
);
140 static void warn_funky_fatsize(void);
141 static void warn_funky_floppy(void);
142 static void dirent_time_fill(struct pcdir
*dep
);
143 static void parse_suboptions(char *optsstr
);
144 static void header_for_dump(void);
145 static void write_bootsects(int fd
, boot_sector_t
*bsp
, bpb_t
*wbpb
,
146 struct fat_od_fsi
*fsinfop
, off64_t seekto
);
147 static void fill_bpb_sizes(bpb_t
*wbpb
, struct ipart part
[],
148 int partno
, off64_t offset
);
149 static void set_fat_string(bpb_t
*wbpb
, int fatsize
);
150 static void partn_lecture(char *dn
);
151 static void store_16_bits(uchar_t
**bp
, uint32_t v
);
152 static void store_32_bits(uchar_t
**bp
, uint32_t v
);
153 static void lookup_floppy(struct fd_char
*fdchar
, bpb_t
*wbpb
);
154 static void label_volume(char *lbl
, bpb_t
*wbpb
);
155 static void mark_cluster(uchar_t
*fatp
, pc_cluster32_t clustnum
,
157 static void missing_arg(char *option
);
158 static void dashm_bail(int fd
);
159 static void dump_bytes(uchar_t
*, int);
160 static void write_rest(bpb_t
*wbpb
, char *efn
,
161 int dfd
, int sfd
, int remaining
);
162 static void write_fat(int fd
, off64_t seekto
, char *fn
, char *lbl
,
163 char *ffn
, bpb_t
*wbpb
);
164 static void bad_arg(char *option
);
165 static void usage(void);
167 static int prepare_image_file(char *fn
, bpb_t
*wbpb
);
168 static int verify_bootblkfile(char *fn
, boot_sector_t
*bs
,
169 ulong_t
*blkfilesize
);
170 static int open_and_examine(char *dn
, bpb_t
*wbpb
);
171 static int verify_firstfile(char *fn
, ulong_t
*filesize
);
172 static int lookup_FAT_size(uchar_t partid
);
173 static int open_and_seek(char *dn
, bpb_t
*wbpb
, off64_t
*seekto
);
174 static int warn_mismatch(char *desc
, char *src
, int expect
, int assigned
);
175 static int copy_bootblk(char *fn
, boot_sector_t
*bootsect
,
176 ulong_t
*bootblksize
);
177 static int parse_drvnum(char *pn
);
178 static int seek_nofdisk(int fd
, bpb_t
*wbpb
, off64_t
*seekto
);
179 static int ask_nicely(char *special
);
180 static int seek_partn(int fd
, char *pn
, bpb_t
*wbpb
, off64_t
*seekto
);
181 static int yes(void);
186 * Display usage message and exit.
192 (void) fprintf(stderr
,
193 gettext("pcfs usage: mkfs [-F FSType] [-V] [-m] "
194 "[-o specific_options] special\n"));
196 (void) fprintf(stderr
,
197 gettext(" -V: print this command line and return\n"
198 " -m: dump command line used to create a FAT on this media\n"
199 "\t(other options are ignored if this option is chosen).\n"
200 " -o: pcfs_specific_options:\n"
201 "\t'pcfs_specific_options' is a comma separated list\n"
202 "\tincluding one or more of the following options:\n"
203 "\t N,v,r,h,s,b=label,B=filename,i=filename,\n"
204 "\t spc=n,fat=n,nsect=n,ntrack=n,nofdisk,size=n,\n"
205 "\t reserve=n,hidden=n\n\n"));
207 (void) fprintf(stderr
,
208 gettext("'Special' should specify a raw diskette "
209 "or raw fixed disk device. \"Fixed\"\n"
210 "disks (which include high-capacity removable "
211 "media such as Zip disks)\n"
212 "may be further qualified with a logical "
214 "Examples are: /dev/rdiskette and "
215 "/dev/rdsk/c0t0d0p0:c\n"));
223 char *affirmative
= gettext("yY");
224 char *a
= affirmative
;
228 while (b
== '\n' && b
!= '\0' && b
!= EOF
)
240 ask_nicely(char *special
)
243 * 4228473 - No way to non-interactively make a pcfs filesystem
245 * If we don't have an input TTY, or we aren't really doing
246 * anything, then don't ask questions. Assume a yes answer
247 * to any questions we would ask.
249 if (Notreally
|| !isatty(fileno(stdin
)))
253 gettext("Construct a new FAT file system on %s: (y/n)? "), special
);
254 (void) fflush(stdout
);
260 * Save the lower 16 bits of a 32 bit value (v) into the provided
261 * buffer (pointed at by *bp), and increment the buffer pointer
262 * as well. This way the routine can be called multiple times in
263 * succession to fill buffers. The value is stored in little-endian
268 store_16_bits(uchar_t
**bp
, uint32_t v
)
273 *l
= (v
>> 8) & 0xff;
279 * Save the 32 bit value (v) into the provided buffer (pointed
280 * at by *bp), and increment the buffer pointer as well. This way
281 * the routine can be called multiple times in succession to fill
282 * buffers. The value is stored in little-endian order.
286 store_32_bits(uchar_t
**bp
, uint32_t v
)
291 for (b
= 0; b
< 4; b
++) {
299 * dump_bytes -- display bytes as hex numbers.
300 * b is the pointer to the byte buffer
301 * n is the number of bytes in the buffer
303 /* Note: BPL = bytes to display per line */
308 dump_bytes(uchar_t
*b
, int n
)
316 /* Display offset, 16 bytes per line, and printable ascii version */
319 (void) printf("\n%06x: ", o
);
320 for (bl
= 0; bl
< BPL
; bl
++) {
322 (void) printf("%02x ", (b
[cu
+bl
] & 0xff));
328 for (bl
= 0; bl
< BPL
; bl
++) {
330 ((b
[cu
+bl
] >= ' ') && (b
[cu
+bl
] <= '~')))
331 (void) printf("%c", b
[cu
+bl
]);
335 cu
+= ac
; o
+= ac
; cd
-= ac
;
337 (void) printf("\n\n");
341 * header_for_dump -- display simple header over what will be output.
345 header_for_dump(void)
349 (void) printf("\n ");
350 for (bl
= 0; bl
< BPL
; bl
++)
351 (void) printf("%02x ", bl
);
352 (void) printf("\n ");
360 * Convert a partition name into a drive number.
364 parse_drvnum(char *pn
)
369 * Determine logical drive to seek after.
371 if (strlen(pn
) == 1 && *pn
>= 'c' && *pn
<= 'z') {
372 drvnum
= *pn
- 'c' + 1;
373 } else if (*pn
>= '0' && *pn
<= '9') {
379 while (*d
&& *d
>= '0' && *d
<= '9') {
389 (void) fprintf(stderr
,
390 gettext("%s: bogus logical drive specification.\n"),
395 } else if (strcmp(pn
, "boot") == 0) {
398 (void) fprintf(stderr
,
399 gettext("%s: bogus logical drive specification.\n"), pn
);
407 * Define some special logical drives we use.
409 #define BOOT_PARTITION_DRIVE 99
410 #define PRIMARY_DOS_DRIVE 1
414 * Boolean function. Give it the systid field for an fdisk partition
415 * and it decides if that's a systid that describes a DOS drive. We
416 * use systid values defined in sys/dktp/fdisk.h.
419 isDosDrive(uchar_t checkMe
)
421 return ((checkMe
== DOSOS12
) || (checkMe
== DOSOS16
) ||
422 (checkMe
== DOSHUGE
) || (checkMe
== FDISK_WINDOWS
) ||
423 (checkMe
== FDISK_EXT_WIN
) || (checkMe
== FDISK_FAT95
) ||
424 (checkMe
== DIAGPART
));
429 * Boolean function. Give it the systid field for an fdisk partition
430 * and it decides if that's a systid that describes an extended DOS
434 isDosExtended(uchar_t checkMe
)
436 return ((checkMe
== EXTDOS
) || (checkMe
== FDISK_EXTLBA
));
441 * Boolean function. Give it the systid field for an fdisk partition
442 * and it decides if that's a systid that describes a Solaris boot
446 isBootPart(uchar_t checkMe
)
448 return (checkMe
== X86BOOT
);
453 warn_mismatch(char *desc
, char *src
, int expect
, int assigned
)
455 if (expect
== assigned
)
459 * 4228473 - No way to non-interactively make a pcfs filesystem
461 * If we don't have an input TTY, or we aren't really doing
462 * anything, then don't ask questions. Assume a yes answer
463 * to any questions we would ask.
465 if (Notreally
|| !isatty(fileno(stdin
))) {
466 (void) printf(gettext("WARNING: User supplied %s is %d,"
467 "\nbut value obtained from the %s is %d.\n"
468 "Using user supplied value.\n"),
469 desc
, assigned
, src
, expect
);
473 (void) printf(gettext("User supplied %s is %d."
474 "\nThe value obtained from the %s is %d.\n"),
475 desc
, assigned
, src
, expect
);
478 gettext("Continue with value given on command line (y/n)? "));
479 (void) fflush(stdout
);
489 fill_fat32_bpb(bpb_t
*wbpb
)
492 * ExtFlags means (according to MSDN BPB (FAT32) document)
494 * Bit 8 indicates info written to the active FAT is written
495 * to all copies of the FAT. (I think they mean bit 7, with
496 * numbering starting at 0)
498 * Lowest 4 bits of field are the 0 based FAT number of the
499 * Active FAT. (only meaningful if bit 8 is set)
501 * Field contains combination of these values:
504 * BGBPB_F_ActiveFATMsk Mask for low four bits
506 * BGBPB_F_NoFATMirror If set FAT mirroring disabled.
507 * (0x0080) If clear, FAT mirroring enabled.
509 * We set the value based on what I've seen on all the FAT32 drives
510 * I've seen created by Windows.
513 wbpb
->bpb32
.ext_flags
= 0x0;
515 * No real explanation of the fs_vers file in the BPB doc. The
516 * high byte is supposed to be the major version and the low the
517 * minor version. Again I set according to what I've seen on Windows.
519 wbpb
->bpb32
.fs_vers_lo
= '\0';
520 wbpb
->bpb32
.fs_vers_hi
= '\0';
522 * The convention appears to be to place the fs info sector
523 * immediately after the boot sector, and that the backup boot
524 * sector should be at sector 6. (based on what I see with
527 wbpb
->bpb32
.fsinfosec
= 1;
528 wbpb
->bpb32
.backupboot
= 6;
533 fill_bpb_sizes(bpb_t
*wbpb
, struct ipart part
[], int partno
, off64_t offset
)
537 if (GetFsParams
|| GetSize
) {
538 usesize
= ltohi(part
[partno
].numsect
);
541 gettext("Partition size (from FDISK table) "
542 "= %d sectors.\n"), usesize
);
545 usesize
= warn_mismatch(
546 gettext("length of partition (in sectors)"),
547 gettext("FDISK table"),
548 ltohi(part
[partno
].numsect
), TotSize
);
554 if (usesize
> 0xffff)
555 wbpb
->bpb
.sectors_in_volume
= 0;
557 wbpb
->bpb
.sectors_in_volume
= usesize
;
558 wbpb
->bpb
.sectors_in_logical_volume
= usesize
;
561 wbpb
->bpb
.hidden_sectors
= offset
;
566 wbpb
->sunbpb
.bs_offset_high
= offset
>> 16;
567 wbpb
->sunbpb
.bs_offset_low
= offset
& 0xFFFF;
574 * Given the FDISK partition file system identifier, return the
575 * expected FAT size for the partition.
579 lookup_FAT_size(uchar_t partid
)
610 * Seek to the beginning of the partition where we need to install
611 * the new FAT. Zero return for any error, but print error
616 seek_partn(int fd
, char *pn
, bpb_t
*wbpb
, off64_t
*seekto
)
618 struct ipart part
[FD_NUMPART
];
619 struct mboot extmboot
;
621 diskaddr_t xstartsect
;
622 off64_t nextseek
= 0;
623 off64_t lastseek
= 0;
624 int logicalDriveCount
= 0;
625 int extendedPart
= -1;
626 int primaryPart
= -1;
628 uint32_t xnumsect
= 0;
633 * Count of drives in the current extended partition's
634 * FDISK table, and indexes of the drives themselves.
636 int extndDrives
[FD_NUMPART
];
639 * Count of drives (beyond primary) in master boot record's
640 * FDISK table, and indexes of the drives themselves.
642 int extraDrives
[FD_NUMPART
];
643 int numExtraDrives
= 0;
645 if ((drvnum
= parse_drvnum(pn
)) < 0)
646 return (PART_NOT_FOUND
);
648 if (read(fd
, &mb
, sizeof (mb
)) != sizeof (mb
)) {
649 (void) fprintf(stderr
,
650 gettext("Couldn't read a Master Boot Record?!\n"));
651 return (PART_NOT_FOUND
);
654 if (ltohs(mb
.signature
) != BOOTSECSIG
) {
655 (void) fprintf(stderr
,
656 gettext("Bad Sig on master boot record!\n"));
657 return (PART_NOT_FOUND
);
663 * Copy partition table into memory
665 (void) memcpy(part
, mb
.parts
, sizeof (part
));
668 * Get a summary of what is in the Master FDISK table.
669 * Normally we expect to find one partition marked as a DOS drive.
670 * This partition is the one Windows calls the primary dos partition.
671 * If the machine has any logical drives then we also expect
672 * to find a partition marked as an extended DOS partition.
674 * Sometimes we'll find multiple partitions marked as DOS drives.
675 * The Solaris fdisk program allows these partitions
676 * to be created, but Windows fdisk no longer does. We still need
677 * to support these, though, since Windows does. We also need to fix
678 * our fdisk to behave like the Windows version.
680 * It turns out that some off-the-shelf media have *only* an
681 * Extended partition, so we need to deal with that case as
684 * Only a single (the first) Extended or Boot Partition will
685 * be recognized. Any others will be ignored.
687 for (i
= 0; i
< FD_NUMPART
; i
++) {
688 if (isDosDrive(part
[i
].systid
)) {
689 if (primaryPart
< 0) {
693 extraDrives
[numExtraDrives
++] = i
;
697 if ((extendedPart
< 0) && isDosExtended(part
[i
].systid
)) {
701 if ((bootPart
< 0) && isBootPart(part
[i
].systid
)) {
707 if (drvnum
== BOOT_PARTITION_DRIVE
) {
709 (void) fprintf(stderr
,
710 gettext("No boot partition found on drive\n"));
711 return (PART_NOT_FOUND
);
713 if ((*seekto
= ltohi(part
[bootPart
].relsect
)) == 0) {
714 (void) fprintf(stderr
, gettext("Bogus FDISK entry? "
715 "A boot partition starting\nat sector 0 would "
716 "collide with the FDISK table!\n"));
717 return (PART_NOT_FOUND
);
720 fill_bpb_sizes(wbpb
, part
, bootPart
, *seekto
);
722 FdiskFATsize
= lookup_FAT_size(part
[bootPart
].systid
);
724 (void) printf(gettext("Boot partition's offset: "
725 "Sector %x.\n"), *seekto
/BPSEC
);
726 if (lseek64(fd
, *seekto
, SEEK_SET
) < 0) {
727 (void) fprintf(stderr
, gettext("Partition %s: "), pn
);
729 return (PART_NOT_FOUND
);
734 if (drvnum
== PRIMARY_DOS_DRIVE
&& primaryPart
>= 0) {
735 if ((*seekto
= ltohi(part
[primaryPart
].relsect
)) == 0) {
736 (void) fprintf(stderr
, gettext("Bogus FDISK entry? "
737 "A partition starting\nat sector 0 would "
738 "collide with the FDISK table!\n"));
739 return (PART_NOT_FOUND
);
742 fill_bpb_sizes(wbpb
, part
, primaryPart
, *seekto
);
744 FdiskFATsize
= lookup_FAT_size(part
[primaryPart
].systid
);
746 (void) printf(gettext("Partition's offset: "
747 "Sector %x.\n"), *seekto
/BPSEC
);
748 if (lseek64(fd
, *seekto
, SEEK_SET
) < 0) {
749 (void) fprintf(stderr
, gettext("Partition %s: "), pn
);
751 return (PART_NOT_FOUND
);
757 * We are not looking for the C: drive (or there was no primary
758 * drive found), so we had better have an extended partition or
759 * extra drives in the Master FDISK table.
761 if ((extendedPart
< 0) && (numExtraDrives
== 0)) {
762 (void) fprintf(stderr
,
763 gettext("No such logical drive "
764 "(missing extended partition entry)\n"));
765 return (PART_NOT_FOUND
);
768 if (extendedPart
>= 0) {
769 nextseek
= xstartsect
= ltohi(part
[extendedPart
].relsect
);
770 xnumsect
= ltohi(part
[extendedPart
].numsect
);
773 * If the seek would not cause us to change
774 * position on the drive, then we're out of
775 * extended partitions to examine.
777 if (nextseek
== lastseek
)
779 logicalDriveCount
+= numDrives
;
781 * Seek the next extended partition, and find
782 * logical drives within it.
784 if (lseek64(fd
, nextseek
* BPSEC
, SEEK_SET
) < 0 ||
785 read(fd
, &extmboot
, sizeof (extmboot
)) !=
787 perror(gettext("Unable to read extended "
788 "partition record"));
789 return (PART_NOT_FOUND
);
791 (void) memcpy(part
, extmboot
.parts
, sizeof (part
));
793 if (ltohs(extmboot
.signature
) != MBB_MAGIC
) {
794 (void) fprintf(stderr
,
795 gettext("Bad signature on "
796 "extended partition\n"));
797 return (PART_NOT_FOUND
);
800 * Count up drives, and track where the next
801 * extended partition is in case we need it. We
802 * are expecting only one extended partition. If
803 * there is more than one we'll only go to the
804 * first one we see, but warn about ignoring.
807 for (i
= 0; i
< FD_NUMPART
; i
++) {
808 if (isDosDrive(part
[i
].systid
)) {
809 extndDrives
[numDrives
++] = i
;
811 } else if (isDosExtended(part
[i
].systid
)) {
812 if (nextseek
!= lastseek
) {
814 * Already found an extended
815 * partition in this table.
817 (void) fprintf(stderr
,
819 "Ignoring unexpected "
820 "additional extended "
824 nextseek
= xstartsect
+
825 ltohi(part
[i
].relsect
);
829 } while (drvnum
> logicalDriveCount
+ numDrives
);
831 if (drvnum
<= logicalDriveCount
+ numDrives
) {
833 * The number of logical drives we've found thus
834 * far is enough to get us to the one we were
837 driveIndex
= logicalDriveCount
+ numDrives
- drvnum
;
839 ltohi(part
[extndDrives
[driveIndex
]].relsect
) +
841 if (*seekto
== lastseek
) {
842 (void) fprintf(stderr
,
843 gettext("Bogus FDISK entry? A logical "
844 "drive starting at\nsector 0x%llx would "
845 "collide with the\nFDISK information in "
846 "that sector.\n"), *seekto
);
847 return (PART_NOT_FOUND
);
848 } else if (*seekto
<= xstartsect
||
849 *seekto
>= (xstartsect
+ xnumsect
)) {
850 (void) fprintf(stderr
,
851 gettext("Bogus FDISK entry? "
852 "Logical drive start sector (0x%llx)\n"
853 "not within extended partition! "
854 "(Expected in range 0x%x - 0x%x)\n"),
855 *seekto
, xstartsect
+ 1,
856 xstartsect
+ xnumsect
- 1);
857 return (PART_NOT_FOUND
);
859 fill_bpb_sizes(wbpb
, part
, extndDrives
[driveIndex
],
862 FdiskFATsize
= lookup_FAT_size(
863 part
[extndDrives
[driveIndex
]].systid
);
865 (void) printf(gettext("Partition's offset: "
866 "Sector 0x%x.\n"), *seekto
/BPSEC
);
867 if (lseek64(fd
, *seekto
, SEEK_SET
) < 0) {
868 (void) fprintf(stderr
,
869 gettext("Partition %s: "), pn
);
871 return (PART_NOT_FOUND
);
876 * We ran out of extended dos partition
877 * drives. The only hope now is to go
878 * back to extra drives defined in the master
879 * fdisk table. But we overwrote that table
880 * already, so we must load it in again.
882 logicalDriveCount
+= numDrives
;
883 (void) memcpy(part
, mb
.parts
, sizeof (part
));
887 * Still haven't found the drive, is it an extra
888 * drive defined in the main FDISK table?
890 if (drvnum
<= logicalDriveCount
+ numExtraDrives
) {
891 driveIndex
= logicalDriveCount
+ numExtraDrives
- drvnum
;
892 *seekto
= ltohi(part
[extraDrives
[driveIndex
]].relsect
);
894 (void) fprintf(stderr
, gettext("Bogus FDISK entry? "
895 "A partition starting\nat sector 0 would "
896 "collide with the FDISK table!\n"));
897 return (PART_NOT_FOUND
);
900 fill_bpb_sizes(wbpb
, part
, extraDrives
[driveIndex
], *seekto
);
903 lookup_FAT_size(part
[extraDrives
[driveIndex
]].systid
);
905 (void) printf(gettext("Partition's offset: "
906 "Sector %x.\n"), *seekto
/BPSEC
);
907 if (lseek64(fd
, *seekto
, SEEK_SET
) < 0) {
908 (void) fprintf(stderr
,
909 gettext("Partition %s: "), pn
);
911 return (PART_NOT_FOUND
);
915 (void) fprintf(stderr
, gettext("No such logical drive\n"));
916 return (PART_NOT_FOUND
);
922 * User is asking us to trust them that they know best.
923 * We basically won't do much seeking here, the only seeking we'll do
924 * is if the 'hidden' parameter was given.
928 seek_nofdisk(int fd
, bpb_t
*wbpb
, off64_t
*seekto
)
930 if (TotSize
> 0xffff)
931 wbpb
->bpb
.sectors_in_volume
= 0;
933 wbpb
->bpb
.sectors_in_volume
= (short)TotSize
;
934 wbpb
->bpb
.sectors_in_logical_volume
= TotSize
;
936 *seekto
= RelOffset
* BPSEC
;
937 wbpb
->bpb
.hidden_sectors
= RelOffset
;
938 wbpb
->sunbpb
.bs_offset_high
= RelOffset
>> 16;
939 wbpb
->sunbpb
.bs_offset_low
= RelOffset
& 0xFFFF;
942 (void) printf(gettext("Requested offset: Sector %x.\n"),
945 if (lseek64(fd
, *seekto
, SEEK_SET
) < 0) {
946 (void) fprintf(stderr
,
947 gettext("User specified start sector %d"), RelOffset
);
949 return (PART_NOT_FOUND
);
957 * Fill in the type string of the FAT
961 set_fat_string(bpb_t
*wbpb
, int fatsize
)
964 (void) strncpy((char *)wbpb
->ebpb
.type
, FAT12_TYPE_STRING
,
965 strlen(FAT12_TYPE_STRING
));
966 } else if (fatsize
== 16) {
967 (void) strncpy((char *)wbpb
->ebpb
.type
, FAT16_TYPE_STRING
,
968 strlen(FAT16_TYPE_STRING
));
970 (void) strncpy((char *)wbpb
->ebpb
.type
, FAT32_TYPE_STRING
,
971 strlen(FAT32_TYPE_STRING
));
978 * Open the file that will hold the image (as opposed to the image
979 * being written to the boot sector of an actual disk).
983 prepare_image_file(char *fn
, bpb_t
*wbpb
)
986 char zerobyte
= '\0';
988 if ((fd
= open(fn
, O_RDWR
| O_CREAT
| O_EXCL
, 0666)) < 0) {
993 if (Imagesize
== 5) {
994 /* Disk image of a 1.2M floppy */
995 wbpb
->bpb
.sectors_in_volume
= 2 * 80 * 15;
996 wbpb
->bpb
.sectors_in_logical_volume
= 2 * 80 * 15;
997 wbpb
->bpb
.sectors_per_track
= 15;
999 wbpb
->bpb
.media
= 0xF9;
1000 wbpb
->bpb
.num_root_entries
= 224;
1001 wbpb
->bpb
.sectors_per_cluster
= 1;
1002 wbpb
->bpb
.sectors_per_fat
= 7;
1004 /* Disk image of a 1.44M floppy */
1005 wbpb
->bpb
.sectors_in_volume
= 2 * 80 * 18;
1006 wbpb
->bpb
.sectors_in_logical_volume
= 2 * 80 * 18;
1007 wbpb
->bpb
.sectors_per_track
= 18;
1008 wbpb
->bpb
.heads
= 2;
1009 wbpb
->bpb
.media
= 0xF0;
1010 wbpb
->bpb
.num_root_entries
= 224;
1011 wbpb
->bpb
.sectors_per_cluster
= 1;
1012 wbpb
->bpb
.sectors_per_fat
= 9;
1016 * Make a holey file, with length the exact
1017 * size of the floppy image.
1019 if (lseek(fd
, (wbpb
->bpb
.sectors_in_volume
* BPSEC
)-1, SEEK_SET
) < 0) {
1025 if (write(fd
, &zerobyte
, 1) != 1) {
1031 if (lseek(fd
, 0, SEEK_SET
) < 0) {
1037 Fatentsize
= 12; /* Size of fat entry in bits */
1038 set_fat_string(wbpb
, Fatentsize
);
1040 wbpb
->ebpb
.phys_drive_num
= 0;
1042 wbpb
->sunbpb
.bs_offset_high
= 0;
1043 wbpb
->sunbpb
.bs_offset_low
= 0;
1051 * Give a brief sermon on dev_name user should pass to
1052 * the program from the command line.
1057 partn_lecture(char *dn
)
1059 (void) fprintf(stderr
,
1060 gettext("\nDevice %s was assumed to be a diskette.\n"
1061 "A diskette specific operation failed on this device.\n"
1062 "If the device is a hard disk, provide the name of "
1063 "the full physical disk,\n"
1064 "and qualify that name with a logical drive specifier.\n\n"
1065 "Hint: the device is usually something similar to\n\n"
1066 "/dev/rdsk/c0d0p0 or /dev/rdsk/c0t0d0p0 (x86)\n"
1067 "/dev/rdsk/c0t5d0s2 (sparc)\n\n"
1068 "The drive specifier is appended to the device name."
1070 "/dev/rdsk/c0t5d0s2:c or /dev/rdsk/c0d0p0:boot\n\n"), dn
);
1075 warn_funky_floppy(void)
1077 (void) fprintf(stderr
,
1078 gettext("Use the 'nofdisk' option to create file systems\n"
1079 "on non-standard floppies.\n\n"));
1085 warn_funky_fatsize(void)
1087 (void) fprintf(stderr
,
1088 gettext("Non-standard FAT size requested for floppy.\n"
1089 "The 'nofdisk' option must be used to\n"
1090 "override the 12 bit floppy default.\n\n"));
1096 floppy_bpb_fillin(bpb_t
*wbpb
, int diam
, int hds
, int spt
)
1104 wbpb
->bpb
.media
= 0xF9;
1105 wbpb
->bpb
.num_root_entries
= 112;
1106 wbpb
->bpb
.sectors_per_cluster
= 2;
1107 wbpb
->bpb
.sectors_per_fat
= 3;
1110 wbpb
->bpb
.media
= 0xF0;
1111 wbpb
->bpb
.num_root_entries
= 224;
1112 wbpb
->bpb
.sectors_per_cluster
= 1;
1113 wbpb
->bpb
.sectors_per_fat
= 9;
1116 wbpb
->bpb
.media
= 0xF0;
1117 wbpb
->bpb
.num_root_entries
= 240;
1118 wbpb
->bpb
.sectors_per_cluster
= 2;
1119 wbpb
->bpb
.sectors_per_fat
= 9;
1122 (void) fprintf(stderr
,
1123 gettext("Unknown diskette parameters! "
1124 "3.5'' diskette with %d heads "
1125 "and %d sectors/track.\n"), hds
, spt
);
1126 warn_funky_floppy();
1131 (void) fprintf(stderr
,
1132 gettext("Unknown diskette parameters! "
1133 "3.5'' diskette with %d heads "), hds
);
1134 warn_funky_floppy();
1142 wbpb
->bpb
.media
= 0xF9;
1143 wbpb
->bpb
.num_root_entries
= 224;
1144 wbpb
->bpb
.sectors_per_cluster
= 1;
1145 wbpb
->bpb
.sectors_per_fat
= 7;
1148 wbpb
->bpb
.media
= 0xFD;
1149 wbpb
->bpb
.num_root_entries
= 112;
1150 wbpb
->bpb
.sectors_per_cluster
= 2;
1151 wbpb
->bpb
.sectors_per_fat
= 2;
1154 wbpb
->bpb
.media
= 0xFF;
1155 wbpb
->bpb
.num_root_entries
= 112;
1156 wbpb
->bpb
.sectors_per_cluster
= 1;
1157 wbpb
->bpb
.sectors_per_fat
= 2;
1160 (void) fprintf(stderr
,
1161 gettext("Unknown diskette parameters! "
1162 "5.25'' diskette with %d heads "
1163 "and %d sectors/track.\n"), hds
, spt
);
1164 warn_funky_floppy();
1170 wbpb
->bpb
.media
= 0xFC;
1171 wbpb
->bpb
.num_root_entries
= 64;
1172 wbpb
->bpb
.sectors_per_cluster
= 1;
1173 wbpb
->bpb
.sectors_per_fat
= 2;
1176 wbpb
->bpb
.media
= 0xFE;
1177 wbpb
->bpb
.num_root_entries
= 64;
1178 wbpb
->bpb
.sectors_per_cluster
= 1;
1179 wbpb
->bpb
.sectors_per_fat
= 1;
1182 (void) fprintf(stderr
,
1183 gettext("Unknown diskette parameters! "
1184 "5.25'' diskette with %d heads "
1185 "and %d sectors/track.\n"), hds
, spt
);
1186 warn_funky_floppy();
1190 (void) fprintf(stderr
,
1191 gettext("Unknown diskette parameters! "
1192 "5.25'' diskette with %d heads."), hds
);
1193 warn_funky_floppy();
1197 (void) fprintf(stderr
,
1198 gettext("\nUnknown diskette type. Only know about "
1199 "5.25'' and 3.5'' diskettes.\n"));
1200 warn_funky_floppy();
1207 * Look up a media descriptor byte and other crucial BPB values
1208 * based on floppy characteristics.
1212 lookup_floppy(struct fd_char
*fdchar
, bpb_t
*wbpb
)
1215 ulong_t cyls
, spt
, hds
, diam
;
1217 cyls
= fdchar
->fdc_ncyl
;
1218 diam
= fdchar
->fdc_medium
;
1219 spt
= fdchar
->fdc_secptrack
;
1220 hds
= fdchar
->fdc_nhead
;
1222 tsize
= cyls
* hds
* spt
;
1228 wbpb
->bpb
.sectors_in_logical_volume
= tsize
;
1230 wbpb
->bpb
.sectors_in_logical_volume
=
1232 gettext("length of partition (in sectors)"),
1233 gettext("FDIOGCHAR call"), tsize
, TotSize
);
1235 wbpb
->bpb
.sectors_in_volume
=
1236 (short)wbpb
->bpb
.sectors_in_logical_volume
;
1239 wbpb
->bpb
.sectors_per_track
= spt
;
1241 wbpb
->bpb
.sectors_per_track
=
1243 gettext("sectors per track"),
1244 gettext("FDIOGCHAR call"), spt
, SecPerTrk
);
1245 spt
= wbpb
->bpb
.sectors_per_track
;
1249 wbpb
->bpb
.heads
= hds
;
1253 gettext("number of heads"),
1254 gettext("FDIOGCHAR call"), hds
, TrkPerCyl
);
1255 hds
= wbpb
->bpb
.heads
;
1258 Fatentsize
= 12; /* Size of fat entry in bits */
1259 if (!GetBPF
&& BitsPerFAT
!= Fatentsize
) {
1260 warn_funky_fatsize();
1262 set_fat_string(wbpb
, Fatentsize
);
1264 wbpb
->ebpb
.phys_drive_num
= 0;
1266 wbpb
->bpb
.hidden_sectors
= 0;
1267 wbpb
->sunbpb
.bs_offset_high
= 0;
1268 wbpb
->sunbpb
.bs_offset_low
= 0;
1270 floppy_bpb_fillin(wbpb
, diam
, hds
, spt
);
1274 * compute_cluster_size
1276 * Compute an acceptable sectors/cluster value.
1278 * Based on values from the Hardware White Paper
1280 * "Microsoft Extensible Firmware Initiative
1281 * FAT32 File System Specification
1282 * FAT: General Overview of On-Disk Format"
1284 * Version 1.03, December 6, 2000
1289 compute_cluster_size(bpb_t
*wbpb
)
1293 ulong_t rds
, tmpval1
, tmpval2
;
1297 #define FAT12_MAX_CLUSTERS 0x0FF4
1298 #define FAT16_MAX_CLUSTERS 0xFFF4
1299 #define FAT32_MAX_CLUSTERS 0x0FFFFFF0
1300 #define FAT32_SUGGESTED_NCLUST 0x400000
1302 /* compute volume size in sectors. */
1303 volsize
= wbpb
->bpb
.sectors_in_volume
? wbpb
->bpb
.sectors_in_volume
:
1304 wbpb
->bpb
.sectors_in_logical_volume
;
1305 volsize
-= wbpb
->bpb
.resv_sectors
;
1309 * User indicated what sort of FAT to create,
1310 * make sure it is valid with the given size
1311 * and compute an SPC value.
1313 if (!MakeFAT32
) { /* FAT16 */
1314 /* volsize is in sectors */
1315 if (volsize
< FAT12_MAX_CLUSTERS
) {
1316 (void) fprintf(stderr
,
1317 gettext("Requested size is too "
1318 "small for FAT16.\n"));
1321 /* SPC must be a power of 2 */
1322 for (spc
= 1; spc
<= 64; spc
= spc
* 2) {
1323 if (volsize
< spc
* FAT16_MAX_CLUSTERS
)
1326 if (volsize
> (spc
* FAT16_MAX_CLUSTERS
)) {
1327 (void) fprintf(stderr
,
1328 gettext("Requested size is too "
1329 "large for FAT16.\n"));
1332 } else { /* FAT32 */
1333 /* volsize is in sectors */
1334 if (volsize
< FAT16_MAX_CLUSTERS
) {
1335 (void) fprintf(stderr
,
1336 gettext("Requested size is too "
1337 "small for FAT32.\n"));
1340 /* SPC must be a power of 2 */
1341 for (spc
= 1; spc
<= 64; spc
= spc
* 2) {
1342 if (volsize
< (spc
* FAT32_SUGGESTED_NCLUST
))
1345 if (volsize
> (spc
* FAT32_MAX_CLUSTERS
)) {
1346 (void) fprintf(stderr
,
1347 gettext("Requested size is too "
1348 "large for FAT32.\n"));
1354 * User gave the SPC as an explicit option,
1355 * make sure it will work with the requested
1361 nclust
= volsize
/ spc
;
1363 if (nclust
<= FAT16_MAX_CLUSTERS
&& MakeFAT32
) {
1364 (void) fprintf(stderr
, gettext("Requested size is too "
1365 "small for FAT32.\n"));
1369 /* Determine if FAT12 or FAT16 */
1370 if (nclust
< FAT12_MAX_CLUSTERS
)
1372 else if (nclust
< FAT16_MAX_CLUSTERS
)
1375 (void) fprintf(stderr
,
1376 gettext("Requested size is too "
1377 "small for FAT32.\n"));
1384 * RootDirSectors = ((BPB_RootEntCnt * 32) +
1385 * (BPB_BytsPerSec 1)) / BPB_BytsPerSec;
1387 rds
= ((wbpb
->bpb
.num_root_entries
* 32) +
1388 (wbpb
->bpb
.bytes_sector
- 1)) / wbpb
->bpb
.bytes_sector
;
1394 Fatentsize
= newfat
;
1396 Fatentsize
= BitsPerFAT
;
1398 if (Fatentsize
== 12 &&
1399 (volsize
- rds
) >= DOS_F12MAXC
* spc
) {
1401 * If we don't have an input TTY, or we aren't
1402 * really doing anything, then don't ask
1403 * questions. Assume a yes answer to any
1404 * questions we would ask.
1406 if (Notreally
|| !isatty(fileno(stdin
))) {
1408 gettext("Volume too large for 12 bit FAT,"
1409 " increasing to 16 bit FAT size.\n"));
1410 (void) fflush(stdout
);
1414 gettext("Volume too large for a 12 bit FAT.\n"
1415 "Increase to 16 bit FAT "
1416 "and continue (y/n)? "));
1417 (void) fflush(stdout
);
1425 wbpb
->bpb
.sectors_per_cluster
= spc
;
1427 if (!GetFsParams
&& FdiskFATsize
< 0) {
1429 gettext("Cannot verify chosen/computed FAT "
1430 "entry size (%d bits) with FDISK table.\n"
1431 "FDISK table has an unknown file system "
1432 "type for this device. Giving up...\n"),
1433 Fatentsize
, Fatentsize
);
1435 } else if (!GetFsParams
&& FdiskFATsize
&& FdiskFATsize
!= Fatentsize
) {
1437 gettext("Chosen/computed FAT entry size (%d bits) "
1438 "does not match FDISK table (%d bits).\n"),
1439 Fatentsize
, FdiskFATsize
);
1441 gettext("Use -o fat=%d to build a FAT "
1442 "that matches the FDISK entry.\n"), FdiskFATsize
);
1445 set_fat_string(wbpb
, Fatentsize
);
1447 * Compure the FAT sizes according to algorithm from Microsoft:
1449 * RootDirSectors = ((BPB_RootEntCnt * 32) +
1450 * (BPB_BytsPerSec 1)) / BPB_BytsPerSec;
1451 * TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors);
1452 * TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
1453 * If (FATType == FAT32)
1454 * TmpVal2 = TmpVal2 / 2;
1455 * FATSz = (TMPVal1 + (TmpVal2 1)) / TmpVal2;
1456 * If (FATType == FAT32) {
1458 * BPB_FATSz32 = FATSz;
1460 * BPB_FATSz16 = LOWORD(FATSz);
1461 * // there is no BPB_FATSz32 in a FAT16 BPB
1464 tmpval1
= volsize
- (wbpb
->bpb
.resv_sectors
+ rds
);
1466 tmpval2
= (256 * wbpb
->bpb
.sectors_per_cluster
) + wbpb
->bpb
.num_fats
;
1468 if (Fatentsize
== 32)
1469 tmpval2
= tmpval2
/ 2;
1471 fatsz
= (tmpval1
+ (tmpval2
- 1)) / tmpval2
;
1473 /* Compute a sector/fat figure */
1474 switch (Fatentsize
) {
1476 wbpb
->bpb
.sectors_per_fat
= 0;
1477 wbpb
->bpb32
.big_sectors_per_fat
= fatsz
;
1479 (void) printf("compute_cluster_size: Sectors per "
1480 "FAT32 = %d\n", wbpb
->bpb32
.big_sectors_per_fat
);
1483 default: /* 16 bit FAT */
1484 wbpb
->bpb
.sectors_per_fat
= (ushort_t
)(fatsz
& 0x0000FFFF);
1486 (void) printf("compute_cluster_size: Sectors per "
1487 "FAT16 = %d\n", wbpb
->bpb
.sectors_per_fat
);
1494 find_fixed_details(int fd
, bpb_t
*wbpb
)
1496 struct dk_geom dginfo
;
1499 * Look up the last remaining bits of info we need
1500 * that is specific to the hard drive using a disk ioctl.
1502 if (GetSPT
|| GetTPC
) {
1503 if (ioctl(fd
, DKIOCG_VIRTGEOM
, &dginfo
) == -1 &&
1504 ioctl(fd
, DKIOCG_PHYGEOM
, &dginfo
) == -1 &&
1505 ioctl(fd
, DKIOCGGEOM
, &dginfo
) == -1) {
1508 gettext("Drive geometry lookup (need "
1509 "tracks/cylinder and/or sectors/track"));
1514 wbpb
->bpb
.heads
= (GetTPC
? dginfo
.dkg_nhead
: TrkPerCyl
);
1515 wbpb
->bpb
.sectors_per_track
= (GetSPT
? dginfo
.dkg_nsect
: SecPerTrk
);
1520 gettext("DKIOCG determined number of heads = %d\n"),
1525 gettext("DKIOCG determined sectors per track"
1526 " = %d\n"), dginfo
.dkg_nsect
);
1531 * XXX - MAY need an additional flag (or flags) to set media
1532 * and physical drive number fields. That in the case of weird
1533 * floppies that have to go through 'nofdisk' route for formatting.
1535 wbpb
->bpb
.media
= 0xF8;
1537 wbpb
->bpb
.num_root_entries
= 0;
1539 wbpb
->bpb
.num_root_entries
= 512;
1540 wbpb
->ebpb
.phys_drive_num
= 0x80;
1541 compute_cluster_size(wbpb
);
1546 stat_actual_disk(char *diskname
, struct stat
*info
, char **suffix
)
1550 if (stat(diskname
, info
)) {
1552 * Device named on command line doesn't exist. That
1553 * probably means there is a partition-specifying
1554 * suffix attached to the actual disk name.
1556 actualdisk
= strtok(strdup(diskname
), ":");
1557 if (*suffix
= strchr(diskname
, ':'))
1560 if (stat(actualdisk
, info
)) {
1565 actualdisk
= strdup(diskname
);
1568 return (actualdisk
);
1573 compute_file_area_size(bpb_t
*wbpb
)
1578 int RootDirSectors
=
1579 ((wbpb
->bpb
.num_root_entries
* 32) + (wbpb
->bpb
.bytes_sector
- 1)) /
1580 wbpb
->bpb
.bytes_sector
;
1582 if (wbpb
->bpb
.sectors_per_fat
) {
1584 * Good old FAT12 or FAT16
1586 FATSz
= wbpb
->bpb
.sectors_per_fat
;
1587 TotSec
= wbpb
->bpb
.sectors_in_volume
;
1592 FATSz
= wbpb
->bpb32
.big_sectors_per_fat
;
1593 TotSec
= wbpb
->bpb
.sectors_in_logical_volume
;
1597 (wbpb
->bpb
.resv_sectors
+ (wbpb
->bpb
.num_fats
* FATSz
) +
1602 * Now change sectors to clusters
1604 TotalClusters
= DataSec
/ wbpb
->bpb
.sectors_per_cluster
;
1607 (void) printf(gettext("Disk has a file area of %d "
1608 "allocation units,\neach with %d sectors = %d "
1609 "bytes.\n"), TotalClusters
, wbpb
->bpb
.sectors_per_cluster
,
1610 TotalClusters
* wbpb
->bpb
.sectors_per_cluster
* BPSEC
);
1615 * swap_pack_{bpb,bpb32,sebpb}cpy
1617 * If not on an x86 we assume the structures making up the bpb
1618 * were not packed and that longs and shorts need to be byte swapped
1619 * (we've kept everything in host order up until now). A new architecture
1620 * might not need to swap or might not need to pack, in which case
1621 * new routines will have to be written. Of course if an architecture
1622 * supports both packing and little-endian host order, it can follow the
1623 * same path as the x86 code.
1627 swap_pack_bpbcpy(struct _boot_sector
*bsp
, bpb_t
*wbpb
)
1631 fillp
= (uchar_t
*)&(bsp
->bs_filler
[ORIG_BPB_START_INDEX
]);
1633 store_16_bits(&fillp
, wbpb
->bpb
.bytes_sector
);
1634 *fillp
++ = wbpb
->bpb
.sectors_per_cluster
;
1635 store_16_bits(&fillp
, wbpb
->bpb
.resv_sectors
);
1636 *fillp
++ = wbpb
->bpb
.num_fats
;
1637 store_16_bits(&fillp
, wbpb
->bpb
.num_root_entries
);
1638 store_16_bits(&fillp
, wbpb
->bpb
.sectors_in_volume
);
1639 *fillp
++ = wbpb
->bpb
.media
;
1640 store_16_bits(&fillp
, wbpb
->bpb
.sectors_per_fat
);
1641 store_16_bits(&fillp
, wbpb
->bpb
.sectors_per_track
);
1642 store_16_bits(&fillp
, wbpb
->bpb
.heads
);
1643 store_32_bits(&fillp
, wbpb
->bpb
.hidden_sectors
);
1644 store_32_bits(&fillp
, wbpb
->bpb
.sectors_in_logical_volume
);
1646 *fillp
++ = wbpb
->ebpb
.phys_drive_num
;
1647 *fillp
++ = wbpb
->ebpb
.reserved
;
1648 *fillp
++ = wbpb
->ebpb
.ext_signature
;
1649 store_32_bits(&fillp
, wbpb
->ebpb
.volume_id
);
1650 (void) strncpy((char *)fillp
, (char *)wbpb
->ebpb
.volume_label
, 11);
1652 (void) strncpy((char *)fillp
, (char *)wbpb
->ebpb
.type
, 8);
1657 swap_pack_bpb32cpy(struct _boot_sector32
*bsp
, bpb_t
*wbpb
)
1662 fillp
= (uchar_t
*)&(bsp
->bs_filler
[ORIG_BPB_START_INDEX
]);
1664 store_16_bits(&fillp
, wbpb
->bpb
.bytes_sector
);
1665 *fillp
++ = wbpb
->bpb
.sectors_per_cluster
;
1666 store_16_bits(&fillp
, wbpb
->bpb
.resv_sectors
);
1667 *fillp
++ = wbpb
->bpb
.num_fats
;
1668 store_16_bits(&fillp
, wbpb
->bpb
.num_root_entries
);
1669 store_16_bits(&fillp
, wbpb
->bpb
.sectors_in_volume
);
1670 *fillp
++ = wbpb
->bpb
.media
;
1671 store_16_bits(&fillp
, wbpb
->bpb
.sectors_per_fat
);
1672 store_16_bits(&fillp
, wbpb
->bpb
.sectors_per_track
);
1673 store_16_bits(&fillp
, wbpb
->bpb
.heads
);
1674 store_32_bits(&fillp
, wbpb
->bpb
.hidden_sectors
);
1675 store_32_bits(&fillp
, wbpb
->bpb
.sectors_in_logical_volume
);
1677 store_32_bits(&fillp
, wbpb
->bpb32
.big_sectors_per_fat
);
1678 store_16_bits(&fillp
, wbpb
->bpb32
.ext_flags
);
1679 *fillp
++ = wbpb
->bpb32
.fs_vers_lo
;
1680 *fillp
++ = wbpb
->bpb32
.fs_vers_hi
;
1681 store_32_bits(&fillp
, wbpb
->bpb32
.root_dir_clust
);
1682 store_16_bits(&fillp
, wbpb
->bpb32
.fsinfosec
);
1683 store_16_bits(&fillp
, wbpb
->bpb32
.backupboot
);
1684 for (r
= 0; r
< 6; r
++)
1685 store_16_bits(&fillp
, wbpb
->bpb32
.reserved
[r
]);
1687 *fillp
++ = wbpb
->ebpb
.phys_drive_num
;
1688 *fillp
++ = wbpb
->ebpb
.reserved
;
1689 *fillp
++ = wbpb
->ebpb
.ext_signature
;
1690 store_32_bits(&fillp
, wbpb
->ebpb
.volume_id
);
1691 (void) strncpy((char *)fillp
, (char *)wbpb
->ebpb
.volume_label
, 11);
1693 (void) strncpy((char *)fillp
, (char *)wbpb
->ebpb
.type
, 8);
1698 swap_pack_sebpbcpy(struct _boot_sector
*bsp
, bpb_t
*wbpb
)
1702 fillp
= bsp
->bs_sun_bpb
;
1703 store_16_bits(&fillp
, wbpb
->sunbpb
.bs_offset_high
);
1704 store_16_bits(&fillp
, wbpb
->sunbpb
.bs_offset_low
);
1709 swap_pack_grabbpb(bpb_t
*wbpb
, struct _boot_sector
*bsp
)
1713 grabp
= (uchar_t
*)&(bsp
->bs_filler
[ORIG_BPB_START_INDEX
]);
1715 ((uchar_t
*)&(wbpb
->bpb
.bytes_sector
))[1] = *grabp
++;
1716 ((uchar_t
*)&(wbpb
->bpb
.bytes_sector
))[0] = *grabp
++;
1717 wbpb
->bpb
.sectors_per_cluster
= *grabp
++;
1718 ((uchar_t
*)&(wbpb
->bpb
.resv_sectors
))[1] = *grabp
++;
1719 ((uchar_t
*)&(wbpb
->bpb
.resv_sectors
))[0] = *grabp
++;
1720 wbpb
->bpb
.num_fats
= *grabp
++;
1721 ((uchar_t
*)&(wbpb
->bpb
.num_root_entries
))[1] = *grabp
++;
1722 ((uchar_t
*)&(wbpb
->bpb
.num_root_entries
))[0] = *grabp
++;
1723 ((uchar_t
*)&(wbpb
->bpb
.sectors_in_volume
))[1] = *grabp
++;
1724 ((uchar_t
*)&(wbpb
->bpb
.sectors_in_volume
))[0] = *grabp
++;
1725 wbpb
->bpb
.media
= *grabp
++;
1726 ((uchar_t
*)&(wbpb
->bpb
.sectors_per_fat
))[1] = *grabp
++;
1727 ((uchar_t
*)&(wbpb
->bpb
.sectors_per_fat
))[0] = *grabp
++;
1728 ((uchar_t
*)&(wbpb
->bpb
.sectors_per_track
))[1] = *grabp
++;
1729 ((uchar_t
*)&(wbpb
->bpb
.sectors_per_track
))[0] = *grabp
++;
1730 ((uchar_t
*)&(wbpb
->bpb
.heads
))[1] = *grabp
++;
1731 ((uchar_t
*)&(wbpb
->bpb
.heads
))[0] = *grabp
++;
1732 ((uchar_t
*)&(wbpb
->bpb
.hidden_sectors
))[3] = *grabp
++;
1733 ((uchar_t
*)&(wbpb
->bpb
.hidden_sectors
))[2] = *grabp
++;
1734 ((uchar_t
*)&(wbpb
->bpb
.hidden_sectors
))[1] = *grabp
++;
1735 ((uchar_t
*)&(wbpb
->bpb
.hidden_sectors
))[0] = *grabp
++;
1736 ((uchar_t
*)&(wbpb
->bpb
.sectors_in_logical_volume
))[3] = *grabp
++;
1737 ((uchar_t
*)&(wbpb
->bpb
.sectors_in_logical_volume
))[2] = *grabp
++;
1738 ((uchar_t
*)&(wbpb
->bpb
.sectors_in_logical_volume
))[1] = *grabp
++;
1739 ((uchar_t
*)&(wbpb
->bpb
.sectors_in_logical_volume
))[0] = *grabp
++;
1740 wbpb
->ebpb
.phys_drive_num
= *grabp
++;
1741 wbpb
->ebpb
.reserved
= *grabp
++;
1742 wbpb
->ebpb
.ext_signature
= *grabp
++;
1743 ((uchar_t
*)&(wbpb
->ebpb
.volume_id
))[3] = *grabp
++;
1744 ((uchar_t
*)&(wbpb
->ebpb
.volume_id
))[2] = *grabp
++;
1745 ((uchar_t
*)&(wbpb
->ebpb
.volume_id
))[1] = *grabp
++;
1746 ((uchar_t
*)&(wbpb
->ebpb
.volume_id
))[0] = *grabp
++;
1748 (void) strncpy((char *)wbpb
->ebpb
.volume_label
, (char *)grabp
, 11);
1750 (void) strncpy((char *)wbpb
->ebpb
.type
, (char *)grabp
, 8);
1755 swap_pack_grabsebpb(bpb_t
*wbpb
, struct _boot_sector
*bsp
)
1759 grabp
= bsp
->bs_sun_bpb
;
1760 ((uchar_t
*)&(wbpb
->sunbpb
.bs_offset_high
))[1] = *grabp
++;
1761 ((uchar_t
*)&(wbpb
->sunbpb
.bs_offset_high
))[0] = *grabp
++;
1762 ((uchar_t
*)&(wbpb
->sunbpb
.bs_offset_low
))[1] = *grabp
++;
1763 ((uchar_t
*)&(wbpb
->sunbpb
.bs_offset_low
))[0] = *grabp
++;
1768 swap_pack_grab32bpb(bpb_t
*wbpb
, struct _boot_sector
*bsp
)
1772 grabp
= (uchar_t
*)&(bsp
->bs_filler
[BPB_32_START_INDEX
]);
1774 ((uchar_t
*)&(wbpb
->bpb32
.big_sectors_per_fat
))[3] = *grabp
++;
1775 ((uchar_t
*)&(wbpb
->bpb32
.big_sectors_per_fat
))[2] = *grabp
++;
1776 ((uchar_t
*)&(wbpb
->bpb32
.big_sectors_per_fat
))[1] = *grabp
++;
1777 ((uchar_t
*)&(wbpb
->bpb32
.big_sectors_per_fat
))[0] = *grabp
++;
1778 ((uchar_t
*)&(wbpb
->bpb32
.ext_flags
))[1] = *grabp
++;
1779 ((uchar_t
*)&(wbpb
->bpb32
.ext_flags
))[0] = *grabp
++;
1780 wbpb
->bpb32
.fs_vers_lo
= *grabp
++;
1781 wbpb
->bpb32
.fs_vers_hi
= *grabp
++;
1782 ((uchar_t
*)&(wbpb
->bpb32
.root_dir_clust
))[3] = *grabp
++;
1783 ((uchar_t
*)&(wbpb
->bpb32
.root_dir_clust
))[2] = *grabp
++;
1784 ((uchar_t
*)&(wbpb
->bpb32
.root_dir_clust
))[1] = *grabp
++;
1785 ((uchar_t
*)&(wbpb
->bpb32
.root_dir_clust
))[0] = *grabp
++;
1786 ((uchar_t
*)&(wbpb
->bpb32
.fsinfosec
))[1] = *grabp
++;
1787 ((uchar_t
*)&(wbpb
->bpb32
.fsinfosec
))[0] = *grabp
++;
1788 ((uchar_t
*)&(wbpb
->bpb32
.backupboot
))[1] = *grabp
++;
1789 ((uchar_t
*)&(wbpb
->bpb32
.backupboot
))[0] = *grabp
++;
1790 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[0]))[1] = *grabp
++;
1791 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[0]))[0] = *grabp
++;
1792 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[1]))[1] = *grabp
++;
1793 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[1]))[0] = *grabp
++;
1794 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[2]))[1] = *grabp
++;
1795 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[2]))[0] = *grabp
++;
1796 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[3]))[1] = *grabp
++;
1797 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[3]))[0] = *grabp
++;
1798 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[4]))[1] = *grabp
++;
1799 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[4]))[0] = *grabp
++;
1800 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[5]))[1] = *grabp
++;
1801 ((uchar_t
*)&(wbpb
->bpb32
.reserved
[5]))[0] = *grabp
++;
1809 (void) fprintf(stderr
,
1810 gettext("This media does not appear to be "
1811 "formatted with a FAT file system.\n"));
1819 * Grab the first sector, which we think is a bios parameter block.
1820 * If it looks bad, bail. Otherwise fill in the parameter struct
1821 * fields that matter.
1825 read_existing_bpb(int fd
, bpb_t
*wbpb
)
1829 if (read(fd
, ubpb
.buf
, BPSEC
) < BPSEC
) {
1830 perror(gettext("Read BIOS parameter block "
1831 "from previously formatted media"));
1836 if (ltohs(ubpb
.mb
.signature
) != BOOTSECSIG
) {
1841 (void) memcpy(&(wbpb
->bpb
), &(ubpb
.bs
.bs_front
.bs_bpb
),
1842 sizeof (wbpb
->bpb
));
1843 (void) memcpy(&(wbpb
->ebpb
), &(ubpb
.bs
.bs_ebpb
), sizeof (wbpb
->ebpb
));
1845 swap_pack_grabbpb(wbpb
, &(ubpb
.bs
));
1849 (void) memcpy(&(wbpb
->sunbpb
), &(ubpb
.bs
.bs_sebpb
),
1850 sizeof (wbpb
->sunbpb
));
1852 swap_pack_grabsebpb(wbpb
, &(ubpb
.bs
));
1855 if (wbpb
->bpb
.bytes_sector
!= BPSEC
) {
1856 (void) fprintf(stderr
,
1857 gettext("Bogus bytes per sector value.\n"));
1858 if (!(ISP2(wbpb
->bpb
.bytes_sector
) &&
1859 IN_RANGE(wbpb
->bpb
.bytes_sector
, 1, BPSEC
* 8))) {
1860 (void) fprintf(stderr
,
1861 gettext("The device name may be missing a "
1862 "logical drive specifier.\n"));
1866 (void) fprintf(stderr
,
1867 gettext("Do not know how to build FATs with a\n"
1868 "non-standard sector size. Standard "
1869 "size is %d bytes,\nyour sector size "
1870 "is %d bytes.\n"), BPSEC
,
1871 wbpb
->bpb
.bytes_sector
);
1876 if (!(ISP2(wbpb
->bpb
.sectors_per_cluster
) &&
1877 IN_RANGE(wbpb
->bpb
.sectors_per_cluster
, 1, 128))) {
1878 (void) fprintf(stderr
,
1879 gettext("Bogus sectors per cluster value.\n"));
1880 (void) fprintf(stderr
,
1881 gettext("The device name may be missing a "
1882 "logical drive specifier.\n"));
1887 if (wbpb
->bpb
.sectors_per_fat
== 0) {
1889 (void) memcpy(&(wbpb
->bpb32
), &(ubpb
.bs32
.bs_bpb32
),
1890 sizeof (wbpb
->bpb32
));
1892 swap_pack_grab32bpb(wbpb
, &(ubpb
.bs
));
1894 compute_file_area_size(wbpb
);
1895 if ((wbpb
->bpb32
.big_sectors_per_fat
* BPSEC
/ 4) >=
1902 compute_file_area_size(wbpb
);
1907 * compare_existing_with_computed
1909 * We use this function when we the user specifies the -m option.
1910 * We compute and look up things like we would if they had asked
1911 * us to make the fs, and compare that to what's already layed down
1912 * in the existing fs. If there's a difference we can tell them what
1913 * options to specify in order to reproduce their existing layout.
1914 * Note that they still may not get an exact duplicate, because we
1915 * don't, for example, preserve their existing boot code. We think
1916 * we've got all the fields that matter covered, though.
1918 * XXX - We're basically ignoring sbpb at this point. I'm unsure
1919 * if we'll ever care about those fields, in terms of the -m option.
1923 compare_existing_with_computed(int fd
, char *suffix
,
1924 bpb_t
*wbpb
, int *prtsize
, int *prtspc
, int *prtbpf
, int *prtnsect
,
1925 int *prtntrk
, int *prtfdisk
, int *prthidden
, int *prtrsrvd
, int *dashos
)
1927 struct dk_geom dginfo
;
1928 struct fd_char fdchar
;
1930 int fd_ioctl_worked
= 0;
1934 * For all non-floppy cases we expect to find a 16-bit FAT
1936 int expectfatsize
= 16;
1941 if (ioctl(fd
, FDIOGCHAR
, &fdchar
) != -1) {
1947 if (fd_ioctl_worked
) {
1949 fdchar
.fdc_medium
= 3;
1951 GetSize
= GetSPT
= GetSPC
= GetTPC
= GetBPF
= 1;
1952 lookup_floppy(&fdchar
, &compare
);
1953 if (compare
.bpb
.heads
!= wbpb
->bpb
.heads
) {
1957 if (compare
.bpb
.sectors_per_track
!=
1958 wbpb
->bpb
.sectors_per_track
) {
1963 int dk_ioctl_worked
= 1;
1970 if (ioctl(fd
, DKIOCG_VIRTGEOM
, &dginfo
) == -1 &&
1971 ioctl(fd
, DKIOCG_PHYGEOM
, &dginfo
) == -1 &&
1972 ioctl(fd
, DKIOCGGEOM
, &dginfo
) == -1) {
1973 *prtnsect
= *prtntrk
= 1;
1975 dk_ioctl_worked
= 0;
1977 if (dk_ioctl_worked
) {
1978 if (dginfo
.dkg_nhead
!= wbpb
->bpb
.heads
) {
1982 if (dginfo
.dkg_nsect
!=
1983 wbpb
->bpb
.sectors_per_track
) {
1988 GetBPF
= GetSPC
= 1;
1989 compute_cluster_size(&compare
);
1992 if (!*prtfdisk
&& TotSize
!= wbpb
->bpb
.sectors_in_volume
&&
1993 TotSize
!= wbpb
->bpb
.sectors_in_logical_volume
) {
1998 if (compare
.bpb
.sectors_per_cluster
!= wbpb
->bpb
.sectors_per_cluster
) {
2003 if (compare
.bpb
.hidden_sectors
!= wbpb
->bpb
.hidden_sectors
) {
2008 if (compare
.bpb
.resv_sectors
!= wbpb
->bpb
.resv_sectors
) {
2014 * Compute approximate Fatentsize. It's approximate because the
2015 * size of the FAT may not be exactly a multiple of the number of
2016 * clusters. It should be close, though.
2023 fatents
= wbpb
->bpb
.sectors_per_fat
* BPSEC
* 2 / 3;
2024 if (fatents
>= TotalClusters
&& wbpb
->ebpb
.type
[4] == '2')
2028 if (Fatentsize
!= expectfatsize
) {
2037 print_reproducing_command(int fd
, char *actualdisk
, char *suffix
, bpb_t
*wbpb
)
2051 compare_existing_with_computed(fd
, suffix
, wbpb
,
2052 &prtsize
, &prtspc
, &prtbpf
, &prtnsect
, &prtntrk
,
2053 &prtfdisk
, &prthidden
, &prtrsrvd
, &dashos
);
2056 * Print out the command line they can use to reproduce the
2059 (void) printf("mkfs -F pcfs");
2061 ll
= min(11, (int)strlen((char *)wbpb
->ebpb
.volume_label
));
2063 * First, eliminate trailing spaces. Now compare the name against
2064 * our default label. If there's a match we don't need to print
2068 while (wbpb
->ebpb
.volume_label
[--i
] == ' ')
2072 if (ll
== strlen(DEFAULT_LABEL
) - 1) {
2075 (void) strcpy(cmpbuf
, DEFAULT_LABEL
);
2076 for (i
= ll
; i
>= 0; i
--) {
2078 toupper((int)(wbpb
->ebpb
.volume_label
[i
]))) {
2087 (void) printf(" -o ");
2088 (void) printf("b=\"");
2089 for (i
= 0; i
<= ll
; i
++) {
2090 (void) printf("%c", wbpb
->ebpb
.volume_label
[i
]);
2092 (void) printf("\"");
2094 } else if (dashos
) {
2095 (void) printf(" -o ");
2098 #define NEXT_DASH_O dashos--; needcomma++; continue
2106 (void) printf("nofdisk");
2111 (void) printf("size=%u", wbpb
->bpb
.sectors_in_volume
?
2112 wbpb
->bpb
.sectors_in_volume
:
2113 wbpb
->bpb
.sectors_in_logical_volume
);
2118 (void) printf("nsect=%d", wbpb
->bpb
.sectors_per_track
);
2123 (void) printf("spc=%d", wbpb
->bpb
.sectors_per_cluster
);
2128 (void) printf("ntrack=%d", wbpb
->bpb
.heads
);
2133 (void) printf("fat=%d", Fatentsize
);
2138 (void) printf("hidden=%u", wbpb
->bpb
.hidden_sectors
);
2143 (void) printf("reserve=%d", wbpb
->bpb
.resv_sectors
);
2149 (void) printf(" %s%c%c\n", actualdisk
,
2150 suffix
? ':' : '\0', suffix
? *suffix
: '\0');
2156 * Open the requested 'dev_name'. Seek to point where
2157 * we'd expect to find boot sectors, etc., based on any ':partition'
2158 * attachments to the dev_name.
2160 * Examine the fields of any existing boot sector and display best
2161 * approximation of how this fs could be reproduced with this command.
2165 open_and_examine(char *dn
, bpb_t
*wbpb
)
2169 char *actualdisk
= NULL
;
2170 char *suffix
= NULL
;
2172 struct dk_minfo dkminfo
;
2175 (void) printf(gettext("Opening destination device/file.\n"));
2177 actualdisk
= stat_actual_disk(dn
, &di
, &suffix
);
2180 * Destination exists, now find more about it.
2182 if (!(S_ISCHR(di
.st_mode
))) {
2183 (void) fprintf(stderr
,
2184 gettext("\n%s: device name must be a "
2185 "character special device.\n"), actualdisk
);
2187 } else if ((fd
= open(actualdisk
, O_RDWR
)) < 0) {
2193 * Check the media sector size
2195 if (ioctl(fd
, DKIOCGMEDIAINFO
, &dkminfo
) != -1) {
2196 if (dkminfo
.dki_lbsize
!= 0 &&
2197 ISP2(dkminfo
.dki_lbsize
/ DEV_BSIZE
) &&
2198 dkminfo
.dki_lbsize
!= DEV_BSIZE
) {
2199 (void) fprintf(stderr
,
2200 gettext("The device sector size %u is not "
2201 "supported by pcfs!\n"), dkminfo
.dki_lbsize
);
2208 * Find appropriate partition if we were requested to do so.
2210 if (suffix
&& !(seek_partn(fd
, suffix
, wbpb
, &ignored
))) {
2215 read_existing_bpb(fd
, wbpb
);
2216 print_reproducing_command(fd
, actualdisk
, suffix
, wbpb
);
2224 * Extracts information about disk path in dn. We need to return both a
2225 * file descriptor and the device's suffix.
2226 * Secondarily, we need to detect the FAT type and size when dealing with
2230 getdiskinfo(char *dn
, char **suffix
)
2232 struct dk_minfo dkminfo
;
2234 int rv
, fd
, reserved
;
2235 char *actualdisk
= NULL
;
2236 dk_gpt_t
*gpt
= NULL
;
2238 actualdisk
= stat_actual_disk(dn
, &di
, suffix
);
2241 * Destination exists, now find more about it.
2243 if (!(S_ISCHR(di
.st_mode
))) {
2244 (void) fprintf(stderr
,
2245 gettext("Device name must indicate a "
2246 "character special device: %s\n"), actualdisk
);
2248 } else if ((fd
= open(actualdisk
, O_RDWR
)) < 0) {
2254 * Check the media sector size
2256 if (ioctl(fd
, DKIOCGMEDIAINFO
, &dkminfo
) != -1) {
2257 if (dkminfo
.dki_lbsize
!= 0 &&
2258 ISP2(dkminfo
.dki_lbsize
/ DEV_BSIZE
) &&
2259 dkminfo
.dki_lbsize
!= DEV_BSIZE
) {
2260 (void) fprintf(stderr
,
2261 gettext("The device sector size %u is not "
2262 "supported by pcfs!\n"), dkminfo
.dki_lbsize
);
2268 rv
= efi_alloc_and_read(fd
, &gpt
);
2270 * We should see only VT_EINVAL, VT_EIO and VT_ERROR.
2271 * VT_EINVAL is for the case there is no GPT label.
2272 * VT_ERROR will happen if device does no support the ioctl, so
2273 * we will exit only in case of VT_EIO and unknown value of rv.
2275 if (rv
< 0 && rv
!= VT_EINVAL
&& rv
!= VT_ERROR
) {
2278 (void) fprintf(stderr
,
2279 gettext("IO Error reading EFI label\n"));
2282 (void) fprintf(stderr
,
2283 gettext("Unknown Error %d reading EFI label\n"),
2292 if (*suffix
!= NULL
) {
2293 (void) fprintf(stderr
,
2294 gettext("Can not use drive specifier \"%s\" with "
2295 "GPT partitioning.\n"), *suffix
);
2300 /* Can not use whole disk, 7 is GPT minor node "wd" */
2302 (void) fprintf(stderr
,
2303 gettext("Device name must indicate a "
2304 "partition: %s\n"), actualdisk
);
2311 TotSize
= gpt
->efi_parts
[rv
].p_size
;
2316 if (GetResrvd
== 1) {
2317 /* FAT32 has 32 reserved sectors */
2323 * The type of FAT is determined by the size of
2324 * the partition - reserved sectors.
2325 * The calculation is based on logic used in
2326 * compute_cluster_size() and therefore we will not
2327 * get into error situation when
2328 * compute_cluster_size() will be called.
2330 if (TotSize
- reserved
< FAT16_MAX_CLUSTERS
) {
2334 if (TotSize
- reserved
< FAT12_MAX_CLUSTERS
) {
2339 * compute sectors per cluster
2342 for (spc
= 1; spc
<= 64;
2344 if (TotSize
- reserved
<
2345 spc
* FAT12_MAX_CLUSTERS
)
2369 * Open the requested 'dev_name'. Seek to point where
2370 * we'll write boot sectors, etc., based on any ':partition'
2371 * attachments to the dev_name.
2373 * By the time we are finished here, the entire BPB will be
2374 * filled in, excepting the volume label.
2378 open_and_seek(char *dn
, bpb_t
*wbpb
, off64_t
*seekto
)
2380 struct fd_char fdchar
;
2382 char *actualdisk
= NULL
;
2383 char *suffix
= NULL
;
2387 (void) printf(gettext("Opening destination device/file.\n"));
2390 * We hold these truths to be self evident, all BPBs we create
2391 * will have these values in these fields.
2393 wbpb
->bpb
.num_fats
= 2;
2394 wbpb
->bpb
.bytes_sector
= BPSEC
;
2397 * Assign or use supplied numbers for hidden and
2398 * reserved sectors in the file system.
2402 wbpb
->bpb
.resv_sectors
= 32;
2404 wbpb
->bpb
.resv_sectors
= 1;
2406 wbpb
->bpb
.resv_sectors
= Resrvd
;
2408 wbpb
->ebpb
.ext_signature
= 0x29; /* Magic number for modern format */
2409 wbpb
->ebpb
.volume_id
= 0;
2412 fill_fat32_bpb(wbpb
);
2415 * If all output goes to a simple file, call a routine to setup
2416 * that scenario. Otherwise, try to find the device.
2419 return (prepare_image_file(dn
, wbpb
));
2421 /* Collect info about device */
2422 fd
= getdiskinfo(dn
, &suffix
);
2425 * Sanity check. If we've been provided a partition-specifying
2426 * suffix, we shouldn't also have been told to ignore the
2429 if (DontUseFdisk
&& suffix
) {
2430 (void) fprintf(stderr
,
2431 gettext("Using 'nofdisk' option precludes "
2432 "appending logical drive\nspecifier "
2433 "to the device name.\n"));
2438 * Find appropriate partition if we were requested to do so.
2440 if (suffix
&& !(seek_partn(fd
, suffix
, wbpb
, seekto
)))
2445 * We have one of two possibilities. Chances are we have
2446 * a floppy drive. But the user may be trying to format
2447 * some weird drive that we don't know about and is supplying
2448 * all the important values. In that case, they should have set
2449 * the 'nofdisk' flag.
2451 * If 'nofdisk' isn't set, do a floppy-specific ioctl to
2452 * get the remainder of our info. If the ioctl fails, we have
2453 * a good idea that they aren't really on a floppy. In that
2454 * case, they should have given us a partition specifier.
2457 if (!(seek_nofdisk(fd
, wbpb
, seekto
)))
2460 find_fixed_details(fd
, wbpb
);
2461 } else if (ioctl(fd
, FDIOGCHAR
, &fdchar
) == -1) {
2463 * It is possible that we are trying to use floppy
2464 * specific FDIOGCHAR ioctl on USB floppy. Since sd
2465 * driver, by which USB floppy is handled, doesn't
2466 * support it, we can try to use disk DKIOCGGEOM ioctl
2467 * to retrieve data we need. sd driver itself
2468 * determines floppy disk by number of blocks
2469 * (<=0x1000), then it sets geometry to 80 cylinders,
2472 * Note that DKIOCGGEOM cannot supply us with type
2473 * of media (e.g. 3.5" or 5.25"). We will set it to
2474 * 3 (3.5") which is most probable value.
2476 if (errno
== ENOTTY
) {
2477 if (ioctl(fd
, DKIOCGGEOM
, &dg
) != -1 &&
2478 dg
.dkg_ncyl
== 80 && dg
.dkg_nhead
== 2) {
2479 fdchar
.fdc_ncyl
= dg
.dkg_ncyl
;
2480 fdchar
.fdc_medium
= 3;
2481 fdchar
.fdc_secptrack
= dg
.dkg_nsect
;
2482 fdchar
.fdc_nhead
= dg
.dkg_nhead
;
2483 lookup_floppy(&fdchar
, wbpb
);
2485 partn_lecture(actualdisk
);
2491 fdchar
.fdc_medium
= 3;
2493 lookup_floppy(&fdchar
, wbpb
);
2496 find_fixed_details(fd
, wbpb
);
2507 * The following is a copy of MS-DOS 4.0 boot block.
2508 * It consists of the BIOS parameter block, and a disk
2509 * bootstrap program.
2511 * The BIOS parameter block contains the right values
2512 * for the 3.5" high-density 1.44MB floppy format.
2514 * This will be our default boot sector, if the user
2515 * didn't point us at a different one.
2519 uchar_t DefBootSec
[512] = {
2520 0xeb, 0x3c, 0x90, /* 8086 short jump + displacement + NOP */
2521 'M', 'S', 'D', 'O', 'S', '4', '.', '0', /* OEM name & version */
2522 0x00, 0x02, 0x01, 0x01, 0x00,
2523 0x02, 0xe0, 0x00, 0x40, 0x0b,
2524 0xf0, 0x09, 0x00, 0x12, 0x00,
2526 0x00, 0x00, 0x00, 0x00,
2527 0x00, 0x00, 0x00, 0x00,
2529 0x29, 0x00, 0x00, 0x00, 0x00,
2530 'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ',
2531 'F', 'A', 'T', '1', '2', ' ', ' ', ' ',
2533 0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07,
2534 0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56,
2535 0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00,
2536 0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe,
2537 0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9,
2538 0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb,
2539 0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06,
2540 0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c,
2541 0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7,
2542 0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13,
2543 0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83,
2544 0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52,
2545 0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c,
2546 0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b,
2547 0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3,
2548 0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c,
2549 0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c,
2550 0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20,
2551 0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b,
2552 0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3,
2553 0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6,
2554 0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18,
2555 0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4,
2556 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44,
2557 0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8,
2558 0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49,
2559 0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51,
2560 0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8,
2561 0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05,
2562 0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b,
2563 0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a,
2564 0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1,
2565 0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac,
2566 0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07,
2567 0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18,
2568 0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe,
2569 0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7,
2570 0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3,
2571 0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02,
2572 0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6,
2573 0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9,
2574 0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c,
2575 0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e,
2576 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
2577 0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20,
2578 0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72,
2579 0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c,
2580 0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
2581 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e,
2582 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68,
2583 0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79,
2584 0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20,
2585 0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53,
2586 0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59,
2587 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
2592 * verify_bootblkfile
2594 * We were provided with the name of a file containing the bootblk
2595 * to install. Verify it has a valid boot sector as best we can. Any
2596 * errors and we return a bad file descriptor. Otherwise we fill up the
2597 * provided buffer with the boot sector, return the file
2598 * descriptor for later use and leave the file pointer just
2599 * past the boot sector part of the boot block file.
2603 verify_bootblkfile(char *fn
, boot_sector_t
*bs
, ulong_t
*blkfilesize
)
2608 if (stat(fn
, &fi
)) {
2610 } else if (fi
.st_size
< BPSEC
) {
2611 (void) fprintf(stderr
,
2612 gettext("%s: Too short to be a boot sector.\n"), fn
);
2613 } else if ((bsfd
= open(fn
, O_RDONLY
)) < 0) {
2615 } else if (read(bsfd
, bs
->buf
, BPSEC
) < BPSEC
) {
2618 perror(gettext("Boot block read"));
2620 if ((bs
->bs
.bs_signature
[0] != (BOOTSECSIG
& 0xFF) &&
2621 bs
->bs
.bs_signature
[1] != ((BOOTSECSIG
>> 8) & 0xFF)) ||
2623 (bs
->bs
.bs_front
.bs_jump_code
[0] != OPCODE1
&&
2624 bs
->bs
.bs_front
.bs_jump_code
[0] != OPCODE2
)
2626 (bs
->bs
.bs_jump_code
[0] != OPCODE1
&&
2627 bs
->bs
.bs_jump_code
[0] != OPCODE2
)
2633 (void) fprintf(stderr
,
2634 gettext("Boot block (%s) bogus.\n"), fn
);
2636 *blkfilesize
= fi
.st_size
;
2644 * We were provided with the name of a file to be the first file
2645 * installed on the disk. We just need to verify it exists and
2646 * find out how big it is. If it doesn't exist, we print a warning
2647 * message about how the file wasn't found. We don't exit fatally,
2648 * though, rather we return a size of 0 and the FAT will be built
2649 * without installing any first file. They can then presumably
2650 * install the correct first file by hand.
2654 verify_firstfile(char *fn
, ulong_t
*filesize
)
2660 if (stat(fn
, &fi
) || (fd
= open(fn
, O_RDONLY
)) < 0) {
2662 (void) fprintf(stderr
,
2663 gettext("Could not access requested file. It will not\n"
2664 "be installed in the new file system.\n"));
2666 *filesize
= fi
.st_size
;
2675 * Fill in BPB with volume label.
2679 label_volume(char *lbl
, bpb_t
*wbpb
)
2683 /* Put a volume label into our BPB. */
2685 lbl
= DEFAULT_LABEL
;
2687 ll
= min(11, (int)strlen(lbl
));
2688 for (i
= 0; i
< ll
; i
++) {
2689 wbpb
->ebpb
.volume_label
[i
] = toupper(lbl
[i
]);
2691 for (; i
< 11; i
++) {
2692 wbpb
->ebpb
.volume_label
[i
] = ' ';
2698 copy_bootblk(char *fn
, boot_sector_t
*bootsect
, ulong_t
*bootblksize
)
2703 (void) printf(gettext("Request to install boot "
2704 "block file %s.\n"), fn
);
2706 (void) printf(gettext("Request to install DOS boot block.\n"));
2709 * If they want to install their own boot block, sanity check
2713 bsfd
= verify_bootblkfile(fn
, bootsect
, bootblksize
);
2717 *bootblksize
= roundup(*bootblksize
, BPSEC
);
2719 (void) memcpy(bootsect
, DefBootSec
, BPSEC
);
2720 *bootblksize
= BPSEC
;
2729 * This routine fills a FAT entry with the value supplied to it as an
2730 * argument. The fatp argument is assumed to be a pointer to the FAT's
2731 * 0th entry. The clustnum is the cluster entry that should be updated.
2732 * The value is the new value for the entry.
2736 mark_cluster(uchar_t
*fatp
, pc_cluster32_t clustnum
, uint32_t value
)
2741 idx
= (Fatentsize
== 32) ? clustnum
* 4 :
2742 (Fatentsize
== 16) ? clustnum
* 2 : clustnum
+ clustnum
/2;
2745 if (Fatentsize
== 32) {
2746 store_32_bits(&ep
, value
);
2747 } else if (Fatentsize
== 16) {
2748 store_16_bits(&ep
, value
);
2751 *ep
= (*ep
& 0x0f) | ((value
<< 4) & 0xf0);
2753 *ep
= (value
>> 4) & 0xff;
2755 *ep
++ = value
& 0xff;
2756 *ep
= (*ep
& 0xf0) | ((value
>> 8) & 0x0f);
2763 build_fat(bpb_t
*wbpb
, struct fat_od_fsi
*fsinfop
, ulong_t bootblksize
,
2764 ulong_t
*fatsize
, char *ffn
, int *fffd
, ulong_t
*ffsize
,
2765 pc_cluster32_t
*ffstartclust
)
2767 pc_cluster32_t nextfree
, ci
;
2769 ushort_t numclust
, numsect
;
2772 /* Alloc space for a FAT and then null it out. */
2774 (void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"),
2775 wbpb
->bpb
.sectors_per_fat
? wbpb
->bpb
.sectors_per_fat
:
2776 wbpb
->bpb32
.big_sectors_per_fat
);
2780 *fatsize
= BPSEC
* wbpb
->bpb32
.big_sectors_per_fat
;
2782 *fatsize
= BPSEC
* wbpb
->bpb
.sectors_per_fat
;
2785 if (!(fatp
= (uchar_t
*)malloc(*fatsize
))) {
2786 perror(gettext("FAT table alloc"));
2789 (void) memset(fatp
, 0, *fatsize
);
2792 /* Build in-memory FAT */
2793 *fatp
= wbpb
->bpb
.media
;
2797 if (Fatentsize
== 16) {
2799 } else if (Fatentsize
== 32) {
2808 * Keep track of clusters used.
2810 remclust
= TotalClusters
;
2814 * Get info on first file to install, if any.
2817 *fffd
= verify_firstfile(ffn
, ffsize
);
2820 * Compute number of clusters to preserve for bootblk overage.
2821 * Remember that we already wrote the first sector of the boot block.
2822 * These clusters are marked BAD to prevent them from being deleted
2823 * or used. The first available cluster is 2, so we always offset
2826 numsect
= idivceil((bootblksize
- BPSEC
), BPSEC
);
2827 numclust
= idivceil(numsect
, wbpb
->bpb
.sectors_per_cluster
);
2829 if (Verbose
&& numclust
)
2830 (void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"),
2832 for (ci
= 0; ci
< numclust
; ci
++)
2833 mark_cluster(fatp
, nextfree
++,
2834 MakeFAT32
? PCF_BADCLUSTER32
: PCF_BADCLUSTER
);
2835 remclust
-= numclust
;
2838 * Reserve a cluster for the root directory on a FAT32.
2841 mark_cluster(fatp
, nextfree
, PCF_LASTCLUSTER32
);
2842 wbpb
->bpb32
.root_dir_clust
= nextfree
++;
2847 * Compute and preserve number of clusters for first file.
2850 *ffstartclust
= nextfree
;
2851 numsect
= idivceil(*ffsize
, BPSEC
);
2852 numclust
= idivceil(numsect
, wbpb
->bpb
.sectors_per_cluster
);
2854 if (numclust
> remclust
) {
2855 (void) fprintf(stderr
,
2856 gettext("Requested first file too large to be\n"
2857 "installed in the new file system.\n"));
2858 (void) close(*fffd
);
2864 (void) printf(gettext("Reserving %d first file "
2865 "cluster(s).\n"), numclust
);
2866 for (ci
= 0; (int)ci
< (int)(numclust
-1); ci
++, nextfree
++)
2867 mark_cluster(fatp
, nextfree
, nextfree
+ 1);
2868 mark_cluster(fatp
, nextfree
++,
2869 MakeFAT32
? PCF_LASTCLUSTER32
: PCF_LASTCLUSTER
);
2870 remclust
-= numclust
;
2875 (void) printf(gettext("First sector of FAT"));
2877 dump_bytes(fatp
, BPSEC
);
2880 (void) memset(fsinfop
, 0, sizeof (*fsinfop
));
2881 fsinfop
->fsi_leadsig
= LE_32(FSI_LEADSIG
);
2882 fsinfop
->fsi_strucsig
= LE_32(FSI_STRUCSIG
);
2883 fsinfop
->fsi_trailsig
= LE_32(FSI_TRAILSIG
);
2884 fsinfop
->fsi_incore
.fs_free_clusters
= LE_32(remclust
);
2885 fsinfop
->fsi_incore
.fs_next_free
= LE_32(nextfree
);
2891 dirent_time_fill(struct pcdir
*dep
)
2898 (void) gettimeofday(&tv
, (struct timezone
*)0);
2899 tp
= localtime(&tv
.tv_sec
);
2900 /* get the time & day into DOS format */
2901 dostime
= tp
->tm_sec
/ 2;
2902 dostime
|= tp
->tm_min
<< 5;
2903 dostime
|= tp
->tm_hour
<< 11;
2904 dosday
= tp
->tm_mday
;
2905 dosday
|= (tp
->tm_mon
+ 1) << 5;
2906 dosday
|= (tp
->tm_year
- 80) << 9;
2907 dep
->pcd_mtime
.pct_time
= htols(dostime
);
2908 dep
->pcd_mtime
.pct_date
= htols(dosday
);
2913 dirent_label_fill(struct pcdir
*dep
, char *fn
)
2918 * We spread the volume label across both the NAME and EXT fields
2920 nl
= min(PCFNAMESIZE
, strlen(fn
));
2921 for (i
= 0; i
< nl
; i
++) {
2922 dep
->pcd_filename
[i
] = toupper(fn
[i
]);
2924 if (i
< PCFNAMESIZE
) {
2925 for (; i
< PCFNAMESIZE
; i
++)
2926 dep
->pcd_filename
[i
] = ' ';
2927 for (i
= 0; i
< PCFEXTSIZE
; i
++)
2928 dep
->pcd_ext
[i
] = ' ';
2931 nl
= min(PCFEXTSIZE
, strlen(fn
) - PCFNAMESIZE
);
2932 for (i
= 0; i
< nl
; i
++)
2933 dep
->pcd_ext
[i
] = toupper(fn
[i
+ PCFNAMESIZE
]);
2934 if (i
< PCFEXTSIZE
) {
2935 for (; i
< PCFEXTSIZE
; i
++)
2936 dep
->pcd_ext
[i
] = ' ';
2942 dirent_fname_fill(struct pcdir
*dep
, char *fn
)
2947 if (fname
= strrchr(fn
, '/')) {
2953 if (fext
= strrchr(fname
, '.')) {
2959 fname
= strtok(fname
, ".");
2961 nl
= min(PCFNAMESIZE
, (int)strlen(fname
));
2962 for (i
= 0; i
< nl
; i
++) {
2963 dep
->pcd_filename
[i
] = toupper(fname
[i
]);
2965 for (; i
< PCFNAMESIZE
; i
++) {
2966 dep
->pcd_filename
[i
] = ' ';
2969 nl
= min(PCFEXTSIZE
, (int)strlen(fext
));
2970 for (i
= 0; i
< nl
; i
++) {
2971 dep
->pcd_ext
[i
] = toupper(fext
[i
]);
2973 for (; i
< PCFEXTSIZE
; i
++) {
2974 dep
->pcd_ext
[i
] = ' ';
2980 build_rootdir(bpb_t
*wbpb
, char *ffn
, int fffd
,
2981 ulong_t ffsize
, pc_cluster32_t ffstart
, ulong_t
*rdirsize
)
2983 struct pcdir
*rootdirp
;
2984 struct pcdir
*entry
;
2987 * Build a root directory. It will have at least one entry,
2988 * the volume label and a second if the first file was defined.
2992 * We devote an entire cluster to the root
2993 * directory on FAT32.
2995 *rdirsize
= wbpb
->bpb
.sectors_per_cluster
* BPSEC
;
2997 *rdirsize
= wbpb
->bpb
.num_root_entries
* sizeof (struct pcdir
);
2999 if ((rootdirp
= (struct pcdir
*)malloc(*rdirsize
)) == NULL
) {
3000 perror(gettext("Root directory allocation"));
3004 (void) memset((char *)rootdirp
, 0, *rdirsize
);
3007 /* Create directory entry for first file, if there is one */
3009 dirent_fname_fill(entry
, ffn
);
3010 entry
->pcd_attr
= Firstfileattr
;
3011 dirent_time_fill(entry
);
3012 entry
->pcd_scluster_lo
= htols(ffstart
);
3014 ffstart
= ffstart
>> 16;
3015 entry
->un
.pcd_scluster_hi
= htols(ffstart
);
3017 entry
->pcd_size
= htoli(ffsize
);
3021 /* Create directory entry for volume label, if there is one */
3022 if (Label
!= NULL
) {
3023 dirent_label_fill(entry
, Label
);
3024 entry
->pcd_attr
= PCA_ARCH
| PCA_LABEL
;
3025 dirent_time_fill(entry
);
3026 entry
->pcd_scluster_lo
= 0;
3028 entry
->un
.pcd_scluster_hi
= 0;
3030 entry
->pcd_size
= 0;
3035 (void) printf(gettext("First two directory entries"));
3037 dump_bytes((uchar_t
*)rootdirp
, 2 * sizeof (struct pcdir
));
3040 return ((uchar_t
*)rootdirp
);
3046 * Write all the bytes from the current file pointer to end of file
3047 * in the source file out to the destination file. The writes should
3048 * be padded to whole clusters with 0's if necessary.
3052 write_rest(bpb_t
*wbpb
, char *efn
, int dfd
, int sfd
, int remaining
)
3055 ushort_t numsect
, numclust
;
3056 ushort_t wnumsect
, s
;
3061 * Compute number of clusters required to contain remaining bytes.
3063 numsect
= idivceil(remaining
, BPSEC
);
3064 numclust
= idivceil(numsect
, wbpb
->bpb
.sectors_per_cluster
);
3066 wnumsect
= numclust
* wbpb
->bpb
.sectors_per_cluster
;
3067 for (s
= 0; s
< wnumsect
; s
++) {
3069 if ((rstat
= read(sfd
, buf
, BPSEC
)) < 0) {
3073 } else if (rstat
== 0) {
3076 (void) memset(&(buf
[rstat
]), 0, BPSEC
- rstat
);
3078 if (write(dfd
, buf
, BPSEC
) != BPSEC
) {
3079 (void) fprintf(stderr
, gettext("Copying "));
3087 write_fat32_bootstuff(int fd
, boot_sector_t
*bsp
,
3088 struct fat_od_fsi
*fsinfop
, off64_t seekto
)
3091 (void) printf(gettext("Dump of the fs info sector"));
3093 dump_bytes((uchar_t
*)fsinfop
, sizeof (*fsinfop
));
3098 * FAT32's have an FS info sector, then a backup of the boot
3099 * sector, and a modified backup of the FS Info sector.
3101 if (write(fd
, fsinfop
, sizeof (*fsinfop
)) != BPSEC
) {
3102 perror(gettext("FS info sector write"));
3105 if (lseek64(fd
, seekto
+ BKUP_BOOTSECT_OFFSET
, SEEK_SET
) < 0) {
3107 perror(gettext("Boot sector backup seek"));
3110 if (write(fd
, bsp
->buf
, sizeof (bsp
->buf
)) != BPSEC
) {
3111 perror(gettext("Boot sector backup write"));
3117 * Second copy of fs info sector is modified to have "don't know"
3118 * as the number of free clusters
3120 fsinfop
->fsi_incore
.fs_next_free
= LE_32(FSINFO_UNKNOWN
);
3123 (void) printf(gettext("Dump of the backup fs info sector"));
3125 dump_bytes((uchar_t
*)fsinfop
, sizeof (*fsinfop
));
3129 if (write(fd
, fsinfop
, sizeof (*fsinfop
)) != BPSEC
) {
3130 perror(gettext("FS info sector backup write"));
3138 write_bootsects(int fd
, boot_sector_t
*bsp
, bpb_t
*wbpb
,
3139 struct fat_od_fsi
*fsinfop
, off64_t seekto
)
3142 /* Copy our BPB into bootsec structure */
3144 (void) memcpy(&(bsp
->bs32
.bs_front
.bs_bpb
), &(wbpb
->bpb
),
3145 sizeof (wbpb
->bpb
));
3146 (void) memcpy(&(bsp
->bs32
.bs_bpb32
), &(wbpb
->bpb32
),
3147 sizeof (wbpb
->bpb32
));
3148 (void) memcpy(&(bsp
->bs32
.bs_ebpb
), &(wbpb
->ebpb
),
3149 sizeof (wbpb
->ebpb
));
3151 swap_pack_bpb32cpy(&(bsp
->bs32
), wbpb
);
3154 /* Copy our BPB into bootsec structure */
3156 (void) memcpy(&(bsp
->bs
.bs_front
.bs_bpb
), &(wbpb
->bpb
),
3157 sizeof (wbpb
->bpb
));
3158 (void) memcpy(&(bsp
->bs
.bs_ebpb
), &(wbpb
->ebpb
),
3159 sizeof (wbpb
->ebpb
));
3161 swap_pack_bpbcpy(&(bsp
->bs
), wbpb
);
3164 /* Copy SUN BPB extensions into bootsec structure */
3167 (void) memcpy(&(bsp
->bs
.bs_sebpb
), &(wbpb
->sunbpb
),
3168 sizeof (wbpb
->sunbpb
));
3170 swap_pack_sebpbcpy(&(bsp
->bs
), wbpb
);
3175 /* Write boot sector */
3176 if (!Notreally
&& write(fd
, bsp
->buf
, sizeof (bsp
->buf
)) != BPSEC
) {
3177 perror(gettext("Boot sector write"));
3182 (void) printf(gettext("Dump of the boot sector"));
3184 dump_bytes(bsp
->buf
, sizeof (bsp
->buf
));
3188 write_fat32_bootstuff(fd
, bsp
, fsinfop
, seekto
);
3193 write_fat(int fd
, off64_t seekto
, char *fn
, char *lbl
, char *ffn
, bpb_t
*wbpb
)
3195 struct fat_od_fsi fsinfo
;
3196 pc_cluster32_t ffsc
;
3197 boot_sector_t bootsect
;
3198 uchar_t
*fatp
, *rdirp
;
3199 ulong_t bootblksize
, fatsize
, rdirsize
, ffsize
;
3203 compute_file_area_size(wbpb
);
3205 bsfd
= copy_bootblk(fn
, &bootsect
, &bootblksize
);
3206 label_volume(lbl
, wbpb
);
3209 (void) printf(gettext("Building FAT.\n"));
3210 fatp
= build_fat(wbpb
, &fsinfo
, bootblksize
, &fatsize
,
3211 ffn
, &fffd
, &ffsize
, &ffsc
);
3213 write_bootsects(fd
, &bootsect
, wbpb
, &fsinfo
, seekto
);
3216 seekto
+ (BPSEC
* wbpb
->bpb
.resv_sectors
), SEEK_SET
) < 0) {
3218 perror(gettext("Seek to end of reserved sectors"));
3224 (void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"),
3225 fatsize
, wbpb
->bpb
.num_fats
);
3228 for (nf
= 0; nf
< (int)wbpb
->bpb
.num_fats
; nf
++)
3229 if ((wb
= write(fd
, fatp
, fatsize
)) != fatsize
) {
3230 perror(gettext("FAT write"));
3235 gettext("Wrote %d bytes\n"), wb
);
3241 (void) printf(gettext("Building root directory.\n"));
3242 rdirp
= build_rootdir(wbpb
, ffn
, fffd
, ffsize
, ffsc
, &rdirsize
);
3245 * In non FAT32, root directory exists outside of the file area
3249 (void) printf(gettext("Writing root directory. "
3250 "%d bytes.\n"), rdirsize
);
3252 if (write(fd
, rdirp
, rdirsize
) != rdirsize
) {
3253 perror(gettext("Root directory write"));
3261 * Now write anything that needs to be in the file space.
3263 if (bootblksize
> BPSEC
) {
3265 (void) printf(gettext("Writing remainder of "
3268 write_rest(wbpb
, fn
, fd
, bsfd
, bootblksize
- BPSEC
);
3273 (void) printf(gettext("Writing root directory. "
3274 "%d bytes.\n"), rdirsize
);
3276 if (write(fd
, rdirp
, rdirsize
) != rdirsize
) {
3277 perror(gettext("Root directory write"));
3286 (void) printf(gettext("Writing first file.\n"));
3288 write_rest(wbpb
, ffn
, fd
, fffd
, ffsize
);
3293 char *LegalOpts
[] = {
3326 #define NOFDISKFLAG 16
3328 #define RESRVFLAG 17
3330 #define HIDDENFLAG 18
3337 bad_arg(char *option
)
3339 (void) fprintf(stderr
,
3340 gettext("Unrecognized option %s.\n"), option
);
3347 missing_arg(char *option
)
3349 (void) fprintf(stderr
,
3350 gettext("Option %s requires a value.\n"), option
);
3357 parse_suboptions(char *optsstr
)
3362 while (*optsstr
!= '\0') {
3363 switch (c
= getsubopt(&optsstr
, LegalOpts
, &value
)) {
3371 Firstfileattr
|= 0x01;
3374 Firstfileattr
|= 0x02;
3377 Firstfileattr
|= 0x04;
3383 if (value
== NULL
) {
3384 missing_arg(LegalOpts
[c
]);
3390 if (value
== NULL
) {
3391 missing_arg(LegalOpts
[c
]);
3397 if (value
== NULL
) {
3398 missing_arg(LegalOpts
[c
]);
3404 if (value
== NULL
) {
3405 missing_arg(LegalOpts
[c
]);
3407 TotSize
= atoi(value
);
3412 if (value
== NULL
) {
3413 missing_arg(LegalOpts
[c
]);
3415 SecPerTrk
= atoi(value
);
3420 if (value
== NULL
) {
3421 missing_arg(LegalOpts
[c
]);
3423 TrkPerCyl
= atoi(value
);
3428 if (value
== NULL
) {
3429 missing_arg(LegalOpts
[c
]);
3431 SecPerClust
= atoi(value
);
3436 if (value
== NULL
) {
3437 missing_arg(LegalOpts
[c
]);
3439 BitsPerFAT
= atoi(value
);
3447 if (value
== NULL
) {
3448 missing_arg(LegalOpts
[c
]);
3450 Resrvd
= atoi(value
);
3455 if (value
== NULL
) {
3456 missing_arg(LegalOpts
[c
]);
3458 RelOffset
= atoi(value
);
3463 if (value
== NULL
) {
3464 missing_arg(LegalOpts
[c
]);
3471 if (value
== NULL
) {
3472 missing_arg(LegalOpts
[c
]);
3474 Imagesize
= atoi(value
);
3486 sanity_check_options(int argc
, int optind
)
3489 if (argc
- optind
!= 1)
3494 if (DontUseFdisk
&& GetOffset
) {
3495 /* Set default relative offset of zero */
3499 if (BitsPerFAT
== 32)
3502 if (Outputtofile
&& (argc
- optind
)) {
3504 } else if (Outputtofile
&& !DiskName
) {
3506 } else if (!Outputtofile
&& (argc
- optind
!= 1)) {
3508 } else if (SunBPBfields
&& !BootBlkFn
) {
3509 (void) fprintf(stderr
,
3510 gettext("Use of the 'S' option requires that\n"
3511 "the 'B=' option also be used.\n\n"));
3513 } else if (Firstfileattr
!= 0x20 && !FirstFn
) {
3514 (void) fprintf(stderr
,
3515 gettext("Use of the 'r', 'h', or 's' options requires\n"
3516 "that the 'i=' option also be used.\n\n"));
3518 } else if (!GetOffset
&& !DontUseFdisk
) {
3519 (void) fprintf(stderr
,
3520 gettext("Use of the 'hidden' option requires that\n"
3521 "the 'nofdisk' option also be used.\n\n"));
3523 } else if (DontUseFdisk
&& GetSize
) {
3524 (void) fprintf(stderr
,
3525 gettext("Use of the 'nofdisk' option requires that\n"
3526 "the 'size=' option also be used.\n\n"));
3528 } else if (!GetBPF
&&
3529 BitsPerFAT
!= 12 && BitsPerFAT
!= 16 && BitsPerFAT
!= 32) {
3530 (void) fprintf(stderr
, gettext("Invalid Bits/Fat value."
3531 " Must be 12, 16 or 32.\n"));
3533 } else if (!GetSPC
&& !(ISP2(SecPerClust
) &&
3534 IN_RANGE(SecPerClust
, 1, 128))) {
3535 (void) fprintf(stderr
,
3536 gettext("Invalid Sectors/Cluster value. Must be a "
3537 "power of 2 between 1 and 128.\n"));
3539 } else if (!GetResrvd
&& (Resrvd
< 1 || Resrvd
> 0xffff)) {
3540 (void) fprintf(stderr
,
3541 gettext("Invalid number of reserved sectors. "
3542 "Must be at least 1 but\nno larger than 65535."));
3544 } else if (!GetResrvd
&& MakeFAT32
&&
3545 (Resrvd
< 32 || Resrvd
> 0xffff)) {
3546 (void) fprintf(stderr
,
3547 gettext("Invalid number of reserved sectors. "
3548 "Must be at least 32 but\nno larger than 65535."));
3550 } else if (Imagesize
!= 3 && Imagesize
!= 5) {
3556 main(int argc
, char **argv
)
3558 off64_t AbsBootSect
= 0;
3564 (void) setlocale(LC_ALL
, "");
3566 #if !defined(TEXT_DOMAIN)
3567 #define TEXT_DOMAIN "SYS_TEST"
3569 (void) textdomain(TEXT_DOMAIN
);
3571 while ((c
= getopt(argc
, argv
, "F:Vmo:")) != EOF
) {
3575 if (strcmp(string
, "pcfs") != 0)
3583 (void) fprintf(stdout
,
3584 gettext("mkfs -F pcfs "));
3585 for (opt_count
= 1; opt_count
< argc
;
3587 opt_text
= argv
[opt_count
];
3589 (void) fprintf(stdout
,
3592 (void) fprintf(stdout
, "\n");
3600 parse_suboptions(string
);
3605 sanity_check_options(argc
, optind
);
3608 DiskName
= argv
[optind
];
3610 (void) memset(&dskparamblk
, 0, sizeof (dskparamblk
));
3613 fd
= open_and_examine(DiskName
, &dskparamblk
);
3615 fd
= open_and_seek(DiskName
, &dskparamblk
, &AbsBootSect
);
3616 if (ask_nicely(DiskName
))
3617 write_fat(fd
, AbsBootSect
, BootBlkFn
, Label
,
3618 FirstFn
, &dskparamblk
);