ast@cs.vu.nl (10/27/89)
In a previous message today, I suggested that we could solve the
STUPID_WINI_ADJUST problem if the driver could tell which partitions
were MINIX and which were not. I have now modified fdisk to be able
to mark partitions as MINIX. There is a new command, 'm', which will
work on an already partitioned disk, as well as a disk being partitioned
for the first time. I have actually tested it on my own hard disk
(this being analogous to doctors using themselves as guinea pigs for
medical research--a fascinating subject with a long history).
In any event, even if my idea for STUPID_WINI_ADJUST doesn't pan out,
I think this fdisk is an improvement over the old one, and will be
part of 1.4b.
I believe that if we use my scheme, after marking partitions as MINIX,
one has to reboot the computer, to get the driver to read in the
partition table again. A slight nuisance, but it only happens once
in the lifetime of each disk.
Andy Tanenbaum (ast@cs.vu.nl)
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'fdisk.c'
sed 's/^X//' > 'fdisk.c' << '+ END-OF-FILE ''fdisk.c'
X/* fdisk - partition a hard disk Author: Jakob Schripsema */
X
X/* First run the DOS utilities FDISK and FORMAT.
X * FDISK puts the boot code in sector 0.
X * Then run fdisk
X *
X * fdisk /dev/hdx (MINIX)
X * fdisk x: (DOS)
X *
X * Compiling
X *
X * cc -o fdisk -DUNIX fdisk.c (MINIX)
X * cl -DDOS fdisk.c (DOS with MS C compiler)
X */
X
X#include <stdio.h>
X#define UNIX /* for MINIX */
X
X#ifdef DOS
X#include <dos.h>
X#endif
X
X/* Constants */
X
X#define NHEAD 4 /* # heads */
X#define NSEC 17 /* sectors / track */
X#define SECSIZE 512 /* sector size */
X#define OK 0
X#define ERR 1
X#define TABLEOFFSET 0x1be /* offset in boot sector */
X
X/* Description of entry in partition table */
Xstruct part_entry {
X char bootind; /* boot indicator 0/0x80 */
X char start_head; /* head value for first sector */
X char start_sec; /* sector value for first sector */
X char start_cyl; /* track value for first sector */
X char sysind; /* system indicator 00=?? 01=DOS */
X char last_head; /* head value for last sector */
X char last_sec; /* sector value for last sector */
X char last_cyl; /* track value for last sector */
X long lowsec; /* logical first sector */
X long size; /* size of partion in sectors */
X};
X
X/* The following codes indicate partition types. */
X#define DOS_PART 0x01
X#define XENIX_PART 0x02
X#define DOS4_PART 0x04
X#define MINIX_PART 0x08
X
X/* Globals */
Xchar secbuf[SECSIZE];
Xchar *devname;
Xchar *dosstr = " DOS ";
Xchar *dosstr4 = " DOS 4";
Xchar *ndosstr = "Non-DOS";
Xchar *xenstr = " Xenix ";
Xchar *minixstr =" MINIX ";
Xint heads;
X
X#ifdef DOS
Xunion REGS regs;
Xstruct SREGS sregs;
Xint drivenum;
X#endif
X
X#ifdef UNIX
Xint devfd;
X#endif
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X char ch;
X
X /* Init */
X
X if (argc > 1 && (*++argv)[0] == '-') { /* flag */
X heads = atoi(&(*argv)[1]);
X printf("heads: %d ", heads);
X argv++;
X argc--;
X } else
X heads = NHEAD;
X
X if (argc > 2) {
X printf("Usage: fdisk [-heads] [/dev/hdx]\n");
X exit(1);
X }
X if (argc == 1)
X devname = "/dev/hd0";
X else
X devname = *argv;
X
X getboot(secbuf); /* get boot sector */
X
X do {
X dpl_partitions();
X print_menu();
X ch = get_a_char();
X putchar('\n');
X switch (ch) {
X case 'm': mark_partition(); break;
X case 'c': change_table(); break;
X case 'w':
X if (chk_table() == OK) {
X putboot(secbuf);
X exit(0);
X }
X break;
X case 'l': load_from_file(); break;
X case 's': save_to_file(); break;
X case 'p': dump_table(); break;
X case 'q': exit(0);
X default: printf(" %c ????\n", ch);
X }
X }
X while (1);
X}
X
X
X
X#ifdef UNIX
X
Xgetboot(buffer)
Xchar *buffer;
X{
X devfd = open(devname, 2);
X if (devfd < 0) {
X printf("Cannot open device %s\n", devname);
X exit(1);
X }
X if (read(devfd, buffer, SECSIZE) != SECSIZE) {
X printf("Cannot read boot sector\n");
X exit(2);
X }
X}
X
Xputboot(buffer)
Xchar *buffer;
X{
X int r;
X
X if (lseek(devfd, 0L, 0) < 0) {
X printf("Seek error during write\n");
X exit(1);
X }
X if (write(devfd, buffer, SECSIZE) != SECSIZE) {
X printf("Write error\n");
X exit(1);
X }
X sync();
X}
X
X#endif
X
X
Xload_from_file()
X{
X/* Load buffer from file */
X
X char file[80];
X int fd;
X
X printf("Enter file name: ");
X gets(file);
X#ifdef UNIX
X fd = open(file, 0);
X#endif
X#ifdef DOS
X fd = open(file, 0x8000);
X#endif
X if (fd < 0) {
X fprintf(stderr, "Cannot load from %s\n", file);
X exit(1);
X }
X if (read(fd, secbuf, SECSIZE) != SECSIZE) {
X fprintf(stderr, "Read error\n");
X exit(1);
X }
X close(fd);
X}
X
X
Xsave_to_file()
X{
X/* Save to file */
X
X char file[80];
X int fd;
X
X printf("Enter file name: ");
X gets(file);
X#ifdef UNIX
X fd = creat(file, 0644);
X#endif
X#ifdef DOS
X fd = creat(file, 0644);
X if (fd < 0) {
X fprintf(stderr, "Cannot creat %s\n", file);
X exit(1);
X }
X close(fd);
X fd = open(file, 0x8001);
X#endif
X if (fd < 0) {
X fprintf(stderr, "Cannot save to %s\n", file);
X exit(1);
X }
X if (write(fd, secbuf, SECSIZE) != SECSIZE) {
X fprintf(stderr, "Write error\n");
X exit(1);
X }
X close(fd);
X}
X
X
Xdump_table()
X{
X/* Dump partition table */
X
X struct part_entry *pe;
X int i;
X
X pe = (struct part_entry *) & secbuf[TABLEOFFSET];
X printf("\n --first--- ---last---\n");
X printf("Prt ac hd sec cyl sys hd sec cyl low size\n");
X for (i = 1; i < 5; i++) {
X printf(" %x %2x %x %2x %2x %2x %x %2x %2x %6D %9D\n",
X i,
X pe->bootind & 0xff,
X pe->start_head & 0xff,
X pe->start_sec & 0xff,
X pe->start_cyl & 0xff,
X pe->sysind & 0xff,
X pe->last_head & 0xff,
X pe->last_sec & 0xff,
X pe->last_cyl & 0xff,
X pe->lowsec,
X pe->size);
X pe++;
X }
X}
X
X
Xdpl_partitions()
X{
X/* Display partition table */
X
X struct part_entry *pe;
X int i;
X
X printf("\nPartition Type Begin End Active\n");
X pe = (struct part_entry *) & secbuf[TABLEOFFSET];
X for (i = 1; i <= 4; i++) {
X dpl_entry(i, pe);
X pe++;
X }
X}
X
X
Xdpl_entry(number, entry)
Xint number;
Xstruct part_entry *entry;
X{
X/* Display an entry */
X
X int low_cyl, high_cyl, temp;
X char *typestring;
X char active;
X
X if (entry->sysind == DOS_PART)
X typestring = dosstr;
X else if (entry->sysind == XENIX_PART)
X typestring = xenstr;
X else if (entry->sysind == DOS4_PART)
X typestring = dosstr4;
X else if (entry->sysind == MINIX_PART)
X typestring = minixstr;
X else
X typestring = ndosstr;
X printf("%5d %s ", number, typestring);
X temp = entry->start_sec & 0xc0;
X low_cyl = (entry->start_cyl & 0xff) + (temp << 2);
X temp = entry->last_sec & 0xc0;
X high_cyl = (entry->last_cyl & 0xff) + (temp << 2);
X printf("%4d %4d", low_cyl, high_cyl);
X if ((entry->bootind & 0xff) == 0x80)
X active = 'A';
X else
X active = 'N';
X printf(" %c\n", active);
X}
X
Xchk_table()
X{
X/* Check partition table */
X
X struct part_entry *pe;
X int i;
X int active;
X long limit;
X
X pe = (struct part_entry *) & secbuf[TABLEOFFSET];
X limit = 0L;
X active = 0;
X for (i = 1; i < 5; i++) {
X if (pe->size == 0L) return(OK);
X if (pe->lowsec <= limit) {
X printf("Overlap between part. %d and %d\n", i, i - 1);
X return(ERR);
X }
X limit = pe->lowsec + pe->size - 1L;
X if (pe->bootind == 0x80) active++;
X pe++;
X }
X if (active > 1) {
X printf("%d active partitions\n", active);
X return(ERR);
X }
X return(OK);
X}
X
Xchk_entry(entry)
Xstruct part_entry *entry;
X{
X/* Check entry
X * head/sector/track info must match logical sector number
X * Used to check 'foreign' partition table during debugging
X */
X
X char head;
X char sector;
X char track;
X
X sec_to_hst(entry->lowsec, &head, §or, &track);
X if ((head != entry->start_head) ||
X (sector != entry->start_sec) ||
X (track != entry->start_cyl))
X return(ERR);
X sec_to_hst(entry->lowsec + entry->size - 1L, &head, §or, &track);
X if ((head != entry->last_head) ||
X (sector != entry->last_sec) ||
X (track != entry->last_cyl))
X return(ERR);
X return(OK);
X}
X
Xsec_to_hst(logsec, hd, sec, cyl)
Xlong logsec;
Xchar *hd, *sec, *cyl;
X{
X/* Convert a logical sector number to head / sector / track */
X
X int bigcyl;
X
X bigcyl = logsec / (heads * NSEC);
X *sec = (logsec % NSEC) + 1 + ((bigcyl >> 2) & 0xc0);
X *cyl = bigcyl & 0xff;
X *hd = (logsec % (heads * NSEC)) / NSEC;
X}
X
Xmark_partition()
X{
X/* Mark a partition as being of type MINIX. */
X
X char ch;
X int p;
X struct part_entry *pe;
X
X pe = (struct part_entry *) & secbuf[TABLEOFFSET];
X while (1) {
X printf("Which partition? ");
X ch = get_a_char();
X if (ch < '1' || ch > '4') {
X printf("\nNot valid. Valid partitions are 1, 2, 3, and 4.\n");
X continue;
X }
X putchar('\n');
X p = ch - '0';
X pe += (p - 1);
X pe->sysind = MINIX_PART;
X return;
X }
X}
X
Xchange_table()
X{
X/* Change partition table */
X
X struct part_entry *pe;
X int i, temp, low_cyl, high_cyl;
X char ch;
X
X pe = (struct part_entry *) & secbuf[TABLEOFFSET];
X for (i = 1; i <= 4; i++) {
X temp = pe->start_sec & 0xc0;
X low_cyl = (pe->start_cyl & 0xff) + (temp << 2);
X temp = pe->last_sec & 0xc0;
X high_cyl = (pe->last_cyl & 0xff) + (temp << 2);
X printf("Partition %d from %d to %d. Change? (y/n) ",
X i, low_cyl, high_cyl);
X ch = get_a_char();
X if (ch == 'y' || ch == 'Y') get_partition(pe);
X pe++;
X }
X putchar('\n');
X}
X
Xget_partition(entry)
Xstruct part_entry *entry;
X{
X/* Get partition info : first & last cylinder */
X
X char buf[80];
X int first, last;
X long low, high;
X char ch;
X
X printf(" Enter first cylinder: ");
X gets(buf);
X sscanf(buf, "%d", &first);
X printf(" Enter last cylinder: ");
X gets(buf);
X sscanf(buf, "%d", &last);;
X if (first == 0 && last == 0) {
X entry->bootind = 0;
X entry->start_head = 0;
X entry->start_sec = 0;
X entry->start_cyl = 0;
X entry->sysind = 0;
X entry->last_head = 0;
X entry->last_sec = 0;
X entry->last_cyl = 0;
X entry->lowsec = 0L;
X entry->size = 0L;
X return;
X }
X low = first & 0xffff;
X low = low * NSEC * heads;
X if (low == 0) low = 1; /* sec0 is master boot record */
X high = last & 0xffff;
X high = (high + 1) * NSEC * heads - 1;
X entry->lowsec = low;
X entry->size = high - low + 1;
X sec_to_hst(low,
X &entry->start_head,
X &entry->start_sec,
X &entry->start_cyl);
X sec_to_hst(high,
X &entry->last_head,
X &entry->last_sec,
X &entry->last_cyl);
X entry->sysind = 0;
X printf(" MINIX partition? (y/n) ");
X ch = get_a_char();
X if (ch == 'y' || ch == 'Y') {
X entry->sysind = MINIX_PART;
X } else {
X printf(" DOS partition? (y/n) ");
X ch = get_a_char();
X if (ch == 'y' || ch == 'Y') entry->sysind = DOS_PART;
X }
X
X printf(" Active partition? (y/n) ");
X ch = get_a_char();
X if (ch == 'y' || ch == 'Y')
X entry->bootind = 0x80;
X else
X entry->bootind = 0;
X}
X
Xget_a_char()
X{
X/* Read 1 character and discard rest of line */
X
X char ch;
X
X ch = getchar();
X if (ch != '\n') while (getchar() != '\n');
X return(ch);
X}
X
Xprint_menu()
X{
X printf("\nType a command letter, then a carriage return:\n");
X printf(" m - mark a partition as a MINIX partition\n");
X printf(" c - change a partition\n");
X printf(" w - write changed partition table back to disk and exit\n");
X printf(" q - quit without making any changes\n");
X printf(" s - save boot block (including partition table) on a file\n");
X printf(" l - load boot block (including partition table) from a file\n");
X printf(" p - print partition table\n\n");
X}
X
X
X/* Here are the DOS routines for reading and writing the boot sector. */
X
X#ifdef DOS
X
Xgetboot(buffer)
Xchar *buffer;
X{
X/* Read boot sector */
X
X segread(&sregs); /* get ds */
X
X if (devname[1] != ':') {
X printf("Invalid drive %s\n", devname);
X exit(1);
X }
X if (*devname >= 'a') *devname += 'A' - 'a';
X drivenum = (*devname - 'C') & 0xff;
X if (drivenum < 0 || drivenum > 7) {
X printf("Funny drive number %d\n", drivenum);
X exit(1);
X }
X regs.x.ax = 0x201; /* read 1 sectors */
X regs.h.ch = 0; /* track */
X regs.h.cl = 1; /* first sector = 1 */
X regs.h.dh = 0; /* head = 0 */
X regs.h.dl = 0x80 + drivenum; /* drive = 0 */
X sregs.es = sregs.ds; /* buffer address */
X regs.x.bx = (int) secbuf;
X
X int86x(0x13, ®s, ®s, &sregs);
X if (regs.x.cflag) {
X printf("Cannot read boot sector\n");
X exit(1);
X }
X}
X
X
Xputboot(buffer)
Xchar *buffer;
X{
X/* Write boot sector */
X
X regs.x.ax = 0x301; /* read 1 sectors */
X regs.h.ch = 0; /* track */
X regs.h.cl = 1; /* first sector = 1 */
X regs.h.dh = 0; /* head = 0 */
X regs.h.dl = 0x80 + drivenum; /* drive = 0 */
X sregs.es = sregs.ds; /* buffer address */
X regs.x.bx = (int) secbuf;
X
X int86x(0x13, ®s, ®s, &sregs);
X if (regs.x.cflag) {
X printf("Cannot write boot sector\n");
X exit(1);
X }
X}
X
X#endif
+ END-OF-FILE fdisk.c
chmod 'u=rw,g=r,o=r' 'fdisk.c'
set `wc -c 'fdisk.c'`
count=$1
case $count in
11463) :;;
*) echo 'Bad character count in ''fdisk.c' >&2
echo 'Count should be 11463' >&2
esac
exit 0