home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************/
- /* Copyright 1988 by Chuck Musciano and Harris Corporation */
- /* */
- /* Permission to use, copy, modify, and distribute this software */
- /* and its documentation for any purpose and without fee is */
- /* hereby granted, provided that the above copyright notice */
- /* appear in all copies and that both that copyright notice and */
- /* this permission notice appear in supporting documentation, and */
- /* that the name of Chuck Musciano and Harris Corporation not be */
- /* used in advertising or publicity pertaining to distribution */
- /* of the software without specific, written prior permission. */
- /* Chuck Musciano and Harris Corporation make no representations */
- /* about the suitability of this software for any purpose. It is */
- /* provided "as is" without express or implied warranty. */
- /************************************************************************/
-
-
- /************************************************************************/
- /* */
- /* contool: capture and display timestamped console i/o */
- /* */
- /************************************************************************/
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #include <suntool/sunview.h>
- #include <suntool/textsw.h>
- #include <suntool/icon_load.h>
-
- /**************** Site dependent parameters ****************************/
-
- /* Where the default contool icons are kept. !Must end in '/'! */
-
- #if !defined(ICON_DIRECTORY)
- #define ICON_DIRECTORY "./icons/"
- #endif
-
- /* The default icon names. Alternate sets are shown, and you might want
- to try these instead of the default set by uncommenting the desired set. */
-
- /* This set gives a blinking stop sign when messages arrive. */
- #define GOOD_ICON "contool.icon"
- #define BAD_ICON "stopsign.icon"
- #define INVERSE_ICON "stopsign_inv.icon"
-
- /* This set gives a terminal, labelled "Console", in a box. The screen
- flashes when messages arrive. */
- /* #define GOOD_ICON "contool.icon" */
- /* #define BAD_ICON "contool.icon" */
- /* #define INVERSE_ICON "contool_bad.icon" */
-
- /* This set gives a terminal, without a box. Again, the screen flashes
- when messages arrive. */
- /* #define GOOD_ICON "console1.icon" */
- /* #define BAD_ICON "console1_bad.icon" */
- /* #define INVERSE_ICON "console1_flash.icon" */
-
- /*************** End of site dependencies ******************************/
-
- #define TOOL_LABEL "<< Console Tool 2.1 >>"
-
- #define MAX_FILTERS 64
-
- #define strsave(s) ((char *) strcpy(malloc(strlen(s) + 1), s))
-
- #define BEEP_COUNT 3
- #define TS_INTERVAL 60
-
- #define NORMAL_MODE 1
- #define QUIET_MODE 2
- #define IGNORE_MODE 3
-
- #define TEXT_SIZE_LIMIT 32768
- #define TEXT_SIZE_FUZZ 1024
- #define TEXT_DELETE_SIZE 1024
-
- #define INPUT_BUFFER_SIZE 4096
-
- /*************** Stuff that regexp(3) needs ****************************/
-
- static regexp_error();
-
- #define INIT register char *expbuf = ep, *sp = instring;
- #define GETC() (*sp++)
- #define PEEKC() (*sp)
- #define UNGETC(c) (--sp)
- #define RETURN(p) {bcopy(expbuf, sp = (char *) malloc(p - expbuf), p - expbuf); return(sp);}
- #define ERROR(val) {regexp_error(val, instring); return(NULL);}
-
- #include <regexp.h>
-
- /*************** Things that contool uses ******************************/
-
- struct f_rec {char *start;
- char *end;
- int scircf;
- int ecircf;
- int mode;
- };
-
- char *ct_usage = "usage: contool [-b <file>] [-c <file>] [-d <size>] [-f <file>] [-g <file>] [-l <size>] [-o <logfile>] [-p] [-r <amt>] [-s <amt>]\n";
-
- static Frame bf;
- static Textsw text;
- static Icon good, bad, inverse;
- static struct pixrect *good_pr, *bad_pr, *inv_pr;
- static Menu_item stop_blink;
- static Rect open_rect;
-
- static char bad_icon[256]; /* -b */
- static char filter_path[256]; /* -c */
- static int delete_amt = TEXT_DELETE_SIZE; /* -d */
- static char inv_icon[256]; /* -f */
- static char good_icon[256]; /* -g */
- static int size_limit = TEXT_SIZE_LIMIT; /* -l */
- static int pop_open = FALSE; /* -p */
- static int resolution = TS_INTERVAL; /* -r */
- static int beep_amount = BEEP_COUNT; /* -s */
-
- static int bad_is_up;
- static int beep_count;
- static int blinking = FALSE;
- static int event_in_progress = FALSE;
- static int explicit_filters = FALSE;
- static struct f_rec filter[MAX_FILTERS];
- static int filters = 0;
- static int icon_height;
- static int icon_width;
- static FILE *master = NULL;
- static int old_time = 0;
- static char *program;
- static FILE *slave = NULL;
- static FILE *logfile = NULL;
-
- static struct itimerval timer = {{0, 500000}, {0, 500000}};
-
- /************************************************************************/
- /* First, some basic console utility routines */
- /************************************************************************/
-
- /************************************************************************/
- static acquire_console(path)
-
- char *path;
-
- {
- if (ioctl(fileno(slave), TIOCCONS, NULL) == -1) {
- fprintf(stderr, "%s: could not attach %s to /dev/console\n", program, path);
- exit(1);
- }
- }
-
- /************************************************************************/
- static clear_messages()
-
- {
- textsw_reset(text, 0, 0);
- old_time = 0;
- }
-
- /************************************************************************/
- static stop_blinking()
-
- {
- notify_set_itimer_func(bf, NULL, ITIMER_REAL, NULL, NULL);
- window_set(bf, FRAME_ICON, good, 0);
- blinking = FALSE;
- menu_set(stop_blink, MENU_INACTIVE, TRUE, 0);
- }
-
- /************************************************************************/
- /* Now, filter and regular expression handlers */
- /************************************************************************/
-
- /************************************************************************/
- static internal_message(a, b, c, d, e, f)
-
- int a, b, c, d, e, f;
-
- { char buf[512];
-
- sprintf(buf, a, b, c, d, e, f);
- time_stamp();
- write_log(buf);
- do_insertion(buf, strlen(buf));
- }
-
- /************************************************************************/
- static internal_error(a, b, c, d, e, f)
-
- int a, b, c, d, e, f;
-
- { char buf[512];
-
- sprintf(buf, a, b, c, d, e, f);
- time_stamp();
- fprintf(stderr, buf);
- }
-
- /************************************************************************/
- static int match_exp(exp, circ, str)
-
- char *exp;
- int circ;
- char *str;
-
- {
- circf = circ;
- return(step(str, exp));
- }
-
- /************************************************************************/
- static regexp_error(val, string)
-
- int val;
- char *string;
-
- { char *msg;
-
- switch (val) {
- case 11 : msg = "range endpoint too large";
- case 16 : msg = "bad number";
- case 25 : msg = "\"\\digit\" out of range";
- case 36 : msg = "illegal or missing delimiter";
- case 41 : msg = "no remembered search string";
- case 42 : msg = "\\(\\) imbalance";
- case 43 : msg = "too many \\(";
- case 44 : msg = "more than 2 numbers given in \\{\\}";
- case 45 : msg = "} expected after \\";
- case 46 : msg = "first number exceeds second in \\{\\}";
- case 49 : msg = "[] imbalance";
- case 50 : msg = "regular expression overflow";
- default : msg = "regular expression compilation error";
- }
- internal_error("*** %s: %s in '%s'\n", program, msg, string);
- }
-
- /************************************************************************/
- static load_filters()
-
- { FILE *f;
- char buf[256], rbuf[1024], *token[6], *p, *index();
- int count;
- struct stat sb;
- static int load_time = 0;
-
- if (stat(filter_path, &sb) == -1) {
- if (explicit_filters && load_time == 0) {
- internal_error("*** %s: filter file %s cannot be accessed\n", program, filter_path);
- load_time = 1;
- }
- return;
- }
- if (sb.st_mtime > load_time) {
- for (count = 0; count < filters; count++) {
- free(filter[count].start);
- if (filter[count].end)
- free(filter[count].end);
- }
- filters = 0;
- }
- else
- return;
-
- if ((f = fopen(filter_path, "r")) != NULL) {
- while (getline(f, buf, 256) != EOF) {
- if ((p = index(buf, '#')) != NULL)
- *p = '\0';
- if (strlen(buf) == 0 || verify(buf, " "))
- continue;
- tokenize(buf, &count, token, 6);
- if (count == 2 || count == 4) {
- if (strcmp(lower(token[0]), "ignore") == 0)
- filter[filters].mode = IGNORE_MODE;
- else if (strcmp(token[0], "quiet") == 0)
- filter[filters].mode = QUIET_MODE;
- else {
- internal_error("*** %s: invalid contool filter:\n***\t%s\n", program, buf);
- continue;
- }
- if ((filter[filters].start = compile(token[1], rbuf, rbuf+1024, '\0')) == NULL)
- continue;
- filter[filters].scircf = circf;
- if (count == 4)
- if (strcmp(lower(token[2]), "to") == 0) {
- filter[filters].end = compile(token[3], rbuf, rbuf+1024, '\0');
- filter[filters].ecircf = circf;
- }
- else {
- internal_error("*** %s: invalid contool filter:\n***\t%s\n", program, buf);
- continue;
- }
- else
- filter[filters].end = NULL;
- filters++;
- }
- else
- internal_error("*** %s: invalid contool filter:\n\t%s\n", program, buf);
- }
- fclose(f);
- internal_message("*** filters loaded from %s\n", filter_path);
- load_time = sb.st_mtime;
- }
- else
- internal_error("*** %s: could not read filter file %s\n", program, filter_path);
- }
-
- /************************************************************************/
- /* Various event handlers for the console frame */
- /************************************************************************/
-
- /************************************************************************/
- static Notify_value blink_proc(me, which)
-
- int *me;
- int which;
-
- {
- if (event_in_progress)
- return(NOTIFY_DONE);
- if (beep_count > 0) {
- window_bell(bf);
- beep_count--;
- }
- else if (blinking) {
- if (bad_is_up)
- window_set(bf, FRAME_ICON, inverse, 0);
- else
- window_set(bf, FRAME_ICON, bad, 0);
- bad_is_up = !bad_is_up;
- }
- if (beep_count == 0 && !blinking)
- notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL);
- return(NOTIFY_DONE);
- }
-
- /************************************************************************/
- static Notify_value close_proc(frame, event, arg, type)
-
- Frame frame;
- Event *event;
- Notify_arg arg;
- Notify_event_type type;
-
- { int init_closed, curr_closed, is_resize;
- Notify_value value;
- Rect *temp;
-
- event_in_progress = TRUE;
- init_closed = (int) window_get(frame, FRAME_CLOSED);
- is_resize = (event_id(event) == WIN_RESIZE);
- value = notify_next_event_func(frame, event, arg, type);
- curr_closed = (int) window_get(frame, FRAME_CLOSED);
- if (init_closed != curr_closed)
- if (!curr_closed && blinking) {
- notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL);
- window_set(bf, FRAME_ICON, good, 0);
- blinking = FALSE;
- menu_set(stop_blink, MENU_INACTIVE, TRUE, 0);
- }
- event_in_progress = FALSE;
- if (is_resize) {
- temp = (Rect *) window_get(frame, FRAME_OPEN_RECT);
- if (temp->r_width <= icon_width && temp->r_height <= icon_height) { /* override spurious resize request */
- window_set(frame, FRAME_OPEN_RECT, &open_rect, FRAME_CLOSED, FALSE, 0);
- notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, NULL, NULL);
- window_set(bf, FRAME_ICON, good, 0);
- blinking = FALSE;
- menu_set(stop_blink, MENU_INACTIVE, TRUE, 0);
- }
- else /* save away new open rect */
- open_rect = *temp;
- }
- return(value);
- }
-
- /************************************************************************/
- static Notify_value destroy_proc(frame, status)
-
- Frame frame;
- Destroy_status status;
-
- {
- if (status == DESTROY_CHECKING) {
- textsw_reset(text, 0, 0);
- return(NOTIFY_DONE);
- }
- else
- return(notify_next_destroy_func(frame, status));
- }
-
- /************************************************************************/
- /* Routines which handle capturing and displaying messages */
- /************************************************************************/
-
- /************************************************************************/
- static write_log(s)
-
- char *s;
-
- { int t;
- static char hostname[100] = "";
-
- if (logfile) {
- if (*hostname == NULL)
- if (gethostname(hostname, 99) != 0)
- strcpy(hostname, "(unknown)");
- t = time(0);
- fseek(logfile, 0L, 2);
- fprintf(logfile, "%s\t%.16s\t%s", hostname, ctime(&t) + 4, s);
- fflush(logfile);
- }
- }
-
- /************************************************************************/
- static do_insertion(buf, len)
-
- char *buf;
- int len;
-
- { int first, last;
-
- while (len > size_limit - ((int) window_get(text, TEXTSW_LENGTH) - TEXT_SIZE_FUZZ)) { /* make some room */
- first = 1;
- last = TEXTSW_INFINITY;
- if (textsw_find_bytes(text, &first, &last, "\n<<<", 4, 0) == -1)
- if (textsw_find_bytes(text, &first, &last, "\n", 1, 0) == -1)
- first = delete_amt;
- textsw_delete(text, 0, first + 1);
- }
- window_set(text, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0);
- textsw_insert(text, buf, len);
- }
-
- /************************************************************************/
- static time_stamp()
-
- { int t, pos;
- char buf[5];
-
- t = time(0);
- if (t - old_time >= resolution) {
- window_set(text, TEXTSW_INSERTION_POINT, TEXTSW_INFINITY, 0);
- pos = (int) window_get(text, TEXTSW_LENGTH);
- if (pos != 0) {
- window_get(text, TEXTSW_CONTENTS, pos - 1, buf, 1);
- if (buf[0] != '\n')
- do_insertion("\n", 1);
- }
- do_insertion("\n<<< ", 5);
- do_insertion(ctime(&t), 24);
- do_insertion(" >>>\n", 5);
- old_time = t;
- }
- }
-
- /************************************************************************/
- static Notify_value input_func(me, fd)
-
- int *me;
- int fd;
-
- { char old_c, *s, *t, *index();
- int i, count, do_blink = FALSE;
- static int curr_filter = -1, curr_mode = NORMAL_MODE;
- static char in_buf[INPUT_BUFFER_SIZE + 2];
-
- while ((count = read(fileno(master), in_buf, INPUT_BUFFER_SIZE)) >= 0) {
- in_buf[count] = '\0';
- while (s = index(in_buf, '\015')) {
- strcpy(s, s + 1);
- count--;
- }
- for (t = in_buf; *t; *s = old_c, t = s) {
- if (s = index(t, '\n')) {
- old_c = *++s;
- *s = '\0';
- }
- else {
- s = t + strlen(t);
- old_c = '\0';
- }
- if (curr_mode == NORMAL_MODE) {
- load_filters();
- for (i = 0; i < filters; i++)
- if (match_exp(filter[i].start, filter[i].scircf, t)) {
- if (filter[i].mode == QUIET_MODE) {
- time_stamp();
- write_log(t);
- do_insertion(t, strlen(t));
- }
- if (filter[i].end) {
- curr_mode = filter[i].mode;
- curr_filter = i;
- }
- break;
- }
- if (i == filters) {
- time_stamp();
- write_log(t);
- do_insertion(t, strlen(t));
- do_blink = TRUE;
- }
- }
- else {
- if (curr_mode == QUIET_MODE) {
- time_stamp();
- write_log(t);
- do_insertion(t, strlen(t));
- }
- if (match_exp(filter[curr_filter].end, filter[curr_filter].ecircf, t)) {
- curr_mode = NORMAL_MODE;
- curr_filter = -1;
- }
- }
- }
- }
- window_set(text, TEXTSW_UPDATE_SCROLLBAR, 0);
- if (do_blink) {
- if (pop_open)
- window_set(bf, FRAME_CLOSED, FALSE, 0);
- if (window_get(bf, FRAME_CLOSED) && !blinking) {
- window_set(bf, FRAME_ICON, bad, 0);
- blinking = TRUE;
- bad_is_up = TRUE;
- menu_set(stop_blink, MENU_INACTIVE, FALSE, 0);
- }
- beep_count = beep_amount;
- notify_set_itimer_func(bf, blink_proc, ITIMER_REAL, &timer, NULL);
- }
- return(NOTIFY_DONE);
- }
-
- /************************************************************************/
- /* Routines which parse options, create windows, and main() */
- /************************************************************************/
-
- /************************************************************************/
- static parse_options(argc, argv)
-
- int *argc;
- char **argv;
-
- { char *s, c;
-
- strcpy(good_icon, ICON_DIRECTORY);
- strcat(good_icon, GOOD_ICON);
- strcpy(bad_icon, ICON_DIRECTORY);
- strcat(bad_icon, BAD_ICON);
- strcpy(inv_icon, ICON_DIRECTORY);
- strcat(inv_icon, INVERSE_ICON);
-
- strcpy(filter_path, getenv("HOME"));
- strcat(filter_path, "/.contool");
-
- while ((c = getopt(argc, argv, "b:c:d:f:g:l:o:pr:s:?", &s)) != EOF)
- switch (c) {
- case 'b' : strcpy(bad_icon, s);
- break;
- case 'c' : strcpy(filter_path, s);
- explicit_filters = TRUE;
- break;
- case 'd' : if (verify(s, "0123456789"))
- delete_amt = atoi(s);
- else {
- fprintf(stderr, "%s: invalid delete amount: %s\n", program, s);
- exit(1);
- }
- break;
- case 'f' : strcpy(inv_icon, s);
- break;
- case 'g' : strcpy(good_icon, s);
- break;
- case 'l' : if (verify(s, "0123456789"))
- window_set(text, TEXTSW_MEMORY_MAXIMUM, (size_limit = atoi(s)) + TEXT_SIZE_FUZZ, 0);
- else {
- fprintf(stderr, "%s: invalid message limit: %s\n", program, s);
- exit(1);
- }
- break;
- case 'o': if ((logfile = fopen(s, "a")) == NULL) {
- fprintf(stderr, "%s : can't open logfile: %s\n", program, s);
- exit(1);
- }
- break;
- case 'p' : pop_open = TRUE;
- break;
- case 'r' : if (verify(s, "0123456789"))
- resolution = atoi(s);
- else {
- fprintf(stderr, "%s: invalid timestamp resolution: %s\n", program, s);
- exit(1);
- }
- break;
- case 's' : if (verify(s, "0123456789"))
- beep_amount = atoi(s);
- else {
- fprintf(stderr, "%s: invalid beep count: %s\n", program, s);
- exit(1);
- }
- break;
- case '?' : fprintf(stderr, ct_usage);
- exit(0);
- break;
- default : fprintf(stderr, ct_usage);
- exit(1);
- }
- }
-
- /************************************************************************/
- static load_icons()
-
- { char msg[IL_ERRORMSG_SIZE];
-
- if ((good_pr = icon_load_mpr(good_icon, msg)) == NULL) {
- fprintf(stderr, "%s: %s\n", program, msg);
- exit(1);
- }
- good = icon_create(ICON_IMAGE, good_pr,
- ICON_LABEL, "",
- ICON_WIDTH, good_pr->pr_size.x,
- ICON_HEIGHT, good_pr->pr_size.y,
- 0);
- icon_width = good_pr->pr_size.x;
- icon_height = good_pr->pr_size.y;
- if ((bad_pr = icon_load_mpr(bad_icon, msg)) == NULL) {
- fprintf(stderr, "%s: %s\n", program, msg);
- exit(1);
- }
- bad = icon_create(ICON_IMAGE, bad_pr,
- ICON_LABEL, "",
- ICON_WIDTH, bad_pr->pr_size.x,
- ICON_HEIGHT, bad_pr->pr_size.y,
- 0);
- if (bad_pr->pr_size.x > icon_width)
- icon_width = bad_pr->pr_size.x;
- if (bad_pr->pr_size.y > icon_height)
- icon_height = bad_pr->pr_size.y;
- if (*inv_icon == '\0')
- strcpy(inv_icon, bad_icon);
- if ((inv_pr = icon_load_mpr(inv_icon, msg)) == NULL) {
- fprintf(stderr, "%s: %s\n", program, msg);
- exit(1);
- }
- inverse = icon_create(ICON_IMAGE, inv_pr,
- ICON_LABEL, "",
- ICON_WIDTH, inv_pr->pr_size.x,
- ICON_HEIGHT, inv_pr->pr_size.y,
- 0);
- if (inv_pr->pr_size.x > icon_width)
- icon_width = inv_pr->pr_size.x;
- if (inv_pr->pr_size.y > icon_height)
- icon_height = inv_pr->pr_size.y;
- window_set(bf, FRAME_ICON, good, 0);
- }
-
- /************************************************************************/
- main(argc, argv)
-
- int argc;
- char **argv;
-
- { char *path, *open_psuedo_tty(), **saveargs();
- int i;
- Menu menu;
-
- program = strsave(argv[0]);
-
- bf = window_create(NULL, FRAME,
- FRAME_ARGC_PTR_ARGV, &argc, argv,
- FRAME_LABEL, TOOL_LABEL,
- 0);
- text = window_create(bf, TEXTSW,
- TEXTSW_DISABLE_CD, TRUE,
- TEXTSW_DISABLE_LOAD, TRUE,
- TEXTSW_AGAIN_RECORDING, FALSE,
- TEXTSW_IGNORE_LIMIT, TEXTSW_INFINITY,
- TEXTSW_MEMORY_MAXIMUM, size_limit + TEXT_SIZE_FUZZ,
- 0);
- open_rect = *((Rect *) window_get(bf, FRAME_OPEN_RECT));
-
- argv = saveargs(argc, argv);
- parse_options(&argc, argv);
- if (argc != 1) {
- fprintf(stderr, ct_usage);
- exit(1);
- }
-
- load_icons();
-
- path = open_psuedo_tty(&master, "r", &slave, "w");
- if (master == NULL) {
- fprintf(stderr, "%s: couldn't open any psuedo-tty\n");
- exit(1);
- }
- if (slave == NULL) {
- fprintf(stderr, "%s: couldn't open slave side of %s\n", program, path);
- exit(1);
- }
-
- i = fcntl(fileno(master), F_GETFL, 0);
- i |= FNDELAY;
- if (fcntl(fileno(master), F_SETFL, i) == -1) {
- fprintf(stderr, "%s: could not force %s to non-blocking i/o\n", program, path);
- exit(1);
- }
-
- acquire_console(path);
-
- stop_blink = menu_create_item(MENU_STRING, "Stop Blinking",
- MENU_INACTIVE, TRUE,
- MENU_ACTION_PROC, stop_blinking,
- 0);
- menu = menu_create(MENU_APPEND_ITEM, stop_blink,
- MENU_ACTION_ITEM, "Become Console", acquire_console,
- MENU_ACTION_ITEM, "Clear Messages", clear_messages,
- MENU_PULLRIGHT_ITEM, "Frame", window_get(bf, WIN_MENU),
- 0);
- window_set(bf, WIN_MENU, menu, 0);
-
- notify_set_input_func(bf, input_func, fileno(master));
- notify_interpose_destroy_func(bf, destroy_proc);
- notify_interpose_event_func(bf, close_proc, NOTIFY_SAFE);
-
- load_filters();
-
- window_main_loop(bf);
- }
-