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>