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