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