www.pudn.com > bootmenu.zip > PFDISK.C


/* 
 * pfdisk - Partition a Fixed DISK 
 *	by Gordon W. Ross, Jan. 1990 
 * 
 * See the file "pfdisk.doc" for user instructions. 
 * 
 * This program uses a simple, line-oriented interpreter, 
 * designed for both interactive and non-interactive use. 
 * To facilitate non-interactive use, the output from the 
 * 'L' (list partitions) command is carefully arranged so it 
 * can be used directly as command input.  Neat trick, eh? 
 */ 
 
char *versionString = 
  "# pfdisk version 1.2 by Gordon W. Ross  Aug. 1990\n"; 
 
/* These don't really matter.  The user is asked to set them. */ 
#define DEFAULT_CYLS 306 
#define DEFAULT_HEADS 4 
#define DEFAULT_SECTORS 17 
#define PROMPT_STRING "pfdisk> " 
 
#include  
#include  
#include  
#include "sysdep.h" 
#include "syscodes.h" 
 
typedef unsigned char uchar; 
typedef unsigned int uint; 
typedef unsigned long ulong; 
 
struct part {	/* An entry in the partition table */ 
  uchar	active;		/* active flag (0x80 or 0) */ 
  uchar	b_head;		/* begin head */ 
  uchar	b_sec;		/* 	 sector */ 
  uchar	b_cyl;		/*	 cylinder */ 
  uchar	sysid;		/* system id (see sysid.c) */ 
  uchar	e_head;		/* end  head */ 
  uchar	e_sec;		/* end	sector */ 
  uchar	e_cyl;		/* end	cylinder */ 
  /* These two are just longs, but this way is machine independent. */ 
  uchar	lsBeg[4];	/* logical sectors, beginning */ 
  uchar	lsLen[4];	/* logical sectors, length */ 
}; 
 
#define LOC_PT		0x1BE 
#define LOC_NT		0x180 
#define LOC_GWR		0x1A0 
#define MAGIC_LOC	0x1FE 
#define MAGIC_0		0x55 
#define MAGIC_1		0xAA 
#define MAX_LINE	80 
 
char	buffer[SECSIZE];	/* The boot block buffer */ 
int	bufmod=0;		/* buffer modified... */ 
		/* (zero means buffer is unmodified) */ 
int	useNTable;		/* boot sector uses name table */ 
 
/* device parameters (force someone to set them!) */ 
unsigned cyls = DEFAULT_CYLS; 
unsigned heads = DEFAULT_HEADS; 
unsigned sectors = DEFAULT_SECTORS; 
 
char	*devname;		/* device name */ 
char	cmdline[MAX_LINE]; 
char	filename[80];		/* used by r/w commands */ 
char	*prompt;		/* null if no tty input */ 
 
/* Some of these strings are used in more than one place. 
 * For consistency, I put a newline on all of them. 
 */ 
char h_h[] = "?              : Help summary\n"; 
char h_l[] = "L                     : List partition table\n"; 
char h_1[] = "1 id first last name  : set partition 1\n"; 
char h_2[] = "2,3,4 ... (like 1)    : set respective partition\n"; 
char h_a[] = "A n                   : Activate partition n\n"; 
char h_g[] = "G cyls heads sectors  : set disk Geometry\n"; 
char h_i[] = "I                     : list known ID numbers\n"; 
char h_r[] = "R [optional-file]     : Read  device (or specified file)\n"; 
char h_w[] = "W [optional-file]     : Write device (or specified file)\n"; 
char h_q[] = "Q[!]                  : Quit (! means force)\n"; 
 
char * helpTable[] = { 
h_h, h_l, h_1, h_2, h_a, h_g, h_i, h_r, h_w, h_q, 
"# (All command letters have lower-case equivalents.)\n", 
(char *) 0 }; /* This MUST have a zero as the last element */ 
 
char *BadArg="Error: bad argument: %s\n"; 
char *WarnNotSaved = 
	"Warning, modified partition table not saved.\n"; 
 
help() 
{ 
  char ** p; 
  for (p = helpTable; *p; p++) 
    printf(*p); 
} 
 
/* forward declarations */ 
void	checkValidity(); 
char *	setPartition(); 
char *	makeActive(); 
char *	setGeometry(); 
ulong	chs2long(); 
char *	nameID(); 
int	printIDs(); 
 
main(argc,argv) 
int	argc; 
char	*argv[]; 
{ 
  char	*cmdp;		/* points to command word */ 
  char	*argp;		/* points to command args */ 
 
  /* check command line args (device name) */ 
  if (argc != 2) { 
    usage(argv[0]);	/* See s-sysname.c */ 
    exit(1); 
  } 
  devname = argv[1]; 
 
  /* Should we prompt? */ 
  prompt = (isatty(fileno(stdin))) ? PROMPT_STRING : (char *) 0; 
 
  /* Print version name. */ 
  fputs(versionString, stderr); 
 
  /* get disk parameters */ 
  getGeometry(devname,&cyls,&heads,§ors); 
 
  /* Get the boot block. */ 
  if (getBBlk(devname, buffer) < 0) 
    fprintf(stderr,"%s: read failed\n", devname); 
  checkValidity(); 
 
  if (prompt) fprintf(stderr,"For help, enter: '?'\n"); 
 
 
  /* Read and process commands a line at a time. */ 
  while (1) { 
    if (prompt) fputs(prompt,stdout); 
    if (! fgets(cmdline, MAX_LINE, stdin)) break; 
 
    /* Find beginning of command word */ 
    cmdp = cmdline; 
    while (isspace(*cmdp)) cmdp++; 
 
    /* find beginning of args */ 
    argp = cmdp; 
    while (*argp && !isspace(*argp)) argp++; 
    while (isspace(*argp) || *argp=='=') argp++; 
 
    switch (*cmdp) { 
 
    case '\0':		/* blank line */ 
    case '#':		/* line comment */ 
      break; 
 
    case '?': case 'h': case 'H': 
      help(); 
      break; 
 
    case '1':	/* set partition entry */ 
    case '2': case '3': case '4': 
      argp = setPartition(cmdp, argp); 
      if (argp) {	/* arg list error */ 
	fprintf(stderr,BadArg,argp); 
	fprintf(stderr,h_1); 
	fprintf(stderr,h_2); 
	break; 
      } 
      bufmod = 1; 
      break; 
 
    case 'a': case 'A':	/* activate partition */ 
      argp = makeActive(argp); 
      if (argp) { 
	fprintf(stderr,BadArg,argp); 
	fprintf(stderr,h_a); 
	break; 
      } 
      bufmod = 1; 
      break; 
 
    case 'g': case 'G':	/* set disk parameters (Geometry) */ 
      argp = setGeometry(argp); 
      if (argp) {	/* arg list error */ 
	fprintf(stderr,BadArg,argp); 
	fprintf(stderr,h_g); 
      } 
      break; 
 
    case 'i': case 'I':	/* List known ID numbers */ 
      printIDs(); 
      break; 
 
    case 'l': case 'L':	/* List the partition table */ 
      listPTable(); 
      break; 
 
    case 'q': case 'Q':	/* Quit */ 
      if (bufmod && (cmdp[1]  != '!')) { 
	fprintf(stderr,"\007%s%s\n", WarnNotSaved, 
		"Use 'wq' or 'q!' (enter ? for help)."); 
	break; 
      } 
      exit(0); 
      /*NOTREACHED*/ 
 
    case 'r': case 'R':	/* read from device or file */ 
      if (sscanf(argp,"%80s",filename) == 1) { 
	/* Arg specified, read from filename */ 
	if (getFile(filename, buffer, SECSIZE) < 0) 
	  fprintf(stderr,"%s: read failed\n", filename); 
	bufmod = 1; 
      } else { 
	/* No arg, use device. */ 
	if (getBBlk(devname, buffer) < 0) 
	  fprintf(stderr,"%s: read failed\n", devname); 
	bufmod = 0; 
      } 
      checkValidity(); 
      break; 
 
    case 'w': case 'W':	/* Write to file or device */ 
      if (sscanf(argp,"%80s",filename) == 1) { 
	/* Arg specified, write to filename */ 
	if (putFile(filename, buffer, SECSIZE) < 0) 
	  fprintf(stderr, "%s: write failed\n", filename); 
      } else {  /* No arg, use device. */ 
	if (putBBlk(devname, buffer) < 0) 
	  fprintf(stderr, "%s: write failed\n", devname); 
	bufmod = 0; 
      } 
      if (cmdp[1] == 'q' || cmdp[1] == 'Q') exit(0); 
      break; 
 
    default: 
      fprintf(stderr,"'%c': unrecognized.  Enter '?' for help.\n", *cmdp); 
      break; 
 
    } /* switch */ 
  } /* while */ 
  if (bufmod) fprintf(stderr, WarnNotSaved); 
  exit(0); 
} /* main */ 
 
 
/* Check for valid boot block (magic number in last two bytes). 
 * Also, check for presence of partition name table. 
 */ 
void checkValidity() 
{ 
  /* Check the magic number. */ 
  if ((buffer[MAGIC_LOC] & 0xFF) != MAGIC_0 || 
      (buffer[MAGIC_LOC+1] & 0xFF) != MAGIC_1 ) { 
    /* The boot sector is not valid -- Fix it. */ 
    buffer[MAGIC_LOC] = MAGIC_0; 
    buffer[MAGIC_LOC+1] = MAGIC_1; 
    bufmod = 1; 
    fprintf(stderr, 
"\n\tWarning:  The boot sector has an invalid magic number.\n\ 
\tThe magic number has been fixed, but the other contents\n\ 
\tare probably garbage.  Initialize using the command:\n\ 
\t\tR boot-program-file	(i.e. bootmenu.bin)\n\ 
\tthen set each partition entry if necessary.\n"); 
  } 
 
  /* Does it use a name table (for a boot menu)? 
   * My boot program does, and can be identified by 
   * finding my name in a particular (unused) area. 
   */ 
  useNTable = !strcmp(&buffer[LOC_GWR], "Gordon W. Ross"); 
 
} 
 
char * setPartition(cmdp,argp)	/* return string on error */ 
char	*cmdp,*argp; 
{ 
  struct part *pp;	/* partition entry */ 
  char *	np;		/* name table pointer */ 
  char *	newname;	/* name field */ 
  int	index;		/* partition index (0..3) */ 
  uint	id;		/* ID code (see syscodes.c) */ 
  uint	first,last;	/* user supplied cylinders */ 
  uint	c,h,s;		/* working cyl,head,sect, */ 
  uint	len;		/* chars seen by sscanf */ 
  ulong	lsbeg, lslen;	/* logical begin, length */ 
 
  /* Value check the index */ 
  index = *cmdp - '1'; 
  if (index < 0 || index > 3) 
    return("index"); 
  pp = (struct part *) &buffer[LOC_PT + index * 16]; 
  np = &buffer[LOC_NT + index * 8]; 
 
  /* Read System ID */ 
  if (sscanf(argp,"%i%n", &id, &len) < 1) 
    return("id"); 
  argp += len; 
 
  /* If ID==0, just clear out the entry and return. */ 
  if (id == 0) { 
    strncpy( (char *) pp, "", 16); 
    if (useNTable) strncpy( np, "", 8); 
    return((char *)0); 
  } 
 
  /* Read first and last cylinder */ 
  if (sscanf(argp,"%i%i%n",&first, &last, &len) < 2) 
    return("first last (missing)"); 
  argp += len; 
 
  /* Reasonable start,end cylinder numbers? */ 
  if (first > last)	return("first > last"); 
  if (first > 1023)	return("first > 1023"); 
  if (last >= cyls)	return("last >= cyls"); 
 
  /* Get (optional) system name. */ 
  if (*argp == '\n') {	/* no name given, use default */ 
    newname = nameID(id); 
  } else {		/* use the given name */ 
    /* skip leading space */ 
    while (*argp == ' ') argp++; 
    newname = argp; 
    /* Remove newline from end */ 
    while (isgraph(*argp)||*argp==' ') argp++; 
    *argp = '\0'; 
    useNTable = 1; 
  } 
 
  /* Set the ID and name. */ 
  pp->sysid = id; 
  if (useNTable) { 
    strncpy(np, newname, 8); 
    strcpy(&buffer[LOC_GWR], "Gordon W. Ross"); 
  } 
 
  /* set beginning c,h,s */ 
  c = first; 
  /* if c == 0, head == 1 (reserve track 0) */ 
  h = (first) ? 0 : 1; 
  s = 1; 
  pp->b_cyl = c & 0xFF; 
  pp->b_head = h; 
  pp->b_sec = s | ((c >> 2) & 0xC0); 
  /* Set the logical sector begin field */ 
  lsbeg = lslen = chs2long(c,h,s); /* using lslen as temp. */ 
  pp->lsBeg[0] = lslen & 0xff; lslen >>= 8; 
  pp->lsBeg[1] = lslen & 0xff; lslen >>= 8; 
  pp->lsBeg[2] = lslen & 0xff; lslen >>= 8; 
  pp->lsBeg[3] = lslen & 0xff; lslen >>= 8; 
 
  /* set ending c,h,s (last may be larger than 1023) */ 
  c = (last>1023) ? 1023 : last; /* limit c to 1023 */ 
  h = heads - 1; s = sectors; 
  pp->e_cyl = c & 0xFF; 
  pp->e_head = h; 
  pp->e_sec = s | ((c >> 2) & 0xC0); 
  /* Set the logical sector length field (using REAL end cylinder) */ 
  lslen = chs2long(last,h,s) + 1 - lsbeg; 
  pp->lsLen[0] = lslen & 0xff; lslen >>= 8; 
  pp->lsLen[1] = lslen & 0xff; lslen >>= 8; 
  pp->lsLen[2] = lslen & 0xff; lslen >>= 8; 
  pp->lsLen[3] = lslen & 0xff; lslen >>= 8; 
 
  return((char *)0);	/* success */ 
} /* setPartition() */ 
 
char * makeActive(argp)	/* return error string or zero */ 
char	*argp; 
{ 
  struct part *pp;	/* partition entry */ 
  int	i,act;		/* which one becomes active */ 
 
  if (sscanf(argp,"%d", &act) < 1) 
    return("missing index"); 
  act--;			/* make it zero-origin */ 
 
  i=0; pp = (struct part *) &buffer[LOC_PT]; 
  while (i<4) { 
    pp->active = 0; 
    if (i == act) { 
      if (pp->sysid == 0) return("partition empty"); 
      pp->active = 0x80; 
    } 
    i++; pp++; 
  } 
  return((char *)0); 
} 
 
char * setGeometry(argp)	/* return string on error */ 
char	*argp; 
{ 
  int	c,h,s; 
 
  if (sscanf(argp,"%i%i%i", &c, &h, &s) < 3) 
    return("(missing)"); 
  if (c<1) return("cyls"); 
  if (h<1) return("heads"); 
  if (s<1) return("sectors"); 
  cyls=c; heads=h; sectors=s; 
  return((char *)0); 
} 
 
listPTable()		/* print out partition table */ 
{ 
  struct part * pp;	/* partition table entry */ 
  char	*name; 
  int	i;		/* partition number */ 
  int	numActive=0;	/* active partition [1-4], 0==none */ 
  uint	pbc,pbh,pbs;	/* physical beginning  c,h,s */ 
  uint	pec,peh,pes;	/* physical ending     c,h,s */ 
  uint	lbc,lbh,lbs;	/* logical beginning   c,h,s */ 
  uint	lec,leh,les;	/* logical ending      c,h,s */ 
  ulong	lsbeg,lslen;	/* logical sectors: begin, length */ 
 
  printf("# Partition table on device: %s\n", devname); 
  printf("geometry %d %d %d (cyls heads sectors)\n", 
	 cyls, heads, sectors); 
  printf("#  ID  First(cyl)  Last(cyl)  Name     "); 
  printf("# start, length (sectors)\n"); 
 
  for (i=0; i<4; i++) { 
    pp = (struct part *) &buffer[LOC_PT + i * 16]; 
 
    if (pp->active) { 
      if(numActive) 
	fprintf(stderr,"Error: multiple active partitions.\n"); 
      else numActive = i+1; 
    } 
 
    /* physical beginning c,h,s */ 
    pbc = pp->b_cyl & 0xff | (pp->b_sec << 2) & 0x300; 
    pbh = pp->b_head; 
    pbs = pp->b_sec & 0x3F; 
 
    /* physical ending c,h,s */ 
    pec = pp->e_cyl & 0xff | (pp->e_sec << 2) & 0x300; 
    peh = pp->e_head; 
    pes = pp->e_sec & 0x3F; 
 
    /* compute logical beginning (c,h,s) */ 
    lsbeg = ((((((pp->lsBeg[3] ) << 8 ) 
		| pp->lsBeg[2] ) << 8 ) 
		| pp->lsBeg[1] ) << 8 ) 
		| pp->lsBeg[0] ; 
    long2chs(lsbeg, &lbc, &lbh, &lbs); 
    /* compute logical ending (c,h,s) */ 
    lslen = ((((((pp->lsLen[3]) << 8 ) 
		| pp->lsLen[2]) << 8 ) 
		| pp->lsLen[1]) << 8 ) 
		| pp->lsLen[0] ; 
    /* keep beginning <= end ... */ 
    if (lslen > 0) long2chs(lsbeg+lslen-1, &lec, &leh, &les); 
    else	   long2chs(lsbeg,	   &lec, &leh, &les); 
 
    if (useNTable) 
      name = &buffer[LOC_NT + i * 8]; 
    else 
      name = nameID((uint) pp->sysid); 
 
    /* show physical begin, logical end (works for cyl>1023) */ 
    /*      #  ID  First(cyl)  Last(cyl)  Name... # ... */ 
    printf("%d %3d   %4d       %4d       %-8.8s # %ld, %ld\n", 
	   i+1, pp->sysid, pbc, lec, name, lsbeg, lslen ); 
 
    /* That's all, for an empty partition. */ 
    if (pp->sysid == 0) continue; 
 
    /* 
     * Now do some consistency checks... 
     */ 
 
    /* Same physical / logical beginning? */ 
    if (pbc != lbc || pbh != lbh || pbs != lbs ) { 
      printf("# note: first(%d): ", i+1); 
      printf("phys=(%d,%d,%d) ",    pbc, pbh, pbs); 
      printf("logical=(%d,%d,%d)\n",lbc, lbh, lbs); 
    } 
    /* Same physical / logical ending? */ 
    if (pec != lec || peh != leh || pes != les ) { 
      printf("# note:  last(%d): ", i+1); 
      printf("phys=(%d,%d,%d) ",    pec, peh, pes); 
      printf("logical=(%d,%d,%d)\n",lec, leh, les); 
    } 
 
    /* Beginning on cylinder boundary? */ 
    if (pbc == 0) { /* exception: start on head 1 */ 
      if (pbh != 1 || pbs != 1) { 
	printf("# note: first(%i): ", i+1); 
	printf("phys=(%d,%d,%d) ", pbc, pbh, pbs); 
	printf("should be (%d,1,1)\n", pbc); 
      } 
    } else { /* not on cyl 0 */ 
      if (pbh != 0 || pbs != 1) { 
	printf("# note: first(%i): ", i+1); 
	printf("phys=(%d,%d,%d) ", pbc, pbh, pbs); 
	printf("should be (%d,0,1)\n", pbc); 
      } 
    } 
 
    /* Ending on cylinder boundary? */ 
    if (peh != (heads-1) || pes != sectors) { 
      printf("# note: last(%i): ", i+1); 
      printf("phys=(%d,%d,%d) ", pec, peh, pes); 
      printf("should be (%d,%d,%d)\n", 
	     pec, heads-1, sectors); 
    } 
 
  } /* for */ 
  printf("active: %d  %s\n", numActive, 
	 (numActive) ? "" : "(none)"); 
} /* listPTable() */ 
 
ulong chs2long(c,h,s) 
uint c,h,s; 
{ 
  ulong	l; 
  if (s<1) s=1; 
  l  = c; l *= heads; 
  l += h; l *= sectors; 
  l += (s - 1); 
  return(l); 
} 
 
long2chs(ls, c, h, s)	/* convert logical sec-num to c,h,s */ 
ulong	ls;		/* Logical Sector number */ 
uint	*c,*h,*s;	/* cyl, head, sector */ 
{ 
  int	spc = heads * sectors; 
  *c = ls / spc; 
  ls = ls % spc; 
  *h = ls / sectors; 
  *s = ls % sectors + 1;	/* sectors count from 1 */ 
} 
 
char * nameID(n) 
unsigned int n; 
{ 
  struct intString *is; 
 
  is = sysCodes; 
  while (is->i) { 
    if (is->i == n) return(is->s); 
    is++; 
  } 
  if (!n) return(is->s); 
  return("unknown"); 
} 
 
int printIDs()		/* print the known system IDs */ 
{ 
  struct intString * is = sysCodes; 
 
  /* This might need to do more processing eventually, i.e. 
   * if (prompt) { ... do more processing ... } 
   */ 
  printf("_ID_\t__Name__ ____Description____\n"); 
  while (is->i) { 
    printf("%3d\t%s\n", is->i, is->s); 
    is++; 
  } 
}