xref: /plan9/sys/src/9/port/devsrv.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier typedef struct Srv Srv;
103e12c5d1SDavid du Colombier struct Srv
113e12c5d1SDavid du Colombier {
129a747e4fSDavid du Colombier 	char	*name;
139a747e4fSDavid du Colombier 	char	*owner;
143e12c5d1SDavid du Colombier 	ulong	perm;
153e12c5d1SDavid du Colombier 	Chan	*chan;
163e12c5d1SDavid du Colombier 	Srv	*link;
173e12c5d1SDavid du Colombier 	ulong	path;
183e12c5d1SDavid du Colombier };
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier static QLock	srvlk;
213e12c5d1SDavid du Colombier static Srv	*srv;
227dd7cddfSDavid du Colombier static int	qidpath;
233e12c5d1SDavid du Colombier 
247dd7cddfSDavid du Colombier static int
srvgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)259a747e4fSDavid du Colombier srvgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
263e12c5d1SDavid du Colombier {
273e12c5d1SDavid du Colombier 	Srv *sp;
289a747e4fSDavid du Colombier 	Qid q;
293e12c5d1SDavid du Colombier 
307dd7cddfSDavid du Colombier 	if(s == DEVDOTDOT){
317dd7cddfSDavid du Colombier 		devdir(c, c->qid, "#s", 0, eve, 0555, dp);
327dd7cddfSDavid du Colombier 		return 1;
337dd7cddfSDavid du Colombier 	}
347dd7cddfSDavid du Colombier 
353e12c5d1SDavid du Colombier 	qlock(&srvlk);
363e12c5d1SDavid du Colombier 	for(sp = srv; sp && s; sp = sp->link)
373e12c5d1SDavid du Colombier 		s--;
383e12c5d1SDavid du Colombier 
393e12c5d1SDavid du Colombier 	if(sp == 0) {
403e12c5d1SDavid du Colombier 		qunlock(&srvlk);
413e12c5d1SDavid du Colombier 		return -1;
423e12c5d1SDavid du Colombier 	}
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier 	mkqid(&q, sp->path, 0, QTFILE);
459a747e4fSDavid du Colombier 	/* make sure name string continues to exist after we release lock */
469a747e4fSDavid du Colombier 	kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
479a747e4fSDavid du Colombier 	devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
483e12c5d1SDavid du Colombier 	qunlock(&srvlk);
493e12c5d1SDavid du Colombier 	return 1;
503e12c5d1SDavid du Colombier }
513e12c5d1SDavid du Colombier 
527dd7cddfSDavid du Colombier static void
srvinit(void)533e12c5d1SDavid du Colombier srvinit(void)
543e12c5d1SDavid du Colombier {
557dd7cddfSDavid du Colombier 	qidpath = 1;
563e12c5d1SDavid du Colombier }
573e12c5d1SDavid du Colombier 
587dd7cddfSDavid du Colombier static Chan*
srvattach(char * spec)593e12c5d1SDavid du Colombier srvattach(char *spec)
603e12c5d1SDavid du Colombier {
613e12c5d1SDavid du Colombier 	return devattach('s', spec);
623e12c5d1SDavid du Colombier }
633e12c5d1SDavid du Colombier 
649a747e4fSDavid du Colombier static Walkqid*
srvwalk(Chan * c,Chan * nc,char ** name,int nname)659a747e4fSDavid du Colombier srvwalk(Chan *c, Chan *nc, char **name, int nname)
663e12c5d1SDavid du Colombier {
679a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, srvgen);
683e12c5d1SDavid du Colombier }
693e12c5d1SDavid du Colombier 
707dd7cddfSDavid du Colombier static Srv*
srvlookup(char * name,ulong qidpath)717dd7cddfSDavid du Colombier srvlookup(char *name, ulong qidpath)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier 	Srv *sp;
747dd7cddfSDavid du Colombier 	for(sp = srv; sp; sp = sp->link)
757dd7cddfSDavid du Colombier 		if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
767dd7cddfSDavid du Colombier 			return sp;
777dd7cddfSDavid du Colombier 	return nil;
787dd7cddfSDavid du Colombier }
797dd7cddfSDavid du Colombier 
809a747e4fSDavid du Colombier static int
srvstat(Chan * c,uchar * db,int n)819a747e4fSDavid du Colombier srvstat(Chan *c, uchar *db, int n)
829a747e4fSDavid du Colombier {
839a747e4fSDavid du Colombier 	return devstat(c, db, n, 0, 0, srvgen);
849a747e4fSDavid du Colombier }
859a747e4fSDavid du Colombier 
867dd7cddfSDavid du Colombier char*
srvname(Chan * c)877dd7cddfSDavid du Colombier srvname(Chan *c)
887dd7cddfSDavid du Colombier {
89*4e3613abSDavid du Colombier 	int size;
907dd7cddfSDavid du Colombier 	Srv *sp;
917dd7cddfSDavid du Colombier 	char *s;
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier 	for(sp = srv; sp; sp = sp->link)
947dd7cddfSDavid du Colombier 		if(sp->chan == c){
95*4e3613abSDavid du Colombier 			size = 3+strlen(sp->name)+1;
96*4e3613abSDavid du Colombier 			s = smalloc(size);
97*4e3613abSDavid du Colombier 			snprint(s, size, "#s/%s", sp->name);
987dd7cddfSDavid du Colombier 			return s;
997dd7cddfSDavid du Colombier 		}
1007dd7cddfSDavid du Colombier 	return nil;
1017dd7cddfSDavid du Colombier }
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier static Chan*
srvopen(Chan * c,int omode)1043e12c5d1SDavid du Colombier srvopen(Chan *c, int omode)
1053e12c5d1SDavid du Colombier {
1063e12c5d1SDavid du Colombier 	Srv *sp;
1073e12c5d1SDavid du Colombier 
1089a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR){
1097dd7cddfSDavid du Colombier 		if(omode & ORCLOSE)
1107dd7cddfSDavid du Colombier 			error(Eperm);
1113e12c5d1SDavid du Colombier 		if(omode != OREAD)
1123e12c5d1SDavid du Colombier 			error(Eisdir);
1133e12c5d1SDavid du Colombier 		c->mode = omode;
1143e12c5d1SDavid du Colombier 		c->flag |= COPEN;
1153e12c5d1SDavid du Colombier 		c->offset = 0;
1163e12c5d1SDavid du Colombier 		return c;
1173e12c5d1SDavid du Colombier 	}
1183e12c5d1SDavid du Colombier 	qlock(&srvlk);
1193e12c5d1SDavid du Colombier 	if(waserror()){
1203e12c5d1SDavid du Colombier 		qunlock(&srvlk);
1213e12c5d1SDavid du Colombier 		nexterror();
1223e12c5d1SDavid du Colombier 	}
1233e12c5d1SDavid du Colombier 
1247dd7cddfSDavid du Colombier 	sp = srvlookup(nil, c->qid.path);
1253e12c5d1SDavid du Colombier 	if(sp == 0 || sp->chan == 0)
1263e12c5d1SDavid du Colombier 		error(Eshutdown);
1273e12c5d1SDavid du Colombier 
1283e12c5d1SDavid du Colombier 	if(omode&OTRUNC)
1297dd7cddfSDavid du Colombier 		error("srv file already exists");
1307dd7cddfSDavid du Colombier 	if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
1313e12c5d1SDavid du Colombier 		error(Eperm);
13259cc4ca5SDavid du Colombier 	devpermcheck(sp->owner, sp->perm, omode);
1333e12c5d1SDavid du Colombier 
1347dd7cddfSDavid du Colombier 	cclose(c);
1353e12c5d1SDavid du Colombier 	incref(sp->chan);
1363e12c5d1SDavid du Colombier 	qunlock(&srvlk);
1373e12c5d1SDavid du Colombier 	poperror();
1383e12c5d1SDavid du Colombier 	return sp->chan;
1393e12c5d1SDavid du Colombier }
1403e12c5d1SDavid du Colombier 
1417dd7cddfSDavid du Colombier static void
srvcreate(Chan * c,char * name,int omode,ulong perm)1423e12c5d1SDavid du Colombier srvcreate(Chan *c, char *name, int omode, ulong perm)
1433e12c5d1SDavid du Colombier {
144ee17ab80SDavid du Colombier 	char *sname;
1453e12c5d1SDavid du Colombier 	Srv *sp;
1463e12c5d1SDavid du Colombier 
1477dd7cddfSDavid du Colombier 	if(openmode(omode) != OWRITE)
1483e12c5d1SDavid du Colombier 		error(Eperm);
1493e12c5d1SDavid du Colombier 
1507dd7cddfSDavid du Colombier 	if(omode & OCEXEC)	/* can't happen */
1517dd7cddfSDavid du Colombier 		panic("someone broke namec");
1527dd7cddfSDavid du Colombier 
153ee17ab80SDavid du Colombier 	sp = smalloc(sizeof *sp);
154ee17ab80SDavid du Colombier 	sname = smalloc(strlen(name)+1);
1553e12c5d1SDavid du Colombier 
1563e12c5d1SDavid du Colombier 	qlock(&srvlk);
1573e12c5d1SDavid du Colombier 	if(waserror()){
1589a747e4fSDavid du Colombier 		free(sp);
159aea505f3SDavid du Colombier 		free(sname);
1603e12c5d1SDavid du Colombier 		qunlock(&srvlk);
1613e12c5d1SDavid du Colombier 		nexterror();
1623e12c5d1SDavid du Colombier 	}
163aea505f3SDavid du Colombier 	if(sp == nil || sname == nil)
164aea505f3SDavid du Colombier 		error(Enomem);
1657dd7cddfSDavid du Colombier 	if(srvlookup(name, -1))
1667dd7cddfSDavid du Colombier 		error(Eexist);
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier 	sp->path = qidpath++;
1693e12c5d1SDavid du Colombier 	sp->link = srv;
170ee17ab80SDavid du Colombier 	strcpy(sname, name);
171ee17ab80SDavid du Colombier 	sp->name = sname;
1729a747e4fSDavid du Colombier 	c->qid.type = QTFILE;
1733e12c5d1SDavid du Colombier 	c->qid.path = sp->path;
1743e12c5d1SDavid du Colombier 	srv = sp;
1753e12c5d1SDavid du Colombier 	qunlock(&srvlk);
1763e12c5d1SDavid du Colombier 	poperror();
1773e12c5d1SDavid du Colombier 
1789a747e4fSDavid du Colombier 	kstrdup(&sp->owner, up->user);
1793e12c5d1SDavid du Colombier 	sp->perm = perm&0777;
1803e12c5d1SDavid du Colombier 
1813e12c5d1SDavid du Colombier 	c->flag |= COPEN;
1823e12c5d1SDavid du Colombier 	c->mode = OWRITE;
1833e12c5d1SDavid du Colombier }
1843e12c5d1SDavid du Colombier 
1857dd7cddfSDavid du Colombier static void
srvremove(Chan * c)1863e12c5d1SDavid du Colombier srvremove(Chan *c)
1873e12c5d1SDavid du Colombier {
1883e12c5d1SDavid du Colombier 	Srv *sp, **l;
1893e12c5d1SDavid du Colombier 
1909a747e4fSDavid du Colombier 	if(c->qid.type == QTDIR)
1913e12c5d1SDavid du Colombier 		error(Eperm);
1923e12c5d1SDavid du Colombier 
1933e12c5d1SDavid du Colombier 	qlock(&srvlk);
1943e12c5d1SDavid du Colombier 	if(waserror()){
1953e12c5d1SDavid du Colombier 		qunlock(&srvlk);
1963e12c5d1SDavid du Colombier 		nexterror();
1973e12c5d1SDavid du Colombier 	}
1983e12c5d1SDavid du Colombier 	l = &srv;
1993e12c5d1SDavid du Colombier 	for(sp = *l; sp; sp = sp->link) {
2003e12c5d1SDavid du Colombier 		if(sp->path == c->qid.path)
2013e12c5d1SDavid du Colombier 			break;
2023e12c5d1SDavid du Colombier 
203219b2ee8SDavid du Colombier 		l = &sp->link;
2043e12c5d1SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier 	if(sp == 0)
2063e12c5d1SDavid du Colombier 		error(Enonexist);
2073e12c5d1SDavid du Colombier 
208673c3d8aSDavid du Colombier 	/*
209673c3d8aSDavid du Colombier 	 * Only eve can remove system services.
210673c3d8aSDavid du Colombier 	 * No one can remove #s/boot.
211673c3d8aSDavid du Colombier 	 */
212673c3d8aSDavid du Colombier 	if(strcmp(sp->owner, eve) == 0 && !iseve())
213673c3d8aSDavid du Colombier 		error(Eperm);
2143e12c5d1SDavid du Colombier 	if(strcmp(sp->name, "boot") == 0)
2153e12c5d1SDavid du Colombier 		error(Eperm);
2163e12c5d1SDavid du Colombier 
217673c3d8aSDavid du Colombier 	/*
218673c3d8aSDavid du Colombier 	 * No removing personal services.
219673c3d8aSDavid du Colombier 	 */
220673c3d8aSDavid du Colombier 	if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
221673c3d8aSDavid du Colombier 		error(Eperm);
222673c3d8aSDavid du Colombier 
2233e12c5d1SDavid du Colombier 	*l = sp->link;
2243e12c5d1SDavid du Colombier 	qunlock(&srvlk);
2253e12c5d1SDavid du Colombier 	poperror();
2263e12c5d1SDavid du Colombier 
2273e12c5d1SDavid du Colombier 	if(sp->chan)
2287dd7cddfSDavid du Colombier 		cclose(sp->chan);
229a4f064b1SDavid du Colombier 	free(sp->owner);
230ee17ab80SDavid du Colombier 	free(sp->name);
2313e12c5d1SDavid du Colombier 	free(sp);
2323e12c5d1SDavid du Colombier }
2333e12c5d1SDavid du Colombier 
2349a747e4fSDavid du Colombier static int
srvwstat(Chan * c,uchar * dp,int n)2359a747e4fSDavid du Colombier srvwstat(Chan *c, uchar *dp, int n)
2363e12c5d1SDavid du Colombier {
237ee17ab80SDavid du Colombier 	char *strs;
2387dd7cddfSDavid du Colombier 	Dir d;
2397dd7cddfSDavid du Colombier 	Srv *sp;
2407dd7cddfSDavid du Colombier 
2419a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
2427dd7cddfSDavid du Colombier 		error(Eperm);
2437dd7cddfSDavid du Colombier 
244ee17ab80SDavid du Colombier 	strs = nil;
2457dd7cddfSDavid du Colombier 	qlock(&srvlk);
2467dd7cddfSDavid du Colombier 	if(waserror()){
2477dd7cddfSDavid du Colombier 		qunlock(&srvlk);
248ee17ab80SDavid du Colombier 		free(strs);
2497dd7cddfSDavid du Colombier 		nexterror();
2503e12c5d1SDavid du Colombier 	}
2513e12c5d1SDavid du Colombier 
2527dd7cddfSDavid du Colombier 	sp = srvlookup(nil, c->qid.path);
2537dd7cddfSDavid du Colombier 	if(sp == 0)
2547dd7cddfSDavid du Colombier 		error(Enonexist);
2557dd7cddfSDavid du Colombier 
256ee17ab80SDavid du Colombier 	if(strcmp(sp->owner, up->user) != 0 && !iseve())
2577dd7cddfSDavid du Colombier 		error(Eperm);
2587dd7cddfSDavid du Colombier 
259ee17ab80SDavid du Colombier 	strs = smalloc(n);
260ee17ab80SDavid du Colombier 	n = convM2D(dp, n, &d, strs);
2619a747e4fSDavid du Colombier 	if(n == 0)
2629a747e4fSDavid du Colombier 		error(Eshortstat);
2639a747e4fSDavid du Colombier 	if(d.mode != ~0UL)
2649a747e4fSDavid du Colombier 		sp->perm = d.mode & 0777;
26539734e7eSDavid du Colombier 	if(d.uid && *d.uid)
26639734e7eSDavid du Colombier 		kstrdup(&sp->owner, d.uid);
267ee17ab80SDavid du Colombier 	if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
268ee17ab80SDavid du Colombier 		if(strchr(d.name, '/') != nil)
269ee17ab80SDavid du Colombier 			error(Ebadchar);
270ee17ab80SDavid du Colombier 		kstrdup(&sp->name, d.name);
271ee17ab80SDavid du Colombier 	}
2727dd7cddfSDavid du Colombier 	qunlock(&srvlk);
273ee17ab80SDavid du Colombier 	free(strs);
2747dd7cddfSDavid du Colombier 	poperror();
2759a747e4fSDavid du Colombier 	return n;
2767dd7cddfSDavid du Colombier }
2777dd7cddfSDavid du Colombier 
2787dd7cddfSDavid du Colombier static void
srvclose(Chan * c)2793e12c5d1SDavid du Colombier srvclose(Chan *c)
2803e12c5d1SDavid du Colombier {
2817dd7cddfSDavid du Colombier 	/*
2827dd7cddfSDavid du Colombier 	 * in theory we need to override any changes in removability
2837dd7cddfSDavid du Colombier 	 * since open, but since all that's checked is the owner,
2847dd7cddfSDavid du Colombier 	 * which is immutable, all is well.
2857dd7cddfSDavid du Colombier 	 */
2869a747e4fSDavid du Colombier 	if(c->flag & CRCLOSE){
2879a747e4fSDavid du Colombier 		if(waserror())
2889a747e4fSDavid du Colombier 			return;
2897dd7cddfSDavid du Colombier 		srvremove(c);
2909a747e4fSDavid du Colombier 		poperror();
2919a747e4fSDavid du Colombier 	}
2923e12c5d1SDavid du Colombier }
2933e12c5d1SDavid du Colombier 
2947dd7cddfSDavid du Colombier static long
srvread(Chan * c,void * va,long n,vlong)2957dd7cddfSDavid du Colombier srvread(Chan *c, void *va, long n, vlong)
2963e12c5d1SDavid du Colombier {
2973e12c5d1SDavid du Colombier 	isdir(c);
2983e12c5d1SDavid du Colombier 	return devdirread(c, va, n, 0, 0, srvgen);
2993e12c5d1SDavid du Colombier }
3003e12c5d1SDavid du Colombier 
3017dd7cddfSDavid du Colombier static long
srvwrite(Chan * c,void * va,long n,vlong)3027dd7cddfSDavid du Colombier srvwrite(Chan *c, void *va, long n, vlong)
3033e12c5d1SDavid du Colombier {
3043e12c5d1SDavid du Colombier 	Srv *sp;
3053e12c5d1SDavid du Colombier 	Chan *c1;
3063e12c5d1SDavid du Colombier 	int fd;
3073e12c5d1SDavid du Colombier 	char buf[32];
3083e12c5d1SDavid du Colombier 
3093e12c5d1SDavid du Colombier 	if(n >= sizeof buf)
3103e12c5d1SDavid du Colombier 		error(Egreg);
3113e12c5d1SDavid du Colombier 	memmove(buf, va, n);	/* so we can NUL-terminate */
3123e12c5d1SDavid du Colombier 	buf[n] = 0;
3133e12c5d1SDavid du Colombier 	fd = strtoul(buf, 0, 0);
3143e12c5d1SDavid du Colombier 
3157dd7cddfSDavid du Colombier 	c1 = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier 	qlock(&srvlk);
3183e12c5d1SDavid du Colombier 	if(waserror()) {
3193e12c5d1SDavid du Colombier 		qunlock(&srvlk);
3207dd7cddfSDavid du Colombier 		cclose(c1);
3213e12c5d1SDavid du Colombier 		nexterror();
3223e12c5d1SDavid du Colombier 	}
3237dd7cddfSDavid du Colombier 	if(c1->flag & (CCEXEC|CRCLOSE))
3247dd7cddfSDavid du Colombier 		error("posted fd has remove-on-close or close-on-exec");
3259a747e4fSDavid du Colombier 	if(c1->qid.type & QTAUTH)
3268cd4f5a6SDavid du Colombier 		error("cannot post auth file in srv");
3277dd7cddfSDavid du Colombier 	sp = srvlookup(nil, c->qid.path);
3283e12c5d1SDavid du Colombier 	if(sp == 0)
3293e12c5d1SDavid du Colombier 		error(Enonexist);
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier 	if(sp->chan)
3327dd7cddfSDavid du Colombier 		error(Ebadusefd);
3333e12c5d1SDavid du Colombier 
3343e12c5d1SDavid du Colombier 	sp->chan = c1;
3353e12c5d1SDavid du Colombier 	qunlock(&srvlk);
3363e12c5d1SDavid du Colombier 	poperror();
3373e12c5d1SDavid du Colombier 	return n;
3383e12c5d1SDavid du Colombier }
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier Dev srvdevtab = {
3417dd7cddfSDavid du Colombier 	's',
3427dd7cddfSDavid du Colombier 	"srv",
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier 	devreset,
3457dd7cddfSDavid du Colombier 	srvinit,
3469a747e4fSDavid du Colombier 	devshutdown,
3477dd7cddfSDavid du Colombier 	srvattach,
3487dd7cddfSDavid du Colombier 	srvwalk,
3497dd7cddfSDavid du Colombier 	srvstat,
3507dd7cddfSDavid du Colombier 	srvopen,
3517dd7cddfSDavid du Colombier 	srvcreate,
3527dd7cddfSDavid du Colombier 	srvclose,
3537dd7cddfSDavid du Colombier 	srvread,
3547dd7cddfSDavid du Colombier 	devbread,
3557dd7cddfSDavid du Colombier 	srvwrite,
3567dd7cddfSDavid du Colombier 	devbwrite,
3577dd7cddfSDavid du Colombier 	srvremove,
3587dd7cddfSDavid du Colombier 	srvwstat,
3597dd7cddfSDavid du Colombier };
360