--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <bio.h>
+#include <event.h>
+
+enum {PNCTL=3};
+
+static char* rdenv(char*);
+int newwin(char*);
+Rectangle screenrect(void);
+
+int nokill;
+int textmode;
+char *title;
+
+Image *light;
+Image *dark;
+Image *text;
+
+void
+initcolor(void)
+{
+ text = display->black;
+ light = allocimagemix(display, DPalegreen, DWhite);
+ dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen);
+}
+
+Rectangle rbar;
+Point ptext;
+vlong n, d;
+int last;
+int lastp = -1;
+int first = 1;
+
+char backup[80];
+
+void
+drawbar(void)
+{
+ int i, j;
+ int p;
+ char buf[200], bar[100], *s;
+ static char lastbar[100];
+
+ if(n > d || n < 0 || d <= 0)
+ return;
+
+ i = (Dx(rbar)*n)/d;
+ p = (n*100LL)/d;
+
+ if(textmode){
+ bar[0] = '|';
+ for(j=0; j<i; j++)
+ bar[j+1] = '#';
+ for(; j<60; j++)
+ bar[j+1] = '-';
+ bar[61] = '|';
+ bar[62] = ' ';
+ sprint(bar+63, "%3d%% ", p);
+ for(i=0; bar[i]==lastbar[i] && bar[i]; i++)
+ ;
+ memset(buf, '\b', strlen(lastbar)-i);
+ strcpy(buf+strlen(lastbar)-i, bar+i);
+ if(buf[0])
+ write(1, buf, strlen(buf));
+ strcpy(lastbar, bar);
+ return;
+ }
+
+ if(lastp == p && last == i)
+ return;
+
+ if(lastp != p){
+ sprint(buf, "%d%%", p);
+
+ stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP);
+ lastp = p;
+ }
+
+ if(last != i){
+ draw(screen, Rect(rbar.min.x+last, rbar.min.y, rbar.min.x+i, rbar.max.y),
+ dark, nil, ZP);
+ last = i;
+ }
+ flushimage(display, 1);
+}
+
+void
+eresized(int new)
+{
+ Point p, q;
+ Rectangle r;
+
+ if(new && getwindow(display, Refnone) < 0)
+ fprint(2,"can't reattach to window");
+
+ r = screen->r;
+ draw(screen, r, light, nil, ZP);
+ p = string(screen, addpt(r.min, Pt(4,4)), text, ZP,
+ display->defaultfont, title);
+
+ p.x = r.min.x+4;
+ p.y += display->defaultfont->height+4;
+
+ q = subpt(r.max, Pt(4,4));
+ rbar = Rpt(p, q);
+
+ ptext = Pt(r.max.x-4-stringwidth(display->defaultfont, "100%"), r.min.x+4);
+ border(screen, rbar, -2, dark, ZP);
+ last = 0;
+ lastp = -1;
+
+ drawbar();
+}
+
+void
+bar(Biobuf *b)
+{
+ char *p, *f[2];
+ Event e;
+ int k, die, parent, child;
+
+ parent = getpid();
+
+ die = 0;
+ if(textmode)
+ child = -1;
+ else
+ switch(child = rfork(RFMEM|RFPROC)) {
+ case 0:
+ sleep(1000);
+ while(!die && (k = eread(Ekeyboard|Emouse, &e))) {
+ if(nokill==0 && k == Ekeyboard && (e.kbdc == 0x7F || e.kbdc == 0x03)) { /* del, ctl-c */
+ die = 1;
+ postnote(PNPROC, parent, "interrupt");
+ _exits("interrupt");
+ }
+ }
+ _exits(0);
+ }
+
+ while(!die && (p = Brdline(b, '\n'))) {
+ p[Blinelen(b)-1] = '\0';
+ if(tokenize(p, f, 2) != 2)
+ continue;
+ n = strtoll(f[0], 0, 0);
+ d = strtoll(f[1], 0, 0);
+ drawbar();
+ }
+ postnote(PNCTL, child, "kill");
+}
+
+
+void
+usage(void)
+{
+ fprint(2, "usage: bargraph [-kt] [-w minx,miny,maxx,maxy] 'title'\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ Biobuf b;
+ char *p, *q;
+ int lfd;
+
+ p = "0,0,200,60";
+
+ ARGBEGIN{
+ case 'w':
+ p = ARGF();
+ break;
+ case 't':
+ textmode = 1;
+ break;
+ case 'k':
+ nokill = 1;
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argc != 1)
+ usage();
+
+ title = argv[0];
+
+ lfd = dup(0, -1);
+
+ while(q = strchr(p, ','))
+ *q = ' ';
+ Binit(&b, lfd, OREAD);
+ if(textmode || newwin(p) < 0){
+ textmode = 1;
+ rbar = Rect(0, 0, 60, 1);
+ }else{
+ initdraw(0, 0, "bar");
+ initcolor();
+ einit(Emouse|Ekeyboard);
+ eresized(0);
+ }
+ bar(&b);
+}
+
+
+/* all code below this line should be in the library, but is stolen from colors instead */
+static char*
+rdenv(char *name)
+{
+ char *v;
+ int fd, size;
+
+ fd = open(name, OREAD);
+ if(fd < 0)
+ return 0;
+ size = seek(fd, 0, 2);
+ v = malloc(size+1);
+ if(v == 0){
+ fprint(2, "%s: can't malloc: %r\n", argv0);
+ exits("no mem");
+ }
+ seek(fd, 0, 0);
+ read(fd, v, size);
+ v[size] = 0;
+ close(fd);
+ return v;
+}
+
+int
+newwin(char *win)
+{
+ char *srv, *mntsrv;
+ char spec[100];
+ int srvfd, cons, pid;
+
+ switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){
+ case -1:
+ fprint(2, "bargraph: can't fork: %r\n");
+ return -1;
+ case 0:
+ break;
+ default:
+ exits(0);
+ }
+
+ srv = rdenv("/env/wsys");
+ if(srv == 0){
+ mntsrv = rdenv("/mnt/term/env/wsys");
+ if(mntsrv == 0){
+ fprint(2, "bargraph: can't find $wsys\n");
+ return -1;
+ }
+ srv = malloc(strlen(mntsrv)+10);
+ sprint(srv, "/mnt/term%s", mntsrv);
+ free(mntsrv);
+ pid = 0; /* can't send notes to remote processes! */
+ }else
+ pid = getpid();
+ USED(pid);
+ srvfd = open(srv, ORDWR);
+ free(srv);
+ if(srvfd == -1){
+ fprint(2, "bargraph: can't open %s: %r\n", srv);
+ return -1;
+ }
+ sprint(spec, "new -r %s", win);
+ if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){
+ fprint(2, "bargraph: can't mount /mnt/wsys: %r (spec=%s)\n", spec);
+ return -1;
+ }
+ close(srvfd);
+ unmount("/mnt/acme", "/dev");
+ bind("/mnt/wsys", "/dev", MBEFORE);
+ cons = open("/dev/cons", OREAD);
+ if(cons==-1){
+ NoCons:
+ fprint(2, "bargraph: can't open /dev/cons: %r");
+ return -1;
+ }
+ dup(cons, 0);
+ close(cons);
+ cons = open("/dev/cons", OWRITE);
+ if(cons==-1)
+ goto NoCons;
+ dup(cons, 1);
+ dup(cons, 2);
+ close(cons);
+// wctlfd = open("/dev/wctl", OWRITE);
+ return 0;
+}
+
+Rectangle
+screenrect(void)
+{
+ int fd;
+ char buf[12*5];
+
+ fd = open("/dev/screen", OREAD);
+ if(fd == -1)
+ fd=open("/mnt/term/dev/screen", OREAD);
+ if(fd == -1){
+ fprint(2, "%s: can't open /dev/screen: %r\n", argv0);
+ exits("window read");
+ }
+ if(read(fd, buf, sizeof buf) != sizeof buf){
+ fprint(2, "%s: can't read /dev/screen: %r\n", argv0);
+ exits("screen read");
+ }
+ close(fd);
+ return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
+}
+
+int
+postnote(int group, int pid, char *note)
+{
+ char file[128];
+ int f, r;
+
+ switch(group) {
+ case PNPROC:
+ sprint(file, "/proc/%d/note", pid);
+ break;
+ case PNGROUP:
+ sprint(file, "/proc/%d/notepg", pid);
+ break;
+ case PNCTL:
+ sprint(file, "/proc/%d/ctl", pid);
+ break;
+ default:
+ return -1;
+ }
+
+ f = open(file, OWRITE);
+ if(f < 0)
+ return -1;
+
+ r = strlen(note);
+ if(write(f, note, r) != r) {
+ close(f);
+ return -1;
+ }
+ close(f);
+ return 0;
+}
--- /dev/null
+/*
+ * Extraordinarily brute force Lempel & Ziv-like
+ * compressor. The input file must fit in memory
+ * during compression, and the output file will
+ * be reconstructed in memory during decompression.
+ * We search for large common sequences and use a
+ * greedy algorithm to choose which sequence gets
+ * compressed first.
+ *
+ * Files begin with "BLZ\n" and a 32-bit uncompressed file length.
+ *
+ * Output format is a series of blocks followed by
+ * a raw data section. Each block begins with a 32-bit big-endian
+ * number. The top bit is type and the next 31 bits
+ * are uncompressed size. Type is one of
+ * 0 - use raw data for this length
+ * 1 - a 32-bit offset follows
+ * After the blocks come the raw data. (The end of the blocks can be
+ * noted by summing block lengths until you reach the file length.)
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#define malloc sbrk
+
+int minrun = 16;
+int win = 16;
+ulong outn;
+int verbose;
+int mindist;
+
+enum { Prime = 16777213 }; /* smallest prime < 2^24 (so p*256+256 < 2^32) */
+enum { NOFF = 3 };
+
+Biobuf bout;
+ulong length;
+uchar *data;
+ulong sum32(ulong, void*, long);
+uchar *odat;
+int nodat;
+int nraw;
+int rawstart;
+int acct;
+int zlength;
+int maxchain;
+int maxrle[256];
+int nnew;
+
+typedef struct Node Node;
+struct Node {
+ Node *link;
+ ulong key;
+ ulong offset[NOFF];
+};
+
+Node *nodepool;
+int nnodepool;
+
+Node **hash;
+uint nhash;
+
+uint maxlen;
+uint maxsame;
+uint replacesame = 8*1024*1024;
+
+Node *freelist, **freeend;
+uint nalloc;
+
+Node*
+allocnode(void)
+{
+ int i;
+ Node *n;
+
+ if(nnodepool == 0){
+ nnodepool = 256*1024;
+ nodepool = malloc(sizeof(Node)*nnodepool);
+ }
+ if(freelist){
+ n = freelist;
+ freelist = n->link;
+ return n;
+ }
+ assert(nnodepool > 0);
+ nalloc++;
+ n = &nodepool[--nnodepool];
+ for(i=0; i<NOFF; i++)
+ n->offset[i] = -1;
+
+ return n;
+}
+
+void
+freenode(Node *n)
+{
+ if(freelist == nil)
+ freelist = n;
+ else
+ *freeend = n;
+ freeend = &n->link;
+ n->link = nil;
+}
+
+Node**
+llookup(ulong key)
+{
+ uint c;
+ Node **l, **top, *n;
+
+ if(nhash == 0){
+ uint x;
+
+ x = length/8;
+ for(nhash=1; nhash<x; nhash<<=1)
+ ;
+ hash = sbrk(sizeof(Node*)*nhash);
+ }
+
+ top = &hash[key&(nhash-1)];
+ c = 0;
+ for(l=top; *l; l=&(*l)->link){
+ c++;
+ if((*l)->key == key){
+ /* move to front */
+ n = *l;
+ *l = n->link;
+ n->link = *top;
+ *top = n;
+ return top;
+ }
+ }
+ if(c > maxlen)
+ maxlen = c;
+ return l;
+}
+
+Node*
+lookup(ulong key)
+{
+ return *llookup(key);
+}
+
+void
+insertnode(ulong key, ulong offset)
+{
+ int i;
+ Node *n, **l;
+
+ l = llookup(key);
+ if(*l == nil){
+ if(l==&hash[key&(nhash-1)])
+ nnew++;
+ *l = allocnode();
+ (*l)->key = key;
+ }
+ n = *l;
+
+ /* add or replace last */
+ for(i=0; i<NOFF-1 && n->offset[i]!=-1; i++)
+ ;
+ n->offset[i] = offset;
+}
+
+void
+Bputint(Biobufhdr *b, int n)
+{
+ uchar p[4];
+
+ p[0] = n>>24;
+ p[1] = n>>16;
+ p[2] = n>>8;
+ p[3] = n;
+ Bwrite(b, p, 4);
+}
+
+void
+flushraw(void)
+{
+ if(nraw){
+ if(verbose)
+ fprint(2, "Raw %d+%d\n", rawstart, nraw);
+ zlength += 4+nraw;
+ Bputint(&bout, (1<<31)|nraw);
+ memmove(odat+nodat, data+rawstart, nraw);
+ nodat += nraw;
+ nraw = 0;
+ }
+}
+
+int
+rawbyte(int i)
+{
+ assert(acct == i);
+ if(nraw == 0)
+ rawstart = i;
+ acct++;
+ nraw++;
+ return 1;
+}
+
+int
+refblock(int i, int len, int off)
+{
+ assert(acct == i);
+ acct += len;
+ if(nraw)
+ flushraw();
+ if(verbose)
+ fprint(2, "Copy %d+%d from %d\n", i, len, off);
+ Bputint(&bout, len);
+ Bputint(&bout, off);
+ zlength += 4+4;
+ return len;
+}
+
+int
+cmprun(uchar *a, uchar *b, int len)
+{
+ int i;
+
+ if(a==b)
+ return 0;
+ for(i=0; i<len && a[i]==b[i]; i++)
+ ;
+ return i;
+}
+
+int
+countrle(uchar *a)
+{
+ int i;
+
+ for(i=0; a[i]==a[0]; i++)
+ ;
+ return i;
+}
+
+void
+compress(void)
+{
+ int best, i, j, o, rle, run, maxrun, maxoff;
+ ulong sum;
+ Node *n;
+
+ sum = 0;
+ for(i=0; i<win && i<length; i++)
+ sum = (sum*256+data[i])%Prime;
+ for(i=0; i<length-win; ){
+ maxrun = 0;
+ maxoff = 0;
+ if(verbose)
+ fprint(2, "look %.6lux\n", sum);
+ n = lookup(sum);
+ if(n){
+ best = -1;
+ for(o=0; o<NOFF; o++){
+ if(n->offset[o] == -1)
+ break;
+ run = cmprun(data+i, data+n->offset[o], length-i);
+ if(run > maxrun && n->offset[o]+mindist < i){
+ maxrun = run;
+ maxoff = n->offset[o];
+ best = o;
+ }
+ }
+ if(best > 0){
+ o = n->offset[best];
+ for(j=best; j>0; j--)
+ n->offset[j] = n->offset[j-1];
+ n->offset[0] = o;
+ }
+ }
+
+ if(maxrun >= minrun)
+ j = i+refblock(i, maxrun, maxoff);
+ else
+ j = i+rawbyte(i);
+ for(; i<j; i++){
+ /* avoid huge chains from large runs of same byte */
+ rle = countrle(data+i);
+ if(rle<4)
+ insertnode(sum, i);
+ else if(rle>maxrle[data[i]]){
+ maxrle[data[i]] = rle;
+ insertnode(sum, i);
+ }
+ sum = (sum*256+data[i+win]) % Prime;
+ sum = (sum + data[i]*outn) % Prime;
+ }
+ }
+ /* could do better here */
+ for(; i<length; i++)
+ rawbyte(i);
+ flushraw();
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: bflz [-n winsize] [file]\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd, i, n;
+ char buf[10485760];
+
+ ARGBEGIN{
+ case 'd':
+ verbose = 1;
+ break;
+ case 's':
+ replacesame = atoi(EARGF(usage()));
+ break;
+ case 'm':
+ mindist = atoi(EARGF(usage()));
+ break;
+ case 'n':
+ win = atoi(EARGF(usage()));
+ minrun = win;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ switch(argc){
+ default:
+ usage();
+ case 0:
+ fd = 0;
+ break;
+ case 1:
+ if((fd = open(argv[0], OREAD)) < 0)
+ sysfatal("open %s: %r", argv[0]);
+ break;
+ }
+
+ while((n = readn(fd, buf, sizeof buf)) > 0){
+ data = realloc(data, length+n);
+ if(data == nil)
+ sysfatal("realloc: %r");
+ memmove(data+length, buf, n);
+ length += n;
+ if(n < sizeof buf)
+ break;
+ }
+ odat = malloc(length);
+ if(odat == nil)
+ sysfatal("malloc: %r");
+
+ Binit(&bout, 1, OWRITE);
+ Bprint(&bout, "BLZ\n");
+ Bputint(&bout, length);
+ outn = 1;
+ for(i=0; i<win; i++)
+ outn = (outn * 256) % Prime;
+
+ if(verbose)
+ fprint(2, "256^%d = %.6lux\n", win, outn);
+ outn = Prime - outn;
+ if(verbose)
+ fprint(2, "outn = %.6lux\n", outn);
+
+ compress();
+ Bwrite(&bout, odat, nodat);
+ Bterm(&bout);
+ fprint(2, "brk %p\n", sbrk(1));
+ fprint(2, "%d nodes used; %d of %d hash slots used\n", nalloc, nnew, nhash);
+ exits(nil);
+}
--- /dev/null
+int unbzip(int);
+void _unbzip(int, int);
+int unbflz(int);
+int xexpand(int);
+void *emalloc(ulong);
+void *erealloc(void*, ulong);
+char *estrdup(char*);
+
+void ramfsmain(int, char**);
+extern int chatty;
+void error(char*, ...);
--- /dev/null
+/*
+ * bzip2-based file system.
+ * the file system itself is just a bzipped2 xzipped mkfs archive
+ * prefixed with "bzfilesystem\n" and suffixed with
+ * a kilobyte of zeros.
+ *
+ * changes to the file system are only kept in
+ * memory, not written back to the disk.
+ *
+ * this is intended for use on a floppy boot disk.
+ * we assume the file is in the dos file system and
+ * contiguous on the disk: finding it amounts to
+ * looking at the beginning of each sector for
+ * "bzfilesystem\n". then we pipe it through
+ * bunzip2 and store the files in a file tree in memory.
+ * things are slightly complicated by the fact that
+ * devfloppy requires reads to be on a 512-byte
+ * boundary and be a multiple of 512 bytes; we
+ * fork a process to relieve bunzip2 of this restriction.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <auth.h>
+#include <fcall.h>
+#include "bzfs.h"
+
+enum{
+ LEN = 8*1024,
+ NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
+};
+
+void mkdirs(char*, char*);
+void mkdir(char*, ulong, ulong, char*, char*);
+void extract(char*, ulong, ulong, char*, char*, ulong);
+void seekpast(ulong);
+void error(char*, ...);
+void warn(char*, ...);
+void usage(void);
+char *mtpt;
+Biobufhdr bin;
+uchar binbuf[2*LEN];
+
+void
+usage(void)
+{
+ fprint(2, "usage: bzfs [-m mtpt] [-s] [-f file] [-h]\n");
+ exits("usage");
+}
+
+/*
+ * floppy disks can only be read on 512-byte
+ * boundaries and in 512 byte multiples.
+ * feed one over a pipe to allow arbitrary reading.
+ */
+char zero[512];
+int
+blockread(int in, char *first, int nfirst)
+{
+ int p[2], out, n, rv;
+ char blk[512];
+
+ if(pipe(p) < 0)
+ sysfatal("pipe: %r");
+ rv = p[0];
+ out = p[1];
+ switch(rfork(RFPROC|RFNOTEG|RFFDG)){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ close(rv);
+ break;
+ default:
+ close(in);
+ close(out);
+ return rv;
+ }
+
+ write(out, first, nfirst);
+
+ while((n=read(in, blk, sizeof blk)) > 0){
+ if(write(out, blk, n) != n)
+ break;
+ if(n == sizeof(blk) && memcmp(zero, blk, n) == n)
+ break;
+ }
+ _exits(0);
+ return -1;
+}
+
+enum { NAMELEN = 28 };
+
+void
+main(int argc, char **argv)
+{
+ char *rargv[10];
+ int rargc;
+ char *fields[NFLDS], name[2*LEN], *p, *namep;
+ char uid[NAMELEN], gid[NAMELEN];
+ ulong mode, bytes, mtime;
+ char *file;
+ int i, n, stdin, fd, chatty;
+ char blk[512];
+
+ if(argc>1 && strcmp(argv[1], "RAMFS") == 0){
+ argv[1] = argv[0];
+ ramfsmain(argc-1, argv+1);
+ exits(nil);
+ }
+ if(argc>1 && strcmp(argv[1], "BUNZIP") == 0){
+ _unbzip(0, 1);
+ exits(nil);
+ }
+
+ rfork(RFNOTEG);
+ stdin = 0;
+ file = nil;
+ namep = name;
+ mtpt = "/root";
+ chatty = 0;
+ ARGBEGIN{
+ case 'd':
+ chatty = !chatty;
+ break;
+ case 'f':
+ file = ARGF();
+ break;
+ case 's':
+ stdin++;
+ break;
+ case 'm':
+ mtpt = ARGF();
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 0)
+ usage();
+
+ if(file == nil) {
+ fprint(2, "must specify -f file\n");
+ usage();
+ }
+
+ if((fd = open(file, OREAD)) < 0) {
+ fprint(2, "cannot open \"%s\": %r\n", file);
+ exits("open");
+ }
+
+ rargv[0] = "ramfs";
+ rargc = 1;
+ if(stdin)
+ rargv[rargc++] = "-i";
+ rargv[rargc++] = "-m";
+ rargv[rargc++] = mtpt;
+ rargv[rargc] = nil;
+ ramfsmain(rargc, rargv);
+
+ if(1 || strstr(file, "disk")) { /* search for archive on block boundary */
+if(chatty) fprint(2, "searching for bz\n");
+ for(i=0;; i++){
+ if((n = readn(fd, blk, sizeof blk)) != sizeof blk)
+ sysfatal("read %d gets %d: %r\n", i, n);
+ if(strncmp(blk, "bzfilesystem\n", 13) == 0)
+ break;
+ }
+if(chatty) fprint(2, "found at %d\n", i);
+ }
+
+ if(chdir(mtpt) < 0)
+ error("chdir %s: %r", mtpt);
+
+ fd = unbflz(unbzip(blockread(fd, blk+13, sizeof(blk)-13)));
+
+ Binits(&bin, fd, OREAD, binbuf, sizeof binbuf);
+ while(p = Brdline(&bin, '\n')){
+ p[Blinelen(&bin)-1] = '\0';
+if(chatty) fprint(2, "%s\n", p);
+ if(strcmp(p, "end of archive") == 0){
+ _exits(0);
+ }
+ if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){
+ warn("too few fields in file header");
+ continue;
+ }
+ strcpy(namep, fields[0]);
+ mode = strtoul(fields[1], 0, 8);
+ mtime = strtoul(fields[4], 0, 10);
+ bytes = strtoul(fields[5], 0, 10);
+ strncpy(uid, fields[2], NAMELEN);
+ strncpy(gid, fields[3], NAMELEN);
+ if(mode & DMDIR)
+ mkdir(name, mode, mtime, uid, gid);
+ else
+ extract(name, mode, mtime, uid, gid, bytes);
+ }
+ fprint(2, "premature end of archive\n");
+ exits("premature end of archive");
+}
+
+char buf[8192];
+
+int
+ffcreate(char *name, ulong mode, char *uid, char *gid, ulong mtime, int length)
+{
+ int fd, om;
+ Dir nd;
+
+ sprint(buf, "%s/%s", mtpt, name);
+ om = ORDWR;
+ if(mode&DMDIR)
+ om = OREAD;
+ if((fd = create(buf, om, (mode&DMDIR)|0666)) < 0)
+ error("create %s: %r", buf);
+
+ nulldir(&nd);
+ nd.mode = mode;
+ nd.uid = uid;
+ nd.gid = gid;
+ nd.mtime = mtime;
+ if(length)
+ nd.length = length;
+ if(dirfwstat(fd, &nd) < 0)
+ error("fwstat %s: %r", buf);
+
+ return fd;
+}
+
+void
+mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
+{
+ close(ffcreate(name, mode, uid, gid, mtime, 0));
+}
+
+void
+extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes)
+{
+ int fd, tot, n;
+
+ fd = ffcreate(name, mode, uid, gid, mtime, bytes);
+
+ for(tot = 0; tot < bytes; tot += n){
+ n = sizeof buf;
+ if(tot + n > bytes)
+ n = bytes - tot;
+ n = Bread(&bin, buf, n);
+ if(n <= 0)
+ error("premature eof reading %s", name);
+ if(write(fd, buf, n) != n)
+ error("short write writing %s", name);
+ }
+ close(fd);
+}
+
+void
+error(char *fmt, ...)
+{
+ char buf[1024];
+ va_list arg;
+
+ sprint(buf, "%s: ", argv0);
+ va_start(arg, fmt);
+ vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%s\n", buf);
+ exits(0);
+}
+
+void
+warn(char *fmt, ...)
+{
+ char buf[1024];
+ va_list arg;
+
+ sprint(buf, "%s: ", argv0);
+ va_start(arg, fmt);
+ vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%s\n", buf);
+}
+
+int
+_efgfmt(Fmt*)
+{
+ return -1;
+}
--- /dev/null
+</$objtype/mkfile
+
+TARG=bzfs
+
+OFILES=\
+ mkext.$O\
+ oramfs.$O\
+ unbflz.$O\
+ unbzip.$O\
+
+HFILES=bzfs.h
+
+BIN=/sys/lib/dist/bin/$objtype
+LIB=/sys/src/cmd/bzip2/lib/libbzip2.a$O
+</sys/src/cmd/mkone
+
+CFLAGS=$CFLAGS -p -I/sys/src/cmd/bzip2/lib
+
+/sys/src/cmd/bzip2/lib/libbzip2.a$O:
+ @{cd /sys/src/cmd/bzip2/lib && mk}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <fcall.h>
+#include "bzfs.h"
+
+/*
+ * Rather than reading /adm/users, which is a lot of work for
+ * a toy program, we assume all groups have the form
+ * NNN:user:user:
+ * meaning that each user is the leader of his own group.
+ */
+
+enum
+{
+ OPERM = 0x3, /* mask of all permission types in open mode */
+ Nram = 512,
+ Maxsize = 512*1024*1024,
+ Maxfdata = 8192,
+};
+
+typedef struct Fid Fid;
+typedef struct Ram Ram;
+
+struct Fid
+{
+ short busy;
+ short open;
+ short rclose;
+ int fid;
+ Fid *next;
+ char *user;
+ Ram *ram;
+};
+
+struct Ram
+{
+ short busy;
+ short open;
+ long parent; /* index in Ram array */
+ Qid qid;
+ long perm;
+ char *name;
+ ulong atime;
+ ulong mtime;
+ char *user;
+ char *group;
+ char *muid;
+ char *data;
+ long ndata;
+};
+
+enum
+{
+ Pexec = 1,
+ Pwrite = 2,
+ Pread = 4,
+ Pother = 1,
+ Pgroup = 8,
+ Powner = 64,
+};
+
+ulong path; /* incremented for each new file */
+Fid *fids;
+Ram ram[Nram];
+int nram;
+int mfd[2];
+char *user;
+uchar mdata[IOHDRSZ+Maxfdata];
+uchar rdata[Maxfdata]; /* buffer for data in reply */
+uchar statbuf[STATMAX];
+Fcall thdr;
+Fcall rhdr;
+int messagesize = sizeof mdata;
+
+Fid * newfid(int);
+uint ramstat(Ram*, uchar*, uint);
+void io(void);
+void *erealloc(void*, ulong);
+void *emalloc(ulong);
+char *estrdup(char*);
+void ramfsusage(void);
+int perm(Fid*, Ram*, int);
+char *atom(char*);
+
+char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
+ *rattach(Fid*), *rwalk(Fid*),
+ *ropen(Fid*), *rcreate(Fid*),
+ *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
+ *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
+
+char *(*fcalls[])(Fid*) = {
+ [Tversion] rversion,
+ [Tflush] rflush,
+ [Tauth] rauth,
+ [Tattach] rattach,
+ [Twalk] rwalk,
+ [Topen] ropen,
+ [Tcreate] rcreate,
+ [Tread] rread,
+ [Twrite] rwrite,
+ [Tclunk] rclunk,
+ [Tremove] rremove,
+ [Tstat] rstat,
+ [Twstat] rwstat,
+};
+
+char Eperm[] = "permission denied";
+char Enotdir[] = "not a directory";
+char Enoauth[] = "no authentication in ramfs";
+char Enotexist[] = "file does not exist";
+char Einuse[] = "file in use";
+char Eexist[] = "file exists";
+char Eisdir[] = "file is a directory";
+char Enotowner[] = "not owner";
+char Eisopen[] = "file already open for I/O";
+char Excl[] = "exclusive use file already open";
+char Ename[] = "illegal name";
+char Eversion[] = "unknown 9P version";
+
+int debug;
+
+void
+notifyf(void *a, char *s)
+{
+ USED(a);
+ if(strncmp(s, "interrupt", 9) == 0)
+ noted(NCONT);
+ noted(NDFLT);
+}
+
+void
+ramfsmain(int argc, char *argv[])
+{
+ Ram *r;
+ char *defmnt;
+ int p[2];
+ char buf[32];
+ int fd, srvfd;
+ int stdio = 0;
+
+ srvfd = -1;
+ defmnt = "/tmp";
+ ARGBEGIN{
+ case 'D':
+ debug = 1;
+ break;
+ case 'i': /* this is DIFFERENT from normal ramfs; use 1 for both for kernel */
+ defmnt = 0;
+ stdio = 1;
+ srvfd = 0;
+ mfd[0] = 1;
+ mfd[1] = 1;
+ break;
+ case 's':
+ defmnt = 0;
+ break;
+ case 'm':
+ defmnt = ARGF();
+ break;
+ default:
+ ramfsusage();
+ }ARGEND
+
+ if(!stdio){
+ if(pipe(p) < 0)
+ error("pipe failed");
+ srvfd = p[1];
+ mfd[0] = p[0];
+ mfd[1] = p[0];
+ if(defmnt == 0){
+ fd = create("#s/ramfs", OWRITE, 0666);
+ if(fd < 0)
+ error("create of /srv/ramfs failed");
+ sprint(buf, "%d", p[1]);
+ if(write(fd, buf, strlen(buf)) < 0)
+ error("writing /srv/ramfs");
+ }
+ }
+
+ user = atom(getuser());
+ notify(notifyf);
+ nram = 1;
+ r = &ram[0];
+ r->busy = 1;
+ r->data = 0;
+ r->ndata = 0;
+ r->perm = DMDIR | 0775;
+ r->qid.type = QTDIR;
+ r->qid.path = 0LL;
+ r->qid.vers = 0;
+ r->parent = 0;
+ r->user = user;
+ r->group = user;
+ r->muid = user;
+ r->atime = time(0);
+ r->mtime = r->atime;
+ r->name = estrdup(".");
+
+ if(debug)
+ fmtinstall('F', fcallfmt);
+ switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
+ case -1:
+ error("fork");
+ case 0:
+ close(srvfd);
+ io();
+ break;
+ default:
+ close(mfd[0]); /* don't deadlock if child fails */
+ if(defmnt && mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
+ error("mount failed: %r");
+ }
+}
+
+char*
+rversion(Fid*)
+{
+ Fid *f;
+
+ for(f = fids; f; f = f->next)
+ if(f->busy)
+ rclunk(f);
+ if(thdr.msize > sizeof mdata)
+ rhdr.msize = sizeof mdata;
+ else
+ rhdr.msize = thdr.msize;
+ messagesize = rhdr.msize;
+ if(strncmp(thdr.version, "9P2000", 6) != 0)
+ return Eversion;
+ rhdr.version = "9P2000";
+ return 0;
+}
+
+char*
+rauth(Fid*)
+{
+ return "ramfs: no authentication required";
+}
+
+char*
+rflush(Fid *f)
+{
+ USED(f);
+ return 0;
+}
+
+char*
+rattach(Fid *f)
+{
+ /* no authentication! */
+ f->busy = 1;
+ f->rclose = 0;
+ f->ram = &ram[0];
+ rhdr.qid = f->ram->qid;
+ if(thdr.uname[0])
+ f->user = atom(thdr.uname);
+ else
+ f->user = atom("none");
+ if(strcmp(user, "none") == 0)
+ user = f->user;
+ return 0;
+}
+
+char*
+clone(Fid *f, Fid **nf)
+{
+ if(f->open)
+ return Eisopen;
+ if(f->ram->busy == 0)
+ return Enotexist;
+ *nf = newfid(thdr.newfid);
+ (*nf)->busy = 1;
+ (*nf)->open = 0;
+ (*nf)->rclose = 0;
+ (*nf)->ram = f->ram;
+ (*nf)->user = f->user; /* no ref count; the leakage is minor */
+ return 0;
+}
+
+char*
+rwalk(Fid *f)
+{
+ Ram *r, *fram;
+ char *name;
+ Ram *parent;
+ Fid *nf;
+ char *err;
+ ulong t;
+ int i;
+
+ err = nil;
+ nf = nil;
+ rhdr.nwqid = 0;
+ if(rhdr.newfid != rhdr.fid){
+ err = clone(f, &nf);
+ if(err)
+ return err;
+ f = nf; /* walk the new fid */
+ }
+ fram = f->ram;
+ if(thdr.nwname > 0){
+ t = time(0);
+ for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
+ if((fram->qid.type & QTDIR) == 0){
+ err = Enotdir;
+ break;
+ }
+ if(fram->busy == 0){
+ err = Enotexist;
+ break;
+ }
+ fram->atime = t;
+ name = thdr.wname[i];
+ if(strcmp(name, ".") == 0){
+ Found:
+ rhdr.nwqid++;
+ rhdr.wqid[i] = fram->qid;
+ continue;
+ }
+ parent = &ram[fram->parent];
+#ifdef CHECKS
+ if(!perm(f, parent, Pexec)){
+ err = Eperm;
+ break;
+ }
+#endif
+ if(strcmp(name, "..") == 0){
+ fram = parent;
+ goto Found;
+ }
+ for(r=ram; r < &ram[nram]; r++)
+ if(r->busy && r->parent==fram-ram && strcmp(name, r->name)==0){
+ fram = r;
+ goto Found;
+ }
+ break;
+ }
+ if(i==0 && err == nil)
+ err = Enotexist;
+ }
+ if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
+ /* clunk the new fid, which is the one we walked */
+ f->busy = 0;
+ f->ram = nil;
+ }
+ if(rhdr.nwqid == thdr.nwname) /* update the fid after a successful walk */
+ f->ram = fram;
+ return err;
+}
+
+char *
+ropen(Fid *f)
+{
+ Ram *r;
+ int mode, trunc;
+
+ if(f->open)
+ return Eisopen;
+ r = f->ram;
+ if(r->busy == 0)
+ return Enotexist;
+ if(r->perm & DMEXCL)
+ if(r->open)
+ return Excl;
+ mode = thdr.mode;
+ if(r->qid.type & QTDIR){
+ if(mode != OREAD)
+ return Eperm;
+ rhdr.qid = r->qid;
+ return 0;
+ }
+ if(mode & ORCLOSE){
+ /* can't remove root; must be able to write parent */
+ if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite))
+ return Eperm;
+ f->rclose = 1;
+ }
+ trunc = mode & OTRUNC;
+ mode &= OPERM;
+ if(mode==OWRITE || mode==ORDWR || trunc)
+ if(!perm(f, r, Pwrite))
+ return Eperm;
+ if(mode==OREAD || mode==ORDWR)
+ if(!perm(f, r, Pread))
+ return Eperm;
+ if(mode==OEXEC)
+ if(!perm(f, r, Pexec))
+ return Eperm;
+ if(trunc && (r->perm&DMAPPEND)==0){
+ r->ndata = 0;
+ if(r->data)
+ free(r->data);
+ r->data = 0;
+ r->qid.vers++;
+ }
+ rhdr.qid = r->qid;
+ rhdr.iounit = messagesize-IOHDRSZ;
+ f->open = 1;
+ r->open++;
+ return 0;
+}
+
+char *
+rcreate(Fid *f)
+{
+ Ram *r;
+ char *name;
+ long parent, prm;
+
+ if(f->open)
+ return Eisopen;
+ if(f->ram->busy == 0)
+ return Enotexist;
+ parent = f->ram - ram;
+ if((f->ram->qid.type&QTDIR) == 0)
+ return Enotdir;
+ /* must be able to write parent */
+#ifdef CHECKS
+ if(!perm(f, f->ram, Pwrite))
+ return Eperm;
+#endif
+ prm = thdr.perm;
+ name = thdr.name;
+ if(strcmp(name, ".")==0 || strcmp(name, "..")==0)
+ return Ename;
+ for(r=ram; r<&ram[nram]; r++)
+ if(r->busy && parent==r->parent)
+ if(strcmp((char*)name, r->name)==0)
+ return Einuse;
+ for(r=ram; r->busy; r++)
+ if(r == &ram[Nram-1])
+ return "no free ram resources";
+ r->busy = 1;
+ r->qid.path = ++path;
+ r->qid.vers = 0;
+ if(prm & DMDIR)
+ r->qid.type |= QTDIR;
+ r->parent = parent;
+ free(r->name);
+ r->name = estrdup(name);
+ r->user = f->user;
+ r->group = f->ram->group;
+ r->muid = f->ram->muid;
+ if(prm & DMDIR)
+ prm = (prm&~0777) | (f->ram->perm&prm&0777);
+ else
+ prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666);
+ r->perm = prm;
+ r->ndata = 0;
+ if(r-ram >= nram)
+ nram = r - ram + 1;
+ r->atime = time(0);
+ r->mtime = r->atime;
+ f->ram->mtime = r->atime;
+ f->ram = r;
+ rhdr.qid = r->qid;
+ rhdr.iounit = messagesize-IOHDRSZ;
+ f->open = 1;
+ if(thdr.mode & ORCLOSE)
+ f->rclose = 1;
+ r->open++;
+ return 0;
+}
+
+char*
+rread(Fid *f)
+{
+ Ram *r;
+ uchar *buf;
+ long off;
+ int n, m, cnt;
+
+ if(f->ram->busy == 0)
+ return Enotexist;
+ n = 0;
+ rhdr.count = 0;
+ off = thdr.offset;
+ buf = rdata;
+ cnt = thdr.count;
+ if(cnt > messagesize) /* shouldn't happen, anyway */
+ cnt = messagesize;
+ if(f->ram->qid.type & QTDIR){
+ for(r=ram+1; off > 0; r++){
+ if(r->busy && r->parent==f->ram-ram)
+ off -= ramstat(r, statbuf, sizeof statbuf);
+ if(r == &ram[nram-1])
+ return 0;
+ }
+ for(; r<&ram[nram] && n < cnt; r++){
+ if(!r->busy || r->parent!=f->ram-ram)
+ continue;
+ m = ramstat(r, buf+n, cnt-n);
+ if(m == 0)
+ break;
+ n += m;
+ }
+ rhdr.data = (char*)rdata;
+ rhdr.count = n;
+ return 0;
+ }
+ r = f->ram;
+ if(off >= r->ndata)
+ return 0;
+ r->atime = time(0);
+ n = cnt;
+ if(off+n > r->ndata)
+ n = r->ndata - off;
+ rhdr.data = r->data+off;
+ rhdr.count = n;
+ return 0;
+}
+
+char*
+rwrite(Fid *f)
+{
+ Ram *r;
+ ulong off;
+ int cnt;
+
+ r = f->ram;
+ if(r->busy == 0)
+ return Enotexist;
+ off = thdr.offset;
+ if(r->perm & DMAPPEND)
+ off = r->ndata;
+ cnt = thdr.count;
+ if(r->qid.type & QTDIR)
+ return Eisdir;
+ if(off+cnt >= Maxsize) /* sanity check */
+ return "write too big";
+ if(off+cnt > r->ndata)
+ r->data = erealloc(r->data, off+cnt);
+ if(off > r->ndata)
+ memset(r->data+r->ndata, 0, off-r->ndata);
+ if(off+cnt > r->ndata)
+ r->ndata = off+cnt;
+ memmove(r->data+off, thdr.data, cnt);
+ r->qid.vers++;
+ r->mtime = time(0);
+ rhdr.count = cnt;
+ return 0;
+}
+
+void
+realremove(Ram *r)
+{
+ r->ndata = 0;
+ if(r->data)
+ free(r->data);
+ r->data = 0;
+ r->parent = 0;
+ memset(&r->qid, 0, sizeof r->qid);
+ free(r->name);
+ r->name = nil;
+ r->busy = 0;
+}
+
+char *
+rclunk(Fid *f)
+{
+ if(f->open)
+ f->ram->open--;
+ if(f->rclose)
+ realremove(f->ram);
+ f->busy = 0;
+ f->open = 0;
+ f->ram = 0;
+ return 0;
+}
+
+char *
+rremove(Fid *f)
+{
+ Ram *r;
+
+ if(f->open)
+ f->ram->open--;
+ f->busy = 0;
+ f->open = 0;
+ r = f->ram;
+ f->ram = 0;
+#ifdef CHECKS
+ if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite))
+ return Eperm;
+#endif
+ ram[r->parent].mtime = time(0);
+ realremove(r);
+ return 0;
+}
+
+char *
+rstat(Fid *f)
+{
+ if(f->ram->busy == 0)
+ return Enotexist;
+ rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf);
+ rhdr.stat = statbuf;
+ return 0;
+}
+
+char *
+rwstat(Fid *f)
+{
+ Ram *r, *s;
+ Dir dir;
+
+ if(f->ram->busy == 0)
+ return Enotexist;
+ convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf);
+ r = f->ram;
+
+ /*
+ * To change length, must have write permission on file.
+ */
+#ifdef CHECKS
+ if(dir.length!=~0 && dir.length!=r->ndata){
+ if(!perm(f, r, Pwrite))
+ return Eperm;
+ }
+#endif
+
+ /*
+ * To change name, must have write permission in parent
+ * and name must be unique.
+ */
+ if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){
+#ifdef CHECKS
+ if(!perm(f, &ram[r->parent], Pwrite))
+ return Eperm;
+#endif
+ for(s=ram; s<&ram[nram]; s++)
+ if(s->busy && s->parent==r->parent)
+ if(strcmp(dir.name, s->name)==0)
+ return Eexist;
+ }
+
+#ifdef OWNERS
+ /*
+ * To change mode, must be owner or group leader.
+ * Because of lack of users file, leader=>group itself.
+ */
+ if(dir.mode!=~0 && r->perm!=dir.mode){
+ if(strcmp(f->user, r->user) != 0)
+ if(strcmp(f->user, r->group) != 0)
+ return Enotowner;
+ }
+
+ /*
+ * To change group, must be owner and member of new group,
+ * or leader of current group and leader of new group.
+ * Second case cannot happen, but we check anyway.
+ */
+ if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){
+ if(strcmp(f->user, r->user) == 0)
+ if(strcmp(f->user, dir.gid) == 0)
+ goto ok;
+ if(strcmp(f->user, r->group) == 0)
+ if(strcmp(f->user, dir.gid) == 0)
+ goto ok;
+ return Enotowner;
+ ok:;
+ }
+#endif
+
+ /* all ok; do it */
+ if(dir.mode != ~0){
+ dir.mode &= ~DMDIR; /* cannot change dir bit */
+ dir.mode |= r->perm&DMDIR;
+ r->perm = dir.mode;
+ }
+ if(dir.name[0] != '\0'){
+ free(r->name);
+ r->name = estrdup(dir.name);
+ }
+ if(dir.gid[0] != '\0')
+ r->group = atom(dir.gid);
+
+ if(dir.uid[0] != '\0')
+ r->user = atom(dir.uid);
+
+ if(dir.length!=~0 && dir.length!=r->ndata){
+ r->data = erealloc(r->data, dir.length);
+ if(r->ndata < dir.length)
+ memset(r->data+r->ndata, 0, dir.length-r->ndata);
+ r->ndata = dir.length;
+ }
+
+ if(dir.mtime != ~0)
+ r->mtime = dir.mtime;
+
+ ram[r->parent].mtime = time(0);
+ return 0;
+}
+
+uint
+ramstat(Ram *r, uchar *buf, uint nbuf)
+{
+ Dir dir;
+
+ dir.name = r->name;
+ dir.qid = r->qid;
+ dir.mode = r->perm;
+ dir.length = r->ndata;
+ dir.uid = r->user;
+ dir.gid = r->group;
+ dir.muid = r->muid;
+ dir.atime = r->atime;
+ dir.mtime = r->mtime;
+ return convD2M(&dir, buf, nbuf);
+}
+
+Fid *
+newfid(int fid)
+{
+ Fid *f, *ff;
+
+ ff = 0;
+ for(f = fids; f; f = f->next)
+ if(f->fid == fid)
+ return f;
+ else if(!ff && !f->busy)
+ ff = f;
+ if(ff){
+ ff->fid = fid;
+ return ff;
+ }
+ f = emalloc(sizeof *f);
+ f->ram = nil;
+ f->fid = fid;
+ f->next = fids;
+ fids = f;
+ return f;
+}
+
+void
+io(void)
+{
+ char *err;
+ int n, pid;
+
+ pid = getpid();
+
+ for(;;){
+ /*
+ * reading from a pipe or a network device
+ * will give an error after a few eof reads.
+ * however, we cannot tell the difference
+ * between a zero-length read and an interrupt
+ * on the processes writing to us,
+ * so we wait for the error.
+ */
+ n = read9pmsg(mfd[0], mdata, messagesize);
+ if(n < 0)
+ error("mount read: %r");
+ if(n == 0)
+ continue;
+ if(convM2S(mdata, n, &thdr) == 0)
+ continue;
+
+ if(debug)
+ fprint(2, "ramfs %d:<-%F\n", pid, &thdr);
+
+ if(!fcalls[thdr.type])
+ err = "bad fcall type";
+ else
+ err = (*fcalls[thdr.type])(newfid(thdr.fid));
+ if(err){
+ rhdr.type = Rerror;
+ rhdr.ename = err;
+ }else{
+ rhdr.type = thdr.type + 1;
+ rhdr.fid = thdr.fid;
+ }
+ rhdr.tag = thdr.tag;
+ if(debug)
+ fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/
+ n = convS2M(&rhdr, mdata, messagesize);
+ if(n == 0)
+ error("convS2M error on write");
+ if(write(mfd[1], mdata, n) != n)
+ error("mount write");
+ }
+}
+
+int
+perm(Fid *f, Ram *r, int p)
+{
+ if((p*Pother) & r->perm)
+ return 1;
+ if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm))
+ return 1;
+ if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm))
+ return 1;
+ return 0;
+}
+
+void *
+emalloc(ulong n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(!p)
+ error("out of memory");
+ memset(p, 0, n);
+ return p;
+}
+
+void *
+erealloc(void *p, ulong n)
+{
+ p = realloc(p, n);
+ if(!p)
+ error("out of memory");
+ return p;
+}
+
+char *
+estrdup(char *q)
+{
+ char *p;
+ int n;
+
+ n = strlen(q)+1;
+ p = malloc(n);
+ if(!p)
+ error("out of memory");
+ memmove(p, q, n);
+ return p;
+}
+
+void
+ramfsusage(void)
+{
+ fprint(2, "usage: %s [-is] [-m mountpoint]\n", argv0);
+ exits("usage");
+}
+
+/*
+ * Custom allocators to avoid malloc overheads on small objects.
+ * We never free these. (See below.)
+ */
+typedef struct Stringtab Stringtab;
+struct Stringtab {
+ Stringtab *link;
+ char *str;
+};
+static Stringtab*
+taballoc(void)
+{
+ static Stringtab *t;
+ static uint nt;
+
+ if(nt == 0){
+ t = malloc(64*sizeof(Stringtab));
+ if(t == 0)
+ sysfatal("out of memory");
+ nt = 64;
+ }
+ nt--;
+ return t++;
+}
+
+static char*
+xstrdup(char *s)
+{
+ char *r;
+ int len;
+ static char *t;
+ static int nt;
+
+ len = strlen(s)+1;
+ if(len >= 8192)
+ sysfatal("strdup big string");
+
+ if(nt < len){
+ t = malloc(8192);
+ if(t == 0)
+ sysfatal("out of memory");
+ nt = 8192;
+ }
+ r = t;
+ t += len;
+ nt -= len;
+ strcpy(r, s);
+ return r;
+}
+
+/*
+ * Return a uniquely allocated copy of a string.
+ * Don't free these -- they stay in the table for the
+ * next caller who wants that particular string.
+ * String comparison can be done with pointer comparison
+ * if you know both strings are atoms.
+ */
+static Stringtab *stab[1024];
+
+static uint
+hash(char *s)
+{
+ uint h;
+ uchar *p;
+
+ h = 0;
+ for(p=(uchar*)s; *p; p++)
+ h = h*37 + *p;
+ return h;
+}
+
+char*
+atom(char *str)
+{
+ uint h;
+ Stringtab *tab;
+
+ h = hash(str) % nelem(stab);
+ for(tab=stab[h]; tab; tab=tab->link)
+ if(strcmp(str, tab->str) == 0)
+ return tab->str;
+
+ tab = taballoc();
+ tab->str = xstrdup(str);
+ tab->link = stab[h];
+ stab[h] = tab;
+ return tab->str;
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "bzfs.h"
+
+int
+Bgetint(Biobuf *b)
+{
+ uchar p[4];
+
+ if(Bread(b, p, 4) != 4)
+ sysfatal("short read");
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+}
+
+/*
+ * memmove but make sure overlap works properly.
+ */
+void
+copy(uchar *dst, uchar *src, int n)
+{
+ while(n-- > 0)
+ *dst++ = *src++;
+}
+
+int
+unbflz(int in)
+{
+ int rv, out, p[2];
+ Biobuf *b, bin;
+ char buf[5];
+ uchar *data;
+ int i, j, length, n, m, o, sum;
+ ulong *blk;
+ int nblk, mblk;
+
+ if(pipe(p) < 0)
+ sysfatal("pipe: %r");
+
+ rv = p[0];
+ out = p[1];
+ switch(rfork(RFPROC|RFFDG|RFNOTEG|RFMEM)){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ close(rv);
+ break;
+ default:
+ close(in);
+ close(out);
+ return rv;
+ }
+
+ Binit(&bin, in, OREAD);
+ b = &bin;
+
+ if(Bread(b, buf, 4) != 4)
+ sysfatal("short read");
+
+ if(memcmp(buf, "BLZ\n", 4) != 0)
+ sysfatal("bad header");
+
+ length = Bgetint(b);
+ data = malloc(length);
+ if(data == nil)
+ sysfatal("out of memory");
+ sum = 0;
+ nblk = 0;
+ mblk = 0;
+ blk = nil;
+ while(sum < length){
+ if(nblk>=mblk){
+ mblk += 16384;
+ blk = realloc(blk, (mblk+1)*sizeof(blk[0]));
+ if(blk == nil)
+ sysfatal("out of memory");
+ }
+ n = Bgetint(b);
+ blk[nblk++] = n;
+ if(n&(1<<31))
+ n &= ~(1<<31);
+ else
+ blk[nblk++] = Bgetint(b);
+ sum += n;
+ }
+ if(sum != length)
+ sysfatal("bad compressed data %d %d", sum, length);
+ i = 0;
+ j = 0;
+ while(i < length){
+ assert(j < nblk);
+ n = blk[j++];
+ if(n&(1<<31)){
+ n &= ~(1<<31);
+ if((m=Bread(b, data+i, n)) != n)
+ sysfatal("short read %d %d", n, m);
+ }else{
+ o = blk[j++];
+ copy(data+i, data+o, n);
+ }
+ i += n;
+ }
+ write(out, data, length);
+ close(in);
+ close(out);
+ _exits(0);
+ return -1;
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "bzfs.h"
+
+/*
+ * THIS FILE IS NOT IDENTICAL TO THE ORIGINAL
+ * FROM THE BZIP2 DISTRIBUTION.
+ *
+ * It has been modified, mainly to break the library
+ * into smaller pieces.
+ *
+ * Russ Cox
+ * rsc@plan9.bell-labs.com
+ * July 2000
+ */
+
+/*---------------------------------------------*/
+/*--
+ Place a 1 beside your platform, and 0 elsewhere.
+ Attempts to autosniff this even if you don't.
+--*/
+
+
+/*--
+ Plan 9 from Bell Labs
+--*/
+#define BZ_PLAN9 1
+#define BZ_UNIX 0
+
+#define exit(x) exits((x) ? "whoops" : nil)
+#define size_t ulong
+
+#ifdef __GNUC__
+# define NORETURN __attribute__ ((noreturn))
+#else
+# define NORETURN /**/
+#endif
+
+/*--
+ Some more stuff for all platforms :-)
+ This might have to get moved into the platform-specific
+ header files if we encounter a machine with different sizes.
+--*/
+
+typedef char Char;
+typedef unsigned char Bool;
+typedef unsigned char UChar;
+typedef int Int32;
+typedef unsigned int UInt32;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#define True ((Bool)1)
+#define False ((Bool)0)
+
+/*--
+ IntNative is your platform's `native' int size.
+ Only here to avoid probs with 64-bit platforms.
+--*/
+typedef int IntNative;
+
+#include "bzfs.h"
+#include "bzlib.h"
+#include "bzlib_private.h"
+
+static int
+bunzip(int ofd, char *ofile, Biobuf *bin)
+{
+ int e, n, done, onemore;
+ char buf[8192];
+ char obuf[8192];
+ Biobuf bout;
+ bz_stream strm;
+
+ USED(ofile);
+
+ memset(&strm, 0, sizeof strm);
+ BZ2_bzDecompressInit(&strm, 0, 0);
+
+ strm.next_in = buf;
+ strm.avail_in = 0;
+ strm.next_out = obuf;
+ strm.avail_out = sizeof obuf;
+
+ done = 0;
+ Binit(&bout, ofd, OWRITE);
+
+ /*
+ * onemore is a crummy hack to go 'round the loop
+ * once after we finish, to flush the output buffer.
+ */
+ onemore = 1;
+ SET(e);
+ do {
+ if(!done && strm.avail_in < sizeof buf) {
+ if(strm.avail_in)
+ memmove(buf, strm.next_in, strm.avail_in);
+
+ n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
+ if(n <= 0)
+ done = 1;
+ else
+ strm.avail_in += n;
+ strm.next_in = buf;
+ }
+ if(strm.avail_out < sizeof obuf) {
+ Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out);
+ strm.next_out = obuf;
+ strm.avail_out = sizeof obuf;
+ }
+
+ if(onemore == 0)
+ break;
+ } while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--);
+
+ if(e != BZ_STREAM_END) {
+ fprint(2, "bunzip2: decompress failed\n");
+ return 0;
+ }
+
+ if(BZ2_bzDecompressEnd(&strm) != BZ_OK) {
+ fprint(2, "bunzip2: decompress end failed (can't happen)\n");
+ return 0;
+ }
+
+ Bterm(&bout);
+
+ return 1;
+}
+
+void
+_unbzip(int in, int out)
+{
+ Biobuf bin;
+
+ Binit(&bin, in, OREAD);
+ if(bunzip(out, nil, &bin) != 1) {
+ fprint(2, "bunzip2 failed\n");
+ _exits("bunzip2");
+ }
+}
+
+int
+unbzip(int in)
+{
+ int rv, out, p[2];
+
+ if(pipe(p) < 0)
+ sysfatal("pipe: %r");
+
+ rv = p[0];
+ out = p[1];
+ switch(rfork(RFPROC|RFFDG|RFNOTEG|RFMEM)){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ close(rv);
+ break;
+ default:
+ close(in);
+ close(out);
+ return rv;
+ }
+
+ _unbzip(in, out);
+ _exits(0);
+ return -1; /* not reached */
+}
+
+int bz_config_ok ( void )
+{
+ if (sizeof(int) != 4) return 0;
+ if (sizeof(short) != 2) return 0;
+ if (sizeof(char) != 1) return 0;
+ return 1;
+}
+
+void* default_bzalloc(void *o, int items, int size)
+{
+ USED(o);
+ return sbrk(items*size);
+}
+
+void default_bzfree(void*, void*)
+{
+}
+
+void
+bz_internal_error(int)
+{
+ abort();
+}
+
+/*-------------------------------------------------------------*/
+/*--- Decompression machinery ---*/
+/*--- decompress.c ---*/
+/*-------------------------------------------------------------*/
+
+/*--
+ This file is a part of bzip2 and/or libbzip2, a program and
+ library for lossless, block-sorting data compression.
+
+ Copyright (C) 1996-2000 Julian R Seward. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Julian Seward, Cambridge, UK.
+ jseward@acm.org
+ bzip2/libbzip2 version 1.0 of 21 March 2000
+
+ This program is based on (at least) the work of:
+ Mike Burrows
+ David Wheeler
+ Peter Fenwick
+ Alistair Moffat
+ Radford Neal
+ Ian H. Witten
+ Robert Sedgewick
+ Jon L. Bentley
+
+ For more information on these sources, see the manual.
+--*/
+
+
+
+/*---------------------------------------------------*/
+static
+void makeMaps_d ( DState* s )
+{
+ Int32 i;
+ s->nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (s->inUse[i]) {
+ s->seqToUnseq[s->nInUse] = i;
+ s->nInUse++;
+ }
+}
+
+
+/*---------------------------------------------------*/
+#define RETURN(rrr) \
+ { retVal = rrr; goto save_state_and_return; };
+
+#define GET_BITS(lll,vvv,nnn) \
+ case lll: \
+ { int x; if((retVal = getbits(s, lll, &x, nnn)) != 99) \
+ goto save_state_and_return; vvv=x; }\
+
+int
+getbits(DState *s, int lll, int *vvv, int nnn)
+{
+ s->state = lll;
+
+ for(;;) {
+ if (s->bsLive >= nnn) {
+ UInt32 v;
+ v = (s->bsBuff >>
+ (s->bsLive-nnn)) & ((1 << nnn)-1);
+ s->bsLive -= nnn;
+ *vvv = v;
+ return 99;
+ }
+ if (s->strm->avail_in == 0) return BZ_OK;
+ s->bsBuff
+ = (s->bsBuff << 8) |
+ ((UInt32)
+ (*((UChar*)(s->strm->next_in))));
+ s->bsLive += 8;
+ s->strm->next_in++;
+ s->strm->avail_in--;
+ s->strm->total_in_lo32++;
+ if (s->strm->total_in_lo32 == 0)
+ s->strm->total_in_hi32++;
+ }
+ return -1; /* KEN */
+}
+
+#define GET_UCHAR(lll,uuu) \
+ GET_BITS(lll,uuu,8)
+
+#define GET_BIT(lll,uuu) \
+ GET_BITS(lll,uuu,1)
+
+/*---------------------------------------------------*/
+#define GET_MTF_VAL(label1,label2,lval) \
+{ \
+ if (groupPos == 0) { \
+ groupNo++; \
+ if (groupNo >= nSelectors) \
+ RETURN(BZ_DATA_ERROR); \
+ groupPos = BZ_G_SIZE; \
+ gSel = s->selector[groupNo]; \
+ gMinlen = s->minLens[gSel]; \
+ gLimit = &(s->limit[gSel][0]); \
+ gPerm = &(s->perm[gSel][0]); \
+ gBase = &(s->base[gSel][0]); \
+ } \
+ groupPos--; \
+ zn = gMinlen; \
+ GET_BITS(label1, zvec, zn); \
+ while (1) { \
+ if (zn > 20 /* the longest code */) \
+ RETURN(BZ_DATA_ERROR); \
+ if (zvec <= gLimit[zn]) break; \
+ zn++; \
+ GET_BIT(label2, zj); \
+ zvec = (zvec << 1) | zj; \
+ }; \
+ if (zvec - gBase[zn] < 0 \
+ || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
+ RETURN(BZ_DATA_ERROR); \
+ lval = gPerm[zvec - gBase[zn]]; \
+}
+
+
+/*---------------------------------------------------*/
+Int32 BZ2_decompress ( DState* s )
+{
+ UChar uc;
+ Int32 retVal;
+ Int32 minLen, maxLen;
+ bz_stream* strm = s->strm;
+
+ /* stuff that needs to be saved/restored */
+ Int32 i;
+ Int32 j;
+ Int32 t;
+ Int32 alphaSize;
+ Int32 nGroups;
+ Int32 nSelectors;
+ Int32 EOB;
+ Int32 groupNo;
+ Int32 groupPos;
+ Int32 nextSym;
+ Int32 nblockMAX;
+ Int32 nblock;
+ Int32 es;
+ Int32 N;
+ Int32 curr;
+ Int32 zt;
+ Int32 zn;
+ Int32 zvec;
+ Int32 zj;
+ Int32 gSel;
+ Int32 gMinlen;
+ Int32* gLimit;
+ Int32* gBase;
+ Int32* gPerm;
+
+ if (s->state == BZ_X_MAGIC_1) {
+ /*initialise the save area*/
+ s->save_i = 0;
+ s->save_j = 0;
+ s->save_t = 0;
+ s->save_alphaSize = 0;
+ s->save_nGroups = 0;
+ s->save_nSelectors = 0;
+ s->save_EOB = 0;
+ s->save_groupNo = 0;
+ s->save_groupPos = 0;
+ s->save_nextSym = 0;
+ s->save_nblockMAX = 0;
+ s->save_nblock = 0;
+ s->save_es = 0;
+ s->save_N = 0;
+ s->save_curr = 0;
+ s->save_zt = 0;
+ s->save_zn = 0;
+ s->save_zvec = 0;
+ s->save_zj = 0;
+ s->save_gSel = 0;
+ s->save_gMinlen = 0;
+ s->save_gLimit = NULL;
+ s->save_gBase = NULL;
+ s->save_gPerm = NULL;
+ }
+
+ /*restore from the save area*/
+ i = s->save_i;
+ j = s->save_j;
+ t = s->save_t;
+ alphaSize = s->save_alphaSize;
+ nGroups = s->save_nGroups;
+ nSelectors = s->save_nSelectors;
+ EOB = s->save_EOB;
+ groupNo = s->save_groupNo;
+ groupPos = s->save_groupPos;
+ nextSym = s->save_nextSym;
+ nblockMAX = s->save_nblockMAX;
+ nblock = s->save_nblock;
+ es = s->save_es;
+ N = s->save_N;
+ curr = s->save_curr;
+ zt = s->save_zt;
+ zn = s->save_zn;
+ zvec = s->save_zvec;
+ zj = s->save_zj;
+ gSel = s->save_gSel;
+ gMinlen = s->save_gMinlen;
+ gLimit = s->save_gLimit;
+ gBase = s->save_gBase;
+ gPerm = s->save_gPerm;
+
+ retVal = BZ_OK;
+
+ switch (s->state) {
+
+ GET_UCHAR(BZ_X_MAGIC_1, uc);
+ if (uc != 'B') RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_UCHAR(BZ_X_MAGIC_2, uc);
+ if (uc != 'Z') RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_UCHAR(BZ_X_MAGIC_3, uc)
+ if (uc != 'h') RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
+ if (s->blockSize100k < '1' ||
+ s->blockSize100k > '9') RETURN(BZ_DATA_ERROR_MAGIC);
+ s->blockSize100k -= '0';
+
+ if (0 && s->smallDecompress) {
+ s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
+ s->ll4 = BZALLOC(
+ ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
+ );
+ if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
+ } else {
+ s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
+ if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
+ }
+
+ GET_UCHAR(BZ_X_BLKHDR_1, uc);
+
+ if (uc == 0x17) goto endhdr_2;
+ if (uc != 0x31) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_2, uc);
+ if (uc != 0x41) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_3, uc);
+ if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_4, uc);
+ if (uc != 0x26) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_5, uc);
+ if (uc != 0x53) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_6, uc);
+ if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+
+ s->currBlockNo++;
+ // if (s->verbosity >= 2)
+ // VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
+
+ s->storedBlockCRC = 0;
+ GET_UCHAR(BZ_X_BCRC_1, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_2, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_3, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_4, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+
+ GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
+
+ s->origPtr = 0;
+ GET_UCHAR(BZ_X_ORIGPTR_1, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+ GET_UCHAR(BZ_X_ORIGPTR_2, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+ GET_UCHAR(BZ_X_ORIGPTR_3, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+
+ if (s->origPtr < 0)
+ RETURN(BZ_DATA_ERROR);
+ if (s->origPtr > 10 + 100000*s->blockSize100k)
+ RETURN(BZ_DATA_ERROR);
+
+ /*--- Receive the mapping table ---*/
+ for (i = 0; i < 16; i++) {
+ GET_BIT(BZ_X_MAPPING_1, uc);
+ if (uc == 1)
+ s->inUse16[i] = True; else
+ s->inUse16[i] = False;
+ }
+
+ for (i = 0; i < 256; i++) s->inUse[i] = False;
+
+ for (i = 0; i < 16; i++)
+ if (s->inUse16[i])
+ for (j = 0; j < 16; j++) {
+ GET_BIT(BZ_X_MAPPING_2, uc);
+ if (uc == 1) s->inUse[i * 16 + j] = True;
+ }
+ makeMaps_d ( s );
+ if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
+ alphaSize = s->nInUse+2;
+
+ /*--- Now the selectors ---*/
+ GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
+ if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
+ GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
+ if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
+ for (i = 0; i < nSelectors; i++) {
+ j = 0;
+ while (True) {
+ GET_BIT(BZ_X_SELECTOR_3, uc);
+ if (uc == 0) break;
+ j++;
+ if (j >= nGroups) RETURN(BZ_DATA_ERROR);
+ }
+ s->selectorMtf[i] = j;
+ }
+
+ /*--- Undo the MTF values for the selectors. ---*/
+ {
+ UChar pos[BZ_N_GROUPS], tmp, v;
+ for (v = 0; v < nGroups; v++) pos[v] = v;
+
+ for (i = 0; i < nSelectors; i++) {
+ v = s->selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) { pos[v] = pos[v-1]; v--; }
+ pos[0] = tmp;
+ s->selector[i] = tmp;
+ }
+ }
+
+ /*--- Now the coding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ GET_BITS(BZ_X_CODING_1, curr, 5);
+ for (i = 0; i < alphaSize; i++) {
+ while (True) {
+ if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
+ GET_BIT(BZ_X_CODING_2, uc);
+ if (uc == 0) break;
+ GET_BIT(BZ_X_CODING_3, uc);
+ if (uc == 0) curr++; else curr--;
+ }
+ s->len[t][i] = curr;
+ }
+ }
+
+ /*--- Create the Huffman decoding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+ if (s->len[t][i] < minLen) minLen = s->len[t][i];
+ }
+ BZ2_hbCreateDecodeTables (
+ &(s->limit[t][0]),
+ &(s->base[t][0]),
+ &(s->perm[t][0]),
+ &(s->len[t][0]),
+ minLen, maxLen, alphaSize
+ );
+ s->minLens[t] = minLen;
+ }
+
+ /*--- Now the MTF values ---*/
+
+ EOB = s->nInUse+1;
+ nblockMAX = 100000 * s->blockSize100k;
+ groupNo = -1;
+ groupPos = 0;
+
+ for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
+
+ /*-- MTF init --*/
+ {
+ Int32 ii, jj, kk;
+ kk = MTFA_SIZE-1;
+ for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
+ for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+ s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
+ kk--;
+ }
+ s->mtfbase[ii] = kk + 1;
+ }
+ }
+ /*-- end MTF init --*/
+
+ nblock = 0;
+ GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
+
+ while (True) {
+
+ if (nextSym == EOB) break;
+
+ if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
+
+ es = -1;
+ N = 1;
+ do {
+ if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
+ if (nextSym == BZ_RUNB) es = es + (1+1) * N;
+ N = N * 2;
+ GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
+ }
+ while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+ es++;
+ uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
+ s->unzftab[uc] += es;
+
+ if (0 && s->smallDecompress)
+ while (es > 0) {
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+ s->ll16[nblock] = (UInt16)uc;
+ nblock++;
+ es--;
+ }
+ else
+ while (es > 0) {
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+ s->tt[nblock] = (UInt32)uc;
+ nblock++;
+ es--;
+ };
+
+ continue;
+
+ } else {
+
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+
+ /*-- uc = MTF ( nextSym-1 ) --*/
+ {
+ Int32 ii, jj, kk, pp, lno, off;
+ UInt32 nn;
+ nn = (UInt32)(nextSym - 1);
+
+ if (nn < MTFL_SIZE) {
+ /* avoid general-case expense */
+ pp = s->mtfbase[0];
+ uc = s->mtfa[pp+nn];
+ while (nn > 3) {
+ Int32 z = pp+nn;
+ s->mtfa[(z) ] = s->mtfa[(z)-1];
+ s->mtfa[(z)-1] = s->mtfa[(z)-2];
+ s->mtfa[(z)-2] = s->mtfa[(z)-3];
+ s->mtfa[(z)-3] = s->mtfa[(z)-4];
+ nn -= 4;
+ }
+ while (nn > 0) {
+ s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
+ };
+ s->mtfa[pp] = uc;
+ } else {
+ /* general case */
+ lno = nn / MTFL_SIZE;
+ off = nn % MTFL_SIZE;
+ pp = s->mtfbase[lno] + off;
+ uc = s->mtfa[pp];
+ while (pp > s->mtfbase[lno]) {
+ s->mtfa[pp] = s->mtfa[pp-1]; pp--;
+ };
+ s->mtfbase[lno]++;
+ while (lno > 0) {
+ s->mtfbase[lno]--;
+ s->mtfa[s->mtfbase[lno]]
+ = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
+ lno--;
+ }
+ s->mtfbase[0]--;
+ s->mtfa[s->mtfbase[0]] = uc;
+ if (s->mtfbase[0] == 0) {
+ kk = MTFA_SIZE-1;
+ for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
+ for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+ s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
+ kk--;
+ }
+ s->mtfbase[ii] = kk + 1;
+ }
+ }
+ }
+ }
+ /*-- end uc = MTF ( nextSym-1 ) --*/
+
+ s->unzftab[s->seqToUnseq[uc]]++;
+ if (0 && s->smallDecompress)
+ s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
+ s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
+ nblock++;
+
+ GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
+ continue;
+ }
+ }
+
+ /* Now we know what nblock is, we can do a better sanity
+ check on s->origPtr.
+ */
+ if (s->origPtr < 0 || s->origPtr >= nblock)
+ RETURN(BZ_DATA_ERROR);
+
+ s->state_out_len = 0;
+ s->state_out_ch = 0;
+ BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
+ s->state = BZ_X_OUTPUT;
+ // if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
+
+ /*-- Set up cftab to facilitate generation of T^(-1) --*/
+ s->cftab[0] = 0;
+ for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+ for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+
+ if (0 && s->smallDecompress) {
+
+ /*-- Make a copy of cftab, used in generation of T --*/
+ for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
+
+ /*-- compute the T vector --*/
+ for (i = 0; i < nblock; i++) {
+ uc = (UChar)(s->ll16[i]);
+ SET_LL(i, s->cftabCopy[uc]);
+ s->cftabCopy[uc]++;
+ }
+
+ /*-- Compute T^(-1) by pointer reversal on T --*/
+ i = s->origPtr;
+ j = GET_LL(i);
+ do {
+ Int32 tmp = GET_LL(j);
+ SET_LL(j, i);
+ i = j;
+ j = tmp;
+ }
+ while (i != s->origPtr);
+
+ s->tPos = s->origPtr;
+ s->nblock_used = 0;
+ if (s->blockRandomised) {
+ BZ_RAND_INIT_MASK;
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
+ } else {
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ }
+
+ } else {
+
+ /*-- compute the T^(-1) vector --*/
+ for (i = 0; i < nblock; i++) {
+ uc = (UChar)(s->tt[i] & 0xff);
+ s->tt[s->cftab[uc]] |= (i << 8);
+ s->cftab[uc]++;
+ }
+
+ s->tPos = s->tt[s->origPtr] >> 8;
+ s->nblock_used = 0;
+ if (s->blockRandomised) {
+ BZ_RAND_INIT_MASK;
+ BZ_GET_FAST(s->k0); s->nblock_used++;
+ BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
+ } else {
+ BZ_GET_FAST(s->k0); s->nblock_used++;
+ }
+
+ }
+
+ RETURN(BZ_OK);
+
+
+
+ endhdr_2:
+
+ GET_UCHAR(BZ_X_ENDHDR_2, uc);
+ if (uc != 0x72) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_3, uc);
+ if (uc != 0x45) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_4, uc);
+ if (uc != 0x38) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_5, uc);
+ if (uc != 0x50) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_6, uc);
+ if (uc != 0x90) RETURN(BZ_DATA_ERROR);
+
+ s->storedCombinedCRC = 0;
+ GET_UCHAR(BZ_X_CCRC_1, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_2, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_3, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_4, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+
+ s->state = BZ_X_IDLE;
+ RETURN(BZ_STREAM_END);
+
+ default: AssertH ( False, 4001 );
+ }
+
+ AssertH ( False, 4002 );
+
+ save_state_and_return:
+
+ s->save_i = i;
+ s->save_j = j;
+ s->save_t = t;
+ s->save_alphaSize = alphaSize;
+ s->save_nGroups = nGroups;
+ s->save_nSelectors = nSelectors;
+ s->save_EOB = EOB;
+ s->save_groupNo = groupNo;
+ s->save_groupPos = groupPos;
+ s->save_nextSym = nextSym;
+ s->save_nblockMAX = nblockMAX;
+ s->save_nblock = nblock;
+ s->save_es = es;
+ s->save_N = N;
+ s->save_curr = curr;
+ s->save_zt = zt;
+ s->save_zn = zn;
+ s->save_zvec = zvec;
+ s->save_zj = zj;
+ s->save_gSel = gSel;
+ s->save_gMinlen = gMinlen;
+ s->save_gLimit = gLimit;
+ s->save_gBase = gBase;
+ s->save_gPerm = gPerm;
+
+ return retVal;
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end decompress.c ---*/
+/*-------------------------------------------------------------*/
--- /dev/null
+/*
+ * The `cd' shell.
+ * Just has cd and lc.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+char *pwd;
+char *root = "/";
+
+void
+usage(void)
+{
+ fprint(2, "usage: cdsh [-r root]\n");
+ exits("usage");
+}
+
+int
+system(char *cmd)
+{
+ int pid;
+ if((pid = fork()) < 0)
+ return -1;
+
+ if(pid == 0) {
+ dup(2, 1);
+ execl("/bin/rc", "rc", "-c", cmd, nil);
+ exits("exec");
+ }
+ waitpid();
+ return 0;
+}
+
+int
+cd(char *s)
+{
+ char *newpwd;
+ int l;
+
+ if(s[0] == '/') {
+ cleanname(s);
+ newpwd = strdup(s);
+ } else {
+ l = strlen(pwd)+1+strlen(s)+1+50; /* 50 = crud for unicode mistakes */
+ newpwd = malloc(l);
+ snprint(newpwd, l, "%s/%s", pwd, s);
+ cleanname(newpwd);
+ assert(newpwd[0] == '/');
+ }
+
+ if(chdir(root) < 0 || (newpwd[1] != '\0' && chdir(newpwd+1) < 0)) {
+ chdir(root);
+ chdir(pwd+1);
+ free(newpwd);
+ return -1;
+ } else {
+ free(pwd);
+ pwd = newpwd;
+ return 0;
+ }
+}
+
+void
+main(int argc, char **argv)
+{
+ char *p;
+ Biobuf bin;
+ char *f[2];
+ int nf;
+
+ ARGBEGIN{
+ case 'r':
+ root = ARGF();
+ if(root == nil)
+ usage();
+ if(root[0] != '/') {
+ fprint(2, "root must be rooted\n");
+ exits("root");
+ }
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argc != 0)
+ usage();
+
+ cleanname(root);
+ if(cd("/") < 0) {
+ fprint(2, "cannot cd %s: %r\n", root);
+ exits("root");
+ }
+
+ Binit(&bin, 0, OREAD);
+ while(fprint(2, "%s%% ", pwd), (p = Brdline(&bin, '\n'))) {
+ p[Blinelen(&bin)-1] = '\0';
+ nf = tokenize(p, f, nelem(f));
+ if(nf < 1)
+ continue;
+ if(strcmp(f[0], "exit") == 0)
+ break;
+ if(strcmp(f[0], "lc") == 0) {
+ if(nf == 1) {
+ if(system("/bin/lc") < 0)
+ fprint(2, "lc: %r\n");
+ } else if(nf == 2) {
+ if(strpbrk(p, "'`{}^@$#&()|\\;><"))
+ fprint(2, "no shell characters allowed\n");
+ else {
+ p = f[1];
+ *--p = ' ';
+ *--p = 'c';
+ *--p = 'l';
+ if(system(p) < 0)
+ fprint(2, "lc: %r\n");
+ }
+ }
+ continue;
+ }
+ if(strcmp(f[0], "cd") == 0) {
+ if(nf < 2)
+ fprint(2, "usage: cd dir\n");
+ else if(cd(f[1]) < 0)
+ fprint(2, "cd: %r\n");
+ continue;
+ }
+ fprint(2, "commands are cd, lc, and exit\n");
+ }
+
+ print("%s\n", pwd);
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+char *argv0;
+
+int
+openlog(char *name)
+{
+ int fd;
+
+ fd = open(name, OWRITE);
+ if(fd < 0){
+ fprint(2, "%s: can't open %s: %r\n", argv0, name);
+ return -1;
+ }
+ seek(fd, 0, 2);
+ return fd;
+}
+
+void
+main(int argc, char **argv)
+{
+ Biobuf in;
+ int fd;
+ char *p, *t;
+ char buf[8192];
+
+ argv0 = argv[0];
+ if(argc != 4){
+ fprint(2, "usage: %s console logfile prefix\n", argv0);
+ exits("usage");
+ }
+
+ fd = open(argv[1], OREAD);
+ if(fd < 0){
+ fprint(2, "%s: can't open %s: %r\n", argv0, argv[1]);
+ exits("open");
+ }
+ Binit(&in, fd, OREAD);
+
+ fd = openlog(argv[2]);
+
+ for(;;){
+ if(p = Brdline(&in, '\n')){
+ p[Blinelen(&in)-1] = 0;
+ if(fprint(fd, "%s: %s\n", argv[3], p) < 0){
+ close(fd);
+ fd = openlog(argv[2]);
+ fprint(fd, "%s: %s\n", t, p);
+ }
+ } else if(Blinelen(&in) == 0) // true eof
+ break;
+ else {
+ Bread(&in, buf, sizeof buf);
+ }
+ }
+ exits(0);
+}
--- /dev/null
+</$objtype/mkfile
+CPUS=386
+
+TARG=\
+ bargraph\
+ bflz\
+ cdsh\
+ tailfsrv\
+ touchfs\
+ unbflz\
+
+OFILES=
+HFILES=
+
+BIN=/sys/lib/dist/bin/$objtype
+</sys/src/cmd/mkmany
+
+all:V: bzfs!all
+install:V: bzfs!install
+clean:V: bzfs!clean
+
+bzfs!%:V:
+ cd bzfs; mk $stem; cd ..
+
--- /dev/null
+objtype=386
+</$objtype/mkfile
+
+TARG=multi
+
+PIECES=\
+ aux/mouse\
+ aux/pcmcia\
+ aux/vga\
+ aux/zerotrunc\
+ disk/fdisk\
+ disk/format\
+ disk/mbr\
+ disk/prep\
+# fossil/fossil\
+# fossil/flfmt\
+ ip/ipconfig\
+ ip/ppp\
+ ndb/cs\
+ ndb/dns\
+# replica/applylog\
+ 9660srv\
+# awk\
+ basename\
+ cat\
+ chgrp\
+ chmod\
+ cleanname\
+ cmp\
+ cp\
+ date\
+ dd\
+ dossrv\
+ echo\
+ ed\
+ ext2srv\
+# fcp\
+ grep\
+ hget\
+ hoc\
+ ls\
+ mc\
+ mount\
+ mv\
+ ps\
+ read\
+# rio\
+ rm\
+ sed\
+ sort\
+ srv\
+# stats\
+ syscall\
+ tail\
+ tee\
+ test\
+ wc\
+ xd\
+
+8.multi:V: mkmulti mkfile
+ mkmulti $PIECES
+ ls -l 8.multi
+ ls -l /386/bin/$PIECES | awk '{s += $6} END{print s}'
+
+scripts:V:
+ rm -rf ../../pc/multi
+ mkdir ../../pc/multi
+ for(i in $PIECES){
+ b=`{basename $i}
+ echo '#!/bin/multi' >>../../pc/multi/$b
+ chmod +x ../../pc/multi/$b
+ }
+
+BIN=/sys/lib/dist/bin/$objtype
+</sys/src/cmd/mkmany
+
--- /dev/null
+#!/bin/rc
+
+targ=multi
+
+n=0
+dir=`{pwd}
+
+fn grab {
+ echo using $*
+ for(i){
+ n=`{echo 1+$n|hoc}
+ mv $i $dir/a.$n.8
+ }
+}
+
+fn getfiles {
+ sed -n 's/^(pcc|8\^l|8l) +(-o [^ ]* +)?([^\-].*)/ \3/p' | sed 's/ -[^ ]*//g' |
+ sed 's/ [^ ]*\.a//g'
+}
+
+rm a.*.8
+>multi.h
+>multiproto.h
+
+for(i){
+echo $i...
+ b=`{basename $i}
+ p=$b
+ if(~ $b [0-9]*)
+ p=_$b
+ echo void $p^_main'(int, char**);' >>$dir/multiproto.h
+ echo "$b", $p^_main, >>$dir/multi.h
+ d=`{basename -d $i}
+ if(~ $i disk/prep disk/fdisk){
+ cd /sys/src/cmd/disk/prep
+ rm 8.$b
+ files=`{mk 8.$b | getfiles}
+ }
+ if not if(test -d /sys/src/cmd/$i && @{cd /sys/src/cmd/$i && mk 8.out}){
+ cd /sys/src/cmd/$i
+ rm 8.out
+ files=`{mk 8.out | getfiles}
+ }
+ if not if(test -d /sys/src/cmd/$i && @{cd /sys/src/cmd/$i && mk 8.$b}){
+ cd /sys/src/cmd/$i
+ rm 8.out
+ files=`{mk 8.$b | getfiles}
+ }
+ if not if(test -d /sys/src/cmd/$d && @{cd /sys/src/cmd/$d && mk 8.$b}){
+ cd /sys/src/cmd/$d
+ rm 8.$b
+ files=`{mk 8.$b | getfiles}
+ }
+ if not{
+ echo do not know how to make $i
+ exit oops
+ }
+ aux/8prefix $p^_ $files
+ grab $files
+ switch(`{pwd}){
+ case /sys/src/cmd /sys/src/cmd/aux /sys/src/cmd/ip
+ rm 8.$b
+ case *
+ mk clean
+ }
+}
+cd $dir
+8c -FVw multi.c
+8l -o 8.$targ multi.8 a.*.8
+# rm a.*.8
--- /dev/null
+#include <u.h>
+#include <libc.h>
+
+#include "multiproto.h"
+struct {
+ char *name;
+ void (*fn)(int, char**);
+} mains[] =
+{
+#include "multi.h"
+};
+
+void
+main(int argc, char **argv)
+{
+ int i;
+ char *cmd, *p;
+
+ if(argc == 1){
+ fprint(2, "usage: multi cmd args...\n");
+ exits("usage");
+ }
+
+ cmd = argv[1];
+ if(p = strrchr(cmd, '/'))
+ cmd = p+1;
+ argv++;
+ argc--;
+
+ for(i=0; i<nelem(mains); i++){
+ if(strcmp(cmd, mains[i].name) == 0){
+ mains[i].fn(argc, argv);
+ return;
+ }
+ }
+ fprint(2, "multi: no such cmd %s\n", cmd);
+ exits("no cmd");
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+
+void
+main(void)
+{
+ int fd, p[2];
+ char buf[8192], n;
+
+ pipe(p);
+ fd = create("/srv/log", OWRITE, 0666);
+ fprint(fd, "%d", p[0]);
+ close(fd);
+ close(p[0]);
+ while((n = read(p[1], buf, sizeof buf)) >= 0)
+ write(1, buf, n);
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+void
+Bpass(Biobuf *bin, Biobuf *bout, int n)
+{
+ char buf[8192];
+ int m;
+
+ while(n > 0) {
+ m = sizeof buf;
+ if(m > n)
+ m = n;
+ m = Bread(bin, buf, m);
+ if(m <= 0) {
+ fprint(2, "corrupt archive\n");
+ exits("notdone");
+ }
+ Bwrite(bout, buf, m);
+ n -= m;
+ }
+ assert(n == 0);
+}
+
+void
+main(int argc, char **argv)
+{
+ char *p, *f[10];
+ Biobuf bin, bout;
+ int nf;
+ ulong d, size;
+
+ if(argc != 2) {
+ fprint(2, "usage: cat mkfs-archive | touchfs date (in seconds)\n");
+ exits("usage");
+ }
+
+ d = strtoul(argv[1], 0, 0);
+
+ quotefmtinstall();
+ Binit(&bin, 0, OREAD);
+ Binit(&bout, 1, OWRITE);
+
+ while(p = Brdline(&bin, '\n')) {
+ p[Blinelen(&bin)-1] = '\0';
+ if(strcmp(p, "end of archive") == 0) {
+ Bprint(&bout, "end of archive\n");
+ exits(0);
+ }
+
+ nf = tokenize(p, f, nelem(f));
+ if(nf != 6) {
+ fprint(2, "corrupt archive\n");
+ exits("notdone");
+ }
+
+ Bprint(&bout, "%q %q %q %q %lud %q\n",
+ f[0], f[1], f[2], f[3], d, f[5]);
+
+ size = strtoul(f[5], 0, 0);
+ Bpass(&bin, &bout, size);
+ }
+ fprint(2, "premature end of archive\n");
+ exits("notdone");
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+void
+usage(void)
+{
+ fprint(2, "usage: unbflz [file]\n");
+ exits("usage");
+}
+
+int
+Bgetint(Biobuf *b)
+{
+ uchar p[4];
+
+ if(Bread(b, p, 4) != 4)
+ sysfatal("short read");
+ return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+}
+
+/*
+ * memmove but make sure overlap works properly.
+ */
+void
+copy(uchar *dst, uchar *src, int n)
+{
+ while(n-- > 0)
+ *dst++ = *src++;
+}
+
+void
+main(int argc, char **argv)
+{
+ Biobuf *b, bin;
+ char buf[5];
+ uchar *data;
+ ulong *blk, l;
+ int nblk, mblk;
+ int sum;
+ int i, j, length, m, n, o;
+
+ ARGBEGIN{
+ default:
+ usage();
+ }ARGEND
+
+ switch(argc){
+ default:
+ usage();
+ case 0:
+ Binit(&bin, 0, OREAD);
+ b = &bin;
+ break;
+ case 1:
+ if((b = Bopen(argv[0], OREAD)) == nil)
+ sysfatal("open %s: %r", argv[0]);
+ break;
+ }
+
+ if(Bread(b, buf, 4) != 4)
+ sysfatal("short read");
+
+ if(memcmp(buf, "BLZ\n", 4) != 0)
+ sysfatal("bad header");
+
+ length = Bgetint(b);
+ data = malloc(length);
+ if(data == nil)
+ sysfatal("out of memory");
+ sum = 0;
+ nblk = 0;
+ mblk = 0;
+ blk = nil;
+ while(sum < length){
+ if(nblk>=mblk){
+ mblk += 16384;
+ blk = realloc(blk, (mblk+1)*sizeof(blk[0]));
+ if(blk == nil)
+ sysfatal("out of memory");
+ }
+ l = Bgetint(b);
+ blk[nblk++] = l;
+ if(l&(1<<31))
+ l &= ~(1<<31);
+ else
+ blk[nblk++] = Bgetint(b);
+ sum += l;
+ }
+ if(sum != length)
+ sysfatal("bad compressed data %d %d", sum, length);
+ i = 0;
+ j = 0;
+ while(i < length){
+ assert(j < nblk);
+ n = blk[j++];
+ if(n&(1<<31)){
+ n &= ~(1<<31);
+ if((m=Bread(b, data+i, n)) != n)
+ sysfatal("short read %d %d", n, m);
+ }else{
+ o = blk[j++];
+ copy(data+i, data+o, n);
+ }
+ i += n;
+ }
+ write(1, data, length);
+ exits(nil);
+}
--- /dev/null
+{
+ verb[$4] = $3
+ data[$4] = sprintf("%s %s %s %s %s %s", $5, $6, $7, $8, $9, $10)
+}
+
+END{
+ for(i in verb)
+ if(verb[i] != "d")
+ printf("a %s %s\n", i, data[i]) |"sort +1"
+ close("sort +1")
+ for(i in verb)
+ if(verb[i] == "d")
+ printf("d %s %s\n", i, data[i]) |"sort -r +1"
+ close("sort -r +1")
+}
--- /dev/null
+{
+ printf("%s %d %s\n", t, NR, $0);
+}
--- /dev/null
+# /sys/lib/dist/mkfile
+src9=/n/sources/plan9 # what to export
+dist=/sys/lib/dist.old # where this machinery lives
+scr=/n/other/dist # scratch space before copying to web.protect
+# import /sys/lib/dist/web.protect from the outside
+x=`{setup}
+
+cd:V: $scr/plan9.iso
+
+ncd:V: $scr/plan9-new.iso.bz2
+
+ncd-dist:V: $scr/plan9-new.iso.bz2
+ mk $dist/web.protect/plan9-new.iso.bz2
+
+cd-dist:V: $scr/plan9.iso.bz2
+ mk $dist/web.protect/plan9.iso.bz2
+
+contrib-cd:V: $scr/contrib.iso.bz2
+ mk $dist/web.protect/contrib.iso.bz2
+
+$scr/%.iso:D: $src9/dist/replica/plan9.log
+ @ { cd pc; mk cddisk }
+ rm -f $target
+ bind pc/cddisk cdstub/bootdisk.img
+ if(! test -f $src9/bootdisk.img)
+ bind -a cdstub $src9
+ title=`{date | sed 's/(...) (...) (..) (..:..):.. (...) (....)/Plan 9 - \2 \3 \6 \4/'}
+ title=$"title
+ echo 'CD:' $title
+ disk/mk9660 -9cj -v $title -s $src9 -b bootdisk.img $target
+
+# copy compressed file from scratch space to the distribution, carefully
+$dist/web.protect/%.iso.bz2: $scr/%.iso.bz2
+ >>$target.new
+ chmod +t $target.new # waste write buf, not venti store
+ cp $prereq $target.new
+ # replace previous version with a flash cut
+ if (test -e $target)
+ mv $target $target.old # try to not clobber downloads in progress
+ mv $target.new $target
+
+cd-cleanup:V:
+ rm -f $dist/web.protect/*.iso.bz2.old # remove old versions after a delay
+
+# generate replica log & db for $src9 only
+scan:V:
+ test -d $scr # make sure other was mounted above
+ test -d $src9
+ test -d $dist/web.protect
+ lock scan.lock replica/scan $dist/sources.replica
+ chmod +t $src9/dist/replica/*.^(db log)
+
+# generate replica log & db for all of /n/sources
+scanall:V:
+ @ {
+ rfork ne
+ d=/n/sources
+ test -d $src9
+ lock scanall.lock replica/scan $dist/sourcesall.replica
+ chmod +t $src9/dist/replica/*.^(db log)
+ }
+
+compresslog:V:
+ {
+ awk -f logcompress.awk $src9/dist/replica/plan9.log |
+ awk -f logtime.awk -v 't='^`{date -n} >/tmp/plan9.log
+ rm -f $src9/dist/replica/plan9.new.log
+ cp /tmp/plan9.log $src9/dist/replica/plan9.new.log &&
+ mv $src9/dist/replica/plan9.new.log $src9/dist/replica/plan9.log
+ } <scan.lock
+
+#restart:V:
+# rm -f $src9/dist/replica/plan9.db
+# rm -f $src9/dist/replica/plan9.log
+# chmod 664 $src9/dist/replica/plan9.db >$src9/dist/replica/plan9.db
+# chmod 664 $src9/dist/replica/plan9.log >$src9/dist/replica/plan9.log
+# chmod +a $src9/dist/replica/plan9.log
+# mk scan
+
+odump:V:
+ disk/dump9660 -9cj -v 'Plan 9 4e Dumps' -s $src9 \
+ -p /sys/lib/sysconfig/proto/allproto $scr/distdump.iso
+
+cd.install:V:
+# if(~ $sysname achille){
+# echo; echo; echo '*** run this on a real machine, like chips.'
+# exit bad
+# }
+ bzip2 -9 <$scr/plan9.iso >web.protect/nplan9.iso.bz2
+
+D.install:V:
+ D=/n/roro/usr/rob/testplan9
+ 9fs roro
+ test -d $D
+ cp $D$dist/pc/ndisk $dist/web.protect/ndisk
+ cp $D$dist/pc/9loaddebug $dist/web.protect/n9loaddebug
+
+reallyinstall:V:
+ if(! ~ $sysname achille){
+ echo; echo; echo '*** this needs to run on achille.'
+ exit bad
+ }
+ cd web.protect
+ for (i in plan9.iso.bz2 disk 9loaddebug vmware.zip)
+ if(test -f n$i){
+ mv $i _$i && { mv n$i $i || mv _$i $i }
+ }
+ rm /srv/ramfs.9down4e
+ $dist/startcache
+
+dump:V:
+ rm -f /srv/9660.xxx
+ 9660srv 9660.xxx
+ mount /srv/9660.xxx /n/kremvax $scr/plan9.iso
+ now=`{mtime $dist/web.protect/plan9.iso.bz2 | awk '{print $1}'}
+ ls -l /rls/plan9/4e.iso
+ disk/dump9660 -9cj -s /n/kremvax -n $now /rls/plan9/4e.iso
+ ls -l /rls/plan9/4e.iso
+ rm /srv/9660.xxx
+
+reencode:V:
+ rm -f $scr/nplan9.iso
+ rm -f /srv/9660.xxx
+ 9660srv 9660.xxx
+ mount /srv/9660.xxx /n/kremvax $scr/plan9.iso
+ disk/mk9660 -9cj -v 'Plan 9 4th Edition' -s /n/kremvax \
+ -b bootdisk.img $scr/nplan9.iso
+ rm /srv/9660.xxx
+
+# compress a cd image in scratch space
+$scr/%.iso.bz2:D: $scr/%.iso
+ @ {
+ cd $scr
+ bzip2 -9 <$stem.iso >n$stem.iso.bz2 &&
+ {
+ if (test -e $stem.iso.bz2)
+ mv $stem.iso.bz2 _$stem.iso.bz2
+ mv n$stem.iso.bz2 $stem.iso.bz2
+ }
+ echo `{date} md5 `{md5sum <$stem.iso.bz2} \
+ sha1 `{sha1sum <$stem.iso.bz2} \
+ $stem.iso.bz2 >>/usr/web/plan9checksums.txt
+ }
+
+$scr/contrib.iso:DV:
+ rm -f $target
+ disk/mk9660 -9cj -v 'Plan 9 Extras' -s /n/sources \
+ -p ./contrib.proto $target
+
+rebuild:V:
+ chmod +l build.lock >>build.lock
+ rebuild <build.lock
+
+rebuild-mail:V:
+ chmod +l build.lock >>build.lock
+ rebuild <build.lock
+ datemail 'nightly build errors' 9trouble <buildit.out
+ datemail 'nightly build differences' 9trouble <checkbuild.out
+ status=''
+
+scansources-mail:V:
+ scansources | datemail 'nightly fs vs. sources scan' 9trouble
+
+worldwritable-mail:V:
+ test -e $src9
+ @ {cd /n/sources; /usr/rsc/bin/$cputype/lsr -t -d} |
+ awk '$2 ~ /[2367]$/' | grep -vf ok-writable |
+ datemail 'WRITABLE FILES ON SOURCES' 9trouble || status=''
+ status=''
+ @ {
+ cd $src9
+ /usr/rsc/bin/$cputype/lsr -t -d $src9
+ } |
+ awk '$2 ~ /[2367][^2367].$/' |
+ datemail 'non-group-writable files on sources' 9trouble
+ status=''
+ # use /n/boot to avoid walking the archives mounted under
+ # /lib/vac, or other mounts or binds.
+ rfork n
+ 9fs boot
+ test -e /n/boot/sys
+ /usr/rsc/bin/$cputype/lsr -t -d /n/boot/sys /n/boot/lib |
+ grep -v '/lib/audio/|/sys/src/cmd/vac/test/' | # give us a break
+ awk '$2 ~ /[2367][^2367].$/' |
+ datemail 'non-group-writable files on fs' 9trouble
+ status=''
+
+9.tar.gz:V:
+ @{
+ rfork n
+ 9fs sources
+ test -e $src9
+ bind -a $src9 $src9/sys/src
+ cd $src9/sys/src
+ tar c LICENSE NOTICE 9
+ } | gzip >$target
+
+9-export:V: 9.tar.gz
+ 9fs sources
+ cp 9.tar.gz /n/sources/extra/9.tgz
+ chmod +t /n/sources/extra/9.tgz
+
+plan9.tar.bz2:V:
+ @{
+ rfork n
+ 9fs sources
+ cd /n/sources
+ test -e $src9
+ bind /n/empty $src9/lib/font
+ bind /n/empty $src9/sys/lib/postscript/font
+ bind /n/empty $src9/sys/lib/ghostscript
+ bind /n/empty $src9/sys/src/cmd/gs
+ tar c plan9/LICENSE* plan9/NOTICE plan9/*/mkfile plan9/*/include \
+ plan9/acme/*/src plan9/acme/bin/source \
+ plan9/^(adm cron lib lp mail rc sys tmp usr)
+ } | bzip2 >$target
+
+plan9-export:V: plan9.tar.bz2
+ 9fs sources
+ chmod +t plan9.tar.bz2
+ mv plan9.tar.bz2 /n/sources/extra/plan9.tar.bz2
--- /dev/null
+#!/bin/rc
+
+window '0 0 100 100' games/clock
+window '80 80 610 360' /usr/glenda/lib/first.window
--- /dev/null
+#!/bin/rc
+echo -n readme > /dev/label
+echo 'You have completed the Installation Process.'
+
+cat<<'!'
+
+Welcome to Plan 9.
+This is rc.
+!
+
+exec rc
--- /dev/null
+if(test -f '#m/mousectl') {
+ echo -n accelerated > '#m/mousectl'
+ echo -n 'res 3' > '#m/mousectl'
+}
+user=`{cat /dev/user}
+home=/usr/$user
+bind -a $home/bin/rc /bin
+bind -a $home/bin/$cputype /bin
+bind -c $home/tmp /tmp
+rio -si inst/gui
+echo
+echo
+echo 'failed to start rio. you can start a text-based installation by running'
+echo
+echo ' inst/textonly'
+echo
--- /dev/null
+#!/bin/rc
+
+rfork e
+
+echo
+echo 'Insert a disk other than your installation boot disk'
+echo 'into your floppy drive; it will be erased to create'
+echo 'the boot floppy.'
+echo
+echo -n 'Press enter when ready.'
+read >/dev/null >[2]/dev/null
+
+if(~ $#adisk 1)
+ ; # do nothing
+if not if(~ $#bootfile 0)
+ adisk=/dev/fd0disk
+if not {
+ switch($bootfile) {
+ case sd*
+ adisk=`{echo $bootfile | sed 's#(sd..).*#/dev/\1/data#'}
+ case fd*
+ adisk=`{echo $bootfile | sed 's#(fd.).*#/dev/\1disk#'}
+ case *
+ echo 'unknown bootfile '^$bootfile^'; mail 9trouble@plan9.bell-labs.com'
+ exit oops
+ }
+}
+
+if(! ~ `{ls -l $adisk | awk '{print $6}'} 1474560){
+ echo 'Will not format non-floppy disk '^$"adisk. >[1=2]
+ exit 'bad adisk'
+}
+
+log Formatting boot floppy
+if (test -e /n/newfs/386/9loadnousb)
+ bind /n/newfs/386/9loadnousb /n/newfs/386/9load # cater to old bioses
+disk/format -b /386/pbs \
+ -fd $adisk /n/newfs/386/9load /n/newfs/386/9pcdisk.gz \
+ /tmp/plan9ini.bak
+x=$status
+
+if(~ $x ''){
+ echo
+ echo 'Done!'
+ echo
+}
+exit $x
--- /dev/null
+#!/bin/rc
+
+first=`{ls -p '#S' | sed 1q}
+if(! ~ $first $disk) {
+ echo 'warning: The plan 9 partition is not on the boot disk,'
+ echo 'so making it the active partition will have no effect.'
+}
+
+p9offset=`{grep '^part 9fat ' /dev/$disk/ctl |awk '{print $3}'}
+if(! ~ $#p9offset 1) {
+ echo 'could not find plan 9 partition.'
+ echo 'cannot happen'
+ exit bad
+}
+
+if(test $p9offset -gt 4128695) { # 65536 * 63 - 10
+ echo
+ echo 'Your Plan 9 partition is more than 2GB into your disk,'
+ echo 'and the master boot records used by Windows 9x/ME'
+ echo 'cannot access it (and thus cannot boot it).'
+ echo
+ echo 'You can install the Plan 9 master boot record, which can load'
+ echo 'partitions far into the disk.'
+ echo
+}
+
+echo 'If you use the Windows NT/2000/XP master boot record'
+echo 'or a master boot record from a Unix clone (e.g., LILO or'
+echo 'FreeBSD bootmgr), it is probably safe to continue using'
+echo 'that boot record rather than install the Plan 9 boot record.'
+echo
+prompt 'Install the Plan 9 master boot record' y n
+switch($rd) {
+case n
+ ;
+case y
+ disk/mbr -m /386/mbr /dev/$disk/data
+}
+
+log Setting Plan 9 partition active.
+p9part=`{disk/fdisk /dev/$disk/data >[2]/dev/null </dev/null |
+ grep PLAN9 | sed 1q | sed 's/ *(p.) .*/\1/'}
+if(~ $#p9part 0){
+ echo 'You have no Plan 9 partitions (How could this happen?)' >[1=2]
+ exit 'no plan 9 partition found'
+}
+p9part=$p9part(1)
+{ echo 'A '^$p9part; echo w } | disk/fdisk /dev/$disk/data >[2]/dev/null >/dev/null
+x=$status
+if(~ $x '' '|'){
+ echo
+ echo 'The Plan 9 partition is now marked as active.'
+ exit ''
+}
+exit $x
--- /dev/null
+#!/bin/rc
+
+# desc: create a boot floppy or configure hard disk to boot plan 9
+# prereq: copydist
+
+switch($1) {
+case go
+ echo
+ echo 'Initializing Plan 9 FAT configuration partition (9fat)'
+ echo
+
+ fat=(/dev/sd*/9fat)
+ fat=$fat(1)
+ disk=`{echo $fat | sed 's:/dev/::;s:/9fat::'}
+ bootfs=`{echo $fs | sed 's:/dev/(sd..)/(.*):\1!\2:'}
+ bootfat=`{echo $fs | sed 's:/dev/(sd..)/(.*):\1!9fat:'}
+ if(! test -f /dev/$disk/9fat) {
+ echo 'You have no 9fat partition. Can''t setup booting.'
+ exit
+ }
+
+ if(! test -f /tmp/plan9.ini) {
+ {
+ sfs=`{echo $fs | sed 's;/dev;#S;'}
+ if(~ $fstype fossil fossil+venti){
+ echo bootfile'='$bootfat!9pcf
+ echo 'bootargs=local!'^$sfs
+ echo 'bootdisk=local!'^$sfs
+ }
+ if not {
+ echo bootfile'='$bootfs!/386/9pcdisk
+ echo 'bootdisk=local!'^$sfs
+ }
+ if(~ $fstype fossil+venti){
+ venti=`{echo $ventiarena | sed 's;/dev;#S;'}
+ echo venti'='^$venti
+ }
+ # sort -u avoids dups which could otherwise trigger
+ # pointless boot menus.
+ grep -v '(^\[)|menuitem|adisk|bootfile|bootdisk|bootargs|nobootprompt|mouseport|vgasize|monitor|cdboot' /tmp/plan9.orig |
+ sort -u
+ echo 'mouseport='^$mouseport
+ echo 'monitor='^$monitor
+ echo 'vgasize='^$vgasize
+ } >/tmp/plan9.ini
+ }
+ if(! test -f /tmp/plan9ini.bak)
+ cp /tmp/plan9.ini /tmp/plan9ini.bak
+
+ need9fatformat=no
+ if(! isfat /dev/$disk/9fat)
+ need9fatformat=yes
+ if not if(! mount -c /srv/dos /n/9fat /dev/$disk/9fat >[2]/dev/null)
+ need9fatformat=yes
+ if not if(! test -f /n/9fat/plan9.ini)
+ need9fatformat=yes
+
+ if (test -e /n/newfs/386/9loadnousb)
+ bind /n/newfs/386/9loadnousb /n/newfs/386/9load # cater to old bioses
+ if(~ $need9fatformat yes){
+ log Initializing Plan 9 FAT partition.
+ disk/format -r 2 -d -b /386/pbs \
+ /dev/$disk/9fat /n/newfs/386/9load
+ # silently install pbslba if the partition is way into the disk.
+ # it''s our only hope. only need this for >8.5GB into the disk.
+ # but...
+ # there are so few non-LBA bioses out
+ # there anymore that we'll do this even if we're only 2GB into
+ # the disk. it's just not worth the headaches of dealing with
+ # crappy bioses that don't address the whole 8.5GB properly
+
+ 9fatoffset=`{grep '^part 9fat ' /dev/$disk/ctl | awk '{print $4}'}
+ if(! ~ $#9fatoffset 1) {
+ echo 'could not find plan 9 partition.'
+ echo 'cannot happen'
+ exit bad
+ }
+ if(test $9fatoffset -gt 2097152) # 2GB
+ disk/format -b /386/pbslba /dev/$disk/9fat
+
+ mount -c /srv/dos /n/9fat /dev/$disk/9fat
+ }
+
+ if(! test -f /n/9fat/4e){
+ logprog cp /n/newfs/386/9load /n/9fat/9load
+ logprog cp /n/newfs/386/9pcf /n/9fat/9pcf
+ if(test -f /n/9fat/plan9.ini && ! test -f /n/9fat/plan9-3e.ini)
+ logprog mv /n/9fat/plan9.ini /n/9fat/plan9-3e.ini
+ if(test -f /n/9fat/9pcdisk && ! test -f /n/9fat/9pc3e)
+ logprog mv /n/9fat/9pcdisk /n/9fat/9pc3e
+
+ awk -f /bin/inst/mkini.awk >/n/9fat/plan9.ini
+ >/n/9fat/4e
+ }
+
+ echo
+ echo 'There are myriad ways to boot a Plan 9 system.'
+ echo 'You can use any of the following.'
+ echo
+ echo ' floppy - create a boot floppy'
+ echo ' plan9 - make the plan 9 disk partition the default for booting'
+ echo ' win9x - add a plan 9 option to windows 9x boot menu'
+ echo ' winnt - add a plan 9 option to windows nt/2000/xp boot manager'
+ echo
+ echo 'If you are upgrading an extant third edition installation and booting'
+ echo 'from something other than a floppy, you needn''t run anything here.'
+ echo 'Just type ctl-d.'
+
+ oldbootsetup=$didbootsetup
+ didbootsetup=1
+ export didbootsetup
+ prompt 'Enable boot method' floppy plan9 win9x winnt
+
+ if(! boot$rd){
+ didbootsetup=$oldbootsetup
+ export didbootsetup
+ }
+
+case checkdone
+ xxxfat=(/dev/sd*/9fat)
+ if(! isfat $xxxfat(1) || ! ~ $didbootsetup 1){
+ bootsetup=ready
+ export bootsetup
+ }
+}
--- /dev/null
+#!/bin/rc
+
+dosdisk=`{ls /dev/sd??/dos >[2]/dev/null | sed 1q | sed 's!.*/(.*)/dos!\1!'}
+if(~ $#dosdisk 0 || ! c: || ! test -f /n/c:/autoexec.bat || ! test -f /n/c:/config.sys) {
+ echo 'Could not find autoexec.bat or config.sys on the first FAT disk.'
+ exit bad
+}
+
+for (i in autoexec config msdos)
+ if(test -f /n/c:/$i.p9) {
+ echo 'A Plan 9 backup already exists; will not edit system files again.'
+ exit bad
+ }
+
+for (i in autoexec.bat config.sys msdos.sys)
+ if(! cp /n/c:/$i /n/c:/^`{echo $i | sed 's/\.(bat|sys)$/.p9/'}) {
+ echo 'Could not back up '^$i^'; will not continue.'
+ exit bad
+ }
+
+if(! test -d /n/c:/plan9 && ! mkdir /n/c:/plan9) {
+ echo 'Could not create directory /n/c:/plan9.'
+ exit bad
+}
+
+if(! cp /n/newfs/386/^(9load ld.com 9pcdisk) /tmp/plan9ini.bak /n/c:/plan9) {
+ echo 'Could not copy Plan 9 boot files into /n/c:/plan9.'
+ exit bad
+}
+
+chmod +w /n/c:/autoexec.bat /n/c:/config.sys /n/c:/msdos.sys
+
+if(grep -si 'Plan ?9' /n/c:/config.sys || grep -si 'Plan ?9' /n/c:/autoexec.bat) {
+ echo 'Plan 9 entries already in config.sys or autoexec.bat.'
+ echo 'Not changing them; refer to Plan 9 install documentation'
+ echo 'to configure manually.'
+ exit bad
+}
+
+if(! grep -si '\[menu\]' /n/c:/config.sys) {
+ {
+ echo 1
+ echo i
+ echo '[menu]\r'
+ echo 'menuitem=windows, Windows\r'
+ echo 'menudefault=windows\r'
+ echo '\r'
+ echo '[common]\r'
+ echo '\r'
+ echo '[windows]\r'
+ echo .
+ echo w
+ echo q
+ } | ed /n/c:/config.sys >/dev/null >[2]/dev/null
+}
+
+{
+ echo 1
+ echo '/\[[Mm][Ee][Nn][Uu]\]'
+ echo '?^[Mm][Ee][Nn][Uu][Ii][Tt][Ee][Mm]='
+ echo a
+ echo 'menuitem=plan9, Plan 9 from Bell Labs\r'
+ echo .
+ echo '$'
+ echo a
+ echo '\r'
+ echo '[plan9]\r'
+ echo '\r'
+ echo .
+ echo w
+ echo q
+} | ed /n/c:/config.sys >/dev/null>[2]/dev/null
+
+{
+ echo 1
+ echo i
+ echo '@echo off\r'
+ echo 'if %config%==plan9 goto plan9\r'
+ echo 'goto notplan9\r'
+ echo ':plan9\r'
+ echo 'plan9\ld '^$dosdisk^'!dos!plan9/9load\r'
+ echo ':notplan9\r'
+ echo .
+ echo w
+ echo q
+} | ed /n/c:/autoexec.bat >/dev/null>[2]/dev/null
+
+fn zeroopt {
+ if(grep -s '^'^$1^'=1' /n/c:/msdos.sys) {
+ {
+ echo '/^'^$1^'=1/s/=1/=0/'
+ echo w
+ echo q
+ } | ed /n/c:/msdos.sys>/dev/null>[2]/dev/null
+ }
+ if not if (grep -s '^'^$1^'=0' /n/c:/msdos.sys)
+ ;
+ if not {
+ {
+ echo 1
+ echo i
+ echo '[Options]\r'
+ echo 'Logo=0\r'
+ echo .
+ echo w
+ echo q
+ } | ed /n/c:/msdos.sys>/dev/null>[2]/dev/null
+ }
+}
+
+if(grep -si '^\[paths\]' /n/c:/msdos.sys){ # Windows 9x rather than DOS
+ zeroopt Logo
+# zeroopt BootGUI
+}
+
+echo 'Plan 9 added to Windows 9X boot menu.'
+exit ''
--- /dev/null
+#!/bin/rc
+
+if(! c: || ! test -f /n/c:/boot.ini) {
+ echo 'Could not find NT''s boot.ini on the first FAT disk.'
+ exit bad
+}
+
+if(test -f /n/c:/boot.p9) {
+ echo 'A Plan 9 backup already exists; will not edit boot.ini again.'
+ exit bad
+}
+
+if(! cp /n/c:/boot.ini /n/c:/boot.p9) {
+ echo 'Could not back up boot.ini; will not continue.'
+ exit bad
+}
+
+chmod +w /n/c:/boot.ini
+
+if(! grep -si '\[operating systems\]' /n/c:/boot.ini) {
+ echo 'Could not parse boot.ini.'
+ exit bad
+}
+
+if(grep -si 'Plan 9' /n/c:/boot.ini) {
+ p9file=`{grep 'Plan 9' /n/c:/boot.ini | sed 1q | sed 's/=.*//'}
+ if(! ~ $p9file [Cc]:'\'*) {
+ echo 'Unexpected Plan 9 entry in boot.ini already; not continuing.'
+ exit bad
+ }
+}
+
+if not {
+ p9file='c:\bootsect.p9'
+ echo 'c:\bootsect.p9 = "Plan 9 from Bell Labs"\r' >>/n/c:/boot.ini
+}
+
+p9file=/n/^`{echo $p9file | sed 's!\\!/!g'}
+
+
+if(dd -if /dev/$disk/plan9 -bs 512 -count 1 -of $p9file >/dev/null >[2]/dev/null) {
+ echo 'Plan 9 added to Windows NT boot menu.'
+ exit ''
+}
+
+echo 'Error copying Plan 9 boot sector to file.'
+exit bad
--- /dev/null
+#!/bin/rc
+
+# desc: set source of distribution archives
+# prereq: mountfs
+
+switch($1) {
+case go
+ echo
+ echo 'Will you be using a distribution archive on local media or the internet?'
+ echo
+
+ prompt 'Distribution is from' local internet
+ archmedium=$rd
+ export archmedium
+
+ switch($archmedium) {
+ case local
+ exec configlocal go
+ case internet
+ exec configip go
+ }
+
+case checkdone
+ switch($#archmedium) {
+ case 1
+ switch($archmedium) {
+ case local
+ exec configlocal checkdone
+ case internet
+ exec configip checkdone
+ case *
+ configarch=notdone
+ export configarch
+ }
+ case *
+ configarch=notdone
+ export configarch
+ }
+}
+
--- /dev/null
+#!/bin/rc
+
+# prereq: mountfs
+# desc: choose the source of the distribution archive
+
+switch($1){
+case checkdone
+ if(! ~ $distisfrom net local){
+ configdist=ready
+ export configdist
+ }
+
+case go
+ echo 'Are you going to download the distribution'
+ echo 'from the internet or do you have it on local media?'
+ echo
+ prompt -d local 'Distribution is from' local net
+ distisfrom=$rd
+ export distisfrom
+}
+
+
--- /dev/null
+#!/bin/rc
+
+# desc: configure your internet connection via an ethernet card
+
+switch($1) {
+case go
+ echo
+ echo 'Please choose a method for configuring your ethernet connection.'
+ echo
+ echo ' manual - specify IP address, network mask, gateway IP address'
+ echo ' dhcp - use DHCP to automatically configure'
+ echo
+
+ prompt 'Configuration method' manual dhcp
+ ethermethod=$rd
+ gwaddr=xxx
+ ipaddr=xxx
+ ipmask=xxx
+ switch($ethermethod){
+ case dhcp
+ echo
+ echo 'Some ISPs, notably @HOME, require a host name passed with DHCP'
+ echo 'requests. An example for @HOME would be "cc1018221-a". If your'
+ echo 'ISP supplied you such a name, enter it.'
+ echo
+ prompt -d none 'host name'; dhcphost=$rd
+ switch($dhcphost){
+ case none
+ dhcphost=();
+ case *
+ dhcphost=(-h $dhcphost)
+ }
+ export dhcphost
+ case manual
+ prompt 'ip address'; ipaddr=$rd
+ prompt 'network mask'; ipmask=$rd
+ prompt 'gateway address'; gwaddr=$rd
+ export ipaddr ipmask gwaddr
+ }
+
+ export ethermethod gwaddr ipaddr ipmask dhcphost
+ exec startether go
+
+case checkdone
+ if(! ~ $ethermethod manual dhcp) {
+ configether=notdone
+ export configether
+ }
+ if(~ $ethermethod manual && ~ 0 $#ipaddr $#ipmask $#gwaddr) {
+ configether=notdone
+ export configether
+ }
+}
--- /dev/null
+#!/bin/rc
+
+# desc: choose the type of file system to install
+
+switch($1){
+case checkdone
+ if(! ~ $fstype fossil fossil+venti){
+ configfs=ready
+ export configfs
+ }
+
+case go
+ echo 'You can install the following types of file systems:'
+ echo
+ echo ' fossil the new Plan9 fileserver'
+ echo ' fossil+venti fossil + a archival dump server'
+ echo
+ prompt -d fossil 'File system' fossil fossil+venti
+ fstype=$rd
+ export fstype
+}
+
+
--- /dev/null
+#!/bin/rc
+
+switch($1) {
+case go
+
+ devs=''
+ if(test -d '#l/ether0' >[2]/dev/null)
+ devs=$devs^ether
+ if(test -f '#t'/eia? >[2]/dev/null)
+ devs=$devs^ppp
+
+ switch($devs){
+ case ''
+ echo
+ echo 'Could not find ethernet card nor serial port nor modem.'
+ echo 'Please use a local copy of the distribution archive.'
+ echo
+ ifc=none
+
+ case ppp
+ echo
+ echo 'No ethernet card was detected, but there is a serial port or modem.'
+ echo 'We will configure PPP.'
+ echo
+ ifc=ppp
+
+ case ether
+ echo
+ echo 'No serial port or modem detected, but there is an ethernet card.'
+ echo 'We will configure the ethernet.'
+ echo
+ ifc=ether
+
+ case etherppp
+ echo
+ echo 'You can connect to the internet via'
+ echo 'a local ethernet or a dial-up PPP connection.'
+ echo
+ prompt 'Interface to use' ether ppp
+ ifc=$rd
+ }
+
+ ipinterface=$ifc
+ export ipinterface
+
+ switch($ifc) {
+ case ether
+ exec configether go
+ case ppp
+ exec configppp go
+ }
+
+case checkdone
+ if(~ $#ipinterface 1)
+ switch($ipinterface) {
+ case ether
+ exec configether checkdone
+ case ppp
+ exec configppp checkdone
+ }
+ configarch=notdone
+ export configarch
+
+}
--- /dev/null
+#!/bin/rc
+
+# prereq: configdist
+# desc: configure the network to download the distribution
+
+switch($1){
+case checkready checkdone
+ if(! ~ $distisfrom net){
+ confignet=notdone
+ export confignet
+ exit
+ }
+ if(~ $distisfrom net && ~ $netisfrom ppp ether){
+ x=config$netisfrom
+ $x=done
+ config$netisfrom checkdone
+ confignet=$$x
+ export confignet
+ exit
+ }
+ confignet=ready
+ export confignet
+ exit
+
+case go
+ devs=''
+ if(test -d '#l/ether0' >[2]/dev/null)
+ devs=$devs^ether
+ if(test -f '#t'/eia? >[2]/dev/null)
+ devs=$devs^ppp
+
+ switch($devs){
+ case ''
+ echo
+ echo 'Could not find ethernet card nor serial port nor modem.'
+ echo 'Please use a local copy of the distribution archive.'
+ echo
+ netisfrom=none
+
+ case ppp
+ echo
+ echo 'No ethernet card was detected, but there is a serial port or modem.'
+ echo 'We will configure PPP.'
+ echo
+ netisfrom=ppp
+
+ case ether
+ echo
+ echo 'No serial port or modem detected, but there is an ethernet card.'
+ echo 'We will configure the ethernet.'
+ echo
+ netisfrom=ether
+
+ case etherppp
+ echo
+ echo 'You can connect to the internet via'
+ echo 'a local ethernet or a dial-up PPP connection.'
+ echo
+ prompt 'Interface to use' ether ppp
+ netisfrom=$rd
+ }
+
+ export netisfrom
+ if(~ $netisfrom ether ppp)
+ exec config$netisfrom go
+}
+
--- /dev/null
+#!/bin/rc
+
+# desc: configure your internet connection via ppp over a modem
+
+switch($1) {
+case go
+ devs=`{ls -p '#t/'eia? >[2]/dev/null}
+ if(~ $#devs 0) {
+ echo 'No serial port found; this can''t happen.' # because configip checks
+ exit
+ }
+
+ # not going to use the mouse for PPP
+ if(~ eia^$mouseport $devs)
+ devs=`{echo $devs | sed 's/eia'^$mouseport^'//'}
+
+ if(~ $#devs 0) {
+ echo 'The only serial port you have is your mouse.'
+ echo 'Cannot configure PPP.'
+ exit
+ }
+
+ echo
+ echo 'Please choose the serial port or modem to use to connect to your ISP.'
+ echo
+ for(i in $devs) {
+ n=`{echo $i | sed 's/eia//'}
+ n=`{hoc -e 1+$n}
+ echo ' '^$i^'(Windows'' COM'^$n^')'
+ }
+ echo
+ prompt 'Serial device' $devs
+ pppdev=$rd
+
+ echo
+ echo 'Pick a baud rate for the PPP connection.'
+ echo
+ prompt -d 115200 'Baud rate'
+ pppbaud=$rd
+
+ echo
+ echo 'You can specify your dialup phone number, username, and password,'
+ echo 'or you can log in manually by typing the modem commands yourself.'
+ echo
+ prompt 'Dialing method' auto manual
+ pppmethod=$rd
+
+ switch($pppmethod){
+ case auto
+ prompt 'PPP phone number'; pppphone=$rd
+ prompt 'PPP phone username'; pppuser=$rd
+ prompt 'PPP phone password'; ppppasswd=$rd
+ }
+
+ export pppdev pppmethod pppphone ppppasswd pppuser pppbaud
+ exec startppp go
+
+case checkdone
+ if(! ~ $#pppmethod 1 || ! test -f /dev/$pppdev){
+ configppp=notdone
+ export configppp
+ }
+}
--- /dev/null
+#!/bin/rc
+
+# prereq: mountdist
+# desc: copy the distribution into the file system
+
+switch($1){
+case checkready
+ if(! test -d /n/dist/dist/replica){
+ copydist=notdone
+ export copydist
+ exit
+ }
+ if(test -f /n/newfs/dist/replica/didplan9){
+ copydist=done
+ export copydist
+ exit
+ }
+case go
+ inst/watchfd applylog 0 `{ls -l /n/dist/dist/replica/plan9.log | awk '{print $6}'} 'Installing file system' &
+ replica/pull -c / /rc/bin/inst/replcfg
+ if(~ $status '' *conflicts || test -f /n/newfs/dist/replica/didplan9witherrors)
+ >/n/newfs/dist/replica/didplan9
+ if not
+ >/n/newfs/dist/replica/didplan9witherrors
+
+case checkdone
+ if(! test -f /n/newfs/dist/replica/didplan9){
+ copydist=notdone
+ export copydist
+ }
+}
--- /dev/null
+nl='
+'
+tab=' '
+if(~ $#distname 0)
+ distname=plan9
+
+wctl=/dev/null
+if(test -w /dev/wctl)
+ wctl=/dev/wctl
+
+fn log {
+ echo $* >>/srv/log
+}
+
+fn logprog {
+ echo '% '^$"* >>/srv/log
+ $* >[2=1] >>/srv/log
+}
+
+fn sigint {
+ # nothing happens
+}
+
+fn prompt {
+ def=()
+ what=()
+ if(~ $1 -d && ! ~ $#* 1){
+ def=$2
+ shift
+ shift
+ }
+
+ optstr=()
+ if(~ $1 -w && ! ~ $#* 1){
+ optstr=$2
+ shift
+ shift
+ }
+
+ pr=$1
+ shift
+
+ opts=($*)
+ if(~ $#opts 0) {
+ suf=' '
+ }
+ if not if(! ~ $#optstr 0) {
+ if(~ $optstr '')
+ suf=' '
+ if not {
+ pr=$pr^' ('^$"optstr^')'
+ suf=''
+ }
+ }
+ if not {
+ pr=$pr^' ('^$1
+ shift
+ for(i)
+ pr=$pr^', '^$i
+ pr=$pr^')'
+ suf=''
+ }
+
+ if(~ $#def 1)
+ pr=$pr^$suf^'['^$def^']'
+ if not
+ pr=$pr^$suf^'[no default]'
+
+ pr=$pr^': '
+
+
+ okay=no
+ while(~ $okay no) {
+ echo -n current >$wctl
+ echo -n top >$wctl
+ echo -n $pr >[1=2]
+ ifs='' {rd=`{read}}
+ if(~ $#rd 0)
+ exit notdone
+ if(~ $rd !*){
+ ifs='' {rd=`{echo $rd | sed 's/!//'}}
+ echo $rd
+ rc -c $rd
+ echo !$status
+ }
+ if not{
+ rd=`{echo $rd}
+ if(~ $#rd 0 || ~ $rd '')
+ rd=$def
+
+ switch($#opts){
+ case 0
+ if(! ~ $rd '')
+ okay=yes
+ case *
+ if(~ $rd $opts)
+ okay=yes
+ }
+ }
+ }
+ echo -n $rd >/env/rd # just in case
+}
+
+fn desc {
+ echo -n ' '^$1^' - '
+ grep '^# desc: ' $1 | sed 's/# desc: //'
+}
+
+fn prereq {
+ grep '^# prereq:' $1 | sed 's/# prereq://'
+}
+
+fn mustdo {
+ echo You must `{grep '^# mustdo:' $1 | sed 's/# mustdo://'}
+}
+
+# there's no easy way to pass shell variables
+# up from children to parents; the parents have
+# to be coerced into noticing that the environment
+# changed, even when in the same environment group.
+#
+# instead, we explicitly export the variables we want
+# to percolate, and the parent calls coherence to reread
+# the variables.
+#
+# we just append to the vars file, so that later exports
+# override earlier ones; when we call coherence,
+# the duplicates are thrown out.
+
+fn export {
+ null=()
+ nonnull=()
+ for(i in $*){
+ if(~ $#$i 0)
+ null=($null $i)
+ if not
+ nonnull=($nonnull $i)
+ }
+ if(! ~ $#nonnull 0)
+ whatis $nonnull |grep -v '^\./' >>/tmp/vars >[2]/dev/null
+ for(i in $null)
+ echo $i^'=()' >>/tmp/vars
+}
+
+fn coherence {
+ if(test -f /tmp/vars) {
+ grep '^[a-z]*=' /tmp/vars >/tmp/vars2
+ v=`{sed 's/^([a-z]*)=.*/\1/' /tmp/vars2 | sort -u}
+ . /tmp/vars2
+ rm /tmp/vars2
+ rm /tmp/vars
+ export $v
+ }
+}
+
+# ip device stats
+
+fn isipdevup {
+ grep -s $1 /net/ipifc/*/status >[2]/dev/null
+}
+
+
--- /dev/null
+#!/bin/rc
+
+# prereq: mountfs
+# desc: download or continue to download the distribution archives
+
+switch($1) {
+case checkready
+ devs=(`{cat /net/ipifc/*/status >[2]/dev/null |
+ grep -v '127\.0\.0\.1' |
+ sed 's/ .*//'})
+ if(~ $#devs 0) {
+ download=notdone
+ export download
+ }
+ if(~ $mountdist done){
+ download=notdone
+ export download
+ }
+
+case go
+ if(! test -f /srv/cs) {
+ log starting cs, dns
+ logprog ndb/cs >>/srv/log >[2=1]
+ logprog ndb/dns -r >>/srv/log >[2=1]
+ }
+ if(! test -f /net/cs) {
+ logprog mount -a /srv/cs /net
+ logprog mount -a /srv/dns /net
+ }
+
+ # BUG make restartable
+ echo 'Downloading distribution package...'
+ baropt='-w 145,129,445,168'
+ if(~ $textinst 1)
+ baropt=-t
+ if(! hget -vo /n/newfs/dist/_plan9.iso.bz2 $installurl/plan9.iso.bz2 |[2] bargraph $baropt 'downloading '^plan9.iso.bz2)
+ exit
+ mv /n/newfs/dist/_plan9.iso.bz2 /n/newfs/dist/plan9.iso.bz2
+ if(~ $fstype fossil){
+ echo fsys main sync >>/srv/fscons
+ }
+
+ echo 'The distribution is downloaded.'
+
+ srvmedia=()
+ mountmedia=(mount /srv/fossil /n/distmedia)
+ distmediadir=/dist
+ export distmediadir mountmedia distmedia
+
+case checkdone
+ if(! test -f /n/newfs/dist/plan9.iso.bz2) {
+ download=notdone
+ export download
+ }
+}
+
--- /dev/null
+#!/bin/rc
+
+# desc: finish the installation and reboot
+# prereq: bootsetup
+# mustdo:
+
+switch($1) {
+case checkdone
+ finish=ready
+ export finish
+
+case go
+ if(~ $cdboot yes){
+ echo 'Congratulations; you''ve completed the install.'
+ echo
+ halt
+ }
+ stop go finished
+}
--- /dev/null
+#!/bin/rc
+
+# desc: initialize disks for a fossil server
+# prereq: configfs
+
+switch($1){
+case checkready checkdone
+ if(! ~ $fstype fossil+venti fossil){
+ fmtfossil=notdone
+ export fmtfossil
+ exit
+ }
+ ff=`{ls /dev/sd*/fossil* /dev/fs/fossil* >[2]/dev/null}
+ if(~ $#ff 0){
+ fmtfossil=notdone
+ export fmtfossil
+ exit
+ }
+ gg=()
+ for(f in $ff)
+ if(isfossil $f)
+ gg=($gg $f)
+ if(~ $#gg 0){
+ fmtfossil=ready
+ export fmtfossil
+ exit
+ }
+ fmtfossil=done
+ export fmtfossil
+ exit
+
+case go
+ ff=`{ls /dev/sd*/fossil* /dev/fs/fossil* >[2]/dev/null}
+ if(~ $#ff 0){
+ echo 'You need to create a partition or partitions to hold the Fossil write cache.'
+ echo 'The partition name must begin with "fossil".'
+ echo
+ fmtfossil=notdone
+ export fmtfossil
+ exit
+ }
+ default=()
+ if(~ $#ff 1){
+ default=(-d $ff)
+ }
+ echo You have the following fossil partitions.
+ echo
+ prompt $default 'Fossil partition to format' $ff
+ f=$rd
+
+ do=yes
+ if(isfossil $f){
+ echo $f appears to already be formatted as Fossil file system.
+ echo Do you really want to reformat it?
+ echo
+ prompt -d no 'Reformat '$f yes no
+ do=$rd
+ }
+ if(~ $do yes){
+ fossil/flfmt -y $f
+ n=`{cat /dev/swap | grep ' user' | sed 's/^[0-9]+\/([0-9]+) .*/\1/'}
+ if(test $n -gt 32768)
+ m=3000 # if have at least 128 user MB, use 24MB for fossil
+ if not if(test $n -gt 16384)
+ m=1500 # 64 user MB => 12MB for fossil
+ if not if(test $n -gt 8192)
+ m=750 # 32 user MB => 6MB for fossil
+ if not
+ m=256 # 2MB for fossil (this will be slow)
+
+ # if we're using a venti in the back, take hourly snapshots
+ # that retire after three days, in addition to the daily dumps at 5am
+ if(~ $fstype fossil+venti){
+ v=''
+ snap='fsys main snaptime -s 60 -a 0500 -t 2880'
+ }
+ # otherwise, take the daily dumps but nothing else --
+ # we can't retire snapshots unless dumps are being archived
+ if not{
+ v='-V'
+ snap=''
+ }
+ echo \
+'fsys main config '^$f^'
+fsys main open '^$v^' -c '^$m^'
+'^$snap^'
+' | fossil/conf -w $f
+ }
+
+ echo Done.
+}
--- /dev/null
+#!/bin/rc
+
+# desc: initialize disks for a venti server
+# prereq: mountdist
+
+switch($1){
+case checkready checkdone
+ if(! ~ $fstype fossil+venti){
+ fmtventi=notdone
+ export fmtventi
+ exit
+ }
+ if(! test -e /bin/venti/fmtarenas || ! test -e /bin/venti/fmtisect || ! test -e /bin/venti/fmtindex){
+ bind -a /n/dist/386/bin/venti /bin/venti
+ if(! test -e /bin/venti/fmtarenas || ! test -e /bin/venti/fmtisect || ! test -e /bin/venti/fmtindex){
+ fmtventi=notdone
+ export fmtventi
+ exit
+ }
+ }
+ ff=`{ls /dev/sd*/arenas* /dev/fs/arenas* >[2]/dev/null}
+ if(~ $#ff 0){
+ fmtventi=notdone
+ export fmtventi
+ exit
+ }
+ gg=()
+ for(f in $ff)
+ if(isventi $f)
+ gg=($gg $f)
+ if(~ $#gg 0){
+ fmtventi=ready
+ export fmtventi
+ exit
+ }
+
+ ventiarena=$gg(1)
+ export ventiarena
+
+ fmtventi=done
+ export fmtventi
+ exit
+
+case go
+ ff=`{ls /dev/sd*/arenas* /dev/fs/arenas* >[2]/dev/null}
+ if(~ $#ff 0){
+ echo 'You need to create a partition or partitions to hold the Venti arenas.'
+ echo 'The arena partition names must begin with "arenas".'
+ echo
+ fmtventi=notdone
+ export fmtventi
+ exit
+ }
+ default=(-d $"ff)
+ if(! ~ $#ventiarena 0){
+ default=(-d $"ventiarena)
+ }
+ echo You have the following Venti arena partitions.
+ ls -l $ff
+ echo
+
+ prompt $default 'Venti arena partitions to use'
+ aa=`{echo $rd}
+ bad=no
+ for(a in $aa){
+ if(! ~ $a $ff){
+ echo 'Bad venti arena partition' $a
+ fmtventi=notdone
+ export fmtventi
+ exit
+ }
+ }
+ ventiarena=$aa
+ export ventiarena
+
+ gg=`{ls /dev/sd*/isect* /dev/fs/isect* >[2]/dev/null}
+ if(~ $#gg 0){
+ echo 'You need to create a partition or partitions to hold the Venti indices.'
+ echo 'The index partition names must begin with "isect".'
+ echo
+ fmtventi=notdone
+ export fmtventi
+ exit
+ }
+ default=(-d $"gg)
+ if(! ~ $#ventiindex 0){
+ default=(-d $"ventiindex)
+ }
+
+ echo You have the following Venti index partitions.
+ ls -l $gg
+ echo
+
+ prompt $default 'Venti index partitions to use'
+ aa=`{echo $rd}
+ bad=no
+ for(a in $aa){
+ if(! ~ $a $gg){
+ echo 'Bad venti index partition' $a
+ fmtventi=notdone
+ export fmtventi
+ exit
+ }
+ }
+ ventiindex=$aa
+ export ventiindex
+
+ n=-1
+ fmta=()
+ for(a in $ventiarena){
+ do=yes
+ n=`{hoc -e 1+$n}
+ if(isventiarenas $a){
+ echo File $a is already formatted as a Venti arenas partition.
+ prompt -d no 'Reformat '$a yes no
+ do=$rd
+ }
+ if(~ $do yes)
+ fmta=($fmta arenas$n:$a)
+ }
+
+ n=-1
+ fmti=()
+ for(a in $ventiindex){
+ do=yes
+ n=`{hoc -e 1+$n}
+ if(isventiisect $a){
+ echo File $a is already formatted as a Venti index section.
+ prompt -d no 'Reformat '$a yes no
+ do=$rd
+ }
+ if(~ $do yes)
+ fmti=($fmti isect$n:$a)
+ }
+
+ echo Formatting Venti arenas and indices (this takes a while).
+ # do each disk in parallel
+ echo good >/tmp/fmt
+ dd=()
+ for(a in $fmta $fmti){
+ d=`{echo $a | sed 's!.*:(/.*/).*!\1!'}
+ if(! ~ $d $dd)
+ dd=($dd $d)
+ }
+ for(d in $dd){
+ {
+ for(a in $fmta){
+ i=`{echo $a | sed 's!(.*):(/.*/)(.*)!\1 \2 \2\3!'}
+ if(~ $i(2) $d){
+ echo $i(3) ...
+ venti/fmtarenas $i(1) $i(3) || echo bad >/tmp/fmt
+ echo done with $i(3)
+ }
+ }
+ for(a in $fmti){
+ i=`{echo $a | sed 's!(.*):(/.*/)(.*)!\1 \2 \2\3!'}
+ if(~ $i(2) $d){
+ echo $i(3) ...
+ venti/fmtisect $i(1) $i(3) || echo bad >/tmp/fmt
+ echo done with $i(3)
+ }
+ }
+ } &
+ }
+ wait
+ if(~ bad `{cat /tmp/fmt}){
+ echo There were errors formatting the indices and arenas.
+ fmtventi=ready
+ export fmtventi
+ exit errors
+ }
+
+ echo Done formatting Venti arenas and indices.
+
+ v=$ventiarena(1)
+ echo Storing Venti config on $v...
+ {
+ echo index main
+ for(i in $ventiindex)
+ echo isect $i
+ for(a in $ventiarena)
+ echo arenas $a
+ } | venti/conf -w $v
+
+ echo Initializing index...
+ venti/fmtindex $v
+
+ echo Done with Venti!
+}
+
--- /dev/null
+#!/bin/rc
+
+cd /bin/inst
+echo blanktime 0 >/dev/vgactl
+. defs
+
+startwin 640 480
--- /dev/null
+#!/bin/rc
+
+echo -n 'Halting file systems...'
+
+if(ps | grep -s ' venti$')
+ venti/sync -h tcp!127.0.0.1!17034
+if(ps | grep -s ' fossil$'){
+ echo fsys all halt >>/srv/fscons
+ slay fossil|rc
+}
+
+echo done
+echo
+echo Remember to take the install disk out of the drive.
+echo Feel free to turn off your computer.
+while()
+ sleep 3600
+
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1) {
+ echo 'usage: hasmbr /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+x=`{xd -b $1 | sed -n '32p;32q'}
+if(~ $x(16) 55 && ~ $x(17) aa)
+ exit ''
+exit nope
+
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1) {
+ echo 'usage: hdrs file.9gz' >[1=2]
+ exit usage
+}
+gunzip < $1 | disk/mkext -h
--- /dev/null
+#!/bin/rc
+
+# 0000000 01 C D 0 0 1 01 00 P L A N 9
+
+if(! ~ $#* 1) {
+ echo 'usage: is9660 /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+ifs=$nl {id=`{dd -if $1 -bs 2048 -skip 16>[2]/dev/null | xd -c | sed 1q | sed 's/.........(....................).*/\1/'}}
+~ $id '01 C D 0 0 1 01'
+exit $status
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1) {
+ echo 'usage: isext2 /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+cmp -s <{dd -if $1 -bs 1 -count 2 -skip 1080 >[2]/dev/null | xd -b |sed 1q} \
+ <{echo '0000000 53 ef'}
+
+exit $status
--- /dev/null
+#!/bin/rc
+
+rfork e
+
+# 0000000 eb 3c 90 P l a n 9 . 0 0 00 02 04 02 00
+# 0000010 02 00 02 02 P f8 14 00 ? 00 ff 00 ~ 04 } 00
+# 0000020 02 P 00 00 80 00 ) a8 04 } 00 C Y L I N
+# 0000030 D R I C A L F A T 1 6 fa 8c
+
+if(! ~ $#* 1) {
+ echo 'usage: isfat /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+arg=$1
+fn fat {
+ cmp -s <{dd -if $arg -bs 1 -count 3 -skip $1 >[2]/dev/null} <{echo -n FAT}
+}
+
+fat 54 || fat 82
+exit $status
+
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1){
+ echo 'usage: isfossil /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+arg=$1
+if(! cmp -s <{dd -quiet 1 -if $arg -bs 1024 -iseek 127 |
+ dd -quiet 1 -bs 14 -count 1} <{echo 'fossil config'})
+ exit noconfig
+if(! cmp -s <{dd -quiet 1 -if $arg -bs 1024 -iseek 128 |
+ dd -quiet 1 -bs 4 -count 1 | xd -b | sed 1q} <{echo '0000000 37 76 ae 89'})
+ exit notwritebuffer
+exit 0
+
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1){
+ echo 'usage: isventi /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+arg=$1
+if(! cmp -s <{dd -quiet 1 -if $arg -bs 1024 -iseek 248 |
+ dd -quiet 1 -bs 13 -count 1} <{echo 'venti config'})
+ exit noconfig
+exit 0
+
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1){
+ echo 'usage: isventiarenas /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+arg=$1
+if(! cmp -s <{dd -quiet 1 -if $arg -bs 1024 -iseek 256 |
+ dd -quiet 1 -bs 4 -count 1 | xd -b | sed 1q} <{echo '0000000 a9 e4 a5 e7'})
+ exit notarenas
+exit 0
+
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1){
+ echo 'usage: isventiisect /dev/sdC0/part' >[1=2]
+ exit usage
+}
+
+arg=$1
+if(! cmp -s <{dd -quiet 1 -if $arg -bs 1024 -iseek 256 |
+ dd -quiet 1 -bs 4 -count 1 | xd -b | sed 1q} <{echo '0000000 d1 5c 5e c7'})
+ exit notisect
+exit 0
+
--- /dev/null
+#!/bin/rc
+
+. defs
+
+while()
+{
+div=--------------------------------------
+echo
+echo $div
+echo
+echo -n 'Preparing menu...'
+
+# must be topologically sorted (by prereq)
+tasks=(\
+ configfs\
+ partdisk prepdisk\
+ fmtfossil\
+ mountfs\
+ configdist\
+ confignet\
+ mountdist\
+ fmtventi\
+ download\
+ copydist\
+ bootsetup finish stop\
+ stopether stopppp\
+)
+# startether startppp stopether stopppp download\
+
+# these don't show up in the menu but still matter
+pseudotasks=(configip havefiles etherup etherdown pppup pppdown)
+
+for(i in $tasks $pseudotasks)
+ $i=notdone
+
+coherence
+
+for(i in $tasks $pseudotasks)
+ if(~ $#$i 0)
+ $i=notdone
+
+#
+# we believe the environment about what is done
+# only if we've confirmed it. since the tasks list is sorted so that
+# prereqs of xxx come before xxx, it's okay to assume xxx
+# is done until proven otherwise -- either a prereq or checkdone
+# will say so.
+#
+
+done=()
+ready=()
+rm /env/done
+rm /env/ready
+for(i in $tasks) {
+ $i=done
+ for(j in `{prereq $i})
+ if(! ~ $$j done)
+ $i=notdone
+ if(~ $$i done) {
+ export $i
+ $i checkdone
+ $i=`{grep '^'$i^'=' /tmp/vars | sed -n '$p' | sed 's/.*=//'}
+ }
+
+ if(~ $$i notdone ready) {
+ okay=yes
+ for(j in `{prereq $i})
+ if(! ~ $$j done)
+ okay=no
+ switch($okay){
+ case yes
+ $i=ready
+ export $i
+ $i checkready
+ $i=`{grep '^'$i^'=' /tmp/vars | sed -n '$p' | sed 's/.*=//'}
+ case no
+ $i=notdone
+ }
+ }
+
+ if(~ $$i done ready)
+ $$i=($$$i $i) # rc can be just as complicated as perl!
+}
+
+export $tasks $pseudotasks done ready
+coherence
+echo
+
+if(! ~ $#done 0) {
+ echo 'The following tasks are done: '
+ for(i in $done)
+ desc $i
+ echo
+}
+
+echo 'The following unfinished tasks are ready to be done:'
+for(i in $ready)
+ desc $i
+echo
+
+if(~ $#ready 0) {
+ echo hey you finished everything! not supposed to happen.
+ sleep 100
+ exit
+}
+
+prompt -d $ready(1) -w '' 'Task to do' $done $ready
+
+echo
+echo $div
+
+$rd go
+$rd=done # if it's not, the check will figure that out
+export $rd
+}
--- /dev/null
+#!/bin/rc
+
+sleep 86400 &
+cd /bin/inst
+. defs
+fn sigint { }
+
+coherence
+
+disks=`{ls /dev/sd*/data >[2]/dev/null | sed 's!/dev/(sd..)/data!\1!'}
+for (i in /dev/sd*/data)
+ if(test -f $i)
+ disk/fdisk -p $i>`{basename -d $i}^/ctl >[2]/dev/null
+for(i in /dev/sd*/plan9*)
+ if(test -f $i)
+ disk/prep -p $i >`{basename -d $i}^/ctl >[2]/dev/null
+
+# we run this while() here so that ctl-d won''t exit from us -- it''ll only exit main!
+# main contains a while() loop too, to avoid the hit of
+# continually reexecing from here.
+
+while()
+ main
--- /dev/null
+BEGIN{
+ m = "common"
+ haveold = 0;
+ while(getline <"/n/9fat/plan9-3e.ini" > 0){
+ haveold = 1
+ if($0 ~ /\[.*\]/){
+ m = substr($0, 2, length($0)-2)
+ continue
+ }
+ if(m=="menu" && $0 ~ /^menuitem=4e,/)
+ continue
+ a[m] = a[m] $0 "\n"
+ }
+
+ a["4e"] = ""
+ while(getline <"/tmp/plan9.ini" > 0)
+ a["4e"] = a["4e"] $0 "\n"
+
+ if(a["menu"] == "" && haveold){
+ a["menu"] = "menuitem=3e, Plan 9 Third Edition\n"
+ a["3e"] = ""
+ }
+
+ if(a["common"] != ""){
+ for(i in a)
+ if(i != "4e" && i != "common" && i != "menu")
+ a[i] = a["common"] a[i]
+ delete a["common"]
+ }
+
+ bootdisk4e=ENVIRON["fs"]
+ gsub("/dev/", "boot(args|disk|file)=local!#S/", bootdisk4e)
+
+ if(!haveold)
+ print a["4e"]
+ else{
+ print "[menu]"
+ print "menuitem=4e, Plan 9 Fourth Edition"
+ print a["menu"]
+ print ""
+ delete a["menu"]
+
+ print "[4e]"
+ print a["4e"]
+ print ""
+ delete a["4e"]
+
+ for(i in a){
+ # BUG: if rootdir is already there we should rewrite it
+ # sometimes into /3e/whatwasthere
+ if(a[i] ~ bootdisk4e && !(a[i] ~ /rootdir=/))
+ a[i] = "rootdir=/root/3e\n" a[i]
+ print "[" i "]"
+ gsub(/9fat!9pcdisk/, "9fat!9pc3e", a[i])
+ print a[i]
+ print ""
+ }
+ }
+}
--- /dev/null
+#!/bin/rc
+
+# prereq: mountfs configdist
+# desc: locate and mount the distribution
+
+fn domount{
+ if(! test -e $mountmedia(2))
+ logprog $srvmedia
+ unmount /n/distmedia >[2]/dev/null
+ logprog $mountmedia
+}
+
+fn exitifdone{
+ if(test -f /n/dist/dist/replica/plan9.db)
+ exit
+}
+
+fn trycdimage{
+ if(test -f $1){
+ rm -f /srv/9660.dist
+ unmount /n/dist
+ 9660srv 9660.dist >[2]/dev/null
+ logprog mount /srv/9660.dist /n/dist $1
+ exitifdone
+ mountdist=notdone
+ export mountdist
+ exit notdone
+ }
+}
+
+fn trycdimagebz2 {
+ if(test -f $1){
+ echo -n 'bunzip2 < '^$1^' >/n/newfs/dist/plan9.iso'
+ bunzip2 < $1 >/n/newfs/dist/_plan9.iso &&
+ mv /n/newfs/dist/_plan9.iso /n/newfs/dist/plan9.iso
+ echo
+ trycdimage /n/newfs/dist/plan9.iso
+ mountdist=notdone
+ export mountdist
+ exit notdone
+ }
+}
+
+fn havedist {
+ test -f $1/dist/replica/plan9.db ||
+ test -f $1/plan9.iso ||
+ test -f $1/plan9.iso.bz2
+}
+
+switch($1){
+case checkready
+ if(! ~ $distisfrom local && ! ~ $download done){
+ mountdist=notdone
+ export mountdist
+ }
+ if(! ~ $#mountmedia 0 1){
+ if(domount){
+ mountdist=done
+ export mountdist
+ if(mountdist checkdone)
+ exit
+ }
+ srvmedia=()
+ mountmedia=()
+ mountdist=ready
+ export srvmedia mountmedia mountdist
+ }
+
+case go
+ fat=()
+ ext2=()
+ x9660=()
+ fossil=()
+
+ echo Please wait... Scanning storage devices...
+
+ parts=`{ls /dev/sd??/* >[2]/dev/null | grep -v '/(plan9.*|ctl|log|raw)$'}
+ for (i in $parts) {
+ echo -n ' '^$i
+ n=`{echo $i | sed 's;/;_;g'}
+ if(! test -f /tmp/localpart.$n)
+ dd -if $i -bs 2048 -count 32 -of /tmp/localpart.$n >[2]/dev/null
+ if(isfat /tmp/localpart.$n)
+ fat=($fat $i)
+ if(isext2 /tmp/localpart.$n)
+ ext2=($ext2 $i)
+ if(is9660 /tmp/localpart.$n)
+ x9660=($x9660 $i)
+ if(isfossil $i)
+ fossil=($fossil $i)
+ echo
+ }
+ echo
+ echo The following storage media were detected.
+ echo Choose the one containing the distribution.
+ echo
+ for(i in $parts){
+ switch($i){
+ case $fat
+ echo ' '^$i^' (microsoft fat)'
+ case $ext2
+ echo ' '^$i^' (linux ext2)'
+ case $x9660
+ echo ' '^$i^' (iso9660 cdrom)'
+ case $fossil
+ echo ' '^$i^' (plan9 fossil)'
+ }
+ }
+ echo
+
+ mountstatus=x
+ while(! ~ $mountstatus ''){
+ prompt -w '' 'Distribution disk' $fat $x9660 $fossil
+ disk=$rd
+
+ srvmedia=()
+ mountmedia=()
+ switch($disk){
+ case $fs
+ mountmedia=(bind /n/newfs /n/distmedia)
+ case $fat
+ srvmedia=(dossrv)
+ mountmedia=(mount /srv/dos /n/distmedia $disk)
+ case $ext2
+ srvmedia=(ext2srv -r)
+ mountmedia=(mount /srv/ext2 /n/distmedia $disk)
+ case $x9660
+ srvmedia=(9660srv)
+ mountmedia=(mount /srv/9660 /n/distmedia $disk)
+ case $fossil
+ echo 'srv fossil.mountdist' > /tmp/fossi.conf
+ echo 'fsys main config '^$disk >> /tmp/fossil.conf
+ echo 'fsys main open -AWVP' >> /tmp/fossil.conf
+ echo 'fsys main' >> /tmp/fossil.conf
+ srvmedia=(fossil/fossil -c '. /tmp/fossil.conf')
+ mountmedia=(mount /srv/fossil.mountdist /n/distmedia)
+ case *
+ echo Unknown disk type '(cannot happen)'
+ exit oops
+ }
+ export srvmedia mountmedia
+ domount
+ mountstatus=$status
+ }
+
+ first=yes
+ dir=/
+ while(~ $first yes || ! havedist /n/distmedia/$dir){
+ if(~ $first yes){
+ echo
+ echo Which directory contains the distribution?
+ echo 'Any of the following will suffice (in order of preference):'
+ echo ' - the root directory of the cd image'
+ echo ' - the directory containing plan9.iso'
+ echo ' - the directory containing plan9.iso.bz2'
+ echo 'Typing `browse'' will put you in a shell that you can use to'
+ echo 'look for the directory.'
+ echo
+ first=no
+ }
+
+ prompt -d browse 'Location of archives'
+ dir=$rd
+ if(~ $dir browse){
+ echo This is a simple shell. Commands are:
+ echo ' cd directory - change to directory'
+ echo ' lc - list contents of current directory'
+ echo ' exit - exit shell'
+ echo
+ echo 'Move to the directory containing the distribution'
+ echo 'and then exit.'
+ echo
+ oifs=$ifs
+ ifs=$nl
+ dir=`{cdsh -r /n/distmedia}
+ ifs=$oifs
+ }
+ if(~ $#dir 0)
+ dir=safdsfdsfdsf
+ if(! ~ $#dir 1)
+ dir=$"dir
+ if(! havedist /n/distmedia/$dir)
+ echo 'No distribution found in '^`{cleanname /$dir}
+ }
+
+ distmediadir=$dir
+ export distmediadir
+
+case checkdone
+ if(! ~ $#distmediadir 1){
+ mountdist=notdone
+ export mountdist
+ exit notdone
+ }
+ if(! havedist /n/distmedia/$distmediadir && ! havedist /n/newfs/dist){
+ mountdist=notdone
+ export mountdist
+ exit notdone
+ }
+
+ exitifdone
+
+ if(test -f /n/distmedia/$distmediadir/dist/replica/plan9.db){
+ bind /n/distmedia/$distmediadir /n/dist
+ bind -a /n/dist/386/bin /bin
+ bind -a /n/dist/rc/bin /bin
+ exitifdone
+ mountdist=notdone
+ export mountdist
+ exit notdone
+ }
+
+ trycdimage /n/distmedia/$distmediadir/plan9.iso
+ trycdimage /n/newfs/dist/plan9.iso
+
+ trycdimagebz2 /n/distmedia/$distmediadir/plan9.iso.bz2
+ trycdimagebz2 /n/newfs/dist/plan9.iso.bz2
+
+ mountdist=notdone
+ export mountdist
+ exit notdone
+}
--- /dev/null
+#!/bin/rc
+
+switch($1){
+case checkready checkdone
+ if(! ~ $fmtfossil done){
+ mountfs=notdone
+ export mountfs
+ exit
+ }
+ if(! test -f /dev/sd*/fossil* && ! test -f /dev/fs/fossil*){
+ mountfs=notdone
+ export mountfs
+ exit
+ }
+ if(! ~ $#fossil 1 || ! test -f $fossil){
+ mountfs=ready
+ export mountfs
+ exit
+ }
+ if(! ps | grep -s ' fossil$'){
+ echo 'srv -p fscons' > /env/fossilconf
+ echo 'srv -AP fossil' >> /env/fossilconf
+ fossil/conf $fossil | sed 's/^fsys main open .*/& -AWVP/' |
+ sed 's/^fsys main snaptime .*//' >> /env/fossilconf
+ if(! logprog fossil/fossil -c .' /env/fossilconf'>>[2]/srv/log){
+ echo 'fossil: '^$status
+ mountfs=ready
+ export mountfs
+ exit oops
+ }
+ if(! test -f /srv/fossil){
+ echo 'fossil did not create /srv/fossil'
+ mountfs=ready
+ exit oops
+ }
+ cat /srv/fscons >>/srv/log &
+ if(! logprog mount -c /srv/fossil /n/newfs){
+ echo 'mount: '^$status
+ mountfs=ready
+ export mountfs
+ exit oops
+ }
+ fs=$fossil
+ export fs
+ }
+ if(! test -s /n/newfs/adm/users){
+ echo fsys main create /active/adm adm sys d775 >>/srv/fscons
+ echo fsys main create /active/adm/users adm sys 664 >>/srv/fscons
+ echo uname upas :upas >>/srv/fscons
+ echo users -w >>/srv/fscons
+ sleep 2
+ }
+ if(! test -s /n/newfs/adm/users){
+ echo 'could not create /adm/users'
+ mountfs=ready
+ export mountfs
+ exit oops
+ }
+ for(i in dist dist/replica dist/replica/client){
+ if(! test -d /n/newfs/$i)
+ echo fsys main create /active/$i sys sys d775 >>/srv/fscons
+ sleep 2
+ }
+ if(! test -d /n/newfs/dist/replica/client){
+ echo 'could not create /dist/replica/client'
+ mountfs=ready
+ export mountfs
+ exit oops
+ }
+ if(! test -e /n/newfs/dist/replica/client/plan9.db){
+ echo fsys main create /active/dist/replica/client/plan9.db sys sys 664 >>/srv/fscons
+ echo fsys main create /active/dist/replica/client/plan9.log sys sys a664 >>/srv/fscons
+ }
+ if(test -d /n/newfs/dist/replica/client && test -f /n/newfs/adm/users){
+ mountfs=done
+ export mountfs
+ exit
+ }
+ mountfs=ready
+ export mountfs
+ exit
+
+case go
+ echo 'The following partitions named fossil* were found.'
+ echo
+ echo 'Please choose one to use as the installation file system'
+ echo 'for your Plan 9 installation.'
+ echo
+ files=(`{ls /dev/sd*/fossil* /dev/fs/fossil* >[2]/dev/null})
+ ls -l $files
+ echo
+ if(~ $#fossil 1 && ~ $fossil $files)
+ default=(-d $fossil)
+ if not if(~ $#files 1)
+ default=(-d $files)
+ if not
+ default=()
+ prompt $default 'Fossil partition' $files
+ slay fossil|rc
+ fossil=$rd
+ export fossil
+}
+
+
--- /dev/null
+#!/bin/rc
+
+# desc: choose and mount file system partition
+# prereq: configfs
+
+switch($fstype){
+case fossil fossil+venti
+ exec mountfossil $*
+case *
+ mountfs=notdone
+ export mountfs
+ exit
+}
+
--- /dev/null
+#!/bin/rc
+
+# desc: move an old third edition plan 9 file system out of the way
+# prereq: mountfs
+
+rootfiles=(\
+ 386\
+ 68000\
+ 68020\
+ LICENSE\
+ NOTICE\
+ acme\
+ adm\
+ alpha\
+ arm\
+ cron\
+ dist\
+ fd\
+ lib\
+ lp\
+ mail\
+ mips\
+ mnt\
+ n\
+ power\
+ rc\
+ sparc\
+ sys\
+ tmp\
+ usr/glenda\
+ wrap\
+)
+
+switch($1){
+case checkready
+ if(! test -d /n/kfs/wrap){
+ moveoldfs=done
+ export moveoldfs
+ }
+
+case go
+ if(test -d /n/kfs/wrap){
+ echo 'You have a Third Edition Plan 9 installation on '^$fs^'.'
+ echo 'We need to move the old file system out of the way (into /3e)'
+ echo 'in order to continue.'
+ echo
+ prompt 'Move old file system' y n
+ switch($rd){
+ case y
+ kname=`{kfsname $fs}
+ log Moving old Plan 9 installation into /3e on kfs
+ logprog disk/kfscmd -n$kname 'create /3e sys sys 555 d' >>[2]/srv/log
+ logprog disk/kfscmd -n$kname 'create /3e/usr sys sys 555 d' >>[2]/srv/log
+ for(i in $rootfiles)
+ if(test -e /n/kfs/$i)
+ logprog disk/kfscmd -n$kname 'rename /'^$i^' /3e/'^$i
+ # copy extant /adm/users in case there have been modifications
+ logprog disk/kfscmd -n$kname 'create /adm adm adm 555 d' >>[2]/srv/log
+ logprog cp /n/kfs/3e/adm/users /n/kfs/adm/users >>[2]/srv/log
+
+ case n
+ echo 'Okay, but we can''t continue.'
+ echo
+ }
+ }
+
+case checkdone
+ if(test -d /n/kfs/wrap){
+ moveoldfs=notdone
+ export moveoldfs
+ }
+}
--- /dev/null
+#!/bin/rc
+
+# desc: edit partition tables (e.g., to create a plan 9 partition)
+# prereq: configfs
+
+switch($1){
+case go
+ disks=`{ls /dev/sd*/data >[2]/dev/null | sed 's!/dev/(sd..)/data!\1!'}
+ if(~ $#disks 0) {
+ echo 'No disk devices were found on your system.'
+ echo 'The installation process cannot continue.'
+ exit giveup
+ }
+
+ echo 'The following disk devices were found.'
+ echo
+ for(i in $disks) {
+ desc=`{cat /dev/$i/ctl | sed 1q | sed 's/inquiry //'}
+ echo $i '-' $desc
+ echo e | disk/fdisk -r /dev/$i/data >[2]/dev/null | grep -v '^ mbr'
+ echo
+ }
+
+ okay=no
+ defdisk=$disks(1)
+
+ if(~ $#disks 1)
+ default=(-d $disks)
+ if not
+ default=()
+ prompt $default 'Disk to partition' $disks
+ disk=$rd
+
+ if(! hasmbr /dev/$disk/data) {
+ echo 'The disk you selected HAS NO master boot record on its first sector.'
+ echo '(Perhaps it is a completely blank disk.)'
+ echo 'You need a master boot record to use the disk.'
+ echo 'Should we install a default master boot record?'
+ echo
+ prompt 'Install mbr' y n
+ switch($rd) {
+ case y
+ disk/mbr -m /386/mbr /dev/$disk/data
+ pickdisk=done
+ }
+ }
+ echo
+ echo 'This is disk/fdisk; use it to create a Plan 9 partition.'
+ echo 'If there is enough room, a Plan 9 partition will be'
+ echo 'suggested; you can probably just type ''w'' and then ''q''.'
+ echo
+ disk/fdisk -a /dev/$disk/data
+ disk/fdisk -p /dev/$disk/data >/dev/$disk/ctl >[2]/dev/null
+ for(i in /dev/sd*/plan9*){
+ if(test -f $i){
+ d=`{basename -d $i}
+ disk/prep -p $i >$d/ctl >[2]/dev/null
+ }
+ }
+
+case checkdone
+ # we want at least one disk with both an mbr and a plan9 partition
+ mbrandplan9=0
+ disks=`{ls /dev/sd*/plan9 >[2]/dev/null | sed 's!/dev/(sd..)/plan9!\1!'}
+ for(disk in $disks) {
+ if(hasmbr /dev/$disk/data)
+ mbrandplan9=1
+ }
+ if(~ $mbrandplan9 0){
+ partdisk=notdone
+ export partdisk
+ }
+}
--- /dev/null
+#!/bin/rc
+
+# desc: subdivide plan 9 disk partition
+# prereq: partdisk
+
+fn autotype {
+ if(~ $fstype fossil)
+ echo -a 9fat -a nvram -a fossil -a swap
+ if(~ $fstype fossil+venti)
+ echo -a 9fat -a nvram -a arenas -a isect -a fossil -a swap # -a other
+}
+
+switch($1) {
+case checkready
+ if(! test -f /dev/sd*/plan9*){
+ prepdisk=notdone
+ export prepdisk
+ }
+
+case go
+ echo 'The following Plan 9 disk partitions were found.'
+ echo
+ disks=(/dev/sd*/plan9*)
+ for (i in $disks){
+ echo $i
+ echo q | disk/prep -r $i >[2]/dev/null
+ echo
+ }
+ if(~ $#disks 1)
+ default=(-d $disks)
+ if not
+ default=()
+ prompt $default 'Plan 9 partition to subdivide' $disks
+ disk=$rd
+
+ echo 'This is disk/prep; use it to subdivide the Plan 9 partition.'
+ echo 'If it is not yet subdivided, a sensible layout will be suggested;'
+ echo 'you can probably just type ''w'' and then ''q''.'
+ echo
+ disk/prep `{autotype} $disk
+ disk/prep -p $disk >`{basename -d $disk}^/ctl >[2]/dev/null
+
+case checkdone
+ if(! test -f /dev/sd*/9fat)
+ prepdisk=ready
+
+ if(! ~ $prepdisk ready){
+ prepdisk=done
+ switch($fstype){
+ case fossil
+ if(! test -f /dev/sd*/fossil* && ! test -f /dev/fs/fossil*)
+ prepdisk=ready
+ case fossil+venti
+ if(! test -f /dev/sd*/fossil* && ! test -f /dev/fs/fossil*)
+ prepdisk=ready
+ if(! test -f /dev/sd*/arenas && ! test -f /dev/fs/arenas*)
+ prepdisk=ready
+ if(! test -f /dev/sd*/isect && ! test -f /dev/fs/isect*)
+ prepdisk=ready
+ }
+ }
+ export prepdisk
+}
--- /dev/null
+#!/bin/rc
+
+s=/n/dist/dist/replica
+serverroot=/n/dist
+serverlog=$s/plan9.log
+serverproto=$s/plan9.proto
+fn servermount { status='' }
+fn serverupdate { status='' }
+
+fn clientmount { status='' }
+c=/n/newfs/dist/replica
+clientroot=/n/newfs
+clientproto=$c/plan9.proto
+clientdb=$c/client/plan9.db
+clientexclude=(dist/replica/client)
+clientlog=$c/client/plan9.log
+
+applyopt=(-t -u -T$c/client/plan9.time)
--- /dev/null
+#!/bin/rc
+
+# desc: activate ethernet card
+# prereq: configether
+
+switch($1) {
+case checkready
+ if(isipdevup /net/ether0) {
+ startether=done
+ export startether
+ }
+
+case go
+ if(isipdevup /net/ether0)
+ exit
+
+ log starting ethernet $ethermethod config
+ switch($ethermethod) {
+ case manual
+ ip/ipconfig -g $gwaddr ether /net/ether0 $ipaddr $ipmask >>[2]/srv/log
+ case dhcp
+ ip/ipconfig $dhcphost -D >>/srv/log >[2=1]
+ }
+
+case checkdone
+ if(! isipdevup /net/ether0) {
+ startether=notdone
+ export startether
+ }
+}
--- /dev/null
+#!/bin/rc
+
+# desc: activate ppp connection
+# prereq: configppp
+
+switch($1) {
+case checkready checkdone
+ if (isipdevup '^pkt[0-9]')
+ startppp=done
+ export startppp
+
+case go
+ if(isipdevup '^pkt[0-9]')
+ exit
+
+ ctl=$pppdev^ctl
+ echo b115200 >$ctl
+
+ switch($pppmethod) {
+ case manual
+ echo
+ echo 'Please dial the modem, and type ctl-d when PPP has started.'
+ echo 'You may need to type ctl-m to send modem commands.'
+ echo
+ ip/ppp -f -u -b b^$pppbaud -p /dev/^$pppdev
+
+ case auto
+ ip/ppp -f -b b^$pppbaud -p /dev/^$pppdev -s $"pppuser:$"ppppasswd -t 'atdt'^$"pppphone
+ }
+}
--- /dev/null
+#!/bin/rc
+
+fn time { date | sed 's/.........$//'}
+
+rm -f /srv/log
+
+if(~ $#* 2) {
+ wid=$1
+ ht=$2
+}
+if not {
+ scr=(`{cat /dev/draw/new >[2]/dev/null || status=''})
+ wid=$scr(7)
+ ht=$scr(8)
+}
+
+if(test $ht -gt 800)
+ ht=800
+
+if(test $wid -gt 800)
+ wid=800
+
+statwid=`{hoc -e $wid^'*.2'}
+if(test $statwid -lt 180)
+ statwid=180
+if(test $statwid -gt 300)
+ statwid=300
+
+logwid=`{hoc -e $wid^-$statwid}
+if(test $logwid -gt 1000)
+ logwid=1000
+
+loght=`{hoc -e $ht^'*.25'}
+if(test $loght -lt 130)
+ loght=130
+
+textht=`{hoc -e $ht^-$loght}
+
+window 0,$textht,$statwid,$ht stats -lmisce
+window $statwid,$textht,^`{hoc -e $logwid+$statwid}^,$ht tailfsrv
+window 0,0,^`{hoc -e $logwid+$statwid}^,$textht inst/mainloop
+
+while(! test -f /srv/log)
+ sleep 1
+
+log `{time} Installation process started
--- /dev/null
+#!/bin/rc
+
+# desc: save the current installation state, to be resumed later
+# prereq:
+# mustdo:
+
+switch($1) {
+case checkdone
+ stop=notdone
+ export stop
+
+case checkready
+ if(~ $cdboot yes){
+ stop=notdone
+ export stop
+ }
+
+case go
+ coherence
+ switch($2){
+ case finished
+ echo 'We need to write the state of the current installation to the install floppy,'
+ echo 'so that you can pick up from here if, for example, you want to set up'
+ echo 'more boot methods.'
+ echo
+ case *
+ echo 'We need to write the state of the current installation to the install floppy.'
+ echo 'so that you can pick up from here when you wish to continue.'
+ echo
+ }
+ echo -n 'Please make sure the install floppy is in the floppy drive and press enter.'
+ read >/dev/null >[2]/dev/null
+
+ if(! a:) {
+ echo 'Couldn''t mount the floppy disk; sorry.'
+ exit
+ }
+
+ if(cp /tmp/vars /n/a:/9inst.cnf || cp /tmp/vars /n/a:/9inst.cnf) {
+ echo 'Your install state has been saved to the install floppy.'
+ if(~ $2 finished){
+ echo
+ echo 'Congratulations; you''ve completed the install.'
+ }
+ echo
+ halt
+ }
+
+ echo 'Couldn''t save the state to your install floppy. Sorry.'
+}
--- /dev/null
+#!/bin/rc
+
+# desc: shut down the ethernet connection
+# prereq:
+
+
+switch($1) {
+case checkready
+ if(! isipdevup /net/ether0) {
+ stopether=notdone
+ export stopether
+ }
+
+case go
+ ip/ipconfig ether /net/ether0 unbind
+
+case checkdone
+ stopether=notdone
+ export stopether
+}
--- /dev/null
+#!/bin/rc
+
+# desc: shut down the ppp connection
+# prereq:
+
+switch($1) {
+case checkready
+ if(! ~ $#pppdev 1 || ! isipdevup '^pkt[0-9]') {
+ stopppp=notdone
+ export stopppp
+ }
+
+case go
+ kill ppp | rc
+
+case checkdone
+ stopppp=notdone
+ export stopppp
+}
--- /dev/null
+#!/bin/rc
+
+# text-only install
+cd /bin/inst
+. defs
+
+textinst=1
+export textinst
+
+tailfsrv &
+while(! test -f /srv/log)
+ sleep 1
+log `{date} Installation process started
+inst/mainloop
+
--- /dev/null
+#!/bin/rc
+
+p=`{ps | grep $1 | sed 's/[^ ]* +([^ ]+) .*/\1/' }
+while(! ~ $#p 1) {
+ sleep 1
+ p=`{ps | grep $1 | sed 's/[^ ]* +([^ ]+) .*/\1/'}
+}
+p=$p(1)
+
+baropt='-w 145,129,445,168'
+if(~ $textinst 1)
+ baropt=-t
+
+{
+ while(test -f /proc/$p/fd)
+ grep '^ *'^$2^' ' /proc/$p/fd >[2]/dev/null
+} | awk '{print $9 " '^$3^'"; fflush("/dev/stdout")}' | bargraph $baropt $4
--- /dev/null
+#!/bin/rc
+
+ip/ipconfig
+echo ' auth=204.178.31.3
+ authdom=cs.bell-labs.com' >>/net/ndb
+ndb/cs
+auth/factotum
+bind -a /bin/auth /
+cpu -e clear -h tcp!204.178.31.2
--- /dev/null
+out=outside # outside web server
+s=/sys/lib/dist/pc
+x=`{bind -b /sys/lib/dist/bin/$cputype /bin}
+default:V: ndisk
+ ls -l ndisk
+
+SUB=`{ls sub inst}
+boot.raw:Q: proto $SUB
+ rm -rf boot
+ mkdir boot
+ bind /dev/null /sys/log/timesync
+ # make files writable for now.
+ cat proto | sed 's!d000!d775!;s!000!664!;s!555!775!;s!444!664!' >proto.cp
+ disk/mkfs -a proto.cp | disk/mkext -d boot
+ @{
+ cd boot/386
+ strip init
+ cd bin
+ strip * */* >[2]/dev/null || status=''
+ }
+ cat proto | sed 's!/.*!!' >proto.cp
+ disk/mkfs -a -s boot proto.cp | tee >{wc -c >[1=2]} |
+ touchfs 1000000000 >boot.raw
+
+boot.bz2:Q: boot.raw
+ ls -l boot.raw
+ bflz -n 32 < boot.raw >boot.bflz
+ ls -l boot.bflz
+ bzip2 -9 < boot.bflz >$target
+ ls -l $target
+
+root.bz2:Q: boot.bz2
+ {
+ echo bzfilesystem
+ cat boot.bz2
+ dd -if /dev/zero -bs 1024 -count 1 >[2]/dev/null
+ } >$target
+ ls -l $target
+
+/sys/src/9/pc/9pcflop.gz: root.bz2
+ @{
+ rfork n
+ cd /sys/src/9/pc
+ mk 'CONF=pcflop' 9pcflop.gz
+ }
+
+/sys/src/9/pc/9pccd.gz:
+ @{
+ cd /sys/src/9/pc
+ mk 'CONF=pccd' 9pccd.gz
+ }
+
+# disk/format apparently uses stat to obtain a file's real name, so
+# binding 9loadusb onto 9load will store the name 9loadusb in the
+# generated fat filesystem. the same is true for plan9.ini.cd and plan9.ini.
+
+9load: /386/9loadlite
+# cp $prereq $target
+ if (test -e /386/9loadnousb)
+ cp /386/9loadnousb $target # cater to old bioses
+ cp /386/9loadlitedebug 9loaddebug
+
+ndisk: 9load /sys/src/9/pc/9pcflop.gz plan9.ini /lib/vgadb
+ dd -if /dev/zero -of ndisk -bs 1024 -count 1440 >[2]/dev/null
+ disk/format -f -b /386/pbs -d ndisk \
+ 9load /sys/src/9/pc/9pcflop.gz plan9.ini /lib/vgadb
+ ls -l ndisk
+
+# cannot list both 9pcflop.gz and 9pccd.gz because they cannot be built
+# in parallel. stupid mk
+cddisk:DV: 9load /sys/src/9/pc/9pcflop.gz plan9.ini.cd /lib/vgadb
+ mk -a /sys/src/9/pc/9pccd.gz
+ mk -a /sys/src/9/pc/9pcflop.gz
+ rfork n
+ cp -x plan9.ini.cd subst/plan9.ini
+ dd -if /dev/zero -of cddisk -bs 1024 -count 2880 >[2]/dev/null
+ disk/format -t 3½QD -f -b /386/pbs -d cddisk \
+ 9load /sys/src/9/pc/^(9pcflop.gz 9pccd.gz) \
+ subst/plan9.ini /lib/vgadb
+ ls -l cddisk
+
+clean:V:
+ if (! unmount 9load >[2]/dev/null)
+ ;
+ rm -rf boot boot.bz2 boot.bflz boot.raw root.bz2 9pcflop ndisk 9load cddisk proto.cp 9loaddebug
+
+install:V: ndisk 9loaddebug
+ 9fs $out
+ dst=/n/$out/sys/lib/dist/web.protect
+ cp 9loaddebug $dst
+ gzip -9 < ndisk > $dst/plan9.flp.gz
+ # mk clean
+
+test:V: ndisk 9loaddebug
+ cp 9loaddebug ../web.protect2/n9loaddebug
+ cp ndisk ../web.protect2/ndisk
+
+cd0:D: cddisk
+ rm -f cd0
+ disk/mk9660 -9cj -v 'Plan 9 4th Edition' -s . -p cd0.proto -b cddisk cd0
--- /dev/null
+# config for initial floppy booting
+
+[menu]
+menuitem=boot, Boot Plan 9
+# menuitem=debug, Boot Plan 9 and debug 9load
+menudefault=boot, 10
+
+[common]
+# very cautious settings to get started.
+# will defeat booting from usb devices.
+*nomp=1
+*nobiosload=1
+# *noahciload=1
+# *debugload=1
+*nodumpstack=1
+# this would disable ether and usb probing.
+# *nousbprobe=1
+# *noetherprobe=1
+distname=plan9
+partition=new
+mouseport=ask
+monitor=ask
+vgasize=ask
+dmamode=ask
+nobootprompt=local!/boot/bzroot
+installurl=http://plan9.bell-labs.com/plan9/download/plan9.iso.bz2
+# serial console on COM1
+#console=0
+
+[boot]
+bootargs=local!#S/sdD0/data
+bootfile=sdD0!cdboot!9pccd.gz
+
+# [debug]
+# bootargs=local!#S/sdD0/data
+# bootfile=sdD0!cdboot!9pccd.gz
+# *debugload=1
--- /dev/null
+THIS IS A 512 byte BLANK PLAN9.INI
+
+
+
+
+
+
+
+
+
--- /dev/null
+# config for initial cd booting
+
+[menu]
+menuitem=install, Install Plan 9 from this CD
+menuitem=cdboot, Boot Plan 9 from this CD
+# menuitem=debug, Boot Plan 9 from this CD and debug 9load
+
+[common]
+# very cautious settings to get started.
+# will defeat booting from usb devices.
+*nomp=1
+*nobiosload=1
+# *noahciload=1
+# *debugload=1
+*nodumpstack=1
+# this would disable ether and usb probing.
+# *nousbprobe=1
+# *noetherprobe=1
+partition=new
+mouseport=ask
+monitor=ask
+vgasize=ask
+dmamode=ask
+adisk=/dev/sdD0/cdboot
+cdboot=yes
+# console=0
+# baud=9600
+
+[install]
+nobootprompt=local!/boot/bzroot
+bootfile=sdD0!cdboot!9pcflop.gz
+
+[cdboot]
+bootargs=local!#S/sdD0/data
+bootfile=sdD0!cdboot!9pccd.gz
+
+# [debug]
+# bootargs=local!#S/sdD0/data
+# bootfile=sdD0!cdboot!9pccd.gz
+# *debugload=1
--- /dev/null
+# config for initial vmware booting
+
+# very cautious settings to get started.
+# will defeat booting from usb devices.
+*nomp=1
+*nobiosload=1
+# *noahciload=1
+# *debugload=1
+# *nodumpstack=1
+
+partition=new
+nobootprompt=local!/boot/bzroot
+bootfile=fd0!9pcflop.gz
+
+mouseport=ps2
+monitor=xga
+vgasize=1024x768x16
+#adisk=/dev/sdD0/cdboot
+console=0
+baud=9600
--- /dev/null
+386 d775 sys sys
+# 9load 555 sys sys
+ init 555 sys sys
+# ld.com 555 sys sys
+ mbr 555 sys sys
+ pbs 555 sys sys
+ pbslba 555 sys sys
+ bin d775 sys sys
+ auth d555 sys sys
+# i think factotum is only needed if we include cpu
+# factotum 555 sys sys
+ aux d555 sys sys
+ isvmware 555 sys sys
+ mouse 555 sys sys /sys/lib/dist/pc/multi/mouse
+ pcmcia 555 sys sys /sys/lib/dist/pc/multi/pcmcia
+ # stub 555 sys sys
+ vga 555 sys sys /sys/lib/dist/pc/multi/vga
+ vmware 555 sys sys /sys/lib/dist/pc/sub/vmware
+ # vmware 555 sys sys
+ # vmwarefs 555 sys sys
+ # vmmousepoll 555 sys sys
+ zerotrunc 555 sys sys /sys/lib/dist/pc/multi/zerotrunc
+ disk d555 sys sys
+ fdisk 555 sys sys /sys/lib/dist/pc/multi/fdisk
+ format 555 sys sys /sys/lib/dist/pc/multi/format
+# kfs 555 sys sys
+# kfscmd 555 sys sys
+ mbr 555 sys sys /sys/lib/dist/pc/multi/mbr
+ prep 555 sys sys /sys/lib/dist/pc/multi/prep
+ fossil d555 sys sys
+ fossil 555 sys sys
+ flfmt 555 sys sys
+ conf 555 sys sys
+ ip d555 sys sys
+ ipconfig 555 sys sys /sys/lib/dist/pc/multi/ipconfig
+ ppp 555 sys sys /sys/lib/dist/pc/multi/ppp
+ ndb d555 sys sys
+# csquery and dnsquery could go
+ cs 555 sys sys /sys/lib/dist/pc/multi/cs
+# csquery 555 sys sys
+ dns 555 sys sys /sys/lib/dist/pc/multi/dns
+# dnsquery 555 sys sys
+ replica d555 sys sys
+ applylog 555 sys sys
+ changes 555 sys sys
+ compactdb 555 sys sys /sys/lib/dist/pc/sub/compactdb
+ pull 555 sys sys
+ venti d555 sys sys
+# venti 555 sys sys
+# conf 555 sys sys
+# fmtarenas 555 sys sys
+# fmtindex 555 sys sys
+# fmtisect 555 sys sys
+ 9660srv 555 sys sys /sys/lib/dist/pc/multi/9660srv
+# acme could go
+# acme 555 sys sys
+ awk 555 sys sys
+ bargraph 555 sys sys /sys/lib/dist/bin/386/bargraph
+ basename 555 sys sys /sys/lib/dist/pc/multi/basename
+ cat 555 sys sys /sys/lib/dist/pc/multi/cat
+ chgrp 555 sys sys /sys/lib/dist/pc/multi/chgrp
+ chmod 555 sys sys /sys/lib/dist/pc/multi/chmod
+ cleanname 555 sys sys /sys/lib/dist/pc/multi/cleanname
+ cmp 555 sys sys /sys/lib/dist/pc/multi/cmp
+ cdsh 555 sys sys /sys/lib/dist/bin/386/cdsh
+ cp 555 sys sys /sys/lib/dist/pc/multi/cp
+# cpu could go
+# cpu 555 sys sys
+ date 555 sys sys /sys/lib/dist/pc/multi/date
+ dd 555 sys sys /sys/lib/dist/pc/multi/dd
+ dossrv 555 sys sys /sys/lib/dist/pc/multi/dossrv
+ echo 555 sys sys /sys/lib/dist/pc/multi/echo
+ ed 555 sys sys /sys/lib/dist/pc/multi/ed
+# if cpu goes, exportfs could go
+# exportfs 555 sys sys
+ ext2srv 555 sys sys /sys/lib/dist/pc/multi/ext2srv
+ fcp 555 sys sys
+ grep 555 sys sys /sys/lib/dist/pc/multi/grep
+ hget 555 sys sys /sys/lib/dist/pc/multi/hget
+ hoc 555 sys sys /sys/lib/dist/pc/multi/hoc
+ ls 555 sys sys /sys/lib/dist/pc/multi/ls
+ mc 555 sys sys /sys/lib/dist/pc/multi/mc
+ mount 555 sys sys /sys/lib/dist/pc/multi/mount
+ multi 555 sys sys /sys/lib/dist/bin/386/multi
+ mv 555 sys sys /sys/lib/dist/pc/multi/mv
+# netkey 555 sys sys
+ ps 555 sys sys /sys/lib/dist/pc/multi/ps
+ rc 555 sys sys
+ read 555 sys sys /sys/lib/dist/pc/multi/read
+ rio 555 sys sys
+ rm 555 sys sys /sys/lib/dist/pc/multi/rm
+ sed 555 sys sys /sys/lib/dist/pc/multi/sed
+# snoopy could go
+# snoopy 555 sys sys
+ sort 555 sys sys /sys/lib/dist/pc/multi/sort
+ srv 555 sys sys /sys/lib/dist/pc/multi/srv
+# ssh 555 sys sys
+ stats 555 sys sys
+ syscall 555 sys sys /sys/lib/dist/pc/multi/syscall
+ tail 555 sys sys /sys/lib/dist/pc/multi/tail
+ tailfsrv 555 sys sys /sys/lib/dist/bin/386/tailfsrv
+ tee 555 sys sys /sys/lib/dist/pc/multi/tee
+# telnet 555 sys sys
+ test 555 sys sys /sys/lib/dist/pc/multi/test
+ wc 555 sys sys /sys/lib/dist/pc/multi/wc
+ xd 555 sys sys /sys/lib/dist/pc/multi/xd
+adm d555 adm adm
+ timezone d555 sys sys
+ local 555 sys sys
+lib d777 sys sys
+ font d555 sys sys
+ bit d555 sys sys
+ lucidasans d555 sys sys
+ lstr.12 444 sys sys
+ typelatin1.7.font 444 sys sys
+# lucm d555 sys sys
+# latin1.9 444 sys sys
+# latin1.9.font 444 sys sys
+ namespace 444 sys sys
+ ndb d555 sys sys
+ common 444 sys sys /sys/lib/dist/pc/sub/common
+ local 444 sys sys /sys/lib/dist/pc/sub/local
+ vgadb 666 sys sys /dev/null
+fd d555 sys sys
+mnt d777 sys sys
+ arch d000 sys sys
+ temp d000 sys sys
+ vmware d000 sys sys
+ wsys d000 sys sys
+n d777 sys sys
+ a: d000 sys sys
+ a d000 sys sys
+ c: d000 sys sys
+ c d000 sys sys
+ 9fat d000 sys sys
+ kremvax d000 sys sys /sys/lib/dist/pc/empty
+ newfs d000 sys sys
+ dist d000 sys sys /sys/lib/dist/pc/empty
+ distmedia d000 sys sys /sys/lib/dist/pc/empty
+rc d555 sys sys
+ bin d775 sys sys
+ inst d775 sys sys /sys/lib/dist/pc/empty
+ + - sys sys /sys/lib/dist/pc/inst
+ 9fat: 555 sys sys
+ a: 555 sys sys /sys/lib/dist/pc/sub/a:
+ bind 555 sys sys /sys/lib/dist/pc/sub/bind
+ boota: 555 sys sys /sys/lib/dist/pc/sub/boota:
+ bunzip2 555 sys sys /sys/lib/dist/pc/sub/bunzip2
+ c: 555 sys sys
+ dosmnt 555 sys sys
+ kill 555 sys sys
+ lc 555 sys sys
+ mkdir 555 sys sys /sys/lib/dist/pc/sub/mkdir
+ pci 555 sys sys
+ pwd 555 sys sys /sys/lib/dist/pc/sub/pwd
+ ramfs 555 sys sys /sys/lib/dist/pc/sub/ramfs
+ replica d555 sys sys
+ changes 555 sys sys
+ defs 555 sys sys
+ pull 555 sys sys
+ slay 555 sys sys
+ sleep 555 sys sys /sys/lib/dist/pc/sub/sleep
+ termrc 555 sys sys /sys/lib/dist/pc/sub/termrc
+ unmount 555 sys sys /sys/lib/dist/pc/sub/unmount
+ window 555 sys sys
+ lib d555 sys sys
+ rcmain 444 sys sys
+sys d555 sys sys
+ log d555 sys sys
+ dns 444 sys sys /sys/lib/dist/pc/emptyfile
+ timesync 444 sys sys /sys/lib/dist/pc/emptyfile
+tmp d555 sys sys
+usr d555 sys sys
+ glenda d775 glenda glenda
+ + - glenda glenda /sys/lib/dist/pc/glenda
--- /dev/null
+#!/bin/rc
+if(! test -f /srv/dos)
+ dossrv >/dev/null </dev/null >[2]/dev/null
+unmount /n/a:>[2]/dev/null
+
+if(~ $#adisk 1)
+ ; # do nothing
+if not if(~ $#bootfile 0)
+ adisk=/dev/fd0disk
+if not {
+ switch($bootfile) {
+ case sd*
+ adisk=`{echo $bootfile | sed 's#(sd..).*#/dev/\1/data#'}
+ case fd*
+ adisk=`{echo $bootfile | sed 's#(fd.).*#/dev/\1disk#'}
+ case *
+ echo 'unknown bootfile '^$bootfile^'; mail 9trouble@plan9.bell-labs.com'
+ exit oops
+ }
+}
+
+mount -c /srv/dos /n/a: $adisk
--- /dev/null
+#!/bin/rc
+
+rfork e
+if(! test -f /srv/dos)
+ dossrv >/dev/null </dev/null >[2]/dev/null
+unmount /n/a:>[2]/dev/null
+
+switch($bootfile) {
+case sd*!cdboot!*
+ # just look for the right file. bootfile isn''t trustworthy
+ adisk=/dev/sd*/cdboot
+ if(! ~ $#adisk 1)
+ adisk=$adisk(1)
+case sd*
+ adisk=`{echo $bootfile | sed 's#(sd..).*#/dev/\1/dos#'}
+case fd*
+ adisk=`{echo $bootfile | sed 's#(fd.).*#/dev/\1disk#'}
+case *
+ echo 'unknown bootfile '^$bootfile^'; mail 9trouble@plan9.bell-labs.com'
+ exit oops
+}
+
+mount -c /srv/dos /n/a: $adisk
+
--- /dev/null
+#!/bin/rc
+
+rfork e
+flag=0
+while(~ $1 -*){
+ switch($1){
+ case -b
+ flag=1
+ case -a
+ flag=2
+ case -c
+ flag=4
+ case -ac -ca
+ flag=6
+ case -bc -cb
+ flag=5
+ }
+ shift
+}
+
+syscall bind $1 $2 $flag >[2]/dev/null
--- /dev/null
+#!/bin/rc
+
+exec /boot/kfs BUNZIP
+# kfs is bzfs
\ No newline at end of file
--- /dev/null
+#
+# services
+#
+tcp=cs port=1
+tcp=echo port=7
+tcp=discard port=9
+tcp=systat port=11
+tcp=daytime port=13
+tcp=netstat port=15
+tcp=chargen port=19
+tcp=ftp-data port=20
+tcp=ftp port=21
+tcp=ssh port=22
+tcp=telnet port=23
+tcp=smtp port=25
+tcp=time port=37
+tcp=whois port=43
+tcp=domain port=53
+tcp=uucp port=64
+tcp=gopher port=70
+tcp=rje port=77
+tcp=finger port=79
+tcp=http port=80
+tcp=link port=87
+tcp=supdup port=95
+tcp=hostnames port=101
+tcp=iso-tsap port=102
+tcp=x400 port=103
+tcp=x400-snd port=104
+tcp=csnet-ns port=105
+tcp=pop-2 port=109
+tcp=pop3 port=110
+tcp=sunrpc port=111
+tcp=uucp-path port=117
+tcp=nntp port=119
+tcp=netbios port=139
+tcp=NeWS port=144
+tcp=print-srv port=170
+tcp=z39.50 port=210
+tcp=fsb port=400
+tcp=sysmon port=401
+tcp=proxy port=402
+tcp=proxyd port=404
+tcp=https port=443
+tcp=ssmtp port=465
+tcp=snntp port=563
+tcp=rexec port=512 restricted=
+tcp=login port=513 restricted=
+tcp=shell port=514 restricted=
+tcp=printer port=515
+tcp=courier port=530
+tcp=cscan port=531
+tcp=uucp port=540
+tcp=9fs port=564
+tcp=whoami port=565
+tcp=guard port=566
+tcp=ticket port=567
+tcp=fmclient port=729
+tcp=ingreslock port=1524
+tcp=webster port=2627
+tcp=weather port=3000
+tcp=Xdisplay port=6000
+tcp=styx port=6666
+tcp=mpeg port=6667
+tcp=rstyx port=6668
+tcp=infdb port=6669
+tcp=infsigner port=6671
+tcp=infcsigner port=6672
+tcp=inflogin port=6673
+tcp=bandt port=7330
+tcp=face port=32000
+tcp=ocpu port=17005
+tcp=ocpunote port=17006
+tcp=exportfs port=17007
+tcp=rexexec port=17009
+tcp=ncpu port=17010
+tcp=ncpunote port=17011
+tcp=cpu port=17013
+tcp=video port=17028
+tcp=vgen port=17029
+tcp=alefnslook port=17030
+tcp=411 port=17031
+tcp=flyboy port=17032
+
+il=echo port=7
+il=discard port=9
+il=chargen port=19
+il=whoami port=565
+il=ticket port=566
+il=challbox port=567
+il=ocpu port=17005
+il=ocpunote port=17006
+il=exportfs port=17007
+il=9fs port=17008
+il=rexexec port=17009
+il=ncpu port=17010
+il=ncpunote port=17011
+il=tcpu port=17012
+il=cpu port=17013
+il=fsauth port=17020
+il=rexauth port=17021
+il=changekey port=17022
+il=chal port=17023
+il=check port=17024
+il=juke port=17026
+il=video port=17028
+il=vgen port=17029
+il=alefnslook port=17030
+il=ramfs port=17031
+
+udp=echo port=7
+udp=tacacs port=49
+udp=tftp port=69
+udp=bootpc port=68
+udp=bootp port=67
+udp=dns port=53
+udp=ntp port=123
+udp=rip port=520
+udp=bfs port=2201
+udp=virgil port=2202
+udp=bandt2 port=7331
+
+gre=ppp port=34827
--- /dev/null
+#!/bin/rc
+
+exec cat $*
+
--- /dev/null
+
+#
+# files comprising the database, use as many as you like
+#
+database=
+ file=/lib/ndb/local
+ file=/lib/ndb/common
+
--- /dev/null
+#!/bin/rc
+
+syscall create $1 0 020000000775 >[2]/dev/null
--- /dev/null
+#!/bin/rc
+
+s=/n/dist/dist/replica
+serverroot=/n/dist
+serverlog=$s/plan9.log
+serverproto=$s/plan9.proto
+fn servermount { status='' }
+fn serverupdate { status='' }
+
+fn clientmount { status='' }
+c=/n/kfs/dist/replica
+clientroot=/n/kfs
+clientproto=$c/plan9.proto
+clientdb=$c/client/plan9.db
+clientexclude=(dist/replica/client)
+clientlog=$c/client/plan9.log
--- /dev/null
+#!/bin/rc
+
+rfork n
+bind '#$' /mnt
+cat /mnt/pci/*ctl
--- /dev/null
+#!/bin/rc
+
+syscall -o fd2path 0 buf 1024 < . >[2]/dev/null
--- /dev/null
+#!/bin/rc
+
+exec boot/kfs RAMFS $*
+# kfs is bzfs
--- /dev/null
+#!/bin/rc
+
+if(! ~ $#* 1) {
+ echo 'usage: sleep n' >[1=2]
+ exit usage
+}
+
+syscall sleep $1^000 >/dev/null >[2]/dev/null
--- /dev/null
+#!/bin/rc
+
+if(~ $#debug 1 && ~ $debug yes)
+ flag x +
+if not
+ debug=0
+
+if(~ $debug yes) echo env...
+sysname=gnot
+font=/lib/font/bit/lucidasans/typelatin1.7.font
+
+for (i in '#P' '#f' '#m' '#t' '#v') {
+ if(~ $debug yes) echo bind $i
+ bind -a $i /dev >/dev/null >[2=1]
+}
+if(~ $debug yes) echo binddev done
+
+for(disk in /dev/sd??) {
+ if(test -f $disk/data && test -f $disk/ctl){
+ disk/fdisk -p $disk/data >$disk/ctl >[2]/dev/null
+# if(~ $#nosddma 0)
+# echo dma on >$disk/ctl
+# if(~ $#nosdrwm 0)
+# echo rwm on >$disk/ctl
+ }
+}
+
+for (i in /sys/log/*) {
+ if(~ $debug yes) echo bind $i
+ bind /dev/null $i
+}
+
+if(~ $debug yes) echo bindlog done
+
+bind -a '#l' /net >/dev/null >[2=1]
+
+dossrv
+boota:
+boota: # again, just in case a timeout made the earlier one fail
+cp /n/a:/plan9.ini /tmp/plan9.orig
+if(! ~ $cdboot yes){
+ pci >/n/a:/pci.txt >[2]/dev/null
+ cp /dev/kmesg /n/a:/boot.txt >[2]/dev/null
+}
+
+# restore a partial install
+if(test -f /n/a:/9inst.cnf)
+ cp /n/a:/9inst.cnf /tmp/vars
+
+# make vgadb easier to edit
+if(test -f /n/a:/vgadb)
+ cp /n/a:/vgadb /lib/vgadb
+
+aux/vmware
+
+# configure loopback device without touching /net/ndb
+{
+ echo bind loopback /dev/null
+ echo add 127.0.0.1 255.255.255.0
+} >/net/ipifc/clone
+
+if(~ $#dmamode 0)
+ dmamode=ask
+if(~ $dmamode ask){
+ echo -n 'use DMA for ide drives[yes]: '
+ dmamode=`{read}
+ if(~ $#dmamode 0)
+ dmamode=yes
+}
+if(~ $dmamode yes)
+ for(i in /dev/sd*/ctl)
+ if(test -f $i)
+ {echo dma on; echo rwm on >[2]/dev/null} >$i
+
+if(~ $installmode ask){
+ echo -n 'install mode is (text, graphics)[graphics]: '
+ installmode=`{read}
+ if(~ $#installmode 0)
+ installmode=graphics
+}
+if(~ $installmode text){
+ mouseport=()
+ vgasize=()
+ monitor=()
+}
+if not
+ installmode=graphics
+
+if(~ $mouseport ask){
+ echo -n 'mouseport is (ps2, ps2intellimouse, 0, 1, 2)[ps2]: '
+ mouseport=`{read}
+ if(~ $#mouseport 0)
+ mouseport=ps2
+}
+if(~ $vgasize ask){
+ echo -n 'vgasize [640x480x8]: '
+ vgasize=`{read}
+ if(~ $#vgasize 0)
+ vgasize=640x480x8
+}
+if(~ $monitor ask){
+ echo -n 'monitor is [xga]: '
+ monitor=`{read}
+ if(~ $#monitor 0)
+ monitor=xga
+}
+if(~ $#mouseport 1) {
+ aux/mouse $mouseport
+ if(~ $#vgasize 1 && ! ~ $vgasize '') {
+ vgasize=`{echo $vgasize}
+ if(! ~ $cdboot yes)
+ aux/vga -vip $vgasize >/n/a:/vgainfo.txt
+ sleep 2 # wait for floppy to finish
+ aux/vga -l $vgasize
+ if(! ~ $#novgaaccel 0)
+ echo -n 'hwaccel off' >'#v/vgactl' >[2]/dev/null
+ if(! ~ $#novgablank 0)
+ echo -n 'hwblank off' >'#v/vgactl' >[2]/dev/null
+ }
+}
+
--- /dev/null
+#!/bin/rc
+
+syscall unmount 0 $1 >[2]/dev/null
--- /dev/null
+-1:adm:adm:
+0:none:none:
+1:tor:tor:
+2:glenda:glenda:
+10000:sys::
+10001:upas:upas:
+10002:bootes:bootes:
--- /dev/null
+#!/bin/rc
+# vmware - if we're running in a vmware virtual machine, tweak set up
+if(aux/isvmware -s){
+ echo hwaccel off >'#v/vgactl'
+ echo -n off >'#P/i8253timerset'
+ for (ctl in '#S'/sd[C-H]?/ctl)
+ if (test -e $ctl && grep -s '^config .* dma ' $ctl &&
+ ! grep -s '^config (848A|.* dma 00000000 )' $ctl)
+ echo 'dma on' >$ctl
+}
--- /dev/null
+# config for initial cd booting
+
+[menu]
+menuitem=install, Install Plan 9 from this CD
+menuitem=cdboot, Boot Plan 9 from this CD
+# menuitem=debug, Boot Plan 9 from this CD and debug 9load
+
+[common]
+# very cautious settings to get started.
+# will defeat booting from usb devices.
+*nomp=1
+*nobiosload=1
+# *noahciload=1
+# *debugload=1
+*nodumpstack=1
+# this would disable ether and usb probing.
+# *nousbprobe=1
+# *noetherprobe=1
+partition=new
+mouseport=ask
+monitor=ask
+vgasize=ask
+dmamode=ask
+adisk=/dev/sdD0/cdboot
+cdboot=yes
+# console=0
+# baud=9600
+
+[install]
+nobootprompt=local!/boot/bzroot
+bootfile=sdD0!cdboot!9pcflop.gz
+
+[cdboot]
+bootargs=local!#S/sdD0/data
+bootfile=sdD0!cdboot!9pccd.gz
+
+# [debug]
+# bootargs=local!#S/sdD0/data
+# bootfile=sdD0!cdboot!9pccd.gz
+# *debugload=1
--- /dev/null
+#!/bin/rc
+# setup - prep for the mkfile
+9fs sources
+9fs other
+9fs outfsother
+if (test -e /cfg/$sysname/config)
+ . /cfg/$sysname/config
+if not
+ outip=204.178.31.2
+import -c tcp!$outip!666 $dist/web.protect
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <bio.h>
-#include <event.h>
-
-enum {PNCTL=3};
-
-static char* rdenv(char*);
-int newwin(char*);
-Rectangle screenrect(void);
-
-int nokill;
-int textmode;
-char *title;
-
-Image *light;
-Image *dark;
-Image *text;
-
-void
-initcolor(void)
-{
- text = display->black;
- light = allocimagemix(display, DPalegreen, DWhite);
- dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen);
-}
-
-Rectangle rbar;
-Point ptext;
-vlong n, d;
-int last;
-int lastp = -1;
-int first = 1;
-
-char backup[80];
-
-void
-drawbar(void)
-{
- int i, j;
- int p;
- char buf[200], bar[100], *s;
- static char lastbar[100];
-
- if(n > d || n < 0 || d <= 0)
- return;
-
- i = (Dx(rbar)*n)/d;
- p = (n*100LL)/d;
-
- if(textmode){
- bar[0] = '|';
- for(j=0; j<i; j++)
- bar[j+1] = '#';
- for(; j<60; j++)
- bar[j+1] = '-';
- bar[61] = '|';
- bar[62] = ' ';
- sprint(bar+63, "%3d%% ", p);
- for(i=0; bar[i]==lastbar[i] && bar[i]; i++)
- ;
- memset(buf, '\b', strlen(lastbar)-i);
- strcpy(buf+strlen(lastbar)-i, bar+i);
- if(buf[0])
- write(1, buf, strlen(buf));
- strcpy(lastbar, bar);
- return;
- }
-
- if(lastp == p && last == i)
- return;
-
- if(lastp != p){
- sprint(buf, "%d%%", p);
-
- stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP);
- lastp = p;
- }
-
- if(last != i){
- draw(screen, Rect(rbar.min.x+last, rbar.min.y, rbar.min.x+i, rbar.max.y),
- dark, nil, ZP);
- last = i;
- }
- flushimage(display, 1);
-}
-
-void
-eresized(int new)
-{
- Point p, q;
- Rectangle r;
-
- if(new && getwindow(display, Refnone) < 0)
- fprint(2,"can't reattach to window");
-
- r = screen->r;
- draw(screen, r, light, nil, ZP);
- p = string(screen, addpt(r.min, Pt(4,4)), text, ZP,
- display->defaultfont, title);
-
- p.x = r.min.x+4;
- p.y += display->defaultfont->height+4;
-
- q = subpt(r.max, Pt(4,4));
- rbar = Rpt(p, q);
-
- ptext = Pt(r.max.x-4-stringwidth(display->defaultfont, "100%"), r.min.x+4);
- border(screen, rbar, -2, dark, ZP);
- last = 0;
- lastp = -1;
-
- drawbar();
-}
-
-void
-bar(Biobuf *b)
-{
- char *p, *f[2];
- Event e;
- int k, die, parent, child;
-
- parent = getpid();
-
- die = 0;
- if(textmode)
- child = -1;
- else
- switch(child = rfork(RFMEM|RFPROC)) {
- case 0:
- sleep(1000);
- while(!die && (k = eread(Ekeyboard|Emouse, &e))) {
- if(nokill==0 && k == Ekeyboard && (e.kbdc == 0x7F || e.kbdc == 0x03)) { /* del, ctl-c */
- die = 1;
- postnote(PNPROC, parent, "interrupt");
- _exits("interrupt");
- }
- }
- _exits(0);
- }
-
- while(!die && (p = Brdline(b, '\n'))) {
- p[Blinelen(b)-1] = '\0';
- if(tokenize(p, f, 2) != 2)
- continue;
- n = strtoll(f[0], 0, 0);
- d = strtoll(f[1], 0, 0);
- drawbar();
- }
- postnote(PNCTL, child, "kill");
-}
-
-
-void
-usage(void)
-{
- fprint(2, "usage: bargraph [-kt] [-w minx,miny,maxx,maxy] 'title'\n");
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- Biobuf b;
- char *p, *q;
- int lfd;
-
- p = "0,0,200,60";
-
- ARGBEGIN{
- case 'w':
- p = ARGF();
- break;
- case 't':
- textmode = 1;
- break;
- case 'k':
- nokill = 1;
- break;
- default:
- usage();
- }ARGEND;
-
- if(argc != 1)
- usage();
-
- title = argv[0];
-
- lfd = dup(0, -1);
-
- while(q = strchr(p, ','))
- *q = ' ';
- Binit(&b, lfd, OREAD);
- if(textmode || newwin(p) < 0){
- textmode = 1;
- rbar = Rect(0, 0, 60, 1);
- }else{
- initdraw(0, 0, "bar");
- initcolor();
- einit(Emouse|Ekeyboard);
- eresized(0);
- }
- bar(&b);
-}
-
-
-/* all code below this line should be in the library, but is stolen from colors instead */
-static char*
-rdenv(char *name)
-{
- char *v;
- int fd, size;
-
- fd = open(name, OREAD);
- if(fd < 0)
- return 0;
- size = seek(fd, 0, 2);
- v = malloc(size+1);
- if(v == 0){
- fprint(2, "%s: can't malloc: %r\n", argv0);
- exits("no mem");
- }
- seek(fd, 0, 0);
- read(fd, v, size);
- v[size] = 0;
- close(fd);
- return v;
-}
-
-int
-newwin(char *win)
-{
- char *srv, *mntsrv;
- char spec[100];
- int srvfd, cons, pid;
-
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){
- case -1:
- fprint(2, "bargraph: can't fork: %r\n");
- return -1;
- case 0:
- break;
- default:
- exits(0);
- }
-
- srv = rdenv("/env/wsys");
- if(srv == 0){
- mntsrv = rdenv("/mnt/term/env/wsys");
- if(mntsrv == 0){
- fprint(2, "bargraph: can't find $wsys\n");
- return -1;
- }
- srv = malloc(strlen(mntsrv)+10);
- sprint(srv, "/mnt/term%s", mntsrv);
- free(mntsrv);
- pid = 0; /* can't send notes to remote processes! */
- }else
- pid = getpid();
- USED(pid);
- srvfd = open(srv, ORDWR);
- free(srv);
- if(srvfd == -1){
- fprint(2, "bargraph: can't open %s: %r\n", srv);
- return -1;
- }
- sprint(spec, "new -r %s", win);
- if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){
- fprint(2, "bargraph: can't mount /mnt/wsys: %r (spec=%s)\n", spec);
- return -1;
- }
- close(srvfd);
- unmount("/mnt/acme", "/dev");
- bind("/mnt/wsys", "/dev", MBEFORE);
- cons = open("/dev/cons", OREAD);
- if(cons==-1){
- NoCons:
- fprint(2, "bargraph: can't open /dev/cons: %r");
- return -1;
- }
- dup(cons, 0);
- close(cons);
- cons = open("/dev/cons", OWRITE);
- if(cons==-1)
- goto NoCons;
- dup(cons, 1);
- dup(cons, 2);
- close(cons);
-// wctlfd = open("/dev/wctl", OWRITE);
- return 0;
-}
-
-Rectangle
-screenrect(void)
-{
- int fd;
- char buf[12*5];
-
- fd = open("/dev/screen", OREAD);
- if(fd == -1)
- fd=open("/mnt/term/dev/screen", OREAD);
- if(fd == -1){
- fprint(2, "%s: can't open /dev/screen: %r\n", argv0);
- exits("window read");
- }
- if(read(fd, buf, sizeof buf) != sizeof buf){
- fprint(2, "%s: can't read /dev/screen: %r\n", argv0);
- exits("screen read");
- }
- close(fd);
- return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
-}
-
-int
-postnote(int group, int pid, char *note)
-{
- char file[128];
- int f, r;
-
- switch(group) {
- case PNPROC:
- sprint(file, "/proc/%d/note", pid);
- break;
- case PNGROUP:
- sprint(file, "/proc/%d/notepg", pid);
- break;
- case PNCTL:
- sprint(file, "/proc/%d/ctl", pid);
- break;
- default:
- return -1;
- }
-
- f = open(file, OWRITE);
- if(f < 0)
- return -1;
-
- r = strlen(note);
- if(write(f, note, r) != r) {
- close(f);
- return -1;
- }
- close(f);
- return 0;
-}
+++ /dev/null
-/*
- * Extraordinarily brute force Lempel & Ziv-like
- * compressor. The input file must fit in memory
- * during compression, and the output file will
- * be reconstructed in memory during decompression.
- * We search for large common sequences and use a
- * greedy algorithm to choose which sequence gets
- * compressed first.
- *
- * Files begin with "BLZ\n" and a 32-bit uncompressed file length.
- *
- * Output format is a series of blocks followed by
- * a raw data section. Each block begins with a 32-bit big-endian
- * number. The top bit is type and the next 31 bits
- * are uncompressed size. Type is one of
- * 0 - use raw data for this length
- * 1 - a 32-bit offset follows
- * After the blocks come the raw data. (The end of the blocks can be
- * noted by summing block lengths until you reach the file length.)
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-#define malloc sbrk
-
-int minrun = 16;
-int win = 16;
-ulong outn;
-int verbose;
-int mindist;
-
-enum { Prime = 16777213 }; /* smallest prime < 2^24 (so p*256+256 < 2^32) */
-enum { NOFF = 3 };
-
-Biobuf bout;
-ulong length;
-uchar *data;
-ulong sum32(ulong, void*, long);
-uchar *odat;
-int nodat;
-int nraw;
-int rawstart;
-int acct;
-int zlength;
-int maxchain;
-int maxrle[256];
-int nnew;
-
-typedef struct Node Node;
-struct Node {
- Node *link;
- ulong key;
- ulong offset[NOFF];
-};
-
-Node *nodepool;
-int nnodepool;
-
-Node **hash;
-uint nhash;
-
-uint maxlen;
-uint maxsame;
-uint replacesame = 8*1024*1024;
-
-Node *freelist, **freeend;
-uint nalloc;
-
-Node*
-allocnode(void)
-{
- int i;
- Node *n;
-
- if(nnodepool == 0){
- nnodepool = 256*1024;
- nodepool = malloc(sizeof(Node)*nnodepool);
- }
- if(freelist){
- n = freelist;
- freelist = n->link;
- return n;
- }
- assert(nnodepool > 0);
- nalloc++;
- n = &nodepool[--nnodepool];
- for(i=0; i<NOFF; i++)
- n->offset[i] = -1;
-
- return n;
-}
-
-void
-freenode(Node *n)
-{
- if(freelist == nil)
- freelist = n;
- else
- *freeend = n;
- freeend = &n->link;
- n->link = nil;
-}
-
-Node**
-llookup(ulong key)
-{
- uint c;
- Node **l, **top, *n;
-
- if(nhash == 0){
- uint x;
-
- x = length/8;
- for(nhash=1; nhash<x; nhash<<=1)
- ;
- hash = sbrk(sizeof(Node*)*nhash);
- }
-
- top = &hash[key&(nhash-1)];
- c = 0;
- for(l=top; *l; l=&(*l)->link){
- c++;
- if((*l)->key == key){
- /* move to front */
- n = *l;
- *l = n->link;
- n->link = *top;
- *top = n;
- return top;
- }
- }
- if(c > maxlen)
- maxlen = c;
- return l;
-}
-
-Node*
-lookup(ulong key)
-{
- return *llookup(key);
-}
-
-void
-insertnode(ulong key, ulong offset)
-{
- int i;
- Node *n, **l;
-
- l = llookup(key);
- if(*l == nil){
- if(l==&hash[key&(nhash-1)])
- nnew++;
- *l = allocnode();
- (*l)->key = key;
- }
- n = *l;
-
- /* add or replace last */
- for(i=0; i<NOFF-1 && n->offset[i]!=-1; i++)
- ;
- n->offset[i] = offset;
-}
-
-void
-Bputint(Biobufhdr *b, int n)
-{
- uchar p[4];
-
- p[0] = n>>24;
- p[1] = n>>16;
- p[2] = n>>8;
- p[3] = n;
- Bwrite(b, p, 4);
-}
-
-void
-flushraw(void)
-{
- if(nraw){
- if(verbose)
- fprint(2, "Raw %d+%d\n", rawstart, nraw);
- zlength += 4+nraw;
- Bputint(&bout, (1<<31)|nraw);
- memmove(odat+nodat, data+rawstart, nraw);
- nodat += nraw;
- nraw = 0;
- }
-}
-
-int
-rawbyte(int i)
-{
- assert(acct == i);
- if(nraw == 0)
- rawstart = i;
- acct++;
- nraw++;
- return 1;
-}
-
-int
-refblock(int i, int len, int off)
-{
- assert(acct == i);
- acct += len;
- if(nraw)
- flushraw();
- if(verbose)
- fprint(2, "Copy %d+%d from %d\n", i, len, off);
- Bputint(&bout, len);
- Bputint(&bout, off);
- zlength += 4+4;
- return len;
-}
-
-int
-cmprun(uchar *a, uchar *b, int len)
-{
- int i;
-
- if(a==b)
- return 0;
- for(i=0; i<len && a[i]==b[i]; i++)
- ;
- return i;
-}
-
-int
-countrle(uchar *a)
-{
- int i;
-
- for(i=0; a[i]==a[0]; i++)
- ;
- return i;
-}
-
-void
-compress(void)
-{
- int best, i, j, o, rle, run, maxrun, maxoff;
- ulong sum;
- Node *n;
-
- sum = 0;
- for(i=0; i<win && i<length; i++)
- sum = (sum*256+data[i])%Prime;
- for(i=0; i<length-win; ){
- maxrun = 0;
- maxoff = 0;
- if(verbose)
- fprint(2, "look %.6lux\n", sum);
- n = lookup(sum);
- if(n){
- best = -1;
- for(o=0; o<NOFF; o++){
- if(n->offset[o] == -1)
- break;
- run = cmprun(data+i, data+n->offset[o], length-i);
- if(run > maxrun && n->offset[o]+mindist < i){
- maxrun = run;
- maxoff = n->offset[o];
- best = o;
- }
- }
- if(best > 0){
- o = n->offset[best];
- for(j=best; j>0; j--)
- n->offset[j] = n->offset[j-1];
- n->offset[0] = o;
- }
- }
-
- if(maxrun >= minrun)
- j = i+refblock(i, maxrun, maxoff);
- else
- j = i+rawbyte(i);
- for(; i<j; i++){
- /* avoid huge chains from large runs of same byte */
- rle = countrle(data+i);
- if(rle<4)
- insertnode(sum, i);
- else if(rle>maxrle[data[i]]){
- maxrle[data[i]] = rle;
- insertnode(sum, i);
- }
- sum = (sum*256+data[i+win]) % Prime;
- sum = (sum + data[i]*outn) % Prime;
- }
- }
- /* could do better here */
- for(; i<length; i++)
- rawbyte(i);
- flushraw();
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: bflz [-n winsize] [file]\n");
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int fd, i, n;
- char buf[10485760];
-
- ARGBEGIN{
- case 'd':
- verbose = 1;
- break;
- case 's':
- replacesame = atoi(EARGF(usage()));
- break;
- case 'm':
- mindist = atoi(EARGF(usage()));
- break;
- case 'n':
- win = atoi(EARGF(usage()));
- minrun = win;
- break;
- default:
- usage();
- }ARGEND
-
- switch(argc){
- default:
- usage();
- case 0:
- fd = 0;
- break;
- case 1:
- if((fd = open(argv[0], OREAD)) < 0)
- sysfatal("open %s: %r", argv[0]);
- break;
- }
-
- while((n = readn(fd, buf, sizeof buf)) > 0){
- data = realloc(data, length+n);
- if(data == nil)
- sysfatal("realloc: %r");
- memmove(data+length, buf, n);
- length += n;
- if(n < sizeof buf)
- break;
- }
- odat = malloc(length);
- if(odat == nil)
- sysfatal("malloc: %r");
-
- Binit(&bout, 1, OWRITE);
- Bprint(&bout, "BLZ\n");
- Bputint(&bout, length);
- outn = 1;
- for(i=0; i<win; i++)
- outn = (outn * 256) % Prime;
-
- if(verbose)
- fprint(2, "256^%d = %.6lux\n", win, outn);
- outn = Prime - outn;
- if(verbose)
- fprint(2, "outn = %.6lux\n", outn);
-
- compress();
- Bwrite(&bout, odat, nodat);
- Bterm(&bout);
- fprint(2, "brk %p\n", sbrk(1));
- fprint(2, "%d nodes used; %d of %d hash slots used\n", nalloc, nnew, nhash);
- exits(nil);
-}
+++ /dev/null
-int unbzip(int);
-void _unbzip(int, int);
-int unbflz(int);
-int xexpand(int);
-void *emalloc(ulong);
-void *erealloc(void*, ulong);
-char *estrdup(char*);
-
-void ramfsmain(int, char**);
-extern int chatty;
-void error(char*, ...);
+++ /dev/null
-/*
- * bzip2-based file system.
- * the file system itself is just a bzipped2 xzipped mkfs archive
- * prefixed with "bzfilesystem\n" and suffixed with
- * a kilobyte of zeros.
- *
- * changes to the file system are only kept in
- * memory, not written back to the disk.
- *
- * this is intended for use on a floppy boot disk.
- * we assume the file is in the dos file system and
- * contiguous on the disk: finding it amounts to
- * looking at the beginning of each sector for
- * "bzfilesystem\n". then we pipe it through
- * bunzip2 and store the files in a file tree in memory.
- * things are slightly complicated by the fact that
- * devfloppy requires reads to be on a 512-byte
- * boundary and be a multiple of 512 bytes; we
- * fork a process to relieve bunzip2 of this restriction.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <auth.h>
-#include <fcall.h>
-#include "bzfs.h"
-
-enum{
- LEN = 8*1024,
- NFLDS = 6, /* filename, modes, uid, gid, mtime, bytes */
-};
-
-void mkdirs(char*, char*);
-void mkdir(char*, ulong, ulong, char*, char*);
-void extract(char*, ulong, ulong, char*, char*, ulong);
-void seekpast(ulong);
-void error(char*, ...);
-void warn(char*, ...);
-void usage(void);
-char *mtpt;
-Biobufhdr bin;
-uchar binbuf[2*LEN];
-
-void
-usage(void)
-{
- fprint(2, "usage: bzfs [-m mtpt] [-s] [-f file] [-h]\n");
- exits("usage");
-}
-
-/*
- * floppy disks can only be read on 512-byte
- * boundaries and in 512 byte multiples.
- * feed one over a pipe to allow arbitrary reading.
- */
-char zero[512];
-int
-blockread(int in, char *first, int nfirst)
-{
- int p[2], out, n, rv;
- char blk[512];
-
- if(pipe(p) < 0)
- sysfatal("pipe: %r");
- rv = p[0];
- out = p[1];
- switch(rfork(RFPROC|RFNOTEG|RFFDG)){
- case -1:
- sysfatal("fork: %r");
- case 0:
- close(rv);
- break;
- default:
- close(in);
- close(out);
- return rv;
- }
-
- write(out, first, nfirst);
-
- while((n=read(in, blk, sizeof blk)) > 0){
- if(write(out, blk, n) != n)
- break;
- if(n == sizeof(blk) && memcmp(zero, blk, n) == n)
- break;
- }
- _exits(0);
- return -1;
-}
-
-enum { NAMELEN = 28 };
-
-void
-main(int argc, char **argv)
-{
- char *rargv[10];
- int rargc;
- char *fields[NFLDS], name[2*LEN], *p, *namep;
- char uid[NAMELEN], gid[NAMELEN];
- ulong mode, bytes, mtime;
- char *file;
- int i, n, stdin, fd, chatty;
- char blk[512];
-
- if(argc>1 && strcmp(argv[1], "RAMFS") == 0){
- argv[1] = argv[0];
- ramfsmain(argc-1, argv+1);
- exits(nil);
- }
- if(argc>1 && strcmp(argv[1], "BUNZIP") == 0){
- _unbzip(0, 1);
- exits(nil);
- }
-
- rfork(RFNOTEG);
- stdin = 0;
- file = nil;
- namep = name;
- mtpt = "/root";
- chatty = 0;
- ARGBEGIN{
- case 'd':
- chatty = !chatty;
- break;
- case 'f':
- file = ARGF();
- break;
- case 's':
- stdin++;
- break;
- case 'm':
- mtpt = ARGF();
- break;
- default:
- usage();
- }ARGEND
-
- if(argc != 0)
- usage();
-
- if(file == nil) {
- fprint(2, "must specify -f file\n");
- usage();
- }
-
- if((fd = open(file, OREAD)) < 0) {
- fprint(2, "cannot open \"%s\": %r\n", file);
- exits("open");
- }
-
- rargv[0] = "ramfs";
- rargc = 1;
- if(stdin)
- rargv[rargc++] = "-i";
- rargv[rargc++] = "-m";
- rargv[rargc++] = mtpt;
- rargv[rargc] = nil;
- ramfsmain(rargc, rargv);
-
- if(1 || strstr(file, "disk")) { /* search for archive on block boundary */
-if(chatty) fprint(2, "searching for bz\n");
- for(i=0;; i++){
- if((n = readn(fd, blk, sizeof blk)) != sizeof blk)
- sysfatal("read %d gets %d: %r\n", i, n);
- if(strncmp(blk, "bzfilesystem\n", 13) == 0)
- break;
- }
-if(chatty) fprint(2, "found at %d\n", i);
- }
-
- if(chdir(mtpt) < 0)
- error("chdir %s: %r", mtpt);
-
- fd = unbflz(unbzip(blockread(fd, blk+13, sizeof(blk)-13)));
-
- Binits(&bin, fd, OREAD, binbuf, sizeof binbuf);
- while(p = Brdline(&bin, '\n')){
- p[Blinelen(&bin)-1] = '\0';
-if(chatty) fprint(2, "%s\n", p);
- if(strcmp(p, "end of archive") == 0){
- _exits(0);
- }
- if(getfields(p, fields, NFLDS, 0, " \t") != NFLDS){
- warn("too few fields in file header");
- continue;
- }
- strcpy(namep, fields[0]);
- mode = strtoul(fields[1], 0, 8);
- mtime = strtoul(fields[4], 0, 10);
- bytes = strtoul(fields[5], 0, 10);
- strncpy(uid, fields[2], NAMELEN);
- strncpy(gid, fields[3], NAMELEN);
- if(mode & DMDIR)
- mkdir(name, mode, mtime, uid, gid);
- else
- extract(name, mode, mtime, uid, gid, bytes);
- }
- fprint(2, "premature end of archive\n");
- exits("premature end of archive");
-}
-
-char buf[8192];
-
-int
-ffcreate(char *name, ulong mode, char *uid, char *gid, ulong mtime, int length)
-{
- int fd, om;
- Dir nd;
-
- sprint(buf, "%s/%s", mtpt, name);
- om = ORDWR;
- if(mode&DMDIR)
- om = OREAD;
- if((fd = create(buf, om, (mode&DMDIR)|0666)) < 0)
- error("create %s: %r", buf);
-
- nulldir(&nd);
- nd.mode = mode;
- nd.uid = uid;
- nd.gid = gid;
- nd.mtime = mtime;
- if(length)
- nd.length = length;
- if(dirfwstat(fd, &nd) < 0)
- error("fwstat %s: %r", buf);
-
- return fd;
-}
-
-void
-mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
-{
- close(ffcreate(name, mode, uid, gid, mtime, 0));
-}
-
-void
-extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes)
-{
- int fd, tot, n;
-
- fd = ffcreate(name, mode, uid, gid, mtime, bytes);
-
- for(tot = 0; tot < bytes; tot += n){
- n = sizeof buf;
- if(tot + n > bytes)
- n = bytes - tot;
- n = Bread(&bin, buf, n);
- if(n <= 0)
- error("premature eof reading %s", name);
- if(write(fd, buf, n) != n)
- error("short write writing %s", name);
- }
- close(fd);
-}
-
-void
-error(char *fmt, ...)
-{
- char buf[1024];
- va_list arg;
-
- sprint(buf, "%s: ", argv0);
- va_start(arg, fmt);
- vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
- va_end(arg);
- fprint(2, "%s\n", buf);
- exits(0);
-}
-
-void
-warn(char *fmt, ...)
-{
- char buf[1024];
- va_list arg;
-
- sprint(buf, "%s: ", argv0);
- va_start(arg, fmt);
- vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);
- va_end(arg);
- fprint(2, "%s\n", buf);
-}
-
-int
-_efgfmt(Fmt*)
-{
- return -1;
-}
+++ /dev/null
-</$objtype/mkfile
-
-TARG=bzfs
-
-OFILES=\
- mkext.$O\
- oramfs.$O\
- unbflz.$O\
- unbzip.$O\
-
-HFILES=bzfs.h
-
-BIN=/sys/lib/dist/bin/$objtype
-LIB=/sys/src/cmd/bzip2/lib/libbzip2.a$O
-</sys/src/cmd/mkone
-
-CFLAGS=$CFLAGS -p -I/sys/src/cmd/bzip2/lib
-
-/sys/src/cmd/bzip2/lib/libbzip2.a$O:
- @{cd /sys/src/cmd/bzip2/lib && mk}
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include "bzfs.h"
-
-/*
- * Rather than reading /adm/users, which is a lot of work for
- * a toy program, we assume all groups have the form
- * NNN:user:user:
- * meaning that each user is the leader of his own group.
- */
-
-enum
-{
- OPERM = 0x3, /* mask of all permission types in open mode */
- Nram = 512,
- Maxsize = 512*1024*1024,
- Maxfdata = 8192,
-};
-
-typedef struct Fid Fid;
-typedef struct Ram Ram;
-
-struct Fid
-{
- short busy;
- short open;
- short rclose;
- int fid;
- Fid *next;
- char *user;
- Ram *ram;
-};
-
-struct Ram
-{
- short busy;
- short open;
- long parent; /* index in Ram array */
- Qid qid;
- long perm;
- char *name;
- ulong atime;
- ulong mtime;
- char *user;
- char *group;
- char *muid;
- char *data;
- long ndata;
-};
-
-enum
-{
- Pexec = 1,
- Pwrite = 2,
- Pread = 4,
- Pother = 1,
- Pgroup = 8,
- Powner = 64,
-};
-
-ulong path; /* incremented for each new file */
-Fid *fids;
-Ram ram[Nram];
-int nram;
-int mfd[2];
-char *user;
-uchar mdata[IOHDRSZ+Maxfdata];
-uchar rdata[Maxfdata]; /* buffer for data in reply */
-uchar statbuf[STATMAX];
-Fcall thdr;
-Fcall rhdr;
-int messagesize = sizeof mdata;
-
-Fid * newfid(int);
-uint ramstat(Ram*, uchar*, uint);
-void io(void);
-void *erealloc(void*, ulong);
-void *emalloc(ulong);
-char *estrdup(char*);
-void ramfsusage(void);
-int perm(Fid*, Ram*, int);
-char *atom(char*);
-
-char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
- *rattach(Fid*), *rwalk(Fid*),
- *ropen(Fid*), *rcreate(Fid*),
- *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
- *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
-
-char *(*fcalls[])(Fid*) = {
- [Tversion] rversion,
- [Tflush] rflush,
- [Tauth] rauth,
- [Tattach] rattach,
- [Twalk] rwalk,
- [Topen] ropen,
- [Tcreate] rcreate,
- [Tread] rread,
- [Twrite] rwrite,
- [Tclunk] rclunk,
- [Tremove] rremove,
- [Tstat] rstat,
- [Twstat] rwstat,
-};
-
-char Eperm[] = "permission denied";
-char Enotdir[] = "not a directory";
-char Enoauth[] = "no authentication in ramfs";
-char Enotexist[] = "file does not exist";
-char Einuse[] = "file in use";
-char Eexist[] = "file exists";
-char Eisdir[] = "file is a directory";
-char Enotowner[] = "not owner";
-char Eisopen[] = "file already open for I/O";
-char Excl[] = "exclusive use file already open";
-char Ename[] = "illegal name";
-char Eversion[] = "unknown 9P version";
-
-int debug;
-
-void
-notifyf(void *a, char *s)
-{
- USED(a);
- if(strncmp(s, "interrupt", 9) == 0)
- noted(NCONT);
- noted(NDFLT);
-}
-
-void
-ramfsmain(int argc, char *argv[])
-{
- Ram *r;
- char *defmnt;
- int p[2];
- char buf[32];
- int fd, srvfd;
- int stdio = 0;
-
- srvfd = -1;
- defmnt = "/tmp";
- ARGBEGIN{
- case 'D':
- debug = 1;
- break;
- case 'i': /* this is DIFFERENT from normal ramfs; use 1 for both for kernel */
- defmnt = 0;
- stdio = 1;
- srvfd = 0;
- mfd[0] = 1;
- mfd[1] = 1;
- break;
- case 's':
- defmnt = 0;
- break;
- case 'm':
- defmnt = ARGF();
- break;
- default:
- ramfsusage();
- }ARGEND
-
- if(!stdio){
- if(pipe(p) < 0)
- error("pipe failed");
- srvfd = p[1];
- mfd[0] = p[0];
- mfd[1] = p[0];
- if(defmnt == 0){
- fd = create("#s/ramfs", OWRITE, 0666);
- if(fd < 0)
- error("create of /srv/ramfs failed");
- sprint(buf, "%d", p[1]);
- if(write(fd, buf, strlen(buf)) < 0)
- error("writing /srv/ramfs");
- }
- }
-
- user = atom(getuser());
- notify(notifyf);
- nram = 1;
- r = &ram[0];
- r->busy = 1;
- r->data = 0;
- r->ndata = 0;
- r->perm = DMDIR | 0775;
- r->qid.type = QTDIR;
- r->qid.path = 0LL;
- r->qid.vers = 0;
- r->parent = 0;
- r->user = user;
- r->group = user;
- r->muid = user;
- r->atime = time(0);
- r->mtime = r->atime;
- r->name = estrdup(".");
-
- if(debug)
- fmtinstall('F', fcallfmt);
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
- case -1:
- error("fork");
- case 0:
- close(srvfd);
- io();
- break;
- default:
- close(mfd[0]); /* don't deadlock if child fails */
- if(defmnt && mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
- error("mount failed: %r");
- }
-}
-
-char*
-rversion(Fid*)
-{
- Fid *f;
-
- for(f = fids; f; f = f->next)
- if(f->busy)
- rclunk(f);
- if(thdr.msize > sizeof mdata)
- rhdr.msize = sizeof mdata;
- else
- rhdr.msize = thdr.msize;
- messagesize = rhdr.msize;
- if(strncmp(thdr.version, "9P2000", 6) != 0)
- return Eversion;
- rhdr.version = "9P2000";
- return 0;
-}
-
-char*
-rauth(Fid*)
-{
- return "ramfs: no authentication required";
-}
-
-char*
-rflush(Fid *f)
-{
- USED(f);
- return 0;
-}
-
-char*
-rattach(Fid *f)
-{
- /* no authentication! */
- f->busy = 1;
- f->rclose = 0;
- f->ram = &ram[0];
- rhdr.qid = f->ram->qid;
- if(thdr.uname[0])
- f->user = atom(thdr.uname);
- else
- f->user = atom("none");
- if(strcmp(user, "none") == 0)
- user = f->user;
- return 0;
-}
-
-char*
-clone(Fid *f, Fid **nf)
-{
- if(f->open)
- return Eisopen;
- if(f->ram->busy == 0)
- return Enotexist;
- *nf = newfid(thdr.newfid);
- (*nf)->busy = 1;
- (*nf)->open = 0;
- (*nf)->rclose = 0;
- (*nf)->ram = f->ram;
- (*nf)->user = f->user; /* no ref count; the leakage is minor */
- return 0;
-}
-
-char*
-rwalk(Fid *f)
-{
- Ram *r, *fram;
- char *name;
- Ram *parent;
- Fid *nf;
- char *err;
- ulong t;
- int i;
-
- err = nil;
- nf = nil;
- rhdr.nwqid = 0;
- if(rhdr.newfid != rhdr.fid){
- err = clone(f, &nf);
- if(err)
- return err;
- f = nf; /* walk the new fid */
- }
- fram = f->ram;
- if(thdr.nwname > 0){
- t = time(0);
- for(i=0; i<thdr.nwname && i<MAXWELEM; i++){
- if((fram->qid.type & QTDIR) == 0){
- err = Enotdir;
- break;
- }
- if(fram->busy == 0){
- err = Enotexist;
- break;
- }
- fram->atime = t;
- name = thdr.wname[i];
- if(strcmp(name, ".") == 0){
- Found:
- rhdr.nwqid++;
- rhdr.wqid[i] = fram->qid;
- continue;
- }
- parent = &ram[fram->parent];
-#ifdef CHECKS
- if(!perm(f, parent, Pexec)){
- err = Eperm;
- break;
- }
-#endif
- if(strcmp(name, "..") == 0){
- fram = parent;
- goto Found;
- }
- for(r=ram; r < &ram[nram]; r++)
- if(r->busy && r->parent==fram-ram && strcmp(name, r->name)==0){
- fram = r;
- goto Found;
- }
- break;
- }
- if(i==0 && err == nil)
- err = Enotexist;
- }
- if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){
- /* clunk the new fid, which is the one we walked */
- f->busy = 0;
- f->ram = nil;
- }
- if(rhdr.nwqid == thdr.nwname) /* update the fid after a successful walk */
- f->ram = fram;
- return err;
-}
-
-char *
-ropen(Fid *f)
-{
- Ram *r;
- int mode, trunc;
-
- if(f->open)
- return Eisopen;
- r = f->ram;
- if(r->busy == 0)
- return Enotexist;
- if(r->perm & DMEXCL)
- if(r->open)
- return Excl;
- mode = thdr.mode;
- if(r->qid.type & QTDIR){
- if(mode != OREAD)
- return Eperm;
- rhdr.qid = r->qid;
- return 0;
- }
- if(mode & ORCLOSE){
- /* can't remove root; must be able to write parent */
- if(r->qid.path==0 || !perm(f, &ram[r->parent], Pwrite))
- return Eperm;
- f->rclose = 1;
- }
- trunc = mode & OTRUNC;
- mode &= OPERM;
- if(mode==OWRITE || mode==ORDWR || trunc)
- if(!perm(f, r, Pwrite))
- return Eperm;
- if(mode==OREAD || mode==ORDWR)
- if(!perm(f, r, Pread))
- return Eperm;
- if(mode==OEXEC)
- if(!perm(f, r, Pexec))
- return Eperm;
- if(trunc && (r->perm&DMAPPEND)==0){
- r->ndata = 0;
- if(r->data)
- free(r->data);
- r->data = 0;
- r->qid.vers++;
- }
- rhdr.qid = r->qid;
- rhdr.iounit = messagesize-IOHDRSZ;
- f->open = 1;
- r->open++;
- return 0;
-}
-
-char *
-rcreate(Fid *f)
-{
- Ram *r;
- char *name;
- long parent, prm;
-
- if(f->open)
- return Eisopen;
- if(f->ram->busy == 0)
- return Enotexist;
- parent = f->ram - ram;
- if((f->ram->qid.type&QTDIR) == 0)
- return Enotdir;
- /* must be able to write parent */
-#ifdef CHECKS
- if(!perm(f, f->ram, Pwrite))
- return Eperm;
-#endif
- prm = thdr.perm;
- name = thdr.name;
- if(strcmp(name, ".")==0 || strcmp(name, "..")==0)
- return Ename;
- for(r=ram; r<&ram[nram]; r++)
- if(r->busy && parent==r->parent)
- if(strcmp((char*)name, r->name)==0)
- return Einuse;
- for(r=ram; r->busy; r++)
- if(r == &ram[Nram-1])
- return "no free ram resources";
- r->busy = 1;
- r->qid.path = ++path;
- r->qid.vers = 0;
- if(prm & DMDIR)
- r->qid.type |= QTDIR;
- r->parent = parent;
- free(r->name);
- r->name = estrdup(name);
- r->user = f->user;
- r->group = f->ram->group;
- r->muid = f->ram->muid;
- if(prm & DMDIR)
- prm = (prm&~0777) | (f->ram->perm&prm&0777);
- else
- prm = (prm&(~0777|0111)) | (f->ram->perm&prm&0666);
- r->perm = prm;
- r->ndata = 0;
- if(r-ram >= nram)
- nram = r - ram + 1;
- r->atime = time(0);
- r->mtime = r->atime;
- f->ram->mtime = r->atime;
- f->ram = r;
- rhdr.qid = r->qid;
- rhdr.iounit = messagesize-IOHDRSZ;
- f->open = 1;
- if(thdr.mode & ORCLOSE)
- f->rclose = 1;
- r->open++;
- return 0;
-}
-
-char*
-rread(Fid *f)
-{
- Ram *r;
- uchar *buf;
- long off;
- int n, m, cnt;
-
- if(f->ram->busy == 0)
- return Enotexist;
- n = 0;
- rhdr.count = 0;
- off = thdr.offset;
- buf = rdata;
- cnt = thdr.count;
- if(cnt > messagesize) /* shouldn't happen, anyway */
- cnt = messagesize;
- if(f->ram->qid.type & QTDIR){
- for(r=ram+1; off > 0; r++){
- if(r->busy && r->parent==f->ram-ram)
- off -= ramstat(r, statbuf, sizeof statbuf);
- if(r == &ram[nram-1])
- return 0;
- }
- for(; r<&ram[nram] && n < cnt; r++){
- if(!r->busy || r->parent!=f->ram-ram)
- continue;
- m = ramstat(r, buf+n, cnt-n);
- if(m == 0)
- break;
- n += m;
- }
- rhdr.data = (char*)rdata;
- rhdr.count = n;
- return 0;
- }
- r = f->ram;
- if(off >= r->ndata)
- return 0;
- r->atime = time(0);
- n = cnt;
- if(off+n > r->ndata)
- n = r->ndata - off;
- rhdr.data = r->data+off;
- rhdr.count = n;
- return 0;
-}
-
-char*
-rwrite(Fid *f)
-{
- Ram *r;
- ulong off;
- int cnt;
-
- r = f->ram;
- if(r->busy == 0)
- return Enotexist;
- off = thdr.offset;
- if(r->perm & DMAPPEND)
- off = r->ndata;
- cnt = thdr.count;
- if(r->qid.type & QTDIR)
- return Eisdir;
- if(off+cnt >= Maxsize) /* sanity check */
- return "write too big";
- if(off+cnt > r->ndata)
- r->data = erealloc(r->data, off+cnt);
- if(off > r->ndata)
- memset(r->data+r->ndata, 0, off-r->ndata);
- if(off+cnt > r->ndata)
- r->ndata = off+cnt;
- memmove(r->data+off, thdr.data, cnt);
- r->qid.vers++;
- r->mtime = time(0);
- rhdr.count = cnt;
- return 0;
-}
-
-void
-realremove(Ram *r)
-{
- r->ndata = 0;
- if(r->data)
- free(r->data);
- r->data = 0;
- r->parent = 0;
- memset(&r->qid, 0, sizeof r->qid);
- free(r->name);
- r->name = nil;
- r->busy = 0;
-}
-
-char *
-rclunk(Fid *f)
-{
- if(f->open)
- f->ram->open--;
- if(f->rclose)
- realremove(f->ram);
- f->busy = 0;
- f->open = 0;
- f->ram = 0;
- return 0;
-}
-
-char *
-rremove(Fid *f)
-{
- Ram *r;
-
- if(f->open)
- f->ram->open--;
- f->busy = 0;
- f->open = 0;
- r = f->ram;
- f->ram = 0;
-#ifdef CHECKS
- if(r->qid.path == 0 || !perm(f, &ram[r->parent], Pwrite))
- return Eperm;
-#endif
- ram[r->parent].mtime = time(0);
- realremove(r);
- return 0;
-}
-
-char *
-rstat(Fid *f)
-{
- if(f->ram->busy == 0)
- return Enotexist;
- rhdr.nstat = ramstat(f->ram, statbuf, sizeof statbuf);
- rhdr.stat = statbuf;
- return 0;
-}
-
-char *
-rwstat(Fid *f)
-{
- Ram *r, *s;
- Dir dir;
-
- if(f->ram->busy == 0)
- return Enotexist;
- convM2D(thdr.stat, thdr.nstat, &dir, (char*)statbuf);
- r = f->ram;
-
- /*
- * To change length, must have write permission on file.
- */
-#ifdef CHECKS
- if(dir.length!=~0 && dir.length!=r->ndata){
- if(!perm(f, r, Pwrite))
- return Eperm;
- }
-#endif
-
- /*
- * To change name, must have write permission in parent
- * and name must be unique.
- */
- if(dir.name[0]!='\0' && strcmp(dir.name, r->name)!=0){
-#ifdef CHECKS
- if(!perm(f, &ram[r->parent], Pwrite))
- return Eperm;
-#endif
- for(s=ram; s<&ram[nram]; s++)
- if(s->busy && s->parent==r->parent)
- if(strcmp(dir.name, s->name)==0)
- return Eexist;
- }
-
-#ifdef OWNERS
- /*
- * To change mode, must be owner or group leader.
- * Because of lack of users file, leader=>group itself.
- */
- if(dir.mode!=~0 && r->perm!=dir.mode){
- if(strcmp(f->user, r->user) != 0)
- if(strcmp(f->user, r->group) != 0)
- return Enotowner;
- }
-
- /*
- * To change group, must be owner and member of new group,
- * or leader of current group and leader of new group.
- * Second case cannot happen, but we check anyway.
- */
- if(dir.gid[0]!='\0' && strcmp(r->group, dir.gid)!=0){
- if(strcmp(f->user, r->user) == 0)
- if(strcmp(f->user, dir.gid) == 0)
- goto ok;
- if(strcmp(f->user, r->group) == 0)
- if(strcmp(f->user, dir.gid) == 0)
- goto ok;
- return Enotowner;
- ok:;
- }
-#endif
-
- /* all ok; do it */
- if(dir.mode != ~0){
- dir.mode &= ~DMDIR; /* cannot change dir bit */
- dir.mode |= r->perm&DMDIR;
- r->perm = dir.mode;
- }
- if(dir.name[0] != '\0'){
- free(r->name);
- r->name = estrdup(dir.name);
- }
- if(dir.gid[0] != '\0')
- r->group = atom(dir.gid);
-
- if(dir.uid[0] != '\0')
- r->user = atom(dir.uid);
-
- if(dir.length!=~0 && dir.length!=r->ndata){
- r->data = erealloc(r->data, dir.length);
- if(r->ndata < dir.length)
- memset(r->data+r->ndata, 0, dir.length-r->ndata);
- r->ndata = dir.length;
- }
-
- if(dir.mtime != ~0)
- r->mtime = dir.mtime;
-
- ram[r->parent].mtime = time(0);
- return 0;
-}
-
-uint
-ramstat(Ram *r, uchar *buf, uint nbuf)
-{
- Dir dir;
-
- dir.name = r->name;
- dir.qid = r->qid;
- dir.mode = r->perm;
- dir.length = r->ndata;
- dir.uid = r->user;
- dir.gid = r->group;
- dir.muid = r->muid;
- dir.atime = r->atime;
- dir.mtime = r->mtime;
- return convD2M(&dir, buf, nbuf);
-}
-
-Fid *
-newfid(int fid)
-{
- Fid *f, *ff;
-
- ff = 0;
- for(f = fids; f; f = f->next)
- if(f->fid == fid)
- return f;
- else if(!ff && !f->busy)
- ff = f;
- if(ff){
- ff->fid = fid;
- return ff;
- }
- f = emalloc(sizeof *f);
- f->ram = nil;
- f->fid = fid;
- f->next = fids;
- fids = f;
- return f;
-}
-
-void
-io(void)
-{
- char *err;
- int n, pid;
-
- pid = getpid();
-
- for(;;){
- /*
- * reading from a pipe or a network device
- * will give an error after a few eof reads.
- * however, we cannot tell the difference
- * between a zero-length read and an interrupt
- * on the processes writing to us,
- * so we wait for the error.
- */
- n = read9pmsg(mfd[0], mdata, messagesize);
- if(n < 0)
- error("mount read: %r");
- if(n == 0)
- continue;
- if(convM2S(mdata, n, &thdr) == 0)
- continue;
-
- if(debug)
- fprint(2, "ramfs %d:<-%F\n", pid, &thdr);
-
- if(!fcalls[thdr.type])
- err = "bad fcall type";
- else
- err = (*fcalls[thdr.type])(newfid(thdr.fid));
- if(err){
- rhdr.type = Rerror;
- rhdr.ename = err;
- }else{
- rhdr.type = thdr.type + 1;
- rhdr.fid = thdr.fid;
- }
- rhdr.tag = thdr.tag;
- if(debug)
- fprint(2, "ramfs %d:->%F\n", pid, &rhdr);/**/
- n = convS2M(&rhdr, mdata, messagesize);
- if(n == 0)
- error("convS2M error on write");
- if(write(mfd[1], mdata, n) != n)
- error("mount write");
- }
-}
-
-int
-perm(Fid *f, Ram *r, int p)
-{
- if((p*Pother) & r->perm)
- return 1;
- if(strcmp(f->user, r->group)==0 && ((p*Pgroup) & r->perm))
- return 1;
- if(strcmp(f->user, r->user)==0 && ((p*Powner) & r->perm))
- return 1;
- return 0;
-}
-
-void *
-emalloc(ulong n)
-{
- void *p;
-
- p = malloc(n);
- if(!p)
- error("out of memory");
- memset(p, 0, n);
- return p;
-}
-
-void *
-erealloc(void *p, ulong n)
-{
- p = realloc(p, n);
- if(!p)
- error("out of memory");
- return p;
-}
-
-char *
-estrdup(char *q)
-{
- char *p;
- int n;
-
- n = strlen(q)+1;
- p = malloc(n);
- if(!p)
- error("out of memory");
- memmove(p, q, n);
- return p;
-}
-
-void
-ramfsusage(void)
-{
- fprint(2, "usage: %s [-is] [-m mountpoint]\n", argv0);
- exits("usage");
-}
-
-/*
- * Custom allocators to avoid malloc overheads on small objects.
- * We never free these. (See below.)
- */
-typedef struct Stringtab Stringtab;
-struct Stringtab {
- Stringtab *link;
- char *str;
-};
-static Stringtab*
-taballoc(void)
-{
- static Stringtab *t;
- static uint nt;
-
- if(nt == 0){
- t = malloc(64*sizeof(Stringtab));
- if(t == 0)
- sysfatal("out of memory");
- nt = 64;
- }
- nt--;
- return t++;
-}
-
-static char*
-xstrdup(char *s)
-{
- char *r;
- int len;
- static char *t;
- static int nt;
-
- len = strlen(s)+1;
- if(len >= 8192)
- sysfatal("strdup big string");
-
- if(nt < len){
- t = malloc(8192);
- if(t == 0)
- sysfatal("out of memory");
- nt = 8192;
- }
- r = t;
- t += len;
- nt -= len;
- strcpy(r, s);
- return r;
-}
-
-/*
- * Return a uniquely allocated copy of a string.
- * Don't free these -- they stay in the table for the
- * next caller who wants that particular string.
- * String comparison can be done with pointer comparison
- * if you know both strings are atoms.
- */
-static Stringtab *stab[1024];
-
-static uint
-hash(char *s)
-{
- uint h;
- uchar *p;
-
- h = 0;
- for(p=(uchar*)s; *p; p++)
- h = h*37 + *p;
- return h;
-}
-
-char*
-atom(char *str)
-{
- uint h;
- Stringtab *tab;
-
- h = hash(str) % nelem(stab);
- for(tab=stab[h]; tab; tab=tab->link)
- if(strcmp(str, tab->str) == 0)
- return tab->str;
-
- tab = taballoc();
- tab->str = xstrdup(str);
- tab->link = stab[h];
- stab[h] = tab;
- return tab->str;
-}
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "bzfs.h"
-
-int
-Bgetint(Biobuf *b)
-{
- uchar p[4];
-
- if(Bread(b, p, 4) != 4)
- sysfatal("short read");
- return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
-}
-
-/*
- * memmove but make sure overlap works properly.
- */
-void
-copy(uchar *dst, uchar *src, int n)
-{
- while(n-- > 0)
- *dst++ = *src++;
-}
-
-int
-unbflz(int in)
-{
- int rv, out, p[2];
- Biobuf *b, bin;
- char buf[5];
- uchar *data;
- int i, j, length, n, m, o, sum;
- ulong *blk;
- int nblk, mblk;
-
- if(pipe(p) < 0)
- sysfatal("pipe: %r");
-
- rv = p[0];
- out = p[1];
- switch(rfork(RFPROC|RFFDG|RFNOTEG|RFMEM)){
- case -1:
- sysfatal("fork: %r");
- case 0:
- close(rv);
- break;
- default:
- close(in);
- close(out);
- return rv;
- }
-
- Binit(&bin, in, OREAD);
- b = &bin;
-
- if(Bread(b, buf, 4) != 4)
- sysfatal("short read");
-
- if(memcmp(buf, "BLZ\n", 4) != 0)
- sysfatal("bad header");
-
- length = Bgetint(b);
- data = malloc(length);
- if(data == nil)
- sysfatal("out of memory");
- sum = 0;
- nblk = 0;
- mblk = 0;
- blk = nil;
- while(sum < length){
- if(nblk>=mblk){
- mblk += 16384;
- blk = realloc(blk, (mblk+1)*sizeof(blk[0]));
- if(blk == nil)
- sysfatal("out of memory");
- }
- n = Bgetint(b);
- blk[nblk++] = n;
- if(n&(1<<31))
- n &= ~(1<<31);
- else
- blk[nblk++] = Bgetint(b);
- sum += n;
- }
- if(sum != length)
- sysfatal("bad compressed data %d %d", sum, length);
- i = 0;
- j = 0;
- while(i < length){
- assert(j < nblk);
- n = blk[j++];
- if(n&(1<<31)){
- n &= ~(1<<31);
- if((m=Bread(b, data+i, n)) != n)
- sysfatal("short read %d %d", n, m);
- }else{
- o = blk[j++];
- copy(data+i, data+o, n);
- }
- i += n;
- }
- write(out, data, length);
- close(in);
- close(out);
- _exits(0);
- return -1;
-}
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "bzfs.h"
-
-/*
- * THIS FILE IS NOT IDENTICAL TO THE ORIGINAL
- * FROM THE BZIP2 DISTRIBUTION.
- *
- * It has been modified, mainly to break the library
- * into smaller pieces.
- *
- * Russ Cox
- * rsc@plan9.bell-labs.com
- * July 2000
- */
-
-/*---------------------------------------------*/
-/*--
- Place a 1 beside your platform, and 0 elsewhere.
- Attempts to autosniff this even if you don't.
---*/
-
-
-/*--
- Plan 9 from Bell Labs
---*/
-#define BZ_PLAN9 1
-#define BZ_UNIX 0
-
-#define exit(x) exits((x) ? "whoops" : nil)
-#define size_t ulong
-
-#ifdef __GNUC__
-# define NORETURN __attribute__ ((noreturn))
-#else
-# define NORETURN /**/
-#endif
-
-/*--
- Some more stuff for all platforms :-)
- This might have to get moved into the platform-specific
- header files if we encounter a machine with different sizes.
---*/
-
-typedef char Char;
-typedef unsigned char Bool;
-typedef unsigned char UChar;
-typedef int Int32;
-typedef unsigned int UInt32;
-typedef short Int16;
-typedef unsigned short UInt16;
-
-#define True ((Bool)1)
-#define False ((Bool)0)
-
-/*--
- IntNative is your platform's `native' int size.
- Only here to avoid probs with 64-bit platforms.
---*/
-typedef int IntNative;
-
-#include "bzfs.h"
-#include "bzlib.h"
-#include "bzlib_private.h"
-
-static int
-bunzip(int ofd, char *ofile, Biobuf *bin)
-{
- int e, n, done, onemore;
- char buf[8192];
- char obuf[8192];
- Biobuf bout;
- bz_stream strm;
-
- USED(ofile);
-
- memset(&strm, 0, sizeof strm);
- BZ2_bzDecompressInit(&strm, 0, 0);
-
- strm.next_in = buf;
- strm.avail_in = 0;
- strm.next_out = obuf;
- strm.avail_out = sizeof obuf;
-
- done = 0;
- Binit(&bout, ofd, OWRITE);
-
- /*
- * onemore is a crummy hack to go 'round the loop
- * once after we finish, to flush the output buffer.
- */
- onemore = 1;
- SET(e);
- do {
- if(!done && strm.avail_in < sizeof buf) {
- if(strm.avail_in)
- memmove(buf, strm.next_in, strm.avail_in);
-
- n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
- if(n <= 0)
- done = 1;
- else
- strm.avail_in += n;
- strm.next_in = buf;
- }
- if(strm.avail_out < sizeof obuf) {
- Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out);
- strm.next_out = obuf;
- strm.avail_out = sizeof obuf;
- }
-
- if(onemore == 0)
- break;
- } while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--);
-
- if(e != BZ_STREAM_END) {
- fprint(2, "bunzip2: decompress failed\n");
- return 0;
- }
-
- if(BZ2_bzDecompressEnd(&strm) != BZ_OK) {
- fprint(2, "bunzip2: decompress end failed (can't happen)\n");
- return 0;
- }
-
- Bterm(&bout);
-
- return 1;
-}
-
-void
-_unbzip(int in, int out)
-{
- Biobuf bin;
-
- Binit(&bin, in, OREAD);
- if(bunzip(out, nil, &bin) != 1) {
- fprint(2, "bunzip2 failed\n");
- _exits("bunzip2");
- }
-}
-
-int
-unbzip(int in)
-{
- int rv, out, p[2];
-
- if(pipe(p) < 0)
- sysfatal("pipe: %r");
-
- rv = p[0];
- out = p[1];
- switch(rfork(RFPROC|RFFDG|RFNOTEG|RFMEM)){
- case -1:
- sysfatal("fork: %r");
- case 0:
- close(rv);
- break;
- default:
- close(in);
- close(out);
- return rv;
- }
-
- _unbzip(in, out);
- _exits(0);
- return -1; /* not reached */
-}
-
-int bz_config_ok ( void )
-{
- if (sizeof(int) != 4) return 0;
- if (sizeof(short) != 2) return 0;
- if (sizeof(char) != 1) return 0;
- return 1;
-}
-
-void* default_bzalloc(void *o, int items, int size)
-{
- USED(o);
- return sbrk(items*size);
-}
-
-void default_bzfree(void*, void*)
-{
-}
-
-void
-bz_internal_error(int)
-{
- abort();
-}
-
-/*-------------------------------------------------------------*/
-/*--- Decompression machinery ---*/
-/*--- decompress.c ---*/
-/*-------------------------------------------------------------*/
-
-/*--
- This file is a part of bzip2 and/or libbzip2, a program and
- library for lossless, block-sorting data compression.
-
- Copyright (C) 1996-2000 Julian R Seward. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. The origin of this software must not be misrepresented; you must
- not claim that you wrote the original software. If you use this
- software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
-
- 3. Altered source versions must be plainly marked as such, and must
- not be misrepresented as being the original software.
-
- 4. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Julian Seward, Cambridge, UK.
- jseward@acm.org
- bzip2/libbzip2 version 1.0 of 21 March 2000
-
- This program is based on (at least) the work of:
- Mike Burrows
- David Wheeler
- Peter Fenwick
- Alistair Moffat
- Radford Neal
- Ian H. Witten
- Robert Sedgewick
- Jon L. Bentley
-
- For more information on these sources, see the manual.
---*/
-
-
-
-/*---------------------------------------------------*/
-static
-void makeMaps_d ( DState* s )
-{
- Int32 i;
- s->nInUse = 0;
- for (i = 0; i < 256; i++)
- if (s->inUse[i]) {
- s->seqToUnseq[s->nInUse] = i;
- s->nInUse++;
- }
-}
-
-
-/*---------------------------------------------------*/
-#define RETURN(rrr) \
- { retVal = rrr; goto save_state_and_return; };
-
-#define GET_BITS(lll,vvv,nnn) \
- case lll: \
- { int x; if((retVal = getbits(s, lll, &x, nnn)) != 99) \
- goto save_state_and_return; vvv=x; }\
-
-int
-getbits(DState *s, int lll, int *vvv, int nnn)
-{
- s->state = lll;
-
- for(;;) {
- if (s->bsLive >= nnn) {
- UInt32 v;
- v = (s->bsBuff >>
- (s->bsLive-nnn)) & ((1 << nnn)-1);
- s->bsLive -= nnn;
- *vvv = v;
- return 99;
- }
- if (s->strm->avail_in == 0) return BZ_OK;
- s->bsBuff
- = (s->bsBuff << 8) |
- ((UInt32)
- (*((UChar*)(s->strm->next_in))));
- s->bsLive += 8;
- s->strm->next_in++;
- s->strm->avail_in--;
- s->strm->total_in_lo32++;
- if (s->strm->total_in_lo32 == 0)
- s->strm->total_in_hi32++;
- }
- return -1; /* KEN */
-}
-
-#define GET_UCHAR(lll,uuu) \
- GET_BITS(lll,uuu,8)
-
-#define GET_BIT(lll,uuu) \
- GET_BITS(lll,uuu,1)
-
-/*---------------------------------------------------*/
-#define GET_MTF_VAL(label1,label2,lval) \
-{ \
- if (groupPos == 0) { \
- groupNo++; \
- if (groupNo >= nSelectors) \
- RETURN(BZ_DATA_ERROR); \
- groupPos = BZ_G_SIZE; \
- gSel = s->selector[groupNo]; \
- gMinlen = s->minLens[gSel]; \
- gLimit = &(s->limit[gSel][0]); \
- gPerm = &(s->perm[gSel][0]); \
- gBase = &(s->base[gSel][0]); \
- } \
- groupPos--; \
- zn = gMinlen; \
- GET_BITS(label1, zvec, zn); \
- while (1) { \
- if (zn > 20 /* the longest code */) \
- RETURN(BZ_DATA_ERROR); \
- if (zvec <= gLimit[zn]) break; \
- zn++; \
- GET_BIT(label2, zj); \
- zvec = (zvec << 1) | zj; \
- }; \
- if (zvec - gBase[zn] < 0 \
- || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
- RETURN(BZ_DATA_ERROR); \
- lval = gPerm[zvec - gBase[zn]]; \
-}
-
-
-/*---------------------------------------------------*/
-Int32 BZ2_decompress ( DState* s )
-{
- UChar uc;
- Int32 retVal;
- Int32 minLen, maxLen;
- bz_stream* strm = s->strm;
-
- /* stuff that needs to be saved/restored */
- Int32 i;
- Int32 j;
- Int32 t;
- Int32 alphaSize;
- Int32 nGroups;
- Int32 nSelectors;
- Int32 EOB;
- Int32 groupNo;
- Int32 groupPos;
- Int32 nextSym;
- Int32 nblockMAX;
- Int32 nblock;
- Int32 es;
- Int32 N;
- Int32 curr;
- Int32 zt;
- Int32 zn;
- Int32 zvec;
- Int32 zj;
- Int32 gSel;
- Int32 gMinlen;
- Int32* gLimit;
- Int32* gBase;
- Int32* gPerm;
-
- if (s->state == BZ_X_MAGIC_1) {
- /*initialise the save area*/
- s->save_i = 0;
- s->save_j = 0;
- s->save_t = 0;
- s->save_alphaSize = 0;
- s->save_nGroups = 0;
- s->save_nSelectors = 0;
- s->save_EOB = 0;
- s->save_groupNo = 0;
- s->save_groupPos = 0;
- s->save_nextSym = 0;
- s->save_nblockMAX = 0;
- s->save_nblock = 0;
- s->save_es = 0;
- s->save_N = 0;
- s->save_curr = 0;
- s->save_zt = 0;
- s->save_zn = 0;
- s->save_zvec = 0;
- s->save_zj = 0;
- s->save_gSel = 0;
- s->save_gMinlen = 0;
- s->save_gLimit = NULL;
- s->save_gBase = NULL;
- s->save_gPerm = NULL;
- }
-
- /*restore from the save area*/
- i = s->save_i;
- j = s->save_j;
- t = s->save_t;
- alphaSize = s->save_alphaSize;
- nGroups = s->save_nGroups;
- nSelectors = s->save_nSelectors;
- EOB = s->save_EOB;
- groupNo = s->save_groupNo;
- groupPos = s->save_groupPos;
- nextSym = s->save_nextSym;
- nblockMAX = s->save_nblockMAX;
- nblock = s->save_nblock;
- es = s->save_es;
- N = s->save_N;
- curr = s->save_curr;
- zt = s->save_zt;
- zn = s->save_zn;
- zvec = s->save_zvec;
- zj = s->save_zj;
- gSel = s->save_gSel;
- gMinlen = s->save_gMinlen;
- gLimit = s->save_gLimit;
- gBase = s->save_gBase;
- gPerm = s->save_gPerm;
-
- retVal = BZ_OK;
-
- switch (s->state) {
-
- GET_UCHAR(BZ_X_MAGIC_1, uc);
- if (uc != 'B') RETURN(BZ_DATA_ERROR_MAGIC);
-
- GET_UCHAR(BZ_X_MAGIC_2, uc);
- if (uc != 'Z') RETURN(BZ_DATA_ERROR_MAGIC);
-
- GET_UCHAR(BZ_X_MAGIC_3, uc)
- if (uc != 'h') RETURN(BZ_DATA_ERROR_MAGIC);
-
- GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
- if (s->blockSize100k < '1' ||
- s->blockSize100k > '9') RETURN(BZ_DATA_ERROR_MAGIC);
- s->blockSize100k -= '0';
-
- if (0 && s->smallDecompress) {
- s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
- s->ll4 = BZALLOC(
- ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
- );
- if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
- } else {
- s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
- if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
- }
-
- GET_UCHAR(BZ_X_BLKHDR_1, uc);
-
- if (uc == 0x17) goto endhdr_2;
- if (uc != 0x31) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_BLKHDR_2, uc);
- if (uc != 0x41) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_BLKHDR_3, uc);
- if (uc != 0x59) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_BLKHDR_4, uc);
- if (uc != 0x26) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_BLKHDR_5, uc);
- if (uc != 0x53) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_BLKHDR_6, uc);
- if (uc != 0x59) RETURN(BZ_DATA_ERROR);
-
- s->currBlockNo++;
- // if (s->verbosity >= 2)
- // VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
-
- s->storedBlockCRC = 0;
- GET_UCHAR(BZ_X_BCRC_1, uc);
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
- GET_UCHAR(BZ_X_BCRC_2, uc);
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
- GET_UCHAR(BZ_X_BCRC_3, uc);
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
- GET_UCHAR(BZ_X_BCRC_4, uc);
- s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
-
- GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
-
- s->origPtr = 0;
- GET_UCHAR(BZ_X_ORIGPTR_1, uc);
- s->origPtr = (s->origPtr << 8) | ((Int32)uc);
- GET_UCHAR(BZ_X_ORIGPTR_2, uc);
- s->origPtr = (s->origPtr << 8) | ((Int32)uc);
- GET_UCHAR(BZ_X_ORIGPTR_3, uc);
- s->origPtr = (s->origPtr << 8) | ((Int32)uc);
-
- if (s->origPtr < 0)
- RETURN(BZ_DATA_ERROR);
- if (s->origPtr > 10 + 100000*s->blockSize100k)
- RETURN(BZ_DATA_ERROR);
-
- /*--- Receive the mapping table ---*/
- for (i = 0; i < 16; i++) {
- GET_BIT(BZ_X_MAPPING_1, uc);
- if (uc == 1)
- s->inUse16[i] = True; else
- s->inUse16[i] = False;
- }
-
- for (i = 0; i < 256; i++) s->inUse[i] = False;
-
- for (i = 0; i < 16; i++)
- if (s->inUse16[i])
- for (j = 0; j < 16; j++) {
- GET_BIT(BZ_X_MAPPING_2, uc);
- if (uc == 1) s->inUse[i * 16 + j] = True;
- }
- makeMaps_d ( s );
- if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
- alphaSize = s->nInUse+2;
-
- /*--- Now the selectors ---*/
- GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
- if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
- GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
- if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
- for (i = 0; i < nSelectors; i++) {
- j = 0;
- while (True) {
- GET_BIT(BZ_X_SELECTOR_3, uc);
- if (uc == 0) break;
- j++;
- if (j >= nGroups) RETURN(BZ_DATA_ERROR);
- }
- s->selectorMtf[i] = j;
- }
-
- /*--- Undo the MTF values for the selectors. ---*/
- {
- UChar pos[BZ_N_GROUPS], tmp, v;
- for (v = 0; v < nGroups; v++) pos[v] = v;
-
- for (i = 0; i < nSelectors; i++) {
- v = s->selectorMtf[i];
- tmp = pos[v];
- while (v > 0) { pos[v] = pos[v-1]; v--; }
- pos[0] = tmp;
- s->selector[i] = tmp;
- }
- }
-
- /*--- Now the coding tables ---*/
- for (t = 0; t < nGroups; t++) {
- GET_BITS(BZ_X_CODING_1, curr, 5);
- for (i = 0; i < alphaSize; i++) {
- while (True) {
- if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
- GET_BIT(BZ_X_CODING_2, uc);
- if (uc == 0) break;
- GET_BIT(BZ_X_CODING_3, uc);
- if (uc == 0) curr++; else curr--;
- }
- s->len[t][i] = curr;
- }
- }
-
- /*--- Create the Huffman decoding tables ---*/
- for (t = 0; t < nGroups; t++) {
- minLen = 32;
- maxLen = 0;
- for (i = 0; i < alphaSize; i++) {
- if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
- if (s->len[t][i] < minLen) minLen = s->len[t][i];
- }
- BZ2_hbCreateDecodeTables (
- &(s->limit[t][0]),
- &(s->base[t][0]),
- &(s->perm[t][0]),
- &(s->len[t][0]),
- minLen, maxLen, alphaSize
- );
- s->minLens[t] = minLen;
- }
-
- /*--- Now the MTF values ---*/
-
- EOB = s->nInUse+1;
- nblockMAX = 100000 * s->blockSize100k;
- groupNo = -1;
- groupPos = 0;
-
- for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
-
- /*-- MTF init --*/
- {
- Int32 ii, jj, kk;
- kk = MTFA_SIZE-1;
- for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
- for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
- s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
- kk--;
- }
- s->mtfbase[ii] = kk + 1;
- }
- }
- /*-- end MTF init --*/
-
- nblock = 0;
- GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
-
- while (True) {
-
- if (nextSym == EOB) break;
-
- if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
-
- es = -1;
- N = 1;
- do {
- if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
- if (nextSym == BZ_RUNB) es = es + (1+1) * N;
- N = N * 2;
- GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
- }
- while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
-
- es++;
- uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
- s->unzftab[uc] += es;
-
- if (0 && s->smallDecompress)
- while (es > 0) {
- if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
- s->ll16[nblock] = (UInt16)uc;
- nblock++;
- es--;
- }
- else
- while (es > 0) {
- if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
- s->tt[nblock] = (UInt32)uc;
- nblock++;
- es--;
- };
-
- continue;
-
- } else {
-
- if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
-
- /*-- uc = MTF ( nextSym-1 ) --*/
- {
- Int32 ii, jj, kk, pp, lno, off;
- UInt32 nn;
- nn = (UInt32)(nextSym - 1);
-
- if (nn < MTFL_SIZE) {
- /* avoid general-case expense */
- pp = s->mtfbase[0];
- uc = s->mtfa[pp+nn];
- while (nn > 3) {
- Int32 z = pp+nn;
- s->mtfa[(z) ] = s->mtfa[(z)-1];
- s->mtfa[(z)-1] = s->mtfa[(z)-2];
- s->mtfa[(z)-2] = s->mtfa[(z)-3];
- s->mtfa[(z)-3] = s->mtfa[(z)-4];
- nn -= 4;
- }
- while (nn > 0) {
- s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
- };
- s->mtfa[pp] = uc;
- } else {
- /* general case */
- lno = nn / MTFL_SIZE;
- off = nn % MTFL_SIZE;
- pp = s->mtfbase[lno] + off;
- uc = s->mtfa[pp];
- while (pp > s->mtfbase[lno]) {
- s->mtfa[pp] = s->mtfa[pp-1]; pp--;
- };
- s->mtfbase[lno]++;
- while (lno > 0) {
- s->mtfbase[lno]--;
- s->mtfa[s->mtfbase[lno]]
- = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
- lno--;
- }
- s->mtfbase[0]--;
- s->mtfa[s->mtfbase[0]] = uc;
- if (s->mtfbase[0] == 0) {
- kk = MTFA_SIZE-1;
- for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
- for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
- s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
- kk--;
- }
- s->mtfbase[ii] = kk + 1;
- }
- }
- }
- }
- /*-- end uc = MTF ( nextSym-1 ) --*/
-
- s->unzftab[s->seqToUnseq[uc]]++;
- if (0 && s->smallDecompress)
- s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
- s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
- nblock++;
-
- GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
- continue;
- }
- }
-
- /* Now we know what nblock is, we can do a better sanity
- check on s->origPtr.
- */
- if (s->origPtr < 0 || s->origPtr >= nblock)
- RETURN(BZ_DATA_ERROR);
-
- s->state_out_len = 0;
- s->state_out_ch = 0;
- BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
- s->state = BZ_X_OUTPUT;
- // if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
-
- /*-- Set up cftab to facilitate generation of T^(-1) --*/
- s->cftab[0] = 0;
- for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
- for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
-
- if (0 && s->smallDecompress) {
-
- /*-- Make a copy of cftab, used in generation of T --*/
- for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
-
- /*-- compute the T vector --*/
- for (i = 0; i < nblock; i++) {
- uc = (UChar)(s->ll16[i]);
- SET_LL(i, s->cftabCopy[uc]);
- s->cftabCopy[uc]++;
- }
-
- /*-- Compute T^(-1) by pointer reversal on T --*/
- i = s->origPtr;
- j = GET_LL(i);
- do {
- Int32 tmp = GET_LL(j);
- SET_LL(j, i);
- i = j;
- j = tmp;
- }
- while (i != s->origPtr);
-
- s->tPos = s->origPtr;
- s->nblock_used = 0;
- if (s->blockRandomised) {
- BZ_RAND_INIT_MASK;
- BZ_GET_SMALL(s->k0); s->nblock_used++;
- BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
- } else {
- BZ_GET_SMALL(s->k0); s->nblock_used++;
- }
-
- } else {
-
- /*-- compute the T^(-1) vector --*/
- for (i = 0; i < nblock; i++) {
- uc = (UChar)(s->tt[i] & 0xff);
- s->tt[s->cftab[uc]] |= (i << 8);
- s->cftab[uc]++;
- }
-
- s->tPos = s->tt[s->origPtr] >> 8;
- s->nblock_used = 0;
- if (s->blockRandomised) {
- BZ_RAND_INIT_MASK;
- BZ_GET_FAST(s->k0); s->nblock_used++;
- BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
- } else {
- BZ_GET_FAST(s->k0); s->nblock_used++;
- }
-
- }
-
- RETURN(BZ_OK);
-
-
-
- endhdr_2:
-
- GET_UCHAR(BZ_X_ENDHDR_2, uc);
- if (uc != 0x72) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_ENDHDR_3, uc);
- if (uc != 0x45) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_ENDHDR_4, uc);
- if (uc != 0x38) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_ENDHDR_5, uc);
- if (uc != 0x50) RETURN(BZ_DATA_ERROR);
- GET_UCHAR(BZ_X_ENDHDR_6, uc);
- if (uc != 0x90) RETURN(BZ_DATA_ERROR);
-
- s->storedCombinedCRC = 0;
- GET_UCHAR(BZ_X_CCRC_1, uc);
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
- GET_UCHAR(BZ_X_CCRC_2, uc);
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
- GET_UCHAR(BZ_X_CCRC_3, uc);
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
- GET_UCHAR(BZ_X_CCRC_4, uc);
- s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
-
- s->state = BZ_X_IDLE;
- RETURN(BZ_STREAM_END);
-
- default: AssertH ( False, 4001 );
- }
-
- AssertH ( False, 4002 );
-
- save_state_and_return:
-
- s->save_i = i;
- s->save_j = j;
- s->save_t = t;
- s->save_alphaSize = alphaSize;
- s->save_nGroups = nGroups;
- s->save_nSelectors = nSelectors;
- s->save_EOB = EOB;
- s->save_groupNo = groupNo;
- s->save_groupPos = groupPos;
- s->save_nextSym = nextSym;
- s->save_nblockMAX = nblockMAX;
- s->save_nblock = nblock;
- s->save_es = es;
- s->save_N = N;
- s->save_curr = curr;
- s->save_zt = zt;
- s->save_zn = zn;
- s->save_zvec = zvec;
- s->save_zj = zj;
- s->save_gSel = gSel;
- s->save_gMinlen = gMinlen;
- s->save_gLimit = gLimit;
- s->save_gBase = gBase;
- s->save_gPerm = gPerm;
-
- return retVal;
-}
-
-
-/*-------------------------------------------------------------*/
-/*--- end decompress.c ---*/
-/*-------------------------------------------------------------*/
+++ /dev/null
-/*
- * The `cd' shell.
- * Just has cd and lc.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-char *pwd;
-char *root = "/";
-
-void
-usage(void)
-{
- fprint(2, "usage: cdsh [-r root]\n");
- exits("usage");
-}
-
-int
-system(char *cmd)
-{
- int pid;
- if((pid = fork()) < 0)
- return -1;
-
- if(pid == 0) {
- dup(2, 1);
- execl("/bin/rc", "rc", "-c", cmd, nil);
- exits("exec");
- }
- waitpid();
- return 0;
-}
-
-int
-cd(char *s)
-{
- char *newpwd;
- int l;
-
- if(s[0] == '/') {
- cleanname(s);
- newpwd = strdup(s);
- } else {
- l = strlen(pwd)+1+strlen(s)+1+50; /* 50 = crud for unicode mistakes */
- newpwd = malloc(l);
- snprint(newpwd, l, "%s/%s", pwd, s);
- cleanname(newpwd);
- assert(newpwd[0] == '/');
- }
-
- if(chdir(root) < 0 || (newpwd[1] != '\0' && chdir(newpwd+1) < 0)) {
- chdir(root);
- chdir(pwd+1);
- free(newpwd);
- return -1;
- } else {
- free(pwd);
- pwd = newpwd;
- return 0;
- }
-}
-
-void
-main(int argc, char **argv)
-{
- char *p;
- Biobuf bin;
- char *f[2];
- int nf;
-
- ARGBEGIN{
- case 'r':
- root = ARGF();
- if(root == nil)
- usage();
- if(root[0] != '/') {
- fprint(2, "root must be rooted\n");
- exits("root");
- }
- break;
- default:
- usage();
- }ARGEND;
-
- if(argc != 0)
- usage();
-
- cleanname(root);
- if(cd("/") < 0) {
- fprint(2, "cannot cd %s: %r\n", root);
- exits("root");
- }
-
- Binit(&bin, 0, OREAD);
- while(fprint(2, "%s%% ", pwd), (p = Brdline(&bin, '\n'))) {
- p[Blinelen(&bin)-1] = '\0';
- nf = tokenize(p, f, nelem(f));
- if(nf < 1)
- continue;
- if(strcmp(f[0], "exit") == 0)
- break;
- if(strcmp(f[0], "lc") == 0) {
- if(nf == 1) {
- if(system("/bin/lc") < 0)
- fprint(2, "lc: %r\n");
- } else if(nf == 2) {
- if(strpbrk(p, "'`{}^@$#&()|\\;><"))
- fprint(2, "no shell characters allowed\n");
- else {
- p = f[1];
- *--p = ' ';
- *--p = 'c';
- *--p = 'l';
- if(system(p) < 0)
- fprint(2, "lc: %r\n");
- }
- }
- continue;
- }
- if(strcmp(f[0], "cd") == 0) {
- if(nf < 2)
- fprint(2, "usage: cd dir\n");
- else if(cd(f[1]) < 0)
- fprint(2, "cd: %r\n");
- continue;
- }
- fprint(2, "commands are cd, lc, and exit\n");
- }
-
- print("%s\n", pwd);
-}
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-char *argv0;
-
-int
-openlog(char *name)
-{
- int fd;
-
- fd = open(name, OWRITE);
- if(fd < 0){
- fprint(2, "%s: can't open %s: %r\n", argv0, name);
- return -1;
- }
- seek(fd, 0, 2);
- return fd;
-}
-
-void
-main(int argc, char **argv)
-{
- Biobuf in;
- int fd;
- char *p, *t;
- char buf[8192];
-
- argv0 = argv[0];
- if(argc != 4){
- fprint(2, "usage: %s console logfile prefix\n", argv0);
- exits("usage");
- }
-
- fd = open(argv[1], OREAD);
- if(fd < 0){
- fprint(2, "%s: can't open %s: %r\n", argv0, argv[1]);
- exits("open");
- }
- Binit(&in, fd, OREAD);
-
- fd = openlog(argv[2]);
-
- for(;;){
- if(p = Brdline(&in, '\n')){
- p[Blinelen(&in)-1] = 0;
- if(fprint(fd, "%s: %s\n", argv[3], p) < 0){
- close(fd);
- fd = openlog(argv[2]);
- fprint(fd, "%s: %s\n", t, p);
- }
- } else if(Blinelen(&in) == 0) // true eof
- break;
- else {
- Bread(&in, buf, sizeof buf);
- }
- }
- exits(0);
-}
+++ /dev/null
-</$objtype/mkfile
-CPUS=386
-
-TARG=\
- bargraph\
- bflz\
- cdsh\
- tailfsrv\
- touchfs\
- unbflz\
-
-OFILES=
-HFILES=
-
-BIN=/sys/lib/dist/bin/$objtype
-</sys/src/cmd/mkmany
-
-all:V: bzfs!all
-install:V: bzfs!install
-clean:V: bzfs!clean
-
-bzfs!%:V:
- cd bzfs; mk $stem; cd ..
-
+++ /dev/null
-objtype=386
-</$objtype/mkfile
-
-TARG=multi
-
-PIECES=\
- aux/mouse\
- aux/pcmcia\
- aux/vga\
- aux/zerotrunc\
- disk/fdisk\
- disk/format\
- disk/mbr\
- disk/prep\
-# fossil/fossil\
-# fossil/flfmt\
- ip/ipconfig\
- ip/ppp\
- ndb/cs\
- ndb/dns\
-# replica/applylog\
- 9660srv\
-# awk\
- basename\
- cat\
- chgrp\
- chmod\
- cleanname\
- cmp\
- cp\
- date\
- dd\
- dossrv\
- echo\
- ed\
- ext2srv\
-# fcp\
- grep\
- hget\
- hoc\
- ls\
- mc\
- mount\
- mv\
- ps\
- read\
-# rio\
- rm\
- sed\
- sort\
- srv\
-# stats\
- syscall\
- tail\
- tee\
- test\
- wc\
- xd\
-
-8.multi:V: mkmulti mkfile
- mkmulti $PIECES
- ls -l 8.multi
- ls -l /386/bin/$PIECES | awk '{s += $6} END{print s}'
-
-scripts:V:
- rm -rf ../../pc/multi
- mkdir ../../pc/multi
- for(i in $PIECES){
- b=`{basename $i}
- echo '#!/bin/multi' >>../../pc/multi/$b
- chmod +x ../../pc/multi/$b
- }
-
-BIN=/sys/lib/dist/bin/$objtype
-</sys/src/cmd/mkmany
-
+++ /dev/null
-#!/bin/rc
-
-targ=multi
-
-n=0
-dir=`{pwd}
-
-fn grab {
- echo using $*
- for(i){
- n=`{echo 1+$n|hoc}
- mv $i $dir/a.$n.8
- }
-}
-
-fn getfiles {
- sed -n 's/^(pcc|8\^l|8l) +(-o [^ ]* +)?([^\-].*)/ \3/p' | sed 's/ -[^ ]*//g' |
- sed 's/ [^ ]*\.a//g'
-}
-
-rm a.*.8
->multi.h
->multiproto.h
-
-for(i){
-echo $i...
- b=`{basename $i}
- p=$b
- if(~ $b [0-9]*)
- p=_$b
- echo void $p^_main'(int, char**);' >>$dir/multiproto.h
- echo "$b", $p^_main, >>$dir/multi.h
- d=`{basename -d $i}
- if(~ $i disk/prep disk/fdisk){
- cd /sys/src/cmd/disk/prep
- rm 8.$b
- files=`{mk 8.$b | getfiles}
- }
- if not if(test -d /sys/src/cmd/$i && @{cd /sys/src/cmd/$i && mk 8.out}){
- cd /sys/src/cmd/$i
- rm 8.out
- files=`{mk 8.out | getfiles}
- }
- if not if(test -d /sys/src/cmd/$i && @{cd /sys/src/cmd/$i && mk 8.$b}){
- cd /sys/src/cmd/$i
- rm 8.out
- files=`{mk 8.$b | getfiles}
- }
- if not if(test -d /sys/src/cmd/$d && @{cd /sys/src/cmd/$d && mk 8.$b}){
- cd /sys/src/cmd/$d
- rm 8.$b
- files=`{mk 8.$b | getfiles}
- }
- if not{
- echo do not know how to make $i
- exit oops
- }
- aux/8prefix $p^_ $files
- grab $files
- switch(`{pwd}){
- case /sys/src/cmd /sys/src/cmd/aux /sys/src/cmd/ip
- rm 8.$b
- case *
- mk clean
- }
-}
-cd $dir
-8c -FVw multi.c
-8l -o 8.$targ multi.8 a.*.8
-# rm a.*.8
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-
-#include "multiproto.h"
-struct {
- char *name;
- void (*fn)(int, char**);
-} mains[] =
-{
-#include "multi.h"
-};
-
-void
-main(int argc, char **argv)
-{
- int i;
- char *cmd, *p;
-
- if(argc == 1){
- fprint(2, "usage: multi cmd args...\n");
- exits("usage");
- }
-
- cmd = argv[1];
- if(p = strrchr(cmd, '/'))
- cmd = p+1;
- argv++;
- argc--;
-
- for(i=0; i<nelem(mains); i++){
- if(strcmp(cmd, mains[i].name) == 0){
- mains[i].fn(argc, argv);
- return;
- }
- }
- fprint(2, "multi: no such cmd %s\n", cmd);
- exits("no cmd");
-}
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-
-void
-main(void)
-{
- int fd, p[2];
- char buf[8192], n;
-
- pipe(p);
- fd = create("/srv/log", OWRITE, 0666);
- fprint(fd, "%d", p[0]);
- close(fd);
- close(p[0]);
- while((n = read(p[1], buf, sizeof buf)) >= 0)
- write(1, buf, n);
-}
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-void
-Bpass(Biobuf *bin, Biobuf *bout, int n)
-{
- char buf[8192];
- int m;
-
- while(n > 0) {
- m = sizeof buf;
- if(m > n)
- m = n;
- m = Bread(bin, buf, m);
- if(m <= 0) {
- fprint(2, "corrupt archive\n");
- exits("notdone");
- }
- Bwrite(bout, buf, m);
- n -= m;
- }
- assert(n == 0);
-}
-
-void
-main(int argc, char **argv)
-{
- char *p, *f[10];
- Biobuf bin, bout;
- int nf;
- ulong d, size;
-
- if(argc != 2) {
- fprint(2, "usage: cat mkfs-archive | touchfs date (in seconds)\n");
- exits("usage");
- }
-
- d = strtoul(argv[1], 0, 0);
-
- quotefmtinstall();
- Binit(&bin, 0, OREAD);
- Binit(&bout, 1, OWRITE);
-
- while(p = Brdline(&bin, '\n')) {
- p[Blinelen(&bin)-1] = '\0';
- if(strcmp(p, "end of archive") == 0) {
- Bprint(&bout, "end of archive\n");
- exits(0);
- }
-
- nf = tokenize(p, f, nelem(f));
- if(nf != 6) {
- fprint(2, "corrupt archive\n");
- exits("notdone");
- }
-
- Bprint(&bout, "%q %q %q %q %lud %q\n",
- f[0], f[1], f[2], f[3], d, f[5]);
-
- size = strtoul(f[5], 0, 0);
- Bpass(&bin, &bout, size);
- }
- fprint(2, "premature end of archive\n");
- exits("notdone");
-}
+++ /dev/null
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-void
-usage(void)
-{
- fprint(2, "usage: unbflz [file]\n");
- exits("usage");
-}
-
-int
-Bgetint(Biobuf *b)
-{
- uchar p[4];
-
- if(Bread(b, p, 4) != 4)
- sysfatal("short read");
- return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
-}
-
-/*
- * memmove but make sure overlap works properly.
- */
-void
-copy(uchar *dst, uchar *src, int n)
-{
- while(n-- > 0)
- *dst++ = *src++;
-}
-
-void
-main(int argc, char **argv)
-{
- Biobuf *b, bin;
- char buf[5];
- uchar *data;
- ulong *blk, l;
- int nblk, mblk;
- int sum;
- int i, j, length, m, n, o;
-
- ARGBEGIN{
- default:
- usage();
- }ARGEND
-
- switch(argc){
- default:
- usage();
- case 0:
- Binit(&bin, 0, OREAD);
- b = &bin;
- break;
- case 1:
- if((b = Bopen(argv[0], OREAD)) == nil)
- sysfatal("open %s: %r", argv[0]);
- break;
- }
-
- if(Bread(b, buf, 4) != 4)
- sysfatal("short read");
-
- if(memcmp(buf, "BLZ\n", 4) != 0)
- sysfatal("bad header");
-
- length = Bgetint(b);
- data = malloc(length);
- if(data == nil)
- sysfatal("out of memory");
- sum = 0;
- nblk = 0;
- mblk = 0;
- blk = nil;
- while(sum < length){
- if(nblk>=mblk){
- mblk += 16384;
- blk = realloc(blk, (mblk+1)*sizeof(blk[0]));
- if(blk == nil)
- sysfatal("out of memory");
- }
- l = Bgetint(b);
- blk[nblk++] = l;
- if(l&(1<<31))
- l &= ~(1<<31);
- else
- blk[nblk++] = Bgetint(b);
- sum += l;
- }
- if(sum != length)
- sysfatal("bad compressed data %d %d", sum, length);
- i = 0;
- j = 0;
- while(i < length){
- assert(j < nblk);
- n = blk[j++];
- if(n&(1<<31)){
- n &= ~(1<<31);
- if((m=Bread(b, data+i, n)) != n)
- sysfatal("short read %d %d", n, m);
- }else{
- o = blk[j++];
- copy(data+i, data+o, n);
- }
- i += n;
- }
- write(1, data, length);
- exits(nil);
-}
+++ /dev/null
-{
- verb[$4] = $3
- data[$4] = sprintf("%s %s %s %s %s %s", $5, $6, $7, $8, $9, $10)
-}
-
-END{
- for(i in verb)
- if(verb[i] != "d")
- printf("a %s %s\n", i, data[i]) |"sort +1"
- close("sort +1")
- for(i in verb)
- if(verb[i] == "d")
- printf("d %s %s\n", i, data[i]) |"sort -r +1"
- close("sort -r +1")
-}
+++ /dev/null
-{
- printf("%s %d %s\n", t, NR, $0);
-}
-# /sys/lib/dist/mkfile
-src9=/n/sources/plan9 # what to export
-dist=/sys/lib/dist # where this machinery lives
-scr=/n/other/dist # scratch space before copying to web.protect
-# import /sys/lib/dist/web.protect from the outside
-x=`{setup}
+src9=/n/src9
+scr=/tmp/dist
-cd:V: $scr/plan9.iso
-
-ncd:V: $scr/plan9-new.iso.bz2
-
-ncd-dist:V: $scr/plan9-new.iso.bz2
- mk $dist/web.protect/plan9-new.iso.bz2
-
-cd-dist:V: $scr/plan9.iso.bz2
- mk $dist/web.protect/plan9.iso.bz2
-
-contrib-cd:V: $scr/contrib.iso.bz2
- mk $dist/web.protect/contrib.iso.bz2
-
-$scr/%.iso:D: $src9/dist/replica/plan9.log
- @ { cd pc; mk cddisk }
- rm -f $target
- bind pc/cddisk cdstub/bootdisk.img
- if(! test -f $src9/bootdisk.img)
- bind -a cdstub $src9
- title=`{date | sed 's/(...) (...) (..) (..:..):.. (...) (....)/Plan 9 - \2 \3 \6 \4/'}
- title=$"title
- echo 'CD:' $title
- disk/mk9660 -9cj -v $title -s $src9 -b bootdisk.img $target
-
-# copy compressed file from scratch space to the distribution, carefully
-$dist/web.protect/%.iso.bz2: $scr/%.iso.bz2
- >>$target.new
- chmod +t $target.new # waste write buf, not venti store
- cp $prereq $target.new
- # replace previous version with a flash cut
- if (test -e $target)
- mv $target $target.old # try to not clobber downloads in progress
- mv $target.new $target
-
-cd-cleanup:V:
- rm -f $dist/web.protect/*.iso.bz2.old # remove old versions after a delay
-
-# generate replica log & db for $src9 only
-scan:V:
- test -d $scr # make sure other was mounted above
- test -d $src9
- test -d $dist/web.protect
- lock scan.lock replica/scan $dist/sources.replica
- chmod +t $src9/dist/replica/*.^(db log)
-
-# generate replica log & db for all of /n/sources
-scanall:V:
- @ {
- rfork ne
- d=/n/sources
- test -d $src9
- lock scanall.lock replica/scan $dist/sourcesall.replica
- chmod +t $src9/dist/replica/*.^(db log)
- }
-
-compresslog:V:
- {
- awk -f logcompress.awk $src9/dist/replica/plan9.log |
- awk -f logtime.awk -v 't='^`{date -n} >/tmp/plan9.log
- rm -f $src9/dist/replica/plan9.new.log
- cp /tmp/plan9.log $src9/dist/replica/plan9.new.log &&
- mv $src9/dist/replica/plan9.new.log $src9/dist/replica/plan9.log
- } <scan.lock
-
-#restart:V:
-# rm -f $src9/dist/replica/plan9.db
-# rm -f $src9/dist/replica/plan9.log
-# chmod 664 $src9/dist/replica/plan9.db >$src9/dist/replica/plan9.db
-# chmod 664 $src9/dist/replica/plan9.log >$src9/dist/replica/plan9.log
-# chmod +a $src9/dist/replica/plan9.log
-# mk scan
-
-odump:V:
- disk/dump9660 -9cj -v 'Plan 9 4e Dumps' -s $src9 \
- -p /sys/lib/sysconfig/proto/allproto $scr/distdump.iso
-
-cd.install:V:
-# if(~ $sysname achille){
-# echo; echo; echo '*** run this on a real machine, like chips.'
-# exit bad
-# }
- bzip2 -9 <$scr/plan9.iso >web.protect/nplan9.iso.bz2
+x=`{mkdir -p $scr}
-D.install:V:
- D=/n/roro/usr/rob/testplan9
- 9fs roro
- test -d $D
- cp $D$dist/pc/ndisk $dist/web.protect/ndisk
- cp $D$dist/pc/9loaddebug $dist/web.protect/n9loaddebug
-
-reallyinstall:V:
- if(! ~ $sysname achille){
- echo; echo; echo '*** this needs to run on achille.'
- exit bad
- }
- cd web.protect
- for (i in plan9.iso.bz2 disk 9loaddebug vmware.zip)
- if(test -f n$i){
- mv $i _$i && { mv n$i $i || mv _$i $i }
- }
- rm /srv/ramfs.9down4e
- $dist/startcache
-
-dump:V:
- rm -f /srv/9660.xxx
- 9660srv 9660.xxx
- mount /srv/9660.xxx /n/kremvax $scr/plan9.iso
- now=`{mtime $dist/web.protect/plan9.iso.bz2 | awk '{print $1}'}
- ls -l /rls/plan9/4e.iso
- disk/dump9660 -9cj -s /n/kremvax -n $now /rls/plan9/4e.iso
- ls -l /rls/plan9/4e.iso
- rm /srv/9660.xxx
-
-reencode:V:
- rm -f $scr/nplan9.iso
- rm -f /srv/9660.xxx
- 9660srv 9660.xxx
- mount /srv/9660.xxx /n/kremvax $scr/plan9.iso
- disk/mk9660 -9cj -v 'Plan 9 4th Edition' -s /n/kremvax \
- -b bootdisk.img $scr/nplan9.iso
- rm /srv/9660.xxx
-
-# compress a cd image in scratch space
-$scr/%.iso.bz2:D: $scr/%.iso
- @ {
- cd $scr
- bzip2 -9 <$stem.iso >n$stem.iso.bz2 &&
- {
- if (test -e $stem.iso.bz2)
- mv $stem.iso.bz2 _$stem.iso.bz2
- mv n$stem.iso.bz2 $stem.iso.bz2
- }
- echo `{date} md5 `{md5sum <$stem.iso.bz2} \
- sha1 `{sha1sum <$stem.iso.bz2} \
- $stem.iso.bz2 >>/usr/web/plan9checksums.txt
- }
-
-$scr/contrib.iso:DV:
- rm -f $target
- disk/mk9660 -9cj -v 'Plan 9 Extras' -s /n/sources \
- -p ./contrib.proto $target
-
-rebuild:V:
- chmod +l build.lock >>build.lock
- rebuild <build.lock
-
-rebuild-mail:V:
- chmod +l build.lock >>build.lock
- rebuild <build.lock
- datemail 'nightly build errors' 9trouble <buildit.out
- datemail 'nightly build differences' 9trouble <checkbuild.out
- status=''
-
-scansources-mail:V:
- scansources | datemail 'nightly fs vs. sources scan' 9trouble
-
-worldwritable-mail:V:
- test -e $src9
- @ {cd /n/sources; /usr/rsc/bin/$cputype/lsr -t -d} |
- awk '$2 ~ /[2367]$/' | grep -vf ok-writable |
- datemail 'WRITABLE FILES ON SOURCES' 9trouble || status=''
- status=''
- @ {
- cd $src9
- /usr/rsc/bin/$cputype/lsr -t -d $src9
- } |
- awk '$2 ~ /[2367][^2367].$/' |
- datemail 'non-group-writable files on sources' 9trouble
- status=''
- # use /n/boot to avoid walking the archives mounted under
- # /lib/vac, or other mounts or binds.
- rfork n
- 9fs boot
- test -e /n/boot/sys
- /usr/rsc/bin/$cputype/lsr -t -d /n/boot/sys /n/boot/lib |
- grep -v '/lib/audio/|/sys/src/cmd/vac/test/' | # give us a break
- awk '$2 ~ /[2367][^2367].$/' |
- datemail 'non-group-writable files on fs' 9trouble
- status=''
-
-9.tar.gz:V:
- @{
- rfork n
- 9fs sources
- test -e $src9
- bind -a $src9 $src9/sys/src
- cd $src9/sys/src
- tar c LICENSE NOTICE 9
- } | gzip >$target
-
-9-export:V: 9.tar.gz
- 9fs sources
- cp 9.tar.gz /n/sources/extra/9.tgz
- chmod +t /n/sources/extra/9.tgz
-
-plan9.tar.bz2:V:
- @{
- rfork n
- 9fs sources
- cd /n/sources
- test -e $src9
- bind /n/empty $src9/lib/font
- bind /n/empty $src9/sys/lib/postscript/font
- bind /n/empty $src9/sys/lib/ghostscript
- bind /n/empty $src9/sys/src/cmd/gs
- tar c plan9/LICENSE* plan9/NOTICE plan9/*/mkfile plan9/*/include \
- plan9/acme/*/src plan9/acme/bin/source \
- plan9/^(adm cron lib lp mail rc sys tmp usr)
- } | bzip2 >$target
-
-plan9-export:V: plan9.tar.bz2
- 9fs sources
- chmod +t plan9.tar.bz2
- mv plan9.tar.bz2 /n/sources/extra/plan9.tar.bz2
+cd:V: $scr/plan9.iso
+
+clean:V:
+ rm -rf $scr
+
+$scr/cdstub:D: $src9/386/9bootiso
+ mkdir -p $target
+ cp $prereq $target
+ cp pc/plan9.ini.cd $target/plan9.ini
+
+$scr/plan9.iso: $scr/cdstub
+ bind -a $src9 $scr/cdstub
+ bind /n/empty $scr/cdstub/.hg
+ disk/mk9660 -9cj -s $scr/cdstub -B 9bootiso $target
+ unmount $scr/cdstub/.hg
+ unmount $scr/cdstub
-# config for initial floppy booting
-
-[menu]
-menuitem=boot, Boot Plan 9
-# menuitem=debug, Boot Plan 9 and debug 9load
-menudefault=boot, 10
-
-[common]
# very cautious settings to get started.
# will defeat booting from usb devices.
*nomp=1
-*nobiosload=1
# *noahciload=1
# *debugload=1
*nodumpstack=1
monitor=ask
vgasize=ask
dmamode=ask
-nobootprompt=local!/boot/bzroot
-installurl=http://plan9.bell-labs.com/plan9/download/plan9.iso.bz2
# serial console on COM1
#console=0
-
-[boot]
bootargs=local!#S/sdD0/data
-bootfile=sdD0!cdboot!9pccd.gz
-
-# [debug]
-# bootargs=local!#S/sdD0/data
-# bootfile=sdD0!cdboot!9pccd.gz
-# *debugload=1
+bootfile=/386/9pccd
# config for initial cd booting
-
-[menu]
-menuitem=install, Install Plan 9 from this CD
-menuitem=cdboot, Boot Plan 9 from this CD
-# menuitem=debug, Boot Plan 9 from this CD and debug 9load
-
-[common]
# very cautious settings to get started.
# will defeat booting from usb devices.
*nomp=1
-*nobiosload=1
# *noahciload=1
# *debugload=1
*nodumpstack=1
monitor=ask
vgasize=ask
dmamode=ask
-adisk=/dev/sdD0/cdboot
+adisk=/dev/sdD0/data
cdboot=yes
# console=0
# baud=9600
-
-[install]
-nobootprompt=local!/boot/bzroot
-bootfile=sdD0!cdboot!9pcflop.gz
-
-[cdboot]
bootargs=local!#S/sdD0/data
-bootfile=sdD0!cdboot!9pccd.gz
-
-# [debug]
-# bootargs=local!#S/sdD0/data
-# bootfile=sdD0!cdboot!9pccd.gz
-# *debugload=1
+bootfile=/386/9pccd
+++ /dev/null
-#!/bin/rc
-# setup - prep for the mkfile
-9fs sources
-9fs other
-9fs outfsother
-if (test -e /cfg/$sysname/config)
- . /cfg/$sysname/config
-if not
- outip=204.178.31.2
-import -c tcp!$outip!666 $dist/web.protect
static int
isowalk(Extend *ex, int drive, char *path)
{
- char name[Maxpath], pad, *end;
+ char name[Maxpath], c, *end;
int i;
Dir d;
break;
i = d.dirlen - (Dirsz + d.namelen);
while(i-- > 0)
- read(ex, &pad, 1);
- name[d.namelen] = 0;
+ read(ex, &c, 1);
+ for(i=0; i<d.namelen; i++){
+ c = name[i];
+ if(c >= 'A' && c <= 'Z'){
+ c -= 'A';
+ c += 'a';
+ }
+ name[i] = c;
+ }
+ name[i] = 0;
while(*path == '/')
path++;
if((end = strchr(path, '/')) == 0)
flashfs\
gps\
na\
- vga
+ vga\
+ realemu
all:V: $DIRS
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+#define ause(cpu) (cpu->abuf + (cpu->iabuf++ % nelem(cpu->abuf)))
+
+Iarg*
+adup(Iarg *x)
+{
+ Iarg *a;
+
+ a = ause(x->cpu);
+ *a = *x;
+ return a;
+}
+
+Iarg*
+areg(Cpu *cpu, uchar len, uchar reg)
+{
+ Iarg *a;
+
+ a = ause(cpu);
+ a->cpu = cpu;
+ a->tag = TREG;
+ a->len = len;
+ a->reg = reg;
+ return a;
+}
+
+Iarg*
+amem(Cpu *cpu, uchar len, uchar sreg, ulong off)
+{
+ Iarg *a;
+
+ a = ause(cpu);
+ a->cpu = cpu;
+ a->tag = TMEM;
+ a->len = len;
+ a->sreg = sreg;
+ a->seg = cpu->reg[sreg];
+ a->off = off;
+ return a;
+}
+
+Iarg*
+afar(Iarg *mem, uchar len, uchar alen)
+{
+ Iarg *a, *p;
+
+ p = adup(mem);
+ p->len = alen;
+ a = amem(mem->cpu, len, R0S, ar(p));
+ p->off += alen;
+ p->len = 2;
+ a->seg = ar(p);
+ return a;
+}
+
+Iarg*
+acon(Cpu *cpu, uchar len, ulong val)
+{
+ Iarg *a;
+
+ a = ause(cpu);
+ a->cpu = cpu;
+ a->tag = TCON;
+ a->len = len;
+ a->val = val;
+ return a;
+}
+
+ulong
+ar(Iarg *a)
+{
+ ulong w, o;
+ Bus *io;
+
+ switch(a->tag){
+ default:
+ abort();
+ case TMEM:
+ o = ((a->seg<<4) + (a->off & 0xFFFF)) & 0xFFFFF;
+ io = a->cpu->mem + (o>>16);
+ w = io->r(io->aux, o, a->len);
+ break;
+ case TREG:
+ w = a->cpu->reg[a->reg];
+ break;
+ case TREG|TH:
+ w = a->cpu->reg[a->reg] >> 8;
+ break;
+ case TCON:
+ w = a->val;
+ break;
+ }
+ switch(a->len){
+ default:
+ abort();
+ case 1:
+ w &= 0xFF;
+ break;
+ case 2:
+ w &= 0xFFFF;
+ break;
+ case 4:
+ break;
+ }
+ return w;
+}
+
+long
+ars(Iarg *a)
+{
+ ulong w = ar(a);
+ switch(a->len){
+ default:
+ abort();
+ case 1:
+ return (char)w;
+ case 2:
+ return (short)w;
+ case 4:
+ return (long)w;
+ }
+}
+
+void
+aw(Iarg *a, ulong w)
+{
+ ulong *p, o;
+ Cpu *cpu;
+ Bus *io;
+
+ cpu = a->cpu;
+ switch(a->tag){
+ default:
+ abort();
+ case TMEM:
+ o = ((a->seg<<4) + (a->off & 0xFFFF)) & 0xFFFFF;
+ io = cpu->mem + (o>>16);
+ io->w(io->aux, o, w, a->len);
+ break;
+ case TREG:
+ p = cpu->reg + a->reg;
+ switch(a->len){
+ case 4:
+ *p = w;
+ break;
+ case 2:
+ *p = (*p & ~0xFFFF) | (w & 0xFFFF);
+ break;
+ case 1:
+ *p = (*p & ~0xFF) | (w & 0xFF);
+ break;
+ }
+ break;
+ case TREG|TH:
+ p = cpu->reg + a->reg;
+ *p = (*p & ~0xFF00) | (w & 0xFF)<<8;
+ break;
+ }
+}
--- /dev/null
+typedef struct Iarg Iarg;
+typedef struct Inst Inst;
+typedef struct Bus Bus;
+typedef struct Cpu Cpu;
+typedef struct Pit Pit;
+
+enum {
+ RAX,
+ RCX,
+ RDX,
+ RBX,
+ RSP,
+ RBP,
+ RSI,
+ RDI,
+
+ RES,
+ RCS,
+ RSS,
+ RDS,
+ RFS,
+ RGS,
+
+ R0S, /* 0 segment */
+
+ RIP,
+ RFL,
+
+ NREG,
+};
+
+struct Iarg
+{
+ Cpu *cpu;
+
+ uchar tag;
+ uchar len;
+ uchar atype;
+
+ union {
+ uchar reg;
+ struct {
+ uchar sreg;
+ ulong seg, off;
+ };
+ ulong val;
+ };
+};
+
+struct Inst
+{
+ uchar op;
+ uchar code;
+ uchar olen;
+ uchar alen;
+
+ Iarg *a1, *a2, *a3;
+
+ uchar rep;
+
+ uchar mod;
+ uchar reg;
+ uchar rm;
+
+ uchar scale;
+ uchar index;
+ uchar base;
+
+ uchar sreg;
+ uchar dsreg;
+
+ ulong off;
+ long disp;
+};
+
+struct Bus
+{
+ void *aux;
+ ulong (*r)(void *aux, ulong off, int len);
+ void (*w)(void *aux, ulong off, ulong data, int len);
+};
+
+struct Cpu
+{
+ ulong reg[NREG];
+
+ /* instruction counter */
+ ulong ic;
+
+ /* mem[16], one entry for each 64k block */
+ Bus *mem;
+
+ /* port[1], in/out */
+ Bus *port;
+
+ int trap;
+ ulong oldip;
+ jmp_buf jmp;
+
+ /* default operand, address and stack pointer length */
+ uchar olen, alen, slen;
+
+ /* argument buffers */
+ ulong iabuf;
+ Iarg abuf[0x80];
+};
+
+struct Pit
+{
+ ulong count;
+
+ /* set by setgate(), cleared by clockpit() */
+ uchar gateraised;
+
+ /* signals */
+ uchar gate;
+ uchar out;
+
+ /* mode and flags */
+ uchar count0;
+
+ uchar bcd;
+ uchar amode;
+ uchar omode;
+
+ /* latch for wpit initial count */
+ uchar wcount;
+ uchar wlatched;
+ uchar wlatch[2];
+
+ /* latch for rpit status/count */
+ uchar rcount;
+ uchar rlatched;
+ uchar rlatch[2];
+};
+
+/* processor flags */
+enum {
+ CF = 1<<0, /* carry flag */
+ PF = 1<<2, /* parity flag */
+ AF = 1<<4, /* aux carry flag */
+ ZF = 1<<6, /* zero flag */
+ SF = 1<<7, /* sign flag */
+ TF = 1<<8, /* trap flag */
+ IF = 1<<9, /* interrupts enabled flag */
+ DF = 1<<10, /* direction flag */
+ OF = 1<<11, /* overflow flag */
+ IOPL= 3<<12, /* I/O privelege level */
+ NT = 1<<14, /* nested task */
+ RF = 1<<16, /* resume flag */
+ VM = 1<<17, /* virtual-8086 mode */
+ AC = 1<<18, /* alignment check */
+ VIF = 1<<19, /* virtual interrupt flag */
+ VIP = 1<<20, /* virtual interrupt pending */
+ ID = 1<<21, /* ID flag */
+};
+
+/* interrupts/traps */
+enum {
+ EDIV0,
+ EDEBUG,
+ ENMI,
+ EBRK,
+ EINTO,
+ EBOUND,
+ EBADOP,
+ ENOFPU,
+ EDBLF,
+ EFPUSEG,
+ EBADTSS,
+ ENP,
+ ESTACK,
+ EGPF,
+ EPF,
+
+ EHALT = 256, /* pseudo-interrupts */
+ EMEM,
+ EIO,
+};
+
+/* argument tags */
+enum {
+ TREG,
+ TMEM,
+ TCON,
+
+ TH = 0x80, /* special flag for AH,BH,CH,DH */
+};
+
+/* argument types */
+enum {
+ ANONE, /* no argument */
+ A0, /* constant 0 */
+ A1, /* constant 1 */
+ A2, /* constant 2 */
+ A3, /* constant 3 */
+ A4, /* constant 4 */
+ AAp, /* 32-bit or 48-bit direct address */
+ AEb, /* r/m8 from modrm byte */
+ AEv, /* r/m16 or r/m32 from modrm byte */
+ AEw, /* r/m16 */
+ AFv, /* flag word */
+ AGb, /* r8 from modrm byte */
+ AGv, /* r16 or r32 from modrm byte */
+ AGw, /* r/m16 */
+ AIb, /* immediate byte */
+ AIc, /* immediate byte sign-extended */
+ AIw, /* immediate 16-bit word */
+ AIv, /* immediate 16-bit or 32-bit word */
+ AJb, /* relative offset byte */
+ AJv, /* relative offset 16-bit or 32-bit word */
+ AJr, /* r/m16 or r/m32 register */
+ AM, /* memory address from modrm */
+ AMa, /* something for bound */
+ AMa2,
+ AMp, /* 32-bit or 48-bit memory address */
+ AOb, /* immediate word-sized offset to a byte */
+ AOv, /* immediate word-size offset to a word */
+ ASw, /* segment register selected by r field of modrm */
+ AXb, /* byte at DS:SI */
+ AXv, /* word at DS:SI */
+ AYb, /* byte at ES:DI */
+ AYv, /* word at ES:DI */
+
+ AAL,
+ ACL,
+ ADL,
+ ABL,
+ AAH,
+ ACH,
+ ADH,
+ ABH,
+
+ AAX,
+ ACX,
+ ADX,
+ ABX,
+ ASP,
+ ABP,
+ ASI,
+ ADI,
+
+ AES,
+ ACS,
+ ASS,
+ ADS,
+ AFS,
+ AGS,
+
+ NATYPE,
+};
+
+/* operators */
+enum {
+ OBAD,
+ O0F,
+ OAAA,
+ OAAD,
+ OAAM,
+ OAAS,
+ OADC,
+ OADD,
+ OAND,
+ OARPL,
+ OASIZE,
+ OBOUND,
+ OBT,
+ OBTS,
+ OBTR,
+ OBTC,
+ OBSF,
+ OBSR,
+ OCALL,
+ OCBW,
+ OCLC,
+ OCLD,
+ OCLI,
+ OCMC,
+ OCMOV,
+ OCMP,
+ OCMPS,
+ OCPUID,
+ OCWD,
+ ODAA,
+ ODAS,
+ ODEC,
+ ODIV,
+ OENTER,
+ OGP1,
+ OGP2,
+ OGP3b,
+ OGP3v,
+ OGP4,
+ OGP5,
+ OGP10,
+ OGP12,
+ OHLT,
+ OIDIV,
+ OIMUL,
+ OIN,
+ OINC,
+ OINS,
+ OINT,
+ OIRET,
+ OJUMP,
+ OLAHF,
+ OLEA,
+ OLEAVE,
+ OLFP,
+ OLOCK,
+ OLODS,
+ OLOOP,
+ OLOOPNZ,
+ OLOOPZ,
+ OMOV,
+ OMOVS,
+ OMOVZX,
+ OMOVSX,
+ OMUL,
+ ONEG,
+ ONOP,
+ ONOT,
+ OOR,
+ OOSIZE,
+ OOUT,
+ OOUTS,
+ OPOP,
+ OPOPA,
+ OPOPF,
+ OPUSH,
+ OPUSHA,
+ OPUSHF,
+ ORCL,
+ ORCR,
+ OREPE,
+ OREPNE,
+ ORET,
+ ORETF,
+ OROL,
+ OROR,
+ OSAHF,
+ OSAR,
+ OSBB,
+ OSCAS,
+ OSEG,
+ OSET,
+ OSHL,
+ OSHLD,
+ OSHR,
+ OSHRD,
+ OSTC,
+ OSTD,
+ OSTI,
+ OSTOS,
+ OSUB,
+ OTEST,
+ OWAIT,
+ OXCHG,
+ OXLAT,
+ OXOR,
+ NUMOP,
+};
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct Optab Optab;
+struct Optab {
+ uchar op;
+ uchar a1, a2, a3;
+};
+
+static Optab optab[256] = {
+//00
+ {OADD, AEb, AGb}, {OADD, AEv, AGv}, {OADD, AGb, AEb}, {OADD, AGv, AEv},
+ {OADD, AAL, AIb}, {OADD, AAX, AIv}, {OPUSH, AES, }, {OPOP, AES },
+ {OOR, AEb, AGb}, {OOR, AEv, AGv}, {OOR, AGb, AEb}, {OOR, AGv, AEv},
+ {OOR, AAL, AIb}, {OOR, AAX, AIv}, {OPUSH, ACS, }, {O0F, },
+//10
+ {OADC, AEb, AGb}, {OADC, AEv, AGv}, {OADC, AGb, AEb}, {OADC, AGv, AEv},
+ {OADC, AAL, AIb}, {OADC, AAX, AIv}, {OPUSH, ASS, }, {OPOP, ASS, },
+ {OSBB, AEb, AGb}, {OSBB, AEv, AGv}, {OSBB, AGb, AEb}, {OSBB, AGv, AEv},
+ {OSBB, AAL, AIb}, {OSBB, AAX, AIv}, {OPUSH, ADS, }, {OPOP, ADS, },
+//20
+ {OAND, AEb, AGb}, {OAND, AEv, AGv}, {OAND, AGb, AEb}, {OAND, AGv, AEv},
+ {OAND, AAL, AIb}, {OAND, AAX, AIv}, {OSEG, AES, }, {ODAA, },
+ {OSUB, AEb, AGb}, {OSUB, AEv, AGv}, {OSUB, AGb, AEb}, {OSUB, AGv, AEv},
+ {OSUB, AAL, AIb}, {OSUB, AAX, AIv}, {OSEG, ACS, }, {ODAS, },
+//30
+ {OXOR, AEb, AGb}, {OXOR, AEv, AGv}, {OXOR, AGb, AEb}, {OXOR, AGv, AEv},
+ {OXOR, AAL, AIb}, {OXOR, AAX, AIv}, {OSEG, ASS, }, {OAAA, },
+ {OCMP, AEb, AGb}, {OCMP, AEv, AGv}, {OCMP, AGb, AEb}, {OCMP, AGv, AEv},
+ {OCMP, AAL, AIb}, {OCMP, AAX, AIv}, {OSEG, ADS, }, {OAAS, },
+//40
+ {OINC, AAX, }, {OINC, ACX, }, {OINC, ADX, }, {OINC, ABX, },
+ {OINC, ASP, }, {OINC, ABP, }, {OINC, ASI, }, {OINC, ADI, },
+ {ODEC, AAX, }, {ODEC, ACX, }, {ODEC, ADX, }, {ODEC, ABX, },
+ {ODEC, ASP, }, {ODEC, ABP, }, {ODEC, ASI, }, {ODEC, ADI, },
+//50
+ {OPUSH, AAX, }, {OPUSH, ACX, }, {OPUSH, ADX, }, {OPUSH, ABX, },
+ {OPUSH, ASP, }, {OPUSH, ABP, }, {OPUSH, ASI, }, {OPUSH, ADI, },
+ {OPOP, AAX, }, {OPOP, ACX, }, {OPOP, ADX, }, {OPOP, ABX, },
+ {OPOP, ASP, }, {OPOP, ABP, }, {OPOP, ASI, }, {OPOP, ADI, },
+//60
+ {OPUSHA, }, {OPOPA, }, {OBOUND,AGv,AMa,AMa2}, {OARPL, AEw, AGw},
+ {OSEG, AFS, }, {OSEG, AGS, }, {OOSIZE, }, {OASIZE, },
+ {OPUSH, AIv, }, {OIMUL,AGv,AEv,AIv},{OPUSH, AIb, }, {OIMUL,AGv,AEv,AIb},
+ {OINS, AYb, ADX}, {OINS, AYv, ADX}, {OOUTS, ADX, AXb}, {OOUTS, ADX, AXv},
+//70
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+ {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, },
+//80
+ {OGP1, AEb, AIb}, {OGP1, AEv, AIv}, {OGP1, AEb, AIb}, {OGP1, AEv, AIc},
+ {OTEST, AEb, AGb}, {OTEST, AEv, AGv}, {OXCHG, AEb, AGb}, {OXCHG, AEv, AGv},
+ {OMOV, AEb, AGb}, {OMOV, AEv, AGv}, {OMOV, AGb, AEb}, {OMOV, AGv, AEv},
+ {OMOV, AEw, ASw}, {OLEA, AGv, AM }, {OMOV, ASw, AEw}, {OGP10, },
+//90
+ {ONOP, }, {OXCHG, ACX, AAX}, {OXCHG, ADX, AAX}, {OXCHG, ABX, AAX},
+ {OXCHG, ASP, AAX}, {OXCHG, ABP, AAX}, {OXCHG, ASI, AAX}, {OXCHG, ADI, AAX},
+ {OCBW, }, {OCWD, }, {OCALL, AAp, }, {OWAIT, },
+ {OPUSHF,AFv, }, {OPOPF, AFv, }, {OSAHF, AAH, }, {OLAHF, AAH, },
+//A0
+ {OMOV, AAL, AOb}, {OMOV, AAX, AOv}, {OMOV, AOb, AAL}, {OMOV, AOv, AAX},
+ {OMOVS, AYb, AXb}, {OMOVS, AYv, AXv}, {OCMPS, AYb, AXb}, {OCMPS, AYv, AXv},
+ {OTEST, AAL, AIb}, {OTEST, AAX, AIv}, {OSTOS, AYb, AAL}, {OSTOS, AYv, AAX},
+ {OLODS, AAL, AXb}, {OLODS, AAX, AXv}, {OSCAS, AYb, AAL}, {OSCAS, AYv, AAX},
+//B0
+ {OMOV, AAL, AIb}, {OMOV, ACL, AIb}, {OMOV, ADL, AIb}, {OMOV, ABL, AIb},
+ {OMOV, AAH, AIb}, {OMOV, ACH, AIb}, {OMOV, ADH, AIb}, {OMOV, ABH, AIb},
+ {OMOV, AAX, AIv}, {OMOV, ACX, AIv}, {OMOV, ADX, AIv}, {OMOV, ABX, AIv},
+ {OMOV, ASP, AIv}, {OMOV, ABP, AIv}, {OMOV, ASI, AIv}, {OMOV, ADI, AIv},
+//C0
+ {OGP2, AEb, AIb}, {OGP2, AEv, AIb}, {ORET, AIw, }, {ORET, A0, },
+ {OLFP,AES,AGv,AMp},{OLFP,ADS,AGv,AMp},{OGP12, AEb, AIb}, {OGP12, AEv, AIv},
+ {OENTER,AIw, AIb}, {OLEAVE, }, {ORETF, AIw, }, {ORETF, A0, },
+ {OINT, A3, }, {OINT, AIb, }, {OINT, A4, }, {OIRET, },
+//D0
+ {OGP2, AEb, A1 }, {OGP2, AEv, A1 }, {OGP2, AEb, ACL}, {OGP2, AEv, ACL},
+ {OAAM, AIb, }, {OAAD, AIb, }, {OBAD, }, {OXLAT, AAL, ABX},
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//E0
+ {OLOOPNZ,AJb, }, {OLOOPZ,AJb, }, {OLOOP, AJb, }, {OJUMP, AJb, },
+ {OIN, AAL, AIb}, {OIN, AAX, AIb}, {OOUT, AIb, AAL}, {OOUT, AIb, AAX},
+ {OCALL, AJv, }, {OJUMP, AJv, }, {OJUMP, AAp, }, {OJUMP, AJb, },
+ {OIN, AAL, ADX}, {OIN, AAX, ADX}, {OOUT, ADX, AAL}, {OOUT, ADX, AAX},
+//F0
+ {OLOCK, }, {OBAD, }, {OREPNE, }, {OREPE, },
+ {OHLT, }, {OCMC, }, {OGP3b, }, {OGP3v, },
+ {OCLC, }, {OSTC, }, {OCLI, }, {OSTI, },
+ {OCLD, }, {OSTD, }, {OGP4, }, {OGP5, },
+};
+
+static Optab optab0F[256] = {
+//00
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//10 - mostly floating point and quadword moves
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//20 - doubleword <-> control register moves, other arcana
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//30 - wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//40 - conditional moves
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+ {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv},
+//50 - floating point, mmx stuff
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//60 - floating point, mmx stuff
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//70 - floating point, mmx stuff
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//80 - long-displacement jumps
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+ {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, },
+//90 - conditional byte set
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+ {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, },
+//A0
+ {OPUSH, AFS, }, {OPOP, AFS, }, {OCPUID, }, {OBT, AEv, AGv},
+ {OSHLD,AEv,AGv,AIb}, {OSHLD,AEv,AGv,ACL}, {OBAD, }, {OBAD, },
+ {OPUSH, AGS, }, {OPOP, AGS, }, {OBAD, }, {OBTS, AEv, AGv},
+ {OSHRD,AEv,AGv,AIb}, {OSHRD,AEv,AGv,ACL}, {OBAD, }, {OIMUL, AGv,AGv,AEv},
+//B0 - mostly arcana
+ {OBAD, }, {OBAD, }, {OLFP,ASS,AGv,AMp},{OBTR,AEv,AGv },
+ {OLFP,AFS,AGv,AMp},{OLFP,AGS,AGv,AMp},{OMOVZX,AGv,AEb }, {OMOVZX,AGv,AEw },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBSF,AGv,AEv }, {OBSR,AGv,AEv }, {OMOVSX,AGv,AEb }, {OMOVSX,AGv,AEw },
+//C0 - more arcana
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//D0 - mmx
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//E0 - mmx
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+//F0 - mmx
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+/* some operands map to whole groups; group numbers from intel opcode map */
+/* args filled in already (in OGP1 entries) */
+static Optab optabgp1[8] = {
+ {OADD, }, {OOR, }, {OADC, }, {OSBB, },
+ {OAND, }, {OSUB, }, {OXOR, }, {OCMP, },
+};
+
+/* args filled in already (in OGP2 entries) */
+static Optab optabgp2[8] = {
+ {OROL, }, {OROR, }, {ORCL, }, {ORCR, },
+ {OSHL, }, {OSHR, }, {OBAD, }, {OSAR, },
+};
+
+static Optab optabgp3b[8] = {
+ {OTEST, AEb, AIb}, {OBAD, }, {ONOT, AEb, }, {ONEG, AEb, },
+ {OMUL,AAX,AAL,AEb},{OIMUL,AAX,AAL,AEb},{ODIV, AEb, }, {OIDIV, AEb, },
+};
+
+static Optab optabgp3v[8] = {
+ {OTEST, AEv, AIv}, {OBAD, }, {ONOT, AEv, }, {ONEG, AEv, },
+ {OMUL,AAX,AAX,AEv},{OIMUL,AAX,AAX,AEv},{ODIV, AEv, }, {OIDIV, AEv, },
+};
+
+static Optab optabgp4[8] = {
+ {OINC, AEb, }, {ODEC, AEb, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+static Optab optabgp5[8] = {
+ {OINC, AEv, }, {ODEC, AEv, }, {OCALL, AEv, }, {OCALL, AMp },
+ {OJUMP, AEv, }, {OJUMP, AMp, }, {OPUSH, AEv, }, {OBAD, },
+};
+
+static Optab optabgp10[8] = {
+ {OPOP, AEv, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+static Optab optabgp12[8] = {
+ {OMOV, }, {OBAD, }, {OBAD, }, {OBAD, },
+ {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, },
+};
+
+/* optabg6 unimplemented - mostly segment manipulation */
+/* optabg7 unimplemented - more segment manipulation */
+/* optabg8 unimplemented - bit tests */
+
+/*
+ * most of optabg9 - optabg16 decode differently depending on the mod value of
+ * the modrm byte. they're mostly arcane instructions so they're not
+ * implemented.
+ */
+
+static Optab *optabgp[NUMOP] = {
+ [OGP1] optabgp1,
+ [OGP2] optabgp2,
+ [OGP3b] optabgp3b,
+ [OGP3v] optabgp3v,
+ [OGP4] optabgp4,
+ [OGP5] optabgp5,
+ [OGP10] optabgp10,
+ [OGP12] optabgp12,
+};
+
+static uchar modrmarg[NATYPE] = {
+ [AEb] 1,
+ [AEw] 1,
+ [AEv] 1,
+ [AGb] 1,
+ [AGw] 1,
+ [AGv] 1,
+ [AM] 1,
+ [AMp] 1,
+ [AMa] 1,
+ [AMa2] 1,
+ [ASw] 1,
+ [AJr] 1,
+};
+
+static void
+getmodrm16(Iarg *ip, Inst *i)
+{
+ Iarg *p;
+ uchar b;
+
+ b = ar(ip); ip->off++;
+
+ i->mod = b>>6;
+ i->reg = (b>>3)&7;
+ i->rm = b&7;
+
+ if(i->mod == 3)
+ return;
+
+ switch(i->rm){
+ case 0:
+ i->off = ar(areg(ip->cpu, 2, RBX)) + ar(areg(ip->cpu, 2, RSI));
+ i->off &= 0xFFFF;
+ break;
+ case 1:
+ i->off = ar(areg(ip->cpu, 2, RBX)) + ar(areg(ip->cpu, 2, RDI));
+ i->off &= 0xFFFF;
+ break;
+ case 2:
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 2, RBP)) + ar(areg(ip->cpu, 2, RSI));
+ i->off &= 0xFFFF;
+ break;
+ case 3:
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 2, RBP)) + ar(areg(ip->cpu, 2, RDI));
+ i->off &= 0xFFFF;
+ break;
+ case 4:
+ i->off = ar(areg(ip->cpu, 2, RSI));
+ break;
+ case 5:
+ i->off = ar(areg(ip->cpu, 2, RDI));
+ break;
+ case 6:
+ if(i->mod == 0){
+ p = adup(ip); ip->off += 2;
+ p->len = 2;
+ i->off = ar(p);
+ return;
+ }
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 2, RBP));
+ break;
+ case 7:
+ i->off = ar(areg(ip->cpu, 2, RBX));
+ break;
+ }
+ switch(i->mod){
+ case 1:
+ i->off += (i->disp = ars(ip)); ip->off++;
+ i->off &= 0xFFFF;
+ break;
+ case 2:
+ p = adup(ip); ip->off += 2;
+ p->len = 2;
+ i->off += (i->disp = ars(p));
+ i->off &= 0xFFFF;
+ break;
+ }
+}
+
+static void
+getmodrm32(Iarg *ip, Inst *i)
+{
+ static uchar scaler[] = {1, 2, 4, 8};
+ Iarg *p;
+ uchar b;
+
+ b = ar(ip); ip->off++;
+
+ i->mod = b>>6;
+ i->reg = (b>>3)&7;
+ i->rm = b&7;
+
+ if(i->mod == 3)
+ return;
+
+ switch(i->rm){
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ i->off = ar(areg(ip->cpu, 4, i->rm + RAX));
+ break;
+ case 4:
+ b = ar(ip); i->off++;
+ i->scale = b>>6;
+ i->index = (b>>3)&7;
+ i->base = b&7;
+
+ if(i->base != 5){
+ i->off = ar(areg(ip->cpu, 4, i->base + RAX));
+ break;
+ }
+ case 5:
+ if(i->mod == 0){
+ p = adup(ip); ip->off += 4;
+ p->len = 4;
+ i->off = ar(p);
+ } else {
+ i->dsreg = RSS;
+ i->off = ar(areg(ip->cpu, 4, RBP));
+ }
+ break;
+ }
+
+ if(i->rm == 4 && i->index != 4)
+ i->off += ar(areg(ip->cpu, 4, i->index + RAX)) * scaler[i->scale];
+
+ switch(i->mod){
+ case 1:
+ i->off += (i->disp = ars(ip)); ip->off++;
+ break;
+ case 2:
+ p = adup(ip); ip->off += 4;
+ p->len = 4;
+ i->off += (i->disp = ars(p));
+ break;
+ }
+}
+
+static Iarg*
+getarg(Iarg *ip, Inst *i, uchar atype)
+{
+ Iarg *a;
+ uchar len, reg;
+
+ len = i->olen;
+ switch(atype){
+ default:
+ abort();
+
+ case A0:
+ case A1:
+ case A2:
+ case A3:
+ case A4:
+ a = acon(ip->cpu, len, atype - A0);
+ break;
+
+ case AEb:
+ len = 1;
+ if(0){
+ case AEw:
+ len = 2;
+ }
+ case AEv:
+ if(i->mod == 3){
+ reg = i->rm;
+ goto REG;
+ }
+ goto MEM;
+
+ case AM:
+ case AMp:
+ case AMa:
+ case AMa2:
+ if(i->mod == 3)
+ trap(ip->cpu, EBADOP);
+ MEM:
+ a = amem(ip->cpu, len, i->sreg, i->off);
+ if(atype == AMa2)
+ a->off += i->olen;
+ break;
+
+ case AGb:
+ len = 1;
+ if(0){
+ case AGw:
+ len = 2;
+ }
+ case AGv:
+ reg = i->reg;
+ REG:
+ a = areg(ip->cpu, len, reg + RAX);
+ if(len == 1 && reg >= 4){
+ a->reg -= 4;
+ a->tag |= TH;
+ }
+ break;
+
+ case AIb:
+ case AIc:
+ len = 1;
+ if(0){
+ case AIw:
+ len = 2;
+ }
+ case AIv:
+ a = adup(ip); ip->off += len;
+ a->len = len;
+ break;
+
+ case AJb:
+ len = 1;
+ case AJv:
+ a = adup(ip); ip->off += len;
+ a->len = len;
+ a->off = ip->off + ars(a);
+ break;
+
+ case AJr:
+ if(i->mod != 3)
+ trap(ip->cpu, EBADOP);
+ a = adup(ip);
+ a->off = ar(areg(ip->cpu, i->olen, i->rm + RAX));
+ break;
+
+ case AAp:
+ a = afar(ip, ip->len, len); ip->off += 2+len;
+ break;
+
+ case AOb:
+ len = 1;
+ case AOv:
+ a = adup(ip); ip->off += i->alen;
+ a->len = i->alen;
+ a = amem(ip->cpu, len, i->sreg, ar(a));
+ break;
+
+ case ASw:
+ reg = i->reg;
+ SREG:
+ a = areg(ip->cpu, 2, reg + RES);
+ break;
+
+ case AXb:
+ len = 1;
+ case AXv:
+ a = amem(ip->cpu, len, i->sreg, ar(areg(ip->cpu, i->alen, RSI)));
+ break;
+
+ case AYb:
+ len = 1;
+ case AYv:
+ a = amem(ip->cpu, len, RES, ar(areg(ip->cpu, i->alen, RDI)));
+ break;
+
+ case AFv:
+ a = areg(ip->cpu, len, RFL);
+ break;
+
+ case AAL:
+ case ACL:
+ case ADL:
+ case ABL:
+ case AAH:
+ case ACH:
+ case ADH:
+ case ABH:
+ len = 1;
+ reg = atype - AAL;
+ goto REG;
+
+ case AAX:
+ case ACX:
+ case ADX:
+ case ABX:
+ case ASP:
+ case ABP:
+ case ASI:
+ case ADI:
+ reg = atype - AAX;
+ goto REG;
+
+ case AES:
+ case ACS:
+ case ASS:
+ case ADS:
+ case AFS:
+ case AGS:
+ reg = atype - AES;
+ goto SREG;
+ }
+ a->atype = atype;
+ return a;
+}
+
+static int
+otherlen(int a)
+{
+ if(a == 2)
+ return 4;
+ else if(a == 4)
+ return 2;
+ abort();
+ return 0;
+}
+
+void
+decode(Iarg *ip, Inst *i)
+{
+ Optab *t, *t2;
+ Cpu *cpu;
+
+ cpu = ip->cpu;
+
+ i->op = 0;
+ i->rep = 0;
+ i->sreg = 0;
+ i->dsreg = RDS;
+ i->olen = cpu->olen;
+ i->alen = cpu->alen;
+
+ for(;;){
+ i->code = ar(ip); ip->off++;
+ t = optab + i->code;
+ switch(t->op){
+ case OOSIZE:
+ i->olen = otherlen(cpu->olen);
+ continue;
+ case OASIZE:
+ i->alen = otherlen(cpu->alen);
+ continue;
+ case OREPE:
+ case OREPNE:
+ i->rep = t->op;
+ continue;
+ case OLOCK:
+ continue;
+ case OSEG:
+ i->sreg = t->a1-AES+RES;
+ continue;
+ case O0F:
+ i->code = ar(ip); ip->off++;
+ t = optab0F + i->code;
+ break;
+ }
+ break;
+ }
+ t2 = optabgp[t->op];
+ if(t2 || modrmarg[t->a1] || modrmarg[t->a2] || modrmarg[t->a3])
+ if(i->alen == 2)
+ getmodrm16(ip, i);
+ else
+ getmodrm32(ip, i);
+ if(i->sreg == 0)
+ i->sreg = i->dsreg;
+
+ i->a1 = i->a2 = i->a3 = nil;
+ for(;;){
+ if(t->a1)
+ i->a1 = getarg(ip, i, t->a1);
+ if(t->a2)
+ i->a2 = getarg(ip, i, t->a2);
+ if(t->a3)
+ i->a3 = getarg(ip, i, t->a3);
+ if(t2 == nil)
+ break;
+ t = t2 + i->reg;
+ t2 = nil;
+ }
+ i->op = t->op;
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+static char *opstr[] = { /* Edit s/O(.*),/[O\1]= "\1",/g */
+ [OBAD]= "BAD",
+ [O0F]= "0F",
+ [OAAA]= "AAA",
+ [OAAD]= "AAD",
+ [OAAM]= "AAM",
+ [OAAS]= "AAS",
+ [OADC]= "ADC",
+ [OADD]= "ADD",
+ [OAND]= "AND",
+ [OARPL]= "ARPL",
+ [OASIZE]= "ASIZE",
+ [OBOUND]= "BOUND",
+ [OBT]= "BT",
+ [OBTC]= "BTC",
+ [OBTR]= "BTR",
+ [OBTS]= "BTS",
+ [OBSF]= "BSF",
+ [OBSR]= "BSR",
+ [OCALL]= "CALL",
+ [OCBW]= "CBW",
+ [OCLC]= "CLC",
+ [OCLD]= "CLD",
+ [OCLI]= "CLI",
+ [OCMC]= "CMC",
+ [OCMOV]= "CMOV",
+ [OCMP]= "CMP",
+ [OCMPS]= "CMPS",
+ [OCWD]= "CWD",
+ [ODAA]= "DAA",
+ [ODAS]= "DAS",
+ [ODEC]= "DEC",
+ [ODIV]= "DIV",
+ [OENTER]= "ENTER",
+ [OGP1]= "GP1",
+ [OGP2]= "GP2",
+ [OGP3b]= "GP3b",
+ [OGP3v]= "GP3v",
+ [OGP4]= "GP4",
+ [OGP5]= "GP5",
+ [OHLT]= "HLT",
+ [OIDIV]= "IDIV",
+ [OIMUL]= "IMUL",
+ [OIN]= "IN",
+ [OINC]= "INC",
+ [OINS]= "INS",
+ [OINT]= "INT",
+ [OIRET]= "IRET",
+ [OJUMP]= "JUMP",
+ [OLAHF]= "LAHF",
+ [OLFP]= "LFP",
+ [OLEA]= "LEA",
+ [OLEAVE]= "LEAVE",
+ [OLOCK]= "LOCK",
+ [OLODS]= "LODS",
+ [OLOOP]= "LOOP",
+ [OLOOPNZ]= "LOOPNZ",
+ [OLOOPZ]= "LOOPZ",
+ [OMOV]= "MOV",
+ [OMOVS]= "MOVS",
+ [OMOVZX]= "MOVZX",
+ [OMOVSX]= "MOVSX",
+ [OMUL]= "MUL",
+ [ONEG]= "NEG",
+ [ONOP]= "NOP",
+ [ONOT]= "NOT",
+ [OOR]= "OR",
+ [OOSIZE]= "OSIZE",
+ [OOUT]= "OUT",
+ [OOUTS]= "OUTS",
+ [OPOP]= "POP",
+ [OPOPA]= "POPA",
+ [OPOPF]= "POPF",
+ [OPUSH]= "PUSH",
+ [OPUSHA]= "PUSHA",
+ [OPUSHF]= "PUSHF",
+ [ORCL]= "RCL",
+ [ORCR]= "RCR",
+ [OREPE]= "REPE",
+ [OREPNE]= "REPNE",
+ [ORET]= "RET",
+ [ORETF]= "RETF",
+ [OROL]= "ROL",
+ [OROR]= "ROR",
+ [OSAHF]= "SAHF",
+ [OSAR]= "SAR",
+ [OSBB]= "SBB",
+ [OSCAS]= "SCAS",
+ [OSEG]= "SEG",
+ [OSET]= "SET",
+ [OSHL]= "SHL",
+ [OSHLD]= "SHLD",
+ [OSHR]= "SHR",
+ [OSHRD]= "SHRD",
+ [OSTC]= "STC",
+ [OSTD]= "STD",
+ [OSTI]= "STI",
+ [OSTOS]= "STOS",
+ [OSUB]= "SUB",
+ [OTEST]= "TEST",
+ [OWAIT]= "WAIT",
+ [OXCHG]= "XCHG",
+ [OXLAT]= "XLAT",
+ [OXOR]= "XOR",
+};
+
+static char *memstr16[] = {
+ "BX+SI",
+ "BX+DI",
+ "BP+SI",
+ "BP+DI",
+ "SI",
+ "DI",
+ "BP",
+ "BX",
+};
+
+static char *memstr32[] = {
+ "EAX",
+ "ECX",
+ "EDX",
+ "EBX",
+ "0",
+ "EBP",
+ "ESI",
+ "EDI",
+};
+
+static int
+argconv(char *p, Inst *i, Iarg *a)
+{
+ jmp_buf jmp;
+ char *s;
+
+ s = p;
+ switch(a->tag){
+ default:
+ abort();
+
+ case TCON:
+ return sprint(p, "%lud", a->val);
+ case TREG:
+ case TREG|TH:
+ switch(a->len){
+ case 1:
+ return sprint(p, "%c%c", "ACDB"[a->reg], "LH"[(a->tag & TH) != 0]);
+ case 4:
+ *p++ = 'E';
+ case 2:
+ p += sprint(p, "%c%c",
+ "ACDBSBSDECSDFGIF"[a->reg],
+ "XXXXPPIISSSSSSPL"[a->reg]);
+ return p - s;
+ }
+ case TMEM:
+ break;
+ }
+
+ /* setup trap jump in case we dereference bad memory */
+ memmove(jmp, a->cpu->jmp, sizeof jmp);
+ if(setjmp(a->cpu->jmp)){
+ p += sprint(p, "<%.4lux:%.4lux>", a->seg, a->off);
+ goto out;
+ }
+
+ switch(a->atype){
+ default:
+ abort();
+
+ case AAp:
+ p += sprint(p, "[%.4lux:%.4lux]", a->seg, a->off);
+ break;
+
+ case AJb:
+ case AJv:
+ p += sprint(p, "[%.4lux]", a->off);
+ break;
+
+ case AIc:
+ p += sprint(p, "$%.2lx", ars(a));
+ break;
+ case AIb:
+ case AIw:
+ case AIv:
+ p += sprint(p, "$%.*lux", (int)a->len*2, ar(a));
+ break;
+
+ case AMp:
+ *p++ = '*';
+ case AEb:
+ case AEw:
+ case AEv:
+ case AM:
+ case AMa:
+ case AMa2:
+ case AOb:
+ case AOv:
+ if(i->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]);
+ if(a->atype == AOb || a->atype == AOv || (i->mod == 0 &&
+ (i->alen == 2 && i->rm == 6) ||
+ (i->alen == 4 && ((i->rm == 5) ||
+ (i->rm == 4 && i->index == 4 && i->base == 5))))){
+ p += sprint(p, "[%.*lux]", (int)i->alen*2, a->off);
+ break;
+ }
+ *p++ = '[';
+ if(i->alen == 2)
+ p += sprint(p, "%s", memstr16[i->rm]);
+ else{
+ if(i->rm == 4){
+ if(i->index != 4)
+ p += sprint(p, "%c*%s+", "1248"[i->scale], memstr32[i->index]);
+ if(i->base != 5)
+ p += sprint(p, "%s", memstr32[i->base]);
+ else{
+ if(i->mod == 0)
+ p += sprint(p, "%.4lux", i->off);
+ else
+ p += sprint(p, "EBP");
+ }
+ } else
+ p += sprint(p, "%s", memstr32[i->rm]);
+ }
+ if(i->mod != 0)
+ p += sprint(p, "%+lx", i->disp);
+ *p++ = ']';
+ break;
+
+ case AXb:
+ case AXv:
+ if(a->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]);
+ p += sprint(p, "[SI]");
+ break;
+ case AYb:
+ case AYv:
+ if(a->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]);
+ p += sprint(p, "[DI]");
+ break;
+ }
+
+out:
+ memmove(a->cpu->jmp, jmp, sizeof jmp);
+ *p = 0;
+ return p - s;
+}
+
+static char *jmpstr[] = {
+ "JO", "JNO", "JC", "JNC", "JZ", "JNZ", "JBE", "JA",
+ "JS", "JNS", "JP", "JNP", "JL", "JGE", "JLE", "JG",
+};
+
+int
+instfmt(Fmt *fmt)
+{
+ Inst *i;
+ char *p, buf[256];
+
+ i = va_arg(fmt->args, Inst*);
+ p = buf;
+
+ if(i->olen == 4)
+ p += sprint(p, "O32: ");
+ if(i->alen == 4)
+ p += sprint(p, "A32: ");
+ if(i->rep)
+ p += sprint(p, "%s: ", opstr[i->rep]);
+
+ if(i->op == OXLAT && i->sreg != RDS)
+ p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]);
+
+ if(i->op == OJUMP){
+ switch(i->code){
+ case 0xE3:
+ p += sprint(p, "%s ", "JCXZ");
+ break;
+ case 0xEB:
+ case 0xE9:
+ case 0xEA:
+ case 0xFF:
+ p += sprint(p, "%s ", "JMP");
+ break;
+ default:
+ p += sprint(p, "%s ", jmpstr[i->code&0xF]);
+ break;
+ }
+ } else
+ p += sprint(p, "%s ", opstr[i->op]);
+
+
+ for(;;){
+ if(i->a1 == nil)
+ break;
+ p += argconv(p, i, i->a1);
+ if(i->a2 == nil)
+ break;
+ *p++ = ',';
+ *p++ = ' ';
+ p += argconv(p, i, i->a2);
+ if(i->a3 == nil)
+ break;
+ *p++ = ',';
+ *p++ = ' ';
+ p += argconv(p, i, i->a3);
+ break;
+ }
+ *p = 0;
+ fmtstrcpy(fmt, buf);
+ return 0;
+}
+
+int
+flagfmt(Fmt *fmt)
+{
+ char buf[16];
+ ulong f;
+
+ f = va_arg(fmt->args, ulong);
+ sprint(buf, "%c%c%c%c%c%c%c",
+ (f & CF) ? 'C' : 'c',
+ (f & SF) ? 'S' : 's',
+ (f & ZF) ? 'Z' : 'z',
+ (f & OF) ? 'O' : 'o',
+ (f & PF) ? 'P' : 'p',
+ (f & DF) ? 'D' : 'd',
+ (f & IF) ? 'I' : 'i');
+ fmtstrcpy(fmt, buf);
+ return 0;
+}
+
+int
+cpufmt(Fmt *fmt)
+{
+ char buf[512];
+ jmp_buf jmp;
+ Cpu *cpu;
+ Inst i;
+
+ cpu = va_arg(fmt->args, Cpu*);
+
+ memmove(jmp, cpu->jmp, sizeof jmp);
+ if(setjmp(cpu->jmp) == 0)
+ decode(amem(cpu, 1, RCS, cpu->reg[RIP]), &i);
+ memmove(cpu->jmp, jmp, sizeof jmp);
+
+ snprint(buf, sizeof(buf),
+ "%.6lux "
+ "%.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux "
+ "%.4lux %.4lux %.4lux %.4lux "
+ "%J %.4lux %.2ux %I",
+
+ cpu->ic,
+
+ cpu->reg[RAX],
+ cpu->reg[RBX],
+ cpu->reg[RCX],
+ cpu->reg[RDX],
+
+ cpu->reg[RDI],
+ cpu->reg[RSI],
+
+ cpu->reg[RBP],
+ cpu->reg[RSP],
+
+ cpu->reg[RDS],
+ cpu->reg[RES],
+ cpu->reg[RSS],
+ cpu->reg[RCS],
+
+ cpu->reg[RFL],
+ cpu->reg[RIP],
+
+ i.code,
+ &i);
+
+ fmtstrcpy(fmt, buf);
+ return 0;
+}
--- /dev/null
+/* arg */
+Iarg *adup(Iarg *x);
+Iarg *areg(Cpu *cpu, uchar len, uchar reg);
+Iarg *amem(Cpu *cpu, uchar len, uchar sreg, ulong off);
+Iarg *afar(Iarg *mem, uchar len, uchar alen);
+Iarg *acon(Cpu *cpu, uchar len, ulong val);
+ulong ar(Iarg *a);
+long ars(Iarg *a);
+void aw(Iarg *a, ulong w);
+
+/* decode */
+void decode(Iarg *ip, Inst *i);
+
+/* xec */
+void trap(Cpu *cpu, int e);
+int intr(Cpu *cpu, int v);
+int xec(Cpu *cpu, int n);
+
+#pragma varargck type "I" Inst*
+#pragma varargck type "J" ulong
+#pragma varargck type "C" Cpu*
+
+int instfmt(Fmt *fmt);
+int flagfmt(Fmt *fmt);
+int cpufmt(Fmt *fmt);
+
+/* pit */
+void clockpit(Pit *pit, vlong cycles);
+void setgate(Pit *ch, uchar gate);
+uchar rpit(Pit *pit, uchar addr);
+void wpit(Pit *pit, uchar addr, uchar data);
--- /dev/null
+#include <u.h>
+#include <libc.h>
+
+#include "/386/include/ureg.h"
+
+static uchar buf[0xFF01];
+
+void
+main(int argc, char *argv[])
+{
+ struct Ureg u;
+ int fd, rreg, rmem, len;
+
+ ARGBEGIN {
+ } ARGEND;
+
+ if(argc == 0){
+ fprint(2, "usage:\t%s file.com\n", argv0);
+ exits("usage");
+ }
+ if((fd = open(*argv, OREAD)) < 0)
+ sysfatal("open: %r");
+
+ if((rreg = open("/dev/realmode", OWRITE)) < 0)
+ sysfatal("open realmode: %r");
+ if((rmem = open("/dev/realmodemem", OWRITE)) < 0)
+ sysfatal("open realmodemem: %r");
+ if((len = readn(fd, buf, sizeof buf)) < 2)
+ sysfatal("file too small");
+
+ memset(&u, 0, sizeof u);
+ u.cs = u.ds = u.es = u.fs = u.gs = 0x1000;
+ u.ss = 0x0000;
+ u.sp = 0xfffe;
+ u.pc = 0x0100;
+
+ seek(rmem, (u.cs<<4) + u.pc, 0);
+ if(write(rmem, buf, len) != len)
+ sysfatal("write mem: %r");
+
+ if(write(rreg, &u, sizeof u) != sizeof u)
+ sysfatal("write reg: %r");
+}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+/* for fs */
+#include <auth.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+
+#include "/386/include/ureg.h"
+
+enum {
+ MEMSIZE = 0x100000,
+
+ RMBUF = 0x9000,
+ RMCODE = 0x8000,
+
+ PITHZ = 1193182,
+ PITNS = 1000000000/PITHZ,
+};
+
+static Cpu cpu;
+static uchar memory[MEMSIZE+4];
+static uchar pageregtmp[0x10];
+static int portfd[5];
+static int realmemfd;
+static int cputrace;
+static int porttrace;
+static Pit pit[3];
+
+static vlong pitclock;
+
+static void
+startclock(void)
+{
+ pitclock = nsec();
+}
+
+static void
+runclock(void)
+{
+ vlong now, dt;
+
+ now = nsec();
+ dt = now - pitclock;
+ if(dt >= PITNS){
+ clockpit(pit, dt/PITNS);
+ pitclock = now;
+ }
+}
+
+static ulong
+gw1(uchar *p)
+{
+ return p[0];
+}
+static ulong
+gw2(uchar *p)
+{
+ return (ulong)p[0] | (ulong)p[1]<<8;
+}
+static ulong
+gw4(uchar *p)
+{
+ return (ulong)p[0] | (ulong)p[1]<<8 | (ulong)p[2]<<16 | (ulong)p[3]<<24;
+}
+static ulong (*gw[5])(uchar *p) = {
+ [1] gw1,
+ [2] gw2,
+ [4] gw4,
+};
+
+static void
+pw1(uchar *p, ulong w)
+{
+ p[0] = w & 0xFF;
+}
+static void
+pw2(uchar *p, ulong w)
+{
+ p[0] = w & 0xFF;
+ p[1] = (w>>8) & 0xFF;
+}
+static void
+pw4(uchar *p, ulong w)
+{
+ p[0] = w & 0xFF;
+ p[1] = (w>>8) & 0xFF;
+ p[2] = (w>>16) & 0xFF;
+ p[3] = (w>>24) & 0xFF;
+}
+static void (*pw[5])(uchar *p, ulong w) = {
+ [1] pw1,
+ [2] pw2,
+ [4] pw4,
+};
+
+static ulong
+rbad(void *, ulong off, int)
+{
+ fprint(2, "bad mem read %.5lux\n", off);
+ trap(&cpu, EMEM);
+
+ /* not reached */
+ return 0;
+}
+
+static void
+wbad(void *, ulong off, ulong, int)
+{
+ fprint(2, "bad mem write %.5lux\n", off);
+ trap(&cpu, EMEM);
+}
+
+static ulong
+rmem(void *, ulong off, int len)
+{
+ return gw[len](memory + off);
+}
+
+static void
+wmem(void *, ulong off, ulong w, int len)
+{
+ pw[len](memory + off, w);
+}
+
+static ulong
+rrealmem(void *, ulong off, int len)
+{
+ uchar data[4];
+
+ if(pread(realmemfd, data, len, off) != len){
+ fprint(2, "bad real mem read %.5lux: %r\n", off);
+ trap(&cpu, EMEM);
+ }
+ return gw[len](data);
+}
+
+static void
+wrealmem(void *, ulong off, ulong w, int len)
+{
+ uchar data[4];
+
+ pw[len](data, w);
+ if(pwrite(realmemfd, data, len, off) != len){
+ fprint(2, "bad real mem write %.5lux: %r\n", off);
+ trap(&cpu, EMEM);
+ }
+}
+
+
+static ulong
+rport(void *, ulong p, int len)
+{
+ uchar data[4];
+ ulong w;
+
+ switch(p){
+ case 0x20: /* PIC 1 */
+ case 0x21:
+ w = 0;
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ runclock();
+ w = rpit(pit, p - 0x40);
+ break;
+ case 0x60: /* keyboard data output buffer */
+ w = 0;
+ break;
+ case 0x61: /* keyboard controller port b */
+ runclock();
+ w = pit[2].out<<5 | pit[2].gate;
+ break;
+ case 0x62: /* PPI (XT only) */
+ runclock();
+ w = pit[2].out<<5;
+ break;
+ case 0x63: /* PPI (XT only) read dip switches */
+ w = 0;
+ break;
+ case 0x65: /* A20 gate */
+ w = 1 << 2;
+ break;
+ case 0x80: /* extra dma registers (temp) */
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x88:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ w = pageregtmp[p-0x80];
+ break;
+ case 0x92: /* A20 gate (system control port a) */
+ w = 1 << 1;
+ break;
+ case 0xa0: /* PIC 2 */
+ case 0xa1:
+ w = 0;
+ break;
+ default:
+ if(pread(portfd[len], data, len, p) != len){
+ fprint(2, "bad %d bit port read %.4lux: %r\n", len*8, p);
+ trap(&cpu, EIO);
+ }
+ w = gw[len](data);
+ }
+ if(porttrace)
+ fprint(2, "rport %.4lux %.*lux\n", p, len<<1, w);
+ return w;
+}
+
+static void
+wport(void *, ulong p, ulong w, int len)
+{
+ uchar data[4];
+
+ if(porttrace)
+ fprint(2, "wport %.4lux %.*lux\n", p, len<<1, w);
+
+ switch(p){
+ case 0x20: /* PIC 1 */
+ case 0x21:
+ break;
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ runclock();
+ wpit(pit, p - 0x40, w);
+ break;
+ case 0x60: /* keyboard controller data port */
+ break;
+ case 0x61: /* keyboard controller port B */
+ setgate(&pit[2], w & 1);
+ break;
+ case 0x62: /* PPI (XT only) */
+ case 0x63:
+ case 0x64: /* KB controller input buffer (ISA, EISA) */
+ case 0x65: /* A20 gate (bit 2) */
+ break;
+ case 0x80:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x88:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ pageregtmp[p-0x80] = w & 0xFF;
+ break;
+ case 0x92: /* system control port a */
+ case 0x94: /* system port enable setup register */
+ case 0x96:
+ break;
+ case 0xA0: /* PIC 2 */
+ case 0xA1:
+ break;
+
+ default:
+ pw[len](data, w);
+ if(pwrite(portfd[len], data, len, p) != len){
+ fprint(2, "bad %d bit port write %.4lux: %r\n", len*8, p);
+ trap(&cpu, EIO);
+ }
+ }
+}
+
+static Bus memio[] = {
+ /* 0 */ memory, rmem, wmem, /* RAM: IVT, BIOS data area */
+ /* 1 */ memory, rmem, wmem, /* custom */
+ /* 2 */ nil, rbad, wbad,
+ /* 3 */ nil, rbad, wbad,
+ /* 4 */ nil, rbad, wbad,
+ /* 5 */ nil, rbad, wbad,
+ /* 6 */ nil, rbad, wbad,
+ /* 7 */ nil, rbad, wbad,
+ /* 8 */ nil, rbad, wbad,
+ /* 9 */ memory, rmem, wmem, /* RAM: extended BIOS data area */
+ /* A */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */
+ /* B */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */
+ /* C */ memory, rmem, wmem, /* ROM: VGA BIOS */
+ /* D */ nil, rbad, wbad,
+ /* E */ memory, rmem, wbad, /* ROM: BIOS */
+ /* F */ memory, rmem, wbad, /* ROM: BIOS */
+};
+
+static Bus portio = {
+ nil, rport, wport,
+};
+
+static void
+cpuinit(void)
+{
+ int i;
+
+ fmtinstall('I', instfmt);
+ fmtinstall('J', flagfmt);
+ fmtinstall('C', cpufmt);
+
+ if((portfd[1] = open("#P/iob", ORDWR)) < 0)
+ sysfatal("open iob: %r");
+ if((portfd[2] = open("#P/iow", ORDWR)) < 0)
+ sysfatal("open iow: %r");
+ if((portfd[4] = open("#P/iol", ORDWR)) < 0)
+ sysfatal("open iol: %r");
+
+ if((realmemfd = open("#P/realmodemem", ORDWR)) < 0)
+ sysfatal("open realmodemem: %r");
+
+ for(i=0; i<nelem(memio); i++){
+ ulong off;
+
+ if(memio[i].r != rmem)
+ continue;
+
+ off = (ulong)i << 16;
+ seek(realmemfd, off, 0);
+ if(readn(realmemfd, memory + off, 0x10000) != 0x10000)
+ sysfatal("read real mem %lux: %r\n", off);
+ }
+
+ cpu.ic = 0;
+ cpu.mem = memio;
+ cpu.port = &portio;
+ cpu.alen = cpu.olen = cpu.slen = 2;
+}
+
+static char Ebusy[] = "device is busy";
+static char Eintr[] = "interrupted";
+static char Eperm[] = "permission denied";
+static char Eio[] = "i/o error";
+static char Emem[] = "bad memory access";
+static char Enonexist[] = "file does not exist";
+static char Ebadspec[] = "bad attach specifier";
+static char Ewalk[] = "walk in non directory";
+static char Ebadureg[] = "write a Ureg";
+static char Ebadoff[] = "invalid offset";
+static char Ebadtrap[] = "bad trap";
+
+static char *trapstr[] = {
+ [EDIV0] "division by zero",
+ [EDEBUG] "debug exception",
+ [ENMI] "not maskable interrupt",
+ [EBRK] "breakpoint",
+ [EINTO] "into overflow",
+ [EBOUND] "bounds check",
+ [EBADOP] "bad opcode",
+ [ENOFPU] "no fpu installed",
+ [EDBLF] "double fault",
+ [EFPUSEG] "fpu segment overflow",
+ [EBADTSS] "invalid task state segment",
+ [ENP] "segment not present",
+ [ESTACK] "stack fault",
+ [EGPF] "general protection fault",
+ [EPF] "page fault",
+};
+
+static int flushed(void *);
+
+#define GETUREG(x) gw[sizeof(u->x)]((uchar*)&u->x)
+#define PUTUREG(x,y) pw[sizeof(u->x)]((uchar*)&u->x,y)
+
+static char*
+realmode(Cpu *cpu, struct Ureg *u, void *r)
+{
+ char *err;
+ int i;
+
+ cpu->reg[RDI] = GETUREG(di);
+ cpu->reg[RSI] = GETUREG(si);
+ cpu->reg[RBP] = GETUREG(bp);
+ cpu->reg[RBX] = GETUREG(bx);
+ cpu->reg[RDX] = GETUREG(dx);
+ cpu->reg[RCX] = GETUREG(cx);
+ cpu->reg[RAX] = GETUREG(ax);
+
+ cpu->reg[RGS] = GETUREG(gs);
+ cpu->reg[RFS] = GETUREG(fs);
+ cpu->reg[RES] = GETUREG(es);
+ cpu->reg[RDS] = GETUREG(ds);
+
+ cpu->reg[RFL] = GETUREG(flags);
+
+ if(i = GETUREG(trap)){
+ cpu->reg[RSS] = 0x0000;
+ cpu->reg[RSP] = 0x7C00;
+ cpu->reg[RCS] = (RMCODE>>4)&0xF000;
+ cpu->reg[RIP] = RMCODE & 0xFFFF;
+ memory[RMCODE] = 0xf4; /* HLT instruction */
+ if(intr(cpu, i) < 0)
+ return Ebadtrap;
+ } else {
+ cpu->reg[RSS] = GETUREG(ss);
+ cpu->reg[RSP] = GETUREG(sp);
+ cpu->reg[RCS] = GETUREG(cs);
+ cpu->reg[RIP] = GETUREG(pc);
+ }
+
+ startclock();
+ for(;;){
+ if(cputrace)
+ fprint(2, "%C\n", cpu);
+ switch(i = xec(cpu, (porttrace | cputrace) ? 1 : 100000)){
+ case -1:
+ if(flushed(r)){
+ err = Eintr;
+ break;
+ }
+ runclock();
+ continue;
+
+ /* normal interrupts */
+ default:
+ if(intr(cpu, i) < 0){
+ err = Ebadtrap;
+ break;
+ }
+ continue;
+
+ /* pseudo-interrupts */
+ case EHALT:
+ err = nil;
+ break;
+ case EIO:
+ err = Eio;
+ break;
+ case EMEM:
+ err = Emem;
+ break;
+
+ /* processor traps */
+ case EDIV0:
+ case EDEBUG:
+ case ENMI:
+ case EBRK:
+ case EINTO:
+ case EBOUND:
+ case EBADOP:
+ case ENOFPU:
+ case EDBLF:
+ case EFPUSEG:
+ case EBADTSS:
+ case ENP:
+ case ESTACK:
+ case EGPF:
+ case EPF:
+ PUTUREG(trap, i);
+ err = trapstr[i];
+ break;
+ }
+
+ break;
+ }
+
+ if(err)
+ fprint(2, "%s\n%C\n", err, cpu);
+
+ PUTUREG(di, cpu->reg[RDI]);
+ PUTUREG(si, cpu->reg[RSI]);
+ PUTUREG(bp, cpu->reg[RBP]);
+ PUTUREG(bx, cpu->reg[RBX]);
+ PUTUREG(dx, cpu->reg[RDX]);
+ PUTUREG(cx, cpu->reg[RCX]);
+ PUTUREG(ax, cpu->reg[RAX]);
+
+ PUTUREG(gs, cpu->reg[RGS]);
+ PUTUREG(fs, cpu->reg[RFS]);
+ PUTUREG(es, cpu->reg[RES]);
+ PUTUREG(ds, cpu->reg[RDS]);
+
+ PUTUREG(flags, cpu->reg[RFL]);
+
+ PUTUREG(pc, cpu->reg[RIP]);
+ PUTUREG(cs, cpu->reg[RCS]);
+ PUTUREG(sp, cpu->reg[RSP]);
+ PUTUREG(ss, cpu->reg[RSS]);
+
+ return err;
+}
+
+enum {
+ Qroot,
+ Qcall,
+ Qmem,
+ Nqid,
+};
+
+static struct Qtab {
+ char *name;
+ int mode;
+ int type;
+ int length;
+} qtab[Nqid] = {
+ "/",
+ DMDIR|0555,
+ QTDIR,
+ 0,
+
+ "realmode",
+ 0666,
+ 0,
+ 0,
+
+ "realmodemem",
+ 0666,
+ 0,
+ MEMSIZE,
+};
+
+static int
+fillstat(ulong qid, Dir *d)
+{
+ struct Qtab *t;
+
+ memset(d, 0, sizeof(Dir));
+ d->uid = "realemu";
+ d->gid = "realemu";
+ d->muid = "";
+ d->qid = (Qid){qid, 0, 0};
+ d->atime = time(0);
+ t = qtab + qid;
+ d->name = t->name;
+ d->qid.type = t->type;
+ d->mode = t->mode;
+ d->length = t->length;
+ return 1;
+}
+
+static void
+fsattach(Req *r)
+{
+ char *spec;
+
+ spec = r->ifcall.aname;
+ if(spec && spec[0]){
+ respond(r, Ebadspec);
+ return;
+ }
+ r->fid->qid = (Qid){Qroot, 0, QTDIR};
+ r->ofcall.qid = r->fid->qid;
+ respond(r, nil);
+}
+
+static void
+fsstat(Req *r)
+{
+ fillstat((ulong)r->fid->qid.path, &r->d);
+ r->d.name = estrdup9p(r->d.name);
+ r->d.uid = estrdup9p(r->d.uid);
+ r->d.gid = estrdup9p(r->d.gid);
+ r->d.muid = estrdup9p(r->d.muid);
+ respond(r, nil);
+}
+
+static char*
+fswalk1(Fid *fid, char *name, Qid *qid)
+{
+ int i;
+ ulong path;
+
+ path = fid->qid.path;
+ switch(path){
+ case Qroot:
+ if (strcmp(name, "..") == 0) {
+ *qid = (Qid){Qroot, 0, QTDIR};
+ fid->qid = *qid;
+ return nil;
+ }
+ for(i = fid->qid.path; i<Nqid; i++){
+ if(strcmp(name, qtab[i].name) != 0)
+ continue;
+ *qid = (Qid){i, 0, 0};
+ fid->qid = *qid;
+ return nil;
+ }
+ return Enonexist;
+
+ default:
+ return Ewalk;
+ }
+}
+
+static void
+fsopen(Req *r)
+{
+ static int need[4] = { 4, 2, 6, 1 };
+ struct Qtab *t;
+ int n;
+
+ t = qtab + r->fid->qid.path;
+ n = need[r->ifcall.mode & 3];
+ if((n & t->mode) != n)
+ respond(r, Eperm);
+ else
+ respond(r, nil);
+}
+
+static int
+readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
+{
+ int i, m, n;
+ long pos;
+ Dir d;
+
+ n = 0;
+ pos = 0;
+ for (i = 1; i < Nqid; i++){
+ fillstat(i, &d);
+ m = convD2M(&d, &buf[n], blen-n);
+ if(off <= pos){
+ if(m <= BIT16SZ || m > cnt)
+ break;
+ n += m;
+ cnt -= m;
+ }
+ pos += m;
+ }
+ return n;
+}
+
+static Channel *reqchan;
+
+static void
+cpuproc(void *)
+{
+ static struct Ureg rmu;
+ ulong path;
+ vlong o;
+ ulong n;
+ char *p;
+ Req *r;
+
+ threadsetname("cpuproc");
+
+ while(r = recvp(reqchan)){
+ if(flushed(r)){
+ respond(r, Eintr);
+ continue;
+ }
+
+ path = r->fid->qid.path;
+
+ p = r->ifcall.data;
+ n = r->ifcall.count;
+ o = r->ifcall.offset;
+
+ switch(((int)r->ifcall.type<<8)|path){
+ case (Tread<<8) | Qmem:
+ readbuf(r, memory, MEMSIZE);
+ respond(r, nil);
+ break;
+
+ case (Tread<<8) | Qcall:
+ readbuf(r, &rmu, sizeof rmu);
+ respond(r, nil);
+ break;
+
+ case (Twrite<<8) | Qmem:
+ if(o < 0 || o >= MEMSIZE || o+n > MEMSIZE){
+ respond(r, Ebadoff);
+ break;
+ }
+ memmove(memory + o, p, n);
+ r->ofcall.count = n;
+ respond(r, nil);
+ break;
+
+ case (Twrite<<8) | Qcall:
+ if(n != sizeof rmu){
+ respond(r, Ebadureg);
+ break;
+ }
+ memmove(&rmu, p, n);
+ if(p = realmode(&cpu, &rmu, r)){
+ respond(r, p);
+ break;
+ }
+ r->ofcall.count = n;
+ respond(r, nil);
+ break;
+ }
+ }
+}
+
+static Channel *flushchan;
+
+static int
+flushed(void *r)
+{
+ return nbrecvp(flushchan) == r;
+}
+
+static void
+fsflush(Req *r)
+{
+ nbsendp(flushchan, r->oldreq);
+ respond(r, nil);
+}
+
+static void
+dispatch(Req *r)
+{
+ if(!nbsendp(reqchan, r))
+ respond(r, Ebusy);
+}
+
+static void
+fsread(Req *r)
+{
+ switch((ulong)r->fid->qid.path){
+ case Qroot:
+ r->ofcall.count = readtopdir(r->fid, (void*)r->ofcall.data, r->ifcall.offset,
+ r->ifcall.count, r->ifcall.count);
+ respond(r, nil);
+ break;
+ default:
+ dispatch(r);
+ }
+}
+
+static void
+fsend(Srv*)
+{
+ threadexitsall(nil);
+}
+
+static Srv fs = {
+ .attach= fsattach,
+ .walk1= fswalk1,
+ .open= fsopen,
+ .read= fsread,
+ .write= dispatch,
+ .stat= fsstat,
+ .flush= fsflush,
+ .end= fsend,
+};
+
+static void
+usage(void)
+{
+ fprint(2, "usgae:\t%s [-Dpt] [-s srvname] [-m mountpoint]\n", argv0);
+ exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ char *mnt = "/dev";
+ char *srv = nil;
+
+ ARGBEGIN{
+ case 'D':
+ chatty9p++;
+ break;
+ case 'p':
+ porttrace = 1;
+ break;
+ case 't':
+ cputrace = 1;
+ break;
+ case 's':
+ srv = EARGF(usage());
+ mnt = nil;
+ break;
+ case 'm':
+ mnt = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ cpuinit();
+
+ reqchan = chancreate(sizeof(Req*), 8);
+ flushchan = chancreate(sizeof(Req*), 8);
+ procrfork(cpuproc, nil, 16*1024, RFNAMEG|RFNOTEG);
+ threadpostmountsrv(&fs, srv, mnt, MBEFORE);
+}
--- /dev/null
+</$objtype/mkfile
+
+BIN=/$objtype/bin/aux
+MAN=/sys/man/8
+
+TARG=realemu
+OFILES=decode.$O arg.$O xec.$O fmt.$O pit.$O main.$O
+HFILES=dat.h fns.h
+
+</sys/src/cmd/mkone
+
+install:V:
+ cp $TARG.man $MAN/$TARG
--- /dev/null
+realmode emulator. binds itself over /dev and provides /dev/realmode
+and /dev/realmodemem to be used with aux/vga -m vesa ...
+
+the command option -t enables instruction tracing to stderr.
+
+requires a updated vgavesa driver to use /dev/realmode instead of
+a direct realmode() call.
+
+patch can be found at: /n/sources/patch/vesa-softscreen-resize
+
+a list with graphics cards that have been successfully enabled
+with the aux/vga and realemu can be found in the vgalist file.
+
+bug reports / suggestions or failed attempts email to:
+
+cinap_lenrek AT gmx DOT de
+
+contributors:
+
+i stole some code from rsc's 8i /n/sources/contrib/rsc/8i, so thanks russ! :)
+
+patient testers from irc: sl, Fish-
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+enum {
+ AC0 = 0,
+ AC1,
+ AC2,
+ Actl,
+
+ Readback = 3,
+
+ RBC0 = 1<<1,
+ RBC1 = 1<<2,
+ RBC2 = 1<<3,
+ RBlatchstatus = 1<<4,
+ RBlatchcount = 1<<5,
+
+ AMlatchcount = 0,
+ AMloonly,
+ AMhionly,
+ AMlohi,
+
+ OM0 = 0,
+ OM1,
+ OM2,
+ OM3,
+ OM4,
+ OM5,
+ OM2b,
+ OM3b,
+};
+
+static void
+latchstatus(Pit *ch)
+{
+ if(ch->rlatched)
+ return;
+ ch->rlatch[0] = ch->bcd | ch->omode<<1 | ch->amode<<4 | ch->count0<<6 | ch->out<<7;
+ ch->rcount = 0;
+ ch->rlatched = 1;
+}
+
+static void
+latchcount(Pit *ch)
+{
+ ulong w;
+
+ if(ch->rlatched)
+ return;
+ w = ch->count & 0xFFFF;
+ if(ch->bcd)
+ w = (w % 10) + ((w/10) % 10)<<4 + ((w/100) % 10)<<8 + ((w/1000) % 10)<<12;
+ ch->rlatch[0] = w & 0xFF;
+ ch->rlatch[1] = (w >> 8) & 0xFF;
+ ch->rcount = 0;
+ ch->rlatched = 1;
+ switch(ch->amode){
+ case AMhionly:
+ ch->rcount++;
+ break;
+ case AMlohi:
+ ch->rlatched++;
+ break;
+ }
+}
+
+static void
+setcount(Pit *ch)
+{
+ ulong w;
+
+ w = (ulong)ch->wlatch[0] | (ulong)ch->wlatch[1] << 8;
+ if(ch->bcd)
+ w = (w & 0xF) + 10*((w >> 4)&0xF) + 100*((w >> 8)&0xF) + 1000*((w >> 12)&0xF);
+ ch->count = w;
+ ch->count0 = 0;
+}
+
+static int
+deccount(Pit *ch, vlong *cycles)
+{
+ if(ch->count0){
+ *cycles = 0;
+ return 0;
+ } else {
+ vlong passed, remain;
+
+ passed = *cycles;
+ if(ch->count == 0){
+ ch->count = ch->bcd ? 9999 : 0xFFFF;
+ passed--;
+ }
+ if(passed <= ch->count){
+ remain = 0;
+ ch->count -= passed;
+ } else {
+ remain = passed - ch->count;
+ ch->count = 0;
+ }
+ *cycles = remain;
+ return ch->count == 0;
+ }
+}
+
+void
+setgate(Pit *ch, uchar gate)
+{
+ if(ch->gate == 0 && gate)
+ ch->gateraised = 1;
+ ch->gate = gate;
+}
+
+static void
+clockpit1(Pit *ch, vlong *cycles)
+{
+ switch(ch->omode){
+ case OM0: /* Interrupt On Terminal Count */
+ if(ch->count0){
+ setcount(ch);
+ ch->out = 0;
+ Next:
+ --*cycles;
+ return;
+ }
+ if(ch->gate && deccount(ch, cycles)){
+ ch->out = 1;
+ return;
+ }
+ break;
+
+ case OM1: /* Hardware Re-triggerable One-shot */
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ ch->out = 0;
+ goto Next;
+ }
+ if(deccount(ch, cycles) && ch->out == 0){
+ ch->out = 1;
+ return;
+ }
+ break;
+
+ case OM2: /* Rate Generator */
+ case OM2b:
+ ch->out = 1;
+ if(ch->count0){
+ setcount(ch);
+ goto Next;
+ }
+ if(ch->gate == 0)
+ break;
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ goto Next;
+ }
+ if(deccount(ch, cycles)){
+ setcount(ch);
+ ch->out = 0;
+ return;
+ }
+ break;
+
+ case OM3: /* Square Wave Generator */
+ case OM3b:
+ if(ch->count0){
+ setcount(ch);
+ goto Next;
+ }
+ if(ch->gate == 0)
+ break;
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ goto Next;
+ }
+ if(deccount(ch, cycles)){
+ setcount(ch);
+ ch->out ^= 1;
+ return;
+ }
+ break;
+
+ case OM4: /* Software Triggered Strobe */
+ ch->out = 1;
+ if(ch->count0){
+ setcount(ch);
+ goto Next;
+ }
+ if(ch->gate && deccount(ch, cycles)){
+ ch->out = 0;
+ return;
+ }
+ break;
+
+ case OM5: /* Hardware Triggered Strobe */
+ ch->out = 1;
+ if(ch->gateraised){
+ ch->gateraised = 0;
+ setcount(ch);
+ goto Next;
+ }
+ if(deccount(ch, cycles)){
+ ch->out = 0;
+ return;
+ }
+ break;
+ }
+ *cycles = 0;
+}
+
+void
+clockpit(Pit *pit, vlong cycles)
+{
+ Pit *ch;
+ int i;
+
+ if(cycles <= 0)
+ return;
+ for(i = 0; i<Actl; i++){
+ ch = pit + i;
+ if(ch->wlatched){
+ vlong c;
+
+ switch(ch->omode){
+ case OM3:
+ case OM3b:
+ c = cycles * 2;
+ break;
+ default:
+ c = cycles;
+ }
+ while(c > 0)
+ clockpit1(ch, &c);
+ }
+ ch->gateraised = 0;
+ }
+}
+
+uchar
+rpit(Pit *pit, uchar addr)
+{
+ Pit *ch;
+ uchar data;
+
+ if(addr >= Actl)
+ return 0;
+ ch = pit + addr;
+ if(ch->rlatched){
+ data = ch->rlatch[ch->rcount & 1];
+ ch->rlatched--;
+ } else {
+ data = 0;
+ switch(ch->amode){
+ case AMloonly:
+ data = ch->count & 0xFF;
+ break;
+ case AMhionly:
+ data = (ch->count >> 8) & 0xFF;
+ break;
+ case AMlohi:
+ data = (ch->count >> ((ch->rcount & 1)<<3)) & 0xFF;
+ break;
+ }
+ }
+ ch->rcount++;
+ if(0) fprint(2, "rpit %p: %.2x %.2x\n", pit, (int)addr, (int)data);
+ return data;
+}
+
+void
+wpit(Pit *pit, uchar addr, uchar data)
+{
+ Pit *ch;
+
+ if(0) fprint(2, "wpit %p: %.2x %.2x\n", pit, (int)addr, (int)data);
+ if(addr > Actl)
+ return;
+ if(addr == Actl){
+ uchar sc, amode, omode, bcd;
+
+ bcd = (data & 1);
+ omode = (data >> 1) & 7;
+ amode = (data >> 4) & 3;
+ sc = (data >> 6) & 3;
+
+ if(sc == Readback){
+ ch = nil;
+ for(;;){
+ if(data & RBC0){
+ ch = pit;
+ break;
+ }
+ if(data & RBC1){
+ ch = pit + 1;
+ break;
+ }
+ if(data & RBC2){
+ ch = pit + 2;
+ break;
+ }
+ break;
+ }
+ if(ch == nil)
+ return;
+ if((data & RBlatchcount) == 0)
+ latchcount(ch);
+ if((data & RBlatchstatus) == 0)
+ latchstatus(ch);
+ return;
+ }
+
+ ch = pit + sc;
+ if(amode == AMlatchcount){
+ latchcount(ch);
+ return;
+ }
+ ch->bcd = bcd;
+
+ ch->amode = amode;
+ ch->omode = omode;
+
+ ch->rlatched = 0;
+ ch->rcount = 0;
+ ch->rlatch[0] = 0;
+ ch->rlatch[1] = 0;
+
+ ch->wlatched = 0;
+ ch->wcount = 0;
+ ch->wlatch[0] = 0;
+ ch->wlatch[1] = 0;
+
+ ch->count0 = 1;
+ ch->out = !!omode;
+ return;
+ }
+
+ ch = pit + addr;
+ switch(ch->amode){
+ case AMloonly:
+ case AMhionly:
+ ch->wlatch[ch->amode - AMloonly] = data;
+ ch->wcount++;
+ break;
+ case AMlohi:
+ ch->wlatch[ch->wcount++ & 1] = data;
+ if(ch->wcount < 2)
+ return;
+ break;
+ }
+ ch->wlatched = ch->wcount;
+ ch->wcount = 0;
+ ch->count0 = 1;
+}
--- /dev/null
+.TH realemu 8
+.SH NAME
+realemu \- software emulation of /dev/realmode
+.SH SYNOPSIS
+.B aux/realemu
+[
+.B -Dpt
+] [
+.B -s
+.I srvname
+] [
+.B -m
+.I mountpoint
+]
+.SH DESCRIPTION
+.PP
+Originally, kernel provided
+.B /dev/realmode
+files with the
+.IR arch (3)
+device to access and call the
+.SM BIOS.
+.PP
+Interrupts had to be disabled and the processor was switched in the
+legacy 16-bit
+.SM realmode
+with memory protection disabled to execute
+.SM BIOS
+code.
+.PP
+This is problematic in case the
+.SM BIOS
+reprograms hardware currently
+used by the operating system or when it reenables interrupts or just
+crashes. This will freeze or reboot the machine with no way to
+recover or diagnose the problem.
+.PP
+To avoid this,
+.I realemu
+is used to emulate the execution of the
+.SM BIOS
+routines by interpreting the machine instructions and intercepting
+dangerous actions that would compromise the systems stability.
+.PP
+Running
+.I realemu
+with no arguments, it mounts itself before
+.B /dev
+and
+replaces the original
+.B /dev/realmode
+file in the current namespace.
+.PP
+Then programs like
+.IR vga (8)
+can use it to make ther
+.SM BIOS
+calls.
+.PP
+The
+.B D
+flag will enable debug messages for 9P. The
+.B p
+and
+.B t
+flags
+control tracing of i/o port access and cpu instructions to
+stderr (fd 2).
+.PP
+When a
+.I srvname
+is given with the
+.B s
+argument, the default
+.I mountpoint
+is ignored and a
+.SM 9P
+channel is created in
+.B /srv
+that can be used to mount
+the filesystem from another namespace. If a
+.I mountpoint
+is given before
+the
+.I srvname
+argument then it is ignored, otherwise it will be used.
+.SH EXAMPLES
+The
+.I realemu
+process is only needed when accessing
+.B /dev/realmode.
+To invoke a subshell so that
+.I realemu
+exits normally after
+.B aux/vga
+completes:
+.IP
+.EX
+% @{rfork n; aux/realemu; aux/vga -m vesa -l $vgasize}
+.SH SOURCE
+.B /sys/src/cmd/aux/realemu
+.SH "SEE ALSO"
+.IR vga (8),
+.IR arch (3)
--- /dev/null
+#vid did bios wired product name
+100b 0030 5.30 STI NSC Geode GX2
+5533 8c2e 1.0 - T23 / S3 savage
+1002 791e 01.00 - ATI RS690
+10de 002c B1 STI NVidia RivaTNT
+15ad 0405 2.0 - VMware
+- - 1.26 - Bochs
+102b 0519 00 STI Matrox MILLENNIUM
+5333 8901 Rev E - S3 Trio64V2/DX/GX
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+#define sign(s) (1UL<<((s)-1))
+#define mask(s) (sign(s)|(sign(s)-1))
+
+int cputrace;
+
+static void
+push(Iarg *sp, Iarg *a)
+{
+ Iarg *p;
+
+ p = amem(sp->cpu, a->len, RSS, ar(sp));
+ p->off -= a->len;
+ aw(p, ar(a));
+ aw(sp, p->off);
+}
+
+static void
+pop(Iarg *sp, Iarg *a)
+{
+ Iarg *p;
+
+ p = amem(sp->cpu, a->len, RSS, ar(sp));
+ aw(a, ar(p));
+ aw(sp, p->off + a->len);
+}
+
+static void
+jump(Iarg *to)
+{
+ Cpu *cpu;
+
+ cpu = to->cpu;
+ switch(to->atype){
+ default:
+ abort();
+ case AMp:
+ to = afar(to, 1, to->len);
+ case AAp:
+ cpu->reg[RCS] = to->seg;
+ case AJb:
+ case AJv:
+ cpu->reg[RIP] = to->off;
+ break;
+ case AEv:
+ cpu->reg[RIP] = ar(to);
+ break;
+ }
+}
+
+static void
+opcall(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ switch(i->a1->atype){
+ default:
+ abort();
+ case AAp:
+ case AMp:
+ push(sp, areg(cpu, i->olen, RCS));
+ case AJv:
+ case AEv:
+ push(sp, areg(cpu, i->olen, RIP));
+ break;
+ }
+ jump(i->a1);
+}
+
+static void
+opint(Cpu *cpu, Inst *i)
+{
+ cpu->trap = ar(i->a1);
+ longjmp(cpu->jmp, 1);
+}
+
+static void
+opiret(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ if(i->olen != 2)
+ trap(cpu, EBADOP);
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, 2, RIP));
+ pop(sp, areg(cpu, 2, RCS));
+ pop(sp, areg(cpu, 2, RFL));
+}
+
+static void
+opret(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+ ulong c;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, i->olen, RIP));
+ if(c = ar(i->a1))
+ aw(sp, ar(sp) + c);
+}
+
+static void
+opretf(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+ ulong c;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, i->olen, RIP));
+ pop(sp, areg(cpu, i->olen, RCS));
+ if(c = ar(i->a1))
+ aw(sp, ar(sp) + c);
+}
+
+static void
+openter(Cpu *cpu, Inst *i)
+{
+ Iarg *sp, *bp;
+ ulong oframe, nframe;
+ int j, n;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ bp = areg(cpu, cpu->slen, RBP);
+ push(sp, bp);
+ oframe = ar(bp);
+ nframe = ar(sp);
+ n = ar(i->a2) % 32;
+ if(n > 0){
+ for(j=1; j<n; j++){
+ aw(bp, oframe - i->olen*j);
+ push(sp, bp);
+ }
+ push(sp, acon(cpu, i->olen, nframe));
+ }
+ aw(bp, nframe);
+ aw(sp, nframe - ar(i->a1));
+}
+
+static void
+opleave(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ aw(sp, ar(areg(cpu, cpu->slen, RBP)));
+ pop(sp, areg(cpu, i->olen, RBP));
+}
+
+static void
+oppush(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ if(i->a1->len == 1) /* 0x6A push imm8 */
+ push(sp, acon(cpu, i->olen, ar(i->a1)));
+ else
+ push(sp, i->a1);
+}
+
+static void
+oppop(Cpu *cpu, Inst *i)
+{
+ pop(areg(cpu, cpu->slen, RSP), i->a1);
+}
+
+static void
+oppusha(Cpu *cpu, Inst *i)
+{
+ Iarg *sp, *osp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ osp = acon(cpu, i->olen, ar(sp));
+ push(sp, areg(cpu, i->olen, RAX));
+ push(sp, areg(cpu, i->olen, RCX));
+ push(sp, areg(cpu, i->olen, RDX));
+ push(sp, areg(cpu, i->olen, RBX));
+ push(sp, osp);
+ push(sp, areg(cpu, i->olen, RBP));
+ push(sp, areg(cpu, i->olen, RSI));
+ push(sp, areg(cpu, i->olen, RDI));
+}
+
+static void
+oppopa(Cpu *cpu, Inst *i)
+{
+ Iarg *sp;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ pop(sp, areg(cpu, i->olen, RDI));
+ pop(sp, areg(cpu, i->olen, RSI));
+ pop(sp, areg(cpu, i->olen, RBP));
+ pop(sp, areg(cpu, i->olen, RBX)); // RSP
+ pop(sp, areg(cpu, i->olen, RBX));
+ pop(sp, areg(cpu, i->olen, RDX));
+ pop(sp, areg(cpu, i->olen, RCX));
+ pop(sp, areg(cpu, i->olen, RAX));
+}
+
+static void
+oppushf(Cpu *cpu, Inst *i)
+{
+ push(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
+}
+
+static void
+oppopf(Cpu *cpu, Inst *i)
+{
+ ulong *f, o;
+
+ f = cpu->reg + RFL;
+ o = *f;
+ pop(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
+ *f &= ~(VM|RF);
+ *f |= (o & (VM|RF));
+}
+
+static void
+oplahf(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, cpu->reg[RFL]);
+}
+
+static void
+opsahf(Cpu *cpu, Inst *i)
+{
+ enum { MASK = SF|ZF|AF|PF|CF };
+ ulong *f;
+
+ f = cpu->reg + RFL;
+ *f &= ~MASK;
+ *f |= (ar(i->a1) & MASK);
+}
+
+static void
+opcli(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] &= ~IF;
+}
+
+static void
+opsti(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] |= IF;
+}
+
+static void
+opcld(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] &= ~DF;
+}
+
+static void
+opstd(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] |= DF;
+}
+
+static void
+opclc(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] &= ~CF;
+}
+
+static void
+opstc(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] |= CF;
+}
+
+static void
+opcmc(Cpu *cpu, Inst *)
+{
+ cpu->reg[RFL] ^= CF;
+}
+
+static void
+parity(ulong *f, ulong r)
+{
+ static ulong tab[8] = {
+ 0x96696996,
+ 0x69969669,
+ 0x69969669,
+ 0x96696996,
+ 0x69969669,
+ 0x96696996,
+ 0x96696996,
+ 0x69969669,
+ };
+ r &= 0xFF;
+ if((tab[r/32] >> (r%32)) & 1)
+ *f &= ~PF;
+ else
+ *f |= PF;
+}
+
+static ulong
+test(ulong *f, long r, int s)
+{
+ *f &= ~(CF|SF|ZF|OF|PF);
+ r &= mask(s);
+ if(r == 0)
+ *f |= ZF;
+ if(r & sign(s))
+ *f |= SF;
+ parity(f, r);
+ return r;
+}
+
+static void
+opshl(Cpu *cpu, Inst *i)
+{
+ ulong *f, r, a, h;
+ int s, n;
+
+ if((n = ar(i->a2) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ r = test(f, a<<n, s);
+ h = sign(s);
+ aw(i->a1, r);
+ if((a<<(n-1)) & h)
+ *f |= CF;
+ if(n == 1 && ((a^r) & h))
+ *f |= OF;
+}
+
+static void
+opshr(Cpu *cpu, Inst *i)
+{
+ ulong *f, a;
+ int s, n;
+
+ if((n = ar(i->a2) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, a>>n, s));
+ if(a & sign(n))
+ *f |= CF;
+ if(n == 1 && (a & sign(s)))
+ *f |= OF;
+}
+
+static void
+opsar(Cpu *cpu, Inst *i)
+{
+ ulong *f;
+ long a;
+ int n;
+
+ if((n = ar(i->a2) & 31) == 0)
+ return;
+ a = ars(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, a>>n, i->a1->len*8));
+ if(a & sign(n))
+ *f |= CF;
+}
+
+static void
+opshld(Cpu *cpu, Inst *i)
+{
+ ulong *f, a;
+ int s, n;
+
+ if((n = ar(i->a3) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, (a<<n)|(ar(i->a2)>>(s-n)), s));
+ if((a<<(n-1)) & sign(s))
+ *f |= CF;
+}
+
+static void
+opshrd(Cpu *cpu, Inst *i)
+{
+ ulong *f, a;
+ int s, n;
+
+ if((n = ar(i->a3) & 31) == 0)
+ return;
+ s = i->a1->len*8;
+ a = ar(i->a1);
+ f = cpu->reg + RFL;
+ aw(i->a1, test(f, (a>>n)|(ar(i->a2)<<(s-n)), s));
+ if(a & sign(n))
+ *f |= CF;
+}
+
+
+static void
+oprcl(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) % (s+1);
+ a = ar(i->a1);
+ r = (a<<n) | ((a>>(s-n))>>1);
+ f = cpu->reg + RFL;
+ if(*f & CF)
+ r |= sign(n);
+ aw(i->a1, r);
+ *f &= ~(CF|OF);
+ if((a>>(s-n)) & 1)
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+oprcr(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r, h;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) % (s+1);
+ a = ar(i->a1);
+ h = a<<(s-n);
+ r = (a>>n) | (h<<1);
+ f = cpu->reg + RFL;
+ if(*f & CF)
+ r |= 1<<(s-n);
+ aw(i->a1, r);
+ *f &= ~(CF|OF);
+ if(h & sign(s))
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+oprol(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) & (s-1);
+ a = ar(i->a1);
+ r = (a<<n) | (a>>(s-n));
+ f = cpu->reg + RFL;
+ aw(i->a1, r);
+ *f &= ~(CF|OF);
+ if(r & 1)
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+opror(Cpu *cpu, Inst *i)
+{
+ ulong *f, a, r;
+ int s, n;
+
+ s = i->a1->len*8;
+ n = ar(i->a2) & (s-1);
+ a = ar(i->a1);
+ r = (a>>n) | (a<<(s-n));
+ aw(i->a1, r);
+ f = cpu->reg + RFL;
+ *f &= ~(CF|OF);
+ if(r & sign(s))
+ *f |= CF;
+ if((a ^ r) & sign(s))
+ *f |= OF;
+ parity(f, r);
+}
+
+static void
+opbts(Cpu *cpu, Inst *i)
+{
+ ulong a, m;
+ int n;
+
+ a = ar(i->a1);
+ n = ar(i->a2) & 31;
+ m = 1<<n;
+ if(a & m)
+ cpu->reg[RFL] |= CF;
+ else {
+ cpu->reg[RFL] &= ~CF;
+ aw(i->a1, a | m);
+ }
+}
+
+static void
+opbtr(Cpu *cpu, Inst *i)
+{
+ ulong a, m;
+ int n;
+
+ a = ar(i->a1);
+ n = ar(i->a2) & 31;
+ m = 1<<n;
+ if(a & m){
+ cpu->reg[RFL] |= CF;
+ aw(i->a1, a & ~m);
+ } else
+ cpu->reg[RFL] &= ~CF;
+}
+
+static void
+opbitscan(Cpu *cpu, Inst *i)
+{
+ ulong a;
+
+ if((a = ar(i->a2)) == 0)
+ cpu->reg[RFL] |= ZF;
+ else {
+ int j;
+
+ if(i->op == OBSF){
+ for(j = 0; (a & (1<<j)) == 0; j++)
+ ;
+ } else {
+ for(j = i->a2->len*8-1; (a & (1<<j)) == 0; j--)
+ ;
+ }
+ aw(i->a1, j);
+ cpu->reg[RFL] &= ~ZF;
+ }
+}
+
+static void
+opand(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8));
+}
+
+static void
+opor(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, test(cpu->reg + RFL, ars(i->a1) | ars(i->a2), i->a1->len*8));
+}
+
+static void
+opxor(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, test(cpu->reg + RFL, ars(i->a1) ^ ars(i->a2), i->a1->len*8));
+}
+
+static void
+opnot(Cpu *, Inst *i)
+{
+ aw(i->a1, ~ar(i->a1));
+}
+
+static void
+optest(Cpu *cpu, Inst *i)
+{
+ test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8);
+}
+
+static ulong
+add(ulong *f, long a, long b, int c, int s)
+{
+ ulong r, cc, m, n;
+
+ *f &= ~(AF|CF|SF|ZF|OF|PF);
+
+ n = sign(s);
+ m = mask(s);
+ r = a + b + c;
+ r &= m;
+ if(r == 0)
+ *f |= ZF;
+ if(r & n)
+ *f |= SF;
+ cc = (a & b) | (~r & (a | b));
+ if(cc & n)
+ *f |= CF;
+ if((cc ^ (cc >> 1)) & (n>>1))
+ *f |= OF;
+ parity(f, r);
+ return r;
+}
+
+static ulong
+sub(ulong *f, long a, long b, int c, int s)
+{
+ ulong r, bc, n;
+
+ *f &= ~(AF|CF|SF|ZF|OF|PF);
+
+ r = a - b - c;
+ n = sign(s);
+ r &= mask(s);
+ if(r == 0)
+ *f |= ZF;
+ if(r & n)
+ *f |= SF;
+ a = ~a;
+ bc = (a & b) | (r & (a | b));
+ if(bc & n)
+ *f |= CF;
+ if((bc ^ (bc >> 1)) & (n>>1))
+ *f |= OF;
+ parity(f, r);
+ return r;
+}
+
+static void
+opadd(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, add(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
+}
+
+static void
+opadc(Cpu *cpu, Inst *i)
+{
+ ulong *f = cpu->reg + RFL;
+
+ aw(i->a1, add(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
+}
+
+static void
+opsub(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
+}
+
+static void
+opsbb(Cpu *cpu, Inst *i)
+{
+ ulong *f = cpu->reg + RFL;
+
+ aw(i->a1, sub(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
+}
+
+static void
+opneg(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, sub(cpu->reg + RFL, 0, ars(i->a1), 0, i->a1->len*8));
+}
+
+static void
+opcmp(Cpu *cpu, Inst *i)
+{
+ sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8);
+}
+
+static void
+opinc(Cpu *cpu, Inst *i)
+{
+ ulong *f, o;
+
+ f = cpu->reg + RFL;
+ o = *f;
+ aw(i->a1, add(f, ars(i->a1), 1, 0, i->a1->len*8));
+ *f = (*f & ~CF) | (o & CF);
+}
+
+static void
+opdec(Cpu *cpu, Inst *i)
+{
+ ulong *f, o;
+
+ f = cpu->reg + RFL;
+ o = *f;
+ aw(i->a1, sub(f, ars(i->a1), 1, 0, i->a1->len*8));
+ *f = (*f & ~CF) | (o & CF);
+}
+
+static void
+opmul(Cpu *cpu, Inst *i)
+{
+ Iarg *la, *ha;
+ ulong l, h, m;
+ uvlong r;
+ int s;
+
+ s = i->a2->len*8;
+ m = mask(s);
+ r = ar(i->a2) * ar(i->a3);
+ l = r & m;
+ h = (r >> s) & m;
+ if(i->a1->atype != AAX)
+ abort();
+ la = areg(cpu, i->a2->len, RAX);
+ if(s == 8){
+ ha = adup(la);
+ ha->tag |= TH;
+ } else
+ ha = areg(cpu, i->a2->len, RDX);
+ aw(la, l);
+ aw(ha, h);
+ if(h)
+ cpu->reg[RFL] |= (CF|OF);
+ else
+ cpu->reg[RFL] &= ~(CF|OF);
+}
+
+static void
+opimul(Cpu *cpu, Inst *i)
+{
+ ulong l, h, m, n;
+ vlong r;
+ int s;
+
+ s = i->a2->len*8;
+ m = mask(s);
+ n = sign(s);
+ r = ars(i->a2) * ars(i->a3);
+ h = (r >> s) & m;
+ l = r & m;
+ if(i->a1->atype == AAX){
+ Iarg *la, *ha;
+
+ la = areg(cpu, i->a2->len, RAX);
+ if(s == 8){
+ ha = adup(la);
+ ha->tag |= TH;
+ }else
+ ha = areg(cpu, i->a2->len, RDX);
+ aw(la, l);
+ aw(ha, h);
+ } else
+ aw(i->a1, l);
+ if((r > (vlong)n-1) || (r < -(vlong)n))
+ cpu->reg[RFL] |= (CF|OF);
+ else
+ cpu->reg[RFL] &= ~(CF|OF);
+}
+
+static void
+opdiv(Cpu *cpu, Inst *i)
+{
+ Iarg *qa, *ra;
+ uvlong n, q;
+ ulong m, r, d;
+ int s;
+
+ s = i->a1->len*8;
+ m = mask(s);
+ d = ar(i->a1);
+ if(d == 0)
+ trap(cpu, EDIV0);
+ if(s == 8){
+ qa = areg(cpu, 1, RAX);
+ ra = adup(qa);
+ ra->tag |= TH;
+ } else {
+ qa = areg(cpu, i->olen, RAX);
+ ra = areg(cpu, i->olen, RDX);
+ }
+ n = (uvlong)ar(ra)<<s | (uvlong)ar(qa);
+ q = n/d;
+ if(q > m)
+ trap(cpu, EGPF);
+ r = n%d;
+ aw(ra, r);
+ aw(qa, q);
+}
+
+
+static int
+cctrue(Cpu *cpu, Inst *i)
+{
+ enum { SO = 1<<16, /* pseudo-flag SF != OF */ };
+ static ulong test[] = {
+ OF, /* JO, JNO */
+ CF, /* JC, JNC */
+ ZF, /* JZ, JNZ */
+ CF|ZF, /* JBE,JA */
+ SF, /* JS, JNS */
+ PF, /* JP, JNP */
+ SO, /* JL, JGE */
+ SO|ZF, /* JLE,JG */
+ };
+ ulong f, t;
+ uchar c;
+
+ c = i->code;
+ switch(c){
+ case 0xE3: /* JCXZ */
+ return ar(areg(cpu, i->alen, RCX)) == 0;
+ case 0xEB: /* JMP */
+ case 0xE9:
+ case 0xEA:
+ case 0xFF:
+ return 1;
+ default:
+ f = cpu->reg[RFL];
+ if(((f&SF)!=0) ^ ((f&OF)!=0))
+ f |= SO;
+ t = test[(c>>1)&7];
+ return ((t&f) != 0) ^ (c&1);
+ }
+}
+
+static void
+opjump(Cpu *cpu, Inst *i)
+{
+ if(cctrue(cpu, i))
+ jump(i->a1);
+}
+
+static void
+oploop(Cpu *cpu, Inst *i)
+{
+ Iarg *cx;
+ ulong c;
+
+ switch(i->op){
+ default:
+ abort();
+ case OLOOPNZ:
+ if(cpu->reg[RFL] & ZF)
+ return;
+ break;
+ case OLOOPZ:
+ if((cpu->reg[RFL] & ZF) == 0)
+ return;
+ break;
+ case OLOOP:
+ break;
+ }
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx) - 1;
+ aw(cx, c);
+ if(c)
+ jump(i->a1);
+}
+
+static void
+oplea(Cpu *, Inst *i)
+{
+ aw(i->a1, i->a2->off);
+}
+
+static void
+opmov(Cpu *, Inst *i)
+{
+ aw(i->a1, ar(i->a2));
+}
+
+static void
+opcbw(Cpu *cpu, Inst *i)
+{
+ aw(areg(cpu, i->olen, RAX), ars(areg(cpu, i->olen>>1, RAX)));
+}
+
+static void
+opcwd(Cpu *cpu, Inst *i)
+{
+ aw(areg(cpu, i->olen, RDX), ars(areg(cpu, i->olen, RAX))>>(i->olen*8-1));
+}
+
+static void
+opmovsx(Cpu *, Inst *i)
+{
+ aw(i->a1, ars(i->a2));
+}
+
+static void
+opxchg(Cpu *, Inst *i)
+{
+ ulong x;
+
+ x = ar(i->a1);
+ aw(i->a1, ar(i->a2));
+ aw(i->a2, x);
+}
+
+static void
+oplfp(Cpu *, Inst *i)
+{
+ Iarg *p;
+
+ p = afar(i->a3, i->olen, i->olen);
+ aw(i->a1, p->seg);
+ aw(i->a2, p->off);
+}
+
+static void
+opbound(Cpu *cpu, Inst *i)
+{
+ ulong p, s, e;
+
+ p = ar(i->a1);
+ s = ar(i->a2);
+ e = ar(i->a3);
+ if((p < s) || (p >= e))
+ trap(cpu, EBOUND);
+}
+
+static void
+opxlat(Cpu *cpu, Inst *i)
+{
+ aw(i->a1, ar(amem(cpu, i->a1->len, i->sreg, ar(areg(cpu, i->alen, i->a2->reg)) + ar(i->a1))));
+}
+
+static void
+opcpuid(Cpu *cpu, Inst *)
+{
+ static struct {
+ ulong level;
+
+ ulong ax;
+ ulong bx;
+ ulong cx;
+ ulong dx;
+ } tab[] = {
+ 0,
+ 5,
+ 0x756e6547,
+ 0x49656e69,
+ 0x6c65746e,
+ 1,
+ 4<<8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 2,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 3,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ };
+
+ int i;
+
+ for(i=0; i<nelem(tab); i++){
+ if(tab[i].level == cpu->reg[RAX]){
+ cpu->reg[RAX] = tab[i].ax;
+ cpu->reg[RBX] = tab[i].bx;
+ cpu->reg[RCX] = tab[i].cx;
+ cpu->reg[RDX] = tab[i].dx;
+ return;
+ }
+ }
+ trap(cpu, EBADOP);
+}
+
+static void
+opmovs(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *d, *s;
+ ulong c;
+ int n;
+
+ d = adup(i->a1);
+ s = adup(i->a2);
+ n = s->len;
+ if(cpu->reg[RFL] & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ while(c){
+ aw(d, ar(s));
+ d->off += n;
+ s->off += n;
+ c--;
+ }
+ aw(areg(cpu, i->alen, RDI), d->off);
+ aw(areg(cpu, i->alen, RSI), s->off);
+ if(cx)
+ aw(cx, 0);
+}
+
+static void
+oplods(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *s;
+ ulong c;
+ int n;
+
+ s = adup(i->a2);
+ n = s->len;
+ if(cpu->reg[RFL] & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ if(c){
+ s->off += n*(c-1);
+ aw(i->a1, ar(s));
+ s->off += n;
+ }
+ aw(areg(cpu, i->alen, RSI), s->off);
+ if(cx)
+ aw(cx, 0);
+}
+
+static void
+opstos(Cpu *cpu, Inst *i)
+{
+ Iarg *cx, *d;
+ ulong c, a;
+ int n;
+
+ d = adup(i->a1);
+ n = d->len;
+ if(cpu->reg[RFL] & DF)
+ n = -n;
+ if(i->rep){
+ cx = areg(cpu, i->alen, RCX);
+ c = ar(cx);
+ } else {
+ cx = nil;
+ c = 1;
+ }
+ a = ar(i->a2);
+ while(c){
+ aw(d, a);
+ d->off += n;
+ c--;
+ }
+ aw(areg(cpu, i->alen, RDI), d->off);
+ if(cx)
+ aw(cx, 0);
+}
+
+static void
+opin(Cpu *cpu, Inst *i)
+{
+ Bus *io;
+
+ io = cpu->port;
+ aw(i->a1, io->r(io->aux, ar(i->a2) & 0xFFFF, i->a1->len));
+}
+
+static void
+opout(Cpu *cpu, Inst *i)
+{
+ Bus *io;
+
+ io = cpu->port;
+ io->w(io->aux, ar(i->a1) & 0xFFFF, ar(i->a2), i->a2->len);
+}
+
+static void
+opnop(Cpu *, Inst *)
+{
+}
+
+static void
+ophlt(Cpu *cpu, Inst *)
+{
+ trap(cpu, EHALT);
+}
+
+static void (*exctab[NUMOP])(Cpu *cpu, Inst*) = {
+ [OINT] = opint,
+ [OIRET] = opiret,
+
+ [OCALL] = opcall,
+ [OJUMP] = opjump,
+
+ [OLOOP] = oploop,
+ [OLOOPZ] = oploop,
+ [OLOOPNZ] = oploop,
+
+ [ORET] = opret,
+ [ORETF] = opretf,
+
+ [OENTER] = openter,
+ [OLEAVE] = opleave,
+
+ [OPUSH] = oppush,
+ [OPOP] = oppop,
+
+ [OPUSHF] = oppushf,
+ [OPOPF] = oppopf,
+ [OLAHF] = oplahf,
+ [OSAHF] = opsahf,
+
+ [OPUSHA] = oppusha,
+ [OPOPA] = oppopa,
+
+ [OCLI] = opcli,
+ [OSTI] = opsti,
+ [OCLC] = opclc,
+ [OSTC] = opstc,
+ [OCMC] = opcmc,
+ [OCLD] = opcld,
+ [OSTD] = opstd,
+
+ [OSHL] = opshl,
+ [OSHR] = opshr,
+ [OSAR] = opsar,
+
+ [OSHLD] = opshld,
+ [OSHRD] = opshrd,
+
+ [ORCL] = oprcl,
+ [ORCR] = oprcr,
+ [OROL] = oprol,
+ [OROR] = opror,
+
+ [OBTS] = opbts,
+ [OBTR] = opbtr,
+ [OBSF] = opbitscan,
+ [OBSR] = opbitscan,
+
+ [OAND] = opand,
+ [OOR] = opor,
+ [OXOR] = opxor,
+ [ONOT] = opnot,
+ [OTEST] = optest,
+
+ [OADD] = opadd,
+ [OADC] = opadc,
+ [OSUB] = opsub,
+ [OSBB] = opsbb,
+ [ONEG] = opneg,
+ [OCMP] = opcmp,
+
+ [OINC] = opinc,
+ [ODEC] = opdec,
+
+ [OMUL] = opmul,
+ [OIMUL] = opimul,
+ [ODIV] = opdiv,
+
+ [OLEA] = oplea,
+ [OMOV] = opmov,
+ [OCBW] = opcbw,
+ [OCWD] = opcwd,
+ [OMOVZX] = opmov,
+ [OMOVSX] = opmovsx,
+ [OXCHG] = opxchg,
+ [OLFP] = oplfp,
+ [OBOUND] = opbound,
+ [OXLAT] = opxlat,
+
+ [OCPUID] = opcpuid,
+
+ [OMOVS] = opmovs,
+ [OSTOS] = opstos,
+ [OLODS] = oplods,
+
+ [OIN] = opin,
+ [OOUT] = opout,
+
+ [ONOP] = opnop,
+ [OHLT] = ophlt,
+};
+
+void
+trap(Cpu *cpu, int e)
+{
+ cpu->reg[RIP] = cpu->oldip;
+ cpu->trap = e;
+ longjmp(cpu->jmp, 1);
+}
+
+int
+intr(Cpu *cpu, int v)
+{
+ Iarg *sp, *ip, *cs, *iv;
+
+ if(v < 0 || v > 0xff || cpu->olen != 2)
+ return -1;
+
+ sp = areg(cpu, cpu->slen, RSP);
+ cs = areg(cpu, 2, RCS);
+ ip = areg(cpu, 2, RIP);
+
+ iv = amem(cpu, 2, R0S, v * 4);
+
+ push(sp, areg(cpu, 2, RFL));
+ push(sp, cs);
+ push(sp, ip);
+
+ cpu->reg[RIP] = ar(iv);
+ iv->off += 2;
+ cpu->reg[RCS] = ar(iv);
+ return 0;
+}
+
+int
+xec(Cpu *cpu, int n)
+{
+ if(setjmp(cpu->jmp))
+ return cpu->trap;
+ while(n--){
+ void (*f)(Cpu *, Inst *);
+ Iarg *ip;
+ Inst i;
+
+ cpu->ic++;
+
+ ip = amem(cpu, 1, RCS, cpu->oldip = cpu->reg[RIP]);
+ decode(ip, &i);
+ cpu->reg[RIP] = ip->off;
+ if((f = exctab[i.op]) == nil)
+ trap(cpu, EBADOP);
+ f(cpu, &i);
+ }
+ return n;
+}
--- /dev/null
+#!/bin/rc
+
+rfork e
+flags=()
+while(! ~ $#* 0 && ~ $1 -*){
+ if(~ $1 -c -s){
+ flags=($flags $1)
+ shift
+ }
+ flags=($flags $1)
+ shift
+}
+if(test -f /srv/kfs.cmd)
+ disk/kfscmd allow
+replica/pull -v $flags /dist/replica/network $*
+if(test -f /srv/kfs.cmd)
+ disk/kfscmd disallow
--- /dev/null
+#!/bin/rc
+
+scr=(`{cat /dev/draw/new >[2]/dev/null || status=''})
+wid=$scr(11)
+ht=$scr(12)
+
+window 0,0,161,117 stats -lmisce
+window 161,0,560,117 faces -i
+
+if(~ `{screensize} small)
+ dump=acme.dump.small
+if not
+ dump=acme.dump
+
+a=`{echo $wid-35 | hoc }
+window 60,90,$a,$ht acme -l lib/$dump
+window 20,140,610,450 /usr/glenda/lib/first.window
--- /dev/null
+#!/bin/rc
+
+scr=(`{cat /dev/draw/new >[2]/dev/null || status=''})
+wid=$scr(11)
+ht=$scr(12)
+if(test $wid -le 1024)
+ echo small
+if not
+ echo normal
--- /dev/null
+/usr/glenda
+/lib/font/bit/lucidasans/unicode.8.font
+/lib/font/bit/lucm/unicode.9.font
+ 0 20 75
+f 0 24 0 0 1
+ 24 34 16 1 0 /usr/glenda/ Del Snarf Get | Look
+f 1 25 567 567 1
+ 25 34 567 0 0 readme.acme Del Snarf Undo | Look
+e 2 0 0 0 1
+ 23 49 52 0 0 /mail/fs/mbox/ Del Snarf | Look Put Mail Delmesg
+/acme/mail
+Mail mbox
--- /dev/null
+/usr/glenda
+/lib/font/bit/lucidasans/unicode.7.font
+/lib/font/bit/lucidasans/typelatin1.7.font
+ 0 20 75
+f 0 24 0 0 1
+ 24 34 16 1 0 /usr/glenda/ Del Snarf Get | Look
+e 0 0 0 0 8
+ 28 51 6 0 1 /usr/glenda/-serzone Del Snarf | Look Send Noscroll
+/usr/glenda
+win
+f 1 25 567 567 1
+ 25 34 567 0 0 readme.acme Del Snarf Undo | Look
+e 2 0 0 0 1
+ 23 49 52 0 0 /mail/fs/mbox/ Del Snarf | Look Put Mail Delmesg
+/acme/mail
+Mail mbox
--- /dev/null
+#!/bin/rc
+echo -n readme > /dev/label
+cat readme.rio
+exec rc -i
+
--- /dev/null
+# to update: cp /usr/glenda/lib/plumbing /mnt/plumb/rules
+
+editor = acme
+
+include basic
+
--- /dev/null
+bind -a $home/bin/rc /bin
+bind -a $home/bin/$cputype /bin
+bind -c tmp /tmp
+if(! syscall create /tmp/xxx 1 0666 >[2]/dev/null)
+ ramfs # in case we're running off a cd
+font = /lib/font/bit/pelm/euro.9.font
+upas/fs
+fn cd { builtin cd $* && awd } # for acme
+switch($service){
+case terminal
+ plumber
+ echo -n accelerated > '#m/mousectl'
+ echo -n 'res 3' > '#m/mousectl'
+ prompt=('term% ' ' ')
+ fn term%{ $* }
+ exec rio -i riostart
+case cpu
+ if (test -e /mnt/term/mnt/wsys) { # rio already running
+ bind -a /mnt/term/mnt/wsys /dev
+ if(test -w /dev/label)
+ echo -n $sysname > /dev/label
+ }
+ bind /mnt/term/dev/cons /dev/cons
+ bind /mnt/term/dev/consctl /dev/consctl
+ bind -a /mnt/term/dev /dev
+ prompt=('cpu% ' ' ')
+ fn cpu%{ $* }
+ news
+ if (! test -e /mnt/term/mnt/wsys) { # cpu call from drawterm
+ font=/lib/font/bit/pelm/latin1.8.font
+ exec rio
+ }
+case con
+ prompt=('cpu% ' ' ')
+ news
+}
--- /dev/null
+Welcome to acme, the editor/shell/window system hybrid. Acme is a
+complete environment you can use to edit, run programs, browse the
+file system, etc.
+
+You can scroll the text this window by moving the mouse into
+the window (no clicking necessary) and typing the up and down
+arrows.
+
+When you start Acme, you see several windows layered into two
+columns. Above each window, you can see a ``tag line'' (in blue). The
+first thing to notice is that all the text you see is just that:
+text. You can edit anything at will.
+
+For example, in the left column is a directory window.
+If you look at the window's tag line, you will see that it contains
+
+ /usr/glenda/ Del Snarf Get | Look
+
+(This might be truncated if the column is narrow.)
+That is just text.
+
+Each mouse button (1, 2, 3, from left to right) does a different
+thing in Acme:
+
+ * Button 1 can be used to select text (press it, sweep, release it),
+ and also to select the point where text would be inserted in the
+ window. Use it now in your /usr/glenda window.
+ * Button 2 can be used to execute things. For example, use button 1
+ to type "ls -l" before "lib/" in the window showing
+ /usr/glenda. Now use button 2 to select "ls -l lib/" (press
+ it, select, release it). As you can see, button 2 means
+ "execute this".
+ * Button 3 can be used to get things. For example, click button 3 on
+ "lib/" within the "/usr/glenda" window. Can you see how a new window
+ shows the contents of "/usr/glenda/lib"? Button 3 can also be used
+ to search within the body of a window. Just click button 3 on the
+ thing you want to search. Again, you can select something with
+ button 1 and then use button 3 on the selection.
+
+You can double-click with button 1 to select words; a double click at
+the end or beginning of a line selects the whole line. Once you have
+text selected, you can click on it with button 2 to execute the
+selected text. A single click of button 2 would execute the word
+clicked as a command.
+
+Now let's pay attention to the tag line once more. As you can see,
+the left part has a path. That is the name for the window and shows
+also the directory for the thing shown (file/directory/program
+output). When you execute something using button 2, the current
+directory for the command is the directory shown in the left part of
+the tag (if the thing shown is a file, its directory is used).
+
+As you saw before in the example, there are windows labeled
+"/dir/+Errors", that is where Acme shows the output of a command
+executed in "/dir".
+
+Another thing you can see is that tag lines contain words like "New",
+"Del", "Snarf", etc. Those are commands understood (implemented) by
+Acme. When you request execution of one of them, Acme does the job.
+For example, click with button 2 on "Del" in the
+"/usr/glenda/+Errors" window: it's gone.
+
+The commands shown by Acme are just text and by no means special. Try
+to type "Del" within the body of the window "/usr/glenda", and then
+click (button-2) on it.
+
+These are some commands understood by Acme:
+ * Newcol: create a new column of windows
+ * Delcol: delete a column
+ * New: create a new window (edit it's tag to be a file name and you
+ would be creating a new file; you would need to click on "Put" to
+ put the file in the file system).
+ * Put: write the body to disk. The file is the one named in the tag.
+ * Get: refresh the body (e.g. if it's a directory, reread it and
+ show it).
+ * Snarf: What other window systems call "Copy".
+ * Paste: Can you guess it?
+ * Exit: exit acme
+
+Acme likes to place new windows itself. If you prefer to change the
+layout of a window, you only need to drag the layout box at the left
+of the tag line and drop it somewhere else. The point where you drop
+it selects the column where the window is to be placed now, as well
+as the line where the window should start. You can also click the
+layout box to enlarge its window a small amount (button 1), as much
+as possible without obscuring other tag lines in the column (button
+2), and to fill the whole column (button 3). You can get your other
+windows back by button-1- or button-2-clicking the layout box.
+
+This is mostly what you need to get started with Acme. You are
+missing a very useful feature: using combinations (chords) of mouse
+buttons to do things. You can cut, paste, snarf, and pass arguments
+to programs using these mouse chords. You can read this in the
+acme(1) manual page, but it's actually extremely simple: Select a
+region with button 1 but don't release the button. Now clicking
+button 2 deletes the selected text (putting it into the snarf
+buffer); clicking button 3 replaces the selected text with the snarf
+buffer. That's it!
+
+For more information, read /sys/doc/acme/acme.ps (you can just
+button-3 click on that string to view the file).
+
--- /dev/null
+Rio is the Plan 9 window system.
+
+To read more of this window, the up and down arrows
+scroll the text up and down half screens.
+
+To effectively use rio, you need at least a three
+button mouse. If you only have a two button mouse you
+can emulate the middle button by holding down shift key
+whilst pressing the right button.
+
+Button 1, 2, and 3 are used to refer to the left,
+middle, and right buttons respectively.
+
+THE POP-UP MENU
+
+Pressing and holding down button 3 on the desktop or
+shell window will give you a menu with the following
+options:
+
+ * New - create a new window
+ * Resize - reshape a window
+ * Move - move a window without reshaping it
+ * Delete - close a window
+ * Hide - hides a window from display (it will appear
+ in this menu)
+ * <label> - the label of a hidden window,
+ selecting it unhides it
+
+You select an item by releasing the button over the
+menu item. rio uses the same button that started an
+action throughout that operation. If you press another
+button during the action the operation is aborted and
+any intermediate changes are reversed.
+
+The menu acts as a action verb selector which then
+requires an object (i.e. window) to be picked to
+indicate which window the verb is to act on. A further
+mouse action may then be required.
+
+EXAMPLES
+
+After selecting New, the cursor will change into a
+cross. Using button 3 again, you should then drag out
+a rectangle to indicate the size and location of the
+new window. When you release the button a new window
+will be created.
+
+New windows will contain the rc shell. Invoking a rio
+program from the shell will allow that program to take
+over the window. As there is no job control in the
+shell (e.g. &, fg, bg), you just create another window
+if you want to run another program concurrently.
+
+To Resize a window, you select Resize, then click
+(remember using the same button that started the
+action, i.e. button 3) on the window you want to
+resize. The cursor will change to a cross-hair theat
+will allow you to drag out the desired shape of the
+window.
+
+After selecting Move, click and keep the button
+depressed over the window you want to move, then move
+the mouse to move the red rectangle that represents the
+new location you want. Release the button to finish
+the action.
+
+Delete and Hide both operate by requiring you to click
+on the window you wish to respectively Delete or Hide.
+
+WINDOW CONTROL TIPS
+
+Clicking on a window brings it to the front.
+
+You can directly change the shape of a window by
+clicking and dragging on the edge or corner of the
+window border. Button 1 or 2 will allow you to drag
+the edge or corner to a new size, and Button 3 will
+allow you to move the window.
+
+The pop-up menu remembers the last command chosen, so
+as a short cut you can just press and release button 3
+without moving the mouse between pressing and releasing
+to select the previous command again.
+
+BASIC TEXT CONTROL
+
+Unlike in other systems, the text cursor can only be
+controlled by the mouse or the side-effects of certain
+commands.
+
+Clicking with button 1 will move the text insertion
+point (indicated by an I-beam) to just before the
+character closest to the mouse pointer. Dragging
+across a section of text will select that portion of
+text. It may be useful to know that the insertion
+I-beam represents an empty selection (between two
+characters). In text editors, the current selection is
+known as "dot".
+
+In the shell window button 2 will invoke a pop-up menu.
+Most of it's commands operate on dot.
+
+ * cut - moves the contents of the dot to the clipboard
+ if dot is non-empty
+ * paste - replaces dot with the contents of the clipboard
+ * snarf - copies dot to the clipboard
+ * plumb - sends dot (or text surrounding dot, if dot is
+ empty)to the plumber.
+ * send - completes the current input line with the dot,
+ if it is non-empty, or the contents of the clipboard.
+ If the dot is non-empty it does a snarf at the same time.
+ * scroll - toggles the automatic scrolling of the window
+ on output.
+
+Double-clicking will allow you to automatically select
+a section of text surrounding that point. The
+selection is made by an analysis of appropriate
+delimeters. A whole line is selected by
+double-clicking at either end of the line. A quoted or
+bracketed selection is made by double-clicking just
+inside of the quote or bracket.
+
+SCROLLING
+
+The arrow keys will let you scroll up or down by half a
+page at a time.
+
+Clicking button 1 on the scrollbar scrolls up by half a
+page. Button 3 scrolls down by half a page. Button 2
+jumps to position in the document relative to the
+position on the scrollbar clicked. Holding a button on
+the scrollbar will have the effect of invoking the
+clicking action continuously.
+
+The white elevator box on the scrollbar is sized
+proportionally to the proportion of the document that
+is currently visible.
+
+Scrolling does not affect the text cursor.
+
+RIO AND THE RC SHELL WINDOW
+
+Rc is a command interpreter for Plan 9 that provides
+similar facilities to UNIX's Bourne shell. See the
+additional references at the end of this document for
+information specifically about rc.
+
+Rio provides some additional features that enhance the
+interface to programs that use the text console. The
+rc shell command interpreter is one such program.
+
+Rc commands are typed after the prompt on the last line
+of the text buffer. The commands are sent to rc only
+after each newline so line editing may be performed if
+desired. You can move the cursor and edit the previous
+lines of commands and program output but none of this
+will be interpreted by rc shell.
+
+The interpretation of commands is supressed altogether
+when ESC is pressed to put the window in hold mode.
+The window border and text will change to dark blue to
+indicate the hold mode is active. In this mode you can
+type multiple lines of commands and edit them.
+Pressing ESC again will release the hold and send the
+lines of text to the rc command interpreter.
+
+The DEL key sends an 'interrupt' note to all processes
+in the window's process group. The usual intent is to
+terminate the execution of the current command. It is
+also a convenient short cut for ensuring you have a
+fresh command prompt.
+
+FURTHER INFORMATION
+
+For further information, try the rio(1) manual page.
+Type "man rio" or click on rio(1) in either of these
+sentences and select plumb from the button 2 menu.
+