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