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 bool tot_vbd_reqs(xenstat_domain *, int, unsigned long long *);
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 repeat_header = 0;
213 int show_full_name = 0;
214 #define PROMPT_VAL_LEN 80
215 char *prompt = NULL;
216 char prompt_val[PROMPT_VAL_LEN];
217 int prompt_val_len = 0;
218 void (*prompt_complete_func)(char *);
219 
220 static WINDOW *cwin;
221 
222 /*
223  * Function definitions
224  */
225 
226 /* Utility functions */
227 
228 /* Print usage message, using given program name */
usage(const char * program)229 static void usage(const char *program)
230 {
231 	printf("Usage: %s [OPTION]\n"
232 	       "Displays ongoing information about xen vm resources \n\n"
233 	       "-h, --help           display this help and exit\n"
234 	       "-V, --version        output version information and exit\n"
235 	       "-d, --delay=SECONDS  seconds between updates (default 3)\n"
236 	       "-n, --networks       output vif network data\n"
237 	       "-x, --vbds           output vbd block device data\n"
238 	       "-r, --repeat-header  repeat table header before each domain\n"
239 	       "-v, --vcpus          output vcpu data\n"
240 	       "-b, --batch	     output in batch mode, no user input accepted\n"
241 	       "-i, --iterations     number of iterations before exiting\n"
242 	       "-f, --full-name      output the full domain name (not truncated)\n"
243 	       "\n" XENTOP_BUGSTO,
244 	       program);
245 	return;
246 }
247 
248 /* Print program version information */
version(void)249 static void version(void)
250 {
251 	printf("xentop " XENTOP_VERSION "\n"
252 	       "Written by Judy Fischbach, David Hendricks, Josh Triplett\n"
253 	       "\n" XENTOP_DISCLAIMER);
254 }
255 
256 /* Clean up any open resources */
cleanup(void)257 static void cleanup(void)
258 {
259 	if(cwin != NULL && !isendwin())
260 		endwin();
261 	if(prev_node != NULL)
262 		xenstat_free_node(prev_node);
263 	if(cur_node != NULL)
264 		xenstat_free_node(cur_node);
265 	if(xhandle != NULL)
266 		xenstat_uninit(xhandle);
267 }
268 
269 /* Display the given message and gracefully exit */
fail(const char * str)270 static void fail(const char *str)
271 {
272 	if(cwin != NULL && !isendwin())
273 		endwin();
274 	fprintf(stderr, "%s", str);
275 	exit(1);
276 }
277 
278 /* Return the row containing the cursor. */
current_row(void)279 static int current_row(void)
280 {
281 	int y, x;
282 	getyx(stdscr, y, x);
283 	return y;
284 }
285 
286 /* Return the number of lines on the screen. */
lines(void)287 static int lines(void)
288 {
289 	int y, x;
290 	getmaxyx(stdscr, y, x);
291 	return y;
292 }
293 
294 /* printf-style print function which calls printw, but only if the cursor is
295  * not on the last line. */
print(const char * fmt,...)296 static void print(const char *fmt, ...)
297 {
298 	va_list args;
299 
300 	if (!batch) {
301 		if((current_row() < lines()-1)) {
302 			va_start(args, fmt);
303 			vw_printw(stdscr, (curses_str_t)fmt, args);
304 			va_end(args);
305 		}
306 	} else {
307 		va_start(args, fmt);
308 		vprintf(fmt, args);
309 		va_end(args);
310 	}
311 }
312 
xentop_attron(int attr)313 static void xentop_attron(int attr)
314 {
315 	if (!batch)
316 		attron(attr);
317 }
318 
xentop_attroff(int attr)319 static void xentop_attroff(int attr)
320 {
321 	if (!batch)
322 		attroff(attr);
323 }
324 
325 /* Print a string with the given attributes set. */
attr_addstr(int attr,const char * str)326 static void attr_addstr(int attr, const char *str)
327 {
328 	xentop_attron(attr);
329 	addstr((curses_str_t)str);
330 	xentop_attroff(attr);
331 }
332 
333 /* Handle setting the delay from the user-supplied value in prompt_val */
set_delay(char * value)334 static void set_delay(char *value)
335 {
336 	int new_delay;
337 	new_delay = atoi(value);
338 	if(new_delay > 0)
339 		delay = new_delay;
340 }
341 
342 /* Enable prompting mode with the given prompt string; call the given function
343  * when a value is available. */
set_prompt(char * new_prompt,void (* func)(char *))344 static void set_prompt(char *new_prompt, void (*func)(char *))
345 {
346 	prompt = new_prompt;
347 	prompt_val[0] = '\0';
348 	prompt_val_len = 0;
349 	prompt_complete_func = func;
350 }
351 
352 /* Handle user input, return 0 if the program should quit, or 1 if not */
handle_key(int ch)353 static int handle_key(int ch)
354 {
355 	if(prompt == NULL) {
356 		/* Not prompting for input; handle interactive commands */
357 		switch(ch) {
358 		case 'n': case 'N':
359 			show_networks ^= 1;
360 			break;
361 		case 'b': case 'B':
362 			show_vbds ^= 1;
363 			break;
364 		case 'r': case 'R':
365 			repeat_header ^= 1;
366 			break;
367 		case 's': case 'S':
368 			sort_field = (sort_field + 1) % NUM_FIELDS;
369 			break;
370 		case 'v': case 'V':
371 			show_vcpus ^= 1;
372 			break;
373 		case KEY_DOWN:
374 			first_domain_index++;
375 			break;
376 		case KEY_UP:
377 			if(first_domain_index > 0)
378 				first_domain_index--;
379 			break;
380 		case 'd': case 'D':
381 			set_prompt("Delay(sec)", set_delay);
382 			break;
383 		case KEY_REPAINT:
384 			clear();
385 			break;
386 		case 'q': case 'Q': case KEY_ESCAPE:
387 			return 0;
388 		}
389 	} else {
390 		/* Prompting for input; handle line editing */
391 		switch(ch) {
392 		case '\r':
393 			prompt_complete_func(prompt_val);
394 			set_prompt(NULL, NULL);
395 			break;
396 		case KEY_ESCAPE:
397 			set_prompt(NULL, NULL);
398 			break;
399 		case KEY_BACKSPACE:
400 			if(prompt_val_len > 0)
401 				prompt_val[--prompt_val_len] = '\0';
402                         break;
403 		default:
404 			if((prompt_val_len+1) < PROMPT_VAL_LEN
405 			   && isprint(ch)) {
406 				prompt_val[prompt_val_len++] = (char)ch;
407 				prompt_val[prompt_val_len] = '\0';
408 			}
409 		}
410 	}
411 
412 	return 1;
413 }
414 
415 /* Compares two integers, returning -1,0,1 for <,=,> */
compare(unsigned long long i1,unsigned long long i2)416 static int compare(unsigned long long i1, unsigned long long i2)
417 {
418 	if(i1 < i2)
419 		return -1;
420 	if(i1 > i2)
421 		return 1;
422 	return 0;
423 }
424 
425 /* Comparison function for use with qsort.  Compares two domains using the
426  * current sort field. */
compare_domains(xenstat_domain ** domain1,xenstat_domain ** domain2)427 static int compare_domains(xenstat_domain **domain1, xenstat_domain **domain2)
428 {
429 	return fields[sort_field].compare(*domain1, *domain2);
430 }
431 
432 /* Field functions */
433 
434 /* Compare domain names, returning -1,0,1 for <,=,> */
compare_name(xenstat_domain * domain1,xenstat_domain * domain2)435 int compare_name(xenstat_domain *domain1, xenstat_domain *domain2)
436 {
437 	return strcasecmp(xenstat_domain_name(domain1), xenstat_domain_name(domain2));
438 }
439 
440 /* Prints domain name */
print_name(xenstat_domain * domain)441 void print_name(xenstat_domain *domain)
442 {
443 	if(show_full_name)
444 		print("%*s", fields[FIELD_NAME-1].default_width, xenstat_domain_name(domain));
445 	else
446 		print("%10.10s", xenstat_domain_name(domain));
447 }
448 
449 struct {
450 	unsigned int (*get)(xenstat_domain *);
451 	char ch;
452 } state_funcs[] = {
453 	{ xenstat_domain_dying,    'd' },
454 	{ xenstat_domain_shutdown, 's' },
455 	{ xenstat_domain_blocked,  'b' },
456 	{ xenstat_domain_crashed,  'c' },
457 	{ xenstat_domain_paused,   'p' },
458 	{ xenstat_domain_running,  'r' }
459 };
460 const unsigned int NUM_STATES = sizeof(state_funcs)/sizeof(*state_funcs);
461 
462 /* Compare states of two domains, returning -1,0,1 for <,=,> */
compare_state(xenstat_domain * domain1,xenstat_domain * domain2)463 static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2)
464 {
465 	unsigned int i, d1s, d2s;
466 	for(i = 0; i < NUM_STATES; i++) {
467 		d1s = state_funcs[i].get(domain1);
468 		d2s = state_funcs[i].get(domain2);
469 		if(d1s && !d2s)
470 			return -1;
471 		if(d2s && !d1s)
472 			return 1;
473 	}
474 	return 0;
475 }
476 
477 /* Prints domain state in abbreviated letter format */
print_state(xenstat_domain * domain)478 static void print_state(xenstat_domain *domain)
479 {
480 	unsigned int i;
481 	for(i = 0; i < NUM_STATES; i++)
482 		print("%c", state_funcs[i].get(domain) ? state_funcs[i].ch
483 		                                       : '-');
484 }
485 
486 /* Compares cpu usage of two domains, returning -1,0,1 for <,=,> */
compare_cpu(xenstat_domain * domain1,xenstat_domain * domain2)487 static int compare_cpu(xenstat_domain *domain1, xenstat_domain *domain2)
488 {
489 	return -compare(xenstat_domain_cpu_ns(domain1),
490 			xenstat_domain_cpu_ns(domain2));
491 }
492 
493 /* Prints domain cpu usage in seconds */
print_cpu(xenstat_domain * domain)494 static void print_cpu(xenstat_domain *domain)
495 {
496 	print("%10llu", xenstat_domain_cpu_ns(domain)/1000000000);
497 }
498 
499 /* Computes the CPU percentage used for a specified domain */
get_cpu_pct(xenstat_domain * domain)500 static double get_cpu_pct(xenstat_domain *domain)
501 {
502 	xenstat_domain *old_domain;
503 	double us_elapsed;
504 
505 	/* Can't calculate CPU percentage without a previous sample. */
506 	if(prev_node == NULL)
507 		return 0.0;
508 
509 	old_domain = xenstat_node_domain(prev_node, xenstat_domain_id(domain));
510 	if(old_domain == NULL)
511 		return 0.0;
512 
513 	/* Calculate the time elapsed in microseconds */
514 	us_elapsed = ((curtime.tv_sec-oldtime.tv_sec)*1000000.0
515 		      +(curtime.tv_usec - oldtime.tv_usec));
516 
517 	/* In the following, nanoseconds must be multiplied by 1000.0 to
518 	 * convert to microseconds, then divided by 100.0 to get a percentage,
519 	 * resulting in a multiplication by 10.0 */
520 	return ((xenstat_domain_cpu_ns(domain)
521 		 -xenstat_domain_cpu_ns(old_domain))/10.0)/us_elapsed;
522 }
523 
compare_cpu_pct(xenstat_domain * domain1,xenstat_domain * domain2)524 static int compare_cpu_pct(xenstat_domain *domain1, xenstat_domain *domain2)
525 {
526 	return -compare(get_cpu_pct(domain1), get_cpu_pct(domain2));
527 }
528 
529 /* Prints cpu percentage statistic */
print_cpu_pct(xenstat_domain * domain)530 static void print_cpu_pct(xenstat_domain *domain)
531 {
532 	print("%6.1f", get_cpu_pct(domain));
533 }
534 
535 /* Compares current memory of two domains, returning -1,0,1 for <,=,> */
compare_mem(xenstat_domain * domain1,xenstat_domain * domain2)536 static int compare_mem(xenstat_domain *domain1, xenstat_domain *domain2)
537 {
538 	return -compare(xenstat_domain_cur_mem(domain1),
539 	                xenstat_domain_cur_mem(domain2));
540 }
541 
542 /* Prints current memory statistic */
print_mem(xenstat_domain * domain)543 static void print_mem(xenstat_domain *domain)
544 {
545 	print("%10llu", xenstat_domain_cur_mem(domain)/1024);
546 }
547 
548 /* Prints memory percentage statistic, ratio of current domain memory to total
549  * node memory */
print_mem_pct(xenstat_domain * domain)550 static void print_mem_pct(xenstat_domain *domain)
551 {
552 	print("%6.1f", (double)xenstat_domain_cur_mem(domain) /
553 	               (double)xenstat_node_tot_mem(cur_node) * 100);
554 }
555 
556 /* Compares maximum memory of two domains, returning -1,0,1 for <,=,> */
compare_maxmem(xenstat_domain * domain1,xenstat_domain * domain2)557 static int compare_maxmem(xenstat_domain *domain1, xenstat_domain *domain2)
558 {
559 	return -compare(xenstat_domain_max_mem(domain1),
560 	                xenstat_domain_max_mem(domain2));
561 }
562 
563 /* Prints maximum domain memory statistic in KB */
print_maxmem(xenstat_domain * domain)564 static void print_maxmem(xenstat_domain *domain)
565 {
566 	unsigned long long max_mem = xenstat_domain_max_mem(domain);
567 	if(max_mem == ((unsigned long long)-1))
568 		print("%10s", "no limit");
569 	else
570 		print("%10llu", max_mem/1024);
571 }
572 
573 /* Prints memory percentage statistic, ratio of current domain memory to total
574  * node memory */
print_max_pct(xenstat_domain * domain)575 static void print_max_pct(xenstat_domain *domain)
576 {
577 	if (xenstat_domain_max_mem(domain) == (unsigned long long)-1)
578 		print("%9s", "n/a");
579 	else
580 		print("%9.1f", (double)xenstat_domain_max_mem(domain) /
581 		               (double)xenstat_node_tot_mem(cur_node) * 100);
582 }
583 
584 /* Compares number of virtual CPUs of two domains, returning -1,0,1 for
585  * <,=,> */
compare_vcpus(xenstat_domain * domain1,xenstat_domain * domain2)586 static int compare_vcpus(xenstat_domain *domain1, xenstat_domain *domain2)
587 {
588 	return -compare(xenstat_domain_num_vcpus(domain1),
589 	                xenstat_domain_num_vcpus(domain2));
590 }
591 
592 /* Prints number of virtual CPUs statistic */
print_vcpus(xenstat_domain * domain)593 static void print_vcpus(xenstat_domain *domain)
594 {
595 	print("%5u", xenstat_domain_num_vcpus(domain));
596 }
597 
598 /* Compares number of virtual networks of two domains, returning -1,0,1 for
599  * <,=,> */
compare_nets(xenstat_domain * domain1,xenstat_domain * domain2)600 static int compare_nets(xenstat_domain *domain1, xenstat_domain *domain2)
601 {
602 	return -compare(xenstat_domain_num_networks(domain1),
603 	                xenstat_domain_num_networks(domain2));
604 }
605 
606 /* Prints number of virtual networks statistic */
print_nets(xenstat_domain * domain)607 static void print_nets(xenstat_domain *domain)
608 {
609 	print("%4u", xenstat_domain_num_networks(domain));
610 }
611 
612 /* Compares number of total network tx bytes of two domains, returning -1,0,1
613  * for <,=,> */
compare_net_tx(xenstat_domain * domain1,xenstat_domain * domain2)614 static int compare_net_tx(xenstat_domain *domain1, xenstat_domain *domain2)
615 {
616 	return -compare(tot_net_bytes(domain1, FALSE),
617 	                tot_net_bytes(domain2, FALSE));
618 }
619 
620 /* Prints number of total network tx bytes statistic */
print_net_tx(xenstat_domain * domain)621 static void print_net_tx(xenstat_domain *domain)
622 {
623 	print("%*llu", fields[FIELD_NET_TX-1].default_width, tot_net_bytes(domain, FALSE)/1024);
624 }
625 
626 /* Compares number of total network rx bytes of two domains, returning -1,0,1
627  * for <,=,> */
compare_net_rx(xenstat_domain * domain1,xenstat_domain * domain2)628 static int compare_net_rx(xenstat_domain *domain1, xenstat_domain *domain2)
629 {
630 	return -compare(tot_net_bytes(domain1, TRUE),
631 	                tot_net_bytes(domain2, TRUE));
632 }
633 
634 /* Prints number of total network rx bytes statistic */
print_net_rx(xenstat_domain * domain)635 static void print_net_rx(xenstat_domain *domain)
636 {
637 	print("%*llu", fields[FIELD_NET_RX-1].default_width, tot_net_bytes(domain, TRUE)/1024);
638 }
639 
640 /* Gets number of total network bytes statistic, if rx true, then rx bytes
641  * otherwise tx bytes
642  */
tot_net_bytes(xenstat_domain * domain,int rx_flag)643 static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag)
644 {
645 	int i = 0;
646 	xenstat_network *network;
647 	unsigned num_networks = 0;
648 	unsigned long long total = 0;
649 
650 	/* How many networks? */
651 	num_networks = xenstat_domain_num_networks(domain);
652 
653 	/* Dump information for each network */
654 	for (i=0; i < num_networks; i++) {
655 		/* Next get the network information */
656 		network = xenstat_domain_network(domain,i);
657 		if (rx_flag)
658 			total += xenstat_network_rbytes(network);
659 		else
660 			total += xenstat_network_tbytes(network);
661 	}
662 
663 	return total;
664 }
665 
666 /* Compares number of virtual block devices of two domains,
667    returning -1,0,1 for * <,=,> */
compare_vbds(xenstat_domain * domain1,xenstat_domain * domain2)668 static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2)
669 {
670 	return -compare(xenstat_domain_num_vbds(domain1),
671 	                xenstat_domain_num_vbds(domain2));
672 }
673 
674 /* Prints number of virtual block devices statistic */
print_vbds(xenstat_domain * domain)675 static void print_vbds(xenstat_domain *domain)
676 {
677 	print("%4u", xenstat_domain_num_vbds(domain));
678 }
679 
680 /* Compares number of total VBD OO requests of two domains,
681    returning -1,0,1 * for <,=,> */
compare_vbd_oo(xenstat_domain * domain1,xenstat_domain * domain2)682 static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2)
683 {
684 	unsigned long long dom1_vbd_oo = 0, dom2_vbd_oo = 0;
685 
686 	tot_vbd_reqs(domain1, FIELD_VBD_OO, &dom1_vbd_oo);
687 	tot_vbd_reqs(domain1, FIELD_VBD_OO, &dom2_vbd_oo);
688 
689 	return -compare(dom1_vbd_oo, dom2_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 	unsigned long long vbd_oo;
696 
697 	if (tot_vbd_reqs(domain, FIELD_VBD_OO, &vbd_oo))
698 	{
699 		print("%8llu", vbd_oo);
700 	}
701 	else
702 	{
703 		print("%8c", '-');
704 	}
705 }
706 
707 /* Compares number of total VBD READ requests of two domains,
708    returning -1,0,1 * for <,=,> */
compare_vbd_rd(xenstat_domain * domain1,xenstat_domain * domain2)709 static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2)
710 {
711 	unsigned long long dom1_vbd_rd = 0, dom2_vbd_rd = 0;
712 
713 	tot_vbd_reqs(domain1, FIELD_VBD_RD, &dom1_vbd_rd);
714 	tot_vbd_reqs(domain1, FIELD_VBD_RD, &dom2_vbd_rd);
715 
716 	return -compare(dom1_vbd_rd, dom1_vbd_rd);
717 }
718 
719 /* Prints number of total VBD READ requests statistic */
print_vbd_rd(xenstat_domain * domain)720 static void print_vbd_rd(xenstat_domain *domain)
721 {
722 	unsigned long long vbd_rd;
723 
724 	if (tot_vbd_reqs(domain, FIELD_VBD_RD, &vbd_rd))
725 	{
726 		print("%*llu", fields[FIELD_VBD_RD-1].default_width, vbd_rd);
727 	}
728 	else
729 	{
730 		print("%*c", fields[FIELD_VBD_RD-1].default_width, '-');
731 	}
732 }
733 
734 /* Compares number of total VBD WRITE requests of two domains,
735    returning -1,0,1 * for <,=,> */
compare_vbd_wr(xenstat_domain * domain1,xenstat_domain * domain2)736 static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2)
737 {
738 	unsigned long long dom1_vbd_wr = 0, dom2_vbd_wr = 0;
739 
740 	tot_vbd_reqs(domain1, FIELD_VBD_WR, &dom1_vbd_wr);
741 	tot_vbd_reqs(domain1, FIELD_VBD_WR, &dom2_vbd_wr);
742 
743 	return -compare(dom1_vbd_wr, dom2_vbd_wr);
744 }
745 
746 /* Prints number of total VBD WRITE requests statistic */
print_vbd_wr(xenstat_domain * domain)747 static void print_vbd_wr(xenstat_domain *domain)
748 {
749 	unsigned long long vbd_wr;
750 
751 	if (tot_vbd_reqs(domain, FIELD_VBD_WR, &vbd_wr))
752 	{
753 		print("%*llu", fields[FIELD_VBD_WR-1].default_width, vbd_wr);
754 	}
755 	else
756 	{
757 		print("%*c", fields[FIELD_VBD_WR-1].default_width, '-');
758 	}
759 }
760 
761 /* Compares number of total VBD READ sectors of two domains,
762    returning -1,0,1 * for <,=,> */
compare_vbd_rsect(xenstat_domain * domain1,xenstat_domain * domain2)763 static int compare_vbd_rsect(xenstat_domain *domain1, xenstat_domain *domain2)
764 {
765 	unsigned long long dom1_vbd_rsect = 0, dom2_vbd_rsect = 0;
766 
767 	tot_vbd_reqs(domain1, FIELD_VBD_RSECT, &dom1_vbd_rsect);
768 	tot_vbd_reqs(domain1, FIELD_VBD_RSECT, &dom2_vbd_rsect);
769 
770 	return -compare(dom1_vbd_rsect, dom2_vbd_rsect);
771 }
772 
773 /* Prints number of total VBD READ sectors statistic */
print_vbd_rsect(xenstat_domain * domain)774 static void print_vbd_rsect(xenstat_domain *domain)
775 {
776 	unsigned long long vbd_rsect;
777 
778 	if (tot_vbd_reqs(domain, FIELD_VBD_RSECT, &vbd_rsect))
779 	{
780 		print("%*llu", fields[FIELD_VBD_RSECT-1].default_width, vbd_rsect);
781 	}
782 	else
783 	{
784 		print("%*c", fields[FIELD_VBD_RSECT-1].default_width, '-');
785 	}
786 }
787 
788 /* Compares number of total VBD WRITE sectors of two domains,
789    returning -1,0,1 * for <,=,> */
compare_vbd_wsect(xenstat_domain * domain1,xenstat_domain * domain2)790 static int compare_vbd_wsect(xenstat_domain *domain1, xenstat_domain *domain2)
791 {
792 	unsigned long long dom1_vbd_wsect = 0, dom2_vbd_wsect = 0;
793 
794 	tot_vbd_reqs(domain1, FIELD_VBD_WSECT, &dom1_vbd_wsect);
795 	tot_vbd_reqs(domain2, FIELD_VBD_WSECT, &dom2_vbd_wsect);
796 
797 	return -compare(dom1_vbd_wsect, dom2_vbd_wsect);
798 }
799 
800 /* Prints number of total VBD WRITE sectors statistic */
print_vbd_wsect(xenstat_domain * domain)801 static void print_vbd_wsect(xenstat_domain *domain)
802 {
803 	unsigned long long vbd_wsect;
804 
805 	if (tot_vbd_reqs(domain, FIELD_VBD_WSECT, &vbd_wsect))
806 	{
807 		print("%*llu", fields[FIELD_VBD_WSECT-1].default_width, vbd_wsect);
808 	}
809 	else
810 	{
811 		print("%*c", fields[FIELD_VBD_WSECT-1].default_width, '-');
812 	}
813 }
814 
815 
816 /* Gets number of total VBD requests statistic,
817  *   if flag is FIELD_VBD_OO, then OO requests,
818  *   if flag is FIELD_VBD_RD, then READ requests,
819  *   if flag is FIELD_VBD_WR, then WRITE requests,
820  *   if flag is FIELD_VBD_RSECT, then READ sectors,
821  *   if flag is FIELD_VBD_WSECT, then WRITE sectors.
822  */
tot_vbd_reqs(xenstat_domain * domain,int flag,unsigned long long * res)823 static bool tot_vbd_reqs(xenstat_domain *domain, int flag, unsigned long long *res)
824 {
825 	int i = 0;
826 	xenstat_vbd *vbd;
827 	unsigned num_vbds = 0;
828 	unsigned long long total = 0;
829 	bool show_stats = false;
830 
831 	num_vbds = xenstat_domain_num_vbds(domain);
832 	if (!num_vbds)
833 		show_stats = true;
834 
835 	for ( i=0 ; i < num_vbds ; i++) {
836 		vbd = xenstat_domain_vbd(domain,i);
837 		if (xenstat_vbd_error(vbd))
838 			continue;
839 		else
840 			show_stats = true;
841 
842 		switch(flag) {
843 		case FIELD_VBD_OO:
844 			total += xenstat_vbd_oo_reqs(vbd);
845 			break;
846 		case FIELD_VBD_RD:
847 			total += xenstat_vbd_rd_reqs(vbd);
848 			break;
849 		case FIELD_VBD_WR:
850 			total += xenstat_vbd_wr_reqs(vbd);
851 			break;
852 		case FIELD_VBD_RSECT:
853 			total += xenstat_vbd_rd_sects(vbd);
854 			break;
855 		case FIELD_VBD_WSECT:
856 			total += xenstat_vbd_wr_sects(vbd);
857 			break;
858 		default:
859 			break;
860 		}
861 	}
862 
863 	*res = total;
864 
865 	return show_stats;
866 }
867 
868 /* Compares security id (ssid) of two domains, returning -1,0,1 for <,=,> */
compare_ssid(xenstat_domain * domain1,xenstat_domain * domain2)869 static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2)
870 {
871 	return compare(xenstat_domain_ssid(domain1),
872 		       xenstat_domain_ssid(domain2));
873 }
874 
875 /* Prints ssid statistic */
print_ssid(xenstat_domain * domain)876 static void print_ssid(xenstat_domain *domain)
877 {
878 	print("%4u", xenstat_domain_ssid(domain));
879 }
880 
881 /* Resets default_width for fields with potentially large numbers */
reset_field_widths(void)882 void reset_field_widths(void)
883 {
884 	fields[FIELD_NET_TX-1].default_width = 8;
885 	fields[FIELD_NET_RX-1].default_width = 8;
886 	fields[FIELD_VBD_RD-1].default_width = 8;
887 	fields[FIELD_VBD_WR-1].default_width = 8;
888 	fields[FIELD_VBD_RSECT-1].default_width = 10;
889 	fields[FIELD_VBD_WSECT-1].default_width = 10;
890 }
891 
892 /* Adjusts default_width for fields with potentially large numbers */
adjust_field_widths(xenstat_domain * domain)893 void adjust_field_widths(xenstat_domain *domain)
894 {
895 	unsigned int length;
896 	unsigned long long vbd_rd, vbd_wr, vbd_rsect, vbd_wsect;
897 
898 	if (show_full_name) {
899 		length = strlen(xenstat_domain_name(domain));
900 		if (length > fields[FIELD_NAME-1].default_width)
901 			fields[FIELD_NAME-1].default_width = length;
902 	}
903 
904 	length = INT_FIELD_WIDTH((tot_net_bytes(domain, FALSE)/1024) + 1);
905 	if (length > fields[FIELD_NET_TX-1].default_width)
906 		fields[FIELD_NET_TX-1].default_width = length;
907 
908 	length = INT_FIELD_WIDTH((tot_net_bytes(domain, TRUE)/1024) + 1);
909 	if (length > fields[FIELD_NET_RX-1].default_width)
910 		fields[FIELD_NET_RX-1].default_width = length;
911 
912 	tot_vbd_reqs(domain, FIELD_VBD_RD, &vbd_rd);
913 	length = INT_FIELD_WIDTH(vbd_rd + 1);
914 	if (length > fields[FIELD_VBD_RD-1].default_width)
915 		fields[FIELD_VBD_RD-1].default_width = length;
916 
917 	tot_vbd_reqs(domain, FIELD_VBD_WR, &vbd_wr);
918 	length = INT_FIELD_WIDTH(vbd_wr + 1);
919 	if (length > fields[FIELD_VBD_WR-1].default_width)
920 		fields[FIELD_VBD_WR-1].default_width = length;
921 
922 	tot_vbd_reqs(domain, FIELD_VBD_RSECT, &vbd_rsect);
923 	length = INT_FIELD_WIDTH(vbd_rsect + 1);
924 	if (length > fields[FIELD_VBD_RSECT-1].default_width)
925 		fields[FIELD_VBD_RSECT-1].default_width = length;
926 
927 	tot_vbd_reqs(domain, FIELD_VBD_WSECT, &vbd_wsect);
928 	length = INT_FIELD_WIDTH(vbd_wsect + 1);
929 	if (length > fields[FIELD_VBD_WSECT-1].default_width)
930 		fields[FIELD_VBD_WSECT-1].default_width = length;
931 }
932 
933 
934 /* Section printing functions */
935 /* Prints the top summary, above the domain table */
do_summary(void)936 void do_summary(void)
937 {
938 #define TIME_STR_LEN 9
939 	const char *TIME_STR_FORMAT = "%H:%M:%S";
940 	char time_str[TIME_STR_LEN];
941 	const char *ver_str;
942 	unsigned run = 0, block = 0, pause = 0,
943 	         crash = 0, dying = 0, shutdown = 0;
944 	unsigned i, num_domains = 0;
945 	unsigned long long used = 0;
946 	xenstat_domain *domain;
947 	time_t curt;
948 
949 	/* Print program name, current time, and number of domains */
950 	curt = curtime.tv_sec;
951 	strftime(time_str, TIME_STR_LEN, TIME_STR_FORMAT, localtime(&curt));
952 	num_domains = xenstat_node_num_domains(cur_node);
953 	ver_str = xenstat_node_xen_version(cur_node);
954 	print("xentop - %s   Xen %s\n", time_str, ver_str);
955 
956 	/* Tabulate what states domains are in for summary */
957 	for (i=0; i < num_domains; i++) {
958 		domain = xenstat_node_domain_by_index(cur_node,i);
959 		if (xenstat_domain_running(domain)) run++;
960 		else if (xenstat_domain_blocked(domain)) block++;
961 		else if (xenstat_domain_paused(domain)) pause++;
962 		else if (xenstat_domain_shutdown(domain)) shutdown++;
963 		else if (xenstat_domain_crashed(domain)) crash++;
964 		else if (xenstat_domain_dying(domain)) dying++;
965 	}
966 
967 	print("%u domains: %u running, %u blocked, %u paused, "
968 	      "%u crashed, %u dying, %u shutdown \n",
969 	      num_domains, run, block, pause, crash, dying, shutdown);
970 
971 	used = xenstat_node_tot_mem(cur_node) - xenstat_node_free_mem(cur_node);
972 
973 	/* Dump node memory and cpu information */
974 	print("Mem: %lluk total, %lluk used, %lluk free    ",
975 	      xenstat_node_tot_mem(cur_node)/1024, used/1024,
976 	      xenstat_node_free_mem(cur_node)/1024);
977 
978 	print("CPUs: %u @ %lluMHz\n",
979 	      xenstat_node_num_cpus(cur_node),
980 	      xenstat_node_cpu_hz(cur_node)/1000000);
981 }
982 
983 /* Display the top header for the domain table */
do_header(void)984 void do_header(void)
985 {
986 	field_id i;
987 
988 	/* Turn on REVERSE highlight attribute for headings */
989 	xentop_attron(A_REVERSE);
990 	for(i = 0; i < NUM_FIELDS; i++) {
991 		if (i != 0)
992 			print(" ");
993 		/* The BOLD attribute is turned on for the sort column */
994 		if (i == sort_field)
995 			xentop_attron(A_BOLD);
996 		print("%*s", fields[i].default_width, fields[i].header);
997 		if (i == sort_field)
998 			xentop_attroff(A_BOLD);
999 	}
1000 	xentop_attroff(A_REVERSE);
1001 	print("\n");
1002 }
1003 
1004 /* Displays bottom status line or current prompt */
do_bottom_line(void)1005 void do_bottom_line(void)
1006 {
1007 	move(lines()-1, 2);
1008 
1009 	if (prompt != NULL) {
1010 		printw("%s: %s", prompt, prompt_val);
1011 	} else {
1012 		addch(A_REVERSE | 'D'); addstr("elay  ");
1013 
1014 		/* network */
1015 		addch(A_REVERSE | 'N');
1016 		attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks");
1017 		addstr("  ");
1018 
1019 		/* VBDs */
1020 		attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "v");
1021 		addch(A_REVERSE | 'B');
1022 		attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "ds");
1023 		addstr("  ");
1024 
1025 		/* vcpus */
1026 		addch(A_REVERSE | 'V');
1027 		attr_addstr(show_vcpus ? COLOR_PAIR(1) : 0, "CPUs");
1028 		addstr("  ");
1029 
1030 		/* repeat */
1031 		addch(A_REVERSE | 'R');
1032 		attr_addstr(repeat_header ? COLOR_PAIR(1) : 0, "epeat header");
1033 		addstr("  ");
1034 
1035 		/* sort order */
1036 		addch(A_REVERSE | 'S'); addstr("ort order  ");
1037 
1038 		addch(A_REVERSE | 'Q'); addstr("uit  ");
1039 	}
1040 }
1041 
1042 /* Prints Domain information */
do_domain(xenstat_domain * domain)1043 void do_domain(xenstat_domain *domain)
1044 {
1045 	unsigned int i;
1046 	for (i = 0; i < NUM_FIELDS; i++) {
1047 		if (i != 0)
1048 			print(" ");
1049 		if (i == sort_field)
1050 			xentop_attron(A_BOLD);
1051 		fields[i].print(domain);
1052 		if (i == sort_field)
1053 			xentop_attroff(A_BOLD);
1054 	}
1055 	print("\n");
1056 }
1057 
1058 /* Output all vcpu information */
do_vcpu(xenstat_domain * domain)1059 void do_vcpu(xenstat_domain *domain)
1060 {
1061 	int i = 0;
1062 	unsigned num_vcpus = 0;
1063 	xenstat_vcpu *vcpu;
1064 
1065 	print("VCPUs(sec): ");
1066 
1067 	num_vcpus = xenstat_domain_num_vcpus(domain);
1068 
1069 	/* for all online vcpus dump out values */
1070 	for (i=0; i< num_vcpus; i++) {
1071 		vcpu = xenstat_domain_vcpu(domain,i);
1072 
1073 		if (xenstat_vcpu_online(vcpu) > 0) {
1074 			if (i != 0 && (i%5)==0)
1075 				print("\n        ");
1076 			print(" %2u: %10llus", i,
1077 					xenstat_vcpu_ns(vcpu)/1000000000);
1078 		}
1079 	}
1080 	print("\n");
1081 }
1082 
1083 /* Output all network information */
do_network(xenstat_domain * domain)1084 void do_network(xenstat_domain *domain)
1085 {
1086 	int i = 0;
1087 	xenstat_network *network;
1088 	unsigned num_networks = 0;
1089 
1090 	/* How many networks? */
1091 	num_networks = xenstat_domain_num_networks(domain);
1092 
1093 	/* Dump information for each network */
1094 	for (i=0; i < num_networks; i++) {
1095 		/* Next get the network information */
1096 		network = xenstat_domain_network(domain,i);
1097 
1098 		print("Net%d RX: %8llubytes %8llupkts %8lluerr %8lludrop  ",
1099 		      i,
1100 		      xenstat_network_rbytes(network),
1101 		      xenstat_network_rpackets(network),
1102 		      xenstat_network_rerrs(network),
1103 		      xenstat_network_rdrop(network));
1104 
1105 		print("TX: %8llubytes %8llupkts %8lluerr %8lludrop\n",
1106 		      xenstat_network_tbytes(network),
1107 		      xenstat_network_tpackets(network),
1108 		      xenstat_network_terrs(network),
1109 		      xenstat_network_tdrop(network));
1110 	}
1111 }
1112 
1113 
1114 /* Output all VBD information */
do_vbd(xenstat_domain * domain)1115 void do_vbd(xenstat_domain *domain)
1116 {
1117 	int i = 0;
1118 	xenstat_vbd *vbd;
1119 	unsigned num_vbds = 0;
1120 
1121 	const char *vbd_type[] = {
1122 		"Unidentified",           /* number 0 */
1123 		"BlkBack",           /* number 1 */
1124 		"BlkTap",            /* number 2 */
1125 	};
1126 
1127 	num_vbds = xenstat_domain_num_vbds(domain);
1128 
1129 	for (i=0 ; i< num_vbds; i++) {
1130 		char details[20];
1131 
1132 		vbd = xenstat_domain_vbd(domain,i);
1133 
1134 #if !defined(__linux__)
1135 		details[0] = '\0';
1136 #else
1137 		snprintf(details, 20, "[%2x:%2x] ",
1138 			 MAJOR(xenstat_vbd_dev(vbd)),
1139 			 MINOR(xenstat_vbd_dev(vbd)));
1140 #endif
1141 		if (xenstat_vbd_error(vbd))
1142 		{
1143 			print("VBD %s %4d %s OO: %8c   RD: %8c   WR: %8c   RSECT: %10c   WSECT: %10c\n",
1144 				vbd_type[xenstat_vbd_type(vbd)],
1145 				xenstat_vbd_dev(vbd), details,
1146 				'-', '-', '-', '-','-');
1147 		}
1148 		else
1149 		{
1150 			print("VBD %s %4d %s OO: %8llu   RD: %8llu   WR: %8llu   RSECT: %10llu   WSECT: %10llu\n",
1151 				vbd_type[xenstat_vbd_type(vbd)],
1152 				xenstat_vbd_dev(vbd), details,
1153 				xenstat_vbd_oo_reqs(vbd),
1154 				xenstat_vbd_rd_reqs(vbd),
1155 				xenstat_vbd_wr_reqs(vbd),
1156 				xenstat_vbd_rd_sects(vbd),
1157 				xenstat_vbd_wr_sects(vbd));
1158 		}
1159 	}
1160 }
1161 
top(void)1162 static void top(void)
1163 {
1164 	xenstat_domain **domains;
1165 	unsigned int i, num_domains = 0;
1166 
1167 	/* Now get the node information */
1168 	if (prev_node != NULL)
1169 		xenstat_free_node(prev_node);
1170 	prev_node = cur_node;
1171 	cur_node = xenstat_get_node(xhandle, XENSTAT_ALL);
1172 	if (cur_node == NULL)
1173 		fail("Failed to retrieve statistics from libxenstat\n");
1174 
1175 	/* dump summary top information */
1176 	if (!batch)
1177 		do_summary();
1178 
1179 	/* Count the number of domains for which to report data */
1180 	num_domains = xenstat_node_num_domains(cur_node);
1181 
1182 	domains = calloc(num_domains, sizeof(xenstat_domain *));
1183 	if(domains == NULL)
1184 		fail("Failed to allocate memory\n");
1185 
1186 	for (i=0; i < num_domains; i++)
1187 		domains[i] = xenstat_node_domain_by_index(cur_node, i);
1188 
1189 	/* Sort */
1190 	qsort(domains, num_domains, sizeof(xenstat_domain *),
1191 	      (int(*)(const void *, const void *))compare_domains);
1192 
1193 	if(first_domain_index >= num_domains)
1194 		first_domain_index = num_domains-1;
1195 
1196 	/* Adjust default_width for fields with potentially large numbers */
1197 	reset_field_widths();
1198 	for (i = first_domain_index; i < num_domains; i++) {
1199 		adjust_field_widths(domains[i]);
1200 	}
1201 
1202 	for (i = first_domain_index; i < num_domains; i++) {
1203 		if(!batch && current_row() == lines()-1)
1204 			break;
1205 		if (i == first_domain_index || repeat_header)
1206 			do_header();
1207 		do_domain(domains[i]);
1208 		if (show_vcpus)
1209 			do_vcpu(domains[i]);
1210 		if (show_networks)
1211 			do_network(domains[i]);
1212 		if (show_vbds)
1213 			do_vbd(domains[i]);
1214 	}
1215 
1216 	if (!batch)
1217 		do_bottom_line();
1218 
1219 	free(domains);
1220 }
1221 
1222 static int signal_exit;
1223 
signal_exit_handler(int sig)1224 static void signal_exit_handler(int sig)
1225 {
1226 	signal_exit = 1;
1227 }
1228 
main(int argc,char ** argv)1229 int main(int argc, char **argv)
1230 {
1231 	int opt, optind = 0;
1232 	int ch = ERR;
1233 
1234 	struct option lopts[] = {
1235 		{ "help",          no_argument,       NULL, 'h' },
1236 		{ "version",       no_argument,       NULL, 'V' },
1237 		{ "networks",      no_argument,       NULL, 'n' },
1238 		{ "vbds",          no_argument,       NULL, 'x' },
1239 		{ "repeat-header", no_argument,       NULL, 'r' },
1240 		{ "vcpus",         no_argument,       NULL, 'v' },
1241 		{ "delay",         required_argument, NULL, 'd' },
1242 		{ "batch",	   no_argument,	      NULL, 'b' },
1243 		{ "iterations",	   required_argument, NULL, 'i' },
1244 		{ "full-name",     no_argument,       NULL, 'f' },
1245 		{ 0, 0, 0, 0 },
1246 	};
1247 	const char *sopts = "hVnxrvd:bi:f";
1248 
1249 	if (atexit(cleanup) != 0)
1250 		fail("Failed to install cleanup handler.\n");
1251 
1252 	while ((opt = getopt_long(argc, argv, sopts, lopts, &optind)) != -1) {
1253 		switch (opt) {
1254 		default:
1255 			usage(argv[0]);
1256 			exit(1);
1257 		case '?':
1258 		case 'h':
1259 			usage(argv[0]);
1260 			exit(0);
1261 		case 'V':
1262 			version();
1263 			exit(0);
1264 		case 'n':
1265 			show_networks = 1;
1266 			break;
1267 		case 'x':
1268 			show_vbds = 1;
1269 			break;
1270 		case 'r':
1271 			repeat_header = 1;
1272 			break;
1273 		case 'v':
1274 			show_vcpus = 1;
1275 			break;
1276 		case 'd':
1277 			delay = atoi(optarg);
1278 			break;
1279 		case 'b':
1280 			batch = 1;
1281 			break;
1282 		case 'i':
1283 			iterations = atoi(optarg);
1284 			loop = 0;
1285 			break;
1286 		case 'f':
1287 			show_full_name = 1;
1288 			break;
1289 		}
1290 	}
1291 
1292 	/* Get xenstat handle */
1293 	xhandle = xenstat_init();
1294 	if (xhandle == NULL)
1295 		fail("Failed to initialize xenstat library\n");
1296 
1297 	if (!batch) {
1298 		/* Begin curses stuff */
1299 		cwin = initscr();
1300 		start_color();
1301 		cbreak();
1302 		noecho();
1303 		nonl();
1304 		keypad(stdscr, TRUE);
1305 		halfdelay(5);
1306 #ifndef __sun__
1307 		use_default_colors();
1308 #endif
1309 		init_pair(1, -1, COLOR_YELLOW);
1310 
1311 		do {
1312 			gettimeofday(&curtime, NULL);
1313 			if(ch != ERR || (curtime.tv_sec - oldtime.tv_sec) >= delay) {
1314 				erase();
1315 				top();
1316 				oldtime = curtime;
1317 				refresh();
1318 				if ((!loop) && !(--iterations))
1319 					break;
1320 			}
1321 			ch = getch();
1322 		} while (handle_key(ch));
1323 	} else {
1324 		struct sigaction sa = {
1325 			.sa_handler = signal_exit_handler,
1326 			.sa_flags = 0
1327 		};
1328 		sigemptyset(&sa.sa_mask);
1329 		sigaction(SIGINT, &sa, NULL);
1330 		sigaction(SIGTERM, &sa, NULL);
1331 
1332 		do {
1333 			gettimeofday(&curtime, NULL);
1334 			top();
1335 			fflush(stdout);
1336 			oldtime = curtime;
1337 			if ((!loop) && !(--iterations))
1338 				break;
1339 			sleep(delay);
1340 		} while (!signal_exit);
1341 	}
1342 
1343 	/* Cleanup occurs in cleanup(), so no work to do here. */
1344 
1345 	return 0;
1346 }
1347