File: | src/usr.bin/vi/build/../ex/ex_script.c |
Warning: | line 197, column 2 Value stored to 'len' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ex_script.c,v 1.27 2017/04/18 01:45:35 deraadt Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1992, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * Copyright (c) 1992, 1993, 1994, 1995, 1996 |
7 | * Keith Bostic. All rights reserved. |
8 | * |
9 | * This code is derived from software contributed to Berkeley by |
10 | * Brian Hirt. |
11 | * |
12 | * See the LICENSE file for redistribution information. |
13 | */ |
14 | |
15 | #include "config.h" |
16 | |
17 | #include <sys/types.h> |
18 | #include <sys/ioctl.h> |
19 | #include <sys/queue.h> |
20 | #include <sys/stat.h> |
21 | #include <sys/time.h> |
22 | #include <sys/wait.h> |
23 | |
24 | #include <bitstring.h> |
25 | #include <errno(*__errno()).h> |
26 | #include <fcntl.h> |
27 | #include <stdio.h> /* XXX: OSF/1 bug: include before <grp.h> */ |
28 | #include <grp.h> |
29 | #include <limits.h> |
30 | #include <poll.h> |
31 | #include <stdlib.h> |
32 | #include <string.h> |
33 | #include <termios.h> |
34 | #include <unistd.h> |
35 | #include <util.h> |
36 | |
37 | #include "../common/common.h" |
38 | #include "../vi/vi.h" |
39 | #include "script.h" |
40 | #include "pathnames.h" |
41 | |
42 | static void sscr_check(SCR *); |
43 | static int sscr_getprompt(SCR *); |
44 | static int sscr_init(SCR *); |
45 | static int sscr_insert(SCR *); |
46 | static int sscr_matchprompt(SCR *, char *, size_t, size_t *); |
47 | static int sscr_setprompt(SCR *, char *, size_t); |
48 | |
49 | /* |
50 | * ex_script -- : sc[ript][!] [file] |
51 | * Switch to script mode. |
52 | * |
53 | * PUBLIC: int ex_script(SCR *, EXCMD *); |
54 | */ |
55 | int |
56 | ex_script(SCR *sp, EXCMD *cmdp) |
57 | { |
58 | /* Vi only command. */ |
59 | if (!F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) { |
60 | msgq(sp, M_ERR, |
61 | "The script command is only available in vi mode"); |
62 | return (1); |
63 | } |
64 | |
65 | /* Switch to the new file. */ |
66 | if (cmdp->argc != 0 && ex_edit(sp, cmdp)) |
67 | return (1); |
68 | |
69 | /* Create the shell, figure out the prompt. */ |
70 | if (sscr_init(sp)) |
71 | return (1); |
72 | |
73 | return (0); |
74 | } |
75 | |
76 | /* |
77 | * sscr_init -- |
78 | * Create a pty setup for a shell. |
79 | */ |
80 | static int |
81 | sscr_init(SCR *sp) |
82 | { |
83 | SCRIPT *sc; |
84 | char *sh, *sh_path; |
85 | |
86 | /* We're going to need a shell. */ |
87 | if (opts_empty(sp, O_SHELL, 0)) |
88 | return (1); |
89 | |
90 | MALLOC_RET(sp, sc, sizeof(SCRIPT)){ if (((sc) = malloc(sizeof(SCRIPT))) == ((void *)0)) { msgq( (sp), M_SYSERR, ((void *)0)); return (1); } }; |
91 | sp->script = sc; |
92 | sc->sh_prompt = NULL((void *)0); |
93 | sc->sh_prompt_len = 0; |
94 | |
95 | /* |
96 | * There are two different processes running through this code. |
97 | * They are the shell and the parent. |
98 | */ |
99 | sc->sh_master = sc->sh_slave = -1; |
100 | |
101 | if (tcgetattr(STDIN_FILENO0, &sc->sh_term) == -1) { |
102 | msgq(sp, M_SYSERR, "tcgetattr"); |
103 | goto err; |
104 | } |
105 | |
106 | /* |
107 | * Turn off output postprocessing and echo. |
108 | */ |
109 | sc->sh_term.c_oflag &= ~OPOST0x00000001; |
110 | sc->sh_term.c_cflag &= ~(ECHO0x00000008|ECHOE0x00000002|ECHONL0x00000010|ECHOK0x00000004); |
111 | |
112 | if (ioctl(STDIN_FILENO0, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff ) << 16) | ((('t')) << 8) | ((104))), &sc->sh_win) == -1) { |
113 | msgq(sp, M_SYSERR, "tcgetattr"); |
114 | goto err; |
115 | } |
116 | |
117 | if (openpty(&sc->sh_master, |
118 | &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) { |
119 | msgq(sp, M_SYSERR, "pty"); |
120 | goto err; |
121 | } |
122 | |
123 | /* |
124 | * __TK__ huh? |
125 | * Don't use vfork() here, because the signal semantics differ from |
126 | * implementation to implementation. |
127 | */ |
128 | switch (sc->sh_pid = fork()) { |
129 | case -1: /* Error. */ |
130 | msgq(sp, M_SYSERR, "fork"); |
131 | err: if (sc->sh_master != -1) |
132 | (void)close(sc->sh_master); |
133 | if (sc->sh_slave != -1) |
134 | (void)close(sc->sh_slave); |
135 | return (1); |
136 | case 0: /* Utility. */ |
137 | /* |
138 | * XXX |
139 | * So that shells that do command line editing turn it off. |
140 | */ |
141 | if (setenv("TERM", "emacs", 1) == -1 || |
142 | setenv("TERMCAP", "emacs:", 1) == -1 || |
143 | setenv("EMACS", "t", 1) == -1) |
144 | _exit(126); |
145 | |
146 | (void)setsid(); |
147 | /* |
148 | * 4.4BSD allocates a controlling terminal using the TIOCSCTTY |
149 | * ioctl, not by opening a terminal device file. POSIX 1003.1 |
150 | * doesn't define a portable way to do this. |
151 | */ |
152 | (void)ioctl(sc->sh_slave, TIOCSCTTY((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) | ((('t')) << 8) | ((97))), 0); |
153 | (void)close(sc->sh_master); |
154 | (void)dup2(sc->sh_slave, STDIN_FILENO0); |
155 | (void)dup2(sc->sh_slave, STDOUT_FILENO1); |
156 | (void)dup2(sc->sh_slave, STDERR_FILENO2); |
157 | (void)close(sc->sh_slave); |
158 | |
159 | /* Assumes that all shells have -i. */ |
160 | sh_path = O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str); |
161 | if ((sh = strrchr(sh_path, '/')) == NULL((void *)0)) |
162 | sh = sh_path; |
163 | else |
164 | ++sh; |
165 | execl(sh_path, sh, "-i", (char *)NULL((void *)0)); |
166 | msgq_str(sp, M_SYSERR, sh_path, "execl: %s"); |
167 | _exit(127); |
168 | default: /* Parent. */ |
169 | break; |
170 | } |
171 | |
172 | if (sscr_getprompt(sp)) |
173 | return (1); |
174 | |
175 | F_SET(sp, SC_SCRIPT)(((sp)->flags) |= ((0x01000000))); |
176 | F_SET(sp->gp, G_SCRWIN)(((sp->gp)->flags) |= ((0x0020))); |
177 | return (0); |
178 | } |
179 | |
180 | /* |
181 | * sscr_getprompt -- |
182 | * Eat lines printed by the shell until a line with no trailing |
183 | * carriage return comes; set the prompt from that line. |
184 | */ |
185 | static int |
186 | sscr_getprompt(SCR *sp) |
187 | { |
188 | CHAR_T *endp, *p, *t, buf[1024]; |
189 | SCRIPT *sc; |
190 | struct pollfd pfd[1]; |
191 | recno_t lline; |
192 | size_t llen, len; |
193 | u_int value; |
194 | int nr; |
195 | |
196 | endp = buf; |
197 | len = sizeof(buf); |
Value stored to 'len' is never read | |
198 | |
199 | /* Wait up to a second for characters to read. */ |
200 | sc = sp->script; |
201 | pfd[0].fd = sc->sh_master; |
202 | pfd[0].events = POLLIN0x0001; |
203 | switch (poll(pfd, 1, 5 * 1000)) { |
204 | case -1: /* Error or interrupt. */ |
205 | msgq(sp, M_SYSERR, "poll"); |
206 | goto prompterr; |
207 | case 0: /* Timeout */ |
208 | msgq(sp, M_ERR, "Error: timed out"); |
209 | goto prompterr; |
210 | default: /* Characters to read. */ |
211 | break; |
212 | } |
213 | |
214 | /* Read the characters. */ |
215 | more: len = sizeof(buf) - (endp - buf); |
216 | switch (nr = read(sc->sh_master, endp, len)) { |
217 | case 0: /* EOF. */ |
218 | msgq(sp, M_ERR, "Error: shell: EOF"); |
219 | goto prompterr; |
220 | case -1: /* Error or interrupt. */ |
221 | msgq(sp, M_SYSERR, "shell"); |
222 | goto prompterr; |
223 | default: |
224 | endp += nr; |
225 | break; |
226 | } |
227 | |
228 | /* If any complete lines, push them into the file. */ |
229 | for (p = t = buf; p < endp; ++p) { |
230 | value = KEY_VAL(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->special_key[ (unsigned char)(*p)] : (unsigned char)(*p) > (sp)->gp-> max_special ? 0 : v_key_val((sp),(*p))); |
231 | if (value == K_CR || value == K_NL) { |
232 | if (db_last(sp, &lline) || |
233 | db_append(sp, 0, lline, t, p - t)) |
234 | goto prompterr; |
235 | t = p + 1; |
236 | } |
237 | } |
238 | if (p > buf) { |
239 | memmove(buf, t, endp - t); |
240 | endp = buf + (endp - t); |
241 | } |
242 | if (endp == buf) |
243 | goto more; |
244 | |
245 | /* Wait up 1/10 of a second to make sure that we got it all. */ |
246 | switch (poll(pfd, 1, 100)) { |
247 | case -1: /* Error or interrupt. */ |
248 | msgq(sp, M_SYSERR, "poll"); |
249 | goto prompterr; |
250 | case 0: /* Timeout */ |
251 | break; |
252 | default: /* Characters to read. */ |
253 | goto more; |
254 | } |
255 | |
256 | /* Timed out, so theoretically we have a prompt. */ |
257 | llen = endp - buf; |
258 | endp = buf; |
259 | |
260 | /* Append the line into the file. */ |
261 | if (db_last(sp, &lline) || db_append(sp, 0, lline, buf, llen)) { |
262 | prompterr: sscr_end(sp); |
263 | return (1); |
264 | } |
265 | |
266 | return (sscr_setprompt(sp, buf, llen)); |
267 | } |
268 | |
269 | /* |
270 | * sscr_exec -- |
271 | * Take a line and hand it off to the shell. |
272 | * |
273 | * PUBLIC: int sscr_exec(SCR *, recno_t); |
274 | */ |
275 | int |
276 | sscr_exec(SCR *sp, recno_t lno) |
277 | { |
278 | SCRIPT *sc; |
279 | recno_t last_lno; |
280 | size_t blen, len, last_len, tlen; |
281 | int isempty, matchprompt, nw, rval; |
282 | char *bp, *p; |
283 | |
284 | /* If there's a prompt on the last line, append the command. */ |
285 | if (db_last(sp, &last_lno)) |
286 | return (1); |
287 | if (db_get(sp, last_lno, DBG_FATAL0x001, &p, &last_len)) |
288 | return (1); |
289 | if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) { |
290 | matchprompt = 1; |
291 | GET_SPACE_RET(sp, bp, blen, last_len + 128){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100 )))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if ( ((last_len + 128)) > ((blen))) { if ((L__bincp = binc(((sp )), ((bp)), &((blen)), ((last_len + 128)))) == ((void *)0 )) return (1); ((bp)) = L__bincp; } }; } else { { void *L__bincp ; if (((last_len + 128)) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen) , ((last_len + 128)))) == ((void *)0)) return (1); (L__gp-> tmp_bp) = L__bincp; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp ->tmp_blen; (((L__gp)->flags) |= ((0x0100))); } }; |
292 | memmove(bp, p, last_len); |
293 | } else |
294 | matchprompt = 0; |
295 | |
296 | /* Get something to execute. */ |
297 | if (db_eget(sp, lno, &p, &len, &isempty)) { |
298 | if (isempty) |
299 | goto empty; |
300 | goto err1; |
301 | } |
302 | |
303 | /* Empty lines aren't interesting. */ |
304 | if (len == 0) |
305 | goto empty; |
306 | |
307 | /* Delete any prompt. */ |
308 | if (sscr_matchprompt(sp, p, len, &tlen)) { |
309 | if (tlen == len) { |
310 | empty: msgq(sp, M_BERR, "No command to execute"); |
311 | goto err1; |
312 | } |
313 | p += (len - tlen); |
314 | len = tlen; |
315 | } |
316 | |
317 | /* Push the line to the shell. */ |
318 | sc = sp->script; |
319 | if ((nw = write(sc->sh_master, p, len)) != len) |
320 | goto err2; |
321 | rval = 0; |
322 | if (write(sc->sh_master, "\n", 1) != 1) { |
323 | err2: if (nw == 0) |
324 | errno(*__errno()) = EIO5; |
325 | msgq(sp, M_SYSERR, "shell"); |
326 | goto err1; |
327 | } |
328 | |
329 | if (matchprompt) { |
330 | ADD_SPACE_RET(sp, bp, blen, last_len + len){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp ) { (((L__gp)->flags) &= ~((0x0100))); { void *L__bincp ; if (((last_len + len)) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen) , ((last_len + len)))) == ((void *)0)) return (1); (L__gp-> tmp_bp) = L__bincp; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp ->tmp_blen; (((L__gp)->flags) |= ((0x0100))); } else { void *L__bincp; if (((last_len + len)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp)), &((blen)), ((last_len + len)))) == ((void *)0)) return (1); ((bp)) = L__bincp; } }; }; |
331 | memmove(bp + last_len, p, len); |
332 | if (db_set(sp, last_lno, bp, last_len + len)) |
333 | err1: rval = 1; |
334 | } |
335 | if (matchprompt) |
336 | FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp ) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }; |
337 | return (rval); |
338 | } |
339 | |
340 | /* |
341 | * sscr_check_input - |
342 | * Check for input from command input or scripting windows. |
343 | * |
344 | * PUBLIC: int sscr_check_input(SCR *sp); |
345 | */ |
346 | int |
347 | sscr_check_input(SCR *sp) |
348 | { |
349 | GS *gp; |
350 | SCR *tsp; |
351 | struct pollfd *pfd; |
352 | int nfds, rval; |
353 | |
354 | gp = sp->gp; |
355 | rval = 0; |
356 | |
357 | /* Allocate space for pfd. */ |
358 | nfds = 1; |
359 | TAILQ_FOREACH(tsp, &gp->dq, q)for((tsp) = ((&gp->dq)->tqh_first); (tsp) != ((void *)0); (tsp) = ((tsp)->q.tqe_next)) |
360 | if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) |
361 | nfds++; |
362 | pfd = calloc(nfds, sizeof(struct pollfd)); |
363 | if (pfd == NULL((void *)0)) { |
364 | msgq(sp, M_SYSERR, "malloc"); |
365 | return (1); |
366 | } |
367 | |
368 | /* Setup events bitmasks. */ |
369 | pfd[0].fd = STDIN_FILENO0; |
370 | pfd[0].events = POLLIN0x0001; |
371 | nfds = 1; |
372 | TAILQ_FOREACH(tsp, &gp->dq, q)for((tsp) = ((&gp->dq)->tqh_first); (tsp) != ((void *)0); (tsp) = ((tsp)->q.tqe_next)) |
373 | if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) { |
374 | pfd[nfds].fd = sp->script->sh_master; |
375 | pfd[nfds].events = POLLIN0x0001; |
376 | nfds++; |
377 | } |
378 | |
379 | loop: |
380 | /* Check for input. */ |
381 | switch (poll(pfd, nfds, INFTIM(-1))) { |
382 | case -1: |
383 | msgq(sp, M_SYSERR, "poll"); |
384 | rval = 1; |
385 | /* FALLTHROUGH */ |
386 | case 0: |
387 | goto done; |
388 | default: |
389 | break; |
390 | } |
391 | |
392 | /* Only insert from the scripting windows if no command input */ |
393 | if (!(pfd[0].revents & POLLIN0x0001)) { |
394 | nfds = 1; |
395 | TAILQ_FOREACH(tsp, &gp->dq, q)for((tsp) = ((&gp->dq)->tqh_first); (tsp) != ((void *)0); (tsp) = ((tsp)->q.tqe_next)) |
396 | if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) { |
397 | if ((pfd[nfds].revents & POLLHUP0x0010) && sscr_end(sp)) |
398 | goto done; |
399 | if ((pfd[nfds].revents & POLLIN0x0001) && sscr_insert(sp)) |
400 | goto done; |
401 | nfds++; |
402 | } |
403 | goto loop; |
404 | } |
405 | done: |
406 | free(pfd); |
407 | return (rval); |
408 | } |
409 | |
410 | /* |
411 | * sscr_input -- |
412 | * Read any waiting shell input. |
413 | * |
414 | * PUBLIC: int sscr_input(SCR *); |
415 | */ |
416 | int |
417 | sscr_input(SCR *sp) |
418 | { |
419 | GS *gp; |
420 | struct pollfd *pfd; |
421 | int nfds, rval; |
422 | |
423 | gp = sp->gp; |
424 | rval = 0; |
425 | |
426 | /* Allocate space for pfd. */ |
427 | nfds = 0; |
428 | TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) |
429 | if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) |
430 | nfds++; |
431 | if (nfds == 0) |
432 | return (0); |
433 | pfd = calloc(nfds, sizeof(struct pollfd)); |
434 | if (pfd == NULL((void *)0)) { |
435 | msgq(sp, M_SYSERR, "malloc"); |
436 | return (1); |
437 | } |
438 | |
439 | /* Setup events bitmasks. */ |
440 | nfds = 0; |
441 | TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) |
442 | if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) { |
443 | pfd[nfds].fd = sp->script->sh_master; |
444 | pfd[nfds].events = POLLIN0x0001; |
445 | nfds++; |
446 | } |
447 | |
448 | loop: |
449 | /* Check for input. */ |
450 | switch (poll(pfd, nfds, 0)) { |
451 | case -1: |
452 | msgq(sp, M_SYSERR, "poll"); |
453 | rval = 1; |
454 | /* FALLTHROUGH */ |
455 | case 0: |
456 | goto done; |
457 | default: |
458 | break; |
459 | } |
460 | |
461 | /* Read the input. */ |
462 | nfds = 0; |
463 | TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) |
464 | if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) { |
465 | if ((pfd[nfds].revents & POLLHUP0x0010) && sscr_end(sp)) |
466 | goto done; |
467 | if ((pfd[nfds].revents & POLLIN0x0001) && sscr_insert(sp)) |
468 | goto done; |
469 | nfds++; |
470 | } |
471 | goto loop; |
472 | done: |
473 | free(pfd); |
474 | return (rval); |
475 | } |
476 | |
477 | /* |
478 | * sscr_insert -- |
479 | * Take a line from the shell and insert it into the file. |
480 | */ |
481 | static int |
482 | sscr_insert(SCR *sp) |
483 | { |
484 | CHAR_T *endp, *p, *t; |
485 | SCRIPT *sc; |
486 | struct pollfd pfd[1]; |
487 | recno_t lno; |
488 | size_t blen, len, tlen; |
489 | u_int value; |
490 | int nr, rval; |
491 | char *bp; |
492 | |
493 | /* Find out where the end of the file is. */ |
494 | if (db_last(sp, &lno)) |
495 | return (1); |
496 | |
497 | #define MINREAD1024 1024 |
498 | GET_SPACE_RET(sp, bp, blen, MINREAD){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100 )))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if ( ((1024)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp)) , &((blen)), ((1024)))) == ((void *)0)) return (1); ((bp) ) = L__bincp; } }; } else { { void *L__bincp; if (((1024)) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (L__gp-> tmp_bp), &(L__gp->tmp_blen), ((1024)))) == ((void *)0) ) return (1); (L__gp->tmp_bp) = L__bincp; } }; (bp) = L__gp ->tmp_bp; (blen) = L__gp->tmp_blen; (((L__gp)->flags ) |= ((0x0100))); } }; |
499 | endp = bp; |
500 | |
501 | /* Read the characters. */ |
502 | rval = 1; |
503 | sc = sp->script; |
504 | more: switch (nr = read(sc->sh_master, endp, MINREAD1024)) { |
505 | case 0: /* EOF; shell just exited. */ |
506 | sscr_end(sp); |
507 | rval = 0; |
508 | goto ret; |
509 | case -1: /* Error or interrupt. */ |
510 | msgq(sp, M_SYSERR, "shell"); |
511 | goto ret; |
512 | default: |
513 | endp += nr; |
514 | break; |
515 | } |
516 | |
517 | /* Append the lines into the file. */ |
518 | for (p = t = bp; p < endp; ++p) { |
519 | value = KEY_VAL(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->special_key[ (unsigned char)(*p)] : (unsigned char)(*p) > (sp)->gp-> max_special ? 0 : v_key_val((sp),(*p))); |
520 | if (value == K_CR || value == K_NL) { |
521 | len = p - t; |
522 | if (db_append(sp, 1, lno++, t, len)) |
523 | goto ret; |
524 | t = p + 1; |
525 | } |
526 | } |
527 | if (p > t) { |
528 | len = p - t; |
529 | /* |
530 | * If the last thing from the shell isn't another prompt, wait |
531 | * up to 1/10 of a second for more stuff to show up, so that |
532 | * we don't break the output into two separate lines. Don't |
533 | * want to hang indefinitely because some program is hanging, |
534 | * confused the shell, or whatever. |
535 | */ |
536 | if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) { |
537 | pfd[0].fd = sc->sh_master; |
538 | pfd[0].events = POLLIN0x0001; |
539 | if (poll(pfd, 1, 100) > 0) { |
540 | memmove(bp, t, len); |
541 | endp = bp + len; |
542 | goto more; |
543 | } |
544 | } |
545 | if (sscr_setprompt(sp, t, len)) |
546 | return (1); |
547 | if (db_append(sp, 1, lno++, t, len)) |
548 | goto ret; |
549 | } |
550 | |
551 | /* The cursor moves to EOF. */ |
552 | sp->lno = lno; |
553 | sp->cno = len ? len - 1 : 0; |
554 | rval = vs_refresh(sp, 1); |
555 | |
556 | ret: FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp ) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }; |
557 | return (rval); |
558 | } |
559 | |
560 | /* |
561 | * sscr_setprompt -- |
562 | * |
563 | * Set the prompt to the last line we got from the shell. |
564 | * |
565 | */ |
566 | static int |
567 | sscr_setprompt(SCR *sp, char *buf, size_t len) |
568 | { |
569 | SCRIPT *sc; |
570 | |
571 | sc = sp->script; |
572 | free(sc->sh_prompt); |
573 | MALLOC(sp, sc->sh_prompt, len + 1){ if (((sc->sh_prompt) = malloc(len + 1)) == ((void *)0)) msgq ((sp), M_SYSERR, ((void *)0)); }; |
574 | if (sc->sh_prompt == NULL((void *)0)) { |
575 | sscr_end(sp); |
576 | return (1); |
577 | } |
578 | memmove(sc->sh_prompt, buf, len); |
579 | sc->sh_prompt_len = len; |
580 | sc->sh_prompt[len] = '\0'; |
581 | return (0); |
582 | } |
583 | |
584 | /* |
585 | * sscr_matchprompt -- |
586 | * Check to see if a line matches the prompt. Nul's indicate |
587 | * parts that can change, in both content and size. |
588 | */ |
589 | static int |
590 | sscr_matchprompt(SCR *sp, char *lp, size_t line_len, size_t *lenp) |
591 | { |
592 | SCRIPT *sc; |
593 | size_t prompt_len; |
594 | char *pp; |
595 | |
596 | sc = sp->script; |
597 | if (line_len < (prompt_len = sc->sh_prompt_len)) |
598 | return (0); |
599 | |
600 | for (pp = sc->sh_prompt; |
601 | prompt_len && line_len; --prompt_len, --line_len) { |
602 | if (*pp == '\0') { |
603 | for (; prompt_len && *pp == '\0'; --prompt_len, ++pp); |
604 | if (!prompt_len) |
605 | return (0); |
606 | for (; line_len && *lp != *pp; --line_len, ++lp); |
607 | if (!line_len) |
608 | return (0); |
609 | } |
610 | if (*pp++ != *lp++) |
611 | break; |
612 | } |
613 | |
614 | if (prompt_len) |
615 | return (0); |
616 | if (lenp != NULL((void *)0)) |
617 | *lenp = line_len; |
618 | return (1); |
619 | } |
620 | |
621 | /* |
622 | * sscr_end -- |
623 | * End the pipe to a shell. |
624 | * |
625 | * PUBLIC: int sscr_end(SCR *); |
626 | */ |
627 | int |
628 | sscr_end(SCR *sp) |
629 | { |
630 | SCRIPT *sc; |
631 | |
632 | if ((sc = sp->script) == NULL((void *)0)) |
633 | return (0); |
634 | |
635 | /* Turn off the script flags. */ |
636 | F_CLR(sp, SC_SCRIPT)(((sp)->flags) &= ~((0x01000000))); |
637 | sscr_check(sp); |
638 | |
639 | /* Close down the parent's file descriptors. */ |
640 | if (sc->sh_master != -1) |
641 | (void)close(sc->sh_master); |
642 | if (sc->sh_slave != -1) |
643 | (void)close(sc->sh_slave); |
644 | |
645 | /* This should have killed the child. */ |
646 | (void)proc_wait(sp, sc->sh_pid, "script-shell", 0, 0); |
647 | |
648 | /* Free memory. */ |
649 | free(sc->sh_prompt); |
650 | free(sc); |
651 | sp->script = NULL((void *)0); |
652 | |
653 | return (0); |
654 | } |
655 | |
656 | /* |
657 | * sscr_check -- |
658 | * Set/clear the global scripting bit. |
659 | */ |
660 | static void |
661 | sscr_check(SCR *sp) |
662 | { |
663 | GS *gp; |
664 | |
665 | gp = sp->gp; |
666 | TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) |
667 | if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) { |
668 | F_SET(gp, G_SCRWIN)(((gp)->flags) |= ((0x0020))); |
669 | return; |
670 | } |
671 | F_CLR(gp, G_SCRWIN)(((gp)->flags) &= ~((0x0020))); |
672 | } |