1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #define _GNU_SOURCE
16
17 #include <fcntl.h>
18 #include <inttypes.h>
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/utsname.h>
23 #include <time.h>
24 #include <unistd.h>
25
26 #include <libxl.h>
27 #include <libxl_json.h>
28 #include <libxl_utils.h>
29 #include <libxlutil.h>
30 #include <xen-tools/arm-arch-capabilities.h>
31 #include <xenstore.h>
32
33 #include "xl.h"
34 #include "xl_utils.h"
35
36 /* Possibly select a specific piece of `xl info` to print. */
37 static const char *info_name;
38 static int maybe_printf(const char *fmt, ...) __attribute__((format(printf,1,2)));
maybe_printf(const char * fmt,...)39 static int maybe_printf(const char *fmt, ...)
40 {
41 va_list ap;
42 char *str;
43 int count = 0;
44
45 va_start(ap, fmt);
46 if (vasprintf(&str, fmt, ap) != -1) {
47 if (info_name) {
48 char *s;
49
50 if (!strncmp(str, info_name, strlen(info_name)) &&
51 (s = strchr(str, ':')) && s[1] == ' ')
52 count = fputs(&s[2], stdout);
53 } else
54 count = fputs(str, stdout);
55
56 free(str);
57 }
58 va_end(ap);
59
60 return count;
61 }
62
printf_info_one_json(yajl_gen hand,int domid,libxl_domain_config * d_config)63 static yajl_gen_status printf_info_one_json(yajl_gen hand, int domid,
64 libxl_domain_config *d_config)
65 {
66 yajl_gen_status s;
67
68 s = yajl_gen_map_open(hand);
69 if (s != yajl_gen_status_ok)
70 goto out;
71
72 s = yajl_gen_string(hand, (const unsigned char *)"domid",
73 sizeof("domid")-1);
74 if (s != yajl_gen_status_ok)
75 goto out;
76 if (domid != -1)
77 s = yajl_gen_integer(hand, domid);
78 else
79 s = yajl_gen_null(hand);
80 if (s != yajl_gen_status_ok)
81 goto out;
82
83 s = yajl_gen_string(hand, (const unsigned char *)"config",
84 sizeof("config")-1);
85 if (s != yajl_gen_status_ok)
86 goto out;
87 s = libxl_domain_config_gen_json(hand, d_config);
88 if (s != yajl_gen_status_ok)
89 goto out;
90
91 s = yajl_gen_map_close(hand);
92 if (s != yajl_gen_status_ok)
93 goto out;
94
95 out:
96 return s;
97 }
98
99 void printf_info(enum output_format output_format,
100 int domid,
101 libxl_domain_config *d_config, FILE *fh);
printf_info(enum output_format output_format,int domid,libxl_domain_config * d_config,FILE * fh)102 void printf_info(enum output_format output_format,
103 int domid,
104 libxl_domain_config *d_config, FILE *fh)
105 {
106 if (output_format == OUTPUT_FORMAT_SXP)
107 return printf_info_sexp(domid, d_config, fh);
108
109 const char *buf;
110 libxl_yajl_length len = 0;
111 yajl_gen_status s;
112 yajl_gen hand;
113
114 hand = libxl_yajl_gen_alloc(NULL);
115 if (!hand) {
116 fprintf(stderr, "unable to allocate JSON generator\n");
117 return;
118 }
119
120 s = printf_info_one_json(hand, domid, d_config);
121 if (s != yajl_gen_status_ok)
122 goto out;
123
124 s = yajl_gen_get_buf(hand, (const unsigned char **)&buf, &len);
125 if (s != yajl_gen_status_ok)
126 goto out;
127
128 fputs(buf, fh);
129
130 out:
131 yajl_gen_free(hand);
132
133 if (s != yajl_gen_status_ok)
134 fprintf(stderr,
135 "unable to format domain config as JSON (YAJL:%d)\n", s);
136
137 flush_stream(fh);
138 }
139
output_xeninfo(void)140 static void output_xeninfo(void)
141 {
142 const libxl_version_info *info;
143 libxl_scheduler sched;
144 int rc;
145
146 if (!(info = libxl_get_version_info(ctx))) {
147 fprintf(stderr, "libxl_get_version_info failed.\n");
148 return;
149 }
150
151 rc = libxl_get_scheduler(ctx);
152 if (rc < 0) {
153 fprintf(stderr, "get_scheduler sysctl failed.\n");
154 return;
155 }
156 sched = rc;
157
158 maybe_printf("xen_major : %d\n", info->xen_version_major);
159 maybe_printf("xen_minor : %d\n", info->xen_version_minor);
160 maybe_printf("xen_extra : %s\n", info->xen_version_extra);
161 maybe_printf("xen_version : %d.%d%s\n", info->xen_version_major,
162 info->xen_version_minor, info->xen_version_extra);
163 maybe_printf("xen_caps : %s\n", info->capabilities);
164 maybe_printf("xen_scheduler : %s\n", libxl_scheduler_to_string(sched));
165 maybe_printf("xen_pagesize : %u\n", info->pagesize);
166 maybe_printf("platform_params : virt_start=0x%"PRIx64"\n", info->virt_start);
167 maybe_printf("xen_changeset : %s\n", info->changeset);
168 maybe_printf("xen_commandline : %s\n", info->commandline);
169 maybe_printf("cc_compiler : %s\n", info->compiler);
170 maybe_printf("cc_compile_by : %s\n", info->compile_by);
171 maybe_printf("cc_compile_domain : %s\n", info->compile_domain);
172 maybe_printf("cc_compile_date : %s\n", info->compile_date);
173 maybe_printf("build_id : %s\n", info->build_id);
174
175 return;
176 }
177
output_nodeinfo(void)178 static void output_nodeinfo(void)
179 {
180 struct utsname utsbuf;
181
182 if (uname(&utsbuf) < 0)
183 return;
184
185 maybe_printf("host : %s\n", utsbuf.nodename);
186 maybe_printf("release : %s\n", utsbuf.release);
187 maybe_printf("version : %s\n", utsbuf.version);
188 maybe_printf("machine : %s\n", utsbuf.machine);
189 }
190
output_physinfo(void)191 static void output_physinfo(void)
192 {
193 libxl_physinfo info;
194 const libxl_version_info *vinfo;
195 unsigned int i;
196 libxl_bitmap cpumap;
197 int n = 0;
198
199 if (libxl_get_physinfo(ctx, &info) != 0) {
200 fprintf(stderr, "libxl_physinfo failed.\n");
201 return;
202 }
203 maybe_printf("nr_cpus : %d\n", info.nr_cpus);
204 maybe_printf("max_cpu_id : %d\n", info.max_cpu_id);
205 maybe_printf("nr_nodes : %d\n", info.nr_nodes);
206 maybe_printf("cores_per_socket : %d\n", info.cores_per_socket);
207 maybe_printf("threads_per_core : %d\n", info.threads_per_core);
208 maybe_printf("cpu_mhz : %d.%03d\n", info.cpu_khz / 1000, info.cpu_khz % 1000);
209
210 maybe_printf("hw_caps : %08x:%08x:%08x:%08x:%08x:%08x:%08x:%08x\n",
211 info.hw_cap[0], info.hw_cap[1], info.hw_cap[2], info.hw_cap[3],
212 info.hw_cap[4], info.hw_cap[5], info.hw_cap[6], info.hw_cap[7]
213 );
214
215 maybe_printf("virt_caps :%s%s%s%s%s%s%s%s%s%s%s\n",
216 info.cap_pv ? " pv" : "",
217 info.cap_hvm ? " hvm" : "",
218 info.cap_hvm && info.cap_hvm_directio ? " hvm_directio" : "",
219 info.cap_pv && info.cap_hvm_directio ? " pv_directio" : "",
220 info.cap_hap ? " hap" : "",
221 info.cap_shadow ? " shadow" : "",
222 info.cap_iommu_hap_pt_share ? " iommu_hap_pt_share" : "",
223 info.cap_vmtrace ? " vmtrace" : "",
224 info.cap_vpmu ? " vpmu" : "",
225 info.cap_gnttab_v1 ? " gnttab-v1" : "",
226 info.cap_gnttab_v2 ? " gnttab-v2" : ""
227 );
228
229 /* Print arm SVE vector length only on ARM platforms */
230 #if defined(__arm__) || defined(__aarch64__)
231 maybe_printf("arm_sve_vector_length : %u\n",
232 arch_capabilities_arm_sve(info.arch_capabilities)
233 );
234 #endif
235
236 vinfo = libxl_get_version_info(ctx);
237 if (vinfo) {
238 i = (1 << 20) / vinfo->pagesize;
239 maybe_printf("total_memory : %"PRIu64"\n", info.total_pages / i);
240 maybe_printf("free_memory : %"PRIu64"\n", (info.free_pages - info.outstanding_pages) / i);
241 maybe_printf("sharing_freed_memory : %"PRIu64"\n", info.sharing_freed_pages / i);
242 maybe_printf("sharing_used_memory : %"PRIu64"\n", info.sharing_used_frames / i);
243 maybe_printf("outstanding_claims : %"PRIu64"\n", info.outstanding_pages / i);
244 }
245 if (!libxl_get_freecpus(ctx, &cpumap)) {
246 libxl_for_each_bit(i, cpumap)
247 if (libxl_bitmap_test(&cpumap, i))
248 n++;
249 maybe_printf("free_cpus : %d\n", n);
250 free(cpumap.map);
251 }
252 libxl_physinfo_dispose(&info);
253 return;
254 }
255
output_numainfo(void)256 static void output_numainfo(void)
257 {
258 libxl_numainfo *info;
259 int i, j, nr;
260
261 info = libxl_get_numainfo(ctx, &nr);
262 if (info == NULL) {
263 fprintf(stderr, "libxl_get_numainfo failed.\n");
264 return;
265 }
266
267 printf("numa_info :\n");
268 printf("node: memsize memfree distances\n");
269
270 for (i = 0; i < nr; i++) {
271 if (info[i].size != LIBXL_NUMAINFO_INVALID_ENTRY) {
272 printf("%4d: %6"PRIu64" %6"PRIu64" %d", i,
273 info[i].size >> 20, info[i].free >> 20,
274 info[i].dists[0]);
275 for (j = 1; j < info[i].num_dists; j++)
276 printf(",%d", info[i].dists[j]);
277 printf("\n");
278 }
279 }
280
281 libxl_numainfo_list_free(info, nr);
282
283 return;
284 }
285
output_topologyinfo(void)286 static void output_topologyinfo(void)
287 {
288 libxl_cputopology *cpuinfo;
289 int i, nr;
290 libxl_pcitopology *pciinfo;
291 int valid_devs = 0;
292
293
294 cpuinfo = libxl_get_cpu_topology(ctx, &nr);
295 if (cpuinfo == NULL) {
296 fprintf(stderr, "libxl_get_cpu_topology failed.\n");
297 return;
298 }
299
300 printf("cpu_topology :\n");
301 printf("cpu: core socket node\n");
302
303 for (i = 0; i < nr; i++) {
304 if (cpuinfo[i].core != LIBXL_CPUTOPOLOGY_INVALID_ENTRY)
305 printf("%3d: %4d %4d %4d\n", i,
306 cpuinfo[i].core, cpuinfo[i].socket, cpuinfo[i].node);
307 }
308
309 libxl_cputopology_list_free(cpuinfo, nr);
310
311 pciinfo = libxl_get_pci_topology(ctx, &nr);
312 if (pciinfo == NULL) {
313 fprintf(stderr, "libxl_get_pci_topology failed.\n");
314 return;
315 }
316
317 printf("device topology :\n");
318 printf("device node\n");
319 for (i = 0; i < nr; i++) {
320 if (pciinfo[i].node != LIBXL_PCITOPOLOGY_INVALID_ENTRY) {
321 printf("%04x:%02x:%02x.%01x %d\n", pciinfo[i].seg,
322 pciinfo[i].bus,
323 ((pciinfo[i].devfn >> 3) & 0x1f), (pciinfo[i].devfn & 7),
324 pciinfo[i].node);
325 valid_devs++;
326 }
327 }
328
329 if (valid_devs == 0)
330 printf("No device topology data available\n");
331
332 libxl_pcitopology_list_free(pciinfo, nr);
333
334 return;
335 }
336
output_xenstore_info(void)337 static void output_xenstore_info(void)
338 {
339 struct xs_handle *xsh;
340 unsigned int features = 0;
341
342 xsh = xs_open(0);
343 if (!xsh) {
344 fprintf(stderr, "xs_open failed.\n");
345 return;
346 }
347
348 /* Ignore error, default to "0" for features. */
349 xs_get_features_supported(xsh, &features);
350
351 maybe_printf("xenstore_features : 0x%08x\n", features);
352
353 xs_close(xsh);
354 }
355
print_info(int numa)356 static void print_info(int numa)
357 {
358 output_nodeinfo();
359
360 output_physinfo();
361
362 if (numa) {
363 output_topologyinfo();
364 output_numainfo();
365 }
366 output_xeninfo();
367
368 output_xenstore_info();
369
370 maybe_printf("xend_config_format : 4\n");
371
372 return;
373 }
374
list_vm(void)375 static void list_vm(void)
376 {
377 libxl_vminfo *info;
378 char *domname;
379 int nb_vm, i;
380
381 info = libxl_list_vm(ctx, &nb_vm);
382
383 if (!info) {
384 fprintf(stderr, "libxl_list_vm failed.\n");
385 exit(EXIT_FAILURE);
386 }
387 printf("UUID ID name\n");
388 for (i = 0; i < nb_vm; i++) {
389 domname = libxl_domid_to_name(ctx, info[i].domid);
390 printf(LIBXL_UUID_FMT " %d %-30s\n", LIBXL_UUID_BYTES(info[i].uuid),
391 info[i].domid, domname);
392 free(domname);
393 }
394 libxl_vminfo_list_free(info, nb_vm);
395 }
396
list_domains(bool verbose,bool context,bool claim,bool numa,bool cpupool,const libxl_dominfo * info,int nb_domain)397 static void list_domains(bool verbose, bool context, bool claim, bool numa,
398 bool cpupool, const libxl_dominfo *info, int nb_domain)
399 {
400 int i;
401 static const char shutdown_reason_letters[]= "-rscwS";
402 libxl_bitmap nodemap;
403 libxl_physinfo physinfo;
404
405 libxl_bitmap_init(&nodemap);
406 libxl_physinfo_init(&physinfo);
407
408 printf("Name ID Mem VCPUs\tState\tTime(s)");
409 if (verbose) printf(" UUID Reason-Code\tSecurity Label");
410 if (context && !verbose) printf(" Security Label");
411 if (claim) printf(" Claimed");
412 if (cpupool) printf(" Cpupool");
413 if (numa) {
414 if (libxl_node_bitmap_alloc(ctx, &nodemap, 0)) {
415 fprintf(stderr, "libxl_node_bitmap_alloc_failed.\n");
416 exit(EXIT_FAILURE);
417 }
418 if (libxl_get_physinfo(ctx, &physinfo) != 0) {
419 fprintf(stderr, "libxl_physinfo failed.\n");
420 libxl_bitmap_dispose(&nodemap);
421 exit(EXIT_FAILURE);
422 }
423
424 printf(" NODE Affinity");
425 }
426 printf("\n");
427 for (i = 0; i < nb_domain; i++) {
428 char *domname;
429 libxl_shutdown_reason shutdown_reason;
430 domname = libxl_domid_to_name(ctx, info[i].domid);
431 shutdown_reason = info[i].shutdown ? info[i].shutdown_reason : 0;
432 printf("%-40s %5d %5lu %5d %c%c%c%c%c%c %8.1f",
433 domname,
434 info[i].domid,
435 (unsigned long) ((info[i].current_memkb +
436 info[i].outstanding_memkb)/ 1024),
437 info[i].vcpu_online,
438 info[i].running ? 'r' : '-',
439 info[i].blocked ? 'b' : '-',
440 info[i].paused ? 'p' : '-',
441 info[i].shutdown ? 's' : '-',
442 (shutdown_reason >= 0 &&
443 shutdown_reason < sizeof(shutdown_reason_letters)-1
444 ? shutdown_reason_letters[shutdown_reason] : '?'),
445 info[i].dying ? 'd' : '-',
446 ((float)info[i].cpu_time / 1e9));
447 free(domname);
448 if (verbose) {
449 printf(" " LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info[i].uuid));
450 if (info[i].shutdown) printf(" %8x", shutdown_reason);
451 else printf(" %8s", "-");
452 }
453 if (claim)
454 printf(" %5lu", (unsigned long)info[i].outstanding_memkb / 1024);
455 if (verbose || context)
456 printf(" %16s", info[i].ssid_label ? : "-");
457 if (cpupool) {
458 char *poolname = libxl_cpupoolid_to_name(ctx, info[i].cpupool);
459 printf("%16s", poolname);
460 free(poolname);
461 }
462 if (numa) {
463 libxl_domain_get_nodeaffinity(ctx, info[i].domid, &nodemap);
464
465 putchar(' ');
466 print_bitmap(nodemap.map, physinfo.nr_nodes, stdout);
467 }
468 putchar('\n');
469 }
470
471 libxl_bitmap_dispose(&nodemap);
472 libxl_physinfo_dispose(&physinfo);
473 }
474
list_domains_details(const libxl_dominfo * info,int nb_domain)475 static void list_domains_details(const libxl_dominfo *info, int nb_domain)
476 {
477 libxl_domain_config d_config;
478
479 int i, rc;
480
481 yajl_gen hand = NULL;
482 yajl_gen_status s;
483 const char *buf;
484 libxl_yajl_length yajl_len = 0;
485
486 if (default_output_format == OUTPUT_FORMAT_JSON) {
487 hand = libxl_yajl_gen_alloc(NULL);
488 if (!hand) {
489 fprintf(stderr, "unable to allocate JSON generator\n");
490 return;
491 }
492
493 s = yajl_gen_array_open(hand);
494 if (s != yajl_gen_status_ok)
495 goto out;
496 } else
497 s = yajl_gen_status_ok;
498
499 for (i = 0; i < nb_domain; i++) {
500 libxl_domain_config_init(&d_config);
501 rc = libxl_retrieve_domain_configuration(ctx, info[i].domid,
502 &d_config, NULL);
503 if (rc)
504 continue;
505 if (default_output_format == OUTPUT_FORMAT_JSON)
506 s = printf_info_one_json(hand, info[i].domid, &d_config);
507 else
508 printf_info_sexp(info[i].domid, &d_config, stdout);
509 libxl_domain_config_dispose(&d_config);
510 if (s != yajl_gen_status_ok)
511 goto out;
512 }
513
514 if (default_output_format == OUTPUT_FORMAT_JSON) {
515 s = yajl_gen_array_close(hand);
516 if (s != yajl_gen_status_ok)
517 goto out;
518
519 s = yajl_gen_get_buf(hand, (const unsigned char **)&buf, &yajl_len);
520 if (s != yajl_gen_status_ok)
521 goto out;
522
523 puts(buf);
524 }
525
526 out:
527 if (default_output_format == OUTPUT_FORMAT_JSON) {
528 yajl_gen_free(hand);
529 if (s != yajl_gen_status_ok)
530 fprintf(stderr,
531 "unable to format domain config as JSON (YAJL:%d)\n", s);
532 }
533 }
534
535
main_list(int argc,char ** argv)536 int main_list(int argc, char **argv)
537 {
538 int opt;
539 bool verbose = false;
540 bool context = false;
541 bool details = false;
542 bool cpupool = false;
543 bool numa = false;
544 static struct option opts[] = {
545 {"long", 0, 0, 'l'},
546 {"verbose", 0, 0, 'v'},
547 {"context", 0, 0, 'Z'},
548 {"cpupool", 0, 0, 'c'},
549 {"numa", 0, 0, 'n'},
550 COMMON_LONG_OPTS
551 };
552
553 libxl_dominfo info_buf;
554 libxl_dominfo *info, *info_free=0;
555 int nb_domain, rc;
556
557 SWITCH_FOREACH_OPT(opt, "lvhZcn", opts, "list", 0) {
558 case 'l':
559 details = true;
560 break;
561 case 'v':
562 verbose = true;
563 break;
564 case 'Z':
565 context = true;
566 break;
567 case 'c':
568 cpupool = true;
569 break;
570 case 'n':
571 numa = true;
572 break;
573 }
574
575 libxl_dominfo_init(&info_buf);
576
577 if (optind >= argc) {
578 info = libxl_list_domain(ctx, &nb_domain);
579 if (!info) {
580 fprintf(stderr, "libxl_list_domain failed.\n");
581 return EXIT_FAILURE;
582 }
583 info_free = info;
584 } else if (optind == argc-1) {
585 uint32_t domid = find_domain(argv[optind]);
586 rc = libxl_domain_info(ctx, &info_buf, domid);
587 if (rc == ERROR_DOMAIN_NOTFOUND) {
588 fprintf(stderr, "Error: Domain \'%s\' does not exist.\n",
589 argv[optind]);
590 return EXIT_FAILURE;
591 }
592 if (rc) {
593 fprintf(stderr, "libxl_domain_info failed (code %d).\n", rc);
594 return EXIT_FAILURE;
595 }
596 info = &info_buf;
597 nb_domain = 1;
598 } else {
599 help("list");
600 return EXIT_FAILURE;
601 }
602
603 if (details)
604 list_domains_details(info, nb_domain);
605 else
606 list_domains(verbose, context, false /* claim */, numa, cpupool,
607 info, nb_domain);
608
609 if (info_free)
610 libxl_dominfo_list_free(info, nb_domain);
611
612 libxl_dominfo_dispose(&info_buf);
613
614 return EXIT_SUCCESS;
615 }
616
main_vm_list(int argc,char ** argv)617 int main_vm_list(int argc, char **argv)
618 {
619 int opt;
620
621 SWITCH_FOREACH_OPT(opt, "", NULL, "vm-list", 0) {
622 /* No options */
623 }
624
625 list_vm();
626 return EXIT_SUCCESS;
627 }
628
main_info(int argc,char ** argv)629 int main_info(int argc, char **argv)
630 {
631 int opt;
632 static struct option opts[] = {
633 {"numa", 0, 0, 'n'},
634 COMMON_LONG_OPTS
635 };
636 int numa = 0;
637
638 SWITCH_FOREACH_OPT(opt, "n", opts, "info", 0) {
639 case 'n':
640 numa = 1;
641 break;
642 }
643
644 /*
645 * If an extra argument is provided, filter out a specific piece of
646 * information.
647 */
648 if (numa == 0 && argc > optind)
649 info_name = argv[optind];
650
651 print_info(numa);
652 return 0;
653 }
654
main_domid(int argc,char ** argv)655 int main_domid(int argc, char **argv)
656 {
657 uint32_t domid;
658 int opt;
659 const char *domname = NULL;
660
661 SWITCH_FOREACH_OPT(opt, "", NULL, "domid", 1) {
662 /* No options */
663 }
664
665 domname = argv[optind];
666
667 if (libxl_name_to_domid(ctx, domname, &domid)) {
668 fprintf(stderr, "Can't get domid of domain name '%s', maybe this domain does not exist.\n", domname);
669 return EXIT_FAILURE;
670 }
671
672 printf("%u\n", domid);
673
674 return EXIT_SUCCESS;
675 }
676
main_domname(int argc,char ** argv)677 int main_domname(int argc, char **argv)
678 {
679 uint32_t domid;
680 int opt;
681 char *domname = NULL;
682 char *endptr = NULL;
683
684 SWITCH_FOREACH_OPT(opt, "", NULL, "domname", 1) {
685 /* No options */
686 }
687
688 domid = strtol(argv[optind], &endptr, 10);
689 if (domid == 0 && !strcmp(endptr, argv[optind])) {
690 /*no digits at all*/
691 fprintf(stderr, "Invalid domain id.\n\n");
692 return EXIT_FAILURE;
693 }
694
695 domname = libxl_domid_to_name(ctx, domid);
696 if (!domname) {
697 fprintf(stderr, "Can't get domain name of domain id '%u', maybe this domain does not exist.\n", domid);
698 return EXIT_FAILURE;
699 }
700
701 printf("%s\n", domname);
702 free(domname);
703
704 return EXIT_SUCCESS;
705 }
706
uptime_to_string(unsigned long uptime,int short_mode)707 static char *uptime_to_string(unsigned long uptime, int short_mode)
708 {
709 int sec, min, hour, day;
710 char *time_string;
711
712 day = (int)(uptime / 86400);
713 uptime -= (day * 86400);
714 hour = (int)(uptime / 3600);
715 uptime -= (hour * 3600);
716 min = (int)(uptime / 60);
717 uptime -= (min * 60);
718 sec = uptime;
719
720 if (short_mode)
721 if (day > 1)
722 xasprintf(&time_string, "%d days, %2d:%02d", day, hour, min);
723 else if (day == 1)
724 xasprintf(&time_string, "%d day, %2d:%02d", day, hour, min);
725 else
726 xasprintf(&time_string, "%2d:%02d", hour, min);
727 else
728 if (day > 1)
729 xasprintf(&time_string, "%d days, %2d:%02d:%02d", day, hour, min, sec);
730 else if (day == 1)
731 xasprintf(&time_string, "%d day, %2d:%02d:%02d", day, hour, min, sec);
732 else
733 xasprintf(&time_string, "%2d:%02d:%02d", hour, min, sec);
734
735 return time_string;
736 }
737
main_claims(int argc,char ** argv)738 int main_claims(int argc, char **argv)
739 {
740 libxl_dominfo *info;
741 int opt;
742 int nb_domain;
743
744 SWITCH_FOREACH_OPT(opt, "", NULL, "claims", 0) {
745 /* No options */
746 }
747
748 if (!claim_mode)
749 fprintf(stderr, "claim_mode not enabled (see man xl.conf).\n");
750
751 info = libxl_list_domain(ctx, &nb_domain);
752 if (!info) {
753 fprintf(stderr, "libxl_list_domain failed.\n");
754 return 1;
755 }
756
757 list_domains(false /* verbose */, false /* context */, true /* claim */,
758 false /* numa */, false /* cpupool */, info, nb_domain);
759
760 libxl_dominfo_list_free(info, nb_domain);
761 return 0;
762 }
763
current_time_to_string(time_t now)764 static char *current_time_to_string(time_t now)
765 {
766 char now_str[100];
767 struct tm *tmp;
768
769 tmp = localtime(&now);
770 if (tmp == NULL) {
771 fprintf(stderr, "Get localtime error");
772 exit(-1);
773 }
774 if (strftime(now_str, sizeof(now_str), "%H:%M:%S", tmp) == 0) {
775 fprintf(stderr, "strftime returned 0");
776 exit(-1);
777 }
778 return strdup(now_str);
779 }
780
print_dom0_uptime(int short_mode,time_t now)781 static void print_dom0_uptime(int short_mode, time_t now)
782 {
783 int fd;
784 ssize_t nr;
785 char buf[512];
786 uint32_t uptime = 0;
787 char *uptime_str = NULL;
788 char *now_str = NULL;
789 char *domname;
790
791 fd = open("/proc/uptime", O_RDONLY);
792 if (fd == -1)
793 goto err;
794
795 nr = read(fd, buf, sizeof(buf) - 1);
796 if (nr == -1) {
797 close(fd);
798 goto err;
799 }
800 close(fd);
801
802 buf[nr] = '\0';
803
804 strtok(buf, " ");
805 uptime = strtoul(buf, NULL, 10);
806
807 domname = libxl_domid_to_name(ctx, 0);
808 if (short_mode)
809 {
810 now_str = current_time_to_string(now);
811 uptime_str = uptime_to_string(uptime, 1);
812 printf(" %s up %s, %s (%d)\n", now_str, uptime_str,
813 domname, 0);
814 }
815 else
816 {
817 now_str = NULL;
818 uptime_str = uptime_to_string(uptime, 0);
819 printf("%-33s %4d %s\n", domname,
820 0, uptime_str);
821 }
822
823 free(now_str);
824 free(uptime_str);
825 free(domname);
826 return;
827 err:
828 fprintf(stderr, "Can not get Dom0 uptime.\n");
829 exit(-1);
830 }
831
print_domU_uptime(uint32_t domuid,int short_mode,time_t now)832 static void print_domU_uptime(uint32_t domuid, int short_mode, time_t now)
833 {
834 uint32_t s_time = 0;
835 uint32_t uptime = 0;
836 char *uptime_str = NULL;
837 char *now_str = NULL;
838 char *domname;
839
840 s_time = libxl_vm_get_start_time(ctx, domuid);
841 if (s_time == -1)
842 return;
843 uptime = now - s_time;
844 domname = libxl_domid_to_name(ctx, domuid);
845 if (short_mode)
846 {
847 now_str = current_time_to_string(now);
848 uptime_str = uptime_to_string(uptime, 1);
849 printf(" %s up %s, %s (%d)\n", now_str, uptime_str,
850 domname, domuid);
851 }
852 else
853 {
854 now_str = NULL;
855 uptime_str = uptime_to_string(uptime, 0);
856 printf("%-33s %4d %s\n", domname,
857 domuid, uptime_str);
858 }
859
860 free(domname);
861 free(now_str);
862 free(uptime_str);
863 return;
864 }
865
print_uptime(int short_mode,uint32_t doms[],int nb_doms)866 static void print_uptime(int short_mode, uint32_t doms[], int nb_doms)
867 {
868 libxl_vminfo *info;
869 time_t now;
870 int nb_vm, i;
871
872 now = time(NULL);
873
874 if (!short_mode)
875 printf("%-33s %4s %s\n", "Name", "ID", "Uptime");
876
877 if (nb_doms == 0) {
878 print_dom0_uptime(short_mode, now);
879 info = libxl_list_vm(ctx, &nb_vm);
880 if (info == NULL) {
881 fprintf(stderr, "Could not list vms.\n");
882 return;
883 }
884 for (i = 0; i < nb_vm; i++) {
885 if (info[i].domid == 0) continue;
886 print_domU_uptime(info[i].domid, short_mode, now);
887 }
888 libxl_vminfo_list_free(info, nb_vm);
889 } else {
890 for (i = 0; i < nb_doms; i++) {
891 if (doms[i] == 0)
892 print_dom0_uptime(short_mode, now);
893 else
894 print_domU_uptime(doms[i], short_mode, now);
895 }
896 }
897 }
898
main_uptime(int argc,char ** argv)899 int main_uptime(int argc, char **argv)
900 {
901 const char *dom;
902 int short_mode = 0;
903 uint32_t domains[100];
904 int nb_doms = 0;
905 int opt;
906
907 SWITCH_FOREACH_OPT(opt, "s", NULL, "uptime", 0) {
908 case 's':
909 short_mode = 1;
910 break;
911 }
912
913 for (;(dom = argv[optind]) != NULL; nb_doms++,optind++)
914 domains[nb_doms] = find_domain(dom);
915
916 print_uptime(short_mode, domains, nb_doms);
917
918 return 0;
919 }
920
main_dmesg(int argc,char ** argv)921 int main_dmesg(int argc, char **argv)
922 {
923 unsigned int clear = 0;
924 libxl_xen_console_reader *cr;
925 char *line;
926 int opt, ret = 1;
927 static struct option opts[] = {
928 {"clear", 0, 0, 'c'},
929 COMMON_LONG_OPTS
930 };
931
932 SWITCH_FOREACH_OPT(opt, "c", opts, "dmesg", 0) {
933 case 'c':
934 clear = 1;
935 break;
936 }
937
938 cr = libxl_xen_console_read_start(ctx, clear);
939 if (!cr)
940 goto finish;
941
942 while ((ret = libxl_xen_console_read_line(ctx, cr, &line)) > 0)
943 printf("%s", line);
944
945 finish:
946 if (cr)
947 libxl_xen_console_read_finish(ctx, cr);
948 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
949 }
950
main_top(int argc,char ** argv)951 int main_top(int argc, char **argv)
952 {
953 int opt;
954
955 SWITCH_FOREACH_OPT(opt, "", NULL, "top", 0) {
956 /* No options */
957 }
958
959 return system("xentop");
960 }
961
962
963 /*
964 * Local variables:
965 * mode: C
966 * c-basic-offset: 4
967 * indent-tabs-mode: nil
968 * End:
969 */
970