[comp.os.minix] New Bootstrapper Update Part 2 of 2

ncoverby@ndsuvax.UUCP (Glen Overby) (06/16/89)

#! /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:
#	b2b/loader.c
#	b2b/main.c
# This archive created: Thu Jun 15 22:54:35 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'b2b/loader.c'" '(23900 characters)'
if test -f 'b2b/loader.c'
then
    echo shar: will not over-write existing file "'b2b/loader.c'"
else
sed 's/^X//' << \SHAR_EOF > 'b2b/loader.c'
X/*
X			Minix Second Stage Boot Loader
X
XIn this program, all the elements of the Minix system are loaded into memory
Xfrom binary files on a filesystem.  All parts of the system are loaded
Xlike any other Minix process, with Text, Data and Stack areas and command
Xoptions on a "command line" (which is actually in a binary format).
X
XThe routines in this file turn a raw disk into a filesystem.  The primary
Xroutines are:
X	inode = open_file(filename)
X	a.out = load_file(inode, starting segment)
X	count = read_file(inode, buffer)
X
X12/2/88 Glen/B
X	Construct this from the reminants of the old (CS548/CS497) boot
X	program.
X*/
X
X/* include files to get inode, super block structs*/
X#include <minix/const.h>
X#include <minix/type.h>
X#include <fs/const.h>
X#include <fs/type.h>
X#include <fs/inode.h>
X#include <fs/super.h>
X#include <stdio.h>
X#include <errno.h>
X#include <a.out.h>
X#include "type.h"
X#include "partition.h"
X/*#include "hdparam.h"*/
X
X/*#undef printf		/* defined in fs/const.h as 'printk' */
X#undef getchar		/* don't want the macros */
X#undef putchar
X#undef putc
X#undef getc
X
Xextern	int	errno;
X	int	def_dev;			/* default (boot) device */
X	char	glb_block[BLOCK_SIZE];		/* misc block buffer */
X	int	cylsiz, tracksiz;		/* for low diskio.. */
X	int	sizes[10];			/* kernel, mm, fs, init size */
X	int	kds, ksp;			/* kernel data seg, sp */
X
X/*#define TRACE*/
X/*#define DEBUG*/
X/*#define DEBUG1*/
X
X/* Function Types */
Xint ll_Block_Read(/* int device, block; char *buffer */);
Xint read_block(/* struct super_block *super; int block; char *buffer; */);
Xstruct super_block *read_super(/* int device; */);
Xstruct part_entry *Read_Part(/* int device; */);
Xstruct param *read_rom(/* int device; */);
Xstruct inode *read_inode(/*struct super_block *sb; int inum;*/);
Xint read_file(/*struct inode *inode; char *buffer;*/);
Xint lload_blocks(/*struct super_block *super; char *buffer;
X		int *list, nlist;*/);
Xstruct inode *open_file(/*char *filename;*/);
Xchar *device_map(/*char *filename; int *device;*/);
Xstruct inode *follow_path(/*struct super_block *super; char *name*/);
Xnext_name(/*char *from, *name;*/);
Xint search_dir(/*struct inode *inode; char *name;*/);
X
X#define	READ	0
X#define	WRITE	1
X
X/*
X * Filesystem parameters which are not supplied in FS' header files
X */
X#define NR_DIRECT_ZONES	NR_ZONE_NUMS-2	/* number of DIRECT zones */
X#define IND_ZONE_NUM	7	/* i_zone offset of indirect zone */
X#define DIND_ZONE_NUM	8	/* i_zone offset of double indirect block */
X#define SECTOR_SIZE	512	/* sector size (bytes) */
X#define HEAD_SIZE	32	/* a.out header size (stripped) */
X
X/*
X * Hardware Parameters
X */
X#define WINI_DISK	0x40	/* first device number of wini */
X#define PART_PER_DRIVE	5	/* how many partitions per wini drive */
X
X#define NSUPERCACHE	10	/* size of super block "cache" */
X#define NINODECACHE	20	/* size of inode "cache" */
X#define NEXECCACHE	10	/* size of a.out header "cache" */ 
X
X/*
X	Intra-Segment Copy
X
X    copy(destination, source, length)
X*/
Xcopy(d,s,l)
Xchar *d, *s;
Xint l;
X{
X	while(l--)	*d++ = *s++;
X}
X
X/*
X	Zero Memory	(for clearing the bss segment)
X
X    zero_mem(segment, offset, length)
X*/
Xzero_mem(segment, offset, length)
Xunsigned int segment, offset, length;
X{
X	static char zero[1024];	/* this will get put in BSS, which is zeroed */
X	int count;
X
X#ifdef DEBUG
X	printf("zero_mem: 0x%x:0x%x 0x%x\n", segment, offset, length);
X#endif
X	count = length / 1024 + 1; /* caveat! trashes to an even 1K boundary */
X				/* (no prob for sequential process loading */
X	while(count--) {
X#ifdef DEBUG
X	printf("zero_mem: 0x%x:0x%x #%d\n", segment, offset, count);
X#endif
X		lcopy(segment, offset, ds(), zero, 1024);
X		segment += 64;
X	}
X}
X/*
X	Clicks
X
X    calculate the number of clicks from bytes (a click is 16 bytes).
X    Compensate for partial clicks by rounding UP.
X*/
Xclicks(bytes)
Xlong bytes;
X{
X	return((bytes%16) ? (bytes>>CLICK_SHIFT)+1 : (bytes>>CLICK_SHIFT));
X}
X
X/*
X	Low-Level Block Read
X
X	procedure low_level_block_read
X		in device, block number, buffer address
X		returns Error_Status
X
XPerforms the lowest level data read by calling the disk I/O services
Xsupplied by the Operating System or ROM Support Routines.  No knowledge
Xof hard-disk partitions is exhibited.
X
X*/
Xint ll_Block_Read(device, block, buffer)
Xint device; unsigned int block; char *buffer;
X{
X	int status;
X#ifdef DEBUG1
X	printf("ll_Block_Read: device=0x%x block=0x%x buffer=0x%x\n", device, block, buffer);
X#endif
X#ifdef DEBUG
X	fgetc();
X#endif
X	status = diskio(READ, block*2, buffer, 1, device);
X	if(status > 255) {
X		errno = EIO;
X		printf("Disk Error reading sector 1 of block %d\n",block);
X		return(ERROR);
X	}
X	status = diskio(READ, block*2+1, buffer+SECTOR_SIZE, 1, device);
X	if(status > 255) {
X		errno = EIO;
X		printf("Disk Error reading sector 2 of block %d\n",block);
X		return(ERROR);
X	}
X	return(OK);
X}
X
X/*
X	Intermediate-Level Block Read
X
X	procedure read_block
X		in Super_Block, block number, buffer address
X		returns Error_Status
X
XReads a block from a disk by calling the Low-Level Block Read.  If
Xthe disk is paritioned, the partition information (stored in the super block)
Xis consulted to determine the offset into the disk of the partition.
X
X*/
X
Xint read_block(super, block, buffer)
XSUPERBLOCK super;
Xint block;
Xchar *buffer;
X{	int device;
X	unsigned int real_block;
X#ifdef DEBUG
X	printf("Block_Read..%u %ld\n", block, super->s_time);
X#endif
X	device = (super->s_dev < WINI_DISK) ? super->s_dev : 
X			0x80 + ((super->s_dev - WINI_DISK) / PART_PER_DRIVE);
X	real_block = block + (unsigned int) (super->s_time & 0xFFFF);
X	return(ll_Block_Read(device, real_block, buffer));
X}
X
X/*
X	Read Super-Block
X
X	procedure read_super_-_block
X		in device
X		returns Super_Block_Ptr
X
XRead the super-block off of the specified device, if this has not yet
Xbeen done.  A pointer to a super-block for the requested device is
Xreturned.  This structure will NOT be overwritten by subsequent
Xrequests for super-blocks on different devices.  NULL is returned if an
Xerror occurs, and the error code will be stored in the variable
X"errno".
X
XIf the disk being read from is a partition of a larger physical drive,
Xit's partition table is read and information about where the partition
Xlies on the physical device is stored in the super block.
X
XAllocation of Super-Blocks is made out of a pool of pre-allocated
Xblocks.  A count of how many blocks have been allocated is kept
Xso that new blocks can be painlessly allocated; since no de-allocation
Xis allowed, this is sufficent.  Prior to allocating a new blocks,
Xall allocated blocks are searched for the wanted block.  If it is not
Xfound, then a new one is allocated and loaded.
X
X*/
X
X/*
Xsearch sb list for this defive
Xif ! found
X	have to load it!...
X	allocate SB
X	if partitioned disk (wini)
X		read partition table
X		build partial super-block
X	else
X		set non-partitioned parameters in SB
X	read SB from disk
Xreturn sb
X
X*/
X
XSUPERBLOCK read_super(device)
Xint device;
X{
X	static struct super_block s_cache[NSUPERCACHE],
X				*last_super = s_cache;
X	SUPERBLOCK sb, last;
X	struct part_entry *partition;
X	long lowsec;		/* low sector of partition */
X
X	Set_Param(device);
X#ifdef TRACE
X	printf("read_super: device=%d...", device);
X#endif
X	/* Search the cache for a possibly already loaded super-block
X	 */
X	for(sb = s_cache;
X	    sb < last_super && sb->s_dev != device;
X	    sb++) ;
X
X	if (sb >= last_super) { /* load it */
X#ifdef TRACE
X		printf("loading super block\n");
X#endif
X		/* The Super-Block is not loaded.  Allocate a new one
X		 * and load it.
X		 */
X		sb = last_super++;	/* allocate new SB */
X		sb->s_dirt++;
X		sb->s_dev = device;
X
X		/* fix up device number and block number for partitioned
X		 * disks (winchesters)
X		 */
X		if (device >= WINI_DISK) { /* partitioned WINI device */
X			partition = Read_Part(device);
X			sb->s_time = partition->lowsec/2;
X			lowsec = partition->lowsec/2;
X		} else {
X			sb->s_time = 0;
X			lowsec = 0;
X		}
X
X		if(read_block(sb, SUPER_BLOCK, glb_block) == OK) {
X			copy(sb, glb_block, SUPER_SIZE);
X			sb->s_dev = device;
X			sb->s_time = lowsec;
X			sb->s_dirt = 1;
X#ifdef DEBUG
X			dump_super(sb);
X#endif
X		} else {
X			sb = NULL;
X		}
X	} else {
X#ifdef TRACE
X		printf("super block already loaded\n");
X#endif
X	}
X	return(sb);
X}
X
X/*
X	Set Parameters
X
X	procedure Set_Param
X		in device
X
XRead and set the disk track and cylinder size parameters appropriately.
XIf the device is a hard disk, read the hard disk parameters from their
XROM tables.
X*/
X
XSet_Param(device)
Xint device;
X{
X/*X	struct param *param; X*/
X
X	if(device < WINI_DISK) {
X		tracksiz = 9;
X		cylsiz = 18;
X	} else {
X		hd_param(0x80 + ((device - WINI_DISK) / PART_PER_DRIVE));
X/*		param = read_rom((device - WINI_DISK) / PART_PER_DRIVE);
X/*		tracksiz = 0x11;			/* not in my rom */
X/*		cylsiz = tracksiz * param->nr_heads;*/
X/*		cylsiz = tracksiz * 6;
X */	}
X}
X
X/*
X	Read Partition Table
X
X	procedure Read_Part
X		in device
X		return Ptr to partition entry
X
XRead the partition table in sector 1 of a hard disk and return a pointer
Xto the partition entry for the device we're using.
X
X*/
Xstruct part_entry *Read_Part(device)
Xint device;
X{
X	int real_dev, partition;
X
X	if(device >= WINI_DISK) {
X		real_dev = 0x80 + ((device - WINI_DISK) / PART_PER_DRIVE);
X		partition = ((device - WINI_DISK) % PART_PER_DRIVE) -1;
X	} else {
X		real_dev = device;
X		partition = 0;
X	}
X
X#ifdef TRACE
X	printf("Read_Part: device=0x%x partition=0x%x\n", real_dev, partition);
X#endif
X	ll_Block_Read(real_dev, 0, glb_block);
X#ifdef DEBUG
X	dump_prt(glb_block + (partition * sizeof(struct part_entry)) + TABLEOFFSET);
X#endif
X	return(glb_block + (partition * sizeof(struct part_entry)) + TABLEOFFSET);
X}
X
X/*
X	Read i-node
X
X	procedure read_i_-_node
X		in super-block, i-node number
X		returns Inode_Ptr
X
XRead one i-node from the specified device.  If the inode has already
Xbeen read into the internal cache, it is not reread.  A pointer to an
Xinternal i-node is returned (this holds more information than an
Xordinary disk inode does).  NULL is returned if an error occurs, and
Xthe error code will be stored in the variable "errno".
X
X*/
X
XINODE read_inode(sb, inum)
XSUPERBLOCK sb;
Xint inum;
X{
X	static struct inode i_cache[NINODECACHE],
X				*last_inode = i_cache;
X	INODE i, last;
X
X	int blk_off, i_off;
X
X#ifdef TRACE
X	printf("read_inode: inum=%d...",inum);
X#endif
X	/* Search the cache for a possibly already loaded i-node
X	 */
X	for(i = i_cache;
X	    i < last_inode && (i->i_num != inum || i->i_dev != sb->s_dev);
X	    i++) ;
X
X	if(i >= last_inode ) {
X#ifdef TRACE
X		printf("loading inode\n");
X#endif
X		/* The i-node is not loaded.  Allocate a new one and load it
X		 */
X		i = last_inode++;	/* error check allocating too many */
X		i->i_dirt++;
X		i->i_count = 1;
X		i->i_num = inum;
X		i->i_dev = sb->s_dev;
X	
X		/* calculate the block and where in the block the inode is */
X		blk_off = (sb->s_imap_blocks + sb->s_zmap_blocks +2) + 
X			  (inum - 1)/INODES_PER_BLOCK;	/* fs/inode.c:8558 */
X#ifdef DEBUG
X		printf("iblock: i=0x%x 0x%x z=0x%x 0x%x\n", sb->s_imap_blocks, sb->s_zmap_blocks, (inum -1)/INODES_PER_BLOCK, INODES_PER_BLOCK);
X#endif
X
X		i_off = ((inum - 1) % INODES_PER_BLOCK);
X
X#ifdef DEBUG
X		printf("Reading Inode i=%d blk=%u off=0x%x\n",inum, blk_off, i_off);
X#endif
X		if(read_block(sb, blk_off, glb_block) == OK) {
X#ifdef DEBUG
X			printf("copy: 0x%x 0x%x 0x%x 0x%x\n",i, glb_block + i_off * INODE_SIZE, INODE_SIZE, i_off * INODE_SIZE);
X#endif
X			copy(i, glb_block + i_off * INODE_SIZE, INODE_SIZE);
X		} else {
X			i = NULL;
X		}
X	}
X#ifdef TRACE
X	else printf("inode already loaded\n");
X#endif
X	return(i);
X}
X
X/*
X	Read File
X
X	procedure read_file
X		in Inode_Ptr, buffer address
X		returns bytes read
X
XReads a disk file into the current data segment.  If the returned byte count
Xis zero, an error has occured and an error code is in the global variable 
X"errno".
X
X*/
X
Xint read_file(inode, buffer)
XINODE inode;
Xchar *buffer;
X{
X	int count, blocks;
X	SUPERBLOCK super;
X	static int indirect[BLOCK_SIZE/2];	/* buffer for indirect block */
X
X#ifdef TRACE
X	printf("Read_File: inum=%d\n", inode->i_num);
X#endif
X	blocks = 0;
X	super = read_super(inode->i_dev);
X	count = lload_blocks(super, buffer, inode->i_zone, NR_DZONE_NUM);
X	buffer += count*BLOCK_SIZE;
X	blocks += count;
X	if(inode->i_zone[NR_DZONE_NUM] != 0) {
X		read_block(super, inode->i_zone[NR_DZONE_NUM], indirect);
X		count = lload_blocks(super, buffer, indirect, BLOCK_SIZE/2);
X		blocks += count;
X	}
X	return(blocks);
X}
X
X/*
X	Local Load Blocks
X
X	procedure Local_Load_Blocks
X		in Super-Block_Ptr, buffer address, list address, list length
X		returns blocks read
X
XLoads disk blocks listed in the "list" into the current data segment.
XA count of blocks read is returned; if this count is zero, an error has
Xoccured and an error code is in the global variable "errno".
X*/
X
Xint lload_blocks(super, buffer, list, nlist)
XSUPERBLOCK super;
Xchar *buffer;
Xunsigned int *list;
Xint nlist;
X{
X	int count = 0;
X#ifdef DEBUG
X	printf("Loading file's data blocks\n");
X#endif
X	while(nlist > 0 && *list != 0) {
X		if(read_block(super, *list, buffer) != OK) {
X			count = 0;	/* Indicate error */
X			break;		/* get outa here! */
X		}
X		buffer += BLOCK_SIZE;
X		list++;
X		nlist--;
X		count++;
X	}
X	return(count);
X}
X
X/*
X	Load File
X
X	procedure  load_file
X		in Inode_Ptr, buffer address (segment)
X		returns a.out header
X
XLoad a Minix format binary object file into any location in memory (the
Xsegment being given in the buffer address).  An "a.out" header
Xstructure is returned.  This contains information on the text, data,
Xbss and stack sizes.  The text and data segments will have been loaded,
Xand the bss and stack segments zeroed at this point, so only writing
Xthe program's arguments to the stack segment remains to be done.  If an
Xerror occurs, NULL is returned and an error code is in the global
Xvariable "errno".
X
X*/
XAOUT load_file(inode, buffer)
XINODE inode;
Xchar *buffer;
X{
X	static struct exec e_cache[NEXECCACHE],
X				*last_exec = e_cache,
X				*e;
X
X	int count;
X	SUPERBLOCK super;
X	static int indirect[BLOCK_SIZE/2];	/* buffer for indirect block */
X
X#ifdef TRACE
X	printf("Load_File: inum=%d\n", inode->i_num);
X#endif
X	super = read_super(inode->i_dev);
X
X	/* first block requires special pampering because it has the
X	   a.out header in it */
X	read_block(super, inode->i_zone[0], glb_block);
X	e = last_exec++;	/* allocate a.out structure */
X	copy(e, glb_block, A_MINHDR);	/* the file *must* be stripped */
X	lcopy(buffer, 0, ds(), glb_block+A_MINHDR, BLOCK_SIZE - A_MINHDR);
X	buffer += (BLOCK_SIZE / 16) - (A_MINHDR / 16);
X
X	count = fload_blocks(super, buffer, inode->i_zone+1, NR_DZONE_NUM - 1);
X	buffer += count * BLOCK_SIZE / 16;
X
X	if(inode->i_zone[NR_DZONE_NUM] != 0) {
X		read_block(super, inode->i_zone[NR_DZONE_NUM], indirect);
X		count = fload_blocks(super, buffer, indirect, BLOCK_SIZE/2);
X	}
X	return(e);
X}
X
X/*
X	Far Load Blocks
X
X	procedure Far_Load_Blocks
X		in Super-Block_Ptr, buffer address, list address, list length
X		returns blocks read
X
XLoads disk blocks listed in the "list" into memory starting at the
Xsegment specified in "buffer address".  A count of blocks read is
Xreturned; if this count is zero, an error has occured and an error code
Xis in the global variable "errno".
X
X*/
Xint fload_blocks(super, buffer, list, nlist)
XSUPERBLOCK super;
Xchar *buffer;
Xunsigned int *list;
Xint nlist;
X{
X	int count = 0;
X#ifdef DEBUG
X	printf("Loading file's data blocks: glb_block= 0x%x:0x%x\n", ds(), glb_block);
X#endif
X	while(nlist > 0 && *list != 0) {
X		if(read_block(super, *list, glb_block) != OK) {
X			count = 0;	/* Indicate error */
X			break;		/* get outa here! */
X		}
X#ifdef DEBUG
X		printf("copy block %u to 0x%x:0x%x\n", *list, buffer, 0);
X#endif
X		lcopy(buffer, 0, ds(), glb_block, BLOCK_SIZE);
X		buffer += BLOCK_SIZE / 16;
X		list++;
X		nlist--;
X		count++;
X	}
X	return(count);
X}
X
X/*
X	Open File
X
X	procecure open_file
X		in filename
X		returns Inode_Ptr
X
XAttempt to open a file with a name of the format "device:path".  The device,
Xif given, specifies which physical drive and partition to load the file
Xfrom.  If an error occurs durring processing, a NULL Inode pointer is returned
Xand an error codes is put in the global variable "errno".
X
XNotes:
X1)	///usr//ast == /usr/ast
X2)	the last element is ALWAYS a file, so the case:
X		/usr/ast/
X	cannot occur.
X*/
XINODE open_file(filename)
Xchar *filename;
X{
X	int device;
X	char *path;
X	struct super_block *super;
X	struct inode *inode;
X
X#ifdef TRACE
X	printf("Open File %s\n",filename);
X#endif
X	path = device_map(filename,&device);
X			/* how to error check? */
X	if((super = read_super(device)) == NULL) {
X		errno = ENODEV;
X		return(NULL);
X	}
X
X	/* follow the pathname down the directory tree */
X	inode = follow_path(super, path);
X
X	/* We now have a proposed file to open.  Make sure it's a
X	 * "regular" file (as opposed to directory or device).
X	 */
X	if(inode != NULL && (inode->i_mode & I_TYPE) != I_REGULAR) {
X		errno = EISDIR;
X		return(NULL);
X	} else {
X		return(inode);
X	}
X}
X
X/*
X	Device Calculation
X
X	procedure device_map
X		in filename
X		out device number
X		returns path
X
XChecks the filename for a device:path form, and if there is a device
Xit is looked up in a table of device names and the given device number 
Xis returned, along with the part of the string that contains only the
Xpath.  If no device name exists, the default device (the one booted from)
Xis returned as the device, and the entire filename (which is just the path)
Xis returned.
X
XIf a invalid device name is given, a device number of -1 is returned, and
Xthe pathname is set as if the device was OK.  This is a feature.
X
X*/
X
Xchar *device_map(filename, device)
Xchar *filename;
Xint *device;
X{
X	char devicename[80];
X	char *s, *d;
X	static struct {
X		char *name;
X		int dev;
X	} map[] = {		/* list of existing devices */
X		"fd0", 0,	"fd1", 1,	"fd2", 2,	"fd3", 3,
X		"hd0.0", 0x40,	"hd0.1", 0x41,	"hd0.2", 0x42,
X				"hd0.3", 0x43,	"hd0.4", 0x44,
X		"hd1.0", 0x45,	"hd1.1", 0x46,	"hd1.2", 0x47,
X				"hd1.3", 0x48,	"hd1.4", 0x49,
X		"", -1
X	}, *mp;
X
X
X	for(s=filename, d=devicename; *s != '\0' && *s != ':'; ) {
X		*d++ = *s++;
X	}
X	if(*s == ':') s++;
X	*d = '\0';
X
X	if(*s == '\0') {
X		/* no ":" found, so there's no device name here */
X		*device = def_dev;
X		return(filename);
X	} else {
X		for(mp = map; mp->dev != -1 && strcmp(mp->name, devicename);
X		    mp++) ;
X		*device = mp->dev;
X		return(s);
X	}
X}
X
X
X/*
X	Follow Path
X
X	procedure follow_path
X		in Pathname, Super_Block
X		returns Inode_Ptr
X
XThe file given in _pathname_ is searched for on the device which the
Xsuper-block is on.  If it exists, an i-node for it is returned; otherwise
XNULL is returned and an error code is placed in the global variable "errno".
X
X*/
XINODE follow_path(super, path)
XSUPERBLOCK super;
Xchar *path;
X{
X	INODE inode;
X	char name[80];
X	int i_num;
X
X	i_num = ROOT_INODE;
X
X	while((path = next_name(path, name)) != NULL) {
X		/* there are more directories to descend.  First make sure
X		 * that our current directory is in fact a directory before
X		 * loading and searching it.
X		 */
X#ifdef DEBUG
X		printf("follow_path: looking for %s in %d\n", name, i_num);
X#endif
X		inode = read_inode(super, i_num);
X			/* obvious problem if an error occurs and read_inode
X			   returns NULL */
X		if((inode->i_mode & I_TYPE) != I_DIRECTORY) {
X			errno = ENOTDIR;
X			printf("ENOTDIR in follow_path\n");
X			return((struct inode *)NULL);
X		}
X
X		/* so far, so good.  Search this directory for the next
X		 * path element.
X		 */ /* inum=zero is an error situation; zero is root */
X		if((i_num = search_dir(inode, name)) == 0) {
X			errno = EINVAL;
X			printf("can't find %s!\n", name);
X			return((struct inode *)NULL);
X		}
X	}
X	inode = read_inode(super, i_num);
X		/* no real problem here if an error occurs and read_inode
X		   returns NULL... it will be detected 1 level up */
X	return(inode);
X}
X
X/*
X	Next Pathname Element
X
X	procedure next_name
X		in pathname
X		out next path element
X		returns remaining path after the current element
X
XMoves down the pathname for the next file name, and returns that and
Xthe remaining path after the next file name.  NULL is returned when
Xthe path is exhausted.
X
X*/
X
Xnext_name(path, name)
Xchar *path, *name;
X{	char *from, *to;
X
X	for(from = path; *from == '/'; from++) ;	/* skip all '/' */
X
X	for(to = name; *from != '/' && *from != '\0';) {
X		*to++ = *from++;
X	}
X	
X	*to = '\0';
X	if(to == name)
X		return(NULL);
X	else
X		return(from);
X}
X
X/*
X	Search Directory
X
X	procedure search_dir
X		in inode, name to search for
X		returns new inode number
X
XSearch the directory described by _inode_ for the file name in _name_.
XIf found, return the inode number of the found file; otherwise return 0.
X
XA static array is used as the destination for the directory load.  An
Xunchecked error condition exists if the directory is larger than this!
X
X*/
X
Xint search_dir(inode, name)
XINODE inode;
Xchar *name;
X{
X	dir_struct *dir, *lastdir;
X	static dir_struct directory[NR_DIR_ENTRIES * 8];
X		/* directory buffer 8 blocks long */
X	int count;	/* directory length in blocks */
X
X#ifdef DEBUG
X	printf("search_dir: inum=%d, name=%s.\n", inode->i_num, name);
X#endif
X	count = read_file(inode, directory);
X	lastdir = directory + NR_DIR_ENTRIES * count + 1;
X#ifdef DEBUG
X	printf("search_dir: count=%d dir=0x%x lastdir=0x%x\n", count, directory, lastdir);
X#endif
X	for(dir = directory; 
X	    dir <= lastdir && strcmp(dir->d_name, name) != 0;
X	    dir++)
X#ifdef DEBUG
X		printf("search_dir: checking %s\n",dir->d_name);
X#endif
X		;
X#ifdef DEBUG
X		printf("search_dir: found %s\n",dir->d_name);
X#endif
X	return(dir > lastdir ? NULL : dir->d_inum);
X}
X
X#ifdef DEBUG
X/* Dump Super-Block contents
X*/
Xdump_super(super)
XSUPBERBLOCK super;
X{
X	printf("\nSuper-Block Contents\n");
X	printf(" s_ninodes=%u      ", super->s_ninodes);
X	printf(" s_nzones=%u       ", super->s_nzones);		fputc('\n');
X	printf(" s_imap_blocks=%u  ", super->s_imap_blocks);
X	printf(" s_zmap_blocks=%u  ", super->s_zmap_blocks);
X	printf(" s_firstdatazone=%u", super->s_firstdatazone);	fputc('\n');
X	printf(" s_log_zone_size=%u", super->s_log_zone_size);
X	printf(" s_max_size=%u     ", super->s_max_size);
X	printf(" s_magic=%u        ", super->s_magic);		fputc('\n');
X
X	printf(" s_dev=%u          ", super->s_dev);
X	printf(" s_time=%ld        ", super->s_time);		fputc('\n');
X	fputc('\n');
X}
X/* dump partition table contents
X*/
Xdump_prt(part)
Xstruct part_entry *part;
X{
X	printf("\nPartition Table Contents\n");
X	printf(" at 0x%x       ", part);			fputc('\n');
X	printf(" bootind=0x%x  ", part->bootind);
X	printf(" start_head=%d ", part->start_head);		fputc('\n');
X	printf(" start_sec=%d  ", part->start_sec);
X	printf(" start_cyl=%d  ", part->start_cyl);		fputc('\n');
X	printf(" sysind=0x%x   ", part->sysind);
X	printf(" last_head=%d  ", part->last_head);		fputc('\n');
X	printf(" last_sec=%d   ", part->last_sec);
X	printf(" last_cyl=%d   ", part->last_cyl);		fputc('\n');
X	printf(" lowsec=%ld    ", part->lowsec);
X	printf(" size=%ld      ", part->size);			fputc('\n');
X	fputc('\n');
X}
X
X/* dump Fixed Disk parameter table
X */
Xdump_param(dest)
Xstruct param *dest;
X{
X	printf("\nParameter Table Contents\n");
X	printf(" nr_cyl=0x%x     ",  dest->nr_cyl);
X	printf(" nr_heads=0x%x   ", dest->nr_heads);		fputc('\n');
X	printf(" reduced_wr=0x%x ", dest->reduced_wr);
X	printf(" wr_precomp=0x%x ", dest->wr_precomp);		fputc('\n');
X	printf(" max_ecc=0x%x    ", dest->max_ecc);
X	printf(" ctrl_byte=0x%x  ", dest->ctrl_byte);		fputc('\n');
X	printf(" sectors=0x%x    ", dest->sectors);
X	fputc('\n');
X}
X#endif
X
X/* dump EXEC structure
X */
Xdump_exec(exec)
XAOUT exec;
X{
X	printf("\nEXEC Structure Contents\n");
X	printf(" magic= 0x%x, 0x%x", exec->a_magic[0], exec->a_magic[1]);
X	printf(" flags= 0x%x    ", exec->a_flags);		fputc('\n');
X	printf(" cpu= 0x%x      ", exec->a_cpu);
X	printf(" hdrlen= 0x%x   ", exec->a_hdrlen);
X	printf(" version= 0x%x  ", exec->a_version);		fputc('\n');
X	printf(" text size= %ld ", exec->a_text);
X	printf(" data size= %ld ", exec->a_data);
X	printf(" bss size= %ld  ", exec->a_bss);
X	printf(" total size= %ld", exec->a_total);		fputc('\n');
X	printf(" syms size= %ld ", exec->a_syms);
X	printf(" entry point= %ld", exec->a_no_entry);		fputc('\n');
X	fputc('\n');
X}
SHAR_EOF
if test 23900 -ne "`wc -c < 'b2b/loader.c'`"
then
    echo shar: error transmitting "'b2b/loader.c'" '(should have been 23900 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'b2b/main.c'" '(3097 characters)'
if test -f 'b2b/main.c'
then
    echo shar: will not over-write existing file "'b2b/main.c'"
else
sed 's/^X//' << \SHAR_EOF > 'b2b/main.c'
X/*
X			Minix Second Stage Boot Loader
X
XIn this program, all the elements of the Minix system are loaded into memory
Xfrom binary files on a filesystem.  All parts of the system are loaded
Xlike any other Minix process, with Text, Data and Stack areas and command
Xoptions on a "command line" (which is actually in a binary format).
X
X*/
X#include <minix/const.h>
X#include <minix/type.h>
X#include <fs/const.h>
X#include <fs/type.h>
X#include <fs/inode.h>
X#include <fs/super.h>
X#include <stdio.h>
X#include <errno.h>
X#include <a.out.h>
X#include "type.h"
X
X/*#define FLOPPY	/* define for fd(0) rather than hd(0,2) */
X/*#undef printf		/* defined in fs/const.h as 'printk' */
X#undef getchar		/* don't want the macros */
X#undef putchar
X#undef putc
X#undef getc
X
Xextern int sizes[], kds, ksp;
Xint error = 0;
Xint segment = 0x60;
Xint filenum = 0;
X
X/*#define DEBUG*/
X
XAOUT load(file)
Xchar *file;
X{	INODE inode;
X	AOUT aout;
X	long t, d, b, s;	/* sizes of Text, Data, BSS and Stack segs */
X
X/*	printf("**********************************************************\n");*/
X	printf("%s\n",file);
X#ifdef DEBUG
X	printf("Segment = 0x%x\n", segment);
X	fgetc();
X#endif
X	if((inode = open_file(file)) == NULL) {
X		error = 1;
X		perror("boot");
X	}
X	aout = load_file(inode, segment);
X#ifdef DEBUG
X	dump_exec(aout);
X#endif
X	if(aout->a_flags & A_SEP) {
X		t = aout->a_text;
X		d = aout->a_data;
X	} else {
X		t = 0;
X		d = aout->a_data + aout->a_text;
X	}
X	b = aout->a_bss;
X	s = aout->a_total - d - b;
X
X#ifdef DEBUG
X	printf("t=%ld d=%ld b=%ld s=%ld\n", t, d, b, s);
X#endif
X	/* write Text, (Data+BSS+STACK) segment info on top of header
X	 * relocation info (that won't be used on 80x86 machines)
X	 */
X	aout->a_trsize = t;
X	aout->a_drsize = d + b;	/* data segment (not including stack) */
X	aout->a_tbase = (long) segment;
X	aout->a_dbase = (long) (segment + clicks(t));
X#ifdef DEBUG
X	printf("trsize=0x%x tbase=0x%x drsize=0x%x dbase=0x%x total=0x%x\n",
X		(int) aout->a_trsize, (int) aout->a_tbase,
X		(int) aout->a_drsize, (int) aout->a_dbase, aout->a_total);
X#endif
X
X	zero_mem(segment + clicks(t + d), 0, (int) b);
X
X	segment += clicks(t + d + b + s);
X/*	sizes[filenum * 2] = clicks(t);
X	sizes[filenum * 2 +1] = clicks(d + b + s);	*/
X	filenum++;
X
X	return(aout);
X}
X
Xmain()
X{	AOUT aout[10];
X	char eq = '\0';
X	int i, stack[5];
X
X	aout[0] = load("/etc/kernel");
X	aout[1] = load("/etc/mm");
X	aout[2] = load("/etc/fs");
X	aout[3] = load("/etc/init");
X
X#ifdef DEBUG
X	printf("System Loaded, Initializing...\n");
X	fgetc();
X#endif
X
X	stack[0] = aout[0]->a_dbase + aout[0]->a_total;
X	mmstack(aout[1],stack+1);
X	fsstack(aout[2],stack+2);
X	ksp = kstack(aout, stack);
X
X/*	for(i = 0;i < 8;i++)
X		printf("sizes[%d] = %d %x\n", i, sizes[i], sizes[i]);*/
X
X/*	printf("Segment = 0x%x\n", segment);*/
X
X	kds = 0x60 + ((aout[0]->a_flags & A_SEP) ? clicks(aout[0]->a_text) : 0);
X	printf("Kernel CS=0x%x DS=0x%x SP=0x%x\n", aout[0]->a_text, kds, ksp);
X
X	if(error) {
X		printf("\n\n\nError occured durring system load!!\n");
X		printf("          REBOOT NOW!\n");
X		fgetc();
X	} else {
X		printf("\n\nStrike '=' to execute system:");
X		while((eq=fgetc()) != '=');
X		return(eq);
X	}
X}
SHAR_EOF
if test 3097 -ne "`wc -c < 'b2b/main.c'`"
then
    echo shar: error transmitting "'b2b/main.c'" '(should have been 3097 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0