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