|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |