Annotation of src/distrib/utils/sysinst/run.c, Revision 1.7
1.7 ! garbled 1: /* $NetBSD: run.c,v 1.6 1998/08/10 02:23:45 perry 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: int do_system __P((const char *cmdstr));
76: char* va_prog_cmdstr __P((char *cmd, va_list ap));
1.7 ! garbled 77: int launch_subwin __P((WINDOW *actionwin, char **args, struct winsize win, int display));
! 78: int log_flip __P((void));
! 79: int script_flip __P((void));
! 80:
! 81: #define BUFSIZE 4096
! 82:
! 83: char log_text[2][30] = {"Logging: Off", "Scripting: Off"};
! 84:
! 85: menu_ent logmenu [2] = {
! 86: { log_text[0], OPT_NOMENU, 0, log_flip},
! 87: { log_text[1], OPT_NOMENU, 0, script_flip} };
! 88:
! 89:
! 90: void
! 91: do_logging(void)
! 92: {
! 93: int menu_no;
! 94:
! 95: menu_no = new_menu (" Logging Functions ", logmenu, 2, 13, 12,
! 96: 0, 55, MC_SCROLL, NULL, NULL, "Pick an option to turn on or off.\n");
! 97:
! 98: if (menu_no < 0) {
! 99: (void)fprintf(stderr, "Dynamic menu creation failed.\n");
! 100: if (logging)
! 101: (void)fprintf(log, "Dynamic menu creation failed.\n");
! 102: exit(EXIT_FAILURE);
! 103: }
! 104: process_menu(menu_no);
! 105: free_menu(menu_no);
! 106: }
! 107:
! 108: int
! 109: log_flip(void)
! 110: {
! 111: time_t tloc;
! 112:
! 113: (void)time(&tloc);
! 114: if (logging == 1) {
! 115: sprintf(log_text[0], "Logging: Off");
! 116: logging = 0;
! 117: fprintf(log, "Log ended at: %s\n", asctime(localtime(&tloc)));
! 118: fflush(log);
! 119: fclose(log);
! 120: } else {
! 121: sprintf(log_text[0], "Logging: On");
! 122: logging = 1;
! 123: log = fopen("sysinst.log", "a");
! 124: fprintf(log, "Log started at: %s\n", asctime(localtime(&tloc)));
! 125: fflush(log);
! 126: }
! 127: return(0);
! 128: }
1.3 jonathan 129:
1.7 ! garbled 130: int
! 131: script_flip(void)
! 132: {
! 133: time_t tloc;
1.3 jonathan 134:
1.7 ! garbled 135: (void)time(&tloc);
! 136: if (scripting == 1) {
! 137: sprintf(log_text[1], "Scripting: Off");
! 138: scripting = 0;
! 139: fprintf(script, "# Script ended at: %s\n", asctime(localtime(&tloc)));
! 140: fflush(script);
! 141: fclose(script);
! 142: } else {
! 143: sprintf(log_text[1], "Scripting: On");
! 144: scripting = 1;
! 145: script = fopen("sysinst.sh", "w");
! 146: fprintf(script, "#!/bin/sh\n");
! 147: fprintf(script, "# Script started at: %s\n", asctime(localtime(&tloc)));
! 148: fflush(script);
! 149: }
! 150: return(0);
! 151: }
1.1 phil 152:
153: int
1.5 mrg 154: collect(int kind, char **buffer, const char *name, ...)
1.1 phil 155: {
156: size_t nbytes; /* Number of bytes in buffer. */
157: size_t fbytes; /* Number of bytes in file. */
158: struct stat st; /* stat information. */
159: int ch;
160: FILE *f;
161: char fileorcmd [STRSIZE];
162: va_list ap;
163:
1.5 mrg 164: va_start(ap, name);
165: vsnprintf(fileorcmd, STRSIZE, name, ap);
166: va_end(ap);
1.1 phil 167:
168: if (kind == T_FILE) {
169: /* Get the file information. */
1.5 mrg 170: if (stat(fileorcmd, &st)) {
1.1 phil 171: *buffer = NULL;
172: return -1;
173: }
174: fbytes = (size_t)st.st_size;
175:
176: /* Open the file. */
1.5 mrg 177: f = fopen(fileorcmd, "r");
1.1 phil 178: if (f == NULL) {
179: *buffer = NULL;
180: return -1;
181: }
182: } else {
183: /* Open the program. */
1.5 mrg 184: f = popen(fileorcmd, "r");
1.1 phil 185: if (f == NULL) {
186: *buffer = NULL;
187: return -1;
188: }
189: fbytes = BUFSIZE;
190: }
191:
192: if (fbytes == 0)
193: fbytes = BUFSIZE;
194:
195: /* Allocate the buffer size. */
1.5 mrg 196: *buffer = (char *)malloc(fbytes + 1);
1.1 phil 197: if (!*buffer)
198: return -1;
199:
200: /* Read the buffer. */
201: nbytes = 0;
202: while (nbytes < fbytes && (ch = fgetc(f)) != EOF)
203: (*buffer)[nbytes++] = ch;
204:
205: (*buffer)[nbytes] = 0;
206:
207: if (kind == T_FILE)
208: fclose(f);
209: else
210: pclose(f);
211:
212: return nbytes;
213: }
214:
215:
1.3 jonathan 216: /*
217: * system(3), but with a debug wrapper.
1.7 ! garbled 218: * use only for curses sub-applications.
1.3 jonathan 219: */
1.5 mrg 220: int
221: do_system(execstr)
222: const char *execstr;
1.3 jonathan 223: {
224: register int ret;
225:
1.5 mrg 226: /*
227: * The following may be more than one function call. Can't just
228: * "return Xsystem (command);"
229: */
1.3 jonathan 230:
1.5 mrg 231: ret = Xsystem(execstr);
232: return (ret);
1.3 jonathan 233:
234: }
235:
236: /*
237: * build command tring for do_system() from anonymous args.
238: * XXX return result is in a static buffer.
239: */
1.5 mrg 240: char *
241: va_prog_cmdstr(char *cmd, va_list ap)
1.3 jonathan 242: {
1.5 mrg 243: static char command[STRSIZE];
1.3 jonathan 244:
1.6 perry 245: memset(command, 0, STRSIZE);
1.5 mrg 246: (void)vsnprintf(command, STRSIZE, cmd, ap);
247: return (command);
1.3 jonathan 248: }
1.7 ! garbled 249:
1.3 jonathan 250:
1.5 mrg 251: /*
1.7 ! garbled 252: * launch a program inside a subwindow, and report it's return status when done
1.5 mrg 253: */
1.7 ! garbled 254:
1.5 mrg 255: int
1.7 ! garbled 256: launch_subwin(actionwin, args, win, display)
! 257: WINDOW *actionwin;
! 258: char **args;
! 259: struct winsize win;
! 260: int display;
1.1 phil 261: {
1.7 ! garbled 262: int xcor,ycor;
! 263: int n, i, j;
! 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;
! 294: case 0: {
! 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);
! 323: } break; /* end of child */
! 324: default: break;
! 325: }
! 326: close(dataflow[1]);
! 327: FD_ZERO(&active_fd_set);
! 328: FD_SET(dataflow[0], &active_fd_set);
! 329: FD_SET(STDIN_FILENO, &active_fd_set);
! 330:
! 331: pid = wait4(child, &status, WNOHANG, 0);
! 332: for (;;) {
! 333: read_fd_set = active_fd_set;
! 334: if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) {
! 335: perror("select");
! 336: if (logging)
! 337: (void)fprintf(log, "select failure: %s\n", strerror(errno));
! 338: exit(EXIT_FAILURE);
! 339: }
! 340: for (i = 0; i < FD_SETSIZE; ++i)
! 341: if (FD_ISSET (i, &read_fd_set)) {
! 342: n = read(i, ibuf, MAXBUF);
! 343: if (i == STDIN_FILENO)
! 344: (void)write(master, ibuf, n);
! 345: for (j=0; j < n; j++) {
! 346: if (display) {
! 347: if (ibuf[j] == '\n' || ibuf[j] == '\r') {
! 348: if (ibuf[j] == '\n') {
! 349: getyx(actionwin, ycor, xcor);
! 350: if (ycor + 1 >= actionwin->maxy) {
! 351: scroll(actionwin);
! 352: wmove(actionwin, actionwin->maxy - 1, 1);
! 353: } else
! 354: wmove(actionwin, ycor + 1, 1);
! 355: if (logging)
! 356: fprintf(log, "\n");
! 357: }
! 358: } else {
! 359: getyx(actionwin, ycor, xcor);
! 360: if (xcor == 0)
! 361: wmove(actionwin, ycor, xcor + 1);
! 362: waddch(actionwin, ibuf[j]);
! 363: wrefresh(actionwin);
! 364: if (logging) {
! 365: putc(ibuf[j], log);
! 366: fflush(log);
! 367: }
! 368: }
! 369: } else { /* display is off */
! 370: if (logging) {
! 371: putc(ibuf[j], log);
! 372: fflush(log);
! 373: }
! 374: }
! 375: }
! 376: }
! 377: pid = wait4(child, &status, WNOHANG, 0);
! 378: if (pid == child && (WIFEXITED(status) || WIFSIGNALED(status)))
! 379: break;
! 380: }
! 381: close(dataflow[0]); /* clean up our leaks */
! 382: close(master);
! 383: close(slave);
! 384: if (logging)
! 385: fflush(log);
! 386:
! 387: (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
! 388: if (WIFEXITED(status))
! 389: return(WEXITSTATUS(status));
! 390: else if (WIFSIGNALED(status))
! 391: return(WTERMSIG(status));
! 392: else
! 393: return(0);
1.3 jonathan 394: }
395:
396: /*
1.7 ! garbled 397: * generic program runner. fatal and display can be set to
! 398: * 1 if you wish the output to be displayed, or an error to be
! 399: * fatal.
1.3 jonathan 400: */
1.7 ! garbled 401:
1.5 mrg 402: int
1.7 ! garbled 403: run_prog(int fatal, int display, char *cmd, ...)
1.3 jonathan 404: {
405: va_list ap;
1.7 ! garbled 406: struct winsize win;
1.3 jonathan 407: int ret;
1.7 ! garbled 408: WINDOW *actionwin, *statuswin, *boxwin;
! 409: char buf2[MAXBUF];
! 410: char *command, *p, *args[51], **aps;
! 411:
! 412: va_start(ap,cmd);
! 413: sprintf(buf2,"%s",va_prog_cmdstr(cmd,ap));
! 414: p = buf2;
! 415: command = strdup(buf2);
! 416:
! 417: /* 51 strings and it's blown! */
! 418: for (aps = args; (*aps = strsep(&p, " ")) != NULL;)
! 419: if (**aps != '\0')
! 420: ++aps;
! 421:
! 422: (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
! 423: if (display) {
! 424: statuswin = subwin(stdscr, win.ws_row, win.ws_col, 0, 0);
! 425: boxwin = subwin(statuswin, win.ws_row - 3, win.ws_col, 3, 0);
! 426: actionwin = subwin(statuswin, win.ws_row - 5, win.ws_col - 3, 4, 1);
! 427: scrollok(actionwin, TRUE);
! 428:
! 429: win.ws_col -= 3;
! 430: win.ws_row -= 5;
! 431:
! 432: wclear(statuswin);
! 433: wrefresh(statuswin);
! 434:
! 435: wclear(boxwin);
! 436: box(boxwin, 124, 45);
! 437: wrefresh(boxwin);
! 438:
! 439: wclear(actionwin);
! 440: wrefresh(actionwin);
! 441:
! 442: wmove(statuswin, 0 , 5);
! 443: waddstr(statuswin, "Status: ");
! 444: wstandout(statuswin);
! 445: waddstr(statuswin, "Running");
! 446: wstandend(statuswin);
! 447:
! 448: wmove(statuswin, 1, 4);
! 449: waddstr(statuswin, "Command: ");
! 450: wstandout(statuswin);
! 451: waddstr(statuswin, command);
! 452: wstandend(statuswin);
! 453: wrefresh(statuswin);
! 454:
! 455: ret = launch_subwin(actionwin, args, win, 1);
! 456:
! 457: wmove(statuswin, 0, 13);
! 458: waddstr(statuswin, " ");
! 459: wmove(statuswin, 0, 13);
! 460: wstandout(statuswin);
! 461: if (ret != 0)
! 462: waddstr(statuswin, "Failed");
! 463: else
! 464: waddstr(statuswin, "Finished");
! 465: wstandend(statuswin);
! 466: wmove(statuswin, 2, 5);
! 467: waddstr(statuswin, "Press any key to continue");
! 468: wrefresh(statuswin);
! 469: (void)getchar();
! 470:
! 471: /* clean things up */
! 472: wclear(actionwin);
! 473: wrefresh(actionwin);
! 474: delwin(actionwin);
! 475: wclear(boxwin);
! 476: wrefresh(boxwin);
! 477: delwin(boxwin);
! 478: wclear(statuswin);
! 479: wrefresh(statuswin);
! 480: delwin(statuswin);
! 481: refresh();
! 482: } else { /* display */
! 483: ret = launch_subwin(NULL, args, win, 0);
! 484: }
1.5 mrg 485: va_end(ap);
1.7 ! garbled 486: if (fatal)
1.5 mrg 487: exit(ret);
1.7 ! garbled 488: else
! 489: return(ret);
1.3 jonathan 490: }
CVSweb <webmaster@jp.NetBSD.org>