/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * fdformat program - formats floppy disks, and then adds a label to them * * ****Warning, Warning, Warning, Warning***** * This program runs suid root. This change was made to * allow it to umount a file system if it's mounted. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* DEFINES */ #if defined(_BIG_ENDIAN) #define getbyte(A, N) (((unsigned char *)(&(A)))[N]) #define htols(S) ((getbyte(S, 1) <<8) | getbyte(S, 0)) #elif defined(_LITTLE_ENDIAN) #define htols(S) (*((ushort_t *)(&(S)))) #else #error One of _BIG_ENDIAN or LITTLE_ENDIAN must be defined #endif #define getlobyte(A) (A & 0xFF) #define gethibyte(A) (A >> 8 & 0xFF) #define uppercase(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c)) #define min(a, b) ((a) < (b) ? (a) : (b)) /* FORMAT PATTERNS */ #define PATTERN_1 0x55; #define PATTERN_2 0xaa; #define PATTERN_3 0xff; #define PATTERN_4 0x00; /* UNINITIALIZED DATA */ static struct fd_char fdchar; static struct dk_geom fdgeom; static struct dk_allmap allmap; static struct dk_cinfo dkinfo; /* EXTERN */ extern char *optarg; extern int optind; /* for verify buffers */ static uchar_t *ibuf1; static uchar_t *obuf; static char *myname; static int fd_debug = 1; /* 1 if debug XXX */ static int b_flag = 0; /* install a volume label to the diskette */ static int d_flag = 0; /* format the diskette in dos format */ static int D_flag = 0; /* double (aka low) density flag */ static int e_flag = 0; /* "eject" diskette when done (if supported) */ static int E_flag = 0; /* extended density */ static int f_flag = 0; /* "force" (no confirmation before start) */ static int H_flag = 0; /* high density */ static int m_flag = 0; /* medium density */ static int n_flag = 0; /* format the diskette in NEC-DOS format */ static int q_flag = 0; /* quiet format flag */ static int U_flag = 0; /* automatically unmount if it's mounted */ static int v_flag = 0; /* verify format/diskette flag */ static int x_flag = 0; /* skip the format, only install SunOS label */ /* or DOS file system */ static int z_flag = 0; /* debugging only, setting partial formatting */ static int interleave = 1; /* interleave factor */ static uid_t euid = 0; /* stores effective user id */ struct bios_param_blk { uchar_t b_bps[2]; /* bytes per sector */ uchar_t b_spcl; /* sectors per alloction unit */ uchar_t b_res_sec[2]; /* reserved sectors, starting at 0 */ uchar_t b_nfat; /* number of FATs */ uchar_t b_rdirents[2]; /* number of root directory entries */ uchar_t b_totalsec[2]; /* total sectors in logical image */ char b_mediadescriptor; /* media descriptor byte */ uchar_t b_fatsec[2]; /* number of sectors per FAT */ uchar_t b_spt[2]; /* sectors per track */ uchar_t b_nhead[2]; /* number of heads */ uchar_t b_hiddensec[2]; /* number of hidden sectors */ }; /* * ON-private functions from libvolmgt */ char *_media_oldaliases(char *name); int _dev_mounted(char *path); int _dev_unmount(char *path); /* * local functions */ static void usage(char *); static int verify(int, int, int); static void write_SunOS_label(int, char *, struct vtoc *); static int valid_DOS_boot(char *, uchar_t **); static void write_DOS_label(int, uchar_t *, int, char *, char *, struct bios_param_blk *, int); static void write_NEC_DOS_label(int, char *); static int check_mount(); static void format_diskette(int, char *, struct vtoc *, struct bios_param_blk *, int *); static void restore_default_chars(int fd, struct fd_char save_fdchar, struct dk_allmap save_allmap); int main(int argc, char **argv) { int altsize = 0; int fd; int i; uchar_t *altboot = NULL; char *altbootname = NULL; char *dev_name = NULL, *real_name, *alias_name; char *vollabel = ""; struct vtoc fd_vtoc; struct bios_param_blk bpb; int rdirsec; char *nullstring = ""; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); myname = argv[0]; while ((i = getopt(argc, argv, "B:b:dDeEfhHlLmMxqt:UvVZ?")) != -1) { switch (i) { case 'B': altbootname = strdup(optarg); d_flag++; /* check for valid boot file now */ altsize = valid_DOS_boot(altbootname, &altboot); if (!altsize) { (void) fprintf(stderr, gettext( "%s: invalid boot loader\n"), myname); exit(1); } break; case 'b': b_flag++; vollabel = strdup(optarg); break; case 'd': /* format a MS-DOS diskette */ d_flag++; break; case 'D': case 'L': case 'l': /* format a Double density 720KB (or 360KB) disk */ D_flag++; break; case 'e': /* eject diskette when done */ e_flag++; break; case 'E': /* format an 2.88MB Extended density disk */ E_flag++; break; case 'f': /* don't ask for confirmation */ f_flag++; break; case 'H': case 'h': /* format a High density 1.2MB or 1.44MB disk */ H_flag++; break; #if 0 case 'i': /* interleave factor */ interleave = atol(optarg); if (interleave <= 0) { (void) fprintf(stderr, gettext( "%s: invalid interleave\n"), myname); exit(1); } break; #endif case 'M': case 'm': /* format a 3.5" HD disk to 1.2MB */ m_flag++; break; case 'x': /* skip format, just write label */ x_flag++; break; case 'q': /* quiet format */ q_flag++; break; case 't': /* Type of DOS formatting: NEC or MS */ if (strcmp(optarg, "nec") == 0) { n_flag++; } if (strcmp(optarg, "dos") == 0) { d_flag++; } break; case 'U': /* umount filesystem if mounted */ U_flag++; break; case 'v': case 'V': /* verify the diskette after format */ v_flag++; break; case 'Z': /* for debug only, format cyl 0 only */ if (!fd_debug) { usage(gettext("unknown argument")); /* NOTREACHED */ } (void) printf(gettext("\nFormat cyl Zero only\n")); z_flag++; break; default: usage(" "); /* NOTREACHED */ } } if (optind < argc -1) { usage(gettext("more than one device name argument")); /* NOTREACHED */ } if (optind == argc -1) { dev_name = argv[optind]; } if (D_flag && H_flag) { usage(gettext("switches -D, -L and -H incompatible")); /* NOTREACHED */ } if (D_flag && E_flag) { usage(gettext("switches -D, -L and -E incompatible")); /* NOTREACHED */ } if (H_flag && E_flag) { usage(gettext("switches -H and -E incompatible")); /* NOTREACHED */ } if (n_flag && d_flag) { usage(gettext("switches nec and dos incompatible")); /* NOTREACHED */ } if (n_flag && !m_flag) { usage(gettext("switch -M required for NEC-DOS")); /* NOTREACHED */ } if (D_flag && m_flag) { usage(gettext("switches -D, -L and -M incompatible")); /* NOTREACHED */ } if (d_flag && m_flag) { usage(gettext("switches -d and -M incompatible")); /* NOTREACHED */ } if (dev_name == NULL) dev_name = "floppy"; if ((real_name = media_findname(dev_name)) == NULL) { if ((alias_name = _media_oldaliases(dev_name)) != NULL) real_name = media_findname(alias_name); if (real_name == NULL) { (void) fprintf(stderr, gettext("No such volume (or no media in specified device): %s\n"), dev_name); exit(1); } } /* * This check is required because program runs suid root. */ if (access(real_name, R_OK|W_OK) < 0) { perror(real_name); exit(1); } /* store callers euid */ euid = geteuid(); /* * See if the given device name is mounted. If this check isn't done * before the open, the open will fail. The failed open will not * indicate that the device is mounted, only that it's busy */ if (_dev_mounted(real_name)) { if (U_flag) { if (!_dev_unmount(real_name)) { (void) fprintf(stderr, gettext("%s: umount of %s failed\n"), myname, real_name); exit(1); } } else { (void) fprintf(stderr, gettext("%s: %s is mounted (use -U flag)\n"), myname, real_name); exit(1); } } /* Set to user access permissions to open file */ (void) seteuid(getuid()); if ((fd = open(real_name, O_NDELAY | O_RDWR | O_EXCL)) == -1) { if (errno == EROFS) { (void) fprintf(stderr, gettext("%s: \"%s\" is write protected\n"), myname, real_name); exit(1); } /* XXX ought to check for "drive not installed", etc. */ (void) fprintf(stderr, gettext("%s: could not open \"%s\": "), myname, real_name); perror(nullstring); exit(1); } /* restore effective id */ (void) seteuid(euid); if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) { (void) fprintf(stderr, gettext("%s: DKIOCINFO failed, "), myname); perror(nullstring); exit(3); } /* See if there are any mounted partitions. */ if (check_mount() != 0) { exit(3); } /* * The fd_vtoc, bpb, and rdirsec structures will be * partially filled in by format_diskette(). * This was done so that write_DOS_label(), * write_SunOS_label(), and write_NEC_DOS_label() could be * device independent. If a new device needs to be added to * fdformat, a new format function like format_diskette should * be added. This function should fill in fd_vtoc, bpb, and * rdirsec with device dependent information. */ (void) memset((void *)&fd_vtoc, (char)0, sizeof (struct vtoc)); (void) memset((void *)&bpb, (char)0, sizeof (struct bios_param_blk)); format_diskette(fd, real_name, &fd_vtoc, &bpb, &rdirsec); if (d_flag) write_DOS_label(fd, altboot, altsize, altbootname, vollabel, &bpb, rdirsec); else if (n_flag) write_NEC_DOS_label(fd, vollabel); else write_SunOS_label(fd, vollabel, &fd_vtoc); if (e_flag) /* eject media if possible */ if (ioctl(fd, FDEJECT, 0)) { (void) fprintf(stderr, gettext("%s: could not eject diskette, "), myname); perror(nullstring); exit(3); } return (0); } /* * Inputs: file descriptor for the device and the device name. * Oututs: the fd_vtoc will be partially filled in with the * device specific information such as partition * information and ascillabel. bpb and rdirsec will * also be partially filled in with device specific information */ void format_diskette(int fd, char *real_name, struct vtoc *fd_vtoc, struct bios_param_blk *bpb, int *rdirsec) { int transfer_rate = 1000; /* transfer rate code */ int sec_size = 512; /* sector size */ uchar_t gap = 0x54; /* format gap size */ uchar_t *fbuf, *p; char *capacity = NULL; int cyl_size; int i; int chgd; /* for testing disk changed/present */ int cyl, hd; int size_of_part, size_of_dev; int spt = 36; /* sectors per track */ int drive_size; uchar_t num_cyl = 80; /* max number of cylinders */ char *nullstring = ""; struct fd_char save_fdchar; /* original diskette characteristics */ struct dk_allmap save_allmap; /* original diskette partition info */ /* FDRAW ioctl command structures for seeking and formatting */ struct fd_raw fdr_seek = { FDRAW_SEEK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; struct fd_raw fdr_form = { 0x4D, 0, 2, 0, 0x54, (char)0xA5, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* nbytes */ 0 /* addr */ }; /* * restore drive to default geometry and characteristics * (probably not implemented on sparc) */ (void) ioctl(fd, FDDEFGEOCHAR, NULL); /* get the default partititon maps */ if (ioctl(fd, DKIOCGAPART, &allmap) == -1) { (void) fprintf(stderr, gettext("%s: DKIOCGAPART failed, "), myname); perror(nullstring); exit(3); } /* Save the original default partition maps */ save_allmap = allmap; /* find out the characteristics of the default diskette */ if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) { (void) fprintf(stderr, gettext("%s: FDIOGCHAR failed, "), myname); perror(nullstring); exit(3); } /* Save the original characteristics of the default diskette */ save_fdchar = fdchar; /* * The user may only format the entire diskette. * formatting partion a or b is not allowed */ size_of_part = allmap.dka_map[dkinfo.dki_partition].dkl_nblk * DEV_BSIZE; size_of_dev = fdchar.fdc_ncyl * fdchar.fdc_nhead * fdchar.fdc_secptrack * fdchar.fdc_sec_size; if (size_of_part != size_of_dev) { (void) fprintf(stderr, /*CSTYLED*/ gettext("%s: The entire diskette must be formatted. Invalid device name.\n"), myname); exit(3); } /* find out the geometry of the drive */ if (ioctl(fd, DKIOCGGEOM, &fdgeom) == -1) { (void) fprintf(stderr, gettext("%s: DKIOCGGEOM failed, "), myname); perror(nullstring); exit(3); } #ifdef sparc fdchar.fdc_medium = 3; #endif if (fdchar.fdc_medium == 5) drive_size = 5; else drive_size = 3; /* * set proper density flag in case we're formating to default * characteristics because no density switch was input */ if ((E_flag | H_flag | D_flag | m_flag) == 0) { switch (fdchar.fdc_transfer_rate) { case 1000: /* assumes only ED uses 1.0 MB/sec */ E_flag++; break; case 500: default: /* * default to HD even though High density and * "medium" density both use 500 KB/sec */ H_flag++; break; #ifndef sparc case 250: /* assumes only DD uses 250 KB/sec */ D_flag++; break; #endif } } if (H_flag) { transfer_rate = 500; num_cyl = 80; sec_size = 512; if (drive_size == 5) { (void) strcpy(fd_vtoc->v_asciilabel, "5.25\" floppy cyl 80 alt 0 hd 2 sec 15"); spt = 15; capacity = "1.2 MB"; } else { (void) strcpy(fd_vtoc->v_asciilabel, "3.5\" floppy cyl 80 alt 0 hd 2 sec 18"); spt = 18; capacity = "1.44 MB"; } gap = 0x54; } else if (D_flag) { transfer_rate = 250; if (drive_size == 5) { (void) strcpy(fd_vtoc->v_asciilabel, "5.25\" floppy cyl 40 alt 0 hd 2 sec 9"); if (fdchar.fdc_transfer_rate == 500) { /* * formatting a 360KB DD diskette in * a 1.2MB drive is not a good idea */ transfer_rate = 300; fdchar.fdc_steps = 2; } num_cyl = 40; gap = 0x50; capacity = "360 KB"; } else { (void) strcpy(fd_vtoc->v_asciilabel, "3.5\" floppy cyl 80 alt 0 hd 2 sec 9"); num_cyl = 80; gap = 0x54; capacity = "720 KB"; } sec_size = 512; spt = 9; } else if (m_flag) { #ifdef sparc transfer_rate = 500; #else /* * 416.67 KB/sec is the effective transfer rate of a "medium" * density diskette spun at 300 rpm instead of 360 rpm */ transfer_rate = 417; #endif (void) strcpy(fd_vtoc->v_asciilabel, "3.5\" floppy cyl 77 alt 0 hd 2 sec 8"); num_cyl = 77; sec_size = 1024; spt = 8; gap = 0x74; capacity = "1.2 MB"; } else if (E_flag) { (void) strcpy(fd_vtoc->v_asciilabel, "3.5\" floppy cyl 80 alt 0 hd 2 sec 36"); transfer_rate = 1000; num_cyl = 80; sec_size = 512; spt = 36; gap = 0x54; capacity = "2.88 MB"; } /* * Medium density diskettes have 1024 byte blocks. The dk_map * structure in dklabel.h assumes the blocks size is DEVBSIZE (512) * bytes. The dkl_nblk field is in terms of DEVBSIZE byte blocks * while the spt variable is in terms of the true block size on * the diskette. */ if (allmap.dka_map[2].dkl_nblk != (2 * num_cyl * spt * (m_flag ? 2 : 1))) { allmap.dka_map[1].dkl_cylno = num_cyl - 1; allmap.dka_map[0].dkl_nblk = 2 * (num_cyl - 1) * spt * (m_flag ? 2 : 1); allmap.dka_map[1].dkl_nblk = 2 * spt * (m_flag ? 2 : 1); allmap.dka_map[2].dkl_nblk = 2 * num_cyl * spt * (m_flag ? 2 : 1); if (allmap.dka_map[3].dkl_nblk) allmap.dka_map[3].dkl_nblk = 2 * (num_cyl - 1) * spt * (m_flag ? 2 : 1); if (allmap.dka_map[4].dkl_nblk) allmap.dka_map[4].dkl_nblk = 2 * spt * (m_flag ? 2 : 1); } /* initialize the vtoc structure */ fd_vtoc->v_nparts = 3; fd_vtoc->v_part[0].p_start = 0; fd_vtoc->v_part[0].p_size = ((num_cyl - 1) * 2 * spt * (m_flag ? 2 : 1)); fd_vtoc->v_part[1].p_start = ((num_cyl - 1) * 2 * spt * (m_flag ? 2 : 1)); fd_vtoc->v_part[1].p_size = 2 * spt * (m_flag ? 2 : 1); fd_vtoc->v_part[2].p_start = 0; fd_vtoc->v_part[2].p_size = num_cyl * 2 * spt * (m_flag ? 2 : 1); /* initialize the bios parameter blockstructure */ bpb->b_nfat = 2; if (E_flag && drive_size == 3) { bpb->b_spcl = 2; *rdirsec = (ushort_t)240; bpb->b_mediadescriptor = (char)0xF0; bpb->b_fatsec[0] = 9; bpb->b_fatsec[1] = 0; } else if (H_flag) { if (drive_size == 5) { bpb->b_spcl = 1; *rdirsec = 224; bpb->b_mediadescriptor = (char)0xF9; bpb->b_fatsec[0] = 7; bpb->b_fatsec[1] = 0; } else { bpb->b_spcl = 1; *rdirsec = 224; bpb->b_mediadescriptor = (char)0xF0; bpb->b_fatsec[0] = 9; bpb->b_fatsec[1] = 0; } } else if (drive_size == 5) { bpb->b_spcl = 2; *rdirsec = 112; bpb->b_mediadescriptor = (char)0xFD; bpb->b_fatsec[0] = 2; bpb->b_fatsec[1] = 0; } else if (drive_size == 3) { bpb->b_spcl = 2; *rdirsec = 112; bpb->b_mediadescriptor = (char)0xF9; bpb->b_fatsec[0] = 3; bpb->b_fatsec[1] = 0; } #ifndef sparc if (num_cyl > fdchar.fdc_ncyl || spt > fdchar.fdc_secptrack || transfer_rate > fdchar.fdc_transfer_rate) { (void) fprintf(stderr, gettext("%s: drive not capable of requested density, "), myname); perror(nullstring); exit(3); } #endif if (num_cyl != fdchar.fdc_ncyl || spt != fdchar.fdc_secptrack || transfer_rate != fdchar.fdc_transfer_rate) { /* * -- CAUTION -- * The SPARC fd driver is using a non-zero value in * fdc_medium to indicate the 360 rpm, 77 track, * 9 sectors/track, 1024 bytes/sector mode of operation * (similar to an 8", DS/DD, 1.2 MB floppy). * * The x86 fd driver uses fdc_medium as the diameter * indicator, either 3 or 5. It should not be modified. */ #ifdef sparc fdchar.fdc_medium = m_flag ? 1 : 0; #endif fdchar.fdc_transfer_rate = transfer_rate; fdchar.fdc_ncyl = num_cyl; fdchar.fdc_sec_size = sec_size; fdchar.fdc_secptrack = spt; if (ioctl(fd, FDIOSCHAR, &fdchar) == -1) { (void) fprintf(stderr, gettext( "%s: FDIOSCHAR (density selection) failed, "), myname); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); perror(nullstring); exit(3); } if (ioctl(fd, DKIOCSAPART, &allmap) == -1) { (void) fprintf(stderr, gettext("%s: DKIOCSAPART failed, "), myname); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); perror(nullstring); exit(3); } } if (interleave != 1 && interleave != fdgeom.dkg_intrlv) { fdgeom.dkg_intrlv = interleave; if (ioctl(fd, DKIOCSGEOM, &fdgeom) == -1) { (void) fprintf(stderr, gettext("%s: DKIOCSGEOM failed, "), myname); perror(nullstring); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } } cyl_size = 2 * sec_size * spt; if ((ibuf1 = (uchar_t *)malloc((size_t)cyl_size)) == 0 || (obuf = (uchar_t *)malloc((size_t)cyl_size)) == 0) { (void) fprintf(stderr, gettext("%s: can't malloc verify buffer, "), myname); perror(nullstring); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(4); } (void) memset(ibuf1, (uchar_t)0xA5, cyl_size); if (x_flag) goto skipformat; if (!(q_flag && f_flag)) { if (interleave != 1) { (void) printf(gettext( "Formatting %s, %d cylinders, %d sectors per trk, interleave=%d in %s\n"), capacity, num_cyl, spt, interleave, real_name); } else { (void) printf(gettext("Formatting %s in %s\n"), capacity, real_name); } } if (!f_flag) { (void) printf( gettext("Press return to start formatting floppy.")); while (getchar() != '\n') ; } /* * for those systems that support this ioctl, they will * return whether or not a diskette is in the drive. */ if (ioctl(fd, FDGETCHANGE, &chgd) == 0) { if (chgd & FDGC_CURRENT) { (void) fprintf(stderr, gettext("%s: no diskette in drive %s\n"), myname, real_name); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(4); } if (chgd & FDGC_CURWPROT) { (void) fprintf(stderr, gettext("%s: \"%s\" is write protected\n"), myname, real_name); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(1); } } if ((fbuf = (uchar_t *)malloc((unsigned)(4 * spt))) == 0) { (void) fprintf(stderr, gettext("%s: can't malloc format header buffer, "), myname); perror(nullstring); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } /* * do the format, a track at a time */ for (cyl = 0; cyl < (z_flag ? 1 : (int)num_cyl); cyl++) { /* * This is not the optimal ioctl to format the floppy. * The device driver should do do the work, * instead of this program mucking with a lot * of low-level, device-dependent code. */ fdr_seek.fdr_cmd[2] = cyl; if (ioctl(fd, FDRAW, &fdr_seek) == -1) { (void) fprintf(stderr, gettext("%s: seek to cyl %d failed\n"), myname, cyl); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } /* * Assume that the fd driver has issued a SENSE_INT * command to complete the seek operation. */ for (hd = 0; hd < fdchar.fdc_nhead; hd++) { p = (uchar_t *)fbuf; for (i = 1; i <= spt; i++) { *p++ = cyl; *p++ = hd; *p++ = i; /* sector # */ *p++ = (sec_size == 1024) ? 3 : 2; } /* * ASSUME the fd driver is going to set drive-select * bits in the second command byte */ fdr_form.fdr_cmd[1] = hd << 2; fdr_form.fdr_cmd[2] = (sec_size == 1024) ? 3 : 2; fdr_form.fdr_cmd[3] = spt; fdr_form.fdr_cmd[4] = gap; fdr_form.fdr_nbytes = 4 * spt; fdr_form.fdr_addr = (char *)fbuf; if (ioctl(fd, FDRAW, &fdr_form) == -1) { (void) fprintf(stderr, gettext( "%s: format of cyl %d head %d failed\n"), myname, cyl, hd); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } if (fdr_form.fdr_result[0] & 0xC0) { if (fdr_form.fdr_result[1] & 0x02) { (void) fprintf(stderr, gettext( /*CSTYLED*/ "%s: diskette is write protected\n"), myname); /* * restore the default * characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } (void) fprintf(stderr, gettext( "%s: format of cyl %d head %d failed\n"), myname, cyl, hd); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } } /* * do a quick verify */ if (!v_flag) { if (lseek(fd, cyl * cyl_size, 0) != cyl * cyl_size) { (void) fprintf(stderr, gettext("%s: bad seek to format verify, "), myname); perror(nullstring); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } if (read(fd, obuf, cyl_size) == cyl_size) { /* write some progress msg */ /* when each cylinder is done. */ if (!q_flag) (void) printf("."); } else { if (!q_flag) (void) printf(gettext("e\n")); (void) fprintf(stderr, gettext( "%s: can't read format data, "), myname); perror(nullstring); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } } else if (!q_flag) (void) printf("."); if (!q_flag) (void) fflush(stdout); } if (!q_flag) (void) printf("\n"); skipformat: if (v_flag) { /* * do a write & read verify of the entire diskette */ if (!q_flag && x_flag) (void) printf(gettext("Verifying %s in %s\n"), capacity, real_name); for (cyl = 0; cyl < (int)num_cyl; cyl++) { int val; if ((val = verify(fd, 2 * spt * cyl, cyl_size)) != 0) { perror(nullstring); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(val); } /* write some progress msg as */ /* each cylinder is done. */ if (!q_flag) (void) printf(gettext("v")); (void) fflush(stdout); } if (!q_flag) (void) printf("\n"); } if (lseek(fd, (off_t)0, 0) != 0) { (void) fprintf(stderr, gettext("%s: seek to blk 0 failed, "), myname); perror(nullstring); /* restore the default characteristics */ restore_default_chars(fd, save_fdchar, save_allmap); exit(3); } } /* * Restore the default characteristics of the floppy diskette. * Fdformat changes the characteristics in the process of formatting. * If fdformat fails while in the process of doing the format, fdformat * should clean up after itself and reset the driver back to the original * state. */ static void restore_default_chars(int fd, struct fd_char save_fdchar, struct dk_allmap save_allmap) { /* * When this function is called, fdformat is failing anyways, * so the errors are not processed. */ (void) ioctl(fd, FDIOSCHAR, &save_fdchar); (void) ioctl(fd, DKIOCSAPART, &save_allmap); /* * Before looking at the diskette's characteristics, format_diskette() * sets the x86 floppy driver to the default characteristics. * restore drive to default geometry and * characteristics. This ioctl isn't implemented on * sparc. */ (void) ioctl(fd, FDDEFGEOCHAR, NULL); } /* * See if any partitions on the device are mounted. Return 1 if a partition is * mounted. Return 0 otherwise. */ static int check_mount() { FILE *fp = NULL; int mfd; struct dk_cinfo dkinfo_tmp; struct mnttab mnt_record; struct mnttab *mp = &mnt_record; struct stat stbuf; char raw_device[MAXPATHLEN]; int found = 0; if ((fp = fopen(MNTTAB, "r")) == NULL) { perror(MNTTAB); exit(3); } while (getmntent(fp, mp) == 0) { if (strstr(mp->mnt_special, "/dev/fd") == NULL && strstr(mp->mnt_special, "/dev/disket") == NULL && strstr(mp->mnt_special, "/dev/c") == NULL) { continue; } (void) strcpy(raw_device, "/dev/r"); (void) strcat(raw_device, mp->mnt_special + strlen("/dev/")); /* * Attempt to open the device. If it fails, skip it. */ if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { continue; } /* * Must be a character device */ if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) { (void) close(mfd); continue; } /* * Attempt to read the configuration info on the disk. */ if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) { (void) close(mfd); continue; } /* * Finished with the opened device */ (void) close(mfd); /* * If it's not the disk we're interested in, it doesn't apply. */ if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype || dkinfo.dki_cnum != dkinfo_tmp.dki_cnum || dkinfo.dki_unit != dkinfo_tmp.dki_unit) { continue; } /* * It's a mount on the disk we're checking. If we are * checking whole disk, then we found trouble. We can * quit searching. */ if (U_flag) { if (!_dev_unmount(mp->mnt_special)) { (void) fprintf(stderr, gettext("%s: umount of %s failed\n"), myname, mp->mnt_special); found = 1; } } else { (void) fprintf(stderr, gettext("%s: %s is mounted (use -U flag)\n"), myname, mp->mnt_special); found = 1; } } return (found); } static void usage(char *str) { char *real_name, *alias_name; if ((real_name = media_findname("floppy")) == NULL) { if ((alias_name = _media_oldaliases("floppy")) != NULL) real_name = media_findname(alias_name); } if (str[0] != ' ') (void) printf("%s: %s\n", myname, str); (void) printf(gettext( /*CSTYLED*/ "\n usage: %s [-dDeEfHlLmMqUvx] [-b label] [-B file] [-t dostype] [devname]\n"), myname); (void) printf(gettext( /*CSTYLED*/ " -b label install \"label\" on media\n")); (void) printf(gettext( " -B file install special boot loader on MS-DOS media\n")); (void) printf(gettext( /*CSTYLED*/ " -d format MS-DOS media\n")); (void) printf(gettext( /*CSTYLED*/ " -D format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n")); (void) printf(gettext( " -e eject the media when done\n")); /*CSTYLED*/ (void) printf(gettext( /*CSTYLED*/ " -E format 2.88MB (3.5\") Extended-density diskette\n")); (void) printf(gettext( " -f \"force\" - don't wait for confirmation\n")); (void) printf(gettext( /*CSTYLED*/ " -H format 1.44MB (3.5\") or 1.2MB (5.25\") High-density diskette\n")); (void) printf(gettext( /*CSTYLED*/ " -l format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n")); (void) printf(gettext( /*CSTYLED*/ " -L format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n")); (void) printf(gettext( " -m format 1.2MB (3.5\") Medium-density diskette\n")); (void) printf(gettext( " -M format 1.2MB (3.5\") Medium-density diskette\n")); (void) printf(gettext( " -q quiet\n")); (void) printf(gettext( /*CSTYLED*/ " -t dos format MS-DOS media (same as -d)\n")); (void) printf(gettext( " -t nec format NEC-DOS media (with -M only)\n")); (void) printf(gettext( /*CSTYLED*/ " -U unmount media if it's mounted\n")); (void) printf(gettext( " -v verify each block of the media\n")); (void) printf(gettext( " -x skip the format, only install SunOS or DOS label\n")); (void) printf(gettext( " devname defaults to '%s'\n"), real_name ? real_name : gettext("no available default device")); exit(1); } static int verify(int fd, int blk, int len) { off_t off; char *nullstring = ""; off = (off_t)(blk * (m_flag ? 1024 : 512)); if (lseek(fd, off, 0) != off) { if (!q_flag) (void) printf(gettext("e\n")); (void) fprintf(stderr, gettext("%s: can't seek to write verify, "), myname); perror(nullstring); return (4); } if (write(fd, ibuf1, len) != len) { if (!q_flag) (void) printf(gettext("e\n")); if (blk == 0) (void) fprintf(stderr, gettext("%s: check diskette density, "), myname); else (void) fprintf(stderr, gettext("%s: can't write verify data, "), myname); perror(nullstring); return (4); } if (lseek(fd, off, 0) != off) { if (!q_flag) (void) printf(gettext("e\n")); (void) fprintf(stderr, gettext("%s: bad seek to read verify, "), myname); perror(nullstring); return (4); } if (read(fd, obuf, len) != len) { if (!q_flag) (void) printf(gettext("e\n")); (void) fprintf(stderr, gettext("%s: can't read verify data, "), myname); perror(nullstring); return (4); } if (memcmp(ibuf1, obuf, len)) { if (!q_flag) (void) printf(gettext("e\n")); (void) fprintf(stderr, gettext("%s: verify data failure\n"), myname); return (4); } return (0); } /* * write a SunOS label * NOTE: this function assumes fd_vtoc has been filled in with the * device specific information such as partition information * and the asciilabel */ static void write_SunOS_label(int fd, char *volname, struct vtoc *fd_vtoc) { char *nullstring = ""; fd_vtoc->v_sanity = VTOC_SANE; /* * The label structure is set up for DEV_BSIZE (512 byte) blocks, * even though a medium density diskette has 1024 byte blocks * See dklabel.h for more details. */ fd_vtoc->v_sectorsz = DEV_BSIZE; (void) strncpy(fd_vtoc->v_volume, volname, sizeof (fd_vtoc->v_volume)); /* let the fd driver finish constructing the label and writing it */ if (ioctl(fd, DKIOCSVTOC, fd_vtoc) == -1) { (void) fprintf(stderr, gettext("%s: write of SunOS label failed, "), myname); perror(nullstring); exit(3); } } /* * MS-DOS Disk layout: * * --------------------- * | Boot sector | * |-------------------| * | Reserved area | * |-------------------| * | FAT #1 | * |-------------------| * | FAT #2 | * |-------------------| * | Root directory | * |-------------------| * | | * | File area | * |___________________| */ /* * The following is a copy of MS-DOS 3.3 boot block. * It consists of the BIOS parameter block, and a disk * bootstrap program. * * The BIOS parameter block contains the right values * for the 3.5" high-density 1.44MB floppy format. * */ static uchar_t bootsec[512] = { 0xeb, 0x34, 0x90, /* 8086 short jump + displacement + NOP */ 'M', 'S', 'D', 'O', 'S', '3', '.', '3', /* OEM name & version */ 0, 2, 1, 1, 0, /* Start of BIOS parameter block */ 2, 224, 0, 0x40, 0xb, 0xf0, 9, 0, 18, 0, 2, 0, 0, 0, /* End of BIOS parameter block */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0xfa, 0x33, /* 0x34, start of the bootstrap. */ 0xc0, 0x8e, 0xd0, 0xbc, 0x0, 0x7c, 0x16, 0x7, 0xbb, 0x78, 0x0, 0x36, 0xc5, 0x37, 0x1e, 0x56, 0x16, 0x53, 0xbf, 0x2b, 0x7c, 0xb9, 0xb, 0x0, 0xfc, 0xac, 0x26, 0x80, 0x3d, 0x0, 0x74, 0x3, 0x26, 0x8a, 0x5, 0xaa, 0x8a, 0xc4, 0xe2, 0xf1, 0x6, 0x1f, 0x89, 0x47, 0x2, 0xc7, 0x7, 0x2b, 0x7c, 0xfb, 0xcd, 0x13, 0x72, 0x67, 0xa0, 0x10, 0x7c, 0x98, 0xf7, 0x26, 0x16, 0x7c, 0x3, 0x6, 0x1c, 0x7c, 0x3, 0x6, 0xe, 0x7c, 0xa3, 0x3f, 0x7c, 0xa3, 0x37, 0x7c, 0xb8, 0x20, 0x0, 0xf7, 0x26, 0x11, 0x7c, 0x8b, 0x1e, 0xb, 0x7c, 0x3, 0xc3, 0x48, 0xf7, 0xf3, 0x1, 0x6, 0x37, 0x7c, 0xbb, 0x0, 0x5, 0xa1, 0x3f, 0x7c, 0xe8, 0x9f, 0x0, 0xb8, 0x1, 0x2, 0xe8, 0xb3, 0x0, 0x72, 0x19, 0x8b, 0xfb, 0xb9, 0xb, 0x0, 0xbe, 0xd6, 0x7d, 0xf3, 0xa6, 0x75, 0xd, 0x8d, 0x7f, 0x20, 0xbe, 0xe1, 0x7d, 0xb9, 0xb, 0x0, 0xf3, 0xa6, 0x74, 0x18, 0xbe, 0x77, 0x7d, 0xe8, 0x6a, 0x0, 0x32, 0xe4, 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x4, 0x8f, 0x44, 0x2, 0xcd, 0x19, 0xbe, 0xc0, 0x7d, 0xeb, 0xeb, 0xa1, 0x1c, 0x5, 0x33, 0xd2, 0xf7, 0x36, 0xb, 0x7c, 0xfe, 0xc0, 0xa2, 0x3c, 0x7c, 0xa1, 0x37, 0x7c, 0xa3, 0x3d, 0x7c, 0xbb, 0x0, 0x7, 0xa1, 0x37, 0x7c, 0xe8, 0x49, 0x0, 0xa1, 0x18, 0x7c, 0x2a, 0x6, 0x3b, 0x7c, 0x40, 0x38, 0x6, 0x3c, 0x7c, 0x73, 0x3, 0xa0, 0x3c, 0x7c, 0x50, 0xe8, 0x4e, 0x0, 0x58, 0x72, 0xc6, 0x28, 0x6, 0x3c, 0x7c, 0x74, 0xc, 0x1, 0x6, 0x37, 0x7c, 0xf7, 0x26, 0xb, 0x7c, 0x3, 0xd8, 0xeb, 0xd0, 0x8a, 0x2e, 0x15, 0x7c, 0x8a, 0x16, 0xfd, 0x7d, 0x8b, 0x1e, 0x3d, 0x7c, 0xea, 0x0, 0x0, 0x70, 0x0, 0xac, 0xa, 0xc0, 0x74, 0x22, 0xb4, 0xe, 0xbb, 0x7, 0x0, 0xcd, 0x10, 0xeb, 0xf2, 0x33, 0xd2, 0xf7, 0x36, 0x18, 0x7c, 0xfe, 0xc2, 0x88, 0x16, 0x3b, 0x7c, 0x33, 0xd2, 0xf7, 0x36, 0x1a, 0x7c, 0x88, 0x16, 0x2a, 0x7c, 0xa3, 0x39, 0x7c, 0xc3, 0xb4, 0x2, 0x8b, 0x16, 0x39, 0x7c, 0xb1, 0x6, 0xd2, 0xe6, 0xa, 0x36, 0x3b, 0x7c, 0x8b, 0xca, 0x86, 0xe9, 0x8a, 0x16, 0xfd, 0x7d, 0x8a, 0x36, 0x2a, 0x7c, 0xcd, 0x13, 0xc3, '\r', '\n', 'N', 'o', 'n', '-', 'S', 'y', 's', 't', 'e', 'm', ' ', 'd', 'i', 's', 'k', ' ', 'o', 'r', ' ', 'd', 'i', 's', 'k', ' ', 'e', 'r', 'r', 'o', 'r', '\r', '\n', 'R', 'e', 'p', 'l', 'a', 'c', 'e', ' ', 'a', 'n', 'd', ' ', 's', 't', 'r', 'i', 'k', 'e', ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y', ' ', 'w', 'h', 'e', 'n', ' ', 'r', 'e', 'a', 'd', 'y', '\r', '\n', '\0', '\r', '\n', 'D', 'i', 's', 'k', ' ', 'B', 'o', 'o', 't', ' ', 'f', 'a', 'i', 'l', 'u', 'r', 'e', '\r', '\n', '\0', 'I', 'O', ' ', ' ', ' ', ' ', ' ', ' ', 'S', 'Y', 'S', 'M', 'S', 'D', 'O', 'S', ' ', ' ', ' ', 'S', 'Y', 'S', '\0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x55, 0xaa }; static int valid_DOS_boot(char *bootfile, uchar_t **bootloadp) { struct stat status; size_t sizebootldr; uchar_t *bootloader; int bfd; int boot_size = 0; int err; char *nullstring = ""; if ((err = stat(bootfile, &status)) != 0) { (void) fprintf(stderr, gettext("%s: \"%s\" stat error %d\n"), myname, bootfile, err); return (0); } if ((boot_size = status.st_size) < 512) { (void) fprintf(stderr, gettext("%s: short boot sector"), myname); perror(nullstring); return (0); } sizebootldr = (boot_size + 511) / 512 * 512; if ((bootloader = (uchar_t *)malloc((size_t)sizebootldr)) == NULL) { (void) fprintf(stderr, gettext("%s: malloc error\n"), myname); return (0); } /* switch to user to access the boot file */ (void) seteuid(getuid()); if ((bfd = open(bootfile, O_RDONLY)) == -1) { (void) fprintf(stderr, gettext("%s: could not open \"%s\": "), myname, bootfile); perror(nullstring); return (0); } /* restore effective id */ (void) seteuid(euid); if (read(bfd, bootloader, boot_size) != boot_size) { (void) fprintf(stderr, gettext("%s: read of MS-DOS boot file failed, "), myname); perror(nullstring); (void) close(bfd); return (0); } if (!((*bootloader == 0xE9 || (*bootloader == 0xEB && *(bootloader + 2) == 0x90)) && *(bootloader + 510) == 0x55 && *(bootloader + 511) == 0xAA)) { (void) fprintf(stderr, gettext("%s: invalid MS-DOS boot loader image\n"), myname); boot_size = 0; } (void) close(bfd); *bootloadp = bootloader; return (boot_size); } static void write_DOS_label(int fd, uchar_t *bootloadr, int bootlen, char *altbootname, char *doslabel, struct bios_param_blk *bpb, int rdirsec) { int i, j; int bootclen; size_t fat_bsize; ushort_t totalsec; uchar_t *fat_rdir; uchar_t *fatptr; char *nullstring = ""; if (bootlen < 512 || !bootloadr) { /* use default boot loader routine */ bootloadr = bootsec; bootlen = 512; } else (void) printf (gettext("%s: using \"%s\" for MS-DOS boot loader\n"), myname, altbootname); if (bootlen % 512 > 0) bootlen = (bootlen + 511) / 512 * 512; bpb->b_bps[0] = getlobyte(512); bpb->b_bps[1] = gethibyte(512); /* MS-DOS 5.0 supports only 1 reserved sector :-( */ bpb->b_res_sec[0] = 1; bpb->b_res_sec[1] = 0; totalsec = fdchar.fdc_ncyl * fdchar.fdc_nhead * fdchar.fdc_secptrack; bpb->b_totalsec[0] = getlobyte(totalsec); bpb->b_totalsec[1] = gethibyte(totalsec); bpb->b_spt[0] = fdchar.fdc_secptrack; bpb->b_spt[1] = 0; bpb->b_nhead[0] = fdchar.fdc_nhead; bpb->b_nhead[1] = 0; bpb->b_hiddensec[0] = 0; bpb->b_hiddensec[1] = 0; bpb->b_rdirents[0] = getlobyte(rdirsec); bpb->b_rdirents[1] = gethibyte(rdirsec); (void) memcpy((char *)(bootloadr + 0x0B), (char *)bpb, sizeof (struct bios_param_blk)); if (write(fd, bootloadr, 512) != 512) { (void) fprintf(stderr, gettext("%s: write of MS-DOS boot sector failed"), myname); perror(nullstring); exit(3); } bootloadr += 512; bootlen -= 512; fat_bsize = 512 * bpb->b_fatsec[0]; fat_rdir = (uchar_t *)malloc(fat_bsize); (void) memset(fat_rdir, (char)0, fat_bsize); *fat_rdir = bpb->b_mediadescriptor; *(fat_rdir + 1) = 0xFF; *(fat_rdir + 2) = 0xFF; bootclen = (bootlen + 512 * (int)bpb->b_spcl - 1) / (512 * (int)bpb->b_spcl); #define BAD_CLUSTER 0xFF7 for (i = 0, fatptr = fat_rdir+3; i < bootclen; i++) /* * pre-allocate any clusters used by boot loader if * loader will occupy more than 1 sector */ if (!(i & 01)) { *fatptr++ = BAD_CLUSTER & 0xFF; *fatptr = (BAD_CLUSTER >> 8) & 0x0F; } else { *fatptr = (*fatptr & 0x0F) | ((BAD_CLUSTER << 4) & 0xF0); fatptr++; *fatptr++ = (BAD_CLUSTER >> 4) & 0xFF; } for (i = 0; i < (int)bpb->b_nfat; ++i) if (write(fd, fat_rdir, fat_bsize) != fat_bsize) { (void) fprintf(stderr, gettext("%s: write of MS-DOS File Allocation Table failed, "), myname); perror(nullstring); exit(3); } rdirsec = bpb->b_rdirents[0]; rdirsec = 32 * (int)rdirsec / 512; if (b_flag) { struct timeval tv; struct tm *tp; ushort_t dostime; ushort_t dosday; /* the label can be no more than 11 characters */ j = min(11, (int)strlen(doslabel)); for (i = 0; i < j; i++) { fat_rdir[i] = uppercase(doslabel[i]); } for (; i < 11; i++) { fat_rdir[i] = ' '; } fat_rdir[0x0B] = 0x28; (void) gettimeofday(&tv, (struct timezone *)0); tp = localtime(&tv.tv_sec); /* get the time & day into DOS format */ dostime = tp->tm_sec / 2; dostime |= tp->tm_min << 5; dostime |= tp->tm_hour << 11; dosday = tp->tm_mday; dosday |= (tp->tm_mon + 1) << 5; dosday |= (tp->tm_year - 80) << 9; fat_rdir[0x16] = getlobyte(dostime); fat_rdir[0x17] = gethibyte(dostime); fat_rdir[0x18] = getlobyte(dosday); fat_rdir[0x19] = gethibyte(dosday); if (write(fd, fat_rdir, 512) != 512) { (void) fprintf(stderr, gettext("%s: write of MS-DOS FAT failed, "), myname); perror(nullstring); exit(3); } i = 1; } else { i = 0; } (void) memset(fat_rdir, (char)0, 512); for (; i < (int)rdirsec; ++i) { if (write(fd, fat_rdir, 512) != 512) { (void) fprintf(stderr, gettext("%s: write of MS-DOS root directory failed, "), myname); perror(nullstring); exit(3); } } /* * Write the rest of the boot loader if it's longer than one sector. * The clusters used are marked Bad in the FAT. * No directory entry exists for this file (so that it cannot be * deleted). */ if (bootlen && write(fd, bootloadr, bootlen) != bootlen) { (void) fprintf(stderr, gettext("%s: write of MS-DOS boot sectors failed"), myname); perror(nullstring); exit(3); } } static void write_NEC_DOS_label(int fd, char *doslabel) { struct bios_param_blk *bpb; ushort_t fatsec; ushort_t rdirsec; char fat_rdir[1024]; int i, j, m = 1; uchar_t bootsec_NEC[1024]; char *nullstring = ""; uchar_t bios_param_NEC[30] = { 0xeb, 0x1c, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1, 0x1, 0x0, 0x2, 0xc0, 0x0, 0xd0, 0x4, 0xfe, 0x2, 0x0, 0x8, 0x0, 0x2, 0x0, 0x0, 0x0 }; uchar_t fatdir[32] = { 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5 }; (void) memset(bootsec_NEC, (char)0, 1024); (void) memcpy(&bootsec_NEC, &bios_param_NEC, 30); bpb = (struct bios_param_blk *)&(bootsec_NEC[0xb]); if (write(fd, &bootsec_NEC[0], 1024) != 1024) { (void) fprintf(stderr, gettext( "%s: write of NEC-DOS boot sector failed, "), myname); perror(nullstring); exit(3); } (void) memset(fat_rdir, (char)0, 1024); fatsec = bpb->b_fatsec[0]; for (i = 0; i < (int)bpb->b_nfat * (int)fatsec; ++i) { if ((i % (int)fatsec) == 0) { fat_rdir[0] = bpb->b_mediadescriptor; fat_rdir[1] = (char)0xff; fat_rdir[2] = (char)0xff; fat_rdir[3] = 0; fat_rdir[4] = 0; fat_rdir[5] = 0; } else { fat_rdir[0] = 0; fat_rdir[1] = 0; fat_rdir[2] = 0; fat_rdir[3] = 0; fat_rdir[4] = 0; fat_rdir[5] = 0; } if (write(fd, &fat_rdir[0], 1024) != 1024) { (void) fprintf(stderr, /*CSTYLED*/ gettext("%s: write of NEC-DOS File Allocation Table failed, "), myname); perror(nullstring); exit(3); } } #ifndef sparc /* LINTED */ rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024; #else rdirsec = (int)htols(bpb->b_rdirents[0]) * 32 /1024; #endif if (b_flag) { struct timeval tv; struct tm *tp; ushort_t dostime; ushort_t dosday; /* the label can be no more than 11 characters */ j = min(11, (int)strlen(doslabel)); for (i = 0; i < j; i++) { fat_rdir[i] = uppercase(doslabel[i]); } for (; i < 11; i++) { fat_rdir[i] = ' '; } fat_rdir[0xb] = 0x28; (void) gettimeofday(&tv, (struct timezone *)0); tp = localtime(&tv.tv_sec); /* get the time & day into DOS format */ dostime = tp->tm_sec / 2; dostime |= tp->tm_min << 5; dostime |= tp->tm_hour << 11; dosday = tp->tm_mday; dosday |= (tp->tm_mon + 1) << 5; dosday |= (tp->tm_year - 80) << 9; fat_rdir[0x16] = getlobyte(dostime); fat_rdir[0x17] = gethibyte(dostime); fat_rdir[0x18] = getlobyte(dosday); fat_rdir[0x19] = gethibyte(dosday); if (write(fd, &fat_rdir[0], 1024) != 1024) { (void) fprintf(stderr, /*CSTYLED*/ gettext("%s: write of NEC-DOS root directory failed, "), myname); perror(nullstring); exit(3); } (void) memset(fat_rdir, (char)0, 512); i = 1; } else { i = 0; while (m < 1024) { (void) memcpy(&fat_rdir[m], &fatdir, 31); m = m + 32; } } for (; i < (int)rdirsec; ++i) { if (write(fd, &fat_rdir[0], 1024) != 1024) { (void) fprintf(stderr, /*CSTYLED*/ gettext("%s: write of NEC-DOS root directory failed, "), myname); perror(nullstring); exit(3); } } }