vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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