1 |
|
|
/* $OpenBSD: region.c,v 1.37 2016/09/09 06:05:51 lum Exp $ */ |
2 |
|
|
|
3 |
|
|
/* This file is in the public domain. */ |
4 |
|
|
|
5 |
|
|
/* |
6 |
|
|
* Region based commands. |
7 |
|
|
* The routines in this file deal with the region, that magic space between |
8 |
|
|
* "." and mark. Some functions are commands. Some functions are just for |
9 |
|
|
* internal use. |
10 |
|
|
*/ |
11 |
|
|
|
12 |
|
|
#include <sys/queue.h> |
13 |
|
|
#include <sys/socket.h> |
14 |
|
|
#include <sys/types.h> |
15 |
|
|
#include <sys/wait.h> |
16 |
|
|
#include <errno.h> |
17 |
|
|
#include <fcntl.h> |
18 |
|
|
#include <poll.h> |
19 |
|
|
#include <signal.h> |
20 |
|
|
#include <stdio.h> |
21 |
|
|
#include <stdlib.h> |
22 |
|
|
#include <string.h> |
23 |
|
|
#include <unistd.h> |
24 |
|
|
|
25 |
|
|
#include "def.h" |
26 |
|
|
|
27 |
|
|
#define TIMEOUT 10000 |
28 |
|
|
|
29 |
|
|
static char leftover[BUFSIZ]; |
30 |
|
|
|
31 |
|
|
static int getregion(struct region *); |
32 |
|
|
static int iomux(int, char * const, int, struct buffer *); |
33 |
|
|
static int preadin(int, struct buffer *); |
34 |
|
|
static void pwriteout(int, char **, int *); |
35 |
|
|
static int setsize(struct region *, RSIZE); |
36 |
|
|
static int shellcmdoutput(char * const[], char * const, int); |
37 |
|
|
|
38 |
|
|
/* |
39 |
|
|
* Kill the region. Ask "getregion" to figure out the bounds of the region. |
40 |
|
|
* Move "." to the start, and kill the characters. Mark is cleared afterwards. |
41 |
|
|
*/ |
42 |
|
|
/* ARGSUSED */ |
43 |
|
|
int |
44 |
|
|
killregion(int f, int n) |
45 |
|
|
{ |
46 |
|
|
int s; |
47 |
|
|
struct region region; |
48 |
|
|
|
49 |
|
|
if ((s = getregion(®ion)) != TRUE) |
50 |
|
|
return (s); |
51 |
|
|
/* This is a kill-type command, so do magic kill buffer stuff. */ |
52 |
|
|
if ((lastflag & CFKILL) == 0) |
53 |
|
|
kdelete(); |
54 |
|
|
thisflag |= CFKILL; |
55 |
|
|
curwp->w_dotp = region.r_linep; |
56 |
|
|
curwp->w_doto = region.r_offset; |
57 |
|
|
curwp->w_dotline = region.r_lineno; |
58 |
|
|
s = ldelete(region.r_size, KFORW | KREG); |
59 |
|
|
clearmark(FFARG, 0); |
60 |
|
|
|
61 |
|
|
return (s); |
62 |
|
|
} |
63 |
|
|
|
64 |
|
|
/* |
65 |
|
|
* Copy all of the characters in the region to the kill buffer, |
66 |
|
|
* clearing the mark afterwards. |
67 |
|
|
* This is a bit like a kill region followed by a yank. |
68 |
|
|
*/ |
69 |
|
|
/* ARGSUSED */ |
70 |
|
|
int |
71 |
|
|
copyregion(int f, int n) |
72 |
|
|
{ |
73 |
|
|
struct line *linep; |
74 |
|
|
struct region region; |
75 |
|
|
int loffs; |
76 |
|
|
int s; |
77 |
|
|
|
78 |
|
|
if ((s = getregion(®ion)) != TRUE) |
79 |
|
|
return (s); |
80 |
|
|
|
81 |
|
|
/* kill type command */ |
82 |
|
|
if ((lastflag & CFKILL) == 0) |
83 |
|
|
kdelete(); |
84 |
|
|
thisflag |= CFKILL; |
85 |
|
|
|
86 |
|
|
/* current line */ |
87 |
|
|
linep = region.r_linep; |
88 |
|
|
|
89 |
|
|
/* current offset */ |
90 |
|
|
loffs = region.r_offset; |
91 |
|
|
|
92 |
|
|
while (region.r_size--) { |
93 |
|
|
if (loffs == llength(linep)) { /* End of line. */ |
94 |
|
|
if ((s = kinsert('\n', KFORW)) != TRUE) |
95 |
|
|
return (s); |
96 |
|
|
linep = lforw(linep); |
97 |
|
|
loffs = 0; |
98 |
|
|
} else { /* Middle of line. */ |
99 |
|
|
if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE) |
100 |
|
|
return (s); |
101 |
|
|
++loffs; |
102 |
|
|
} |
103 |
|
|
} |
104 |
|
|
clearmark(FFARG, 0); |
105 |
|
|
|
106 |
|
|
return (TRUE); |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
/* |
110 |
|
|
* Lower case region. Zap all of the upper case characters in the region to |
111 |
|
|
* lower case. Use the region code to set the limits. Scan the buffer, doing |
112 |
|
|
* the changes. Call "lchange" to ensure that redisplay is done in all |
113 |
|
|
* buffers. |
114 |
|
|
*/ |
115 |
|
|
/* ARGSUSED */ |
116 |
|
|
int |
117 |
|
|
lowerregion(int f, int n) |
118 |
|
|
{ |
119 |
|
|
struct line *linep; |
120 |
|
|
struct region region; |
121 |
|
|
int loffs, c, s; |
122 |
|
|
|
123 |
|
|
if ((s = checkdirty(curbp)) != TRUE) |
124 |
|
|
return (s); |
125 |
|
|
if (curbp->b_flag & BFREADONLY) { |
126 |
|
|
dobeep(); |
127 |
|
|
ewprintf("Buffer is read-only"); |
128 |
|
|
return (FALSE); |
129 |
|
|
} |
130 |
|
|
|
131 |
|
|
if ((s = getregion(®ion)) != TRUE) |
132 |
|
|
return (s); |
133 |
|
|
|
134 |
|
|
undo_add_change(region.r_linep, region.r_offset, region.r_size); |
135 |
|
|
|
136 |
|
|
lchange(WFFULL); |
137 |
|
|
linep = region.r_linep; |
138 |
|
|
loffs = region.r_offset; |
139 |
|
|
while (region.r_size--) { |
140 |
|
|
if (loffs == llength(linep)) { |
141 |
|
|
linep = lforw(linep); |
142 |
|
|
loffs = 0; |
143 |
|
|
} else { |
144 |
|
|
c = lgetc(linep, loffs); |
145 |
|
|
if (ISUPPER(c) != FALSE) |
146 |
|
|
lputc(linep, loffs, TOLOWER(c)); |
147 |
|
|
++loffs; |
148 |
|
|
} |
149 |
|
|
} |
150 |
|
|
return (TRUE); |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
/* |
154 |
|
|
* Upper case region. Zap all of the lower case characters in the region to |
155 |
|
|
* upper case. Use the region code to set the limits. Scan the buffer, |
156 |
|
|
* doing the changes. Call "lchange" to ensure that redisplay is done in all |
157 |
|
|
* buffers. |
158 |
|
|
*/ |
159 |
|
|
/* ARGSUSED */ |
160 |
|
|
int |
161 |
|
|
upperregion(int f, int n) |
162 |
|
|
{ |
163 |
|
|
struct line *linep; |
164 |
|
|
struct region region; |
165 |
|
|
int loffs, c, s; |
166 |
|
|
|
167 |
|
|
if ((s = checkdirty(curbp)) != TRUE) |
168 |
|
|
return (s); |
169 |
|
|
if (curbp->b_flag & BFREADONLY) { |
170 |
|
|
dobeep(); |
171 |
|
|
ewprintf("Buffer is read-only"); |
172 |
|
|
return (FALSE); |
173 |
|
|
} |
174 |
|
|
if ((s = getregion(®ion)) != TRUE) |
175 |
|
|
return (s); |
176 |
|
|
|
177 |
|
|
undo_add_change(region.r_linep, region.r_offset, region.r_size); |
178 |
|
|
|
179 |
|
|
lchange(WFFULL); |
180 |
|
|
linep = region.r_linep; |
181 |
|
|
loffs = region.r_offset; |
182 |
|
|
while (region.r_size--) { |
183 |
|
|
if (loffs == llength(linep)) { |
184 |
|
|
linep = lforw(linep); |
185 |
|
|
loffs = 0; |
186 |
|
|
} else { |
187 |
|
|
c = lgetc(linep, loffs); |
188 |
|
|
if (ISLOWER(c) != FALSE) |
189 |
|
|
lputc(linep, loffs, TOUPPER(c)); |
190 |
|
|
++loffs; |
191 |
|
|
} |
192 |
|
|
} |
193 |
|
|
return (TRUE); |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
/* |
197 |
|
|
* This routine figures out the bound of the region in the current window, |
198 |
|
|
* and stores the results into the fields of the REGION structure. Dot and |
199 |
|
|
* mark are usually close together, but I don't know the order, so I scan |
200 |
|
|
* outward from dot, in both directions, looking for mark. The size is kept |
201 |
|
|
* in a long. At the end, after the size is figured out, it is assigned to |
202 |
|
|
* the size field of the region structure. If this assignment loses any bits, |
203 |
|
|
* then we print an error. This is "type independent" overflow checking. All |
204 |
|
|
* of the callers of this routine should be ready to get an ABORT status, |
205 |
|
|
* because I might add a "if regions is big, ask before clobbering" flag. |
206 |
|
|
*/ |
207 |
|
|
static int |
208 |
|
|
getregion(struct region *rp) |
209 |
|
|
{ |
210 |
|
|
struct line *flp, *blp; |
211 |
|
|
long fsize, bsize; |
212 |
|
|
|
213 |
|
|
if (curwp->w_markp == NULL) { |
214 |
|
|
dobeep(); |
215 |
|
|
ewprintf("No mark set in this window"); |
216 |
|
|
return (FALSE); |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
/* "r_size" always ok */ |
220 |
|
|
if (curwp->w_dotp == curwp->w_markp) { |
221 |
|
|
rp->r_linep = curwp->w_dotp; |
222 |
|
|
rp->r_lineno = curwp->w_dotline; |
223 |
|
|
if (curwp->w_doto < curwp->w_marko) { |
224 |
|
|
rp->r_offset = curwp->w_doto; |
225 |
|
|
rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto); |
226 |
|
|
} else { |
227 |
|
|
rp->r_offset = curwp->w_marko; |
228 |
|
|
rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko); |
229 |
|
|
} |
230 |
|
|
return (TRUE); |
231 |
|
|
} |
232 |
|
|
/* get region size */ |
233 |
|
|
flp = blp = curwp->w_dotp; |
234 |
|
|
bsize = curwp->w_doto; |
235 |
|
|
fsize = llength(flp) - curwp->w_doto + 1; |
236 |
|
|
while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) { |
237 |
|
|
if (lforw(flp) != curbp->b_headp) { |
238 |
|
|
flp = lforw(flp); |
239 |
|
|
if (flp == curwp->w_markp) { |
240 |
|
|
rp->r_linep = curwp->w_dotp; |
241 |
|
|
rp->r_offset = curwp->w_doto; |
242 |
|
|
rp->r_lineno = curwp->w_dotline; |
243 |
|
|
return (setsize(rp, |
244 |
|
|
(RSIZE)(fsize + curwp->w_marko))); |
245 |
|
|
} |
246 |
|
|
fsize += llength(flp) + 1; |
247 |
|
|
} |
248 |
|
|
if (lback(blp) != curbp->b_headp) { |
249 |
|
|
blp = lback(blp); |
250 |
|
|
bsize += llength(blp) + 1; |
251 |
|
|
if (blp == curwp->w_markp) { |
252 |
|
|
rp->r_linep = blp; |
253 |
|
|
rp->r_offset = curwp->w_marko; |
254 |
|
|
rp->r_lineno = curwp->w_markline; |
255 |
|
|
return (setsize(rp, |
256 |
|
|
(RSIZE)(bsize - curwp->w_marko))); |
257 |
|
|
} |
258 |
|
|
} |
259 |
|
|
} |
260 |
|
|
dobeep(); |
261 |
|
|
ewprintf("Bug: lost mark"); |
262 |
|
|
return (FALSE); |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
/* |
266 |
|
|
* Set size, and check for overflow. |
267 |
|
|
*/ |
268 |
|
|
static int |
269 |
|
|
setsize(struct region *rp, RSIZE size) |
270 |
|
|
{ |
271 |
|
|
rp->r_size = size; |
272 |
|
|
if (rp->r_size != size) { |
273 |
|
|
dobeep(); |
274 |
|
|
ewprintf("Region is too large"); |
275 |
|
|
return (FALSE); |
276 |
|
|
} |
277 |
|
|
return (TRUE); |
278 |
|
|
} |
279 |
|
|
|
280 |
|
|
#define PREFIXLENGTH 40 |
281 |
|
|
static char prefix_string[PREFIXLENGTH] = {'>', '\0'}; |
282 |
|
|
|
283 |
|
|
/* |
284 |
|
|
* Prefix the region with whatever is in prefix_string. Leaves dot at the |
285 |
|
|
* beginning of the line after the end of the region. If an argument is |
286 |
|
|
* given, prompts for the line prefix string. |
287 |
|
|
*/ |
288 |
|
|
/* ARGSUSED */ |
289 |
|
|
int |
290 |
|
|
prefixregion(int f, int n) |
291 |
|
|
{ |
292 |
|
|
struct line *first, *last; |
293 |
|
|
struct region region; |
294 |
|
|
char *prefix = prefix_string; |
295 |
|
|
int nline; |
296 |
|
|
int s; |
297 |
|
|
|
298 |
|
|
if ((s = checkdirty(curbp)) != TRUE) |
299 |
|
|
return (s); |
300 |
|
|
if (curbp->b_flag & BFREADONLY) { |
301 |
|
|
dobeep(); |
302 |
|
|
ewprintf("Buffer is read-only"); |
303 |
|
|
return (FALSE); |
304 |
|
|
} |
305 |
|
|
if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE)) |
306 |
|
|
return (s); |
307 |
|
|
|
308 |
|
|
/* get # of lines to affect */ |
309 |
|
|
if ((s = getregion(®ion)) != TRUE) |
310 |
|
|
return (s); |
311 |
|
|
first = region.r_linep; |
312 |
|
|
last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp; |
313 |
|
|
for (nline = 1; first != last; nline++) |
314 |
|
|
first = lforw(first); |
315 |
|
|
|
316 |
|
|
/* move to beginning of region */ |
317 |
|
|
curwp->w_dotp = region.r_linep; |
318 |
|
|
curwp->w_doto = region.r_offset; |
319 |
|
|
curwp->w_dotline = region.r_lineno; |
320 |
|
|
|
321 |
|
|
/* for each line, go to beginning and insert the prefix string */ |
322 |
|
|
while (nline--) { |
323 |
|
|
(void)gotobol(FFRAND, 1); |
324 |
|
|
for (prefix = prefix_string; *prefix; prefix++) |
325 |
|
|
(void)linsert(1, *prefix); |
326 |
|
|
(void)forwline(FFRAND, 1); |
327 |
|
|
} |
328 |
|
|
(void)gotobol(FFRAND, 1); |
329 |
|
|
return (TRUE); |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
/* |
333 |
|
|
* Set line prefix string. Used by prefixregion. |
334 |
|
|
*/ |
335 |
|
|
/* ARGSUSED */ |
336 |
|
|
int |
337 |
|
|
setprefix(int f, int n) |
338 |
|
|
{ |
339 |
|
|
char buf[PREFIXLENGTH], *rep; |
340 |
|
|
int retval; |
341 |
|
|
|
342 |
|
|
if (prefix_string[0] == '\0') |
343 |
|
|
rep = eread("Prefix string: ", buf, sizeof(buf), |
344 |
|
|
EFNEW | EFCR); |
345 |
|
|
else |
346 |
|
|
rep = eread("Prefix string (default %s): ", buf, sizeof(buf), |
347 |
|
|
EFNUL | EFNEW | EFCR, prefix_string); |
348 |
|
|
if (rep == NULL) |
349 |
|
|
return (ABORT); |
350 |
|
|
if (rep[0] != '\0') { |
351 |
|
|
(void)strlcpy(prefix_string, rep, sizeof(prefix_string)); |
352 |
|
|
retval = TRUE; |
353 |
|
|
} else if (rep[0] == '\0' && prefix_string[0] != '\0') { |
354 |
|
|
/* CR -- use old one */ |
355 |
|
|
retval = TRUE; |
356 |
|
|
} else |
357 |
|
|
retval = FALSE; |
358 |
|
|
return (retval); |
359 |
|
|
} |
360 |
|
|
|
361 |
|
|
int |
362 |
|
|
region_get_data(struct region *reg, char *buf, int len) |
363 |
|
|
{ |
364 |
|
|
int i, off; |
365 |
|
|
struct line *lp; |
366 |
|
|
|
367 |
|
|
off = reg->r_offset; |
368 |
|
|
lp = reg->r_linep; |
369 |
|
|
for (i = 0; i < len; i++) { |
370 |
|
|
if (off == llength(lp)) { |
371 |
|
|
lp = lforw(lp); |
372 |
|
|
if (lp == curbp->b_headp) |
373 |
|
|
break; |
374 |
|
|
off = 0; |
375 |
|
|
buf[i] = '\n'; |
376 |
|
|
} else { |
377 |
|
|
buf[i] = lgetc(lp, off); |
378 |
|
|
off++; |
379 |
|
|
} |
380 |
|
|
} |
381 |
|
|
buf[i] = '\0'; |
382 |
|
|
return (i); |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
void |
386 |
|
|
region_put_data(const char *buf, int len) |
387 |
|
|
{ |
388 |
|
|
int i; |
389 |
|
|
|
390 |
|
|
for (i = 0; buf[i] != '\0' && i < len; i++) { |
391 |
|
|
if (buf[i] == '\n') |
392 |
|
|
lnewline(); |
393 |
|
|
else |
394 |
|
|
linsert(1, buf[i]); |
395 |
|
|
} |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
/* |
399 |
|
|
* Mark whole buffer by first traversing to end-of-buffer |
400 |
|
|
* and then to beginning-of-buffer. Mark, dot are implicitly |
401 |
|
|
* set to eob, bob respectively during traversal. |
402 |
|
|
*/ |
403 |
|
|
int |
404 |
|
|
markbuffer(int f, int n) |
405 |
|
|
{ |
406 |
|
|
if (gotoeob(f,n) == FALSE) |
407 |
|
|
return (FALSE); |
408 |
|
|
if (gotobob(f,n) == FALSE) |
409 |
|
|
return (FALSE); |
410 |
|
|
return (TRUE); |
411 |
|
|
} |
412 |
|
|
|
413 |
|
|
/* |
414 |
|
|
* Pipe text from current region to external command. |
415 |
|
|
*/ |
416 |
|
|
/*ARGSUSED */ |
417 |
|
|
int |
418 |
|
|
piperegion(int f, int n) |
419 |
|
|
{ |
420 |
|
|
struct region region; |
421 |
|
|
int len; |
422 |
|
|
char *cmd, cmdbuf[NFILEN], *text; |
423 |
|
|
char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL}; |
424 |
|
|
|
425 |
|
|
/* C-u M-| is not supported yet */ |
426 |
|
|
if (n > 1) |
427 |
|
|
return (ABORT); |
428 |
|
|
|
429 |
|
|
if (curwp->w_markp == NULL) { |
430 |
|
|
dobeep(); |
431 |
|
|
ewprintf("The mark is not set now, so there is no region"); |
432 |
|
|
return (FALSE); |
433 |
|
|
} |
434 |
|
|
|
435 |
|
|
if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf), |
436 |
|
|
EFNEW | EFCR)) == NULL || (cmd[0] == '\0')) |
437 |
|
|
return (ABORT); |
438 |
|
|
|
439 |
|
|
argv[2] = cmd; |
440 |
|
|
|
441 |
|
|
if (getregion(®ion) != TRUE) |
442 |
|
|
return (FALSE); |
443 |
|
|
|
444 |
|
|
len = region.r_size; |
445 |
|
|
|
446 |
|
|
if ((text = malloc(len + 1)) == NULL) { |
447 |
|
|
dobeep(); |
448 |
|
|
ewprintf("Cannot allocate memory."); |
449 |
|
|
return (FALSE); |
450 |
|
|
} |
451 |
|
|
|
452 |
|
|
region_get_data(®ion, text, len); |
453 |
|
|
|
454 |
|
|
return shellcmdoutput(argv, text, len); |
455 |
|
|
} |
456 |
|
|
|
457 |
|
|
/* |
458 |
|
|
* Get command from mini-buffer and execute externally. |
459 |
|
|
*/ |
460 |
|
|
/*ARGSUSED */ |
461 |
|
|
int |
462 |
|
|
shellcommand(int f, int n) |
463 |
|
|
{ |
464 |
|
|
|
465 |
|
|
char *cmd, cmdbuf[NFILEN]; |
466 |
|
|
char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL}; |
467 |
|
|
|
468 |
|
|
if (n > 1) |
469 |
|
|
return (ABORT); |
470 |
|
|
|
471 |
|
|
if ((cmd = eread("Shell command: ", cmdbuf, sizeof(cmdbuf), |
472 |
|
|
EFNEW | EFCR)) == NULL || (cmd[0] == '\0')) |
473 |
|
|
return (ABORT); |
474 |
|
|
|
475 |
|
|
argv[2] = cmd; |
476 |
|
|
|
477 |
|
|
return shellcmdoutput(argv, NULL, 0); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
|
481 |
|
|
int |
482 |
|
|
shellcmdoutput(char* const argv[], char* const text, int len) |
483 |
|
|
{ |
484 |
|
|
|
485 |
|
|
struct buffer *bp; |
486 |
|
|
char *shellp; |
487 |
|
|
int ret; |
488 |
|
|
|
489 |
|
|
bp = bfind("*Shell Command Output*", TRUE); |
490 |
|
|
bp->b_flag |= BFREADONLY; |
491 |
|
|
if (bclear(bp) != TRUE) { |
492 |
|
|
free(text); |
493 |
|
|
return (FALSE); |
494 |
|
|
} |
495 |
|
|
|
496 |
|
|
shellp = getenv("SHELL"); |
497 |
|
|
|
498 |
|
|
ret = pipeio(shellp, argv, text, len, bp); |
499 |
|
|
|
500 |
|
|
if (ret == TRUE) { |
501 |
|
|
eerase(); |
502 |
|
|
if (lforw(bp->b_headp) == bp->b_headp) |
503 |
|
|
addline(bp, "(Shell command succeeded with no output)"); |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
free(text); |
507 |
|
|
return (ret); |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
/* |
511 |
|
|
* Create a socketpair, fork and execv path with argv. |
512 |
|
|
* STDIN, STDOUT and STDERR of child process are redirected to socket. |
513 |
|
|
* Parent writes len chars from text to socket. |
514 |
|
|
*/ |
515 |
|
|
int |
516 |
|
|
pipeio(const char* const path, char* const argv[], char* const text, int len, |
517 |
|
|
struct buffer *outbp) |
518 |
|
|
{ |
519 |
|
|
int s[2], ret; |
520 |
|
|
char *err; |
521 |
|
|
pid_t pid; |
522 |
|
|
|
523 |
|
|
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) { |
524 |
|
|
dobeep(); |
525 |
|
|
ewprintf("socketpair error"); |
526 |
|
|
return (FALSE); |
527 |
|
|
} |
528 |
|
|
|
529 |
|
|
switch((pid = fork())) { |
530 |
|
|
case -1: |
531 |
|
|
dobeep(); |
532 |
|
|
ewprintf("Can't fork"); |
533 |
|
|
return (FALSE); |
534 |
|
|
case 0: |
535 |
|
|
/* Child process */ |
536 |
|
|
close(s[0]); |
537 |
|
|
if (dup2(s[1], STDIN_FILENO) == -1) |
538 |
|
|
_exit(1); |
539 |
|
|
if (dup2(s[1], STDOUT_FILENO) == -1) |
540 |
|
|
_exit(1); |
541 |
|
|
if (dup2(s[1], STDERR_FILENO) == -1) |
542 |
|
|
_exit(1); |
543 |
|
|
if (path == NULL) |
544 |
|
|
_exit(1); |
545 |
|
|
|
546 |
|
|
execv(path, argv); |
547 |
|
|
err = strerror(errno); |
548 |
|
|
write(s[1], err, strlen(err)); |
549 |
|
|
_exit(1); |
550 |
|
|
default: |
551 |
|
|
/* Parent process */ |
552 |
|
|
close(s[1]); |
553 |
|
|
ret = iomux(s[0], text, len, outbp); |
554 |
|
|
waitpid(pid, NULL, 0); /* Collect child to prevent zombies */ |
555 |
|
|
|
556 |
|
|
return (ret); |
557 |
|
|
} |
558 |
|
|
return (FALSE); |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
/* |
562 |
|
|
* Multiplex read, write on socket fd passed. Put output in outbp |
563 |
|
|
* Poll on the fd for both read and write readiness. |
564 |
|
|
*/ |
565 |
|
|
int |
566 |
|
|
iomux(int fd, char* const text, int len, struct buffer *outbp) |
567 |
|
|
{ |
568 |
|
|
struct pollfd pfd[1]; |
569 |
|
|
int nfds; |
570 |
|
|
char *textcopy; |
571 |
|
|
|
572 |
|
|
textcopy = text; |
573 |
|
|
fcntl(fd, F_SETFL, O_NONBLOCK); |
574 |
|
|
pfd[0].fd = fd; |
575 |
|
|
|
576 |
|
|
/* There is nothing to write if len is zero |
577 |
|
|
* but the cmd's output should be read so shutdown |
578 |
|
|
* the socket for writing only and don't wait for POLLOUT |
579 |
|
|
*/ |
580 |
|
|
if (len == 0) { |
581 |
|
|
shutdown(fd, SHUT_WR); |
582 |
|
|
pfd[0].events = POLLIN; |
583 |
|
|
} else |
584 |
|
|
pfd[0].events = POLLIN | POLLOUT; |
585 |
|
|
|
586 |
|
|
while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 || |
587 |
|
|
(pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) { |
588 |
|
|
if (pfd[0].revents & POLLOUT && len > 0) |
589 |
|
|
pwriteout(fd, &textcopy, &len); |
590 |
|
|
else if (pfd[0].revents & POLLIN) |
591 |
|
|
if (preadin(fd, outbp) == FALSE) |
592 |
|
|
break; |
593 |
|
|
if (len == 0 && pfd[0].events & POLLOUT) |
594 |
|
|
pfd[0].events = POLLIN; |
595 |
|
|
} |
596 |
|
|
close(fd); |
597 |
|
|
|
598 |
|
|
/* In case if last line doesn't have a '\n' add the leftover |
599 |
|
|
* characters to buffer. |
600 |
|
|
*/ |
601 |
|
|
if (leftover[0] != '\0') { |
602 |
|
|
addline(outbp, leftover); |
603 |
|
|
leftover[0] = '\0'; |
604 |
|
|
} |
605 |
|
|
if (nfds == 0) { |
606 |
|
|
dobeep(); |
607 |
|
|
ewprintf("poll timed out"); |
608 |
|
|
return (FALSE); |
609 |
|
|
} else if (nfds == -1) { |
610 |
|
|
dobeep(); |
611 |
|
|
ewprintf("poll error"); |
612 |
|
|
return (FALSE); |
613 |
|
|
} |
614 |
|
|
return (popbuftop(outbp, WNONE)); |
615 |
|
|
} |
616 |
|
|
|
617 |
|
|
/* |
618 |
|
|
* Write some text from region to fd. Once done shutdown the |
619 |
|
|
* write end. |
620 |
|
|
*/ |
621 |
|
|
void |
622 |
|
|
pwriteout(int fd, char **text, int *len) |
623 |
|
|
{ |
624 |
|
|
int w; |
625 |
|
|
|
626 |
|
|
if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) { |
627 |
|
|
switch(errno) { |
628 |
|
|
case EPIPE: |
629 |
|
|
*len = -1; |
630 |
|
|
break; |
631 |
|
|
case EAGAIN: |
632 |
|
|
return; |
633 |
|
|
} |
634 |
|
|
} else |
635 |
|
|
*len -= w; |
636 |
|
|
|
637 |
|
|
*text += w; |
638 |
|
|
if (*len <= 0) |
639 |
|
|
shutdown(fd, SHUT_WR); |
640 |
|
|
} |
641 |
|
|
|
642 |
|
|
/* |
643 |
|
|
* Read some data from socket fd, break on '\n' and add |
644 |
|
|
* to buffer. If couldn't break on newline hold leftover |
645 |
|
|
* characters and append in next iteration. |
646 |
|
|
*/ |
647 |
|
|
int |
648 |
|
|
preadin(int fd, struct buffer *bp) |
649 |
|
|
{ |
650 |
|
|
int len; |
651 |
|
|
char buf[BUFSIZ], *p, *q; |
652 |
|
|
|
653 |
|
|
if ((len = read(fd, buf, BUFSIZ - 1)) <= 0) |
654 |
|
|
return (FALSE); |
655 |
|
|
|
656 |
|
|
buf[len] = '\0'; |
657 |
|
|
p = q = buf; |
658 |
|
|
if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) { |
659 |
|
|
*q++ = '\0'; |
660 |
|
|
if (strlcat(leftover, p, sizeof(leftover)) >= |
661 |
|
|
sizeof(leftover)) { |
662 |
|
|
dobeep(); |
663 |
|
|
ewprintf("line too long"); |
664 |
|
|
return (FALSE); |
665 |
|
|
} |
666 |
|
|
addline(bp, leftover); |
667 |
|
|
leftover[0] = '\0'; |
668 |
|
|
p = q; |
669 |
|
|
} |
670 |
|
|
while ((q = strchr(p, '\n')) != NULL) { |
671 |
|
|
*q++ = '\0'; |
672 |
|
|
addline(bp, p); |
673 |
|
|
p = q; |
674 |
|
|
} |
675 |
|
|
if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) { |
676 |
|
|
dobeep(); |
677 |
|
|
ewprintf("line too long"); |
678 |
|
|
return (FALSE); |
679 |
|
|
} |
680 |
|
|
return (TRUE); |
681 |
|
|
} |