#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
#include <locale.h>
#include <libintl.h>
#include <volmgt.h>
#include <sys/isa_defs.h>
#include <sys/ioccom.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/dklabel.h>
#include <sys/ioctl.h>
#include <sys/dkio.h>
#include <sys/fdio.h>
#include <sys/stat.h>
#include <sys/vtoc.h>
#include <sys/mnttab.h>
#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))
#define PATTERN_1 0x55;
#define PATTERN_2 0xaa;
#define PATTERN_3 0xff;
#define PATTERN_4 0x00;
static struct fd_char fdchar;
static struct dk_geom fdgeom;
static struct dk_allmap allmap;
static struct dk_cinfo dkinfo;
extern char *optarg;
extern int optind;
static uchar_t *ibuf1;
static uchar_t *obuf;
static char *myname;
static int fd_debug = 1;
static int b_flag = 0;
static int d_flag = 0;
static int D_flag = 0;
static int e_flag = 0;
static int E_flag = 0;
static int f_flag = 0;
static int H_flag = 0;
static int m_flag = 0;
static int n_flag = 0;
static int q_flag = 0;
static int U_flag = 0;
static int v_flag = 0;
static int x_flag = 0;
static int z_flag = 0;
static int interleave = 1;
static uid_t euid = 0;
struct bios_param_blk {
uchar_t b_bps[2];
uchar_t b_spcl;
uchar_t b_res_sec[2];
uchar_t b_nfat;
uchar_t b_rdirents[2];
uchar_t b_totalsec[2];
char b_mediadescriptor;
uchar_t b_fatsec[2];
uchar_t b_spt[2];
uchar_t b_nhead[2];
uchar_t b_hiddensec[2];
};
char *_media_oldaliases(char *name);
int _dev_mounted(char *path);
int _dev_unmount(char *path);
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++;
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':
d_flag++;
break;
case 'D':
case 'L':
case 'l':
D_flag++;
break;
case 'e':
e_flag++;
break;
case 'E':
E_flag++;
break;
case 'f':
f_flag++;
break;
case 'H':
case 'h':
H_flag++;
break;
#if 0
case 'i':
interleave = atol(optarg);
if (interleave <= 0) {
(void) fprintf(stderr, gettext(
"%s: invalid interleave\n"), myname);
exit(1);
}
break;
#endif
case 'M':
case 'm':
m_flag++;
break;
case 'x':
x_flag++;
break;
case 'q':
q_flag++;
break;
case 't':
if (strcmp(optarg, "nec") == 0) {
n_flag++;
}
if (strcmp(optarg, "dos") == 0) {
d_flag++;
}
break;
case 'U':
U_flag++;
break;
case 'v':
case 'V':
v_flag++;
break;
case 'Z':
if (!fd_debug) {
usage(gettext("unknown argument"));
}
(void) printf(gettext("\nFormat cyl Zero only\n"));
z_flag++;
break;
default:
usage(" ");
}
}
if (optind < argc -1) {
usage(gettext("more than one device name argument"));
}
if (optind == argc -1) {
dev_name = argv[optind];
}
if (D_flag && H_flag) {
usage(gettext("switches -D, -L and -H incompatible"));
}
if (D_flag && E_flag) {
usage(gettext("switches -D, -L and -E incompatible"));
}
if (H_flag && E_flag) {
usage(gettext("switches -H and -E incompatible"));
}
if (n_flag && d_flag) {
usage(gettext("switches nec and dos incompatible"));
}
if (n_flag && !m_flag) {
usage(gettext("switch -M required for NEC-DOS"));
}
if (D_flag && m_flag) {
usage(gettext("switches -D, -L and -M incompatible"));
}
if (d_flag && m_flag) {
usage(gettext("switches -d and -M incompatible"));
}
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);
}
}
if (access(real_name, R_OK|W_OK) < 0) {
perror(real_name);
exit(1);
}
euid = geteuid();
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);
}
}
(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);
}
(void) fprintf(stderr, gettext("%s: could not open \"%s\": "),
myname, real_name);
perror(nullstring);
exit(1);
}
(void) seteuid(euid);
if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
(void) fprintf(stderr,
gettext("%s: DKIOCINFO failed, "), myname);
perror(nullstring);
exit(3);
}
if (check_mount() != 0) {
exit(3);
}
(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)
if (ioctl(fd, FDEJECT, 0)) {
(void) fprintf(stderr,
gettext("%s: could not eject diskette, "), myname);
perror(nullstring);
exit(3);
}
return (0);
}
void
format_diskette(int fd, char *real_name, struct vtoc *fd_vtoc,
struct bios_param_blk *bpb, int *rdirsec)
{
int transfer_rate = 1000;
int sec_size = 512;
uchar_t gap = 0x54;
uchar_t *fbuf, *p;
char *capacity = NULL;
int cyl_size;
int i;
int chgd;
int cyl, hd;
int size_of_part, size_of_dev;
int spt = 36;
int drive_size;
uchar_t num_cyl = 80;
char *nullstring = "";
struct fd_char save_fdchar;
struct dk_allmap save_allmap;
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,
0
};
(void) ioctl(fd, FDDEFGEOCHAR, NULL);
if (ioctl(fd, DKIOCGAPART, &allmap) == -1) {
(void) fprintf(stderr,
gettext("%s: DKIOCGAPART failed, "), myname);
perror(nullstring);
exit(3);
}
save_allmap = allmap;
if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) {
(void) fprintf(stderr,
gettext("%s: FDIOGCHAR failed, "), myname);
perror(nullstring);
exit(3);
}
save_fdchar = fdchar;
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,
gettext("%s: The entire diskette must be formatted. Invalid device name.\n"),
myname);
exit(3);
}
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;
if ((E_flag | H_flag | D_flag | m_flag) == 0) {
switch (fdchar.fdc_transfer_rate) {
case 1000:
E_flag++;
break;
case 500:
default:
H_flag++;
break;
#ifndef sparc
case 250:
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) {
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
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";
}
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);
}
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);
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) {
#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_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_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_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_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')
;
}
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_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_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_default_chars(fd, save_fdchar, save_allmap);
exit(3);
}
for (cyl = 0; cyl < (z_flag ? 1 : (int)num_cyl); cyl++) {
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_default_chars(fd, save_fdchar, save_allmap);
exit(3);
}
for (hd = 0; hd < fdchar.fdc_nhead; hd++) {
p = (uchar_t *)fbuf;
for (i = 1; i <= spt; i++) {
*p++ = cyl;
*p++ = hd;
*p++ = i;
*p++ = (sec_size == 1024) ? 3 : 2;
}
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_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(
"%s: diskette is write protected\n"),
myname);
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_default_chars(fd, save_fdchar,
save_allmap);
exit(3);
}
}
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_default_chars(fd, save_fdchar,
save_allmap);
exit(3);
}
if (read(fd, obuf, cyl_size) == cyl_size) {
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_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) {
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_default_chars(fd, save_fdchar,
save_allmap);
exit(val);
}
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_default_chars(fd, save_fdchar, save_allmap);
exit(3);
}
}
static void
restore_default_chars(int fd,
struct fd_char save_fdchar,
struct dk_allmap save_allmap)
{
(void) ioctl(fd, FDIOSCHAR, &save_fdchar);
(void) ioctl(fd, DKIOCSAPART, &save_allmap);
(void) ioctl(fd, FDDEFGEOCHAR, NULL);
}
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/"));
if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) {
continue;
}
if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
(void) close(mfd);
continue;
}
if (ioctl(mfd, DKIOCINFO, &dkinfo_tmp) < 0) {
(void) close(mfd);
continue;
}
(void) close(mfd);
if (dkinfo.dki_ctype != dkinfo_tmp.dki_ctype ||
dkinfo.dki_cnum != dkinfo_tmp.dki_cnum ||
dkinfo.dki_unit != dkinfo_tmp.dki_unit) {
continue;
}
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(
"\n usage: %s [-dDeEfHlLmMqUvx] [-b label] [-B file] [-t dostype] [devname]\n"),
myname);
(void) printf(gettext(
" -b label install \"label\" on media\n"));
(void) printf(gettext(
" -B file install special boot loader on MS-DOS media\n"));
(void) printf(gettext(
" -d format MS-DOS media\n"));
(void) printf(gettext(
" -D format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
(void) printf(gettext(
" -e eject the media when done\n"));
(void) printf(gettext(
" -E format 2.88MB (3.5\") Extended-density diskette\n"));
(void) printf(gettext(
" -f \"force\" - don't wait for confirmation\n"));
(void) printf(gettext(
" -H format 1.44MB (3.5\") or 1.2MB (5.25\") High-density diskette\n"));
(void) printf(gettext(
" -l format 720KB (3.5\") or 360KB (5.25\") Double-density diskette\n"));
(void) printf(gettext(
" -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(
" -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(
" -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);
}
static void
write_SunOS_label(int fd, char *volname, struct vtoc *fd_vtoc)
{
char *nullstring = "";
fd_vtoc->v_sanity = VTOC_SANE;
fd_vtoc->v_sectorsz = DEV_BSIZE;
(void) strncpy(fd_vtoc->v_volume, volname, sizeof (fd_vtoc->v_volume));
if (ioctl(fd, DKIOCSVTOC, fd_vtoc) == -1) {
(void) fprintf(stderr,
gettext("%s: write of SunOS label failed, "), myname);
perror(nullstring);
exit(3);
}
}
static uchar_t bootsec[512] = {
0xeb, 0x34, 0x90,
'M', 'S', 'D', 'O', 'S', '3', '.', '3',
0, 2, 1, 1, 0,
2, 224, 0, 0x40, 0xb, 0xf0, 9, 0,
18, 0, 2, 0, 0, 0,
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,
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);
}
(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);
}
(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) {
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);
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++)
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;
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);
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);
}
}
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,
gettext("%s: write of NEC-DOS File Allocation Table failed, "), myname);
perror(nullstring);
exit(3);
}
}
#ifndef sparc
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;
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);
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,
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,
gettext("%s: write of NEC-DOS root directory failed, "), myname);
perror(nullstring);
exit(3);
}
}
}