xref: /plan9/sys/src/cmd/sam/shell.c (revision f19e7b749ec99577072cd8e44030fe810f42c7ad)
1 #include "sam.h"
2 #include "parse.h"
3 
4 extern	jmp_buf	mainloop;
5 
6 char	errfile[64];
7 String	plan9cmd;	/* null terminated */
8 Buffer	plan9buf;
9 void	checkerrs(void);
10 
11 int
plan9(File * f,int type,String * s,int nest)12 plan9(File *f, int type, String *s, int nest)
13 {
14 	long l;
15 	int m;
16 	int pid, fd;
17 	int retcode;
18 	char *retmsg;
19 	int pipe1[2], pipe2[2];
20 
21 	if(s->s[0]==0 && plan9cmd.s[0]==0)
22 		error(Enocmd);
23 	else if(s->s[0])
24 		Strduplstr(&plan9cmd, s);
25 	if(downloaded){
26 		samerr(errfile);
27 		remove(errfile);
28 	}
29 	if(type!='!' && pipe(pipe1)==-1)
30 		error(Epipe);
31 	if(type=='|')
32 		snarf(f, addr.r.p1, addr.r.p2, &plan9buf, 1);
33 	if((pid=fork()) == 0){
34 		if(downloaded){	/* also put nasty fd's into errfile */
35 			fd = create(errfile, 1, 0666L);
36 			if(fd < 0)
37 				fd = create("/dev/null", 1, 0666L);
38 			dup(fd, 2);
39 			close(fd);
40 			/* 2 now points at err file */
41 			if(type == '>')
42 				dup(2, 1);
43 			else if(type=='!'){
44 				dup(2, 1);
45 				fd = open("/dev/null", 0);
46 				dup(fd, 0);
47 				close(fd);
48 			}
49 		}
50 		if(type != '!') {
51 			if(type=='<' || type=='|')
52 				dup(pipe1[1], 1);
53 			else if(type == '>')
54 				dup(pipe1[0], 0);
55 			close(pipe1[0]);
56 			close(pipe1[1]);
57 		}
58 		if(type == '|'){
59 			if(pipe(pipe2) == -1)
60 				exits("pipe");
61 			if((pid = fork())==0){
62 				/*
63 				 * It's ok if we get SIGPIPE here
64 				 */
65 				close(pipe2[0]);
66 				io = pipe2[1];
67 				if(retcode=!setjmp(mainloop)){	/* assignment = */
68 					char *c;
69 					for(l = 0; l<plan9buf.nc; l+=m){
70 						m = plan9buf.nc-l;
71 						if(m>BLOCKSIZE-1)
72 							m = BLOCKSIZE-1;
73 						bufread(&plan9buf, l, genbuf, m);
74 						genbuf[m] = 0;
75 						c = Strtoc(tmprstr(genbuf, m+1));
76 						Write(pipe2[1], c, strlen(c));
77 						free(c);
78 					}
79 				}
80 				exits(retcode? "error" : 0);
81 			}
82 			if(pid==-1){
83 				fprint(2, "Can't fork?!\n");
84 				exits("fork");
85 			}
86 			dup(pipe2[0], 0);
87 			close(pipe2[0]);
88 			close(pipe2[1]);
89 		}
90 		if(type=='<'){
91 			close(0);	/* so it won't read from terminal */
92 			open("/dev/null", 0);
93 		}
94 		execl(SHPATH, SH, "-c", Strtoc(&plan9cmd), nil);
95 		exits("exec");
96 	}
97 	if(pid == -1)
98 		error(Efork);
99 	if(type=='<' || type=='|'){
100 		int nulls;
101 		if(downloaded && addr.r.p1 != addr.r.p2)
102 			outTl(Hsnarflen, addr.r.p2-addr.r.p1);
103 		snarf(f, addr.r.p1, addr.r.p2, &snarfbuf, 0);
104 		logdelete(f, addr.r.p1, addr.r.p2);
105 		close(pipe1[1]);
106 		io = pipe1[0];
107 		f->tdot.p1 = -1;
108 		f->ndot.r.p2 = addr.r.p2+readio(f, &nulls, 0, FALSE);
109 		f->ndot.r.p1 = addr.r.p2;
110 		closeio((Posn)-1);
111 	}else if(type=='>'){
112 		close(pipe1[0]);
113 		io = pipe1[1];
114 		bpipeok = 1;
115 		writeio(f);
116 		bpipeok = 0;
117 		closeio((Posn)-1);
118 	}
119 	retmsg = waitfor(pid);
120 	if(type=='|' || type=='<')
121 		if(retmsg[0]!=0)
122 			warn_s(Wbadstatus, retmsg);
123 	if(downloaded)
124 		checkerrs();
125 	if(!nest)
126 		dprint("!\n");
127 	return retmsg[0] ? -1 : 0;
128 }
129 
130 void
checkerrs(void)131 checkerrs(void)
132 {
133 	char buf[256];
134 	int f, n, nl;
135 	char *p;
136 	long l;
137 
138 	if(statfile(errfile, 0, 0, 0, &l, 0) > 0 && l != 0){
139 		if((f=open((char *)errfile, 0)) != -1){
140 			if((n=read(f, buf, sizeof buf-1)) > 0){
141 				for(nl=0,p=buf; nl<3 && p<&buf[n]; p++)
142 					if(*p=='\n')
143 						nl++;
144 				*p = 0;
145 				dprint("%s", buf);
146 				if(p-buf < l-1)
147 					dprint("(sam: more in %s)\n", errfile);
148 			}
149 			close(f);
150 		}
151 	}else
152 		remove((char *)errfile);
153 }
154