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

[Xen-devel] [PATCH] tools/xenconsoled: Log guest serial consoles



The ability to log guest consoles can now be controlled using xenstore keys
under /local/logconsole.

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

--
This has been used extensivly in the XenServer automated testing
infrastructure for many years, and interest has been expressed in having the
functionality upstream.
---
 docs/misc/xenstore-paths.markdown |   15 +++++++
 tools/console/daemon/io.c         |   82 +++++++++++++++++++++++++++++++++++++
 tools/console/daemon/io.h         |    1 +
 tools/console/daemon/main.c       |    2 +
 4 files changed, 100 insertions(+)

diff --git a/docs/misc/xenstore-paths.markdown 
b/docs/misc/xenstore-paths.markdown
index 1c634b5..c2de6d1 100644
--- a/docs/misc/xenstore-paths.markdown
+++ b/docs/misc/xenstore-paths.markdown
@@ -348,6 +348,21 @@ The time which the guest was started in 
SECONDS.MICROSECONDS format
 
 The guest's virtual time offset from UTC in seconds.
 
+## Logging paths
+
+### /local/logconsole/$DOMID = PATH [n,INTERNAL]
+
+Write a path to this key to enable console logging for the specified domain.
+Writing an empty string or removing the node causes logging to stop.
+Rewriting the path causes the daemon to close and reopen the file, which can
+be uses to rotate the log file.
+
+### /local/logconsole/@ = PATH [n,INTERNAL]
+
+Wildcard logging path, for domains without a `/local/logconsole/$DOMID` path.
+The path must contain "%d" which shall be substituted with the domid, and must
+not contain any other "%" characters.
+
 ## Platform-Level paths
 
 ### libxl Specific Paths
diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index 250550a..86314c4 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -103,8 +103,12 @@ struct domain {
        struct xencons_interface *interface;
        int event_count;
        long long next_period;
+       FILE *logfile;
 };
 
+static void update_logconsole(struct domain *);
+static char *wildcard_logfile = NULL;
+
 static struct domain *dom_head;
 
 static int write_all(int fd, const char* buf, size_t len)
@@ -158,6 +162,7 @@ static void buffer_append(struct domain *dom)
        struct buffer *buffer = &dom->buffer;
        XENCONS_RING_IDX cons, prod, size;
        struct xencons_interface *intf = dom->interface;
+       size_t begin;
 
        cons = intf->out_cons;
        prod = intf->out_prod;
@@ -176,9 +181,15 @@ static void buffer_append(struct domain *dom)
                }
        }
 
+       begin = buffer->size;
        while (cons != prod)
                buffer->data[buffer->size++] = intf->out[
                        MASK_XENCONS_IDX(cons++, intf->out)];
+       if (dom->logfile && buffer->size != begin) {
+               fwrite(&buffer->data[begin], buffer->size - begin, 1,
+                      dom->logfile);
+               fflush(dom->logfile);
+       }
 
        xen_mb();
        intf->out_cons = cons;
@@ -683,6 +694,9 @@ static struct domain *create_domain(int domid)
        if (!watch_domain(dom, true))
                goto out;
 
+       dom->logfile = NULL;
+       update_logconsole(dom);
+
        dom->next = dom_head;
        dom_head = dom;
 
@@ -714,6 +728,9 @@ static void remove_domain(struct domain *dom)
        for (pp = &dom_head; *pp; pp = &(*pp)->next) {
                if (dom == *pp) {
                        *pp = dom->next;
+                       if (dom->logfile)
+                               fclose(dom->logfile);
+                       dom->logfile = NULL;
                        free(dom);
                        break;
                }
@@ -773,6 +790,37 @@ static void enum_domains(void)
        }
 }
 
+static void update_logconsole(struct domain *dom)
+{
+       char *fname = NULL, *path = NULL;
+       FILE *oldfile;
+
+       oldfile = dom->logfile;
+
+       if (asprintf(&path, "/local/logconsole/%d", dom->domid) == -1)
+               goto out;
+
+       fname = xs_read(xs, XBT_NULL, path, NULL);
+       if (!fname && wildcard_logfile)
+               if (asprintf(&fname, wildcard_logfile, dom->domid) == -1)
+                       goto out;
+       if (!fname || !fname[0])
+               goto out;
+
+       dom->logfile = fopen(fname, "a");
+       if (!dom->logfile)
+               dolog(LOG_ERR, "fopen %s failed", fname);
+
+ out:
+       if (oldfile && dom->logfile == oldfile) {
+               dom->logfile = NULL;
+               fclose(oldfile);
+       }
+       free(fname);
+       free(path);
+       return;
+}
+
 static int ring_free_bytes(struct domain *dom)
 {
        struct xencons_interface *intf = dom->interface;
@@ -896,6 +944,30 @@ static void handle_xs(void)
                   been removed, so dom may be NULL here. */
                if (dom && dom->is_dead == false)
                        domain_create_ring(dom);
+       } else if (!strcmp(vec[XS_WATCH_TOKEN], "logconsole")) {
+               if (sscanf(vec[XS_WATCH_PATH], "/local/logconsole/%u",
+                          &domid) == 1) {
+                       dom = lookup_domain(domid);
+                       if (dom && dom->is_dead == false)
+                               update_logconsole(dom);
+               } else if (!strcmp(vec[XS_WATCH_PATH],
+                                  "/local/logconsole/@")) {
+                       char *wildcard, *tmp;
+                       free(wildcard_logfile);
+                       wildcard_logfile = NULL;
+                       wildcard = xs_read(xs, XBT_NULL,
+                                          "/local/logconsole/@", NULL);
+                       /* Sanitise string, as it gets used by asprintf().  It
+                        * should contain exactly one "%d" and no futher "%"s */
+                       if(wildcard) {
+                               tmp = strchr(wildcard, '%');
+                               if(tmp && tmp[1] == 'd' &&
+                                  strchr(&tmp[1], '%') == NULL)
+                                       wildcard_logfile = wildcard;
+                               else
+                                       free(wildcard);
+                       }
+               }
        }
 
        free(vec);
@@ -1197,6 +1269,16 @@ void handle_io(void)
        log_hv_evtchn = -1;
 }
 
+void watch_logconsole(void)
+{
+      bool success;
+
+      success = xs_watch(xs, "/local/logconsole", "logconsole");
+      if (!success)
+              dolog(LOG_ERR, "logconsole watch failed");
+      wildcard_logfile = xs_read(xs, XBT_NULL, "/local/logconsole/@", NULL);
+}
+
 /*
  * Local variables:
  *  c-file-style: "linux"
diff --git a/tools/console/daemon/io.h b/tools/console/daemon/io.h
index f658bfc..96e08b4 100644
--- a/tools/console/daemon/io.h
+++ b/tools/console/daemon/io.h
@@ -22,5 +22,6 @@
 #define CONSOLED_IO_H
 
 void handle_io(void);
+void watch_logconsole(void);
 
 #endif
diff --git a/tools/console/daemon/main.c b/tools/console/daemon/main.c
index 92d2fc4..8229162 100644
--- a/tools/console/daemon/main.c
+++ b/tools/console/daemon/main.c
@@ -161,6 +161,8 @@ int main(int argc, char **argv)
        if (!xen_setup())
                exit(1);
 
+       watch_logconsole();
+
        handle_io();
 
        closelog();
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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