xref: /plan9/sys/src/cmd/aux/disksim.c (revision ec46fab06dcae3e636b775c4eaa679036316e1d8)
13ff48bf5SDavid du Colombier #include <u.h>
23ff48bf5SDavid du Colombier #include <libc.h>
33ff48bf5SDavid du Colombier #include <auth.h>
43ff48bf5SDavid du Colombier #include <fcall.h>
53ff48bf5SDavid du Colombier #include <thread.h>
63ff48bf5SDavid du Colombier #include <9p.h>
73ff48bf5SDavid du Colombier 
83ff48bf5SDavid du Colombier typedef struct Part Part;
93ff48bf5SDavid du Colombier typedef struct Trip Trip;
103ff48bf5SDavid du Colombier typedef struct Dbl Dbl;
113ff48bf5SDavid du Colombier typedef struct Ind Ind;
123ff48bf5SDavid du Colombier 
133ff48bf5SDavid du Colombier /*
143ff48bf5SDavid du Colombier  * with 8192-byte blocks and 4-byte pointers,
153ff48bf5SDavid du Colombier  * double-indirect gets us 34 GB.
163ff48bf5SDavid du Colombier  * triple-indirect gets us 70,368 GB.
173ff48bf5SDavid du Colombier  */
183ff48bf5SDavid du Colombier 
193ff48bf5SDavid du Colombier enum
203ff48bf5SDavid du Colombier {
213ff48bf5SDavid du Colombier 	LOGBLKSZ = 13,
223ff48bf5SDavid du Colombier 	BLKSZ = 1<<LOGBLKSZ,	/* 8192 */
233ff48bf5SDavid du Colombier 	LOGNPTR = LOGBLKSZ-2,	/* assume sizeof(void*) == 4 */
243ff48bf5SDavid du Colombier 	NPTR = 1<<LOGNPTR,
253ff48bf5SDavid du Colombier };
26*bbd061d4SDavid du Colombier static uchar zero[BLKSZ];
273ff48bf5SDavid du Colombier 
283ff48bf5SDavid du Colombier struct Trip
293ff48bf5SDavid du Colombier {
303ff48bf5SDavid du Colombier 	Dbl *dbl[NPTR];
313ff48bf5SDavid du Colombier };
323ff48bf5SDavid du Colombier 
333ff48bf5SDavid du Colombier struct Dbl
343ff48bf5SDavid du Colombier {
353ff48bf5SDavid du Colombier 	Ind *ind[NPTR];
363ff48bf5SDavid du Colombier };
373ff48bf5SDavid du Colombier 
383ff48bf5SDavid du Colombier struct Ind
393ff48bf5SDavid du Colombier {
403ff48bf5SDavid du Colombier 	uchar *blk[NPTR];
413ff48bf5SDavid du Colombier };
423ff48bf5SDavid du Colombier 
433ff48bf5SDavid du Colombier Trip trip;
443ff48bf5SDavid du Colombier 
453ff48bf5SDavid du Colombier struct Part
463ff48bf5SDavid du Colombier {
473ff48bf5SDavid du Colombier 	int inuse;
483ff48bf5SDavid du Colombier 	int vers;
493ff48bf5SDavid du Colombier 	ulong mode;
503ff48bf5SDavid du Colombier 	char *name;
513ff48bf5SDavid du Colombier 	vlong offset;	/* in sectors */
523ff48bf5SDavid du Colombier 	vlong length;	/* in sectors */
533ff48bf5SDavid du Colombier };
543ff48bf5SDavid du Colombier 
553ff48bf5SDavid du Colombier enum
563ff48bf5SDavid du Colombier {
573ff48bf5SDavid du Colombier 	Qroot = 0,
583ff48bf5SDavid du Colombier 	Qdir,
593ff48bf5SDavid du Colombier 	Qctl,
603ff48bf5SDavid du Colombier 	Qpart,
613ff48bf5SDavid du Colombier };
623ff48bf5SDavid du Colombier 
633ff48bf5SDavid du Colombier Part tab[64];
6411e1fb05SDavid du Colombier int fd = -1;
653ff48bf5SDavid du Colombier char *sdname = "sdXX";
663ff48bf5SDavid du Colombier ulong ctlmode = 0666;
673ff48bf5SDavid du Colombier char *inquiry = "aux/disksim hard drive";
683ff48bf5SDavid du Colombier vlong nsect, sectsize, c, h, s;
693ff48bf5SDavid du Colombier ulong time0;
7011e1fb05SDavid du Colombier int rdonly;
713ff48bf5SDavid du Colombier 
723ff48bf5SDavid du Colombier char*
ctlstring(void)733ff48bf5SDavid du Colombier ctlstring(void)
743ff48bf5SDavid du Colombier {
753ff48bf5SDavid du Colombier 	int i;
763ff48bf5SDavid du Colombier 	Fmt fmt;
773ff48bf5SDavid du Colombier 
783ff48bf5SDavid du Colombier 	fmtstrinit(&fmt);
793ff48bf5SDavid du Colombier 	fmtprint(&fmt, "inquiry %s\n", inquiry);
803ff48bf5SDavid du Colombier 	fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
813ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
823ff48bf5SDavid du Colombier 		if(tab[i].inuse)
833ff48bf5SDavid du Colombier 			fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
843ff48bf5SDavid du Colombier 	return fmtstrflush(&fmt);
853ff48bf5SDavid du Colombier }
863ff48bf5SDavid du Colombier 
873ff48bf5SDavid du Colombier int
addpart(char * name,vlong start,vlong end)883ff48bf5SDavid du Colombier addpart(char *name, vlong start, vlong end)
893ff48bf5SDavid du Colombier {
903ff48bf5SDavid du Colombier 	int i;
913ff48bf5SDavid du Colombier 
923ff48bf5SDavid du Colombier 	if(start < 0 || start > end || end > nsect){
933ff48bf5SDavid du Colombier 		werrstr("bad partition boundaries");
943ff48bf5SDavid du Colombier 		return -1;
953ff48bf5SDavid du Colombier 	}
963ff48bf5SDavid du Colombier 
973ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
983ff48bf5SDavid du Colombier 		if(tab[i].inuse == 0)
993ff48bf5SDavid du Colombier 			break;
1003ff48bf5SDavid du Colombier 	if(i == nelem(tab)){
1013ff48bf5SDavid du Colombier 		werrstr("no free partition slots");
1023ff48bf5SDavid du Colombier 		return -1;
1033ff48bf5SDavid du Colombier 	}
1043ff48bf5SDavid du Colombier 
1053ff48bf5SDavid du Colombier 	free(tab[i].name);
1063ff48bf5SDavid du Colombier 	tab[i].inuse = 1;
1073ff48bf5SDavid du Colombier 	tab[i].name = estrdup9p(name);
1083ff48bf5SDavid du Colombier 	tab[i].offset = start;
1093ff48bf5SDavid du Colombier 	tab[i].length = end - start;
1103ff48bf5SDavid du Colombier 	tab[i].mode = ctlmode;
1113ff48bf5SDavid du Colombier 	tab[i].vers++;
1123ff48bf5SDavid du Colombier 
1133ff48bf5SDavid du Colombier 	return 0;
1143ff48bf5SDavid du Colombier }
1153ff48bf5SDavid du Colombier 
1163ff48bf5SDavid du Colombier int
delpart(char * s)1173ff48bf5SDavid du Colombier delpart(char *s)
1183ff48bf5SDavid du Colombier {
1193ff48bf5SDavid du Colombier 	int i;
1203ff48bf5SDavid du Colombier 
1213ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
1223ff48bf5SDavid du Colombier 		if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
1233ff48bf5SDavid du Colombier 			break;
1243ff48bf5SDavid du Colombier 	if(i==nelem(tab)){
1253ff48bf5SDavid du Colombier 		werrstr("partition not found");
1263ff48bf5SDavid du Colombier 		return -1;
1273ff48bf5SDavid du Colombier 	}
1283ff48bf5SDavid du Colombier 
1293ff48bf5SDavid du Colombier 	tab[i].inuse = 0;
1303ff48bf5SDavid du Colombier 	free(tab[i].name);
1313ff48bf5SDavid du Colombier 	tab[i].name = 0;
1323ff48bf5SDavid du Colombier 	return 0;
1333ff48bf5SDavid du Colombier }
1343ff48bf5SDavid du Colombier 
1353ff48bf5SDavid du Colombier void
ctlwrite(Req * r)1363ff48bf5SDavid du Colombier ctlwrite(Req *r)
1373ff48bf5SDavid du Colombier {
1383ff48bf5SDavid du Colombier 	int i;
1393ff48bf5SDavid du Colombier 	Cmdbuf *cb;
1403ff48bf5SDavid du Colombier 	vlong start, end;
1413ff48bf5SDavid du Colombier 
1423ff48bf5SDavid du Colombier 	r->ofcall.count = r->ifcall.count;
1433ff48bf5SDavid du Colombier 	cb = parsecmd(r->ifcall.data, r->ifcall.count);
1443ff48bf5SDavid du Colombier 	if(cb->nf < 1){
1453ff48bf5SDavid du Colombier 		respond(r, "empty control message");
1463ff48bf5SDavid du Colombier 		free(cb);
1473ff48bf5SDavid du Colombier 		return;
1483ff48bf5SDavid du Colombier 	}
1493ff48bf5SDavid du Colombier 
1503ff48bf5SDavid du Colombier 	if(strcmp(cb->f[0], "part") == 0){
1513ff48bf5SDavid du Colombier 		if(cb->nf != 4){
1523ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "part takes 3 args");
1533ff48bf5SDavid du Colombier 			free(cb);
1543ff48bf5SDavid du Colombier 			return;
1553ff48bf5SDavid du Colombier 		}
1563ff48bf5SDavid du Colombier 		start = strtoll(cb->f[2], 0, 0);
1573ff48bf5SDavid du Colombier 		end = strtoll(cb->f[3], 0, 0);
1583ff48bf5SDavid du Colombier 		if(addpart(cb->f[1], start, end) < 0){
1593ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "%r");
1603ff48bf5SDavid du Colombier 			free(cb);
1613ff48bf5SDavid du Colombier 			return;
1623ff48bf5SDavid du Colombier 		}
1633ff48bf5SDavid du Colombier 	}
1643ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "delpart") == 0){
1653ff48bf5SDavid du Colombier 		if(cb->nf != 2){
1663ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "delpart takes 1 arg");
1673ff48bf5SDavid du Colombier 			free(cb);
1683ff48bf5SDavid du Colombier 			return;
1693ff48bf5SDavid du Colombier 		}
1703ff48bf5SDavid du Colombier 		if(delpart(cb->f[1]) < 0){
1713ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "%r");
1723ff48bf5SDavid du Colombier 			free(cb);
1733ff48bf5SDavid du Colombier 			return;
1743ff48bf5SDavid du Colombier 		}
1753ff48bf5SDavid du Colombier 	}
1763ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "inquiry") == 0){
1773ff48bf5SDavid du Colombier 		if(cb->nf != 2){
1783ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "inquiry takes 1 arg");
1793ff48bf5SDavid du Colombier 			free(cb);
1803ff48bf5SDavid du Colombier 			return;
1813ff48bf5SDavid du Colombier 		}
1823ff48bf5SDavid du Colombier 		free(inquiry);
1833ff48bf5SDavid du Colombier 		inquiry = estrdup9p(cb->f[1]);
1843ff48bf5SDavid du Colombier 	}
1853ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "geometry") == 0){
1863ff48bf5SDavid du Colombier 		if(cb->nf != 6){
1873ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "geometry takes 5 args");
1883ff48bf5SDavid du Colombier 			free(cb);
1893ff48bf5SDavid du Colombier 			return;
1903ff48bf5SDavid du Colombier 		}
1913ff48bf5SDavid du Colombier 		nsect = strtoll(cb->f[1], 0, 0);
1923ff48bf5SDavid du Colombier 		sectsize = strtoll(cb->f[2], 0, 0);
1933ff48bf5SDavid du Colombier 		c = strtoll(cb->f[3], 0, 0);
1943ff48bf5SDavid du Colombier 		h = strtoll(cb->f[4], 0, 0);
1953ff48bf5SDavid du Colombier 		s = strtoll(cb->f[5], 0, 0);
1963ff48bf5SDavid du Colombier 		if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
1973ff48bf5SDavid du Colombier 			tab[0].offset = 0;
1983ff48bf5SDavid du Colombier 			tab[0].length = nsect;
1993ff48bf5SDavid du Colombier 		}
2003ff48bf5SDavid du Colombier 		for(i=0; i<nelem(tab); i++){
2013ff48bf5SDavid du Colombier 			if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
2023ff48bf5SDavid du Colombier 				tab[i].inuse = 0;
2033ff48bf5SDavid du Colombier 				free(tab[i].name);
2043ff48bf5SDavid du Colombier 				tab[i].name = 0;
2053ff48bf5SDavid du Colombier 			}
2063ff48bf5SDavid du Colombier 		}
2073ff48bf5SDavid du Colombier 	}
2083ff48bf5SDavid du Colombier 	else{
2093ff48bf5SDavid du Colombier 		respondcmderror(r, cb, "unknown control message");
2103ff48bf5SDavid du Colombier 		free(cb);
2113ff48bf5SDavid du Colombier 		return;
2123ff48bf5SDavid du Colombier 	}
2133ff48bf5SDavid du Colombier 
2143ff48bf5SDavid du Colombier 	free(cb);
2153ff48bf5SDavid du Colombier 	respond(r, nil);
2163ff48bf5SDavid du Colombier }
2173ff48bf5SDavid du Colombier 
2183ff48bf5SDavid du Colombier void*
allocblk(vlong addr)21911e1fb05SDavid du Colombier allocblk(vlong addr)
2203ff48bf5SDavid du Colombier {
2213ff48bf5SDavid du Colombier 	uchar *op;
2223ff48bf5SDavid du Colombier 	static uchar *p;
2233ff48bf5SDavid du Colombier 	static ulong n;
2243ff48bf5SDavid du Colombier 
2253ff48bf5SDavid du Colombier 	if(n == 0){
2263ff48bf5SDavid du Colombier 		p = malloc(4*1024*1024);
2273ff48bf5SDavid du Colombier 		if(p == 0)
2283ff48bf5SDavid du Colombier 			sysfatal("out of memory");
2293ff48bf5SDavid du Colombier 		n = 4*1024*1024;
2303ff48bf5SDavid du Colombier 	}
2313ff48bf5SDavid du Colombier 	op = p;
2323ff48bf5SDavid du Colombier 	p += BLKSZ;
2333ff48bf5SDavid du Colombier 	n -= BLKSZ;
2343ff48bf5SDavid du Colombier 	memset(op, 0, BLKSZ);
23511e1fb05SDavid du Colombier 	if(fd != -1 && addr != -1)
23611e1fb05SDavid du Colombier 		pread(fd, op, BLKSZ, addr);
2373ff48bf5SDavid du Colombier 	return op;
2383ff48bf5SDavid du Colombier }
2393ff48bf5SDavid du Colombier 
2403ff48bf5SDavid du Colombier uchar*
getblock(vlong addr,int alloc)2413ff48bf5SDavid du Colombier getblock(vlong addr, int alloc)
2423ff48bf5SDavid du Colombier {
2433ff48bf5SDavid du Colombier  	Dbl *p2;
2443ff48bf5SDavid du Colombier 	Ind *p1;
2453ff48bf5SDavid du Colombier 	uchar *p0;
2463ff48bf5SDavid du Colombier 	uint i0, i1, i2;
24711e1fb05SDavid du Colombier 	vlong oaddr;
24811e1fb05SDavid du Colombier 
2490b9a5132SDavid du Colombier 	if(fd >= 0)
25011e1fb05SDavid du Colombier 		alloc = 1;
2513ff48bf5SDavid du Colombier 
2523ff48bf5SDavid du Colombier 	addr >>= LOGBLKSZ;
25311e1fb05SDavid du Colombier 	oaddr = addr<<LOGBLKSZ;
2543ff48bf5SDavid du Colombier 	i0 = addr & (NPTR-1);
2553ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
2563ff48bf5SDavid du Colombier 	i1 = addr & (NPTR-1);
2573ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
2583ff48bf5SDavid du Colombier 	i2 = addr & (NPTR-1);
2593ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
2603ff48bf5SDavid du Colombier 	assert(addr == 0);
2613ff48bf5SDavid du Colombier 
2623ff48bf5SDavid du Colombier 	if((p2 = trip.dbl[i2]) == 0){
2633ff48bf5SDavid du Colombier 		if(!alloc)
2643ff48bf5SDavid du Colombier 			return zero;
26511e1fb05SDavid du Colombier 		trip.dbl[i2] = p2 = allocblk(-1);
2663ff48bf5SDavid du Colombier 	}
2673ff48bf5SDavid du Colombier 
2683ff48bf5SDavid du Colombier 	if((p1 = p2->ind[i1]) == 0){
2693ff48bf5SDavid du Colombier 		if(!alloc)
2703ff48bf5SDavid du Colombier 			return zero;
27111e1fb05SDavid du Colombier 		p2->ind[i1] = p1 = allocblk(-1);
2723ff48bf5SDavid du Colombier 	}
2733ff48bf5SDavid du Colombier 
2743ff48bf5SDavid du Colombier 	if((p0 = p1->blk[i0]) == 0){
2753ff48bf5SDavid du Colombier 		if(!alloc)
2763ff48bf5SDavid du Colombier 			return zero;
27711e1fb05SDavid du Colombier 		p1->blk[i0] = p0 = allocblk(oaddr);
2783ff48bf5SDavid du Colombier 	}
2793ff48bf5SDavid du Colombier 	return p0;
2803ff48bf5SDavid du Colombier }
2813ff48bf5SDavid du Colombier 
28211e1fb05SDavid du Colombier void
dirty(vlong addr,uchar * buf)28311e1fb05SDavid du Colombier dirty(vlong addr, uchar *buf)
28411e1fb05SDavid du Colombier {
28511e1fb05SDavid du Colombier 	vlong oaddr;
28611e1fb05SDavid du Colombier 
28711e1fb05SDavid du Colombier 	if(fd == -1 || rdonly)
28811e1fb05SDavid du Colombier 		return;
28911e1fb05SDavid du Colombier 	oaddr = addr&~((vlong)BLKSZ-1);
29011e1fb05SDavid du Colombier 	if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)
29111e1fb05SDavid du Colombier 		sysfatal("write: %r");
29211e1fb05SDavid du Colombier }
29311e1fb05SDavid du Colombier 
2943ff48bf5SDavid du Colombier int
rootgen(int off,Dir * d,void *)2953ff48bf5SDavid du Colombier rootgen(int off, Dir *d, void*)
2963ff48bf5SDavid du Colombier {
2973ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
2983ff48bf5SDavid du Colombier 	d->atime = time0;
2993ff48bf5SDavid du Colombier 	d->mtime = time0;
3003ff48bf5SDavid du Colombier 	if(off == 0){
3013ff48bf5SDavid du Colombier 		d->name = estrdup9p(sdname);
3023ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
3033ff48bf5SDavid du Colombier 		d->qid.path = Qdir;
3043ff48bf5SDavid du Colombier 		d->qid.type = QTDIR;
3053ff48bf5SDavid du Colombier 		d->uid = estrdup9p("disksim");
3063ff48bf5SDavid du Colombier 		d->gid = estrdup9p("disksim");
3073ff48bf5SDavid du Colombier 		d->muid = estrdup9p("");
3083ff48bf5SDavid du Colombier 		return 0;
3093ff48bf5SDavid du Colombier 	}
3103ff48bf5SDavid du Colombier 	return -1;
3113ff48bf5SDavid du Colombier }
3123ff48bf5SDavid du Colombier 
3133ff48bf5SDavid du Colombier int
dirgen(int off,Dir * d,void *)3143ff48bf5SDavid du Colombier dirgen(int off, Dir *d, void*)
3153ff48bf5SDavid du Colombier {
3163ff48bf5SDavid du Colombier 	int n, j;
3173ff48bf5SDavid du Colombier 
3183ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
3193ff48bf5SDavid du Colombier 	d->atime = time0;
3203ff48bf5SDavid du Colombier 	d->mtime = time0;
3213ff48bf5SDavid du Colombier 	if(off == 0){
3223ff48bf5SDavid du Colombier 		d->name = estrdup9p("ctl");
3233ff48bf5SDavid du Colombier 		d->mode = ctlmode;
3243ff48bf5SDavid du Colombier 		d->qid.path = Qctl;
3253ff48bf5SDavid du Colombier 		goto Have;
3263ff48bf5SDavid du Colombier 	}
3273ff48bf5SDavid du Colombier 
3283ff48bf5SDavid du Colombier 	off--;
3293ff48bf5SDavid du Colombier 	n = 0;
3303ff48bf5SDavid du Colombier 	for(j=0; j<nelem(tab); j++){
3313ff48bf5SDavid du Colombier 		if(tab[j].inuse==0)
3323ff48bf5SDavid du Colombier 			continue;
3333ff48bf5SDavid du Colombier 		if(n == off){
3343ff48bf5SDavid du Colombier 			d->name = estrdup9p(tab[j].name);
33581cf8742SDavid du Colombier 			d->length = tab[j].length*sectsize;
3363ff48bf5SDavid du Colombier 			d->mode = tab[j].mode;
3373ff48bf5SDavid du Colombier 			d->qid.path = Qpart+j;
3383ff48bf5SDavid du Colombier 			d->qid.vers = tab[j].vers;
3393ff48bf5SDavid du Colombier 			goto Have;
3403ff48bf5SDavid du Colombier 		}
3413ff48bf5SDavid du Colombier 		n++;
3423ff48bf5SDavid du Colombier 	}
3433ff48bf5SDavid du Colombier 	return -1;
3443ff48bf5SDavid du Colombier 
3453ff48bf5SDavid du Colombier Have:
3463ff48bf5SDavid du Colombier 	d->uid = estrdup9p("disksim");
3473ff48bf5SDavid du Colombier 	d->gid = estrdup9p("disksim");
3483ff48bf5SDavid du Colombier 	d->muid = estrdup9p("");
3493ff48bf5SDavid du Colombier 	return 0;
3503ff48bf5SDavid du Colombier }
3513ff48bf5SDavid du Colombier 
3523ff48bf5SDavid du Colombier void*
evommem(void * a,void * b,ulong n)3533ff48bf5SDavid du Colombier evommem(void *a, void *b, ulong n)
3543ff48bf5SDavid du Colombier {
3553ff48bf5SDavid du Colombier 	return memmove(b, a, n);
3563ff48bf5SDavid du Colombier }
3573ff48bf5SDavid du Colombier 
3583ff48bf5SDavid du Colombier int
isnonzero(void * v,ulong n)359*bbd061d4SDavid du Colombier isnonzero(void *v, ulong n)
360*bbd061d4SDavid du Colombier {
361*bbd061d4SDavid du Colombier 	uchar *a, *ea;
362*bbd061d4SDavid du Colombier 
363*bbd061d4SDavid du Colombier 	a = v;
364*bbd061d4SDavid du Colombier 	ea = a+n;
365*bbd061d4SDavid du Colombier 	for(; a<ea; a++)
366*bbd061d4SDavid du Colombier 		if(*a)
367*bbd061d4SDavid du Colombier 			return 1;
368*bbd061d4SDavid du Colombier 	return 0;
369*bbd061d4SDavid du Colombier }
370*bbd061d4SDavid du Colombier 
371*bbd061d4SDavid du Colombier int
rdwrpart(Req * r)3723ff48bf5SDavid du Colombier rdwrpart(Req *r)
3733ff48bf5SDavid du Colombier {
374*bbd061d4SDavid du Colombier 	int q, nonzero;
3753ff48bf5SDavid du Colombier 	Part *p;
3763ff48bf5SDavid du Colombier 	vlong offset;
3773ff48bf5SDavid du Colombier 	long count, tot, n, o;
3783ff48bf5SDavid du Colombier 	uchar *blk, *dat;
3793ff48bf5SDavid du Colombier 	void *(*move)(void*, void*, ulong);
3803ff48bf5SDavid du Colombier 
3813ff48bf5SDavid du Colombier 	q = r->fid->qid.path-Qpart;
3823ff48bf5SDavid du Colombier 	if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
3833ff48bf5SDavid du Colombier 		respond(r, "unknown partition");
3843ff48bf5SDavid du Colombier 		return -1;
3853ff48bf5SDavid du Colombier 	}
3863ff48bf5SDavid du Colombier 
3873ff48bf5SDavid du Colombier 	p = &tab[q];
3883ff48bf5SDavid du Colombier 	offset = r->ifcall.offset;
3893ff48bf5SDavid du Colombier 	count = r->ifcall.count;
3903ff48bf5SDavid du Colombier 	if(offset < 0){
3913ff48bf5SDavid du Colombier 		respond(r, "negative offset");
3923ff48bf5SDavid du Colombier 		return -1;
3933ff48bf5SDavid du Colombier 	}
3943ff48bf5SDavid du Colombier 	if(count < 0){
3953ff48bf5SDavid du Colombier 		respond(r, "negative count");
3963ff48bf5SDavid du Colombier 		return -1;
3973ff48bf5SDavid du Colombier 	}
3983ff48bf5SDavid du Colombier 	if(offset > p->length*sectsize){
3993ff48bf5SDavid du Colombier 		respond(r, "offset past end of partition");
4003ff48bf5SDavid du Colombier 		return -1;
4013ff48bf5SDavid du Colombier 	}
4023ff48bf5SDavid du Colombier 	if(offset+count > p->length*sectsize)
4033ff48bf5SDavid du Colombier 		count = p->length*sectsize - offset;
4043ff48bf5SDavid du Colombier 	offset += p->offset*sectsize;
4053ff48bf5SDavid du Colombier 
4063ff48bf5SDavid du Colombier 	if(r->ifcall.type == Tread)
4073ff48bf5SDavid du Colombier 		move = memmove;
4083ff48bf5SDavid du Colombier 	else
4093ff48bf5SDavid du Colombier 		move = evommem;
4103ff48bf5SDavid du Colombier 
4113ff48bf5SDavid du Colombier 	tot = 0;
412*bbd061d4SDavid du Colombier 	nonzero = 1;
4133ff48bf5SDavid du Colombier 	if(r->ifcall.type == Tread)
4143ff48bf5SDavid du Colombier 		dat = (uchar*)r->ofcall.data;
415*bbd061d4SDavid du Colombier 	else{
4163ff48bf5SDavid du Colombier 		dat = (uchar*)r->ifcall.data;
417*bbd061d4SDavid du Colombier 		nonzero = isnonzero(dat, r->ifcall.count);
418*bbd061d4SDavid du Colombier 	}
4193ff48bf5SDavid du Colombier 	o = offset & (BLKSZ-1);
4203ff48bf5SDavid du Colombier 
4213ff48bf5SDavid du Colombier 	/* left fringe block */
4223ff48bf5SDavid du Colombier 	if(o && count){
423*bbd061d4SDavid du Colombier 		blk = getblock(offset, r->ifcall.type==Twrite && nonzero);
4243ff48bf5SDavid du Colombier 		n = BLKSZ - o;
4253ff48bf5SDavid du Colombier 		if(n > count)
4263ff48bf5SDavid du Colombier 			n = count;
427*bbd061d4SDavid du Colombier 		if(r->ifcall.type != Twrite || blk != zero)
4283ff48bf5SDavid du Colombier 			(*move)(dat, blk+o, n);
42911e1fb05SDavid du Colombier 		if(r->ifcall.type == Twrite)
43011e1fb05SDavid du Colombier 			dirty(offset, blk);
4313ff48bf5SDavid du Colombier 		tot += n;
4323ff48bf5SDavid du Colombier 	}
4333ff48bf5SDavid du Colombier 	/* full and right fringe blocks */
4343ff48bf5SDavid du Colombier 	while(tot < count){
435*bbd061d4SDavid du Colombier 		blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);
4363ff48bf5SDavid du Colombier 		n = BLKSZ;
43711e1fb05SDavid du Colombier 		if(n > count-tot)
43811e1fb05SDavid du Colombier 			n = count-tot;
439*bbd061d4SDavid du Colombier 		if(r->ifcall.type != Twrite || blk != zero)
4403ff48bf5SDavid du Colombier 			(*move)(dat+tot, blk, n);
44111e1fb05SDavid du Colombier 		if(r->ifcall.type == Twrite)
44211e1fb05SDavid du Colombier 			dirty(offset+tot, blk);
4433ff48bf5SDavid du Colombier 		tot += n;
4443ff48bf5SDavid du Colombier 	}
4453ff48bf5SDavid du Colombier 	r->ofcall.count = tot;
4463ff48bf5SDavid du Colombier 	respond(r, nil);
4473ff48bf5SDavid du Colombier 	return 0;
4483ff48bf5SDavid du Colombier }
4493ff48bf5SDavid du Colombier 
4503ff48bf5SDavid du Colombier void
fsread(Req * r)4513ff48bf5SDavid du Colombier fsread(Req *r)
4523ff48bf5SDavid du Colombier {
4533ff48bf5SDavid du Colombier 	char *s;
4543ff48bf5SDavid du Colombier 
4553ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
4563ff48bf5SDavid du Colombier 	case Qroot:
4573ff48bf5SDavid du Colombier 		dirread9p(r, rootgen, nil);
4583ff48bf5SDavid du Colombier 		respond(r, nil);
4593ff48bf5SDavid du Colombier 		break;
4603ff48bf5SDavid du Colombier 
4613ff48bf5SDavid du Colombier 	case Qdir:
4623ff48bf5SDavid du Colombier 		dirread9p(r, dirgen, nil);
4633ff48bf5SDavid du Colombier 		respond(r, nil);
4643ff48bf5SDavid du Colombier 		break;
4653ff48bf5SDavid du Colombier 
4663ff48bf5SDavid du Colombier 	case Qctl:
4673ff48bf5SDavid du Colombier 		s = ctlstring();
4683ff48bf5SDavid du Colombier 		readstr(r, s);
4693ff48bf5SDavid du Colombier 		free(s);
4703ff48bf5SDavid du Colombier 		respond(r, nil);
4713ff48bf5SDavid du Colombier 		break;
4723ff48bf5SDavid du Colombier 
4733ff48bf5SDavid du Colombier 	default:
4743ff48bf5SDavid du Colombier 		rdwrpart(r);
4753ff48bf5SDavid du Colombier 		break;
4763ff48bf5SDavid du Colombier 	}
4773ff48bf5SDavid du Colombier }
4783ff48bf5SDavid du Colombier 
4793ff48bf5SDavid du Colombier void
fswrite(Req * r)4803ff48bf5SDavid du Colombier fswrite(Req *r)
4813ff48bf5SDavid du Colombier {
4823ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
4833ff48bf5SDavid du Colombier 	case Qroot:
4843ff48bf5SDavid du Colombier 	case Qdir:
4853ff48bf5SDavid du Colombier 		respond(r, "write to a directory?");
4863ff48bf5SDavid du Colombier 		break;
4873ff48bf5SDavid du Colombier 
4883ff48bf5SDavid du Colombier 	case Qctl:
4893ff48bf5SDavid du Colombier 		ctlwrite(r);
4903ff48bf5SDavid du Colombier 		break;
4913ff48bf5SDavid du Colombier 
4923ff48bf5SDavid du Colombier 	default:
4933ff48bf5SDavid du Colombier 		rdwrpart(r);
4943ff48bf5SDavid du Colombier 		break;
4953ff48bf5SDavid du Colombier 	}
4963ff48bf5SDavid du Colombier }
4973ff48bf5SDavid du Colombier 
4983ff48bf5SDavid du Colombier void
fsopen(Req * r)4993ff48bf5SDavid du Colombier fsopen(Req *r)
5003ff48bf5SDavid du Colombier {
5013ff48bf5SDavid du Colombier 	if(r->ifcall.mode&ORCLOSE)
5023ff48bf5SDavid du Colombier 		respond(r, "cannot open ORCLOSE");
5033ff48bf5SDavid du Colombier 
5043ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
5053ff48bf5SDavid du Colombier 	case Qroot:
5063ff48bf5SDavid du Colombier 	case Qdir:
5073ff48bf5SDavid du Colombier 		if(r->ifcall.mode != OREAD){
5083ff48bf5SDavid du Colombier 			respond(r, "bad mode for directory open");
5093ff48bf5SDavid du Colombier 			return;
5103ff48bf5SDavid du Colombier 		}
5113ff48bf5SDavid du Colombier 	}
5123ff48bf5SDavid du Colombier 
5133ff48bf5SDavid du Colombier 	respond(r, nil);
5143ff48bf5SDavid du Colombier }
5153ff48bf5SDavid du Colombier 
5163ff48bf5SDavid du Colombier void
fsstat(Req * r)5173ff48bf5SDavid du Colombier fsstat(Req *r)
5183ff48bf5SDavid du Colombier {
5193ff48bf5SDavid du Colombier 	int q;
5203ff48bf5SDavid du Colombier 	Dir *d;
5213ff48bf5SDavid du Colombier 	Part *p;
5223ff48bf5SDavid du Colombier 
5233ff48bf5SDavid du Colombier 	d = &r->d;
5243ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
5253ff48bf5SDavid du Colombier 	d->qid = r->fid->qid;
5263ff48bf5SDavid du Colombier 	d->atime = d->mtime = time0;
5273ff48bf5SDavid du Colombier 	q = r->fid->qid.path;
5283ff48bf5SDavid du Colombier 	switch(q){
5293ff48bf5SDavid du Colombier 	case Qroot:
5303ff48bf5SDavid du Colombier 		d->name = estrdup9p("/");
5313ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
5323ff48bf5SDavid du Colombier 		break;
5333ff48bf5SDavid du Colombier 
5343ff48bf5SDavid du Colombier 	case Qdir:
5353ff48bf5SDavid du Colombier 		d->name = estrdup9p(sdname);
5363ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
5373ff48bf5SDavid du Colombier 		break;
5383ff48bf5SDavid du Colombier 
5393ff48bf5SDavid du Colombier 	default:
5403ff48bf5SDavid du Colombier 		q -= Qpart;
5413ff48bf5SDavid du Colombier 		if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
5423ff48bf5SDavid du Colombier 			respond(r, "partition no longer exists");
5433ff48bf5SDavid du Colombier 			return;
5443ff48bf5SDavid du Colombier 		}
5453ff48bf5SDavid du Colombier 		p = &tab[q];
5463ff48bf5SDavid du Colombier 		d->name = estrdup9p(p->name);
5473ff48bf5SDavid du Colombier 		d->length = p->length * sectsize;
5483ff48bf5SDavid du Colombier 		d->mode = p->mode;
5493ff48bf5SDavid du Colombier 		break;
5503ff48bf5SDavid du Colombier 	}
5513ff48bf5SDavid du Colombier 
5523ff48bf5SDavid du Colombier 	d->uid = estrdup9p("disksim");
5533ff48bf5SDavid du Colombier 	d->gid = estrdup9p("disksim");
5543ff48bf5SDavid du Colombier 	d->muid = estrdup9p("");
5553ff48bf5SDavid du Colombier 	respond(r, nil);
5563ff48bf5SDavid du Colombier }
5573ff48bf5SDavid du Colombier 
5583ff48bf5SDavid du Colombier void
fsattach(Req * r)5593ff48bf5SDavid du Colombier fsattach(Req *r)
5603ff48bf5SDavid du Colombier {
5613ff48bf5SDavid du Colombier 	char *spec;
5623ff48bf5SDavid du Colombier 
5633ff48bf5SDavid du Colombier 	spec = r->ifcall.aname;
5643ff48bf5SDavid du Colombier 	if(spec && spec[0]){
5653ff48bf5SDavid du Colombier 		respond(r, "invalid attach specifier");
5663ff48bf5SDavid du Colombier 		return;
5673ff48bf5SDavid du Colombier 	}
5683ff48bf5SDavid du Colombier 	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
5693ff48bf5SDavid du Colombier 	r->fid->qid = r->ofcall.qid;
5703ff48bf5SDavid du Colombier 	respond(r, nil);
5713ff48bf5SDavid du Colombier }
5723ff48bf5SDavid du Colombier 
5733ff48bf5SDavid du Colombier char*
fswalk1(Fid * fid,char * name,Qid * qid)5743ff48bf5SDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
5753ff48bf5SDavid du Colombier {
5763ff48bf5SDavid du Colombier 	int i;
5773ff48bf5SDavid du Colombier 	switch((int)fid->qid.path){
5783ff48bf5SDavid du Colombier 	case Qroot:
5793ff48bf5SDavid du Colombier 		if(strcmp(name, sdname) == 0){
5803ff48bf5SDavid du Colombier 			fid->qid.path = Qdir;
5813ff48bf5SDavid du Colombier 			fid->qid.type = QTDIR;
5823ff48bf5SDavid du Colombier 			*qid = fid->qid;
5833ff48bf5SDavid du Colombier 			return nil;
5843ff48bf5SDavid du Colombier 		}
5853ff48bf5SDavid du Colombier 		break;
5863ff48bf5SDavid du Colombier 	case Qdir:
5873ff48bf5SDavid du Colombier 		if(strcmp(name, "ctl") == 0){
5883ff48bf5SDavid du Colombier 			fid->qid.path = Qctl;
5893ff48bf5SDavid du Colombier 			fid->qid.vers = 0;
5903ff48bf5SDavid du Colombier 			fid->qid.type = 0;
5913ff48bf5SDavid du Colombier 			*qid = fid->qid;
5923ff48bf5SDavid du Colombier 			return nil;
5933ff48bf5SDavid du Colombier 		}
5943ff48bf5SDavid du Colombier 		for(i=0; i<nelem(tab); i++){
5953ff48bf5SDavid du Colombier 			if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
5963ff48bf5SDavid du Colombier 				fid->qid.path = i+Qpart;
5973ff48bf5SDavid du Colombier 				fid->qid.vers = tab[i].vers;
5983ff48bf5SDavid du Colombier 				fid->qid.type = 0;
5993ff48bf5SDavid du Colombier 				*qid = fid->qid;
6003ff48bf5SDavid du Colombier 				return nil;
6013ff48bf5SDavid du Colombier 			}
6023ff48bf5SDavid du Colombier 		}
6033ff48bf5SDavid du Colombier 		break;
6043ff48bf5SDavid du Colombier 	}
6053ff48bf5SDavid du Colombier 	return "file not found";
6063ff48bf5SDavid du Colombier }
6073ff48bf5SDavid du Colombier 
6083ff48bf5SDavid du Colombier Srv fs = {
6093ff48bf5SDavid du Colombier 	.attach=	fsattach,
6103ff48bf5SDavid du Colombier 	.open=	fsopen,
6113ff48bf5SDavid du Colombier 	.read=	fsread,
6123ff48bf5SDavid du Colombier 	.write=	fswrite,
6133ff48bf5SDavid du Colombier 	.stat=	fsstat,
6143ff48bf5SDavid du Colombier 	.walk1=	fswalk1,
6153ff48bf5SDavid du Colombier };
6163ff48bf5SDavid du Colombier 
6173ff48bf5SDavid du Colombier char *mtpt = "/dev";
6183ff48bf5SDavid du Colombier char *srvname;
6193ff48bf5SDavid du Colombier 
6203ff48bf5SDavid du Colombier void
usage(void)6213ff48bf5SDavid du Colombier usage(void)
6223ff48bf5SDavid du Colombier {
62311e1fb05SDavid du Colombier 	fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");
6243ff48bf5SDavid du Colombier 	fprint(2, "\tdefault mtpt is /dev\n");
6253ff48bf5SDavid du Colombier 	exits("usage");
6263ff48bf5SDavid du Colombier }
6273ff48bf5SDavid du Colombier 
6283ff48bf5SDavid du Colombier void
main(int argc,char ** argv)6293ff48bf5SDavid du Colombier main(int argc, char **argv)
6303ff48bf5SDavid du Colombier {
63111e1fb05SDavid du Colombier 	char *file;
63211e1fb05SDavid du Colombier 
63311e1fb05SDavid du Colombier 	file = nil;
6343ff48bf5SDavid du Colombier 	quotefmtinstall();
6353ff48bf5SDavid du Colombier 	time0 = time(0);
6363ff48bf5SDavid du Colombier 	if(NPTR != BLKSZ/sizeof(void*))
6373ff48bf5SDavid du Colombier 		sysfatal("unexpected pointer size");
6383ff48bf5SDavid du Colombier 
6393ff48bf5SDavid du Colombier 	ARGBEGIN{
6403ff48bf5SDavid du Colombier 	case 'D':
6413ff48bf5SDavid du Colombier 		chatty9p++;
6423ff48bf5SDavid du Colombier 		break;
64311e1fb05SDavid du Colombier 	case 'f':
64411e1fb05SDavid du Colombier 		file = EARGF(usage());
64511e1fb05SDavid du Colombier 		break;
64611e1fb05SDavid du Colombier 	case 'r':
64711e1fb05SDavid du Colombier 		rdonly = 1;
64811e1fb05SDavid du Colombier 		break;
6493ff48bf5SDavid du Colombier 	case 's':
6503ff48bf5SDavid du Colombier 		srvname = EARGF(usage());
6513ff48bf5SDavid du Colombier 		break;
6523ff48bf5SDavid du Colombier 	case 'm':
6533ff48bf5SDavid du Colombier 		mtpt = EARGF(usage());
6543ff48bf5SDavid du Colombier 		break;
6553ff48bf5SDavid du Colombier 	default:
6563ff48bf5SDavid du Colombier 		usage();
6573ff48bf5SDavid du Colombier 	}ARGEND
6583ff48bf5SDavid du Colombier 
6593ff48bf5SDavid du Colombier 	if(argc > 1)
6603ff48bf5SDavid du Colombier 		usage();
6613ff48bf5SDavid du Colombier 	if(argc == 1)
6623ff48bf5SDavid du Colombier 		sdname = argv[0];
6633ff48bf5SDavid du Colombier 
66411e1fb05SDavid du Colombier 	if(file){
66511e1fb05SDavid du Colombier 		if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
66611e1fb05SDavid du Colombier 			sysfatal("open %s: %r", file);
66711e1fb05SDavid du Colombier 	}
66811e1fb05SDavid du Colombier 
6693ff48bf5SDavid du Colombier 	inquiry = estrdup9p(inquiry);
6703ff48bf5SDavid du Colombier 	tab[0].name = estrdup9p("data");
6713ff48bf5SDavid du Colombier 	tab[0].inuse = 1;
6723ff48bf5SDavid du Colombier 	tab[0].mode = 0666;
6733ff48bf5SDavid du Colombier 
6743ff48bf5SDavid du Colombier 	postmountsrv(&fs, srvname, mtpt, MBEFORE);
6753ff48bf5SDavid du Colombier 	exits(nil);
6763ff48bf5SDavid du Colombier }
677