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