xref: /titanic_44/usr/src/cmd/fdformat/fdformat.c (revision 49b225e1cfa7bbf7738d4df0a03f18e3283426eb)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1991-2002 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * fdformat program - formats floppy disks, and then adds a label to them
31  *
32  *	 ****Warning, Warning, Warning, Warning*****
33  *	 This program runs suid root.  This change was made to
34  *	 allow it to umount a file system if it's mounted.
35  */
36 
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <memory.h>
43 #include <errno.h>
44 #include <locale.h>
45 #include <libintl.h>
46 #include <volmgt.h>
47 #include <sys/isa_defs.h>
48 #include <sys/ioccom.h>
49 #include <sys/types.h>
50 #include <sys/time.h>
51 #include <sys/file.h>
52 #include <sys/dklabel.h>
53 #include <sys/ioctl.h>
54 #include <sys/dkio.h>
55 #include <sys/fdio.h>
56 #include <sys/stat.h>
57 #include <sys/vtoc.h>
58 #include <sys/mnttab.h>
59 
60 /* DEFINES */
61 #if defined(_BIG_ENDIAN)
62 #define	getbyte(A, N)	(((unsigned char *)(&(A)))[N])
63 #define	htols(S)	((getbyte(S, 1) <<8) | getbyte(S, 0))
64 #elif defined(_LITTLE_ENDIAN)
65 #define	htols(S)	(*((ushort_t *)(&(S))))
66 #else
67 #error One of _BIG_ENDIAN or LITTLE_ENDIAN must be defined
68 #endif
69 
70 #define	getlobyte(A)	(A & 0xFF)
71 #define	gethibyte(A)	(A >> 8 & 0xFF)
72 #define	uppercase(c)	((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
73 #define	min(a, b)	((a) < (b) ? (a) : (b))
74 
75 /*
76  * These defines are from the PCMCIA memory driver driver
77  *	header files (pcramio.h/pcramvar.h) and they are in
78  *	the Platform Specific (PS) train.
79  */
80 #ifndef PCRAM_PROBESIZE
81 #define	PCRAMIOC	('P' << 8)
82 #define	PCRAM_PROBESIZE (PCRAMIOC|22)   /* Probe memory card size */
83 #endif
84 
85 /* FORMAT PATTERNS */
86 #define		PATTERN_1	0x55;
87 #define		PATTERN_2	0xaa;
88 #define		PATTERN_3	0xff;
89 #define		PATTERN_4	0x00;
90 
91 /* UNINITIALIZED DATA */
92 static 	struct fd_char 		fdchar;
93 static 	struct dk_geom 		fdgeom;
94 static 	struct dk_allmap 	allmap;
95 static 	struct dk_cinfo 	dkinfo;
96 static  struct dk_geom  	dkg;
97 
98 /* EXTERN */
99 extern char	*optarg;
100 extern int	optind;
101 
102 /* for verify buffers */
103 static uchar_t	*ibuf1;
104 static uchar_t	*obuf;
105 
106 static char	*myname;
107 
108 static 	int	fd_debug = 1;	/* 1 if debug XXX */
109 static 	int	b_flag = 0;	/* install a volume label to the diskette */
110 static 	int	d_flag = 0;	/* format the diskette in dos format */
111 static 	int	D_flag = 0;	/* double (aka low) density flag */
112 static 	int	e_flag = 0;	/* "eject" diskette when done (if supported) */
113 static 	int	E_flag = 0;	/* extended density */
114 static 	int	f_flag = 0;	/* "force" (no confirmation before start) */
115 static 	int	H_flag = 0;	/* high density */
116 static 	int	m_flag = 0;	/* medium density */
117 static 	int	n_flag = 0;	/* format the diskette in NEC-DOS format */
118 static 	int	q_flag = 0;	/* quiet format flag */
119 static 	int	U_flag = 0;	/* automatically unmount if it's mounted */
120 static 	int	v_flag = 0;	/* verify format/diskette flag */
121 static 	int	x_flag = 0;	/* skip the format, only install SunOS label */
122 				/* or DOS file system */
123 static 	int	z_flag = 0;	/* debugging only, setting partial formatting */
124 static 	int	interleave = 1;	/* interleave factor */
125 static	int	pcmcia = 0;	/* 1 if media is a pcmcia card */
126 
127 static	uid_t	euid = 0;	/* stores effective user id */
128 
129 struct bios_param_blk {
130 	uchar_t	b_bps[2];		/* bytes per sector */
131 	uchar_t	b_spcl;			/* sectors per alloction unit */
132 	uchar_t	b_res_sec[2];		/* reserved sectors, starting at 0 */
133 	uchar_t	b_nfat;			/* number of FATs */
134 	uchar_t	b_rdirents[2];		/* number of root directory entries */
135 	uchar_t	b_totalsec[2];		/* total sectors in logical image */
136 	char	b_mediadescriptor;	/* media descriptor byte */
137 	uchar_t	b_fatsec[2];		/* number of sectors per FAT */
138 	uchar_t	b_spt[2];		/* sectors per track */
139 	uchar_t	b_nhead[2];		/* number of heads */
140 	uchar_t	b_hiddensec[2];		/* number of hidden sectors */
141 };
142 
143 /*
144  * ON-private functions from libvolmgt
145  */
146 char	*_media_oldaliases(char *name);
147 int	_dev_mounted(char *path);
148 int	_dev_unmount(char *path);
149 
150 /*
151  * local functions
152  */
153 static void	usage(char *);
154 static int	verify(int, int, int);
155 static void	write_SunOS_label(int, char *, struct vtoc *);
156 static int	valid_DOS_boot(char *, uchar_t **);
157 static void	write_DOS_label(int, uchar_t *, int, char *, char *,
158 			struct  bios_param_blk *, int);
159 static void	write_NEC_DOS_label(int, char *);
160 static int	check_mount();
161 static void	format_diskette(int, char *, struct vtoc *,
162 				struct  bios_param_blk *,  int *);
163 static void	format_pcmcia_card(int, char *, struct vtoc *,
164 				    struct  bios_param_blk *, int *);
165 static void	restore_default_chars(int fd,
166 				    struct fd_char save_fdchar,
167 				    struct dk_allmap save_allmap);
168 
169 int
170 main(int argc, char **argv)
171 {
172 	int	altsize = 0;
173 	int	fd;
174 	int	i;
175 	uchar_t	*altboot = NULL;
176 	char	*altbootname = NULL;
177 	char	*dev_name = NULL, *real_name, *alias_name;
178 	char	*vollabel = "";
179 	struct  vtoc fd_vtoc;
180 	struct	bios_param_blk bpb;
181 	int	rdirsec;
182 	char    *nullstring = "";
183 
184 	(void) setlocale(LC_ALL, "");
185 
186 #if !defined(TEXT_DOMAIN)
187 #define	TEXT_DOMAIN	"SYS_TEST"
188 #endif
189 
190 	(void) textdomain(TEXT_DOMAIN);
191 
192 	myname = argv[0];
193 	while ((i = getopt(argc, argv, "B:b:dDeEfhHlLmMxqt:UvVZ?")) != -1) {
194 		switch (i) {
195 
196 		case 'B':
197 			altbootname = strdup(optarg);
198 			d_flag++;
199 			/* check for valid boot file now */
200 			altsize = valid_DOS_boot(altbootname, &altboot);
201 			if (!altsize) {
202 				(void) fprintf(stderr, gettext(
203 				    "%s: invalid boot loader\n"), myname);
204 				exit(1);
205 			}
206 			break;
207 
208 		case 'b':
209 			b_flag++;
210 			vollabel = strdup(optarg);
211 			break;
212 
213 		case 'd':
214 			/* format a MS-DOS diskette */
215 			d_flag++;
216 			break;
217 
218 		case 'D':
219 		case 'L':
220 		case 'l':
221 			/* format a Double density 720KB (or 360KB) disk */
222 			D_flag++;
223 			break;
224 
225 		case 'e':
226 			/* eject diskette when done */
227 			e_flag++;
228 			break;
229 
230 		case 'E':
231 			/* format an 2.88MB Extended density disk */
232 			E_flag++;
233 			break;
234 
235 		case 'f':
236 			/* don't ask for confirmation */
237 			f_flag++;
238 			break;
239 
240 		case 'H':
241 		case 'h':
242 			/* format a High density 1.2MB or 1.44MB disk */
243 			H_flag++;
244 			break;
245 
246 #if 0
247 		case 'i':
248 			/* interleave factor */
249 			interleave = atol(optarg);
250 			if (interleave <= 0) {
251 				(void) fprintf(stderr, gettext(
252 				    "%s: invalid interleave\n"), myname);
253 				exit(1);
254 			}
255 			break;
256 #endif
257 
258 		case 'M':
259 		case 'm':
260 			/* format a 3.5" HD disk to 1.2MB */
261 			m_flag++;
262 			break;
263 
264 		case 'x':
265 			/* skip format, just write label */
266 			x_flag++;
267 			break;
268 
269 		case 'q':
270 			/* quiet format */
271 			q_flag++;
272 			break;
273 
274 		case 't':
275 			/* Type of DOS formatting: NEC or MS */
276 			if (strcmp(optarg, "nec") == 0) {
277 				n_flag++;
278 			}
279 			if (strcmp(optarg, "dos") == 0) {
280 				d_flag++;
281 			}
282 			break;
283 
284 		case 'U':
285 			/* umount filesystem if mounted */
286 			U_flag++;
287 			break;
288 
289 		case 'v':
290 		case 'V':
291 			/* verify the diskette after format */
292 			v_flag++;
293 			break;
294 
295 		case 'Z':
296 			/* for debug only, format cyl 0 only */
297 			if (!fd_debug) {
298 				usage(gettext("unknown argument"));
299 				/* NOTREACHED */
300 			}
301 			(void) printf(gettext("\nFormat cyl Zero only\n"));
302 			z_flag++;
303 			break;
304 
305 		default:
306 			usage(" ");
307 			/* NOTREACHED */
308 		}
309 	}
310 
311 	if (optind < argc -1) {
312 		usage(gettext("more than one device name argument"));
313 		/* NOTREACHED */
314 	}
315 	if (optind == argc -1) {
316 		dev_name = argv[optind];
317 	}
318 	if (D_flag && H_flag) {
319 		usage(gettext("switches -D, -L and -H incompatible"));
320 		/* NOTREACHED */
321 	}
322 	if (D_flag && E_flag) {
323 		usage(gettext("switches -D, -L and -E incompatible"));
324 		/* NOTREACHED */
325 	}
326 	if (H_flag && E_flag) {
327 		usage(gettext("switches -H and -E incompatible"));
328 		/* NOTREACHED */
329 	}
330 	if (n_flag && d_flag) {
331 		usage(gettext("switches nec and dos incompatible"));
332 		/* NOTREACHED */
333 	}
334 	if (n_flag && !m_flag) {
335 		usage(gettext("switch -M required for NEC-DOS"));
336 		/* NOTREACHED */
337 	}
338 	if (D_flag && m_flag) {
339 		usage(gettext("switches -D, -L and -M incompatible"));
340 		/* NOTREACHED */
341 	}
342 	if (d_flag && m_flag) {
343 		usage(gettext("switches -d and -M incompatible"));
344 		/* NOTREACHED */
345 	}
346 
347 	if (dev_name == NULL)
348 		dev_name = "floppy";
349 
350 	if ((real_name = media_findname(dev_name)) == NULL) {
351 		if ((alias_name = _media_oldaliases(dev_name)) != NULL)
352 			real_name = media_findname(alias_name);
353 		if (real_name == NULL) {
354 			(void) fprintf(stderr,
355 gettext("No such volume (or no media in specified device): %s\n"),
356 					dev_name);
357 			exit(1);
358 		}
359 	}
360 
361 	/*
362 	 * This check is required because program runs suid root.
363 	 */
364 	if (access(real_name, R_OK|W_OK) < 0) {
365 		perror(real_name);
366 		exit(1);
367 	}
368 
369 	/* store callers euid */
370 
371 	euid = geteuid();
372 
373 	/*
374 	 * See if the given device name is mounted.  If this check isn't done
375 	 * before the open, the open will fail.  The failed open will not
376 	 * indicate that the device is mounted, only that it's busy
377 	 */
378 	if (_dev_mounted(real_name)) {
379 		if (U_flag) {
380 			if (!_dev_unmount(real_name)) {
381 				(void) fprintf(stderr,
382 					gettext("%s: umount of %s failed\n"),
383 				myname, real_name);
384 				exit(1);
385 			}
386 		} else {
387 			(void) fprintf(stderr,
388 				gettext("%s: %s is mounted (use -U flag)\n"),
389 				myname, real_name);
390 			exit(1);
391 		}
392 	}
393 
394 	/* Set to user access permissions to open file */
395 	(void) seteuid(getuid());
396 
397 	if ((fd = open(real_name, O_NDELAY | O_RDWR | O_EXCL)) == -1) {
398 		if (errno == EROFS) {
399 			(void) fprintf(stderr,
400 			    gettext("%s: \"%s\" is write protected\n"),
401 			    myname, real_name);
402 			exit(1);
403 		}
404 		/* XXX ought to check for "drive not installed", etc. */
405 		(void) fprintf(stderr, gettext("%s: could not open \"%s\": "),
406 		    myname, real_name);
407 		perror(nullstring);
408 		exit(1);
409 	}
410 
411 	/* restore effective id */
412 	(void) seteuid(euid);
413 
414 	if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
415 		(void) fprintf(stderr,
416 			gettext("%s: DKIOCINFO failed, "), myname);
417 		perror(nullstring);
418 		exit(3);
419 	}
420 
421 	/* See if there are any mounted partitions. */
422 	if (check_mount() != 0) {
423 			exit(3);
424 	}
425 
426 	/* See if the device is a PCMCIA card */
427 	if (dkinfo.dki_ctype == DKC_PCMCIA_MEM)
428 		pcmcia = 1;
429 
430 
431 	/*
432 	 * The fd_vtoc, bpb, and rdirsec structures will be
433 	 * partially filled in by format_pcmcia_card() or
434 	 * format_diskette().  This was done so that write_DOS_label(),
435 	 * write_SunOS_label(), and write_NEC_DOS_label() could be
436 	 * device independent.  If a new device needs to be added to
437 	 * fdformat, a new format function like format_diskette should
438 	 * be added.  This function should fill in fd_vtoc, bpb, and
439 	 * rdirsec with device dependent information.
440 	 */
441 	(void) memset((void *)&fd_vtoc, (char)0, sizeof (struct vtoc));
442 	(void) memset((void *)&bpb, (char)0, sizeof (struct  bios_param_blk));
443 
444 	if (pcmcia)
445 		format_pcmcia_card(fd, real_name, &fd_vtoc, &bpb, &rdirsec);
446 	else
447 		format_diskette(fd, real_name, &fd_vtoc, &bpb, &rdirsec);
448 
449 	if (d_flag)
450 		write_DOS_label(fd, altboot, altsize, altbootname,
451 				vollabel, &bpb, rdirsec);
452 	else if (n_flag)
453 		write_NEC_DOS_label(fd, vollabel);
454 	else
455 		write_SunOS_label(fd, vollabel, &fd_vtoc);
456 
457 	if (e_flag)
458 		/* eject media if possible */
459 		if (ioctl(fd, FDEJECT, 0)) {
460 			(void) fprintf(stderr,
461 			    gettext("%s: could not eject diskette, "), myname);
462 			perror(nullstring);
463 			exit(3);
464 		}
465 
466 	return (0);
467 }
468 
469 /*
470  * Inputs: file descriptor for the device and the device name.
471  * Oututs: the fd_vtoc will be partially filled in with the
472  *         device specific information such as partition
473  *         information and ascillabel. bpb and rdirsec will
474  *	   also be partially filled in with device specific information
475  */
476 void
477 format_diskette(int fd, char *real_name, struct vtoc *fd_vtoc,
478 				struct  bios_param_blk *bpb, int *rdirsec)
479 {
480 	int	transfer_rate = 1000;   /* transfer rate code */
481 	int	sec_size = 512;		/* sector size */
482 	uchar_t	gap = 0x54;		/* format gap size */
483 	uchar_t *fbuf, *p;
484 	char    *capacity = NULL;
485 	int	cyl_size;
486 	int	i;
487 	int	chgd;			/* for testing disk changed/present */
488 	int	cyl, hd;
489 	int	size_of_part, size_of_dev;
490 	int	spt = 36;		/* sectors per track */
491 	int	drive_size;
492 	uchar_t	num_cyl = 80;		/*  max number of cylinders */
493 	char    *nullstring = "";
494 	struct fd_char save_fdchar;	/* original diskette characteristics */
495 	struct dk_allmap save_allmap;	/* original diskette partition info */
496 
497 
498 	/* FDIOCMD ioctl command structure for formatting */
499 	/* LINTED */
500 	struct fd_cmd fcmd_fmt = {
501 		FDCMD_FORMAT_TRACK,
502 		0xA5,
503 		0,
504 		1,
505 		0,
506 		0
507 	};
508 
509 	/* FDRAW ioctl command structures for seeking and formatting */
510 	struct fd_raw fdr_seek = {
511 		FDRAW_SEEK, 0, 0, 0, 0, 0, 0, 0, 0, 0,
512 		3,
513 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
514 		0,
515 		0
516 	};
517 
518 	struct fd_raw fdr_form = {
519 		0x4D, 0, 2, 0, 0x54, (char)0xA5, 0, 0, 0, 0,
520 		6,
521 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
522 		0,	/* nbytes */
523 		0	/* addr */
524 	};
525 
526 
527 	/*
528 	 * restore drive to default geometry and characteristics
529 	 * (probably not implemented on sparc)
530 	 */
531 	(void) ioctl(fd, FDDEFGEOCHAR, NULL);
532 
533 	/* get the default partititon maps */
534 	if (ioctl(fd, DKIOCGAPART, &allmap) == -1) {
535 		(void) fprintf(stderr,
536 		    gettext("%s: DKIOCGAPART failed, "), myname);
537 		perror(nullstring);
538 		exit(3);
539 	}
540 
541 	/* Save the original default partition maps */
542 	save_allmap = allmap;
543 
544 	/* find out the characteristics of the default diskette */
545 	if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) {
546 		(void) fprintf(stderr,
547 		    gettext("%s: FDIOGCHAR failed, "), myname);
548 		perror(nullstring);
549 		exit(3);
550 	}
551 
552 	/* Save the original characteristics of the default diskette */
553 	save_fdchar = fdchar;
554 
555 	/*
556 	 * The user may only format the entire diskette.
557 	 * formatting partion a or b is not allowed
558 	 */
559 	size_of_part = allmap.dka_map[dkinfo.dki_partition].dkl_nblk
560 			* DEV_BSIZE;
561 	size_of_dev = fdchar.fdc_ncyl * fdchar.fdc_nhead
562 			* fdchar.fdc_secptrack * fdchar.fdc_sec_size;
563 
564 	if (size_of_part != size_of_dev) {
565 		(void) fprintf(stderr,
566 			/*CSTYLED*/
567 			gettext("%s: The entire diskette must be formatted. Invalid device name.\n"),
568 			myname);
569 		exit(3);
570 	}
571 
572 
573 	/* find out the geometry of the drive */
574 	if (ioctl(fd, DKIOCGGEOM, &fdgeom) == -1) {
575 		(void) fprintf(stderr,
576 		    gettext("%s: DKIOCGGEOM failed, "), myname);
577 		perror(nullstring);
578 		exit(3);
579 	}
580 
581 #ifdef sparc
582 	fdchar.fdc_medium = 3;
583 #endif
584 	if (fdchar.fdc_medium == 5)
585 		drive_size = 5;
586 	else
587 		drive_size = 3;
588 
589 	/*
590 	 * set proper density flag in case we're formating to default
591 	 * characteristics because no density switch was input
592 	 */
593 	if ((E_flag | H_flag | D_flag | m_flag) == 0) {
594 		switch (fdchar.fdc_transfer_rate) {
595 		case 1000:
596 			/* assumes only ED uses 1.0 MB/sec */
597 			E_flag++;
598 			break;
599 		case 500:
600 		default:
601 			/*
602 			 * default to HD even though High density and
603 			 * "medium" density both use 500 KB/sec
604 			 */
605 			H_flag++;
606 			break;
607 #ifndef sparc
608 		case 250:
609 			/* assumes only DD uses 250 KB/sec */
610 			D_flag++;
611 			break;
612 #endif
613 		}
614 	}
615 
616 	if (H_flag) {
617 		transfer_rate = 500;
618 		num_cyl = 80;
619 		sec_size = 512;
620 		if (drive_size == 5) {
621 			(void) strcpy(fd_vtoc->v_asciilabel,
622 				"5.25\" floppy cyl 80 alt 0 hd 2 sec 15");
623 			spt = 15;
624 			capacity = "1.2 MB";
625 		} else {
626 			(void) strcpy(fd_vtoc->v_asciilabel,
627 				"3.5\" floppy cyl 80 alt 0 hd 2 sec 18");
628 			spt = 18;
629 			capacity = "1.44 MB";
630 		}
631 		gap = 0x54;
632 	} else if (D_flag) {
633 		transfer_rate = 250;
634 		if (drive_size == 5) {
635 			(void) strcpy(fd_vtoc->v_asciilabel,
636 				"5.25\" floppy cyl 40 alt 0 hd 2 sec 9");
637 			if (fdchar.fdc_transfer_rate == 500) {
638 				/*
639 				 * formatting a 360KB DD diskette in
640 				 * a 1.2MB drive is not a good idea
641 				 */
642 				transfer_rate = 300;
643 				fdchar.fdc_steps = 2;
644 			}
645 			num_cyl = 40;
646 			gap = 0x50;
647 			capacity = "360 KB";
648 		} else {
649 			(void) strcpy(fd_vtoc->v_asciilabel,
650 				"3.5\" floppy cyl 80 alt 0 hd 2 sec 9");
651 			num_cyl = 80;
652 			gap = 0x54;
653 			capacity = "720 KB";
654 		}
655 		sec_size = 512;
656 		spt = 9;
657 	} else if (m_flag) {
658 #ifdef sparc
659 		transfer_rate = 500;
660 #else
661 		/*
662 		 * 416.67 KB/sec is the effective transfer rate of a "medium"
663 		 * density diskette spun at 300 rpm instead of 360 rpm
664 		 */
665 		transfer_rate = 417;
666 #endif
667 		(void) strcpy(fd_vtoc->v_asciilabel,
668 				"3.5\" floppy cyl 77 alt 0 hd 2 sec 8");
669 		num_cyl = 77;
670 		sec_size = 1024;
671 		spt = 8;
672 		gap = 0x74;
673 		capacity = "1.2 MB";
674 	} else if (E_flag) {
675 		(void) strcpy(fd_vtoc->v_asciilabel,
676 				"3.5\" floppy cyl 80 alt 0 hd 2 sec 36");
677 		transfer_rate = 1000;
678 		num_cyl = 80;
679 		sec_size = 512;
680 		spt = 36;
681 		gap = 0x54;
682 		capacity = "2.88 MB";
683 	}
684 	/*
685 	 * Medium density diskettes have 1024 byte blocks.  The dk_map
686 	 * structure in dklabel.h assumes the blocks size is DEVBSIZE (512)
687 	 * bytes.  The dkl_nblk field is in terms of DEVBSIZE byte blocks
688 	 * while the spt variable is in terms of the true block size on
689 	 * the diskette.
690 	 */
691 	if (allmap.dka_map[2].dkl_nblk !=
692 			(2 * num_cyl * spt * (m_flag ? 2 : 1))) {
693 		allmap.dka_map[1].dkl_cylno = num_cyl - 1;
694 		allmap.dka_map[0].dkl_nblk = 2 * (num_cyl - 1) * spt *
695 							(m_flag ? 2 : 1);
696 		allmap.dka_map[1].dkl_nblk = 2 * spt * (m_flag ? 2 : 1);
697 		allmap.dka_map[2].dkl_nblk = 2 * num_cyl * spt *
698 							(m_flag ? 2 : 1);
699 		if (allmap.dka_map[3].dkl_nblk)
700 			allmap.dka_map[3].dkl_nblk = 2 * (num_cyl - 1) * spt *
701 							(m_flag ? 2 : 1);
702 		if (allmap.dka_map[4].dkl_nblk)
703 			allmap.dka_map[4].dkl_nblk =
704 					2 * spt * (m_flag ? 2 : 1);
705 	}
706 
707 
708 	/* initialize the vtoc structure */
709 	fd_vtoc->v_nparts = 3;
710 
711 	fd_vtoc->v_part[0].p_start = 0;
712 	fd_vtoc->v_part[0].p_size = ((num_cyl - 1) * 2 * spt *
713 							(m_flag ? 2 : 1));
714 	fd_vtoc->v_part[1].p_start = ((num_cyl - 1) * 2 * spt *
715 							(m_flag ? 2 : 1));
716 	fd_vtoc->v_part[1].p_size = 2 * spt * (m_flag ? 2 : 1);
717 
718 	fd_vtoc->v_part[2].p_start = 0;
719 	fd_vtoc->v_part[2].p_size = num_cyl * 2 * spt * (m_flag ? 2 : 1);
720 
721 	/* initialize the bios parameter blockstructure */
722 	bpb->b_nfat = 2;
723 	if (E_flag && drive_size == 3) {
724 		bpb->b_spcl = 2;
725 		*rdirsec = (ushort_t)240;
726 		bpb->b_mediadescriptor = (char)0xF0;
727 		bpb->b_fatsec[0] = 9;
728 		bpb->b_fatsec[1] = 0;
729 	} else if (H_flag) {
730 		if (drive_size == 5) {
731 			bpb->b_spcl = 1;
732 			*rdirsec = 224;
733 			bpb->b_mediadescriptor = (char)0xF9;
734 			bpb->b_fatsec[0] = 7;
735 			bpb->b_fatsec[1] = 0;
736 		} else {
737 			bpb->b_spcl = 1;
738 			*rdirsec = 224;
739 			bpb->b_mediadescriptor = (char)0xF0;
740 			bpb->b_fatsec[0] = 9;
741 			bpb->b_fatsec[1] = 0;
742 		}
743 	} else if (drive_size == 5) {
744 		bpb->b_spcl = 2;
745 		*rdirsec = 112;
746 		bpb->b_mediadescriptor = (char)0xFD;
747 		bpb->b_fatsec[0] = 2;
748 		bpb->b_fatsec[1] = 0;
749 	} else if (drive_size == 3) {
750 		bpb->b_spcl = 2;
751 		*rdirsec = 112;
752 		bpb->b_mediadescriptor = (char)0xF9;
753 		bpb->b_fatsec[0] = 3;
754 		bpb->b_fatsec[1] = 0;
755 	}
756 
757 
758 
759 #ifndef sparc
760 	if (num_cyl > fdchar.fdc_ncyl || spt > fdchar.fdc_secptrack ||
761 	    transfer_rate > fdchar.fdc_transfer_rate) {
762 		(void) fprintf(stderr,
763 		    gettext("%s: drive not capable of requested density, "),
764 		    myname);
765 		perror(nullstring);
766 		exit(3);
767 	}
768 #endif
769 	if (num_cyl != fdchar.fdc_ncyl || spt != fdchar.fdc_secptrack ||
770 	    transfer_rate != fdchar.fdc_transfer_rate) {
771 		/*
772 		 * -- CAUTION --
773 		 * The SPARC fd driver is using a non-zero value in
774 		 * fdc_medium to indicate the 360 rpm, 77 track,
775 		 * 9 sectors/track, 1024 bytes/sector mode of operation
776 		 * (similar to an 8", DS/DD, 1.2 MB floppy).
777 		 *
778 		 * The x86 fd driver uses fdc_medium as the diameter
779 		 * indicator, either 3 or 5.  It should not be modified.
780 		 */
781 #ifdef sparc
782 		fdchar.fdc_medium = m_flag ? 1 : 0;
783 #endif
784 		fdchar.fdc_transfer_rate = transfer_rate;
785 		fdchar.fdc_ncyl = num_cyl;
786 		fdchar.fdc_sec_size = sec_size;
787 		fdchar.fdc_secptrack = spt;
788 
789 		if (ioctl(fd, FDIOSCHAR, &fdchar) == -1) {
790 			(void) fprintf(stderr, gettext(
791 			    "%s: FDIOSCHAR (density selection) failed, "),
792 			    myname);
793 
794 			/* restore the default characteristics */
795 			restore_default_chars(fd, save_fdchar, save_allmap);
796 			perror(nullstring);
797 			exit(3);
798 		}
799 		if (ioctl(fd, DKIOCSAPART, &allmap) == -1) {
800 			(void) fprintf(stderr,
801 			    gettext("%s: DKIOCSAPART failed, "),
802 			    myname);
803 
804 			/* restore the default characteristics */
805 			restore_default_chars(fd, save_fdchar, save_allmap);
806 
807 			perror(nullstring);
808 			exit(3);
809 		}
810 	}
811 
812 	if (interleave != 1 && interleave != fdgeom.dkg_intrlv) {
813 		fdgeom.dkg_intrlv = interleave;
814 		if (ioctl(fd, DKIOCSGEOM, &fdgeom) == -1) {
815 			(void) fprintf(stderr,
816 			    gettext("%s: DKIOCSGEOM failed, "), myname);
817 			perror(nullstring);
818 
819 			/* restore the default characteristics */
820 			restore_default_chars(fd, save_fdchar, save_allmap);
821 
822 			exit(3);
823 		}
824 	}
825 
826 	cyl_size = 2 * sec_size * spt;
827 
828 	if ((ibuf1 = (uchar_t *)malloc((size_t)cyl_size)) == 0 ||
829 	    (obuf = (uchar_t *)malloc((size_t)cyl_size)) == 0) {
830 		(void) fprintf(stderr,
831 		    gettext("%s: can't malloc verify buffer, "),
832 		    myname);
833 		perror(nullstring);
834 		/* restore the default characteristics */
835 		restore_default_chars(fd, save_fdchar, save_allmap);
836 
837 		exit(4);
838 	}
839 	(void) memset(ibuf1, (uchar_t)0xA5, cyl_size);
840 
841 	if (x_flag)
842 		goto skipformat;
843 
844 	if (!(q_flag && f_flag))
845 		if (interleave != 1)
846 			(void) printf(gettext(
847 "Formatting %s, %d cylinders, %d sectors per trk, interleave=%d in %s\n"),
848 			    capacity, num_cyl, spt, interleave, real_name);
849 		else
850 			(void) printf(gettext("Formatting %s in %s\n"),
851 			    capacity, real_name);
852 
853 	if (!f_flag) {
854 		(void) printf(
855 		    gettext("Press return to start formatting floppy."));
856 		while (getchar() != '\n')
857 			;
858 	}
859 	/*
860 	 * for those systems that support this ioctl, they will
861 	 * return whether or not a diskette is in the drive.
862 	 */
863 	if (ioctl(fd, FDGETCHANGE, &chgd) == 0) {
864 		if (chgd & FDGC_CURRENT) {
865 			(void) fprintf(stderr,
866 			    gettext("%s: no diskette in drive %s\n"),
867 			    myname, real_name);
868 
869 			/* restore the default characteristics */
870 			restore_default_chars(fd, save_fdchar, save_allmap);
871 
872 			exit(4);
873 		}
874 		if (chgd & FDGC_CURWPROT) {
875 			(void) fprintf(stderr,
876 			    gettext("%s: \"%s\" is write protected\n"),
877 			    myname, real_name);
878 
879 			/* restore the default characteristics */
880 			restore_default_chars(fd, save_fdchar, save_allmap);
881 
882 			exit(1);
883 		}
884 	}
885 
886 	if ((fbuf = (uchar_t *)malloc((unsigned)(4 * spt))) == 0) {
887 		(void) fprintf(stderr,
888 		    gettext("%s: can't malloc format header buffer, "),
889 		    myname);
890 		perror(nullstring);
891 
892 		/* restore the default characteristics */
893 		restore_default_chars(fd, save_fdchar, save_allmap);
894 
895 		exit(3);
896 	}
897 	/*
898 	 * do the format, a track at a time
899 	 */
900 	fcmd_fmt.fdc_blkno = 0;
901 	for (cyl = 0; cyl < (z_flag ? 1 : (int)num_cyl); cyl++) {
902 #if 0
903 		/*
904 		 * This should be the ioctl used to format the floppy.
905 		 * The device driver should do do the work,
906 		 * instead of this program mucking with a lot
907 		 * of low-level, device-dependent code.
908 		 */
909 		for (hd = 0; hd < fdchar.fdc_nhead; hd++) {
910 			if (ioctl(fd, FDIOCMD, &fcmd_fmt) == -1) {
911 				(void) fprintf(stderr,
912 			gettext("%s: format of cyl %d head %d failed\n"),
913 				    myname, cyl, hd);
914 
915 				/* restore the default characteristics */
916 				restore_default_chars(fd, save_fdchar,
917 								save_allmap);
918 				exit(3);
919 			}
920 			fcmd_fmt.fdc_blkno += spt;
921 		}
922 #else
923 		/*
924 		 * This is not the optimal ioctl to format the floppy.
925 		 * The device driver should do do the work,
926 		 * instead of this program mucking with a lot
927 		 * of low-level, device-dependent code.
928 		 */
929 		fdr_seek.fdr_cmd[2] = cyl;
930 		if (ioctl(fd, FDRAW, &fdr_seek) == -1) {
931 			(void) fprintf(stderr,
932 			    gettext("%s: seek to cyl %d failed\n"),
933 			    myname, cyl);
934 
935 			/* restore the default characteristics */
936 			restore_default_chars(fd, save_fdchar, save_allmap);
937 
938 			exit(3);
939 		}
940 		/*
941 		 * Assume that the fd driver has issued a SENSE_INT
942 		 * command to complete the seek operation.
943 		 */
944 		for (hd = 0; hd < fdchar.fdc_nhead; hd++) {
945 			p = (uchar_t *)fbuf;
946 			for (i = 1; i <= spt; i++) {
947 				*p++ = cyl;
948 				*p++ = hd;
949 				*p++ = i; /* sector # */
950 				*p++ = (sec_size == 1024) ? 3 : 2;
951 			}
952 			/*
953 			 * ASSUME the fd driver is going to set drive-select
954 			 * bits in the second command byte
955 			 */
956 			fdr_form.fdr_cmd[1] = hd << 2;
957 			fdr_form.fdr_cmd[2] = (sec_size == 1024) ? 3 : 2;
958 			fdr_form.fdr_cmd[3] = spt;
959 			fdr_form.fdr_cmd[4] = gap;
960 			fdr_form.fdr_nbytes = 4 * spt;
961 			fdr_form.fdr_addr = (char *)fbuf;
962 
963 			if (ioctl(fd, FDRAW, &fdr_form) == -1) {
964 
965 
966 				(void) fprintf(stderr, gettext(
967 				    "%s: format of cyl %d head %d failed\n"),
968 				    myname, cyl, hd);
969 
970 				/* restore the default characteristics */
971 				restore_default_chars(fd, save_fdchar,
972 						    save_allmap);
973 
974 				exit(3);
975 			}
976 			if (fdr_form.fdr_result[0] & 0xC0) {
977 				if (fdr_form.fdr_result[1] & 0x02) {
978 					(void) fprintf(stderr, gettext(
979 					/*CSTYLED*/
980 					"%s: diskette is write protected\n"),
981 					    myname);
982 
983 					/*
984 					 * restore the default
985 					 * characteristics
986 					 */
987 					restore_default_chars(fd, save_fdchar,
988 						    save_allmap);
989 
990 					exit(3);
991 				}
992 				(void) fprintf(stderr, gettext(
993 				    "%s: format of cyl %d head %d failed\n"),
994 				    myname, cyl, hd);
995 
996 				/* restore the default characteristics */
997 				restore_default_chars(fd, save_fdchar,
998 						    save_allmap);
999 
1000 				exit(3);
1001 			}
1002 
1003 		}
1004 #endif
1005 
1006 		/*
1007 		 *  do a quick verify
1008 		 */
1009 		if (!v_flag) {
1010 			if (lseek(fd, cyl * cyl_size, 0) != cyl * cyl_size) {
1011 				(void) fprintf(stderr,
1012 				    gettext("%s: bad seek to format verify, "),
1013 				    myname);
1014 				perror(nullstring);
1015 				/* restore the default characteristics */
1016 				restore_default_chars(fd, save_fdchar,
1017 						    save_allmap);
1018 
1019 				exit(3);
1020 			}
1021 			if (read(fd, obuf, cyl_size) == cyl_size) {
1022 				/* write some progress msg */
1023 				/* when each cylinder is done. */
1024 				if (!q_flag)
1025 					(void) printf(".");
1026 			} else {
1027 				if (!q_flag)
1028 					(void) printf(gettext("e\n"));
1029 				(void) fprintf(stderr, gettext(
1030 				    "%s: can't read format data, "), myname);
1031 				perror(nullstring);
1032 				/* restore the default characteristics */
1033 				restore_default_chars(fd, save_fdchar,
1034 						    save_allmap);
1035 
1036 				exit(3);
1037 			}
1038 		} else
1039 			if (!q_flag)
1040 				(void) printf(".");
1041 		if (!q_flag)
1042 			(void) fflush(stdout);
1043 	}
1044 	if (!q_flag)
1045 		(void) printf("\n");
1046 skipformat:
1047 	if (v_flag) {
1048 		/*
1049 		 *  do a write & read verify of the entire diskette
1050 		 */
1051 		if (!q_flag && x_flag)
1052 			(void) printf(gettext("Verifying %s in %s\n"),
1053 			    capacity, real_name);
1054 
1055 		for (cyl = 0; cyl < (int)num_cyl; cyl++) {
1056 
1057 			int val;
1058 			if ((val = verify(fd, 2 * spt * cyl, cyl_size)) != 0) {
1059 				perror(nullstring);
1060 
1061 				/* restore the default characteristics */
1062 				restore_default_chars(fd, save_fdchar,
1063 						save_allmap);
1064 
1065 				exit(val);
1066 
1067 			}
1068 			/* write some progress msg as */
1069 			/* each cylinder is done. */
1070 			if (!q_flag)
1071 				(void) printf(gettext("v"));
1072 			(void) fflush(stdout);
1073 		}
1074 		if (!q_flag)
1075 			(void) printf("\n");
1076 	}
1077 
1078 	if (lseek(fd, (off_t)0, 0) != 0) {
1079 		(void) fprintf(stderr, gettext("%s: seek to blk 0 failed, "),
1080 		    myname);
1081 		perror(nullstring);
1082 		/* restore the default characteristics */
1083 		restore_default_chars(fd, save_fdchar, save_allmap);
1084 
1085 		exit(3);
1086 	}
1087 
1088 }
1089 
1090 
1091 /*
1092  * Restore the default characteristics of the floppy diskette.
1093  * Fdformat changes the characteristics in the process of formatting.
1094  * If fdformat fails while in the process of doing the format, fdformat
1095  * should clean up after itself and reset the driver back to the original
1096  * state.
1097  */
1098 
1099 static void
1100 restore_default_chars(int fd,
1101 			struct fd_char save_fdchar,
1102 			struct dk_allmap save_allmap)
1103 {
1104 
1105 
1106 	/*
1107 	 * When this function is called, fdformat is failing anyways,
1108 	 * so the errors are not processed.
1109 	 */
1110 
1111 	(void) ioctl(fd, FDIOSCHAR, &save_fdchar);
1112 
1113 	(void) ioctl(fd, DKIOCSAPART, &save_allmap);
1114 
1115 	/*
1116 	 * Before looking at the diskette's characteristics, format_diskette()
1117 	 * sets the x86 floppy driver to the default characteristics.
1118 	 * restore drive to default geometry and
1119 	 * characteristics.  This ioctl isn't implemented on
1120 	 * sparc.
1121 	 */
1122 	(void) ioctl(fd, FDDEFGEOCHAR, NULL);
1123 
1124 }
1125 
1126 /*
1127  * Inputs: file descriptor for the device and the device name.
1128  * Oututs: the fd_vtoc will be partially filled in with the
1129  * device specific information such as partition
1130  * information and ascillabel. The bpb structure and rdirsec will also be
1131  * partially filled in with device specific information.
1132  */
1133 void
1134 format_pcmcia_card(int fd, char *real_name, struct vtoc *fd_vtoc,
1135 				struct  bios_param_blk *bpb, int *rdirsec)
1136 {
1137 	int	sec_size;	/* sector size */
1138 	int	i, j;
1139 	char    wrpat;
1140 	char    wrbuf[512];
1141 	char    rdbuf[512];
1142 	enum dkio_state		state = DKIO_NONE;
1143 	int	card_size;	/* PCMCIA memory card size */
1144 	ulong_t	max_cyl;	/* max number of cylinders */
1145 	int	sec_fat;
1146 
1147 	/*
1148 	 * Using DKIOCSTATE ioctl()
1149 	 * to replace FDGETCHANGE ioctl()
1150 	 * start out with state=DKIO_NONE
1151 	 */
1152 	if (ioctl(fd, DKIOCSTATE, &state) < 0) {
1153 		(void) fprintf(stderr,
1154 			gettext("%s: DKIOCSTATE failed, "),
1155 			myname);
1156 		perror("");
1157 		exit(3);
1158 	}
1159 
1160 	if (state != DKIO_INSERTED) {
1161 			(void) fprintf(stderr,
1162 				gettext("%s: no media in %s\n"),
1163 				myname, real_name);
1164 		exit(4);
1165 	}
1166 
1167 
1168 	/* initialize the asciilabel */
1169 	(void) strcpy(fd_vtoc->v_asciilabel, "PCMCIA Memory Card");
1170 
1171 	/*  Get card cyl/head/secptrack info  */
1172 	if (ioctl(fd, DKIOCGGEOM, &dkg) == -1) {
1173 		/*
1174 		 * Card doesn't have a CIS. So, ask driver to probe
1175 		 * card size info
1176 		 */
1177 		if (ioctl(fd, PCRAM_PROBESIZE, &dkg) == -1) {
1178 			(void) fprintf(stderr,
1179 			gettext("%s: Unable to get card size information"),
1180 				myname);
1181 			perror("");
1182 			exit(3);
1183 		}
1184 	}
1185 
1186 	/* PCMCIA memory default sector size */
1187 	sec_size = DEV_BSIZE;
1188 
1189 	fdchar.fdc_sec_size	= sec_size;
1190 	fdchar.fdc_ncyl		= dkg.dkg_ncyl;
1191 	fdchar.fdc_nhead	= dkg.dkg_nhead;
1192 	fdchar.fdc_secptrack    = dkg.dkg_nsect;
1193 
1194 	max_cyl = fdchar.fdc_ncyl;
1195 
1196 	/* Initialize the vtoc information */
1197 	fd_vtoc->v_part[2].p_start = 0;
1198 	fd_vtoc->v_part[2].p_size =  max_cyl * fdchar.fdc_nhead
1199 						* fdchar.fdc_secptrack;
1200 	fd_vtoc->v_nparts = 1;
1201 
1202 	card_size = fdchar.fdc_ncyl * fdchar.fdc_nhead *
1203 		fdchar.fdc_secptrack * fdchar.fdc_sec_size;
1204 
1205 	/* Initialize the bios parameter block information */
1206 	bpb->b_nfat = 1;
1207 	if (card_size < 1048576) {
1208 		bpb->b_spcl = 2;
1209 		*rdirsec = 112;
1210 	} else {
1211 		bpb->b_spcl = 1;
1212 		*rdirsec = 224;
1213 	}
1214 	bpb->b_mediadescriptor = (char)0xf8;    /* fixed disk */
1215 
1216 	/*
1217 	 *	card_size	  sec_fat
1218 	 *  	524288			3
1219 	 * 	1048576			6
1220 	 *  	2097152			12
1221 	 */
1222 
1223 	sec_fat = (card_size * 3) / 524288;
1224 	bpb->b_fatsec[0] = sec_fat % 0x100;
1225 	bpb->b_fatsec[1] = sec_fat / 0x100;
1226 
1227 
1228 	(void) printf(gettext("Formatting %d bytes in %s\n"),
1229 			card_size, real_name);
1230 
1231 	if (!f_flag && !x_flag) {
1232 		(void) printf(gettext(
1233 		/*CSTYLED*/
1234 		"Press return to start formatting PCMCIA memory card."));
1235 		while (getchar() != '\n')
1236 			;
1237 		}
1238 
1239 
1240 	/*
1241 	 *  Skip the format, only install SunOS label or DOS file system.
1242 	 */
1243 	if (x_flag)
1244 		goto skipformat;
1245 
1246 	/*
1247 	 * First try to format only 512 bytes with four different
1248 	 * patterns.
1249 	 */
1250 	for (i = 0; i < 4; ++i) {
1251 		switch (i) {
1252 
1253 		case 0:
1254 			wrpat = (uchar_t)PATTERN_1;
1255 			break;
1256 		case 1:
1257 			wrpat = (uchar_t)PATTERN_2;
1258 			break;
1259 		case 2:
1260 			wrpat = (uchar_t)PATTERN_3;
1261 			break;
1262 		case 3:
1263 			wrpat = PATTERN_4;
1264 			break;
1265 		}
1266 
1267 		if (lseek(fd, (off_t)0, 0) != 0) {
1268 			(void) fprintf(stderr,
1269 				gettext("%s: seek to blk 0 failed, "),
1270 				myname);
1271 			perror("");
1272 			exit(3);
1273 		}
1274 
1275 		(void) memset(wrbuf, wrpat, 512);
1276 
1277 		if (write(fd, &wrbuf[0], 512) != 512) {
1278 			(void) fprintf(stderr,
1279 				/*CSTYLED*/
1280 				gettext("%s: Format Write failed, "), myname);
1281 			perror("");
1282 			exit(3);
1283 		}
1284 
1285 		if (lseek(fd, (off_t)0, 0) != 0) {
1286 			(void) fprintf(stderr,
1287 				gettext("%s: seek to blk 0 failed, "),
1288 				myname);
1289 			perror("");
1290 			exit(3);
1291 		}
1292 
1293 		if (read(fd, &rdbuf[0], 512) != 512) {
1294 			(void) fprintf(stderr,
1295 				/*CSTYLED*/
1296 				gettext("%s: Format Read failed, "), myname);
1297 			perror("");
1298 			exit(3);
1299 		}
1300 
1301 		if (memcmp(wrbuf, rdbuf, 512) != 0) {
1302 			(void) fprintf(stderr,
1303 				/*CSTYLED*/
1304 				gettext("%s: Format Compare Error, "), myname);
1305 			perror("");
1306 			exit(3);
1307 		}
1308 	}
1309 	/*
1310 	 * Then format the whole memory card with patterns
1311 	 * 0xff and 0x00 to erase the card.
1312 	 */
1313 	for (i = 0; i < 2; ++i) {
1314 
1315 		if (i == 0) {
1316 			wrpat = (uchar_t)PATTERN_3;
1317 		} else {
1318 			wrpat = PATTERN_4;
1319 		}
1320 
1321 		if (lseek(fd, (off_t)0, 0) != 0) {
1322 			(void) fprintf(stderr,
1323 				gettext("%s: seek to blk 0 failed, "),
1324 				myname);
1325 			perror("");
1326 			exit(3);
1327 		}
1328 
1329 		(void) memset(wrbuf, wrpat, 512);
1330 
1331 		for (j = 0; j < (card_size/512); ++j) {
1332 			if (write(fd, &wrbuf[0], 512) != 512) {
1333 				(void) fprintf(stderr,
1334 					/*CSTYLED*/
1335 				gettext("%s: Format Write failed, "), myname);
1336 				perror("");
1337 				exit(3);
1338 			}
1339 			/*
1340 			 * write some progress msg when each
1341 			 * 512KB block is done.
1342 			 */
1343 			if (((j%1024) == 0) && (!q_flag)) {
1344 				(void) printf(".");
1345 				(void) fflush(stdout);
1346 			}
1347 		}
1348 		/*
1349 		 * do a verify
1350 		 */
1351 
1352 		if (lseek(fd, (off_t)0, 0) != 0) {
1353 			(void) fprintf(stderr,
1354 				gettext("%s: seek to blk 0 failed, "),
1355 				myname);
1356 			perror("");
1357 			exit(3);
1358 		}
1359 
1360 		for (j = 0; j < (card_size/512); ++j) {
1361 			if (read(fd, &rdbuf[0], 512) != 512) {
1362 				(void) fprintf(stderr,
1363 					/*CSTYLED*/
1364 				gettext("%s: Format Read failed, "), myname);
1365 				perror("");
1366 				exit(3);
1367 			}
1368 			if (memcmp(wrbuf, rdbuf, 512) != 0) {
1369 				(void) fprintf(stderr,
1370 					/*CSTYLED*/
1371 				gettext("%s: Format Compare Error, "), myname);
1372 				perror("");
1373 				exit(3);
1374 			}
1375 		/*CSTYLED*/
1376 		/* write some progress msg when each 512KB block is done. */
1377 			if ((j%1024) == 0) {
1378 				if (!q_flag) {
1379 					(void) printf(".");
1380 					(void) fflush(stdout);
1381 				}
1382 			}
1383 		}
1384 	}
1385 	if (!q_flag)
1386 		(void) printf("\n");
1387 
1388 skipformat:
1389 	if (lseek(fd, (off_t)0, 0) != 0) {
1390 		(void) fprintf(stderr, gettext("%s: seek to blk 0 failed, "),
1391 			myname);
1392 		perror("");
1393 		exit(3);
1394 	}
1395 }
1396 
1397 
1398 
1399 /*
1400  * See if any partitions on the device are mounted.  Return 1 if a partition is
1401  * mounted.  Return 0 otherwise.
1402  */
1403 static int
1404 check_mount()
1405 {
1406 	FILE	*fp = NULL;
1407 	int	mfd;
1408 	struct dk_cinfo dkinfo_tmp;
1409 	struct mnttab   mnt_record;
1410 	struct mnttab   *mp = &mnt_record;
1411 	struct stat	stbuf;
1412 	char		raw_device[MAXPATHLEN];
1413 	int	found = 0;
1414 
1415 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
1416 		perror(MNTTAB);
1417 		exit(3);
1418 	}
1419 
1420 	while (getmntent(fp, mp) == 0) {
1421 		if (strstr(mp->mnt_special, "/dev/fd") == NULL &&
1422 		    strstr(mp->mnt_special, "/dev/disket") == NULL &&
1423 		    strstr(mp->mnt_special, "/dev/c") == NULL) {
1424 			continue;
1425 		}
1426 
1427 		(void) strcpy(raw_device, "/dev/r");
1428 		(void) strcat(raw_device, mp->mnt_special + strlen("/dev/"));
1429 
1430 		/*
1431 		 * Attempt to open the device.  If it fails, skip it.
1432 		 */
1433 		if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
1434 			continue;
1435 		}
1436 
1437 		/*
1438 		 * Must be a character device
1439 		 */
1440 		if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
1441 			(void) close(mfd);
1442 			continue;
1443 		}
1444 		/*
1445 		 * Attempt to read the configuration info on the disk.
1446 		 */
1447 		if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) {
1448 			(void) close(mfd);
1449 			continue;
1450 		}
1451 		/*
1452 		 * Finished with the opened device
1453 		 */
1454 		(void) close(mfd);
1455 
1456 		/*
1457 		 * If it's not the disk we're interested in, it doesn't apply.
1458 		 */
1459 		if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype ||
1460 			dkinfo.dki_cnum != dkinfo_tmp.dki_cnum ||
1461 			dkinfo.dki_unit != dkinfo_tmp.dki_unit) {
1462 				continue;
1463 		}
1464 		/*
1465 		 * It's a mount on the disk we're checking.  If we are
1466 		 * checking whole disk, then we found trouble.  We can
1467 		 * quit searching.
1468 		 */
1469 
1470 		if (U_flag) {
1471 			if (!_dev_unmount(mp->mnt_special)) {
1472 					(void) fprintf(stderr,
1473 					gettext("%s: umount of %s failed\n"),
1474 					myname, mp->mnt_special);
1475 				found = 1;
1476 			}
1477 		} else {
1478 			(void) fprintf(stderr,
1479 				gettext("%s: %s is mounted (use -U flag)\n"),
1480 				myname, mp->mnt_special);
1481 			found = 1;
1482 		}
1483 	}
1484 	return (found);
1485 }
1486 
1487 static void
1488 usage(char *str)
1489 {
1490 char    *real_name, *alias_name;
1491 
1492 	if ((real_name = media_findname("floppy")) == NULL) {
1493 		if ((alias_name = _media_oldaliases("floppy")) != NULL)
1494 			real_name = media_findname(alias_name);
1495 	}
1496 
1497 	if (str[0] != ' ')
1498 		(void) printf("%s: %s\n", myname, str);
1499 	(void) printf(gettext(
1500 /*CSTYLED*/
1501 "\n   usage: %s [-dDeEfHlLmMqUvx] [-b label] [-B file] [-t dostype] [devname]\n"),
1502 	    myname);
1503 
1504 	(void) printf(gettext(
1505 /*CSTYLED*/
1506 	    "      -b label install \"label\" on media\n"));
1507 	(void) printf(gettext(
1508 	    "      -B file  install special boot loader on MS-DOS media\n"));
1509 	(void) printf(gettext(
1510 /*CSTYLED*/
1511 	    "      -d       format MS-DOS media\n"));
1512 	(void) printf(gettext(
1513 /*CSTYLED*/
1514 "      -D       format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
1515 	(void) printf(gettext(
1516 	    "      -e       eject the media when done\n"));
1517 /*CSTYLED*/
1518 	(void) printf(gettext(
1519 /*CSTYLED*/
1520 	    "      -E       format 2.88MB (3.5\") Extended-density diskette\n"));
1521 	(void) printf(gettext(
1522 	    "      -f       \"force\" - don't wait for confirmation\n"));
1523 	(void) printf(gettext(
1524 /*CSTYLED*/
1525 "      -H       format 1.44MB (3.5\") or 1.2MB (5.25\") High-density diskette\n"));
1526 	(void) printf(gettext(
1527 /*CSTYLED*/
1528 "      -l       format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
1529 	(void) printf(gettext(
1530 /*CSTYLED*/
1531 "      -L       format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
1532 	(void) printf(gettext(
1533 	    "      -m       format 1.2MB (3.5\") Medium-density diskette\n"));
1534 	(void) printf(gettext(
1535 	    "      -M       format 1.2MB (3.5\") Medium-density diskette\n"));
1536 	(void) printf(gettext(
1537 	    "      -q       quiet\n"));
1538 	(void) printf(gettext(
1539 /*CSTYLED*/
1540 	    "      -t dos   format MS-DOS media (same as -d)\n"));
1541 	(void) printf(gettext(
1542 	    "      -t nec   format NEC-DOS media (with -M only)\n"));
1543 (void) printf(gettext(
1544 /*CSTYLED*/
1545 	    "      -U       unmount media if it's mounted\n"));
1546 	(void) printf(gettext(
1547 	    "      -v       verify each block of the media\n"));
1548 	(void) printf(gettext(
1549 "      -x       skip the format, only install SunOS or DOS label\n"));
1550 
1551 	(void) printf(gettext(
1552 	    "      devname defaults to '%s'\n"),
1553 	    real_name ? real_name : gettext("no available default device"));
1554 
1555 	exit(1);
1556 
1557 }
1558 
1559 
1560 static int
1561 verify(int fd, int blk, int len)
1562 {
1563 	off_t	off;
1564 	char    *nullstring = "";
1565 
1566 	off = (off_t)(blk * (m_flag ? 1024 : 512));
1567 
1568 	if (lseek(fd, off, 0) != off) {
1569 		if (!q_flag)
1570 			(void) printf(gettext("e\n"));
1571 		(void) fprintf(stderr,
1572 		    gettext("%s: can't seek to write verify, "), myname);
1573 		perror(nullstring);
1574 		return (4);
1575 	}
1576 	if (write(fd, ibuf1, len) != len) {
1577 		if (!q_flag)
1578 			(void) printf(gettext("e\n"));
1579 		if (blk == 0)
1580 			(void) fprintf(stderr,
1581 			    gettext("%s: check diskette density, "),
1582 			    myname);
1583 		else
1584 			(void) fprintf(stderr,
1585 			    gettext("%s: can't write verify data, "),
1586 			    myname);
1587 		perror(nullstring);
1588 		return (4);
1589 	}
1590 
1591 	if (lseek(fd, off, 0) != off) {
1592 		if (!q_flag)
1593 			(void) printf(gettext("e\n"));
1594 		(void) fprintf(stderr,
1595 		    gettext("%s: bad seek to read verify, "),
1596 		    myname);
1597 		perror(nullstring);
1598 		return (4);
1599 	}
1600 	if (read(fd, obuf, len) != len) {
1601 		if (!q_flag)
1602 			(void) printf(gettext("e\n"));
1603 		(void) fprintf(stderr,
1604 		    gettext("%s: can't read verify data, "), myname);
1605 		perror(nullstring);
1606 		return (4);
1607 	}
1608 	if (memcmp(ibuf1, obuf, len)) {
1609 		if (!q_flag)
1610 			(void) printf(gettext("e\n"));
1611 		(void) fprintf(stderr, gettext("%s: verify data failure\n"),
1612 		    myname);
1613 		return (4);
1614 	}
1615 	return (0);
1616 }
1617 
1618 /*
1619  *  write a SunOS label
1620  *  NOTE:  this function assumes fd_vtoc has been filled in with the
1621  *  device specific information such as partition information
1622  *  and the asciilabel
1623  */
1624 static void
1625 write_SunOS_label(int fd, char *volname, struct vtoc *fd_vtoc)
1626 {
1627 	char    *nullstring = "";
1628 
1629 	fd_vtoc->v_sanity = VTOC_SANE;
1630 
1631 	/*
1632 	 * The label structure is set up for DEV_BSIZE (512 byte) blocks,
1633 	 * even though a medium density diskette has 1024 byte blocks
1634 	 * See dklabel.h for more details.
1635 	 */
1636 	fd_vtoc->v_sectorsz = DEV_BSIZE;
1637 
1638 	(void) strncpy(fd_vtoc->v_volume, volname, sizeof (fd_vtoc->v_volume));
1639 
1640 	/* let the fd driver finish constructing the label and writing it */
1641 	if (ioctl(fd, DKIOCSVTOC, fd_vtoc) == -1) {
1642 		(void) fprintf(stderr,
1643 		    gettext("%s: write of SunOS label failed, "), myname);
1644 		perror(nullstring);
1645 		exit(3);
1646 	}
1647 
1648 }
1649 
1650 
1651 /*
1652  *	MS-DOS Disk layout:
1653  *
1654  *	---------------------
1655  *	|    Boot sector    |
1656  *	|-------------------|
1657  *	|   Reserved area   |
1658  *	|-------------------|
1659  *	|	FAT #1      |
1660  *	|-------------------|
1661  *	|	FAT #2      |
1662  *	|-------------------|
1663  *	|   Root directory  |
1664  *	|-------------------|
1665  *	|                   |
1666  *	|     File area     |
1667  *	|___________________|
1668  */
1669 
1670 /*
1671  * The following is a copy of MS-DOS 3.3 boot block.
1672  * It consists of the BIOS parameter block, and a disk
1673  * bootstrap program.
1674  *
1675  * The BIOS parameter block contains the right values
1676  * for the 3.5" high-density 1.44MB floppy format.
1677  *
1678  */
1679 static uchar_t bootsec[512] = {
1680 	0xeb, 0x34, 0x90,	/* 8086 short jump + displacement + NOP */
1681 	'M', 'S', 'D', 'O', 'S', '3', '.', '3',	/* OEM name & version */
1682 	0, 2, 1, 1, 0,		/* Start of BIOS parameter block */
1683 	2, 224, 0, 0x40, 0xb, 0xf0, 9, 0,
1684 	18, 0, 2, 0, 0, 0,	/* End of BIOS parameter block */
1685 	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1686 	0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12,
1687 	0x0, 0x0, 0x0, 0x0,
1688 	0x1, 0x0, 0xfa, 0x33,	/* 0x34, start of the bootstrap. */
1689 	0xc0, 0x8e, 0xd0, 0xbc, 0x0, 0x7c, 0x16, 0x7,
1690 	0xbb, 0x78, 0x0, 0x36, 0xc5, 0x37, 0x1e, 0x56,
1691 	0x16, 0x53, 0xbf, 0x2b, 0x7c, 0xb9, 0xb, 0x0,
1692 	0xfc, 0xac, 0x26, 0x80, 0x3d, 0x0, 0x74, 0x3,
1693 	0x26, 0x8a, 0x5, 0xaa, 0x8a, 0xc4, 0xe2, 0xf1,
1694 	0x6, 0x1f, 0x89, 0x47, 0x2, 0xc7, 0x7, 0x2b,
1695 	0x7c, 0xfb, 0xcd, 0x13, 0x72, 0x67, 0xa0, 0x10,
1696 	0x7c, 0x98, 0xf7, 0x26, 0x16, 0x7c, 0x3, 0x6,
1697 	0x1c, 0x7c, 0x3, 0x6, 0xe, 0x7c, 0xa3, 0x3f,
1698 	0x7c, 0xa3, 0x37, 0x7c, 0xb8, 0x20, 0x0, 0xf7,
1699 	0x26, 0x11, 0x7c, 0x8b, 0x1e, 0xb, 0x7c, 0x3,
1700 	0xc3, 0x48, 0xf7, 0xf3, 0x1, 0x6, 0x37, 0x7c,
1701 	0xbb, 0x0, 0x5, 0xa1, 0x3f, 0x7c, 0xe8, 0x9f,
1702 	0x0, 0xb8, 0x1, 0x2, 0xe8, 0xb3, 0x0, 0x72,
1703 	0x19, 0x8b, 0xfb, 0xb9, 0xb, 0x0, 0xbe, 0xd6,
1704 	0x7d, 0xf3, 0xa6, 0x75, 0xd, 0x8d, 0x7f, 0x20,
1705 	0xbe, 0xe1, 0x7d, 0xb9, 0xb, 0x0, 0xf3, 0xa6,
1706 	0x74, 0x18, 0xbe, 0x77, 0x7d, 0xe8, 0x6a, 0x0,
1707 	0x32, 0xe4, 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x4,
1708 	0x8f, 0x44, 0x2, 0xcd, 0x19, 0xbe, 0xc0, 0x7d,
1709 	0xeb, 0xeb, 0xa1, 0x1c, 0x5, 0x33, 0xd2, 0xf7,
1710 	0x36, 0xb, 0x7c, 0xfe, 0xc0, 0xa2, 0x3c, 0x7c,
1711 	0xa1, 0x37, 0x7c, 0xa3, 0x3d, 0x7c, 0xbb, 0x0,
1712 	0x7, 0xa1, 0x37, 0x7c, 0xe8, 0x49, 0x0, 0xa1,
1713 	0x18, 0x7c, 0x2a, 0x6, 0x3b, 0x7c, 0x40, 0x38,
1714 	0x6, 0x3c, 0x7c, 0x73, 0x3, 0xa0, 0x3c, 0x7c,
1715 	0x50, 0xe8, 0x4e, 0x0, 0x58, 0x72, 0xc6, 0x28,
1716 	0x6, 0x3c, 0x7c, 0x74, 0xc, 0x1, 0x6, 0x37,
1717 	0x7c, 0xf7, 0x26, 0xb, 0x7c, 0x3, 0xd8, 0xeb,
1718 	0xd0, 0x8a, 0x2e, 0x15, 0x7c, 0x8a, 0x16, 0xfd,
1719 	0x7d, 0x8b, 0x1e, 0x3d, 0x7c, 0xea, 0x0, 0x0,
1720 	0x70, 0x0, 0xac, 0xa, 0xc0, 0x74, 0x22, 0xb4,
1721 	0xe, 0xbb, 0x7, 0x0, 0xcd, 0x10, 0xeb, 0xf2,
1722 	0x33, 0xd2, 0xf7, 0x36, 0x18, 0x7c, 0xfe, 0xc2,
1723 	0x88, 0x16, 0x3b, 0x7c, 0x33, 0xd2, 0xf7, 0x36,
1724 	0x1a, 0x7c, 0x88, 0x16, 0x2a, 0x7c, 0xa3, 0x39,
1725 	0x7c, 0xc3, 0xb4, 0x2, 0x8b, 0x16, 0x39, 0x7c,
1726 	0xb1, 0x6, 0xd2, 0xe6, 0xa, 0x36, 0x3b, 0x7c,
1727 	0x8b, 0xca, 0x86, 0xe9, 0x8a, 0x16, 0xfd, 0x7d,
1728 	0x8a, 0x36, 0x2a, 0x7c, 0xcd, 0x13, 0xc3, '\r',
1729 	'\n', 'N', 'o', 'n', '-', 'S', 'y', 's',
1730 	't', 'e', 'm', ' ', 'd', 'i', 's', 'k',
1731 	' ', 'o', 'r', ' ', 'd', 'i', 's', 'k',
1732 	' ', 'e', 'r', 'r', 'o', 'r', '\r', '\n',
1733 	'R', 'e', 'p', 'l', 'a', 'c', 'e', ' ',
1734 	'a', 'n', 'd', ' ', 's', 't', 'r', 'i',
1735 	'k', 'e', ' ', 'a', 'n', 'y', ' ', 'k',
1736 	'e', 'y', ' ', 'w', 'h', 'e', 'n', ' ',
1737 	'r', 'e', 'a', 'd', 'y', '\r', '\n', '\0',
1738 	'\r', '\n', 'D', 'i', 's', 'k', ' ', 'B',
1739 	'o', 'o', 't', ' ', 'f', 'a', 'i', 'l',
1740 	'u', 'r', 'e', '\r', '\n', '\0', 'I', 'O',
1741 	' ', ' ', ' ', ' ', ' ', ' ', 'S', 'Y',
1742 	'S', 'M', 'S', 'D', 'O', 'S', ' ', ' ',
1743 	' ', 'S', 'Y', 'S', '\0', 0, 0, 0,
1744 	0, 0, 0, 0, 0, 0, 0, 0, 0,
1745 	0, 0, 0, 0, 0, 0x55, 0xaa
1746 };
1747 
1748 static int
1749 valid_DOS_boot(char *bootfile, uchar_t **bootloadp)
1750 {
1751 	struct	stat status;
1752 	size_t	sizebootldr;
1753 	uchar_t	*bootloader;
1754 	int	bfd;
1755 	int	boot_size = 0;
1756 	int	err;
1757 	char	*nullstring = "";
1758 
1759 	if (err = stat(bootfile, &status)) {
1760 		(void) fprintf(stderr, gettext("%s: \"%s\" stat error %d\n"),
1761 		    myname, bootfile, err);
1762 		return (0);
1763 	}
1764 	if ((boot_size = status.st_size) < 512) {
1765 		(void) fprintf(stderr,
1766 		    gettext("%s: short boot sector"), myname);
1767 		perror(nullstring);
1768 		return (0);
1769 	}
1770 	sizebootldr = (boot_size + 511) / 512 * 512;
1771 	if ((bootloader = (uchar_t *)malloc((size_t)sizebootldr)) == NULL) {
1772 		(void) fprintf(stderr, gettext("%s: malloc error\n"),
1773 		    myname);
1774 		return (0);
1775 	}
1776 
1777 	/* switch to user to access the boot file */
1778 	(void) seteuid(getuid());
1779 
1780 	if ((bfd = open(bootfile, O_RDONLY)) == -1) {
1781 		(void) fprintf(stderr, gettext("%s: could not open \"%s\": "),
1782 		    myname, bootfile);
1783 		perror(nullstring);
1784 		return (0);
1785 	}
1786 
1787 	/* restore effective id */
1788 	(void) seteuid(euid);
1789 
1790 	if (read(bfd, bootloader, boot_size) != boot_size) {
1791 		(void) fprintf(stderr,
1792 		    gettext("%s: read of MS-DOS boot file failed, "), myname);
1793 		perror(nullstring);
1794 		(void) close(bfd);
1795 		return (0);
1796 	}
1797 
1798 	if (!((*bootloader == 0xE9 ||
1799 	    (*bootloader == 0xEB && *(bootloader + 2) == 0x90)) &&
1800 		*(bootloader + 510) == 0x55 &&
1801 		*(bootloader + 511) == 0xAA)) {
1802 		(void) fprintf(stderr,
1803 		    gettext("%s: invalid MS-DOS boot loader image\n"), myname);
1804 		boot_size = 0;
1805 	}
1806 
1807 	(void) close(bfd);
1808 	*bootloadp = bootloader;
1809 	return (boot_size);
1810 }
1811 
1812 
1813 static void
1814 write_DOS_label(int fd, uchar_t *bootloadr, int bootlen, char *altbootname,
1815     char *doslabel, struct  bios_param_blk *bpb, int rdirsec)
1816 {
1817 	int		i, j;
1818 	int		bootclen;
1819 	size_t		fat_bsize;
1820 	ushort_t	totalsec;
1821 	uchar_t		*fat_rdir;
1822 	uchar_t		*fatptr;
1823 	char		*nullstring = "";
1824 
1825 	if (bootlen < 512 || !bootloadr) {
1826 		/* use default boot loader routine */
1827 		bootloadr = bootsec;
1828 		bootlen = 512;
1829 	} else
1830 		(void) printf
1831 			(gettext("%s: using \"%s\" for MS-DOS boot loader\n"),
1832 		    myname, altbootname);
1833 	if (bootlen % 512 > 0)
1834 		bootlen = (bootlen + 511) / 512 * 512;
1835 
1836 	bpb->b_bps[0] = getlobyte(512);
1837 	bpb->b_bps[1] = gethibyte(512);
1838 	/* MS-DOS 5.0 supports only 1 reserved sector :-( */
1839 	bpb->b_res_sec[0] = 1;
1840 	bpb->b_res_sec[1] = 0;
1841 
1842 	totalsec = fdchar.fdc_ncyl * fdchar.fdc_nhead * fdchar.fdc_secptrack;
1843 	bpb->b_totalsec[0] = getlobyte(totalsec);
1844 	bpb->b_totalsec[1] = gethibyte(totalsec);
1845 	bpb->b_spt[0] = fdchar.fdc_secptrack;
1846 	bpb->b_spt[1] = 0;
1847 	bpb->b_nhead[0] = fdchar.fdc_nhead;
1848 	bpb->b_nhead[1] = 0;
1849 	bpb->b_hiddensec[0] = 0;
1850 	bpb->b_hiddensec[1] = 0;
1851 
1852 	bpb->b_rdirents[0] = getlobyte(rdirsec);
1853 	bpb->b_rdirents[1] = gethibyte(rdirsec);
1854 
1855 	(void) memcpy((char *)(bootloadr + 0x0B), (char *)bpb,
1856 					sizeof (struct  bios_param_blk));
1857 
1858 	if (write(fd, bootloadr, 512) != 512) {
1859 		(void) fprintf(stderr,
1860 		    gettext("%s: write of MS-DOS boot sector failed"), myname);
1861 		perror(nullstring);
1862 		exit(3);
1863 	}
1864 	bootloadr += 512;
1865 	bootlen -= 512;
1866 
1867 	fat_bsize = 512 * bpb->b_fatsec[0];
1868 	fat_rdir = (uchar_t *)malloc(fat_bsize);
1869 	(void) memset(fat_rdir, (char)0, fat_bsize);
1870 
1871 	*fat_rdir = bpb->b_mediadescriptor;
1872 	*(fat_rdir + 1) = 0xFF;
1873 	*(fat_rdir + 2) = 0xFF;
1874 	bootclen = (bootlen + 512 * (int)bpb->b_spcl - 1) /
1875 	    (512 * (int)bpb->b_spcl);
1876 #define	BAD_CLUSTER 0xFF7
1877 	for (i = 0, fatptr = fat_rdir+3; i < bootclen; i++)
1878 		/*
1879 		 * pre-allocate any clusters used by boot loader if
1880 		 * loader will occupy more than 1 sector
1881 		 */
1882 		if (!(i & 01)) {
1883 			*fatptr++ = BAD_CLUSTER & 0xFF;
1884 			*fatptr = (BAD_CLUSTER >> 8) & 0x0F;
1885 		} else {
1886 			*fatptr = (*fatptr & 0x0F) |
1887 			    ((BAD_CLUSTER << 4) & 0xF0);
1888 			fatptr++;
1889 			*fatptr++ = (BAD_CLUSTER >> 4) & 0xFF;
1890 		}
1891 	for (i = 0; i < (int)bpb->b_nfat; ++i)
1892 		if (write(fd, fat_rdir, fat_bsize) != fat_bsize) {
1893 			(void) fprintf(stderr,
1894 gettext("%s: write of MS-DOS File Allocation Table failed, "),
1895 			    myname);
1896 			perror(nullstring);
1897 			exit(3);
1898 		}
1899 	rdirsec = bpb->b_rdirents[0];
1900 	rdirsec = 32 * (int)rdirsec / 512;
1901 	if (b_flag) {
1902 		struct  timeval tv;
1903 		struct	tm	*tp;
1904 		ushort_t	dostime;
1905 		ushort_t	dosday;
1906 
1907 		/* the label can be no more than 11 characters */
1908 		j = min(11, (int)strlen(doslabel));
1909 		for (i = 0; i < j; i++) {
1910 			fat_rdir[i] = uppercase(doslabel[i]);
1911 		}
1912 		for (; i < 11; i++) {
1913 			fat_rdir[i] = ' ';
1914 		}
1915 		fat_rdir[0x0B] = 0x28;
1916 		(void) gettimeofday(&tv, (struct timezone *)0);
1917 		tp = localtime(&tv.tv_sec);
1918 		/* get the time & day into DOS format */
1919 		dostime = tp->tm_sec / 2;
1920 		dostime |= tp->tm_min << 5;
1921 		dostime |= tp->tm_hour << 11;
1922 		dosday = tp->tm_mday;
1923 		dosday |= (tp->tm_mon + 1) << 5;
1924 		dosday |= (tp->tm_year - 80) << 9;
1925 		fat_rdir[0x16] = getlobyte(dostime);
1926 		fat_rdir[0x17] = gethibyte(dostime);
1927 		fat_rdir[0x18] = getlobyte(dosday);
1928 		fat_rdir[0x19] = gethibyte(dosday);
1929 
1930 		if (write(fd, fat_rdir, 512) != 512) {
1931 			(void) fprintf(stderr,
1932 			    gettext("%s: write of MS-DOS FAT failed, "),
1933 			    myname);
1934 			perror(nullstring);
1935 			exit(3);
1936 		}
1937 		i = 1;
1938 	} else {
1939 		i = 0;
1940 	}
1941 	(void) memset(fat_rdir, (char)0, 512);
1942 	for (; i < (int)rdirsec; ++i) {
1943 		if (write(fd, fat_rdir, 512) != 512) {
1944 			(void) fprintf(stderr,
1945 gettext("%s: write of MS-DOS root directory failed, "),
1946 			    myname);
1947 			perror(nullstring);
1948 			exit(3);
1949 		}
1950 	}
1951 	/*
1952 	 * Write the rest of the boot loader if it's longer than one sector.
1953 	 * The clusters used are marked Bad in the FAT.
1954 	 * No directory entry exists for this file (so that it cannot be
1955 	 * deleted).
1956 	 */
1957 	if (bootlen && write(fd, bootloadr, bootlen) != bootlen) {
1958 		(void) fprintf(stderr,
1959 		    gettext("%s: write of MS-DOS boot sectors failed"), myname);
1960 		perror(nullstring);
1961 		exit(3);
1962 	}
1963 }
1964 
1965 static void
1966 write_NEC_DOS_label(int fd, char *doslabel)
1967 {
1968 	struct		bios_param_blk *bpb;
1969 	ushort_t	fatsec;
1970 	ushort_t	rdirsec;
1971 	char		fat_rdir[1024];
1972 	int		i, j, m = 1;
1973 	uchar_t		bootsec_NEC[1024];
1974 	char		*nullstring = "";
1975 
1976 	uchar_t bios_param_NEC[30] = { 0xeb, 0x1c, 0x90, 0x0, 0x0, 0x0, 0x0,
1977 				0x0, 0x0,  0x0,  0x0, 0x0, 0x4, 0x1, 0x1, 0x0,
1978 				0x2, 0xc0, 0x0, 0xd0, 0x4, 0xfe, 0x2, 0x0,
1979 				0x8, 0x0, 0x2, 0x0, 0x0, 0x0
1980 	};
1981 
1982 	uchar_t fatdir[32] = {   0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
1983 			0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
1984 			0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
1985 			0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5
1986 
1987 	};
1988 
1989 
1990 	(void) memset(bootsec_NEC, (char)0, 1024);
1991 
1992 	(void) memcpy(&bootsec_NEC, &bios_param_NEC, 30);
1993 
1994 	bpb = (struct bios_param_blk *)&(bootsec_NEC[0xb]);
1995 	if (write(fd, &bootsec_NEC[0], 1024) != 1024) {
1996 		(void) fprintf(stderr, gettext(
1997 		    "%s: write of NEC-DOS boot sector failed, "),
1998 		    myname);
1999 		perror(nullstring);
2000 		exit(3);
2001 	}
2002 	(void) memset(fat_rdir, (char)0, 1024);
2003 	fatsec = bpb->b_fatsec[0];
2004 	for (i = 0; i < (int)bpb->b_nfat * (int)fatsec; ++i) {
2005 		if ((i % (int)fatsec) == 0) {
2006 			fat_rdir[0] = bpb->b_mediadescriptor;
2007 			fat_rdir[1] = (char)0xff;
2008 			fat_rdir[2] = (char)0xff;
2009 			fat_rdir[3] = 0;
2010 			fat_rdir[4] = 0;
2011 			fat_rdir[5] = 0;
2012 		} else {
2013 			fat_rdir[0] = 0;
2014 			fat_rdir[1] = 0;
2015 			fat_rdir[2] = 0;
2016 			fat_rdir[3] = 0;
2017 			fat_rdir[4] = 0;
2018 			fat_rdir[5] = 0;
2019 		}
2020 		if (write(fd, &fat_rdir[0], 1024) != 1024) {
2021 			(void) fprintf(stderr,
2022 /*CSTYLED*/
2023 gettext("%s: write of NEC-DOS File Allocation Table failed, "), myname);
2024 			perror(nullstring);
2025 			exit(3);
2026 		}
2027 	}
2028 #ifndef	sparc
2029 	/* LINTED */
2030 	rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024;
2031 #else
2032 	rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024;
2033 #endif
2034 	if (b_flag) {
2035 		struct  timeval tv;
2036 		struct	tm	*tp;
2037 		ushort_t	dostime;
2038 		ushort_t	dosday;
2039 
2040 		/* the label can be no more than 11 characters */
2041 		j = min(11, (int)strlen(doslabel));
2042 		for (i = 0; i < j; i++) {
2043 			fat_rdir[i] = uppercase(doslabel[i]);
2044 		}
2045 		for (; i < 11; i++) {
2046 			fat_rdir[i] = ' ';
2047 		}
2048 		fat_rdir[0xb] = 0x28;
2049 		(void) gettimeofday(&tv, (struct timezone *)0);
2050 		tp = localtime(&tv.tv_sec);
2051 		/* get the time & day into DOS format */
2052 		dostime = tp->tm_sec / 2;
2053 		dostime |= tp->tm_min << 5;
2054 		dostime |= tp->tm_hour << 11;
2055 		dosday = tp->tm_mday;
2056 		dosday |= (tp->tm_mon + 1) << 5;
2057 		dosday |= (tp->tm_year - 80) << 9;
2058 		fat_rdir[0x16] = getlobyte(dostime);
2059 		fat_rdir[0x17] = gethibyte(dostime);
2060 		fat_rdir[0x18] = getlobyte(dosday);
2061 		fat_rdir[0x19] = gethibyte(dosday);
2062 
2063 		if (write(fd, &fat_rdir[0], 1024) != 1024) {
2064 			(void) fprintf(stderr,
2065 			    /*CSTYLED*/
2066 gettext("%s: write of NEC-DOS root directory failed, "), myname);
2067 			perror(nullstring);
2068 			exit(3);
2069 		}
2070 		(void) memset(fat_rdir, (char)0, 512);
2071 		i = 1;
2072 	} else {
2073 		i = 0;
2074 
2075 		while (m < 1024) {
2076 			(void) memcpy(&fat_rdir[m], &fatdir, 31);
2077 			m = m + 32;
2078 		}
2079 	}
2080 	for (; i < (int)rdirsec; ++i) {
2081 
2082 		if (write(fd, &fat_rdir[0], 1024) != 1024) {
2083 			(void) fprintf(stderr,
2084 			    /*CSTYLED*/
2085 gettext("%s: write of NEC-DOS root directory failed, "), myname);
2086 			perror(nullstring);
2087 			exit(3);
2088 		}
2089 	}
2090 }
2091