[comp.os.minix] New fdisk.c that understands MINIX partitions

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, &sector, &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, &sector, &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, &regs, &regs, &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, &regs, &regs, &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