File: | src/usr.bin/vi/build/../ex/ex_script.c |
Warning: | line 292, column 3 Null pointer passed as 1st argument to memory copy function |
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); | |||
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 | } |