[BACK]Return to run.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / distrib / utils / sysinst

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>