1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * fdformat program - formats floppy disks, and then adds a label to them
28 *
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.
32 */
33
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>
56
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
66
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))
71
72 /* FORMAT PATTERNS */
73 #define PATTERN_1 0x55;
74 #define PATTERN_2 0xaa;
75 #define PATTERN_3 0xff;
76 #define PATTERN_4 0x00;
77
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;
83
84 /* EXTERN */
85 extern char *optarg;
86 extern int optind;
87
88 /* for verify buffers */
89 static uchar_t *ibuf1;
90 static uchar_t *obuf;
91
92 static char *myname;
93
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 */
111
112 static uid_t euid = 0; /* stores effective user id */
113
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 */
126 };
127
128 /*
129 * ON-private functions from libvolmgt
130 */
131 char *_media_oldaliases(char *name);
132 int _dev_mounted(char *path);
133 int _dev_unmount(char *path);
134
135 /*
136 * local functions
137 */
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);
151
152 int
main(int argc,char ** argv)153 main(int argc, char **argv)
154 {
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 = "";
166
167 (void) setlocale(LC_ALL, "");
168
169 #if !defined(TEXT_DOMAIN)
170 #define TEXT_DOMAIN "SYS_TEST"
171 #endif
172
173 (void) textdomain(TEXT_DOMAIN);
174
175 myname = argv[0];
176 while ((i = getopt(argc, argv, "B:b:dDeEfhHlLmMxqt:UvVZ?")) != -1) {
177 switch (i) {
178
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);
188 }
189 break;
190
191 case 'b':
192 b_flag++;
193 vollabel = strdup(optarg);
194 break;
195
196 case 'd':
197 /* format a MS-DOS diskette */
198 d_flag++;
199 break;
200
201 case 'D':
202 case 'L':
203 case 'l':
204 /* format a Double density 720KB (or 360KB) disk */
205 D_flag++;
206 break;
207
208 case 'e':
209 /* eject diskette when done */
210 e_flag++;
211 break;
212
213 case 'E':
214 /* format an 2.88MB Extended density disk */
215 E_flag++;
216 break;
217
218 case 'f':
219 /* don't ask for confirmation */
220 f_flag++;
221 break;
222
223 case 'H':
224 case 'h':
225 /* format a High density 1.2MB or 1.44MB disk */
226 H_flag++;
227 break;
228
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);
237 }
238 break;
239 #endif
240
241 case 'M':
242 case 'm':
243 /* format a 3.5" HD disk to 1.2MB */
244 m_flag++;
245 break;
246
247 case 'x':
248 /* skip format, just write label */
249 x_flag++;
250 break;
251
252 case 'q':
253 /* quiet format */
254 q_flag++;
255 break;
256
257 case 't':
258 /* Type of DOS formatting: NEC or MS */
259 if (strcmp(optarg, "nec") == 0) {
260 n_flag++;
261 }
262 if (strcmp(optarg, "dos") == 0) {
263 d_flag++;
264 }
265 break;
266
267 case 'U':
268 /* umount filesystem if mounted */
269 U_flag++;
270 break;
271
272 case 'v':
273 case 'V':
274 /* verify the diskette after format */
275 v_flag++;
276 break;
277
278 case 'Z':
279 /* for debug only, format cyl 0 only */
280 if (!fd_debug) {
281 usage(gettext("unknown argument"));
282 /* NOTREACHED */
283 }
284 (void) printf(gettext("\nFormat cyl Zero only\n"));
285 z_flag++;
286 break;
287
288 default:
289 usage(" ");
290 /* NOTREACHED */
291 }
292 }
293
294 if (optind < argc -1) {
295 usage(gettext("more than one device name argument"));
296 /* NOTREACHED */
297 }
298 if (optind == argc -1) {
299 dev_name = argv[optind];
300 }
301 if (D_flag && H_flag) {
302 usage(gettext("switches -D, -L and -H incompatible"));
303 /* NOTREACHED */
304 }
305 if (D_flag && E_flag) {
306 usage(gettext("switches -D, -L and -E incompatible"));
307 /* NOTREACHED */
308 }
309 if (H_flag && E_flag) {
310 usage(gettext("switches -H and -E incompatible"));
311 /* NOTREACHED */
312 }
313 if (n_flag && d_flag) {
314 usage(gettext("switches nec and dos incompatible"));
315 /* NOTREACHED */
316 }
317 if (n_flag && !m_flag) {
318 usage(gettext("switch -M required for NEC-DOS"));
319 /* NOTREACHED */
320 }
321 if (D_flag && m_flag) {
322 usage(gettext("switches -D, -L and -M incompatible"));
323 /* NOTREACHED */
324 }
325 if (d_flag && m_flag) {
326 usage(gettext("switches -d and -M incompatible"));
327 /* NOTREACHED */
328 }
329
330 if (dev_name == NULL)
331 dev_name = "floppy";
332
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);
341 }
342 }
343
344 /*
345 * This check is required because program runs suid root.
346 */
347 if (access(real_name, R_OK|W_OK) < 0) {
348 perror(real_name);
349 exit(1);
350 }
351
352 /* store callers euid */
353
354 euid = geteuid();
355
356 /*
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
360 */
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);
368 }
369 } else {
370 (void) fprintf(stderr,
371 gettext("%s: %s is mounted (use -U flag)\n"),
372 myname, real_name);
373 exit(1);
374 }
375 }
376
377 /* Set to user access permissions to open file */
378 (void) seteuid(getuid());
379
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);
386 }
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);
392 }
393
394 /* restore effective id */
395 (void) seteuid(euid);
396
397 if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
398 (void) fprintf(stderr,
399 gettext("%s: DKIOCINFO failed, "), myname);
400 perror(nullstring);
401 exit(3);
402 }
403
404 /* See if there are any mounted partitions. */
405 if (check_mount() != 0) {
406 exit(3);
407 }
408
409 /*
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.
418 */
419 (void) memset((void *)&fd_vtoc, (char)0, sizeof (struct vtoc));
420 (void) memset((void *)&bpb, (char)0, sizeof (struct bios_param_blk));
421
422 format_diskette(fd, real_name, &fd_vtoc, &bpb, &rdirsec);
423
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);
431
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);
439 }
440
441 return (0);
442 }
443
444 /*
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
450 */
451 void
format_diskette(int fd,char * real_name,struct vtoc * fd_vtoc,struct bios_param_blk * bpb,int * rdirsec)452 format_diskette(int fd, char *real_name, struct vtoc *fd_vtoc,
453 struct bios_param_blk *bpb, int *rdirsec)
454 {
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 */
471
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,
475 3,
476 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
477 0,
478 0
479 };
480
481 struct fd_raw fdr_form = {
482 0x4D, 0, 2, 0, 0x54, (char)0xA5, 0, 0, 0, 0,
483 6,
484 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
485 0, /* nbytes */
486 0 /* addr */
487 };
488
489
490 /*
491 * restore drive to default geometry and characteristics
492 * (probably not implemented on sparc)
493 */
494 (void) ioctl(fd, FDDEFGEOCHAR, NULL);
495
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);
502 }
503
504 /* Save the original default partition maps */
505 save_allmap = allmap;
506
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);
513 }
514
515 /* Save the original characteristics of the default diskette */
516 save_fdchar = fdchar;
517
518 /*
519 * The user may only format the entire diskette.
520 * formatting partion a or b is not allowed
521 */
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;
526
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);
533 }
534
535
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);
542 }
543
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;
551
552 /*
553 * set proper density flag in case we're formating to default
554 * characteristics because no density switch was input
555 */
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:
564 /*
565 * default to HD even though High density and
566 * "medium" density both use 500 KB/sec
567 */
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
576 }
577 }
578
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";
593 }
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) {
601 /*
602 * formatting a 360KB DD diskette in
603 * a 1.2MB drive is not a good idea
604 */
605 transfer_rate = 300;
606 fdchar.fdc_steps = 2;
607 }
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";
617 }
618 sec_size = 512;
619 spt = 9;
620 } else if (m_flag) {
621 #ifdef sparc
622 transfer_rate = 500;
623 #else
624 /*
625 * 416.67 KB/sec is the effective transfer rate of a "medium"
626 * density diskette spun at 300 rpm instead of 360 rpm
627 */
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";
646 }
647 /*
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.
653 */
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);
668 }
669
670
671 /* initialize the vtoc structure */
672 fd_vtoc->v_nparts = 3;
673
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);
680
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);
683
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;
705 }
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;
718 }
719
720
721
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);
730 }
731 #endif
732 if (num_cyl != fdchar.fdc_ncyl || spt != fdchar.fdc_secptrack ||
733 transfer_rate != fdchar.fdc_transfer_rate) {
734 /*
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).
740 *
741 * The x86 fd driver uses fdc_medium as the diameter
742 * indicator, either 3 or 5. It should not be modified.
743 */
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;
751
752 if (ioctl(fd, FDIOSCHAR, &fdchar) == -1) {
753 (void) fprintf(stderr, gettext(
754 "%s: FDIOSCHAR (density selection) failed, "),
755 myname);
756
757 /* restore the default characteristics */
758 restore_default_chars(fd, save_fdchar, save_allmap);
759 perror(nullstring);
760 exit(3);
761 }
762 if (ioctl(fd, DKIOCSAPART, &allmap) == -1) {
763 (void) fprintf(stderr,
764 gettext("%s: DKIOCSAPART failed, "),
765 myname);
766
767 /* restore the default characteristics */
768 restore_default_chars(fd, save_fdchar, save_allmap);
769
770 perror(nullstring);
771 exit(3);
772 }
773 }
774
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);
781
782 /* restore the default characteristics */
783 restore_default_chars(fd, save_fdchar, save_allmap);
784
785 exit(3);
786 }
787 }
788
789 cyl_size = 2 * sec_size * spt;
790
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);
799
800 exit(4);
801 }
802 (void) memset(ibuf1, (uchar_t)0xA5, cyl_size);
803
804 if (x_flag)
805 goto skipformat;
806
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);
815 }
816 }
817 if (!f_flag) {
818 (void) printf(
819 gettext("Press return to start formatting floppy."));
820 while (getchar() != '\n')
821 ;
822 }
823 /*
824 * for those systems that support this ioctl, they will
825 * return whether or not a diskette is in the drive.
826 */
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);
832
833 /* restore the default characteristics */
834 restore_default_chars(fd, save_fdchar, save_allmap);
835
836 exit(4);
837 }
838 if (chgd & FDGC_CURWPROT) {
839 (void) fprintf(stderr,
840 gettext("%s: \"%s\" is write protected\n"),
841 myname, real_name);
842
843 /* restore the default characteristics */
844 restore_default_chars(fd, save_fdchar, save_allmap);
845
846 exit(1);
847 }
848 }
849
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);
855
856 /* restore the default characteristics */
857 restore_default_chars(fd, save_fdchar, save_allmap);
858
859 exit(3);
860 }
861 /*
862 * do the format, a track at a time
863 */
864 for (cyl = 0; cyl < (z_flag ? 1 : (int)num_cyl); cyl++) {
865 /*
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.
870 */
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);
876
877 /* restore the default characteristics */
878 restore_default_chars(fd, save_fdchar, save_allmap);
879
880 exit(3);
881 }
882 /*
883 * Assume that the fd driver has issued a SENSE_INT
884 * command to complete the seek operation.
885 */
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;
893 }
894 /*
895 * ASSUME the fd driver is going to set drive-select
896 * bits in the second command byte
897 */
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;
904
905 if (ioctl(fd, FDRAW, &fdr_form) == -1) {
906
907
908 (void) fprintf(stderr, gettext(
909 "%s: format of cyl %d head %d failed\n"),
910 myname, cyl, hd);
911
912 /* restore the default characteristics */
913 restore_default_chars(fd, save_fdchar,
914 save_allmap);
915
916 exit(3);
917 }
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);
924
925 /*
926 * restore the default
927 * characteristics
928 */
929 restore_default_chars(fd, save_fdchar,
930 save_allmap);
931
932 exit(3);
933 }
934 (void) fprintf(stderr, gettext(
935 "%s: format of cyl %d head %d failed\n"),
936 myname, cyl, hd);
937
938 /* restore the default characteristics */
939 restore_default_chars(fd, save_fdchar,
940 save_allmap);
941
942 exit(3);
943 }
944
945 }
946
947 /*
948 * do a quick verify
949 */
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);
959
960 exit(3);
961 }
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);
976
977 exit(3);
978 }
979 } else
980 if (!q_flag)
981 (void) printf(".");
982 if (!q_flag)
983 (void) fflush(stdout);
984 }
985 if (!q_flag)
986 (void) printf("\n");
987 skipformat:
988 if (v_flag) {
989 /*
990 * do a write & read verify of the entire diskette
991 */
992 if (!q_flag && x_flag)
993 (void) printf(gettext("Verifying %s in %s\n"),
994 capacity, real_name);
995
996 for (cyl = 0; cyl < (int)num_cyl; cyl++) {
997
998 int val;
999 if ((val = verify(fd, 2 * spt * cyl, cyl_size)) != 0) {
1000 perror(nullstring);
1001
1002 /* restore the default characteristics */
1003 restore_default_chars(fd, save_fdchar,
1004 save_allmap);
1005
1006 exit(val);
1007
1008 }
1009 /* write some progress msg as */
1010 /* each cylinder is done. */
1011 if (!q_flag)
1012 (void) printf(gettext("v"));
1013 (void) fflush(stdout);
1014 }
1015 if (!q_flag)
1016 (void) printf("\n");
1017 }
1018
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);
1025
1026 exit(3);
1027 }
1028
1029 }
1030
1031
1032 /*
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.
1038 */
1039
1040 static void
restore_default_chars(int fd,struct fd_char save_fdchar,struct dk_allmap save_allmap)1041 restore_default_chars(int fd,
1042 struct fd_char save_fdchar,
1043 struct dk_allmap save_allmap)
1044 {
1045
1046
1047 /*
1048 * When this function is called, fdformat is failing anyways,
1049 * so the errors are not processed.
1050 */
1051
1052 (void) ioctl(fd, FDIOSCHAR, &save_fdchar);
1053
1054 (void) ioctl(fd, DKIOCSAPART, &save_allmap);
1055
1056 /*
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.
1062 */
1063 (void) ioctl(fd, FDDEFGEOCHAR, NULL);
1064
1065 }
1066
1067 /*
1068 * See if any partitions on the device are mounted. Return 1 if a partition is
1069 * mounted. Return 0 otherwise.
1070 */
1071 static int
check_mount()1072 check_mount()
1073 {
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;
1082
1083 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1084 perror(MNTTAB);
1085 exit(3);
1086 }
1087
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;
1093 }
1094
1095 (void) strcpy(raw_device, "/dev/r");
1096 (void) strcat(raw_device, mp->mnt_special + strlen("/dev/"));
1097
1098 /*
1099 * Attempt to open the device. If it fails, skip it.
1100 */
1101 if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
1102 continue;
1103 }
1104
1105 /*
1106 * Must be a character device
1107 */
1108 if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
1109 (void) close(mfd);
1110 continue;
1111 }
1112 /*
1113 * Attempt to read the configuration info on the disk.
1114 */
1115 if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) {
1116 (void) close(mfd);
1117 continue;
1118 }
1119 /*
1120 * Finished with the opened device
1121 */
1122 (void) close(mfd);
1123
1124 /*
1125 * If it's not the disk we're interested in, it doesn't apply.
1126 */
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;
1131 }
1132 /*
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.
1136 */
1137
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;
1144 }
1145 } else {
1146 (void) fprintf(stderr,
1147 gettext("%s: %s is mounted (use -U flag)\n"),
1148 myname, mp->mnt_special);
1149 found = 1;
1150 }
1151 }
1152 return (found);
1153 }
1154
1155 static void
usage(char * str)1156 usage(char *str)
1157 {
1158 char *real_name, *alias_name;
1159
1160 if ((real_name = media_findname("floppy")) == NULL) {
1161 if ((alias_name = _media_oldaliases("floppy")) != NULL)
1162 real_name = media_findname(alias_name);
1163 }
1164
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);
1171
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"));
1218
1219 (void) printf(gettext(
1220 " devname defaults to '%s'\n"),
1221 real_name ? real_name : gettext("no available default device"));
1222
1223 exit(1);
1224
1225 }
1226
1227
1228 static int
verify(int fd,int blk,int len)1229 verify(int fd, int blk, int len)
1230 {
1231 off_t off;
1232 char *nullstring = "";
1233
1234 off = (off_t)(blk * (m_flag ? 1024 : 512));
1235
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);
1243 }
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);
1257 }
1258
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);
1267 }
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);
1275 }
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);
1282 }
1283 return (0);
1284 }
1285
1286 /*
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
1291 */
1292 static void
write_SunOS_label(int fd,char * volname,struct vtoc * fd_vtoc)1293 write_SunOS_label(int fd, char *volname, struct vtoc *fd_vtoc)
1294 {
1295 char *nullstring = "";
1296
1297 fd_vtoc->v_sanity = VTOC_SANE;
1298
1299 /*
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.
1303 */
1304 fd_vtoc->v_sectorsz = DEV_BSIZE;
1305
1306 (void) strncpy(fd_vtoc->v_volume, volname, sizeof (fd_vtoc->v_volume));
1307
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);
1314 }
1315
1316 }
1317
1318
1319 /*
1320 * MS-DOS Disk layout:
1321 *
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 * |___________________|
1336 */
1337
1338 /*
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.
1342 *
1343 * The BIOS parameter block contains the right values
1344 * for the 3.5" high-density 1.44MB floppy format.
1345 *
1346 */
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
1414 };
1415
1416 static int
valid_DOS_boot(char * bootfile,uchar_t ** bootloadp)1417 valid_DOS_boot(char *bootfile, uchar_t **bootloadp)
1418 {
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 = "";
1426
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);
1431 }
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);
1437 }
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);
1443 }
1444
1445 /* switch to user to access the boot file */
1446 (void) seteuid(getuid());
1447
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);
1453 }
1454
1455 /* restore effective id */
1456 (void) seteuid(euid);
1457
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);
1464 }
1465
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;
1473 }
1474
1475 (void) close(bfd);
1476 *bootloadp = bootloader;
1477 return (boot_size);
1478 }
1479
1480
1481 static void
write_DOS_label(int fd,uchar_t * bootloadr,int bootlen,char * altbootname,char * doslabel,struct bios_param_blk * bpb,int rdirsec)1482 write_DOS_label(int fd, uchar_t *bootloadr, int bootlen, char *altbootname,
1483 char *doslabel, struct bios_param_blk *bpb, int rdirsec)
1484 {
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 = "";
1492
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;
1503
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;
1509
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;
1519
1520 bpb->b_rdirents[0] = getlobyte(rdirsec);
1521 bpb->b_rdirents[1] = gethibyte(rdirsec);
1522
1523 (void) memcpy((char *)(bootloadr + 0x0B), (char *)bpb,
1524 sizeof (struct bios_param_blk));
1525
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);
1531 }
1532 bootloadr += 512;
1533 bootlen -= 512;
1534
1535 fat_bsize = 512 * bpb->b_fatsec[0];
1536 fat_rdir = (uchar_t *)malloc(fat_bsize);
1537 (void) memset(fat_rdir, (char)0, fat_bsize);
1538
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++)
1546 /*
1547 * pre-allocate any clusters used by boot loader if
1548 * loader will occupy more than 1 sector
1549 */
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;
1558 }
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);
1566 }
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;
1574
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]);
1579 }
1580 for (; i < 11; i++) {
1581 fat_rdir[i] = ' ';
1582 }
1583 fat_rdir[0x0B] = 0x28;
1584 (void) gettimeofday(&tv, (struct timezone *)0);
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);
1597
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);
1604 }
1605 i = 1;
1606 } else {
1607 i = 0;
1608 }
1609 (void) memset(fat_rdir, (char)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);
1617 }
1618 }
1619 /*
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).
1624 */
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);
1630 }
1631 }
1632
1633 static void
write_NEC_DOS_label(int fd,char * doslabel)1634 write_NEC_DOS_label(int fd, char *doslabel)
1635 {
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 = "";
1643
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
1648 };
1649
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
1654
1655 };
1656
1657
1658 (void) memset(bootsec_NEC, (char)0, 1024);
1659
1660 (void) memcpy(&bootsec_NEC, &bios_param_NEC, 30);
1661
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);
1669 }
1670 (void) memset(fat_rdir, (char)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;
1687 }
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);
1694 }
1695 }
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;
1707
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]);
1712 }
1713 for (; i < 11; i++) {
1714 fat_rdir[i] = ' ';
1715 }
1716 fat_rdir[0xb] = 0x28;
1717 (void) gettimeofday(&tv, (struct timezone *)0);
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);
1730
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);
1737 }
1738 (void) memset(fat_rdir, (char)0, 512);
1739 i = 1;
1740 } else {
1741 i = 0;
1742
1743 while (m < 1024) {
1744 (void) memcpy(&fat_rdir[m], &fatdir, 31);
1745 m = m + 32;
1746 }
1747 }
1748 for (; i < (int)rdirsec; ++i) {
1749
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);
1756 }
1757 }
1758 }
1759