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