[comp.unix.sysv386] BOOTMENU and PFDISK 1.2

gwr@linus.mitre.org (Gordon W. Ross) (09/08/90)

Here is part 1 of the BOOTMENU and PFDISK 2.1 distribution.

BOOTMENU is a replacement primary boot sector which allows boot-time
selection of the boot partition using a menu.  PFDISK is a replacement
"fdisk" command for installing BOOTMENU without clobbering partitions.

More detailed descriptions are found in the README file at the
beginning of the first shell archive.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	bootmenu.doc
#	pfdisk.doc
#	pfdisk.man
#	Changes
#	Makefile
#	pfdisk.c
#	syscodes.c
#	syscodes.h
#	sysdep.h
#	s_esix.c
#	s_i386.c
#	s_unix.c
#	bootmenu.hex
#	bootauto.hex
#	hex2bin.c
# This archive created: Fri Sep  7 18:37:57 1990
# By:	Gordon W. Ross (The MITRE Corporation, Bedford, MA.)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(3018 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

BOOTMENU is a hard-disk primary bootstrap program which allows
boot-time selection of the boot partition.

BOOTAUTO is similar to BOOTMENU but allows both unattended reboot
and the ability to override the automatic selection of the active
partition at boot-time.  (I used to call this version boot-hdp).

BOOTMENU cannot do an unattended reboot but is very small and
(as a result) will not be clobbered if you use the SpeedStor
disk formatting/diagnostics program.  (Notes about SpeedStor's
usage of the primary boot sector are in the file SStor.txt).

PFDISK is a replacement for both DOS and UNIX fdisk programs.
This replacement is distinguished for its ability to put
an arbitrary binary image into the primary boot sector without
clobbering an existing partition table.  PFDISK has no boot
program built-in, but allows you to take the boot program
from a file.  At least one of the boot program file such as
BOOTMENU must be available to PFDISK if it is expected to
initialize a newly formatted disk.  Unlike MSDOS fdisk,
PFDISK correctly handles partition entries which extend
beyond cyl 1023.  Unlike UNIX fdisk, PFDISK is not confused
about the difference between highest-usable-cylinder-number
and (beginning-cylinder plus number-of-cylinders).

Documentation included:

The file bootmenu.doc explains how to install and use the new
boot programs.  The file pfdisk.1 is manual entry in nroff format,
and pfdisk.doc is a formatted manual for those without nroff.

How to compile:

To build pfdisk, edit the Makefile to uncomment the appropriate
line (i.e. SYS=i386) and type "make".

The boot program binaries are distributed as simple HEX encoded
text files.  The (included) program hex2bin will convert them
for the benefit of those without the MASM (DOS) assembler.

Related packages (distributed separately):

The MSDOS-FIX package contains patches for MSDOS 3.3 to allow it to
use the first 1024 cylinders of a hard disk when the disk controller
BIOS has installed disk parameters showing more than 1024 cylinders.
Note that this patch is designed for use on PC/AT compatible disk
controllers that have a BIOS parameter override feature, such as the
RLL and ESDI controllers by Adaptec and Western Digital.
The MSDOS-FIX package has been posted:

	Newsgroups: comp.sys.ibm.pc
	Subject: MSDOS 3.3 patch for >1024 cyl hard disk
	Date: 6 Sep 90 16:12:35 GMT

The ESIX-BOOT package contains patches to make ESIX (Everex Systems
SysV/386) boot from an inactive partition.  Normally, ESIX will refuse
to boot unless its partition is marked as active.  These patches allow
one to configure the partition table such that bootmenu will always
present its boot menu (no partition marked active).
This package should be seen in comp.unix.i386 by mid October (after
it is updated to include fixes for Rev.D as well as Rev.C).

Gordon W. Ross	(M/S E095)	| internet: gwr@linus.mitre.org
The MITRE Corporation		| uucp: (backbone-host)!linus!gwr
Burlington Road			| Day-phone: 617-271-3205
Bedford, MA 01730 (U.S.A.)	|

SHAR_EOF
if test 3018 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 3018 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'bootmenu.doc'" '(3884 characters)'
if test -f 'bootmenu.doc'
then
	echo shar: will not over-write existing file "'bootmenu.doc'"
else
cat << \SHAR_EOF > 'bootmenu.doc'

	BOOTMENU -- a BOOT sector program with a MENU
	---------------------------------------------
		by Gordon W. Ross, Aug 1990

	This program is loaded by the PC ROM BIOS and is responsible
	for selecting one of four partitions to boot from.  The normal
	(MS-DOS) version of this program always boots the "active"
	partition, but this version allows any partition to be
	selected for booting, wether marked "active" or not.

	Two versions of this program are now distributed:

	BOOTMENU is small (less than 256 bytes of code) and compatible
	with the SpeedStor hard disk formatting package.  (Note that
	SpeedStor writes in several locations in the boot sector!)
	This version, however, does not allow unattended reboots.
	After BOOTMENU displays its partition menu, it waits
	indefinitely for someone to select a boot partition.

	BOOTAUTO (previously called "boot-hdp") is a full-featured
	boot program which allows boot-time partition selection, but
	also provides a default selection which is used if no user
	input arrives within five seconds.

	The behaviour of BOOTAUTO is as follows:

	BOOTAUTO displays the message:
		Booting device: hd0,
	and then pauses for a five second delay.

	If the user presses any key before the delay expires, a menu
	of bootable partitions is displayed, and the user is prompted
	for the number of the partition to boot from.  If no key is
	pressed before the delay ends, the first partition marked as
	"active" is used.  If no partition is marked as active, the
	boot menu is presented without delay, as if a key were struck.
	In essence, this program interprets the "active" mark (if
	present) as a default choice indicator.

	Once a partition has been selected this program displays the
	selected partition number and loads its secondary boot
	program.  Errors are printed if (1) the selected partition is
	empty, (2) the secondary boot program lacks a valid signature,
	or (3) an error occurs while reading the secondary boot sector.

	Installation:
	------------
	The "pfdisk" utility included with this program simplifies
	installation of BOOTAUTO into the primary boot sector.
	Instructions for using "pfdisk" are in the pfdisk.doc file.

	Limitations:
	-----------
	Names in the boot menu:

	BOOTMENU and BOOTAUTO contain a name table that is used to
	generate the boot menu.  This name table is recognized (using
	a signature) and updated by pfdisk but not by other fdisk
	programs. If another fdisk program is used to modify the
	partition table, the name table may be left with misleading
	entries.  Note that pfdisk only updates the name field for any
	entry when the entry is set as in: 	1 0x04 0 127 DOS
	Furthermore, the name supplied as the fourth arg. is truncated
	to eight characters.  (Space is tight in the boot sector.)

	The signature which flags the presence of a name table is
	written into any boot sector every time the fourth argument is
	given in a partition setting command (1,2,3,4).  This
	signature occupies locations 0x1A0 -- 0x1AD which does not
	clobber anything used by any of: UNIX or DOS boot programs,
	SpeedStor or WesternDigital Auto-configuring controllers.

	Booting inactive partitions:

	MS-DOS will boot from an inactive partition without needing
	any modifications.  Unfortunately, some systems refuse to boot
	from a partition which is not marked as active.

	ESIX (from Everex Systems) Sys.V Rel.3.2 will not (as shipped)
	boot unless its partition is marked active.  Other versions of
	Sys.V/386 are similar in this regard.  The easiest solution is
	to mark the UNIX partition as active, and use BOOTMENU to
	offer you a choice between DOS and UNIX.

	If you wish, it is also possible to patch UNIX so that it will
	boot without demanding that its partition be marked active.
	These patches (called "esix-boot") are available from the
	author.  Send EMAIL to gwr@linus.mitre.org if you want them.

SHAR_EOF
if test 3884 -ne "`wc -c < 'bootmenu.doc'`"
then
	echo shar: error transmitting "'bootmenu.doc'" '(should have been 3884 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'pfdisk.doc'" '(6548 characters)'
if test -f 'pfdisk.doc'
then
	echo shar: will not over-write existing file "'pfdisk.doc'"
else
cat << \SHAR_EOF > 'pfdisk.doc'



PFDISK(8)             MAINTENANCE COMMANDS              PFDISK(8)



NAME
     pfdisk - partition fixed disk

SYNOPSIS
     pfdisk device

DESCRIPTION
     pfdisk partitions the fixed disk identified as  device  into
     (at  most)  four  parts,  each of which may be independently
     loaded with an operating system.  The actual name of  device
     depends  on  the  operating system in use.  For ESIX (System
     V/386)  the  device  name  is  either   "/dev/rdsk/0s0"   or
     "/dev/rdsk/1s0".  For Minix, it is "/dev/hd0" or "/dev/hd5".
     For MS-DOS it is a single digit (zero or one).

     pfdisk reads the hard disk partition table from  block  zero
     of  device  into  memory  and  allows  the  user to examine,
     modify, or save the partition table.  A regular file may  be
     used instead of device for testing purposes, though the dev-
     ice geometry will be demanded and the "r" and  "w"  commands
     will only work with a file-name argument.

     The partition table on device is  not  modified  unless  the
     write (w) command is used (with no argument).

USAGE
  Commands
     All pfdisk commands consist of a single letter (which may be
     followed  by  any  number  of non-blank letters) followed by
     blank-separated  command  arguments.   Extra  arguments  are
     ignored.   Numeric arguments may be given in C syntax.  File
     name arguments are used exactly as given.

     The commands are:

     ?    Prints a command summary (help).

     #    This line is a comment (to be ignored).

     1 sys-id first last sys-name
          Set the partition table  entry  for  part  one,  using:
          sys-id  as its system ID code, first as the lowest num-
          bered cylinder it uses, last as  the  highest  numbered
          cylinder it uses, and sys-name as the (optional) system
          name.

     2|3|4 sys-id first last sys-name
          Similar to 1 but sets partition two,  three,  or  four,
          respectively.

     a number
          Mark partition number as active (so it will be used for



Release 1.2           Last change: Aug 1990                     1






PFDISK(8)             MAINTENANCE COMMANDS              PFDISK(8)



          booting).   If  number  is  zero,  no partition will be
          active.

     g cylinders heads sectors
          Inform pfdisk what the geometry of the device is.

     i    Print a summary of the known ID codes.

     l    List the partition table.  See Output Format below.

     q    Quit without saving.  If the memory copy of the  parti-
          tion  table  was modified, a warning will be issued and
          the command ignored.

     q!   Quit, even if the memory copy of  the  partition  table
          was not saved.

     r file-name
          Read boot sector from file-name  (if  given)  otherwise
          read from device.

     w file-name
          Write boot sector to file-name.  (if  given)  otherwise
          write to device.

     wq   Same as "write" followed by "quit".

  Output Format
     Here is a sample of the output from the l command:


          # Partition table on device: /dev/rdsk/0s0
          geometry 1222 15 34 (cyls heads sectors)
          # SysID First Last  Name...   # start, length (sectors)
          1  0x04     0  127  MS-LOSS   # 34, 65246
          2  0x00     0    0  (empty)   # 0, 0
          3  0x00     0    0  (empty)   # 0, 0
          4  0x63   128 1220  ESIX      # 65280, 557430
          # note:  last(4): phys=(1023,14,34) logical=(1220,14,34)
          active: 4

     This output format is carefully constructed so that  it  may
     be  saved  in  a  file  (by redirecting standard output) and
     later used as input (by redirecting standard input).   On  a
     UNIX system, one can save this output using the command:

          (echo l) | pfdisk device-name > save-file

     save-file is a complete record of the partition table.  On a
     UNIX  system,  one  could use save-file to re-initialize the
     partition table using the command:




Release 1.2           Last change: Aug 1990                     2






PFDISK(8)             MAINTENANCE COMMANDS              PFDISK(8)



          (cat save-file ; echo wq) | pfdisk device-name

     Consistency of each partition table entry is  checked  while
     the  table  is  listed.   Any inconsistencies discovered are
     reported in a commentary note as shown  above.   Each  entry
     has both a "physical" (cylinder,head,sector) and a "logical"
     (absolute sector number) first and last field.  These fields
     will  normally  agree  except when a disk has more than 1024
     cylinders.  (The physical last cylinder is  only  a  ten-bit
     field, but the logical field has 32 bits.)

  Partition Names
     The Name field in the partition table is  treated  specially
     if  the  bootmenu  program  is installed in the primary boot
     sector.  (See the file bootmenu.doc for  more  information.)
     pfdisk  can  recognize  the  name table used by bootmenu and
     will show the actual names present in that name  table.   If
     any  other boot program is used then the Name field reflects
     the result of a table-lookup of the system ID.

     If you provide a name when setting any partition entry,  the
     boot-sector is marked as using a name table, so that on sub-
     sequent uses of pfdisk you will see the partition names  you
     have  specified.   (I personally like to name the DOS parti-
     tion "MS-LOSS".)

  Boot program replacement
     You can replace the boot program in your boot  sector  using
     pfdisk  as  follows.   First, (as always) save a copy of the
     current boot sector (on a floppy) using the  "w  file"  com-
     mand.   Then,  use the "r file" command to read the new boot
     program.  If the boot program read in is less than 446 bytes
     long, the partition table will be unchanged.

     Unlike the DOS or UNIX fdisk programs, pfdisk  has  NO  boot
     program  compiled into its executable image.  If you wish to
     use pfdisk to partition a newly  formatted  hard  disk,  you
     must  have  a  boot program image available to read in using
     the "r file" command.  Two boot programs, "bootmenu.bin" and
     "bootauto.bin"  are  distributed  with  pfdisk and should be
     found with its source files.  See the file bootmenu.doc  for
     further information about these boot programs.

AUTHOR
     Gordon W. Ross










Release 1.2           Last change: Aug 1990                     3



SHAR_EOF
if test 6548 -ne "`wc -c < 'pfdisk.doc'`"
then
	echo shar: error transmitting "'pfdisk.doc'" '(should have been 6548 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'pfdisk.man'" '(5616 characters)'
if test -f 'pfdisk.man'
then
	echo shar: will not over-write existing file "'pfdisk.man'"
else
cat << \SHAR_EOF > 'pfdisk.man'
.TH PFDISK 8 "Aug 1990" "Release 1.2"
.SH NAME
pfdisk \- partition fixed disk
.SH SYNOPSIS
.B pfdisk
.I device
.SH DESCRIPTION
.LP
.B pfdisk
partitions the fixed disk identified as
.I device
into (at most) four parts, each of which may
be independently loaded with an operating system.
The actual name of
.I device
depends on the operating system in use.
For ESIX (System V/386) the device name is either
"/dev/rdsk/0s0" or "/dev/rdsk/1s0".
For Minix, it is "/dev/hd0" or "/dev/hd5".
For MS-DOS it is a single digit (zero or one).
.LP
.B pfdisk
reads the hard disk partition table from block zero of
.I device
into memory and allows the user to examine, modify, or save the
partition table.  A regular file may be used instead of
.I device
for testing purposes, though the device geometry will be demanded and
the "r" and "w" commands will only work with a file-name argument.
.LP
The partition table on
.I device
is not modified unless the write (w) command is used (with no argument).
.SH USAGE
.SS Commands
.LP
All
.B pfdisk
commands consist of a single letter
(which may be followed by any number of non-blank letters)
followed by blank-separated command arguments.
Extra arguments are ignored.
Numeric arguments may be given in C syntax.
File name arguments are used exactly as given.
.LP
The commands are:
.TP
.B ?
Prints a command summary (help).
.TP
.B #
This line is a comment (to be ignored).
.TP
.BI 1 " sys-id first last sys-name"
Set the partition table entry for part one, using:
.I sys-id
as its system ID code,
.I first
as the lowest numbered cylinder it uses,
.I last
as the highest numbered cylinder it uses, and
.I sys-name
as the (optional) system name.
.TP
.BI 2|3|4 " sys-id first last sys-name"
Similar to
.B 1
but sets partition two, three, or four, respectively.
.TP
.BI a " number"
Mark partition
.I number
as active (so it will be used for booting).  If
.I number
is zero, no partition will be active.
.TP
.BI g " cylinders heads sectors"
Inform
.B pfdisk
what the geometry of the device is.
.TP
.B i
Print a summary of the known ID codes.
.TP
.B l
List the partition table.
See
.B "Output Format"
below.
.TP
.B q
Quit without saving.  If the memory copy of the partition table was
modified, a warning will be issued and the command ignored.
.TP
.B q!
Quit, even if the memory copy of the partition table was not saved.
.TP
.BI r " file-name"
Read boot sector from
.I file-name
(if given) otherwise read from
.I device.
.TP
.BI w " file-name"
Write boot sector to
.I file-name.
(if given) otherwise write to
.I device.
.TP
.B wq
Same as "write" followed by "quit".
.SS "Output Format"
.LP
Here is a sample of the output from the
.B l
command:
.IP
.nf
# Partition table on device: /dev/rdsk/0s0
geometry 1222 15 34 (cyls heads sectors)
# SysID First Last  Name...   # start, length (sectors)
1  0x04     0  127  MS-LOSS   # 34, 65246
2  0x00     0    0  (empty)   # 0, 0
3  0x00     0    0  (empty)   # 0, 0
4  0x63   128 1220  ESIX      # 65280, 557430
# note:  last(4): phys=(1023,14,34) logical=(1220,14,34)
active: 4
.fi
.LP
This output format is carefully constructed so that it
may be saved in a file  (by redirecting standard output)
and later used as input (by redirecting standard input).
On a UNIX system, one can save this output using the command:
.IP
(echo l) | pfdisk device-name >
.I save-file
.LP The printable representation saved in
.I save-file
is a complete record of the partition table.
On a UNIX system, one could use
.I save-file
to re-initialize the partition table using the command:
.IP
(cat save-file ; echo wq) | pfdisk device-name
.LP
Consistency of each partition table entry is checked
while the table is listed.  Any inconsistencies discovered
are reported in a commentary note as shown above.
Each entry has both a "physical" (cylinder,head,sector)
and a "logical" (absolute sector number) first and last field.
These fields will normally agree except when a disk has
more than 1024 cylinders.  (The physical last cylinder is
only a ten-bit field, but the logical field has 32 bits.)
.SS "Partition Names"
.LP
The
.B Name
field in the partition table is treated specially if the
.B bootmenu
program is installed in the primary boot sector.
(See the file bootmenu.doc for more information.)
.B pfdisk
can recognize the name table used by
.B bootmenu
and will show the actual names present in that name table.
If any other boot program is used then the
.B Name
field reflects the result of a table-lookup of the system ID.
.LP
If you provide a name when setting any partition entry, the
boot-sector is marked as using a name table, so that on
subsequent uses of
.B pfdisk
you will see the partition names you have specified.
(I personally like to name the DOS partition "MS-LOSS".)
.SS "Boot program replacement"
.LP
You can replace the boot program in your boot sector using
.B pfdisk
as follows.  First, (as always) save a copy of the current boot
sector (on a floppy) using the "w file" command.  Then, use the
"r file" command to read the new boot program.
If the boot program read in is less than 446 bytes long, the
partition table will be unchanged.
.LP
Unlike the DOS or UNIX
.B fdisk
programs,
.B pfdisk
has
.I NO
boot program compiled into its executable image.
If you wish to use
.B pfdisk
to partition a newly formatted hard disk, you must have a boot program
image available to read in using the "r file" command.
Two boot programs, "bootmenu.bin" and "bootauto.bin" are distributed with
.B pfdisk
and should be found with its source files.  See the file bootmenu.doc
for further information about these boot programs.
.SH AUTHOR
Gordon W. Ross
SHAR_EOF
if test 5616 -ne "`wc -c < 'pfdisk.man'`"
then
	echo shar: error transmitting "'pfdisk.man'" '(should have been 5616 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Changes'" '(812 characters)'
if test -f 'Changes'
then
	echo shar: will not over-write existing file "'Changes'"
else
cat << \SHAR_EOF > 'Changes'
Changes leading to Version 1.2
Sept '90
	Added new, smaller version of boot program (BOOTMENU).
	Renamed boot-hdp to BOOTAUTO (more descriptive of its function?)
	Added prompt (people were confused wihout it)
	Made pfdisk show real name field with sysid==0.
	Made pfdisk set the signature whenever a (1,2,3,4) command
		specifies the optional name argument.
	Made pfdisk complain about invalid boot sector and mark it valid.

Changes leading to Version 1.1
Feb '90
	Added MSDOS compatibility to hex2bin.c
	Moved ESIX patches into a separate package.

	Renamed s_minix.c to s_unix.c (it's generic)
	Created an s_isc.c for Interactive Systems UNIX

	Fixed inconsistencies in esix-fix.sh and
	Removed byte-order dependencies from pfdisk.c

	Revised instructions in boot-hdp.doc

Version 1.0 released (initial beta)
SHAR_EOF
if test 812 -ne "`wc -c < 'Changes'`"
then
	echo shar: error transmitting "'Changes'" '(should have been 812 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(1245 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# This makefile supports all UNIX-like systems.
# Uncomment one of the SYS definitions below, or
# use a make command like:
#	make SYS=esix
# (For compiling on MS-DOS, see make_msc.bat)
#
# Uncomment for ESIX  Sys.V/386 Rel. 3.2
SYS=esix
# Uncomment for other Sys.V/386 systems (ISC,SCO,Intel...)
#SYS=i386
# Uncomment for Minix, other UNIX-like systems
#SYS=unix
# Uncomment for MSDOS with UNIX-style make (i.e. ndmake)
#SYS=msdos

OBJS= pfdisk.o syscodes.o s_$(SYS).o

FILES1=	README bootmenu.doc pfdisk.doc pfdisk.man Changes Makefile \
 pfdisk.c syscodes.c syscodes.h sysdep.h s_esix.c s_i386.c s_unix.c \
 bootmenu.hex bootauto.hex hex2bin.c
FILES2= SStor.txt s_msdos.c bootmenu.asm bootauto.asm \
 asm2bin.bat make_msc.bat

all: pfdisk bootmenu.bin bootauto.bin

pfdisk: $(OBJS)
	$(CC) $(CFLAGS) -o $@ $(OBJS)

pfdisk.o : syscodes.h sysdep.h
syscodes.o : syscodes.h
s_$(SYS).o : sysdep.h

bootmenu.bin: hex2bin
	hex2bin <bootmenu.hex >bootmenu.bin
bootauto.bin: hex2bin
	hex2bin <bootauto.hex >bootauto.bin

pfdisk.doc: pfdisk.man
	nroff -man pfdisk.man >pfdisk.doc

clean:
	rm -f *.o

Shar1.out: Head1.txt $(FILES1)
	(cat Head1.txt ; shar -v -c $(FILES1)) > $@
Shar2.out: Head2.txt $(FILES2)
	(cat Head2.txt ; shar -v -c $(FILES2)) > $@

SHAR_EOF
if test 1245 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 1245 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'pfdisk.c'" '(14756 characters)'
if test -f 'pfdisk.c'
then
	echo shar: will not over-write existing file "'pfdisk.c'"
else
cat << \SHAR_EOF > '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 <stdio.h>
#include <string.h>
#include <ctype.h>
#include "sysdep.h"
#include "syscodes.h"

typedef unsigned char uchar;
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 */
		/* logical sectors, begin (long, Intel format) */
  uchar	ls_b0, ls_b1, ls_b2, ls_b3;
		/* logical sectors, length (long, Intel format) */
  uchar	ls_l0, ls_l1, ls_l2, ls_l3;
};

#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 same as block 0) */
int	useNTable;		/* boot sector uses name table */
int	verbose=1;		/* enable verbose commentary */

	/* device parameters (force someone to set them!) */
int	cyls, heads, sectors;

char	*devname;		/* device name */
char	cmdline[MAX_LINE];
char	filename[80];	/* used by r/w commands */

/* 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>             : summarize commands\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,
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);
  putchar('\n');
}

/* forward declarations */
void	checkValidity();
char *	setPartition();
char *	makeActive();
char *	setGeometry();
ulong	chs2long();

main(argc,argv)
int	argc;
char	*argv[];
{
  char	*cmdp;		/* points to command word */
  char	*argp;		/* points to command args */
  char	*prompt;

  /* 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 */
  if(getGeometry(devname,&cyls,&heads,&sectors)) {
    cyls = DEFAULT_CYLS;
    heads = DEFAULT_HEADS;
    sectors = DEFAULT_SECTORS;
    fprintf(stderr,"# %s %s\n# %s\n",
	    "Can't determine geometry of device:", devname,
	    "Please set it using:  g cyls heads sectors");
  }

  /* get block zero */
  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 != 0) 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 '?':
      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':	/* activate partition */
      argp = makeActive(argp);
      if (argp) {
	fprintf(stderr,BadArg,argp);
	fprintf(stderr,h_a);
	break;
      }
      bufmod = 1;
      break;

    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':	/* List known ID numbers */
      printIDs();
      break;

    case 'l':	/* List the partition table */
      listPTable();
      break;

    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':	/* read from device or file */
      if (sscanf(argp,"%80s",filename) == 1) {
	/* Arg specified, read from filename */
	getFile(filename, buffer, SECSIZE);
	bufmod = 1;
      } else {
	/* No arg, use device. */
	getBBlk(devname, buffer);
	bufmod = 0;
      }
      checkValidity();
      break;

    case 'w':	/* Write to file or device */
      if (sscanf(argp,"%80s",filename) == 1) {
	/* Arg specified, write to filename */
	putFile(filename, buffer, SECSIZE);
      } else {  /* No arg, use device. */
	putBBlk(devname, buffer);
	bufmod = 0;
      }
      if (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;
    fprintf(stderr,
	"Warning:  The boot sector has an invalid magic number.\n\
	The magic number has been fixed, but the other contents\n\
	are probably garbage.  Initialize using the command:\n\
		r boot-program-file	(i.e. bootmenu.bin)\n\
	then 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,id;
  int	first,last;	/* user supplied cylinders */
  int	c,h,s;		/* working cyl,head,sect, */
  int	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 < 0)   	return("first < 0");
  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 name given, even if blank */
    newname = argp + 1;	/* skip one space */
    /* 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->ls_b0 = lslen & 0xff; lslen >>= 8;
  pp->ls_b1 = lslen & 0xff; lslen >>= 8;
  pp->ls_b2 = lslen & 0xff; lslen >>= 8;
  pp->ls_b3 = 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->ls_l0 = lslen & 0xff; lslen >>= 8;
  pp->ls_l1 = lslen & 0xff; lslen >>= 8;
  pp->ls_l2 = lslen & 0xff; lslen >>= 8;
  pp->ls_l3 = 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 */
  int	pbc,pbh,pbs;	/* physical beginning  c,h,s */
  int	pec,peh,pes;	/* physical ending     c,h,s */
  int	lbc,lbh,lbs;	/* logical beginning   c,h,s */
  int	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("# SysID First Last  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->ls_b3) << 8 ) | pp->ls_b2) << 8 ) |
	       pp->ls_b1) << 8 ) | pp->ls_b0;
    long2chs(lsbeg, &lbc, &lbh, &lbs);
    /* compute logical ending (c,h,s) */
    lslen = (( (( ((pp->ls_l3) << 8 ) | pp->ls_l2) << 8 ) |
	      pp->ls_l1) << 8 ) | pp->ls_l0;
    /* 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(pp->sysid);

    /* show physical begin, logical end (works for cyl>1023) */
    printf("%d  0x%02x  ", i+1, pp->sysid);
    printf("%4d %4d  ", pbc, lec);
    printf("%-8.8s  ", name);
    printf("# %ld, %ld\n", 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\n", numActive,
	 (numActive) ? "" : "(none)");
} /* listPTable() */

ulong chs2long(c,h,s)
int 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 */
int	*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 */
}
SHAR_EOF
if test 14756 -ne "`wc -c < 'pfdisk.c'`"
then
	echo shar: error transmitting "'pfdisk.c'" '(should have been 14756 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'syscodes.c'" '(1053 characters)'
if test -f 'syscodes.c'
then
	echo shar: will not over-write existing file "'syscodes.c'"
else
cat << \SHAR_EOF > 'syscodes.c'
/* This file holds all knowledge of partition ID codes */

#include <stdio.h>
#define extern
#include "syscodes.h"
#undef  extern

struct intString { int i; char * s; };

/* Note that my boot program menu can only use the
 * first 8 characters of these names.
 */
struct intString sysCodes[] = {
{ 0x01, "DOS 2   :12-bit FAT" },
{ 0x02, "XENIX   :root" },
{ 0x03, "XENIX   :usr?" },
{ 0x04, "DOS 3   :16-bit FAT" },
{ 0x05, "DOS ext :DOS 3.3 extended volume" },
{ 0x06, "DOS 4   :DOS 4.0 large volume" },
{ 0x07, "type 7? :Reserved?" },
{ 0x08, "IBM AIX" },

{ 0x52, "CPM ?  " },
{ 0x63, "UNIX    :System V/386" },
{ 0xDB,	"C.DOS   :Concurrent DOS" },

/* Make sure this is last! */
{    0, "(empty)" }
};

int printIDs()
{
	struct intString *is;

	is = sysCodes;
	printf("ID    Name\n");
	while (is->i) {
	  printf("0x%02x  %s\n", is->i, is->s);
	  is++;
	}
	putchar('\n');
}

char * nameID(n)
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");
}
SHAR_EOF
if test 1053 -ne "`wc -c < 'syscodes.c'`"
then
	echo shar: error transmitting "'syscodes.c'" '(should have been 1053 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'syscodes.h'" '(47 characters)'
if test -f 'syscodes.h'
then
	echo shar: will not over-write existing file "'syscodes.h'"
else
cat << \SHAR_EOF > 'syscodes.h'
extern char * nameID();
extern int printIDs();
SHAR_EOF
if test 47 -ne "`wc -c < 'syscodes.h'`"
then
	echo shar: error transmitting "'syscodes.h'" '(should have been 47 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'sysdep.h'" '(684 characters)'
if test -f 'sysdep.h'
then
	echo shar: will not over-write existing file "'sysdep.h'"
else
cat << \SHAR_EOF > 'sysdep.h'
/* communicate declarations from the files: s_*.c */

#define SECSIZE 0x200

extern int usage();		/* print a usage message */
	/* (char *progname) */

extern int getGeometry(); /* determine disk parameters (0==success) */
	/* (char *dev, int *cyls, int *heads, int *sectors) */

extern int getFile();	/* open, read, close, return(num-read) */
	/* (char *name, char *buf, int len) */

extern int putFile();	/* open, write, close, return(num-writen) */
	/* (char *name, char *buf, int len) */

extern int getBBlk();	/* open, read, close, return(num-read) */
	/* (char *dev, char *buf) */

extern int putBBlk();	/* open, write, close, return(num-writen) */
	/* (char *dev, char *buf) */
SHAR_EOF
if test 684 -ne "`wc -c < 'sysdep.h'`"
then
	echo shar: error transmitting "'sysdep.h'" '(should have been 684 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'s_esix.c'" '(3111 characters)'
if test -f 's_esix.c'
then
	echo shar: will not over-write existing file "'s_esix.c'"
else
cat << \SHAR_EOF > 's_esix.c'
/* This file contains system-specific functions for ESIX.
 * The program pfdisk.c calls these routines.
 * Note that ESIX can't use the generic Sys.V/386 version of
 * this file because it uses ioctl calls to access the
 * primary boot sector.  Other systems provide a device which
 * maps onto the whole disk (starting with the boot sector).
 */
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/vtoc.h>

#define extern
#include "sysdep.h"
#undef extern

int usage(prog)	/* print a usage message */
char	*prog;	/* program name */
{
  fprintf(stderr,"Usage: %s dev\n\t%s\n", prog,
	  "where 'dev' is the device name, i.e. /dev/rdsk/0s0");
}

int getGeometry(dev, c, h, s)
char	*dev;		/* device name */
int	*c,*h,*s;	/* cyls, heads, sectors */
{
  int devfd, retval;
  struct disk_parms dp;
  
  devfd = open(dev, O_RDONLY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for reading\n", dev);
    return(devfd);
  }
  retval = ioctl(devfd, V_GETPARMS, &dp);
  close(devfd);
  if (retval < 0) {
    fprintf(stderr,"%s: can't get disk parameters\n", dev);
    return(retval);
  }
  if (dp.dp_type != DPT_WINI) {
    fprintf(stderr,"%s: not a Winchester Disk\n", dev);
    return(-1);
  }
  *c = dp.dp_cyls;
  *h = dp.dp_heads;
  *s = dp.dp_sectors;
  return(0);
}

int getFile(name, buf, len)	/* read file into buffer */
char	*name, *buf;
int	len;
{	/* (open, read, close) */
  int devfd, retval;
  
  devfd = open(name, O_RDONLY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for reading\n", name);
    return(devfd);
  }
  retval = read(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: read failed\n", name);
  close(devfd);
  return(retval);
}

int putFile(name, buf, len)	/* write buffer to file */
char	*name, *buf;
int	len;
{	/* (open, write, close) */
  int devfd, retval;
  
  devfd = open(name, O_WRONLY|O_CREAT, 0666);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for writing\n", name);
    return(devfd);
  }
  retval = write(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: write failed\n", name);
  close(devfd);
  return(retval);
}

int getBBlk(name, buf)	/* read Boot Block into buffer */
char	*name, *buf;
{	/* (open, read, close) */
  int devfd, retval;
  struct absio abs;
  
  devfd = open(name, O_RDONLY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for reading\n", name);
    return(devfd);
  }
  abs.abs_sec = 0;	/* the primary boot sector */
  abs.abs_buf = buf;
  retval = ioctl(devfd, V_RDABS, &abs);
  if (retval < 0)
    fprintf(stderr,"%s: read failed\n", name);
  close(devfd);
  return(retval);
}

int putBBlk(name, buf)	/* write buffer to Boot Block */
char	*name, *buf;
{	/* (open, write, close) */
  int devfd, retval;
  struct absio abs;
  
  devfd = open(name, O_WRONLY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for writing\n", name);
    return(devfd);
  }
  abs.abs_sec = 0;	/* the primary boot sector */
  abs.abs_buf = buf;
  retval = ioctl(devfd, V_WRABS, &abs);
  if (retval < 0)
    fprintf(stderr,"%s: write failed\n", name);
  close(devfd);
  return(retval);
}
SHAR_EOF
if test 3111 -ne "`wc -c < 's_esix.c'`"
then
	echo shar: error transmitting "'s_esix.c'" '(should have been 3111 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'s_i386.c'" '(2673 characters)'
if test -f 's_i386.c'
then
	echo shar: will not over-write existing file "'s_i386.c'"
else
cat << \SHAR_EOF > 's_i386.c'
/* This file contains system-specific functions suitable for
 * most AT&T System V/386 variants (ISC,SCO,Intel...).
 * The program pfdisk.c calls these routines.
 */
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/vtoc.h>

#define extern
#include "sysdep.h"
#undef extern

int usage(prog)	/* print a usage message */
char	*prog;	/* program name */
{
  fprintf(stderr,"Usage: %s dev\n\
	where 'dev' is the device name, i.e. /dev/rdsk/0p0\n\
	(The device must start on absolute sector zero.)\n",prog);
}

int getGeometry(dev, c, h, s)
char	*dev;		/* device name */
int	*c,*h,*s;	/* cyls, heads, sectors */
{
  int devfd, retval;
  struct disk_parms dp;
  
  devfd = open(dev, O_RDONLY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for reading\n", dev);
    return(devfd);
  }
  retval = ioctl(devfd, V_GETPARMS, &dp);
  close(devfd);
  if (retval < 0) {
    fprintf(stderr,"%s: can't get disk parameters\n", dev);
    return(retval);
  }
  if (dp.dp_type != DPT_WINI) {
    fprintf(stderr,"%s: not a Winchester Disk\n", dev);
    return(-1);
  }
  *c = dp.dp_cyls;
  *h = dp.dp_heads;
  *s = dp.dp_sectors;
  return(0);
}

int getFile(name, buf, len)	/* read file into buffer */
char	*name, *buf;
int	len;
{	/* (open, read, close) */
  int devfd, retval;
  
  devfd = open(name, O_RDONLY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for reading\n", name);
    return(devfd);
  }
  retval = read(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: read failed\n", name);
  close(devfd);
  return(retval);
}

int putFile(name, buf, len)	/* write buffer to file */
char	*name, *buf;
int	len;
{	/* (open, write, close) */
  int devfd, retval;
  
  devfd = open(name, O_WRONLY|O_CREAT, 0666);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for writing\n", name);
    return(devfd);
  }
  retval = write(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: write failed\n", name);
  close(devfd);
  return(retval);
}

int getBBlk(devname, buffer)	/* read block into buffer */
char	*devname, *buffer;	/* (open, read, close) */
{
  int devfd, retval;
  
  devfd = open(devname,O_RDONLY);
  if (devfd < 0) {
    printf("%s: can't open for read\n", devname);
    return(devfd);
  }
  retval = read(devfd, buffer, SECSIZE);
  close(devfd);
  return(retval);
}

int putBBlk(devname, buffer)	/* write buffer to device */
char	*devname, *buffer;	/* (open, write, close) */
{
  int devfd, retval;
  
  devfd = open(devname,O_WRONLY);
  if (devfd < 0) {
    printf("%s: can't open for write\n",devname);
    return(devfd);
  }
  retval = write(devfd, buffer, SECSIZE);
  sync();
  close(devfd);
  return(retval);
}
SHAR_EOF
if test 2673 -ne "`wc -c < 's_i386.c'`"
then
	echo shar: error transmitting "'s_i386.c'" '(should have been 2673 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'s_unix.c'" '(2122 characters)'
if test -f 's_unix.c'
then
	echo shar: will not over-write existing file "'s_unix.c'"
else
cat << \SHAR_EOF > 's_unix.c'
/* This file contains system-specific functions for generic UNIX.
 * The program pfdisk.c calls these routines.
 */
#include <stdio.h>
#include <fcntl.h>

#define extern
#include "sysdep.h"
#undef extern

int usage(prog)	/* print a usage message */
char	*prog;	/* program name */
{
  fprintf(stderr,"Usage: %s dev\n\
	where 'dev' is the device name, i.e. /dev/hd0\n\
	(The device must start on absolute sector zero.)\n",prog);
}

int getGeometry(dev, c, h, s)
char	*dev;		/* device name */
int	*c,*h,*s;	/* cyls, heads, sectors */
{
  /* Sorry, don't know how to do this in a portable way. */
  return(-1);
}

int getFile(name, buf, len)	/* read file into buffer */
char	*name, *buf;
int	len;
{	/* (open, read, close) */
  int devfd, retval;
  
  devfd = open(name, O_RDONLY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for reading\n", name);
    return(devfd);
  }
  retval = read(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: read failed\n", name);
  close(devfd);
  return(retval);
}

int putFile(name, buf, len)	/* write buffer to file */
char	*name, *buf;
int	len;
{	/* (open, write, close) */
  int devfd, retval;
  
  devfd = open(name, O_WRONLY|O_CREAT, 0666);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for writing\n", name);
    return(devfd);
  }
  retval = write(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: write failed\n", name);
  close(devfd);
  return(retval);
}

int getBBlk(devname, buffer)	/* read block into buffer */
char	*devname, *buffer;	/* (open, read, close) */
{
  int devfd, retval;
  
  devfd = open(devname,O_RDONLY);
  if (devfd < 0) {
    printf("%s: can't open for read\n", devname);
    return(devfd);
  }
  retval = read(devfd, buffer, SECSIZE);
  close(devfd);
  return(retval);
}

int putBBlk(devname, buffer)	/* write buffer to device */
char	*devname, *buffer;	/* (open, write, close) */
{
  int devfd, retval;
  
  devfd = open(devname,O_WRONLY);
  if (devfd < 0) {
    printf("%s: can't open for write\n",devname);
    return(devfd);
  }
  retval = write(devfd, buffer, SECSIZE);
  sync();
  close(devfd);
  return(retval);
}
SHAR_EOF
if test 2122 -ne "`wc -c < 's_unix.c'`"
then
	echo shar: error transmitting "'s_unix.c'" '(should have been 2122 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'bootmenu.hex'" '(1177 characters)'
if test -f 'bootmenu.hex'
then
	echo shar: will not over-write existing file "'bootmenu.hex'"
else
cat << \SHAR_EOF > 'bootmenu.hex'
 33 C0 BE 00 7C FA 8E D0 8B E6 FB 8E D8 8E C0 BE
 00 7C BF 00 06 B9 00 01 FC F3 A5 EA 20 06 00 00
 E8 9E 00 BE 80 07 B0 31 56 50 E8 8C 00 B0 20 E8
 87 00 B9 08 00 E8 97 00 E8 86 00 58 5E 83 C6 08
 FE C0 3C 34 76 E2 E8 78 00 BE 00 07 E8 7D 00 B4
 00 CD 16 50 E8 62 00 E8 67 00 58 2C 31 3C 04 73
 E5 BE BE 07 B1 10 F6 E1 03 F0 8A 44 04 3C 00 75
 06 BE 17 07 EB 3A 90 B0 80 88 04 B9 05 00 51 8B
 14 8B 4C 02 BB 00 7C B8 01 02 CD 13 73 0D 33 C0
 CD 13 59 E2 E9 BE 1E 07 EB 16 90 59 B8 55 AA 3B
 06 FE 7D 74 06 BE 2A 07 EB 06 90 EA 00 7C 00 00
 E8 19 00 E8 0B 00 E9 67 FF B4 0E BB 07 00 CD 10
 C3 B0 0D E8 F3 FF B0 0A E8 EE FF C3 B9 50 00 AC
 3C 00 74 07 51 E8 E1 FF 59 E2 F4 C3 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 42 6F 6F 74 20 70 61 72 74 69 74 69 6F 6E 3F 20
 28 31 2D 34 29 20 00 45 6D 70 74 79 21 00 52 65
 61 64 20 65 72 72 6F 72 21 00 49 6E 76 61 6C 69
 64 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

SHAR_EOF
if test 1177 -ne "`wc -c < 'bootmenu.hex'`"
then
	echo shar: error transmitting "'bootmenu.hex'" '(should have been 1177 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'bootauto.hex'" '(1177 characters)'
if test -f 'bootauto.hex'
then
	echo shar: will not over-write existing file "'bootauto.hex'"
else
cat << \SHAR_EOF > 'bootauto.hex'
 33 C0 BE 00 7C FA 8E D0 8B E6 FB 8E D8 8E C0 BE
 00 7C BF 00 06 B9 00 01 FC F3 A5 EA 20 06 00 00
 8B EC 83 EC 04 BE 35 07 E8 EE 00 B0 00 E8 F9 00
 8A 14 80 FA 80 74 09 FE C0 3C 04 72 F0 EB 28 90
 89 46 FE B4 00 CD 1A 83 C2 5A 89 56 FC B4 01 CD
 16 75 14 B4 00 CD 1A 2B 56 FC 78 F1 B0 2C E8 A5
 00 8B 46 FE EB 46 90 B4 01 CD 16 74 06 B4 00 CD
 16 EB F4 E8 98 00 BE 80 07 B0 31 56 50 E8 86 00
 B0 20 E8 81 00 B9 08 00 E8 91 00 E8 80 00 58 5E
 83 C6 08 FE C0 3C 34 76 E2 E8 72 00 BE 46 07 E8
 77 00 B4 00 CD 16 2C 31 3C 04 73 ED E8 7A 00 04
 31 E8 52 00 E8 57 00 8A 44 04 3C 00 75 06 BE 5D
 07 EB 3A 90 B0 80 88 04 B9 05 00 51 8B 14 8B 4C
 02 BB 00 7C B8 01 02 CD 13 73 0D 33 C0 CD 13 59
 E2 E9 BE 64 07 EB 16 90 59 B8 55 AA 3B 06 FE 7D
 74 06 BE 70 07 EB 06 90 EA 00 7C 00 00 E8 19 00
 E8 0B 00 E9 61 FF B4 0E BB 07 00 CD 10 C3 B0 0D
 E8 F3 FF B0 0A E8 EE FF C3 B9 50 00 AC 3C 00 74
 07 51 E8 E1 FF 59 E2 F4 C3 50 BE BE 07 B1 10 F6
 E1 03 F0 58 C3 42 6F 6F 74 20 64 65 76 69 63 65
 3A 20 68 64 30 00 42 6F 6F 74 20 70 61 72 74 69
 74 69 6F 6E 3F 20 28 31 2D 34 29 20 00 45 6D 70
 74 79 21 00 52 65 61 64 20 65 72 72 6F 72 21 00
 49 6E 76 61 6C 69 64 21 00 00 00 00 00 00 00 00

SHAR_EOF
if test 1177 -ne "`wc -c < 'bootauto.hex'`"
then
	echo shar: error transmitting "'bootauto.hex'" '(should have been 1177 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hex2bin.c'" '(200 characters)'
if test -f 'hex2bin.c'
then
	echo shar: will not over-write existing file "'hex2bin.c'"
else
cat << \SHAR_EOF > 'hex2bin.c'
/*
 * hex2bin - a simple hex to binary converter
 */
#include <stdio.h>
main()
{
  int c;

#ifdef MSDOS
  setmode(stdout,O_BINARY);
#endif

  while (scanf("%x", &c) == 1)
    putchar(c);
  exit(0);
}
SHAR_EOF
if test 200 -ne "`wc -c < 'hex2bin.c'`"
then
	echo shar: error transmitting "'hex2bin.c'" '(should have been 200 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
Gordon W. Ross	(M/S E095)	| internet: gwr@linus.mitre.org
The MITRE Corporation		| uucp: (backbone-host)!linus!gwr
Burlington Road			| Day-phone: 617-271-3205
Bedford, MA 01730 (U.S.A.)	|

gwr@linus.mitre.org (Gordon W. Ross) (09/08/90)

Here is part 2 of the BOOTMENU and PFDISK 2.1 distribution.

More detailed descriptions are found in the README file at the
beginning of the first shell archive.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	SStor.txt
#	s_msdos.c
#	bootmenu.asm
#	bootauto.asm
#	asm2bin.bat
#	make_msc.bat
# This archive created: Fri Sep  7 18:37:59 1990
# By:	Gordon W. Ross (The MITRE Corporation, Bedford, MA.)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'SStor.txt'" '(1027 characters)'
if test -f 'SStor.txt'
then
	echo shar: will not over-write existing file "'SStor.txt'"
else
cat << \SHAR_EOF > 'SStor.txt'

Note: SpeedStor (sstor) modifies MANY locations in the boot sector!

The SpeedStor manual says it does not modify locations 0xEA -- 0x17D
BUT THEY LIE!  If you use the "Parameter Override" feature, sstor
(evidently) puts the new disk parameters in locations 0xEA -- 0xF9.

If you install BOOTAUTO and then run sstor, using the parameter
override feature, you will have clobbered the BOOTAUTO program in a
way such that it hangs or repeats its menu when you make a selection!
(Yes, I learned this the hard way...)

To get around this problem, I wrote a slimmed-down version of the boot
program, called BOOTMENU, which is designed to carefully avoid the
locations clobbered by SpeedStor.  Though this version has the
advantage of SpeedStor compatibility, it does not have the ability to
do automatic, unattended reboots the way BOOTAUTO can.  Oh well.

For future reference, also note that sstor will modify locations
0x17E -- 0x1BD if you create SpeedStor partitions.  To their credit,
this is indeed mentioned in the manual.

SHAR_EOF
if test 1027 -ne "`wc -c < 'SStor.txt'`"
then
	echo shar: error transmitting "'SStor.txt'" '(should have been 1027 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'s_msdos.c'" '(3787 characters)'
if test -f 's_msdos.c'
then
	echo shar: will not over-write existing file "'s_msdos.c'"
else
cat << \SHAR_EOF > 's_msdos.c'
/* This file contains system-specific functions for MS-DOS.
 * The program pfdisk.c calls these routines.
 */
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dos.h>

#define extern
#include "sysdep.h"
#undef extern

int usage(prog)	/* print a usage message */
char	*prog;	/* program name */
{
  fprintf(stderr,"Usage: %s <disk>\n", prog);
  fprintf(stderr,"\twhere <disk> is a digit [0-9]\n");
}

int getGeometry(name, c, h, s)
char	*name;		/* device name */
int	*c,*h,*s;	/* cyls, heads, sectors */
{
  int dev;	/* hard disk number */
  union 	REGS	regs;
  struct	SREGS	sregs;
  
  if (name[0] < '0' ||
      name[0] > '9' ||
      name[1] != 0  )
    {
      fprintf(stderr,"%s: device name must be a digit\n", name);
      return(-1);
    }
  dev = (name[0] - '0');
  
  regs.h.ah = 8;		/* get param.	*/
  regs.h.dl = dev | 0x80;
  
  int86x(0x13,&regs,&regs,&sregs);
  
  /* Are that many drives responding? */
  if (regs.h.dl <= dev ) {
    fprintf(stderr,"%s: drive not found\n", name);
    return(-1);
  }
  if (regs.x.cflag) {
    fprintf(stderr,"%s: can't get disk parameters\n", name);
    return(-1);
  }
  *c = ((((int) regs.h.cl << 2) & 0x300) | regs.h.ch) + 1;
  *h = regs.h.dh + 1;
  *s = regs.h.cl & 0x3F;
  return(0);
}

int getFile(name, buf, len)	/* read file into buffer */
char	*name, *buf;
int	len;
{	/* (open, read, close) */
  int devfd, retval;
  
  devfd = open(name, O_RDONLY|O_BINARY, 0);
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for reading\n", name);
    return(devfd);
  }
  retval = read(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: read failed\n", name);
  close(devfd);
  return(retval);
}

int putFile(name, buf, len)	/* write buffer to file */
char	*name, *buf;
int	len;
{	/* (open, write, close) */
  int devfd, retval;
  
  devfd = open(name,
	       O_WRONLY|O_CREAT|O_BINARY,
	       S_IREAD|S_IWRITE ); /* stupid DOS... */
  if (devfd < 0) {
    fprintf(stderr,"%s: can't open for writing\n", name);
    return(devfd);
  }
  retval = write(devfd, buf, len);
  if (retval < 0)
    fprintf(stderr,"%s: write failed\n", name);
  close(devfd);
  return(retval);
}

int getBBlk(name, buf)	/* read boot block into buffer */
char	*name, *buf;
{	/* BIOS absolute disk read */
  int dev;
  union 	REGS	regs;
  struct	SREGS	sregs;
  
  if (name[0] < '0' ||
      name[0] > '9' ||
      name[1] != 0  )
    {
      fprintf(stderr,"%s: device name must be a digit\n",name);
      return(-1);
    }
  dev = (name[0] - '0');
  
  segread(&sregs);	/* get ds */
  sregs.es = sregs.ds;	/* buffer address */
  regs.x.bx = (int) buf;
  
  regs.h.ah = 2;		/* read		*/
  regs.h.al = 1;		/* sector count	*/
  regs.h.ch = 0;		/* track	*/
  regs.h.cl = 1;		/* start sector	*/
  regs.h.dh = 0;		/* head		*/
  regs.h.dl = dev|0x80;	/* drive	*/
  
  int86x(0x13,&regs,&regs,&sregs);
  if (regs.x.cflag) {
    fprintf(stderr,"%s: read failed\n", name);
    return(-1);
  }
  return(SECSIZE);
}

int putBBlk(name, buf)	/* write buffer to boot block */
char	*name, *buf;
{	/* BIOS absolute disk write */
  int dev;
  union 	REGS	regs;
  struct	SREGS	sregs;
  
  if (name[0] < '0' ||
      name[0] > '9' ||
      name[1] != 0  )
    {
      fprintf(stderr,"%s: device name must be a digit\n", name);
      return(-1);
    }
  dev = (name[0] - '0');
  
  segread(&sregs);	/* get ds */
  sregs.es = sregs.ds;	/* buffer address */
  regs.x.bx = (int) buf;
  
  regs.h.ah = 3;		/* write	*/
  regs.h.al = 1;		/* sector count	*/
  regs.h.ch = 0;		/* track	*/
  regs.h.cl = 1;		/* start sector	*/
  regs.h.dh = 0;		/* head		*/
  regs.h.dl = dev|0x80;	/* drive	*/
  
  int86x(0x13,&regs,&regs,&sregs);
  if (regs.x.cflag) {
    fprintf(stderr,"%s: write failed\n",name);
    return(-1);
  }
  return(SECSIZE);
}
SHAR_EOF
if test 3787 -ne "`wc -c < 's_msdos.c'`"
then
	echo shar: error transmitting "'s_msdos.c'" '(should have been 3787 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'bootmenu.asm'" '(5005 characters)'
if test -f 'bootmenu.asm'
then
	echo shar: will not over-write existing file "'bootmenu.asm'"
else
cat << \SHAR_EOF > 'bootmenu.asm'
	PAGE 60,132
;	bootmenu: BOOT Hard Disk Partition
;	by Gordon W. Ross, Aug 1990
;
;	See the file bootmenu.doc for user instructions.
;
;	This version of bootmenu is compatible with SpeedStor.
;	See the file sstor-bug.txt for the gory details.
;
;	The following is an outline of the program:
;
;	Relocate self from 0x7c00 to 0x0600
;	Display partition menu
;	Prompt for and read user selection
;
;	Boot from the selected partition:
;	(was selected by user, or was active)
;	Read first sector of selected partition into 0x7c00
;	Verify good second-stage boot sector (magic word)
;	Set-up correct register values and jump to it.
;

CODEORG	equ 0600h	; offset of this code in code seg
; All values computed from offsets in codeseg need to be
; adjusted by adding CODEORG to each.  The obvious method,
; using "org CODEORG" causes MASM/LINK to fill in the space.

codeseg	segment
	assume cs:codeseg, ds:codeseg

; Initial program entry point
; (Assembler is told this is at offset zero.)

main:
	; Set up the stack
	xor	ax,ax
	mov	si,7C00h	; just before load location
	cli
	mov	ss,ax
	mov	sp,si
	sti

; Relocate this code from 0:7C00h to 0:CODEORG
	mov	ds,ax
	mov	es,ax
	mov	si,7C00h	; where this program is initially loaded
	mov	di,CODEORG
	mov	cx,0100h
	cld
	rep	movsw

; Jump to relocated code (0:CODEORG)
	jmp	far ptr begin1
begin	equ	$	; The above jump lands here.

; Print partition menu from name table
menu:
	call	putnl		; print newline
	mov	si, offset pnames ; no org fix-up here!
	mov	al, '1'
prname:
	push	si
	push	ax

	call	putc
	mov	al,' '
	call	putc
	mov	cx,8		; maximum name length
	call	putn
	call	putnl

	pop	ax
	pop	si
	add	si,8
	inc	al
	cmp	al,'4'
	jbe	prname

; Prompt for and read user selection
select:
	call	putnl	; print prompt
	mov	si, offset prompt + CODEORG
	call	puts

	mov	ah,0	; Read a keystroke and print it
	int	16h
	push	ax
	call	putc
	call	putnl
	pop	ax

	sub	al,'1'	; range check and convert to index
	cmp	al,04
	jnb	select

boot:
; Boot from the selected partition.
; On entry to this section:  AL = index of ptable element

	; get address of ptable element (si = & ptable[AL])
	mov	si, offset ptable ; no org fix-up here
	mov	cl,16	; size of array element
	mul	cl		; ax = al * cl
	add	si,ax

; Check for valid system ID (non-zero)

	mov	al,[si+4]
	cmp	al,0
	jnz	id_ok
	mov	si, offset msgempty + CODEORG
	jmp	error
id_ok:

; Read first sector of selected partition into 0x7c00
; Also, mark this entry active (in RAM only) in case the
; secondary boot program looks at it (which it may).

	mov	al,80h	; active flag
	mov	[si], al
	mov	cx,5	; retry count
retry:	push	cx
	mov	dx,[si]	; drive, head
	mov	cx,[si+2]	; cyl, sector
	mov	bx,7C00h	; destination (es=0)
	mov	ax,0201h	; BIOS read one sector
	int	13h
	jnc	rd_ok
	xor	ax,ax	; reset disk
	int	13h
	pop	cx
	loop	retry
	mov	si, offset msgread + CODEORG
	jmp	error
rd_ok:	pop	cx

; Check for valid magic number in secondary boot sector
	mov	ax, 0AA55h
	assume	ds:seg0		; Actually, codeseg == seg0
	cmp	ax, magic2
	assume	ds:codeseg
	jz	magic_ok
	mov	si, offset msginvalid + CODEORG
	jmp	error
magic_ok:

; Make sure ds:si points to the booted partition, and
; Jump to the secondary boot program.
	jmp	far ptr begin2

; Jump here with si=error-message
error:
	call	puts
	call	putnl
	jmp	menu

;*************************************************************
; Subroutines
;*************************************************************
CR	EQU	13
LF	EQU	10
TAB	EQU	 9

putc	proc	near		; print char in AL
	mov	ah, 0Eh		; uses: ax, bx
	mov	bx, 07
	int	10h
	ret
putc	endp

putnl	proc	near		; print a newline
	mov	al, CR		; uses: ax, bx
	call	putc
	mov	al, LF
	call	putc
	ret
putnl	endp

puts	proc	near		; print string at address SI
	mov	cx,80		; Stop at null or CX chars
putn:	lodsb			; uses: ax, bx, cx, si
	cmp	al,0
	jz	puts_e
	push	cx
	call	putc
	pop	cx
	loop	putn
puts_e:	ret
puts	endp

;**********************************************************
; A little space here makes this program live happily with
; SpeedStor, which wants to write type-override stuff here.
;**********************************************************

	org	100h
;**********************************************************
; Strings
;**********************************************************

prompt		db	"Boot partition? (1-4) ",0
msgempty	db	"Empty!",0
msgread		db	"Read error!",0
msginvalid	db	"Invalid!",0

codeseg	ends

; Declares some offsets in segment zero
seg0	segment	at 0

	org	CODEORG + (offset begin - offset main)
begin1	equ	$

; Here is the name table used for the partition menu.
; The accompanying fdisk program updates this table.
	org	CODEORG + 180h
pnames	db	32 dup(?)

; The locations after 1AE are (reportedly) used by some
; Western Digital controllers in "auto-configure" mode.
; Don't put anything critical between here and ptable.

; Here is the partition table
	org	CODEORG + 1BEh
ptable	db	(4 * 16) dup(?)

; Here is where the secondary boot sector is loaded.
	org	7C00h
begin2	equ	$
	org	7DFEh
magic2	dw	?
seg0	ends

	end	main
SHAR_EOF
if test 5005 -ne "`wc -c < 'bootmenu.asm'`"
then
	echo shar: error transmitting "'bootmenu.asm'" '(should have been 5005 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'bootauto.asm'" '(6427 characters)'
if test -f 'bootauto.asm'
then
	echo shar: will not over-write existing file "'bootauto.asm'"
else
cat << \SHAR_EOF > 'bootauto.asm'
	PAGE 60,132
;	bootauto:  Auto-boot version of BOOTMENU program
;	by Gordon W. Ross, Aug 1990
;
;	See the file bootmenu.doc for user instructions.
;
;	The following is an outline of the program:
;
;	Relocate self from 0x7C00 to 0x0600
;	Display message "Booting from HD0,"
;	Search partition table for an active entry
;	If an active partition is found,
;		Delay while watching for key press (5 sec.)
;		If (key pressed) GOTO menu:
;		Else GOTO boot:
;		EndIf
;	Else (no active partition)
; menu:		Display partition menu
;		Prompt for and read user selection
;	EndIf
; boot:	Boot from the selected partition:
;	(was selected by user, or was active)
;	Read first sector of selected partition into 0x7c00
;	Verify good second-stage boot sector (magic word)
;	Set-up correct register values and jump to it.
;	If (Errors during boot) { complain; GOTO menu: }
;

DELAY	equ	5*18	; in ticks (1/18 sec.)
CODEORG	equ 0600h	; offset of this code in code seg
; All values computed from offsets in codeseg need to be
; adjusted by adding CODEORG to each.  The obvious method,
; using "org CODEORG" causes MASM/LINK to fill in the space.

codeseg	segment
	assume cs:codeseg, ds:codeseg

; Initial program entry point
; (Assembler is told this is at offset zero.)

main:
	; Set up the stack
	xor	ax,ax
	mov	si,7C00h	; just before load location
	cli
	mov	ss,ax
	mov	sp,si
	sti

; Relocate this code from 0:7C00h to 0:CODEORG
	mov	ds,ax
	mov	es,ax
	mov	si,7C00h	; where this program is initially loaded
	mov	di,CODEORG
	mov	cx,0100h
	cld
	rep	movsw

; Jump to relocated code (0:CODEORG)
	jmp	far ptr begin1
begin	equ	$
	mov	bp,sp	; frame pointer = 0x7C00
	sub	sp,4
; 2 words of local storage:
;	[bp-2] = ptable index [0-3]
;	[bp-4] = temporary value

; Display message "Boot device: HD0"
	mov	si, offset bootdev + CODEORG
	call	puts

; Search partition table for an active entry
	mov	al,0
search:
	call	addr_pt	; si = & ptable[AL]
	mov	DL,[si]
	cmp	DL,80h
	jz	found
	inc	al
	cmp	al,04
	jb	search
; Active partition not found
	jmp	menu

found:	; Found a partition marked active.
	mov	[bp-2],ax	; Save the ptable array index

; Delay while watching for key press (2 sec.)
; Get start time, compute end time.
	mov	ah,00
	int	1Ah		; BIOS get time of day
	add	dx, DELAY	; compute end time
	mov	[bp-4],dx	; save expiration time

; Check for key press
waitkey:
	mov	ah,1
	int	16h		; BIOS Keyboard
	jnz	menu	; key pressed

; Check for expiration of delay
	mov	ah,00
	int	1Ah		; BIOS get time of day
	sub	dx,[bp-4]
	js	waitkey	; delay not expired

; Delay has expired, so boot the active partition
	mov	al,','
	call	putc
	mov	ax,[bp-2]	; ptable index
	; the index and newline are printed later
	jmp	boot

; Display partition menu
menu:
	mov	ah,1		; flush input
	int	16h
	jz	fl_done
	mov	ah,0
	int	16h
	jmp	menu
fl_done:

; Print partition menu from name table

	call	putnl		; print newline
	mov	si, offset pnames ; no org fix-up here
	mov	al, '1'
prname:
	push	si
	push	ax

	call	putc
	mov	al,' '
	call	putc
	mov	cx,8		; maximum name length
	call	putn
	call	putnl

	pop	ax
	pop	si
	add	si,8
	inc	al
	cmp	al,'4'
	jbe	prname

; Prompt for and read user selection
select:
	call	putnl
	mov	si, offset prompt + CODEORG
	call	puts
	; Read a key and convert it to a number
	mov	ah,0
	int	16h
	sub	al,'1'
	cmp	al,04
	jnb	select
	; The key and a newline are printed below

boot:
; Boot from the selected partition.
; On entry to this section:  AL = index of ptable element

	; get address of ptable element
	call	addr_pt	; si = & ptable[AL]

	; print the parition index and a newline
	add	al,'1'
	call	putc
	call	putnl

; Check for valid system ID (non-zero)

	mov	al,[si+4]
	cmp	al,0
	jnz	id_ok
	mov	si, offset msgempty + CODEORG
	jmp	error
id_ok:

; Read first sector of selected partition into 0x7c00
; Also, mark this entry active (in RAM only) in case the
; secondary boot program looks at it (which it may).

	mov	al,80h	; active flag
	mov	[si], al
	mov	cx,5	; retry count
retry:	push	cx
	mov	dx,[si]	; drive, head
	mov	cx,[si+2]	; cyl, sector
	mov	bx,7C00h	; destination (es=0)
	mov	ax,0201h	; BIOS read one sector
	int	13h
	jnc	rd_ok
	xor	ax,ax	; reset disk
	int	13h
	pop	cx
	loop	retry
	mov	si, offset msgread + CODEORG
	jmp	error
rd_ok:	pop	cx

; Check for valid magic number in secondary boot sector
	mov	ax, 0AA55h
	assume	ds:seg0		; Actually, codeseg == seg0
	cmp	ax, magic2
	assume	ds:codeseg
	jz	magic_ok
	mov	si, offset msginvalid + CODEORG
	jmp	error
magic_ok:

; Make sure ds:si points to the booted partition, and
; Jump to the secondary boot program.
	jmp	far ptr begin2

; Jump here with si=error-message
error:
	call	puts
	call	putnl
	jmp	menu

;*************************************************************
; Subroutines
;*************************************************************
CR	EQU	13
LF	EQU	10
TAB	EQU	 9

putc	proc	near		; print char in AL
	mov	ah, 0Eh		; uses: ax, bx
	mov	bx, 07
	int	10h
	ret
putc	endp

putnl	proc	near		; print a newline
	mov	al, CR		; uses: ax, bx
	call	putc
	mov	al, LF
	call	putc
	ret
putnl	endp

puts	proc	near		; print string at address SI
	mov	cx,80		; Stop at null or CX chars
putn:	lodsb			; uses: ax, bx, cx, si
	cmp	al,0
	jz	puts_e
	push	cx
	call	putc
	pop	cx
	loop	putn
puts_e:	ret
puts	endp

addr_pt	proc	near		; set SI = address of ptable[al]
	push	ax		; uses: cx (but preserves ax)
	mov	si, offset ptable ; no org fix-up here
	mov	cl,16	; size of array element
	mul	cl		; ax = al * cl
	add	si,ax
	pop	ax
	ret
addr_pt	endp

;**********************************************************
; Strings
;**********************************************************

bootdev		db	"Boot device: hd0",0
prompt		db	"Boot partition? (1-4) ",0
msgempty	db	"Empty!",0
msgread		db	"Read error!",0
msginvalid	db	"Invalid!",0
	org	180h	; this pads the length (it seems)
codeseg	ends

; Declares some offsets in segment zero
seg0	segment	at 0

	org	CODEORG + (offset begin - offset main)
begin1	equ	$

; Here is the name table used for the partition menu.
; The accompanying fdisk program updates this table.
	org	CODEORG + 180h
pnames	db	32 dup(?)

; The locations after 1AE are (reportedly) used by some
; Western Digital controllers in "auto-configure" mode.
; Don't put anything critical between here and ptable.

; Here is the partition table
	org	CODEORG + 1BEh
ptable	db	(4 * 16) dup(?)

; Here is where the secondary boot sector is loaded.
	org	7C00h
begin2	equ	$

	org	7DFEh
magic2	dw	?

seg0	ends

	end	main
SHAR_EOF
if test 6427 -ne "`wc -c < 'bootauto.asm'`"
then
	echo shar: error transmitting "'bootauto.asm'" '(should have been 6427 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'asm2bin.bat'" '(262 characters)'
if test -f 'asm2bin.bat'
then
	echo shar: will not over-write existing file "'asm2bin.bat'"
else
cat << \SHAR_EOF > 'asm2bin.bat'
@echo off
REM This batch file builds file.bin from file.asm
if not arg%1==arg%1 goto arg
echo supply base name of file.asm, i.e. file
goto exit
:arg
echo on
masm %1,,;
link boot-hdp,;
@echo Ignore the 'no stack...' warning
del %1.obj
exe2bin %1
del %1.exe
:exit
SHAR_EOF
if test 262 -ne "`wc -c < 'asm2bin.bat'`"
then
	echo shar: error transmitting "'asm2bin.bat'" '(should have been 262 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'make_msc.bat'" '(104 characters)'
if test -f 'make_msc.bat'
then
	echo shar: will not over-write existing file "'make_msc.bat'"
else
cat << \SHAR_EOF > 'make_msc.bat'
REM this batch file uses Microsoft C to build pfdisk.exe
cl -o pfdisk.exe pfdisk.c syscodes.c s_msdos.c
SHAR_EOF
if test 104 -ne "`wc -c < 'make_msc.bat'`"
then
	echo shar: error transmitting "'make_msc.bat'" '(should have been 104 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
Gordon W. Ross	(M/S E095)	| internet: gwr@linus.mitre.org
The MITRE Corporation		| uucp: (backbone-host)!linus!gwr
Burlington Road			| Day-phone: 617-271-3205
Bedford, MA 01730 (U.S.A.)	|