ref: 4ac3a0224ed9d54818f858fba69c8e94f38f2c12
dir: /9front/c17447a0c0bc8211015c87261abe57ed46ffe0ca.patch/
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