ast@cs.vu.nl (Andy Tanenbaum) (06/06/91)
echo x - format.c sed '/^X/s///' > format.c << '/' X/* format - floppy disk format (PC-MINIX) Author: D. Chapman */ X X/* Author: Donald E. Chapman. Copyright 1991 by Donald E. Chapman X * X * Usage: format [-q][-a][special [kbsize]][-v [dosvollabel]] X * X * Flags: -q: quiet will skip the "are you sure" prompt. X * -v: volume label added along with structures Dos needs. X * If no label is given format will prompt for it. X * -a: sort interactive list alphabetically rather than by size. X * X * Format allows super user to format disks. If it is suid X * then it allows others to format if they are at the console. X * Format will format all seven of the non-automatic X * disk/media combinations that PC-Minix supports. It will X * also try to format automatics (minor 0 through 3) if a device X * size was given when the node was made. Format usually expects X * special devices to have sizes. X * Format will optionally add the structures Dos needs, X * including a "non-bootable" message, if either the device X * name is a dos device, like dosA, or if the -v flag is used. X * If a special device is specified in the command line then X * a size may also be specified there. If a size is specified X * in the command line the size must agree with the capability X * of the special device. X * If no special device is specified in the command line X * format will interactively help you to determine which of X * your drives you wish to format on. It actually allows X * the automatic devices to be formatted that way even if X * they were made with a size of zero. X * X * Warning: Some disk drives are media sensitive and on them you X * should use DD or HD media as appropriate for the density X * you are formatting. For some media sensitive drives if X * you try to format media of the wrong density the disk X * can not be formatted correctly. X * X * Examples: format /dev/at0 format disk in /dev/at0. X * format /dev/at0 360 format disk to size 360. X * format /dev/dosA format for Dos. X * format /dev/fd1 -v DOS_DISK format labeled Dos disk. X * format interactive mode formatting. X * X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <minix/config.h> X#include <minix/const.h> X#ifndef _V15_ X#include <minix/minlib.h> X#endif X#include <dirent.h> X#include <ctype.h> X#include <signal.h> X#include <stdlib.h> X#include <time.h> X#include <unistd.h> X#include <fcntl.h> X#include <string.h> X#include <stdio.h> X X/* Kludges */ X#ifdef _V15_ X#define mknod4 mknod X#endif X X/* Macros */ X#define maj(d) ( ((d) >> MAJOR) & BYTE) X#define min(d) ( ((d) >> MINOR) & 0x7F) /* ignore format bit */ X#define illegal(s) ((s)!=360 && (s)!=720 && (s)!=1200 && (s)!=1440) X X/* For the list of existing drives */ Xstruct drive { X dev_t device; X int dos_type; X int is_auto; X off_t msize; X char *name; X struct drive *next; X}; X Xstruct param_struct { /* Must align with diskparm.h */ X unsigned char s1; X unsigned char s2; X unsigned char motor_off; X unsigned char sec_size_code; /* Needed */ X unsigned char sec_per_cyl; /* Needed */ X unsigned char gap; X unsigned char data_len; X unsigned char gap_fmt; /* Needed */ X unsigned char fill_byte; /* Needed */ X unsigned char head_settle; X unsigned char motor_start; X}; X Xstruct table_entry { X unsigned char cyl; X unsigned char head; X unsigned char sector; X unsigned char sec_size_code; X}; X X/* Some constants */ X#define NULL_L (struct drive *)NULL X#define NULL_D (struct dirent *)NULL X#define SEC_SIZE 512 X#define NR_HEADS 2 X#define F_MAJOR 2 X#define F_DRIVE_BITS 0x03 X#define F_BIT 0x80 X#define UNLINK TRUE X#define OMIT FALSE X#define NAME_MAX 14 /* was in limit.h strangely */ X#define PATH_MAX 255 X#define FAIL_MOUNTED TRUE X#define NOT_MOUNTED FALSE X X#define FAIL_OPEN 1 X#define FAIL_SEEK 2 X#define FAIL_WRITE 4 X#define MAX_TRIES 10 X X#ifndef CONSOLE X#define CONSOLE "/dev/tty0" X#endif X X/* Constants for DOS */ X#define BOOT_SIZE sizeof(non_boot) X#define VE_SIZE sizeof(vol_entry) X#define VEL_SIZE sizeof(vol_entry.label) X#define BLANKS " " /* max 11 */ X#define SMALL_DIR 0x70 X#define LARGE_DIR 0xE0 X#define DIRENT_SIZE 32 X#define VOL_ARC 0x28 X#define Y_SHIFT 9 X#define MON_SHIFT 5 X#define H_SHIFT 11 X#define MIN_SHIFT 5 X#define SEC_DIV 2 X#define DOS_BASE_YEAR 80 X#define FAT_SIZE 3 X#define MAGIC_SIZE 5 X#define MAGIC_LOC 510 X#define NO_FAILURE 0 X#define FAIL_D0 1 X#define FAIL_DCLEAR 2 X#define FAIL_DFAT2 4 X#define FAIL_DVOL 8 X#define FAIL_DFAT1 16 X Xstatic char version[] = {"format V1.1, Copyright 1991 by Donald E. Chapman"}; X X/* Globals */ Xstruct param_struct param; X Xunsigned char non_boot[113] = { /* hand constructed with loving care */ X 0xEB, 0x50, 0x90, 0x4D, 0x49, 0x4E, 0x49, 0x58, 0x66, 0x31, X 0x31, 0x00, 0x02, 0x01, 0x01, 0x00, 0x02, 0xE0, 0x00, 0x60, X 0x09, 0xF9, 0x07, 0x00, 0x0F, 0x00, 0x02, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x0D, 0x0A, 0x4E, 0x6F, 0x74, 0x20, 0x61, 0x20, X 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x20, 0x64, 0x69, 0x73, X 0x6B, 0x2E, 0x20, 0x52, 0x65, 0x70, 0x6C, 0x61, 0x63, 0x65, X 0x20, 0x61, 0x6E, 0x64, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, X 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x2E, 0x0D, X 0x0A, 0x00, 0xFA, 0x33, 0xC0, 0x8E, 0xD0, 0x8E, 0xD8, 0xBC, X 0x00, 0x7C, 0xBE, 0x20, 0x7C, 0xFC, 0xAC, 0x3C, 0x00, 0x74, X 0x06, 0xB4, 0x0E, 0xCD, 0x10, 0xEB, 0xF5, 0x33, 0xC0, 0xCD, X 0x16, 0xCD, 0x19 X}; X X/* Magic number for DOS and fat bytes */ Xstatic unsigned char f_bytes[5] = {0x55, 0xAA, 0xF9, 0xFF, 0xFF}; X X/* Volume label and date */ Xstruct vol_entry { X char label[11]; X unsigned char attrib; X char reserv[10]; X short time; X short date; X} vol_entry; Xstatic char vol_temp[20] = {'\0'}; X X/* Formatting work area */ Xstatic union u { X char buffer[BLOCK_SIZE]; X struct p { X struct table_entry /* max 128 */ X table[BLOCK_SIZE / 2 / sizeof(struct table_entry)]; X struct param_struct param; X } p; X} u; X X/* MINIX Drive/media combinations (automatics are mapped.) X * minor 0-3 4-7 8-11 12-15 12-15 16-19 16-19 20-23 24-27 28-31 X * dtype 0 1 2 3 3 4 4 5 6 7 X * drv. au. 360 1.2M 720 1.44M 720 1.44M 1.2M 1.2M 1.44M X * med. au. 360 1.2M 360 360 720 720 360 720 1.44M X */ X Xint dsize[] = {0, 360, 1200, 720, 720, 1200, 1200, 1440}; Xunsigned char cyl_table[] = {0, 39, 79, 39, 79, 39, 79, 79}; Xunsigned char gap_fmt_table[] = {0, 0x50, 0x54, 0x50, 0x50, 0x50, 0x50, 0x54}; Xunsigned char media_id[] = {0, 0xFD, 0xF9, 0xFD, 0xF9, 0xFD, 0xF9, 0xF0}; Xunsigned char sector_table[] = {0, 9, 15, 9, 9, 9, 9, 18}; Xunsigned char sec_cluster[] = {0, 2, 1, 2, 2, 2, 2, 1}; Xunsigned char sec_fat[] = {0, 2, 7, 2, 3, 2, 3, 9}; Xunsigned char dir_size[] = {0, SMALL_DIR, LARGE_DIR, SMALL_DIR, X SMALL_DIR, SMALL_DIR, SMALL_DIR, LARGE_DIR}; X X/* Chart of dtype mapping. 3.5 inch 1440's serve as 720's too. X * dsize X * map[u][m] 360 720 1200 1440 X * usize 360 1 3 5 3 X * usize 720 . 4 6 4 X * usize 1200 . . 2 . X * usize 1440 . . . 7 X */ Xint dtype_map[4][4] = {1, 3, 5, 3, -1, 4, 6, 4, -1, -1, 2, -1, -1, -1, -1, 7}; X Xchar *progname, *nname; Xint interrupt = FALSE; /* If sigint or sigquit occurs */ Xint a_flag = FALSE; /* Don't sort alphabetically */ Xint v_flag = 0; /* Can be -1, 0 or +n */ Xint dos_type = FALSE; Xint interactive = TRUE; Xint max_cyl; Xint max_len; /* Length of longest special name */ Xint msize = 0; /* usually holds media size in Kb */ Xint usize = 0; /* User specified size in Kb */ Xoff_t dir_start; Xoff_t dir_max; Xoff_t second_fat; X X_PROTOTYPE(void usage, (void)); X_PROTOTYPE(void quit, (char *mess, char *more, int linked)); X_PROTOTYPE(void add_to_list, (struct drive ** h, struct drive * f)); X_PROTOTYPE(void make_list, (struct drive ** drive_list)); X_PROTOTYPE(struct drive * make_selection, (struct drive * list_head)); X_PROTOTYPE(struct drive * command_line_check, (struct drive * dp)); X_PROTOTYPE(void set_parameters, (int dtype)); X_PROTOTYPE(void adjust_bootblock, (int dtype, int msize)); X_PROTOTYPE(int mounted, (char *dname)); X_PROTOTYPE(void Sigint, (int s)); X_PROTOTYPE(void Sigquit, (int s)); X_PROTOTYPE(void prepare_node, (Dev_t device)); X_PROTOTYPE(int format_track, (int cyl, int head, int logical)); X_PROTOTYPE(int full_format, (void)); X_PROTOTYPE(int add_vol_label, (int fd)); X_PROTOTYPE(int add_structures, (char *dname, Dev_t device)); X_PROTOTYPE(int test_error, (char *dname)); X_PROTOTYPE(int main, (int argc, char *argv[])); X X Xvoid usage() X{ X fprintf(stderr, X "\nUsage: %s [-q][-a][special [kbsize]][-v [dosvollabel]]\n", X progname); X exit(EXIT_FAILURE); X} X Xvoid quit(mess, more, linked) Xchar *mess; Xchar *more; Xint linked; X{ X if (linked) unlink(nname); /* remove temporary */ X fprintf(stderr, "\n%s: %s%s.\n", progname, mess, more); X exit(EXIT_FAILURE); X} X Xvoid add_to_list(h, f) /* by sizes or alphabetic */ Xstruct drive **h, *f; X{ X /* At the tail */ X if ((*h) == NULL_L) { X f->next = (*h); X (*h) = f; X } else if (a_flag && strcmp((*h)->name, f->name) > 0 || X !a_flag && ((*h)->msize > f->msize || X (*h)->msize == f->msize && ( X (*h)->device > f->device || X (*h)->device == f->device && X (*h)->dos_type > f->dos_type) X ) X ) { X /* Amid the list */ X f->next = *h; X (*h) = f; X } else /* Recursion */ X add_to_list(&((*h)->next), f); X} X X/* Make a list of existing floppy drives found in /dev */ Xvoid make_list(drive_list) Xstruct drive **drive_list; X{ X struct drive *dp; X DIR *dd1; X struct stat dstat; X struct dirent *dentry; X char *dname; X int sres, nlen; X X max_len = 0; X dd1 = opendir("/dev"); X while ((dentry = readdir(dd1)) != NULL_D) { X if (dentry->d_name[0] != '.') { X dname = (char *) malloc(strlen(dentry->d_name) + 6); X strcpy(dname, "/dev/"); X strcat(dname, dentry->d_name); X sres = stat(dname, &dstat); X if (sres >= 0 X && S_ISBLK(dstat.st_mode) X && maj(dstat.st_rdev) == F_MAJOR) { X dp = (struct drive *) malloc(sizeof(struct drive)); X dp->device = dstat.st_rdev; X dp->msize = dstat.st_size / BLOCK_SIZE; X dp->name = dname; X nlen = strlen(dp->name); X if (nlen > max_len) max_len = nlen; X dp->dos_type = !strncmp(dentry->d_name, "dos", 3); X if (!((dstat.st_rdev >> 2) & 0x1F)) X dp->is_auto = TRUE; X else X dp->is_auto = FALSE; X add_to_list(drive_list, dp); X } else X free(dname); /* no leaks */ X } X } X closedir(dd1); X} /* make list */ X X/* Interactive query routine */ Xstruct drive X*make_selection(list_head) Xstruct drive *list_head; X{ X static char insize[10] = {'\0'}; X static char choice[5] = {'\0'}; X struct drive *dp; X int i, m, n, minor, drnr, dtype, fbit; X dev_t device; X X if (list_head == NULL_L) X quit("Use mknod with specific minor devices first", "", OMIT); X printf("\nYour floppy drives:\n\n"); X for (dp = list_head, i = 1; X dp != NULL_L; X dp = dp->next, i++) { X device = dp->device; X fbit = device & F_BIT; X minor = min(device); X drnr = minor & F_DRIVE_BITS; X dtype = minor >> 2; X msize = dp->msize; X if (dp->is_auto) printf( X "Number %2d %-*s ? Kb on %4s KB drive %d%s Auto.%s\n", X i, max_len, dp->name, msize ? itoa(msize) : "?", X drnr, dp->dos_type ? " Dos" : " ", X fbit ? " Fbit" : ""); X else X printf("Number %2d %-*s %4d Kb on %4d KB drive %d%s %s\n", X i, max_len, dp->name, msize, dsize[dtype], X drnr, dp->dos_type ? " Dos" : " ", X fbit ? " Fbit" : ""); X } X m = i - 1; X printf("\nWhich do you wish to format (number)? "); X fgets(choice, 4, stdin); X n = atoi(choice); X if (n < 1 || n > m) exit(EXIT_FAILURE); X for (dp = list_head, i = 1; i != n && dp != NULL_L; dp = dp->next, i++); X msize = dp->msize; X if (dp->is_auto) { X /* Try to determine the drive type */ X printf("This is an automatic drive.\n"); X printf("Format how many Kb (360 720 1200 1440) ? "); X fgets(insize, 7, stdin); X usize = atoi(insize); X if (illegal(msize)) { X printf("What is the drive size (360 720 1200 1440) ? "); X fgets(insize, 7, stdin); X msize = atoi(insize); X } X } X return(dp); X} /* make selection */ X X/* Check the name and size from the command line */ Xstruct drive X*command_line_check(dp) Xstruct drive *dp; X{ X struct stat dstat; X char *ptr; X int fd; X int dtype; X X if (dp == NULL_L) usage(); /* at least special */ X X /* Check spelling of name for DOS */ X ptr = (char *) (dp->name + strlen(dp->name)); X while (*ptr != '/' && ptr > dp->name) ptr--; X if (*ptr == '/') ptr++; X X /* Also perhaps there was -v after special name */ X dp->dos_type = dos_type || !strncmp(ptr, "dos", 3); X fd = open(dp->name, O_RDONLY); X if (fd < 0) quit("Can't open ", dp->name, OMIT); X if (fstat(fd, &dstat) != 0) quit("Can't stat ", dp->name, OMIT); X close(fd); X if (!S_ISBLK(dstat.st_mode) || maj(dstat.st_rdev) != F_MAJOR) X quit("Not a floppy ", dp->name, OMIT); X dp->device = dstat.st_rdev; X dtype = min(dp->device) >> 2; X msize = dp->msize = dstat.st_size / BLOCK_SIZE; X if (!usize) usize = msize; X X /* Auto will set device as determined by usize and msize */ X if (!dtype) { X if (!msize) quit("Device size unknown. Mknod with size, ", X dp->name, OMIT); X dp->is_auto = TRUE; X } else { X dp->is_auto = FALSE; X if (!msize || msize != usize) X quit("Size error, drive is ", itoa(msize), OMIT); X } X return(dp); X} /* command_line_check */ X X/* Set the values for formatting parameters */ Xvoid set_parameters(dtype) Xint dtype; X{ X param.sec_size_code = (unsigned char) 2; X param.sec_per_cyl = sector_table[dtype]; /* sec/cyl */ X param.gap_fmt = gap_fmt_table[dtype]; X param.fill_byte = (unsigned char) 0xF6; /* traditional */ X} X X/* Put proper values into the boot block header */ Xvoid adjust_bootblock(dtype, msize) Xint dtype; Xint msize; X{ X non_boot[0x0D] = sec_cluster[dtype]; /* sec/cluster */ X non_boot[0x11] = dir_size[dtype]; X non_boot[0x13] = X (unsigned char) (msize * (BLOCK_SIZE / SEC_SIZE)) % 256; X non_boot[0x14] = X (unsigned char) (msize * (BLOCK_SIZE / SEC_SIZE)) / 256; X non_boot[0x15] = media_id[dtype]; /* media id. */ X non_boot[0x16] = sec_fat[dtype]; /* sec/fat */ X non_boot[0x18] = sector_table[dtype]; /* sec/cyl */ X} X X/* See if drive is already mounted by any name. */ Xint mounted(dname) Xchar *dname; X{ X int n, ddrive, mdrive; X struct stat dstat, mstat; X#ifdef _V15_ X FILE *fp; X char line[60],mname[20]; X#else X char mdevice[PATH_MAX + 1], mounted[PATH_MAX + 1], vers[5], flag[15]; X#endif X /* Device may be mounted under a pseudonym */ X stat(dname, &dstat); X ddrive = dstat.st_rdev & F_DRIVE_BITS; X#ifdef _V15_ X if((fp = fopen("/etc/mtab","r")) == (FILE *) NULL) return(FAIL_MOUNTED); X while (TRUE) { X fgets(line,59,fp); X if(feof(fp)) break; X sscanf(line,"%s",mname); X stat(mname,&mstat); X if (maj(mstat.st_rdev) != F_MAJOR) continue; X mdrive = mstat.st_rdev & F_DRIVE_BITS; X if (ddrive == mdrive) X quit("Won't format, drive is mounted as ", mname, OMIT); X } X fclose(fp); X return(NOT_MOUNTED); X#else X if (load_mtab(progname) < 0) return(FAIL_MOUNTED); X while (TRUE) { X n = get_mtab_entry(mdevice, mounted, vers, flag); X if (n < 0) return(NOT_MOUNTED); X stat(mdevice, &mstat); X if (maj(mstat.st_rdev) != F_MAJOR) continue; X mdrive = mstat.st_rdev & F_DRIVE_BITS; X if (ddrive == mdrive) X quit("Won't format, drive is mounted as ", mdevice, OMIT); X } X#endif X} X Xvoid Sigint(s) Xint s; X{ X interrupt = SIGINT; X} X X Xvoid Sigquit(s) Xint s; X{ X interrupt = SIGQUIT; X} X X X/* Make a temporary formatting node. It will be deleted after use. */ Xvoid prepare_node(device) Xdev_t device; X{ X int fd, mres; X struct stat dstat; X char *ptr; X X /* Make a temporary name. Chop progname of excessive renaming. */ X ptr = (char *) progname + strlen(progname); X while (*ptr != '/' && ptr > progname) ptr--; X if (*ptr == '/') ptr++; /* Elide path */ X nname = (char *) malloc(strlen(ptr) < 8 ? strlen(ptr) + 12 : 20); X strcpy(nname, "/tmp/"); X strncat(nname, ptr, 8); X strcat(nname, "XXXXXX"); X mktemp(nname); X mres = mknod4(nname, S_IFBLK | S_IWUSR | S_IRUSR, device | F_BIT, msize); X if (mres) quit("Can't make temporary node ", nname, OMIT); X X /* As a pre-check open and stat the node */ X fd = open(nname, O_WRONLY | O_EXCL); X if (fd < 0) quit("Can't open temporary node ", nname, UNLINK); X if (fstat(fd, &dstat) != 0) { X close(fd); X quit("Can't stat temporary node ", nname, UNLINK); X } X close(fd); X} /* prepare_node */ X X/* Format one track */ Xint format_track(cyl, head, logical) Xint cyl, head, logical; X{ X int errnum = 0; X int physical; X off_t cyl_start; X int fd; X X /* Setup to do one head */ X memset(u.buffer, 0, BLOCK_SIZE); X u.p.param = param; X for (physical = 0; physical <= param.sec_per_cyl; ++physical) { X u.p.table[physical].cyl = (unsigned char) cyl; X u.p.table[physical].head = (unsigned char) head; X u.p.table[physical].sector = (unsigned char) (physical + 1); X u.p.table[physical].sec_size_code = param.sec_size_code; X } X X /* Need to set only the cylinder and head for the drive with a seek. X * Close enough: */ X cyl_start = (((off_t) logical) / 2) * 2 * SEC_SIZE; X if ((fd = open(nname, O_WRONLY)) < 0) errnum |= FAIL_OPEN; X if (lseek(fd, cyl_start, SEEK_SET) != cyl_start) { X printf("Seek error: cyl %d head %d.\n", cyl, head); X errnum |= FAIL_SEEK; X } X if (write(fd, u.buffer, (unsigned) BLOCK_SIZE) != BLOCK_SIZE) { X printf("Write error: cyl %d head %d.\n", cyl, head); X errnum |= FAIL_WRITE; X } X close(fd); /* Don't need sync. This will do. */ X return(errnum); X} /* format_track */ X X/* Format all of the tracks on the disk */ Xint full_format() X{ X int cyl; X int head; X int logical; X int errnum = 0; X int tries; X X for (cyl = 0, logical = 1; cyl <= max_cyl && !errnum; cyl++) { X /* Check for interrupt */ X if (interrupt) quit("Interrupted..", "", UNLINK); X X /* Go ahead and do both heads */ X for (head = 0; head < NR_HEADS && !errnum; ++head) { X printf("\r%s: Cyl. %2d, Head %1d. ", progname, cyl, head); X fflush(stdout); X tries = 0; X errnum = format_track(cyl, head, logical); X X /* Were FS slots busy for other processes? */ X while (errnum & FAIL_OPEN && tries++ < MAX_TRIES) { X printf("Retry: cyl %d head %d.\n", cyl, head); X if (interrupt) quit("Interrupted..", "", UNLINK); X sleep(1); X errnum = format_track(cyl, head, logical); X } X logical += param.sec_per_cyl; X } /* for head */ X } /* for cyl */ X return(errnum); X} /* full_format */ X X/* Put label and date in directory for Dos */ Xint add_vol_label(fd) Xint fd; X{ X char *c; X time_t now; X struct tm *local; X X /* Use a different label next time */ X if (v_flag) v_flag = -1; X X /* Massage and pad the volume label */ X vol_temp[11] = '\0'; /* Guard */ X c = vol_temp; X while (*c != '\0') { X if (*c == '\n' || *c == '\r') { X *c = '\0'; X break; X } else if (!isalpha(*c) && !isdigit(*c) && *c != '.') X *c = '_'; X else if (islower(*c)) X *c = toupper(*c); X c++; X } X if (strlen(vol_temp) < VEL_SIZE) X strncat(vol_temp, BLANKS, VEL_SIZE - strlen(vol_temp)); X strncpy(vol_entry.label, vol_temp, sizeof(vol_entry.label)); X vol_entry.attrib = VOL_ARC; X time(&now); X local = localtime(&now); X vol_entry.date = (local->tm_year - DOS_BASE_YEAR) << Y_SHIFT; X vol_entry.date += (local->tm_mon + 1) << MON_SHIFT; X vol_entry.date += local->tm_mday; X vol_entry.time = (local->tm_hour) << H_SHIFT; X vol_entry.time += (local->tm_min) << MIN_SHIFT; X vol_entry.time += local->tm_sec / SEC_DIV; X if (lseek(fd, dir_start, SEEK_SET) != dir_start) return(FAIL_DVOL); X if (write(fd, (char *) &vol_entry, VE_SIZE) != VE_SIZE) return (FAIL_DVOL); X return(0); /* No errors, errnum == 0 */ X} /* add_vol_label */ X X/* Add the structures Dos needs to the disk. */ Xint add_structures(dname, device) Xchar *dname; Xdev_t device; X{ X int fd; X int errnum; X off_t dos_position; X off_t to_do; X int written; X int do_label; X X /* If special has format bit set it can't write normally */ X if (device & F_BIT) X quit("Format Bit Set, Can't add structures Dos needs, rm ", X dname, UNLINK); X printf("\nAdding structures Dos needs. "); X if (interactive || v_flag < 0) { X printf("\nEnter Volume Label (11 or less) : "); X fgets(vol_temp, 19, stdin); X if (vol_temp[0] == '\n') X do_label = FALSE; X else X do_label = TRUE; X printf("\n"); X } X if ((fd = open(dname, O_WRONLY)) < 0) X quit("Can't open to write structures Dos needs ", X dname, UNLINK); X X /* Write the boot block */ X if (lseek(fd, (off_t) 0, SEEK_SET) != (off_t) 0) return(FAIL_D0); X dos_position = write(fd, (char *) non_boot, BOOT_SIZE); X if (dos_position != (off_t) BOOT_SIZE) return(FAIL_D0); X X /* Round out the first block, then zero enough of them */ X memset(u.buffer, 0, BLOCK_SIZE); X to_do = (off_t) BLOCK_SIZE - dos_position; X while (to_do > (off_t) 0) { X if (interrupt) quit("Interrupted..", "", UNLINK); X written = write(fd, u.buffer, (int) to_do); X if (written != (int) to_do) return(FAIL_DCLEAR); X dos_position += written; X /* Do whole blocks */ X to_do = dir_max - dos_position; X if (to_do > (off_t) BLOCK_SIZE) to_do = (off_t) BLOCK_SIZE; X } X X /* Add volume label and date */ X if (do_label || v_flag > 0) { X errnum = add_vol_label(fd); X if (errnum) return(errnum); X } X if (second_fat) { X dos_position = lseek(fd, second_fat, SEEK_SET); X if (dos_position != second_fat) return(FAIL_DFAT2); X written = write(fd, (char *) &f_bytes[2], FAT_SIZE); X if (written != FAT_SIZE) return(FAIL_DFAT2); X } X X /* Do DOS magic number and first fat */ X dos_position = lseek(fd, (off_t) MAGIC_LOC, SEEK_SET); X if (dos_position != (off_t) MAGIC_LOC) return(FAIL_DFAT1); X written = write(fd, (char *) f_bytes, MAGIC_SIZE); X if (written != MAGIC_SIZE) return(FAIL_DFAT1); X close(fd); /* close dos structure device */ X return(NO_FAILURE); X} /* add_structures */ X X/* Try to read block 0 from the disk */ Xint test_error(dname) Xchar *dname; X{ X int fd; X if ((fd = open(dname, O_RDONLY)) < 0) return(TRUE); X if (lseek(fd, (off_t) 0, SEEK_SET) != (off_t) 0) { X close(fd); X return(TRUE); X } X if (read(fd, u.buffer, BLOCK_SIZE) != BLOCK_SIZE) { X close(fd); X return(TRUE); X } X close(fd); X return(FALSE); X} X Xmain(argc, argv) Xint argc; Xchar *argv[]; { X X int q_flag = FALSE; X char *dname; X static char answer[4] = {'n'}; X struct drive *dp = NULL_L; X struct drive *drive_list = NULL_L; X int is_auto = FALSE; X dev_t device; X int minor, dtype, drnr; X int i, errnum; X X progname = argv[0]; /* this became a variable */ X X/* Su should decide who is allowed to format. Normally only su should format. X * Plucky su's could suid it however... X */ X if (geteuid() != 0) quit("Must be su to format", "", OMIT); X X /* Normally only from the console. */ X if (strcmp(ttyname(0), CONSOLE)) { X /* Suid'ed user must be at console. */ X if (getuid() != 0) quit("Only from the console", "", OMIT); X /* Su can make big mistakes. :-) */ X } X X /* Get command line parameters if there are some. */ X for (i = 1; i < argc; i++) { X if (argv[i][0] == '-') { X if (argv[i][1] == 'v') { X dos_type = TRUE; X if (argc - 1 - i > 0) { X v_flag = i + 1; X strncpy(vol_temp, argv[v_flag], 11); X i++; X } else X v_flag = -1; X } X if (argv[i][1] == 'q') q_flag = TRUE; X if (argv[i][1] == 'a') a_flag = TRUE; X } else if (isdigit(argv[i][0])) { X interactive = FALSE; X msize = usize = atoi(argv[i]); X } else if (isalpha(argv[i][0]) || X argv[i][0] == '/' || X argv[i][0] == '.') { X /* Name or path */ X interactive = FALSE; X if (dp != NULL_L) free(dp); X dp = (struct drive *) malloc(sizeof(struct drive)); X dp->name = (char *) malloc(strlen(argv[i]) + 1); X strcpy(dp->name, argv[i]); X } else X usage(); X } X X if (interactive) { X make_list(&drive_list); X dp = make_selection(drive_list); X } else X dp = command_line_check(dp); X X if (illegal(msize)) quit("Can't do drive size ", itoa(msize), OMIT); X X if (dp->is_auto) { X is_auto = TRUE; X if (illegal(usize)) quit("Can't do size ", itoa(usize), OMIT); X dtype = dtype_map[usize / 360 - 1][msize / 360 - 1]; X if (dtype == -1) quit("Invalid size for drive ", dp->name, OMIT); X dp->device |= (dtype << 2); X msize = dp->msize = usize; X } X device = dp->device; X minor = min(device); X drnr = minor & F_DRIVE_BITS; X dtype = minor >> 2; X dos_type = dp->dos_type || v_flag; X dname = dp->name; X X set_parameters(dtype); X X max_cyl = cyl_table[dtype]; X X if (dos_type) { X adjust_bootblock(dtype, msize); X f_bytes[2] = non_boot[0x15]; /* media id. for fat */ X second_fat = SEC_SIZE * X (unsigned int) non_boot[0x16] + SEC_SIZE; X dir_start = (off_t) non_boot[0x16] * SEC_SIZE + second_fat; X dir_max = (off_t) non_boot[0x11] * DIRENT_SIZE + dir_start; X } X X /* Check /etc/mtab */ X if (mounted(dname)) exit(EXIT_FAILURE); X X /* Trap interrupts to allow cleanup of temporary node */ X if (signal(SIGINT, SIG_IGN) != SIG_IGN) { X signal(SIGINT, Sigint); X signal(SIGQUIT, Sigquit); X } X prepare_node(device); X X if (interactive) X printf("%s %s%4d Kb on %4d Kb %sdrive %d (cyl 0-%d, sec 1-%d)\n", X dname, dos_type ? "Dos " : "", msize, X dsize[dtype], is_auto ? "Auto. " : "", drnr, X max_cyl, param.sec_per_cyl); X X if (interactive || !q_flag) { X printf("Are you sure (y/n) ? "); X fgets(answer, 3, stdin); X if (answer[0] != 'y') { X unlink(nname); X exit(EXIT_FAILURE); X } X printf("\n"); X } X do { /* While answer == 'y' */ X X errnum = full_format(); X if (errnum) quit("Format errors on ", dname, UNLINK); X X if (test_error(dname)) X quit("Wrong media? Format failed on ", dname, UNLINK); X X if (dos_type) { X errnum = add_structures(dname, device); X if (errnum) quit("Failed to add structures Dos needs, ", X itoa(errnum), UNLINK); X } X if (interactive || !q_flag) { X printf("\nAnother %s%d Kb on drive %d (y/n) ? ", X dos_type ? "Dos Disk " : "", msize, drnr); X fgets(answer, 3, stdin); X } else { X printf("\n"); X answer[0] = 'n'; X } X } while (answer[0] == 'y'); X unlink(nname); X exit(EXIT_SUCCESS); X} /