Path: utzoo!news-server.csri.toronto.edu!rutgers!usc!elroy.jpl.nasa.gov!decwrl!world!gwr From: gwr@world.std.com (Gordon W. Ross) Newsgroups: comp.unix.sysv386 Subject: BOOTMENU and PFDISK 1.3 (part 1/2) Summary: primary boot sector program with menu Keywords: fdisk boot partition menu bootmenu pfdisk Message-ID: <1991Mar9.012510.7387@world.std.com> Date: 9 Mar 91 01:25:10 GMT Organization: The World @ Software Tool & Die Lines: 1662 [ This was sent to comp.sources.misc on 23 Oct 90 but I hear that it never came out. How can I get this archived? - gwr ] Here is part 1 of the BOOTMENU and PFDISK 1.3 distribution. BOOTMENU is a replacement primary boot sector for MS-DOS compatible machines which allows boot-time selection of the active hard disk partition using a menu. For example, users with both UNIX and DOS on their hard disk can choose which system to use at boot time. PFDISK is a replacement "fdisk" command for installing BOOTMENU without clobbering your partition table. See the README file at the beginning of the shell archive below for a general description of this package. Program documentation for both BOOTMENU and PFDISK are at the beginning of the second posting. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh README <<'END_OF_README' X XBOOTMENU is a replacement primary boot sector for MS-DOS compatible Xmachines which allows boot-time selection of the active hard disk Xpartition using a menu. For example, users with both UNIX and DOS Xon their hard disk can choose which system to use at boot time. X XBOOTAUTO is similar to BOOTMENU but allows both unattended reboot Xand the ability to override the automatic selection of the active Xpartition at boot-time. (I used to call this version boot-hdp). X XBOOTMENU cannot do an unattended reboot but is very small and X(as a result) will not be clobbered if you use the SpeedStor Xdisk formatting/diagnostics program. (Notes about SpeedStor's Xusage of the primary boot sector are in the file SStor.txt). X XPFDISK is a replacement for both DOS and UNIX fdisk programs. XThis replacement is distinguished for its ability to put Xan arbitrary binary image into the primary boot sector without Xclobbering an existing partition table. PFDISK has no boot Xprogram built-in, but allows you to take the boot program Xfrom a file. At least one of the boot program files, such as XBOOTMENU, must be available to PFDISK if it is expected to Xinitialize a newly formatted disk. Unlike MSDOS fdisk, XPFDISK correctly handles partition entries which extend Xbeyond cyl 1023. Unlike UNIX fdisk, PFDISK is not confused Xabout the difference between highest-usable-cylinder-number Xand (beginning-cylinder plus number-of-cylinders). X XDocumentation included: X XThe file bootmenu.doc explains how to install and use the new Xboot programs. The file pfdisk.man is manual entry in UNIX *roff Xformat, and pfdisk.doc is a formatted copy for those without nroff. X XHow to compile: X XTo build pfdisk, either edit the Makefile to uncomment the Xappropriate line (i.e. SYS=i386) and type "make", or Xuse a make command line like: X make SYS=i386 XThis will just build the pfdisk program and boot sector binaries. XIt will not try to modify the hard disk boot sector. X XThe boot program binaries are distributed as simple HEX encoded Xtext files. The (included) program hex2bin will convert them Xfor the benefit of those without the MASM (DOS) assembler. X XEnjoy! X XGordon Ross (gwr@world.std.com) END_OF_README if test 2160 -ne `wc -c pfdisk.man <<'END_OF_pfdisk.man' X.TH PFDISK 8 "Oct 1990" "Release 1.3" X.SH NAME Xpfdisk \- partition fixed disk X.SH SYNOPSIS X.B pfdisk X.I device X.SH DESCRIPTION X.LP X.B pfdisk Xpartitions the fixed disk identified as X.I device Xinto (at most) four parts, each of which may Xbe independently loaded with an operating system. XThe actual name of X.I device Xdepends on the operating system in use. XFor ESIX (System V/386) the device name is either X"/dev/rdsk/0s0" or "/dev/rdsk/1s0". XFor Minix, it is "/dev/hd0" or "/dev/hd5". XFor MS-DOS it is a single digit (zero or one). X.LP X.B pfdisk Xreads the hard disk partition table from block zero of X.I device Xinto memory and allows the user to examine, modify, or save the Xpartition table. A regular file may be used instead of a real X.I device Xfor testing purposes, though the device geometry must be specified Xmanually, and some systems will requrire a file-name argument with Xthe "R" and "W" commands (DOS, ESIX). X.LP XThe partition table on X.I device Xis NOT modified unless the write command (W) is used with no argument. X.SH USAGE X.SS Commands X.LP XAll X.B pfdisk Xcommands consist of a command word followed by optional Xblank-separated command arguments. XNote that only the first letter of a command word is significant X(except for "wq" and "q!"). XAll command letters are accepted in either upper or lower case. XNumeric arguments are specified using C syntax. XExtra arguments are silently ignored. X.LP XThe commands are: X.TP X.B ? XPrints a command summary (help). X.TP X.BI 1 " sys_id first last sys_name" XSet the partition table entry for part one, using: X.I sys_id Xas its system ID code, X.I first Xas the lowest numbered cylinder it uses, X.I last Xas the highest numbered cylinder it uses, and X.I sys_name X(optional) as the system name (in the menu name table). X.TP X.BI 2|3|4 " sys-id first last sys-name" XSimilar to X.B 1 Xbut sets partition two, three, or four, respectively. X.TP X.BI A " number" XMark partition X.I number Xas active (so it will be used for booting). If X.I number Xis zero, no partition will be active. X.TP X.BI G " cylinders heads sectors" XInform X.B pfdisk Xwhat the geometry of the device is. X.TP X.B I XPrint a summary of the known ID codes. X.TP X.B L XList the partition table. XSee X.B "Output Format" Xbelow. X.TP X.B Q XQuit without saving. If the memory copy of the partition table was Xmodified, a warning will be issued and the command ignored. X.TP X.B Q! XQuit, even if the memory copy of the partition table was not saved. X.TP X.BI R " file-name" XRead boot sector from X.I file-name X(if given) otherwise read from X.I device. X.TP X.BI W " file-name" XWrite boot sector to X.I file-name. X(if given) otherwise write to X.I device. X.TP X.B WQ XSame as "write" followed by "quit". X.TP X.B # XThis line is a comment (to be ignored). X.SS "Output Format" X.LP XHere is a sample of the output from the X.B L Xcommand: X.LP X.nf X# Partition table on device: /dev/rdsk/0s0 Xgeometry 1222 15 34 (cyls heads sectors) X# ID First(cyl) Last(cyl) Name # start, length (sectors) X1 4 0 127 MS-LOSS # 34, 65246 X2 129 128 255 Minix # 65280, 65280 X3 0 0 0 # 0, 0 X4 99 256 1220 ESIX # 130560, 492150 X# note: last(4): phys=(1023,14,34) logical=(1220,14,34) Xactive: 4 X.fi X.LP XThis output format is carefully constructed so that it Xmay be saved in a file (by redirecting standard output) Xand later used as input (by redirecting standard input). XOn a UNIX system, one can save this output using the command: X.IP X(echo L) | pfdisk device-name > X.I save-file X.LP The printable representation saved in X.I save-file Xis a complete record of the partition table. XOn a UNIX system, one could use X.I save-file Xto re-initialize the partition table using the command: X.IP X(cat save-file ; echo wq) | pfdisk device-name X.LP XConsistency of each partition table entry is checked Xwhile the table is listed. Any inconsistencies discovered Xare reported in a commentary note as shown above. X.SS "Physical vs. Logical" X.LP XEach partition table entry has both "physical" and a "logical" fields. XThe physical fields specify the lowest and highest cylinder,head,sector Xcombinations to be used in that partition. The logical start field Xhas the total number of sectors which precede this partition, and Xthe logical length field has the total number of sectors contained Xin this partition. These fields should be self consistent unless Xthe disk has more than 1024 cylinders. X.LP XThe physical cylinder fields are only ten-bits wide so the contents Xare limited to 1023. The logical sector fields are 32 bits wide and Xalways show the true logical beginning and length of the partition. XGenerally, the physical start field is used only to locate the Xsecondary boot sector, and the logical start and length fields are Xused to actually delimit the partition used by a particular system. X.SS "Partition Names" X.LP XThe X.B Name Xfield in the partition table is treated specially if the X.B bootmenu Xprogram is installed in the primary boot sector. X(See the file bootmenu.doc for more information.) X.B pfdisk Xcan recognize the name table used by X.B bootmenu Xand will show the actual names present in that name table. XIf any other boot program is used then the X.B Name Xfield reflects the result of a table-lookup of the system ID. X.LP XIf you provide a name when setting any partition entry, the Xboot-sector is marked as using a name table, so that on Xsubsequent uses of X.B pfdisk Xyou will see the partition names you have specified. X.SS "Boot program replacement" X.LP XYou can replace the boot program in your boot sector without Xaffecting the partition table by using X.B pfdisk Xas follows. First, (as always) save a copy of the current boot Xsector (on a floppy) using the "W file" command. Then, use the X"R file" command to read the new boot program. XIf the boot program read in is less than 446 bytes long, the Xpartition table will be unchanged. X.LP XUnlike the DOS or UNIX X.B fdisk Xprograms, X.B pfdisk Xhas X.I NO Xboot program compiled into its executable image. XIf you wish to use X.B pfdisk Xto partition a newly formatted hard disk, you must have a boot program Ximage available to read in using the "r file" command. XTwo boot programs, "bootmenu.bin" and "bootauto.bin" are distributed with X.B pfdisk Xand should be found with its source files. See the file bootmenu.doc Xfor further information about these boot programs. X.SH AUTHOR XGordon W. Ross END_OF_pfdisk.man if test 6386 -ne `wc -c Changes <<'END_OF_Changes' XNew in version 1.3: XOct 90 X Updated documentation for comp.sources.misc posting. X Cleaned up slightly, using unsigned where appropriate. X Forced "small" model for MicroSoft C compiler. (DOS...) X pfdisk command letters can be upper or lower case X Added partition ID codes as (generously) reported by X leendert@cs.vu.nl (Leendert van Doorn) X XNew in version 1.2: XSept '90 X Added new, smaller version of boot program (BOOTMENU). X Renamed boot-hdp to BOOTAUTO (more descriptive of its function?) X Added prompt (people were confused wihout it) X Made pfdisk show real name field with sysid==0. X Made pfdisk set the signature whenever a (1,2,3,4) command X specifies the optional name argument. X Made pfdisk complain about invalid boot sector and mark it valid. X XNew in version 1.1: XFeb '90 X Added MSDOS compatibility to hex2bin.c X Moved ESIX patches into a separate package. X X Renamed s_minix.c to s_unix.c (it's generic) X Created an s_isc.c for Interactive Systems UNIX X X Fixed inconsistencies in esix-fix.sh and X Removed byte-order dependencies from pfdisk.c X X Revised instructions in boot-hdp.doc X XVersion 1.0 released (initial beta) END_OF_Changes if test 1131 -ne `wc -c Makefile <<'END_OF_Makefile' X# This makefile supports all UNIX-like systems. X# Uncomment one of the SYS definitions below, or X# use a make command like: X# make SYS=esix X# (For compiling on MS-DOS, see make_msc.bat) X# (To compile on Minix, use: make minix) X# X# Uncomment for Everex Systems (ESIX) Sys.V/386 Rel. 3.2 X#SYS=esix X# Uncomment for Interactive Systems (ISC) Sys.V/386 X#SYS=i386 X# Uncomment for MSDOS with UNIX-style make (i.e. ndmake) X#SYS=msdos X# Uncomment for other UNIX-compatible systems (for testing) XSYS=unix X X# Compilation options: XCC=cc XCFLAGS=-g X XFILES1= README pfdisk.man Changes Makefile pfdisk.c syscodes.c \ X syscodes.h sysdep.h s_esix.c s_i386.c s_unix.c s_msdos.c XFILES2= bootmenu.doc pfdisk.doc SStor.txt bootmenu.asm bootauto.asm \ X asm2bin.bat make_msc.bat bootmenu.hex bootauto.hex hex2bin.c X XOBJS= pfdisk.o syscodes.o s_$(SYS).o XLSRC= pfdisk.c syscodes.c s_$(SYS).c X Xtest: pfdisk X (echo "g 1222 15 34";\ X echo "1 4 0 127 MS-LOSS";\ X echo "2 129 128 255 Minix";\ X echo "4 99 256 1221 ESIX";\ X echo "a 4"; echo l; echo 'q!' \ X ) | pfdisk /dev/null X Xall: pfdisk bootmenu.bin bootauto.bin X Xpfdisk: $(OBJS) X $(CC) $(CFLAGS) -o $@ $(OBJS) X Xminix: bootmenu.bin bootauto.bin X $(CC) $(CFLAGS) -o pfdisk $(LSRC) X Xpfdisk.o : syscodes.h sysdep.h Xsyscodes.o : syscodes.h Xs_$(SYS).o : sysdep.h X Xlint: $(LSRC) X lint $(CFLAGS) $(LSRC) X Xbootmenu.bin: hex2bin X hex2bin pfdisk.doc X Xclean: X rm -f *.o X XShar1.out: Head1.txt $(FILES1) X (cat Head1.txt ; shar $(FILES1)) > $@ XShar2.out: Head2.txt $(FILES2) X (cat Head2.txt ; shar $(FILES2)) > $@ X XDist.tar: HeadTar.txt $(FILES1) $(FILES2) X tar cf $@ HeadTar.txt $(FILES1) $(FILES2) END_OF_Makefile if test 1765 -ne `wc -c pfdisk.c <<'END_OF_pfdisk.c' X/* X * pfdisk - Partition a Fixed DISK X * by Gordon W. Ross, Jan. 1990 X * X * See the file "pfdisk.doc" for user instructions. X * X * This program uses a simple, line-oriented interpreter, X * designed for both interactive and non-interactive use. X * To facilitate non-interactive use, the output from the X * 'L' (list partitions) command is carefully arranged so it X * can be used directly as command input. Neat trick, eh? X */ X Xchar *versionString = X "# pfdisk version 1.3 by Gordon W. Ross Oct. 1990\n"; X X/* These don't really matter. The user is asked to set them. */ X#define DEFAULT_CYLS 306 X#define DEFAULT_HEADS 4 X#define DEFAULT_SECTORS 17 X#define PROMPT_STRING "pfdisk> " X X#include X#include X#include X#include "sysdep.h" X#include "syscodes.h" X Xtypedef unsigned char uchar; Xtypedef unsigned int uint; Xtypedef unsigned long ulong; X Xstruct part { /* An entry in the partition table */ X uchar active; /* active flag (0x80 or 0) */ X uchar b_head; /* begin head */ X uchar b_sec; /* sector */ X uchar b_cyl; /* cylinder */ X uchar sysid; /* system id (see sysid.c) */ X uchar e_head; /* end head */ X uchar e_sec; /* end sector */ X uchar e_cyl; /* end cylinder */ X /* These two are just longs, but this way is machine independent. */ X uchar lsBeg[4]; /* logical sectors, beginning */ X uchar lsLen[4]; /* logical sectors, length */ X}; X X#define LOC_PT 0x1BE X#define LOC_NT 0x180 X#define LOC_GWR 0x1A0 X#define MAGIC_LOC 0x1FE X#define MAGIC_0 0x55 X#define MAGIC_1 0xAA X#define MAX_LINE 80 X Xchar buffer[SECSIZE]; /* The boot block buffer */ Xint bufmod=0; /* buffer modified... */ X /* (zero means buffer is unmodified) */ Xint useNTable; /* boot sector uses name table */ X X/* device parameters (force someone to set them!) */ Xunsigned cyls = DEFAULT_CYLS; Xunsigned heads = DEFAULT_HEADS; Xunsigned sectors = DEFAULT_SECTORS; X Xchar *devname; /* device name */ Xchar cmdline[MAX_LINE]; Xchar filename[80]; /* used by r/w commands */ Xchar *prompt; /* null if no tty input */ X X/* Some of these strings are used in more than one place. X * For consistency, I put a newline on all of them. X */ Xchar h_h[] = "? : Help summary\n"; Xchar h_l[] = "L : List partition table\n"; Xchar h_1[] = "1 id first last name : set partition 1\n"; Xchar h_2[] = "2,3,4 ... (like 1) : set respective partition\n"; Xchar h_a[] = "A n : Activate partition n\n"; Xchar h_g[] = "G cyls heads sectors : set disk Geometry\n"; Xchar h_i[] = "I : list known ID numbers\n"; Xchar h_r[] = "R [optional-file] : Read device (or specified file)\n"; Xchar h_w[] = "W [optional-file] : Write device (or specified file)\n"; Xchar h_q[] = "Q[!] : Quit (! means force)\n"; X Xchar * helpTable[] = { Xh_h, h_l, h_1, h_2, h_a, h_g, h_i, h_r, h_w, h_q, X"# (All command letters have lower-case equivalents.)\n", X(char *) 0 }; /* This MUST have a zero as the last element */ X Xchar *BadArg="Error: bad argument: %s\n"; Xchar *WarnNotSaved = X "Warning, modified partition table not saved.\n"; X X/* forward declarations */ Xvoid main(); Xvoid help(); Xvoid listPTable(); Xvoid checkValidity(); Xchar * setPartition(); Xchar * makeActive(); Xchar * setGeometry(); Xvoid long2chs(); Xulong chs2long(); Xchar * nameID(); Xvoid printIDs(); X Xvoid help() X{ X char ** p; X for (p = helpTable; *p; p++) X printf(*p); X} X Xvoid main(argc,argv) Xint argc; Xchar *argv[]; X{ X char *cmdp; /* points to command word */ X char *argp; /* points to command args */ X X /* check command line args (device name) */ X if (argc != 2) { X usage(argv[0]); /* See s-sysname.c */ X exit(1); X } X devname = argv[1]; X X /* Should we prompt? */ X prompt = (isatty(fileno(stdin))) ? PROMPT_STRING : (char *) 0; X X /* Print version name. */ X fputs(versionString, stderr); X X /* get disk parameters */ X getGeometry(devname,&cyls,&heads,§ors); X X /* Get the boot block. */ X if (getBBlk(devname, buffer) < 0) X fprintf(stderr,"%s: read failed\n", devname); X checkValidity(); X X if (prompt) fprintf(stderr,"For help, enter: '?'\n"); X X X /* Read and process commands a line at a time. */ X while (1) { X if (prompt) fputs(prompt,stdout); X if (! fgets(cmdline, MAX_LINE, stdin)) break; X X /* Find beginning of command word */ X cmdp = cmdline; X while (isspace(*cmdp)) cmdp++; X X /* find beginning of args */ X argp = cmdp; X while (*argp && !isspace(*argp)) argp++; X while (isspace(*argp) || *argp=='=') argp++; X X switch (*cmdp) { X X case '\0': /* blank line */ X case '#': /* line comment */ X break; X X case '?': case 'h': case 'H': X help(); X break; X X case '1': /* set partition entry */ X case '2': case '3': case '4': X argp = setPartition(cmdp, argp); X if (argp) { /* arg list error */ X fprintf(stderr,BadArg,argp); X fprintf(stderr,h_1); X fprintf(stderr,h_2); X break; X } X bufmod = 1; X break; X X case 'a': case 'A': /* activate partition */ X argp = makeActive(argp); X if (argp) { X fprintf(stderr,BadArg,argp); X fprintf(stderr,h_a); X break; X } X bufmod = 1; X break; X X case 'g': case 'G': /* set disk parameters (Geometry) */ X argp = setGeometry(argp); X if (argp) { /* arg list error */ X fprintf(stderr,BadArg,argp); X fprintf(stderr,h_g); X } X break; X X case 'i': case 'I': /* List known ID numbers */ X printIDs(); X break; X X case 'l': case 'L': /* List the partition table */ X listPTable(); X break; X X case 'q': case 'Q': /* Quit */ X if (bufmod && (cmdp[1] != '!')) { X fprintf(stderr,"\007%s%s\n", WarnNotSaved, X "Use 'wq' or 'q!' (enter ? for help)."); X break; X } X exit(0); X /*NOTREACHED*/ X X case 'r': case 'R': /* read from device or file */ X if (sscanf(argp,"%80s",filename) == 1) { X /* Arg specified, read from filename */ X if (getFile(filename, buffer, SECSIZE) < 0) X fprintf(stderr,"%s: read failed\n", filename); X bufmod = 1; X } else { X /* No arg, use device. */ X if (getBBlk(devname, buffer) < 0) X fprintf(stderr,"%s: read failed\n", devname); X bufmod = 0; X } X checkValidity(); X break; X X case 'w': case 'W': /* Write to file or device */ X if (sscanf(argp,"%80s",filename) == 1) { X /* Arg specified, write to filename */ X if (putFile(filename, buffer, SECSIZE) < 0) X fprintf(stderr, "%s: write failed\n", filename); X } else { /* No arg, use device. */ X if (putBBlk(devname, buffer) < 0) X fprintf(stderr, "%s: write failed\n", devname); X bufmod = 0; X } X if (cmdp[1] == 'q' || cmdp[1] == 'Q') exit(0); X break; X X default: X fprintf(stderr,"'%c': unrecognized. Enter '?' for help.\n", *cmdp); X break; X X } /* switch */ X } /* while */ X if (bufmod) fprintf(stderr, WarnNotSaved); X exit(0); X} /* main */ X X X/* Check for valid boot block (magic number in last two bytes). X * Also, check for presence of partition name table. X */ Xvoid checkValidity() X{ X /* Check the magic number. */ X if ((buffer[MAGIC_LOC] & 0xFF) != MAGIC_0 || X (buffer[MAGIC_LOC+1] & 0xFF) != MAGIC_1 ) { X /* The boot sector is not valid -- Fix it. */ X buffer[MAGIC_LOC] = MAGIC_0; X buffer[MAGIC_LOC+1] = MAGIC_1; X bufmod = 1; X fprintf(stderr, X"\n\tWarning: The boot sector has an invalid magic number.\n\ X\tThe magic number has been fixed, but the other contents\n\ X\tare probably garbage. Initialize using the command:\n\ X\t\tR boot-program-file (i.e. bootmenu.bin)\n\ X\tthen set each partition entry if necessary.\n"); X } X X /* Does it use a name table (for a boot menu)? X * My boot program does, and can be identified by X * finding my name in a particular (unused) area. X */ X useNTable = !strcmp(buffer+LOC_GWR, "Gordon W. Ross"); X X} X Xchar * setPartition(cmdp,argp) /* return string on error */ Xchar *cmdp,*argp; X{ X struct part *pp; /* partition entry */ X char * np; /* name table pointer */ X char * newname; /* name field */ X int index; /* partition index (0..3) */ X uint id; /* ID code (see syscodes.c) */ X uint first,last; /* user supplied cylinders */ X uint c,h,s; /* working cyl,head,sect, */ X uint len; /* chars seen by sscanf */ X ulong lsbeg, lslen; /* logical begin, length */ X X /* Value check the index */ X index = *cmdp - '1'; X if (index < 0 || index > 3) X return("index"); X pp = (struct part *) (buffer + LOC_PT + index * 16); X np = buffer + LOC_NT + index * 8; X X /* Read System ID */ X if (sscanf(argp,"%i%n", &id, &len) < 1) X return("id"); X argp += len; X X /* If ID==0, just clear out the entry and return. */ X if (id == 0) { X strncpy( (char *) pp, "", 16); X if (useNTable) strncpy( np, "", 8); X return((char *)0); X } X X /* Read first and last cylinder */ X if (sscanf(argp,"%i%i%n",&first, &last, &len) < 2) X return("first last (missing)"); X argp += len; X X /* Reasonable start,end cylinder numbers? */ X if (first > last) return("first > last"); X if (first > 1023) return("first > 1023"); X if (last >= cyls) return("last >= cyls"); X X /* Get (optional) system name. */ X if (*argp == '\n') { /* no name given, use default */ X newname = nameID(id); X } else { /* use the given name */ X /* skip leading space */ X while (*argp == ' ') argp++; X newname = argp; X /* Remove newline from end */ X while (isgraph(*argp)||*argp==' ') argp++; X *argp = '\0'; X useNTable = 1; X } X X /* Set the ID and name. */ X pp->sysid = id; X if (useNTable) { X strncpy(np, newname, 8); X strcpy(buffer + LOC_GWR, "Gordon W. Ross"); X } X X /* set beginning c,h,s */ X c = first; X /* if c == 0, head == 1 (reserve track 0) */ X h = (first) ? 0 : 1; X s = 1; X pp->b_cyl = c & 0xFF; X pp->b_head = h; X pp->b_sec = s | ((c >> 2) & 0xC0); X /* Set the logical sector begin field */ X lsbeg = lslen = chs2long(c,h,s); /* using lslen as temp. */ X pp->lsBeg[0] = lslen & 0xff; lslen >>= 8; X pp->lsBeg[1] = lslen & 0xff; lslen >>= 8; X pp->lsBeg[2] = lslen & 0xff; lslen >>= 8; X pp->lsBeg[3] = lslen & 0xff; lslen >>= 8; X X /* set ending c,h,s (last may be larger than 1023) */ X c = (last>1023) ? 1023 : last; /* limit c to 1023 */ X h = heads - 1; s = sectors; X pp->e_cyl = c & 0xFF; X pp->e_head = h; X pp->e_sec = s | ((c >> 2) & 0xC0); X /* Set the logical sector length field (using REAL end cylinder) */ X lslen = chs2long(last,h,s) + 1 - lsbeg; X pp->lsLen[0] = lslen & 0xff; lslen >>= 8; X pp->lsLen[1] = lslen & 0xff; lslen >>= 8; X pp->lsLen[2] = lslen & 0xff; lslen >>= 8; X pp->lsLen[3] = lslen & 0xff; lslen >>= 8; X X return((char *)0); /* success */ X} /* setPartition() */ X Xchar * makeActive(argp) /* return error string or zero */ Xchar *argp; X{ X struct part *pp; /* partition entry */ X int i,act; /* which one becomes active */ X X if (sscanf(argp,"%d", &act) < 1) X return("missing index"); X act--; /* make it zero-origin */ X X i=0; pp = (struct part *) (buffer + LOC_PT); X while (i<4) { X pp->active = 0; X if (i == act) { X if (pp->sysid == 0) return("partition empty"); X pp->active = 0x80; X } X i++; pp++; X } X return((char *)0); X} X Xchar * setGeometry(argp) /* return string on error */ Xchar *argp; X{ X int c,h,s; X X if (sscanf(argp,"%i%i%i", &c, &h, &s) < 3) X return("(missing)"); X if (c<1) return("cyls"); X if (h<1) return("heads"); X if (s<1) return("sectors"); X cyls=c; heads=h; sectors=s; X return((char *)0); X} X Xvoid listPTable() /* print out partition table */ X{ X struct part * pp; /* partition table entry */ X int i; /* partition number */ X int numActive=0; /* active partition [1-4], 0==none */ X uint pbc,pbh,pbs; /* physical beginning c,h,s */ X uint pec,peh,pes; /* physical ending c,h,s */ X uint lbc,lbh,lbs; /* logical beginning c,h,s */ X uint lec,leh,les; /* logical ending c,h,s */ X ulong lsbeg,lslen; /* logical sectors: begin, length */ X X printf("# Partition table on device: %s\n", devname); X printf("geometry %d %d %d (cyls heads sectors)\n", X cyls, heads, sectors); X printf("# ID First(cyl) Last(cyl) Name "); X printf("# start, length (sectors)\n"); X X for (i=0; i<4; i++) { X pp = (struct part *) (buffer + LOC_PT + i * 16); X X if (pp->active) { X if(numActive) X fprintf(stderr,"Error: multiple active partitions.\n"); X else numActive = i+1; X } X X /* physical beginning c,h,s */ X pbc = pp->b_cyl & 0xff | (pp->b_sec << 2) & 0x300; X pbh = pp->b_head; X pbs = pp->b_sec & 0x3F; X X /* physical ending c,h,s */ X pec = pp->e_cyl & 0xff | (pp->e_sec << 2) & 0x300; X peh = pp->e_head; X pes = pp->e_sec & 0x3F; X X /* compute logical beginning (c,h,s) */ X lsbeg = ((((((pp->lsBeg[3] ) << 8 ) X | pp->lsBeg[2] ) << 8 ) X | pp->lsBeg[1] ) << 8 ) X | pp->lsBeg[0] ; X long2chs(lsbeg, &lbc, &lbh, &lbs); X /* compute logical ending (c,h,s) */ X lslen = ((((((pp->lsLen[3]) << 8 ) X | pp->lsLen[2]) << 8 ) X | pp->lsLen[1]) << 8 ) X | pp->lsLen[0] ; X /* keep beginning <= end ... */ X if (lslen > 0) long2chs(lsbeg+lslen-1, &lec, &leh, &les); X else long2chs(lsbeg, &lec, &leh, &les); X X /* show physical begin, logical end (works for cyl>1023) */ X /* # ID First(cyl) Last(cyl) Name... # ... */ X printf("%d %3d %4d %4d ", i+1, pp->sysid, pbc, lec); X if (useNTable) printf("%-8.8s ", buffer + LOC_NT + i * 8); X else printf("# %-8.8s ", nameID((uint) pp->sysid)); X printf("# %ld, %ld\n", lsbeg, lslen ); X X /* That's all, for an empty partition. */ X if (pp->sysid == 0) continue; X X /* X * Now do some consistency checks... X */ X X /* Same physical / logical beginning? */ X if (pbc != lbc || pbh != lbh || pbs != lbs ) { X printf("# note: first(%d): ", i+1); X printf("phys=(%d,%d,%d) ", pbc, pbh, pbs); X printf("logical=(%d,%d,%d)\n",lbc, lbh, lbs); X } X /* Same physical / logical ending? */ X if (pec != lec || peh != leh || pes != les ) { X printf("# note: last(%d): ", i+1); X printf("phys=(%d,%d,%d) ", pec, peh, pes); X printf("logical=(%d,%d,%d)\n",lec, leh, les); X } X X /* Beginning on cylinder boundary? */ X if (pbc == 0) { /* exception: start on head 1 */ X if (pbh != 1 || pbs != 1) { X printf("# note: first(%i): ", i+1); X printf("phys=(%d,%d,%d) ", pbc, pbh, pbs); X printf("should be (%d,1,1)\n", pbc); X } X } else { /* not on cyl 0 */ X if (pbh != 0 || pbs != 1) { X printf("# note: first(%i): ", i+1); X printf("phys=(%d,%d,%d) ", pbc, pbh, pbs); X printf("should be (%d,0,1)\n", pbc); X } X } X X /* Ending on cylinder boundary? */ X if (peh != (heads-1) || pes != sectors) { X printf("# note: last(%i): ", i+1); X printf("phys=(%d,%d,%d) ", pec, peh, pes); X printf("should be (%d,%d,%d)\n", X pec, heads-1, sectors); X } X X } /* for */ X printf("active: %d %s\n", numActive, X (numActive) ? "" : "(none)"); X} /* listPTable() */ X Xulong chs2long(c,h,s) Xuint c,h,s; X{ X ulong l; X if (s<1) s=1; X l = c; l *= heads; X l += h; l *= sectors; X l += (s - 1); X return(l); X} X Xvoid long2chs(ls, c, h, s) /* convert logical sec-num to c,h,s */ Xulong ls; /* Logical Sector number */ Xuint *c,*h,*s; /* cyl, head, sector */ X{ X int spc = heads * sectors; X *c = ls / spc; X ls = ls % spc; X *h = ls / sectors; X *s = ls % sectors + 1; /* sectors count from 1 */ X} X Xchar * nameID(n) Xunsigned int n; X{ X struct intString *is; X X is = sysCodes; X while (is->i) { X if (is->i == n) return(is->s); X is++; X } X if (!n) return(is->s); X return("unknown"); X} X Xvoid printIDs() /* print the known system IDs */ X{ X struct intString * is = sysCodes; X X /* This might need to do more processing eventually, i.e. X * if (prompt) { ... do more processing ... } X */ X printf("_ID_\t__Name__ ____Description____\n"); X while (is->i) { X printf("%3d\t%s\n", is->i, is->s); X is++; X } X} END_OF_pfdisk.c if test 15779 -ne `wc -c syscodes.c <<'END_OF_syscodes.c' X/* This file holds all knowledge of partition ID codes. X * Thanks to leendert@cs.vu.nl (Leendert van Doorn) for X * collecting most of this information. X */ X X#define extern X#include "syscodes.h" X#undef extern X X/* Note that my boot program menu can only use the first 8 characters X * of these names. The colon in the nineth position shows where the X * first truncated char is. (There's not much room in the bootblock!) X */ Xstruct intString sysCodes[] = { X{ 0x01, "DOS-12 :12-bit FAT" }, X{ 0x02, "XENIX :root" }, X{ 0x03, "XENIX :usr" }, X{ 0x04, "DOS-16 :16-bit FAT" }, X{ 0x05, "DOS-ext :DOS 3.3 extended volume" }, X{ 0x06, "DOS-big :DOS 4.0 large volume" }, X{ 0x07, "OS/2 :OS/2 (or QNX or Adv. UNIX...)" }, X{ 0x08, "AIX :file system" }, X{ 0x09, "AIX-boot:boot partition" }, X X{ 0x10, "OPUS :?" }, X{ 0x40, "VENIX :Venix 80286" }, X{ 0x51, "NOVELL :?" }, X{ 0x52, "CPM :?" }, X{ 0x63, "UNIX :System V/386" }, X{ 0x64, "NOVELL :?" }, X{ 0x75, "PC/IX :?" }, X{ 0x80, "Minix :Minix (ver. 1.4a and earlier)" }, X{ 0x81, "Minix :Minix (ver. 1.4b and later)" }, X{ 0x93, "Amoeba :Amoeba file system" }, X{ 0x94, "Amoeba :Amoeba bad block table?" }, X{ 0xDB, "C.DOS :Concurrent DOS" }, X X/* { 0xF2, "DOS-2nd :DOS 3.3+ second partition" }, */ X/* { 0xFF, "BAD-TRK :Bad track table?" }, */ X X/* Make sure this is last! */ X{ 0, "(empty)" } X}; END_OF_syscodes.c if test 1357 -ne `wc -c syscodes.h <<'END_OF_syscodes.h' Xstruct intString { unsigned int i; char * s; }; Xextern struct intString sysCodes[]; END_OF_syscodes.h if test 84 -ne `wc -c sysdep.h <<'END_OF_sysdep.h' X/* communicate declarations from the files: s_*.c */ X X#define SECSIZE 0x200 X Xextern void usage(); /* print a usage message */ X /* (char *progname) */ X Xextern void getGeometry(); /* determine disk parameters */ X /* (char *dev, uint *cyls, uint *heads, uint *sectors) */ X Xextern int getFile(); /* open, read, close, return(num-read) */ X /* (char *name, char *buf, int len) */ X Xextern int putFile(); /* open, write, close, return(num-writen) */ X /* (char *name, char *buf, int len) */ X Xextern int getBBlk(); /* open, read, close, return(num-read) */ X /* (char *dev, char *buf) */ X Xextern int putBBlk(); /* open, write, close, return(num-writen) */ X /* (char *dev, char *buf) */ END_OF_sysdep.h if test 676 -ne `wc -c s_esix.c <<'END_OF_s_esix.c' X/* This file contains system-specific functions for ESIX. X * The program pfdisk.c calls these routines. X * Note that ESIX can't use the generic Sys.V/386 version of X * this file because it uses ioctl calls to access the X * primary boot sector. Other systems provide a device which X * maps onto the whole disk (starting with the boot sector). X */ X#include X#include X#include X#include X X#define extern X#include "sysdep.h" X#undef extern X Xvoid usage(prog) /* print a usage message */ Xchar *prog; /* program name */ X{ X fprintf(stderr,"Usage: %s dev\n\t%s\n", prog, X "where 'dev' is the device name, i.e. /dev/rdsk/0s0"); X} X Xvoid getGeometry(dev, c, h, s) Xchar *dev; /* device name */ Xunsigned *c,*h,*s; /* cyls, heads, sectors */ X{ X int devfd, retval; X struct disk_parms dp; X X devfd = open(dev, O_RDONLY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for reading\n", dev); X return; X } X retval = ioctl(devfd, V_GETPARMS, &dp); X close(devfd); X if (retval < 0) { X fprintf(stderr,"%s: can't get disk parameters\n", dev); X return; X } X if (dp.dp_type != DPT_WINI) { X fprintf(stderr,"%s: not a Winchester Disk\n", dev); X return; X } X *c = dp.dp_cyls; X *h = dp.dp_heads; X *s = dp.dp_sectors; X} X Xint getFile(name, buf, len) /* read file into buffer */ Xchar *name, *buf; Xint len; X{ /* (open, read, close) */ X int devfd, retval; X X devfd = open(name, O_RDONLY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for reading\n", name); X return(devfd); X } X retval = read(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: read failed\n", name); X close(devfd); X return(retval); X} X Xint putFile(name, buf, len) /* write buffer to file */ Xchar *name, *buf; Xint len; X{ /* (open, write, close) */ X int devfd, retval; X X devfd = open(name, O_WRONLY|O_CREAT, 0666); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for writing\n", name); X return(devfd); X } X retval = write(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: write failed\n", name); X close(devfd); X return(retval); X} X Xint getBBlk(name, buf) /* read Boot Block into buffer */ Xchar *name, *buf; X{ /* (open, read, close) */ X int devfd, retval; X struct absio abs; X X devfd = open(name, O_RDONLY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for reading\n", name); X return(devfd); X } X abs.abs_sec = 0; /* the primary boot sector */ X abs.abs_buf = buf; X retval = ioctl(devfd, V_RDABS, &abs); X if (retval < 0) X fprintf(stderr,"%s: read failed\n", name); X close(devfd); X return(retval); X} X Xint putBBlk(name, buf) /* write buffer to Boot Block */ Xchar *name, *buf; X{ /* (open, write, close) */ X int devfd, retval; X struct absio abs; X X devfd = open(name, O_WRONLY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for writing\n", name); X return(devfd); X } X abs.abs_sec = 0; /* the primary boot sector */ X abs.abs_buf = buf; X retval = ioctl(devfd, V_WRABS, &abs); X if (retval < 0) X fprintf(stderr,"%s: write failed\n", name); X close(devfd); X return(retval); X} END_OF_s_esix.c if test 3086 -ne `wc -c s_i386.c <<'END_OF_s_i386.c' X/* This file contains system-specific functions suitable for X * most AT&T System V/386 variants (ISC,SCO,Intel...). X * The program pfdisk.c calls these routines. X */ X#include X#include X#include X#include X X#define extern X#include "sysdep.h" X#undef extern X Xvoid usage(prog) /* print a usage message */ Xchar *prog; /* program name */ X{ X fprintf(stderr,"Usage: %s dev\n\ X where 'dev' is the device name, i.e. /dev/rdsk/0p0\n\ X (The device must start on absolute sector zero.)\n",prog); X} X Xvoid getGeometry(dev, c, h, s) Xchar *dev; /* device name */ Xunsigned *c,*h,*s; /* cyls, heads, sectors */ X{ X int devfd, retval; X struct disk_parms dp; X X devfd = open(dev, O_RDONLY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for reading\n", dev); X return; X } X retval = ioctl(devfd, V_GETPARMS, &dp); X close(devfd); X if (retval < 0) { X fprintf(stderr,"%s: can't get disk parameters\n", dev); X return; X } X if (dp.dp_type != DPT_WINI) { X fprintf(stderr,"%s: not a Winchester Disk\n", dev); X return; X } X *c = dp.dp_cyls; X *h = dp.dp_heads; X *s = dp.dp_sectors; X} X Xint getFile(name, buf, len) /* read file into buffer */ Xchar *name, *buf; Xint len; X{ /* (open, read, close) */ X int devfd, retval; X X devfd = open(name, O_RDONLY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for reading\n", name); X return(devfd); X } X retval = read(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: read failed\n", name); X close(devfd); X return(retval); X} X Xint putFile(name, buf, len) /* write buffer to file */ Xchar *name, *buf; Xint len; X{ /* (open, write, close) */ X int devfd, retval; X X devfd = open(name, O_WRONLY|O_CREAT, 0666); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for writing\n", name); X return(devfd); X } X retval = write(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: write failed\n", name); X close(devfd); X return(retval); X} X Xint getBBlk(devname, buffer) /* read block into buffer */ Xchar *devname, *buffer; /* (open, read, close) */ X{ X int devfd, retval; X X devfd = open(devname,O_RDONLY); X if (devfd < 0) { X printf("%s: can't open for read\n", devname); X return(devfd); X } X retval = read(devfd, buffer, SECSIZE); X close(devfd); X return(retval); X} X Xint putBBlk(devname, buffer) /* write buffer to device */ Xchar *devname, *buffer; /* (open, write, close) */ X{ X int devfd, retval; X X devfd = open(devname,O_WRONLY); X if (devfd < 0) { X printf("%s: can't open for write\n",devname); X return(devfd); X } X retval = write(devfd, buffer, SECSIZE); X sync(); X close(devfd); X return(retval); X} END_OF_s_i386.c if test 2648 -ne `wc -c s_unix.c <<'END_OF_s_unix.c' X/* This file contains system-specific functions for generic UNIX. X * The program pfdisk.c calls these routines. X */ X#include X#include X X#define extern X#include "sysdep.h" X#undef extern X Xvoid usage(prog) /* print a usage message */ Xchar *prog; /* program name */ X{ X fprintf(stderr,"Usage: %s dev\n\ X\twhere 'dev' is the device name, i.e. /dev/hd0\n\ X\t(The device must start on absolute sector zero.)\n",prog); X} X Xvoid getGeometry(dev, c, h, s) Xchar *dev; /* device name */ Xunsigned *c,*h,*s; /* cyls, heads, sectors */ X{ X fprintf(stderr, X"\n\tWarning: The device \"%s\" is assumed to have:\n\ X\tcyls=%d, heads=%d, sectors=%d (an arbitrary guess).\n", X dev, *c, *h, *s); X fprintf(stderr, X"\n\tThis program was compiled for generic UNIX and therefore\n\ X\tdoes not know how to determine the disk parameters. You must\n\ X\tdescribe the disk geometry manually, using the 'G' command.\n"); X} X Xint getFile(name, buf, len) /* read file into buffer */ Xchar *name, *buf; Xint len; X{ /* (open, read, close) */ X int devfd, retval; X X devfd = open(name, O_RDONLY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for reading\n", name); X return(devfd); X } X retval = read(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: read failed\n", name); X close(devfd); X return(retval); X} X Xint putFile(name, buf, len) /* write buffer to file */ Xchar *name, *buf; Xint len; X{ /* (open, write, close) */ X int devfd, retval; X X devfd = open(name, O_WRONLY|O_CREAT, 0666); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for writing\n", name); X return(devfd); X } X retval = write(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: write failed\n", name); X close(devfd); X return(retval); X} X Xint getBBlk(devname, buffer) /* read block into buffer */ Xchar *devname, *buffer; /* (open, read, close) */ X{ X int devfd, retval; X X devfd = open(devname,O_RDONLY); X if (devfd < 0) { X printf("%s: can't open for read\n", devname); X return(devfd); X } X retval = read(devfd, buffer, SECSIZE); X close(devfd); X return(retval); X} X Xint putBBlk(devname, buffer) /* write buffer to device */ Xchar *devname, *buffer; /* (open, write, close) */ X{ X int devfd, retval; X X devfd = open(devname,O_WRONLY); X if (devfd < 0) { X printf("%s: can't open for write\n",devname); X return(devfd); X } X retval = write(devfd, buffer, SECSIZE); X sync(); X close(devfd); X return(retval); X} END_OF_s_unix.c if test 2427 -ne `wc -c s_msdos.c <<'END_OF_s_msdos.c' X/* This file contains system-specific functions for MS-DOS. X * The program pfdisk.c calls these routines. X */ X#include X#include X#include X#include X#include X X#define extern X#include "sysdep.h" X#undef extern X Xvoid usage(prog) /* print a usage message */ Xchar *prog; /* program name */ X{ X fprintf(stderr,"Usage: %s \n", prog); X fprintf(stderr,"\twhere is a digit [0-9]\n"); X} X Xvoid getGeometry(name, c, h, s) Xchar *name; /* device name */ Xunsigned *c,*h,*s; /* cyls, heads, sectors */ X{ X int dev; /* hard disk number */ X union REGS regs; X struct SREGS sregs; X X if (name[0] < '0' || X name[0] > '9' || X name[1] != 0 ) X { X fprintf(stderr,"%s: device name must be a digit\n", name); X return; X } X dev = (name[0] - '0'); X X regs.h.ah = 8; /* get param. */ X regs.h.dl = dev | 0x80; X X int86x(0x13,®s,®s,&sregs); X X /* Are that many drives responding? */ X if (regs.h.dl <= dev ) { X fprintf(stderr,"%s: drive not found\n", name); X return; X } X if (regs.x.cflag) { X fprintf(stderr,"%s: can't get disk parameters\n", name); X return; X } X *c = ((((int) regs.h.cl << 2) & 0x300) | regs.h.ch) + 1; X *h = regs.h.dh + 1; X *s = regs.h.cl & 0x3F; X} X Xint getFile(name, buf, len) /* read file into buffer */ Xchar *name, *buf; Xint len; X{ /* (open, read, close) */ X int devfd, retval; X X devfd = open(name, O_RDONLY|O_BINARY, 0); X if (devfd < 0) { X fprintf(stderr,"%s: can't open for reading\n", name); X return(devfd); X } X retval = read(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: read failed\n", name); X close(devfd); X return(retval); X} X Xint putFile(name, buf, len) /* write buffer to file */ Xchar *name, *buf; Xint len; X{ /* (open, write, close) */ X int devfd, retval; X X devfd = open(name, X O_WRONLY|O_CREAT|O_BINARY, X S_IREAD|S_IWRITE ); /* stupid DOS... */ X if (devfd < 0) { X fprintf(stderr,"%s: can't open for writing\n", name); X return(devfd); X } X retval = write(devfd, buf, len); X if (retval < 0) X fprintf(stderr,"%s: write failed\n", name); X close(devfd); X return(retval); X} X Xint getBBlk(name, buf) /* read boot block into buffer */ Xchar *name, *buf; X{ /* BIOS absolute disk read */ X int dev; X union REGS regs; X struct SREGS sregs; X X if (name[0] < '0' || X name[0] > '9' || X name[1] != 0 ) X { X fprintf(stderr,"%s: device name must be a digit\n",name); X return(-1); X } X dev = (name[0] - '0'); X X segread(&sregs); /* get ds */ X sregs.es = sregs.ds; /* buffer address */ X regs.x.bx = (int) buf; X X regs.h.ah = 2; /* read */ X regs.h.al = 1; /* sector count */ X regs.h.ch = 0; /* track */ X regs.h.cl = 1; /* start sector */ X regs.h.dh = 0; /* head */ X regs.h.dl = dev|0x80; /* drive */ X X int86x(0x13,®s,®s,&sregs); X if (regs.x.cflag) { X fprintf(stderr,"%s: read failed\n", name); X return(-1); X } X return(SECSIZE); X} X Xint putBBlk(name, buf) /* write buffer to boot block */ Xchar *name, *buf; X{ /* BIOS absolute disk write */ X int dev; X union REGS regs; X struct SREGS sregs; X X if (name[0] < '0' || X name[0] > '9' || X name[1] != 0 ) X { X fprintf(stderr,"%s: device name must be a digit\n", name); X return(-1); X } X dev = (name[0] - '0'); X X segread(&sregs); /* get ds */ X sregs.es = sregs.ds; /* buffer address */ X regs.x.bx = (int) buf; X X regs.h.ah = 3; /* write */ X regs.h.al = 1; /* sector count */ X regs.h.ch = 0; /* track */ X regs.h.cl = 1; /* start sector */ X regs.h.dh = 0; /* head */ X regs.h.dl = dev|0x80; /* drive */ X X int86x(0x13,®s,®s,&sregs); X if (regs.x.cflag) { X fprintf(stderr,"%s: write failed\n",name); X return(-1); X } X return(SECSIZE); X} END_OF_s_msdos.c if test 3769 -ne `wc -c