shithub: patches

ref: 4ac3a0224ed9d54818f858fba69c8e94f38f2c12
dir: /9front/c17447a0c0bc8211015c87261abe57ed46ffe0ca.patch/

View raw version
From: Romano <me+git@fallglow.com>
Date: Thu, 11 Jul 2024 05:32:38 +0000
Subject: [PATCH] rc: keep env vars and functions in sync


	From env(3):
	          The env device serves a one-level directory containing files
	          with arbitrary names and contents.  The intention is that
	          the file name is the name of an environment variable (see
	          rc(1)), and the content is the variable's current value.

	And from rc(1):
        Environment
          The environment is a list of strings made available to exe-
          cuting binaries by the env device (see env(3)).

	But currently, the environment variables and functions are not kept
	in sync with /env . For instance, '>/env/a echo -n b' will not
	update $a to be 'b'. Also, even when the namespaces are shared
	between processes, once the child process completes the namespaces
	are out of sync.

	This patch attempts to address that by updating the environment
	variables and functions after children processes exit when the
	children share the same namespace. Tests are added for the
	functionality as well.
---
diff 8a64e5171aad8bb0201a61e7df3046892ee6617f c17447a0c0bc8211015c87261abe57ed46ffe0ca
--- a/sys/src/cmd/rc/fns.h
+++ b/sys/src/cmd/rc/fns.h
@@ -27,6 +27,7 @@
 void	Setstatus(char*);
 void	Trapinit(void);
 void	Updenv(void);
+void	Updenvall(void);
 void	Vinit(void);
 int	Waitfor(int);
 long	Write(int, void*, long);
--- a/sys/src/cmd/rc/havefork.c
+++ b/sys/src/cmd/rc/havefork.c
@@ -64,6 +64,7 @@
 		setvar("apid", newword(npid, (word *)0));
 		break;
 	}
+	Updenvall();
 }
 
 void
@@ -99,6 +100,7 @@
 		p->pid = pid;
 		break;
 	}
+	Updenvall();
 }
 
 /*
@@ -128,7 +130,7 @@
 		Close(pfd[PRD]);
 		start(runq->code, runq->pc+1, runq->local, runq->redir);
 		pushredir(ROPEN, pfd[PWR], 1);
-		return;
+		break;
 	default:
 		addwaitpid(pid);
 		Close(pfd[PWR]);
@@ -149,8 +151,9 @@
 		Waitfor(pid);
 
 		runq->pc = runq->code[runq->pc].i;
-		return;
+		break;
 	}
+	Updenvall();
 }
 
 void
@@ -196,6 +199,7 @@
 		p->pc = p->code[pc+1].i;
 		break;
 	}
+	Updenvall();
 }
 
 void
@@ -219,6 +223,7 @@
 		runq->pc = runq->code[runq->pc].i;
 		break;
 	}
+	Updenvall();
 }
 
 int
--- a/sys/src/cmd/rc/plan9.c
+++ b/sys/src/cmd/rc/plan9.c
@@ -259,6 +259,17 @@
 }
 
 void
+Updenvall(void)
+{
+	Vinit();
+	char *cmds = estrdup("for(fn in /env/fn'#'*) { . -bq $fn }\n");
+	int line = runq->line;
+	execcmds(openiocore(cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
+	runq->lex->line = line;
+	runq->lex->qflag = 1;
+}
+
+void
 Exec(char **argv)
 {
 	exec(argv[0], argv+1);
--- a/sys/src/cmd/rc/simple.c
+++ b/sys/src/cmd/rc/simple.c
@@ -102,6 +102,7 @@
 			/* interrupts don't get us out */
 			while(Waitfor(pid) < 0)
 				;
+			Updenvall();
 		}
 	}
 }
--- /dev/null
+++ b/sys/src/cmd/rc/test/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TEST=\
+	updenvall\
+
+</sys/src/cmd/mktest
--- /dev/null
+++ b/sys/src/cmd/rc/test/updenvall.file
@@ -1,0 +1,80 @@
+>/env/var1 echo -n a
+ok `{whatis var1} 'var1=a
+' '$var1 is /env/var1'
+ok $var1 a '$var1 is a'
+ok `{cat /env/var1} a '/env/var1 is a'
+
+echo testing var with rc
+../$O.out -c 'var1=ab'
+ok `{whatis var1} 'var1=ab
+' 'var1 is ab'
+ok $var1 ab '$var1 is ab'
+ok `{cat /env/var1} ab '/env/var1 is ab'
+
+echo testing var with rc -c
+../$O.out -c 'var1=b'
+ok `{whatis var1} 'var1=b
+' 'var1 is b'
+ok $var1 b '$var1 is b'
+ok `{cat /env/var1} b '/env/var1 is b'
+
+echo testing var with subshell
+@{ var1=c }
+ok `{whatis var1} 'var1=c
+' 'var1 is c'
+ok $var1 c '$var1 is c'
+ok `{cat /env/var1} c '/env/var1 is c'
+
+echo testing var with backtick
+echo `{ var1=d } >/dev/null
+ok `{whatis var1} 'var1=d
+' 'var1 is d'
+ok $var1 d '$var1 is d'
+ok `{cat /env/var1} d '/env/var1 is d'
+
+a=()
+> '/env/fn#a' echo -n 'fn a {
+	echo a
+}
+'
+ok `{whatis a} 'fn a {
+	echo a
+}
+' 'fn a is echo a'
+ok `{cat '/env/fn#a'} 'fn a {
+	echo a
+}
+' '/env/fn#a is echo a'
+
+echo testing fn with rc -c
+../$O.out -c 'fn a { echo b }'
+ok `{whatis a} 'fn a {
+	echo b
+}
+' 'fn a is echo b'
+ok `{cat '/env/fn#a'} 'fn a {
+	echo b
+}
+' '/env/fn#a is echo b'
+
+echo testing fn with subshell
+@{ fn a { echo c } }
+ok `{whatis a} 'fn a {
+	echo c
+}
+' 'fn b is echo c'
+ok `{cat '/env/fn#a'} 'fn a {
+	echo c
+}
+' '/env/fn#a is echo c'
+
+echo testing fn with backtick
+echo `{fn a { echo d } } >/dev/null
+ok `{whatis a} 'fn a {
+	echo d
+}
+' 'fn a is echo d'
+ok `{cat '/env/fn#a'} 'fn a {
+	echo d
+}
+' '/env/fn#a is echo d'
--- /dev/null
+++ b/sys/src/cmd/rc/test/updenvall.rc
@@ -1,0 +1,16 @@
+#!/bin/rc
+# test that all environment variables and functions
+# are in sync.
+
+fn ok {
+	actual=$1
+	shift
+	expected=$1
+	shift
+	desc=$1
+	if(~ $"actual $"expected)	echo ok $desc
+	if not echo 'not ok '^$"desc^', got '$"actual
+}
+
+# now let's run the test with our build
+../$O.out <updenvall.file