run.c revision 1.2.2.2 1 1.2.2.2 tls /* $NetBSD: run.c,v 1.2.2.2 2014/08/10 07:00:24 tls Exp $ */
2 1.2.2.2 tls
3 1.2.2.2 tls /*
4 1.2.2.2 tls * Copyright 1997 Piermont Information Systems Inc.
5 1.2.2.2 tls * All rights reserved.
6 1.2.2.2 tls *
7 1.2.2.2 tls * Written by Philip A. Nelson for Piermont Information Systems Inc.
8 1.2.2.2 tls *
9 1.2.2.2 tls * Redistribution and use in source and binary forms, with or without
10 1.2.2.2 tls * modification, are permitted provided that the following conditions
11 1.2.2.2 tls * are met:
12 1.2.2.2 tls * 1. Redistributions of source code must retain the above copyright
13 1.2.2.2 tls * notice, this list of conditions and the following disclaimer.
14 1.2.2.2 tls * 2. Redistributions in binary form must reproduce the above copyright
15 1.2.2.2 tls * notice, this list of conditions and the following disclaimer in the
16 1.2.2.2 tls * documentation and/or other materials provided with the distribution.
17 1.2.2.2 tls * 3. The name of Piermont Information Systems Inc. may not be used to endorse
18 1.2.2.2 tls * or promote products derived from this software without specific prior
19 1.2.2.2 tls * written permission.
20 1.2.2.2 tls *
21 1.2.2.2 tls * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
22 1.2.2.2 tls * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 1.2.2.2 tls * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 1.2.2.2 tls * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
25 1.2.2.2 tls * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 1.2.2.2 tls * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 1.2.2.2 tls * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 1.2.2.2 tls * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.2.2.2 tls * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.2.2.2 tls * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 1.2.2.2 tls * THE POSSIBILITY OF SUCH DAMAGE.
32 1.2.2.2 tls *
33 1.2.2.2 tls */
34 1.2.2.2 tls
35 1.2.2.2 tls /* run.c -- routines to interact with other programs. */
36 1.2.2.2 tls
37 1.2.2.2 tls /* XXX write return codes ignored. XXX */
38 1.2.2.2 tls
39 1.2.2.2 tls #include <errno.h>
40 1.2.2.2 tls #include <stdio.h>
41 1.2.2.2 tls #include <stdarg.h>
42 1.2.2.2 tls #include <stdlib.h>
43 1.2.2.2 tls #include <unistd.h>
44 1.2.2.2 tls #include <fcntl.h>
45 1.2.2.2 tls #include <curses.h>
46 1.2.2.2 tls #include <termios.h>
47 1.2.2.2 tls #include <dirent.h>
48 1.2.2.2 tls #include <util.h>
49 1.2.2.2 tls #include <signal.h>
50 1.2.2.2 tls #include <err.h>
51 1.2.2.2 tls #include <sys/ioctl.h>
52 1.2.2.2 tls #include <sys/types.h>
53 1.2.2.2 tls #include <sys/wait.h>
54 1.2.2.2 tls #include <sys/stat.h>
55 1.2.2.2 tls #include "defs.h"
56 1.2.2.2 tls
57 1.2.2.2 tls #include "menu_defs.h"
58 1.2.2.2 tls #include "msg_defs.h"
59 1.2.2.2 tls
60 1.2.2.2 tls #define MAXBUF 256
61 1.2.2.2 tls
62 1.2.2.2 tls #ifdef DEBUG
63 1.2.2.2 tls #define Xsystem(y) printf ("%s\n", y), 0
64 1.2.2.2 tls #else
65 1.2.2.2 tls #define Xsystem(y) system(y)
66 1.2.2.2 tls #endif
67 1.2.2.2 tls
68 1.2.2.2 tls /*
69 1.2.2.2 tls * local prototypes
70 1.2.2.2 tls */
71 1.2.2.2 tls int log_flip (menudesc *, void *);
72 1.2.2.2 tls static int script_flip (menudesc *, void *);
73 1.2.2.2 tls
74 1.2.2.2 tls #define BUFSIZE 4096
75 1.2.2.2 tls
76 1.2.2.2 tls menu_ent logmenu [2] = {
77 1.2.2.2 tls { NULL, OPT_NOMENU, 0, log_flip},
78 1.2.2.2 tls { NULL, OPT_NOMENU, 0, script_flip} };
79 1.2.2.2 tls
80 1.2.2.2 tls static void
81 1.2.2.2 tls log_menu_label(menudesc *m, int opt, void *arg)
82 1.2.2.2 tls {
83 1.2.2.2 tls wprintw(m->mw, "%s: %s",
84 1.2.2.2 tls msg_string(opt ? MSG_Scripting : MSG_Logging),
85 1.2.2.2 tls msg_string((opt ? script != NULL : logfp != NULL) ?
86 1.2.2.2 tls MSG_On : MSG_Off));
87 1.2.2.2 tls }
88 1.2.2.2 tls
89 1.2.2.2 tls void
90 1.2.2.2 tls do_logging(void)
91 1.2.2.2 tls {
92 1.2.2.2 tls int menu_no;
93 1.2.2.2 tls
94 1.2.2.2 tls menu_no = new_menu(MSG_Logging_functions, logmenu, 2, -1, 12,
95 1.2.2.2 tls 0, 20, MC_SCROLL, NULL, log_menu_label, NULL,
96 1.2.2.2 tls MSG_Pick_an_option, NULL);
97 1.2.2.2 tls
98 1.2.2.2 tls if (menu_no < 0) {
99 1.2.2.2 tls (void)fprintf(stderr, "Dynamic menu creation failed.\n");
100 1.2.2.2 tls if (logfp)
101 1.2.2.2 tls (void)fprintf(logfp, "Dynamic menu creation failed.\n");
102 1.2.2.2 tls exit(EXIT_FAILURE);
103 1.2.2.2 tls }
104 1.2.2.2 tls process_menu(menu_no, NULL);
105 1.2.2.2 tls free_menu(menu_no);
106 1.2.2.2 tls }
107 1.2.2.2 tls
108 1.2.2.2 tls int
109 1.2.2.2 tls /*ARGSUSED*/
110 1.2.2.2 tls log_flip(menudesc *m, void *arg)
111 1.2.2.2 tls {
112 1.2.2.2 tls time_t tloc;
113 1.2.2.2 tls
114 1.2.2.2 tls (void)time(&tloc);
115 1.2.2.2 tls if (logfp) {
116 1.2.2.2 tls fprintf(logfp, "Log ended at: %s\n", asctime(localtime(&tloc)));
117 1.2.2.2 tls fflush(logfp);
118 1.2.2.2 tls fclose(logfp);
119 1.2.2.2 tls logfp = NULL;
120 1.2.2.2 tls } else {
121 1.2.2.2 tls logfp = fopen("/tmp/sysinst.log", "a");
122 1.2.2.2 tls if (logfp != NULL) {
123 1.2.2.2 tls fprintf(logfp,
124 1.2.2.2 tls "Log started at: %s\n", asctime(localtime(&tloc)));
125 1.2.2.2 tls fflush(logfp);
126 1.2.2.2 tls } else {
127 1.2.2.2 tls if (mainwin) {
128 1.2.2.2 tls msg_display(MSG_openfail, "log file",
129 1.2.2.2 tls strerror(errno));
130 1.2.2.2 tls } else {
131 1.2.2.2 tls fprintf(stderr, "could not open /tmp/sysinst.log: %s\n",
132 1.2.2.2 tls strerror(errno));
133 1.2.2.2 tls exit(1);
134 1.2.2.2 tls }
135 1.2.2.2 tls }
136 1.2.2.2 tls }
137 1.2.2.2 tls return(0);
138 1.2.2.2 tls }
139 1.2.2.2 tls
140 1.2.2.2 tls static int
141 1.2.2.2 tls /*ARGSUSED*/
142 1.2.2.2 tls script_flip(menudesc *m, void *arg)
143 1.2.2.2 tls {
144 1.2.2.2 tls time_t tloc;
145 1.2.2.2 tls
146 1.2.2.2 tls (void)time(&tloc);
147 1.2.2.2 tls if (script) {
148 1.2.2.2 tls scripting_fprintf(NULL, "# Script ended at: %s\n",
149 1.2.2.2 tls asctime(localtime(&tloc)));
150 1.2.2.2 tls fflush(script);
151 1.2.2.2 tls fclose(script);
152 1.2.2.2 tls script = NULL;
153 1.2.2.2 tls } else {
154 1.2.2.2 tls script = fopen("/tmp/sysinst.sh", "w");
155 1.2.2.2 tls if (script != NULL) {
156 1.2.2.2 tls scripting_fprintf(NULL, "#!/bin/sh\n");
157 1.2.2.2 tls scripting_fprintf(NULL, "# Script started at: %s\n",
158 1.2.2.2 tls asctime(localtime(&tloc)));
159 1.2.2.2 tls fflush(script);
160 1.2.2.2 tls } else {
161 1.2.2.2 tls msg_display(MSG_openfail, "script file",
162 1.2.2.2 tls strerror(errno));
163 1.2.2.2 tls }
164 1.2.2.2 tls }
165 1.2.2.2 tls return(0);
166 1.2.2.2 tls }
167 1.2.2.2 tls
168 1.2.2.2 tls int
169 1.2.2.2 tls collect(int kind, char **buffer, const char *name, ...)
170 1.2.2.2 tls {
171 1.2.2.2 tls size_t nbytes; /* Number of bytes in buffer. */
172 1.2.2.2 tls size_t fbytes; /* Number of bytes in file. */
173 1.2.2.2 tls struct stat st; /* stat information. */
174 1.2.2.2 tls int ch;
175 1.2.2.2 tls FILE *f;
176 1.2.2.2 tls char fileorcmd[STRSIZE];
177 1.2.2.2 tls va_list ap;
178 1.2.2.2 tls char *cp;
179 1.2.2.2 tls
180 1.2.2.2 tls va_start(ap, name);
181 1.2.2.2 tls vsnprintf(fileorcmd, sizeof fileorcmd, name, ap);
182 1.2.2.2 tls va_end(ap);
183 1.2.2.2 tls
184 1.2.2.2 tls if (kind == T_FILE) {
185 1.2.2.2 tls /* Get the file information. */
186 1.2.2.2 tls if (stat(fileorcmd, &st)) {
187 1.2.2.2 tls *buffer = NULL;
188 1.2.2.2 tls return -1;
189 1.2.2.2 tls }
190 1.2.2.2 tls fbytes = (size_t)st.st_size;
191 1.2.2.2 tls
192 1.2.2.2 tls /* Open the file. */
193 1.2.2.2 tls f = fopen(fileorcmd, "r");
194 1.2.2.2 tls if (f == NULL) {
195 1.2.2.2 tls *buffer = NULL;
196 1.2.2.2 tls return -1;
197 1.2.2.2 tls }
198 1.2.2.2 tls } else {
199 1.2.2.2 tls /* Open the program. */
200 1.2.2.2 tls f = popen(fileorcmd, "r");
201 1.2.2.2 tls if (f == NULL) {
202 1.2.2.2 tls *buffer = NULL;
203 1.2.2.2 tls return -1;
204 1.2.2.2 tls }
205 1.2.2.2 tls fbytes = BUFSIZE;
206 1.2.2.2 tls }
207 1.2.2.2 tls
208 1.2.2.2 tls if (fbytes == 0)
209 1.2.2.2 tls fbytes = BUFSIZE;
210 1.2.2.2 tls
211 1.2.2.2 tls /* Allocate the buffer size. */
212 1.2.2.2 tls *buffer = cp = malloc(fbytes + 1);
213 1.2.2.2 tls if (!cp)
214 1.2.2.2 tls nbytes = -1;
215 1.2.2.2 tls else {
216 1.2.2.2 tls /* Read the buffer. */
217 1.2.2.2 tls nbytes = 0;
218 1.2.2.2 tls while (nbytes < fbytes && (ch = fgetc(f)) != EOF)
219 1.2.2.2 tls cp[nbytes++] = ch;
220 1.2.2.2 tls cp[nbytes] = 0;
221 1.2.2.2 tls }
222 1.2.2.2 tls
223 1.2.2.2 tls if (kind == T_FILE)
224 1.2.2.2 tls fclose(f);
225 1.2.2.2 tls else
226 1.2.2.2 tls pclose(f);
227 1.2.2.2 tls
228 1.2.2.2 tls return nbytes;
229 1.2.2.2 tls }
230 1.2.2.2 tls
231 1.2.2.2 tls
232 1.2.2.2 tls /*
233 1.2.2.2 tls * system(3), but with a debug wrapper.
234 1.2.2.2 tls * use only for curses sub-applications.
235 1.2.2.2 tls */
236 1.2.2.2 tls int
237 1.2.2.2 tls do_system(const char *execstr)
238 1.2.2.2 tls {
239 1.2.2.2 tls register int ret;
240 1.2.2.2 tls
241 1.2.2.2 tls /*
242 1.2.2.2 tls * The following may be more than one function call. Can't just
243 1.2.2.2 tls * "return Xsystem (command);"
244 1.2.2.2 tls */
245 1.2.2.2 tls
246 1.2.2.2 tls ret = Xsystem(execstr);
247 1.2.2.2 tls return (ret);
248 1.2.2.2 tls
249 1.2.2.2 tls }
250 1.2.2.2 tls
251 1.2.2.2 tls static char **
252 1.2.2.2 tls make_argv(const char *cmd)
253 1.2.2.2 tls {
254 1.2.2.2 tls char **argv = 0;
255 1.2.2.2 tls int argc = 0;
256 1.2.2.2 tls const char *cp;
257 1.2.2.2 tls char *dp, *fn;
258 1.2.2.2 tls DIR *dir;
259 1.2.2.2 tls struct dirent *dirent;
260 1.2.2.2 tls int l;
261 1.2.2.2 tls
262 1.2.2.2 tls for (; *cmd != 0; cmd = cp + strspn(cp, " "), argc++) {
263 1.2.2.2 tls if (*cmd == '\'')
264 1.2.2.2 tls cp = strchr(++cmd, '\'');
265 1.2.2.2 tls else
266 1.2.2.2 tls cp = strchr(cmd, ' ');
267 1.2.2.2 tls if (cp == NULL)
268 1.2.2.2 tls cp = strchr(cmd, 0);
269 1.2.2.2 tls argv = realloc(argv, (argc + 2) * sizeof *argv);
270 1.2.2.2 tls if (argv == NULL)
271 1.2.2.2 tls err(1, "realloc(argv) for %s", cmd);
272 1.2.2.2 tls asprintf(argv + argc, "%.*s", (int)(cp - cmd), cmd);
273 1.2.2.2 tls /* Hack to remove %xx encoded ftp password */
274 1.2.2.2 tls dp = strstr(cmd, ":%");
275 1.2.2.2 tls if (dp != NULL && dp < cp) {
276 1.2.2.2 tls for (fn = dp + 4; *fn == '%'; fn += 3)
277 1.2.2.2 tls continue;
278 1.2.2.2 tls if (*fn == '@')
279 1.2.2.2 tls memset(dp + 1, '*', fn - dp - 1);
280 1.2.2.2 tls }
281 1.2.2.2 tls if (*cp == '\'')
282 1.2.2.2 tls cp++;
283 1.2.2.2 tls if (cp[-1] != '*')
284 1.2.2.2 tls continue;
285 1.2.2.2 tls /* do limited filename globbing */
286 1.2.2.2 tls dp = argv[argc];
287 1.2.2.2 tls fn = strrchr(dp, '/');
288 1.2.2.2 tls if (fn != NULL)
289 1.2.2.2 tls *fn = 0;
290 1.2.2.2 tls dir = opendir(dp);
291 1.2.2.2 tls if (fn != NULL)
292 1.2.2.2 tls *fn++ = '/';
293 1.2.2.2 tls else
294 1.2.2.2 tls fn = dp;
295 1.2.2.2 tls if (dir == NULL)
296 1.2.2.2 tls continue;
297 1.2.2.2 tls l = strlen(fn) - 1;
298 1.2.2.2 tls while ((dirent = readdir(dir))) {
299 1.2.2.2 tls if (dirent->d_name[0] == '.')
300 1.2.2.2 tls continue;
301 1.2.2.2 tls if (strncmp(dirent->d_name, fn, l) != 0)
302 1.2.2.2 tls continue;
303 1.2.2.2 tls if (dp != argv[argc])
304 1.2.2.2 tls argc++;
305 1.2.2.2 tls argv = realloc(argv, (argc + 2) * sizeof *argv);
306 1.2.2.2 tls if (argv == NULL)
307 1.2.2.2 tls err(1, "realloc(argv) for %s", cmd);
308 1.2.2.2 tls asprintf(argv + argc, "%.*s%s", (int)(fn - dp), dp,
309 1.2.2.2 tls dirent->d_name);
310 1.2.2.2 tls }
311 1.2.2.2 tls if (dp != argv[argc])
312 1.2.2.2 tls free(dp);
313 1.2.2.2 tls closedir(dir);
314 1.2.2.2 tls }
315 1.2.2.2 tls argv[argc] = NULL;
316 1.2.2.2 tls return argv;
317 1.2.2.2 tls }
318 1.2.2.2 tls
319 1.2.2.2 tls static void
320 1.2.2.2 tls free_argv(char **argv)
321 1.2.2.2 tls {
322 1.2.2.2 tls char **n, *a;
323 1.2.2.2 tls
324 1.2.2.2 tls for (n = argv; (a = *n++);)
325 1.2.2.2 tls free(a);
326 1.2.2.2 tls free(argv);
327 1.2.2.2 tls }
328 1.2.2.2 tls
329 1.2.2.2 tls static WINDOW *
330 1.2.2.2 tls show_cmd(const char *scmd, struct winsize *win)
331 1.2.2.2 tls {
332 1.2.2.2 tls int n, m;
333 1.2.2.2 tls WINDOW *actionwin;
334 1.2.2.2 tls int nrow;
335 1.2.2.2 tls
336 1.2.2.2 tls wclear(stdscr);
337 1.2.2.2 tls clearok(stdscr, 1);
338 1.2.2.2 tls touchwin(stdscr);
339 1.2.2.2 tls refresh();
340 1.2.2.2 tls
341 1.2.2.2 tls mvaddstr(0, 4, msg_string(MSG_Status));
342 1.2.2.2 tls standout();
343 1.2.2.2 tls addstr(msg_string(MSG_Running));
344 1.2.2.2 tls standend();
345 1.2.2.2 tls mvaddstr(1, 4, msg_string(MSG_Command));
346 1.2.2.2 tls standout();
347 1.2.2.2 tls printw("%s", scmd);
348 1.2.2.2 tls standend();
349 1.2.2.2 tls addstr("\n\n");
350 1.2.2.2 tls for (n = win->ws_col; (m = min(n, 30)) > 0; n -= m)
351 1.2.2.2 tls addstr( "------------------------------" + 30 - m);
352 1.2.2.2 tls refresh();
353 1.2.2.2 tls
354 1.2.2.2 tls nrow = getcury(stdscr) + 1;
355 1.2.2.2 tls
356 1.2.2.2 tls actionwin = subwin(stdscr, win->ws_row - nrow, win->ws_col, nrow, 0);
357 1.2.2.2 tls if (actionwin == NULL) {
358 1.2.2.2 tls fprintf(stderr, "sysinst: failed to allocate output window.\n");
359 1.2.2.2 tls exit(1);
360 1.2.2.2 tls }
361 1.2.2.2 tls scrollok(actionwin, TRUE);
362 1.2.2.2 tls if (has_colors()) {
363 1.2.2.2 tls wbkgd(actionwin, getbkgd(stdscr));
364 1.2.2.2 tls wattrset(actionwin, getattrs(stdscr));
365 1.2.2.2 tls }
366 1.2.2.2 tls
367 1.2.2.2 tls wmove(actionwin, 0, 0);
368 1.2.2.2 tls wrefresh(actionwin);
369 1.2.2.2 tls
370 1.2.2.2 tls return actionwin;
371 1.2.2.2 tls }
372 1.2.2.2 tls
373 1.2.2.2 tls /*
374 1.2.2.2 tls * launch a program inside a subwindow, and report its return status when done
375 1.2.2.2 tls */
376 1.2.2.2 tls static int
377 1.2.2.2 tls launch_subwin(WINDOW **actionwin, char **args, struct winsize *win, int flags,
378 1.2.2.2 tls const char *scmd, const char **errstr)
379 1.2.2.2 tls {
380 1.2.2.2 tls int n, i;
381 1.2.2.2 tls int selectfailed;
382 1.2.2.2 tls int status, master, slave;
383 1.2.2.2 tls fd_set active_fd_set, read_fd_set;
384 1.2.2.2 tls pid_t child, pid;
385 1.2.2.2 tls char ibuf[MAXBUF];
386 1.2.2.2 tls char pktdata;
387 1.2.2.2 tls char *cp, *ncp;
388 1.2.2.2 tls struct termios rtt, tt;
389 1.2.2.2 tls struct timeval tmo;
390 1.2.2.2 tls static int do_tioccons = 2;
391 1.2.2.2 tls
392 1.2.2.2 tls (void)tcgetattr(STDIN_FILENO, &tt);
393 1.2.2.2 tls if (openpty(&master, &slave, NULL, &tt, win) == -1) {
394 1.2.2.2 tls *errstr = "openpty() failed";
395 1.2.2.2 tls return -1;
396 1.2.2.2 tls }
397 1.2.2.2 tls
398 1.2.2.2 tls rtt = tt;
399 1.2.2.2 tls
400 1.2.2.2 tls /* ignore tty signals until we're done with subprocess setup */
401 1.2.2.2 tls ttysig_ignore = 1;
402 1.2.2.2 tls ioctl(master, TIOCPKT, &ttysig_ignore);
403 1.2.2.2 tls
404 1.2.2.2 tls /* Try to get console output into our pipe */
405 1.2.2.2 tls if (do_tioccons) {
406 1.2.2.2 tls if (ioctl(slave, TIOCCONS, &do_tioccons) == 0
407 1.2.2.2 tls && do_tioccons == 2) {
408 1.2.2.2 tls /* test our output - we don't want it grabbed */
409 1.2.2.2 tls write(1, " \b", 2);
410 1.2.2.2 tls ioctl(master, FIONREAD, &do_tioccons);
411 1.2.2.2 tls if (do_tioccons != 0) {
412 1.2.2.2 tls do_tioccons = 0;
413 1.2.2.2 tls ioctl(slave, TIOCCONS, &do_tioccons);
414 1.2.2.2 tls } else
415 1.2.2.2 tls do_tioccons = 1;
416 1.2.2.2 tls }
417 1.2.2.2 tls }
418 1.2.2.2 tls
419 1.2.2.2 tls if (logfp)
420 1.2.2.2 tls fflush(logfp);
421 1.2.2.2 tls if (script)
422 1.2.2.2 tls fflush(script);
423 1.2.2.2 tls
424 1.2.2.2 tls child = fork();
425 1.2.2.2 tls switch (child) {
426 1.2.2.2 tls case -1:
427 1.2.2.2 tls ttysig_ignore = 0;
428 1.2.2.2 tls refresh();
429 1.2.2.2 tls *errstr = "fork() failed";
430 1.2.2.2 tls return -1;
431 1.2.2.2 tls case 0: /* child */
432 1.2.2.2 tls (void)close(STDIN_FILENO);
433 1.2.2.2 tls /* silently stop curses */
434 1.2.2.2 tls (void)close(STDOUT_FILENO);
435 1.2.2.2 tls (void)open("/dev/null", O_RDWR, 0);
436 1.2.2.2 tls dup2(STDIN_FILENO, STDOUT_FILENO);
437 1.2.2.2 tls endwin();
438 1.2.2.2 tls (void)close(master);
439 1.2.2.2 tls rtt = tt;
440 1.2.2.2 tls rtt.c_lflag |= (ICANON|ECHO);
441 1.2.2.2 tls (void)tcsetattr(slave, TCSANOW, &rtt);
442 1.2.2.2 tls login_tty(slave);
443 1.2.2.2 tls if (logfp) {
444 1.2.2.2 tls fprintf(logfp, "executing: %s\n", scmd);
445 1.2.2.2 tls fclose(logfp);
446 1.2.2.2 tls logfp = NULL;
447 1.2.2.2 tls }
448 1.2.2.2 tls if (script) {
449 1.2.2.2 tls fprintf(script, "%s\n", scmd);
450 1.2.2.2 tls fclose(script);
451 1.2.2.2 tls script = NULL;
452 1.2.2.2 tls }
453 1.2.2.2 tls if (strcmp(args[0], "cd") == 0 && strcmp(args[2], "&&") == 0) {
454 1.2.2.2 tls target_chdir_or_die(args[1]);
455 1.2.2.2 tls args += 3;
456 1.2.2.2 tls }
457 1.2.2.2 tls if (flags & RUN_XFER_DIR)
458 1.2.2.2 tls target_chdir_or_die(xfer_dir);
459 1.2.2.2 tls /*
460 1.2.2.2 tls * If target_prefix == "", the chroot will fail, but
461 1.2.2.2 tls * that's ok, since we don't need it then.
462 1.2.2.2 tls */
463 1.2.2.2 tls if (flags & RUN_CHROOT && *target_prefix()
464 1.2.2.2 tls && chroot(target_prefix()) != 0)
465 1.2.2.2 tls warn("chroot(%s) for %s", target_prefix(), *args);
466 1.2.2.2 tls else {
467 1.2.2.2 tls execvp(*args, args);
468 1.2.2.2 tls warn("execvp %s", *args);
469 1.2.2.2 tls }
470 1.2.2.2 tls _exit(EXIT_FAILURE);
471 1.2.2.2 tls // break; /* end of child */
472 1.2.2.2 tls default:
473 1.2.2.2 tls /*
474 1.2.2.2 tls * parent: we've set up the subprocess.
475 1.2.2.2 tls * forward tty signals to its process group.
476 1.2.2.2 tls */
477 1.2.2.2 tls ttysig_forward = child;
478 1.2.2.2 tls ttysig_ignore = 0;
479 1.2.2.2 tls break;
480 1.2.2.2 tls }
481 1.2.2.2 tls
482 1.2.2.2 tls /*
483 1.2.2.2 tls * Now loop transferring program output to screen, and keyboard
484 1.2.2.2 tls * input to the program.
485 1.2.2.2 tls */
486 1.2.2.2 tls
487 1.2.2.2 tls FD_ZERO(&active_fd_set);
488 1.2.2.2 tls FD_SET(master, &active_fd_set);
489 1.2.2.2 tls FD_SET(STDIN_FILENO, &active_fd_set);
490 1.2.2.2 tls
491 1.2.2.2 tls for (selectfailed = 0;;) {
492 1.2.2.2 tls if (selectfailed) {
493 1.2.2.2 tls const char mmsg[] =
494 1.2.2.2 tls "select(2) failed but no child died?";
495 1.2.2.2 tls if (logfp)
496 1.2.2.2 tls (void)fprintf(logfp, mmsg);
497 1.2.2.2 tls errx(1, mmsg);
498 1.2.2.2 tls }
499 1.2.2.2 tls read_fd_set = active_fd_set;
500 1.2.2.2 tls tmo.tv_sec = 2;
501 1.2.2.2 tls tmo.tv_usec = 0;
502 1.2.2.2 tls i = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tmo);
503 1.2.2.2 tls if (i == 0 && *actionwin == NULL)
504 1.2.2.2 tls *actionwin = show_cmd(scmd, win);
505 1.2.2.2 tls if (i < 0) {
506 1.2.2.2 tls if (errno != EINTR) {
507 1.2.2.2 tls warn("select");
508 1.2.2.2 tls if (logfp)
509 1.2.2.2 tls (void)fprintf(logfp,
510 1.2.2.2 tls "select failure: %s\n",
511 1.2.2.2 tls strerror(errno));
512 1.2.2.2 tls selectfailed = 1;
513 1.2.2.2 tls }
514 1.2.2.2 tls } else for (i = 0; i < FD_SETSIZE; ++i) {
515 1.2.2.2 tls if (!FD_ISSET(i, &read_fd_set))
516 1.2.2.2 tls continue;
517 1.2.2.2 tls n = read(i, ibuf, sizeof ibuf - 1);
518 1.2.2.2 tls if (n <= 0) {
519 1.2.2.2 tls if (n < 0)
520 1.2.2.2 tls warn("read");
521 1.2.2.2 tls continue;
522 1.2.2.2 tls }
523 1.2.2.2 tls ibuf[n] = 0;
524 1.2.2.2 tls cp = ibuf;
525 1.2.2.2 tls if (i == STDIN_FILENO) {
526 1.2.2.2 tls (void)write(master, ibuf, (size_t)n);
527 1.2.2.2 tls if (!(rtt.c_lflag & ECHO))
528 1.2.2.2 tls continue;
529 1.2.2.2 tls } else {
530 1.2.2.2 tls pktdata = ibuf[0];
531 1.2.2.2 tls if (pktdata != 0) {
532 1.2.2.2 tls if (pktdata & TIOCPKT_IOCTL)
533 1.2.2.2 tls memcpy(&rtt, ibuf, sizeof(rtt));
534 1.2.2.2 tls continue;
535 1.2.2.2 tls }
536 1.2.2.2 tls cp += 1;
537 1.2.2.2 tls }
538 1.2.2.2 tls if (*cp == 0 || flags & RUN_SILENT)
539 1.2.2.2 tls continue;
540 1.2.2.2 tls if (logfp) {
541 1.2.2.2 tls fprintf(logfp, "%s", cp);
542 1.2.2.2 tls fflush(logfp);
543 1.2.2.2 tls }
544 1.2.2.2 tls if (*actionwin == NULL)
545 1.2.2.2 tls *actionwin = show_cmd(scmd, win);
546 1.2.2.2 tls /* posix curses is braindead wrt \r\n so... */
547 1.2.2.2 tls for (ncp = cp; (ncp = strstr(ncp, "\r\n")); ncp += 2) {
548 1.2.2.2 tls ncp[0] = '\n';
549 1.2.2.2 tls ncp[1] = '\r';
550 1.2.2.2 tls }
551 1.2.2.2 tls waddstr(*actionwin, cp);
552 1.2.2.2 tls wrefresh(*actionwin);
553 1.2.2.2 tls }
554 1.2.2.2 tls pid = wait4(child, &status, WNOHANG, 0);
555 1.2.2.2 tls if (pid == child && (WIFEXITED(status) || WIFSIGNALED(status)))
556 1.2.2.2 tls break;
557 1.2.2.2 tls }
558 1.2.2.2 tls close(master);
559 1.2.2.2 tls close(slave);
560 1.2.2.2 tls if (logfp)
561 1.2.2.2 tls fflush(logfp);
562 1.2.2.2 tls
563 1.2.2.2 tls /* from here on out, we take tty signals ourselves */
564 1.2.2.2 tls ttysig_forward = 0;
565 1.2.2.2 tls
566 1.2.2.2 tls reset_prog_mode();
567 1.2.2.2 tls
568 1.2.2.2 tls if (WIFEXITED(status)) {
569 1.2.2.2 tls *errstr = msg_string(MSG_Command_failed);
570 1.2.2.2 tls return WEXITSTATUS(status);
571 1.2.2.2 tls }
572 1.2.2.2 tls if (WIFSIGNALED(status)) {
573 1.2.2.2 tls *errstr = msg_string(MSG_Command_ended_on_signal);
574 1.2.2.2 tls return WTERMSIG(status);
575 1.2.2.2 tls }
576 1.2.2.2 tls return 0;
577 1.2.2.2 tls }
578 1.2.2.2 tls
579 1.2.2.2 tls /*
580 1.2.2.2 tls * generic program runner.
581 1.2.2.2 tls * flags:
582 1.2.2.2 tls * RUN_DISPLAY display command name and output
583 1.2.2.2 tls * RUN_FATAL program errors are fatal
584 1.2.2.2 tls * RUN_CHROOT chroot to target before the exec
585 1.2.2.2 tls * RUN_FULLSCREEN display output only
586 1.2.2.2 tls * RUN_SILENT do not display program output
587 1.2.2.2 tls * RUN_ERROR_OK don't wait for key if program fails
588 1.2.2.2 tls * RUN_PROGRESS don't wait for key if program has output
589 1.2.2.2 tls * If both RUN_DISPLAY and RUN_SILENT are clear then the program name will
590 1.2.2.2 tls * be displayed as soon as it generates output.
591 1.2.2.2 tls * Steps are taken to collect console messages, they will be interleaved
592 1.2.2.2 tls * into the program output - but not upset curses.
593 1.2.2.2 tls */
594 1.2.2.2 tls
595 1.2.2.2 tls int
596 1.2.2.2 tls run_program(int flags, const char *cmd, ...)
597 1.2.2.2 tls {
598 1.2.2.2 tls va_list ap;
599 1.2.2.2 tls struct winsize win;
600 1.2.2.2 tls int ret;
601 1.2.2.2 tls WINDOW *actionwin = NULL;
602 1.2.2.2 tls char *scmd;
603 1.2.2.2 tls char **args;
604 1.2.2.2 tls const char *errstr = NULL;
605 1.2.2.2 tls
606 1.2.2.2 tls va_start(ap, cmd);
607 1.2.2.2 tls vasprintf(&scmd, cmd, ap);
608 1.2.2.2 tls va_end(ap);
609 1.2.2.2 tls if (scmd == NULL)
610 1.2.2.2 tls err(1, "vasprintf(&scmd, \"%s\", ...)", cmd);
611 1.2.2.2 tls
612 1.2.2.2 tls args = make_argv(scmd);
613 1.2.2.2 tls
614 1.2.2.2 tls /* Make curses save tty settings */
615 1.2.2.2 tls def_prog_mode();
616 1.2.2.2 tls
617 1.2.2.2 tls (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
618 1.2.2.2 tls /* Apparently, we sometimes get 0x0 back, and that's not useful */
619 1.2.2.2 tls if (win.ws_row == 0)
620 1.2.2.2 tls win.ws_row = 24;
621 1.2.2.2 tls if (win.ws_col == 0)
622 1.2.2.2 tls win.ws_col = 80;
623 1.2.2.2 tls
624 1.2.2.2 tls if ((flags & RUN_DISPLAY) != 0) {
625 1.2.2.2 tls if (flags & RUN_FULLSCREEN) {
626 1.2.2.2 tls wclear(stdscr);
627 1.2.2.2 tls clearok(stdscr, 1);
628 1.2.2.2 tls touchwin(stdscr);
629 1.2.2.2 tls refresh();
630 1.2.2.2 tls actionwin = stdscr;
631 1.2.2.2 tls } else
632 1.2.2.2 tls actionwin = show_cmd(scmd, &win);
633 1.2.2.2 tls } else
634 1.2.2.2 tls win.ws_row -= 4;
635 1.2.2.2 tls
636 1.2.2.2 tls ret = launch_subwin(&actionwin, args, &win, flags, scmd, &errstr);
637 1.2.2.2 tls fpurge(stdin);
638 1.2.2.2 tls
639 1.2.2.2 tls /* If the command failed, show command name */
640 1.2.2.2 tls if (actionwin == NULL && ret != 0 && !(flags & RUN_ERROR_OK))
641 1.2.2.2 tls actionwin = show_cmd(scmd, &win);
642 1.2.2.2 tls
643 1.2.2.2 tls if (actionwin != NULL) {
644 1.2.2.2 tls int y, x;
645 1.2.2.2 tls getyx(actionwin, y, x);
646 1.2.2.2 tls if (actionwin != stdscr)
647 1.2.2.2 tls mvaddstr(0, 4, msg_string(MSG_Status));
648 1.2.2.2 tls if (ret != 0) {
649 1.2.2.2 tls if (actionwin == stdscr && x != 0)
650 1.2.2.2 tls addstr("\n");
651 1.2.2.2 tls x = 1; /* force newline below */
652 1.2.2.2 tls standout();
653 1.2.2.2 tls addstr(errstr);
654 1.2.2.2 tls standend();
655 1.2.2.2 tls } else {
656 1.2.2.2 tls if (actionwin != stdscr) {
657 1.2.2.2 tls standout();
658 1.2.2.2 tls addstr(msg_string(MSG_Finished));
659 1.2.2.2 tls standend();
660 1.2.2.2 tls }
661 1.2.2.2 tls }
662 1.2.2.2 tls clrtoeol();
663 1.2.2.2 tls refresh();
664 1.2.2.2 tls if ((ret != 0 && !(flags & RUN_ERROR_OK)) ||
665 1.2.2.2 tls (y + x != 0 && !(flags & RUN_PROGRESS))) {
666 1.2.2.2 tls if (actionwin != stdscr)
667 1.2.2.2 tls move(getbegy(actionwin) - 2, 5);
668 1.2.2.2 tls else if (x != 0)
669 1.2.2.2 tls addstr("\n");
670 1.2.2.2 tls addstr(msg_string(MSG_Hit_enter_to_continue));
671 1.2.2.2 tls refresh();
672 1.2.2.2 tls getchar();
673 1.2.2.2 tls } else {
674 1.2.2.2 tls if (y + x != 0) {
675 1.2.2.2 tls /* give user 1 second to see messages */
676 1.2.2.2 tls refresh();
677 1.2.2.2 tls sleep(1);
678 1.2.2.2 tls }
679 1.2.2.2 tls }
680 1.2.2.2 tls }
681 1.2.2.2 tls
682 1.2.2.2 tls /* restore tty setting we saved earlier */
683 1.2.2.2 tls reset_prog_mode();
684 1.2.2.2 tls
685 1.2.2.2 tls /* clean things up */
686 1.2.2.2 tls if (actionwin != NULL) {
687 1.2.2.2 tls if (actionwin != stdscr)
688 1.2.2.2 tls delwin(actionwin);
689 1.2.2.2 tls if (errstr == 0 || !(flags & RUN_NO_CLEAR)) {
690 1.2.2.2 tls wclear(stdscr);
691 1.2.2.2 tls touchwin(stdscr);
692 1.2.2.2 tls clearok(stdscr, 1);
693 1.2.2.2 tls refresh();
694 1.2.2.2 tls }
695 1.2.2.2 tls }
696 1.2.2.2 tls
697 1.2.2.2 tls free(scmd);
698 1.2.2.2 tls free_argv(args);
699 1.2.2.2 tls
700 1.2.2.2 tls if (ret != 0 && flags & RUN_FATAL)
701 1.2.2.2 tls exit(ret);
702 1.2.2.2 tls return ret;
703 1.2.2.2 tls }
704