1 /*
2  *  Copyright (C) International Business Machines  Corp., 2005
3  *  Author(s): Judy Fischbach <jfisch@cs.pdx.edu>
4  *             David Hendricks <cro_marmot@comcast.net>
5  *             Josh Triplett <josh@kernel.org>
6  *    based on code from Anthony Liguori <aliguori@us.ibm.com>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; under version 2 of the License.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /* get curses header from configure */
22 #include INCLUDE_CURSES_H
23 
24 #include <ctype.h>
25 #include <errno.h>
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <sys/time.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #if defined(__linux__)
36 #include <linux/kdev_t.h>
37 #endif
38 
39 #include <xenstat.h>
40 
41 #define XENTOP_VERSION "1.0"
42 
43 #define XENTOP_DISCLAIMER \
44 "Copyright (C) 2005  International Business Machines  Corp\n"\
45 "This is free software; see the source for copying conditions.There is NO\n"\
46 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
47 #define XENTOP_BUGSTO "Report bugs to <xen-devel@lists.xen.org>.\n"
48 
49 #define _GNU_SOURCE
50 #include <getopt.h>
51 
52 #if !defined(__GNUC__) && !defined(__GNUG__)
53 #define __attribute__(arg) /* empty */
54 #endif
55 
56 #define KEY_ESCAPE '\x1B'
57 #define KEY_REPAINT '\x0C'
58 
59 #ifdef HOST_SunOS
60 /* Old curses library on Solaris takes non-const strings. Also, ERR interferes
61  * with curse's definition.
62  */
63 #undef ERR
64 #define ERR (-1)
65 #define curses_str_t char *
66 #else
67 #define curses_str_t const char *
68 #endif
69 
70 #define INT_FIELD_WIDTH(n) ((unsigned int)(log10(n) + 1))
71 
72 /*
73  * Function prototypes
74  */
75 /* Utility functions */
76 static void usage(const char *);
77 static void version(void);
78 static void cleanup(void);
79 static void fail(const char *);
80 static int current_row(void);
81 static int lines(void);
82 static void print(const char *, ...) __attribute__((format(printf,1,2)));
83 static void attr_addstr(int attr, const char *str);
84 static void set_delay(char *value);
85 static void set_prompt(char *new_prompt, void (*func)(char *));
86 static int handle_key(int);
87 static int compare(unsigned long long, unsigned long long);
88 static int compare_domains(xenstat_domain **, xenstat_domain **);
89 static unsigned long long tot_net_bytes( xenstat_domain *, int);
90 static unsigned long long tot_vbd_reqs( xenstat_domain *, int);
91 
92 /* Field functions */
93 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2);
94 static void print_state(xenstat_domain *domain);
95 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2);
96 static void print_cpu(xenstat_domain *domain);
97 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2);
98 static void print_cpu_pct(xenstat_domain *domain);
99 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2);
100 static void print_mem(xenstat_domain *domain);
101 static void print_mem_pct(xenstat_domain *domain);
102 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2);
103 static void print_maxmem(xenstat_domain *domain);
104 static void print_max_pct(xenstat_domain *domain);
105 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2);
106 static void print_vcpus(xenstat_domain *domain);
107 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2);
108 static void print_nets(xenstat_domain *domain);
109 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2);
110 static void print_net_tx(xenstat_domain *domain);
111 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2);
112 static void print_net_rx(xenstat_domain *domain);
113 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2);
114 static void print_ssid(xenstat_domain *domain);
115 static int compare_name(xenstat_domain *domain1, xenstat_domain *domain2);
116 static void print_name(xenstat_domain *domain);
117 static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2);
118 static void print_vbds(xenstat_domain *domain);
119 static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2);
120 static void print_vbd_oo(xenstat_domain *domain);
121 static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2);
122 static void print_vbd_rd(xenstat_domain *domain);
123 static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2);
124 static void print_vbd_wr(xenstat_domain *domain);
125 static int compare_vbd_rsect(xenstat_domain *domain1, xenstat_domain *domain2);
126 static void print_vbd_rsect(xenstat_domain *domain);
127 static int compare_vbd_wsect(xenstat_domain *domain1, xenstat_domain *domain2);
128 static void print_vbd_wsect(xenstat_domain *domain);
129 static void reset_field_widths(void);
130 static void adjust_field_widths(xenstat_domain *domain);
131 
132 /* Section printing functions */
133 static void do_summary(void);
134 static void do_header(void);
135 static void do_bottom_line(void);
136 static void do_domain(xenstat_domain *);
137 static void do_vcpu(xenstat_domain *);
138 static void do_network(xenstat_domain *);
139 static void do_vbd(xenstat_domain *);
140 static void top(void);
141 
142 /* Field types */
143 typedef enum field_id {
144 	FIELD_DOMID,
145 	FIELD_NAME,
146 	FIELD_STATE,
147 	FIELD_CPU,
148 	FIELD_CPU_PCT,
149 	FIELD_MEM,
150 	FIELD_MEM_PCT,
151 	FIELD_MAXMEM,
152 	FIELD_MAX_PCT,
153 	FIELD_VCPUS,
154 	FIELD_NETS,
155 	FIELD_NET_TX,
156 	FIELD_NET_RX,
157 	FIELD_VBDS,
158 	FIELD_VBD_OO,
159 	FIELD_VBD_RD,
160 	FIELD_VBD_WR,
161 	FIELD_VBD_RSECT,
162 	FIELD_VBD_WSECT,
163 	FIELD_SSID
164 } field_id;
165 
166 typedef struct field {
167 	field_id num;
168 	const char *header;
169 	unsigned int default_width;
170 	int (*compare)(xenstat_domain *domain1, xenstat_domain *domain2);
171 	void (*print)(xenstat_domain *domain);
172 } field;
173 
174 field fields[] = {
175 	{ FIELD_NAME,      "NAME",      10, compare_name,      print_name    },
176 	{ FIELD_STATE,     "STATE",      6, compare_state,     print_state   },
177 	{ FIELD_CPU,       "CPU(sec)",  10, compare_cpu,       print_cpu     },
178 	{ FIELD_CPU_PCT,   "CPU(%)",     6, compare_cpu_pct,   print_cpu_pct },
179 	{ FIELD_MEM,       "MEM(k)",    10, compare_mem,       print_mem     },
180 	{ FIELD_MEM_PCT,   "MEM(%)",     6, compare_mem,       print_mem_pct },
181 	{ FIELD_MAXMEM,    "MAXMEM(k)", 10, compare_maxmem,    print_maxmem  },
182 	{ FIELD_MAX_PCT,   "MAXMEM(%)",  9, compare_maxmem,    print_max_pct },
183 	{ FIELD_VCPUS,     "VCPUS",      5, compare_vcpus,     print_vcpus   },
184 	{ FIELD_NETS,      "NETS",       4, compare_nets,      print_nets    },
185 	{ FIELD_NET_TX,    "NETTX(k)",   8, compare_net_tx,    print_net_tx  },
186 	{ FIELD_NET_RX,    "NETRX(k)",   8, compare_net_rx,    print_net_rx  },
187 	{ FIELD_VBDS,      "VBDS",       4, compare_vbds,      print_vbds    },
188 	{ FIELD_VBD_OO,    "VBD_OO",     8, compare_vbd_oo,    print_vbd_oo  },
189 	{ FIELD_VBD_RD,    "VBD_RD",     8, compare_vbd_rd,    print_vbd_rd  },
190 	{ FIELD_VBD_WR,    "VBD_WR",     8, compare_vbd_wr,    print_vbd_wr  },
191 	{ FIELD_VBD_RSECT, "VBD_RSECT", 10, compare_vbd_rsect, print_vbd_rsect  },
192 	{ FIELD_VBD_WSECT, "VBD_WSECT", 10, compare_vbd_wsect, print_vbd_wsect  },
193 	{ FIELD_SSID,      "SSID",       4, compare_ssid,      print_ssid    }
194 };
195 
196 const unsigned int NUM_FIELDS = sizeof(fields)/sizeof(field);
197 
198 /* Globals */
199 struct timeval curtime, oldtime;
200 xenstat_handle *xhandle = NULL;
201 xenstat_node *prev_node = NULL;
202 xenstat_node *cur_node = NULL;
203 field_id sort_field = FIELD_DOMID;
204 unsigned int first_domain_index = 0;
205 unsigned int delay = 3;
206 unsigned int batch = 0;
207 unsigned int loop = 1;
208 unsigned int iterations = 0;
209 int show_vcpus = 0;
210 int show_networks = 0;
211 int show_vbds = 0;
212 int show_tmem = 0;
213 int repeat_header = 0;
214 int show_full_name = 0;
215 #define PROMPT_VAL_LEN 80
216 char *prompt = NULL;
217 char prompt_val[PROMPT_VAL_LEN];
218 int prompt_val_len = 0;
219 void (*prompt_complete_func)(char *);
220 
221 static WINDOW *cwin;
222 
223 /*
224  * Function definitions
225  */
226 
227 /* Utility functions */
228 
229 /* Print usage message, using given program name */
usage(const char * program)230 static void usage(const char *program)
231 {
232 	printf("Usage: %s [OPTION]\n"
233 	       "Displays ongoing information about xen vm resources \n\n"
234 	       "-h, --help           display this help and exit\n"
235 	       "-V, --version        output version information and exit\n"
236 	       "-d, --delay=SECONDS  seconds between updates (default 3)\n"
237 	       "-n, --networks       output vif network data\n"
238 	       "-x, --vbds           output vbd block device data\n"
239 	       "-r, --repeat-header  repeat table header before each domain\n"
240 	       "-v, --vcpus          output vcpu data\n"
241 	       "-b, --batch	     output in batch mode, no user input accepted\n"
242 	       "-i, --iterations     number of iterations before exiting\n"
243 	       "-f, --full-name      output the full domain name (not truncated)\n"
244 	       "\n" XENTOP_BUGSTO,
245 	       program);
246 	return;
247 }
248 
249 /* Print program version information */
version(void)250 static void version(void)
251 {
252 	printf("xentop " XENTOP_VERSION "\n"
253 	       "Written by Judy Fischbach, David Hendricks, Josh Triplett\n"
254 	       "\n" XENTOP_DISCLAIMER);
255 }
256 
257 /* Clean up any open resources */
cleanup(void)258 static void cleanup(void)
259 {
260 	if(cwin != NULL && !isendwin())
261 		endwin();
262 	if(prev_node != NULL)
263 		xenstat_free_node(prev_node);
264 	if(cur_node != NULL)
265 		xenstat_free_node(cur_node);
266 	if(xhandle != NULL)
267 		xenstat_uninit(xhandle);
268 }
269 
270 /* Display the given message and gracefully exit */
fail(const char * str)271 static void fail(const char *str)
272 {
273 	if(cwin != NULL && !isendwin())
274 		endwin();
275 	fprintf(stderr, "%s", str);
276 	exit(1);
277 }
278 
279 /* Return the row containing the cursor. */
current_row(void)280 static int current_row(void)
281 {
282 	int y, x;
283 	getyx(stdscr, y, x);
284 	return y;
285 }
286 
287 /* Return the number of lines on the screen. */
lines(void)288 static int lines(void)
289 {
290 	int y, x;
291 	getmaxyx(stdscr, y, x);
292 	return y;
293 }
294 
295 /* printf-style print function which calls printw, but only if the cursor is
296  * not on the last line. */
print(const char * fmt,...)297 static void print(const char *fmt, ...)
298 {
299 	va_list args;
300 
301 	if (!batch) {
302 		if((current_row() < lines()-1)) {
303 			va_start(args, fmt);
304 			vwprintw(stdscr, (curses_str_t)fmt, args);
305 			va_end(args);
306 		}
307 	} else {
308 		va_start(args, fmt);
309 		vprintf(fmt, args);
310 		va_end(args);
311 	}
312 }
313 
xentop_attron(int attr)314 static void xentop_attron(int attr)
315 {
316 	if (!batch)
317 		attron(attr);
318 }
319 
xentop_attroff(int attr)320 static void xentop_attroff(int attr)
321 {
322 	if (!batch)
323 		attroff(attr);
324 }
325 
326 /* Print a string with the given attributes set. */
attr_addstr(int attr,const char * str)327 static void attr_addstr(int attr, const char *str)
328 {
329 	xentop_attron(attr);
330 	addstr((curses_str_t)str);
331 	xentop_attroff(attr);
332 }
333 
334 /* Handle setting the delay from the user-supplied value in prompt_val */
set_delay(char * value)335 static void set_delay(char *value)
336 {
337 	int new_delay;
338 	new_delay = atoi(value);
339 	if(new_delay > 0)
340 		delay = new_delay;
341 }
342 
343 /* Enable prompting mode with the given prompt string; call the given function
344  * when a value is available. */
set_prompt(char * new_prompt,void (* func)(char *))345 static void set_prompt(char *new_prompt, void (*func)(char *))
346 {
347 	prompt = new_prompt;
348 	prompt_val[0] = '\0';
349 	prompt_val_len = 0;
350 	prompt_complete_func = func;
351 }
352 
353 /* Handle user input, return 0 if the program should quit, or 1 if not */
handle_key(int ch)354 static int handle_key(int ch)
355 {
356 	if(prompt == NULL) {
357 		/* Not prompting for input; handle interactive commands */
358 		switch(ch) {
359 		case 'n': case 'N':
360 			show_networks ^= 1;
361 			break;
362 		case 'b': case 'B':
363 			show_vbds ^= 1;
364 			break;
365 		case 't': case 'T':
366 			show_tmem ^= 1;
367 			break;
368 		case 'r': case 'R':
369 			repeat_header ^= 1;
370 			break;
371 		case 's': case 'S':
372 			sort_field = (sort_field + 1) % NUM_FIELDS;
373 			break;
374 		case 'v': case 'V':
375 			show_vcpus ^= 1;
376 			break;
377 		case KEY_DOWN:
378 			first_domain_index++;
379 			break;
380 		case KEY_UP:
381 			if(first_domain_index > 0)
382 				first_domain_index--;
383 			break;
384 		case 'd': case 'D':
385 			set_prompt("Delay(sec)", set_delay);
386 			break;
387 		case KEY_REPAINT:
388 			clear();
389 			break;
390 		case 'q': case 'Q': case KEY_ESCAPE:
391 			return 0;
392 		}
393 	} else {
394 		/* Prompting for input; handle line editing */
395 		switch(ch) {
396 		case '\r':
397 			prompt_complete_func(prompt_val);
398 			set_prompt(NULL, NULL);
399 			break;
400 		case KEY_ESCAPE:
401 			set_prompt(NULL, NULL);
402 			break;
403 		case KEY_BACKSPACE:
404 			if(prompt_val_len > 0)
405 				prompt_val[--prompt_val_len] = '\0';
406                         break;
407 		default:
408 			if((prompt_val_len+1) < PROMPT_VAL_LEN
409 			   && isprint(ch)) {
410 				prompt_val[prompt_val_len++] = (char)ch;
411 				prompt_val[prompt_val_len] = '\0';
412 			}
413 		}
414 	}
415 
416 	return 1;
417 }
418 
419 /* Compares two integers, returning -1,0,1 for <,=,> */
compare(unsigned long long i1,unsigned long long i2)420 static int compare(unsigned long long i1, unsigned long long i2)
421 {
422 	if(i1 < i2)
423 		return -1;
424 	if(i1 > i2)
425 		return 1;
426 	return 0;
427 }
428 
429 /* Comparison function for use with qsort.  Compares two domains using the
430  * current sort field. */
compare_domains(xenstat_domain ** domain1,xenstat_domain ** domain2)431 static int compare_domains(xenstat_domain **domain1, xenstat_domain **domain2)
432 {
433 	return fields[sort_field].compare(*domain1, *domain2);
434 }
435 
436 /* Field functions */
437 
438 /* Compare domain names, returning -1,0,1 for <,=,> */
compare_name(xenstat_domain * domain1,xenstat_domain * domain2)439 int compare_name(xenstat_domain *domain1, xenstat_domain *domain2)
440 {
441 	return strcasecmp(xenstat_domain_name(domain1), xenstat_domain_name(domain2));
442 }
443 
444 /* Prints domain name */
print_name(xenstat_domain * domain)445 void print_name(xenstat_domain *domain)
446 {
447 	if(show_full_name)
448 		print("%*s", fields[FIELD_NAME-1].default_width, xenstat_domain_name(domain));
449 	else
450 		print("%10.10s", xenstat_domain_name(domain));
451 }
452 
453 struct {
454 	unsigned int (*get)(xenstat_domain *);
455 	char ch;
456 } state_funcs[] = {
457 	{ xenstat_domain_dying,    'd' },
458 	{ xenstat_domain_shutdown, 's' },
459 	{ xenstat_domain_blocked,  'b' },
460 	{ xenstat_domain_crashed,  'c' },
461 	{ xenstat_domain_paused,   'p' },
462 	{ xenstat_domain_running,  'r' }
463 };
464 const unsigned int NUM_STATES = sizeof(state_funcs)/sizeof(*state_funcs);
465 
466 /* Compare states of two domains, returning -1,0,1 for <,=,> */
compare_state(xenstat_domain * domain1,xenstat_domain * domain2)467 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2)
468 {
469 	unsigned int i, d1s, d2s;
470 	for(i = 0; i < NUM_STATES; i++) {
471 		d1s = state_funcs[i].get(domain1);
472 		d2s = state_funcs[i].get(domain2);
473 		if(d1s && !d2s)
474 			return -1;
475 		if(d2s && !d1s)
476 			return 1;
477 	}
478 	return 0;
479 }
480 
481 /* Prints domain state in abbreviated letter format */
print_state(xenstat_domain * domain)482 static void print_state(xenstat_domain *domain)
483 {
484 	unsigned int i;
485 	for(i = 0; i < NUM_STATES; i++)
486 		print("%c", state_funcs[i].get(domain) ? state_funcs[i].ch
487 		                                       : '-');
488 }
489 
490 /* Compares cpu usage of two domains, returning -1,0,1 for <,=,> */
compare_cpu(xenstat_domain * domain1,xenstat_domain * domain2)491 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2)
492 {
493 	return -compare(xenstat_domain_cpu_ns(domain1),
494 			xenstat_domain_cpu_ns(domain2));
495 }
496 
497 /* Prints domain cpu usage in seconds */
print_cpu(xenstat_domain * domain)498 static void print_cpu(xenstat_domain *domain)
499 {
500 	print("%10llu", xenstat_domain_cpu_ns(domain)/1000000000);
501 }
502 
503 /* Computes the CPU percentage used for a specified domain */
get_cpu_pct(xenstat_domain * domain)504 static double get_cpu_pct(xenstat_domain *domain)
505 {
506 	xenstat_domain *old_domain;
507 	double us_elapsed;
508 
509 	/* Can't calculate CPU percentage without a previous sample. */
510 	if(prev_node == NULL)
511 		return 0.0;
512 
513 	old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain));
514 	if(old_domain == NULL)
515 		return 0.0;
516 
517 	/* Calculate the time elapsed in microseconds */
518 	us_elapsed = ((curtime.tv_sec-oldtime.tv_sec)*1000000.0
519 		      +(curtime.tv_usec - oldtime.tv_usec));
520 
521 	/* In the following, nanoseconds must be multiplied by 1000.0 to
522 	 * convert to microseconds, then divided by 100.0 to get a percentage,
523 	 * resulting in a multiplication by 10.0 */
524 	return ((xenstat_domain_cpu_ns(domain)
525 		 -xenstat_domain_cpu_ns(old_domain))/10.0)/us_elapsed;
526 }
527 
compare_cpu_pct(xenstat_domain * domain1,xenstat_domain * domain2)528 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2)
529 {
530 	return -compare(get_cpu_pct(domain1), get_cpu_pct(domain2));
531 }
532 
533 /* Prints cpu percentage statistic */
print_cpu_pct(xenstat_domain * domain)534 static void print_cpu_pct(xenstat_domain *domain)
535 {
536 	print("%6.1f", get_cpu_pct(domain));
537 }
538 
539 /* Compares current memory of two domains, returning -1,0,1 for <,=,> */
compare_mem(xenstat_domain * domain1,xenstat_domain * domain2)540 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2)
541 {
542 	return -compare(xenstat_domain_cur_mem(domain1),
543 	                xenstat_domain_cur_mem(domain2));
544 }
545 
546 /* Prints current memory statistic */
print_mem(xenstat_domain * domain)547 static void print_mem(xenstat_domain *domain)
548 {
549 	print("%10llu", xenstat_domain_cur_mem(domain)/1024);
550 }
551 
552 /* Prints memory percentage statistic, ratio of current domain memory to total
553  * node memory */
print_mem_pct(xenstat_domain * domain)554 static void print_mem_pct(xenstat_domain *domain)
555 {
556 	print("%6.1f", (double)xenstat_domain_cur_mem(domain) /
557 	               (double)xenstat_node_tot_mem(cur_node) * 100);
558 }
559 
560 /* Compares maximum memory of two domains, returning -1,0,1 for <,=,> */
compare_maxmem(xenstat_domain * domain1,xenstat_domain * domain2)561 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2)
562 {
563 	return -compare(xenstat_domain_max_mem(domain1),
564 	                xenstat_domain_max_mem(domain2));
565 }
566 
567 /* Prints maximum domain memory statistic in KB */
print_maxmem(xenstat_domain * domain)568 static void print_maxmem(xenstat_domain *domain)
569 {
570 	unsigned long long max_mem = xenstat_domain_max_mem(domain);
571 	if(max_mem == ((unsigned long long)-1))
572 		print("%10s", "no limit");
573 	else
574 		print("%10llu", max_mem/1024);
575 }
576 
577 /* Prints memory percentage statistic, ratio of current domain memory to total
578  * node memory */
print_max_pct(xenstat_domain * domain)579 static void print_max_pct(xenstat_domain *domain)
580 {
581 	if (xenstat_domain_max_mem(domain) == (unsigned long long)-1)
582 		print("%9s", "n/a");
583 	else
584 		print("%9.1f", (double)xenstat_domain_max_mem(domain) /
585 		               (double)xenstat_node_tot_mem(cur_node) * 100);
586 }
587 
588 /* Compares number of virtual CPUs of two domains, returning -1,0,1 for
589  * <,=,> */
compare_vcpus(xenstat_domain * domain1,xenstat_domain * domain2)590 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2)
591 {
592 	return -compare(xenstat_domain_num_vcpus(domain1),
593 	                xenstat_domain_num_vcpus(domain2));
594 }
595 
596 /* Prints number of virtual CPUs statistic */
print_vcpus(xenstat_domain * domain)597 static void print_vcpus(xenstat_domain *domain)
598 {
599 	print("%5u", xenstat_domain_num_vcpus(domain));
600 }
601 
602 /* Compares number of virtual networks of two domains, returning -1,0,1 for
603  * <,=,> */
compare_nets(xenstat_domain * domain1,xenstat_domain * domain2)604 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2)
605 {
606 	return -compare(xenstat_domain_num_networks(domain1),
607 	                xenstat_domain_num_networks(domain2));
608 }
609 
610 /* Prints number of virtual networks statistic */
print_nets(xenstat_domain * domain)611 static void print_nets(xenstat_domain *domain)
612 {
613 	print("%4u", xenstat_domain_num_networks(domain));
614 }
615 
616 /* Compares number of total network tx bytes of two domains, returning -1,0,1
617  * for <,=,> */
compare_net_tx(xenstat_domain * domain1,xenstat_domain * domain2)618 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2)
619 {
620 	return -compare(tot_net_bytes(domain1, FALSE),
621 	                tot_net_bytes(domain2, FALSE));
622 }
623 
624 /* Prints number of total network tx bytes statistic */
print_net_tx(xenstat_domain * domain)625 static void print_net_tx(xenstat_domain *domain)
626 {
627 	print("%*llu", fields[FIELD_NET_TX-1].default_width, tot_net_bytes(domain, FALSE)/1024);
628 }
629 
630 /* Compares number of total network rx bytes of two domains, returning -1,0,1
631  * for <,=,> */
compare_net_rx(xenstat_domain * domain1,xenstat_domain * domain2)632 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2)
633 {
634 	return -compare(tot_net_bytes(domain1, TRUE),
635 	                tot_net_bytes(domain2, TRUE));
636 }
637 
638 /* Prints number of total network rx bytes statistic */
print_net_rx(xenstat_domain * domain)639 static void print_net_rx(xenstat_domain *domain)
640 {
641 	print("%*llu", fields[FIELD_NET_RX-1].default_width, tot_net_bytes(domain, TRUE)/1024);
642 }
643 
644 /* Gets number of total network bytes statistic, if rx true, then rx bytes
645  * otherwise tx bytes
646  */
tot_net_bytes(xenstat_domain * domain,int rx_flag)647 static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag)
648 {
649 	int i = 0;
650 	xenstat_network *network;
651 	unsigned num_networks = 0;
652 	unsigned long long total = 0;
653 
654 	/* How many networks? */
655 	num_networks = xenstat_domain_num_networks(domain);
656 
657 	/* Dump information for each network */
658 	for (i=0; i < num_networks; i++) {
659 		/* Next get the network information */
660 		network = xenstat_domain_network(domain,i);
661 		if (rx_flag)
662 			total += xenstat_network_rbytes(network);
663 		else
664 			total += xenstat_network_tbytes(network);
665 	}
666 
667 	return total;
668 }
669 
670 /* Compares number of virtual block devices of two domains,
671    returning -1,0,1 for * <,=,> */
compare_vbds(xenstat_domain * domain1,xenstat_domain * domain2)672 static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2)
673 {
674 	return -compare(xenstat_domain_num_vbds(domain1),
675 	                xenstat_domain_num_vbds(domain2));
676 }
677 
678 /* Prints number of virtual block devices statistic */
print_vbds(xenstat_domain * domain)679 static void print_vbds(xenstat_domain *domain)
680 {
681 	print("%4u", xenstat_domain_num_vbds(domain));
682 }
683 
684 /* Compares number of total VBD OO requests of two domains,
685    returning -1,0,1 * for <,=,> */
compare_vbd_oo(xenstat_domain * domain1,xenstat_domain * domain2)686 static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2)
687 {
688   return -compare(tot_vbd_reqs(domain1, FIELD_VBD_OO),
689 		  tot_vbd_reqs(domain2, FIELD_VBD_OO));
690 }
691 
692 /* Prints number of total VBD OO requests statistic */
print_vbd_oo(xenstat_domain * domain)693 static void print_vbd_oo(xenstat_domain *domain)
694 {
695 	print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_OO));
696 }
697 
698 /* Compares number of total VBD READ requests of two domains,
699    returning -1,0,1 * for <,=,> */
compare_vbd_rd(xenstat_domain * domain1,xenstat_domain * domain2)700 static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2)
701 {
702 	return -compare(tot_vbd_reqs(domain1, FIELD_VBD_RD),
703 			tot_vbd_reqs(domain2, FIELD_VBD_RD));
704 }
705 
706 /* Prints number of total VBD READ requests statistic */
print_vbd_rd(xenstat_domain * domain)707 static void print_vbd_rd(xenstat_domain *domain)
708 {
709 	print("%*llu", fields[FIELD_VBD_RD-1].default_width, tot_vbd_reqs(domain, FIELD_VBD_RD));
710 }
711 
712 /* Compares number of total VBD WRITE requests of two domains,
713    returning -1,0,1 * for <,=,> */
compare_vbd_wr(xenstat_domain * domain1,xenstat_domain * domain2)714 static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2)
715 {
716 	return -compare(tot_vbd_reqs(domain1, FIELD_VBD_WR),
717 			tot_vbd_reqs(domain2, FIELD_VBD_WR));
718 }
719 
720 /* Prints number of total VBD WRITE requests statistic */
print_vbd_wr(xenstat_domain * domain)721 static void print_vbd_wr(xenstat_domain *domain)
722 {
723 	print("%*llu", fields[FIELD_VBD_WR-1].default_width, tot_vbd_reqs(domain, FIELD_VBD_WR));
724 }
725 
726 /* Compares number of total VBD READ sectors of two domains,
727    returning -1,0,1 * for <,=,> */
compare_vbd_rsect(xenstat_domain * domain1,xenstat_domain * domain2)728 static int compare_vbd_rsect(xenstat_domain *domain1, xenstat_domain *domain2)
729 {
730 	return -compare(tot_vbd_reqs(domain1, FIELD_VBD_RSECT),
731 			tot_vbd_reqs(domain2, FIELD_VBD_RSECT));
732 }
733 
734 /* Prints number of total VBD READ sectors statistic */
print_vbd_rsect(xenstat_domain * domain)735 static void print_vbd_rsect(xenstat_domain *domain)
736 {
737 	print("%*llu", fields[FIELD_VBD_RSECT-1].default_width, tot_vbd_reqs(domain, FIELD_VBD_RSECT));
738 }
739 
740 /* Compares number of total VBD WRITE sectors of two domains,
741    returning -1,0,1 * for <,=,> */
compare_vbd_wsect(xenstat_domain * domain1,xenstat_domain * domain2)742 static int compare_vbd_wsect(xenstat_domain *domain1, xenstat_domain *domain2)
743 {
744 	return -compare(tot_vbd_reqs(domain1, FIELD_VBD_WSECT),
745 			tot_vbd_reqs(domain2, FIELD_VBD_WSECT));
746 }
747 
748 /* Prints number of total VBD WRITE sectors statistic */
print_vbd_wsect(xenstat_domain * domain)749 static void print_vbd_wsect(xenstat_domain *domain)
750 {
751 	print("%*llu", fields[FIELD_VBD_WSECT-1].default_width, tot_vbd_reqs(domain, FIELD_VBD_WSECT));
752 }
753 
754 
755 /* Gets number of total VBD requests statistic,
756  *   if flag is FIELD_VBD_OO, then OO requests,
757  *   if flag is FIELD_VBD_RD, then READ requests,
758  *   if flag is FIELD_VBD_WR, then WRITE requests,
759  *   if flag is FIELD_VBD_RSECT, then READ sectors,
760  *   if flag is FIELD_VBD_WSECT, then WRITE sectors.
761  */
tot_vbd_reqs(xenstat_domain * domain,int flag)762 static unsigned long long tot_vbd_reqs(xenstat_domain *domain, int flag)
763 {
764 	int i = 0;
765 	xenstat_vbd *vbd;
766 	unsigned num_vbds = 0;
767 	unsigned long long total = 0;
768 
769 	num_vbds = xenstat_domain_num_vbds(domain);
770 
771 	for ( i=0 ; i < num_vbds ; i++) {
772 		vbd = xenstat_domain_vbd(domain,i);
773 		switch(flag) {
774 		case FIELD_VBD_OO:
775 			total += xenstat_vbd_oo_reqs(vbd);
776 			break;
777 		case FIELD_VBD_RD:
778 			total += xenstat_vbd_rd_reqs(vbd);
779 			break;
780 		case FIELD_VBD_WR:
781 			total += xenstat_vbd_wr_reqs(vbd);
782 			break;
783 		case FIELD_VBD_RSECT:
784 			total += xenstat_vbd_rd_sects(vbd);
785 			break;
786 		case FIELD_VBD_WSECT:
787 			total += xenstat_vbd_wr_sects(vbd);
788 			break;
789 		default:
790 			break;
791 		}
792 	}
793 
794 	return total;
795 }
796 
797 /* Compares security id (ssid) of two domains, returning -1,0,1 for <,=,> */
compare_ssid(xenstat_domain * domain1,xenstat_domain * domain2)798 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2)
799 {
800 	return compare(xenstat_domain_ssid(domain1),
801 		       xenstat_domain_ssid(domain2));
802 }
803 
804 /* Prints ssid statistic */
print_ssid(xenstat_domain * domain)805 static void print_ssid(xenstat_domain *domain)
806 {
807 	print("%4u", xenstat_domain_ssid(domain));
808 }
809 
810 /* Resets default_width for fields with potentially large numbers */
reset_field_widths(void)811 void reset_field_widths(void)
812 {
813 	fields[FIELD_NET_TX-1].default_width = 8;
814 	fields[FIELD_NET_RX-1].default_width = 8;
815 	fields[FIELD_VBD_RD-1].default_width = 8;
816 	fields[FIELD_VBD_WR-1].default_width = 8;
817 	fields[FIELD_VBD_RSECT-1].default_width = 10;
818 	fields[FIELD_VBD_WSECT-1].default_width = 10;
819 }
820 
821 /* Adjusts default_width for fields with potentially large numbers */
adjust_field_widths(xenstat_domain * domain)822 void adjust_field_widths(xenstat_domain *domain)
823 {
824 	unsigned int length;
825 
826 	if (show_full_name) {
827 		length = strlen(xenstat_domain_name(domain));
828 		if (length > fields[FIELD_NAME-1].default_width)
829 			fields[FIELD_NAME-1].default_width = length;
830 	}
831 
832 	length = INT_FIELD_WIDTH((tot_net_bytes(domain, FALSE)/1024) + 1);
833 	if (length > fields[FIELD_NET_TX-1].default_width)
834 		fields[FIELD_NET_TX-1].default_width = length;
835 
836 	length = INT_FIELD_WIDTH((tot_net_bytes(domain, TRUE)/1024) + 1);
837 	if (length > fields[FIELD_NET_RX-1].default_width)
838 		fields[FIELD_NET_RX-1].default_width = length;
839 
840 	length = INT_FIELD_WIDTH((tot_vbd_reqs(domain, FIELD_VBD_RD)) + 1);
841 	if (length > fields[FIELD_VBD_RD-1].default_width)
842 		fields[FIELD_VBD_RD-1].default_width = length;
843 
844 	length = INT_FIELD_WIDTH((tot_vbd_reqs(domain, FIELD_VBD_WR)) + 1);
845 	if (length > fields[FIELD_VBD_WR-1].default_width)
846 		fields[FIELD_VBD_WR-1].default_width = length;
847 
848 	length = INT_FIELD_WIDTH((tot_vbd_reqs(domain, FIELD_VBD_RSECT)) + 1);
849 	if (length > fields[FIELD_VBD_RSECT-1].default_width)
850 		fields[FIELD_VBD_RSECT-1].default_width = length;
851 
852 	length = INT_FIELD_WIDTH((tot_vbd_reqs(domain, FIELD_VBD_WSECT)) + 1);
853 	if (length > fields[FIELD_VBD_WSECT-1].default_width)
854 		fields[FIELD_VBD_WSECT-1].default_width = length;
855 }
856 
857 
858 /* Section printing functions */
859 /* Prints the top summary, above the domain table */
do_summary(void)860 void do_summary(void)
861 {
862 #define TIME_STR_LEN 9
863 	const char *TIME_STR_FORMAT = "%H:%M:%S";
864 	char time_str[TIME_STR_LEN];
865 	const char *ver_str;
866 	unsigned run = 0, block = 0, pause = 0,
867 	         crash = 0, dying = 0, shutdown = 0;
868 	unsigned i, num_domains = 0;
869 	unsigned long long used = 0;
870 	long freeable_mb = 0;
871 	xenstat_domain *domain;
872 	time_t curt;
873 
874 	/* Print program name, current time, and number of domains */
875 	curt = curtime.tv_sec;
876 	strftime(time_str, TIME_STR_LEN, TIME_STR_FORMAT, localtime(&curt));
877 	num_domains = xenstat_node_num_domains(cur_node);
878 	ver_str = xenstat_node_xen_version(cur_node);
879 	print("xentop - %s   Xen %s\n", time_str, ver_str);
880 
881 	/* Tabulate what states domains are in for summary */
882 	for (i=0; i < num_domains; i++) {
883 		domain = xenstat_node_domain_by_index(cur_node,i);
884 		if (xenstat_domain_running(domain)) run++;
885 		else if (xenstat_domain_blocked(domain)) block++;
886 		else if (xenstat_domain_paused(domain)) pause++;
887 		else if (xenstat_domain_shutdown(domain)) shutdown++;
888 		else if (xenstat_domain_crashed(domain)) crash++;
889 		else if (xenstat_domain_dying(domain)) dying++;
890 	}
891 
892 	print("%u domains: %u running, %u blocked, %u paused, "
893 	      "%u crashed, %u dying, %u shutdown \n",
894 	      num_domains, run, block, pause, crash, dying, shutdown);
895 
896 	used = xenstat_node_tot_mem(cur_node)-xenstat_node_free_mem(cur_node);
897 	freeable_mb = xenstat_node_freeable_mb(cur_node);
898 
899 	/* Dump node memory and cpu information */
900 	if ( freeable_mb <= 0 )
901 	     print("Mem: %lluk total, %lluk used, %lluk free    ",
902 	      xenstat_node_tot_mem(cur_node)/1024, used/1024,
903 	      xenstat_node_free_mem(cur_node)/1024);
904 	else
905 	     print("Mem: %lluk total, %lluk used, %lluk free, %ldk freeable, ",
906 	      xenstat_node_tot_mem(cur_node)/1024, used/1024,
907 	      xenstat_node_free_mem(cur_node)/1024, freeable_mb*1024);
908 	print("CPUs: %u @ %lluMHz\n",
909 	      xenstat_node_num_cpus(cur_node),
910 	      xenstat_node_cpu_hz(cur_node)/1000000);
911 }
912 
913 /* Display the top header for the domain table */
do_header(void)914 void do_header(void)
915 {
916 	field_id i;
917 
918 	/* Turn on REVERSE highlight attribute for headings */
919 	xentop_attron(A_REVERSE);
920 	for(i = 0; i < NUM_FIELDS; i++) {
921 		if (i != 0)
922 			print(" ");
923 		/* The BOLD attribute is turned on for the sort column */
924 		if (i == sort_field)
925 			xentop_attron(A_BOLD);
926 		print("%*s", fields[i].default_width, fields[i].header);
927 		if (i == sort_field)
928 			xentop_attroff(A_BOLD);
929 	}
930 	xentop_attroff(A_REVERSE);
931 	print("\n");
932 }
933 
934 /* Displays bottom status line or current prompt */
do_bottom_line(void)935 void do_bottom_line(void)
936 {
937 	move(lines()-1, 2);
938 
939 	if (prompt != NULL) {
940 		printw("%s: %s", prompt, prompt_val);
941 	} else {
942 		addch(A_REVERSE | 'D'); addstr("elay  ");
943 
944 		/* network */
945 		addch(A_REVERSE | 'N');
946 		attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks");
947 		addstr("  ");
948 
949 		/* VBDs */
950 		attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "v");
951 		addch(A_REVERSE | 'B');
952 		attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "ds");
953 		addstr("  ");
954 
955 		/* tmem */
956 		addch(A_REVERSE | 'T');
957 		attr_addstr(show_tmem ? COLOR_PAIR(1) : 0, "mem");
958 		addstr("  ");
959 
960 
961 		/* vcpus */
962 		addch(A_REVERSE | 'V');
963 		attr_addstr(show_vcpus ? COLOR_PAIR(1) : 0, "CPUs");
964 		addstr("  ");
965 
966 		/* repeat */
967 		addch(A_REVERSE | 'R');
968 		attr_addstr(repeat_header ? COLOR_PAIR(1) : 0, "epeat header");
969 		addstr("  ");
970 
971 		/* sort order */
972 		addch(A_REVERSE | 'S'); addstr("ort order  ");
973 
974 		addch(A_REVERSE | 'Q'); addstr("uit  ");
975 	}
976 }
977 
978 /* Prints Domain information */
do_domain(xenstat_domain * domain)979 void do_domain(xenstat_domain *domain)
980 {
981 	unsigned int i;
982 	for (i = 0; i < NUM_FIELDS; i++) {
983 		if (i != 0)
984 			print(" ");
985 		if (i == sort_field)
986 			xentop_attron(A_BOLD);
987 		fields[i].print(domain);
988 		if (i == sort_field)
989 			xentop_attroff(A_BOLD);
990 	}
991 	print("\n");
992 }
993 
994 /* Output all vcpu information */
do_vcpu(xenstat_domain * domain)995 void do_vcpu(xenstat_domain *domain)
996 {
997 	int i = 0;
998 	unsigned num_vcpus = 0;
999 	xenstat_vcpu *vcpu;
1000 
1001 	print("VCPUs(sec): ");
1002 
1003 	num_vcpus = xenstat_domain_num_vcpus(domain);
1004 
1005 	/* for all online vcpus dump out values */
1006 	for (i=0; i< num_vcpus; i++) {
1007 		vcpu = xenstat_domain_vcpu(domain,i);
1008 
1009 		if (xenstat_vcpu_online(vcpu) > 0) {
1010 			if (i != 0 && (i%5)==0)
1011 				print("\n        ");
1012 			print(" %2u: %10llus", i,
1013 					xenstat_vcpu_ns(vcpu)/1000000000);
1014 		}
1015 	}
1016 	print("\n");
1017 }
1018 
1019 /* Output all network information */
do_network(xenstat_domain * domain)1020 void do_network(xenstat_domain *domain)
1021 {
1022 	int i = 0;
1023 	xenstat_network *network;
1024 	unsigned num_networks = 0;
1025 
1026 	/* How many networks? */
1027 	num_networks = xenstat_domain_num_networks(domain);
1028 
1029 	/* Dump information for each network */
1030 	for (i=0; i < num_networks; i++) {
1031 		/* Next get the network information */
1032 		network = xenstat_domain_network(domain,i);
1033 
1034 		print("Net%d RX: %8llubytes %8llupkts %8lluerr %8lludrop  ",
1035 		      i,
1036 		      xenstat_network_rbytes(network),
1037 		      xenstat_network_rpackets(network),
1038 		      xenstat_network_rerrs(network),
1039 		      xenstat_network_rdrop(network));
1040 
1041 		print("TX: %8llubytes %8llupkts %8lluerr %8lludrop\n",
1042 		      xenstat_network_tbytes(network),
1043 		      xenstat_network_tpackets(network),
1044 		      xenstat_network_terrs(network),
1045 		      xenstat_network_tdrop(network));
1046 	}
1047 }
1048 
1049 
1050 /* Output all VBD information */
do_vbd(xenstat_domain * domain)1051 void do_vbd(xenstat_domain *domain)
1052 {
1053 	int i = 0;
1054 	xenstat_vbd *vbd;
1055 	unsigned num_vbds = 0;
1056 
1057 	const char *vbd_type[] = {
1058 		"Unidentified",           /* number 0 */
1059 		"BlkBack",           /* number 1 */
1060 		"BlkTap",            /* number 2 */
1061 	};
1062 
1063 	num_vbds = xenstat_domain_num_vbds(domain);
1064 
1065 	for (i=0 ; i< num_vbds; i++) {
1066 		char details[20];
1067 
1068 		vbd = xenstat_domain_vbd(domain,i);
1069 
1070 #if !defined(__linux__)
1071 		details[0] = '\0';
1072 #else
1073 		snprintf(details, 20, "[%2x:%2x] ",
1074 			 MAJOR(xenstat_vbd_dev(vbd)),
1075 			 MINOR(xenstat_vbd_dev(vbd)));
1076 #endif
1077 
1078 		print("VBD %s %4d %s OO: %8llu   RD: %8llu   WR: %8llu   RSECT: %10llu   WSECT: %10llu\n",
1079 		      vbd_type[xenstat_vbd_type(vbd)],
1080 		      xenstat_vbd_dev(vbd), details,
1081 		      xenstat_vbd_oo_reqs(vbd),
1082 		      xenstat_vbd_rd_reqs(vbd),
1083 		      xenstat_vbd_wr_reqs(vbd),
1084 		      xenstat_vbd_rd_sects(vbd),
1085 		      xenstat_vbd_wr_sects(vbd));
1086 	}
1087 }
1088 
1089 /* Output all tmem information */
do_tmem(xenstat_domain * domain)1090 void do_tmem(xenstat_domain *domain)
1091 {
1092 	xenstat_tmem *tmem = xenstat_domain_tmem(domain);
1093 	unsigned long long curr_eph_pages = xenstat_tmem_curr_eph_pages(tmem);
1094 	unsigned long long succ_eph_gets = xenstat_tmem_succ_eph_gets(tmem);
1095 	unsigned long long succ_pers_puts = xenstat_tmem_succ_pers_puts(tmem);
1096 	unsigned long long succ_pers_gets = xenstat_tmem_succ_pers_gets(tmem);
1097 
1098 	if (curr_eph_pages | succ_eph_gets | succ_pers_puts | succ_pers_gets)
1099 		print("Tmem:  Curr eph pages: %8llu   Succ eph gets: %8llu   "
1100 	              "Succ pers puts: %8llu   Succ pers gets: %8llu\n",
1101 			curr_eph_pages, succ_eph_gets,
1102 			succ_pers_puts, succ_pers_gets);
1103 
1104 }
1105 
top(void)1106 static void top(void)
1107 {
1108 	xenstat_domain **domains;
1109 	unsigned int i, num_domains = 0;
1110 
1111 	/* Now get the node information */
1112 	if (prev_node != NULL)
1113 		xenstat_free_node(prev_node);
1114 	prev_node = cur_node;
1115 	cur_node = xenstat_get_node(xhandle, XENSTAT_ALL);
1116 	if (cur_node == NULL)
1117 		fail("Failed to retrieve statistics from libxenstat\n");
1118 
1119 	/* dump summary top information */
1120 	if (!batch)
1121 		do_summary();
1122 
1123 	/* Count the number of domains for which to report data */
1124 	num_domains = xenstat_node_num_domains(cur_node);
1125 
1126 	domains = calloc(num_domains, sizeof(xenstat_domain *));
1127 	if(domains == NULL)
1128 		fail("Failed to allocate memory\n");
1129 
1130 	for (i=0; i < num_domains; i++)
1131 		domains[i] = xenstat_node_domain_by_index(cur_node, i);
1132 
1133 	/* Sort */
1134 	qsort(domains, num_domains, sizeof(xenstat_domain *),
1135 	      (int(*)(const void *, const void *))compare_domains);
1136 
1137 	if(first_domain_index >= num_domains)
1138 		first_domain_index = num_domains-1;
1139 
1140 	/* Adjust default_width for fields with potentially large numbers */
1141 	reset_field_widths();
1142 	for (i = first_domain_index; i < num_domains; i++) {
1143 		adjust_field_widths(domains[i]);
1144 	}
1145 
1146 	for (i = first_domain_index; i < num_domains; i++) {
1147 		if(!batch && current_row() == lines()-1)
1148 			break;
1149 		if (i == first_domain_index || repeat_header)
1150 			do_header();
1151 		do_domain(domains[i]);
1152 		if (show_vcpus)
1153 			do_vcpu(domains[i]);
1154 		if (show_networks)
1155 			do_network(domains[i]);
1156 		if (show_vbds)
1157 			do_vbd(domains[i]);
1158 		if (show_tmem)
1159 			do_tmem(domains[i]);
1160 	}
1161 
1162 	if (!batch)
1163 		do_bottom_line();
1164 
1165 	free(domains);
1166 }
1167 
1168 static int signal_exit;
1169 
signal_exit_handler(int sig)1170 static void signal_exit_handler(int sig)
1171 {
1172 	signal_exit = 1;
1173 }
1174 
main(int argc,char ** argv)1175 int main(int argc, char **argv)
1176 {
1177 	int opt, optind = 0;
1178 	int ch = ERR;
1179 
1180 	struct option lopts[] = {
1181 		{ "help",          no_argument,       NULL, 'h' },
1182 		{ "version",       no_argument,       NULL, 'V' },
1183 		{ "networks",      no_argument,       NULL, 'n' },
1184 		{ "vbds",          no_argument,       NULL, 'x' },
1185 		{ "repeat-header", no_argument,       NULL, 'r' },
1186 		{ "vcpus",         no_argument,       NULL, 'v' },
1187 		{ "delay",         required_argument, NULL, 'd' },
1188 		{ "batch",	   no_argument,	      NULL, 'b' },
1189 		{ "iterations",	   required_argument, NULL, 'i' },
1190 		{ "full-name",     no_argument,       NULL, 'f' },
1191 		{ 0, 0, 0, 0 },
1192 	};
1193 	const char *sopts = "hVnxrvd:bi:f";
1194 
1195 	if (atexit(cleanup) != 0)
1196 		fail("Failed to install cleanup handler.\n");
1197 
1198 	while ((opt = getopt_long(argc, argv, sopts, lopts, &optind)) != -1) {
1199 		switch (opt) {
1200 		default:
1201 			usage(argv[0]);
1202 			exit(1);
1203 		case '?':
1204 		case 'h':
1205 			usage(argv[0]);
1206 			exit(0);
1207 		case 'V':
1208 			version();
1209 			exit(0);
1210 		case 'n':
1211 			show_networks = 1;
1212 			break;
1213 		case 'x':
1214 			show_vbds = 1;
1215 			break;
1216 		case 'r':
1217 			repeat_header = 1;
1218 			break;
1219 		case 'v':
1220 			show_vcpus = 1;
1221 			break;
1222 		case 'd':
1223 			delay = atoi(optarg);
1224 			break;
1225 		case 'b':
1226 			batch = 1;
1227 			break;
1228 		case 'i':
1229 			iterations = atoi(optarg);
1230 			loop = 0;
1231 			break;
1232 		case 'f':
1233 			show_full_name = 1;
1234 			break;
1235 		case 't':
1236 			show_tmem = 1;
1237 			break;
1238 		}
1239 	}
1240 
1241 	/* Get xenstat handle */
1242 	xhandle = xenstat_init();
1243 	if (xhandle == NULL)
1244 		fail("Failed to initialize xenstat library\n");
1245 
1246 	if (!batch) {
1247 		/* Begin curses stuff */
1248 		cwin = initscr();
1249 		start_color();
1250 		cbreak();
1251 		noecho();
1252 		nonl();
1253 		keypad(stdscr, TRUE);
1254 		halfdelay(5);
1255 #ifndef __sun__
1256 		use_default_colors();
1257 #endif
1258 		init_pair(1, -1, COLOR_YELLOW);
1259 
1260 		do {
1261 			gettimeofday(&curtime, NULL);
1262 			if(ch != ERR || (curtime.tv_sec - oldtime.tv_sec) >= delay) {
1263 				erase();
1264 				top();
1265 				oldtime = curtime;
1266 				refresh();
1267 				if ((!loop) && !(--iterations))
1268 					break;
1269 			}
1270 			ch = getch();
1271 		} while (handle_key(ch));
1272 	} else {
1273 		struct sigaction sa = {
1274 			.sa_handler = signal_exit_handler,
1275 			.sa_flags = 0
1276 		};
1277 		sigemptyset(&sa.sa_mask);
1278 		sigaction(SIGINT, &sa, NULL);
1279 		sigaction(SIGTERM, &sa, NULL);
1280 
1281 		do {
1282 			gettimeofday(&curtime, NULL);
1283 			top();
1284 			fflush(stdout);
1285 			oldtime = curtime;
1286 			if ((!loop) && !(--iterations))
1287 				break;
1288 			sleep(delay);
1289 		} while (!signal_exit);
1290 	}
1291 
1292 	/* Cleanup occurs in cleanup(), so no work to do here. */
1293 
1294 	return 0;
1295 }
1296