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