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

1.11.2.1! perry       1: /*     $NetBSD: run.c,v 1.14 1999/04/13 14:49:56 bouyer 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.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software develooped for the NetBSD Project by
                     20:  *      Piermont Information Systems Inc.
                     21:  * 4. The name of Piermont Information Systems Inc. may not be used to endorse
                     22:  *    or promote products derived from this software without specific prior
                     23:  *    written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
                     26:  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     27:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     28:  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
                     29:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     30:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     31:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     32:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     33:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     34:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
                     35:  * THE POSSIBILITY OF SUCH DAMAGE.
                     36:  *
                     37:  */
                     38:
                     39: /* run.c -- routines to interact with other programs. */
                     40:
1.7       garbled    41: /* XXX write return codes ignored. XXX */
                     42:
                     43: #include <errno.h>
1.1       phil       44: #include <stdio.h>
                     45: #include <stdarg.h>
                     46: #include <stdlib.h>
1.7       garbled    47: #include <unistd.h>
                     48: #include <fcntl.h>
                     49: #include <curses.h>
                     50: #include <termios.h>
                     51: #include <util.h>
                     52: #include <err.h>
                     53: #include <sys/ioctl.h>
1.1       phil       54: #include <sys/types.h>
1.7       garbled    55: #include <sys/wait.h>
1.1       phil       56: #include <sys/stat.h>
                     57: #include "defs.h"
                     58:
1.7       garbled    59: #include "menu_defs.h"
1.3       jonathan   60: #include "msg_defs.h"
                     61:
1.7       garbled    62: #define MAXBUF 256
                     63:
1.1       phil       64: #ifdef DEBUG
1.2       phil       65: #define Xsystem(y) printf ("%s\n", y), 0
1.1       phil       66: #else
                     67: #define Xsystem(y) system(y)
                     68: #endif
                     69:
1.7       garbled    70: extern int errno;
                     71:
1.3       jonathan   72: /*
                     73:  * local prototypes
                     74:  */
1.5       mrg        75: char* va_prog_cmdstr __P((char *cmd, va_list ap));
1.7       garbled    76: int launch_subwin __P((WINDOW *actionwin, char **args, struct winsize win, int display));
                     77: int log_flip __P((void));
                     78: int script_flip __P((void));
                     79:
                     80: #define BUFSIZE 4096
                     81:
                     82: char log_text[2][30] = {"Logging: Off", "Scripting: Off"};
                     83:
                     84: menu_ent logmenu [2] = {
                     85:        { log_text[0], OPT_NOMENU, 0, log_flip},
                     86:        { log_text[1], OPT_NOMENU, 0, script_flip} };
                     87:
                     88:
                     89: void
                     90: do_logging(void)
                     91: {
                     92:        int menu_no;
                     93:
                     94:        menu_no = new_menu (" Logging Functions ", logmenu, 2, 13, 12,
                     95:                0, 55, MC_SCROLL, NULL, NULL, "Pick an option to turn on or off.\n");
                     96:
                     97:        if (menu_no < 0) {
                     98:                (void)fprintf(stderr, "Dynamic menu creation failed.\n");
                     99:                if (logging)
                    100:                        (void)fprintf(log, "Dynamic menu creation failed.\n");
                    101:                exit(EXIT_FAILURE);
                    102:        }
                    103:        process_menu(menu_no);
                    104:        free_menu(menu_no);
                    105: }
                    106:
                    107: int
                    108: log_flip(void)
                    109: {
                    110:        time_t tloc;
                    111:
                    112:        (void)time(&tloc);
                    113:        if (logging == 1) {
                    114:                sprintf(log_text[0], "Logging: Off");
                    115:                logging = 0;
                    116:                fprintf(log, "Log ended at: %s\n", asctime(localtime(&tloc)));
                    117:                fflush(log);
                    118:                fclose(log);
                    119:        } else {
                    120:                sprintf(log_text[0], "Logging: On");
                    121:                logging = 1;
                    122:                log = fopen("sysinst.log", "a");
                    123:                fprintf(log, "Log started at: %s\n", asctime(localtime(&tloc)));
                    124:                fflush(log);
                    125:        }
                    126:        return(0);
                    127: }
1.3       jonathan  128:
1.7       garbled   129: int
                    130: script_flip(void)
                    131: {
                    132:        time_t tloc;
1.3       jonathan  133:
1.7       garbled   134:        (void)time(&tloc);
                    135:        if (scripting == 1) {
                    136:                sprintf(log_text[1], "Scripting: Off");
                    137:                scripting = 0;
                    138:                fprintf(script, "# Script ended at: %s\n", asctime(localtime(&tloc)));
                    139:                fflush(script);
                    140:                fclose(script);
                    141:        } else {
                    142:                sprintf(log_text[1], "Scripting: On");
                    143:                scripting = 1;
                    144:                script = fopen("sysinst.sh", "w");
                    145:                fprintf(script, "#!/bin/sh\n");
                    146:                fprintf(script, "# Script started at: %s\n", asctime(localtime(&tloc)));
                    147:                fflush(script);
                    148:        }
                    149:        return(0);
                    150: }
1.1       phil      151:
                    152: int
1.5       mrg       153: collect(int kind, char **buffer, const char *name, ...)
1.1       phil      154: {
                    155:        size_t nbytes;          /* Number of bytes in buffer. */
                    156:        size_t fbytes;          /* Number of bytes in file. */
                    157:        struct stat st;         /* stat information. */
                    158:        int ch;
                    159:        FILE *f;
                    160:        char fileorcmd [STRSIZE];
                    161:        va_list ap;
                    162:
1.5       mrg       163:        va_start(ap, name);
                    164:        vsnprintf(fileorcmd, STRSIZE, name, ap);
                    165:        va_end(ap);
1.1       phil      166:
                    167:        if (kind == T_FILE) {
                    168:                /* Get the file information. */
1.5       mrg       169:                if (stat(fileorcmd, &st)) {
1.1       phil      170:                        *buffer = NULL;
                    171:                        return -1;
                    172:                }
                    173:                fbytes = (size_t)st.st_size;
                    174:
                    175:                /* Open the file. */
1.5       mrg       176:                f = fopen(fileorcmd, "r");
1.1       phil      177:                if (f == NULL) {
                    178:                        *buffer = NULL;
                    179:                        return -1;
                    180:                }
                    181:        } else {
                    182:                /* Open the program. */
1.5       mrg       183:                f = popen(fileorcmd, "r");
1.1       phil      184:                if (f == NULL) {
                    185:                        *buffer = NULL;
                    186:                        return -1;
                    187:                }
                    188:                fbytes = BUFSIZE;
                    189:        }
                    190:
                    191:        if (fbytes == 0)
                    192:                fbytes = BUFSIZE;
                    193:
                    194:        /* Allocate the buffer size. */
1.5       mrg       195:        *buffer = (char *)malloc(fbytes + 1);
1.1       phil      196:        if (!*buffer)
                    197:                return -1;
                    198:
                    199:        /* Read the buffer. */
                    200:        nbytes = 0;
                    201:        while (nbytes < fbytes && (ch = fgetc(f)) != EOF)
                    202:                (*buffer)[nbytes++] = ch;
                    203:
                    204:        (*buffer)[nbytes] = 0;
                    205:
                    206:        if (kind == T_FILE)
                    207:                fclose(f);
                    208:        else
                    209:                pclose(f);
                    210:
                    211:        return nbytes;
                    212: }
                    213:
                    214:
1.3       jonathan  215: /*
                    216:  * system(3), but with a debug wrapper.
1.7       garbled   217:  * use only for curses sub-applications.
1.3       jonathan  218:  */
1.5       mrg       219: int
                    220: do_system(execstr)
                    221:        const char *execstr;
1.3       jonathan  222: {
                    223:        register int ret;
                    224:
1.5       mrg       225:        /*
                    226:         * The following may be more than one function call.  Can't just
                    227:         * "return Xsystem (command);"
                    228:         */
1.3       jonathan  229:
1.5       mrg       230:        ret = Xsystem(execstr);
                    231:        return (ret);
1.3       jonathan  232:
                    233: }
                    234:
                    235: /*
                    236:  *  build command tring for do_system() from anonymous args.
                    237:  *  XXX return result is in a static buffer.
                    238:  */
1.5       mrg       239: char *
                    240: va_prog_cmdstr(char *cmd, va_list ap)
1.3       jonathan  241: {
1.5       mrg       242:        static char command[STRSIZE];
1.3       jonathan  243:
1.6       perry     244:        memset(command, 0, STRSIZE);
1.5       mrg       245:        (void)vsnprintf(command, STRSIZE, cmd, ap);
                    246:        return (command);
1.3       jonathan  247: }
1.7       garbled   248:
1.3       jonathan  249:
1.5       mrg       250: /*
1.7       garbled   251:  * launch a program inside a subwindow, and report it's return status when done
1.5       mrg       252:  */
1.7       garbled   253:
1.5       mrg       254: int
1.7       garbled   255: launch_subwin(actionwin, args, win, display)
                    256:        WINDOW *actionwin;
                    257:        char **args;
                    258:        struct winsize win;
                    259:        int display;
1.1       phil      260: {
1.7       garbled   261:        int xcor,ycor;
                    262:        int n, i, j;
1.11      ross      263:        int selectfailed;
1.7       garbled   264:        int status, master, slave;
                    265:        fd_set active_fd_set, read_fd_set;
                    266:        int dataflow[2];
                    267:        pid_t child, subchild, pid;
                    268:        char ibuf[MAXBUF], obuf[MAXBUF];
                    269:        char *command, *p, *argzero, **origargs;
                    270:        struct termios rtt;
                    271:        struct termios tt;
                    272:
                    273:        pipe(dataflow);
                    274:
                    275:        argzero = *args;
                    276:        origargs = args;
                    277:
                    278:        command = (char *)malloc(MAXBUF * sizeof(char));
                    279:        for (p = *args; p != NULL; p = *++args) {
                    280:                strcat(command, p);
                    281:                strcat(command, " ");
                    282:        }
                    283:        (void)tcgetattr(STDIN_FILENO, &tt);
                    284:        if (openpty(&master, &slave, NULL, &tt, &win) == -1)
                    285:                return(1);
                    286:        rtt = tt;
                    287:        rtt.c_lflag &= ~ECHO;
                    288:        (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
1.1       phil      289:
1.7       garbled   290:        switch(child=fork()) {
                    291:        case -1:
                    292:                return -1;
                    293:                break;
1.11      ross      294:        case 0:
1.7       garbled   295:                (void)close(STDIN_FILENO);
                    296:                subchild = fork();
                    297:                if (subchild == 0) {
                    298:                        close(dataflow[0]);
                    299:                        for (;;) {
                    300:                                n = read(master, obuf, sizeof(obuf));
                    301:                                if (n <= 0)
                    302:                                        break;
                    303:                                write(dataflow[1], obuf, n);
                    304:                        } /* while spinning */
                    305:                        nonl();
                    306:                        _exit(EXIT_SUCCESS);
                    307:                } /* subchild, child forks */
                    308:                (void)close(master);
                    309:                close(dataflow[1]);
                    310:                close(dataflow[0]);
                    311:                login_tty(slave);
                    312:                if (logging) {
                    313:                        fprintf(log, "executing: %s\n", command);
                    314:                        fflush(log);
                    315:                        fclose(log);
                    316:                }
                    317:                if (scripting) {
                    318:                        fprintf(script, "%s\n", command);
                    319:                        fflush(script);
                    320:                        fclose(script);
                    321:                }
                    322:                execvp(argzero, origargs);
1.10      marc      323:                /* the parent will see this as the output from the
                    324:                   child */
1.11      ross      325:                warn("execvp %s", argzero);
1.10      marc      326:                _exit(EXIT_FAILURE);
1.11      ross      327:                break; /* end of child */
1.7       garbled   328:        default: break;
                    329:        }
                    330:        close(dataflow[1]);
                    331:        FD_ZERO(&active_fd_set);
                    332:        FD_SET(dataflow[0], &active_fd_set);
                    333:        FD_SET(STDIN_FILENO, &active_fd_set);
                    334:
                    335:        pid = wait4(child, &status, WNOHANG, 0);
1.11      ross      336:        for (selectfailed = 0;;) {
                    337:                if (selectfailed) {
                    338:                        char *msg = "select(2) failed but no child died?";
                    339:                        if(logging)
                    340:                                (void)fprintf(log, msg);
                    341:                        errx(1, msg);
                    342:                }
1.7       garbled   343:                read_fd_set = active_fd_set;
                    344:                if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) {
                    345:                        perror("select");
                    346:                        if (logging)
                    347:                                (void)fprintf(log, "select failure: %s\n", strerror(errno));
1.11      ross      348:                        ++selectfailed;
                    349:                } else for (i = 0; i < FD_SETSIZE; ++i) {
1.7       garbled   350:                        if (FD_ISSET (i, &read_fd_set)) {
                    351:                                n = read(i, ibuf, MAXBUF);
                    352:                                if (i == STDIN_FILENO)
                    353:                                        (void)write(master, ibuf, n);
                    354:                                for (j=0; j < n; j++) {
                    355:                                        if (display) {
                    356:                                                if (ibuf[j] == '\n' || ibuf[j] == '\r') {
                    357:                                                        if (ibuf[j] == '\n') {
                    358:                                                                getyx(actionwin, ycor, xcor);
                    359:                                                                if (ycor + 1 >= actionwin->maxy) {
                    360:                                                                        scroll(actionwin);
                    361:                                                                        wmove(actionwin, actionwin->maxy - 1, 1);
                    362:                                                                } else
                    363:                                                                        wmove(actionwin, ycor + 1, 1);
                    364:                                                                if (logging)
                    365:                                                                        fprintf(log, "\n");
                    366:                                                        }
                    367:                                                } else {
                    368:                                                        getyx(actionwin, ycor, xcor);
                    369:                                                        if (xcor == 0)
                    370:                                                        wmove(actionwin, ycor, xcor + 1);
                    371:                                                        waddch(actionwin, ibuf[j]);
                    372:                                                        wrefresh(actionwin);
                    373:                                                        if (logging) {
                    374:                                                                putc(ibuf[j], log);
                    375:                                                                fflush(log);
                    376:                                                        }
                    377:                                                }
                    378:                                        } else {  /* display is off */
                    379:                                                if (logging) {
                    380:                                                        putc(ibuf[j], log);
                    381:                                                        fflush(log);
                    382:                                                }
                    383:                                        }
                    384:                                }
                    385:                        }
1.11      ross      386:                }
1.7       garbled   387:                pid = wait4(child, &status, WNOHANG, 0);
                    388:                if (pid == child && (WIFEXITED(status) || WIFSIGNALED(status)))
                    389:                        break;
                    390:        }
                    391:        close(dataflow[0]); /* clean up our leaks */
                    392:        close(master);
                    393:        close(slave);
                    394:        if (logging)
                    395:                fflush(log);
                    396:
                    397:        (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
                    398:        if (WIFEXITED(status))
                    399:                return(WEXITSTATUS(status));
                    400:        else if (WIFSIGNALED(status))
                    401:                return(WTERMSIG(status));
                    402:        else
                    403:                return(0);
1.3       jonathan  404: }
                    405:
                    406: /*
1.7       garbled   407:  * generic program runner.  fatal and display can be set to
                    408:  * 1 if you wish the output to be displayed, or an error to be
                    409:  * fatal.
1.3       jonathan  410:  */
1.7       garbled   411:
1.5       mrg       412: int
1.11.2.1! perry     413: run_prog(int fatal, int display, char *errmsg, char *cmd, ...)
1.3       jonathan  414: {
                    415:        va_list ap;
1.7       garbled   416:        struct winsize win;
1.3       jonathan  417:        int ret;
1.7       garbled   418:        WINDOW *actionwin, *statuswin, *boxwin;
                    419:        char buf2[MAXBUF];
                    420:        char *command, *p, *args[51], **aps;
                    421:
                    422:        va_start(ap,cmd);
                    423:        sprintf(buf2,"%s",va_prog_cmdstr(cmd,ap));
                    424:        p = buf2;
                    425:        command = strdup(buf2);
                    426:
                    427:        /* 51 strings and it's blown! */
                    428:        for (aps = args; (*aps = strsep(&p, " ")) != NULL;)
                    429:                if (**aps != '\0')
                    430:                        ++aps;
                    431:
                    432:        (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
1.9       he        433:        /* Apparently, we sometimes get 0x0 back, and that's not useful */
                    434:        if (win.ws_row == 0)
                    435:                win.ws_row = 24;
                    436:        if (win.ws_col == 0)
                    437:                win.ws_col = 80;
                    438:
1.7       garbled   439:        if (display) {
1.11.2.1! perry     440:                wclear(stdscr); /* XXX shouldn't be needed */
        !           441:                wrefresh(stdscr);
1.7       garbled   442:                statuswin = subwin(stdscr, win.ws_row, win.ws_col, 0, 0);
                    443:                boxwin = subwin(statuswin, win.ws_row - 3, win.ws_col, 3, 0);
1.11.2.1! perry     444:                actionwin = subwin(statuswin, win.ws_row - 5, win.ws_col - 3,
        !           445:                   4, 1);
1.7       garbled   446:                scrollok(actionwin, TRUE);
                    447:
                    448:                win.ws_col -= 3;
                    449:                win.ws_row -= 5;
                    450:
                    451:                wclear(statuswin);
                    452:                wrefresh(statuswin);
                    453:
                    454:                wclear(boxwin);
                    455:                box(boxwin, 124, 45);
                    456:                wrefresh(boxwin);
                    457:
                    458:                wclear(actionwin);
                    459:                wrefresh(actionwin);
                    460:
                    461:                wmove(statuswin, 0 , 5);
                    462:                waddstr(statuswin, "Status: ");
                    463:                wstandout(statuswin);
                    464:                waddstr(statuswin, "Running");
                    465:                wstandend(statuswin);
                    466:
                    467:                wmove(statuswin, 1, 4);
                    468:                waddstr(statuswin, "Command: ");
                    469:                wstandout(statuswin);
                    470:                waddstr(statuswin, command);
                    471:                wstandend(statuswin);
                    472:                wrefresh(statuswin);
                    473:
                    474:                ret = launch_subwin(actionwin, args, win, 1);
                    475:
                    476:                wmove(statuswin, 0, 13);
                    477:                waddstr(statuswin, "          ");
                    478:                wmove(statuswin, 0, 13);
                    479:                wstandout(statuswin);
                    480:                if (ret != 0)
                    481:                        waddstr(statuswin, "Failed");
                    482:                else
                    483:                        waddstr(statuswin, "Finished");
                    484:                wstandend(statuswin);
                    485:                wmove(statuswin, 2, 5);
1.11.2.1! perry     486:                if (ret != 0)
        !           487:                        waddstr(statuswin, "Press any key to continue");
1.7       garbled   488:                wrefresh(statuswin);
1.11.2.1! perry     489:                if (ret != 0)
        !           490:                        (void)getchar();
1.7       garbled   491:
                    492:                /* clean things up */
                    493:                wclear(actionwin);
                    494:                wrefresh(actionwin);
                    495:                delwin(actionwin);
                    496:                wclear(boxwin);
                    497:                wrefresh(boxwin);
                    498:                delwin(boxwin);
                    499:                wclear(statuswin);
                    500:                wrefresh(statuswin);
                    501:                delwin(statuswin);
                    502:                refresh();
                    503:        } else { /* display */
                    504:                ret = launch_subwin(NULL, args, win, 0);
                    505:        }
1.5       mrg       506:        va_end(ap);
1.11.2.1! perry     507:        if (fatal && ret != 0)
1.5       mrg       508:                exit(ret);
1.11.2.1! perry     509:        if (ret && errmsg) {
        !           510:                msg_printf(errmsg, command);
        !           511:                process_menu(MENU_ok);
        !           512:        }
        !           513:        return(ret);
1.3       jonathan  514: }

CVSweb <webmaster@jp.NetBSD.org>