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