home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #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[] = "? <enter> : 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++;
- }
- }
-