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