[comp.unix.microport] All you wanted to know about V/AT disk layouts

plocher@sally.Sun.COM (John Plocher) (03/19/90)

Here is some code I wrote several years ago that allows one to access
and decode the info stored in the Master Boot Block, the Partition Boot
Block, the Partition End Record, the Bad Block remap table, et al...

It even includes a partially written program that would use the stuff
provided.

I haven't used V/AT for over a year now so don't expect me to care too
much about what you do with this :-)

No Copyrights, restrictions, or legal viruses here, just use it and
learn from it...

   -John Plocher


#! /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:
#	mbb.h
#	pbb.h
#	romtable.h
#	per.h
#	btt.h
#	cmos.h
#	fdisk.h
#	disk.c
#	diskio.c
#	fdisk.c
#	getput.c
#	wn.man
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'mbb.h'
then
	echo shar: "will not over-write existing file 'mbb.h'"
else
cat << \SHAR_EOF > 'mbb.h'
/*
**      mbb.h
**              Master Boot Block for DOS type hard disk
**      The pre-boot code, partition table and signature are found here.
**      Pre version 2.3 V/AT 286 also stored disk geometry here.
**      2.3 and above moved this info to the Partition Boot Block.
**
**      $Header: mbb.h,v 1.1 88/04/07 23:11:40 root Alpha $
*/

#ifndef MBB_H
#define MBB_H

/*
**      Master Boot Block as it appears on physical block 0 of a hard disk.
**      Size of this structure must be exactly 512 bytes.  At offset 0x1a6
**      the drive geometry may be stored (in a checksummed atructure).  The
**      partition table starts at offset 0x01BE.  There are four entries and
**      each entry is 16 bytes.  The block signature is in last two bytes.
*/

/*
**    The MBB Drive Geometry table
**
**          +--------+-------+
** 0x1A6    | Cylinders      |
**          +--------+-------+
** 0x1A8    | Heads          |
**          +--------+-------+
** 0x1AA    | Precomp        |
**          +--------+-------+
** 0x1AC    | Landing Zone   |
**          +--------+-------+
** 0x1AE    |    CHECKSUM    |
**          +--------+-------+
*/

typedef struct {
        short numcyls,
              numheads,
              precompcyl,
              landingzone,
              checksum;
} dparm_t;

/*
**          +--------+-------+
** 0x1B0    |                |
** 0x1B2    |                |
** 0x1B4    |                |
** 0x1B6    | filler[ 14 ]   |
** 0x1B8    |                |
** 0x1BA    |                |
** 0x1BC    |                |
**          +--------+-------+
*/

/*
**        DOS assumes a 10 bit cylinder number in its ROM bios tables.
**      this is mapped as follows:
**              lower 8 bits are stored in the CYL field
**              upper 2 bits are stored as 2 high order bits in the SEC field
**        All partitions are allocated in cylinder multiples and begin on
**      sector 1 head 0.  EXCEPTION:  The partition that is located at the
**      beginning of the disk *must* start at sector 2 to leave room for the
**      disk's Master Boot Record.
**        The relative sector field is the count of the number of sectors
**      which preceede this partition on the disk.  The starting sector of
**      this partition is found by using the value CYLINDER as found in the
**      partition table, and the known geometry of the drive:
**              relsec = CYL * (HeadsOnDrive * SecsPerHead) 
**      The field is stored with the least significant word first.
**
**        e.g., For a 4 head drive with 17 sectors per track, assume that
**              the second partition starts on cyl 1 (sector 1 and head 1
**              are implied for all but the first partition)
**                      relsec = 1 * ( 4 * 17 )  (cyl 1, 4 heads, 17 sec/track)
**                      relsec = 68
**              For the first partition, relsec = 1 ('cuz of master boot block)
**
**        The number of sectors allocated in this partition is kept in the
**      next field.  It too is stored with the least significant word first.

**                       The partition table:
**      Offset  Description             +--------+--------+--------+--------+
** P1   0x1BE   beginning of partition  |boot ind|  head  | sector |cylinder|
**      0x1C2   end of partition        |syst ind|  head  | sector |cylinder|
**      0x1C6   reletive sector         |    low word     |    high word    |
**      0x1CA   number of sectors       |    low word     |    high word    |
**                                      +--------+--------+--------+--------+
** P2   0x1CE   beginning of partition  |boot ind|  head  | sector |cylinder|
**      0x1D2   end of partition        |syst ind|  head  | sector |cylinder|
**      0x1D6   reletive sector         |    low word     |    high word    |
**      0x1DA   number of sectors       |    low word     |    high word    |
**                                      +--------+--------+--------+--------+
** P3   0x1DE   beginning of partition  |boot ind|  head  | sector |cylinder|
**      0x1E2   end of partition        |syst ind|  head  | sector |cylinder|
**      0x1E6   reletive sector         |    low word     |    high word    |
**      0x1EA   number of sectors       |    low word     |    high word    |
**                                      +--------+--------+--------+--------+
** P4   0x1EE   beginning of partition  |boot ind|  head  | sector |cylinder|
**      0x1F2   end of partition        |syst ind|  head  | sector |cylinder|
**      0x1F6   reletive sector         |    low word     |    high word    |
**      0x1FA   number of sectors       |    low word     |    high word    |
**                                      +--------+--------+--------+--------+
*/

#define NPART   4               /* # of partitions in partition table */

typedef struct  {
    unsigned char   pt_bootind;         /* boot indicator 0x00 | 0x80 */
    unsigned char   pt_bhead;           /* head, sector, & cyl of     */
    unsigned char   pt_bsector;         /*  the boot sector for this  */
    unsigned char   pt_bcyl;            /*  partition (load at 0:7C00)*/
    unsigned char   pt_sys;             /* partition (system) type    */
    unsigned char   pt_ehead;           /* head, sector and cyl of    */
    unsigned char   pt_esector;         /*  the end of this           */
    unsigned char   pt_ecyl;            /*  partition                 */
    unsigned long   pt_start;           /* starting sector            */
    unsigned long   pt_size;            /* size in sectors            */
} partition_t;

/*
**        The Master Boot Block Signature is the last 2 bytes of the boot record
**      which have the values 0x55 and 0xAA.
**
**                                      +--------+--------+
**      0x1FE   Master Boot Signature   |  0x55  |  0xAA  |
**                                      +--------+--------+
*/

#define PT_INFO         (0x1a6) /* WN.H */              /* start of driveinfo*/

typedef struct  {
    char          bootcode[ PT_INFO ];  /* boot code  at start of MBB */
    dparm_t       geometry;             /* cyls, heads, ... */
    char          filler[ 14 ];
    partition_t   partitiontable[ NPART ];
    unsigned int  signature;
} mbb_t;

#define PT_SIG          0xaa55                          /* magic constant    */
#define PT_BOOT         0x80                            /* active  partition */
#define PT_NULL         0x00                            /* passive partition */
#define PT_UNUSED       0x00                            /* unused system type*/

#define PART(mbb,i)    ((mbb)->partition[ (i) ])
#define CYL_BOOT(ptp)  ((ptp)->pt_bcyl | (((ptp)->pt_bsector & 0x00C0)<<2))
#define HEAD_BOOT(ptp) ((ptp)->pt_bhead)
#define SEC_BOOT(ptp)  ((ptp)->pt_bsector & 0x003F)
#define CYL_END(ptp)   ((ptp)->pt_ecyl | (((ptp)->pt_esector & 0x00C0)<<2))
#define HEAD_END(ptp)  ((ptp)->pt_ehead)
#define SEC_END(ptp)   ((ptp)->pt_esector & 0x003F)

#endif /* MBB_H */

SHAR_EOF
fi
if test -f 'pbb.h'
then
	echo shar: "will not over-write existing file 'pbb.h'"
else
cat << \SHAR_EOF > 'pbb.h'
/*
**      pbb.h
**              Partition Boot Block
**      This block holds both the unix boot code and the disk geometry
**      for SV/AT 286 version 2.3 and beyond.
**
**      $Header: pbb.h,v 1.2 87/09/16 02:12:51 root Exp $
**
**      The layout of the PBB is:
**
**              +--------------------+
**        0x000 |   Unix Boot Code   |
**              |        ...         |
**              |           ...      |
**              |              ...   |
**        .. -1 | 0x90               |
** BOOTDRTBLOFF | ROM-type diskinfo  |  16 bytes long  ( see romtable.h )
**        0x1FD | 0x00               |
**        0x1FE | 0xAA55             |
**              +--------------------+
*/

#ifndef PBB_H
#define PBB_H

#include "romtable.h"

typedef char pbb_t[512];

/* the BOOT record DRiveTaBLeOFFset into the partition boot block */
#define BOOTDRTBLOFF    0x1ee

#define ROMTABLE( pbbp )        ((romtable *)((pbbp)+BOOTDRTBLOFF))

#define VALID_PBB( pbbp ) (*((int *) (pbbp)+0x1FE) == 0xAA55 && \
                           *((pbbp)+0x1FD) == 0              || \
                           *((pbbp)+(BOOTDRTBLOFF-1)) == 0x90)

#define VALIDATE_PBB( pbbp ) {                                      \
    *((int *) &pbbp[0x1FE]) = 0xAA55;   /* ... and magic PBB sig */ \
    pbbp[0x1FD] = 0;                    /* .. more sig info */      \
    pbbp[BOOTDRTBLOFF-1] = 0x90;        /* ... */                   \
}


#endif /* PBB_H */
SHAR_EOF
fi
if test -f 'romtable.h'
then
	echo shar: "will not over-write existing file 'romtable.h'"
else
cat << \SHAR_EOF > 'romtable.h'
/*
**	romtable.h
**		What a drive type table entry looks like in ROM
**		(The disk geometry table)
**
**	$Header: romtable.h,v 1.1 88/04/07 23:12:17 root Alpha $
**
**	The ROM type diskinfo is:
**
**        0                2        3        4       5                  7
**    +--------+-------+--------+--------+--------+--------+--------+--------+
**    | Number of cyls | heads  |   0    |   0    |    precomp cyl  |   0    |
**    +--------+-------+--------+--------+--------+--------+--------+--------+
**    | hdflag |       |        |        |   Landing Zone  | sec/trk|        |
**    +--------+-------+--------+--------+--------+--------+--------+--------+
**        8       9        10       11       12                14
*/

#ifndef ROMTABLE_H
#define ROMTABLE_H

#define MORETHAN8HEADS	0x08
#define LESSTHAN8HEADS	0x00

#ifdef COMPILER_PACKS_STRUCTURES	/* V/AT does NOT */
typedef struct {
    short	  r_cyls;	/* number of cyls               */
    unsigned char r_heads;	/*           heads              */
    char          r_dummy1[2];	/* unknown/unused               */
    short         r_precomp;	/* cyl # to start precomp on    */
    char          r_dummy2;     /* unknown/unused               */
    char          r_hdflag;     /* iff more than 8 heads        */
    char          r_dummy3[3];	/* unknown/unused               */
    short         r_lz;         /* cyl where head lands         */
    unsigned char r_spt;        /* Sectors per track (17,26,34) */
    char          r_dummy4;     /* unknown/unused            */
} romtable;

/* given a pointer to a rom table entry (rtp) we need the value */

#define R_CYLS( rtp )		((rtp)->r_cyls)
#define R_HEADS( rtp )		((rtp)->r_heads)
#define R_PRECOMP( rtp )	((rtp)->r_precomp)
#define R_HDFLAG( rtp )		((rtp)->r_hdflag)
#define R_LZ( rtp )		((rtp)->r_lz)
#define R_SPT( rtp )		((rtp)->r_spt)

#else	/* V/AT needs to use an uglier method... */

typedef char romtable[16];

/* rtp is a pointer to a romtable (which is an array of chars) */

#define R_CYLS( rtp )		(*(short         *)(&(rtp)[0]))
#define R_HEADS( rtp )		(*(unsigned char *)(&(rtp)[2]))
#define R_PRECOMP( rtp )	(*(short         *)(&(rtp)[5]))
#define R_HDFLAG( rtp )		(*(unsigned char *)(&(rtp)[8]))
#define R_LZ( rtp )		(*(short         *)(&(rtp)[12]))
#define R_SPT( rtp )		(*(unsigned char *)(&(rtp)[14]))

#endif

#endif /* ROMTABLE_H */
SHAR_EOF
fi
if test -f 'per.h'
then
	echo shar: "will not over-write existing file 'per.h'"
else
cat << \SHAR_EOF > 'per.h'
/*
**      Partition End Record
**  The *real* drive table and the slice table are found here.
**  The drive info found in the mbb, pbb, and cmos are only used by
**  other OSs, format(1), fdisk(1), and divvy(1).  The kernel uses
**  the info stored here.
**
**  The Boot Sequence is as follows:
**      ROM Code at 0xFF:0000   gains control at power on, performs POST,
**                              reads in the boot code from the Master Boot
**                              Block, and then executes it.
**      The MBB code is read from Hard disk Unit 0, Cyl 0, Head 0, sector 1
**                              (The first physical sector on the disk)
**                              This code scans the partition table and
**                              loads the Partition Boot Block code from the
**                              active partition.  This code is the Unix
**                              pre-boot code - it's job is to load the kernel
**                              into memory and start it running...
**      The Partition End Record holds info that the kernel and the hard disk
**                              driver need in managing the drives:
**      The Disk geometry stored here is that which is used by the hard disk
**                              driver itself - the copies in the MBB and the
**                              PBB are only used by the boot code to load and
**                              initialize the kernel (and its drivers)
**          The slice table tells unix where and how big your filesystems are.
**          The minor device table on the FIRST hard disk holds the info for
**                              BOTH the hard disks.  The minor device table on
**                              the second hard disk is NOT USED.
**                              (I don't really know what this table is for)
**      The Bad Track Table is read in at boot time by the hard disk driver and
**                              is used to map out bad tracks on the drive.
**
**  $Header: per.h,v 1.2 87/09/16 02:12:58 root Exp $
*/

#ifndef PER_H
#define PER_H

#define SLICES 16
#define MINORS 21   /* entries in minor device table */
#define NUNITS 2    /* # of disk drives */

/* 
** The last sector in the active partition on each drive contains
** the following structure:
*/

typedef struct {
    struct i1010drtab drtab;            /* drive geometry           */
    struct i1010slice slice[SLICES];    /* slice table              */
    unsigned int      miner[MINORS];    /* minor devices            */
    unsigned char     dummy[ 512 - (    /* padding to block boundry */
									 sizeof(struct i1010drtab) +
									(sizeof(struct i1010slice) * SLICES) +
									(sizeof(unsigned int)      * MINORS)
								   ) ];
} per_t;

#define DRTOFFSET   0     /* drive table offset from start of PER */
#define SLTOFFSET   DRTOFFSET + sizeof(struct i1010drtab)

/*
 * The minor device number is used as index into the i1010minor array.
 * This array is defined in hd.conf.c. The defines below are to help
 * understand the encoding, but it is still confusing.
 */

#ifdef MP386
#define USRDEV 3
#define TMPDEV -1
#define ROOTDEV 1
#define SWAPDEV 2
#else
#define USRDEV 2
#define TMPDEV 3
#define ROOTDEV 0
#define SWAPDEV 1
#endif

/* THESE DEFS HAVE BEEN KLUDGED TO ALLOW THE DRIVE TABLE TO GROW > 16
   The BOARD field has been shortened by two bits; DRTAB extended two */

#define BOARD(dev)      ((i1010minor[minor(dev)] >> 14 ) & 0x03)
#define UNIT(dev)       ((i1010minor[minor(dev)] >> 10 ) & 0x0f)
#define DRTAB(dev)      ((i1010minor[minor(dev)] >>  4 ) & 0x3f)
#define SLICE(dev)      ((i1010minor[minor(dev)]       ) & 0x0f)

#define i1010MINOR(board,unit,drtab,slice) \
        ((board<<14)|(unit<<10)|(drtab<<4)|slice)

/*
 * Slice structure.  One per drtab[] entry.
 */

struct  i1010slice {
        daddr_t p_fsec;                 /* first sector */
        daddr_t p_nsec;                 /* number sectors */
};

/*
 * this is the drive table for the WD1010 devices
 */

struct  i1010drtab {    /* note that since the V/AT cc does not        */
						/* pack structures, this is not going to       */
						/* match the DOS ROM anyways...  SO why bother */
						/* putting in these stupid nulls?      -John P */
        unsigned short  dr_ncyl;        /* # cylinders            */
        unsigned char   dr_nfhead;      /* # of fixed heads       */
        unsigned short  dr_null0;       /* dos compatable null    */
        unsigned short  dr_precomp;     /* cylinder for precomp   */
        unsigned char   dr_null1;       /*      dos null          */
        unsigned char   dr_control;     /* dos disk control byte  */
        unsigned char   dr_null2;       /*      dos null          */
        unsigned char   dr_null3;       /*      dos null          */
        unsigned char   dr_null4;       /*      dos null          */
        unsigned short  dr_lzone;       /* landing zone for close */
        unsigned char   dr_nsec;        /* # sectors per track    */
        unsigned char   dr_null5;       /*      dos null          */

    /* Extensions from the DOS ROM type follow */

        unsigned short  dr_secsiz;      /* sector size */
        unsigned char   dr_nalt;        /* # of alternate cylinders */
        unsigned short  dr_spc;         /* actual sectors/cylinder */

        struct i1010slice *dr_slice;    /* slice table pointer */
};
#endif /* PER_H */

SHAR_EOF
fi
if test -f 'btt.h'
then
	echo shar: "will not over-write existing file 'btt.h'"
else
cat << \SHAR_EOF > 'btt.h'
/*
**		Bad Track Table
**	This block contains the mapping between bad tracks and their
**	replacements (or alternates).  This table occupies the second
**	to last sector in the active partition.
**	$Header: btt.h,v 1.2 87/09/16 02:11:51 root Exp $
*/

#ifndef BTT_H
#define BTT_H

typedef struct {
        unsigned short  bad_cylinder;
        unsigned char   bad_track;
        unsigned short  new_cylinder;
        unsigned char   new_track;
} badtrack;

#define BADTRACKMAPS_PER_SECTOR	85	/* 85 * sizeof(bad_track_map) == 510 */

typedef badtrack btt_t[BADTRACKMAPS_PER_SECTOR + 1]; /* > 512 */

#endif /* BTT_H */

SHAR_EOF
fi
if test -f 'cmos.h'
then
	echo shar: "will not over-write existing file 'cmos.h'"
else
cat << \SHAR_EOF > 'cmos.h'
/* uportid = "@(#)cmos.h	Microport Rev Id  1.3.7 8/11/86"
 * $Header: cmos.h,v 1.2 87/09/16 02:12:08 root Exp $
 * 
 * The layout of cmos for the IBM AT. See pps 1-45 to 1-55 of
 * the IBM Technical Reference Manual.
 */

#ifndef CMOS_H
#define CMOS_H

#define	CMOSSIZE	0x40			/* # of bytes in cmos	*/
#define	CMOSDEV		"/dev/cmos"		/* where cmos lives	*/

typedef struct cmos {				/* the layout of cmos	*/
						/* realtime clock info	*/
		unsigned char sec;		/* 0: seconds		*/
		unsigned char secalarm;		/* 1: second alarm	*/
		unsigned char min;		/* 2: minutes		*/
		unsigned char minalarm;		/* 3: minute alarm	*/
		unsigned char hours;		/* 4: hours		*/
		unsigned char houralarm;	/* 5: hour alarm	*/
		unsigned char weekday;		/* 6: day of week	*/
		unsigned char monthday;		/* 7: day of month	*/
		unsigned char month;		/* 8: month		*/
		unsigned char year;		/* 9: year		*/

						/* status registers	*/
		unsigned char statusa;		/* A: status reg.A	*/
		unsigned char statusb;		/* B: status reg.B	*/
		unsigned char statusc;		/* C: status reg.C	*/
		unsigned char statusd;		/* D: status reg.D	*/
		unsigned char diagsts;		/* E: diagnostic status byte*/
		unsigned char shutdown;		/* F: shutdown status byte */

						/* device characteristics */
		unsigned char diskette;		/* 10: floppy drives:A&B*/
		unsigned char res1;		/* 11: unused		*/
		unsigned char disk;		/* 12: fixed disk: C & D*/
		unsigned char res2;		/* 13: unused		*/
		unsigned char equip;		/* 14: equipment byte	*/
		unsigned char lowbase;		/* 15: low base mem byte*/
		unsigned char hibase;		/* 16: hi base mem byte	*/
		unsigned char lowexp1;		/* 17: low exp. mem byte*/
		unsigned char hiexp1;		/* 18: hi exp. mem byte */
		unsigned char diskC;		/* 19: disk type ext.: C*/
		unsigned char diskD;		/* 1A: disk type ext.: D*/
		unsigned char res3[18];		/* 1B: unused		*/
		unsigned int chksum;		/* 2E-2F: cmos checksum	*/
		unsigned char lowexp2;		/* 30: low exp. mem byte*/
		unsigned char hiexp2;		/* 31: hi exp. mem byte */
		unsigned char century;		/* 32: date century byte*/
		unsigned char infoflags;	/* 33: information flags*/
		unsigned char res4[11];		/* 34-3F: unused	*/
} cmos_t;

/* The actual declaration of a variable does NOT belong in this file! */
#endif /* CMOS_H */

SHAR_EOF
fi
if test -f 'fdisk.h'
then
	echo shar: "will not over-write existing file 'fdisk.h'"
else
cat << \SHAR_EOF > 'fdisk.h'
/*
 * fdisk.h
 * $Header: fdisk.h,v 1.1 88/04/07 23:10:59 root Alpha $
 */

#define FAIL	0	/* result codes for the getxxxx() routines */
#define OK	1
#define NEW	2

/*
**	Defaults and driver limitations
*/

#define	MAX_NCYLS	1024		/* max # cylinders on a drive	*/
#define	DEF_SECHD	17		/* default sectors per track	*/
#define	DEF_BLKSIZE	512		/* sector size in bytes		*/

/* in names.c ... */
#define LAST_TYPE	(0xff)		/* Marker for end of lookup table */

#define	FDISK		"fdisk"		/* how is this program invoked	*/
#define	DDISK		"ddisk"		/*  for display only */

/*
**		SCREEN POSITIONS FOR DISPLAY STUFF
**	The defaults assume that your terminal cursor addressing is
**	from X position of 1 to 80 and from Y position of 1 to 24.
*/

#define	X_POS		1	/* start in first column		*/
#define	Y_BANNER	1	/* put BANNER on this line		*/
#define	Y_PART		3	/* put PARTITION DUMP on this line	*/
#define	Y_PARM		11	/* put PARAMETER DUMP on this line	*/
#define	Y_QUIT		23	/* put QUIT MESSAGE on this line	*/
#define	Y_PROMPT	24	/* put PROMPTS on this line		*/

/*
**	Forward declarations and externals
*/
extern char    *getstr(), *makelower(), *makeupper();
extern char    *strrchr();

/*
**	These are defined in screen.c and are terminal dependent.
*/
extern	char	clear[];	/* clear and home cursor	*/
extern	char	rvon[];		/* reverse video on		*/
extern	char	rvoff[];	/* reverse video off		*/
extern	char	hlon[];		/* highlight on			*/
extern	char	hloff[];	/* highlight off		*/
extern	char	ulon[];		/* underline on			*/
extern	char	uloff[];	/* underline off		*/
extern	char	blon[];		/* blink on			*/
extern	char	bloff[];	/* blink off			*/
extern	char	alloff[];	/* all attributes off		*/

/*
**	Partition names - see names.c
*/

struct	part_type_struct {
	unsigned char	type;
	char		*name;
};

extern char *nameofpart();
extern struct part_type_struct part_type[];

extern int	drv_fd;
extern char	*progname, *drivename;

SHAR_EOF
fi
if test -f 'disk.c'
then
	echo shar: "will not over-write existing file 'disk.c'"
else
cat << \SHAR_EOF > 'disk.c'
/* TODO
 *		Do not allow any changes to unit 0 if HD rooted.
 *		if tried, give message stating that unit 0 is READONLY if HD rooted.
 */

/*
**	Disk Configuration utility for Microport Unix V/AT
**
**	THIS PROGRAM IS NOT COMPLETE
**
**	It WILL NOT work (or compile) AS-IS.
**
**	Replaces fdisk, divvy, and showbad
**	Adds "addbad" and "printconfiguration" utilities
**
**	Author: John Plocher		April 1988
**
**	Last modified by $Author: plocher$ on $Date: 88/04/12 04:29:04 $
**
**	Locked by $Locker: plocher$
**	          $Revision: 1.0 $
**
**  Source is found in $Source$
**
**
**	Modification Log
**  ----------------
**  $Log$
*/

#ifndef lint
    static char rcsid[] =
    "$Header$";
#endif

#include <stdio.h>

#include "localdisk.h"

#include "mbb.h"
#include "pbb.h"
#include "per.h"
#include "btt.h"

#define NEEDED	0x00		/* Status states for various buffers */
#define INCORE	0x01
#define INVALID	0x02
#define BADGEO	0x04
#define DIRTY	0x08

		/* NEEDED - needs to be read in */
		/* INCORE - we have a copy - See INVALID bit for "goodness" */
		/* INCORE + BADGEO means that the geometry info in this thing */
		/*              is out of date and needs to be updated to match */
		/*              the PER geometry */
		/* INCORE + INVALID - bad copy on disk - need to regenerate */
		/* INCORE + DIRTY - need to update disk copy */

#define CYL(x)		x	/* For clarification of code */
#define HEAD(x)		x
#define SECTOR(x)	x


int HDRooted;		/* "true" if booted off of hard disk */

mbb_t mbb;		/* structure to contain the Master boot Block */
pbb_t pbb;		/* Partition Boot Block */
per_t per;		/* Partition End Record */
btt_t btt;		/* Bad Track Table */

int GEOstatus = NEEDED;
						/* NEEDED = not found yet */
						/* DIRTY  = PBB and PER is out of date */
						/* BADGEO = out of bounds for HD Driver */
int MBBstatus = NEEDED;
						/* INVALID= No MBB found on disk */
						/* depends on /etc/master.bblock, and PT */
int PTstatus  = NEEDED;
						/* DIRTY  = PT changed */
						/* INVALID= bad numbers in it */
int PBBstatus = NEEDED;
						/* DIRTY  = needs to be written to disk */
						/* INVALID= No PBB found on disk */
						/* depends on GEO and /etc/boot.hd */
int PERstatus = NEEDED;
						/* DIRTY  = needs to be written to disk */
						/* INVALID= no PER found on disk */
						/* depends on GEO & SLICE */
int SLICEstatus = NEEDED;
						/* DIRTY  = modified */
int BTTstatus = NEEDED;
						/* DIRTY  = in core copy differs from disk copy */
						/* INVALID= blocks conflict with MBB/PBB/PER/BTT */
int CMOSstatus= NEEDED;
						/* DIRTY  = in core copy differs from CMOS RAM */
						/* INVALID= Bad Checksum - MUST RUN SETUP */

main( argc, argv )
int argc;
char *argv[];
{

	int unit      = 0;
	int pbbcyl, pbbhead, pbbsec;
	int percyl, perhead, persec;
	partition_t *activepartition;

	/*
	 *	For each of MBB PBB PER try reading and validating before assuming
	 *  it is invalid.  This allows the user to screw up the partition table,
	 *	restore it, and not lose too much sleep (or info).
	 */

	/*
	 	We look in the MBB, the PBB, the CMOS, and lastly in the user's brain
		for the drive geometry.  When we find it, we will put it into the PBB
		if it is new/changed.  NOTE that this will not work with PRE 2.3 
		systems that expect the drive info to be found in the MBB!  We do
		NOT write the geometry to the MBB because other OSs may be using
		the space... (not mentioning names, but some DOS programs are really
		not very well behaved!)
	 */

		CMOSstatus = getCMOS( &cmos );
		if (CMOSstatus != INCORE || !CMOSdriveEnabled( unit, &cmos )) {
			fprintf(stderr,
"Error: You must use the setup program to tell the machine that you have\n");
			fprintf(stderr,
"a hard disk drive attached.  If you don't have a ROM type which matches\n");
			fprintf(stderr,
"your drive exactly, pick a type with the same number of heads and the\n");
			fprintf(stderr,
"closest number of cylinders.  If in doubt, be generous with the cylinders.\n");
			exit( -1 );
		}

		while (1) {
			if (MBBstatus == NEEDED)  {
				if ((MBBstatus = getMBB(unit, &mbb)) == INCORE) {
					if ((GEOstatus & INCORE) != INCORE) {
!						if (MBBGeometryIsValid( &mbb )) {
!							GEOstatus = MBBgeoToPERgeo(mbb.geometry, geometry);
						}
					}
				}
			}
			
			if ((MBBstatus & INCORE) == INCORE)
!				activepartition = GetActive( &mbb );
			else activepartition = NULL;

			if (activepartition == NULL) {
				PTstatus = INCORE + INVALID;
			} else {

				pbbcyl = CYL_BOOT( activepartition );
				pbbhead= HEAD_BOOT(activepartition );
				pbbsec = SEC_BOOT( activepartition );

				if (PBBstatus == NEEDED) {
					if ((PBBstatus= getPBB(unit, pbbcyl, pbbhead, pbbsec, &pbb))
								 == INCORE) {

						/* Try reading a 2.3+ geometry specification */

						if ((GEOstatus & INCORE) != INCORE) {
							/* by definition - if a PBB is valid, it */
							/* has a valid geometry table */
!							GEOstatus = PBBgeoToPERgeo(pbb.geometry, geometry);
						}
					}
				}

				/*
					At this point, if we don't have valid drive geometry info,
					we need to grab it from the CMOS ... 
				 */
    
				if ((GEOstatus & INCORE) != INCORE) {
!					GEOstatus=CMOSgeoToPERgeo(&cmos,unit,geometry);
					if ((GEOstatus & INCORE) != INCORE) {
						reinitialize drive
					}
				}

				/* now snarf up the PER ... */

				percyl = CYL_END( activepartition );
				perhead= HEAD_END(activepartition );
				persec = SEC_END( activepartition );

				if (PERstatus == NEEDED)
					PERstatus=read_sector(unit,&per,percyl,perhead,persec);

				SLICEstatus = ValidSliceTable( unit, &per );

				if (BTTstatus == NEEDED)
					BTTstatus=read_sector(unit,&btt,percyl,perhead,persec - 1);
			}

		DISPLAY
			GEO,	if any are NEEDED or INVALID, label as such, else
			PT,		show contents on the screen
			PER,
			BTT, and
			SLICE	(also note if valid superblock found there)

		Select one of GEO PT BTT SLICE to modify
			/* GEO */
			if ((GEOstatus & INCORE) != INCORE) { /* virgin disk! */
!				while ((GEOstatus = GetGEOfromUser(geometry)) != INCORE)
					; /* wait till the user gets it right */
				GEOstatus |= DIRTY;
			}
			if changed GEO, reinit drive & set MBB,PBB,PER,&BTT to NEEDED
		
			if changed PT, re-read PBB, PER, and BTT & set MBB |= DIRTY
			  if not valid, mark on screen and dont allow update till fixed
		
			if changed BTT - check for conflicts with the MBB, PBB, BTT, and PER
			  if conflicts, complain and allow user to modify PT to bypass these
		
			if changed SLICE, set SLICEstatus |= DIRTY
			/* at this point check over the NEEDED/INVALID bits */
			/* if any of PT, GEO, BTT, or SLICE are still set, tell what */
			/* is needed and go back to the loop */
			/* if all is kosher, quit... (OK if MBB, PBB, or PER invalid) */
		}
		/* ... to here where we must figure out what needs updating */
		/* if MBB is INVALID then read in boot code */
		/* if PBB is INVALID then read in boot code */
		/* if CMOS is BADGEO then need to update with GEO */
		/* if GEO dirty, need to update PBB, PER & set dirty, unset GEO dirty */
		/* if PT dirty, update & set MBB dirty, unset PT dirty */
		/* if SLICE dirty, update & set PER dirty */

		/* if MBB dirty, write & unset */
		/* if PBB dirty ... */
		/* if PER dirty ... */
		/* if BTT dirty ... */

		/* if SLICE dirty then need to do smartMKFSing remembering that */
		/* changes to 0s0 if HD rooted are not allowed */
}

getMBB( unit, mbbp )
int unit;
mbb_t *mbbp;
{
	int cc;

	if ( read_sector( unit, mbbp, CYL(0), HEAD(0), SECTOR(1)) == ERROR ) {
		fprintf(stderr, "Error reading MBB from HD unit %d",unit);
		return INVALID;
	}
	if ( mbbp->signature == PT_SIG )
		return INCORE;
	else
		return INVALID;
}


getPBB( unit, pbbcyl, pbbhead, pbbsec, pbbp )
int unit;
int pbbcyl, pbbhead, pbbsec;
pbb_t *pbbp;
{
	int cc;

	if ( read_sector( unit, pbbp, pbbcyl, pbbhead, pbbsec) == ERROR ) {
		fprintf(stderr, "Error reading PBB from HD unit %d",unit);
		return INVALID;
	}
	if ( VALID_PBB( pbbp ) )
		return INCORE;
	else
		return INVALID;
}

				/* forcibly update CMOS */
				CMOSstatus = PERgeoToCMOSgeo(&cmos, unit, geometry);
				if ((CMOSstatus & DIRTY) == DIRTY) {
					writeCMOS( &cmos );
					CMOSstatus &= ~DIRTY;
				}
SHAR_EOF
fi
if test -f 'diskio.c'
then
	echo shar: "will not over-write existing file 'diskio.c'"
else
cat << \SHAR_EOF > 'diskio.c'
/***************************************************************
 *
 *	Low Level Read/Write routines to access the info on the disk
 *	and the contents of the CMOS RAM chip
 *
 *	init(         unit )		initialize the specified drive
 *	done(         unit )		close down the specified drive
 *	read_sector(  unit, buf, cyl, head, sector)
 *	write_sector( unit, buf, cyl, head, sector)
 *	raw_io(       unit, buf, cyl, head, sector, op)
 *
 *	readCMOS( buffer )	read the contents of the CMOS RAM
 *	writeCMOS( buffer )	write to the CMOS RAM
 *
 ***************************************************************
 *
 *	Revision Control Information
 *
 *	By:		$Author: root $
 *			$Revision: 1.2 $
 *	Last modified:	$Date: 87/09/16 02:12:24 $
 *	$Source: /u/src/microport/newfdisk/test/RCS/getput.c,v $
 *
 *	Release state:	$State: Exp $
 *
 ***************************************************************
 *
 * Modification Log
 * ----------------
 * $Log:	getput.c,v $
 * Revision 1.2  87/09/16  02:12:24  root
 * maintenance update
 * 
 * Revision 1.1  88/04/07  23:11:20  root
 * Initial revision
 * 
 ***************************************************************
 */

#ifndef lint
    static char rcsid[] =
    "$Header: getput.c,v 1.2 87/09/16 02:12:24 root Exp $";
#endif

#include <fcntl.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
#include <malloc.h>
#include "cmos.h"		/* cmos layout */

/* #define PRODUCTION	/* Define to eliminate error messages on stderr */
#define NOWRITE			/* Define to DISABLE absolute writes to the disk */

#ifdef PRODUCTION
# ifdef NOWRITE
	ERROR: Why do you want a production version which can not write to the disk?
# endif
#endif

static int fds[2] = { -1, -1 };	/* fds for both hard disk drives */

static char *unitname[] = {	/* entire disk... */
	"/dev/rdsk/0s0",
	"/dev/rdsk/1s0"
};

/*
**	Open a file which corrosponds to the entire disk.
**	All other operations require that this be done before they call
**	any disk I/O routines!
*/

int init( unit )
int unit;
{
    char dummyblock[512];

    if (unit < 0 || unit > 1)
	return ERROR;

    if ( fds[unit] != -1 )
	closeunit( unit );

    if ((fds[unit] = open(unitname[unit], O_RDWR)) == -1) {
		fprintf(stderr, "Can't open %s, errno=%d\n", unitname[unit], errno);
		exit(errno);
    }

    /*
    **	WHY is this needed???
    */

    read(fds[unit],dummyblock,512);	/* dummy read to force wnsweep */

    return OK;
}

done( unit )
int unit;
{
    close( fds[unit] );
    fds[unit] = -1;
    return OK;
}

readCMOS( cmosp )
struct cmos *cmosp;
{
    int	cmosfd;

    if ((cmosfd = open(CMOSDEV, 0)) == -1) {
		perror("Opening cmos device");
		exit(1);
    }
    if ( sizeof(struct cmos) != read(cmosfd, cmosp, sizeof(struct cmos))) {
		perror("Reading cmos device");
		exit(1);
    }
    close(cmosfd);
}

writeCMOS( cmosp )
struct cmos *cmosp;
{
    unsigned int  cksum, i;
    unsigned char *c;
    int	cmosfds[unit];

        /* calculate new checksum */
    c = (unsigned char *) &cmos;
    cksum = 0;
    for(i=0x10; i<0x21; i++)
	cksum += *(c+i);
        /* Set new checksum */
    *(c + 0x2e ) = cksum >> 8;	/* this is also known as cmos.cksum */
    *(c + 0x2f ) = cksum ;

    if ((cmosfd = open(CMOSDEV, 1)) == -1) {
		perror("Opening cmos device");
		exit(1);
    }
    if ( sizeof(struct cmos) != write(cmosfd, cmosp, sizeof(struct cmos))) {
		perror("writing cmos device");
		exit(1);
    }
    close(cmosfd);
}

/*
 *  read or write a sector by disk address (cyl,head,sector)
 */

read_sector(unit, buf, cyl, head, sector)
int unit;				/* NOTE THIS CHANGE! */
byte *buf,head,sector;
int cyl;
{
	int i;
	struct i1010iopb *io, iopb;

	if (fds[unit] == -1) {
		init( unit );
	}
	io = &iopb;
	io->i_addr = (long) buf;
	io->i_actcylinder = cyl;
	io->i_acthead = head;
	io->i_sector = sector;
	io->i_funct = WD_READ_OP;
	i = ioctl(fds[unit],I1010_RAWIO,io);
#ifndef PRODUCTION
	if (i)
		fprintf(stderr, "\nread_sector(U=%d, C=%d, H=%d, S=%d) errno= %d\n",
					unit, cyl, head, sector, i);
#endif
	return(i);
}

write_sector(unit,buf,cyl,head,sector)
int unit;
byte *buf,head,sector;
int cyl;
{
	int i;
	struct i1010iopb *io, iopb;

	if (fds[unit] == -1) {
		init( unit );
	}

#ifdef NOWRITE
return(0);
#endif

	io = &iopb;
	io->i_addr = (long) buf;
	io->i_actcylinder = cyl;
	io->i_acthead = head;
	io->i_sector = sector;
	io->i_funct = WD_WRITE_OP;
	i = ioctl(fds[ unit ], I1010_RAWIO, io);
#ifndef PRODUCTION
	if (i)
		fprintf(stderr, "\nwrite_sector(U=%d, C=%d, H=%d, S=%d) errno= %d\n",
					unit, cyl, head, sector, i);
#endif
	return(i);
}

raw_io(unit,buf,cyl,head,sector,op)
int unit;
byte *buf,head,sector;
int cyl,op;
{
	int i;
	struct i1010iopb *io, iopb;

	if (fds[unit] == -1) {
		init( unit );
	}
	io = &iopb;
	io->i_addr = (long) buf;
	io->i_actcylinder = cyl;
	io->i_acthead = head;
	io->i_sector = sector;
	io->i_funct = op;
	i = ioctl(fds[ unit ], I1010_RAWIO, io);
#ifndef PRODUCTION
	if (i) printf("\nRaw I/O( U=%d C=%d H=%d S=%d op=%d) errno= %d\n",
				  unit, cyl, head, sector, op, i);
#endif
	return(i);
}

SHAR_EOF
fi
if test -f 'fdisk.c'
then
	echo shar: "will not over-write existing file 'fdisk.c'"
else
cat << \SHAR_EOF > 'fdisk.c'
/***************************************************************
 *	Fdisk Prototype
 ***************************************************************
 *
 *	Revision Control Information
 *
 *	By:		$Author: root $
 *			$Revision: 1.2 $
 *	Last modified:	$Date: 87/09/16 02:12:16 $
 *	$Source: /u/src/microport/newfdisk/test/RCS/fdisk.c,v $
 *
 *	Release state:	$State: Exp $
 *
 ***************************************************************
 *
 * Modification Log
 * ----------------
 * $Log:	fdisk.c,v $
 * Revision 1.2  87/09/16  02:12:16  root
 * maintenance update
 * 
 * Revision 1.1  88/04/07  23:10:47  root
 * Initial revision
 * 
 * 
 ***************************************************************
 *
 *	Get Master Boot Block which contains
 *		* possable disk geometry info
 *		  Partition structure
 *		  MBB signature
 *
 *	If MBB not valid:	(Newly formatted disk)
 *		  Get disk geometry from user
 *		  Get partition table info from user
 *		  Get Slice Table from user
 *		  initialize MBB with contents of /etc/master.bblock
 *		  initialize PBB
 *		  initialize PER
 *		  initialize BTT
 *		  initialize SLICE TABLE
 *		  Recalibrate drive
 *
 *	else (MBB is valid)
 *		  get PBB
 *		  get PER
 *		  get BTT
 *		  get SLICE TABLE
 *		  get disk geometry from PER/PBB/MBB/cmos
 *
 *	Allow user to modify:
 *		Drive type:			invalidates MBB,PBB,PER
 *		Partition table from MBB:	if act part changes,
 *						 PER&BTT need to be redone
 *		BTT:				nothing invalidated.
 *		PER:?
 *		SLICE TABLE:			need to mkfs the thing...
 ***************************************************************
 */
#ifndef lint
    static char rcsid[] =
    "$Header: fdisk.c,v 1.2 87/09/16 02:12:16 root Exp $";
#endif

#include <fcntl.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
#include <malloc.h>
#include "cmos.h"		/* cmos layout */
#include "mbb.h"		/* master boot block */
#include "pbb.h"		/* partition boot block */
#include "btt.h"		/* bad track table */
#include "per.h"		/* partition end record */

#include "fdisk.h"

cmos_t cmos;	/* CMOS contents */
mbb_t mbb;	/* Master Boot Block */
pbb_t pbb;	/* Partition Boot Block */
btt_t btt;	/* Bad Track Table */
per_t per;	/* Partition End Record */

main() {

    int cc;

    cc  = openunit( 0 );
    cc |= get_cmos( &cmos );
    cc |= get_mbb( 0, &mbb );
    cc |= get_pbb( 0, &mbb, &pbb );
    cc |= get_per( 0, &mbb, &per );
    cc |= get_btt( 0, &mbb, &btt );
    cc |= closeunit( 0 );

}

SHAR_EOF
fi
if test -f 'getput.c'
then
	echo shar: "will not over-write existing file 'getput.c'"
else
cat << \SHAR_EOF > 'getput.c'
/***************************************************************
 *
 *	Read/Write routines to access the basic block info needed:
 *		The Master Boot Block
 *		The Partition Boot Block
 *		The Bad Track Table
 *		The Partition End Record Block
 *	  and	The contents of the CMOS RAM chip
 *
 ***************************************************************
 *
 *	Revision Control Information
 *
 *	By:		$Author: root $
 *			$Revision: 1.2 $
 *	Last modified:	$Date: 87/09/16 02:12:24 $
 *	$Source: /u/src/microport/newfdisk/test/RCS/getput.c,v $
 *
 *	Release state:	$State: Exp $
 *
 ***************************************************************
 *
 * Modification Log
 * ----------------
 * $Log:	getput.c,v $
 * Revision 1.2  87/09/16  02:12:24  root
 * maintenance update
 * 
 * Revision 1.1  88/04/07  23:11:20  root
 * Initial revision
 * 
 * 
 ***************************************************************
 */

#ifndef lint
    static char rcsid[] =
    "$Header: getput.c,v 1.2 87/09/16 02:12:24 root Exp $";
#endif

#include <fcntl.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
#include <malloc.h>
#include "cmos.h"		/* cmos layout */
#include "mbb.h"		/* master boot block */
#include "pbb.h"		/* partition boot block */
#include "btt.h"		/* bad track table */
#include "per.h"		/* partition end record */

#include "fdisk.h"

static int fds[2] = { -1, -1 };	/* fds for both hard disk drives */

static char *unitname[] = {	/* entire disk... */
	"/dev/rdsk/0s10",
	"/dev/rdsk/1s10"
};

/*
**	Open a file which corrosponds to the entire disk.
**	All other operations require that this be done before they call
**	any disk I/O routines!
*/

int openunit( unit )
int unit;
{
    char dummyblock[512];

    if (unit < 0 || unit > 1)
	return ERROR;

    if ( fds[unit] != -1 )
	closeunit( unit );

    if ((fds[unit] = open(unitname[unit], O_RDWR)) == -1) {
	fprintf(stderr, "Can't open %s, errno=%d\n", unitname[unit], errno);
	exit(errno);
    }

    /*
    **	WHY is this needed???
    */

    read(fds[unit],dummyblock,512);	/* dummy read to force wnsweep */
    return OK;
}

closeunit( unit )
int unit;
{
    close( fds[unit] );
    fds[unit] = -1;
    return OK;
}

/*
**	Read the Master Boot Block (MBB) from the hard disk
*/

get_MBB( unit, mbbp )
int unit;
mbb_t *mbbp;
{
    if (read_sector(fds[unit],mbbp,0,0,1 )) {
	fprintf(stderr, "read error: %s (c0,h0,s1), errno=%d\n",
			 unitname[unit], errno);
	exit(errno);
    }
}

/*
**	Write the Master Boot Block (MBB) to the hard disk
*/

put_MBB( unit, mbbp )
int unit;
mbb_t *mbbp;
{
    if (write_sector(fds[unit],mbbp,0,0,1 )) {
	fprintf(stderr, "write error: %s (c0,h0,s1), errno=%d\n",
		unitname[unit], errno);
	exit(errno);
    }
}

#define BOOTDRTBLOFF	0x1ee

int get_PBB( unit, mbbp, pbbp );	/* Return OK if a valid PBB, */
int unit;				/* FAIL if not a uport PBB */
mbb_t *mbbp;
pbb_t *pbbp;
{
int	dptdbg = 0;

    partition_t  *pn;
    unsigned char  beginsec;
    unsigned int   begincyl;

    /*
     *  Get the active unix partition boot sector where a ROM compatible
     *  drive parameter entry (and Unix boot code) may be written
     */

    pn = (partition_t *) (mbbp + PTOFFSET);
    for (i=0; i < 4; ++i, ++pn)		/* find active paratition */
	if (pn->part_boot == 0x80 &&
	    ( pn->part_sys == 5 || pn->part_sys == 0x52 ) /* types 5 and 52 */
	   )						  /* are System5    */
	    break;
    if (i < 4) {	/* we found the active Microport Unix partition */
	begincyl = ((pn->part_start_s & 0xC0) << 2) | pn->part_start_c;
	beginsec = pn->part_start_s & 0x3F;		/* why is this here? */

	read_sector(fds[unit],pbbp,begincyl,
				   pn->part_start_h,
				   pn->part_start_s & 0x1f);
	if (VALID_PBB(pbbp))
	    return OK;
    }
    return FAIL;	/* indicate not uport boot sector */
}

init_PBB( unit, mbbp, pbbp, driveinfo );
int unit;		/* unit to write drive table on */
mbb_t *mbbp;		/* this holds current partition table */
pbb_t *pbbp;		/* 512 byte work space */
i1010drtab *driveinfo;	/* and this the disk geometry */
{
    int	bsfd;
    if ((bsfd=open("/etc/boot.hd", 0)) < 0) {
	fprintf(stderr,"Can't open /etc/boot.hd\n");
	fprintf(stderr,"System5 partition on Hard Disk %d isn't bootable\n",
			    unit);
	return;
    }
    if (dptdbg)
	fprintf(stderr, "Reading /etc/boot.hd\n");
    read(bsfd, pbbp, 512);
    close(bsfds[unit]);

    R_CYLS(    ROMTABLE(pbbp) )	= driveinfo->dr_ncyl;
    R_HEADS(   ROMTABLE(pbbp) )	= driveinfo->dr_nfhead;
    if (driveinfo->dr_nfhead > 8)
	R_HDFLAG(  ROMTABLE(pbbp) )	= MORETHAN8HEADS;
    else
	R_HDFLAG(  ROMTABLE(pbbp) )	= LESSTHAN8HEADS;
    R_PRECOMP( ROMTABLE(pbbp) )	= driveinfo->dr_precomp;
    R_LZ(      ROMTABLE(pbbp) )	= driveinfo->dr_lzone;
    R_SPT(     ROMTABLE(pbbp) )	= driveinfo->dr_nsec;

    VALIDATE_PBB( pbbp );

    return OK;
}

write_PBB( unit, mbbp, pbbp );
int unit;		/* unit to write drive table on */
mbb_t *mbbp;		/* this holds current partition table */
pbb_t *pbbp;		/* filled in and valid pbb */
{
    partition_t  *pn;			/* partition table entry */
    unsigned char  beginsec;
    unsigned int   begincyl;

    /*
     *  Find the Active Microport partition in the MBB and write the
     *  Partition Boot Record to the beginning of it.
     */

    pn = (partition_t *) (mbbp + PTOFFSET);	/* partition table */

    for (i=0; i < 4; ++i, ++pn)		/* find active paratition */
	if (pn->part_boot == 0x80 &&
	    ( pn->part_sys == 5 || pn->part_sys == 0x52 )
	   )
	    break;
    if (i < 4) {	/* we found the active Microport Unix partition */
	begincyl = ((pn->part_start_s & 0xC0) << 2) | pn->part_start_c;
	beginsec = pn->part_start_s & 0x3F;		/* why is this here? */

	if (dptdbg)
	    fprintf(stderr,"Update PBB at C %u, H %d, S %d for unit %d\n",
	    begincyl, pt->part_start_h & 0xff, pt->part_start_s & 0x1f, unit);

	write_sector(fds[unit],pbbp,begincyl, pn->part_start_h,
				              pn->part_start_s & 0x1F);
    }
}


get_CMOS( cmosp )
struct cmos *cmosp;
{
    int	cmosfd;

    if ((cmosfd = open(CMOSDEV, 0)) == -1) {
	perror("Opening cmos device");
	exit(1);
    }
    if ( sizeof(struct cmos) != read(cmosfd, cmosp, sizeof(struct cmos))) {
	perror("Reading cmos device");
	exit(1);
    }
    close(cmosfd);
}

put_CMOS( cmosp )
struct cmos *cmosp;
{
    unsigned int  cksum, i;
    unsigned char *c;
    int	cmosfds[unit];

        /* calculate new checksum */
    c = (unsigned char *) &cmos;
    cksum = 0;
    for(i=0x10; i<0x21; i++)
	cksum += *(c+i);
        /* Set new checksum */
    *(c + 0x2e ) = cksum >> 8;	/* this is also known as cmos.cksum */
    *(c + 0x2f ) = cksum ;

    if ((cmosfd = open(CMOSDEV, 1)) == -1) {
	perror("Opening cmos device");
	exit(1);
    }
    if ( sizeof(struct cmos) != write(cmosfd, cmosp, sizeof(struct cmos))) {
	perror("writing cmos device");
	exit(1);
    }
    close(cmosfd);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!  YET TO DO  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
**	read end-of-partition record, if any.
**	get drtabs, slice table, and pointer to first bad-track sector
**
**	fds[unit] = fd of open /dev/rdsk/0x?0 
**	er = pointer to buffer to read the stuff into
**	cyl, head, and sect are place on disk to read from
*/

read_PER( unit, perp, cyl, head, sector)
int unit;
char *perp;
int cyl, head, sector;
{
    read_sector (fds[unit],perp,cyl,head,sector & 0x1f);
}

	/* write updated partition end record back to disk */

write_PER()
{
    if (er) {
	/* move drive table to buffer */
	memcpy (er, (byte *) &drvtab, sizeof(struct i1010drtab));
	write_sector (fds[unit],er,endcyl,pt->ehead,pt->esect & 0x1f );
    }
}


	/* read bad track table from disk */

read_BT()
{
        read_sector (fds[unit],bad,endcyl,pt->ehead, (pt->esect&0x1f)-1);
}

	/* write updated bad track table back to disk */

write_BT()
{
    if (bad)
        write_sector (fds[unit],bad,endcyl,pt->ehead, (pt->esect&0x1f)-1);
}

SHAR_EOF
fi
if test -f 'wn.man'
then
	echo shar: "will not over-write existing file 'wn.man'"
else
cat << \SHAR_EOF > 'wn.man'
wn(7) ioctls


EXAMPLE
main()
{
	int fd;
	char dummyblock[512], mbb[512];

    if ((fd = open("/dev/dsk/0s0", O_RDWR)) == -1) {
		fprintf(stderr, "Can't open drive, errno=%d\n", errno);
		exit(errno);
    }

    /*
    **	WHY is this needed???
    */

    read(fd,dummyblock,512);	/* dummy read to force wnsweep */

	read_sector( fd, mbb, 0, 0, 1 );	/* read Master Boot Block */

	/* user code to modify it ... */

	write_sector( fd, mbb, 0, 0, 1 );	/* and write it back */

    close( fd );
}


read_sector(fd, buf, cyl, head, sector)
dev_t fd;
byte *buf,head,sector;
int cyl;
{
	int i;
	struct i1010iopb *io, iopb;

	io = &iopb;
	io->i_addr = (long) buf;
	io->i_actcylinder = cyl;
	io->i_acthead = head;
	io->i_sector = sector;
	io->i_funct = WD_READ_OP;
	i = ioctl(fd,I1010_RAWIO,io);
	if (i)
		fprintf(stderr, "\nread_sector(C=%d, H=%d, S=%d) errno= %d\n",
					cyl, head, sector, i);
	return(i);
}

write_sector(fd,buf,cyl,head,sector)
dev_t fd;
byte *buf,head,sector;
int cyl;
{
	int i;
	struct i1010iopb *io, iopb;

	io = &iopb;
	io->i_addr = (long) buf;
	io->i_actcylinder = cyl;
	io->i_acthead = head;
	io->i_sector = sector;
	io->i_funct = WD_WRITE_OP;
	i = ioctl(fd, I1010_RAWIO, io);
	if (i)
		fprintf(stderr, "\nwrite_sector(C=%d, H=%d, S=%d) errno= %d\n",
					cyl, head, sector, i);
	return(i);
}

raw_io(fd,buf,cyl,head,sector,op)
dev_t fd;
byte *buf,head,sector;
int cyl,op;
{
	int i;
	struct i1010iopb *io, iopb;

	io = &iopb;
	io->i_addr = (long) buf;
	io->i_actcylinder = cyl;
	io->i_acthead = head;
	io->i_sector = sector;
	io->i_funct = op;
	i = ioctl(fd, I1010_RAWIO, io);
	if (i) printf("\nRaw I/O(C=%d H=%d S=%d op=%d) errno= %d\n",
				  cyl, head, sector, op, i);
	return(i);
}

SHAR_EOF
fi
exit 0
#	End of shell archive