596 lines · 10.4 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * partfs - serve an underlying file, with devsd-style partitions */#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <9p.h> typedef struct Part Part;struct Part{	int	inuse;	int	vers;	ulong	mode;	char	*name;	vlong	offset;		/* in sectors */	vlong	length;		/* in sectors */}; enum{	Qroot = 0,	Qdir,	Qctl,	Qpart,}; int fd = -1, ctlfd = -1;int rdonly;ulong ctlmode = 0666;ulong time0;vlong nsect, sectsize; char *inquiry = "partfs hard drive";char *sdname = "sdXX";Part tab[64]; char*ctlstring(void){	Part *p;	Fmt fmt; 	fmtstrinit(&fmt);	fmtprint(&fmt, "inquiry %s\n", inquiry);	fmtprint(&fmt, "geometry %lld %lld\n", nsect, sectsize);	for (p = tab; p < tab + nelem(tab); p++)		if (p->inuse)			fmtprint(&fmt, "part %s %lld %lld\n",				p->name, p->offset, p->length);	return fmtstrflush(&fmt);} intaddpart(char *name, vlong start, vlong end){	Part *p; 	if(start < 0 || start > end || end > nsect){		werrstr("bad partition boundaries");		return -1;	} 	if (strcmp(name, "ctl") == 0 || strcmp(name, "data") == 0) {		werrstr("partition name already in use");		return -1;	}	for (p = tab; p < tab + nelem(tab) && p->inuse; p++)		if (strcmp(p->name, name) == 0) {			werrstr("partition name already in use");			return -1;		}	if(p == tab + nelem(tab)){		werrstr("no free partition slots");		return -1;	} 	p->inuse = 1;	free(p->name);	p->name = estrdup9p(name);	p->offset = start;	p->length = end - start;	p->mode = ctlmode;	p->vers++;	return 0;} intdelpart(char *s){	Part *p; 	for (p = tab; p < tab + nelem(tab); p++)		if(p->inuse && strcmp(p->name, s) == 0)			break;	if(p == tab + nelem(tab)){		werrstr("partition not found");		return -1;	} 	p->inuse = 0;	free(p->name);	p->name = nil;	return 0;} static voidaddparts(char *buf){	char *f[4], *p, *q; 	/*	 * Use partitions passed from boot program,	 * e.g.	 *	sdC0part=dos 63 123123/plan9 123123 456456	 * This happens before /boot sets hostname so the	 * partitions will have the null-string for user.	 */	for(p = buf; p != nil; p = q){		if(q = strchr(p, '/'))			*q++ = '\0';		if(tokenize(p, f, nelem(f)) >= 3 &&		    addpart(f[0], strtoull(f[1], 0, 0), strtoull(f[2], 0, 0)) < 0)			fprint(2, "%s: addpart %s: %r\n", argv0, f[0]);	}} static voidctlwrite0(Req *r, char *msg, Cmdbuf *cb){	vlong start, end;	Part *p; 	r->ofcall.count = r->ifcall.count; 	if(cb->nf < 1){		respond(r, "empty control message");		return;	} 	if(strcmp(cb->f[0], "part") == 0){		if(cb->nf != 4){			respondcmderror(r, cb, "part takes 3 args");			return;		}		start = strtoll(cb->f[2], 0, 0);		end = strtoll(cb->f[3], 0, 0);		if(addpart(cb->f[1], start, end) < 0){			respondcmderror(r, cb, "%r");			return;		}	}	else if(strcmp(cb->f[0], "delpart") == 0){		if(cb->nf != 2){			respondcmderror(r, cb, "delpart takes 1 arg");			return;		}		if(delpart(cb->f[1]) < 0){			respondcmderror(r, cb, "%r");			return;		}	}	else if(strcmp(cb->f[0], "inquiry") == 0){		if(cb->nf != 2){			respondcmderror(r, cb, "inquiry takes 1 arg");			return;		}		free(inquiry);		inquiry = estrdup9p(cb->f[1]);	}	else if(strcmp(cb->f[0], "geometry") == 0){		if(cb->nf != 3){			respondcmderror(r, cb, "geometry takes 2 args");			return;		}		nsect = strtoll(cb->f[1], 0, 0);		sectsize = strtoll(cb->f[2], 0, 0);		if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 &&		    tab[0].vers == 0){			tab[0].offset = 0;			tab[0].length = nsect;		}		for(p = tab; p < tab + nelem(tab); p++)			if(p->inuse && p->offset + p->length > nsect){				p->inuse = 0;				free(p->name);				p->name = nil;			}	} else		/* pass through to underlying ctl file, if any */		if (write(ctlfd, msg, r->ifcall.count) != r->ifcall.count) {			respondcmderror(r, cb, "%r");			return;		}	respond(r, nil);} voidctlwrite(Req *r){	char *msg;	Cmdbuf *cb; 	r->ofcall.count = r->ifcall.count; 	msg = emalloc9p(r->ifcall.count+1);	memmove(msg, r->ifcall.data, r->ifcall.count);	msg[r->ifcall.count] = '\0'; 	cb = parsecmd(r->ifcall.data, r->ifcall.count);	ctlwrite0(r, msg, cb); 	free(cb);	free(msg);} introotgen(int off, Dir *d, void*){	memset(d, 0, sizeof *d);	d->atime = time0;	d->mtime = time0;	if(off == 0){		d->name = estrdup9p(sdname);		d->mode = DMDIR|0777;		d->qid.path = Qdir;		d->qid.type = QTDIR;		d->uid = estrdup9p("partfs");		d->gid = estrdup9p("partfs");		d->muid = estrdup9p("");		return 0;	}	return -1;} intdirgen(int off, Dir *d, void*){	int n;	Part *p; 	memset(d, 0, sizeof *d);	d->atime = time0;	d->mtime = time0;	if(off == 0){		d->name = estrdup9p("ctl");		d->mode = ctlmode;		d->qid.path = Qctl;		goto Have;	} 	off--;	n = 0;	for(p = tab; p < tab + nelem(tab); p++, n++){		if(!p->inuse)			continue;		if(n == off){			d->name = estrdup9p(p->name);			d->length = p->length*sectsize;			d->mode = p->mode;			d->qid.path = Qpart + p - tab;			d->qid.vers = p->vers;			goto Have;		}	}	return -1; Have:	d->uid = estrdup9p("partfs");	d->gid = estrdup9p("partfs");	d->muid = estrdup9p("");	return 0;} intrdwrpart(Req *r){	int q;	long count, tot;	vlong offset;	uchar *dat;	Part *p; 	q = r->fid->qid.path - Qpart;	if(q < 0 || q > nelem(tab) || !tab[q].inuse ||	    tab[q].vers != r->fid->qid.vers){		respond(r, "unknown partition");		return -1;	}	p = &tab[q]; 	offset = r->ifcall.offset;	count = r->ifcall.count;	if(offset < 0){		respond(r, "negative offset");		return -1;	}	if(count < 0){		respond(r, "negative count");		return -1;	}	if(offset > p->length*sectsize){		respond(r, "offset past end of partition");		return -1;	}	if(offset+count > p->length*sectsize)		count = p->length*sectsize - offset;	offset += p->offset*sectsize; 	if(r->ifcall.type == Tread)		dat = (uchar*)r->ofcall.data;	else		dat = (uchar*)r->ifcall.data; 	/* pass i/o through to underlying file */	seek(fd, offset, 0);	if (r->ifcall.type == Twrite) {		tot = write(fd, dat, count);		if (tot != count) {			respond(r, "%r");			return -1;		}	} else {		tot = read(fd, dat, count);		if (tot < 0) {			respond(r, "%r");			return -1;		}	}	r->ofcall.count = tot;	respond(r, nil);	return 0;} voidfsread(Req *r){	char *s; 	switch((int)r->fid->qid.path){	case Qroot:		dirread9p(r, rootgen, nil);		break;	case Qdir:		dirread9p(r, dirgen, nil);		break;	case Qctl:		s = ctlstring();		readstr(r, s);		free(s);		break;	default:		rdwrpart(r);		return;	}	respond(r, nil);} voidfswrite(Req *r){	switch((int)r->fid->qid.path){	case Qroot:	case Qdir:		respond(r, "write to a directory?");		break;	case Qctl:		ctlwrite(r);		break;	default:		rdwrpart(r);		break;	}} voidfsopen(Req *r){	if(r->ifcall.mode&ORCLOSE)		respond(r, "cannot open ORCLOSE"); 	switch((int)r->fid->qid.path){	case Qroot:	case Qdir:		if(r->ifcall.mode != OREAD){			respond(r, "bad mode for directory open");			return;		}	} 	respond(r, nil);} voidfsstat(Req *r){	int q;	Dir *d;	Part *p; 	d = &r->d;	memset(d, 0, sizeof *d);	d->qid = r->fid->qid;	d->atime = d->mtime = time0;	q = r->fid->qid.path;	switch(q){	case Qroot:		d->name = estrdup9p("/");		d->mode = DMDIR|0777;		break; 	case Qdir:		d->name = estrdup9p(sdname);		d->mode = DMDIR|0777;		break; 	case Qctl:		d->name = estrdup9p("ctl");		d->mode = 0666;		break; 	default:		q -= Qpart;		if(q < 0 || q > nelem(tab) || tab[q].inuse == 0 ||		    r->fid->qid.vers != tab[q].vers){			respond(r, "partition no longer exists");			return;		}		p = &tab[q];		d->name = estrdup9p(p->name);		d->length = p->length * sectsize;		d->mode = p->mode;		break;	} 	d->uid = estrdup9p("partfs");	d->gid = estrdup9p("partfs");	d->muid = estrdup9p("");	respond(r, nil);} voidfsattach(Req *r){	char *spec; 	spec = r->ifcall.aname;	if(spec && spec[0]){		respond(r, "invalid attach specifier");		return;	}	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};	r->fid->qid = r->ofcall.qid;	respond(r, nil);} char*fswalk1(Fid *fid, char *name, Qid *qid){	Part *p; 	switch((int)fid->qid.path){	case Qroot:		if(strcmp(name, sdname) == 0){			fid->qid.path = Qdir;			fid->qid.type = QTDIR;			*qid = fid->qid;			return nil;		}		break;	case Qdir:		if(strcmp(name, "ctl") == 0){			fid->qid.path = Qctl;			fid->qid.vers = 0;			fid->qid.type = 0;			*qid = fid->qid;			return nil;		}		for(p = tab; p < tab + nelem(tab); p++)			if(p->inuse && strcmp(p->name, name) == 0){				fid->qid.path = p - tab + Qpart;				fid->qid.vers = p->vers;				fid->qid.type = 0;				*qid = fid->qid;				return nil;			}		break;	}	return "file not found";

Lines 1–500 of 596.