xref: /plan9/sys/src/cmd/aux/disksim.c (revision 3ff48bf5ed603850fcd251ddf13025d23d693782)
1*3ff48bf5SDavid du Colombier #include <u.h>
2*3ff48bf5SDavid du Colombier #include <libc.h>
3*3ff48bf5SDavid du Colombier #include <auth.h>
4*3ff48bf5SDavid du Colombier #include <fcall.h>
5*3ff48bf5SDavid du Colombier #include <thread.h>
6*3ff48bf5SDavid du Colombier #include <9p.h>
7*3ff48bf5SDavid du Colombier 
8*3ff48bf5SDavid du Colombier typedef struct Part Part;
9*3ff48bf5SDavid du Colombier typedef struct Trip Trip;
10*3ff48bf5SDavid du Colombier typedef struct Dbl Dbl;
11*3ff48bf5SDavid du Colombier typedef struct Ind Ind;
12*3ff48bf5SDavid du Colombier 
13*3ff48bf5SDavid du Colombier /*
14*3ff48bf5SDavid du Colombier  * with 8192-byte blocks and 4-byte pointers,
15*3ff48bf5SDavid du Colombier  * double-indirect gets us 34 GB.
16*3ff48bf5SDavid du Colombier  * triple-indirect gets us 70,368 GB.
17*3ff48bf5SDavid du Colombier  */
18*3ff48bf5SDavid du Colombier 
19*3ff48bf5SDavid du Colombier enum
20*3ff48bf5SDavid du Colombier {
21*3ff48bf5SDavid du Colombier 	LOGBLKSZ = 13,
22*3ff48bf5SDavid du Colombier 	BLKSZ = 1<<LOGBLKSZ,	/* 8192 */
23*3ff48bf5SDavid du Colombier 	LOGNPTR = LOGBLKSZ-2,	/* assume sizeof(void*) == 4 */
24*3ff48bf5SDavid du Colombier 	NPTR = 1<<LOGNPTR,
25*3ff48bf5SDavid du Colombier };
26*3ff48bf5SDavid du Colombier 
27*3ff48bf5SDavid du Colombier struct Trip
28*3ff48bf5SDavid du Colombier {
29*3ff48bf5SDavid du Colombier 	Dbl *dbl[NPTR];
30*3ff48bf5SDavid du Colombier };
31*3ff48bf5SDavid du Colombier 
32*3ff48bf5SDavid du Colombier struct Dbl
33*3ff48bf5SDavid du Colombier {
34*3ff48bf5SDavid du Colombier 	Ind *ind[NPTR];
35*3ff48bf5SDavid du Colombier };
36*3ff48bf5SDavid du Colombier 
37*3ff48bf5SDavid du Colombier struct Ind
38*3ff48bf5SDavid du Colombier {
39*3ff48bf5SDavid du Colombier 	uchar *blk[NPTR];
40*3ff48bf5SDavid du Colombier };
41*3ff48bf5SDavid du Colombier 
42*3ff48bf5SDavid du Colombier Trip trip;
43*3ff48bf5SDavid du Colombier 
44*3ff48bf5SDavid du Colombier struct Part
45*3ff48bf5SDavid du Colombier {
46*3ff48bf5SDavid du Colombier 	int inuse;
47*3ff48bf5SDavid du Colombier 	int vers;
48*3ff48bf5SDavid du Colombier 	ulong mode;
49*3ff48bf5SDavid du Colombier 	char *name;
50*3ff48bf5SDavid du Colombier 	vlong offset;	/* in sectors */
51*3ff48bf5SDavid du Colombier 	vlong length;	/* in sectors */
52*3ff48bf5SDavid du Colombier };
53*3ff48bf5SDavid du Colombier 
54*3ff48bf5SDavid du Colombier enum
55*3ff48bf5SDavid du Colombier {
56*3ff48bf5SDavid du Colombier 	Qroot = 0,
57*3ff48bf5SDavid du Colombier 	Qdir,
58*3ff48bf5SDavid du Colombier 	Qctl,
59*3ff48bf5SDavid du Colombier 	Qpart,
60*3ff48bf5SDavid du Colombier };
61*3ff48bf5SDavid du Colombier 
62*3ff48bf5SDavid du Colombier Part tab[64];
63*3ff48bf5SDavid du Colombier 
64*3ff48bf5SDavid du Colombier char *sdname = "sdXX";
65*3ff48bf5SDavid du Colombier ulong ctlmode = 0666;
66*3ff48bf5SDavid du Colombier char *inquiry = "aux/disksim hard drive";
67*3ff48bf5SDavid du Colombier vlong nsect, sectsize, c, h, s;
68*3ff48bf5SDavid du Colombier ulong time0;
69*3ff48bf5SDavid du Colombier 
70*3ff48bf5SDavid du Colombier char*
71*3ff48bf5SDavid du Colombier ctlstring(void)
72*3ff48bf5SDavid du Colombier {
73*3ff48bf5SDavid du Colombier 	int i;
74*3ff48bf5SDavid du Colombier 	Fmt fmt;
75*3ff48bf5SDavid du Colombier 
76*3ff48bf5SDavid du Colombier 	fmtstrinit(&fmt);
77*3ff48bf5SDavid du Colombier 	fmtprint(&fmt, "inquiry %s\n", inquiry);
78*3ff48bf5SDavid du Colombier 	fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
79*3ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
80*3ff48bf5SDavid du Colombier 		if(tab[i].inuse)
81*3ff48bf5SDavid du Colombier 			fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
82*3ff48bf5SDavid du Colombier 	return fmtstrflush(&fmt);
83*3ff48bf5SDavid du Colombier }
84*3ff48bf5SDavid du Colombier 
85*3ff48bf5SDavid du Colombier int
86*3ff48bf5SDavid du Colombier addpart(char *name, vlong start, vlong end)
87*3ff48bf5SDavid du Colombier {
88*3ff48bf5SDavid du Colombier 	int i;
89*3ff48bf5SDavid du Colombier 
90*3ff48bf5SDavid du Colombier 	if(start < 0 || start > end || end > nsect){
91*3ff48bf5SDavid du Colombier 		werrstr("bad partition boundaries");
92*3ff48bf5SDavid du Colombier 		return -1;
93*3ff48bf5SDavid du Colombier 	}
94*3ff48bf5SDavid du Colombier 
95*3ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
96*3ff48bf5SDavid du Colombier 		if(tab[i].inuse == 0)
97*3ff48bf5SDavid du Colombier 			break;
98*3ff48bf5SDavid du Colombier 	if(i == nelem(tab)){
99*3ff48bf5SDavid du Colombier 		werrstr("no free partition slots");
100*3ff48bf5SDavid du Colombier 		return -1;
101*3ff48bf5SDavid du Colombier 	}
102*3ff48bf5SDavid du Colombier 
103*3ff48bf5SDavid du Colombier 	free(tab[i].name);
104*3ff48bf5SDavid du Colombier 	tab[i].inuse = 1;
105*3ff48bf5SDavid du Colombier 	tab[i].name = estrdup9p(name);
106*3ff48bf5SDavid du Colombier 	tab[i].offset = start;
107*3ff48bf5SDavid du Colombier 	tab[i].length = end - start;
108*3ff48bf5SDavid du Colombier 	tab[i].mode = ctlmode;
109*3ff48bf5SDavid du Colombier 	tab[i].vers++;
110*3ff48bf5SDavid du Colombier 
111*3ff48bf5SDavid du Colombier 	return 0;
112*3ff48bf5SDavid du Colombier }
113*3ff48bf5SDavid du Colombier 
114*3ff48bf5SDavid du Colombier int
115*3ff48bf5SDavid du Colombier delpart(char *s)
116*3ff48bf5SDavid du Colombier {
117*3ff48bf5SDavid du Colombier 	int i;
118*3ff48bf5SDavid du Colombier 
119*3ff48bf5SDavid du Colombier 	for(i=0; i<nelem(tab); i++)
120*3ff48bf5SDavid du Colombier 		if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
121*3ff48bf5SDavid du Colombier 			break;
122*3ff48bf5SDavid du Colombier 	if(i==nelem(tab)){
123*3ff48bf5SDavid du Colombier 		werrstr("partition not found");
124*3ff48bf5SDavid du Colombier 		return -1;
125*3ff48bf5SDavid du Colombier 	}
126*3ff48bf5SDavid du Colombier 
127*3ff48bf5SDavid du Colombier 	tab[i].inuse = 0;
128*3ff48bf5SDavid du Colombier 	free(tab[i].name);
129*3ff48bf5SDavid du Colombier 	tab[i].name = 0;
130*3ff48bf5SDavid du Colombier 	return 0;
131*3ff48bf5SDavid du Colombier }
132*3ff48bf5SDavid du Colombier 
133*3ff48bf5SDavid du Colombier void
134*3ff48bf5SDavid du Colombier ctlwrite(Req *r)
135*3ff48bf5SDavid du Colombier {
136*3ff48bf5SDavid du Colombier 	int i;
137*3ff48bf5SDavid du Colombier 	Cmdbuf *cb;
138*3ff48bf5SDavid du Colombier 	vlong start, end;
139*3ff48bf5SDavid du Colombier 
140*3ff48bf5SDavid du Colombier 	r->ofcall.count = r->ifcall.count;
141*3ff48bf5SDavid du Colombier 	cb = parsecmd(r->ifcall.data, r->ifcall.count);
142*3ff48bf5SDavid du Colombier 	if(cb->nf < 1){
143*3ff48bf5SDavid du Colombier 		respond(r, "empty control message");
144*3ff48bf5SDavid du Colombier 		free(cb);
145*3ff48bf5SDavid du Colombier 		return;
146*3ff48bf5SDavid du Colombier 	}
147*3ff48bf5SDavid du Colombier 
148*3ff48bf5SDavid du Colombier 	if(strcmp(cb->f[0], "part") == 0){
149*3ff48bf5SDavid du Colombier 		if(cb->nf != 4){
150*3ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "part takes 3 args");
151*3ff48bf5SDavid du Colombier 			free(cb);
152*3ff48bf5SDavid du Colombier 			return;
153*3ff48bf5SDavid du Colombier 		}
154*3ff48bf5SDavid du Colombier 		start = strtoll(cb->f[2], 0, 0);
155*3ff48bf5SDavid du Colombier 		end = strtoll(cb->f[3], 0, 0);
156*3ff48bf5SDavid du Colombier 		if(addpart(cb->f[1], start, end) < 0){
157*3ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "%r");
158*3ff48bf5SDavid du Colombier 			free(cb);
159*3ff48bf5SDavid du Colombier 			return;
160*3ff48bf5SDavid du Colombier 		}
161*3ff48bf5SDavid du Colombier 	}
162*3ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "delpart") == 0){
163*3ff48bf5SDavid du Colombier 		if(cb->nf != 2){
164*3ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "delpart takes 1 arg");
165*3ff48bf5SDavid du Colombier 			free(cb);
166*3ff48bf5SDavid du Colombier 			return;
167*3ff48bf5SDavid du Colombier 		}
168*3ff48bf5SDavid du Colombier 		if(delpart(cb->f[1]) < 0){
169*3ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "%r");
170*3ff48bf5SDavid du Colombier 			free(cb);
171*3ff48bf5SDavid du Colombier 			return;
172*3ff48bf5SDavid du Colombier 		}
173*3ff48bf5SDavid du Colombier 	}
174*3ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "inquiry") == 0){
175*3ff48bf5SDavid du Colombier 		if(cb->nf != 2){
176*3ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "inquiry takes 1 arg");
177*3ff48bf5SDavid du Colombier 			free(cb);
178*3ff48bf5SDavid du Colombier 			return;
179*3ff48bf5SDavid du Colombier 		}
180*3ff48bf5SDavid du Colombier 		free(inquiry);
181*3ff48bf5SDavid du Colombier 		inquiry = estrdup9p(cb->f[1]);
182*3ff48bf5SDavid du Colombier 	}
183*3ff48bf5SDavid du Colombier 	else if(strcmp(cb->f[0], "geometry") == 0){
184*3ff48bf5SDavid du Colombier 		if(cb->nf != 6){
185*3ff48bf5SDavid du Colombier 			respondcmderror(r, cb, "geometry takes 5 args");
186*3ff48bf5SDavid du Colombier 			free(cb);
187*3ff48bf5SDavid du Colombier 			return;
188*3ff48bf5SDavid du Colombier 		}
189*3ff48bf5SDavid du Colombier 		nsect = strtoll(cb->f[1], 0, 0);
190*3ff48bf5SDavid du Colombier 		sectsize = strtoll(cb->f[2], 0, 0);
191*3ff48bf5SDavid du Colombier 		c = strtoll(cb->f[3], 0, 0);
192*3ff48bf5SDavid du Colombier 		h = strtoll(cb->f[4], 0, 0);
193*3ff48bf5SDavid du Colombier 		s = strtoll(cb->f[5], 0, 0);
194*3ff48bf5SDavid du Colombier 		if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
195*3ff48bf5SDavid du Colombier 			tab[0].offset = 0;
196*3ff48bf5SDavid du Colombier 			tab[0].length = nsect;
197*3ff48bf5SDavid du Colombier 		}
198*3ff48bf5SDavid du Colombier 		for(i=0; i<nelem(tab); i++){
199*3ff48bf5SDavid du Colombier 			if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
200*3ff48bf5SDavid du Colombier 				tab[i].inuse = 0;
201*3ff48bf5SDavid du Colombier 				free(tab[i].name);
202*3ff48bf5SDavid du Colombier 				tab[i].name = 0;
203*3ff48bf5SDavid du Colombier 			}
204*3ff48bf5SDavid du Colombier 		}
205*3ff48bf5SDavid du Colombier 	}
206*3ff48bf5SDavid du Colombier 	else{
207*3ff48bf5SDavid du Colombier 		respondcmderror(r, cb, "unknown control message");
208*3ff48bf5SDavid du Colombier 		free(cb);
209*3ff48bf5SDavid du Colombier 		return;
210*3ff48bf5SDavid du Colombier 	}
211*3ff48bf5SDavid du Colombier 
212*3ff48bf5SDavid du Colombier 	free(cb);
213*3ff48bf5SDavid du Colombier 	respond(r, nil);
214*3ff48bf5SDavid du Colombier }
215*3ff48bf5SDavid du Colombier 
216*3ff48bf5SDavid du Colombier void*
217*3ff48bf5SDavid du Colombier allocblk(void)
218*3ff48bf5SDavid du Colombier {
219*3ff48bf5SDavid du Colombier 	uchar *op;
220*3ff48bf5SDavid du Colombier 	static uchar *p;
221*3ff48bf5SDavid du Colombier 	static ulong n;
222*3ff48bf5SDavid du Colombier 
223*3ff48bf5SDavid du Colombier 	if(n == 0){
224*3ff48bf5SDavid du Colombier 		p = malloc(4*1024*1024);
225*3ff48bf5SDavid du Colombier 		if(p == 0)
226*3ff48bf5SDavid du Colombier 			sysfatal("out of memory");
227*3ff48bf5SDavid du Colombier 		n = 4*1024*1024;
228*3ff48bf5SDavid du Colombier 	}
229*3ff48bf5SDavid du Colombier 	op = p;
230*3ff48bf5SDavid du Colombier 	p += BLKSZ;
231*3ff48bf5SDavid du Colombier 	n -= BLKSZ;
232*3ff48bf5SDavid du Colombier 	memset(op, 0, BLKSZ);
233*3ff48bf5SDavid du Colombier 	return op;
234*3ff48bf5SDavid du Colombier }
235*3ff48bf5SDavid du Colombier 
236*3ff48bf5SDavid du Colombier uchar*
237*3ff48bf5SDavid du Colombier getblock(vlong addr, int alloc)
238*3ff48bf5SDavid du Colombier {
239*3ff48bf5SDavid du Colombier 	static uchar zero[BLKSZ];
240*3ff48bf5SDavid du Colombier  	Dbl *p2;
241*3ff48bf5SDavid du Colombier 	Ind *p1;
242*3ff48bf5SDavid du Colombier 	uchar *p0;
243*3ff48bf5SDavid du Colombier 	uint i0, i1, i2;
244*3ff48bf5SDavid du Colombier 
245*3ff48bf5SDavid du Colombier 	addr >>= LOGBLKSZ;
246*3ff48bf5SDavid du Colombier 	i0 = addr & (NPTR-1);
247*3ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
248*3ff48bf5SDavid du Colombier 	i1 = addr & (NPTR-1);
249*3ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
250*3ff48bf5SDavid du Colombier 	i2 = addr & (NPTR-1);
251*3ff48bf5SDavid du Colombier 	addr >>= LOGNPTR;
252*3ff48bf5SDavid du Colombier 	assert(addr == 0);
253*3ff48bf5SDavid du Colombier 
254*3ff48bf5SDavid du Colombier 	if((p2 = trip.dbl[i2]) == 0){
255*3ff48bf5SDavid du Colombier 		if(!alloc)
256*3ff48bf5SDavid du Colombier 			return zero;
257*3ff48bf5SDavid du Colombier 		trip.dbl[i2] = p2 = allocblk();
258*3ff48bf5SDavid du Colombier 	}
259*3ff48bf5SDavid du Colombier 
260*3ff48bf5SDavid du Colombier 	if((p1 = p2->ind[i1]) == 0){
261*3ff48bf5SDavid du Colombier 		if(!alloc)
262*3ff48bf5SDavid du Colombier 			return zero;
263*3ff48bf5SDavid du Colombier 		p2->ind[i1] = p1 = allocblk();
264*3ff48bf5SDavid du Colombier 	}
265*3ff48bf5SDavid du Colombier 
266*3ff48bf5SDavid du Colombier 	if((p0 = p1->blk[i0]) == 0){
267*3ff48bf5SDavid du Colombier 		if(!alloc)
268*3ff48bf5SDavid du Colombier 			return zero;
269*3ff48bf5SDavid du Colombier 		p1->blk[i0] = p0 = allocblk();
270*3ff48bf5SDavid du Colombier 	}
271*3ff48bf5SDavid du Colombier 	return p0;
272*3ff48bf5SDavid du Colombier }
273*3ff48bf5SDavid du Colombier 
274*3ff48bf5SDavid du Colombier int
275*3ff48bf5SDavid du Colombier rootgen(int off, Dir *d, void*)
276*3ff48bf5SDavid du Colombier {
277*3ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
278*3ff48bf5SDavid du Colombier 	d->atime = time0;
279*3ff48bf5SDavid du Colombier 	d->mtime = time0;
280*3ff48bf5SDavid du Colombier 	if(off == 0){
281*3ff48bf5SDavid du Colombier 		d->name = estrdup9p(sdname);
282*3ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
283*3ff48bf5SDavid du Colombier 		d->qid.path = Qdir;
284*3ff48bf5SDavid du Colombier 		d->qid.type = QTDIR;
285*3ff48bf5SDavid du Colombier 		d->uid = estrdup9p("disksim");
286*3ff48bf5SDavid du Colombier 		d->gid = estrdup9p("disksim");
287*3ff48bf5SDavid du Colombier 		d->muid = estrdup9p("");
288*3ff48bf5SDavid du Colombier 		return 0;
289*3ff48bf5SDavid du Colombier 	}
290*3ff48bf5SDavid du Colombier 	return -1;
291*3ff48bf5SDavid du Colombier }
292*3ff48bf5SDavid du Colombier 
293*3ff48bf5SDavid du Colombier int
294*3ff48bf5SDavid du Colombier dirgen(int off, Dir *d, void*)
295*3ff48bf5SDavid du Colombier {
296*3ff48bf5SDavid du Colombier 	int n, j;
297*3ff48bf5SDavid du Colombier 
298*3ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
299*3ff48bf5SDavid du Colombier 	d->atime = time0;
300*3ff48bf5SDavid du Colombier 	d->mtime = time0;
301*3ff48bf5SDavid du Colombier 	if(off == 0){
302*3ff48bf5SDavid du Colombier 		d->name = estrdup9p("ctl");
303*3ff48bf5SDavid du Colombier 		d->mode = ctlmode;
304*3ff48bf5SDavid du Colombier 		d->qid.path = Qctl;
305*3ff48bf5SDavid du Colombier 		goto Have;
306*3ff48bf5SDavid du Colombier 	}
307*3ff48bf5SDavid du Colombier 
308*3ff48bf5SDavid du Colombier 	off--;
309*3ff48bf5SDavid du Colombier 	n = 0;
310*3ff48bf5SDavid du Colombier 	for(j=0; j<nelem(tab); j++){
311*3ff48bf5SDavid du Colombier 		if(tab[j].inuse==0)
312*3ff48bf5SDavid du Colombier 			continue;
313*3ff48bf5SDavid du Colombier 		if(n == off){
314*3ff48bf5SDavid du Colombier 			d->name = estrdup9p(tab[j].name);
315*3ff48bf5SDavid du Colombier 			d->length = tab[j].length;
316*3ff48bf5SDavid du Colombier 			d->mode = tab[j].mode;
317*3ff48bf5SDavid du Colombier 			d->qid.path = Qpart+j;
318*3ff48bf5SDavid du Colombier 			d->qid.vers = tab[j].vers;
319*3ff48bf5SDavid du Colombier 			goto Have;
320*3ff48bf5SDavid du Colombier 		}
321*3ff48bf5SDavid du Colombier 		n++;
322*3ff48bf5SDavid du Colombier 	}
323*3ff48bf5SDavid du Colombier 	return -1;
324*3ff48bf5SDavid du Colombier 
325*3ff48bf5SDavid du Colombier Have:
326*3ff48bf5SDavid du Colombier 	d->uid = estrdup9p("disksim");
327*3ff48bf5SDavid du Colombier 	d->gid = estrdup9p("disksim");
328*3ff48bf5SDavid du Colombier 	d->muid = estrdup9p("");
329*3ff48bf5SDavid du Colombier 	return 0;
330*3ff48bf5SDavid du Colombier }
331*3ff48bf5SDavid du Colombier 
332*3ff48bf5SDavid du Colombier void*
333*3ff48bf5SDavid du Colombier evommem(void *a, void *b, ulong n)
334*3ff48bf5SDavid du Colombier {
335*3ff48bf5SDavid du Colombier 	return memmove(b, a, n);
336*3ff48bf5SDavid du Colombier }
337*3ff48bf5SDavid du Colombier 
338*3ff48bf5SDavid du Colombier int
339*3ff48bf5SDavid du Colombier rdwrpart(Req *r)
340*3ff48bf5SDavid du Colombier {
341*3ff48bf5SDavid du Colombier 	int q;
342*3ff48bf5SDavid du Colombier 	Part *p;
343*3ff48bf5SDavid du Colombier 	vlong offset;
344*3ff48bf5SDavid du Colombier 	long count, tot, n, o;
345*3ff48bf5SDavid du Colombier 	uchar *blk, *dat;
346*3ff48bf5SDavid du Colombier 	void *(*move)(void*, void*, ulong);
347*3ff48bf5SDavid du Colombier 
348*3ff48bf5SDavid du Colombier 	q = r->fid->qid.path-Qpart;
349*3ff48bf5SDavid du Colombier 	if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
350*3ff48bf5SDavid du Colombier 		respond(r, "unknown partition");
351*3ff48bf5SDavid du Colombier 		return -1;
352*3ff48bf5SDavid du Colombier 	}
353*3ff48bf5SDavid du Colombier 
354*3ff48bf5SDavid du Colombier 	p = &tab[q];
355*3ff48bf5SDavid du Colombier 	offset = r->ifcall.offset;
356*3ff48bf5SDavid du Colombier 	count = r->ifcall.count;
357*3ff48bf5SDavid du Colombier 	if(offset < 0){
358*3ff48bf5SDavid du Colombier 		respond(r, "negative offset");
359*3ff48bf5SDavid du Colombier 		return -1;
360*3ff48bf5SDavid du Colombier 	}
361*3ff48bf5SDavid du Colombier 	if(count < 0){
362*3ff48bf5SDavid du Colombier 		respond(r, "negative count");
363*3ff48bf5SDavid du Colombier 		return -1;
364*3ff48bf5SDavid du Colombier 	}
365*3ff48bf5SDavid du Colombier 	if(offset > p->length*sectsize){
366*3ff48bf5SDavid du Colombier 		respond(r, "offset past end of partition");
367*3ff48bf5SDavid du Colombier 		return -1;
368*3ff48bf5SDavid du Colombier 	}
369*3ff48bf5SDavid du Colombier 	if(offset+count > p->length*sectsize)
370*3ff48bf5SDavid du Colombier 		count = p->length*sectsize - offset;
371*3ff48bf5SDavid du Colombier 	offset += p->offset*sectsize;
372*3ff48bf5SDavid du Colombier 
373*3ff48bf5SDavid du Colombier 	if(r->ifcall.type == Tread)
374*3ff48bf5SDavid du Colombier 		move = memmove;
375*3ff48bf5SDavid du Colombier 	else
376*3ff48bf5SDavid du Colombier 		move = evommem;
377*3ff48bf5SDavid du Colombier 
378*3ff48bf5SDavid du Colombier 	tot = 0;
379*3ff48bf5SDavid du Colombier 	if(r->ifcall.type == Tread)
380*3ff48bf5SDavid du Colombier 		dat = (uchar*)r->ofcall.data;
381*3ff48bf5SDavid du Colombier 	else
382*3ff48bf5SDavid du Colombier 		dat = (uchar*)r->ifcall.data;
383*3ff48bf5SDavid du Colombier 	o = offset & (BLKSZ-1);
384*3ff48bf5SDavid du Colombier 
385*3ff48bf5SDavid du Colombier 	/* left fringe block */
386*3ff48bf5SDavid du Colombier 	if(o && count){
387*3ff48bf5SDavid du Colombier 		blk = getblock(offset, r->ifcall.type==Twrite);
388*3ff48bf5SDavid du Colombier 		if(blk == nil)
389*3ff48bf5SDavid du Colombier 			abort();
390*3ff48bf5SDavid du Colombier 		n = BLKSZ - o;
391*3ff48bf5SDavid du Colombier 		if(n > count)
392*3ff48bf5SDavid du Colombier 			n = count;
393*3ff48bf5SDavid du Colombier 		(*move)(dat, blk+o, n);
394*3ff48bf5SDavid du Colombier 		tot += n;
395*3ff48bf5SDavid du Colombier 	}
396*3ff48bf5SDavid du Colombier 	/* full and right fringe blocks */
397*3ff48bf5SDavid du Colombier 	while(tot < count){
398*3ff48bf5SDavid du Colombier 		blk = getblock(offset+tot, r->ifcall.type==Twrite);
399*3ff48bf5SDavid du Colombier 		if(blk == nil)
400*3ff48bf5SDavid du Colombier 			abort();
401*3ff48bf5SDavid du Colombier 		n = BLKSZ;
402*3ff48bf5SDavid du Colombier 		if(n > count)
403*3ff48bf5SDavid du Colombier 			n = count;
404*3ff48bf5SDavid du Colombier 		(*move)(dat+tot, blk, n);
405*3ff48bf5SDavid du Colombier 		tot += n;
406*3ff48bf5SDavid du Colombier 	}
407*3ff48bf5SDavid du Colombier 	r->ofcall.count = tot;
408*3ff48bf5SDavid du Colombier 	respond(r, nil);
409*3ff48bf5SDavid du Colombier 	return 0;
410*3ff48bf5SDavid du Colombier }
411*3ff48bf5SDavid du Colombier 
412*3ff48bf5SDavid du Colombier void
413*3ff48bf5SDavid du Colombier fsread(Req *r)
414*3ff48bf5SDavid du Colombier {
415*3ff48bf5SDavid du Colombier 	char *s;
416*3ff48bf5SDavid du Colombier 
417*3ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
418*3ff48bf5SDavid du Colombier 	case Qroot:
419*3ff48bf5SDavid du Colombier 		dirread9p(r, rootgen, nil);
420*3ff48bf5SDavid du Colombier 		respond(r, nil);
421*3ff48bf5SDavid du Colombier 		break;
422*3ff48bf5SDavid du Colombier 
423*3ff48bf5SDavid du Colombier 	case Qdir:
424*3ff48bf5SDavid du Colombier 		dirread9p(r, dirgen, nil);
425*3ff48bf5SDavid du Colombier 		respond(r, nil);
426*3ff48bf5SDavid du Colombier 		break;
427*3ff48bf5SDavid du Colombier 
428*3ff48bf5SDavid du Colombier 	case Qctl:
429*3ff48bf5SDavid du Colombier 		s = ctlstring();
430*3ff48bf5SDavid du Colombier 		readstr(r, s);
431*3ff48bf5SDavid du Colombier 		free(s);
432*3ff48bf5SDavid du Colombier 		respond(r, nil);
433*3ff48bf5SDavid du Colombier 		break;
434*3ff48bf5SDavid du Colombier 
435*3ff48bf5SDavid du Colombier 	default:
436*3ff48bf5SDavid du Colombier 		rdwrpart(r);
437*3ff48bf5SDavid du Colombier 		break;
438*3ff48bf5SDavid du Colombier 	}
439*3ff48bf5SDavid du Colombier }
440*3ff48bf5SDavid du Colombier 
441*3ff48bf5SDavid du Colombier void
442*3ff48bf5SDavid du Colombier fswrite(Req *r)
443*3ff48bf5SDavid du Colombier {
444*3ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
445*3ff48bf5SDavid du Colombier 	case Qroot:
446*3ff48bf5SDavid du Colombier 	case Qdir:
447*3ff48bf5SDavid du Colombier 		respond(r, "write to a directory?");
448*3ff48bf5SDavid du Colombier 		break;
449*3ff48bf5SDavid du Colombier 
450*3ff48bf5SDavid du Colombier 	case Qctl:
451*3ff48bf5SDavid du Colombier 		ctlwrite(r);
452*3ff48bf5SDavid du Colombier 		break;
453*3ff48bf5SDavid du Colombier 
454*3ff48bf5SDavid du Colombier 	default:
455*3ff48bf5SDavid du Colombier 		rdwrpart(r);
456*3ff48bf5SDavid du Colombier 		break;
457*3ff48bf5SDavid du Colombier 	}
458*3ff48bf5SDavid du Colombier }
459*3ff48bf5SDavid du Colombier 
460*3ff48bf5SDavid du Colombier void
461*3ff48bf5SDavid du Colombier fsopen(Req *r)
462*3ff48bf5SDavid du Colombier {
463*3ff48bf5SDavid du Colombier 	if(r->ifcall.mode&ORCLOSE)
464*3ff48bf5SDavid du Colombier 		respond(r, "cannot open ORCLOSE");
465*3ff48bf5SDavid du Colombier 
466*3ff48bf5SDavid du Colombier 	switch((int)r->fid->qid.path){
467*3ff48bf5SDavid du Colombier 	case Qroot:
468*3ff48bf5SDavid du Colombier 	case Qdir:
469*3ff48bf5SDavid du Colombier 		if(r->ifcall.mode != OREAD){
470*3ff48bf5SDavid du Colombier 			respond(r, "bad mode for directory open");
471*3ff48bf5SDavid du Colombier 			return;
472*3ff48bf5SDavid du Colombier 		}
473*3ff48bf5SDavid du Colombier 	}
474*3ff48bf5SDavid du Colombier 
475*3ff48bf5SDavid du Colombier 	respond(r, nil);
476*3ff48bf5SDavid du Colombier }
477*3ff48bf5SDavid du Colombier 
478*3ff48bf5SDavid du Colombier void
479*3ff48bf5SDavid du Colombier fsstat(Req *r)
480*3ff48bf5SDavid du Colombier {
481*3ff48bf5SDavid du Colombier 	int q;
482*3ff48bf5SDavid du Colombier 	Dir *d;
483*3ff48bf5SDavid du Colombier 	Part *p;
484*3ff48bf5SDavid du Colombier 
485*3ff48bf5SDavid du Colombier 	d = &r->d;
486*3ff48bf5SDavid du Colombier 	memset(d, 0, sizeof *d);
487*3ff48bf5SDavid du Colombier 	d->qid = r->fid->qid;
488*3ff48bf5SDavid du Colombier 	d->atime = d->mtime = time0;
489*3ff48bf5SDavid du Colombier 	q = r->fid->qid.path;
490*3ff48bf5SDavid du Colombier 	switch(q){
491*3ff48bf5SDavid du Colombier 	case Qroot:
492*3ff48bf5SDavid du Colombier 		d->name = estrdup9p("/");
493*3ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
494*3ff48bf5SDavid du Colombier 		break;
495*3ff48bf5SDavid du Colombier 
496*3ff48bf5SDavid du Colombier 	case Qdir:
497*3ff48bf5SDavid du Colombier 		d->name = estrdup9p(sdname);
498*3ff48bf5SDavid du Colombier 		d->mode = DMDIR|0777;
499*3ff48bf5SDavid du Colombier 		break;
500*3ff48bf5SDavid du Colombier 
501*3ff48bf5SDavid du Colombier 	default:
502*3ff48bf5SDavid du Colombier 		q -= Qpart;
503*3ff48bf5SDavid du Colombier 		if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
504*3ff48bf5SDavid du Colombier 			respond(r, "partition no longer exists");
505*3ff48bf5SDavid du Colombier 			return;
506*3ff48bf5SDavid du Colombier 		}
507*3ff48bf5SDavid du Colombier 		p = &tab[q];
508*3ff48bf5SDavid du Colombier 		d->name = estrdup9p(p->name);
509*3ff48bf5SDavid du Colombier 		d->length = p->length * sectsize;
510*3ff48bf5SDavid du Colombier 		d->mode = p->mode;
511*3ff48bf5SDavid du Colombier 		break;
512*3ff48bf5SDavid du Colombier 	}
513*3ff48bf5SDavid du Colombier 
514*3ff48bf5SDavid du Colombier 	d->uid = estrdup9p("disksim");
515*3ff48bf5SDavid du Colombier 	d->gid = estrdup9p("disksim");
516*3ff48bf5SDavid du Colombier 	d->muid = estrdup9p("");
517*3ff48bf5SDavid du Colombier 	respond(r, nil);
518*3ff48bf5SDavid du Colombier }
519*3ff48bf5SDavid du Colombier 
520*3ff48bf5SDavid du Colombier void
521*3ff48bf5SDavid du Colombier fsattach(Req *r)
522*3ff48bf5SDavid du Colombier {
523*3ff48bf5SDavid du Colombier 	char *spec;
524*3ff48bf5SDavid du Colombier 
525*3ff48bf5SDavid du Colombier 	spec = r->ifcall.aname;
526*3ff48bf5SDavid du Colombier 	if(spec && spec[0]){
527*3ff48bf5SDavid du Colombier 		respond(r, "invalid attach specifier");
528*3ff48bf5SDavid du Colombier 		return;
529*3ff48bf5SDavid du Colombier 	}
530*3ff48bf5SDavid du Colombier 	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
531*3ff48bf5SDavid du Colombier 	r->fid->qid = r->ofcall.qid;
532*3ff48bf5SDavid du Colombier 	respond(r, nil);
533*3ff48bf5SDavid du Colombier }
534*3ff48bf5SDavid du Colombier 
535*3ff48bf5SDavid du Colombier char*
536*3ff48bf5SDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
537*3ff48bf5SDavid du Colombier {
538*3ff48bf5SDavid du Colombier 	int i;
539*3ff48bf5SDavid du Colombier 	switch((int)fid->qid.path){
540*3ff48bf5SDavid du Colombier 	case Qroot:
541*3ff48bf5SDavid du Colombier 		if(strcmp(name, sdname) == 0){
542*3ff48bf5SDavid du Colombier 			fid->qid.path = Qdir;
543*3ff48bf5SDavid du Colombier 			fid->qid.type = QTDIR;
544*3ff48bf5SDavid du Colombier 			*qid = fid->qid;
545*3ff48bf5SDavid du Colombier 			return nil;
546*3ff48bf5SDavid du Colombier 		}
547*3ff48bf5SDavid du Colombier 		break;
548*3ff48bf5SDavid du Colombier 	case Qdir:
549*3ff48bf5SDavid du Colombier 		if(strcmp(name, "ctl") == 0){
550*3ff48bf5SDavid du Colombier 			fid->qid.path = Qctl;
551*3ff48bf5SDavid du Colombier 			fid->qid.vers = 0;
552*3ff48bf5SDavid du Colombier 			fid->qid.type = 0;
553*3ff48bf5SDavid du Colombier 			*qid = fid->qid;
554*3ff48bf5SDavid du Colombier 			return nil;
555*3ff48bf5SDavid du Colombier 		}
556*3ff48bf5SDavid du Colombier 		for(i=0; i<nelem(tab); i++){
557*3ff48bf5SDavid du Colombier 			if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
558*3ff48bf5SDavid du Colombier 				fid->qid.path = i+Qpart;
559*3ff48bf5SDavid du Colombier 				fid->qid.vers = tab[i].vers;
560*3ff48bf5SDavid du Colombier 				fid->qid.type = 0;
561*3ff48bf5SDavid du Colombier 				*qid = fid->qid;
562*3ff48bf5SDavid du Colombier 				return nil;
563*3ff48bf5SDavid du Colombier 			}
564*3ff48bf5SDavid du Colombier 		}
565*3ff48bf5SDavid du Colombier 		break;
566*3ff48bf5SDavid du Colombier 	}
567*3ff48bf5SDavid du Colombier 	return "file not found";
568*3ff48bf5SDavid du Colombier }
569*3ff48bf5SDavid du Colombier 
570*3ff48bf5SDavid du Colombier Srv fs = {
571*3ff48bf5SDavid du Colombier 	.attach=	fsattach,
572*3ff48bf5SDavid du Colombier 	.open=	fsopen,
573*3ff48bf5SDavid du Colombier 	.read=	fsread,
574*3ff48bf5SDavid du Colombier 	.write=	fswrite,
575*3ff48bf5SDavid du Colombier 	.stat=	fsstat,
576*3ff48bf5SDavid du Colombier 	.walk1=	fswalk1,
577*3ff48bf5SDavid du Colombier };
578*3ff48bf5SDavid du Colombier 
579*3ff48bf5SDavid du Colombier char *mtpt = "/dev";
580*3ff48bf5SDavid du Colombier char *srvname;
581*3ff48bf5SDavid du Colombier 
582*3ff48bf5SDavid du Colombier void
583*3ff48bf5SDavid du Colombier usage(void)
584*3ff48bf5SDavid du Colombier {
585*3ff48bf5SDavid du Colombier 	fprint(2, "usage: aux/disksim [-D] [-s srvname] [-m mtpt] [sdXX]\n");
586*3ff48bf5SDavid du Colombier 	fprint(2, "\tdefault mtpt is /dev\n");
587*3ff48bf5SDavid du Colombier 	exits("usage");
588*3ff48bf5SDavid du Colombier }
589*3ff48bf5SDavid du Colombier 
590*3ff48bf5SDavid du Colombier void
591*3ff48bf5SDavid du Colombier main(int argc, char **argv)
592*3ff48bf5SDavid du Colombier {
593*3ff48bf5SDavid du Colombier 	quotefmtinstall();
594*3ff48bf5SDavid du Colombier 	time0 = time(0);
595*3ff48bf5SDavid du Colombier 	if(NPTR != BLKSZ/sizeof(void*))
596*3ff48bf5SDavid du Colombier 		sysfatal("unexpected pointer size");
597*3ff48bf5SDavid du Colombier 
598*3ff48bf5SDavid du Colombier 	ARGBEGIN{
599*3ff48bf5SDavid du Colombier 	case 'D':
600*3ff48bf5SDavid du Colombier 		chatty9p++;
601*3ff48bf5SDavid du Colombier 		break;
602*3ff48bf5SDavid du Colombier 	case 's':
603*3ff48bf5SDavid du Colombier 		srvname = EARGF(usage());
604*3ff48bf5SDavid du Colombier 		break;
605*3ff48bf5SDavid du Colombier 	case 'm':
606*3ff48bf5SDavid du Colombier 		mtpt = EARGF(usage());
607*3ff48bf5SDavid du Colombier 		break;
608*3ff48bf5SDavid du Colombier 	default:
609*3ff48bf5SDavid du Colombier 		usage();
610*3ff48bf5SDavid du Colombier 	}ARGEND
611*3ff48bf5SDavid du Colombier 
612*3ff48bf5SDavid du Colombier 	if(argc > 1)
613*3ff48bf5SDavid du Colombier 		usage();
614*3ff48bf5SDavid du Colombier 	if(argc == 1)
615*3ff48bf5SDavid du Colombier 		sdname = argv[0];
616*3ff48bf5SDavid du Colombier 
617*3ff48bf5SDavid du Colombier 	inquiry = estrdup9p(inquiry);
618*3ff48bf5SDavid du Colombier 	tab[0].name = estrdup9p("data");
619*3ff48bf5SDavid du Colombier 	tab[0].inuse = 1;
620*3ff48bf5SDavid du Colombier 	tab[0].mode = 0666;
621*3ff48bf5SDavid du Colombier 
622*3ff48bf5SDavid du Colombier 	postmountsrv(&fs, srvname, mtpt, MBEFORE);
623*3ff48bf5SDavid du Colombier 	exits(nil);
624*3ff48bf5SDavid du Colombier }
625