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 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 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 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 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 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 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 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 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 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 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