Blob Blame History Raw
diff -rup xen-3.1.0-src/tools/console/daemon/io.c xen-3.1.0-src.new/tools/console/daemon/io.c
--- xen-3.1.0-src/tools/console/daemon/io.c	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src.new/tools/console/daemon/io.c	2007-06-12 10:27:43.000000000 -0400
@@ -44,6 +44,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;
@@ -57,6 +65,7 @@ struct domain
 {
 	int domid;
 	int tty_fd;
+	int log_fd;
 	bool is_dead;
 	struct buffer buffer;
 	struct domain *next;
@@ -103,6 +112,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. */
@@ -144,6 +166,54 @@ 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;
+	}
+	namepath = s;
+	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)
 {
 	char *path;
@@ -325,6 +395,9 @@ static int domain_create_ring(struct dom
 		}
 	}
 
+	if (log_guest)
+		dom->log_fd = create_domain_log(dom);
+
  out:
 	return err;
 }
@@ -352,6 +425,7 @@ static bool watch_domain(struct domain *
 	return success;
 }
 
+
 static struct domain *create_domain(int domid)
 {
 	struct domain *dom;
@@ -383,6 +457,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;
@@ -444,6 +520,10 @@ static void cleanup_domain(struct domain
 		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);
 	d->buffer.data = NULL;
@@ -605,13 +685,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);
@@ -637,7 +758,34 @@ 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 (log_reload) {
+			handle_log_reload();
+			log_reload = 0;
+		}
+
+		/* Abort if select failed, except for EINTR cases
+		   which indicate a possible log reload */
+		if (ret == -1) {
+			if (errno == EINTR)
+				continue;
+			dolog(LOG_ERR, "Failure in select: %d (%s)",
+			      errno, strerror(errno));
+			break;
+		}
+
+		/* Always process HV logs even if not a timeout */
+		if (log_hv_fd != -1)
+			handle_hv_logs();
+
+		/* Must not check return FDSET if it was a timeout */
+		if (ret == 0) {
+			continue;
+		}
 
 		if (FD_ISSET(xs_fileno(xs), &readfds))
 			handle_xs();
@@ -657,7 +805,16 @@ void handle_io(void)
 			if (d->is_dead)
 				cleanup_domain(d);
 		}
-	} while (ret > -1);
+	}
+
+	if (log_hv_fd != -1) {
+		close(log_hv_fd);
+		log_hv_fd = -1;
+	}
+	if (xc_handle != -1) {
+		xc_interface_close(xc_handle);
+		xc_handle = -1;
+	}
 }
 
 /*
diff -rup xen-3.1.0-src/tools/console/daemon/main.c xen-3.1.0-src.new/tools/console/daemon/main.c
--- xen-3.1.0-src/tools/console/daemon/main.c	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src.new/tools/console/daemon/main.c	2007-06-12 09:32:51.000000000 -0400
@@ -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 -rup xen-3.1.0-src/tools/console/daemon/utils.c xen-3.1.0-src.new/tools/console/daemon/utils.c
--- xen-3.1.0-src/tools/console/daemon/utils.c	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src.new/tools/console/daemon/utils.c	2007-06-12 09:28:21.000000000 -0400
@@ -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);
 	}