2 * partfs - serve an underlying file, with devsd-style partitions
11 typedef struct Part Part;
18 vlong offset; /* in sectors */
19 vlong length; /* in sectors */
30 int fd = -1, ctlfd = -1;
34 vlong nsect, sectsize;
36 char *inquiry = "partfs hard drive";
37 char *sdname = "sdXX";
47 fmtprint(&fmt, "inquiry %s\n", inquiry);
48 fmtprint(&fmt, "geometry %lld %lld\n", nsect, sectsize);
49 for (p = tab; p < tab + nelem(tab); p++)
51 fmtprint(&fmt, "part %s %lld %lld\n",
52 p->name, p->offset, p->offset + p->length);
53 return fmtstrflush(&fmt);
57 addpart(char *name, vlong start, vlong end)
61 if(start < 0 || start > end || end > nsect){
62 werrstr("bad partition boundaries");
66 if (strcmp(name, "ctl") == 0 || strcmp(name, "data") == 0) {
67 werrstr("partition name already in use");
70 for (p = tab; p < tab + nelem(tab); p++)
71 if (p->inuse && strcmp(p->name, name) == 0) {
72 /* adding identical partition is no-op */
73 if(p->offset == start && p->length == end - start)
75 werrstr("partition name already in use");
78 for (p = tab; p < tab + nelem(tab); p++)
81 if(p == tab + nelem(tab)){
82 werrstr("no free partition slots");
88 p->name = estrdup9p(name);
90 p->length = end - start;
101 for (p = tab; p < tab + nelem(tab); p++)
102 if(p->inuse && strcmp(p->name, s) == 0)
104 if(p == tab + nelem(tab)){
105 werrstr("partition not found");
116 ctlwrite0(Req *r, char *msg, Cmdbuf *cb)
121 r->ofcall.count = r->ifcall.count;
124 respond(r, "empty control message");
128 if(strcmp(cb->f[0], "part") == 0){
130 respondcmderror(r, cb, "part takes 3 args");
133 start = strtoll(cb->f[2], 0, 0);
134 end = strtoll(cb->f[3], 0, 0);
135 if(addpart(cb->f[1], start, end) < 0){
136 respondcmderror(r, cb, "%r");
140 else if(strcmp(cb->f[0], "delpart") == 0){
142 respondcmderror(r, cb, "delpart takes 1 arg");
145 if(delpart(cb->f[1]) < 0){
146 respondcmderror(r, cb, "%r");
150 else if(strcmp(cb->f[0], "inquiry") == 0){
152 respondcmderror(r, cb, "inquiry takes 1 arg");
156 inquiry = estrdup9p(cb->f[1]);
158 else if(strcmp(cb->f[0], "geometry") == 0){
160 respondcmderror(r, cb, "geometry takes 2 args");
163 nsect = strtoll(cb->f[1], 0, 0);
164 sectsize = strtoll(cb->f[2], 0, 0);
165 if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 &&
168 tab[0].length = nsect;
170 for(p = tab; p < tab + nelem(tab); p++)
171 if(p->inuse && p->offset + p->length > nsect){
177 /* pass through to underlying ctl file, if any */
178 if (write(ctlfd, msg, r->ifcall.count) != r->ifcall.count) {
179 respondcmderror(r, cb, "%r");
191 r->ofcall.count = r->ifcall.count;
193 msg = emalloc9p(r->ifcall.count+1);
194 memmove(msg, r->ifcall.data, r->ifcall.count);
195 msg[r->ifcall.count] = '\0';
197 cb = parsecmd(r->ifcall.data, r->ifcall.count);
198 ctlwrite0(r, msg, cb);
205 rootgen(int off, Dir *d, void*)
207 memset(d, 0, sizeof *d);
211 d->name = estrdup9p(sdname);
212 d->mode = DMDIR|0777;
215 d->uid = estrdup9p("partfs");
216 d->gid = estrdup9p("partfs");
217 d->muid = estrdup9p("");
224 dirgen(int off, Dir *d, void*)
229 memset(d, 0, sizeof *d);
233 d->name = estrdup9p("ctl");
241 for(p = tab; p < tab + nelem(tab); p++, n++){
245 d->name = estrdup9p(p->name);
246 d->length = p->length*sectsize;
248 d->qid.path = Qpart + p - tab;
249 d->qid.vers = p->vers;
256 d->uid = estrdup9p("partfs");
257 d->gid = estrdup9p("partfs");
258 d->muid = estrdup9p("");
263 evommem(void *a, void *b, ulong n)
265 return memmove(b, a, n);
277 q = r->fid->qid.path - Qpart;
278 if(q < 0 || q > nelem(tab) || !tab[q].inuse ||
279 tab[q].vers != r->fid->qid.vers){
280 respond(r, "unknown partition");
285 offset = r->ifcall.offset;
286 count = r->ifcall.count;
288 respond(r, "negative offset");
292 respond(r, "negative count");
295 if(offset > p->length*sectsize){
296 respond(r, "offset past end of partition");
299 if(offset+count > p->length*sectsize)
300 count = p->length*sectsize - offset;
301 offset += p->offset*sectsize;
303 if(r->ifcall.type == Tread)
304 dat = (uchar*)r->ofcall.data;
306 dat = (uchar*)r->ifcall.data;
308 /* pass i/o through to underlying file */
310 if (r->ifcall.type == Twrite) {
311 tot = write(fd, dat, count);
317 tot = read(fd, dat, count);
323 r->ofcall.count = tot;
333 switch((int)r->fid->qid.path){
335 dirread9p(r, rootgen, nil);
338 dirread9p(r, dirgen, nil);
355 switch((int)r->fid->qid.path){
358 respond(r, "write to a directory?");
372 if(r->ifcall.mode&ORCLOSE)
373 respond(r, "cannot open ORCLOSE");
375 switch((int)r->fid->qid.path){
378 if(r->ifcall.mode != OREAD){
379 respond(r, "bad mode for directory open");
395 memset(d, 0, sizeof *d);
396 d->qid = r->fid->qid;
397 d->atime = d->mtime = time0;
398 q = r->fid->qid.path;
401 d->name = estrdup9p("/");
402 d->mode = DMDIR|0777;
406 d->name = estrdup9p(sdname);
407 d->mode = DMDIR|0777;
411 d->name = estrdup9p("ctl");
417 if(q < 0 || q > nelem(tab) || tab[q].inuse == 0 ||
418 r->fid->qid.vers != tab[q].vers){
419 respond(r, "partition no longer exists");
423 d->name = estrdup9p(p->name);
424 d->length = p->length * sectsize;
429 d->uid = estrdup9p("partfs");
430 d->gid = estrdup9p("partfs");
431 d->muid = estrdup9p("");
440 spec = r->ifcall.aname;
442 respond(r, "invalid attach specifier");
445 r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
446 r->fid->qid = r->ofcall.qid;
451 fswalk1(Fid *fid, char *name, Qid *qid)
455 switch((int)fid->qid.path){
457 if(strcmp(name, sdname) == 0){
458 fid->qid.path = Qdir;
459 fid->qid.type = QTDIR;
465 if(strcmp(name, "ctl") == 0){
466 fid->qid.path = Qctl;
472 for(p = tab; p < tab + nelem(tab); p++)
473 if(p->inuse && strcmp(p->name, name) == 0){
474 fid->qid.path = p - tab + Qpart;
475 fid->qid.vers = p->vers;
482 return "file not found";
500 fprint(2, "usage: %s [-Dr] [-d sdname] [-m mtpt] [-s srvname] diskimage\n",
502 fprint(2, "\tdefault mtpt is /dev\n");
507 main(int argc, char **argv)
521 sdname = EARGF(usage());
524 mtpt = EARGF(usage());
530 srvname = EARGF(usage());
541 sysfatal("%s: %r", file);
542 isdir = (dir->mode & DMDIR) != 0;
546 cname = smprint("%s/ctl", file);
547 if ((ctlfd = open(cname, ORDWR)) < 0)
548 sysfatal("open %s: %r", cname);
549 file = smprint("%s/data", file);
551 if((fd = open(file, rdonly? OREAD: ORDWR)) < 0)
552 sysfatal("open %s: %r", file);
554 sectsize = 512; /* conventional */
557 nsect = dir->length / sectsize;
560 inquiry = estrdup9p(inquiry);
562 tab[0].name = estrdup9p("data");
564 tab[0].length = nsect;
566 postmountsrv(&fs, srvname, mtpt, MBEFORE);