#include <9pm/u.h>
#include <9pm/libc.h>
#include "dat.h"
#include "fns.h"
enum
{
Maxenvsize = 16300,
};
static int
envgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp)
{
Egrp *eg;
Evalue *e;
USED(name);
USED(tab);
USED(ntab);
if(s == DEVDOTDOT){
devdir(c, c->qid, "#e", 0, up->user, DMDIR|0775, dp);
return 1;
}
eg = up->egrp;
qlock(&eg->lk);
for(e = eg->entries; e && s; e = e->link)
s--;
if(e == 0) {
qunlock(&eg->lk);
return -1;
}
/* make sure name string continues to exist after we release lock */
kstrcpy(up->genbuf, e->name, sizeof up->genbuf);
devdir(c, e->qid, up->genbuf, e->len, up->user, 0666, dp);
qunlock(&eg->lk);
return 1;
}
static Evalue*
envlookup(Egrp *eg, char *name, ulong qidpath)
{
Evalue *e;
for(e = eg->entries; e; e = e->link)
if(e->qid.path == qidpath || (name && strcmp(e->name, name) == 0))
return e;
return nil;
}
static Chan*
envattach(char *spec)
{
return devattach('e', spec);
}
static Walkqid*
envwalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, 0, 0, envgen);
}
static int
envstat(Chan *c, uchar *db, int n)
{
if(c->qid.type & QTDIR)
c->qid.vers = up->egrp->vers;
return devstat(c, db, n, 0, 0, envgen);
}
static Chan*
envopen(Chan *c, int omode)
{
Egrp *eg;
Evalue *e;
eg = up->egrp;
if(c->qid.type & QTDIR) {
if(omode != OREAD)
error(Eperm);
}
else {
qlock(&eg->lk);
e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
qunlock(&eg->lk);
error(Enonexist);
}
if((omode & OTRUNC) && e->value) {
e->qid.vers++;
free(e->value);
e->value = 0;
e->len = 0;
}
qunlock(&eg->lk);
}
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
static void
envcreate(Chan *c, char *name, int omode, ulong perm)
{
Egrp *eg;
Evalue *e;
USED(perm);
if(c->qid.type != QTDIR)
error(Eperm);
omode = openmode(omode);
eg = up->egrp;
qlock(&eg->lk);
if(waserror()) {
qunlock(&eg->lk);
nexterror();
}
if(envlookup(eg, name, -1))
error(Eexist);
e = smalloc(sizeof(Evalue));
e->name = smalloc(strlen(name)+1);
strcpy(e->name, name);
e->qid.path = ++eg->path;
e->qid.vers = 0;
eg->vers++;
e->link = eg->entries;
eg->entries = e;
c->qid = e->qid;
qunlock(&eg->lk);
poperror();
c->offset = 0;
c->mode = omode;
c->flag |= COPEN;
}
static void
envremove(Chan *c)
{
Egrp *eg;
Evalue *e, **l;
if(c->qid.type & QTDIR)
error(Eperm);
eg = up->egrp;
qlock(&eg->lk);
l = &eg->entries;
for(e = *l; e; e = e->link) {
if(e->qid.path == c->qid.path)
break;
l = &e->link;
}
if(e == 0) {
qunlock(&eg->lk);
error(Enonexist);
}
*l = e->link;
eg->vers++;
qunlock(&eg->lk);
free(e->name);
if(e->value)
free(e->value);
free(e);
}
static void
envclose(Chan *c)
{
/*
* cclose can't fail, so errors from remove will be ignored.
* since permissions aren't checked,
* envremove can't not remove it if its there.
*/
if(c->flag & CRCLOSE)
envremove(c);
}
static long
envread(Chan *c, void *a, long n, vlong off)
{
Egrp *eg;
Evalue *e;
ulong offset = off;
if(c->qid.type & QTDIR)
return devdirread(c, a, n, 0, 0, envgen);
eg = up->egrp;
qlock(&eg->lk);
e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
qunlock(&eg->lk);
error(Enonexist);
}
if(offset + n > e->len)
n = e->len - offset;
if(n <= 0)
n = 0;
else
memmove(a, e->value+offset, n);
qunlock(&eg->lk);
return n;
}
static long
envwrite(Chan *c, void *a, long n, vlong off)
{
char *s;
int vend;
Egrp *eg;
Evalue *e;
ulong offset = off;
if(n <= 0)
return 0;
vend = offset+n;
if(vend > Maxenvsize)
error(Etoobig);
eg = up->egrp;
qlock(&eg->lk);
e = envlookup(eg, nil, c->qid.path);
if(e == 0) {
qunlock(&eg->lk);
error(Enonexist);
}
if(vend > e->len) {
s = smalloc(offset+n);
if(e->value){
memmove(s, e->value, e->len);
free(e->value);
}
e->value = s;
e->len = vend;
}
memmove(e->value+offset, a, n);
e->qid.vers++;
eg->vers++;
qunlock(&eg->lk);
return n;
}
Dev devenv = {
'e',
"env",
devreset,
envattach,
envwalk,
envstat,
envopen,
envcreate,
envclose,
envread,
devbread,
envwrite,
devbwrite,
envremove,
devwstat,
};
void
envcpy(Egrp *to, Egrp *from)
{
Evalue **l, *ne, *e;
l = &to->entries;
qlock(&from->lk);
for(e = from->entries; e; e = e->link) {
ne = smalloc(sizeof(Evalue));
ne->name = smalloc(strlen(e->name)+1);
strcpy(ne->name, e->name);
if(e->value) {
ne->value = smalloc(e->len);
memmove(ne->value, e->value, e->len);
ne->len = e->len;
}
ne->qid.path = ++to->path;
*l = ne;
l = &ne->link;
}
qunlock(&from->lk);
}
void
closeegrp(Egrp *eg)
{
Evalue *e, *next;
if(decref(&eg->ref) == 0) {
for(e = eg->entries; e; e = next) {
next = e->link;
free(e->name);
if(e->value)
free(e->value);
free(e);
}
free(eg);
}
}
/*
* to let the kernel set environment variables
*/
void
ksetenv(char *ename, char *eval)
{
Chan *c;
char buf[2*KNAMELEN];
c = namec(buf, Acreate, OWRITE, 0600);
devtab[c->type]->write(c, eval, strlen(eval), 0);
cclose(c);
}
syntax highlighted by Code2HTML, v. 0.9.1