[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[WIP PATCH 09/16] WIP: tools/xl: Implement generalized output formatting for `xl list`



Implement a generalized output formatting function for the `xl list`
subcommands.  Notably `xl list` and `xl vm-list` could make use of
alternative output list formats.

Signed-off-by: Elliott Mitchell <ehem+xen@xxxxxxx>
---
I'm a bit unsure of #include <xen-tools/libs.h>.  When looking for an
implementation of ARRAY_SIZE(), that was the header I found.  I can
readily write it myself, but rather than inlining, I looked for a copy in
a header and found that.
---
 tools/xl/xl_list.c | 285 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 285 insertions(+)

diff --git a/tools/xl/xl_list.c b/tools/xl/xl_list.c
index e30536fd9a..1c04f2126b 100644
--- a/tools/xl/xl_list.c
+++ b/tools/xl/xl_list.c
@@ -14,10 +14,14 @@
 
 #define _GNU_SOURCE
 
+#include <ctype.h>
 #include <inttypes.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <unistd.h>
 
+#include <xen-tools/libs.h>
+
 #include <libxl.h>
 #include <libxl_utils.h>
 
@@ -25,6 +29,287 @@
 #include "xl_utils.h"
 
 
+struct format_entry;
+
+typedef void (format_function_t)(const struct format_entry *,
+                                 const void *, const char *, size_t);
+
+typedef struct format_entry {
+    char *const header;
+    char formatc[3];
+    format_function_t *formatf;
+    ptrdiff_t offset;
+    union {
+        int i;
+        unsigned long lu;
+        float f;
+        void *v;
+        char *(*xlfunc)(libxl_ctx *, uint32_t);
+    } extra;
+} format_table_t['z' - 'A' + 1];
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+static void format_normal(const struct format_entry *entry,
+                          const void *info, const char *format,
+                          size_t len)
+{
+    char *buf = alloca(len + 3);
+    memcpy(buf, format, len);
+    if (info) {
+        const char *str;
+        int i;
+        unsigned long lu;
+        float f;
+        strcpy(buf + len, entry->formatc);
+        switch (entry->formatc[0]) {
+        case 's':
+            str = ((char **)info)[entry->offset];
+            if (!str) str = "-";
+            printf(buf, str);
+            break;
+        case 'f':
+            f = ((float *)info)[entry->offset];
+            if (entry->extra.f != 0) f /= entry->extra.f;
+            printf(buf, f);
+            break;
+        case 'l':
+            lu = ((unsigned long *)info)[entry->offset];
+            if (entry->extra.lu) lu /= entry->extra.lu;
+            printf(buf, lu);
+            break;
+        case 'd':
+        default:
+            i = ((int *)info)[entry->offset];
+            if (entry->extra.i) i /= entry->extra.i;
+            printf(buf, i);
+            break;
+        }
+    } else {
+        if (entry->formatc[0] == 'f') {
+            char *tmp;
+            buf[len] = '\0';
+            if ((tmp = rindex(buf, '.')))
+                len = tmp - buf - 1;
+        }
+        strcpy(buf + len, "s");
+        printf(buf, entry->header);
+    }
+}
+
+static void format_allocstr(const struct format_entry *entry,
+                            const void *info, const char *format,
+                            size_t len)
+{
+    char *fmt = alloca(len + 2);
+    char *outbuf;
+    memcpy(fmt, format, len);
+    strcpy(fmt + len, "s");
+
+    if (info) {
+        outbuf = entry->extra.xlfunc(ctx, ((uint32_t *)info)[entry->offset]);
+        printf(fmt, outbuf);
+        free(outbuf);
+    } else printf(fmt, entry->header);
+}
+
+static void format_uuid(const struct format_entry *entry,
+                        const void *info, const char *format,
+                        size_t len)
+{
+    if (info) printf(LIBXL_UUID_FMT, LIBXL_UUID_BYTES(*(libxl_uuid *)((char 
*)info + entry->offset)));
+    else fputs(entry->header, stdout);
+}
+
+static void format_time(const struct format_entry *entry,
+                        const void *_info, const char *format,
+                        size_t len)
+{
+    const libxl_dominfo *info = _info;
+    char *fmt = alloca(len + 2);
+    memcpy(fmt, format, len);
+
+    if (info) {
+        strcpy(fmt + len, "f");
+        printf(fmt, ((float)info->cpu_time / 1e9));
+    } else {
+        char *tmp;
+        if (!(tmp = index(fmt, '.'))) tmp = fmt + len;
+        strcpy(tmp, "s");
+        printf(fmt, entry->header);
+    }
+}
+
+static void format_state(const struct format_entry *entry,
+                         const void *_info, const char *format,
+                         size_t len)
+{
+    const libxl_dominfo *info = _info;
+    if (info) {
+        const char shutdown_reason_letters[] = "-rscwS";
+        libxl_shutdown_reason shutdown_reason;
+        static const char letters[] = "rbps";
+        int i;
+       const bool *flags;
+
+       flags = &info->running;
+        for (i = 0; i < strlen(letters); ++i)
+            putchar(flags[i] ? letters[i] : '-');
+
+        shutdown_reason = info->shutdown ? info->shutdown_reason : 0;
+        putchar((shutdown_reason >= 0 &&
+            shutdown_reason < sizeof(shutdown_reason_letters)-1
+            ? shutdown_reason_letters[shutdown_reason] : '?'));
+
+        putchar(info->dying ? 'd' : '-');
+    } else printf("%6s", entry->header);
+}
+
+static void format_reason(const struct format_entry *entry,
+                          const void *_info, const char *format,
+                          size_t len)
+{
+    const libxl_dominfo *info = _info;
+    const char *output = entry->header;
+    if (info) {
+        if (info->shutdown) {
+            printf("%8x", info->shutdown_reason);
+            return;
+        }
+        output = "-";
+    }
+    printf("%8s", output);
+}
+
+static void format_memory(const struct format_entry *entry,
+                          const void *_info, const char *format,
+                          size_t len)
+{
+    const libxl_dominfo *info = _info;
+    char *fmt = alloca(len + 3);
+    memcpy(fmt, format, len);
+    if (info) {
+        strcpy(fmt + len, entry->formatc);
+        printf(fmt, (info->current_memkb + info->outstanding_memkb) >> 10);
+    } else {
+        strcpy(fmt + len, "s");
+        printf(fmt, "Mem");
+    }
+}
+
+static void format_node(const struct format_entry *entry,
+                        const void *_info, const char *format,
+                        size_t len)
+{
+    const libxl_dominfo *info = _info;
+    static bool need_init = true;
+    static libxl_bitmap nodemap;
+    static libxl_physinfo physinfo;
+
+    if (need_init) {
+        libxl_bitmap_init(&nodemap);
+        libxl_physinfo_init(&physinfo);
+        need_init = false;
+
+        if (libxl_node_bitmap_alloc(ctx, &nodemap, 0)) {
+            fprintf(stderr, "libxl_node_bitmap_alloc_failed.\n");
+            exit(EXIT_FAILURE);
+        }
+        if (libxl_get_physinfo(ctx, &physinfo) != 0) {
+            fprintf(stderr, "libxl_physinfo failed.\n");
+            libxl_bitmap_dispose(&nodemap);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (info) {
+        libxl_domain_get_nodeaffinity(ctx, info->domid, &nodemap);
+
+        putchar(' ');
+        print_bitmap(nodemap.map, physinfo.nr_nodes, stdout);
+    } else fputs(entry->header, stdout);
+
+#if 0
+    /* unfortunately these get leaked on exit */
+    libxl_bitmap_dispose(&nodemap);
+    libxl_physinfo_dispose(&physinfo);
+#endif
+}
+
+#pragma GCC diagnostic pop
+
+static bool isfmtchar(int c)
+{
+    const bool opts[] = {
+        ['0'] = true,
+        ['1'] = true,
+        ['2'] = true,
+        ['3'] = true,
+        ['4'] = true,
+        ['5'] = true,
+        ['6'] = true,
+        ['7'] = true,
+        ['8'] = true,
+        ['9'] = true,
+        ['.'] = true,
+        ['#'] = true,
+        ['-'] = true,
+        ['+'] = true,
+        [' '] = true,
+        ['\''] = true,
+    };
+    if ((unsigned int)c < ARRAY_SIZE(opts) && opts[c]) return true;
+    else return false;
+}
+
+static void format(const format_table_t fmttab, const char *fmt,
+                   const void *info)
+{
+    while (fmt[0]) {
+        if (fmt[0] == '\\') {
+            switch (fmt[1]) {
+            case 0:
+                /* Uhm... */
+                return;
+            case '0':
+                putchar(0);
+                break;
+            case 'n':
+                fputs("\n", stdout);
+                break;
+            case 't':
+                putchar('\t');
+                break;
+            default:
+                putchar(fmt[1]);
+            }
+            fmt+=2;
+        } else if (fmt[0] == '%') {
+            size_t len=1;
+            unsigned char entryn;
+
+            while (isfmtchar(fmt[len])) ++len;
+
+            entryn = fmt[len] - 'A';
+            if (entryn < sizeof(format_table_t) / sizeof(fmttab[0]) &&
+                    fmttab[entryn].formatf)
+                fmttab[entryn].formatf(fmttab + entryn, info, fmt, len);
+            else {
+                fprintf(stderr, "Invalid conversion character \'%c\'\n",
+                        entryn);
+                exit(EXIT_FAILURE);
+            }
+
+            fmt += len + 1;
+        } else {
+            putchar(*fmt);
+            ++fmt;
+        }
+    }
+}
+
+
 static void list_vm(void)
 {
     libxl_vminfo *info;
-- 


-- 
(\___(\___(\______          --=> 8-) EHM <=--          ______/)___/)___/)
 \BS (    |         ehem+sigmsg@xxxxxxx  PGP 87145445         |    )   /
  \_CS\   |  _____  -O #include <stddisclaimer.h> O-   _____  |   /  _/
8A19\___\_|_/58D2 7E3D DDF4 7BA6 <-PGP-> 41D1 B375 37D0 8714\_|_/___/5445






 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.