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