ref: 566f277947682ea7513fa7ff91320607d2ff63f0
parent: 11729e23cb62f2e262afd4580906b6aca4f7a113
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Jun 19 19:18:15 EDT 2020
Add devenv to provide exit status for rcpu (thanks Fazlul) Original change applied, but with different handling of $rstatus using atexit() handler instead of modifying exportfs read loop. Also importing plan9 libc getenv().
--- a/cpu.c
+++ b/cpu.c
@@ -121,6 +121,14 @@
return aanclient(na, aanto);
}
+static void
+rcpuexit(void)
+{
+ char *s = getenv("rstatus");
+ if(s != nil)
+ exit(*s);
+}
+
void
rcpu(char *host, char *cmd)
{
@@ -133,6 +141,7 @@
" bind -q /mnt/term/dev/cons /dev/cons\n"
"}\n"
"</dev/cons >/dev/cons >[2=1] service=cpu %s\n"
+"echo -n $status >/mnt/term/env/rstatus >[2]/dev/null\n"
"echo -n hangup >/proc/$pid/notepg\n";
int fd;
@@ -162,6 +171,10 @@
if(fprint(fd, "%7ld\n%s", strlen(cmd), cmd) < 0)
sysfatal("sending script: %r");
free(cmd);
+
+ /* /env/rstatus is written by the remote script to communicate exit status */
+ remove("/env/rstatus");
+ atexit(rcpuexit);
/* Begin serving the namespace */
exportfs(fd);
--- a/gui-x11/x11.c
+++ b/gui-x11/x11.c
@@ -19,6 +19,8 @@
#define Display XDisplay
#define Cursor XCursor
+#undef getenv
+
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
--- a/include/user.h
+++ b/include/user.h
@@ -26,6 +26,7 @@
#undef sleep
#define sleep osmsleep
#define iounit sysiounit
+#define getenv sysgetenv
extern int bind(char*, char*, int);
extern int chdir(char*);
@@ -96,3 +97,4 @@
extern int iprint(char*, ...);
extern int atexit(void (*)(void));
extern void exits(char*);
+extern char* getenv(char*);
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -13,6 +13,7 @@
devcmd.$O\
devcons.$O\
devdraw.$O\
+ devenv.$O\
devfs-$(OS).$O\
devip.$O\
devip-$(OS).$O\
--- /dev/null
+++ b/kern/devenv.c
@@ -1,0 +1,426 @@
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+enum
+{
+ Maxenvsize = 16300,
+};
+
+static Egrp *envgrp(Chan *c);
+static int envwriteable(Chan *c);
+static void initunix();
+
+static Egrp unixegrp; /* unix environment group */
+
+static Evalue*
+envlookup(Egrp *eg, char *name, ulong qidpath)
+{
+ Evalue *e;
+ int i;
+
+ for(i=0; i<eg->nent; i++){
+ e = eg->ent[i];
+ if(e->qid.path == qidpath || (name && e->name[0]==name[0] && strcmp(e->name, name) == 0))
+ return e;
+ }
+ return nil;
+}
+
+static int
+envgen(Chan *c, char *name, Dirtab *_1, int _2, int s, Dir *dp)
+{
+ Egrp *eg;
+ Evalue *e;
+
+ if(s == DEVDOTDOT){
+ devdir(c, c->qid, "#e", 0, eve, DMDIR|0775, dp);
+ return 1;
+ }
+
+ eg = envgrp(c);
+ rlock(&eg->lk);
+ e = 0;
+ if(name)
+ e = envlookup(eg, name, -1);
+ else if(s < eg->nent)
+ e = eg->ent[s];
+
+ if(e == 0) {
+ runlock(&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, eve, 0666, dp);
+ runlock(&eg->lk);
+ return 1;
+}
+
+static Chan*
+envattach(char *spec)
+{
+ Chan *c;
+
+ if(spec && *spec) {
+ error(Ebadarg);
+ }
+ initunix();
+ c = devattach('e', spec);
+ c->aux = &unixegrp;
+ return c;
+}
+
+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 = envgrp(c)->vers;
+ return devstat(c, db, n, 0, 0, envgen);
+}
+
+static Chan*
+envopen(Chan *c, int omode)
+{
+ Egrp *eg;
+ Evalue *e;
+ int trunc;
+
+ eg = envgrp(c);
+ if(c->qid.type & QTDIR) {
+ if(omode != OREAD)
+ error(Eperm);
+ }
+ else {
+ trunc = omode & OTRUNC;
+ if(omode != OREAD && !envwriteable(c))
+ error(Eperm);
+ if(trunc)
+ wlock(&eg->lk);
+ else
+ rlock(&eg->lk);
+ e = envlookup(eg, nil, c->qid.path);
+ if(e == 0) {
+ if(trunc)
+ wunlock(&eg->lk);
+ else
+ runlock(&eg->lk);
+ error(Enonexist);
+ }
+ if(trunc && e->value) {
+ e->qid.vers++;
+ free(e->value);
+ e->value = 0;
+ e->len = 0;
+ }
+ if(trunc)
+ wunlock(&eg->lk);
+ else
+ runlock(&eg->lk);
+ }
+ c->mode = openmode(omode);
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+}
+
+static Chan*
+envcreate(Chan *c, char *name, int omode, ulong _)
+{
+ Egrp *eg;
+ Evalue *e;
+ Evalue **ent;
+
+ if(c->qid.type != QTDIR)
+ error(Eperm);
+ if(strlen(name) >= sizeof up->genbuf)
+ error("name too long"); /* protect envgen */
+
+ omode = openmode(omode);
+ eg = envgrp(c);
+
+ wlock(&eg->lk);
+ if(waserror()) {
+ wunlock(&eg->lk);
+ nexterror();
+ }
+
+ if(envlookup(eg, name, -1))
+ error(Eexist);
+
+ e = smalloc(sizeof(Evalue));
+ e->name = smalloc(strlen(name)+1);
+ strcpy(e->name, name);
+
+ if(eg->nent == eg->ment){
+ eg->ment += 32;
+ ent = smalloc(sizeof(eg->ent[0])*eg->ment);
+ if(eg->nent)
+ memmove(ent, eg->ent, sizeof(eg->ent[0])*eg->nent);
+ free(eg->ent);
+ eg->ent = ent;
+ }
+ e->qid.path = ++eg->path;
+ e->qid.vers = 0;
+ eg->vers++;
+ eg->ent[eg->nent++] = e;
+ c->qid = e->qid;
+
+ wunlock(&eg->lk);
+ poperror();
+
+ c->offset = 0;
+ c->mode = omode;
+ c->flag |= COPEN;
+ return c;
+}
+
+static void
+envremove(Chan *c)
+{
+ int i;
+ Egrp *eg;
+ Evalue *e;
+
+ if(c->qid.type & QTDIR)
+ error(Eperm);
+
+ eg = envgrp(c);
+ wlock(&eg->lk);
+ e = 0;
+ for(i=0; i<eg->nent; i++){
+ if(eg->ent[i]->qid.path == c->qid.path){
+ e = eg->ent[i];
+ eg->nent--;
+ eg->ent[i] = eg->ent[eg->nent];
+ eg->vers++;
+ break;
+ }
+ }
+ wunlock(&eg->lk);
+ if(e == 0)
+ error(Enonexist);
+ 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 = envgrp(c);
+ rlock(&eg->lk);
+ e = envlookup(eg, nil, c->qid.path);
+ if(e == 0) {
+ runlock(&eg->lk);
+ error(Enonexist);
+ }
+
+ if(offset > e->len) /* protects against overflow converting vlong to ulong */
+ n = 0;
+ else if(offset + n > e->len)
+ n = e->len - offset;
+ if(n <= 0)
+ n = 0;
+ else
+ memmove(a, e->value+offset, n);
+ runlock(&eg->lk);
+ return n;
+}
+
+static long
+envwrite(Chan *c, void *a, long n, vlong off)
+{
+ char *s;
+ ulong len;
+ Egrp *eg;
+ Evalue *e;
+ ulong offset = off;
+
+ if(n <= 0)
+ return 0;
+ if(offset > Maxenvsize || n > (Maxenvsize - offset))
+ error(Etoobig);
+
+ eg = envgrp(c);
+ wlock(&eg->lk);
+ e = envlookup(eg, nil, c->qid.path);
+ if(e == 0) {
+ wunlock(&eg->lk);
+ error(Enonexist);
+ }
+
+ len = offset+n;
+ if(len > e->len) {
+ s = smalloc(len);
+ if(e->value){
+ memmove(s, e->value, e->len);
+ free(e->value);
+ }
+ e->value = s;
+ e->len = len;
+ }
+ memmove(e->value+offset, a, n);
+ e->qid.vers++;
+ eg->vers++;
+ wunlock(&eg->lk);
+ return n;
+}
+
+Dev envdevtab = {
+ 'e',
+ "env",
+
+ devreset,
+ devinit,
+ devshutdown,
+ envattach,
+ envwalk,
+ envstat,
+ envopen,
+ envcreate,
+ envclose,
+ envread,
+ devbread,
+ envwrite,
+ devbwrite,
+ envremove,
+ devwstat,
+};
+
+extern char **environ;
+
+static void
+initunix()
+{
+ Egrp *eg = &unixegrp;
+ Evalue **ent, *e;
+ char *eq, **envp, *line;
+ int n;
+
+ wlock(&eg->lk);
+
+ if(eg->path > 0 || eg->ment > 0 || !environ){
+ // already initialized or nothing in environent
+ wunlock(&eg->lk);
+ return;
+ }
+
+ for(envp = environ; *envp != nil; envp++)
+ eg->ment++;
+ ent = smalloc(sizeof(eg->ent[0])*eg->ment);
+ eg->ent = ent;
+
+ for(envp = environ; *envp != nil; envp++){
+ line = *envp;
+ n = strlen(line);
+
+ eq = strchr(line, '=');
+ if(eq == nil)
+ eq = &line[n];
+ e = smalloc(sizeof(Evalue));
+ e->name = smalloc(eq-line+1);
+ strncpy(e->name, line, eq-line);
+
+ if(eq[0] != '\0')
+ eq++;
+ e->len = line+n-eq;
+ e->value = smalloc(e->len);
+ memmove(e->value, eq, e->len);
+
+ e->qid.path = ++eg->path;
+ e->qid.vers = 0;
+ eg->vers++;
+ eg->ent[eg->nent++] = e;
+ }
+
+ wunlock(&eg->lk);
+}
+
+void
+envcpy(Egrp *to, Egrp *from)
+{
+ int i;
+ Evalue *ne, *e;
+
+ rlock(&from->lk);
+ to->ment = (from->nent+31)&~31;
+ to->ent = smalloc(to->ment*sizeof(to->ent[0]));
+ for(i=0; i<from->nent; i++){
+ e = from->ent[i];
+ 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;
+ to->ent[i] = ne;
+ }
+ to->nent = from->nent;
+ runlock(&from->lk);
+}
+
+void
+closeegrp(Egrp *eg)
+{
+ int i;
+ Evalue *e;
+
+ if(decref(&eg->ref) == 0){
+ for(i=0; i<eg->nent; i++){
+ e = eg->ent[i];
+ free(e->name);
+ if(e->value)
+ free(e->value);
+ free(e);
+ }
+ free(eg->ent);
+ free(eg);
+ }
+}
+
+static Egrp*
+envgrp(Chan *c)
+{
+ if(c->aux == nil)
+ return &unixegrp;
+ return c->aux;
+}
+
+static int
+envwriteable(Chan *c)
+{
+ return iseve() || c->aux == nil;
+}
--- a/kern/devtab.c
+++ b/kern/devtab.c
@@ -18,6 +18,7 @@
extern Dev audiodevtab;
extern Dev kbddevtab;
extern Dev cmddevtab;
+extern Dev envdevtab;
Dev *devtab[] = {
&rootdevtab,
@@ -34,6 +35,7 @@
&audiodevtab,
&kbddevtab,
&cmddevtab,
+ &envdevtab,
0
};
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -33,6 +33,7 @@
fmtstr.$O\
fmtvprint.$O\
fprint.$O\
+ getenv.$O\
getfields.$O\
getpid.$O\
lock.$O\
--- /dev/null
+++ b/libc/getenv.c
@@ -1,0 +1,45 @@
+#include <u.h>
+#include <libc.h>
+
+char*
+getenv(char *name)
+{
+ enum { HUNK = 100, };
+ char *s, *p;
+ int f, r, n;
+
+ if(name[0]=='\0' || strcmp(name, ".")==0 || strcmp(name, "..")==0 || strchr(name, '/')!=nil
+ || strlen(name) >= HUNK-5){
+ werrstr("bad env name: %s", name);
+ return nil;
+ }
+ if((s = malloc(HUNK)) == nil)
+ return nil;
+ snprint(s, HUNK, "/env/%s", name);
+ n = 0;
+ r = -1;
+ if((f = open(s, OREAD)) >= 0){
+ while((r = read(f, s+n, HUNK)) > 0){
+ n += r;
+ r = -1;
+ if((p = realloc(s, n+HUNK)) == nil)
+ break;
+ s = p;
+ }
+ close(f);
+ }
+ if(r < 0 || (p = realloc(s, n+1)) == nil){
+ free(s);
+ return nil;
+ }
+ s = p;
+ setmalloctag(s, getcallerpc(&name));
+ while(n > 0 && s[n-1] == '\0')
+ n--;
+ s[n] = '\0';
+ while(--n >= 0){
+ if(s[n] == '\0')
+ s[n] = ' ';
+ }
+ return s;
+}
--- a/main.c
+++ b/main.c
@@ -47,6 +47,8 @@
if(bind("#c", "/dev", MBEFORE) < 0)
panic("bind #c: %r");
+ if(bind("#e", "/env", MREPL|MCREATE) < 0)
+ panic("bind #e: %r");
if(bind("#I", "/net", MBEFORE) < 0)
panic("bind #I: %r");
if(bind("#U", "/root", MREPL) < 0)