[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.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>