xref: /plan9/sys/src/cmd/disk/partfs.c (revision 23173ec17955c609738f37acefe0c6e72a169a75)
1715d0f95SDavid du Colombier /*
2715d0f95SDavid du Colombier  * partfs - serve an underlying file, with devsd-style partitions
3715d0f95SDavid du Colombier  */
4715d0f95SDavid du Colombier #include <u.h>
5715d0f95SDavid du Colombier #include <libc.h>
6715d0f95SDavid du Colombier #include <auth.h>
7715d0f95SDavid du Colombier #include <fcall.h>
8715d0f95SDavid du Colombier #include <thread.h>
9715d0f95SDavid du Colombier #include <9p.h>
10715d0f95SDavid du Colombier 
11715d0f95SDavid du Colombier typedef struct Part Part;
12715d0f95SDavid du Colombier struct Part
13715d0f95SDavid du Colombier {
14715d0f95SDavid du Colombier 	int	inuse;
15715d0f95SDavid du Colombier 	int	vers;
16715d0f95SDavid du Colombier 	ulong	mode;
17715d0f95SDavid du Colombier 	char	*name;
18715d0f95SDavid du Colombier 	vlong	offset;		/* in sectors */
19715d0f95SDavid du Colombier 	vlong	length;		/* in sectors */
20715d0f95SDavid du Colombier };
21715d0f95SDavid du Colombier 
22715d0f95SDavid du Colombier enum
23715d0f95SDavid du Colombier {
24715d0f95SDavid du Colombier 	Qroot = 0,
25715d0f95SDavid du Colombier 	Qdir,
26715d0f95SDavid du Colombier 	Qctl,
27715d0f95SDavid du Colombier 	Qpart,
28715d0f95SDavid du Colombier };
29715d0f95SDavid du Colombier 
30715d0f95SDavid du Colombier int fd = -1, ctlfd = -1;
31715d0f95SDavid du Colombier int rdonly;
32715d0f95SDavid du Colombier ulong ctlmode = 0666;
33715d0f95SDavid du Colombier ulong time0;
34715d0f95SDavid du Colombier vlong nsect, sectsize;
35715d0f95SDavid du Colombier 
36715d0f95SDavid du Colombier char *inquiry = "partfs hard drive";
37715d0f95SDavid du Colombier char *sdname = "sdXX";
38715d0f95SDavid du Colombier Part tab[64];
39715d0f95SDavid du Colombier 
40715d0f95SDavid du Colombier char*
ctlstring(void)41715d0f95SDavid du Colombier ctlstring(void)
42715d0f95SDavid du Colombier {
43715d0f95SDavid du Colombier 	Part *p;
44715d0f95SDavid du Colombier 	Fmt fmt;
45715d0f95SDavid du Colombier 
46715d0f95SDavid du Colombier 	fmtstrinit(&fmt);
47715d0f95SDavid du Colombier 	fmtprint(&fmt, "inquiry %s\n", inquiry);
48715d0f95SDavid du Colombier 	fmtprint(&fmt, "geometry %lld %lld\n", nsect, sectsize);
49715d0f95SDavid du Colombier 	for (p = tab; p < tab + nelem(tab); p++)
50715d0f95SDavid du Colombier 		if (p->inuse)
51715d0f95SDavid du Colombier 			fmtprint(&fmt, "part %s %lld %lld\n",
52715d0f95SDavid du Colombier 				p->name, p->offset, p->length);
53715d0f95SDavid du Colombier 	return fmtstrflush(&fmt);
54715d0f95SDavid du Colombier }
55715d0f95SDavid du Colombier 
56715d0f95SDavid du Colombier int
addpart(char * name,vlong start,vlong end)57715d0f95SDavid du Colombier addpart(char *name, vlong start, vlong end)
58715d0f95SDavid du Colombier {
59715d0f95SDavid du Colombier 	Part *p;
60715d0f95SDavid du Colombier 
61715d0f95SDavid du Colombier 	if(start < 0 || start > end || end > nsect){
62715d0f95SDavid du Colombier 		werrstr("bad partition boundaries");
63715d0f95SDavid du Colombier 		return -1;
64715d0f95SDavid du Colombier 	}
65715d0f95SDavid du Colombier 
66715d0f95SDavid du Colombier 	if (strcmp(name, "ctl") == 0 || strcmp(name, "data") == 0) {
67715d0f95SDavid du Colombier 		werrstr("partition name already in use");
68715d0f95SDavid du Colombier 		return -1;
69715d0f95SDavid du Colombier 	}
70715d0f95SDavid du Colombier 	for (p = tab; p < tab + nelem(tab) && p->inuse; p++)
71715d0f95SDavid du Colombier 		if (strcmp(p->name, name) == 0) {
72715d0f95SDavid du Colombier 			werrstr("partition name already in use");
73715d0f95SDavid du Colombier 			return -1;
74715d0f95SDavid du Colombier 		}
75715d0f95SDavid du Colombier 	if(p == tab + nelem(tab)){
76715d0f95SDavid du Colombier 		werrstr("no free partition slots");
77715d0f95SDavid du Colombier 		return -1;
78715d0f95SDavid du Colombier 	}
79715d0f95SDavid du Colombier 
80715d0f95SDavid du Colombier 	p->inuse = 1;
81715d0f95SDavid du Colombier 	free(p->name);
82715d0f95SDavid du Colombier 	p->name = estrdup9p(name);
83715d0f95SDavid du Colombier 	p->offset = start;
84715d0f95SDavid du Colombier 	p->length = end - start;
85715d0f95SDavid du Colombier 	p->mode = ctlmode;
86715d0f95SDavid du Colombier 	p->vers++;
87715d0f95SDavid du Colombier 	return 0;
88715d0f95SDavid du Colombier }
89715d0f95SDavid du Colombier 
90715d0f95SDavid du Colombier int
delpart(char * s)91715d0f95SDavid du Colombier delpart(char *s)
92715d0f95SDavid du Colombier {
93715d0f95SDavid du Colombier 	Part *p;
94715d0f95SDavid du Colombier 
95715d0f95SDavid du Colombier 	for (p = tab; p < tab + nelem(tab); p++)
96715d0f95SDavid du Colombier 		if(p->inuse && strcmp(p->name, s) == 0)
97715d0f95SDavid du Colombier 			break;
98715d0f95SDavid du Colombier 	if(p == tab + nelem(tab)){
99715d0f95SDavid du Colombier 		werrstr("partition not found");
100715d0f95SDavid du Colombier 		return -1;
101715d0f95SDavid du Colombier 	}
102715d0f95SDavid du Colombier 
103715d0f95SDavid du Colombier 	p->inuse = 0;
104715d0f95SDavid du Colombier 	free(p->name);
105715d0f95SDavid du Colombier 	p->name = nil;
106715d0f95SDavid du Colombier 	return 0;
107715d0f95SDavid du Colombier }
108715d0f95SDavid du Colombier 
109715d0f95SDavid du Colombier static void
addparts(char * buf)110*8c055935SDavid du Colombier addparts(char *buf)
111*8c055935SDavid du Colombier {
112*8c055935SDavid du Colombier 	char *f[4], *p, *q;
113*8c055935SDavid du Colombier 
114*8c055935SDavid du Colombier 	/*
115*8c055935SDavid du Colombier 	 * Use partitions passed from boot program,
116*8c055935SDavid du Colombier 	 * e.g.
117*8c055935SDavid du Colombier 	 *	sdC0part=dos 63 123123/plan9 123123 456456
118*8c055935SDavid du Colombier 	 * This happens before /boot sets hostname so the
119*8c055935SDavid du Colombier 	 * partitions will have the null-string for user.
120*8c055935SDavid du Colombier 	 */
121*8c055935SDavid du Colombier 	for(p = buf; p != nil; p = q){
122*8c055935SDavid du Colombier 		if(q = strchr(p, '/'))
123*8c055935SDavid du Colombier 			*q++ = '\0';
124*8c055935SDavid du Colombier 		if(tokenize(p, f, nelem(f)) >= 3 &&
125*8c055935SDavid du Colombier 		    addpart(f[0], strtoull(f[1], 0, 0), strtoull(f[2], 0, 0)) < 0)
126*8c055935SDavid du Colombier 			fprint(2, "%s: addpart %s: %r\n", argv0, f[0]);
127*8c055935SDavid du Colombier 	}
128*8c055935SDavid du Colombier }
129*8c055935SDavid du Colombier 
130*8c055935SDavid du Colombier static void
ctlwrite0(Req * r,char * msg,Cmdbuf * cb)131715d0f95SDavid du Colombier ctlwrite0(Req *r, char *msg, Cmdbuf *cb)
132715d0f95SDavid du Colombier {
133715d0f95SDavid du Colombier 	vlong start, end;
134715d0f95SDavid du Colombier 	Part *p;
135715d0f95SDavid du Colombier 
136715d0f95SDavid du Colombier 	r->ofcall.count = r->ifcall.count;
137715d0f95SDavid du Colombier 
138715d0f95SDavid du Colombier 	if(cb->nf < 1){
139715d0f95SDavid du Colombier 		respond(r, "empty control message");
140715d0f95SDavid du Colombier 		return;
141715d0f95SDavid du Colombier 	}
142715d0f95SDavid du Colombier 
143715d0f95SDavid du Colombier 	if(strcmp(cb->f[0], "part") == 0){
144715d0f95SDavid du Colombier 		if(cb->nf != 4){
145715d0f95SDavid du Colombier 			respondcmderror(r, cb, "part takes 3 args");
146715d0f95SDavid du Colombier 			return;
147715d0f95SDavid du Colombier 		}
148715d0f95SDavid du Colombier 		start = strtoll(cb->f[2], 0, 0);
149715d0f95SDavid du Colombier 		end = strtoll(cb->f[3], 0, 0);
150715d0f95SDavid du Colombier 		if(addpart(cb->f[1], start, end) < 0){
151715d0f95SDavid du Colombier 			respondcmderror(r, cb, "%r");
152715d0f95SDavid du Colombier 			return;
153715d0f95SDavid du Colombier 		}
154715d0f95SDavid du Colombier 	}
155715d0f95SDavid du Colombier 	else if(strcmp(cb->f[0], "delpart") == 0){
156715d0f95SDavid du Colombier 		if(cb->nf != 2){
157715d0f95SDavid du Colombier 			respondcmderror(r, cb, "delpart takes 1 arg");
158715d0f95SDavid du Colombier 			return;
159715d0f95SDavid du Colombier 		}
160715d0f95SDavid du Colombier 		if(delpart(cb->f[1]) < 0){
161715d0f95SDavid du Colombier 			respondcmderror(r, cb, "%r");
162715d0f95SDavid du Colombier 			return;
163715d0f95SDavid du Colombier 		}
164715d0f95SDavid du Colombier 	}
165715d0f95SDavid du Colombier 	else if(strcmp(cb->f[0], "inquiry") == 0){
166715d0f95SDavid du Colombier 		if(cb->nf != 2){
167715d0f95SDavid du Colombier 			respondcmderror(r, cb, "inquiry takes 1 arg");
168715d0f95SDavid du Colombier 			return;
169715d0f95SDavid du Colombier 		}
170715d0f95SDavid du Colombier 		free(inquiry);
171715d0f95SDavid du Colombier 		inquiry = estrdup9p(cb->f[1]);
172715d0f95SDavid du Colombier 	}
173715d0f95SDavid du Colombier 	else if(strcmp(cb->f[0], "geometry") == 0){
174715d0f95SDavid du Colombier 		if(cb->nf != 3){
175715d0f95SDavid du Colombier 			respondcmderror(r, cb, "geometry takes 2 args");
176715d0f95SDavid du Colombier 			return;
177715d0f95SDavid du Colombier 		}
178715d0f95SDavid du Colombier 		nsect = strtoll(cb->f[1], 0, 0);
179715d0f95SDavid du Colombier 		sectsize = strtoll(cb->f[2], 0, 0);
180715d0f95SDavid du Colombier 		if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 &&
181715d0f95SDavid du Colombier 		    tab[0].vers == 0){
182715d0f95SDavid du Colombier 			tab[0].offset = 0;
183715d0f95SDavid du Colombier 			tab[0].length = nsect;
184715d0f95SDavid du Colombier 		}
185715d0f95SDavid du Colombier 		for(p = tab; p < tab + nelem(tab); p++)
186715d0f95SDavid du Colombier 			if(p->inuse && p->offset + p->length > nsect){
187715d0f95SDavid du Colombier 				p->inuse = 0;
188715d0f95SDavid du Colombier 				free(p->name);
189715d0f95SDavid du Colombier 				p->name = nil;
190715d0f95SDavid du Colombier 			}
191715d0f95SDavid du Colombier 	} else
192715d0f95SDavid du Colombier 		/* pass through to underlying ctl file, if any */
193715d0f95SDavid du Colombier 		if (write(ctlfd, msg, r->ifcall.count) != r->ifcall.count) {
194715d0f95SDavid du Colombier 			respondcmderror(r, cb, "%r");
195715d0f95SDavid du Colombier 			return;
196715d0f95SDavid du Colombier 		}
197715d0f95SDavid du Colombier 	respond(r, nil);
198715d0f95SDavid du Colombier }
199715d0f95SDavid du Colombier 
200715d0f95SDavid du Colombier void
ctlwrite(Req * r)201715d0f95SDavid du Colombier ctlwrite(Req *r)
202715d0f95SDavid du Colombier {
203715d0f95SDavid du Colombier 	char *msg;
204715d0f95SDavid du Colombier 	Cmdbuf *cb;
205715d0f95SDavid du Colombier 
206715d0f95SDavid du Colombier 	r->ofcall.count = r->ifcall.count;
207715d0f95SDavid du Colombier 
208715d0f95SDavid du Colombier 	msg = emalloc9p(r->ifcall.count+1);
209715d0f95SDavid du Colombier 	memmove(msg, r->ifcall.data, r->ifcall.count);
210715d0f95SDavid du Colombier 	msg[r->ifcall.count] = '\0';
211715d0f95SDavid du Colombier 
212715d0f95SDavid du Colombier 	cb = parsecmd(r->ifcall.data, r->ifcall.count);
213715d0f95SDavid du Colombier 	ctlwrite0(r, msg, cb);
214715d0f95SDavid du Colombier 
215715d0f95SDavid du Colombier 	free(cb);
216715d0f95SDavid du Colombier 	free(msg);
217715d0f95SDavid du Colombier }
218715d0f95SDavid du Colombier 
219715d0f95SDavid du Colombier int
rootgen(int off,Dir * d,void *)220715d0f95SDavid du Colombier rootgen(int off, Dir *d, void*)
221715d0f95SDavid du Colombier {
222715d0f95SDavid du Colombier 	memset(d, 0, sizeof *d);
223715d0f95SDavid du Colombier 	d->atime = time0;
224715d0f95SDavid du Colombier 	d->mtime = time0;
225715d0f95SDavid du Colombier 	if(off == 0){
226715d0f95SDavid du Colombier 		d->name = estrdup9p(sdname);
227715d0f95SDavid du Colombier 		d->mode = DMDIR|0777;
228715d0f95SDavid du Colombier 		d->qid.path = Qdir;
229715d0f95SDavid du Colombier 		d->qid.type = QTDIR;
230715d0f95SDavid du Colombier 		d->uid = estrdup9p("partfs");
231715d0f95SDavid du Colombier 		d->gid = estrdup9p("partfs");
232715d0f95SDavid du Colombier 		d->muid = estrdup9p("");
233715d0f95SDavid du Colombier 		return 0;
234715d0f95SDavid du Colombier 	}
235715d0f95SDavid du Colombier 	return -1;
236715d0f95SDavid du Colombier }
237715d0f95SDavid du Colombier 
238715d0f95SDavid du Colombier int
dirgen(int off,Dir * d,void *)239715d0f95SDavid du Colombier dirgen(int off, Dir *d, void*)
240715d0f95SDavid du Colombier {
241715d0f95SDavid du Colombier 	int n;
242715d0f95SDavid du Colombier 	Part *p;
243715d0f95SDavid du Colombier 
244715d0f95SDavid du Colombier 	memset(d, 0, sizeof *d);
245715d0f95SDavid du Colombier 	d->atime = time0;
246715d0f95SDavid du Colombier 	d->mtime = time0;
247715d0f95SDavid du Colombier 	if(off == 0){
248715d0f95SDavid du Colombier 		d->name = estrdup9p("ctl");
249715d0f95SDavid du Colombier 		d->mode = ctlmode;
250715d0f95SDavid du Colombier 		d->qid.path = Qctl;
251715d0f95SDavid du Colombier 		goto Have;
252715d0f95SDavid du Colombier 	}
253715d0f95SDavid du Colombier 
254715d0f95SDavid du Colombier 	off--;
255715d0f95SDavid du Colombier 	n = 0;
256715d0f95SDavid du Colombier 	for(p = tab; p < tab + nelem(tab); p++, n++){
257715d0f95SDavid du Colombier 		if(!p->inuse)
258715d0f95SDavid du Colombier 			continue;
259715d0f95SDavid du Colombier 		if(n == off){
260715d0f95SDavid du Colombier 			d->name = estrdup9p(p->name);
261715d0f95SDavid du Colombier 			d->length = p->length*sectsize;
262715d0f95SDavid du Colombier 			d->mode = p->mode;
263715d0f95SDavid du Colombier 			d->qid.path = Qpart + p - tab;
264715d0f95SDavid du Colombier 			d->qid.vers = p->vers;
265715d0f95SDavid du Colombier 			goto Have;
266715d0f95SDavid du Colombier 		}
267715d0f95SDavid du Colombier 	}
268715d0f95SDavid du Colombier 	return -1;
269715d0f95SDavid du Colombier 
270715d0f95SDavid du Colombier Have:
271715d0f95SDavid du Colombier 	d->uid = estrdup9p("partfs");
272715d0f95SDavid du Colombier 	d->gid = estrdup9p("partfs");
273715d0f95SDavid du Colombier 	d->muid = estrdup9p("");
274715d0f95SDavid du Colombier 	return 0;
275715d0f95SDavid du Colombier }
276715d0f95SDavid du Colombier 
277715d0f95SDavid du Colombier int
rdwrpart(Req * r)278715d0f95SDavid du Colombier rdwrpart(Req *r)
279715d0f95SDavid du Colombier {
280715d0f95SDavid du Colombier 	int q;
281715d0f95SDavid du Colombier 	long count, tot;
282715d0f95SDavid du Colombier 	vlong offset;
283715d0f95SDavid du Colombier 	uchar *dat;
284715d0f95SDavid du Colombier 	Part *p;
285715d0f95SDavid du Colombier 
286715d0f95SDavid du Colombier 	q = r->fid->qid.path - Qpart;
287715d0f95SDavid du Colombier 	if(q < 0 || q > nelem(tab) || !tab[q].inuse ||
288715d0f95SDavid du Colombier 	    tab[q].vers != r->fid->qid.vers){
289715d0f95SDavid du Colombier 		respond(r, "unknown partition");
290715d0f95SDavid du Colombier 		return -1;
291715d0f95SDavid du Colombier 	}
292715d0f95SDavid du Colombier 	p = &tab[q];
293715d0f95SDavid du Colombier 
294715d0f95SDavid du Colombier 	offset = r->ifcall.offset;
295715d0f95SDavid du Colombier 	count = r->ifcall.count;
296715d0f95SDavid du Colombier 	if(offset < 0){
297715d0f95SDavid du Colombier 		respond(r, "negative offset");
298715d0f95SDavid du Colombier 		return -1;
299715d0f95SDavid du Colombier 	}
300715d0f95SDavid du Colombier 	if(count < 0){
301715d0f95SDavid du Colombier 		respond(r, "negative count");
302715d0f95SDavid du Colombier 		return -1;
303715d0f95SDavid du Colombier 	}
304715d0f95SDavid du Colombier 	if(offset > p->length*sectsize){
305715d0f95SDavid du Colombier 		respond(r, "offset past end of partition");
306715d0f95SDavid du Colombier 		return -1;
307715d0f95SDavid du Colombier 	}
308715d0f95SDavid du Colombier 	if(offset+count > p->length*sectsize)
309715d0f95SDavid du Colombier 		count = p->length*sectsize - offset;
310715d0f95SDavid du Colombier 	offset += p->offset*sectsize;
311715d0f95SDavid du Colombier 
312715d0f95SDavid du Colombier 	if(r->ifcall.type == Tread)
313715d0f95SDavid du Colombier 		dat = (uchar*)r->ofcall.data;
314715d0f95SDavid du Colombier 	else
315715d0f95SDavid du Colombier 		dat = (uchar*)r->ifcall.data;
316715d0f95SDavid du Colombier 
317715d0f95SDavid du Colombier 	/* pass i/o through to underlying file */
318715d0f95SDavid du Colombier 	seek(fd, offset, 0);
319715d0f95SDavid du Colombier 	if (r->ifcall.type == Twrite) {
320715d0f95SDavid du Colombier 		tot = write(fd, dat, count);
321715d0f95SDavid du Colombier 		if (tot != count) {
322715d0f95SDavid du Colombier 			respond(r, "%r");
323715d0f95SDavid du Colombier 			return -1;
324715d0f95SDavid du Colombier 		}
325715d0f95SDavid du Colombier 	} else {
326715d0f95SDavid du Colombier 		tot = read(fd, dat, count);
327715d0f95SDavid du Colombier 		if (tot < 0) {
328715d0f95SDavid du Colombier 			respond(r, "%r");
329715d0f95SDavid du Colombier 			return -1;
330715d0f95SDavid du Colombier 		}
331715d0f95SDavid du Colombier 	}
332715d0f95SDavid du Colombier 	r->ofcall.count = tot;
333715d0f95SDavid du Colombier 	respond(r, nil);
334715d0f95SDavid du Colombier 	return 0;
335715d0f95SDavid du Colombier }
336715d0f95SDavid du Colombier 
337715d0f95SDavid du Colombier void
fsread(Req * r)338715d0f95SDavid du Colombier fsread(Req *r)
339715d0f95SDavid du Colombier {
340715d0f95SDavid du Colombier 	char *s;
341715d0f95SDavid du Colombier 
342715d0f95SDavid du Colombier 	switch((int)r->fid->qid.path){
343715d0f95SDavid du Colombier 	case Qroot:
344715d0f95SDavid du Colombier 		dirread9p(r, rootgen, nil);
345715d0f95SDavid du Colombier 		break;
346715d0f95SDavid du Colombier 	case Qdir:
347715d0f95SDavid du Colombier 		dirread9p(r, dirgen, nil);
348715d0f95SDavid du Colombier 		break;
349715d0f95SDavid du Colombier 	case Qctl:
350715d0f95SDavid du Colombier 		s = ctlstring();
351715d0f95SDavid du Colombier 		readstr(r, s);
352715d0f95SDavid du Colombier 		free(s);
353715d0f95SDavid du Colombier 		break;
354715d0f95SDavid du Colombier 	default:
355715d0f95SDavid du Colombier 		rdwrpart(r);
356715d0f95SDavid du Colombier 		return;
357715d0f95SDavid du Colombier 	}
358715d0f95SDavid du Colombier 	respond(r, nil);
359715d0f95SDavid du Colombier }
360715d0f95SDavid du Colombier 
361715d0f95SDavid du Colombier void
fswrite(Req * r)362715d0f95SDavid du Colombier fswrite(Req *r)
363715d0f95SDavid du Colombier {
364715d0f95SDavid du Colombier 	switch((int)r->fid->qid.path){
365715d0f95SDavid du Colombier 	case Qroot:
366715d0f95SDavid du Colombier 	case Qdir:
367715d0f95SDavid du Colombier 		respond(r, "write to a directory?");
368715d0f95SDavid du Colombier 		break;
369715d0f95SDavid du Colombier 	case Qctl:
370715d0f95SDavid du Colombier 		ctlwrite(r);
371715d0f95SDavid du Colombier 		break;
372715d0f95SDavid du Colombier 	default:
373715d0f95SDavid du Colombier 		rdwrpart(r);
374715d0f95SDavid du Colombier 		break;
375715d0f95SDavid du Colombier 	}
376715d0f95SDavid du Colombier }
377715d0f95SDavid du Colombier 
378715d0f95SDavid du Colombier void
fsopen(Req * r)379715d0f95SDavid du Colombier fsopen(Req *r)
380715d0f95SDavid du Colombier {
381715d0f95SDavid du Colombier 	if(r->ifcall.mode&ORCLOSE)
382715d0f95SDavid du Colombier 		respond(r, "cannot open ORCLOSE");
383715d0f95SDavid du Colombier 
384715d0f95SDavid du Colombier 	switch((int)r->fid->qid.path){
385715d0f95SDavid du Colombier 	case Qroot:
386715d0f95SDavid du Colombier 	case Qdir:
387715d0f95SDavid du Colombier 		if(r->ifcall.mode != OREAD){
388715d0f95SDavid du Colombier 			respond(r, "bad mode for directory open");
389715d0f95SDavid du Colombier 			return;
390715d0f95SDavid du Colombier 		}
391715d0f95SDavid du Colombier 	}
392715d0f95SDavid du Colombier 
393715d0f95SDavid du Colombier 	respond(r, nil);
394715d0f95SDavid du Colombier }
395715d0f95SDavid du Colombier 
396715d0f95SDavid du Colombier void
fsstat(Req * r)397715d0f95SDavid du Colombier fsstat(Req *r)
398715d0f95SDavid du Colombier {
399715d0f95SDavid du Colombier 	int q;
400715d0f95SDavid du Colombier 	Dir *d;
401715d0f95SDavid du Colombier 	Part *p;
402715d0f95SDavid du Colombier 
403715d0f95SDavid du Colombier 	d = &r->d;
404715d0f95SDavid du Colombier 	memset(d, 0, sizeof *d);
405715d0f95SDavid du Colombier 	d->qid = r->fid->qid;
406715d0f95SDavid du Colombier 	d->atime = d->mtime = time0;
407715d0f95SDavid du Colombier 	q = r->fid->qid.path;
408715d0f95SDavid du Colombier 	switch(q){
409715d0f95SDavid du Colombier 	case Qroot:
410715d0f95SDavid du Colombier 		d->name = estrdup9p("/");
411715d0f95SDavid du Colombier 		d->mode = DMDIR|0777;
412715d0f95SDavid du Colombier 		break;
413715d0f95SDavid du Colombier 
414715d0f95SDavid du Colombier 	case Qdir:
415715d0f95SDavid du Colombier 		d->name = estrdup9p(sdname);
416715d0f95SDavid du Colombier 		d->mode = DMDIR|0777;
417715d0f95SDavid du Colombier 		break;
418715d0f95SDavid du Colombier 
419715d0f95SDavid du Colombier 	case Qctl:
420715d0f95SDavid du Colombier 		d->name = estrdup9p("ctl");
421715d0f95SDavid du Colombier 		d->mode = 0666;
422715d0f95SDavid du Colombier 		break;
423715d0f95SDavid du Colombier 
424715d0f95SDavid du Colombier 	default:
425715d0f95SDavid du Colombier 		q -= Qpart;
426715d0f95SDavid du Colombier 		if(q < 0 || q > nelem(tab) || tab[q].inuse == 0 ||
427715d0f95SDavid du Colombier 		    r->fid->qid.vers != tab[q].vers){
428715d0f95SDavid du Colombier 			respond(r, "partition no longer exists");
429715d0f95SDavid du Colombier 			return;
430715d0f95SDavid du Colombier 		}
431715d0f95SDavid du Colombier 		p = &tab[q];
432715d0f95SDavid du Colombier 		d->name = estrdup9p(p->name);
433715d0f95SDavid du Colombier 		d->length = p->length * sectsize;
434715d0f95SDavid du Colombier 		d->mode = p->mode;
435715d0f95SDavid du Colombier 		break;
436715d0f95SDavid du Colombier 	}
437715d0f95SDavid du Colombier 
438715d0f95SDavid du Colombier 	d->uid = estrdup9p("partfs");
439715d0f95SDavid du Colombier 	d->gid = estrdup9p("partfs");
440715d0f95SDavid du Colombier 	d->muid = estrdup9p("");
441715d0f95SDavid du Colombier 	respond(r, nil);
442715d0f95SDavid du Colombier }
443715d0f95SDavid du Colombier 
444715d0f95SDavid du Colombier void
fsattach(Req * r)445715d0f95SDavid du Colombier fsattach(Req *r)
446715d0f95SDavid du Colombier {
447715d0f95SDavid du Colombier 	char *spec;
448715d0f95SDavid du Colombier 
449715d0f95SDavid du Colombier 	spec = r->ifcall.aname;
450715d0f95SDavid du Colombier 	if(spec && spec[0]){
451715d0f95SDavid du Colombier 		respond(r, "invalid attach specifier");
452715d0f95SDavid du Colombier 		return;
453715d0f95SDavid du Colombier 	}
454715d0f95SDavid du Colombier 	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
455715d0f95SDavid du Colombier 	r->fid->qid = r->ofcall.qid;
456715d0f95SDavid du Colombier 	respond(r, nil);
457715d0f95SDavid du Colombier }
458715d0f95SDavid du Colombier 
459715d0f95SDavid du Colombier char*
fswalk1(Fid * fid,char * name,Qid * qid)460715d0f95SDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
461715d0f95SDavid du Colombier {
462715d0f95SDavid du Colombier 	Part *p;
463715d0f95SDavid du Colombier 
464715d0f95SDavid du Colombier 	switch((int)fid->qid.path){
465715d0f95SDavid du Colombier 	case Qroot:
466715d0f95SDavid du Colombier 		if(strcmp(name, sdname) == 0){
467715d0f95SDavid du Colombier 			fid->qid.path = Qdir;
468715d0f95SDavid du Colombier 			fid->qid.type = QTDIR;
469715d0f95SDavid du Colombier 			*qid = fid->qid;
470715d0f95SDavid du Colombier 			return nil;
471715d0f95SDavid du Colombier 		}
472715d0f95SDavid du Colombier 		break;
473715d0f95SDavid du Colombier 	case Qdir:
474715d0f95SDavid du Colombier 		if(strcmp(name, "ctl") == 0){
475715d0f95SDavid du Colombier 			fid->qid.path = Qctl;
476715d0f95SDavid du Colombier 			fid->qid.vers = 0;
477715d0f95SDavid du Colombier 			fid->qid.type = 0;
478715d0f95SDavid du Colombier 			*qid = fid->qid;
479715d0f95SDavid du Colombier 			return nil;
480715d0f95SDavid du Colombier 		}
481715d0f95SDavid du Colombier 		for(p = tab; p < tab + nelem(tab); p++)
482715d0f95SDavid du Colombier 			if(p->inuse && strcmp(p->name, name) == 0){
483715d0f95SDavid du Colombier 				fid->qid.path = p - tab + Qpart;
484715d0f95SDavid du Colombier 				fid->qid.vers = p->vers;
485715d0f95SDavid du Colombier 				fid->qid.type = 0;
486715d0f95SDavid du Colombier 				*qid = fid->qid;
487715d0f95SDavid du Colombier 				return nil;
488715d0f95SDavid du Colombier 			}
489715d0f95SDavid du Colombier 		break;
490715d0f95SDavid du Colombier 	}
491715d0f95SDavid du Colombier 	return "file not found";
492715d0f95SDavid du Colombier }
493715d0f95SDavid du Colombier 
494715d0f95SDavid du Colombier Srv fs = {
495715d0f95SDavid du Colombier 	.attach=fsattach,
496715d0f95SDavid du Colombier 	.open=	fsopen,
497715d0f95SDavid du Colombier 	.read=	fsread,
498715d0f95SDavid du Colombier 	.write=	fswrite,
499715d0f95SDavid du Colombier 	.stat=	fsstat,
500715d0f95SDavid du Colombier 	.walk1=	fswalk1,
501715d0f95SDavid du Colombier };
502715d0f95SDavid du Colombier 
503715d0f95SDavid du Colombier char *mtpt = "/dev";
504715d0f95SDavid du Colombier char *srvname;
505715d0f95SDavid du Colombier 
506715d0f95SDavid du Colombier void
usage(void)507715d0f95SDavid du Colombier usage(void)
508715d0f95SDavid du Colombier {
509*8c055935SDavid du Colombier 	fprint(2, "usage: %s [-Dr] [-d sdname] [-m mtpt] [-p 9parts] "
510*8c055935SDavid du Colombier 		"[-s srvname] diskimage\n", argv0);
511715d0f95SDavid du Colombier 	fprint(2, "\tdefault mtpt is /dev\n");
512715d0f95SDavid du Colombier 	exits("usage");
513715d0f95SDavid du Colombier }
514715d0f95SDavid du Colombier 
515715d0f95SDavid du Colombier void
main(int argc,char ** argv)516715d0f95SDavid du Colombier main(int argc, char **argv)
517715d0f95SDavid du Colombier {
518715d0f95SDavid du Colombier 	int isdir;
519*8c055935SDavid du Colombier 	char *file, *cname, *parts;
520715d0f95SDavid du Colombier 	Dir *dir;
521715d0f95SDavid du Colombier 
522715d0f95SDavid du Colombier 	quotefmtinstall();
523715d0f95SDavid du Colombier 	time0 = time(0);
524*8c055935SDavid du Colombier 	parts = nil;
525715d0f95SDavid du Colombier 
526715d0f95SDavid du Colombier 	ARGBEGIN{
527715d0f95SDavid du Colombier 	case 'D':
528715d0f95SDavid du Colombier 		chatty9p++;
529715d0f95SDavid du Colombier 		break;
530950da38cSDavid du Colombier 	case 'd':
531950da38cSDavid du Colombier 		sdname = EARGF(usage());
532715d0f95SDavid du Colombier 		break;
533715d0f95SDavid du Colombier 	case 'm':
534715d0f95SDavid du Colombier 		mtpt = EARGF(usage());
535715d0f95SDavid du Colombier 		break;
536*8c055935SDavid du Colombier 	case 'p':
537*8c055935SDavid du Colombier 		parts = EARGF(usage());
538*8c055935SDavid du Colombier 		break;
539715d0f95SDavid du Colombier 	case 'r':
540715d0f95SDavid du Colombier 		rdonly = 1;
541715d0f95SDavid du Colombier 		break;
542715d0f95SDavid du Colombier 	case 's':
543715d0f95SDavid du Colombier 		srvname = EARGF(usage());
544715d0f95SDavid du Colombier 		break;
545715d0f95SDavid du Colombier 	default:
546715d0f95SDavid du Colombier 		usage();
547715d0f95SDavid du Colombier 	}ARGEND
548715d0f95SDavid du Colombier 
549950da38cSDavid du Colombier 	if(argc != 1)
550715d0f95SDavid du Colombier 		usage();
551950da38cSDavid du Colombier 	file = argv[0];
552715d0f95SDavid du Colombier 	dir = dirstat(file);
553715d0f95SDavid du Colombier 	if(!dir)
554715d0f95SDavid du Colombier 		sysfatal("%s: %r", file);
555715d0f95SDavid du Colombier 	isdir = (dir->mode & DMDIR) != 0;
556715d0f95SDavid du Colombier 	free(dir);
557715d0f95SDavid du Colombier 
558715d0f95SDavid du Colombier 	if (isdir) {
559715d0f95SDavid du Colombier 		cname = smprint("%s/ctl", file);
560715d0f95SDavid du Colombier 		if ((ctlfd = open(cname, ORDWR)) < 0)
561715d0f95SDavid du Colombier 			sysfatal("open %s: %r", cname);
562715d0f95SDavid du Colombier 		file = smprint("%s/data", file);
563715d0f95SDavid du Colombier 	}
564715d0f95SDavid du Colombier 	if((fd = open(file, rdonly? OREAD: ORDWR)) < 0)
565715d0f95SDavid du Colombier 		sysfatal("open %s: %r", file);
566715d0f95SDavid du Colombier 
567715d0f95SDavid du Colombier 	sectsize = 512;			/* conventional */
568715d0f95SDavid du Colombier 	dir = dirfstat(fd);
569715d0f95SDavid du Colombier 	if (dir)
570715d0f95SDavid du Colombier 		nsect = dir->length / sectsize;
571715d0f95SDavid du Colombier 	free(dir);
572715d0f95SDavid du Colombier 
573715d0f95SDavid du Colombier 	inquiry = estrdup9p(inquiry);
574715d0f95SDavid du Colombier 	tab[0].inuse = 1;
575715d0f95SDavid du Colombier 	tab[0].name = estrdup9p("data");
576715d0f95SDavid du Colombier 	tab[0].mode = 0666;
577715d0f95SDavid du Colombier 	tab[0].length = nsect;
578715d0f95SDavid du Colombier 
579*8c055935SDavid du Colombier 	/*
580*8c055935SDavid du Colombier 	 * hack for booting from usb: add 9load partitions.
581*8c055935SDavid du Colombier 	 */
582*8c055935SDavid du Colombier 	if(parts != nil)
583*8c055935SDavid du Colombier 		addparts(parts);
584*8c055935SDavid du Colombier 
585715d0f95SDavid du Colombier 	postmountsrv(&fs, srvname, mtpt, MBEFORE);
586715d0f95SDavid du Colombier 	exits(nil);
587715d0f95SDavid du Colombier }
588