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