ref: e61dd8794563ad8a88e713ec0ed56f4a730829d8
parent: 9febeeb92c8dd89a519a1c45bc67648b5284d3ab
author: 9ferno <gophone2015@gmail.com>
date: Thu Nov 11 10:54:27 EST 2021
import 9front devenv.c
--- a/os/port/devenv.c
+++ b/os/port/devenv.c
@@ -8,37 +8,60 @@
#include "dat.h"
#include "fns.h"
-static void envremove(Chan*);
-
enum
{
+ DELTAENV = 32,
Maxenvsize = 16300,
};
+static Egrp *envgrp(Chan *c);
+static int envwriteable(Chan *c);
+
static Egrp confegrp; /* global environment group containing the kernel configuration */
+static Evalue*
+envlookup(Egrp *eg, char *name, ulong qidpath)
+{
+ Evalue *e, *ee;
+
+ e = eg->ent;
+ for(ee = e + eg->nent; e < ee; e++){
+ if(e->qid.path == qidpath
+ || (name != nil && name[0] == e->name[0] && strcmp(e->name, name) == 0))
+ return e;
+ }
+ return nil;
+}
+
static int
-envgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
+envgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
{
Egrp *eg;
Evalue *e;
if(s == DEVDOTDOT){
- devdir(c, c->qid, "#e", 0, eve, DMDIR|0775, dp);
+ devdir(c, c->qid, "#e", 0, eve, 0775, dp);
return 1;
}
- eg = up->env->egrp;
- qlock(eg);
- for(e = eg->entries; e != nil && s != 0; e = e->next)
- s--;
- if(e == nil) {
- qunlock(eg);
+
+ eg = envgrp(c);
+ rlock(eg);
+ if(name != nil)
+ e = envlookup(eg, name, -1);
+ else if(s < eg->nent)
+ e = &eg->ent[s];
+ else
+ e = nil;
+ if(e == nil || name != nil && (strlen(e->name) >= sizeof(up->genbuf))) {
+ runlock(eg);
return -1;
}
+
/* make sure name string continues to exist after we release lock */
- kstrcpy(up->genbuf, e->var, sizeof up->genbuf);
- devdir(c, e->qid, up->genbuf, e->len, eve, 0666, dp);
- qunlock(eg);
+ kstrcpy(up->genbuf, e->name, sizeof up->genbuf);
+ devdir(c, e->qid, up->genbuf, e->len, eve,
+ eg == &confegrp || eg != up->env->egrp ? 0664: 0666, dp);
+ runlock(eg);
return 1;
}
@@ -45,9 +68,18 @@
static Chan*
envattach(char *spec)
{
- if(up->env == nil || up->env->egrp == nil)
- error(Enodev);
- return devattach('e', spec);
+ Chan *c;
+ Egrp *egrp = nil;
+
+ if(spec != nil && *spec != '\0') {
+ if(strcmp(spec, "c") != 0)
+ error(Ebadarg);
+ egrp = &confegrp;
+ }
+
+ c = devattach('e', spec);
+ c->aux = egrp;
+ return c;
}
static Walkqid*
@@ -60,111 +92,171 @@
envstat(Chan *c, uchar *db, int n)
{
if(c->qid.type & QTDIR)
- c->qid.vers = up->env->egrp->vers;
+ c->qid.vers = envgrp(c)->vers;
return devstat(c, db, n, 0, 0, envgen);
}
-static Chan *
-envopen(Chan *c, u32 mode)
+static Chan*
+envopen(Chan *c, u32 omode)
{
Egrp *eg;
Evalue *e;
-
+ int trunc;
+
+ eg = envgrp(c);
if(c->qid.type & QTDIR) {
- if(mode != OREAD)
+ if(omode != OREAD)
error(Eperm);
- c->mode = mode;
- c->flag |= COPEN;
- c->offset = 0;
- return c;
}
- eg = up->env->egrp;
- qlock(eg);
- for(e = eg->entries; e != nil; e = e->next)
- if(e->qid.path == c->qid.path)
- break;
- if(e == nil) {
- qunlock(eg);
- error(Enonexist);
+ else {
+ trunc = omode & OTRUNC;
+ if(omode != OREAD && !envwriteable(c))
+ error(Eperm);
+ if(trunc)
+ wlock(eg);
+ else
+ rlock(eg);
+ e = envlookup(eg, nil, c->qid.path);
+ if(e == nil) {
+ if(trunc)
+ wunlock(eg);
+ else
+ runlock(eg);
+ error(Enonexist);
+ }
+ if(trunc && e->value != nil) {
+ e->qid.vers++;
+ free(e->value);
+ e->value = nil;
+ e->len = 0;
+ }
+ if(trunc)
+ wunlock(eg);
+ else
+ runlock(eg);
}
- if((mode & OTRUNC) && e->val) {
- free(e->val);
- e->val = 0;
- e->len = 0;
- e->qid.vers++;
- }
- qunlock(eg);
- c->mode = openmode(mode);
- c->flag |= COPEN;
+ c->mode = openmode(omode);
+ incref(eg);
+ c->aux = eg;
c->offset = 0;
+ c->flag |= COPEN;
return c;
}
static void
-envcreate(Chan *c, char *name, u32 mode, u32)
+envcreate(Chan *c, char *name, u32 omode, u32)
{
Egrp *eg;
- Evalue *e, **le;
+ Evalue *e;
- if(c->qid.type != QTDIR)
+ if(c->qid.type != QTDIR || !envwriteable(c))
error(Eperm);
+
if(strlen(name) >= sizeof(up->genbuf))
- error("name too long"); /* needs to fit for stat */
- mode = openmode(mode);
- eg = up->env->egrp;
- qlock(eg);
- if(waserror()){
- qunlock(eg);
+ error(Etoolong);
+
+ omode = openmode(omode);
+ eg = envgrp(c);
+ wlock(eg);
+ if(waserror()) {
+ wunlock(eg);
nexterror();
}
- for(le = &eg->entries; (e = *le) != nil; le = &e->next)
- if(strcmp(e->var, name) == 0)
- error(Eexist);
- e = smalloc(sizeof(Evalue));
- e->var = smalloc(strlen(name)+1);
- strcpy(e->var, name);
- e->val = 0;
+
+ if(envlookup(eg, name, -1) != nil)
+ error(Eexist);
+
+ if(eg->nent == eg->ment){
+ Evalue *tmp;
+
+ eg->ment += DELTAENV;
+ if((tmp = realloc(eg->ent, sizeof(eg->ent[0])*eg->ment)) == nil){
+ eg->ment -= DELTAENV;
+ error(Enomem);
+ }
+ eg->ent = tmp;
+ }
+ eg->vers++;
+ e = &eg->ent[eg->nent++];
+ e->value = nil;
e->len = 0;
- e->qid.path = ++eg->path;
- e->next = nil;
- e->qid.vers = 0;
- *le = e;
+ e->name = smalloc(strlen(name)+1);
+ strcpy(e->name, name);
+ mkqid(&e->qid, ++eg->path, 0, QTFILE);
c->qid = e->qid;
- eg->vers++;
+
+ wunlock(eg);
poperror();
- qunlock(eg);
+ incref(eg);
+ c->aux = eg;
c->offset = 0;
+ c->mode = omode;
c->flag |= COPEN;
- c->mode = mode;
+ return;
}
static void
+envremove(Chan *c)
+{
+ Egrp *eg;
+ Evalue *e;
+
+ if(c->qid.type & QTDIR || !envwriteable(c))
+ error(Eperm);
+
+ eg = envgrp(c);
+ wlock(eg);
+ e = envlookup(eg, nil, c->qid.path);
+ if(e == nil){
+ wunlock(eg);
+ error(Enonexist);
+ }
+ free(e->name);
+ free(e->value);
+ *e = eg->ent[--eg->nent];
+ eg->vers++;
+ wunlock(eg);
+}
+
+static void
envclose(Chan *c)
{
- if(c->flag & CRCLOSE)
- envremove(c);
+ if(c->flag & COPEN){
+ /*
+ * 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 && !waserror()){
+ envremove(c);
+ poperror();
+ }
+ closeegrp((Egrp*)c->aux);
+ c->aux = nil;
+ }
}
static s32
-envread(Chan *c, void *a, s32 n, s64 offset)
+envread(Chan *c, void *a, s32 n, s64 off)
{
Egrp *eg;
Evalue *e;
+ ulong offset = off;
if(c->qid.type & QTDIR)
return devdirread(c, a, n, 0, 0, envgen);
- eg = up->env->egrp;
- qlock(eg);
+
+ eg = envgrp(c);
+ rlock(eg);
if(waserror()){
- qunlock(eg);
+ runlock(eg);
nexterror();
}
- for(e = eg->entries; e != nil; e = e->next)
- if(e->qid.path == c->qid.path)
- break;
+
+ e = envlookup(eg, nil, c->qid.path);
if(e == nil)
error(Enonexist);
- if(offset > e->len) /* protects against overflow converting vlong to ulong */
+ if(offset >= e->len || e->value == nil)
n = 0;
else if(offset + n > e->len)
n = e->len - offset;
@@ -171,77 +263,56 @@
if(n <= 0)
n = 0;
else
- memmove(a, e->val+offset, n);
+ memmove(a, e->value+offset, n);
+
+ runlock(eg);
poperror();
- qunlock(eg);
return n;
}
static s32
-envwrite(Chan *c, void *a, s32 n, s64 offset)
+envwrite(Chan *c, void *a, s32 n, s64 off)
{
char *s;
- ulong ve;
+ ulong len;
Egrp *eg;
Evalue *e;
+ ulong offset = off;
if(n <= 0)
return 0;
- ve = offset+n;
- if(ve > Maxenvsize)
+ if(offset > Maxenvsize || n > (Maxenvsize - offset))
error(Etoobig);
- eg = up->env->egrp;
- qlock(eg);
+
+ eg = envgrp(c);
+ wlock(eg);
if(waserror()){
- qunlock(eg);
+ wunlock(eg);
nexterror();
}
- for(e = eg->entries; e != nil; e = e->next)
- if(e->qid.path == c->qid.path)
- break;
+
+ e = envlookup(eg, nil, c->qid.path);
if(e == nil)
error(Enonexist);
- if(ve > e->len) {
- s = smalloc(ve);
- memmove(s, e->val, e->len);
- if(e->val != nil)
- free(e->val);
- e->val = s;
- e->len = ve;
+
+ len = offset+n;
+ if(len > e->len) {
+ s = realloc(e->value, len);
+ if(s == nil)
+ error(Enomem);
+ memset(s+offset, 0, n);
+ e->value = s;
+ e->len = len;
}
- memmove(e->val+offset, a, n);
+ memmove(e->value+offset, a, n);
e->qid.vers++;
+ eg->vers++;
+
+ wunlock(eg);
poperror();
- qunlock(eg);
return n;
}
-static void
-envremove(Chan *c)
-{
- Egrp *eg;
- Evalue *e, **l;
-
- if(c->qid.type & QTDIR)
- error(Eperm);
- eg = up->env->egrp;
- qlock(eg);
- for(l = &eg->entries; (e = *l) != nil; l = &e->next)
- if(e->qid.path == c->qid.path)
- break;
- if(e == nil) {
- qunlock(eg);
- error(Enonexist);
- }
- *l = e->next;
- eg->vers++;
- qunlock(eg);
- free(e->var);
- if(e->val != nil)
- free(e->val);
- free(e);
-}
-
Dev envdevtab = {
'e',
"env",
@@ -272,55 +343,69 @@
Egrp *e;
e = smalloc(sizeof(Egrp));
- e->ref = 1;
+ incref(e);
return e;
}
void
-closeegrp(Egrp *e)
+closeegrp(Egrp *eg)
{
- Evalue *el, *nl;
+ Evalue *e, *ee;
- if(e == nil || decref(e) != 0)
+ if(eg == nil)
return;
- for (el = e->entries; el != nil; el = nl) {
- free(el->var);
- if (el->val)
- free(el->val);
- nl = el->next;
- free(el);
+ if(decref(eg) == 0 && eg != &confegrp){
+ e = eg->ent;
+ for(ee = e + eg->nent; e < ee; e++){
+ free(e->name);
+ free(e->value);
+ }
+ free(eg->ent);
+ free(eg);
}
- free(e);
}
+static Egrp*
+envgrp(Chan *c)
+{
+ if(c->aux == nil)
+ return up->env->egrp;
+ return c->aux;
+}
+
+static int
+envwriteable(Chan *c)
+{
+ return c->aux == nil || c->aux == up->env->egrp || iseve();
+}
+
+/* same as envcpy() of 9front */
void
egrpcpy(Egrp *to, Egrp *from)
{
- Evalue *e, *ne, **last;
+ Evalue *e, *ee, *ne;
- if(from == nil)
- return;
- last = &to->entries;
- qlock(from);
- for (e = from->entries; e != nil; e = e->next) {
- ne = smalloc(sizeof(Evalue));
- ne->var = smalloc(strlen(e->var)+1);
- strcpy(ne->var, e->var);
- if (e->val) {
- ne->val = smalloc(e->len);
- memmove(ne->val, e->val, e->len);
+ rlock(from);
+ to->ment = ROUND(from->nent, DELTAENV);
+ to->ent = smalloc(to->ment*sizeof(to->ent[0]));
+ ne = to->ent;
+ e = from->ent;
+ for(ee = e + from->nent; e < ee; e++, ne++){
+ ne->name = smalloc(strlen(e->name)+1);
+ strcpy(ne->name, e->name);
+ if(e->value != nil){
+ ne->value = smalloc(e->len);
+ memmove(ne->value, e->value, e->len);
ne->len = e->len;
}
- ne->qid.path = ++to->path;
- *last = ne;
- last = &ne->next;
+ mkqid(&ne->qid, ++to->path, 0, QTFILE);
}
- qunlock(from);
+ to->nent = from->nent;
+ runlock(from);
}
/*
* to let the kernel set environment variables
- * TODO 9ferno shows both #ec and #e variables for ls '#e' and ls '#ec'
*/
void
ksetenv(char *ename, char *eval, int conf)
@@ -329,18 +414,8 @@
char buf[2*KNAMELEN];
snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
- if(waserror()){
- return;
- }
c = namec(buf, Acreate, OWRITE, 0666);
- poperror();
- if(!waserror()){
- if(!waserror()){
- devtab[c->type]->write(c, eval, strlen(eval), 0);
- poperror();
- }
- poperror();
- }
+ devtab[c->type]->write(c, eval, strlen(eval), 0);
cclose(c);
}
@@ -357,9 +432,9 @@
char *p, *q;
int n;
- qlock(eg);
+ rlock(eg);
if(waserror()) {
- qunlock(eg);
+ runlock(eg);
nexterror();
}
@@ -384,7 +459,7 @@
}
*q = '\0';
- qunlock(eg);
+ runlock(eg);
poperror();
return p;
}
--- a/os/port/portdat.h
+++ b/os/port/portdat.h
@@ -95,21 +95,22 @@
struct Osenv
{
- char *syserrstr; /* last error from a system call, errbuf0 or 1 */
+ char *syserrstr; /* last error from a system call, errbuf0 or 1 - obsolete in inferno */
+ intptr errpc;
char *errstr; /* reason we're unwinding the error stack, errbuf1 or 0 */
char errbuf0[ERRMAX];
char errbuf1[ERRMAX];
- Pgrp* pgrp; /* Ref to namespace, working dir and root */
- Fgrp* fgrp; /* Ref to file descriptors */
- Egrp* egrp; /* Environment vars */
- Skeyset* sigs; /* Signed module keys */
- Rendez* rend; /* Synchro point */
- Queue* waitq; /* Info about dead children */
- Queue* childq; /* Info about children for debuggers */
- void* debug; /* Debugging master */
+ Pgrp *pgrp; /* Ref to namespace, working dir and root */
+ Fgrp *fgrp; /* Ref to file descriptors */
+ Egrp *egrp; /* Environment vars */
+ Skeyset *sigs; /* Signed module keys */
+ Rendez *rend; /* Synchro point */
+ Queue *waitq; /* Info about dead children */
+ Queue *childq; /* Info about children for debuggers */
+ void *debug; /* Debugging master */
s32 uid; /* Numeric user id for system */
s32 gid; /* Numeric group id for system */
- char* user; /* Inferno user name */
+ char *user; /* Inferno user name */
int fpuostate;
/* from 9front */
@@ -453,31 +454,24 @@
struct Evalue
{
- union {
- char *name;
- char *var;
- };
- union {
- char *value;
- char *val;
- };
+ char *name;
+ char *value;
s32 len;
Qid qid;
- Evalue *next;
};
struct Egrp
{
Ref;
- QLock;
- union{
+ RWlock;
+ union{ /* array of Evalue's */
Evalue *entries;
Evalue *ent;
};
int nent;
int ment;
- ulong path; /* qid.path of next Evalue to be allocated */
- ulong vers; /* of Egrp */
+ u32 path; /* qid.path of next Evalue to be allocated */
+ u32 vers; /* of Egrp */
};
struct Signerkey
@@ -737,10 +731,10 @@
/* inferno specific fields */
s32 type;
- void* prog; /* Dummy Prog for interp release */
- void* iprog;
- Osenv* env;
- Osenv defenv;
+ void *prog; /* Dummy Prog for interp release */
+ void *iprog;
+ Osenv *env;
+ Osenv defenv;
s32 swipend; /* software interrupt pending for Prog TODO replace with notepending? */
Lock sysio; /* note handler lock */
@@ -747,7 +741,7 @@
/* inferno specific fields that are obsolete? */
int fpstate;
int killed; /* by swiproc */
- Proc* tlink;
+ Proc *tlink;
ulong movetime; /* next time process should switch processors */
int dbgstop; /* don't run this kproc */
};
--- a/os/port/proc.c
+++ b/os/port/proc.c
@@ -1011,12 +1011,15 @@
if(up->nerrlab >= NERR)
panic("error stack too deep");
kstrcpy(up->env->errstr, err, ERRMAX);
- /* proactively show issues */
- /* if(err[0] != '\0')
- print("up->nerrlab %d error %s raised by 0x%zx\n",
- up->nerrlab, err, getcallerpc(&err));
- showerrlabs();
- */
+ if(err[0] == '\0'){
+ up->env->errpc = 0;
+ }else{
+ up->env->errpc = getcallerpc(&err);
+ /* proactively show issues */
+ /* print("up->nerrlab %d error %s raised by 0x%zx\n",
+ up->nerrlab, err, getcallerpc(&err)); */
+ /* showerrlabs(); */
+ }
setlabel(&up->errlab[NERR-1]); /* to store the location where error() was raised(?) */
nexterror();
}