summaryrefslogtreecommitdiff
path: root/sam/shell.c
diff options
context:
space:
mode:
authorPeter Mikkelsen <petermikkelsen10@gmail.com>2025-10-15 19:46:13 +0200
committerPeter Mikkelsen <petermikkelsen10@gmail.com>2025-10-15 19:46:13 +0200
commit184526f3bf90e2948b1d09b9da58d66814181f4d (patch)
treed39614e3e29fb89594d1dc52ef07805bc754c4c7 /sam/shell.c
parentfd41e6cc88f98121db5c64a0693e4169962f6c2c (diff)
Import sam and samterm sources
Diffstat (limited to 'sam/shell.c')
-rw-r--r--sam/shell.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/sam/shell.c b/sam/shell.c
new file mode 100644
index 0000000..db4db97
--- /dev/null
+++ b/sam/shell.c
@@ -0,0 +1,191 @@
+#include "sam.h"
+#include "parse.h"
+
+extern jmp_buf mainloop;
+
+char errfile[64];
+String plan9cmd; /* null terminated */
+Buffer plan9buf;
+void checkerrs(void);
+Buffer cmdbuf;
+int cmdbufpos;
+
+static void
+updateenv(File *f)
+{
+ static int fd = -1;
+ int n;
+ char buf[64], *p, *e;
+
+ if(f == nil){
+ putenv("%", "");
+ putenv("%dot", "");
+ return;
+ }
+
+ p = Strtoc(&f->name);
+ putenv("%", p);
+ free(p);
+
+ p = buf;
+ e = buf+sizeof(buf);
+ p = seprint(p, e, "%lud", 1+nlcount(f, 0, f->dot.r.p1));
+ p = seprint(p+1, e, "%lud", f->dot.r.p1);
+ p = seprint(p+1, e, "%lud", f->dot.r.p2);
+ n = p - buf;
+ if(fd == -1)
+ if((fd = create("/env/%dot", OWRITE, 0666)) < 0)
+ fprint(2, "updateenv create: %r\n");
+ if(write(fd, buf, n) != n)
+ fprint(2, "updateenv write: %r\n");
+}
+
+int
+plan9(File *f, int type, String *s, int nest)
+{
+ long l;
+ int m;
+ int pid, fd;
+ char *retmsg;
+ int pipe1[2], pipe2[2];
+
+ if(s->s[0]==0 && plan9cmd.s[0]==0)
+ error(Enocmd);
+ else if(s->s[0])
+ Strduplstr(&plan9cmd, s);
+ if(downloaded){
+ samerr(errfile);
+ remove(errfile);
+ }
+ if(type!='!' && pipe(pipe1)==-1)
+ error(Epipe);
+ if(type=='|' || type=='_')
+ snarf(f, addr.r.p1, addr.r.p2, &plan9buf, 1);
+ if((pid=fork()) == 0){
+ if(downloaded){ /* also put nasty fd's into errfile */
+ fd = create(errfile, 1, 0666L);
+ if(fd < 0)
+ fd = create("/dev/null", 1, 0666L);
+ dup(fd, 2);
+ close(fd);
+ /* 2 now points at err file */
+ if(type == '>')
+ dup(2, 1);
+ else if(type=='!'){
+ dup(2, 1);
+ fd = open("/dev/null", 0);
+ dup(fd, 0);
+ close(fd);
+ }
+ }
+ if(type != '!') {
+ if(type == '>')
+ dup(pipe1[0], 0);
+ else
+ dup(pipe1[1], 1);
+ close(pipe1[0]);
+ close(pipe1[1]);
+ }
+ if(type == '|' || type == '_'){
+ if(pipe(pipe2) == -1)
+ exits("pipe");
+ if((pid = fork())==0){
+ /*
+ * It's ok if we get SIGPIPE here
+ */
+ close(pipe2[0]);
+ io = pipe2[1];
+ if(setjmp(mainloop))
+ exits("error");
+
+ char *c;
+ for(l = 0; l<plan9buf.nc; l+=m){
+ m = plan9buf.nc-l;
+ if(m>BLOCKSIZE-1)
+ m = BLOCKSIZE-1;
+ bufread(&plan9buf, l, genbuf, m);
+ genbuf[m] = 0;
+ c = Strtoc(tmprstr(genbuf, m+1));
+ Write(pipe2[1], c, strlen(c));
+ free(c);
+ }
+ exits(nil);
+ }
+ if(pid==-1){
+ fprint(2, "Can't fork?!\n");
+ exits("fork");
+ }
+ dup(pipe2[0], 0);
+ close(pipe2[0]);
+ close(pipe2[1]);
+ }
+ if(type=='<' || type=='^'){
+ close(0); /* so it won't read from terminal */
+ open("/dev/null", 0);
+ }
+ updateenv(f);
+ execl(SHPATH, SH, "-c", Strtoc(&plan9cmd), nil);
+ exits("exec");
+ }
+ if(pid == -1)
+ error(Efork);
+ if(type=='<' || type=='|'){
+ int nulls;
+ if(downloaded && addr.r.p1 != addr.r.p2)
+ outTl(Hsnarflen, addr.r.p2-addr.r.p1);
+ snarf(f, addr.r.p1, addr.r.p2, &snarfbuf, 0);
+ logdelete(f, addr.r.p1, addr.r.p2);
+ close(pipe1[1]);
+ io = pipe1[0];
+ f->tdot.p1 = -1;
+ f->ndot.r.p2 = addr.r.p2+readio(f, &nulls, 0, FALSE);
+ f->ndot.r.p1 = addr.r.p2;
+ closeio((Posn)-1);
+ }else if(type=='>'){
+ close(pipe1[0]);
+ io = pipe1[1];
+ bpipeok = 1;
+ writeio(f);
+ bpipeok = 0;
+ closeio((Posn)-1);
+ }else if(type == '^' || type == '_'){
+ int nulls;
+ close(pipe1[1]);
+ bufload(&cmdbuf, cmdbufpos, pipe1[0], &nulls);
+ close(pipe1[0]);
+ }
+ retmsg = waitfor(pid);
+ if(type=='|' || type=='<' || type=='_' || type=='^')
+ if(retmsg[0]!=0)
+ warn_s(Wbadstatus, retmsg);
+ if(downloaded)
+ checkerrs();
+ if(!nest)
+ dprint("!\n");
+ return retmsg[0] ? -1 : 0;
+}
+
+void
+checkerrs(void)
+{
+ char buf[256];
+ int f, n, nl;
+ char *p;
+ long l;
+
+ if(statfile(errfile, 0, 0, 0, &l, 0) > 0 && l != 0){
+ if((f=open((char *)errfile, 0)) != -1){
+ if((n=read(f, buf, sizeof buf-1)) > 0){
+ for(nl=0,p=buf; nl<3 && p<&buf[n]; p++)
+ if(*p=='\n')
+ nl++;
+ *p = 0;
+ dprint("%s", buf);
+ if(p-buf < l-1)
+ dprint("(sam: more in %s)\n", errfile);
+ }
+ close(f);
+ }
+ }else
+ remove((char *)errfile);
+}