1 1.16 rillig /* $NetBSD: run.c,v 1.16 2024/10/04 15:11:09 rillig Exp $ */ 2 1.1 dholland 3 1.1 dholland /* 4 1.1 dholland * Copyright 1997 Piermont Information Systems Inc. 5 1.1 dholland * All rights reserved. 6 1.1 dholland * 7 1.1 dholland * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 1.1 dholland * 9 1.1 dholland * Redistribution and use in source and binary forms, with or without 10 1.1 dholland * modification, are permitted provided that the following conditions 11 1.1 dholland * are met: 12 1.1 dholland * 1. Redistributions of source code must retain the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer. 14 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer in the 16 1.1 dholland * documentation and/or other materials provided with the distribution. 17 1.1 dholland * 3. The name of Piermont Information Systems Inc. may not be used to endorse 18 1.1 dholland * or promote products derived from this software without specific prior 19 1.1 dholland * written permission. 20 1.1 dholland * 21 1.1 dholland * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 22 1.1 dholland * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 25 1.1 dholland * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 1.1 dholland * THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 dholland * 33 1.1 dholland */ 34 1.1 dholland 35 1.1 dholland /* run.c -- routines to interact with other programs. */ 36 1.1 dholland 37 1.1 dholland /* XXX write return codes ignored. XXX */ 38 1.1 dholland 39 1.1 dholland #include <errno.h> 40 1.1 dholland #include <stdio.h> 41 1.1 dholland #include <stdarg.h> 42 1.1 dholland #include <stdlib.h> 43 1.1 dholland #include <unistd.h> 44 1.1 dholland #include <fcntl.h> 45 1.1 dholland #include <curses.h> 46 1.1 dholland #include <termios.h> 47 1.1 dholland #include <dirent.h> 48 1.1 dholland #include <util.h> 49 1.1 dholland #include <signal.h> 50 1.1 dholland #include <err.h> 51 1.1 dholland #include <sys/ioctl.h> 52 1.1 dholland #include <sys/types.h> 53 1.1 dholland #include <sys/wait.h> 54 1.1 dholland #include <sys/stat.h> 55 1.1 dholland #include "defs.h" 56 1.1 dholland 57 1.1 dholland #include "menu_defs.h" 58 1.1 dholland #include "msg_defs.h" 59 1.1 dholland 60 1.1 dholland #define MAXBUF 256 61 1.1 dholland 62 1.6 martin #if defined(DEBUG) && defined(DEBUG_SYSTEM) 63 1.6 martin static inline int 64 1.6 martin Xsystem(const char *y) 65 1.6 martin { 66 1.6 martin printf ("%s\n", y); 67 1.6 martin return 0; 68 1.6 martin } 69 1.1 dholland #else 70 1.1 dholland #define Xsystem(y) system(y) 71 1.1 dholland #endif 72 1.1 dholland 73 1.1 dholland /* 74 1.1 dholland * local prototypes 75 1.1 dholland */ 76 1.1 dholland int log_flip (menudesc *, void *); 77 1.1 dholland static int script_flip (menudesc *, void *); 78 1.1 dholland 79 1.1 dholland #define BUFSIZE 4096 80 1.1 dholland 81 1.1 dholland menu_ent logmenu [2] = { 82 1.12 christos { .opt_action=log_flip}, 83 1.12 christos { .opt_action=script_flip} 84 1.7 martin }; 85 1.1 dholland 86 1.1 dholland static void 87 1.1 dholland log_menu_label(menudesc *m, int opt, void *arg) 88 1.1 dholland { 89 1.1 dholland wprintw(m->mw, "%s: %s", 90 1.1 dholland msg_string(opt ? MSG_Scripting : MSG_Logging), 91 1.1 dholland msg_string((opt ? script != NULL : logfp != NULL) ? 92 1.1 dholland MSG_On : MSG_Off)); 93 1.1 dholland } 94 1.1 dholland 95 1.1 dholland void 96 1.1 dholland do_logging(void) 97 1.1 dholland { 98 1.1 dholland int menu_no; 99 1.1 dholland 100 1.1 dholland menu_no = new_menu(MSG_Logging_functions, logmenu, 2, -1, 12, 101 1.1 dholland 0, 20, MC_SCROLL, NULL, log_menu_label, NULL, 102 1.13 martin MSG_Pick_an_option, MSG_exit_menu_generic); 103 1.1 dholland 104 1.1 dholland if (menu_no < 0) { 105 1.1 dholland (void)fprintf(stderr, "Dynamic menu creation failed.\n"); 106 1.1 dholland if (logfp) 107 1.1 dholland (void)fprintf(logfp, "Dynamic menu creation failed.\n"); 108 1.1 dholland exit(EXIT_FAILURE); 109 1.1 dholland } 110 1.1 dholland process_menu(menu_no, NULL); 111 1.1 dholland free_menu(menu_no); 112 1.1 dholland } 113 1.1 dholland 114 1.1 dholland int 115 1.1 dholland /*ARGSUSED*/ 116 1.1 dholland log_flip(menudesc *m, void *arg) 117 1.1 dholland { 118 1.1 dholland time_t tloc; 119 1.1 dholland 120 1.1 dholland (void)time(&tloc); 121 1.1 dholland if (logfp) { 122 1.3 christos fprintf(logfp, "Log ended at: %s\n", safectime(&tloc)); 123 1.1 dholland fflush(logfp); 124 1.1 dholland fclose(logfp); 125 1.1 dholland logfp = NULL; 126 1.1 dholland } else { 127 1.1 dholland logfp = fopen("/tmp/sysinst.log", "a"); 128 1.1 dholland if (logfp != NULL) { 129 1.1 dholland fprintf(logfp, 130 1.3 christos "Log started at: %s\n", safectime(&tloc)); 131 1.1 dholland fflush(logfp); 132 1.1 dholland } else { 133 1.2 martin if (mainwin) { 134 1.11 christos msg_fmt_display(MSG_openfail, "%s%s", 135 1.11 christos "log file", strerror(errno)); 136 1.2 martin } else { 137 1.2 martin fprintf(stderr, "could not open /tmp/sysinst.log: %s\n", 138 1.2 martin strerror(errno)); 139 1.2 martin exit(1); 140 1.2 martin } 141 1.1 dholland } 142 1.1 dholland } 143 1.1 dholland return(0); 144 1.1 dholland } 145 1.1 dholland 146 1.1 dholland static int 147 1.1 dholland /*ARGSUSED*/ 148 1.1 dholland script_flip(menudesc *m, void *arg) 149 1.1 dholland { 150 1.1 dholland time_t tloc; 151 1.1 dholland 152 1.1 dholland (void)time(&tloc); 153 1.1 dholland if (script) { 154 1.1 dholland scripting_fprintf(NULL, "# Script ended at: %s\n", 155 1.3 christos safectime(&tloc)); 156 1.1 dholland fflush(script); 157 1.1 dholland fclose(script); 158 1.1 dholland script = NULL; 159 1.1 dholland } else { 160 1.1 dholland script = fopen("/tmp/sysinst.sh", "w"); 161 1.1 dholland if (script != NULL) { 162 1.1 dholland scripting_fprintf(NULL, "#!/bin/sh\n"); 163 1.1 dholland scripting_fprintf(NULL, "# Script started at: %s\n", 164 1.3 christos safectime(&tloc)); 165 1.1 dholland fflush(script); 166 1.1 dholland } else { 167 1.11 christos msg_fmt_display(MSG_openfail, "%s%s", "script file", 168 1.1 dholland strerror(errno)); 169 1.1 dholland } 170 1.1 dholland } 171 1.1 dholland return(0); 172 1.1 dholland } 173 1.1 dholland 174 1.1 dholland int 175 1.1 dholland collect(int kind, char **buffer, const char *name, ...) 176 1.1 dholland { 177 1.1 dholland size_t nbytes; /* Number of bytes in buffer. */ 178 1.1 dholland size_t fbytes; /* Number of bytes in file. */ 179 1.14 martin size_t abytes; /* allocated size of buffer */ 180 1.1 dholland struct stat st; /* stat information. */ 181 1.1 dholland int ch; 182 1.1 dholland FILE *f; 183 1.1 dholland char fileorcmd[STRSIZE]; 184 1.1 dholland va_list ap; 185 1.1 dholland char *cp; 186 1.1 dholland 187 1.1 dholland va_start(ap, name); 188 1.1 dholland vsnprintf(fileorcmd, sizeof fileorcmd, name, ap); 189 1.1 dholland va_end(ap); 190 1.1 dholland 191 1.1 dholland if (kind == T_FILE) { 192 1.1 dholland /* Get the file information. */ 193 1.1 dholland if (stat(fileorcmd, &st)) { 194 1.1 dholland *buffer = NULL; 195 1.1 dholland return -1; 196 1.1 dholland } 197 1.1 dholland fbytes = (size_t)st.st_size; 198 1.1 dholland 199 1.1 dholland /* Open the file. */ 200 1.1 dholland f = fopen(fileorcmd, "r"); 201 1.1 dholland if (f == NULL) { 202 1.14 martin if (logfp) 203 1.14 martin fprintf(logfp, "%s: failed to open %s\n", 204 1.14 martin __func__, fileorcmd); 205 1.1 dholland *buffer = NULL; 206 1.1 dholland return -1; 207 1.1 dholland } 208 1.1 dholland } else { 209 1.1 dholland /* Open the program. */ 210 1.1 dholland f = popen(fileorcmd, "r"); 211 1.1 dholland if (f == NULL) { 212 1.14 martin if (logfp) 213 1.14 martin fprintf(logfp, "%s: failed to open %s\n", 214 1.14 martin __func__, fileorcmd); 215 1.1 dholland *buffer = NULL; 216 1.1 dholland return -1; 217 1.1 dholland } 218 1.14 martin fbytes = 0; 219 1.1 dholland } 220 1.1 dholland 221 1.1 dholland if (fbytes == 0) 222 1.14 martin abytes = BUFSIZE; 223 1.14 martin else 224 1.14 martin abytes = fbytes+1; 225 1.1 dholland 226 1.1 dholland /* Allocate the buffer size. */ 227 1.14 martin *buffer = cp = malloc(abytes); 228 1.1 dholland if (!cp) 229 1.1 dholland nbytes = -1; 230 1.1 dholland else { 231 1.1 dholland /* Read the buffer. */ 232 1.1 dholland nbytes = 0; 233 1.14 martin while ((ch = fgetc(f)) != EOF) { 234 1.14 martin if (nbytes >= abytes-1) { 235 1.14 martin if (fbytes > 0 || abytes >= 512*BUFSIZE) { 236 1.14 martin free(cp); 237 1.14 martin *buffer = cp = NULL; 238 1.14 martin nbytes = -1; 239 1.14 martin break; 240 1.14 martin } 241 1.14 martin abytes *= 2; 242 1.14 martin *buffer = cp = realloc(cp, abytes); 243 1.14 martin if (!cp) { 244 1.14 martin nbytes = -1; 245 1.14 martin break; 246 1.14 martin } 247 1.14 martin 248 1.14 martin } 249 1.1 dholland cp[nbytes++] = ch; 250 1.14 martin } 251 1.14 martin if (cp) 252 1.14 martin cp[nbytes] = 0; 253 1.1 dholland } 254 1.1 dholland 255 1.1 dholland if (kind == T_FILE) 256 1.1 dholland fclose(f); 257 1.1 dholland else 258 1.1 dholland pclose(f); 259 1.1 dholland 260 1.14 martin if (nbytes <= 0 && logfp) 261 1.14 martin fprintf(logfp, "%s: failed for %s\n", __func__, fileorcmd); 262 1.14 martin 263 1.1 dholland return nbytes; 264 1.1 dholland } 265 1.1 dholland 266 1.1 dholland 267 1.1 dholland /* 268 1.1 dholland * system(3), but with a debug wrapper. 269 1.1 dholland * use only for curses sub-applications. 270 1.1 dholland */ 271 1.1 dholland int 272 1.1 dholland do_system(const char *execstr) 273 1.1 dholland { 274 1.1 dholland register int ret; 275 1.1 dholland 276 1.1 dholland /* 277 1.1 dholland * The following may be more than one function call. Can't just 278 1.1 dholland * "return Xsystem (command);" 279 1.1 dholland */ 280 1.1 dholland 281 1.1 dholland ret = Xsystem(execstr); 282 1.1 dholland return (ret); 283 1.1 dholland 284 1.1 dholland } 285 1.1 dholland 286 1.1 dholland static char ** 287 1.16 rillig make_argv(char *cmd) 288 1.1 dholland { 289 1.1 dholland char **argv = 0; 290 1.1 dholland int argc = 0; 291 1.16 rillig char *cp, *dp, *fn; 292 1.1 dholland DIR *dir; 293 1.1 dholland struct dirent *dirent; 294 1.1 dholland int l; 295 1.1 dholland 296 1.1 dholland for (; *cmd != 0; cmd = cp + strspn(cp, " "), argc++) { 297 1.1 dholland if (*cmd == '\'') 298 1.1 dholland cp = strchr(++cmd, '\''); 299 1.1 dholland else 300 1.1 dholland cp = strchr(cmd, ' '); 301 1.1 dholland if (cp == NULL) 302 1.1 dholland cp = strchr(cmd, 0); 303 1.1 dholland argv = realloc(argv, (argc + 2) * sizeof *argv); 304 1.1 dholland if (argv == NULL) 305 1.1 dholland err(1, "realloc(argv) for %s", cmd); 306 1.1 dholland asprintf(argv + argc, "%.*s", (int)(cp - cmd), cmd); 307 1.1 dholland /* Hack to remove %xx encoded ftp password */ 308 1.1 dholland dp = strstr(cmd, ":%"); 309 1.1 dholland if (dp != NULL && dp < cp) { 310 1.1 dholland for (fn = dp + 4; *fn == '%'; fn += 3) 311 1.1 dholland continue; 312 1.1 dholland if (*fn == '@') 313 1.1 dholland memset(dp + 1, '*', fn - dp - 1); 314 1.1 dholland } 315 1.1 dholland if (*cp == '\'') 316 1.1 dholland cp++; 317 1.1 dholland if (cp[-1] != '*') 318 1.1 dholland continue; 319 1.1 dholland /* do limited filename globbing */ 320 1.1 dholland dp = argv[argc]; 321 1.1 dholland fn = strrchr(dp, '/'); 322 1.1 dholland if (fn != NULL) 323 1.1 dholland *fn = 0; 324 1.1 dholland dir = opendir(dp); 325 1.1 dholland if (fn != NULL) 326 1.1 dholland *fn++ = '/'; 327 1.1 dholland else 328 1.1 dholland fn = dp; 329 1.1 dholland if (dir == NULL) 330 1.1 dholland continue; 331 1.1 dholland l = strlen(fn) - 1; 332 1.1 dholland while ((dirent = readdir(dir))) { 333 1.1 dholland if (dirent->d_name[0] == '.') 334 1.1 dholland continue; 335 1.1 dholland if (strncmp(dirent->d_name, fn, l) != 0) 336 1.1 dholland continue; 337 1.1 dholland if (dp != argv[argc]) 338 1.1 dholland argc++; 339 1.1 dholland argv = realloc(argv, (argc + 2) * sizeof *argv); 340 1.1 dholland if (argv == NULL) 341 1.1 dholland err(1, "realloc(argv) for %s", cmd); 342 1.1 dholland asprintf(argv + argc, "%.*s%s", (int)(fn - dp), dp, 343 1.1 dholland dirent->d_name); 344 1.1 dholland } 345 1.1 dholland if (dp != argv[argc]) 346 1.1 dholland free(dp); 347 1.1 dholland closedir(dir); 348 1.1 dholland } 349 1.1 dholland argv[argc] = NULL; 350 1.1 dholland return argv; 351 1.1 dholland } 352 1.1 dholland 353 1.1 dholland static void 354 1.1 dholland free_argv(char **argv) 355 1.1 dholland { 356 1.1 dholland char **n, *a; 357 1.1 dholland 358 1.1 dholland for (n = argv; (a = *n++);) 359 1.1 dholland free(a); 360 1.1 dholland free(argv); 361 1.1 dholland } 362 1.1 dholland 363 1.1 dholland static WINDOW * 364 1.1 dholland show_cmd(const char *scmd, struct winsize *win) 365 1.1 dholland { 366 1.1 dholland WINDOW *actionwin; 367 1.1 dholland int nrow; 368 1.1 dholland 369 1.1 dholland wclear(stdscr); 370 1.1 dholland clearok(stdscr, 1); 371 1.1 dholland touchwin(stdscr); 372 1.1 dholland refresh(); 373 1.1 dholland 374 1.1 dholland mvaddstr(0, 4, msg_string(MSG_Status)); 375 1.1 dholland standout(); 376 1.1 dholland addstr(msg_string(MSG_Running)); 377 1.1 dholland standend(); 378 1.1 dholland mvaddstr(1, 4, msg_string(MSG_Command)); 379 1.1 dholland standout(); 380 1.1 dholland printw("%s", scmd); 381 1.1 dholland standend(); 382 1.1 dholland addstr("\n\n"); 383 1.10 martin hline(0, win->ws_col); 384 1.1 dholland refresh(); 385 1.1 dholland 386 1.1 dholland nrow = getcury(stdscr) + 1; 387 1.1 dholland 388 1.1 dholland actionwin = subwin(stdscr, win->ws_row - nrow, win->ws_col, nrow, 0); 389 1.1 dholland if (actionwin == NULL) { 390 1.1 dholland fprintf(stderr, "sysinst: failed to allocate output window.\n"); 391 1.1 dholland exit(1); 392 1.1 dholland } 393 1.1 dholland scrollok(actionwin, TRUE); 394 1.1 dholland if (has_colors()) { 395 1.1 dholland wbkgd(actionwin, getbkgd(stdscr)); 396 1.1 dholland wattrset(actionwin, getattrs(stdscr)); 397 1.1 dholland } 398 1.1 dholland 399 1.1 dholland wmove(actionwin, 0, 0); 400 1.1 dholland wrefresh(actionwin); 401 1.1 dholland 402 1.1 dholland return actionwin; 403 1.1 dholland } 404 1.1 dholland 405 1.1 dholland /* 406 1.1 dholland * launch a program inside a subwindow, and report its return status when done 407 1.1 dholland */ 408 1.1 dholland static int 409 1.1 dholland launch_subwin(WINDOW **actionwin, char **args, struct winsize *win, int flags, 410 1.1 dholland const char *scmd, const char **errstr) 411 1.1 dholland { 412 1.1 dholland int n, i; 413 1.1 dholland int selectfailed; 414 1.1 dholland int status, master, slave; 415 1.1 dholland fd_set active_fd_set, read_fd_set; 416 1.1 dholland pid_t child, pid; 417 1.1 dholland char ibuf[MAXBUF]; 418 1.1 dholland char pktdata; 419 1.1 dholland char *cp, *ncp; 420 1.1 dholland struct termios rtt, tt; 421 1.1 dholland struct timeval tmo; 422 1.1 dholland static int do_tioccons = 2; 423 1.1 dholland 424 1.1 dholland (void)tcgetattr(STDIN_FILENO, &tt); 425 1.1 dholland if (openpty(&master, &slave, NULL, &tt, win) == -1) { 426 1.1 dholland *errstr = "openpty() failed"; 427 1.1 dholland return -1; 428 1.1 dholland } 429 1.1 dholland 430 1.1 dholland rtt = tt; 431 1.1 dholland 432 1.1 dholland /* ignore tty signals until we're done with subprocess setup */ 433 1.1 dholland ttysig_ignore = 1; 434 1.1 dholland ioctl(master, TIOCPKT, &ttysig_ignore); 435 1.1 dholland 436 1.1 dholland /* Try to get console output into our pipe */ 437 1.1 dholland if (do_tioccons) { 438 1.1 dholland if (ioctl(slave, TIOCCONS, &do_tioccons) == 0 439 1.1 dholland && do_tioccons == 2) { 440 1.1 dholland /* test our output - we don't want it grabbed */ 441 1.1 dholland write(1, " \b", 2); 442 1.1 dholland ioctl(master, FIONREAD, &do_tioccons); 443 1.1 dholland if (do_tioccons != 0) { 444 1.1 dholland do_tioccons = 0; 445 1.1 dholland ioctl(slave, TIOCCONS, &do_tioccons); 446 1.1 dholland } else 447 1.1 dholland do_tioccons = 1; 448 1.1 dholland } 449 1.1 dholland } 450 1.1 dholland 451 1.1 dholland if (logfp) 452 1.1 dholland fflush(logfp); 453 1.1 dholland if (script) 454 1.1 dholland fflush(script); 455 1.1 dholland 456 1.1 dholland child = fork(); 457 1.1 dholland switch (child) { 458 1.1 dholland case -1: 459 1.1 dholland ttysig_ignore = 0; 460 1.1 dholland refresh(); 461 1.1 dholland *errstr = "fork() failed"; 462 1.1 dholland return -1; 463 1.1 dholland case 0: /* child */ 464 1.1 dholland (void)close(STDIN_FILENO); 465 1.1 dholland /* silently stop curses */ 466 1.1 dholland (void)close(STDOUT_FILENO); 467 1.1 dholland (void)open("/dev/null", O_RDWR, 0); 468 1.1 dholland dup2(STDIN_FILENO, STDOUT_FILENO); 469 1.1 dholland endwin(); 470 1.1 dholland (void)close(master); 471 1.1 dholland rtt = tt; 472 1.1 dholland rtt.c_lflag |= (ICANON|ECHO); 473 1.1 dholland (void)tcsetattr(slave, TCSANOW, &rtt); 474 1.1 dholland login_tty(slave); 475 1.1 dholland if (logfp) { 476 1.1 dholland fprintf(logfp, "executing: %s\n", scmd); 477 1.1 dholland fclose(logfp); 478 1.1 dholland logfp = NULL; 479 1.1 dholland } 480 1.1 dholland if (script) { 481 1.1 dholland fprintf(script, "%s\n", scmd); 482 1.1 dholland fclose(script); 483 1.1 dholland script = NULL; 484 1.1 dholland } 485 1.1 dholland if (strcmp(args[0], "cd") == 0 && strcmp(args[2], "&&") == 0) { 486 1.1 dholland target_chdir_or_die(args[1]); 487 1.1 dholland args += 3; 488 1.1 dholland } 489 1.1 dholland if (flags & RUN_XFER_DIR) 490 1.1 dholland target_chdir_or_die(xfer_dir); 491 1.1 dholland /* 492 1.1 dholland * If target_prefix == "", the chroot will fail, but 493 1.1 dholland * that's ok, since we don't need it then. 494 1.1 dholland */ 495 1.1 dholland if (flags & RUN_CHROOT && *target_prefix() 496 1.1 dholland && chroot(target_prefix()) != 0) 497 1.1 dholland warn("chroot(%s) for %s", target_prefix(), *args); 498 1.1 dholland else { 499 1.1 dholland execvp(*args, args); 500 1.1 dholland warn("execvp %s", *args); 501 1.1 dholland } 502 1.1 dholland _exit(EXIT_FAILURE); 503 1.1 dholland // break; /* end of child */ 504 1.1 dholland default: 505 1.1 dholland /* 506 1.1 dholland * parent: we've set up the subprocess. 507 1.1 dholland * forward tty signals to its process group. 508 1.1 dholland */ 509 1.1 dholland ttysig_forward = child; 510 1.1 dholland ttysig_ignore = 0; 511 1.1 dholland break; 512 1.1 dholland } 513 1.1 dholland 514 1.1 dholland /* 515 1.1 dholland * Now loop transferring program output to screen, and keyboard 516 1.1 dholland * input to the program. 517 1.1 dholland */ 518 1.1 dholland 519 1.1 dholland FD_ZERO(&active_fd_set); 520 1.1 dholland FD_SET(master, &active_fd_set); 521 1.1 dholland FD_SET(STDIN_FILENO, &active_fd_set); 522 1.1 dholland 523 1.1 dholland for (selectfailed = 0;;) { 524 1.1 dholland if (selectfailed) { 525 1.1 dholland const char mmsg[] = 526 1.1 dholland "select(2) failed but no child died?"; 527 1.1 dholland if (logfp) 528 1.1 dholland (void)fprintf(logfp, mmsg); 529 1.1 dholland errx(1, mmsg); 530 1.1 dholland } 531 1.1 dholland read_fd_set = active_fd_set; 532 1.4 martin tmo.tv_sec = flags & RUN_SILENT ? 20 : 2; 533 1.1 dholland tmo.tv_usec = 0; 534 1.1 dholland i = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tmo); 535 1.5 martin if (i == 0 && *actionwin == NULL && (flags & RUN_SILENT) == 0) 536 1.1 dholland *actionwin = show_cmd(scmd, win); 537 1.1 dholland if (i < 0) { 538 1.1 dholland if (errno != EINTR) { 539 1.1 dholland warn("select"); 540 1.1 dholland if (logfp) 541 1.1 dholland (void)fprintf(logfp, 542 1.1 dholland "select failure: %s\n", 543 1.1 dholland strerror(errno)); 544 1.1 dholland selectfailed = 1; 545 1.1 dholland } 546 1.1 dholland } else for (i = 0; i < FD_SETSIZE; ++i) { 547 1.1 dholland if (!FD_ISSET(i, &read_fd_set)) 548 1.1 dholland continue; 549 1.1 dholland n = read(i, ibuf, sizeof ibuf - 1); 550 1.1 dholland if (n <= 0) { 551 1.1 dholland if (n < 0) 552 1.1 dholland warn("read"); 553 1.1 dholland continue; 554 1.1 dholland } 555 1.1 dholland ibuf[n] = 0; 556 1.1 dholland cp = ibuf; 557 1.1 dholland if (i == STDIN_FILENO) { 558 1.1 dholland (void)write(master, ibuf, (size_t)n); 559 1.1 dholland if (!(rtt.c_lflag & ECHO)) 560 1.1 dholland continue; 561 1.1 dholland } else { 562 1.1 dholland pktdata = ibuf[0]; 563 1.1 dholland if (pktdata != 0) { 564 1.1 dholland if (pktdata & TIOCPKT_IOCTL) 565 1.1 dholland memcpy(&rtt, ibuf, sizeof(rtt)); 566 1.1 dholland continue; 567 1.1 dholland } 568 1.1 dholland cp += 1; 569 1.1 dholland } 570 1.1 dholland if (*cp == 0 || flags & RUN_SILENT) 571 1.1 dholland continue; 572 1.1 dholland if (logfp) { 573 1.1 dholland fprintf(logfp, "%s", cp); 574 1.1 dholland fflush(logfp); 575 1.1 dholland } 576 1.1 dholland if (*actionwin == NULL) 577 1.1 dholland *actionwin = show_cmd(scmd, win); 578 1.1 dholland /* posix curses is braindead wrt \r\n so... */ 579 1.1 dholland for (ncp = cp; (ncp = strstr(ncp, "\r\n")); ncp += 2) { 580 1.1 dholland ncp[0] = '\n'; 581 1.1 dholland ncp[1] = '\r'; 582 1.1 dholland } 583 1.1 dholland waddstr(*actionwin, cp); 584 1.1 dholland wrefresh(*actionwin); 585 1.1 dholland } 586 1.1 dholland pid = wait4(child, &status, WNOHANG, 0); 587 1.1 dholland if (pid == child && (WIFEXITED(status) || WIFSIGNALED(status))) 588 1.1 dholland break; 589 1.1 dholland } 590 1.1 dholland close(master); 591 1.1 dholland close(slave); 592 1.1 dholland if (logfp) 593 1.1 dholland fflush(logfp); 594 1.1 dholland 595 1.1 dholland /* from here on out, we take tty signals ourselves */ 596 1.1 dholland ttysig_forward = 0; 597 1.1 dholland 598 1.1 dholland reset_prog_mode(); 599 1.1 dholland 600 1.1 dholland if (WIFEXITED(status)) { 601 1.1 dholland *errstr = msg_string(MSG_Command_failed); 602 1.1 dholland return WEXITSTATUS(status); 603 1.1 dholland } 604 1.1 dholland if (WIFSIGNALED(status)) { 605 1.1 dholland *errstr = msg_string(MSG_Command_ended_on_signal); 606 1.1 dholland return WTERMSIG(status); 607 1.1 dholland } 608 1.1 dholland return 0; 609 1.1 dholland } 610 1.1 dholland 611 1.1 dholland /* 612 1.1 dholland * generic program runner. 613 1.1 dholland * flags: 614 1.1 dholland * RUN_DISPLAY display command name and output 615 1.1 dholland * RUN_FATAL program errors are fatal 616 1.1 dholland * RUN_CHROOT chroot to target before the exec 617 1.1 dholland * RUN_FULLSCREEN display output only 618 1.1 dholland * RUN_SILENT do not display program output 619 1.1 dholland * RUN_ERROR_OK don't wait for key if program fails 620 1.1 dholland * RUN_PROGRESS don't wait for key if program has output 621 1.1 dholland * If both RUN_DISPLAY and RUN_SILENT are clear then the program name will 622 1.1 dholland * be displayed as soon as it generates output. 623 1.1 dholland * Steps are taken to collect console messages, they will be interleaved 624 1.1 dholland * into the program output - but not upset curses. 625 1.1 dholland */ 626 1.1 dholland 627 1.1 dholland int 628 1.1 dholland run_program(int flags, const char *cmd, ...) 629 1.1 dholland { 630 1.1 dholland va_list ap; 631 1.1 dholland struct winsize win; 632 1.1 dholland int ret; 633 1.1 dholland WINDOW *actionwin = NULL; 634 1.1 dholland char *scmd; 635 1.1 dholland char **args; 636 1.1 dholland const char *errstr = NULL; 637 1.1 dholland 638 1.1 dholland va_start(ap, cmd); 639 1.1 dholland vasprintf(&scmd, cmd, ap); 640 1.1 dholland va_end(ap); 641 1.1 dholland if (scmd == NULL) 642 1.1 dholland err(1, "vasprintf(&scmd, \"%s\", ...)", cmd); 643 1.1 dholland 644 1.1 dholland args = make_argv(scmd); 645 1.1 dholland 646 1.1 dholland /* Make curses save tty settings */ 647 1.1 dholland def_prog_mode(); 648 1.1 dholland 649 1.1 dholland (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win); 650 1.1 dholland /* Apparently, we sometimes get 0x0 back, and that's not useful */ 651 1.1 dholland if (win.ws_row == 0) 652 1.1 dholland win.ws_row = 24; 653 1.1 dholland if (win.ws_col == 0) 654 1.1 dholland win.ws_col = 80; 655 1.1 dholland 656 1.1 dholland if ((flags & RUN_DISPLAY) != 0) { 657 1.15 martin if (flags & RUN_STDSCR) { 658 1.15 martin actionwin = stdscr; 659 1.15 martin wmove(stdscr, msg_row()+2, 0); 660 1.15 martin wrefresh(stdscr); 661 1.15 martin } else if (flags & RUN_FULLSCREEN) { 662 1.1 dholland wclear(stdscr); 663 1.1 dholland clearok(stdscr, 1); 664 1.1 dholland touchwin(stdscr); 665 1.1 dholland refresh(); 666 1.1 dholland actionwin = stdscr; 667 1.15 martin } else { 668 1.1 dholland actionwin = show_cmd(scmd, &win); 669 1.15 martin } 670 1.1 dholland } else 671 1.1 dholland win.ws_row -= 4; 672 1.1 dholland 673 1.1 dholland ret = launch_subwin(&actionwin, args, &win, flags, scmd, &errstr); 674 1.1 dholland fpurge(stdin); 675 1.1 dholland 676 1.1 dholland /* If the command failed, show command name */ 677 1.1 dholland if (actionwin == NULL && ret != 0 && !(flags & RUN_ERROR_OK)) 678 1.1 dholland actionwin = show_cmd(scmd, &win); 679 1.1 dholland 680 1.1 dholland if (actionwin != NULL) { 681 1.1 dholland int y, x; 682 1.1 dholland getyx(actionwin, y, x); 683 1.1 dholland if (actionwin != stdscr) 684 1.1 dholland mvaddstr(0, 4, msg_string(MSG_Status)); 685 1.1 dholland if (ret != 0) { 686 1.1 dholland if (actionwin == stdscr && x != 0) 687 1.1 dholland addstr("\n"); 688 1.1 dholland x = 1; /* force newline below */ 689 1.1 dholland standout(); 690 1.1 dholland addstr(errstr); 691 1.1 dholland standend(); 692 1.1 dholland } else { 693 1.1 dholland if (actionwin != stdscr) { 694 1.1 dholland standout(); 695 1.1 dholland addstr(msg_string(MSG_Finished)); 696 1.1 dholland standend(); 697 1.1 dholland } 698 1.1 dholland } 699 1.1 dholland clrtoeol(); 700 1.1 dholland refresh(); 701 1.1 dholland if ((ret != 0 && !(flags & RUN_ERROR_OK)) || 702 1.1 dholland (y + x != 0 && !(flags & RUN_PROGRESS))) { 703 1.1 dholland if (actionwin != stdscr) 704 1.1 dholland move(getbegy(actionwin) - 2, 5); 705 1.1 dholland else if (x != 0) 706 1.1 dholland addstr("\n"); 707 1.1 dholland addstr(msg_string(MSG_Hit_enter_to_continue)); 708 1.1 dholland refresh(); 709 1.1 dholland getchar(); 710 1.1 dholland } else { 711 1.1 dholland if (y + x != 0) { 712 1.1 dholland /* give user 1 second to see messages */ 713 1.1 dholland refresh(); 714 1.1 dholland sleep(1); 715 1.1 dholland } 716 1.1 dholland } 717 1.1 dholland } 718 1.1 dholland 719 1.1 dholland /* restore tty setting we saved earlier */ 720 1.1 dholland reset_prog_mode(); 721 1.1 dholland 722 1.1 dholland /* clean things up */ 723 1.1 dholland if (actionwin != NULL) { 724 1.1 dholland if (actionwin != stdscr) 725 1.1 dholland delwin(actionwin); 726 1.1 dholland if (errstr == 0 || !(flags & RUN_NO_CLEAR)) { 727 1.1 dholland wclear(stdscr); 728 1.1 dholland touchwin(stdscr); 729 1.1 dholland clearok(stdscr, 1); 730 1.1 dholland refresh(); 731 1.1 dholland } 732 1.1 dholland } 733 1.1 dholland 734 1.1 dholland free(scmd); 735 1.1 dholland free_argv(args); 736 1.1 dholland 737 1.1 dholland if (ret != 0 && flags & RUN_FATAL) 738 1.1 dholland exit(ret); 739 1.1 dholland return ret; 740 1.1 dholland } 741