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