[comp.os.cpm] UZI Utilities, part 1 of 2

dbraun@cadavr.intel.com (Doug Braun ~) (12/22/88)

This and the following posting contain a set of UZI utility programs.
These programs run under CP/M, and allow you to build, check, and manipulate
a UZI filesystem.  They must be linked with the device drivers you
must write for your disks.  This is also the best way to get device drivers
working in the first place.  See the .DOC file for more info.



#!/bin/sh
#
#Run this file through sh to get:
#    xmachdep.c
#    ucp.c
#    fsck.c
#    xdevtty.c
#    bd.c
#    mkfs.c
#    unix.azm
#    loadutil.sub
#    filflop.sub
#    uzi_util.doc
#    filfs.sub
#    filelist
#    read.me
echo -n 'Extracting xmachdep.c ... '
sed 's/^X//' > xmachdep.c << 'EOF_xmachdep.c'
X
X/**************************************************
XUZI (Unix Z80 Implementation) Utilities:  xmachdep.c
X***************************************************/
X
X
X#include "unix.h"
X#include "extern.h"
X
X
X/* This is called at the very beginning to initialize everything. */
X/* It is the equivalent of main() */
X
Xfs_init()
X{
X    inint = 0;
X    udata.u_euid = 0;
X    udata.u_insys = 1;
X}
X
X
X/* This checks to see if a user-suppled address is legitimate */
Xvaladr(base,size)
Xchar *base;
Xuint16 size;
X{
X    return(1);
X}
X
X
X/* This adds two tick counts together.
XThe t_time field holds up to one second of ticks,
Xwhile the t_date field counts minutes */
X
Xaddtick(t1,t2)
Xtime_t *t1, *t2;
X{
X
X    t1->t_time += t2->t_time;
X    t1->t_date += t2->t_date;
X    if (t1->t_time >= 60*TICKSPERSEC)
X    {
X	t1->t_time -= 60*TICKSPERSEC;
X	++t1->t_date;
X    }
X}
X
Xincrtick(t)
Xtime_t *t;
X{
X    if (++t->t_time == 60*TICKSPERSEC)
X    {
X	t->t_time = 0;
X	++t->t_date;
X    }
X}
X
X
X
Xstkreset()
X{
X#asm 8080
X	POP	H
X	LXI	SP,udata?-2
X	PCHL
X#endasm
X}
X
X
X/* Port addresses of clock chip registers. */
X
X#define SECS 0xe2
X#define MINS 0xe3
X#define HRS 0xe4
X#define DAY 0xe6
X#define MON 0xe7
X#define YEAR 86
X
Xsttime()
X{
X    panic("Calling sttime");
X}
X
X
Xrdtime(tloc)
Xtime_t *tloc;
X{
X    tloc->t_time = (tread(SECS)>>1) | (tread(MINS)<<5) | (tread(HRS)<<11);
X    tloc->t_date = tread(DAY) | (tread(MON)<<5) | (YEAR<<9);
X}
X
X
X/* Update global time of day */
Xrdtod()
X{
X    tod.t_time = (tread(SECS)>>1) | (tread(MINS)<<5) | (tread(HRS)<<11);
X    tod.t_date = tread(DAY) | (tread(MON)<<5) | (YEAR<<9);
X}
X
X
X/* Read BCD clock register, convert to binary. */
Xtread(port)
Xuint16 port;
X{
X    int n;
X
X    n = in(port);
X    return ( 10*((n>>4)&0x0f) + (n&0x0f) );
X}
X
X
X/* Disable interrupts */
Xdi()
X{
X#asm 8080
X	DI	;disable interrupts
X#endasm
X}
X
X/* Enable interrupts if we are not in service routine */
Xei()
X{
X    if (inint)
X	return;
X    ;	/* Empty statement necessary to fool compiler */
X
X#asm 8080
X	EI	;disable interrupts
X#endasm
X}
X
X
X
X/* This shifts an unsigned int right 8 places. */
X
Xshift8()
X{
X#asm 8080
X	POP	D  	;ret addr
X	POP	H
X	MOV	L,H
X	MVI	H,0
X	MOV	A,L
X	ANA	A	;set Z flag on result
X	PUSH	H
X	PUSH	D	;restore stack
X#endasm
X}
X
X
X/* This prints an error message and dies. */
X
Xpanic(s)
Xchar *s;
X{
X    inint = 1;
X    kprintf("PANIC: %s\n",s);
X    idump();
X    abort();
X}
X
X
Xwarning(s)
Xchar *s;
X{
X    kprintf("WARNING: %s\n",s);
X}
X
X
Xkputs(s)
Xchar *s;
X{
X    while (*s)
X	kputchar(*(s++));
X}
X
Xkputchar(c)
Xint c;
X{
X    if (c == '\n')
X	_putc('\r');
X    _putc(c);
X}
X
X
X
Xidump()
X{
X    inoptr ip;
X    ptptr pp;
X    extern struct cinode i_tab[];
X    bufptr j;
X
X    kprintf(
X        "   MAGIC  DEV  NUM  MODE  NLINK (DEV) REFS DIRTY err %d root %d\n",
X            udata.u_error, root - i_tab);
X
X    for (ip=i_tab; ip < i_tab+ITABSIZE; ++ip)
X    {
X	kprintf("%d %d %d %u 0%o %d %d %d %d\n",
X	       ip-i_tab, ip->c_magic,ip->c_dev, ip->c_num,
X	       ip->c_node.i_mode,ip->c_node.i_nlink,ip->c_node.i_addr[0],
X	       ip->c_refs,ip->c_dirty);
X	ifnot (ip->c_magic)	
X	    break;
X    }
X
X    kprintf("\n   STAT WAIT   PID PPTR  ALARM  PENDING  IGNORED\n");
X    for (pp=ptab; pp < ptab+PTABSIZE; ++pp)
X    {
X	kprintf("%d %d    0x%x %d %d  %d 0x%x 0x%x\n",
X	       pp-ptab, pp->p_status, pp->p_wait,  pp->p_pid,
X	       pp->p_pptr-ptab, pp->p_alarm, pp->p_pending,
X		pp->p_ignored);
X        ifnot(pp->p_pptr)
X	    break;
X    }	
X    
X    kprintf("\ndev blk drty bsy\n");
X    for (j=bufpool; j < bufpool+NBUFS; ++j)
X	kprintf("%d %u %d %d\n",j->bf_dev,j->bf_blk,j->bf_dirty,j->bf_busy);
X
X    kprintf("\ninsys %d ptab %d call %d cwd %d sp 0x%x\n",
X	udata.u_insys,udata.u_ptab-ptab, udata.u_callno, udata.u_cwd-i_tab,
X       udata.u_sp);
X}
X
X
X
X/* Short version of printf to save space */
Xkprintf(nargs)
X	{
X	register char **arg, *fmt;
X	register c, base;
X	char s[7], *itob();
X
X	arg = (char **)&nargs + nargs;
X	fmt = *arg;
X	while (c = *fmt++) {
X		if (c != '%') {
X			kputchar(c);
X			continue;
X			}
X		switch (c = *fmt++) {
X		case 'c':
X			kputchar(*--arg);
X			continue;
X		case 'd':
X			base = -10;
X			goto prt;
X		case 'o':
X			base = 8;
X			goto prt;
X		case 'u':
X			base = 10;
X			goto prt;
X		case 'x':
X			base = 16;
X		prt:
X			kputs(itob(*--arg, s, base));
X			continue;
X		case 's':
X			kputs(*--arg);
X			continue;
X		default:
X			kputchar(c);
X			continue;
X			}
X		}
X	}
EOF_xmachdep.c
echo 'Done'

echo -n 'Extracting ucp.c ... '
sed 's/^X//' > ucp.c << 'EOF_ucp.c'
X
X/**************************************************
XUZI (Unix Z80 Implementation) Utilities:  ucp.c
X***************************************************/
X
X
X#include <stdio.h>
X#include "unix.h";
X#include "extern.h"
X
Xint16  *syserror = &udata.u_error;
Xstatic char cwd[100];
Xstatic char line[128];
X
X#ifndef CPM
Xextern char *sys_errlist[];
X#endif
X
X
Xmain(argc,argval)
Xint argc;
Xchar *argval[];
X{
X    int rdev;
X    char cmd[30], arg1[30], arg2[30], arg3[30];
X    int count;
X    struct filesys fsys;
X    int j;
X    char *argv[5];
X
X    if (argc < 2)
X	rdev = 0;
X    else
X	rdev = atoi(argval[1]);
X
X    xfs_init(rdev);
X    strcpy(cwd,"/");
X
X    for(;;)
X    {
X	printf("unix: ");
X	if (gets(line) == NULL)
X	{
X	    xfs_end();
X	    exit();
X	}
X	cmd[0] = '\0';
X	*arg1 = '\0';
X	arg2[0] = '\0';
X	arg3[0] = '\0';
X	count = sscanf(line,"%s %s %s %s",cmd, arg1, arg2, arg3);
X	if (count == 0 || cmd[0] == '\0')
X	    continue;
X
X	_sync();
X
X	if (strcmp(cmd,"\n") == 0)
X	    continue;
X	else if (strcmp(cmd,"exit") == 0)
X	{
X	    xfs_end();
X	    exit();
X	}
X	else if (strcmp(cmd,"ls") == 0)
X	{
X	    if (*arg1 )
X		ls(arg1);
X	    else
X		ls(".");
X	}
X	else if (strcmp(cmd,"cd") == 0)
X	{
X	    if (*arg1 )
X	    {
X		strcpy(cwd,arg1);
X		if (_chdir(arg1) != 0)
X		{
X		    printf("cd: error number %d\n",*syserror);
X		}
X	    }
X	}
X	else if (strcmp(cmd,"mkdir") == 0)
X	{
X	    if (*arg1 )
X		mkdir(arg1);
X	}
X	else if (strcmp(cmd,"mknod") == 0)
X	{
X	    if (*arg1  && *arg2 && *arg3 )
X		mknod(arg1,arg2, arg3);
X	}
X	else if (strcmp(cmd,"chmod") == 0)
X	{
X	    if (*arg1 && *arg2 )
X		chmod(arg1,arg2);
X	}
X	else if (strcmp(cmd,"get") == 0)
X	{
X            if (*arg1 )
X		get(arg1,0);
X	}
X	else if (strcmp(cmd,"bget") == 0)
X	{
X            if (*arg1 )
X		get(arg1,1);
X	}
X	else if (strcmp(cmd,"put") == 0)
X	{
X            if (*arg1 )
X		put(arg1,0);
X	}
X	else if (strcmp(cmd,"bput") == 0)
X	{
X            if (*arg1 )
X		put(arg1,1);
X	}
X	else if (strcmp(cmd,"type") == 0)
X	{
X            if (*arg1 )
X		type(arg1);
X	}
X	else if (strcmp(cmd,"dump") == 0)
X	{
X            if (*arg1 )
X		fdump(arg1);
X	}
X	else if (strcmp(cmd,"rm") == 0)
X	{
X            if (*arg1 )
X		unlink(arg1);
X	}
X	else if (strcmp(cmd,"df") == 0)
X	{
X	    for (j=0; j < 4; ++j)
X	    {
X		_getfsys(j,&fsys);
X		if (fsys.s_mounted)
X		{
X		    printf("%d:   %u blks used %u blks free %u inodes used %u inodes free\n",
X		    j,(fsys.s_fsize - fsys.s_isize)-fsys.s_tfree, fsys.s_tfree,
X		    (8*(fsys.s_isize-2)-fsys.s_tinode), fsys.s_tinode);
X		}
X	    }
X	}
X	else if (strcmp(cmd,"rmdir") == 0)
X	{
X            if (*arg1 )
X		rmdir(arg1);
X	}
X	else if (strcmp(cmd,"mount") == 0)
X	{
X	    if (*arg1 && *arg2)
X		if (_mount(arg1,arg2,0) != 0)
X		{
X		    printf("Mount error.%d\n", *syserror);
X		}
X	}
X	else if (strcmp(cmd,"umount") == 0)
X	{
X	    if (*arg1)
X		if (_umount(arg1) != 0)
X		{
X		    printf("Umount error.%d\n", *syserror);
X		}
X	}
X	else
X	{
X	    printf("Unknown command\n");
X	}
X    }
X}
X
X
X
Xls(path)
Xchar *path;
X{
X    struct direct buf;
X    struct stat statbuf;
X    char dname[128];
X    int d;
X    
X    d = _open(path,0);
X    if (d < 0)
X    {
X	printf("ls: can't open %s\n",path);
X	return;
X    }
X
X    while (_read(d,(char *)&buf,16) == 16)
X    {
X	if (buf.d_name[0] == '\0')
X	    continue;
X
X	if (path[0] != '.' || path[1] )
X	{
X	    strcpy(dname,path);
X	    strcat(dname,"/");
X	}
X	else
X	    dname[0] = '\0';
X	strcat(dname,buf.d_name);
X
X	if (_stat(dname,&statbuf) != 0)
X	{
X	    printf("ls: can't stat %s\n",dname);
X	    continue;
X	}
X
X	if ((statbuf.st_mode & F_MASK) == F_DIR)
X	    strcat(dname,"/");
X
X	printf("%-6d %-15s",
X		(statbuf.st_mode & F_CDEV) ?
X		    statbuf.st_rdev :
X		    512*statbuf.st_size.o_blkno + statbuf.st_size.o_offset,
X		dname);
X
X	printf("  0%-6o %-2d %-5d\n", statbuf.st_mode, statbuf.st_nlink,
X		statbuf.st_ino);
X    }
X    _close(d);
X}
X
X
Xchmod(path,modes)
Xchar *path;
Xchar *modes;
X{
X    int mode;
X    int dev;
X
X    mode = -1;
X    sscanf(modes,"%o",&mode);
X    if (mode == -1 )
X    {
X	printf("chmod: bad mode\n");
X	return(-1);
X    }
X
X    if (_chmod(path,mode))
X    {
X	printf("_chmod: error %d\n",*syserror);
X	return(-1);
X    }
X
X}
X
X
Xmknod(path,modes, devs)
Xchar *path;
Xchar *modes;
Xchar *devs;
X{
X    int mode;
X    int dev;
X
X    mode = -1;
X    sscanf(modes,"%o",&mode);
X    if (mode == -1 )
X    {
X	printf("mknod: bad mode\n");
X	return(-1);
X    }
X    
X    if ((mode & F_MASK) != F_BDEV && (mode & F_MASK) != F_CDEV)
X    {
X	printf("mknod: mode is not device\n");
X	return(-1);
X    }
X
X    dev = -1;
X    sscanf(devs,"%d",&dev);
X    if (dev == -1 )
X    {
X	printf("mknod: bad device\n");
X	return(-1);
X    }
X
X    if (_mknod(path,mode,dev) != 0)
X    {
X	printf("_mknod: error %d\n",*syserror);
X	return(-1);
X    }
X
X    return(0);
X}
X
X
X
Xmkdir(path)
Xchar *path;
X{
X
X    char dot[100];
X
X    if ( _mknod(path, 040000 | 0777, 0) != 0)
X    {
X	printf("mkdir: mknod error %d\n",*syserror);
X	return(-1);
X    }
X
X    strcpy(dot,path);
X    strcat(dot,"/.");
X    if ( _link(path,dot) != 0)
X    {
X	printf("mkdir: link dot error %d\n",*syserror);
X	return(-1);
X    }
X
X    strcpy(dot,path);
X    strcat(dot,"/..");
X    if ( _link(".",dot) != 0)
X    {
X	printf("mkdir: link dotdot error %d\n",*syserror);
X	return(-1);
X    }
X
X    return(0);
X}
X
X
X
X
Xget(arg,binflag)
Xchar *arg;
Xint binflag;
X{
X    FILE *fp;
X    int d;
X    char cbuf[512];
X    int nread;
X
X    fp = fopen(arg,binflag ? "rb" : "r");
X    if (fp == NULL)
X    {
X	printf("Source file not found\n");
X	return(-1);
X    }
X
X    d = _creat(arg,0666);
X    if (d < 0)
X    {
X	printf("Cant open unix file error %d\n",*syserror);
X   	return(-1);
X    }
X    
X    for (;;)
X    {
X        nread = fread(cbuf,1,512,fp);
X        if (nread == 0)
X	    break;
X        if (_write(d,cbuf,nread) != nread)
X        {
X	    printf("_write error %d\n",*syserror);
X	    fclose(fp);
X	    _close(d);
X	    return(-1);
X        }
X    }
X    fclose(fp);
X    _close(d);
X    return(0);
X}
X
X
Xput(arg,binflag)
Xchar *arg;
Xint binflag;
X{
X    FILE *fp;
X    int d;
X    char cbuf[512];
X    int nread;
X
X    fp = fopen(arg,binflag ? "wb" : "w");
X    if (fp == NULL)
X    {
X	printf("Cant open destination file.\n");
X	return(-1);
X    }
X
X    d = _open(arg,0);
X    if (d < 0)
X    {
X	printf("Cant open unix file error %d\n",*syserror);
X   	return(-1);
X    }
X    
X    for (;;)
X    {
X        if ((nread =_read(d,cbuf,512)) == 0)
X	    break;
X        if (fwrite(cbuf,1,nread,fp) != nread)
X        {
X	    printf("fwrite error");
X	    fclose(fp);
X	    _close(d);
X	    return(-1);
X        }
X    }
X    fclose(fp);
X    _close(d);
X    return(0);
X}
X
X
Xtype(arg)
Xchar *arg;
X{
X    int d;
X    char cbuf[512];
X    int nread;
X
X    d = _open(arg,0);
X    if (d < 0)
X    {
X	printf("Cant open unix file error %d\n",*syserror);
X   	return(-1);
X    }
X
X    for (;;)
X    {
X	if( (nread = _read(d,cbuf,512)) == 0)
X	    break;
X
X	fwrite(cbuf, 1, nread, stdout);
X    }
X    _close(d);
X    return(0);
X}
X
X
Xfdump(arg)
Xchar *arg;
X{
X    int d;
X    char cbuf[512];
X    int nread;
X
X    printf("Dump starting.\n");
X    d = _open(arg,0);
X    if (d < 0)
X    {
X	printf("Cant open unix file error %d\n",*syserror);
X   	return(-1);
X    }
X
X    for (;;)
X    {
X	if( (nread = _read(d,cbuf,512)) == 0)
X	    break;
X    }
X    _close(d);
X    printf("Dump done.\n");
X    return(0);
X}
X
X
X
X
Xunlink(path)
Xchar *path;
X{
X    struct stat statbuf;
X
X    if (_stat(path,&statbuf) != 0)
X    {
X	printf("unlink: can't stat %s\n",path);
X	return(-1);
X    }
X
X    if ((statbuf.st_mode & F_MASK) == F_DIR)
X    {
X	printf("unlink: %s directory\n",path);
X	return(-1);
X    }
X
X    if (_unlink(path) != 0)
X    {
X	printf("unlink: _unlink errn=or %d\n",*syserror);
X	return(-1);
X    }
X
X    return(0);
X}
X
X
Xrmdir(path)
Xchar *path;
X{
X    struct stat statbuf;
X    char newpath[100];
X    struct direct dir;
X    int fd;
X
X    if (_stat(path,&statbuf) != 0)
X    {
X	printf("rmdir: can't stat %s\n",path);
X	return(-1);
X    }
X
X    if (statbuf.st_mode & F_DIR == 0)
X    {
X	printf("rmdir: %s not directory\n",path);
X	return(-1);
X    }
X
X    if((fd = _open(path,0)) < 0) {
X	    printf("rmdir: %s unreadable\n", path);
X	    return(-1);
X    }
X    while(_read(fd, (char *)&dir, sizeof (dir)) == sizeof (dir)) {
X	    if(dir.d_ino == 0) continue;
X	    if(!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, ".."))
X		    continue;
X	    printf("rmdir: %s not empty\n", path);
X	    _close(fd);
X	    return(-1);
X    }
X    _close(fd);
X
X    strcpy(newpath,path);
X    strcat(newpath,"/.");
X    if (_unlink(newpath) != 0)
X    {
X	printf("rmdir: can't unlink \".\"  error %d\n",*syserror);
X	return(-1);
X    }
X
X    strcat(newpath,".");
X    if (_unlink(newpath) != 0)
X    {
X	printf("rmdir: can't unlink \"..\"  error %d\n",*syserror);
X	return(-1);
X    }
X
X    if (_unlink(path) != 0)
X    {
X	printf("rmdir: _unlink error %d\n",*syserror);
X	return(-1);
X    }
X
X    return(0);
X}
X
EOF_ucp.c
echo 'Done'

echo -n 'Extracting fsck.c ... '
sed 's/^X//' > fsck.c << 'EOF_fsck.c'
X
X/**************************************************
XUZI (Unix Z80 Implementation) Utilities:  fsck.c
X***************************************************/
X
X
X#include <stdio.h>
X
X#include "unix.h"
X#include "extern.h"
X
X#define MAXDEPTH 20   /* Maximum depth of directory tree to search */
X
X/* This checks a filesystem */
X
Xint dev;
Xstruct filesys filsys;
X
Xchar *bitmap;
Xint16 *linkmap;
X
X
Xchar *strcpy(), *strcat(), *sprintf();
Xchar *daread();
Xchar *calloc();
Xchar *da_read();
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X
X    char *buf;
X
X    if (argc != 2 || argv[1][0] < '0' || argv[1][0] > '9')
X    {
X	fprintf(stderr,"Usage: fsck device#\n");
X	exit(-1);
X    }
X
X    dev = atoi(argv[1]);
X
X	bufinit();
X    if (d_open(dev))
X    {
X	fprintf(stderr,"Can't open device number %d\n",dev);
X	exit(-1);
X    }
X
X    /* Read in the super block. */
X
X    buf = daread(1);
X    bcopy(buf, (char *)&filsys, sizeof(struct filesys));
X
X    /* Verify the fsize and isize parameters */
X
X    if (filsys.s_mounted != SMOUNTED)
X    {
X	printf("Device %d has invalid magic number %d. Fix? ",
X	       dev, filsys.s_mounted);
X	if (!yes())
X	    exit(-1);
X	filsys.s_mounted = SMOUNTED;
X	dwrite((blkno_t)1,(char *)&filsys);
X    }
X
X    printf("Device %d has fsize = %d and isize = %d. Continue? ",
X		dev, filsys.s_fsize, filsys.s_isize);
X    if (!yes())
X	exit(-1);
X
X    bitmap = calloc(filsys.s_fsize,sizeof(char));
X    linkmap = (int16 *)calloc(8 * filsys.s_isize, sizeof(int16));
X
X    if (!bitmap || !linkmap)
X    {
X	fprintf(stderr,"Not enough memory.\n");
X	exit(-1);
X    }
X
X    printf("Pass 1: Checking inodes.\n");
X    pass1();
X
X    printf("Pass 2: Rebuilding free list.\n");
X    pass2();
X
X    printf("Pass 3: Checking block allocation.\n");
X    pass3();
X
X    printf("Pass 4: Checking directory entries.\n");
X    pass4();
X
X    printf("Pass 5: Checking link counts.\n");
X    pass5();
X
X	bufsync();
X    printf("Done.\n");
X
X    exit(0);
X}
X
X
X
X/* Pass 1 checks each inode independently for validity, zaps bad block
Xnumbers in the inodes, and builds the block allocation map. */
X
Xpass1()
X{
X    uint16 n;
X    struct dinode ino;
X    uint16 mode;
X    blkno_t b;
X    blkno_t bno;
X    uint16 icount;
X    blkno_t *buf;
X
X    blkno_t getblkno();
X
X    icount = 0;
X
X    for (n = ROOTINODE; n < 8*(filsys.s_isize-2); ++n)
X    {
X	iread(n, &ino);
X	linkmap[n] = -1;
X
X	if (ino.i_mode == 0)
X	    continue;
X
X	mode = ino.i_mode & F_MASK;
X
X	/* Check mode */
X	if (mode != F_REG && mode != F_DIR && mode != F_BDEV && mode != F_CDEV)
X	{
X	    printf("Inode %d with mode 0%o is not of correct type. Zap? ",
X		    n, ino.i_mode);
X	    if (yes())
X	    {
X		ino.i_mode = 0;
X		ino.i_nlink = 0;
X		iwrite(n, &ino);
X		continue;
X	    }
X	}
X
X	linkmap[n] = 0;
X	++icount;
X	/* Check size */
X
X	if (ino.i_size.o_offset >= 512)
X	{
X	    printf("Inode %d offset is too big with value of %d. Fix? ",
X		    n,ino.i_size.o_offset);
X	    if (yes())
X	    {
X		while (ino.i_size.o_offset >= 512)
X		{
X		    ino.i_size.o_offset -= 512;
X		    ++ino.i_size.o_blkno;
X		}
X		iwrite(n,&ino);
X	    }
X	}
X
X
X	if (ino.i_size.o_offset < 0)
X	{
X	    printf("Inode %d offset is negative with value of %d. Fix? ",
X		    n,ino.i_size.o_offset);
X	    if (yes())
X	    {
X		ino.i_size.o_offset = 0;
X		iwrite(n,&ino);
X	    }
X	}
X
X	
X	/* Check blocks and build free block map */
X	if (mode == F_REG || mode == F_DIR)
X	{
X	    /* Check singly indirect blocks */
X
X	    for (b=18; b < 20; ++b)
X	    {
X		if (ino.i_addr[b] != 0 && (ino.i_addr[b] < filsys.s_isize ||
X			ino.i_addr[b] >= filsys.s_fsize))
X		{
X		    printf("Inode %d singly indirect block %d is out of range with value of %u. Zap? ",
X			    n, b, ino.i_addr[b]);
X		    if (yes())
X		    {
X			ino.i_addr[b] = 0;
X			iwrite(n, &ino);
X		    }
X		}
X
X		if (ino.i_addr[b] != 0 && ino.i_size.o_blkno < 18)
X		{
X		    printf("Inode %d singly indirect block %d is past end of file with value of %u. Zap? ",
X			    n, b, ino.i_addr[b]);
X		    if (yes())
X		    {
X			ino.i_addr[b] = 0;
X			iwrite(n, &ino);
X		    }
X		}
X		if (ino.i_addr[b] != 0)
X		    bitmap[ino.i_addr[b]] = 1;
X	    }
X
X	    /* Check the double indirect blocks */
X	    if (ino.i_addr[19] != 0)
X	    {
X		buf = (blkno_t *)daread(ino.i_addr[19]);
X		for (b=0; b < 256; ++b)
X		{
X		    if (buf[b] != 0 && (buf[b] < filsys.s_isize ||
X			    buf[b] >= filsys.s_fsize))
X		    {
X			printf("Inode %d doubly indirect block %d is out of range with value of %u. Zap? ",
X				n, b, buf[b]);
X			if (yes())
X			{
X			    buf[b] = 0;
X			    dwrite(b, (char *)buf);
X			}
X		    }
X		    if (buf[b] != 0)
X			bitmap[buf[b]] = 1;
X		    
X		}
X	    }
X
X
X	    /* Check the rest */
X	    for (bno=0; bno <= ino.i_size.o_blkno; ++bno)
X	    {
X		b = getblkno(&ino, bno);
X
X	        if (b != 0 && (b < filsys.s_isize ||
X			b >= filsys.s_fsize))
X		{
X		    printf("Inode %d block %d is out of range with value of %u. Zap? ",
X			    n, bno, b);
X		    if (yes())
X		    {
X			setblkno(&ino, bno,0);
X			iwrite(n, &ino);
X		    }
X		}
X
X		if (b != 0)
X		    bitmap[b] = 1;
X	    }
X
X	}
X    }
X
X    /* Fix free inode count in super block */
X    if (filsys.s_tinode != 8*(filsys.s_isize-2) - ROOTINODE - icount)
X    {
X	printf("Free inode count in super block is %u should be %u. Fix? ",
X	    filsys.s_tinode, 8*(filsys.s_isize-2) - ROOTINODE - icount);
X	
X	if (yes())
X	{
X	    filsys.s_tinode = 8*(filsys.s_isize-2) - ROOTINODE - icount;
X	    dwrite((blkno_t)1,(char *)&filsys);
X	}
X    }
X}
X		    
X
X
X/* Clear inode free list, rebuild block free list using bit map. */
X
Xpass2()
X{
X    blkno_t j;
X    blkno_t oldtfree;
X
X    printf("Rebuild free list? ");
X    if (!yes())
X	return;
X
X    oldtfree = filsys.s_tfree;
X
X    /* Initialize the super-block */
X
X    filsys.s_ninode =  0;
X    filsys.s_nfree =  1;
X    filsys.s_free[0] =  0;
X    filsys.s_tfree =  0;
X
X    /* Free each block, building the free list */
X
X    for (j= filsys.s_fsize-1; j >= filsys.s_isize; --j)
X    {
X	if (bitmap[j] == 0)
X	{
X	    if (filsys.s_nfree == 50)
X	    {
X		dwrite(j, (char *)&filsys.s_nfree);
X		filsys.s_nfree = 0;
X	    }
X
X	    ++filsys.s_tfree;
X	    filsys.s_free[(filsys.s_nfree)++] = j;
X	}
X    }
X
X    dwrite((blkno_t)1,(char *)&filsys);
X
X    if (oldtfree != filsys.s_tfree)
X	printf("During free list regeneration s_tfree was changed to %d from %d.\n",
X		filsys.s_tfree, oldtfree);
X
X}
X
X
X
X/* Pass 3 finds and fixes multiply allocated blocks. */
Xpass3()
X{
X    uint16 n;
X    struct dinode ino;
X    uint16 mode;
X    blkno_t b;
X    blkno_t bno;
X    blkno_t newno;
X    blkno_t blk_alloc();
X    blkno_t getblkno();
X
X    for (b = filsys.s_isize; b < filsys.s_fsize; ++b)
X	bitmap[b] = 0;
X
X    for (n = ROOTINODE; n < 8*(filsys.s_isize-2); ++n)
X    {
X	iread(n, &ino);
X
X	mode = ino.i_mode & F_MASK;
X	if (mode != F_REG && mode != F_DIR)
X	    continue;
X
X	/* Check singly indirect blocks */
X
X	for (b=18; b < 20; ++b)
X	{
X	    if (ino.i_addr[b] != 0)
X	    {
X		if (bitmap[ino.i_addr[b]] != 0)
X		{
X		    printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ", b, n, ino.i_addr[b]);
X		    if (yes())
X		    {
X			newno = blk_alloc(&filsys);
X			if (newno == 0)
X			    printf("Sorry... No more free blocks.\n");
X			else
X			{
X			    dwrite(newno,daread(ino.i_addr[b]));
X			    ino.i_addr[b] = newno;
X			    iwrite(n, &ino);
X			}
X		    }
X		}
X		else
X		    bitmap[ino.i_addr[b]] = 1;
X	    }
X	}
X
X	/* Check the rest */
X	for (bno=0; bno <= ino.i_size.o_blkno; ++bno)
X	{
X	    b = getblkno(&ino, bno);
X
X	    if (b != 0)
X	    {
X		if (bitmap[b] != 0)
X		{
X		    printf("Block %d in inode %u value %u multiply allocated. Fix? ",
X		    	    bno, n, b);
X		    if (yes())
X		    {
X			newno = blk_alloc(&filsys);
X			if (newno == 0)
X			    printf("Sorry... No more free blocks.\n");
X			else
X			{
X			    dwrite(newno,daread(b));
X			    setblkno(&ino, bno, newno);
X			    iwrite(n, &ino);
X			}
X		    }
X		}
X		else
X		    bitmap[b] = 1;
X	    }
X	}
X
X    }
X
X}
X
Xint depth;
X
X/* Pass 4 traverses the directory tree, fixing bad directory entries
Xand finding the actual number of references to each inode. */
X
Xpass4()
X{
X    depth = 0;
X    linkmap[ROOTINODE] = 1;
X    ckdir(ROOTINODE,ROOTINODE,"/");
X    if (depth != 0)
X	panic("Inconsistent depth");
X}
X
X
X
X/* This recursively checks the directories */
Xckdir(inum, pnum, name)
Xuint16 inum;
Xuint16 pnum;
Xchar *name;
X{
X    struct dinode ino;
X    struct direct dentry;
X    uint16 j;
X    int c;
X    int nentries;
X    char ename[150];
X
X    iread(inum, &ino);
X    if ((ino.i_mode & F_MASK) != F_DIR)
X	return;
X    ++depth;
X
X    if (ino.i_size.o_offset % 16 != 0)
X    {
X	printf("Directory inode %d has improper length. Fix? ");
X	if (yes())
X	{
X	    ino.i_size.o_offset &= (~0x0f);
X	    ++ino.i_size.o_offset;
X	    iwrite(inum, &ino);
X	}
X    }
X
X    nentries = 8*ino.i_size.o_blkno + ino.i_size.o_offset/16;
X
X    for (j=0; j < nentries; ++j)
X    {
X	dirread(&ino, j, &dentry);
X
X	if (dentry.d_ino == 0)
X	    continue;
X
X	if (dentry.d_ino < ROOTINODE || dentry.d_ino >= 8*filsys.s_isize)
X	{
X	    printf("Directory entry %s%-1.14s has out-of-range inode %u. Zap? ",
X		   name, dentry.d_name, dentry.d_ino);
X	    if (yes())
X	    {
X		dentry.d_ino = 0;
X		dentry.d_name[0] = '\0';
X		dirwrite(&ino, j, &dentry);
X		continue;
X	    }
X	}
X
X	if (dentry.d_ino && linkmap[dentry.d_ino] == -1)
X	{
X	    printf("Directory entry %s%-1.14s points to bogus inode %u. Zap? ",
X		   name, dentry.d_name, dentry.d_ino);
X	    if (yes())
X	    {
X		dentry.d_ino = 0;
X		dentry.d_name[0] = '\0';
X		dirwrite(&ino, j, &dentry);
X		continue;
X	    }
X	}
X
X	++linkmap[dentry.d_ino];
X
X	for (c=0; c<14 && dentry.d_name[c]; ++c)
X	{
X	    if (dentry.d_name[c] == '/')
X	    {
X		printf("Directory entry %s%-1.14s contains slash. Fix? ",
X		       name, dentry.d_name);
X		if (yes())
X		{
X		    dentry.d_name[c] = 'X';
X		    dirwrite(&ino, j, &dentry);
X		}
X	    }
X	}
X
X	if (strncmp(dentry.d_name,".",14) == 0 && dentry.d_ino != inum)
X	{
X	    printf("Dot entry %s%-1.14s points to wrong place. Fix? ",
X		   name, dentry.d_name);
X	    if (yes())
X	    {
X		dentry.d_ino = inum;
X		dirwrite(&ino, j, &dentry);
X	    }
X	}
X
X	if (strncmp(dentry.d_name,"..",14) == 0 && dentry.d_ino != pnum)
X	{
X	    printf("DotDot entry %s%-1.14s points to wrong place. Fix? ",
X		   name, dentry.d_name);
X	    if (yes())
X	    {
X		dentry.d_ino = pnum;
X		dirwrite(&ino, j, &dentry);
X	    }
X	}
X
X	if (dentry.d_ino != pnum && dentry.d_ino != inum && depth < MAXDEPTH) 
X	{
X	    strcpy(ename,name);
X	    strcat(ename,dentry.d_name);
X	    strcat(ename,"/");
X	    ckdir(dentry.d_ino,inum,ename);
X	}
X    }
X    --depth;
X}
X
X
X/* Pass 5 compares the link counts found in pass 4 with the inodes. */
X
Xpass5()
X{
X    uint16 n;
X    struct dinode ino;
X
X    for (n = ROOTINODE; n < 8*(filsys.s_isize-2); ++n)
X    {
X	iread(n, &ino);
X
X	if (ino.i_mode == 0)
X	{
X	    if (linkmap[n] != -1)
X		panic("Inconsistent linkmap");
X	    continue;
X	}
X
X	if (linkmap[n] == -1 && ino.i_mode != 0)
X	    panic("Inconsistent linkmap");
X
X	if (linkmap[n] > 0 && ino.i_nlink != linkmap[n])
X	{
X	    printf("Inode %d has link count %d should be %d. Fix? ",
X		    n, ino.i_nlink, linkmap[n]);
X	    if (yes())
X	    {
X		ino.i_nlink = linkmap[n];
X		iwrite(n, &ino);
X	    }
X	}
X
X	if (linkmap[n] == 0)
X	{
X	    if ((ino.i_mode&F_MASK) == F_BDEV ||
X	        (ino.i_mode&F_MASK) == F_CDEV ||
X	        (ino.i_size.o_blkno == 0 && ino.i_size.o_offset == 0))
X	    {
X		printf("Useless inode %d with mode 0%o has become detached. Link count is %d. Zap? ",
X			n, ino.i_mode, ino.i_nlink);
X		if (yes())
X		{
X		    ino.i_nlink = 0;
X		    ino.i_mode = 0;
X		    iwrite(n, &ino);
X		    ++filsys.s_tinode;
X		    dwrite((blkno_t)1,(char *)&filsys);
X		}
X	    }
X	    else
X	    {
X		printf("Inode %d has become detached. Link count is %d. Fix? ",
X			n, ino.i_nlink);
X		if (yes())
X		{
X		    ino.i_nlink = 1;
X		    iwrite(n, &ino);
X		    mkentry(n);
X		}
X	    }
X	}
X    }
X}
X
X
X/* This makes an entry in "lost+found" for inode n */
X
Xmkentry(inum)
Xuint16 inum;
X{
X    struct dinode rootino;
X    struct direct dentry;
X    uint16 d;
X
X    iread(ROOTINODE,&rootino);
X    for (d=0; d < 32*rootino.i_size.o_blkno + rootino.i_size.o_offset/16; ++d)
X    {
X	dirread(&rootino,d,&dentry);
X	if (dentry.d_ino == 0 && dentry.d_name[0] == '\0')
X	{
X	   dentry.d_ino = inum;
X	   sprintf(dentry.d_name,"l+f%d",inum);
X	   dirwrite(&rootino,d,&dentry);
X	   return;
X	}
X    }
X    printf("Sorry... No empty slots in root directory.\n");
X}
X
X/* Beginning of fsck1.c */
X
X/* Getblkno gets a pointer index, and a number of a block in the file.
XIt returns the number of the block on the disk.  A value of zero
Xmeans an unallocated block. */
X
Xchar *daread();
X
Xblkno_t 
Xgetblkno(ino,num)
Xstruct dinode *ino;
Xblkno_t num;
X{
X
X    blkno_t indb;
X    blkno_t dindb;
X    blkno_t *buf;
X
X    if (num < 18) /* Direct block */
X    {
X	return(ino->i_addr[num]);
X    }
X
X    if (num < 256+18)  /* Single indirect */
X    {
X	indb = ino->i_addr[18];
X	if (indb==0)
X	    return(0);
X	buf = (blkno_t *)daread(indb);
X	return(buf[num - 18]);
X    }
X
X    /* Double indirect */
X    indb = ino->i_addr[19];
X    if(indb==0)
X	return(0);
X
X    buf = (blkno_t *)daread(indb);
X
X    dindb = buf[ (num-(18+256)) >> 8];
X    buf = (blkno_t *)daread(dindb);
X
X    return(buf[ (num-(18+256)) & 0x00ff]);
X}
X
X
X/* Setblkno sets the given block number of the given file to the given
Xdisk block number, possibly creating or modifiying the indirect blocks.
XA return of zero means there were no blocks available to create an 
Xindirect block. This should never happen in fsck. */
X
X
Xsetblkno(ino,num,dnum)
Xstruct dinode *ino;
Xblkno_t num;
Xblkno_t dnum;
X{
X
X    blkno_t indb;
X    blkno_t dindb;
X    blkno_t *buf;
X    char *zerobuf();
X
X
X    if (num < 18) /* Direct block */
X    {
X	ino->i_addr[num] = dnum;
X    }
X    else if (num < 256+18)  /* Single indirect */
X    {
X	indb = ino->i_addr[18];
X	if (indb==0)
X	    panic("Missing indirect block");
X
X	buf = (blkno_t *)daread(indb);
X	buf[num - 18] = dnum;
X	dwrite(indb,(char *)buf);
X    }
X    else /* Double indirect */
X    {
X	indb = ino->i_addr[19];
X	if (indb == 0)
X	    panic("Missing indirect block");
X
X	buf = (blkno_t *)daread(indb);
X	dindb = buf[ (num-(18+256)) >> 8];
X	if (dindb==0)
X	    panic("Missing indirect block");
X
X	buf = (blkno_t *)daread(dindb);
X	buf[ (num-(18+256)) & 0x00ff] = num;
X	dwrite(indb,(char *)buf);
X    }
X
X}
X
X
X/* Blk_alloc allocates an unused block.
XA returned block number of zero means no more blocks. */
X
Xblkno_t
Xblk_alloc(filsys)
Xstruct filesys *filsys;
X{
X
X    blkno_t newno;
X    blkno_t *buf;
X    int16 j;
X
X    newno = filsys->s_free[--filsys->s_nfree];
X    ifnot (newno)
X    {
X	++filsys->s_nfree;
X	return(0);
X    }
X
X    /* See if we must refill the s_free array */
X
X    ifnot (filsys->s_nfree)
X    {
X	buf = (blkno_t *)daread(newno);
X	filsys->s_nfree = buf[0];
X	for (j=0; j < 50; j++)
X	{
X	    filsys->s_free[j] = buf[j+1];
X	}
X    }
X
X    --filsys->s_tfree;
X
X    if (newno < filsys->s_isize || newno >= filsys->s_fsize)
X    {
X	printf("Free list is corrupt.  Did you rebuild it?\n");
X	return(0);
X    }
X
X    dwrite((blkno_t)1,(char *)filsys);
X    return(newno);
X}
X
X
X
Xchar *
Xdaread(blk)
Xuint16 blk;
X{
X    char *buf;
X    if (da_read(dev,blk,&buf) != 512)
X    {
X        fprintf(stderr,"Read of block %d failed.\n",blk);
X        abort();
X    }
X    return(buf);
X}
X
X
X
Xdwrite(blk, addr)
Xuint16 blk;
Xchar *addr;
X{
X    if (d_write(dev,blk,addr) != 512)
X    {
X        fprintf(stderr,"Write of block %d failed.\n",blk);
X        abort();
X    }
X}
X    
X    
X
Xiread(ino, buf)
Xuint16 ino;
Xstruct dinode *buf;
X{
X    struct dinode *addr;
X
X    addr = (struct dinode *) daread((ino>>3) + 2);
X    bcopy((char *)&addr[ino & 7], (char *)buf, sizeof(struct dinode));
X}
X
X
Xiwrite(ino, buf)
Xuint16 ino;
Xstruct dinode *buf;
X{
X    struct dinode *addr;
X
X    addr = (struct dinode *) daread((ino>>3) + 2);
X    bcopy((char *)buf, (char *)&addr[ino & 7], sizeof(struct dinode));
X    dwrite((ino>>3) + 2,(char *)addr);
X}
X
X
Xdirread(ino, j, dentry)
Xstruct dinode *ino;
Xuint16 j;
Xstruct direct *dentry;
X{
X    blkno_t blkno;
X    char *buf;
X
X    blkno = getblkno(ino,(blkno_t)j/32);
X    if (blkno == 0)
X	panic("Missing block in directory");
X    buf = daread(blkno);
X    bcopy(buf+(16*j), (char *)dentry, 16);
X}
X
X
Xdirwrite(ino, j, dentry)
Xstruct dinode *ino;
Xuint16 j;
Xstruct direct *dentry;
X{
X    blkno_t blkno;
X    char *buf;
X
X    blkno = getblkno(ino,(blkno_t)j/32);
X    if (blkno == 0)
X	panic("Missing block in directory");
X    buf = daread(blkno);
X    bcopy((char *)dentry, buf+(16*j), 16);
X    dwrite(blkno,buf);
X}
X
X
Xyes()
X{
X    char line[20];
X
X    if (!fgets(line,sizeof(line),stdin) || (*line != 'y' && *line != 'Y'))
X	return(0);
X
X    return(1);
X}
X
X
EOF_fsck.c
echo 'Done'

echo -n 'Extracting xdevtty.c ... '
sed 's/^X//' > xdevtty.c << 'EOF_xdevtty.c'
X
X/**************************************************
XUZI (Unix Z80 Implementation) Utilities:  xdevtty.c
X***************************************************/
X
X
X#include "unix.h"
X#include "extern.h"
X
X#define LINESIZ 128
X
Xstatic char line[LINESIZ];
X
Xtty_read(minor, rawflag)
Xint16 minor;
Xint rawflag;
X{
X    int nread;
X
X    line[0] = udata.u_count;
X    line[1] = 0;
X    bdos(10,line);  /* Read console buffer */
X    bdos(2,'\n');
X    nread = line[1];
X    line[nread+2] = '\n';
X    bcopy(line+2,udata.u_base,nread+1);
X    return(nread+1);
X}
X
X
Xtty_write(minor, rawflag)
Xint16 minor;
Xint rawflag;
X{
X    while (udata.u_count-- != 0)
X    {
X        if (*udata.u_base=='\n')
X	    bdos(2,'\r');
X        bdos(2,*udata.u_base);
X	++udata.u_base;
X    }
X}
X
X
X_putc(c)
Xint c;
X{
X    bdos(2,c);
X}
X
X
Xtty_open(minor)
Xint minor;
X{
X    return(0);
X}
X
X
Xtty_close(minor)
Xint minor;
X{
X    return(0);
X}
X
X
Xtty_ioctl(minor)
Xint minor;
X{
X    return(-1);
X}
EOF_xdevtty.c
echo 'Done'

echo -n 'Extracting bd.c ... '
sed 's/^X//' > bd.c << 'EOF_bd.c'
X
X/**************************************************
XUZI (Unix Z80 Implementation) Utilities:  bd.c
X***************************************************/
X
X
X#include <stdio.h>
X#include "unix.h"
X#include "extern.h"
X
X/* Block dump: to examine hard disk.
X
XUsage:  bd dev blkno
X
X************************************************** */
X
Xchar buf[512];
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    int i,j;
X    unsigned blkno;
X    int dev;
X
X    if (argc != 3 || !isdigit(argv[1][0]))
X    {
X	fprintf(stderr,"Usage: bd device blkno\n");
X	exit(1);
X    }
X
X    dev = atoi(argv[1]);
X    blkno = atoi(argv[2]);
X	bufinit();
X    d_open(dev);
X
X    dread(dev,blkno,buf);
X
X    for (i=0; i < 512/24; ++i)
X    {
X	printf("%4x  ",24*i);
X	for (j=0; j < 24; ++j)
X	{
X	    if (( buf[24*i+j]&0x00ff) < 16)
X	        printf("0%1x ",buf[24*i + j] & 0x00ff);
X	    else
X	        printf("%2x ",buf[24*i + j] & 0x00ff);
X	}
X	printf("\n");
X    }  
X    
X    exit(0);
X}
X
X
X
Xdread(dev, blk, addr)
Xint dev;
Xuint16 blk;
Xchar *addr;
X{
X    char *buf;
X    char *bread();
X
X    buf = bread(dev, blk, 0);
X    bcopy(buf, addr, 512);
X    bfree(buf, 0);
X}
EOF_bd.c
echo 'Done'

echo -n 'Extracting mkfs.c ... '
sed 's/^X//' > mkfs.c << 'EOF_mkfs.c'
X
X/**************************************************
XUZI (Unix Z80 Implementation) Utilities:  mkfs.c
X***************************************************/
X
X
X#include <stdio.h>
X#include "unix.h";
X#include "extern.h"
X
X/* This makes a filesystem */
X
Xint dev;
X
Xextern char zerobuf();
Xdirect dirbuf[32] = { ROOTINODE,".",ROOTINODE,".." };
Xstruct dinode inode[8];
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    uint16 fsize, isize;
X
X    if (argc != 4)
X    {
X	printf("Usage: mkfs device isize fsize\n");
X	exit(-1);
X    }
X
X    dev = atoi(argv[1]);
X    isize = (uint16)atoi(argv[2]);
X    fsize = (uint16)atoi(argv[3]);
X
X    if (dev == 0 && argv[1][0] != '0')
X    {
X	printf("Invalid device\n");
X	exit(-1);
X    }
X    if (dev < 0 || dev >= NDEVS)
X    {
X	printf("Invalid device\n");
X	exit(-1);
X    }
X
X    if (fsize < 3 || isize < 2 || isize >= fsize)
X    {
X	printf("Bad parameter values\n");
X	exit(-1);
X    }
X
X
X    printf("Making filesystem on device %d with isize %u fsize %u. Confirm? ",
X	    dev,isize,fsize);
X    if (!yes())
X	exit(-1);
X
X	bufinit();
X    if (d_open(dev))
X    {
X	printf("Can't open device");
X	exit(-1);
X    }
X
X    mkfs(fsize,isize);
X	bufsync();
X    exit(0);
X}
X
X
X
X
Xmkfs(fsize, isize)
Xuint16 fsize, isize;
X{
X    uint16 j;
X
X    /* Zero out the blocks */
X
X#ifdef CPM
X    for (j=0; j < isize; ++j)   /* Don't waste time in CPM */
X	dwrite(j,zerobuf());
X#else
X    for (j=0; j < fsize; ++j)
X	dwrite(j,zerobuf());
X#endif
X
X    /* Initialize the super-block */
X
X    fs_tab[dev].s_mounted = SMOUNTED; /* Magic number */
X    fs_tab[dev].s_isize =  isize;
X    fs_tab[dev].s_fsize =  fsize;
X    fs_tab[dev].s_nfree =  1;
X    fs_tab[dev].s_free[0] =  0;
X    fs_tab[dev].s_tfree =  0;
X    fs_tab[dev].s_ninode = 0;
X    fs_tab[dev].s_tinode =  8 * (isize-2) - 2;
X
X    /* Free each block, building the free list */
X
X    for (j= fsize-1; j >= isize+1; --j)
X    {
X	if (fs_tab[dev].s_nfree == 50)
X	{
X	    dwrite(j, (char *)&fs_tab[dev].s_nfree);
X	    fs_tab[dev].s_nfree = 0;
X	}
X
X	++fs_tab[dev].s_tfree;
X	fs_tab[dev].s_free[(fs_tab[dev].s_nfree)++] = j;
X    }
X
X    /* The inodes are already zeroed out */
X    /* create the root dir */
X
X
X    inode[ROOTINODE].i_mode = F_DIR | (0777 & MODE_MASK);
X    inode[ROOTINODE].i_nlink = 3;
X    inode[ROOTINODE].i_size.o_blkno = 0;
X    inode[ROOTINODE].i_size.o_offset = 32;
X    inode[ROOTINODE].i_addr[0] = isize;
X
X    /* Reserve reserved inode */
X    inode[0].i_nlink = 1;
X    inode[0].i_mode = ~0;
X
X    dwrite(2,(char *)inode);
X
X    dwrite(isize,(char *)dirbuf);
X
X    /* Write out super block */
X    dwrite(1,(char *)&fs_tab[dev]);
X}
X
X
X
Xdwrite(blk, addr)
Xuint16 blk;
Xchar *addr;
X{
X    char *buf;
X    char *bread();
X
X    buf = bread(dev, blk, 1);
X    bcopy(addr, buf, 512);
X    bfree(buf, 1);
X}
X    
X
Xyes()
X{
X    char line[20];
X
X    if (!fgets(line,sizeof(line),stdin) || (*line != 'y' && *line != 'Y'))
X	return(0);
X
X    return(1);
X}
X
EOF_mkfs.c
echo 'Done'

echo -n 'Extracting unix.azm ... '
sed 's/^X//' > unix.azm << 'EOF_unix.azm'
X; Loader program for UZI image
X
X.pabs
X.loc 100h
X
Xlxi     sp,0100h
Xlxi     d,fcb
Xmvi     c,0fh
Xcall 5
Xcpi 0ffh
Xjz 0000         ;open file
X
Xloop:
Xlhld addr
Xxchg
Xmvi     c,1ah
Xcall 5          ;set dma addr
X
Xlxi     d,fcb
Xmvi     c,14h
Xcall 5          ;read
Xana a
Xjnz move
Xlhld addr
Xlxi d,128
Xdad d
Xshld addr
Xjmp loop
X
X
Xmove:
Xlxi     h,8202h
Xlxi     d,0ffffh
Xlxi     b,8010h
Xlddr
X
Xjmp     8000h-3
X
Xaddr: .word 01f8h       ;initial address
Xfcb:    .byte 0
X        .ascii  'UNIX    BIN'
X        .byte 0,0,0,0,0
X        .blkb   16
X
X
X
X.end
X
X11A>
EOF_unix.azm
echo 'Done'

echo -n 'Extracting loadutil.sub ... '
sed 's/^X//' > loadutil.sub << 'EOF_loadutil.sub'
Xb:l80 $1,a:devio,xdevtty,xmachdep,a:devwd,a:devflop,a:devmisc,a:data,a:extras,xfs/s,b:libqcc/s,$1/n/y/e
X
EOF_loadutil.sub
echo 'Done'

echo -n 'Extracting filflop.sub ... '
sed 's/^X//' > filflop.sub << 'EOF_filflop.sub'
Xxsub
Xmkfs 1 30 500
Xy
Xpip d:=e:sh[ov]
Xxsub
Xucp 1
Xmkdir /dev
Xcd /dev
Xmknod wd0 060644 0
Xmknod wd1 060644 2
Xmknod wd2 060644 3
Xmknod fd0 060644 1
Xmknod rwd0 020444 0
Xmknod rwd1 020444 2
Xmknod rwd2 020444 3
Xmknod rfd0 020444 1
Xmknod lpr 020222 4
Xmknod null 020666 6
Xmknod mem 020444 7
Xmknod kmem 020444 7
Xmknod rmt 020444 8
Xmknod swap 060644 3
Xcd /
Xmkdir /tmp
Xmkdir /bin
Xbget init
Xchmod init 0755
Xcd bin
Xbget sh
Xchmod sh 0755
Xbget minish
Xchmod minish 0755
Xbget l
Xchmod l 0755
Xbget ls
Xchmod ls 0755
Xbget ps
Xchmod ps 0755
Xbget ed
Xchmod ed 0755
Xbget reboot
Xchmod reboot 0755
Xbget dd
Xchmod dd 0755
Xbget mvdir
Xchmod mvdir 0755
Xbget mv
Xchmod mv 0755
Xbget cat
Xchmod cat 0755
Xbget chmod
Xchmod chmod 0755
Xbget echo
Xchmod echo 0755
Xbget fsck
Xchmod fsck 0755
Xbget kill
Xchmod kill 0755
Xbget lpr
Xchmod lpr 0755
Xbget pwd
Xchmod pwd 0755
Xbget wc
Xchmod wc 0755
Xbget mkdir
Xchmod mkdir 4755
Xbget rm
Xchmod rm 0755
Xbget rmdir
Xchmod rmdir 4755
Xbget printenv
Xchmod printenv 0755
Xbget date
Xchmod date 0755
Xbget ls
Xchmod ls 0755
Xbget sync
Xchmod sync 0755
Xexit
Xunxsub
EOF_filflop.sub
echo 'Done'

echo -n 'Extracting uzi_util.doc ... '
sed 's/^X//' > uzi_util.doc << 'EOF_uzi_util.doc'
X	UZI	UTILITIES
X
XThis package contains several utilities to
Xmanage UZI filesystems from a different host operating
Xsystem.  They have been compiled and used under CP/M
Xto build and repair UZI filesystems, and debug device drivers.
XThis has been useful because UZI was developed
Xand compiled under CP/M.  They have also
Xbeen used under SYS V Unix to debug the UZI filesystem
Xcode (using a Unix file to serve as a virtual UZI device).
X
XThere are four programs, each contained in the C file of the same name:
X
XMKFS: This makes a file system.	 It takes three arguments: a device
Xnumber, the total number of blocks, and the number of inodes.
X
XFSCK: This checks file system consistency.  It takes a single argument,
Xthe device number to check.
X
XBD:	This dumps (in hex) a block of a device.  It takes two arguments:
Xthe device number, and the block number to dump.
X
XUCP: This is an interactive program taht performs a number of operations.
XIt can be used to make and delete directories and device files,
Xupload and download files between the host OS and the UZI filesystem,
Xlist directories, and print files.  It takes a single argument, the
Xdevice number.  It then prompts for commands.  Look at the code for a
Xcomplete list of commands.
X
XEach program is linked with the device drivers for your system,
Xsome files from UZI itself, and some modified versions of other
XUZI files (the ones beginning with "x").  The file "loadutil.sub"
Xshows what needs to be linked.  The files "filfs.sub" and "filflop.sub"
Xare examples of how these utilities are used to build and populate 
XUZI filesystems.
X
XThe file UNIX.AZM is the source (in a obscure Z80 assembly language) for
Xa little program that opens the UZI binary image file, loads it
Xinto memory, and starts it running from CP/M.
X
XIf you are trying to get UZI running on a new system, these programs
Xwill be very helpful in getting your device drivers working, and
Xwill allow UZI to have something on its disks when it finally runs.
EOF_uzi_util.doc
echo 'Done'

echo -n 'Extracting filfs.sub ... '
sed 's/^X//' > filfs.sub << 'EOF_filfs.sub'
Xxsub
Xmkfs 0$1 200 3072
Xy
Xpip d:=e:sh[ov]
Xxsub
Xucp 0$1
Xmkdir /dev
Xcd /dev
Xmknod tty 020666 5
Xmknod wd0 060644 0
Xmknod wd1 060644 2
Xmknod wd2 060644 3
Xmknod fd0 060644 1
Xmknod rwd0 020444 0
Xmknod rwd1 020444 2
Xmknod rwd2 020444 3
Xmknod rfd0 020444 1
Xmknod lpr 020222 4
Xmknod null 020666 6
Xmknod mem 020444 7
Xmknod kmem 020444 7
Xmknod rmt 020444 8
Xmknod swap 060644 3
Xcd /
Xmkdir /tmp
Xmkdir /bin
Xbget init
Xchmod init 0755
Xcd bin
Xbget sh
Xchmod sh 0755
Xbget minish
Xchmod minish 0755
Xbget l
Xchmod l 0755
Xbget ls
Xchmod ls 0755
Xbget ps
Xchmod ps 0755
Xbget ed
Xchmod ed 0755
Xbget reboot
Xchmod reboot 0755
Xbget dd
Xchmod dd 0755
Xbget mvdir
Xchmod mvdir 0755
Xbget mv
Xchmod mv 0755
Xbget cat
Xchmod cat 0755
Xbget chmod
Xchmod chmod 0755
Xbget echo
Xchmod echo 0755
Xbget fork
Xchmod fork 0755
Xbget fsck
Xchmod fsck 0755
Xbget head
Xchmod head 0755
Xbget kill
Xchmod kill 0755
Xbget lpr
Xchmod lpr 0755
Xbget pwd
Xchmod pwd 0755
Xbget mkfs
Xchmod mkfs 0755
Xbget wc
Xchmod wc 0755
Xbget mkdir
Xchmod mkdir 4755
Xbget rm
Xchmod rm 0755
Xbget rmdir
Xchmod rmdir 4755
Xbget tar
Xchmod tar 0755
Xbget printenv
Xchmod printenv 0755
Xbget date
Xchmod date 0755
Xbget ls
Xchmod ls 0755
Xbget sync
Xchmod sync 0755
Xbget mount
Xchmod mount 0755
Xbget time
Xchmod time 0755
Xbget diff
Xchmod diff 0755
Xexit
Xunxsub
EOF_filfs.sub
echo 'Done'

echo -n 'Extracting filelist ... '
sed 's/^X//' > filelist << 'EOF_filelist'
Xxfs.c
Xxmachdep.c
Xucp.c
Xfsck.c
Xxdevtty.c
Xbd.c
Xmkfs.c
Xunix.azm
Xloadutil.sub
Xfilflop.sub
Xuzi_util.doc
Xfilfs.sub
Xfilelist
Xread.me
EOF_filelist
echo 'Done'

echo -n 'Extracting read.me ... '
sed 's/^X//' > read.me << 'EOF_read.me'
XUZI is a UNIX kernel clone written for Z-80 systems.
XAll code is public domain, not being based on any AT&T code.
X
XThis archive is a supplement to the main archive,
Xand contains programs to manipulate UZI file systems
Xfrom a different host operating system.
XThe file UZI_UTILS.DOC contains more information.
X
XThe author, Douglas Braun, can be reached at:
X
X7696 West Zayante Rd.
XFelton, CA 95018
X
Xoliveb!intelca!mipos3!cadev4!dbraun
EOF_read.me
echo 'Done'

exit 0

Doug Braun				Intel Corp CAD
					408 765-4279

 / decwrl \
 | hplabs |
-| oliveb |- !intelca!mipos3!cadev4!dbraun
 | amd    |
 \ qantel /

sme@computing-maths.cardiff.ac.uk (Simon Elliott) (01/13/89)

Did anyone get the UZI utilities part 2/2?  If so, please could someone mail
it?  Thank you in advance.

-- 
--------------------------------------------------------------------------
Simon Elliott            Internet: sme%v1.cm.cf.ac.uk@cunyvm.cuny.edu
UWCC Computer Centre     JANET:    sme@uk.ac.cf.cm.v1
40/41 Park Place         UUCP:     {backbones}!mcvax!ukc!reading!cf-cm!sme
Cardiff, Wales           PHONE:    +44 222 874300