xref: /plan9-contrib/sys/src/9k/port/devsrv.c (revision 406c76facc4b13aa2a55454bf4091aab9f03da22)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier 
99ef1f84bSDavid du Colombier typedef struct Srv Srv;
109ef1f84bSDavid du Colombier struct Srv
119ef1f84bSDavid du Colombier {
129ef1f84bSDavid du Colombier 	char	*name;
139ef1f84bSDavid du Colombier 	char	*owner;
149ef1f84bSDavid du Colombier 	ulong	perm;
159ef1f84bSDavid du Colombier 	Chan	*chan;
169ef1f84bSDavid du Colombier 	Srv	*link;
179ef1f84bSDavid du Colombier 	ulong	path;
189ef1f84bSDavid du Colombier };
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier static QLock	srvlk;
219ef1f84bSDavid du Colombier static Srv	*srv;
229ef1f84bSDavid du Colombier static int	qidpath;
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier static int
srvgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)259ef1f84bSDavid du Colombier srvgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
269ef1f84bSDavid du Colombier {
279ef1f84bSDavid du Colombier 	Srv *sp;
289ef1f84bSDavid du Colombier 	Qid q;
299ef1f84bSDavid du Colombier 
309ef1f84bSDavid du Colombier 	if(s == DEVDOTDOT){
319ef1f84bSDavid du Colombier 		devdir(c, c->qid, "#s", 0, eve, 0555, dp);
329ef1f84bSDavid du Colombier 		return 1;
339ef1f84bSDavid du Colombier 	}
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier 	qlock(&srvlk);
369ef1f84bSDavid du Colombier 	for(sp = srv; sp && s; sp = sp->link)
379ef1f84bSDavid du Colombier 		s--;
389ef1f84bSDavid du Colombier 
399ef1f84bSDavid du Colombier 	if(sp == 0) {
409ef1f84bSDavid du Colombier 		qunlock(&srvlk);
419ef1f84bSDavid du Colombier 		return -1;
429ef1f84bSDavid du Colombier 	}
439ef1f84bSDavid du Colombier 
449ef1f84bSDavid du Colombier 	mkqid(&q, sp->path, 0, QTFILE);
459ef1f84bSDavid du Colombier 	/* make sure name string continues to exist after we release lock */
469ef1f84bSDavid du Colombier 	kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
479ef1f84bSDavid du Colombier 	devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
489ef1f84bSDavid du Colombier 	qunlock(&srvlk);
499ef1f84bSDavid du Colombier 	return 1;
509ef1f84bSDavid du Colombier }
519ef1f84bSDavid du Colombier 
529ef1f84bSDavid du Colombier static void
srvinit(void)539ef1f84bSDavid du Colombier srvinit(void)
549ef1f84bSDavid du Colombier {
559ef1f84bSDavid du Colombier 	qidpath = 1;
569ef1f84bSDavid du Colombier }
579ef1f84bSDavid du Colombier 
589ef1f84bSDavid du Colombier static Chan*
srvattach(char * spec)599ef1f84bSDavid du Colombier srvattach(char *spec)
609ef1f84bSDavid du Colombier {
619ef1f84bSDavid du Colombier 	return devattach('s', spec);
629ef1f84bSDavid du Colombier }
639ef1f84bSDavid du Colombier 
649ef1f84bSDavid du Colombier static Walkqid*
srvwalk(Chan * c,Chan * nc,char ** name,int nname)659ef1f84bSDavid du Colombier srvwalk(Chan *c, Chan *nc, char **name, int nname)
669ef1f84bSDavid du Colombier {
679ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, srvgen);
689ef1f84bSDavid du Colombier }
699ef1f84bSDavid du Colombier 
709ef1f84bSDavid du Colombier static Srv*
srvlookup(char * name,ulong qidpath)719ef1f84bSDavid du Colombier srvlookup(char *name, ulong qidpath)
729ef1f84bSDavid du Colombier {
739ef1f84bSDavid du Colombier 	Srv *sp;
749ef1f84bSDavid du Colombier 	for(sp = srv; sp; sp = sp->link)
759ef1f84bSDavid du Colombier 		if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
769ef1f84bSDavid du Colombier 			return sp;
779ef1f84bSDavid du Colombier 	return nil;
789ef1f84bSDavid du Colombier }
799ef1f84bSDavid du Colombier 
809ef1f84bSDavid du Colombier static long
srvstat(Chan * c,uchar * db,long n)819ef1f84bSDavid du Colombier srvstat(Chan *c, uchar *db, long n)
829ef1f84bSDavid du Colombier {
839ef1f84bSDavid du Colombier 	return devstat(c, db, n, 0, 0, srvgen);
849ef1f84bSDavid du Colombier }
859ef1f84bSDavid du Colombier 
869ef1f84bSDavid du Colombier char*
srvname(Chan * c)879ef1f84bSDavid du Colombier srvname(Chan *c)
889ef1f84bSDavid du Colombier {
89*406c76faSDavid du Colombier 	int size;
909ef1f84bSDavid du Colombier 	Srv *sp;
919ef1f84bSDavid du Colombier 	char *s;
929ef1f84bSDavid du Colombier 
939ef1f84bSDavid du Colombier 	for(sp = srv; sp; sp = sp->link)
949ef1f84bSDavid du Colombier 		if(sp->chan == c){
95*406c76faSDavid du Colombier 			size = 3+strlen(sp->name)+1;
96*406c76faSDavid du Colombier 			s = smalloc(size);
97*406c76faSDavid du Colombier 			snprint(s, size, "#s/%s", sp->name);
989ef1f84bSDavid du Colombier 			return s;
999ef1f84bSDavid du Colombier 		}
1009ef1f84bSDavid du Colombier 	return nil;
1019ef1f84bSDavid du Colombier }
1029ef1f84bSDavid du Colombier 
1039ef1f84bSDavid du Colombier static Chan*
srvopen(Chan * c,int omode)1049ef1f84bSDavid du Colombier srvopen(Chan *c, int omode)
1059ef1f84bSDavid du Colombier {
1069ef1f84bSDavid du Colombier 	Srv *sp;
1079ef1f84bSDavid du Colombier 
1089ef1f84bSDavid du Colombier 	if(c->qid.type == QTDIR){
1099ef1f84bSDavid du Colombier 		if(omode & ORCLOSE)
1109ef1f84bSDavid du Colombier 			error(Eperm);
1119ef1f84bSDavid du Colombier 		if(omode != OREAD)
1129ef1f84bSDavid du Colombier 			error(Eisdir);
1139ef1f84bSDavid du Colombier 		c->mode = omode;
1149ef1f84bSDavid du Colombier 		c->flag |= COPEN;
1159ef1f84bSDavid du Colombier 		c->offset = 0;
1169ef1f84bSDavid du Colombier 		return c;
1179ef1f84bSDavid du Colombier 	}
1189ef1f84bSDavid du Colombier 	qlock(&srvlk);
1199ef1f84bSDavid du Colombier 	if(waserror()){
1209ef1f84bSDavid du Colombier 		qunlock(&srvlk);
1219ef1f84bSDavid du Colombier 		nexterror();
1229ef1f84bSDavid du Colombier 	}
1239ef1f84bSDavid du Colombier 
1249ef1f84bSDavid du Colombier 	sp = srvlookup(nil, c->qid.path);
1259ef1f84bSDavid du Colombier 	if(sp == 0 || sp->chan == 0)
1269ef1f84bSDavid du Colombier 		error(Eshutdown);
1279ef1f84bSDavid du Colombier 
1289ef1f84bSDavid du Colombier 	if(omode&OTRUNC)
1299ef1f84bSDavid du Colombier 		error("srv file already exists");
1309ef1f84bSDavid du Colombier 	if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
1319ef1f84bSDavid du Colombier 		error(Eperm);
1329ef1f84bSDavid du Colombier 	devpermcheck(sp->owner, sp->perm, omode);
1339ef1f84bSDavid du Colombier 
1349ef1f84bSDavid du Colombier 	cclose(c);
1359ef1f84bSDavid du Colombier 	incref(sp->chan);
1369ef1f84bSDavid du Colombier 	qunlock(&srvlk);
1379ef1f84bSDavid du Colombier 	poperror();
1389ef1f84bSDavid du Colombier 	return sp->chan;
1399ef1f84bSDavid du Colombier }
1409ef1f84bSDavid du Colombier 
1419ef1f84bSDavid du Colombier static void
srvcreate(Chan * c,char * name,int omode,int perm)1429ef1f84bSDavid du Colombier srvcreate(Chan *c, char *name, int omode, int perm)
1439ef1f84bSDavid du Colombier {
1449ef1f84bSDavid du Colombier 	Srv *sp;
1459ef1f84bSDavid du Colombier 	char *sname;
1469ef1f84bSDavid du Colombier 
1479ef1f84bSDavid du Colombier 	if(openmode(omode) != OWRITE)
1489ef1f84bSDavid du Colombier 		error(Eperm);
1499ef1f84bSDavid du Colombier 
1509ef1f84bSDavid du Colombier 	if(omode & OCEXEC)	/* can't happen */
1519ef1f84bSDavid du Colombier 		panic("someone broke namec");
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier 	sp = smalloc(sizeof *sp);
1549ef1f84bSDavid du Colombier 	sname = smalloc(strlen(name)+1);
1559ef1f84bSDavid du Colombier 
1569ef1f84bSDavid du Colombier 	qlock(&srvlk);
1579ef1f84bSDavid du Colombier 	if(waserror()){
1589ef1f84bSDavid du Colombier 		free(sname);
1599ef1f84bSDavid du Colombier 		free(sp);
1609ef1f84bSDavid du Colombier 		qunlock(&srvlk);
1619ef1f84bSDavid du Colombier 		nexterror();
1629ef1f84bSDavid du Colombier 	}
1639ef1f84bSDavid du Colombier 	if(sp == nil || sname == nil)
1649ef1f84bSDavid du Colombier 		error(Enomem);
1659ef1f84bSDavid du Colombier 	if(srvlookup(name, -1))
1669ef1f84bSDavid du Colombier 		error(Eexist);
1679ef1f84bSDavid du Colombier 
1689ef1f84bSDavid du Colombier 	sp->path = qidpath++;
1699ef1f84bSDavid du Colombier 	sp->link = srv;
1709ef1f84bSDavid du Colombier 	strcpy(sname, name);
1719ef1f84bSDavid du Colombier 	sp->name = sname;
1729ef1f84bSDavid du Colombier 	c->qid.type = QTFILE;
1739ef1f84bSDavid du Colombier 	c->qid.path = sp->path;
1749ef1f84bSDavid du Colombier 	srv = sp;
1759ef1f84bSDavid du Colombier 	qunlock(&srvlk);
1769ef1f84bSDavid du Colombier 	poperror();
1779ef1f84bSDavid du Colombier 
1789ef1f84bSDavid du Colombier 	kstrdup(&sp->owner, up->user);
1799ef1f84bSDavid du Colombier 	sp->perm = perm&0777;
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	c->flag |= COPEN;
1829ef1f84bSDavid du Colombier 	c->mode = OWRITE;
1839ef1f84bSDavid du Colombier }
1849ef1f84bSDavid du Colombier 
1859ef1f84bSDavid du Colombier static void
srvremove(Chan * c)1869ef1f84bSDavid du Colombier srvremove(Chan *c)
1879ef1f84bSDavid du Colombier {
1889ef1f84bSDavid du Colombier 	Srv *sp, **l;
1899ef1f84bSDavid du Colombier 
1909ef1f84bSDavid du Colombier 	if(c->qid.type == QTDIR)
1919ef1f84bSDavid du Colombier 		error(Eperm);
1929ef1f84bSDavid du Colombier 
1939ef1f84bSDavid du Colombier 	qlock(&srvlk);
1949ef1f84bSDavid du Colombier 	if(waserror()){
1959ef1f84bSDavid du Colombier 		qunlock(&srvlk);
1969ef1f84bSDavid du Colombier 		nexterror();
1979ef1f84bSDavid du Colombier 	}
1989ef1f84bSDavid du Colombier 	l = &srv;
1999ef1f84bSDavid du Colombier 	for(sp = *l; sp; sp = sp->link) {
2009ef1f84bSDavid du Colombier 		if(sp->path == c->qid.path)
2019ef1f84bSDavid du Colombier 			break;
2029ef1f84bSDavid du Colombier 
2039ef1f84bSDavid du Colombier 		l = &sp->link;
2049ef1f84bSDavid du Colombier 	}
2059ef1f84bSDavid du Colombier 	if(sp == 0)
2069ef1f84bSDavid du Colombier 		error(Enonexist);
2079ef1f84bSDavid du Colombier 
2089ef1f84bSDavid du Colombier 	/*
2099ef1f84bSDavid du Colombier 	 * Only eve can remove system services.
2109ef1f84bSDavid du Colombier 	 * No one can remove #s/boot.
2119ef1f84bSDavid du Colombier 	 */
2129ef1f84bSDavid du Colombier 	if(strcmp(sp->owner, eve) == 0 && !iseve())
2139ef1f84bSDavid du Colombier 		error(Eperm);
2149ef1f84bSDavid du Colombier 	if(strcmp(sp->name, "boot") == 0)
2159ef1f84bSDavid du Colombier 		error(Eperm);
2169ef1f84bSDavid du Colombier 
2179ef1f84bSDavid du Colombier 	/*
2189ef1f84bSDavid du Colombier 	 * No removing personal services.
2199ef1f84bSDavid du Colombier 	 */
2209ef1f84bSDavid du Colombier 	if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
2219ef1f84bSDavid du Colombier 		error(Eperm);
2229ef1f84bSDavid du Colombier 
2239ef1f84bSDavid du Colombier 	*l = sp->link;
2249ef1f84bSDavid du Colombier 	qunlock(&srvlk);
2259ef1f84bSDavid du Colombier 	poperror();
2269ef1f84bSDavid du Colombier 
2279ef1f84bSDavid du Colombier 	if(sp->chan)
2289ef1f84bSDavid du Colombier 		cclose(sp->chan);
2299ef1f84bSDavid du Colombier 	free(sp->owner);
2309ef1f84bSDavid du Colombier 	free(sp->name);
2319ef1f84bSDavid du Colombier 	free(sp);
2329ef1f84bSDavid du Colombier }
2339ef1f84bSDavid du Colombier 
2349ef1f84bSDavid du Colombier static long
srvwstat(Chan * c,uchar * dp,long n)2359ef1f84bSDavid du Colombier srvwstat(Chan *c, uchar *dp, long n)
2369ef1f84bSDavid du Colombier {
2379ef1f84bSDavid du Colombier 	Dir d;
2389ef1f84bSDavid du Colombier 	Srv *sp;
2399ef1f84bSDavid du Colombier 	char *strs;
2409ef1f84bSDavid du Colombier 
2419ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
2429ef1f84bSDavid du Colombier 		error(Eperm);
2439ef1f84bSDavid du Colombier 
2449ef1f84bSDavid du Colombier 	strs = nil;
2459ef1f84bSDavid du Colombier 	qlock(&srvlk);
2469ef1f84bSDavid du Colombier 	if(waserror()){
2479ef1f84bSDavid du Colombier 		qunlock(&srvlk);
2489ef1f84bSDavid du Colombier 		free(strs);
2499ef1f84bSDavid du Colombier 		nexterror();
2509ef1f84bSDavid du Colombier 	}
2519ef1f84bSDavid du Colombier 
2529ef1f84bSDavid du Colombier 	sp = srvlookup(nil, c->qid.path);
2539ef1f84bSDavid du Colombier 	if(sp == 0)
2549ef1f84bSDavid du Colombier 		error(Enonexist);
2559ef1f84bSDavid du Colombier 
2569ef1f84bSDavid du Colombier 	if(strcmp(sp->owner, up->user) != 0 && !iseve())
2579ef1f84bSDavid du Colombier 		error(Eperm);
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier 	strs = smalloc(n);
2609ef1f84bSDavid du Colombier 	n = convM2D(dp, n, &d, strs);
2619ef1f84bSDavid du Colombier 	if(n == 0)
2629ef1f84bSDavid du Colombier 		error(Eshortstat);
2639ef1f84bSDavid du Colombier 	if(d.mode != ~0UL)
2649ef1f84bSDavid du Colombier 		sp->perm = d.mode & 0777;
2659ef1f84bSDavid du Colombier 	if(d.uid && *d.uid)
2669ef1f84bSDavid du Colombier 		kstrdup(&sp->owner, d.uid);
2679ef1f84bSDavid du Colombier 	if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
2689ef1f84bSDavid du Colombier 		if(strchr(d.name, '/') != nil)
2699ef1f84bSDavid du Colombier 			error(Ebadchar);
2709ef1f84bSDavid du Colombier 		kstrdup(&sp->name, d.name);
2719ef1f84bSDavid du Colombier 	}
2729ef1f84bSDavid du Colombier 
2739ef1f84bSDavid du Colombier 	qunlock(&srvlk);
2749ef1f84bSDavid du Colombier 	free(strs);
2759ef1f84bSDavid du Colombier 	poperror();
2769ef1f84bSDavid du Colombier 	return n;
2779ef1f84bSDavid du Colombier }
2789ef1f84bSDavid du Colombier 
2799ef1f84bSDavid du Colombier static void
srvclose(Chan * c)2809ef1f84bSDavid du Colombier srvclose(Chan *c)
2819ef1f84bSDavid du Colombier {
2829ef1f84bSDavid du Colombier 	/*
2839ef1f84bSDavid du Colombier 	 * in theory we need to override any changes in removability
2849ef1f84bSDavid du Colombier 	 * since open, but since all that's checked is the owner,
2859ef1f84bSDavid du Colombier 	 * which is immutable, all is well.
2869ef1f84bSDavid du Colombier 	 */
2879ef1f84bSDavid du Colombier 	if(c->flag & CRCLOSE){
2889ef1f84bSDavid du Colombier 		if(waserror())
2899ef1f84bSDavid du Colombier 			return;
2909ef1f84bSDavid du Colombier 		srvremove(c);
2919ef1f84bSDavid du Colombier 		poperror();
2929ef1f84bSDavid du Colombier 	}
2939ef1f84bSDavid du Colombier }
2949ef1f84bSDavid du Colombier 
2959ef1f84bSDavid du Colombier static long
srvread(Chan * c,void * va,long n,vlong)2969ef1f84bSDavid du Colombier srvread(Chan *c, void *va, long n, vlong)
2979ef1f84bSDavid du Colombier {
2989ef1f84bSDavid du Colombier 	isdir(c);
2999ef1f84bSDavid du Colombier 	return devdirread(c, va, n, 0, 0, srvgen);
3009ef1f84bSDavid du Colombier }
3019ef1f84bSDavid du Colombier 
3029ef1f84bSDavid du Colombier static long
srvwrite(Chan * c,void * va,long n,vlong)3039ef1f84bSDavid du Colombier srvwrite(Chan *c, void *va, long n, vlong)
3049ef1f84bSDavid du Colombier {
3059ef1f84bSDavid du Colombier 	Srv *sp;
3069ef1f84bSDavid du Colombier 	Chan *c1;
3079ef1f84bSDavid du Colombier 	int fd;
3089ef1f84bSDavid du Colombier 	char buf[32];
3099ef1f84bSDavid du Colombier 
3109ef1f84bSDavid du Colombier 	if(n >= sizeof buf)
3119ef1f84bSDavid du Colombier 		error(Egreg);
3129ef1f84bSDavid du Colombier 	memmove(buf, va, n);	/* so we can NUL-terminate */
3139ef1f84bSDavid du Colombier 	buf[n] = 0;
3149ef1f84bSDavid du Colombier 	fd = strtoul(buf, 0, 0);
3159ef1f84bSDavid du Colombier 
3169ef1f84bSDavid du Colombier 	c1 = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
3179ef1f84bSDavid du Colombier 
3189ef1f84bSDavid du Colombier 	qlock(&srvlk);
3199ef1f84bSDavid du Colombier 	if(waserror()) {
3209ef1f84bSDavid du Colombier 		qunlock(&srvlk);
3219ef1f84bSDavid du Colombier 		cclose(c1);
3229ef1f84bSDavid du Colombier 		nexterror();
3239ef1f84bSDavid du Colombier 	}
3249ef1f84bSDavid du Colombier 	if(c1->flag & (CCEXEC|CRCLOSE))
3259ef1f84bSDavid du Colombier 		error("posted fd has remove-on-close or close-on-exec");
3269ef1f84bSDavid du Colombier 	if(c1->qid.type & QTAUTH)
3279ef1f84bSDavid du Colombier 		error("cannot post auth file in srv");
3289ef1f84bSDavid du Colombier 	sp = srvlookup(nil, c->qid.path);
3299ef1f84bSDavid du Colombier 	if(sp == 0)
3309ef1f84bSDavid du Colombier 		error(Enonexist);
3319ef1f84bSDavid du Colombier 
3329ef1f84bSDavid du Colombier 	if(sp->chan)
3339ef1f84bSDavid du Colombier 		error(Ebadusefd);
3349ef1f84bSDavid du Colombier 
3359ef1f84bSDavid du Colombier 	sp->chan = c1;
3369ef1f84bSDavid du Colombier 	qunlock(&srvlk);
3379ef1f84bSDavid du Colombier 	poperror();
3389ef1f84bSDavid du Colombier 	return n;
3399ef1f84bSDavid du Colombier }
3409ef1f84bSDavid du Colombier 
3419ef1f84bSDavid du Colombier Dev srvdevtab = {
3429ef1f84bSDavid du Colombier 	's',
3439ef1f84bSDavid du Colombier 	"srv",
3449ef1f84bSDavid du Colombier 
3459ef1f84bSDavid du Colombier 	devreset,
3469ef1f84bSDavid du Colombier 	srvinit,
3479ef1f84bSDavid du Colombier 	devshutdown,
3489ef1f84bSDavid du Colombier 	srvattach,
3499ef1f84bSDavid du Colombier 	srvwalk,
3509ef1f84bSDavid du Colombier 	srvstat,
3519ef1f84bSDavid du Colombier 	srvopen,
3529ef1f84bSDavid du Colombier 	srvcreate,
3539ef1f84bSDavid du Colombier 	srvclose,
3549ef1f84bSDavid du Colombier 	srvread,
3559ef1f84bSDavid du Colombier 	devbread,
3569ef1f84bSDavid du Colombier 	srvwrite,
3579ef1f84bSDavid du Colombier 	devbwrite,
3589ef1f84bSDavid du Colombier 	srvremove,
3599ef1f84bSDavid du Colombier 	srvwstat,
3609ef1f84bSDavid du Colombier };
361