Mailing List Archive

[xen-unstable] Add persistent guest & hv logging in xenconsoled.
# HG changeset patch
# User kfraser@localhost.localdomain
# Date 1180964952 -3600
# Node ID edf407a3dd70db0af60617b6c90aa3589d7c1c7d
# Parent da3185b03113611fd322e439f17103af4d11b064
Add persistent guest & hv logging in xenconsoled.

* The --log command line argument takes one of 4 values

- none - no logging (the default)
- hv - log all hypervisor messages
- guest - log all guest messages
- both - log all guest & hypervisor messages

* The --log-dir command line argument takes a path to specify where
to store logfiles. If omitted it defaults to /var/log/xen/console

* The hypervisor logfile is $LOGDIR/hypervisor.log

* The guest logfile is $LOGDIR/guest-[NAME].log

* If receiving a SIGHUP it will close & re-open all log files to
enable logrotate to do its magic

* Fixes the permissions of /var/run/xenconsoled.pid

* Adds a --pid-file command line argument to override the default
location of pid file (this is not really related to logging, but
since I was in that code...)

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
tools/console/daemon/io.c | 154 ++++++++++++++++++++++++++++++++++++++++++-
tools/console/daemon/main.c | 54 ++++++++++++++-
tools/console/daemon/utils.c | 2
3 files changed, 204 insertions(+), 6 deletions(-)

diff -r da3185b03113 -r edf407a3dd70 tools/console/daemon/io.c
--- a/tools/console/daemon/io.c Mon Jun 04 14:40:12 2007 +0100
+++ b/tools/console/daemon/io.c Mon Jun 04 14:49:12 2007 +0100
@@ -43,6 +43,14 @@
/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)

+extern int log_reload;
+extern int log_guest;
+extern int log_hv;
+extern char *log_dir;
+
+static int log_hv_fd = -1;
+static int xc_handle = -1;
+
struct buffer
{
char *data;
@@ -56,6 +64,7 @@ struct domain
{
int domid;
int tty_fd;
+ int log_fd;
bool is_dead;
struct buffer buffer;
struct domain *next;
@@ -102,6 +111,19 @@ static void buffer_append(struct domain
intf->out_cons = cons;
xc_evtchn_notify(dom->xce_handle, dom->local_port);

+ /* Get the data to the logfile as early as possible because if
+ * no one is listening on the console pty then it will fill up
+ * and handle_tty_write will stop being called.
+ */
+ if (dom->log_fd != -1) {
+ int len = write(dom->log_fd,
+ buffer->data + buffer->size - size,
+ size);
+ if (len < 0)
+ dolog(LOG_ERR, "Write to log failed on domain %d: %d (%s)\n",
+ dom->domid, errno, strerror(errno));
+ }
+
if (buffer->max_capacity &&
buffer->size > buffer->max_capacity) {
/* Discard the middle of the data. */
@@ -142,6 +164,53 @@ static bool domain_is_valid(int domid)

return ret;
}
+
+static int create_hv_log(void)
+{
+ char logfile[PATH_MAX];
+ int fd;
+ snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir);
+ logfile[PATH_MAX-1] = '\0';
+
+ fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ if (fd == -1)
+ dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
+ logfile, errno, strerror(errno));
+ return fd;
+}
+
+static int create_domain_log(struct domain *dom)
+{
+ char logfile[PATH_MAX];
+ char *namepath, *data, *s;
+ int fd, len;
+
+ namepath = xs_get_domain_path(xs, dom->domid);
+ s = realloc(namepath, strlen(namepath) + 6);
+ if (s == NULL) {
+ free(namepath);
+ return -1;
+ }
+ strcat(namepath, "/name");
+ data = xs_read(xs, XBT_NULL, namepath, &len);
+ if (!data)
+ return -1;
+ if (!len) {
+ free(data);
+ return -1;
+ }
+
+ snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data);
+ free(data);
+ logfile[PATH_MAX-1] = '\0';
+
+ fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ if (fd == -1)
+ dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
+ logfile, errno, strerror(errno));
+ return fd;
+}
+

static int domain_create_tty(struct domain *dom)
{
@@ -324,6 +393,9 @@ static int domain_create_ring(struct dom
}
}

+ if (log_guest)
+ dom->log_fd = create_domain_log(dom);
+
out:
return err;
}
@@ -351,6 +423,7 @@ static bool watch_domain(struct domain *
return success;
}

+
static struct domain *create_domain(int domid)
{
struct domain *dom;
@@ -382,6 +455,8 @@ static struct domain *create_domain(int
strcat(dom->conspath, "/console");

dom->tty_fd = -1;
+ dom->log_fd = -1;
+
dom->is_dead = false;
dom->buffer.data = 0;
dom->buffer.consumed = 0;
@@ -442,6 +517,10 @@ static void cleanup_domain(struct domain
if (d->tty_fd != -1) {
close(d->tty_fd);
d->tty_fd = -1;
+ }
+ if (d->log_fd != -1) {
+ close(d->log_fd);
+ d->log_fd = -1;
}

free(d->buffer.data);
@@ -604,13 +683,54 @@ static void handle_xs(void)
free(vec);
}

+static void handle_hv_logs(void)
+{
+ char buffer[1024*16];
+ char *bufptr = buffer;
+ unsigned int size = sizeof(buffer);
+ if (xc_readconsolering(xc_handle, &bufptr, &size, 1) == 0) {
+ int len = write(log_hv_fd, buffer, size);
+ if (len < 0)
+ dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)",
+ errno, strerror(errno));
+ }
+}
+
+static void handle_log_reload(void)
+{
+ if (log_guest) {
+ struct domain *d;
+ for (d = dom_head; d; d = d->next) {
+ if (d->log_fd != -1)
+ close(d->log_fd);
+ d->log_fd = create_domain_log(d);
+ }
+ }
+
+ if (log_hv) {
+ if (log_hv_fd != -1)
+ close(log_hv_fd);
+ log_hv_fd = create_hv_log();
+ }
+}
+
void handle_io(void)
{
fd_set readfds, writefds;
int ret;

- do {
+ if (log_hv) {
+ xc_handle = xc_interface_open();
+ if (xc_handle == -1)
+ dolog(LOG_ERR, "Failed to open xc handle: %d (%s)",
+ errno, strerror(errno));
+ else
+ log_hv_fd = create_hv_log();
+ }
+
+ for (;;) {
struct domain *d, *n;
+ struct timeval timeout = { 1, 0 }; /* Read HV logs every 1 second */
int max_fd = -1;

FD_ZERO(&readfds);
@@ -636,7 +756,30 @@ void handle_io(void)
}
}

- ret = select(max_fd + 1, &readfds, &writefds, 0, NULL);
+ /* XXX I wish we didn't have to busy wait for hypervisor logs
+ * but there's no obvious way to get event channel notifications
+ * for new HV log data as we can with guest */
+ ret = select(max_fd + 1, &readfds, &writefds, 0, log_hv_fd != -1 ? &timeout : NULL);
+
+ if (ret == -1) {
+ if (errno == EINTR) {
+ if (log_reload) {
+ handle_log_reload();
+ log_reload = 0;
+ }
+ continue;
+ }
+ dolog(LOG_ERR, "Failure in select: %d (%s)",
+ errno, strerror(errno));
+ break;
+ }
+
+ /* Check for timeout */
+ if (ret == 0) {
+ if (log_hv_fd != -1)
+ handle_hv_logs();
+ continue;
+ }

if (FD_ISSET(xs_fileno(xs), &readfds))
handle_xs();
@@ -656,7 +799,12 @@ void handle_io(void)
if (d->is_dead)
cleanup_domain(d);
}
- } while (ret > -1);
+ }
+
+ if (log_hv_fd != -1)
+ close(log_hv_fd);
+ if (xc_handle != -1)
+ xc_interface_close(xc_handle);
}

/*
diff -r da3185b03113 -r edf407a3dd70 tools/console/daemon/main.c
--- a/tools/console/daemon/main.c Mon Jun 04 14:40:12 2007 +0100
+++ b/tools/console/daemon/main.c Mon Jun 04 14:49:12 2007 +0100
@@ -23,6 +23,8 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
+#include <string.h>
+#include <signal.h>
#include <sys/types.h>

#include "xenctrl.h"
@@ -30,9 +32,19 @@
#include "utils.h"
#include "io.h"

+int log_reload = 0;
+int log_guest = 0;
+int log_hv = 0;
+char *log_dir = NULL;
+
+static void handle_hup(int sig)
+{
+ log_reload = 1;
+}
+
static void usage(char *name)
{
- printf("Usage: %s [-h] [-V] [-v] [-i]\n", name);
+ printf("Usage: %s [-h] [-V] [-v] [-i] [--log=none|guest|hv|all] [--log-dir=DIR] [--pid-file=PATH]\n", name);
}

static void version(char *name)
@@ -48,6 +60,9 @@ int main(int argc, char **argv)
{ "version", 0, 0, 'V' },
{ "verbose", 0, 0, 'v' },
{ "interactive", 0, 0, 'i' },
+ { "log", 1, 0, 'l' },
+ { "log-dir", 1, 0, 'r' },
+ { "pid-file", 1, 0, 'p' },
{ 0 },
};
bool is_interactive = false;
@@ -55,6 +70,7 @@ int main(int argc, char **argv)
int syslog_option = LOG_CONS;
int syslog_mask = LOG_WARNING;
int opt_ind = 0;
+ char *pidfile = NULL;

while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
switch (ch) {
@@ -71,6 +87,22 @@ int main(int argc, char **argv)
case 'i':
is_interactive = true;
break;
+ case 'l':
+ if (!strcmp(optarg, "all")) {
+ log_hv = 1;
+ log_guest = 1;
+ } else if (!strcmp(optarg, "hv")) {
+ log_hv = 1;
+ } else if (!strcmp(optarg, "guest")) {
+ log_guest = 1;
+ }
+ break;
+ case 'r':
+ log_dir = strdup(optarg);
+ break;
+ case 'p':
+ pidfile = strdup(optarg);
+ break;
case '?':
fprintf(stderr,
"Try `%s --help' for more information\n",
@@ -79,16 +111,22 @@ int main(int argc, char **argv)
}
}

+ if (!log_dir) {
+ log_dir = strdup("/var/log/xen/console");
+ }
+
if (geteuid() != 0) {
fprintf(stderr, "%s requires root to run.\n", argv[0]);
exit(EPERM);
}

+ signal(SIGHUP, handle_hup);
+
openlog("xenconsoled", syslog_option, LOG_DAEMON);
setlogmask(syslog_mask);

if (!is_interactive) {
- daemonize("/var/run/xenconsoled.pid");
+ daemonize(pidfile ? pidfile : "/var/run/xenconsoled.pid");
}

if (!xen_setup())
@@ -99,6 +137,18 @@ int main(int argc, char **argv)
handle_io();

closelog();
+ free(log_dir);
+ free(pidfile);

return 0;
}
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * indent-tabs-mode: t
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff -r da3185b03113 -r edf407a3dd70 tools/console/daemon/utils.c
--- a/tools/console/daemon/utils.c Mon Jun 04 14:40:12 2007 +0100
+++ b/tools/console/daemon/utils.c Mon Jun 04 14:49:12 2007 +0100
@@ -86,7 +86,7 @@ void daemonize(const char *pidfile)
if (chdir("/") < 0)
exit (1);

- fd = open(pidfile, O_RDWR | O_CREAT);
+ fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR);
if (fd == -1) {
exit(1);
}

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog