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