2 * capq - print out state of CAP queue (obtained from capqd).
4 * capq [-c] [-i interval] [-h cap-host]
6 * Author: Paul Mackerras, June 1993.
14 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/termios.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
23 #define CAPQD_PORT 6123 /* capqd's well-known port number */
24 #define CAP_HOST_DFLT "cafe" /* default value for -h option */
26 FILE *capqd_w, *capqd_r; /* streams to and from capqd */
27 char *cap_host; /* hostname where capqd is */
29 /* used for terminal capabilities */
30 char termcap_entry[1024], string_caps[1024];
32 #define MAXLINES 100 /* max # lines for continuous display */
33 #define MAXCOLS 100 /* max # columns */
35 double last_change_time; /* cap_host's time of last queue change */
36 double our_time; /* time according to our clock */
37 double host_time_diff; /* cap_host's clock - our clock */
38 double timez[MAXLINES]; /* start time for each line of display */
39 int num_lines; /* # entries valid in timez[] */
41 /* Convert from a timeval to a floating-point number of seconds */
42 #define double_time(x) ((x)->tv_sec + (x)->tv_usec / 1.0E6)
44 /* Termcap routines */
47 extern char *tgetstr();
48 extern int tgetflag();
52 int continuous; /* => display the queue continuously */
53 double interval; /* with updates at this interval */
55 /* Capability strings and terminal information from termcap */
56 int screen_lines; /* screen has this many lines */
57 int screen_width; /* and this many columns */
58 char *term; /* terminal type */
59 char *home; /* go to top-left corner of screen */
60 char *init_str; /* initialize terminal */
61 char *finish_str; /* reset terminal before exit */
62 char *clr_screen; /* clear whole screen */
63 char *clr_eol; /* clear to end of line */
64 char *clr_eos; /* clear to end of screen */
66 int size_changed; /* set when the window size changes */
82 struct timeval *timo, tval;
86 cap_host = getenv("AP1000HOST");
87 if( cap_host == NULL )
88 cap_host = CAP_HOST_DFLT;
92 /* parse command-line options */
93 while( (c = getopt(argc, argv, "c:h:")) != -1 ){
100 interval = atof(optarg);
103 fprintf(stderr, "Usage: %s [-h host]\n", argv[0]);
108 /* connect to the capqd process */
109 fd = connect_tcp(cap_host, CAPQD_PORT);
112 capqd_r = fdopen(fd, "r");
113 capqd_w = fdopen(fd, "w");
114 if( capqd_r == NULL || capqd_w == NULL ){
115 fprintf(stderr, "fdopen failed!\n");
119 /* request the current state of the queue */
120 fputs("queue\n", capqd_w);
124 /* just print the queue once and exit. */
129 /* Continuous mode - get information about the terminal. */
130 if( tcgetattr(0, &tio) == 0 )
131 ospeed = cfgetospeed(&tio);
134 home = clr_screen = clr_eol = finish_str = NULL;
135 term = getenv("TERM");
136 if( term != NULL && tgetent(termcap_entry, term) > 0 ){
138 screen_lines = tgetnum("li");
139 screen_width = tgetnum("co");
140 home = tgetstr("ho", &ptr);
141 clr_screen = tgetstr("cl", &ptr);
142 clr_eol = tgetstr("ce", &ptr);
143 clr_eos = tgetstr("cd", &ptr);
144 init_str = tgetstr("ti", &ptr);
145 finish_str = tgetstr("te", &ptr);
146 if( init_str != NULL )
147 tputs(init_str, screen_lines, outchar);
150 /* default to the ANSI sequences */
153 if( clr_screen == NULL )
154 clr_screen = "\033[H\033[J";
155 if( clr_eol == NULL )
157 if( clr_eos == NULL )
159 if( finish_str == NULL )
161 tputs(clr_screen, screen_lines, outchar);
164 if( screen_lines > MAXLINES )
165 screen_lines = MAXLINES;
166 if( screen_width > MAXCOLS )
167 screen_width = MAXCOLS;
169 /* fix up the terminal and exit on these signals */
170 signal(SIGINT, getout);
171 signal(SIGTERM, getout);
172 /* update the terminal size on this signal */
173 signal(SIGWINCH, hoist);
176 * This loop waits for either (a) an update to arrive from capqd,
177 * or (b) for it to be time to change the time values displayed
178 * for jobs in the queue, or (c) for the terminal window size to change.
184 /* no times to update - don't time out */
188 /* work out how long until the first time displayed
189 should change, i.e. until it's a multiple of `interval'. */
190 gettimeofday(&tval, NULL);
191 our_time = double_time(&tval);
195 t = our_time + host_time_diff - t;
196 t = interval - fmod(t, interval);
197 tval.tv_sec = (int) floor(t);
198 tval.tv_usec = (int) floor((t - tval.tv_sec) * 1.0E6);
202 /* wait for something */
205 n = select(fd+1, &ready, NULL, NULL, timo);
206 if( n < 0 && errno != EINTR ){
207 tputs(finish_str, screen_lines, outchar);
213 /* update display with new information, then ask for
214 another report when the queue changes. */
217 fprintf(capqd_w, "queue %.2f\n", last_change_time);
220 } else if( size_changed ){
221 /* ask for the queues again */
222 fprintf(capqd_w, "queue\n");
227 /* timeout - no new information from capqd */
231 /* leave the cursor at the top left of the screen */
232 tputs(home, 0, outchar);
238 * Fatal signal - clean up terminal and exit.
244 tputs(finish_str, screen_lines, outchar);
249 * Window size changed - winch up the new size.
255 struct winsize winsz;
257 if( ioctl(fileno(stdout), TIOCGWINSZ, &winsz) == 0 ){
259 screen_lines = winsz.ws_row;
260 screen_width = winsz.ws_col;
261 if( screen_lines > MAXLINES )
262 screen_lines = MAXLINES;
263 if( screen_width > MAXCOLS )
264 screen_width = MAXCOLS;
269 * Output character routine for tputs to use.
279 * New information from capqd - display it, and (in continuous mode)
280 * record the start times for the users shown on each line of the display.
285 int n, index, run_done, lnum;
289 char user[64], more[8];
294 /* initialize, print heading */
298 sprintf(str, " CAP queue on %.50s", cap_host);
301 /* get lines from capqd */
303 if( fgets(line, sizeof(line), capqd_r) == NULL ){
304 /* EOF or error - capqd must have gone away */
306 tputs(finish_str, screen_lines, outchar);
309 fprintf(stderr, "read error\n");
314 /* end of queue report */
316 if( line[0] == 'T' ){
317 /* first line of queue report: T last-change-time time-now */
318 gettimeofday(&now, NULL);
319 our_time = double_time(&now);
320 sscanf(line+2, "%lf %lf", &last_change_time, &host_time_diff);
321 host_time_diff -= our_time;
325 /* line specifying next user in queue:
326 index user start-time { pids... } */
327 n = sscanf(line, "%d %s %lf { %d %d %d %d %s", &index,
328 user, &start_time, &pid[0], &pid[1], &pid[2],
331 /* couldn't parse line - ignore it */
333 fprintf(stderr, "bad line %s", line);
338 /* accumulate a line to be printed in str */
341 /* this is the running job */
342 sprint_time(&ptr, start_time);
343 sprintf(ptr, " Run %.20s (pid %d", user, pid[0]);
346 /* print the rest of the pids which are waiting */
349 sprint_pids_waiting(&ptr, pid, n, 1);
350 strcpy(ptr, " waiting");
357 /* a user in the queue */
358 if( continuous && !run_done ){
359 /* no running job - leave a blank line for it */
366 if( continuous && lnum >= screen_lines - 1 ){
367 /* no more room on screen */
368 if( lnum == screen_lines - 1 ){
369 strcpy(ptr, " (more)");
373 ptr = NULL; /* don't print anything */
375 /* format this line into str */
376 sprint_time(&ptr, start_time);
377 sprintf(ptr, " %3d %.20s (", index, user);
379 sprint_pids_waiting(&ptr, pid, n, 0);
383 /* print out the line we've formatted */
388 timez[lnum] = start_time;
395 if( lnum > screen_lines )
399 /* clear the remainder of the screen */
400 if( continuous && lnum < screen_lines )
401 tputs(clr_eos, screen_lines - lnum + 1, outchar);
405 * Output a line to the screen. In continuous mode, truncate the
406 * line to the screen width and clear the remainder of the line.
413 if( lnum < screen_lines ){
414 str[screen_width] = 0;
416 if( strlen(str) < screen_width )
417 tputs(clr_eol, 1, outchar);
418 if( lnum < screen_lines - 1 )
426 * Format the time since time t on the cap_host into the buffer
427 * at **pp, advancing *pp past the formatted string.
435 t = floor(our_time + host_time_diff - t + 0.5);
438 sprintf(*pp, "%3d:", x);
446 sprintf(*pp, "%.2d:%.2d", x, (int)(t - x * 60));
451 * Format a list of pids waiting into **pp, advancing *pp.
453 sprint_pids_waiting(pp, pid, n, i)
457 sprintf(*pp, "pid%s %d", (n > i+1? "s": ""), pid[i]);
459 for( ++i; i < n && i < 4; ++i ){
460 sprintf(*pp, ", %d", pid[i]);
464 strcpy(*pp, ", ...");
470 * Update the times displayed for each user.
479 gettimeofday(&now, NULL);
480 our_time = double_time(&now);
481 for( i = 0; i < num_lines; ++i ){
483 if( (t = timez[i]) != 0 ){
484 sprint_time(&ptr, t);
485 if( screen_width < sizeof(str) )
486 str[screen_width] = 0;
490 if( i < num_lines - 1 )
496 * Establish a TCP/IP connection with the process at the given hostname
500 connect_tcp(host, port)
506 struct hostent *hent;
507 struct sockaddr_in addr;
509 hnum = inet_addr(host);
511 hent = gethostbyname(host);
513 fprintf(stderr, "hostname %s not recognized\n", host);
516 hnum = *(unsigned long *)(hent->h_addr_list[0]);
519 if( (fd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ){
524 bzero(&addr, sizeof(addr));
525 addr.sin_family = AF_INET;
526 addr.sin_port = htons(port);
527 addr.sin_addr.s_addr = hnum;
529 if( connect(fd, &addr, sizeof(addr)) < 0 ){