ref: 4ac3a0224ed9d54818f858fba69c8e94f38f2c12
dir: /9front/675bcd62992e59002c834ef445d515b346f4374d.patch/
From: Romano <me+git@fallglow.com> Date: Fri, 12 Jul 2024 19:24:48 +0000 Subject: [PATCH] rc: do not share certain special vars; fix $status bug for most cases Certain special vars (namely $*, $pid, $apid, and $status) are used internally and should not be set after a child returns. There has been a long-standing bug where checking the value of $status with ~ overwrites the value of $status. $status is now restored in most cases, other than running it as a standalone built-in command. Man page for rc is updated --- diff 7637f8f5fd6490d07ba64bcf404321028e698ed9 675bcd62992e59002c834ef445d515b346f4374d --- a/sys/src/cmd/rc/code.c +++ b/sys/src/cmd/rc/code.c @@ -275,6 +275,8 @@ codeswitch(t, eflag); break; case TWIDDLE: + if(c0 && c0->type=='$' && c0->child[0] && (c0->child[0]->type==WORD && strcmp(c0->child[0]->str, "status")==0)) + emitf(Xstashstatus); emitf(Xmark); noglobs(c1, 1); outcode(c1, eflag); --- a/sys/src/cmd/rc/exec.c +++ b/sys/src/cmd/rc/exec.c @@ -282,6 +282,16 @@ dotrap(); } } + +void +unstashstatus(void) +{ + var *oldstatus = vlook("status-"); + if(oldstatus->val && oldstatus->val->word){ + setstatus(oldstatus->val->word); + } +} + /* * Opcode routines * Arguments on stack (...) @@ -415,6 +425,7 @@ void Xifnot(void) { + unstashstatus(); if(ifnot) runq->pc++; else @@ -597,7 +608,9 @@ void Xtrue(void) { - if(truestatus()) runq->pc++; + int stat = truestatus(); + unstashstatus(); + if(stat) runq->pc++; else runq->pc = runq->code[runq->pc].i; } @@ -605,7 +618,9 @@ Xif(void) { ifnot = 1; - if(truestatus()) runq->pc++; + int stat = truestatus(); + unstashstatus(); + if(stat) runq->pc++; else runq->pc = runq->code[runq->pc].i; } @@ -661,6 +676,12 @@ } poplist(); poplist(); +} + +void +Xstashstatus(void) +{ + setvar("status-", Newword(estrdup(getstatus()), (word *)0)); } void --- a/sys/src/cmd/rc/exec.h +++ b/sys/src/cmd/rc/exec.h @@ -4,7 +4,7 @@ extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void); extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(void), Xdup(void); extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void); -extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void), Xhere(void), Xhereq(void); +extern void Xjump(void), Xmark(void), Xmatch(void), Xstashstatus(void), Xpipe(void), Xread(void), Xhere(void), Xhereq(void); extern void Xrdwr(void), Xsrcline(void); extern void Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void); --- a/sys/src/cmd/rc/pfnc.c +++ b/sys/src/cmd/rc/pfnc.c @@ -30,6 +30,7 @@ Xword, "Xword", Xwrite, "Xwrite", Xmatch, "Xmatch", + Xstashstatus, "Xstashstatus", Xcase, "Xcase", Xconc, "Xconc", Xassign, "Xassign", --- a/sys/src/cmd/rc/plan9.c +++ b/sys/src/cmd/rc/plan9.c @@ -144,7 +144,12 @@ if(n <= 0) break; for(i = 0; i<n; i++){ - if(ent[i].length<=0 || strncmp(ent[i].name, "fn#", 3)==0) + if(ent[i].length<=0 + || strncmp(ent[i].name, "fn#", 3)==0 + || strcmp(ent[i].name,"*")==0 + || strcmp(ent[i].name,"apid")==0 + || strcmp(ent[i].name,"pid")==0 + || strcmp(ent[i].name,"status")==0) continue; if((fd = Open(Env(ent[i].name, 0), 0))>=0){ io *f = openiofd(fd); --- a/sys/src/cmd/rc/test/updenvall.file +++ b/sys/src/cmd/rc/test/updenvall.file @@ -78,3 +78,40 @@ echo d } ' '/env/fn#a is echo d' + +echo testing special vars +*=b +echo -n a > /env/'*' +ok $"* 'b' '* not set' +echo -n $"pid >/tmp/pid.rc.test +rc -c '' +ok $"pid `{cat /tmp/pid.rc.test} 'pid not set' +rm /tmp/pid.rc.test +echo -n `{apid=foobar; echo $apid} >/dev/null +ok $"apid '' 'apid not set' +echo -n foo > /env/status +ok $"status '' 'status not set' +status=foo +~ $status foo +ok $"status '' 'naked ~ sets status to ''''' +status=`{echo foo} +ok $"status foo 'backtick sets status' +if(~ $status foo) + ok $"status foo '$status' +if(! ~ $status a) + ok $"status foo '$status for ! ~' +if(~ $status a) + ; +if not + ok $status foo '$status for if not' +if(~ $"status foo) + ok $"status foo '$"status' +if(echo a | grep -s a || ls) + ok $"status foo '||' +while(! ~ $status foo) + status=bar +ok $status foo 'after while not match' +while(~ $status foo) + status=bar; +ok $status bar 'after while match' +status='' --- a/sys/src/cmd/rc/test/updenvall.rc +++ b/sys/src/cmd/rc/test/updenvall.rc @@ -9,7 +9,7 @@ shift desc=$1 if(~ $"actual $"expected) echo ok $desc - if not echo 'not ok '^$"desc^', got '$"actual + if not echo 'NOT OK '^$"desc^', got '$"actual } # now let's run the test with our build