code: drawterm

Download patch

ref: 566f277947682ea7513fa7ff91320607d2ff63f0
parent: 11729e23cb62f2e262afd4580906b6aca4f7a113
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Jun 19 17: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)