6645a82
diff -rup xen-3.1.0-src/tools/console/daemon/io.c xen-3.1.0-src.new/tools/console/daemon/io.c
6645a82
--- xen-3.1.0-src/tools/console/daemon/io.c	2007-05-18 10:45:21.000000000 -0400
549d626
+++ xen-3.1.0-src.new/tools/console/daemon/io.c	2007-06-12 10:27:43.000000000 -0400
6645a82
@@ -44,6 +44,14 @@
6645a82
 /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
6645a82
 #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
6645a82
 
6645a82
+extern int log_reload;
6645a82
+extern int log_guest;
6645a82
+extern int log_hv;
6645a82
+extern char *log_dir;
6645a82
+
6645a82
+static int log_hv_fd = -1;
6645a82
+static int xc_handle = -1;
6645a82
+
6645a82
 struct buffer
6645a82
 {
6645a82
 	char *data;
6645a82
@@ -57,6 +65,7 @@ struct domain
6645a82
 {
6645a82
 	int domid;
6645a82
 	int tty_fd;
6645a82
+	int log_fd;
6645a82
 	bool is_dead;
6645a82
 	struct buffer buffer;
6645a82
 	struct domain *next;
6645a82
@@ -103,6 +112,19 @@ static void buffer_append(struct domain 
6645a82
 	intf->out_cons = cons;
6645a82
 	xc_evtchn_notify(dom->xce_handle, dom->local_port);
6645a82
 
6645a82
+	/* Get the data to the logfile as early as possible because if
6645a82
+	 * no one is listening on the console pty then it will fill up
6645a82
+	 * and handle_tty_write will stop being called.
6645a82
+	 */
6645a82
+	if (dom->log_fd != -1) {
6645a82
+		int len = write(dom->log_fd,
6645a82
+				buffer->data + buffer->size - size,
6645a82
+				size);
6645a82
+		if (len < 0)
6645a82
+			dolog(LOG_ERR, "Write to log failed on domain %d: %d (%s)\n",
6645a82
+			      dom->domid, errno, strerror(errno));
6645a82
+	}
6645a82
+
6645a82
 	if (buffer->max_capacity &&
6645a82
 	    buffer->size > buffer->max_capacity) {
6645a82
 		/* Discard the middle of the data. */
549d626
@@ -144,6 +166,54 @@ static bool domain_is_valid(int domid)
6645a82
 	return ret;
6645a82
 }
6645a82
 
6645a82
+static int create_hv_log(void)
6645a82
+{
6645a82
+	char logfile[PATH_MAX];
6645a82
+	int fd;
6645a82
+	snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir);
6645a82
+	logfile[PATH_MAX-1] = '\0';
6645a82
+
6645a82
+	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
6645a82
+	if (fd == -1)
6645a82
+		dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
6645a82
+		      logfile, errno, strerror(errno));
6645a82
+	return fd;
6645a82
+}
6645a82
+
6645a82
+static int create_domain_log(struct domain *dom)
6645a82
+{
6645a82
+	char logfile[PATH_MAX];
6645a82
+	char *namepath, *data, *s;
6645a82
+	int fd, len;
6645a82
+
6645a82
+	namepath = xs_get_domain_path(xs, dom->domid);
6645a82
+	s = realloc(namepath, strlen(namepath) + 6);
6645a82
+	if (s == NULL) {
6645a82
+		free(namepath);
6645a82
+		return -1;
6645a82
+	}
549d626
+	namepath = s;
6645a82
+	strcat(namepath, "/name");
6645a82
+	data = xs_read(xs, XBT_NULL, namepath, &len;;
6645a82
+	if (!data)
6645a82
+		return -1;
6645a82
+	if (!len) {
6645a82
+		free(data);
6645a82
+		return -1;
6645a82
+	}
6645a82
+
6645a82
+	snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data);
6645a82
+	free(data);
6645a82
+	logfile[PATH_MAX-1] = '\0';
6645a82
+
6645a82
+	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
6645a82
+	if (fd == -1)
6645a82
+		dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
6645a82
+		      logfile, errno, strerror(errno));
6645a82
+	return fd;
6645a82
+}
6645a82
+
6645a82
+
6645a82
 static int domain_create_tty(struct domain *dom)
6645a82
 {
6645a82
 	char *path;
549d626
@@ -325,6 +395,9 @@ static int domain_create_ring(struct dom
6645a82
 		}
6645a82
 	}
6645a82
 
6645a82
+	if (log_guest)
6645a82
+		dom->log_fd = create_domain_log(dom);
6645a82
+
6645a82
  out:
6645a82
 	return err;
6645a82
 }
549d626
@@ -352,6 +425,7 @@ static bool watch_domain(struct domain *
6645a82
 	return success;
6645a82
 }
6645a82
 
6645a82
+
6645a82
 static struct domain *create_domain(int domid)
6645a82
 {
6645a82
 	struct domain *dom;
549d626
@@ -383,6 +457,8 @@ static struct domain *create_domain(int 
6645a82
 	strcat(dom->conspath, "/console");
6645a82
 
6645a82
 	dom->tty_fd = -1;
6645a82
+	dom->log_fd = -1;
6645a82
+
6645a82
 	dom->is_dead = false;
6645a82
 	dom->buffer.data = 0;
6645a82
 	dom->buffer.consumed = 0;
549d626
@@ -444,6 +520,10 @@ static void cleanup_domain(struct domain
6645a82
 		close(d->tty_fd);
6645a82
 		d->tty_fd = -1;
6645a82
 	}
6645a82
+	if (d->log_fd != -1) {
6645a82
+		close(d->log_fd);
6645a82
+		d->log_fd = -1;
6645a82
+	}
6645a82
 
6645a82
 	free(d->buffer.data);
6645a82
 	d->buffer.data = NULL;
549d626
@@ -605,13 +685,54 @@ static void handle_xs(void)
6645a82
 	free(vec);
6645a82
 }
6645a82
 
6645a82
+static void handle_hv_logs(void)
6645a82
+{
6645a82
+	char buffer[1024*16];
6645a82
+	char *bufptr = buffer;
6645a82
+	unsigned int size = sizeof(buffer);
6645a82
+	if (xc_readconsolering(xc_handle, &bufptr, &size, 1) == 0) {
6645a82
+		int len = write(log_hv_fd, buffer, size);
6645a82
+		if (len < 0)
6645a82
+			dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)",
6645a82
+			      errno, strerror(errno));
6645a82
+	}
6645a82
+}
6645a82
+
6645a82
+static void handle_log_reload(void)
6645a82
+{
6645a82
+	if (log_guest) {
6645a82
+		struct domain *d;
6645a82
+		for (d = dom_head; d; d = d->next) {
6645a82
+			if (d->log_fd != -1)
6645a82
+				close(d->log_fd);
6645a82
+			d->log_fd = create_domain_log(d);
6645a82
+		}
6645a82
+	}
6645a82
+
6645a82
+	if (log_hv) {
6645a82
+		if (log_hv_fd != -1)
6645a82
+			close(log_hv_fd);
6645a82
+		log_hv_fd = create_hv_log();
6645a82
+	}
6645a82
+}
6645a82
+
6645a82
 void handle_io(void)
6645a82
 {
6645a82
 	fd_set readfds, writefds;
6645a82
 	int ret;
6645a82
 
6645a82
-	do {
6645a82
+	if (log_hv) {
6645a82
+		xc_handle = xc_interface_open();
6645a82
+		if (xc_handle == -1)
6645a82
+			dolog(LOG_ERR, "Failed to open xc handle: %d (%s)",
6645a82
+			      errno, strerror(errno));
6645a82
+		else
6645a82
+			log_hv_fd = create_hv_log();
6645a82
+	}
6645a82
+
6645a82
+	for (;;) {
6645a82
 		struct domain *d, *n;
6645a82
+		struct timeval timeout = { 1, 0 }; /* Read HV logs every 1 second */
6645a82
 		int max_fd = -1;
6645a82
 
6645a82
 		FD_ZERO(&readfds);
549d626
@@ -637,7 +758,34 @@ void handle_io(void)
6645a82
 			}
6645a82
 		}
6645a82
 
6645a82
-		ret = select(max_fd + 1, &readfds, &writefds, 0, NULL);
6645a82
+		/* XXX I wish we didn't have to busy wait for hypervisor logs
6645a82
+		 * but there's no obvious way to get event channel notifications
6645a82
+		 * for new HV log data as we can with guest */
6645a82
+		ret = select(max_fd + 1, &readfds, &writefds, 0, log_hv_fd != -1 ? &timeout : NULL);
6645a82
+
6645a82
+		if (log_reload) {
6645a82
+			handle_log_reload();
6645a82
+			log_reload = 0;
6645a82
+		}
6645a82
+
6645a82
+		/* Abort if select failed, except for EINTR cases
6645a82
+		   which indicate a possible log reload */
6645a82
+		if (ret == -1) {
6645a82
+			if (errno == EINTR)
6645a82
+				continue;
6645a82
+			dolog(LOG_ERR, "Failure in select: %d (%s)",
6645a82
+			      errno, strerror(errno));
6645a82
+			break;
6645a82
+		}
6645a82
+
6645a82
+		/* Always process HV logs even if not a timeout */
6645a82
+		if (log_hv_fd != -1)
6645a82
+			handle_hv_logs();
6645a82
+
6645a82
+		/* Must not check return FDSET if it was a timeout */
6645a82
+		if (ret == 0) {
6645a82
+			continue;
6645a82
+		}
6645a82
 
6645a82
 		if (FD_ISSET(xs_fileno(xs), &readfds))
6645a82
 			handle_xs();
549d626
@@ -657,7 +805,16 @@ void handle_io(void)
6645a82
 			if (d->is_dead)
6645a82
 				cleanup_domain(d);
6645a82
 		}
6645a82
-	} while (ret > -1);
6645a82
+	}
6645a82
+
6645a82
+	if (log_hv_fd != -1) {
6645a82
+		close(log_hv_fd);
6645a82
+		log_hv_fd = -1;
6645a82
+	}
6645a82
+	if (xc_handle != -1) {
6645a82
+		xc_interface_close(xc_handle);
6645a82
+		xc_handle = -1;
6645a82
+	}
6645a82
 }
6645a82
 
6645a82
 /*
6645a82
diff -rup xen-3.1.0-src/tools/console/daemon/main.c xen-3.1.0-src.new/tools/console/daemon/main.c
6645a82
--- xen-3.1.0-src/tools/console/daemon/main.c	2007-05-18 10:45:21.000000000 -0400
6645a82
+++ xen-3.1.0-src.new/tools/console/daemon/main.c	2007-06-12 09:32:51.000000000 -0400
6645a82
@@ -23,6 +23,8 @@
6645a82
 #include <stdio.h>
6645a82
 #include <errno.h>
6645a82
 #include <unistd.h>
6645a82
+#include <string.h>
6645a82
+#include <signal.h>
6645a82
 #include <sys/types.h>
6645a82
 
6645a82
 #include "xenctrl.h"
6645a82
@@ -30,9 +32,19 @@
6645a82
 #include "utils.h"
6645a82
 #include "io.h"
6645a82
 
6645a82
+int log_reload = 0;
6645a82
+int log_guest = 0;
6645a82
+int log_hv = 0;
6645a82
+char *log_dir = NULL;
6645a82
+
6645a82
+static void handle_hup(int sig)
6645a82
+{
6645a82
+        log_reload = 1;
6645a82
+}
6645a82
+
6645a82
 static void usage(char *name)
6645a82
 {
6645a82
-	printf("Usage: %s [-h] [-V] [-v] [-i]\n", name);
6645a82
+	printf("Usage: %s [-h] [-V] [-v] [-i] [--log=none|guest|hv|all] [--log-dir=DIR] [--pid-file=PATH]\n", name);
6645a82
 }
6645a82
 
6645a82
 static void version(char *name)
6645a82
@@ -48,6 +60,9 @@ int main(int argc, char **argv)
6645a82
 		{ "version", 0, 0, 'V' },
6645a82
 		{ "verbose", 0, 0, 'v' },
6645a82
 		{ "interactive", 0, 0, 'i' },
6645a82
+		{ "log", 1, 0, 'l' },
6645a82
+		{ "log-dir", 1, 0, 'r' },
6645a82
+		{ "pid-file", 1, 0, 'p' },
6645a82
 		{ 0 },
6645a82
 	};
6645a82
 	bool is_interactive = false;
6645a82
@@ -55,6 +70,7 @@ int main(int argc, char **argv)
6645a82
 	int syslog_option = LOG_CONS;
6645a82
 	int syslog_mask = LOG_WARNING;
6645a82
 	int opt_ind = 0;
6645a82
+	char *pidfile = NULL;
6645a82
 
6645a82
 	while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
6645a82
 		switch (ch) {
6645a82
@@ -71,6 +87,22 @@ int main(int argc, char **argv)
6645a82
 		case 'i':
6645a82
 			is_interactive = true;
6645a82
 			break;
6645a82
+		case 'l':
6645a82
+		        if (!strcmp(optarg, "all")) {
6645a82
+			      log_hv = 1;
6645a82
+			      log_guest = 1;
6645a82
+			} else if (!strcmp(optarg, "hv")) {
6645a82
+			      log_hv = 1;
6645a82
+			} else if (!strcmp(optarg, "guest")) {
6645a82
+			      log_guest = 1;
6645a82
+			}
6645a82
+			break;
6645a82
+		case 'r':
6645a82
+		        log_dir = strdup(optarg);
6645a82
+			break;
6645a82
+		case 'p':
6645a82
+		        pidfile = strdup(optarg);
6645a82
+			break;
6645a82
 		case '?':
6645a82
 			fprintf(stderr,
6645a82
 				"Try `%s --help' for more information\n",
6645a82
@@ -79,16 +111,22 @@ int main(int argc, char **argv)
6645a82
 		}
6645a82
 	}
6645a82
 
6645a82
+	if (!log_dir) {
6645a82
+		log_dir = strdup("/var/log/xen/console");
6645a82
+	}
6645a82
+
6645a82
 	if (geteuid() != 0) {
6645a82
 		fprintf(stderr, "%s requires root to run.\n", argv[0]);
6645a82
 		exit(EPERM);
6645a82
 	}
6645a82
 
6645a82
+	signal(SIGHUP, handle_hup);
6645a82
+
6645a82
 	openlog("xenconsoled", syslog_option, LOG_DAEMON);
6645a82
 	setlogmask(syslog_mask);
6645a82
 
6645a82
 	if (!is_interactive) {
6645a82
-		daemonize("/var/run/xenconsoled.pid");
6645a82
+		daemonize(pidfile ? pidfile : "/var/run/xenconsoled.pid");
6645a82
 	}
6645a82
 
6645a82
 	if (!xen_setup())
6645a82
@@ -99,6 +137,18 @@ int main(int argc, char **argv)
6645a82
 	handle_io();
6645a82
 
6645a82
 	closelog();
6645a82
+	free(log_dir);
6645a82
+	free(pidfile);
6645a82
 
6645a82
 	return 0;
6645a82
 }
6645a82
+
6645a82
+/*
6645a82
+ * Local variables:
6645a82
+ *  c-file-style: "linux"
6645a82
+ *  indent-tabs-mode: t
6645a82
+ *  c-indent-level: 8
6645a82
+ *  c-basic-offset: 8
6645a82
+ *  tab-width: 8
6645a82
+ * End:
6645a82
+ */
6645a82
diff -rup xen-3.1.0-src/tools/console/daemon/utils.c xen-3.1.0-src.new/tools/console/daemon/utils.c
6645a82
--- xen-3.1.0-src/tools/console/daemon/utils.c	2007-05-18 10:45:21.000000000 -0400
6645a82
+++ xen-3.1.0-src.new/tools/console/daemon/utils.c	2007-06-12 09:28:21.000000000 -0400
6645a82
@@ -86,7 +86,7 @@ void daemonize(const char *pidfile)
6645a82
 	if (chdir("/") < 0)
6645a82
 		exit (1);
6645a82
 
6645a82
-	fd = open(pidfile, O_RDWR | O_CREAT);
6645a82
+	fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR);
6645a82
 	if (fd == -1) {
6645a82
 		exit(1);
6645a82
 	}