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