devsrv.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devsrv.c (5982B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 
            9 typedef struct Srv Srv;
           10 struct Srv
           11 {
           12         char        *name;
           13         char        *owner;
           14         ulong        perm;
           15         Chan        *chan;
           16         Srv        *link;
           17         ulong        path;
           18 };
           19 
           20 static QLock        srvlk;
           21 static Srv        *srv;
           22 static int        qidpath;
           23 
           24 static int
           25 srvgen(Chan *c, char *name, Dirtab *dt, int i, int s, Dir *dp)
           26 {
           27         Srv *sp;
           28         Qid q;
           29 
           30         if(s == DEVDOTDOT){
           31                 devdir(c, c->qid, "#s", 0, eve, 0555, dp);
           32                 return 1;
           33         }
           34 
           35         qlock(&srvlk);
           36         for(sp = srv; sp && s; sp = sp->link)
           37                 s--;
           38 
           39         if(sp == 0) {
           40                 qunlock(&srvlk);
           41                 return -1;
           42         }
           43 
           44         mkqid(&q, sp->path, 0, QTFILE);
           45         /* make sure name string continues to exist after we release lock */
           46         kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
           47         devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
           48         qunlock(&srvlk);
           49         return 1;
           50 }
           51 
           52 static void
           53 srvinit(void)
           54 {
           55         qidpath = 1;
           56 }
           57 
           58 static Chan*
           59 srvattach(char *spec)
           60 {
           61         return devattach('s', spec);
           62 }
           63 
           64 static Walkqid*
           65 srvwalk(Chan *c, Chan *nc, char **name, int nname)
           66 {
           67         return devwalk(c, nc, name, nname, 0, 0, srvgen);
           68 }
           69 
           70 static Srv*
           71 srvlookup(char *name, ulong qidpath)
           72 {
           73         Srv *sp;
           74         for(sp = srv; sp; sp = sp->link)
           75                 if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
           76                         return sp;
           77         return nil;
           78 }
           79 
           80 static int
           81 srvstat(Chan *c, uchar *db, int n)
           82 {
           83         return devstat(c, db, n, 0, 0, srvgen);
           84 }
           85 
           86 char*
           87 srvname(Chan *c)
           88 {
           89         Srv *sp;
           90         char *s;
           91 
           92         for(sp = srv; sp; sp = sp->link)
           93                 if(sp->chan == c){
           94                         s = smalloc(3+strlen(sp->name)+1);
           95                         sprint(s, "#s/%s", sp->name);
           96                         return s;
           97                 }
           98         return nil;
           99 }
          100 
          101 static Chan*
          102 srvopen(Chan *c, int omode)
          103 {
          104         Srv *sp;
          105 
          106         if(c->qid.type == QTDIR){
          107                 if(omode & ORCLOSE)
          108                         error(Eperm);
          109                 if(omode != OREAD)
          110                         error(Eisdir);
          111                 c->mode = omode;
          112                 c->flag |= COPEN;
          113                 c->offset = 0;
          114                 return c;
          115         }
          116         qlock(&srvlk);
          117         if(waserror()){
          118                 qunlock(&srvlk);
          119                 nexterror();
          120         }
          121 
          122         sp = srvlookup(nil, c->qid.path);
          123         if(sp == 0 || sp->chan == 0)
          124                 error(Eshutdown);
          125 
          126         if(omode&OTRUNC)
          127                 error("srv file already exists");
          128         if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
          129                 error(Eperm);
          130         devpermcheck(sp->owner, sp->perm, omode);
          131 
          132         cclose(c);
          133         incref(&sp->chan->ref);
          134         qunlock(&srvlk);
          135         poperror();
          136         return sp->chan;
          137 }
          138 
          139 static void
          140 srvcreate(Chan *c, char *name, int omode, ulong perm)
          141 {
          142         char *sname;
          143         Srv *sp;
          144 
          145         if(openmode(omode) != OWRITE)
          146                 error(Eperm);
          147 
          148         if(omode & OCEXEC)        /* can't happen */
          149                 panic("someone broke namec");
          150 
          151         sp = smalloc(sizeof *sp);
          152         sname = smalloc(strlen(name)+1);
          153 
          154         qlock(&srvlk);
          155         if(waserror()){
          156                 free(sp);
          157                 free(sname);
          158                 qunlock(&srvlk);
          159                 nexterror();
          160         }
          161         if(sp == nil || sname == nil)
          162                 error(Enomem);
          163         if(srvlookup(name, -1))
          164                 error(Eexist);
          165 
          166         sp->path = qidpath++;
          167         sp->link = srv;
          168         strcpy(sname, name);
          169         sp->name = sname;
          170         c->qid.type = QTFILE;
          171         c->qid.path = sp->path;
          172         srv = sp;
          173         qunlock(&srvlk);
          174         poperror();
          175 
          176         kstrdup(&sp->owner, up->user);
          177         sp->perm = perm&0777;
          178 
          179         c->flag |= COPEN;
          180         c->mode = OWRITE;
          181 }
          182 
          183 static void
          184 srvremove(Chan *c)
          185 {
          186         Srv *sp, **l;
          187 
          188         if(c->qid.type == QTDIR)
          189                 error(Eperm);
          190 
          191         qlock(&srvlk);
          192         if(waserror()){
          193                 qunlock(&srvlk);
          194                 nexterror();
          195         }
          196         l = &srv;
          197         for(sp = *l; sp; sp = sp->link) {
          198                 if(sp->path == c->qid.path)
          199                         break;
          200 
          201                 l = &sp->link;
          202         }
          203         if(sp == 0)
          204                 error(Enonexist);
          205 
          206         /*
          207          * Only eve can remove system services.
          208          * No one can remove #s/boot.
          209          */
          210         if(strcmp(sp->owner, eve) == 0 && !iseve())
          211                 error(Eperm);
          212         if(strcmp(sp->name, "boot") == 0)
          213                 error(Eperm);
          214 
          215         /*
          216          * No removing personal services.
          217          */
          218         if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
          219                 error(Eperm);
          220 
          221         *l = sp->link;
          222         qunlock(&srvlk);
          223         poperror();
          224 
          225         if(sp->chan)
          226                 cclose(sp->chan);
          227         free(sp->name);
          228         free(sp);
          229 }
          230 
          231 static int
          232 srvwstat(Chan *c, uchar *dp, int n)
          233 {
          234         char *strs;
          235         Dir d;
          236         Srv *sp;
          237 
          238         if(c->qid.type & QTDIR)
          239                 error(Eperm);
          240 
          241         strs = nil;
          242         qlock(&srvlk);
          243         if(waserror()){
          244                 qunlock(&srvlk);
          245                 free(strs);
          246                 nexterror();
          247         }
          248 
          249         sp = srvlookup(nil, c->qid.path);
          250         if(sp == 0)
          251                 error(Enonexist);
          252 
          253         if(strcmp(sp->owner, up->user) != 0 && !iseve())
          254                 error(Eperm);
          255 
          256         strs = smalloc(n);
          257         n = convM2D(dp, n, &d, strs);
          258         if(n == 0)
          259                 error(Eshortstat);
          260         if(d.mode != ~0UL)
          261                 sp->perm = d.mode & 0777;
          262         if(d.uid && *d.uid)
          263                 kstrdup(&sp->owner, d.uid);
          264         if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
          265                 if(strchr(d.name, '/') != nil)
          266                         error(Ebadchar);
          267                 kstrdup(&sp->name, d.name);
          268         }
          269         qunlock(&srvlk);
          270         free(strs);
          271         poperror();
          272         return n;
          273 }
          274 
          275 static void
          276 srvclose(Chan *c)
          277 {
          278         /*
          279          * in theory we need to override any changes in removability
          280          * since open, but since all that's checked is the owner,
          281          * which is immutable, all is well.
          282          */
          283         if(c->flag & CRCLOSE){
          284                 if(waserror())
          285                         return;
          286                 srvremove(c);
          287                 poperror();
          288         }
          289 }
          290 
          291 static long
          292 srvread(Chan *c, void *va, long n, vlong off)
          293 {
          294         isdir(c);
          295         return devdirread(c, va, n, 0, 0, srvgen);
          296 }
          297 static void srvadd(Chan*, Chan*);
          298 
          299 
          300 static long
          301 srvwrite(Chan *c, void *va, long n, vlong off)
          302 {
          303         Chan *c1;
          304         int fd;
          305         char buf[32];
          306 
          307         if(n >= sizeof buf)
          308                 error(Egreg);
          309         memmove(buf, va, n);        /* so we can NUL-terminate */
          310         buf[n] = 0;
          311         fd = strtoul(buf, 0, 0);
          312 
          313         c1 = fdtochan(fd, -1, 0, 1);        /* error check and inc ref */
          314         srvadd(c, c1);
          315         return n;
          316 }
          317 
          318 // Plan 9 VX split srvadd out from srvwrite.
          319 static void
          320 srvadd(Chan *c, Chan *c1)
          321 {
          322         Srv *sp;
          323 
          324         /* c1 already incref'ed */
          325 
          326         qlock(&srvlk);
          327         if(waserror()) {
          328                 qunlock(&srvlk);
          329                 cclose(c1);
          330                 nexterror();
          331         }
          332         if(c1->flag & (CCEXEC|CRCLOSE))
          333                 error("posted fd has remove-on-close or close-on-exec");
          334         if(c1->qid.type & QTAUTH)
          335                 error("cannot post auth file in srv");
          336         sp = srvlookup(nil, c->qid.path);
          337         if(sp == 0)
          338                 error(Enonexist);
          339 
          340         if(sp->chan)
          341                 error(Ebadusefd);
          342 
          343         sp->chan = c1;
          344         qunlock(&srvlk);
          345         poperror();
          346 }
          347 
          348 Dev srvdevtab = {
          349         's',
          350         "srv",
          351 
          352         devreset,
          353         srvinit,        
          354         devshutdown,
          355         srvattach,
          356         srvwalk,
          357         srvstat,
          358         srvopen,
          359         srvcreate,
          360         srvclose,
          361         srvread,
          362         devbread,
          363         srvwrite,
          364         devbwrite,
          365         srvremove,
          366         srvwstat,
          367 };
          368 
          369 // Plan 9 VX addition
          370 void
          371 ksrvadd(Chan *c, Chan *c1)
          372 {
          373         incref(&c1->ref);
          374         srvadd(c, c1);
          375 }
          376