dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fdformat / fdformat.c
blob29a298a105c7b615d36cf80a364f8dbb12a3370f
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * fdformat program - formats floppy disks, and then adds a label to them
29 * ****Warning, Warning, Warning, Warning*****
30 * This program runs suid root. This change was made to
31 * allow it to umount a file system if it's mounted.
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <memory.h>
40 #include <errno.h>
41 #include <locale.h>
42 #include <libintl.h>
43 #include <volmgt.h>
44 #include <sys/isa_defs.h>
45 #include <sys/ioccom.h>
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <sys/file.h>
49 #include <sys/dklabel.h>
50 #include <sys/ioctl.h>
51 #include <sys/dkio.h>
52 #include <sys/fdio.h>
53 #include <sys/stat.h>
54 #include <sys/vtoc.h>
55 #include <sys/mnttab.h>
57 /* DEFINES */
58 #if defined(_BIG_ENDIAN)
59 #define getbyte(A, N) (((unsigned char *)(&(A)))[N])
60 #define htols(S) ((getbyte(S, 1) <<8) | getbyte(S, 0))
61 #elif defined(_LITTLE_ENDIAN)
62 #define htols(S) (*((ushort_t *)(&(S))))
63 #else
64 #error One of _BIG_ENDIAN or LITTLE_ENDIAN must be defined
65 #endif
67 #define getlobyte(A) (A & 0xFF)
68 #define gethibyte(A) (A >> 8 & 0xFF)
69 #define uppercase(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
70 #define min(a, b) ((a) < (b) ? (a) : (b))
72 /* FORMAT PATTERNS */
73 #define PATTERN_1 0x55;
74 #define PATTERN_2 0xaa;
75 #define PATTERN_3 0xff;
76 #define PATTERN_4 0x00;
78 /* UNINITIALIZED DATA */
79 static struct fd_char fdchar;
80 static struct dk_geom fdgeom;
81 static struct dk_allmap allmap;
82 static struct dk_cinfo dkinfo;
84 /* EXTERN */
85 extern char *optarg;
86 extern int optind;
88 /* for verify buffers */
89 static uchar_t *ibuf1;
90 static uchar_t *obuf;
92 static char *myname;
94 static int fd_debug = 1; /* 1 if debug XXX */
95 static int b_flag = 0; /* install a volume label to the diskette */
96 static int d_flag = 0; /* format the diskette in dos format */
97 static int D_flag = 0; /* double (aka low) density flag */
98 static int e_flag = 0; /* "eject" diskette when done (if supported) */
99 static int E_flag = 0; /* extended density */
100 static int f_flag = 0; /* "force" (no confirmation before start) */
101 static int H_flag = 0; /* high density */
102 static int m_flag = 0; /* medium density */
103 static int n_flag = 0; /* format the diskette in NEC-DOS format */
104 static int q_flag = 0; /* quiet format flag */
105 static int U_flag = 0; /* automatically unmount if it's mounted */
106 static int v_flag = 0; /* verify format/diskette flag */
107 static int x_flag = 0; /* skip the format, only install SunOS label */
108 /* or DOS file system */
109 static int z_flag = 0; /* debugging only, setting partial formatting */
110 static int interleave = 1; /* interleave factor */
112 static uid_t euid = 0; /* stores effective user id */
114 struct bios_param_blk {
115 uchar_t b_bps[2]; /* bytes per sector */
116 uchar_t b_spcl; /* sectors per alloction unit */
117 uchar_t b_res_sec[2]; /* reserved sectors, starting at 0 */
118 uchar_t b_nfat; /* number of FATs */
119 uchar_t b_rdirents[2]; /* number of root directory entries */
120 uchar_t b_totalsec[2]; /* total sectors in logical image */
121 char b_mediadescriptor; /* media descriptor byte */
122 uchar_t b_fatsec[2]; /* number of sectors per FAT */
123 uchar_t b_spt[2]; /* sectors per track */
124 uchar_t b_nhead[2]; /* number of heads */
125 uchar_t b_hiddensec[2]; /* number of hidden sectors */
129 * ON-private functions from libvolmgt
131 char *_media_oldaliases(char *name);
132 int _dev_mounted(char *path);
133 int _dev_unmount(char *path);
136 * local functions
138 static void usage(char *);
139 static int verify(int, int, int);
140 static void write_SunOS_label(int, char *, struct vtoc *);
141 static int valid_DOS_boot(char *, uchar_t **);
142 static void write_DOS_label(int, uchar_t *, int, char *, char *,
143 struct bios_param_blk *, int);
144 static void write_NEC_DOS_label(int, char *);
145 static int check_mount();
146 static void format_diskette(int, char *, struct vtoc *,
147 struct bios_param_blk *, int *);
148 static void restore_default_chars(int fd,
149 struct fd_char save_fdchar,
150 struct dk_allmap save_allmap);
153 main(int argc, char **argv)
155 int altsize = 0;
156 int fd;
157 int i;
158 uchar_t *altboot = NULL;
159 char *altbootname = NULL;
160 char *dev_name = NULL, *real_name, *alias_name;
161 char *vollabel = "";
162 struct vtoc fd_vtoc;
163 struct bios_param_blk bpb;
164 int rdirsec;
165 char *nullstring = "";
167 (void) setlocale(LC_ALL, "");
169 #if !defined(TEXT_DOMAIN)
170 #define TEXT_DOMAIN "SYS_TEST"
171 #endif
173 (void) textdomain(TEXT_DOMAIN);
175 myname = argv[0];
176 while ((i = getopt(argc, argv, "B:b:dDeEfhHlLmMxqt:UvVZ?")) != -1) {
177 switch (i) {
179 case 'B':
180 altbootname = strdup(optarg);
181 d_flag++;
182 /* check for valid boot file now */
183 altsize = valid_DOS_boot(altbootname, &altboot);
184 if (!altsize) {
185 (void) fprintf(stderr, gettext(
186 "%s: invalid boot loader\n"), myname);
187 exit(1);
189 break;
191 case 'b':
192 b_flag++;
193 vollabel = strdup(optarg);
194 break;
196 case 'd':
197 /* format a MS-DOS diskette */
198 d_flag++;
199 break;
201 case 'D':
202 case 'L':
203 case 'l':
204 /* format a Double density 720KB (or 360KB) disk */
205 D_flag++;
206 break;
208 case 'e':
209 /* eject diskette when done */
210 e_flag++;
211 break;
213 case 'E':
214 /* format an 2.88MB Extended density disk */
215 E_flag++;
216 break;
218 case 'f':
219 /* don't ask for confirmation */
220 f_flag++;
221 break;
223 case 'H':
224 case 'h':
225 /* format a High density 1.2MB or 1.44MB disk */
226 H_flag++;
227 break;
229 #if 0
230 case 'i':
231 /* interleave factor */
232 interleave = atol(optarg);
233 if (interleave <= 0) {
234 (void) fprintf(stderr, gettext(
235 "%s: invalid interleave\n"), myname);
236 exit(1);
238 break;
239 #endif
241 case 'M':
242 case 'm':
243 /* format a 3.5" HD disk to 1.2MB */
244 m_flag++;
245 break;
247 case 'x':
248 /* skip format, just write label */
249 x_flag++;
250 break;
252 case 'q':
253 /* quiet format */
254 q_flag++;
255 break;
257 case 't':
258 /* Type of DOS formatting: NEC or MS */
259 if (strcmp(optarg, "nec") == 0) {
260 n_flag++;
262 if (strcmp(optarg, "dos") == 0) {
263 d_flag++;
265 break;
267 case 'U':
268 /* umount filesystem if mounted */
269 U_flag++;
270 break;
272 case 'v':
273 case 'V':
274 /* verify the diskette after format */
275 v_flag++;
276 break;
278 case 'Z':
279 /* for debug only, format cyl 0 only */
280 if (!fd_debug) {
281 usage(gettext("unknown argument"));
282 /* NOTREACHED */
284 (void) printf(gettext("\nFormat cyl Zero only\n"));
285 z_flag++;
286 break;
288 default:
289 usage(" ");
290 /* NOTREACHED */
294 if (optind < argc -1) {
295 usage(gettext("more than one device name argument"));
296 /* NOTREACHED */
298 if (optind == argc -1) {
299 dev_name = argv[optind];
301 if (D_flag && H_flag) {
302 usage(gettext("switches -D, -L and -H incompatible"));
303 /* NOTREACHED */
305 if (D_flag && E_flag) {
306 usage(gettext("switches -D, -L and -E incompatible"));
307 /* NOTREACHED */
309 if (H_flag && E_flag) {
310 usage(gettext("switches -H and -E incompatible"));
311 /* NOTREACHED */
313 if (n_flag && d_flag) {
314 usage(gettext("switches nec and dos incompatible"));
315 /* NOTREACHED */
317 if (n_flag && !m_flag) {
318 usage(gettext("switch -M required for NEC-DOS"));
319 /* NOTREACHED */
321 if (D_flag && m_flag) {
322 usage(gettext("switches -D, -L and -M incompatible"));
323 /* NOTREACHED */
325 if (d_flag && m_flag) {
326 usage(gettext("switches -d and -M incompatible"));
327 /* NOTREACHED */
330 if (dev_name == NULL)
331 dev_name = "floppy";
333 if ((real_name = media_findname(dev_name)) == NULL) {
334 if ((alias_name = _media_oldaliases(dev_name)) != NULL)
335 real_name = media_findname(alias_name);
336 if (real_name == NULL) {
337 (void) fprintf(stderr,
338 gettext("No such volume (or no media in specified device): %s\n"),
339 dev_name);
340 exit(1);
345 * This check is required because program runs suid root.
347 if (access(real_name, R_OK|W_OK) < 0) {
348 perror(real_name);
349 exit(1);
352 /* store callers euid */
354 euid = geteuid();
357 * See if the given device name is mounted. If this check isn't done
358 * before the open, the open will fail. The failed open will not
359 * indicate that the device is mounted, only that it's busy
361 if (_dev_mounted(real_name)) {
362 if (U_flag) {
363 if (!_dev_unmount(real_name)) {
364 (void) fprintf(stderr,
365 gettext("%s: umount of %s failed\n"),
366 myname, real_name);
367 exit(1);
369 } else {
370 (void) fprintf(stderr,
371 gettext("%s: %s is mounted (use -U flag)\n"),
372 myname, real_name);
373 exit(1);
377 /* Set to user access permissions to open file */
378 (void) seteuid(getuid());
380 if ((fd = open(real_name, O_NDELAY | O_RDWR | O_EXCL)) == -1) {
381 if (errno == EROFS) {
382 (void) fprintf(stderr,
383 gettext("%s: \"%s\" is write protected\n"),
384 myname, real_name);
385 exit(1);
387 /* XXX ought to check for "drive not installed", etc. */
388 (void) fprintf(stderr, gettext("%s: could not open \"%s\": "),
389 myname, real_name);
390 perror(nullstring);
391 exit(1);
394 /* restore effective id */
395 (void) seteuid(euid);
397 if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
398 (void) fprintf(stderr,
399 gettext("%s: DKIOCINFO failed, "), myname);
400 perror(nullstring);
401 exit(3);
404 /* See if there are any mounted partitions. */
405 if (check_mount() != 0) {
406 exit(3);
410 * The fd_vtoc, bpb, and rdirsec structures will be
411 * partially filled in by format_diskette().
412 * This was done so that write_DOS_label(),
413 * write_SunOS_label(), and write_NEC_DOS_label() could be
414 * device independent. If a new device needs to be added to
415 * fdformat, a new format function like format_diskette should
416 * be added. This function should fill in fd_vtoc, bpb, and
417 * rdirsec with device dependent information.
419 (void) memset(&fd_vtoc, 0, sizeof (struct vtoc));
420 (void) memset(&bpb, 0, sizeof (struct bios_param_blk));
422 format_diskette(fd, real_name, &fd_vtoc, &bpb, &rdirsec);
424 if (d_flag)
425 write_DOS_label(fd, altboot, altsize, altbootname,
426 vollabel, &bpb, rdirsec);
427 else if (n_flag)
428 write_NEC_DOS_label(fd, vollabel);
429 else
430 write_SunOS_label(fd, vollabel, &fd_vtoc);
432 if (e_flag)
433 /* eject media if possible */
434 if (ioctl(fd, FDEJECT, 0)) {
435 (void) fprintf(stderr,
436 gettext("%s: could not eject diskette, "), myname);
437 perror(nullstring);
438 exit(3);
441 return (0);
445 * Inputs: file descriptor for the device and the device name.
446 * Oututs: the fd_vtoc will be partially filled in with the
447 * device specific information such as partition
448 * information and ascillabel. bpb and rdirsec will
449 * also be partially filled in with device specific information
451 void
452 format_diskette(int fd, char *real_name, struct vtoc *fd_vtoc,
453 struct bios_param_blk *bpb, int *rdirsec)
455 int transfer_rate = 1000; /* transfer rate code */
456 int sec_size = 512; /* sector size */
457 uchar_t gap = 0x54; /* format gap size */
458 uchar_t *fbuf, *p;
459 char *capacity = NULL;
460 int cyl_size;
461 int i;
462 int chgd; /* for testing disk changed/present */
463 int cyl, hd;
464 int size_of_part, size_of_dev;
465 int spt = 36; /* sectors per track */
466 int drive_size;
467 uchar_t num_cyl = 80; /* max number of cylinders */
468 char *nullstring = "";
469 struct fd_char save_fdchar; /* original diskette characteristics */
470 struct dk_allmap save_allmap; /* original diskette partition info */
472 /* FDRAW ioctl command structures for seeking and formatting */
473 struct fd_raw fdr_seek = {
474 FDRAW_SEEK, 0, 0, 0, 0, 0, 0, 0, 0, 0,
476 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
481 struct fd_raw fdr_form = {
482 0x4D, 0, 2, 0, 0x54, (char)0xA5, 0, 0, 0, 0,
484 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
485 0, /* nbytes */
486 0 /* addr */
491 * restore drive to default geometry and characteristics
492 * (probably not implemented on sparc)
494 (void) ioctl(fd, FDDEFGEOCHAR, NULL);
496 /* get the default partititon maps */
497 if (ioctl(fd, DKIOCGAPART, &allmap) == -1) {
498 (void) fprintf(stderr,
499 gettext("%s: DKIOCGAPART failed, "), myname);
500 perror(nullstring);
501 exit(3);
504 /* Save the original default partition maps */
505 save_allmap = allmap;
507 /* find out the characteristics of the default diskette */
508 if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) {
509 (void) fprintf(stderr,
510 gettext("%s: FDIOGCHAR failed, "), myname);
511 perror(nullstring);
512 exit(3);
515 /* Save the original characteristics of the default diskette */
516 save_fdchar = fdchar;
519 * The user may only format the entire diskette.
520 * formatting partion a or b is not allowed
522 size_of_part = allmap.dka_map[dkinfo.dki_partition].dkl_nblk
523 * DEV_BSIZE;
524 size_of_dev = fdchar.fdc_ncyl * fdchar.fdc_nhead
525 * fdchar.fdc_secptrack * fdchar.fdc_sec_size;
527 if (size_of_part != size_of_dev) {
528 (void) fprintf(stderr,
529 /*CSTYLED*/
530 gettext("%s: The entire diskette must be formatted. Invalid device name.\n"),
531 myname);
532 exit(3);
536 /* find out the geometry of the drive */
537 if (ioctl(fd, DKIOCGGEOM, &fdgeom) == -1) {
538 (void) fprintf(stderr,
539 gettext("%s: DKIOCGGEOM failed, "), myname);
540 perror(nullstring);
541 exit(3);
544 #ifdef sparc
545 fdchar.fdc_medium = 3;
546 #endif
547 if (fdchar.fdc_medium == 5)
548 drive_size = 5;
549 else
550 drive_size = 3;
553 * set proper density flag in case we're formating to default
554 * characteristics because no density switch was input
556 if ((E_flag | H_flag | D_flag | m_flag) == 0) {
557 switch (fdchar.fdc_transfer_rate) {
558 case 1000:
559 /* assumes only ED uses 1.0 MB/sec */
560 E_flag++;
561 break;
562 case 500:
563 default:
565 * default to HD even though High density and
566 * "medium" density both use 500 KB/sec
568 H_flag++;
569 break;
570 #ifndef sparc
571 case 250:
572 /* assumes only DD uses 250 KB/sec */
573 D_flag++;
574 break;
575 #endif
579 if (H_flag) {
580 transfer_rate = 500;
581 num_cyl = 80;
582 sec_size = 512;
583 if (drive_size == 5) {
584 (void) strcpy(fd_vtoc->v_asciilabel,
585 "5.25\" floppy cyl 80 alt 0 hd 2 sec 15");
586 spt = 15;
587 capacity = "1.2 MB";
588 } else {
589 (void) strcpy(fd_vtoc->v_asciilabel,
590 "3.5\" floppy cyl 80 alt 0 hd 2 sec 18");
591 spt = 18;
592 capacity = "1.44 MB";
594 gap = 0x54;
595 } else if (D_flag) {
596 transfer_rate = 250;
597 if (drive_size == 5) {
598 (void) strcpy(fd_vtoc->v_asciilabel,
599 "5.25\" floppy cyl 40 alt 0 hd 2 sec 9");
600 if (fdchar.fdc_transfer_rate == 500) {
602 * formatting a 360KB DD diskette in
603 * a 1.2MB drive is not a good idea
605 transfer_rate = 300;
606 fdchar.fdc_steps = 2;
608 num_cyl = 40;
609 gap = 0x50;
610 capacity = "360 KB";
611 } else {
612 (void) strcpy(fd_vtoc->v_asciilabel,
613 "3.5\" floppy cyl 80 alt 0 hd 2 sec 9");
614 num_cyl = 80;
615 gap = 0x54;
616 capacity = "720 KB";
618 sec_size = 512;
619 spt = 9;
620 } else if (m_flag) {
621 #ifdef sparc
622 transfer_rate = 500;
623 #else
625 * 416.67 KB/sec is the effective transfer rate of a "medium"
626 * density diskette spun at 300 rpm instead of 360 rpm
628 transfer_rate = 417;
629 #endif
630 (void) strcpy(fd_vtoc->v_asciilabel,
631 "3.5\" floppy cyl 77 alt 0 hd 2 sec 8");
632 num_cyl = 77;
633 sec_size = 1024;
634 spt = 8;
635 gap = 0x74;
636 capacity = "1.2 MB";
637 } else if (E_flag) {
638 (void) strcpy(fd_vtoc->v_asciilabel,
639 "3.5\" floppy cyl 80 alt 0 hd 2 sec 36");
640 transfer_rate = 1000;
641 num_cyl = 80;
642 sec_size = 512;
643 spt = 36;
644 gap = 0x54;
645 capacity = "2.88 MB";
648 * Medium density diskettes have 1024 byte blocks. The dk_map
649 * structure in dklabel.h assumes the blocks size is DEVBSIZE (512)
650 * bytes. The dkl_nblk field is in terms of DEVBSIZE byte blocks
651 * while the spt variable is in terms of the true block size on
652 * the diskette.
654 if (allmap.dka_map[2].dkl_nblk !=
655 (2 * num_cyl * spt * (m_flag ? 2 : 1))) {
656 allmap.dka_map[1].dkl_cylno = num_cyl - 1;
657 allmap.dka_map[0].dkl_nblk = 2 * (num_cyl - 1) * spt *
658 (m_flag ? 2 : 1);
659 allmap.dka_map[1].dkl_nblk = 2 * spt * (m_flag ? 2 : 1);
660 allmap.dka_map[2].dkl_nblk = 2 * num_cyl * spt *
661 (m_flag ? 2 : 1);
662 if (allmap.dka_map[3].dkl_nblk)
663 allmap.dka_map[3].dkl_nblk = 2 * (num_cyl - 1) * spt *
664 (m_flag ? 2 : 1);
665 if (allmap.dka_map[4].dkl_nblk)
666 allmap.dka_map[4].dkl_nblk =
667 2 * spt * (m_flag ? 2 : 1);
671 /* initialize the vtoc structure */
672 fd_vtoc->v_nparts = 3;
674 fd_vtoc->v_part[0].p_start = 0;
675 fd_vtoc->v_part[0].p_size = ((num_cyl - 1) * 2 * spt *
676 (m_flag ? 2 : 1));
677 fd_vtoc->v_part[1].p_start = ((num_cyl - 1) * 2 * spt *
678 (m_flag ? 2 : 1));
679 fd_vtoc->v_part[1].p_size = 2 * spt * (m_flag ? 2 : 1);
681 fd_vtoc->v_part[2].p_start = 0;
682 fd_vtoc->v_part[2].p_size = num_cyl * 2 * spt * (m_flag ? 2 : 1);
684 /* initialize the bios parameter blockstructure */
685 bpb->b_nfat = 2;
686 if (E_flag && drive_size == 3) {
687 bpb->b_spcl = 2;
688 *rdirsec = (ushort_t)240;
689 bpb->b_mediadescriptor = (char)0xF0;
690 bpb->b_fatsec[0] = 9;
691 bpb->b_fatsec[1] = 0;
692 } else if (H_flag) {
693 if (drive_size == 5) {
694 bpb->b_spcl = 1;
695 *rdirsec = 224;
696 bpb->b_mediadescriptor = (char)0xF9;
697 bpb->b_fatsec[0] = 7;
698 bpb->b_fatsec[1] = 0;
699 } else {
700 bpb->b_spcl = 1;
701 *rdirsec = 224;
702 bpb->b_mediadescriptor = (char)0xF0;
703 bpb->b_fatsec[0] = 9;
704 bpb->b_fatsec[1] = 0;
706 } else if (drive_size == 5) {
707 bpb->b_spcl = 2;
708 *rdirsec = 112;
709 bpb->b_mediadescriptor = (char)0xFD;
710 bpb->b_fatsec[0] = 2;
711 bpb->b_fatsec[1] = 0;
712 } else if (drive_size == 3) {
713 bpb->b_spcl = 2;
714 *rdirsec = 112;
715 bpb->b_mediadescriptor = (char)0xF9;
716 bpb->b_fatsec[0] = 3;
717 bpb->b_fatsec[1] = 0;
722 #ifndef sparc
723 if (num_cyl > fdchar.fdc_ncyl || spt > fdchar.fdc_secptrack ||
724 transfer_rate > fdchar.fdc_transfer_rate) {
725 (void) fprintf(stderr,
726 gettext("%s: drive not capable of requested density, "),
727 myname);
728 perror(nullstring);
729 exit(3);
731 #endif
732 if (num_cyl != fdchar.fdc_ncyl || spt != fdchar.fdc_secptrack ||
733 transfer_rate != fdchar.fdc_transfer_rate) {
735 * -- CAUTION --
736 * The SPARC fd driver is using a non-zero value in
737 * fdc_medium to indicate the 360 rpm, 77 track,
738 * 9 sectors/track, 1024 bytes/sector mode of operation
739 * (similar to an 8", DS/DD, 1.2 MB floppy).
741 * The x86 fd driver uses fdc_medium as the diameter
742 * indicator, either 3 or 5. It should not be modified.
744 #ifdef sparc
745 fdchar.fdc_medium = m_flag ? 1 : 0;
746 #endif
747 fdchar.fdc_transfer_rate = transfer_rate;
748 fdchar.fdc_ncyl = num_cyl;
749 fdchar.fdc_sec_size = sec_size;
750 fdchar.fdc_secptrack = spt;
752 if (ioctl(fd, FDIOSCHAR, &fdchar) == -1) {
753 (void) fprintf(stderr, gettext(
754 "%s: FDIOSCHAR (density selection) failed, "),
755 myname);
757 /* restore the default characteristics */
758 restore_default_chars(fd, save_fdchar, save_allmap);
759 perror(nullstring);
760 exit(3);
762 if (ioctl(fd, DKIOCSAPART, &allmap) == -1) {
763 (void) fprintf(stderr,
764 gettext("%s: DKIOCSAPART failed, "),
765 myname);
767 /* restore the default characteristics */
768 restore_default_chars(fd, save_fdchar, save_allmap);
770 perror(nullstring);
771 exit(3);
775 if (interleave != 1 && interleave != fdgeom.dkg_intrlv) {
776 fdgeom.dkg_intrlv = interleave;
777 if (ioctl(fd, DKIOCSGEOM, &fdgeom) == -1) {
778 (void) fprintf(stderr,
779 gettext("%s: DKIOCSGEOM failed, "), myname);
780 perror(nullstring);
782 /* restore the default characteristics */
783 restore_default_chars(fd, save_fdchar, save_allmap);
785 exit(3);
789 cyl_size = 2 * sec_size * spt;
791 if ((ibuf1 = (uchar_t *)malloc((size_t)cyl_size)) == 0 ||
792 (obuf = (uchar_t *)malloc((size_t)cyl_size)) == 0) {
793 (void) fprintf(stderr,
794 gettext("%s: can't malloc verify buffer, "),
795 myname);
796 perror(nullstring);
797 /* restore the default characteristics */
798 restore_default_chars(fd, save_fdchar, save_allmap);
800 exit(4);
802 (void) memset(ibuf1, (uchar_t)0xA5, cyl_size);
804 if (x_flag)
805 goto skipformat;
807 if (!(q_flag && f_flag)) {
808 if (interleave != 1) {
809 (void) printf(gettext(
810 "Formatting %s, %d cylinders, %d sectors per trk, interleave=%d in %s\n"),
811 capacity, num_cyl, spt, interleave, real_name);
812 } else {
813 (void) printf(gettext("Formatting %s in %s\n"),
814 capacity, real_name);
817 if (!f_flag) {
818 (void) printf(
819 gettext("Press return to start formatting floppy."));
820 while (getchar() != '\n')
824 * for those systems that support this ioctl, they will
825 * return whether or not a diskette is in the drive.
827 if (ioctl(fd, FDGETCHANGE, &chgd) == 0) {
828 if (chgd & FDGC_CURRENT) {
829 (void) fprintf(stderr,
830 gettext("%s: no diskette in drive %s\n"),
831 myname, real_name);
833 /* restore the default characteristics */
834 restore_default_chars(fd, save_fdchar, save_allmap);
836 exit(4);
838 if (chgd & FDGC_CURWPROT) {
839 (void) fprintf(stderr,
840 gettext("%s: \"%s\" is write protected\n"),
841 myname, real_name);
843 /* restore the default characteristics */
844 restore_default_chars(fd, save_fdchar, save_allmap);
846 exit(1);
850 if ((fbuf = (uchar_t *)malloc((unsigned)(4 * spt))) == 0) {
851 (void) fprintf(stderr,
852 gettext("%s: can't malloc format header buffer, "),
853 myname);
854 perror(nullstring);
856 /* restore the default characteristics */
857 restore_default_chars(fd, save_fdchar, save_allmap);
859 exit(3);
862 * do the format, a track at a time
864 for (cyl = 0; cyl < (z_flag ? 1 : (int)num_cyl); cyl++) {
866 * This is not the optimal ioctl to format the floppy.
867 * The device driver should do do the work,
868 * instead of this program mucking with a lot
869 * of low-level, device-dependent code.
871 fdr_seek.fdr_cmd[2] = cyl;
872 if (ioctl(fd, FDRAW, &fdr_seek) == -1) {
873 (void) fprintf(stderr,
874 gettext("%s: seek to cyl %d failed\n"),
875 myname, cyl);
877 /* restore the default characteristics */
878 restore_default_chars(fd, save_fdchar, save_allmap);
880 exit(3);
883 * Assume that the fd driver has issued a SENSE_INT
884 * command to complete the seek operation.
886 for (hd = 0; hd < fdchar.fdc_nhead; hd++) {
887 p = (uchar_t *)fbuf;
888 for (i = 1; i <= spt; i++) {
889 *p++ = cyl;
890 *p++ = hd;
891 *p++ = i; /* sector # */
892 *p++ = (sec_size == 1024) ? 3 : 2;
895 * ASSUME the fd driver is going to set drive-select
896 * bits in the second command byte
898 fdr_form.fdr_cmd[1] = hd << 2;
899 fdr_form.fdr_cmd[2] = (sec_size == 1024) ? 3 : 2;
900 fdr_form.fdr_cmd[3] = spt;
901 fdr_form.fdr_cmd[4] = gap;
902 fdr_form.fdr_nbytes = 4 * spt;
903 fdr_form.fdr_addr = (char *)fbuf;
905 if (ioctl(fd, FDRAW, &fdr_form) == -1) {
908 (void) fprintf(stderr, gettext(
909 "%s: format of cyl %d head %d failed\n"),
910 myname, cyl, hd);
912 /* restore the default characteristics */
913 restore_default_chars(fd, save_fdchar,
914 save_allmap);
916 exit(3);
918 if (fdr_form.fdr_result[0] & 0xC0) {
919 if (fdr_form.fdr_result[1] & 0x02) {
920 (void) fprintf(stderr, gettext(
921 /*CSTYLED*/
922 "%s: diskette is write protected\n"),
923 myname);
926 * restore the default
927 * characteristics
929 restore_default_chars(fd, save_fdchar,
930 save_allmap);
932 exit(3);
934 (void) fprintf(stderr, gettext(
935 "%s: format of cyl %d head %d failed\n"),
936 myname, cyl, hd);
938 /* restore the default characteristics */
939 restore_default_chars(fd, save_fdchar,
940 save_allmap);
942 exit(3);
948 * do a quick verify
950 if (!v_flag) {
951 if (lseek(fd, cyl * cyl_size, 0) != cyl * cyl_size) {
952 (void) fprintf(stderr,
953 gettext("%s: bad seek to format verify, "),
954 myname);
955 perror(nullstring);
956 /* restore the default characteristics */
957 restore_default_chars(fd, save_fdchar,
958 save_allmap);
960 exit(3);
962 if (read(fd, obuf, cyl_size) == cyl_size) {
963 /* write some progress msg */
964 /* when each cylinder is done. */
965 if (!q_flag)
966 (void) printf(".");
967 } else {
968 if (!q_flag)
969 (void) printf(gettext("e\n"));
970 (void) fprintf(stderr, gettext(
971 "%s: can't read format data, "), myname);
972 perror(nullstring);
973 /* restore the default characteristics */
974 restore_default_chars(fd, save_fdchar,
975 save_allmap);
977 exit(3);
979 } else
980 if (!q_flag)
981 (void) printf(".");
982 if (!q_flag)
983 (void) fflush(stdout);
985 if (!q_flag)
986 (void) printf("\n");
987 skipformat:
988 if (v_flag) {
990 * do a write & read verify of the entire diskette
992 if (!q_flag && x_flag)
993 (void) printf(gettext("Verifying %s in %s\n"),
994 capacity, real_name);
996 for (cyl = 0; cyl < (int)num_cyl; cyl++) {
998 int val;
999 if ((val = verify(fd, 2 * spt * cyl, cyl_size)) != 0) {
1000 perror(nullstring);
1002 /* restore the default characteristics */
1003 restore_default_chars(fd, save_fdchar,
1004 save_allmap);
1006 exit(val);
1009 /* write some progress msg as */
1010 /* each cylinder is done. */
1011 if (!q_flag)
1012 (void) printf(gettext("v"));
1013 (void) fflush(stdout);
1015 if (!q_flag)
1016 (void) printf("\n");
1019 if (lseek(fd, (off_t)0, 0) != 0) {
1020 (void) fprintf(stderr, gettext("%s: seek to blk 0 failed, "),
1021 myname);
1022 perror(nullstring);
1023 /* restore the default characteristics */
1024 restore_default_chars(fd, save_fdchar, save_allmap);
1026 exit(3);
1033 * Restore the default characteristics of the floppy diskette.
1034 * Fdformat changes the characteristics in the process of formatting.
1035 * If fdformat fails while in the process of doing the format, fdformat
1036 * should clean up after itself and reset the driver back to the original
1037 * state.
1040 static void
1041 restore_default_chars(int fd,
1042 struct fd_char save_fdchar,
1043 struct dk_allmap save_allmap)
1048 * When this function is called, fdformat is failing anyways,
1049 * so the errors are not processed.
1052 (void) ioctl(fd, FDIOSCHAR, &save_fdchar);
1054 (void) ioctl(fd, DKIOCSAPART, &save_allmap);
1057 * Before looking at the diskette's characteristics, format_diskette()
1058 * sets the x86 floppy driver to the default characteristics.
1059 * restore drive to default geometry and
1060 * characteristics. This ioctl isn't implemented on
1061 * sparc.
1063 (void) ioctl(fd, FDDEFGEOCHAR, NULL);
1068 * See if any partitions on the device are mounted. Return 1 if a partition is
1069 * mounted. Return 0 otherwise.
1071 static int
1072 check_mount()
1074 FILE *fp = NULL;
1075 int mfd;
1076 struct dk_cinfo dkinfo_tmp;
1077 struct mnttab mnt_record;
1078 struct mnttab *mp = &mnt_record;
1079 struct stat stbuf;
1080 char raw_device[MAXPATHLEN];
1081 int found = 0;
1083 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1084 perror(MNTTAB);
1085 exit(3);
1088 while (getmntent(fp, mp) == 0) {
1089 if (strstr(mp->mnt_special, "/dev/fd") == NULL &&
1090 strstr(mp->mnt_special, "/dev/disket") == NULL &&
1091 strstr(mp->mnt_special, "/dev/c") == NULL) {
1092 continue;
1095 (void) strcpy(raw_device, "/dev/r");
1096 (void) strcat(raw_device, mp->mnt_special + strlen("/dev/"));
1099 * Attempt to open the device. If it fails, skip it.
1101 if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
1102 continue;
1106 * Must be a character device
1108 if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
1109 (void) close(mfd);
1110 continue;
1113 * Attempt to read the configuration info on the disk.
1115 if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) {
1116 (void) close(mfd);
1117 continue;
1120 * Finished with the opened device
1122 (void) close(mfd);
1125 * If it's not the disk we're interested in, it doesn't apply.
1127 if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype ||
1128 dkinfo.dki_cnum != dkinfo_tmp.dki_cnum ||
1129 dkinfo.dki_unit != dkinfo_tmp.dki_unit) {
1130 continue;
1133 * It's a mount on the disk we're checking. If we are
1134 * checking whole disk, then we found trouble. We can
1135 * quit searching.
1138 if (U_flag) {
1139 if (!_dev_unmount(mp->mnt_special)) {
1140 (void) fprintf(stderr,
1141 gettext("%s: umount of %s failed\n"),
1142 myname, mp->mnt_special);
1143 found = 1;
1145 } else {
1146 (void) fprintf(stderr,
1147 gettext("%s: %s is mounted (use -U flag)\n"),
1148 myname, mp->mnt_special);
1149 found = 1;
1152 return (found);
1155 static void
1156 usage(char *str)
1158 char *real_name, *alias_name;
1160 if ((real_name = media_findname("floppy")) == NULL) {
1161 if ((alias_name = _media_oldaliases("floppy")) != NULL)
1162 real_name = media_findname(alias_name);
1165 if (str[0] != ' ')
1166 (void) printf("%s: %s\n", myname, str);
1167 (void) printf(gettext(
1168 /*CSTYLED*/
1169 "\n usage: %s [-dDeEfHlLmMqUvx] [-b label] [-B file] [-t dostype] [devname]\n"),
1170 myname);
1172 (void) printf(gettext(
1173 /*CSTYLED*/
1174 " -b label install \"label\" on media\n"));
1175 (void) printf(gettext(
1176 " -B file install special boot loader on MS-DOS media\n"));
1177 (void) printf(gettext(
1178 /*CSTYLED*/
1179 " -d format MS-DOS media\n"));
1180 (void) printf(gettext(
1181 /*CSTYLED*/
1182 " -D format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
1183 (void) printf(gettext(
1184 " -e eject the media when done\n"));
1185 /*CSTYLED*/
1186 (void) printf(gettext(
1187 /*CSTYLED*/
1188 " -E format 2.88MB (3.5\") Extended-density diskette\n"));
1189 (void) printf(gettext(
1190 " -f \"force\" - don't wait for confirmation\n"));
1191 (void) printf(gettext(
1192 /*CSTYLED*/
1193 " -H format 1.44MB (3.5\") or 1.2MB (5.25\") High-density diskette\n"));
1194 (void) printf(gettext(
1195 /*CSTYLED*/
1196 " -l format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
1197 (void) printf(gettext(
1198 /*CSTYLED*/
1199 " -L format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
1200 (void) printf(gettext(
1201 " -m format 1.2MB (3.5\") Medium-density diskette\n"));
1202 (void) printf(gettext(
1203 " -M format 1.2MB (3.5\") Medium-density diskette\n"));
1204 (void) printf(gettext(
1205 " -q quiet\n"));
1206 (void) printf(gettext(
1207 /*CSTYLED*/
1208 " -t dos format MS-DOS media (same as -d)\n"));
1209 (void) printf(gettext(
1210 " -t nec format NEC-DOS media (with -M only)\n"));
1211 (void) printf(gettext(
1212 /*CSTYLED*/
1213 " -U unmount media if it's mounted\n"));
1214 (void) printf(gettext(
1215 " -v verify each block of the media\n"));
1216 (void) printf(gettext(
1217 " -x skip the format, only install SunOS or DOS label\n"));
1219 (void) printf(gettext(
1220 " devname defaults to '%s'\n"),
1221 real_name ? real_name : gettext("no available default device"));
1223 exit(1);
1228 static int
1229 verify(int fd, int blk, int len)
1231 off_t off;
1232 char *nullstring = "";
1234 off = (off_t)(blk * (m_flag ? 1024 : 512));
1236 if (lseek(fd, off, 0) != off) {
1237 if (!q_flag)
1238 (void) printf(gettext("e\n"));
1239 (void) fprintf(stderr,
1240 gettext("%s: can't seek to write verify, "), myname);
1241 perror(nullstring);
1242 return (4);
1244 if (write(fd, ibuf1, len) != len) {
1245 if (!q_flag)
1246 (void) printf(gettext("e\n"));
1247 if (blk == 0)
1248 (void) fprintf(stderr,
1249 gettext("%s: check diskette density, "),
1250 myname);
1251 else
1252 (void) fprintf(stderr,
1253 gettext("%s: can't write verify data, "),
1254 myname);
1255 perror(nullstring);
1256 return (4);
1259 if (lseek(fd, off, 0) != off) {
1260 if (!q_flag)
1261 (void) printf(gettext("e\n"));
1262 (void) fprintf(stderr,
1263 gettext("%s: bad seek to read verify, "),
1264 myname);
1265 perror(nullstring);
1266 return (4);
1268 if (read(fd, obuf, len) != len) {
1269 if (!q_flag)
1270 (void) printf(gettext("e\n"));
1271 (void) fprintf(stderr,
1272 gettext("%s: can't read verify data, "), myname);
1273 perror(nullstring);
1274 return (4);
1276 if (memcmp(ibuf1, obuf, len)) {
1277 if (!q_flag)
1278 (void) printf(gettext("e\n"));
1279 (void) fprintf(stderr, gettext("%s: verify data failure\n"),
1280 myname);
1281 return (4);
1283 return (0);
1287 * write a SunOS label
1288 * NOTE: this function assumes fd_vtoc has been filled in with the
1289 * device specific information such as partition information
1290 * and the asciilabel
1292 static void
1293 write_SunOS_label(int fd, char *volname, struct vtoc *fd_vtoc)
1295 char *nullstring = "";
1297 fd_vtoc->v_sanity = VTOC_SANE;
1300 * The label structure is set up for DEV_BSIZE (512 byte) blocks,
1301 * even though a medium density diskette has 1024 byte blocks
1302 * See dklabel.h for more details.
1304 fd_vtoc->v_sectorsz = DEV_BSIZE;
1306 (void) strncpy(fd_vtoc->v_volume, volname, sizeof (fd_vtoc->v_volume));
1308 /* let the fd driver finish constructing the label and writing it */
1309 if (ioctl(fd, DKIOCSVTOC, fd_vtoc) == -1) {
1310 (void) fprintf(stderr,
1311 gettext("%s: write of SunOS label failed, "), myname);
1312 perror(nullstring);
1313 exit(3);
1320 * MS-DOS Disk layout:
1322 * ---------------------
1323 * | Boot sector |
1324 * |-------------------|
1325 * | Reserved area |
1326 * |-------------------|
1327 * | FAT #1 |
1328 * |-------------------|
1329 * | FAT #2 |
1330 * |-------------------|
1331 * | Root directory |
1332 * |-------------------|
1333 * | |
1334 * | File area |
1335 * |___________________|
1339 * The following is a copy of MS-DOS 3.3 boot block.
1340 * It consists of the BIOS parameter block, and a disk
1341 * bootstrap program.
1343 * The BIOS parameter block contains the right values
1344 * for the 3.5" high-density 1.44MB floppy format.
1347 static uchar_t bootsec[512] = {
1348 0xeb, 0x34, 0x90, /* 8086 short jump + displacement + NOP */
1349 'M', 'S', 'D', 'O', 'S', '3', '.', '3', /* OEM name & version */
1350 0, 2, 1, 1, 0, /* Start of BIOS parameter block */
1351 2, 224, 0, 0x40, 0xb, 0xf0, 9, 0,
1352 18, 0, 2, 0, 0, 0, /* End of BIOS parameter block */
1353 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1354 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12,
1355 0x0, 0x0, 0x0, 0x0,
1356 0x1, 0x0, 0xfa, 0x33, /* 0x34, start of the bootstrap. */
1357 0xc0, 0x8e, 0xd0, 0xbc, 0x0, 0x7c, 0x16, 0x7,
1358 0xbb, 0x78, 0x0, 0x36, 0xc5, 0x37, 0x1e, 0x56,
1359 0x16, 0x53, 0xbf, 0x2b, 0x7c, 0xb9, 0xb, 0x0,
1360 0xfc, 0xac, 0x26, 0x80, 0x3d, 0x0, 0x74, 0x3,
1361 0x26, 0x8a, 0x5, 0xaa, 0x8a, 0xc4, 0xe2, 0xf1,
1362 0x6, 0x1f, 0x89, 0x47, 0x2, 0xc7, 0x7, 0x2b,
1363 0x7c, 0xfb, 0xcd, 0x13, 0x72, 0x67, 0xa0, 0x10,
1364 0x7c, 0x98, 0xf7, 0x26, 0x16, 0x7c, 0x3, 0x6,
1365 0x1c, 0x7c, 0x3, 0x6, 0xe, 0x7c, 0xa3, 0x3f,
1366 0x7c, 0xa3, 0x37, 0x7c, 0xb8, 0x20, 0x0, 0xf7,
1367 0x26, 0x11, 0x7c, 0x8b, 0x1e, 0xb, 0x7c, 0x3,
1368 0xc3, 0x48, 0xf7, 0xf3, 0x1, 0x6, 0x37, 0x7c,
1369 0xbb, 0x0, 0x5, 0xa1, 0x3f, 0x7c, 0xe8, 0x9f,
1370 0x0, 0xb8, 0x1, 0x2, 0xe8, 0xb3, 0x0, 0x72,
1371 0x19, 0x8b, 0xfb, 0xb9, 0xb, 0x0, 0xbe, 0xd6,
1372 0x7d, 0xf3, 0xa6, 0x75, 0xd, 0x8d, 0x7f, 0x20,
1373 0xbe, 0xe1, 0x7d, 0xb9, 0xb, 0x0, 0xf3, 0xa6,
1374 0x74, 0x18, 0xbe, 0x77, 0x7d, 0xe8, 0x6a, 0x0,
1375 0x32, 0xe4, 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x4,
1376 0x8f, 0x44, 0x2, 0xcd, 0x19, 0xbe, 0xc0, 0x7d,
1377 0xeb, 0xeb, 0xa1, 0x1c, 0x5, 0x33, 0xd2, 0xf7,
1378 0x36, 0xb, 0x7c, 0xfe, 0xc0, 0xa2, 0x3c, 0x7c,
1379 0xa1, 0x37, 0x7c, 0xa3, 0x3d, 0x7c, 0xbb, 0x0,
1380 0x7, 0xa1, 0x37, 0x7c, 0xe8, 0x49, 0x0, 0xa1,
1381 0x18, 0x7c, 0x2a, 0x6, 0x3b, 0x7c, 0x40, 0x38,
1382 0x6, 0x3c, 0x7c, 0x73, 0x3, 0xa0, 0x3c, 0x7c,
1383 0x50, 0xe8, 0x4e, 0x0, 0x58, 0x72, 0xc6, 0x28,
1384 0x6, 0x3c, 0x7c, 0x74, 0xc, 0x1, 0x6, 0x37,
1385 0x7c, 0xf7, 0x26, 0xb, 0x7c, 0x3, 0xd8, 0xeb,
1386 0xd0, 0x8a, 0x2e, 0x15, 0x7c, 0x8a, 0x16, 0xfd,
1387 0x7d, 0x8b, 0x1e, 0x3d, 0x7c, 0xea, 0x0, 0x0,
1388 0x70, 0x0, 0xac, 0xa, 0xc0, 0x74, 0x22, 0xb4,
1389 0xe, 0xbb, 0x7, 0x0, 0xcd, 0x10, 0xeb, 0xf2,
1390 0x33, 0xd2, 0xf7, 0x36, 0x18, 0x7c, 0xfe, 0xc2,
1391 0x88, 0x16, 0x3b, 0x7c, 0x33, 0xd2, 0xf7, 0x36,
1392 0x1a, 0x7c, 0x88, 0x16, 0x2a, 0x7c, 0xa3, 0x39,
1393 0x7c, 0xc3, 0xb4, 0x2, 0x8b, 0x16, 0x39, 0x7c,
1394 0xb1, 0x6, 0xd2, 0xe6, 0xa, 0x36, 0x3b, 0x7c,
1395 0x8b, 0xca, 0x86, 0xe9, 0x8a, 0x16, 0xfd, 0x7d,
1396 0x8a, 0x36, 0x2a, 0x7c, 0xcd, 0x13, 0xc3, '\r',
1397 '\n', 'N', 'o', 'n', '-', 'S', 'y', 's',
1398 't', 'e', 'm', ' ', 'd', 'i', 's', 'k',
1399 ' ', 'o', 'r', ' ', 'd', 'i', 's', 'k',
1400 ' ', 'e', 'r', 'r', 'o', 'r', '\r', '\n',
1401 'R', 'e', 'p', 'l', 'a', 'c', 'e', ' ',
1402 'a', 'n', 'd', ' ', 's', 't', 'r', 'i',
1403 'k', 'e', ' ', 'a', 'n', 'y', ' ', 'k',
1404 'e', 'y', ' ', 'w', 'h', 'e', 'n', ' ',
1405 'r', 'e', 'a', 'd', 'y', '\r', '\n', '\0',
1406 '\r', '\n', 'D', 'i', 's', 'k', ' ', 'B',
1407 'o', 'o', 't', ' ', 'f', 'a', 'i', 'l',
1408 'u', 'r', 'e', '\r', '\n', '\0', 'I', 'O',
1409 ' ', ' ', ' ', ' ', ' ', ' ', 'S', 'Y',
1410 'S', 'M', 'S', 'D', 'O', 'S', ' ', ' ',
1411 ' ', 'S', 'Y', 'S', '\0', 0, 0, 0,
1412 0, 0, 0, 0, 0, 0, 0, 0, 0,
1413 0, 0, 0, 0, 0, 0x55, 0xaa
1416 static int
1417 valid_DOS_boot(char *bootfile, uchar_t **bootloadp)
1419 struct stat status;
1420 size_t sizebootldr;
1421 uchar_t *bootloader;
1422 int bfd;
1423 int boot_size = 0;
1424 int err;
1425 char *nullstring = "";
1427 if ((err = stat(bootfile, &status)) != 0) {
1428 (void) fprintf(stderr, gettext("%s: \"%s\" stat error %d\n"),
1429 myname, bootfile, err);
1430 return (0);
1432 if ((boot_size = status.st_size) < 512) {
1433 (void) fprintf(stderr,
1434 gettext("%s: short boot sector"), myname);
1435 perror(nullstring);
1436 return (0);
1438 sizebootldr = (boot_size + 511) / 512 * 512;
1439 if ((bootloader = (uchar_t *)malloc((size_t)sizebootldr)) == NULL) {
1440 (void) fprintf(stderr, gettext("%s: malloc error\n"),
1441 myname);
1442 return (0);
1445 /* switch to user to access the boot file */
1446 (void) seteuid(getuid());
1448 if ((bfd = open(bootfile, O_RDONLY)) == -1) {
1449 (void) fprintf(stderr, gettext("%s: could not open \"%s\": "),
1450 myname, bootfile);
1451 perror(nullstring);
1452 return (0);
1455 /* restore effective id */
1456 (void) seteuid(euid);
1458 if (read(bfd, bootloader, boot_size) != boot_size) {
1459 (void) fprintf(stderr,
1460 gettext("%s: read of MS-DOS boot file failed, "), myname);
1461 perror(nullstring);
1462 (void) close(bfd);
1463 return (0);
1466 if (!((*bootloader == 0xE9 ||
1467 (*bootloader == 0xEB && *(bootloader + 2) == 0x90)) &&
1468 *(bootloader + 510) == 0x55 &&
1469 *(bootloader + 511) == 0xAA)) {
1470 (void) fprintf(stderr,
1471 gettext("%s: invalid MS-DOS boot loader image\n"), myname);
1472 boot_size = 0;
1475 (void) close(bfd);
1476 *bootloadp = bootloader;
1477 return (boot_size);
1481 static void
1482 write_DOS_label(int fd, uchar_t *bootloadr, int bootlen, char *altbootname,
1483 char *doslabel, struct bios_param_blk *bpb, int rdirsec)
1485 int i, j;
1486 int bootclen;
1487 size_t fat_bsize;
1488 ushort_t totalsec;
1489 uchar_t *fat_rdir;
1490 uchar_t *fatptr;
1491 char *nullstring = "";
1493 if (bootlen < 512 || !bootloadr) {
1494 /* use default boot loader routine */
1495 bootloadr = bootsec;
1496 bootlen = 512;
1497 } else
1498 (void) printf
1499 (gettext("%s: using \"%s\" for MS-DOS boot loader\n"),
1500 myname, altbootname);
1501 if (bootlen % 512 > 0)
1502 bootlen = (bootlen + 511) / 512 * 512;
1504 bpb->b_bps[0] = getlobyte(512);
1505 bpb->b_bps[1] = gethibyte(512);
1506 /* MS-DOS 5.0 supports only 1 reserved sector :-( */
1507 bpb->b_res_sec[0] = 1;
1508 bpb->b_res_sec[1] = 0;
1510 totalsec = fdchar.fdc_ncyl * fdchar.fdc_nhead * fdchar.fdc_secptrack;
1511 bpb->b_totalsec[0] = getlobyte(totalsec);
1512 bpb->b_totalsec[1] = gethibyte(totalsec);
1513 bpb->b_spt[0] = fdchar.fdc_secptrack;
1514 bpb->b_spt[1] = 0;
1515 bpb->b_nhead[0] = fdchar.fdc_nhead;
1516 bpb->b_nhead[1] = 0;
1517 bpb->b_hiddensec[0] = 0;
1518 bpb->b_hiddensec[1] = 0;
1520 bpb->b_rdirents[0] = getlobyte(rdirsec);
1521 bpb->b_rdirents[1] = gethibyte(rdirsec);
1523 (void) memcpy((char *)(bootloadr + 0x0B), (char *)bpb,
1524 sizeof (struct bios_param_blk));
1526 if (write(fd, bootloadr, 512) != 512) {
1527 (void) fprintf(stderr,
1528 gettext("%s: write of MS-DOS boot sector failed"), myname);
1529 perror(nullstring);
1530 exit(3);
1532 bootloadr += 512;
1533 bootlen -= 512;
1535 fat_bsize = 512 * bpb->b_fatsec[0];
1536 fat_rdir = (uchar_t *)malloc(fat_bsize);
1537 (void) memset(fat_rdir, 0, fat_bsize);
1539 *fat_rdir = bpb->b_mediadescriptor;
1540 *(fat_rdir + 1) = 0xFF;
1541 *(fat_rdir + 2) = 0xFF;
1542 bootclen = (bootlen + 512 * (int)bpb->b_spcl - 1) /
1543 (512 * (int)bpb->b_spcl);
1544 #define BAD_CLUSTER 0xFF7
1545 for (i = 0, fatptr = fat_rdir+3; i < bootclen; i++)
1547 * pre-allocate any clusters used by boot loader if
1548 * loader will occupy more than 1 sector
1550 if (!(i & 01)) {
1551 *fatptr++ = BAD_CLUSTER & 0xFF;
1552 *fatptr = (BAD_CLUSTER >> 8) & 0x0F;
1553 } else {
1554 *fatptr = (*fatptr & 0x0F) |
1555 ((BAD_CLUSTER << 4) & 0xF0);
1556 fatptr++;
1557 *fatptr++ = (BAD_CLUSTER >> 4) & 0xFF;
1559 for (i = 0; i < (int)bpb->b_nfat; ++i)
1560 if (write(fd, fat_rdir, fat_bsize) != fat_bsize) {
1561 (void) fprintf(stderr,
1562 gettext("%s: write of MS-DOS File Allocation Table failed, "),
1563 myname);
1564 perror(nullstring);
1565 exit(3);
1567 rdirsec = bpb->b_rdirents[0];
1568 rdirsec = 32 * (int)rdirsec / 512;
1569 if (b_flag) {
1570 struct timeval tv;
1571 struct tm *tp;
1572 ushort_t dostime;
1573 ushort_t dosday;
1575 /* the label can be no more than 11 characters */
1576 j = min(11, (int)strlen(doslabel));
1577 for (i = 0; i < j; i++) {
1578 fat_rdir[i] = uppercase(doslabel[i]);
1580 for (; i < 11; i++) {
1581 fat_rdir[i] = ' ';
1583 fat_rdir[0x0B] = 0x28;
1584 (void) gettimeofday(&tv, NULL);
1585 tp = localtime(&tv.tv_sec);
1586 /* get the time & day into DOS format */
1587 dostime = tp->tm_sec / 2;
1588 dostime |= tp->tm_min << 5;
1589 dostime |= tp->tm_hour << 11;
1590 dosday = tp->tm_mday;
1591 dosday |= (tp->tm_mon + 1) << 5;
1592 dosday |= (tp->tm_year - 80) << 9;
1593 fat_rdir[0x16] = getlobyte(dostime);
1594 fat_rdir[0x17] = gethibyte(dostime);
1595 fat_rdir[0x18] = getlobyte(dosday);
1596 fat_rdir[0x19] = gethibyte(dosday);
1598 if (write(fd, fat_rdir, 512) != 512) {
1599 (void) fprintf(stderr,
1600 gettext("%s: write of MS-DOS FAT failed, "),
1601 myname);
1602 perror(nullstring);
1603 exit(3);
1605 i = 1;
1606 } else {
1607 i = 0;
1609 (void) memset(fat_rdir, 0, 512);
1610 for (; i < (int)rdirsec; ++i) {
1611 if (write(fd, fat_rdir, 512) != 512) {
1612 (void) fprintf(stderr,
1613 gettext("%s: write of MS-DOS root directory failed, "),
1614 myname);
1615 perror(nullstring);
1616 exit(3);
1620 * Write the rest of the boot loader if it's longer than one sector.
1621 * The clusters used are marked Bad in the FAT.
1622 * No directory entry exists for this file (so that it cannot be
1623 * deleted).
1625 if (bootlen && write(fd, bootloadr, bootlen) != bootlen) {
1626 (void) fprintf(stderr,
1627 gettext("%s: write of MS-DOS boot sectors failed"), myname);
1628 perror(nullstring);
1629 exit(3);
1633 static void
1634 write_NEC_DOS_label(int fd, char *doslabel)
1636 struct bios_param_blk *bpb;
1637 ushort_t fatsec;
1638 ushort_t rdirsec;
1639 char fat_rdir[1024];
1640 int i, j, m = 1;
1641 uchar_t bootsec_NEC[1024];
1642 char *nullstring = "";
1644 uchar_t bios_param_NEC[30] = { 0xeb, 0x1c, 0x90, 0x0, 0x0, 0x0, 0x0,
1645 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1, 0x1, 0x0,
1646 0x2, 0xc0, 0x0, 0xd0, 0x4, 0xfe, 0x2, 0x0,
1647 0x8, 0x0, 0x2, 0x0, 0x0, 0x0
1650 uchar_t fatdir[32] = { 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
1651 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
1652 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
1653 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5
1658 (void) memset(bootsec_NEC, 0, 1024);
1660 (void) memcpy(&bootsec_NEC, &bios_param_NEC, 30);
1662 bpb = (struct bios_param_blk *)&(bootsec_NEC[0xb]);
1663 if (write(fd, &bootsec_NEC[0], 1024) != 1024) {
1664 (void) fprintf(stderr, gettext(
1665 "%s: write of NEC-DOS boot sector failed, "),
1666 myname);
1667 perror(nullstring);
1668 exit(3);
1670 (void) memset(fat_rdir, 0, 1024);
1671 fatsec = bpb->b_fatsec[0];
1672 for (i = 0; i < (int)bpb->b_nfat * (int)fatsec; ++i) {
1673 if ((i % (int)fatsec) == 0) {
1674 fat_rdir[0] = bpb->b_mediadescriptor;
1675 fat_rdir[1] = (char)0xff;
1676 fat_rdir[2] = (char)0xff;
1677 fat_rdir[3] = 0;
1678 fat_rdir[4] = 0;
1679 fat_rdir[5] = 0;
1680 } else {
1681 fat_rdir[0] = 0;
1682 fat_rdir[1] = 0;
1683 fat_rdir[2] = 0;
1684 fat_rdir[3] = 0;
1685 fat_rdir[4] = 0;
1686 fat_rdir[5] = 0;
1688 if (write(fd, &fat_rdir[0], 1024) != 1024) {
1689 (void) fprintf(stderr,
1690 /*CSTYLED*/
1691 gettext("%s: write of NEC-DOS File Allocation Table failed, "), myname);
1692 perror(nullstring);
1693 exit(3);
1696 #ifndef sparc
1697 /* LINTED */
1698 rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024;
1699 #else
1700 rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024;
1701 #endif
1702 if (b_flag) {
1703 struct timeval tv;
1704 struct tm *tp;
1705 ushort_t dostime;
1706 ushort_t dosday;
1708 /* the label can be no more than 11 characters */
1709 j = min(11, (int)strlen(doslabel));
1710 for (i = 0; i < j; i++) {
1711 fat_rdir[i] = uppercase(doslabel[i]);
1713 for (; i < 11; i++) {
1714 fat_rdir[i] = ' ';
1716 fat_rdir[0xb] = 0x28;
1717 (void) gettimeofday(&tv, NULL);
1718 tp = localtime(&tv.tv_sec);
1719 /* get the time & day into DOS format */
1720 dostime = tp->tm_sec / 2;
1721 dostime |= tp->tm_min << 5;
1722 dostime |= tp->tm_hour << 11;
1723 dosday = tp->tm_mday;
1724 dosday |= (tp->tm_mon + 1) << 5;
1725 dosday |= (tp->tm_year - 80) << 9;
1726 fat_rdir[0x16] = getlobyte(dostime);
1727 fat_rdir[0x17] = gethibyte(dostime);
1728 fat_rdir[0x18] = getlobyte(dosday);
1729 fat_rdir[0x19] = gethibyte(dosday);
1731 if (write(fd, &fat_rdir[0], 1024) != 1024) {
1732 (void) fprintf(stderr,
1733 /*CSTYLED*/
1734 gettext("%s: write of NEC-DOS root directory failed, "), myname);
1735 perror(nullstring);
1736 exit(3);
1738 (void) memset(fat_rdir, 0, 512);
1739 i = 1;
1740 } else {
1741 i = 0;
1743 while (m < 1024) {
1744 (void) memcpy(&fat_rdir[m], &fatdir, 31);
1745 m = m + 32;
1748 for (; i < (int)rdirsec; ++i) {
1750 if (write(fd, &fat_rdir[0], 1024) != 1024) {
1751 (void) fprintf(stderr,
1752 /*CSTYLED*/
1753 gettext("%s: write of NEC-DOS root directory failed, "), myname);
1754 perror(nullstring);
1755 exit(3);