1*95b05310Srillig /* $NetBSD: run.c,v 1.16 2024/10/04 15:11:09 rillig Exp $ */ 250dbef1aSdholland 350dbef1aSdholland /* 450dbef1aSdholland * Copyright 1997 Piermont Information Systems Inc. 550dbef1aSdholland * All rights reserved. 650dbef1aSdholland * 750dbef1aSdholland * Written by Philip A. Nelson for Piermont Information Systems Inc. 850dbef1aSdholland * 950dbef1aSdholland * Redistribution and use in source and binary forms, with or without 1050dbef1aSdholland * modification, are permitted provided that the following conditions 1150dbef1aSdholland * are met: 1250dbef1aSdholland * 1. Redistributions of source code must retain the above copyright 1350dbef1aSdholland * notice, this list of conditions and the following disclaimer. 1450dbef1aSdholland * 2. Redistributions in binary form must reproduce the above copyright 1550dbef1aSdholland * notice, this list of conditions and the following disclaimer in the 1650dbef1aSdholland * documentation and/or other materials provided with the distribution. 1750dbef1aSdholland * 3. The name of Piermont Information Systems Inc. may not be used to endorse 1850dbef1aSdholland * or promote products derived from this software without specific prior 1950dbef1aSdholland * written permission. 2050dbef1aSdholland * 2150dbef1aSdholland * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 2250dbef1aSdholland * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2350dbef1aSdholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2450dbef1aSdholland * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 2550dbef1aSdholland * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2650dbef1aSdholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2750dbef1aSdholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2850dbef1aSdholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2950dbef1aSdholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3050dbef1aSdholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3150dbef1aSdholland * THE POSSIBILITY OF SUCH DAMAGE. 3250dbef1aSdholland * 3350dbef1aSdholland */ 3450dbef1aSdholland 3550dbef1aSdholland /* run.c -- routines to interact with other programs. */ 3650dbef1aSdholland 3750dbef1aSdholland /* XXX write return codes ignored. XXX */ 3850dbef1aSdholland 3950dbef1aSdholland #include <errno.h> 4050dbef1aSdholland #include <stdio.h> 4150dbef1aSdholland #include <stdarg.h> 4250dbef1aSdholland #include <stdlib.h> 4350dbef1aSdholland #include <unistd.h> 4450dbef1aSdholland #include <fcntl.h> 4550dbef1aSdholland #include <curses.h> 4650dbef1aSdholland #include <termios.h> 4750dbef1aSdholland #include <dirent.h> 4850dbef1aSdholland #include <util.h> 4950dbef1aSdholland #include <signal.h> 5050dbef1aSdholland #include <err.h> 5150dbef1aSdholland #include <sys/ioctl.h> 5250dbef1aSdholland #include <sys/types.h> 5350dbef1aSdholland #include <sys/wait.h> 5450dbef1aSdholland #include <sys/stat.h> 5550dbef1aSdholland #include "defs.h" 5650dbef1aSdholland 5750dbef1aSdholland #include "menu_defs.h" 5850dbef1aSdholland #include "msg_defs.h" 5950dbef1aSdholland 6050dbef1aSdholland #define MAXBUF 256 6150dbef1aSdholland 6213376b1dSmartin #if defined(DEBUG) && defined(DEBUG_SYSTEM) 6313376b1dSmartin static inline int 6413376b1dSmartin Xsystem(const char *y) 6513376b1dSmartin { 6613376b1dSmartin printf ("%s\n", y); 6713376b1dSmartin return 0; 6813376b1dSmartin } 6950dbef1aSdholland #else 7050dbef1aSdholland #define Xsystem(y) system(y) 7150dbef1aSdholland #endif 7250dbef1aSdholland 7350dbef1aSdholland /* 7450dbef1aSdholland * local prototypes 7550dbef1aSdholland */ 7650dbef1aSdholland int log_flip (menudesc *, void *); 7750dbef1aSdholland static int script_flip (menudesc *, void *); 7850dbef1aSdholland 7950dbef1aSdholland #define BUFSIZE 4096 8050dbef1aSdholland 8150dbef1aSdholland menu_ent logmenu [2] = { 82ce713491Schristos { .opt_action=log_flip}, 83ce713491Schristos { .opt_action=script_flip} 8439e50615Smartin }; 8550dbef1aSdholland 8650dbef1aSdholland static void 8750dbef1aSdholland log_menu_label(menudesc *m, int opt, void *arg) 8850dbef1aSdholland { 8950dbef1aSdholland wprintw(m->mw, "%s: %s", 9050dbef1aSdholland msg_string(opt ? MSG_Scripting : MSG_Logging), 9150dbef1aSdholland msg_string((opt ? script != NULL : logfp != NULL) ? 9250dbef1aSdholland MSG_On : MSG_Off)); 9350dbef1aSdholland } 9450dbef1aSdholland 9550dbef1aSdholland void 9650dbef1aSdholland do_logging(void) 9750dbef1aSdholland { 9850dbef1aSdholland int menu_no; 9950dbef1aSdholland 10050dbef1aSdholland menu_no = new_menu(MSG_Logging_functions, logmenu, 2, -1, 12, 10150dbef1aSdholland 0, 20, MC_SCROLL, NULL, log_menu_label, NULL, 1027ca7eecaSmartin MSG_Pick_an_option, MSG_exit_menu_generic); 10350dbef1aSdholland 10450dbef1aSdholland if (menu_no < 0) { 10550dbef1aSdholland (void)fprintf(stderr, "Dynamic menu creation failed.\n"); 10650dbef1aSdholland if (logfp) 10750dbef1aSdholland (void)fprintf(logfp, "Dynamic menu creation failed.\n"); 10850dbef1aSdholland exit(EXIT_FAILURE); 10950dbef1aSdholland } 11050dbef1aSdholland process_menu(menu_no, NULL); 11150dbef1aSdholland free_menu(menu_no); 11250dbef1aSdholland } 11350dbef1aSdholland 11450dbef1aSdholland int 11550dbef1aSdholland /*ARGSUSED*/ 11650dbef1aSdholland log_flip(menudesc *m, void *arg) 11750dbef1aSdholland { 11850dbef1aSdholland time_t tloc; 11950dbef1aSdholland 12050dbef1aSdholland (void)time(&tloc); 12150dbef1aSdholland if (logfp) { 122e47dca20Schristos fprintf(logfp, "Log ended at: %s\n", safectime(&tloc)); 12350dbef1aSdholland fflush(logfp); 12450dbef1aSdholland fclose(logfp); 12550dbef1aSdholland logfp = NULL; 12650dbef1aSdholland } else { 12750dbef1aSdholland logfp = fopen("/tmp/sysinst.log", "a"); 12850dbef1aSdholland if (logfp != NULL) { 12950dbef1aSdholland fprintf(logfp, 130e47dca20Schristos "Log started at: %s\n", safectime(&tloc)); 13150dbef1aSdholland fflush(logfp); 13250dbef1aSdholland } else { 1334b2364d9Smartin if (mainwin) { 13424ecf24eSchristos msg_fmt_display(MSG_openfail, "%s%s", 13524ecf24eSchristos "log file", strerror(errno)); 1364b2364d9Smartin } else { 1374b2364d9Smartin fprintf(stderr, "could not open /tmp/sysinst.log: %s\n", 1384b2364d9Smartin strerror(errno)); 1394b2364d9Smartin exit(1); 1404b2364d9Smartin } 14150dbef1aSdholland } 14250dbef1aSdholland } 14350dbef1aSdholland return(0); 14450dbef1aSdholland } 14550dbef1aSdholland 14650dbef1aSdholland static int 14750dbef1aSdholland /*ARGSUSED*/ 14850dbef1aSdholland script_flip(menudesc *m, void *arg) 14950dbef1aSdholland { 15050dbef1aSdholland time_t tloc; 15150dbef1aSdholland 15250dbef1aSdholland (void)time(&tloc); 15350dbef1aSdholland if (script) { 15450dbef1aSdholland scripting_fprintf(NULL, "# Script ended at: %s\n", 155e47dca20Schristos safectime(&tloc)); 15650dbef1aSdholland fflush(script); 15750dbef1aSdholland fclose(script); 15850dbef1aSdholland script = NULL; 15950dbef1aSdholland } else { 16050dbef1aSdholland script = fopen("/tmp/sysinst.sh", "w"); 16150dbef1aSdholland if (script != NULL) { 16250dbef1aSdholland scripting_fprintf(NULL, "#!/bin/sh\n"); 16350dbef1aSdholland scripting_fprintf(NULL, "# Script started at: %s\n", 164e47dca20Schristos safectime(&tloc)); 16550dbef1aSdholland fflush(script); 16650dbef1aSdholland } else { 16724ecf24eSchristos msg_fmt_display(MSG_openfail, "%s%s", "script file", 16850dbef1aSdholland strerror(errno)); 16950dbef1aSdholland } 17050dbef1aSdholland } 17150dbef1aSdholland return(0); 17250dbef1aSdholland } 17350dbef1aSdholland 17450dbef1aSdholland int 17550dbef1aSdholland collect(int kind, char **buffer, const char *name, ...) 17650dbef1aSdholland { 17750dbef1aSdholland size_t nbytes; /* Number of bytes in buffer. */ 17850dbef1aSdholland size_t fbytes; /* Number of bytes in file. */ 17971830ed8Smartin size_t abytes; /* allocated size of buffer */ 18050dbef1aSdholland struct stat st; /* stat information. */ 18150dbef1aSdholland int ch; 18250dbef1aSdholland FILE *f; 18350dbef1aSdholland char fileorcmd[STRSIZE]; 18450dbef1aSdholland va_list ap; 18550dbef1aSdholland char *cp; 18650dbef1aSdholland 18750dbef1aSdholland va_start(ap, name); 18850dbef1aSdholland vsnprintf(fileorcmd, sizeof fileorcmd, name, ap); 18950dbef1aSdholland va_end(ap); 19050dbef1aSdholland 19150dbef1aSdholland if (kind == T_FILE) { 19250dbef1aSdholland /* Get the file information. */ 19350dbef1aSdholland if (stat(fileorcmd, &st)) { 19450dbef1aSdholland *buffer = NULL; 19550dbef1aSdholland return -1; 19650dbef1aSdholland } 19750dbef1aSdholland fbytes = (size_t)st.st_size; 19850dbef1aSdholland 19950dbef1aSdholland /* Open the file. */ 20050dbef1aSdholland f = fopen(fileorcmd, "r"); 20150dbef1aSdholland if (f == NULL) { 20271830ed8Smartin if (logfp) 20371830ed8Smartin fprintf(logfp, "%s: failed to open %s\n", 20471830ed8Smartin __func__, fileorcmd); 20550dbef1aSdholland *buffer = NULL; 20650dbef1aSdholland return -1; 20750dbef1aSdholland } 20850dbef1aSdholland } else { 20950dbef1aSdholland /* Open the program. */ 21050dbef1aSdholland f = popen(fileorcmd, "r"); 21150dbef1aSdholland if (f == NULL) { 21271830ed8Smartin if (logfp) 21371830ed8Smartin fprintf(logfp, "%s: failed to open %s\n", 21471830ed8Smartin __func__, fileorcmd); 21550dbef1aSdholland *buffer = NULL; 21650dbef1aSdholland return -1; 21750dbef1aSdholland } 21871830ed8Smartin fbytes = 0; 21950dbef1aSdholland } 22050dbef1aSdholland 22150dbef1aSdholland if (fbytes == 0) 22271830ed8Smartin abytes = BUFSIZE; 22371830ed8Smartin else 22471830ed8Smartin abytes = fbytes+1; 22550dbef1aSdholland 22650dbef1aSdholland /* Allocate the buffer size. */ 22771830ed8Smartin *buffer = cp = malloc(abytes); 22850dbef1aSdholland if (!cp) 22950dbef1aSdholland nbytes = -1; 23050dbef1aSdholland else { 23150dbef1aSdholland /* Read the buffer. */ 23250dbef1aSdholland nbytes = 0; 23371830ed8Smartin while ((ch = fgetc(f)) != EOF) { 23471830ed8Smartin if (nbytes >= abytes-1) { 23571830ed8Smartin if (fbytes > 0 || abytes >= 512*BUFSIZE) { 23671830ed8Smartin free(cp); 23771830ed8Smartin *buffer = cp = NULL; 23871830ed8Smartin nbytes = -1; 23971830ed8Smartin break; 24071830ed8Smartin } 24171830ed8Smartin abytes *= 2; 24271830ed8Smartin *buffer = cp = realloc(cp, abytes); 24371830ed8Smartin if (!cp) { 24471830ed8Smartin nbytes = -1; 24571830ed8Smartin break; 24671830ed8Smartin } 24771830ed8Smartin 24871830ed8Smartin } 24950dbef1aSdholland cp[nbytes++] = ch; 25071830ed8Smartin } 25171830ed8Smartin if (cp) 25250dbef1aSdholland cp[nbytes] = 0; 25350dbef1aSdholland } 25450dbef1aSdholland 25550dbef1aSdholland if (kind == T_FILE) 25650dbef1aSdholland fclose(f); 25750dbef1aSdholland else 25850dbef1aSdholland pclose(f); 25950dbef1aSdholland 26071830ed8Smartin if (nbytes <= 0 && logfp) 26171830ed8Smartin fprintf(logfp, "%s: failed for %s\n", __func__, fileorcmd); 26271830ed8Smartin 26350dbef1aSdholland return nbytes; 26450dbef1aSdholland } 26550dbef1aSdholland 26650dbef1aSdholland 26750dbef1aSdholland /* 26850dbef1aSdholland * system(3), but with a debug wrapper. 26950dbef1aSdholland * use only for curses sub-applications. 27050dbef1aSdholland */ 27150dbef1aSdholland int 27250dbef1aSdholland do_system(const char *execstr) 27350dbef1aSdholland { 27450dbef1aSdholland register int ret; 27550dbef1aSdholland 27650dbef1aSdholland /* 27750dbef1aSdholland * The following may be more than one function call. Can't just 27850dbef1aSdholland * "return Xsystem (command);" 27950dbef1aSdholland */ 28050dbef1aSdholland 28150dbef1aSdholland ret = Xsystem(execstr); 28250dbef1aSdholland return (ret); 28350dbef1aSdholland 28450dbef1aSdholland } 28550dbef1aSdholland 28650dbef1aSdholland static char ** 287*95b05310Srillig make_argv(char *cmd) 28850dbef1aSdholland { 28950dbef1aSdholland char **argv = 0; 29050dbef1aSdholland int argc = 0; 291*95b05310Srillig char *cp, *dp, *fn; 29250dbef1aSdholland DIR *dir; 29350dbef1aSdholland struct dirent *dirent; 29450dbef1aSdholland int l; 29550dbef1aSdholland 29650dbef1aSdholland for (; *cmd != 0; cmd = cp + strspn(cp, " "), argc++) { 29750dbef1aSdholland if (*cmd == '\'') 29850dbef1aSdholland cp = strchr(++cmd, '\''); 29950dbef1aSdholland else 30050dbef1aSdholland cp = strchr(cmd, ' '); 30150dbef1aSdholland if (cp == NULL) 30250dbef1aSdholland cp = strchr(cmd, 0); 30350dbef1aSdholland argv = realloc(argv, (argc + 2) * sizeof *argv); 30450dbef1aSdholland if (argv == NULL) 30550dbef1aSdholland err(1, "realloc(argv) for %s", cmd); 30650dbef1aSdholland asprintf(argv + argc, "%.*s", (int)(cp - cmd), cmd); 30750dbef1aSdholland /* Hack to remove %xx encoded ftp password */ 30850dbef1aSdholland dp = strstr(cmd, ":%"); 30950dbef1aSdholland if (dp != NULL && dp < cp) { 31050dbef1aSdholland for (fn = dp + 4; *fn == '%'; fn += 3) 31150dbef1aSdholland continue; 31250dbef1aSdholland if (*fn == '@') 31350dbef1aSdholland memset(dp + 1, '*', fn - dp - 1); 31450dbef1aSdholland } 31550dbef1aSdholland if (*cp == '\'') 31650dbef1aSdholland cp++; 31750dbef1aSdholland if (cp[-1] != '*') 31850dbef1aSdholland continue; 31950dbef1aSdholland /* do limited filename globbing */ 32050dbef1aSdholland dp = argv[argc]; 32150dbef1aSdholland fn = strrchr(dp, '/'); 32250dbef1aSdholland if (fn != NULL) 32350dbef1aSdholland *fn = 0; 32450dbef1aSdholland dir = opendir(dp); 32550dbef1aSdholland if (fn != NULL) 32650dbef1aSdholland *fn++ = '/'; 32750dbef1aSdholland else 32850dbef1aSdholland fn = dp; 32950dbef1aSdholland if (dir == NULL) 33050dbef1aSdholland continue; 33150dbef1aSdholland l = strlen(fn) - 1; 33250dbef1aSdholland while ((dirent = readdir(dir))) { 33350dbef1aSdholland if (dirent->d_name[0] == '.') 33450dbef1aSdholland continue; 33550dbef1aSdholland if (strncmp(dirent->d_name, fn, l) != 0) 33650dbef1aSdholland continue; 33750dbef1aSdholland if (dp != argv[argc]) 33850dbef1aSdholland argc++; 33950dbef1aSdholland argv = realloc(argv, (argc + 2) * sizeof *argv); 34050dbef1aSdholland if (argv == NULL) 34150dbef1aSdholland err(1, "realloc(argv) for %s", cmd); 34250dbef1aSdholland asprintf(argv + argc, "%.*s%s", (int)(fn - dp), dp, 34350dbef1aSdholland dirent->d_name); 34450dbef1aSdholland } 34550dbef1aSdholland if (dp != argv[argc]) 34650dbef1aSdholland free(dp); 34750dbef1aSdholland closedir(dir); 34850dbef1aSdholland } 34950dbef1aSdholland argv[argc] = NULL; 35050dbef1aSdholland return argv; 35150dbef1aSdholland } 35250dbef1aSdholland 35350dbef1aSdholland static void 35450dbef1aSdholland free_argv(char **argv) 35550dbef1aSdholland { 35650dbef1aSdholland char **n, *a; 35750dbef1aSdholland 35850dbef1aSdholland for (n = argv; (a = *n++);) 35950dbef1aSdholland free(a); 36050dbef1aSdholland free(argv); 36150dbef1aSdholland } 36250dbef1aSdholland 36350dbef1aSdholland static WINDOW * 36450dbef1aSdholland show_cmd(const char *scmd, struct winsize *win) 36550dbef1aSdholland { 36650dbef1aSdholland WINDOW *actionwin; 36750dbef1aSdholland int nrow; 36850dbef1aSdholland 36950dbef1aSdholland wclear(stdscr); 37050dbef1aSdholland clearok(stdscr, 1); 37150dbef1aSdholland touchwin(stdscr); 37250dbef1aSdholland refresh(); 37350dbef1aSdholland 37450dbef1aSdholland mvaddstr(0, 4, msg_string(MSG_Status)); 37550dbef1aSdholland standout(); 37650dbef1aSdholland addstr(msg_string(MSG_Running)); 37750dbef1aSdholland standend(); 37850dbef1aSdholland mvaddstr(1, 4, msg_string(MSG_Command)); 37950dbef1aSdholland standout(); 38050dbef1aSdholland printw("%s", scmd); 38150dbef1aSdholland standend(); 38250dbef1aSdholland addstr("\n\n"); 3831f77ea37Smartin hline(0, win->ws_col); 38450dbef1aSdholland refresh(); 38550dbef1aSdholland 38650dbef1aSdholland nrow = getcury(stdscr) + 1; 38750dbef1aSdholland 38850dbef1aSdholland actionwin = subwin(stdscr, win->ws_row - nrow, win->ws_col, nrow, 0); 38950dbef1aSdholland if (actionwin == NULL) { 39050dbef1aSdholland fprintf(stderr, "sysinst: failed to allocate output window.\n"); 39150dbef1aSdholland exit(1); 39250dbef1aSdholland } 39350dbef1aSdholland scrollok(actionwin, TRUE); 39450dbef1aSdholland if (has_colors()) { 39550dbef1aSdholland wbkgd(actionwin, getbkgd(stdscr)); 39650dbef1aSdholland wattrset(actionwin, getattrs(stdscr)); 39750dbef1aSdholland } 39850dbef1aSdholland 39950dbef1aSdholland wmove(actionwin, 0, 0); 40050dbef1aSdholland wrefresh(actionwin); 40150dbef1aSdholland 40250dbef1aSdholland return actionwin; 40350dbef1aSdholland } 40450dbef1aSdholland 40550dbef1aSdholland /* 40650dbef1aSdholland * launch a program inside a subwindow, and report its return status when done 40750dbef1aSdholland */ 40850dbef1aSdholland static int 40950dbef1aSdholland launch_subwin(WINDOW **actionwin, char **args, struct winsize *win, int flags, 41050dbef1aSdholland const char *scmd, const char **errstr) 41150dbef1aSdholland { 41250dbef1aSdholland int n, i; 41350dbef1aSdholland int selectfailed; 41450dbef1aSdholland int status, master, slave; 41550dbef1aSdholland fd_set active_fd_set, read_fd_set; 41650dbef1aSdholland pid_t child, pid; 41750dbef1aSdholland char ibuf[MAXBUF]; 41850dbef1aSdholland char pktdata; 41950dbef1aSdholland char *cp, *ncp; 42050dbef1aSdholland struct termios rtt, tt; 42150dbef1aSdholland struct timeval tmo; 42250dbef1aSdholland static int do_tioccons = 2; 42350dbef1aSdholland 42450dbef1aSdholland (void)tcgetattr(STDIN_FILENO, &tt); 42550dbef1aSdholland if (openpty(&master, &slave, NULL, &tt, win) == -1) { 42650dbef1aSdholland *errstr = "openpty() failed"; 42750dbef1aSdholland return -1; 42850dbef1aSdholland } 42950dbef1aSdholland 43050dbef1aSdholland rtt = tt; 43150dbef1aSdholland 43250dbef1aSdholland /* ignore tty signals until we're done with subprocess setup */ 43350dbef1aSdholland ttysig_ignore = 1; 43450dbef1aSdholland ioctl(master, TIOCPKT, &ttysig_ignore); 43550dbef1aSdholland 43650dbef1aSdholland /* Try to get console output into our pipe */ 43750dbef1aSdholland if (do_tioccons) { 43850dbef1aSdholland if (ioctl(slave, TIOCCONS, &do_tioccons) == 0 43950dbef1aSdholland && do_tioccons == 2) { 44050dbef1aSdholland /* test our output - we don't want it grabbed */ 44150dbef1aSdholland write(1, " \b", 2); 44250dbef1aSdholland ioctl(master, FIONREAD, &do_tioccons); 44350dbef1aSdholland if (do_tioccons != 0) { 44450dbef1aSdholland do_tioccons = 0; 44550dbef1aSdholland ioctl(slave, TIOCCONS, &do_tioccons); 44650dbef1aSdholland } else 44750dbef1aSdholland do_tioccons = 1; 44850dbef1aSdholland } 44950dbef1aSdholland } 45050dbef1aSdholland 45150dbef1aSdholland if (logfp) 45250dbef1aSdholland fflush(logfp); 45350dbef1aSdholland if (script) 45450dbef1aSdholland fflush(script); 45550dbef1aSdholland 45650dbef1aSdholland child = fork(); 45750dbef1aSdholland switch (child) { 45850dbef1aSdholland case -1: 45950dbef1aSdholland ttysig_ignore = 0; 46050dbef1aSdholland refresh(); 46150dbef1aSdholland *errstr = "fork() failed"; 46250dbef1aSdholland return -1; 46350dbef1aSdholland case 0: /* child */ 46450dbef1aSdholland (void)close(STDIN_FILENO); 46550dbef1aSdholland /* silently stop curses */ 46650dbef1aSdholland (void)close(STDOUT_FILENO); 46750dbef1aSdholland (void)open("/dev/null", O_RDWR, 0); 46850dbef1aSdholland dup2(STDIN_FILENO, STDOUT_FILENO); 46950dbef1aSdholland endwin(); 47050dbef1aSdholland (void)close(master); 47150dbef1aSdholland rtt = tt; 47250dbef1aSdholland rtt.c_lflag |= (ICANON|ECHO); 47350dbef1aSdholland (void)tcsetattr(slave, TCSANOW, &rtt); 47450dbef1aSdholland login_tty(slave); 47550dbef1aSdholland if (logfp) { 47650dbef1aSdholland fprintf(logfp, "executing: %s\n", scmd); 47750dbef1aSdholland fclose(logfp); 47850dbef1aSdholland logfp = NULL; 47950dbef1aSdholland } 48050dbef1aSdholland if (script) { 48150dbef1aSdholland fprintf(script, "%s\n", scmd); 48250dbef1aSdholland fclose(script); 48350dbef1aSdholland script = NULL; 48450dbef1aSdholland } 48550dbef1aSdholland if (strcmp(args[0], "cd") == 0 && strcmp(args[2], "&&") == 0) { 48650dbef1aSdholland target_chdir_or_die(args[1]); 48750dbef1aSdholland args += 3; 48850dbef1aSdholland } 48950dbef1aSdholland if (flags & RUN_XFER_DIR) 49050dbef1aSdholland target_chdir_or_die(xfer_dir); 49150dbef1aSdholland /* 49250dbef1aSdholland * If target_prefix == "", the chroot will fail, but 49350dbef1aSdholland * that's ok, since we don't need it then. 49450dbef1aSdholland */ 49550dbef1aSdholland if (flags & RUN_CHROOT && *target_prefix() 49650dbef1aSdholland && chroot(target_prefix()) != 0) 49750dbef1aSdholland warn("chroot(%s) for %s", target_prefix(), *args); 49850dbef1aSdholland else { 49950dbef1aSdholland execvp(*args, args); 50050dbef1aSdholland warn("execvp %s", *args); 50150dbef1aSdholland } 50250dbef1aSdholland _exit(EXIT_FAILURE); 50350dbef1aSdholland // break; /* end of child */ 50450dbef1aSdholland default: 50550dbef1aSdholland /* 50650dbef1aSdholland * parent: we've set up the subprocess. 50750dbef1aSdholland * forward tty signals to its process group. 50850dbef1aSdholland */ 50950dbef1aSdholland ttysig_forward = child; 51050dbef1aSdholland ttysig_ignore = 0; 51150dbef1aSdholland break; 51250dbef1aSdholland } 51350dbef1aSdholland 51450dbef1aSdholland /* 51550dbef1aSdholland * Now loop transferring program output to screen, and keyboard 51650dbef1aSdholland * input to the program. 51750dbef1aSdholland */ 51850dbef1aSdholland 51950dbef1aSdholland FD_ZERO(&active_fd_set); 52050dbef1aSdholland FD_SET(master, &active_fd_set); 52150dbef1aSdholland FD_SET(STDIN_FILENO, &active_fd_set); 52250dbef1aSdholland 52350dbef1aSdholland for (selectfailed = 0;;) { 52450dbef1aSdholland if (selectfailed) { 52550dbef1aSdholland const char mmsg[] = 52650dbef1aSdholland "select(2) failed but no child died?"; 52750dbef1aSdholland if (logfp) 52850dbef1aSdholland (void)fprintf(logfp, mmsg); 52950dbef1aSdholland errx(1, mmsg); 53050dbef1aSdholland } 53150dbef1aSdholland read_fd_set = active_fd_set; 532099d1616Smartin tmo.tv_sec = flags & RUN_SILENT ? 20 : 2; 53350dbef1aSdholland tmo.tv_usec = 0; 53450dbef1aSdholland i = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tmo); 5353cbe7ed1Smartin if (i == 0 && *actionwin == NULL && (flags & RUN_SILENT) == 0) 53650dbef1aSdholland *actionwin = show_cmd(scmd, win); 53750dbef1aSdholland if (i < 0) { 53850dbef1aSdholland if (errno != EINTR) { 53950dbef1aSdholland warn("select"); 54050dbef1aSdholland if (logfp) 54150dbef1aSdholland (void)fprintf(logfp, 54250dbef1aSdholland "select failure: %s\n", 54350dbef1aSdholland strerror(errno)); 54450dbef1aSdholland selectfailed = 1; 54550dbef1aSdholland } 54650dbef1aSdholland } else for (i = 0; i < FD_SETSIZE; ++i) { 54750dbef1aSdholland if (!FD_ISSET(i, &read_fd_set)) 54850dbef1aSdholland continue; 54950dbef1aSdholland n = read(i, ibuf, sizeof ibuf - 1); 55050dbef1aSdholland if (n <= 0) { 55150dbef1aSdholland if (n < 0) 55250dbef1aSdholland warn("read"); 55350dbef1aSdholland continue; 55450dbef1aSdholland } 55550dbef1aSdholland ibuf[n] = 0; 55650dbef1aSdholland cp = ibuf; 55750dbef1aSdholland if (i == STDIN_FILENO) { 55850dbef1aSdholland (void)write(master, ibuf, (size_t)n); 55950dbef1aSdholland if (!(rtt.c_lflag & ECHO)) 56050dbef1aSdholland continue; 56150dbef1aSdholland } else { 56250dbef1aSdholland pktdata = ibuf[0]; 56350dbef1aSdholland if (pktdata != 0) { 56450dbef1aSdholland if (pktdata & TIOCPKT_IOCTL) 56550dbef1aSdholland memcpy(&rtt, ibuf, sizeof(rtt)); 56650dbef1aSdholland continue; 56750dbef1aSdholland } 56850dbef1aSdholland cp += 1; 56950dbef1aSdholland } 57050dbef1aSdholland if (*cp == 0 || flags & RUN_SILENT) 57150dbef1aSdholland continue; 57250dbef1aSdholland if (logfp) { 57350dbef1aSdholland fprintf(logfp, "%s", cp); 57450dbef1aSdholland fflush(logfp); 57550dbef1aSdholland } 57650dbef1aSdholland if (*actionwin == NULL) 57750dbef1aSdholland *actionwin = show_cmd(scmd, win); 57850dbef1aSdholland /* posix curses is braindead wrt \r\n so... */ 57950dbef1aSdholland for (ncp = cp; (ncp = strstr(ncp, "\r\n")); ncp += 2) { 58050dbef1aSdholland ncp[0] = '\n'; 58150dbef1aSdholland ncp[1] = '\r'; 58250dbef1aSdholland } 58350dbef1aSdholland waddstr(*actionwin, cp); 58450dbef1aSdholland wrefresh(*actionwin); 58550dbef1aSdholland } 58650dbef1aSdholland pid = wait4(child, &status, WNOHANG, 0); 58750dbef1aSdholland if (pid == child && (WIFEXITED(status) || WIFSIGNALED(status))) 58850dbef1aSdholland break; 58950dbef1aSdholland } 59050dbef1aSdholland close(master); 59150dbef1aSdholland close(slave); 59250dbef1aSdholland if (logfp) 59350dbef1aSdholland fflush(logfp); 59450dbef1aSdholland 59550dbef1aSdholland /* from here on out, we take tty signals ourselves */ 59650dbef1aSdholland ttysig_forward = 0; 59750dbef1aSdholland 59850dbef1aSdholland reset_prog_mode(); 59950dbef1aSdholland 60050dbef1aSdholland if (WIFEXITED(status)) { 60150dbef1aSdholland *errstr = msg_string(MSG_Command_failed); 60250dbef1aSdholland return WEXITSTATUS(status); 60350dbef1aSdholland } 60450dbef1aSdholland if (WIFSIGNALED(status)) { 60550dbef1aSdholland *errstr = msg_string(MSG_Command_ended_on_signal); 60650dbef1aSdholland return WTERMSIG(status); 60750dbef1aSdholland } 60850dbef1aSdholland return 0; 60950dbef1aSdholland } 61050dbef1aSdholland 61150dbef1aSdholland /* 61250dbef1aSdholland * generic program runner. 61350dbef1aSdholland * flags: 61450dbef1aSdholland * RUN_DISPLAY display command name and output 61550dbef1aSdholland * RUN_FATAL program errors are fatal 61650dbef1aSdholland * RUN_CHROOT chroot to target before the exec 61750dbef1aSdholland * RUN_FULLSCREEN display output only 61850dbef1aSdholland * RUN_SILENT do not display program output 61950dbef1aSdholland * RUN_ERROR_OK don't wait for key if program fails 62050dbef1aSdholland * RUN_PROGRESS don't wait for key if program has output 62150dbef1aSdholland * If both RUN_DISPLAY and RUN_SILENT are clear then the program name will 62250dbef1aSdholland * be displayed as soon as it generates output. 62350dbef1aSdholland * Steps are taken to collect console messages, they will be interleaved 62450dbef1aSdholland * into the program output - but not upset curses. 62550dbef1aSdholland */ 62650dbef1aSdholland 62750dbef1aSdholland int 62850dbef1aSdholland run_program(int flags, const char *cmd, ...) 62950dbef1aSdholland { 63050dbef1aSdholland va_list ap; 63150dbef1aSdholland struct winsize win; 63250dbef1aSdholland int ret; 63350dbef1aSdholland WINDOW *actionwin = NULL; 63450dbef1aSdholland char *scmd; 63550dbef1aSdholland char **args; 63650dbef1aSdholland const char *errstr = NULL; 63750dbef1aSdholland 63850dbef1aSdholland va_start(ap, cmd); 63950dbef1aSdholland vasprintf(&scmd, cmd, ap); 64050dbef1aSdholland va_end(ap); 64150dbef1aSdholland if (scmd == NULL) 64250dbef1aSdholland err(1, "vasprintf(&scmd, \"%s\", ...)", cmd); 64350dbef1aSdholland 64450dbef1aSdholland args = make_argv(scmd); 64550dbef1aSdholland 64650dbef1aSdholland /* Make curses save tty settings */ 64750dbef1aSdholland def_prog_mode(); 64850dbef1aSdholland 64950dbef1aSdholland (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win); 65050dbef1aSdholland /* Apparently, we sometimes get 0x0 back, and that's not useful */ 65150dbef1aSdholland if (win.ws_row == 0) 65250dbef1aSdholland win.ws_row = 24; 65350dbef1aSdholland if (win.ws_col == 0) 65450dbef1aSdholland win.ws_col = 80; 65550dbef1aSdholland 65650dbef1aSdholland if ((flags & RUN_DISPLAY) != 0) { 65718183f70Smartin if (flags & RUN_STDSCR) { 65818183f70Smartin actionwin = stdscr; 65918183f70Smartin wmove(stdscr, msg_row()+2, 0); 66018183f70Smartin wrefresh(stdscr); 66118183f70Smartin } else if (flags & RUN_FULLSCREEN) { 66250dbef1aSdholland wclear(stdscr); 66350dbef1aSdholland clearok(stdscr, 1); 66450dbef1aSdholland touchwin(stdscr); 66550dbef1aSdholland refresh(); 66650dbef1aSdholland actionwin = stdscr; 66718183f70Smartin } else { 66850dbef1aSdholland actionwin = show_cmd(scmd, &win); 66918183f70Smartin } 67050dbef1aSdholland } else 67150dbef1aSdholland win.ws_row -= 4; 67250dbef1aSdholland 67350dbef1aSdholland ret = launch_subwin(&actionwin, args, &win, flags, scmd, &errstr); 67450dbef1aSdholland fpurge(stdin); 67550dbef1aSdholland 67650dbef1aSdholland /* If the command failed, show command name */ 67750dbef1aSdholland if (actionwin == NULL && ret != 0 && !(flags & RUN_ERROR_OK)) 67850dbef1aSdholland actionwin = show_cmd(scmd, &win); 67950dbef1aSdholland 68050dbef1aSdholland if (actionwin != NULL) { 68150dbef1aSdholland int y, x; 68250dbef1aSdholland getyx(actionwin, y, x); 68350dbef1aSdholland if (actionwin != stdscr) 68450dbef1aSdholland mvaddstr(0, 4, msg_string(MSG_Status)); 68550dbef1aSdholland if (ret != 0) { 68650dbef1aSdholland if (actionwin == stdscr && x != 0) 68750dbef1aSdholland addstr("\n"); 68850dbef1aSdholland x = 1; /* force newline below */ 68950dbef1aSdholland standout(); 69050dbef1aSdholland addstr(errstr); 69150dbef1aSdholland standend(); 69250dbef1aSdholland } else { 69350dbef1aSdholland if (actionwin != stdscr) { 69450dbef1aSdholland standout(); 69550dbef1aSdholland addstr(msg_string(MSG_Finished)); 69650dbef1aSdholland standend(); 69750dbef1aSdholland } 69850dbef1aSdholland } 69950dbef1aSdholland clrtoeol(); 70050dbef1aSdholland refresh(); 70150dbef1aSdholland if ((ret != 0 && !(flags & RUN_ERROR_OK)) || 70250dbef1aSdholland (y + x != 0 && !(flags & RUN_PROGRESS))) { 70350dbef1aSdholland if (actionwin != stdscr) 70450dbef1aSdholland move(getbegy(actionwin) - 2, 5); 70550dbef1aSdholland else if (x != 0) 70650dbef1aSdholland addstr("\n"); 70750dbef1aSdholland addstr(msg_string(MSG_Hit_enter_to_continue)); 70850dbef1aSdholland refresh(); 70950dbef1aSdholland getchar(); 71050dbef1aSdholland } else { 71150dbef1aSdholland if (y + x != 0) { 71250dbef1aSdholland /* give user 1 second to see messages */ 71350dbef1aSdholland refresh(); 71450dbef1aSdholland sleep(1); 71550dbef1aSdholland } 71650dbef1aSdholland } 71750dbef1aSdholland } 71850dbef1aSdholland 71950dbef1aSdholland /* restore tty setting we saved earlier */ 72050dbef1aSdholland reset_prog_mode(); 72150dbef1aSdholland 72250dbef1aSdholland /* clean things up */ 72350dbef1aSdholland if (actionwin != NULL) { 72450dbef1aSdholland if (actionwin != stdscr) 72550dbef1aSdholland delwin(actionwin); 72650dbef1aSdholland if (errstr == 0 || !(flags & RUN_NO_CLEAR)) { 72750dbef1aSdholland wclear(stdscr); 72850dbef1aSdholland touchwin(stdscr); 72950dbef1aSdholland clearok(stdscr, 1); 73050dbef1aSdholland refresh(); 73150dbef1aSdholland } 73250dbef1aSdholland } 73350dbef1aSdholland 73450dbef1aSdholland free(scmd); 73550dbef1aSdholland free_argv(args); 73650dbef1aSdholland 73750dbef1aSdholland if (ret != 0 && flags & RUN_FATAL) 73850dbef1aSdholland exit(ret); 73950dbef1aSdholland return ret; 74050dbef1aSdholland } 741