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 473 /* FDIOCMD ioctl command structure for formatting */ 474 /* LINTED */ 475 struct fd_cmd fcmd_fmt = { 476 FDCMD_FORMAT_TRACK, 477 0xA5, 478 0, 479 1, 480 0, 481 0 482 }; 483 484 /* FDRAW ioctl command structures for seeking and formatting */ 485 struct fd_raw fdr_seek = { 486 FDRAW_SEEK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 487 3, 488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 489 0, 490 0 491 }; 492 493 struct fd_raw fdr_form = { 494 0x4D, 0, 2, 0, 0x54, (char)0xA5, 0, 0, 0, 0, 495 6, 496 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 497 0, /* nbytes */ 498 0 /* addr */ 499 }; 500 501 502 /* 503 * restore drive to default geometry and characteristics 504 * (probably not implemented on sparc) 505 */ 506 (void) ioctl(fd, FDDEFGEOCHAR, NULL); 507 508 /* get the default partititon maps */ 509 if (ioctl(fd, DKIOCGAPART, &allmap) == -1) { 510 (void) fprintf(stderr, 511 gettext("%s: DKIOCGAPART failed, "), myname); 512 perror(nullstring); 513 exit(3); 514 } 515 516 /* Save the original default partition maps */ 517 save_allmap = allmap; 518 519 /* find out the characteristics of the default diskette */ 520 if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) { 521 (void) fprintf(stderr, 522 gettext("%s: FDIOGCHAR failed, "), myname); 523 perror(nullstring); 524 exit(3); 525 } 526 527 /* Save the original characteristics of the default diskette */ 528 save_fdchar = fdchar; 529 530 /* 531 * The user may only format the entire diskette. 532 * formatting partion a or b is not allowed 533 */ 534 size_of_part = allmap.dka_map[dkinfo.dki_partition].dkl_nblk 535 * DEV_BSIZE; 536 size_of_dev = fdchar.fdc_ncyl * fdchar.fdc_nhead 537 * fdchar.fdc_secptrack * fdchar.fdc_sec_size; 538 539 if (size_of_part != size_of_dev) { 540 (void) fprintf(stderr, 541 /*CSTYLED*/ 542 gettext("%s: The entire diskette must be formatted. Invalid device name.\n"), 543 myname); 544 exit(3); 545 } 546 547 548 /* find out the geometry of the drive */ 549 if (ioctl(fd, DKIOCGGEOM, &fdgeom) == -1) { 550 (void) fprintf(stderr, 551 gettext("%s: DKIOCGGEOM failed, "), myname); 552 perror(nullstring); 553 exit(3); 554 } 555 556 #ifdef sparc 557 fdchar.fdc_medium = 3; 558 #endif 559 if (fdchar.fdc_medium == 5) 560 drive_size = 5; 561 else 562 drive_size = 3; 563 564 /* 565 * set proper density flag in case we're formating to default 566 * characteristics because no density switch was input 567 */ 568 if ((E_flag | H_flag | D_flag | m_flag) == 0) { 569 switch (fdchar.fdc_transfer_rate) { 570 case 1000: 571 /* assumes only ED uses 1.0 MB/sec */ 572 E_flag++; 573 break; 574 case 500: 575 default: 576 /* 577 * default to HD even though High density and 578 * "medium" density both use 500 KB/sec 579 */ 580 H_flag++; 581 break; 582 #ifndef sparc 583 case 250: 584 /* assumes only DD uses 250 KB/sec */ 585 D_flag++; 586 break; 587 #endif 588 } 589 } 590 591 if (H_flag) { 592 transfer_rate = 500; 593 num_cyl = 80; 594 sec_size = 512; 595 if (drive_size == 5) { 596 (void) strcpy(fd_vtoc->v_asciilabel, 597 "5.25\" floppy cyl 80 alt 0 hd 2 sec 15"); 598 spt = 15; 599 capacity = "1.2 MB"; 600 } else { 601 (void) strcpy(fd_vtoc->v_asciilabel, 602 "3.5\" floppy cyl 80 alt 0 hd 2 sec 18"); 603 spt = 18; 604 capacity = "1.44 MB"; 605 } 606 gap = 0x54; 607 } else if (D_flag) { 608 transfer_rate = 250; 609 if (drive_size == 5) { 610 (void) strcpy(fd_vtoc->v_asciilabel, 611 "5.25\" floppy cyl 40 alt 0 hd 2 sec 9"); 612 if (fdchar.fdc_transfer_rate == 500) { 613 /* 614 * formatting a 360KB DD diskette in 615 * a 1.2MB drive is not a good idea 616 */ 617 transfer_rate = 300; 618 fdchar.fdc_steps = 2; 619 } 620 num_cyl = 40; 621 gap = 0x50; 622 capacity = "360 KB"; 623 } else { 624 (void) strcpy(fd_vtoc->v_asciilabel, 625 "3.5\" floppy cyl 80 alt 0 hd 2 sec 9"); 626 num_cyl = 80; 627 gap = 0x54; 628 capacity = "720 KB"; 629 } 630 sec_size = 512; 631 spt = 9; 632 } else if (m_flag) { 633 #ifdef sparc 634 transfer_rate = 500; 635 #else 636 /* 637 * 416.67 KB/sec is the effective transfer rate of a "medium" 638 * density diskette spun at 300 rpm instead of 360 rpm 639 */ 640 transfer_rate = 417; 641 #endif 642 (void) strcpy(fd_vtoc->v_asciilabel, 643 "3.5\" floppy cyl 77 alt 0 hd 2 sec 8"); 644 num_cyl = 77; 645 sec_size = 1024; 646 spt = 8; 647 gap = 0x74; 648 capacity = "1.2 MB"; 649 } else if (E_flag) { 650 (void) strcpy(fd_vtoc->v_asciilabel, 651 "3.5\" floppy cyl 80 alt 0 hd 2 sec 36"); 652 transfer_rate = 1000; 653 num_cyl = 80; 654 sec_size = 512; 655 spt = 36; 656 gap = 0x54; 657 capacity = "2.88 MB"; 658 } 659 /* 660 * Medium density diskettes have 1024 byte blocks. The dk_map 661 * structure in dklabel.h assumes the blocks size is DEVBSIZE (512) 662 * bytes. The dkl_nblk field is in terms of DEVBSIZE byte blocks 663 * while the spt variable is in terms of the true block size on 664 * the diskette. 665 */ 666 if (allmap.dka_map[2].dkl_nblk != 667 (2 * num_cyl * spt * (m_flag ? 2 : 1))) { 668 allmap.dka_map[1].dkl_cylno = num_cyl - 1; 669 allmap.dka_map[0].dkl_nblk = 2 * (num_cyl - 1) * spt * 670 (m_flag ? 2 : 1); 671 allmap.dka_map[1].dkl_nblk = 2 * spt * (m_flag ? 2 : 1); 672 allmap.dka_map[2].dkl_nblk = 2 * num_cyl * spt * 673 (m_flag ? 2 : 1); 674 if (allmap.dka_map[3].dkl_nblk) 675 allmap.dka_map[3].dkl_nblk = 2 * (num_cyl - 1) * spt * 676 (m_flag ? 2 : 1); 677 if (allmap.dka_map[4].dkl_nblk) 678 allmap.dka_map[4].dkl_nblk = 679 2 * spt * (m_flag ? 2 : 1); 680 } 681 682 683 /* initialize the vtoc structure */ 684 fd_vtoc->v_nparts = 3; 685 686 fd_vtoc->v_part[0].p_start = 0; 687 fd_vtoc->v_part[0].p_size = ((num_cyl - 1) * 2 * spt * 688 (m_flag ? 2 : 1)); 689 fd_vtoc->v_part[1].p_start = ((num_cyl - 1) * 2 * spt * 690 (m_flag ? 2 : 1)); 691 fd_vtoc->v_part[1].p_size = 2 * spt * (m_flag ? 2 : 1); 692 693 fd_vtoc->v_part[2].p_start = 0; 694 fd_vtoc->v_part[2].p_size = num_cyl * 2 * spt * (m_flag ? 2 : 1); 695 696 /* initialize the bios parameter blockstructure */ 697 bpb->b_nfat = 2; 698 if (E_flag && drive_size == 3) { 699 bpb->b_spcl = 2; 700 *rdirsec = (ushort_t)240; 701 bpb->b_mediadescriptor = (char)0xF0; 702 bpb->b_fatsec[0] = 9; 703 bpb->b_fatsec[1] = 0; 704 } else if (H_flag) { 705 if (drive_size == 5) { 706 bpb->b_spcl = 1; 707 *rdirsec = 224; 708 bpb->b_mediadescriptor = (char)0xF9; 709 bpb->b_fatsec[0] = 7; 710 bpb->b_fatsec[1] = 0; 711 } else { 712 bpb->b_spcl = 1; 713 *rdirsec = 224; 714 bpb->b_mediadescriptor = (char)0xF0; 715 bpb->b_fatsec[0] = 9; 716 bpb->b_fatsec[1] = 0; 717 } 718 } else if (drive_size == 5) { 719 bpb->b_spcl = 2; 720 *rdirsec = 112; 721 bpb->b_mediadescriptor = (char)0xFD; 722 bpb->b_fatsec[0] = 2; 723 bpb->b_fatsec[1] = 0; 724 } else if (drive_size == 3) { 725 bpb->b_spcl = 2; 726 *rdirsec = 112; 727 bpb->b_mediadescriptor = (char)0xF9; 728 bpb->b_fatsec[0] = 3; 729 bpb->b_fatsec[1] = 0; 730 } 731 732 733 734 #ifndef sparc 735 if (num_cyl > fdchar.fdc_ncyl || spt > fdchar.fdc_secptrack || 736 transfer_rate > fdchar.fdc_transfer_rate) { 737 (void) fprintf(stderr, 738 gettext("%s: drive not capable of requested density, "), 739 myname); 740 perror(nullstring); 741 exit(3); 742 } 743 #endif 744 if (num_cyl != fdchar.fdc_ncyl || spt != fdchar.fdc_secptrack || 745 transfer_rate != fdchar.fdc_transfer_rate) { 746 /* 747 * -- CAUTION -- 748 * The SPARC fd driver is using a non-zero value in 749 * fdc_medium to indicate the 360 rpm, 77 track, 750 * 9 sectors/track, 1024 bytes/sector mode of operation 751 * (similar to an 8", DS/DD, 1.2 MB floppy). 752 * 753 * The x86 fd driver uses fdc_medium as the diameter 754 * indicator, either 3 or 5. It should not be modified. 755 */ 756 #ifdef sparc 757 fdchar.fdc_medium = m_flag ? 1 : 0; 758 #endif 759 fdchar.fdc_transfer_rate = transfer_rate; 760 fdchar.fdc_ncyl = num_cyl; 761 fdchar.fdc_sec_size = sec_size; 762 fdchar.fdc_secptrack = spt; 763 764 if (ioctl(fd, FDIOSCHAR, &fdchar) == -1) { 765 (void) fprintf(stderr, gettext( 766 "%s: FDIOSCHAR (density selection) failed, "), 767 myname); 768 769 /* restore the default characteristics */ 770 restore_default_chars(fd, save_fdchar, save_allmap); 771 perror(nullstring); 772 exit(3); 773 } 774 if (ioctl(fd, DKIOCSAPART, &allmap) == -1) { 775 (void) fprintf(stderr, 776 gettext("%s: DKIOCSAPART failed, "), 777 myname); 778 779 /* restore the default characteristics */ 780 restore_default_chars(fd, save_fdchar, save_allmap); 781 782 perror(nullstring); 783 exit(3); 784 } 785 } 786 787 if (interleave != 1 && interleave != fdgeom.dkg_intrlv) { 788 fdgeom.dkg_intrlv = interleave; 789 if (ioctl(fd, DKIOCSGEOM, &fdgeom) == -1) { 790 (void) fprintf(stderr, 791 gettext("%s: DKIOCSGEOM failed, "), myname); 792 perror(nullstring); 793 794 /* restore the default characteristics */ 795 restore_default_chars(fd, save_fdchar, save_allmap); 796 797 exit(3); 798 } 799 } 800 801 cyl_size = 2 * sec_size * spt; 802 803 if ((ibuf1 = (uchar_t *)malloc((size_t)cyl_size)) == 0 || 804 (obuf = (uchar_t *)malloc((size_t)cyl_size)) == 0) { 805 (void) fprintf(stderr, 806 gettext("%s: can't malloc verify buffer, "), 807 myname); 808 perror(nullstring); 809 /* restore the default characteristics */ 810 restore_default_chars(fd, save_fdchar, save_allmap); 811 812 exit(4); 813 } 814 (void) memset(ibuf1, (uchar_t)0xA5, cyl_size); 815 816 if (x_flag) 817 goto skipformat; 818 819 if (!(q_flag && f_flag)) 820 if (interleave != 1) 821 (void) printf(gettext( 822 "Formatting %s, %d cylinders, %d sectors per trk, interleave=%d in %s\n"), 823 capacity, num_cyl, spt, interleave, real_name); 824 else 825 (void) printf(gettext("Formatting %s in %s\n"), 826 capacity, real_name); 827 828 if (!f_flag) { 829 (void) printf( 830 gettext("Press return to start formatting floppy.")); 831 while (getchar() != '\n') 832 ; 833 } 834 /* 835 * for those systems that support this ioctl, they will 836 * return whether or not a diskette is in the drive. 837 */ 838 if (ioctl(fd, FDGETCHANGE, &chgd) == 0) { 839 if (chgd & FDGC_CURRENT) { 840 (void) fprintf(stderr, 841 gettext("%s: no diskette in drive %s\n"), 842 myname, real_name); 843 844 /* restore the default characteristics */ 845 restore_default_chars(fd, save_fdchar, save_allmap); 846 847 exit(4); 848 } 849 if (chgd & FDGC_CURWPROT) { 850 (void) fprintf(stderr, 851 gettext("%s: \"%s\" is write protected\n"), 852 myname, real_name); 853 854 /* restore the default characteristics */ 855 restore_default_chars(fd, save_fdchar, save_allmap); 856 857 exit(1); 858 } 859 } 860 861 if ((fbuf = (uchar_t *)malloc((unsigned)(4 * spt))) == 0) { 862 (void) fprintf(stderr, 863 gettext("%s: can't malloc format header buffer, "), 864 myname); 865 perror(nullstring); 866 867 /* restore the default characteristics */ 868 restore_default_chars(fd, save_fdchar, save_allmap); 869 870 exit(3); 871 } 872 /* 873 * do the format, a track at a time 874 */ 875 fcmd_fmt.fdc_blkno = 0; 876 for (cyl = 0; cyl < (z_flag ? 1 : (int)num_cyl); cyl++) { 877 #if 0 878 /* 879 * This should be the ioctl used to format the floppy. 880 * The device driver should do do the work, 881 * instead of this program mucking with a lot 882 * of low-level, device-dependent code. 883 */ 884 for (hd = 0; hd < fdchar.fdc_nhead; hd++) { 885 if (ioctl(fd, FDIOCMD, &fcmd_fmt) == -1) { 886 (void) fprintf(stderr, 887 gettext("%s: format of cyl %d head %d failed\n"), 888 myname, cyl, hd); 889 890 /* restore the default characteristics */ 891 restore_default_chars(fd, save_fdchar, 892 save_allmap); 893 exit(3); 894 } 895 fcmd_fmt.fdc_blkno += spt; 896 } 897 #else 898 /* 899 * This is not the optimal ioctl to format the floppy. 900 * The device driver should do do the work, 901 * instead of this program mucking with a lot 902 * of low-level, device-dependent code. 903 */ 904 fdr_seek.fdr_cmd[2] = cyl; 905 if (ioctl(fd, FDRAW, &fdr_seek) == -1) { 906 (void) fprintf(stderr, 907 gettext("%s: seek to cyl %d failed\n"), 908 myname, cyl); 909 910 /* restore the default characteristics */ 911 restore_default_chars(fd, save_fdchar, save_allmap); 912 913 exit(3); 914 } 915 /* 916 * Assume that the fd driver has issued a SENSE_INT 917 * command to complete the seek operation. 918 */ 919 for (hd = 0; hd < fdchar.fdc_nhead; hd++) { 920 p = (uchar_t *)fbuf; 921 for (i = 1; i <= spt; i++) { 922 *p++ = cyl; 923 *p++ = hd; 924 *p++ = i; /* sector # */ 925 *p++ = (sec_size == 1024) ? 3 : 2; 926 } 927 /* 928 * ASSUME the fd driver is going to set drive-select 929 * bits in the second command byte 930 */ 931 fdr_form.fdr_cmd[1] = hd << 2; 932 fdr_form.fdr_cmd[2] = (sec_size == 1024) ? 3 : 2; 933 fdr_form.fdr_cmd[3] = spt; 934 fdr_form.fdr_cmd[4] = gap; 935 fdr_form.fdr_nbytes = 4 * spt; 936 fdr_form.fdr_addr = (char *)fbuf; 937 938 if (ioctl(fd, FDRAW, &fdr_form) == -1) { 939 940 941 (void) fprintf(stderr, gettext( 942 "%s: format of cyl %d head %d failed\n"), 943 myname, cyl, hd); 944 945 /* restore the default characteristics */ 946 restore_default_chars(fd, save_fdchar, 947 save_allmap); 948 949 exit(3); 950 } 951 if (fdr_form.fdr_result[0] & 0xC0) { 952 if (fdr_form.fdr_result[1] & 0x02) { 953 (void) fprintf(stderr, gettext( 954 /*CSTYLED*/ 955 "%s: diskette is write protected\n"), 956 myname); 957 958 /* 959 * restore the default 960 * characteristics 961 */ 962 restore_default_chars(fd, save_fdchar, 963 save_allmap); 964 965 exit(3); 966 } 967 (void) fprintf(stderr, gettext( 968 "%s: format of cyl %d head %d failed\n"), 969 myname, cyl, hd); 970 971 /* restore the default characteristics */ 972 restore_default_chars(fd, save_fdchar, 973 save_allmap); 974 975 exit(3); 976 } 977 978 } 979 #endif 980 981 /* 982 * do a quick verify 983 */ 984 if (!v_flag) { 985 if (lseek(fd, cyl * cyl_size, 0) != cyl * cyl_size) { 986 (void) fprintf(stderr, 987 gettext("%s: bad seek to format verify, "), 988 myname); 989 perror(nullstring); 990 /* restore the default characteristics */ 991 restore_default_chars(fd, save_fdchar, 992 save_allmap); 993 994 exit(3); 995 } 996 if (read(fd, obuf, cyl_size) == cyl_size) { 997 /* write some progress msg */ 998 /* when each cylinder is done. */ 999 if (!q_flag) 1000 (void) printf("."); 1001 } else { 1002 if (!q_flag) 1003 (void) printf(gettext("e\n")); 1004 (void) fprintf(stderr, gettext( 1005 "%s: can't read format data, "), myname); 1006 perror(nullstring); 1007 /* restore the default characteristics */ 1008 restore_default_chars(fd, save_fdchar, 1009 save_allmap); 1010 1011 exit(3); 1012 } 1013 } else 1014 if (!q_flag) 1015 (void) printf("."); 1016 if (!q_flag) 1017 (void) fflush(stdout); 1018 } 1019 if (!q_flag) 1020 (void) printf("\n"); 1021 skipformat: 1022 if (v_flag) { 1023 /* 1024 * do a write & read verify of the entire diskette 1025 */ 1026 if (!q_flag && x_flag) 1027 (void) printf(gettext("Verifying %s in %s\n"), 1028 capacity, real_name); 1029 1030 for (cyl = 0; cyl < (int)num_cyl; cyl++) { 1031 1032 int val; 1033 if ((val = verify(fd, 2 * spt * cyl, cyl_size)) != 0) { 1034 perror(nullstring); 1035 1036 /* restore the default characteristics */ 1037 restore_default_chars(fd, save_fdchar, 1038 save_allmap); 1039 1040 exit(val); 1041 1042 } 1043 /* write some progress msg as */ 1044 /* each cylinder is done. */ 1045 if (!q_flag) 1046 (void) printf(gettext("v")); 1047 (void) fflush(stdout); 1048 } 1049 if (!q_flag) 1050 (void) printf("\n"); 1051 } 1052 1053 if (lseek(fd, (off_t)0, 0) != 0) { 1054 (void) fprintf(stderr, gettext("%s: seek to blk 0 failed, "), 1055 myname); 1056 perror(nullstring); 1057 /* restore the default characteristics */ 1058 restore_default_chars(fd, save_fdchar, save_allmap); 1059 1060 exit(3); 1061 } 1062 1063 } 1064 1065 1066 /* 1067 * Restore the default characteristics of the floppy diskette. 1068 * Fdformat changes the characteristics in the process of formatting. 1069 * If fdformat fails while in the process of doing the format, fdformat 1070 * should clean up after itself and reset the driver back to the original 1071 * state. 1072 */ 1073 1074 static void 1075 restore_default_chars(int fd, 1076 struct fd_char save_fdchar, 1077 struct dk_allmap save_allmap) 1078 { 1079 1080 1081 /* 1082 * When this function is called, fdformat is failing anyways, 1083 * so the errors are not processed. 1084 */ 1085 1086 (void) ioctl(fd, FDIOSCHAR, &save_fdchar); 1087 1088 (void) ioctl(fd, DKIOCSAPART, &save_allmap); 1089 1090 /* 1091 * Before looking at the diskette's characteristics, format_diskette() 1092 * sets the x86 floppy driver to the default characteristics. 1093 * restore drive to default geometry and 1094 * characteristics. This ioctl isn't implemented on 1095 * sparc. 1096 */ 1097 (void) ioctl(fd, FDDEFGEOCHAR, NULL); 1098 1099 } 1100 1101 /* 1102 * See if any partitions on the device are mounted. Return 1 if a partition is 1103 * mounted. Return 0 otherwise. 1104 */ 1105 static int 1106 check_mount() 1107 { 1108 FILE *fp = NULL; 1109 int mfd; 1110 struct dk_cinfo dkinfo_tmp; 1111 struct mnttab mnt_record; 1112 struct mnttab *mp = &mnt_record; 1113 struct stat stbuf; 1114 char raw_device[MAXPATHLEN]; 1115 int found = 0; 1116 1117 if ((fp = fopen(MNTTAB, "r")) == NULL) { 1118 perror(MNTTAB); 1119 exit(3); 1120 } 1121 1122 while (getmntent(fp, mp) == 0) { 1123 if (strstr(mp->mnt_special, "/dev/fd") == NULL && 1124 strstr(mp->mnt_special, "/dev/disket") == NULL && 1125 strstr(mp->mnt_special, "/dev/c") == NULL) { 1126 continue; 1127 } 1128 1129 (void) strcpy(raw_device, "/dev/r"); 1130 (void) strcat(raw_device, mp->mnt_special + strlen("/dev/")); 1131 1132 /* 1133 * Attempt to open the device. If it fails, skip it. 1134 */ 1135 if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { 1136 continue; 1137 } 1138 1139 /* 1140 * Must be a character device 1141 */ 1142 if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) { 1143 (void) close(mfd); 1144 continue; 1145 } 1146 /* 1147 * Attempt to read the configuration info on the disk. 1148 */ 1149 if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) { 1150 (void) close(mfd); 1151 continue; 1152 } 1153 /* 1154 * Finished with the opened device 1155 */ 1156 (void) close(mfd); 1157 1158 /* 1159 * If it's not the disk we're interested in, it doesn't apply. 1160 */ 1161 if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype || 1162 dkinfo.dki_cnum != dkinfo_tmp.dki_cnum || 1163 dkinfo.dki_unit != dkinfo_tmp.dki_unit) { 1164 continue; 1165 } 1166 /* 1167 * It's a mount on the disk we're checking. If we are 1168 * checking whole disk, then we found trouble. We can 1169 * quit searching. 1170 */ 1171 1172 if (U_flag) { 1173 if (!_dev_unmount(mp->mnt_special)) { 1174 (void) fprintf(stderr, 1175 gettext("%s: umount of %s failed\n"), 1176 myname, mp->mnt_special); 1177 found = 1; 1178 } 1179 } else { 1180 (void) fprintf(stderr, 1181 gettext("%s: %s is mounted (use -U flag)\n"), 1182 myname, mp->mnt_special); 1183 found = 1; 1184 } 1185 } 1186 return (found); 1187 } 1188 1189 static void 1190 usage(char *str) 1191 { 1192 char *real_name, *alias_name; 1193 1194 if ((real_name = media_findname("floppy")) == NULL) { 1195 if ((alias_name = _media_oldaliases("floppy")) != NULL) 1196 real_name = media_findname(alias_name); 1197 } 1198 1199 if (str[0] != ' ') 1200 (void) printf("%s: %s\n", myname, str); 1201 (void) printf(gettext( 1202 /*CSTYLED*/ 1203 "\n usage: %s [-dDeEfHlLmMqUvx] [-b label] [-B file] [-t dostype] [devname]\n"), 1204 myname); 1205 1206 (void) printf(gettext( 1207 /*CSTYLED*/ 1208 " -b label install \"label\" on media\n")); 1209 (void) printf(gettext( 1210 " -B file install special boot loader on MS-DOS media\n")); 1211 (void) printf(gettext( 1212 /*CSTYLED*/ 1213 " -d format MS-DOS media\n")); 1214 (void) printf(gettext( 1215 /*CSTYLED*/ 1216 " -D format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n")); 1217 (void) printf(gettext( 1218 " -e eject the media when done\n")); 1219 /*CSTYLED*/ 1220 (void) printf(gettext( 1221 /*CSTYLED*/ 1222 " -E format 2.88MB (3.5\") Extended-density diskette\n")); 1223 (void) printf(gettext( 1224 " -f \"force\" - don't wait for confirmation\n")); 1225 (void) printf(gettext( 1226 /*CSTYLED*/ 1227 " -H format 1.44MB (3.5\") or 1.2MB (5.25\") High-density diskette\n")); 1228 (void) printf(gettext( 1229 /*CSTYLED*/ 1230 " -l format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n")); 1231 (void) printf(gettext( 1232 /*CSTYLED*/ 1233 " -L format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n")); 1234 (void) printf(gettext( 1235 " -m format 1.2MB (3.5\") Medium-density diskette\n")); 1236 (void) printf(gettext( 1237 " -M format 1.2MB (3.5\") Medium-density diskette\n")); 1238 (void) printf(gettext( 1239 " -q quiet\n")); 1240 (void) printf(gettext( 1241 /*CSTYLED*/ 1242 " -t dos format MS-DOS media (same as -d)\n")); 1243 (void) printf(gettext( 1244 " -t nec format NEC-DOS media (with -M only)\n")); 1245 (void) printf(gettext( 1246 /*CSTYLED*/ 1247 " -U unmount media if it's mounted\n")); 1248 (void) printf(gettext( 1249 " -v verify each block of the media\n")); 1250 (void) printf(gettext( 1251 " -x skip the format, only install SunOS or DOS label\n")); 1252 1253 (void) printf(gettext( 1254 " devname defaults to '%s'\n"), 1255 real_name ? real_name : gettext("no available default device")); 1256 1257 exit(1); 1258 1259 } 1260 1261 1262 static int 1263 verify(int fd, int blk, int len) 1264 { 1265 off_t off; 1266 char *nullstring = ""; 1267 1268 off = (off_t)(blk * (m_flag ? 1024 : 512)); 1269 1270 if (lseek(fd, off, 0) != off) { 1271 if (!q_flag) 1272 (void) printf(gettext("e\n")); 1273 (void) fprintf(stderr, 1274 gettext("%s: can't seek to write verify, "), myname); 1275 perror(nullstring); 1276 return (4); 1277 } 1278 if (write(fd, ibuf1, len) != len) { 1279 if (!q_flag) 1280 (void) printf(gettext("e\n")); 1281 if (blk == 0) 1282 (void) fprintf(stderr, 1283 gettext("%s: check diskette density, "), 1284 myname); 1285 else 1286 (void) fprintf(stderr, 1287 gettext("%s: can't write verify data, "), 1288 myname); 1289 perror(nullstring); 1290 return (4); 1291 } 1292 1293 if (lseek(fd, off, 0) != off) { 1294 if (!q_flag) 1295 (void) printf(gettext("e\n")); 1296 (void) fprintf(stderr, 1297 gettext("%s: bad seek to read verify, "), 1298 myname); 1299 perror(nullstring); 1300 return (4); 1301 } 1302 if (read(fd, obuf, len) != len) { 1303 if (!q_flag) 1304 (void) printf(gettext("e\n")); 1305 (void) fprintf(stderr, 1306 gettext("%s: can't read verify data, "), myname); 1307 perror(nullstring); 1308 return (4); 1309 } 1310 if (memcmp(ibuf1, obuf, len)) { 1311 if (!q_flag) 1312 (void) printf(gettext("e\n")); 1313 (void) fprintf(stderr, gettext("%s: verify data failure\n"), 1314 myname); 1315 return (4); 1316 } 1317 return (0); 1318 } 1319 1320 /* 1321 * write a SunOS label 1322 * NOTE: this function assumes fd_vtoc has been filled in with the 1323 * device specific information such as partition information 1324 * and the asciilabel 1325 */ 1326 static void 1327 write_SunOS_label(int fd, char *volname, struct vtoc *fd_vtoc) 1328 { 1329 char *nullstring = ""; 1330 1331 fd_vtoc->v_sanity = VTOC_SANE; 1332 1333 /* 1334 * The label structure is set up for DEV_BSIZE (512 byte) blocks, 1335 * even though a medium density diskette has 1024 byte blocks 1336 * See dklabel.h for more details. 1337 */ 1338 fd_vtoc->v_sectorsz = DEV_BSIZE; 1339 1340 (void) strncpy(fd_vtoc->v_volume, volname, sizeof (fd_vtoc->v_volume)); 1341 1342 /* let the fd driver finish constructing the label and writing it */ 1343 if (ioctl(fd, DKIOCSVTOC, fd_vtoc) == -1) { 1344 (void) fprintf(stderr, 1345 gettext("%s: write of SunOS label failed, "), myname); 1346 perror(nullstring); 1347 exit(3); 1348 } 1349 1350 } 1351 1352 1353 /* 1354 * MS-DOS Disk layout: 1355 * 1356 * --------------------- 1357 * | Boot sector | 1358 * |-------------------| 1359 * | Reserved area | 1360 * |-------------------| 1361 * | FAT #1 | 1362 * |-------------------| 1363 * | FAT #2 | 1364 * |-------------------| 1365 * | Root directory | 1366 * |-------------------| 1367 * | | 1368 * | File area | 1369 * |___________________| 1370 */ 1371 1372 /* 1373 * The following is a copy of MS-DOS 3.3 boot block. 1374 * It consists of the BIOS parameter block, and a disk 1375 * bootstrap program. 1376 * 1377 * The BIOS parameter block contains the right values 1378 * for the 3.5" high-density 1.44MB floppy format. 1379 * 1380 */ 1381 static uchar_t bootsec[512] = { 1382 0xeb, 0x34, 0x90, /* 8086 short jump + displacement + NOP */ 1383 'M', 'S', 'D', 'O', 'S', '3', '.', '3', /* OEM name & version */ 1384 0, 2, 1, 1, 0, /* Start of BIOS parameter block */ 1385 2, 224, 0, 0x40, 0xb, 0xf0, 9, 0, 1386 18, 0, 2, 0, 0, 0, /* End of BIOS parameter block */ 1387 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1388 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 1389 0x0, 0x0, 0x0, 0x0, 1390 0x1, 0x0, 0xfa, 0x33, /* 0x34, start of the bootstrap. */ 1391 0xc0, 0x8e, 0xd0, 0xbc, 0x0, 0x7c, 0x16, 0x7, 1392 0xbb, 0x78, 0x0, 0x36, 0xc5, 0x37, 0x1e, 0x56, 1393 0x16, 0x53, 0xbf, 0x2b, 0x7c, 0xb9, 0xb, 0x0, 1394 0xfc, 0xac, 0x26, 0x80, 0x3d, 0x0, 0x74, 0x3, 1395 0x26, 0x8a, 0x5, 0xaa, 0x8a, 0xc4, 0xe2, 0xf1, 1396 0x6, 0x1f, 0x89, 0x47, 0x2, 0xc7, 0x7, 0x2b, 1397 0x7c, 0xfb, 0xcd, 0x13, 0x72, 0x67, 0xa0, 0x10, 1398 0x7c, 0x98, 0xf7, 0x26, 0x16, 0x7c, 0x3, 0x6, 1399 0x1c, 0x7c, 0x3, 0x6, 0xe, 0x7c, 0xa3, 0x3f, 1400 0x7c, 0xa3, 0x37, 0x7c, 0xb8, 0x20, 0x0, 0xf7, 1401 0x26, 0x11, 0x7c, 0x8b, 0x1e, 0xb, 0x7c, 0x3, 1402 0xc3, 0x48, 0xf7, 0xf3, 0x1, 0x6, 0x37, 0x7c, 1403 0xbb, 0x0, 0x5, 0xa1, 0x3f, 0x7c, 0xe8, 0x9f, 1404 0x0, 0xb8, 0x1, 0x2, 0xe8, 0xb3, 0x0, 0x72, 1405 0x19, 0x8b, 0xfb, 0xb9, 0xb, 0x0, 0xbe, 0xd6, 1406 0x7d, 0xf3, 0xa6, 0x75, 0xd, 0x8d, 0x7f, 0x20, 1407 0xbe, 0xe1, 0x7d, 0xb9, 0xb, 0x0, 0xf3, 0xa6, 1408 0x74, 0x18, 0xbe, 0x77, 0x7d, 0xe8, 0x6a, 0x0, 1409 0x32, 0xe4, 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x4, 1410 0x8f, 0x44, 0x2, 0xcd, 0x19, 0xbe, 0xc0, 0x7d, 1411 0xeb, 0xeb, 0xa1, 0x1c, 0x5, 0x33, 0xd2, 0xf7, 1412 0x36, 0xb, 0x7c, 0xfe, 0xc0, 0xa2, 0x3c, 0x7c, 1413 0xa1, 0x37, 0x7c, 0xa3, 0x3d, 0x7c, 0xbb, 0x0, 1414 0x7, 0xa1, 0x37, 0x7c, 0xe8, 0x49, 0x0, 0xa1, 1415 0x18, 0x7c, 0x2a, 0x6, 0x3b, 0x7c, 0x40, 0x38, 1416 0x6, 0x3c, 0x7c, 0x73, 0x3, 0xa0, 0x3c, 0x7c, 1417 0x50, 0xe8, 0x4e, 0x0, 0x58, 0x72, 0xc6, 0x28, 1418 0x6, 0x3c, 0x7c, 0x74, 0xc, 0x1, 0x6, 0x37, 1419 0x7c, 0xf7, 0x26, 0xb, 0x7c, 0x3, 0xd8, 0xeb, 1420 0xd0, 0x8a, 0x2e, 0x15, 0x7c, 0x8a, 0x16, 0xfd, 1421 0x7d, 0x8b, 0x1e, 0x3d, 0x7c, 0xea, 0x0, 0x0, 1422 0x70, 0x0, 0xac, 0xa, 0xc0, 0x74, 0x22, 0xb4, 1423 0xe, 0xbb, 0x7, 0x0, 0xcd, 0x10, 0xeb, 0xf2, 1424 0x33, 0xd2, 0xf7, 0x36, 0x18, 0x7c, 0xfe, 0xc2, 1425 0x88, 0x16, 0x3b, 0x7c, 0x33, 0xd2, 0xf7, 0x36, 1426 0x1a, 0x7c, 0x88, 0x16, 0x2a, 0x7c, 0xa3, 0x39, 1427 0x7c, 0xc3, 0xb4, 0x2, 0x8b, 0x16, 0x39, 0x7c, 1428 0xb1, 0x6, 0xd2, 0xe6, 0xa, 0x36, 0x3b, 0x7c, 1429 0x8b, 0xca, 0x86, 0xe9, 0x8a, 0x16, 0xfd, 0x7d, 1430 0x8a, 0x36, 0x2a, 0x7c, 0xcd, 0x13, 0xc3, '\r', 1431 '\n', 'N', 'o', 'n', '-', 'S', 'y', 's', 1432 't', 'e', 'm', ' ', 'd', 'i', 's', 'k', 1433 ' ', 'o', 'r', ' ', 'd', 'i', 's', 'k', 1434 ' ', 'e', 'r', 'r', 'o', 'r', '\r', '\n', 1435 'R', 'e', 'p', 'l', 'a', 'c', 'e', ' ', 1436 'a', 'n', 'd', ' ', 's', 't', 'r', 'i', 1437 'k', 'e', ' ', 'a', 'n', 'y', ' ', 'k', 1438 'e', 'y', ' ', 'w', 'h', 'e', 'n', ' ', 1439 'r', 'e', 'a', 'd', 'y', '\r', '\n', '\0', 1440 '\r', '\n', 'D', 'i', 's', 'k', ' ', 'B', 1441 'o', 'o', 't', ' ', 'f', 'a', 'i', 'l', 1442 'u', 'r', 'e', '\r', '\n', '\0', 'I', 'O', 1443 ' ', ' ', ' ', ' ', ' ', ' ', 'S', 'Y', 1444 'S', 'M', 'S', 'D', 'O', 'S', ' ', ' ', 1445 ' ', 'S', 'Y', 'S', '\0', 0, 0, 0, 1446 0, 0, 0, 0, 0, 0, 0, 0, 0, 1447 0, 0, 0, 0, 0, 0x55, 0xaa 1448 }; 1449 1450 static int 1451 valid_DOS_boot(char *bootfile, uchar_t **bootloadp) 1452 { 1453 struct stat status; 1454 size_t sizebootldr; 1455 uchar_t *bootloader; 1456 int bfd; 1457 int boot_size = 0; 1458 int err; 1459 char *nullstring = ""; 1460 1461 if (err = stat(bootfile, &status)) { 1462 (void) fprintf(stderr, gettext("%s: \"%s\" stat error %d\n"), 1463 myname, bootfile, err); 1464 return (0); 1465 } 1466 if ((boot_size = status.st_size) < 512) { 1467 (void) fprintf(stderr, 1468 gettext("%s: short boot sector"), myname); 1469 perror(nullstring); 1470 return (0); 1471 } 1472 sizebootldr = (boot_size + 511) / 512 * 512; 1473 if ((bootloader = (uchar_t *)malloc((size_t)sizebootldr)) == NULL) { 1474 (void) fprintf(stderr, gettext("%s: malloc error\n"), 1475 myname); 1476 return (0); 1477 } 1478 1479 /* switch to user to access the boot file */ 1480 (void) seteuid(getuid()); 1481 1482 if ((bfd = open(bootfile, O_RDONLY)) == -1) { 1483 (void) fprintf(stderr, gettext("%s: could not open \"%s\": "), 1484 myname, bootfile); 1485 perror(nullstring); 1486 return (0); 1487 } 1488 1489 /* restore effective id */ 1490 (void) seteuid(euid); 1491 1492 if (read(bfd, bootloader, boot_size) != boot_size) { 1493 (void) fprintf(stderr, 1494 gettext("%s: read of MS-DOS boot file failed, "), myname); 1495 perror(nullstring); 1496 (void) close(bfd); 1497 return (0); 1498 } 1499 1500 if (!((*bootloader == 0xE9 || 1501 (*bootloader == 0xEB && *(bootloader + 2) == 0x90)) && 1502 *(bootloader + 510) == 0x55 && 1503 *(bootloader + 511) == 0xAA)) { 1504 (void) fprintf(stderr, 1505 gettext("%s: invalid MS-DOS boot loader image\n"), myname); 1506 boot_size = 0; 1507 } 1508 1509 (void) close(bfd); 1510 *bootloadp = bootloader; 1511 return (boot_size); 1512 } 1513 1514 1515 static void 1516 write_DOS_label(int fd, uchar_t *bootloadr, int bootlen, char *altbootname, 1517 char *doslabel, struct bios_param_blk *bpb, int rdirsec) 1518 { 1519 int i, j; 1520 int bootclen; 1521 size_t fat_bsize; 1522 ushort_t totalsec; 1523 uchar_t *fat_rdir; 1524 uchar_t *fatptr; 1525 char *nullstring = ""; 1526 1527 if (bootlen < 512 || !bootloadr) { 1528 /* use default boot loader routine */ 1529 bootloadr = bootsec; 1530 bootlen = 512; 1531 } else 1532 (void) printf 1533 (gettext("%s: using \"%s\" for MS-DOS boot loader\n"), 1534 myname, altbootname); 1535 if (bootlen % 512 > 0) 1536 bootlen = (bootlen + 511) / 512 * 512; 1537 1538 bpb->b_bps[0] = getlobyte(512); 1539 bpb->b_bps[1] = gethibyte(512); 1540 /* MS-DOS 5.0 supports only 1 reserved sector :-( */ 1541 bpb->b_res_sec[0] = 1; 1542 bpb->b_res_sec[1] = 0; 1543 1544 totalsec = fdchar.fdc_ncyl * fdchar.fdc_nhead * fdchar.fdc_secptrack; 1545 bpb->b_totalsec[0] = getlobyte(totalsec); 1546 bpb->b_totalsec[1] = gethibyte(totalsec); 1547 bpb->b_spt[0] = fdchar.fdc_secptrack; 1548 bpb->b_spt[1] = 0; 1549 bpb->b_nhead[0] = fdchar.fdc_nhead; 1550 bpb->b_nhead[1] = 0; 1551 bpb->b_hiddensec[0] = 0; 1552 bpb->b_hiddensec[1] = 0; 1553 1554 bpb->b_rdirents[0] = getlobyte(rdirsec); 1555 bpb->b_rdirents[1] = gethibyte(rdirsec); 1556 1557 (void) memcpy((char *)(bootloadr + 0x0B), (char *)bpb, 1558 sizeof (struct bios_param_blk)); 1559 1560 if (write(fd, bootloadr, 512) != 512) { 1561 (void) fprintf(stderr, 1562 gettext("%s: write of MS-DOS boot sector failed"), myname); 1563 perror(nullstring); 1564 exit(3); 1565 } 1566 bootloadr += 512; 1567 bootlen -= 512; 1568 1569 fat_bsize = 512 * bpb->b_fatsec[0]; 1570 fat_rdir = (uchar_t *)malloc(fat_bsize); 1571 (void) memset(fat_rdir, (char)0, fat_bsize); 1572 1573 *fat_rdir = bpb->b_mediadescriptor; 1574 *(fat_rdir + 1) = 0xFF; 1575 *(fat_rdir + 2) = 0xFF; 1576 bootclen = (bootlen + 512 * (int)bpb->b_spcl - 1) / 1577 (512 * (int)bpb->b_spcl); 1578 #define BAD_CLUSTER 0xFF7 1579 for (i = 0, fatptr = fat_rdir+3; i < bootclen; i++) 1580 /* 1581 * pre-allocate any clusters used by boot loader if 1582 * loader will occupy more than 1 sector 1583 */ 1584 if (!(i & 01)) { 1585 *fatptr++ = BAD_CLUSTER & 0xFF; 1586 *fatptr = (BAD_CLUSTER >> 8) & 0x0F; 1587 } else { 1588 *fatptr = (*fatptr & 0x0F) | 1589 ((BAD_CLUSTER << 4) & 0xF0); 1590 fatptr++; 1591 *fatptr++ = (BAD_CLUSTER >> 4) & 0xFF; 1592 } 1593 for (i = 0; i < (int)bpb->b_nfat; ++i) 1594 if (write(fd, fat_rdir, fat_bsize) != fat_bsize) { 1595 (void) fprintf(stderr, 1596 gettext("%s: write of MS-DOS File Allocation Table failed, "), 1597 myname); 1598 perror(nullstring); 1599 exit(3); 1600 } 1601 rdirsec = bpb->b_rdirents[0]; 1602 rdirsec = 32 * (int)rdirsec / 512; 1603 if (b_flag) { 1604 struct timeval tv; 1605 struct tm *tp; 1606 ushort_t dostime; 1607 ushort_t dosday; 1608 1609 /* the label can be no more than 11 characters */ 1610 j = min(11, (int)strlen(doslabel)); 1611 for (i = 0; i < j; i++) { 1612 fat_rdir[i] = uppercase(doslabel[i]); 1613 } 1614 for (; i < 11; i++) { 1615 fat_rdir[i] = ' '; 1616 } 1617 fat_rdir[0x0B] = 0x28; 1618 (void) gettimeofday(&tv, (struct timezone *)0); 1619 tp = localtime(&tv.tv_sec); 1620 /* get the time & day into DOS format */ 1621 dostime = tp->tm_sec / 2; 1622 dostime |= tp->tm_min << 5; 1623 dostime |= tp->tm_hour << 11; 1624 dosday = tp->tm_mday; 1625 dosday |= (tp->tm_mon + 1) << 5; 1626 dosday |= (tp->tm_year - 80) << 9; 1627 fat_rdir[0x16] = getlobyte(dostime); 1628 fat_rdir[0x17] = gethibyte(dostime); 1629 fat_rdir[0x18] = getlobyte(dosday); 1630 fat_rdir[0x19] = gethibyte(dosday); 1631 1632 if (write(fd, fat_rdir, 512) != 512) { 1633 (void) fprintf(stderr, 1634 gettext("%s: write of MS-DOS FAT failed, "), 1635 myname); 1636 perror(nullstring); 1637 exit(3); 1638 } 1639 i = 1; 1640 } else { 1641 i = 0; 1642 } 1643 (void) memset(fat_rdir, (char)0, 512); 1644 for (; i < (int)rdirsec; ++i) { 1645 if (write(fd, fat_rdir, 512) != 512) { 1646 (void) fprintf(stderr, 1647 gettext("%s: write of MS-DOS root directory failed, "), 1648 myname); 1649 perror(nullstring); 1650 exit(3); 1651 } 1652 } 1653 /* 1654 * Write the rest of the boot loader if it's longer than one sector. 1655 * The clusters used are marked Bad in the FAT. 1656 * No directory entry exists for this file (so that it cannot be 1657 * deleted). 1658 */ 1659 if (bootlen && write(fd, bootloadr, bootlen) != bootlen) { 1660 (void) fprintf(stderr, 1661 gettext("%s: write of MS-DOS boot sectors failed"), myname); 1662 perror(nullstring); 1663 exit(3); 1664 } 1665 } 1666 1667 static void 1668 write_NEC_DOS_label(int fd, char *doslabel) 1669 { 1670 struct bios_param_blk *bpb; 1671 ushort_t fatsec; 1672 ushort_t rdirsec; 1673 char fat_rdir[1024]; 1674 int i, j, m = 1; 1675 uchar_t bootsec_NEC[1024]; 1676 char *nullstring = ""; 1677 1678 uchar_t bios_param_NEC[30] = { 0xeb, 0x1c, 0x90, 0x0, 0x0, 0x0, 0x0, 1679 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1, 0x1, 0x0, 1680 0x2, 0xc0, 0x0, 0xd0, 0x4, 0xfe, 0x2, 0x0, 1681 0x8, 0x0, 0x2, 0x0, 0x0, 0x0 1682 }; 1683 1684 uchar_t fatdir[32] = { 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 1685 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 1686 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 1687 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5 1688 1689 }; 1690 1691 1692 (void) memset(bootsec_NEC, (char)0, 1024); 1693 1694 (void) memcpy(&bootsec_NEC, &bios_param_NEC, 30); 1695 1696 bpb = (struct bios_param_blk *)&(bootsec_NEC[0xb]); 1697 if (write(fd, &bootsec_NEC[0], 1024) != 1024) { 1698 (void) fprintf(stderr, gettext( 1699 "%s: write of NEC-DOS boot sector failed, "), 1700 myname); 1701 perror(nullstring); 1702 exit(3); 1703 } 1704 (void) memset(fat_rdir, (char)0, 1024); 1705 fatsec = bpb->b_fatsec[0]; 1706 for (i = 0; i < (int)bpb->b_nfat * (int)fatsec; ++i) { 1707 if ((i % (int)fatsec) == 0) { 1708 fat_rdir[0] = bpb->b_mediadescriptor; 1709 fat_rdir[1] = (char)0xff; 1710 fat_rdir[2] = (char)0xff; 1711 fat_rdir[3] = 0; 1712 fat_rdir[4] = 0; 1713 fat_rdir[5] = 0; 1714 } else { 1715 fat_rdir[0] = 0; 1716 fat_rdir[1] = 0; 1717 fat_rdir[2] = 0; 1718 fat_rdir[3] = 0; 1719 fat_rdir[4] = 0; 1720 fat_rdir[5] = 0; 1721 } 1722 if (write(fd, &fat_rdir[0], 1024) != 1024) { 1723 (void) fprintf(stderr, 1724 /*CSTYLED*/ 1725 gettext("%s: write of NEC-DOS File Allocation Table failed, "), myname); 1726 perror(nullstring); 1727 exit(3); 1728 } 1729 } 1730 #ifndef sparc 1731 /* LINTED */ 1732 rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024; 1733 #else 1734 rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024; 1735 #endif 1736 if (b_flag) { 1737 struct timeval tv; 1738 struct tm *tp; 1739 ushort_t dostime; 1740 ushort_t dosday; 1741 1742 /* the label can be no more than 11 characters */ 1743 j = min(11, (int)strlen(doslabel)); 1744 for (i = 0; i < j; i++) { 1745 fat_rdir[i] = uppercase(doslabel[i]); 1746 } 1747 for (; i < 11; i++) { 1748 fat_rdir[i] = ' '; 1749 } 1750 fat_rdir[0xb] = 0x28; 1751 (void) gettimeofday(&tv, (struct timezone *)0); 1752 tp = localtime(&tv.tv_sec); 1753 /* get the time & day into DOS format */ 1754 dostime = tp->tm_sec / 2; 1755 dostime |= tp->tm_min << 5; 1756 dostime |= tp->tm_hour << 11; 1757 dosday = tp->tm_mday; 1758 dosday |= (tp->tm_mon + 1) << 5; 1759 dosday |= (tp->tm_year - 80) << 9; 1760 fat_rdir[0x16] = getlobyte(dostime); 1761 fat_rdir[0x17] = gethibyte(dostime); 1762 fat_rdir[0x18] = getlobyte(dosday); 1763 fat_rdir[0x19] = gethibyte(dosday); 1764 1765 if (write(fd, &fat_rdir[0], 1024) != 1024) { 1766 (void) fprintf(stderr, 1767 /*CSTYLED*/ 1768 gettext("%s: write of NEC-DOS root directory failed, "), myname); 1769 perror(nullstring); 1770 exit(3); 1771 } 1772 (void) memset(fat_rdir, (char)0, 512); 1773 i = 1; 1774 } else { 1775 i = 0; 1776 1777 while (m < 1024) { 1778 (void) memcpy(&fat_rdir[m], &fatdir, 31); 1779 m = m + 32; 1780 } 1781 } 1782 for (; i < (int)rdirsec; ++i) { 1783 1784 if (write(fd, &fat_rdir[0], 1024) != 1024) { 1785 (void) fprintf(stderr, 1786 /*CSTYLED*/ 1787 gettext("%s: write of NEC-DOS root directory failed, "), myname); 1788 perror(nullstring); 1789 exit(3); 1790 } 1791 } 1792 } 1793