# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID deff07c1b686479f117d18ed12334e94310e9f69
# Parent ec1878b6956ea9eab2349fde6dccb7d814585ff4
Really include renamed console files. :-)
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
diff -r ec1878b6956e -r deff07c1b686 tools/console/Makefile
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/Makefile Sun Aug 7 09:13:39 2005
@@ -0,0 +1,39 @@
+
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+DAEMON_INSTALL_DIR = /usr/sbin
+CLIENT_INSTALL_DIR = /usr/libexec/xen
+
+INSTALL = install
+INSTALL_PROG = $(INSTALL) -m0755
+INSTALL_DIR = $(INSTALL) -d -m0755
+
+CC = gcc
+CFLAGS = -Wall -Werror -g3
+
+CFLAGS += -I $(XEN_XCS)
+CFLAGS += -I $(XEN_LIBXC)
+CFLAGS += -I $(XEN_XENSTORE)
+
+BIN = xenconsoled xenconsole
+
+all: $(BIN)
+
+clean:
+ $(RM) *.a *.so *.o *.rpm $(BIN)
+ $(RM) client/*.o daemon/*.o
+
+xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
+ $(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
+ -lxc -lxenstore
+
+xenconsole: $(patsubst %.c,%.o,$(wildcard client/*.c))
+ $(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
+ -lxc -lxenstore
+
+install: $(BIN)
+ $(INSTALL_DIR) -p $(DESTDIR)/$(DAEMON_INSTALL_DIR)
+ $(INSTALL_PROG) xenconsoled $(DESTDIR)/$(DAEMON_INSTALL_DIR)
+ $(INSTALL_DIR) -p $(DESTDIR)/$(CLIENT_INSTALL_DIR)
+ $(INSTALL_PROG) xenconsole $(DESTDIR)/$(CLIENT_INSTALL_DIR)
diff -r ec1878b6956e -r deff07c1b686 tools/console/client/main.c
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/client/main.c Sun Aug 7 09:13:39 2005
@@ -0,0 +1,228 @@
+/*\
+ * Copyright (C) International Business Machines Corp., 2005
+ * Author(s): Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ * Xen Console Daemon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+\*/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/select.h>
+#include <err.h>
+#include <errno.h>
+#include <pty.h>
+
+#include "xc.h"
+#include "xs.h"
+
+#define ESCAPE_CHARACTER 0x1d
+
+static volatile sig_atomic_t received_signal = 0;
+
+static void sighandler(int signum)
+{
+ received_signal = 1;
+}
+
+static bool write_sync(int fd, const void *data, size_t size)
+{
+ size_t offset = 0;
+ ssize_t len;
+
+ while (offset < size) {
+ len = write(fd, data + offset, size - offset);
+ if (len < 1) {
+ return false;
+ }
+ offset += len;
+ }
+
+ return true;
+}
+
+static void usage(const char *program) {
+ printf("Usage: %s [OPTION] DOMID\n"
+ "Attaches to a virtual domain console\n"
+ "\n"
+ " -h, --help display this help and exit\n"
+ , program);
+}
+
+/* don't worry too much if setting terminal attributes fail */
+static void init_term(int fd, struct termios *old)
+{
+ struct termios new_term;
+
+ if (tcgetattr(fd, old) == -1) {
+ return;
+ }
+
+ new_term = *old;
+ cfmakeraw(&new_term);
+
+ tcsetattr(fd, TCSAFLUSH, &new_term);
+}
+
+static void restore_term(int fd, struct termios *old)
+{
+ tcsetattr(fd, TCSAFLUSH, old);
+}
+
+static int console_loop(int xc_handle, domid_t domid, int fd)
+{
+ int ret;
+
+ do {
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ FD_SET(fd, &fds);
+
+ ret = select(fd + 1, &fds, NULL, NULL, NULL);
+ if (ret == -1) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ return -1;
+ }
+
+ if (FD_ISSET(STDIN_FILENO, &fds)) {
+ ssize_t len;
+ char msg[60];
+
+ len = read(STDIN_FILENO, msg, sizeof(msg));
+ if (len == 1 && msg[0] == ESCAPE_CHARACTER) {
+ return 0;
+ }
+
+ if (len == 0 || len == -1) {
+ if (len == -1 &&
+ (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
+ return -1;
+ }
+
+ if (!write_sync(fd, msg, len)) {
+ perror("write() failed");
+ return -1;
+ }
+ }
+
+ if (FD_ISSET(fd, &fds)) {
+ ssize_t len;
+ char msg[512];
+
+ len = read(fd, msg, sizeof(msg));
+ if (len == 0 || len == -1) {
+ if (len == -1 &&
+ (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
+ return -1;
+ }
+
+ if (!write_sync(STDOUT_FILENO, msg, len)) {
+ perror("write() failed");
+ return -1;
+ }
+ }
+ } while (received_signal == 0);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct termios attr;
+ int domid;
+ int xc_handle;
+ char *sopt = "hf:pc";
+ int ch;
+ int opt_ind=0;
+ struct option lopt[] = {
+ { "help", 0, 0, 'h' },
+ { "file", 1, 0, 'f' },
+ { "pty", 0, 0, 'p' },
+ { "ctty", 0, 0, 'c' },
+ { 0 },
+
+ };
+ char *str_pty;
+ char path[1024];
+ int spty;
+ unsigned int len = 0;
+ struct xs_handle *xs;
+
+ while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+ switch(ch) {
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1) {
+ fprintf(stderr, "Invalid number of arguments\n");
+ fprintf(stderr, "Try `%s --help' for more information.\n",
+ argv[0]);
+ exit(EINVAL);
+ }
+
+ domid = atoi(argv[optind]);
+
+ xs = xs_daemon_open();
+ if (xs == NULL) {
+ err(errno, "Could not contact XenStore");
+ }
+
+ xc_handle = xc_interface_open();
+ if (xc_handle == -1) {
+ err(errno, "xc_interface_open()");
+ }
+
+ signal(SIGTERM, sighandler);
+
+ snprintf(path, sizeof(path), "/console/%d/tty", domid);
+ str_pty = xs_read(xs, path, &len);
+ if (str_pty == NULL) {
+ err(errno, "Could not read tty from store");
+ }
+ spty = open(str_pty, O_RDWR | O_NOCTTY);
+ if (spty == -1) {
+ err(errno, "Could not open tty `%s'", str_pty);
+ }
+ free(str_pty);
+
+ init_term(STDIN_FILENO, &attr);
+ console_loop(xc_handle, domid, spty);
+ restore_term(STDIN_FILENO, &attr);
+
+ return 0;
+ }
diff -r ec1878b6956e -r deff07c1b686 tools/console/daemon/io.c
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/daemon/io.c Sun Aug 7 09:13:39 2005
@@ -0,0 +1,343 @@
+/*\
+ * Copyright (C) International Business Machines Corp., 2005
+ * Author(s): Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ * Xen Console Daemon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+\*/
+
+#define _GNU_SOURCE
+
+#include "utils.h"
+#include "io.h"
+
+#include "xc.h"
+#include "xs.h"
+#include "xen/io/domain_controller.h"
+#include "xcs_proto.h"
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+struct buffer
+{
+ char *data;
+ size_t size;
+ size_t capacity;
+ size_t max_capacity;
+};
+
+static void buffer_append(struct buffer *buffer, const void *data, size_t size)
+{
+ if ((buffer->capacity - buffer->size) < size) {
+ buffer->capacity += (size + 1024);
+ buffer->data = realloc(buffer->data, buffer->capacity);
+ if (buffer->data == NULL) {
+ dolog(LOG_ERR, "Memory allocation failed");
+ exit(ENOMEM);
+ }
+ }
+
+ memcpy(buffer->data + buffer->size, data, size);
+ buffer->size += size;
+
+ if (buffer->max_capacity &&
+ buffer->size > buffer->max_capacity) {
+ memmove(buffer->data + (buffer->size - buffer->max_capacity),
+ buffer->data, buffer->max_capacity);
+ buffer->data = realloc(buffer->data, buffer->max_capacity);
+ buffer->capacity = buffer->max_capacity;
+ }
+}
+
+static bool buffer_empty(struct buffer *buffer)
+{
+ return buffer->size == 0;
+}
+
+static void buffer_advance(struct buffer *buffer, size_t size)
+{
+ size = MIN(size, buffer->size);
+ memmove(buffer->data, buffer + size, buffer->size - size);
+ buffer->size -= size;
+}
+
+struct domain
+{
+ int domid;
+ int tty_fd;
+ struct buffer buffer;
+ struct domain *next;
+};
+
+static struct domain *dom_head;
+
+static bool domain_is_valid(int domid)
+{
+ bool ret;
+ xc_dominfo_t info;
+
+ ret = (xc_domain_getinfo(xc, domid, 1, &info) == 1 &&
+ info.domid == domid);
+
+ return ret;
+}
+
+static int domain_create_tty(struct domain *dom)
+{
+ char path[1024];
+ int master;
+
+ if ((master = getpt()) == -1 ||
+ grantpt(master) == -1 || unlockpt(master) == -1) {
+ dolog(LOG_ERR, "Failed to create tty for domain-%d",
+ dom->domid);
+ master = -1;
+ } else {
+ const char *slave = ptsname(master);
+ struct termios term;
+ char *data;
+ unsigned int len;
+
+ if (tcgetattr(master, &term) != -1) {
+ cfmakeraw(&term);
+ tcsetattr(master, TCSAFLUSH, &term);
+ }
+
+ xs_mkdir(xs, "/console");
+ snprintf(path, sizeof(path), "/console/%d", dom->domid);
+ xs_mkdir(xs, path);
+ strcat(path, "/tty");
+
+ xs_write(xs, path, slave, strlen(slave), O_CREAT);
+
+ snprintf(path, sizeof(path), "/console/%d/limit", dom->domid);
+ data = xs_read(xs, path, &len);
+ if (data) {
+ dom->buffer.max_capacity = strtoul(data, 0, 0);
+ free(data);
+ }
+ }
+
+ return master;
+}
+
+static struct domain *create_domain(int domid)
+{
+ struct domain *dom;
+
+ dom = (struct domain *)malloc(sizeof(struct domain));
+ if (dom == NULL) {
+ dolog(LOG_ERR, "Out of memory %s:%s():L%d",
+ __FILE__, __FUNCTION__, __LINE__);
+ exit(ENOMEM);
+ }
+
+ dom->domid = domid;
+ dom->tty_fd = domain_create_tty(dom);
+ dom->buffer.data = 0;
+ dom->buffer.size = 0;
+ dom->buffer.capacity = 0;
+ dom->buffer.max_capacity = 0;
+
+ dolog(LOG_DEBUG, "New domain %d", domid);
+
+ return dom;
+}
+
+static struct domain *lookup_domain(int domid)
+{
+ struct domain **pp;
+
+ for (pp = &dom_head; *pp; pp = &(*pp)->next) {
+ struct domain *dom = *pp;
+
+ if (dom->domid == domid) {
+ return dom;
+ } else if (dom->domid > domid) {
+ *pp = create_domain(domid);
+ (*pp)->next = dom;
+ return *pp;
+ }
+ }
+
+ *pp = create_domain(domid);
+ return *pp;
+}
+
+static void remove_domain(struct domain *dom)
+{
+ struct domain **pp;
+
+ dolog(LOG_DEBUG, "Removing domain-%d", dom->domid);
+
+ for (pp = &dom_head; *pp; pp = &(*pp)->next) {
+ struct domain *d = *pp;
+
+ if (dom->domid == d->domid) {
+ *pp = d->next;
+ if (d->buffer.data) {
+ free(d->buffer.data);
+ }
+ free(d);
+ break;
+ }
+ }
+}
+
+static void handle_tty_read(struct domain *dom)
+{
+ ssize_t len;
+ xcs_msg_t msg;
+
+ msg.type = XCS_REQUEST;
+ msg.u.control.remote_dom = dom->domid;
+ msg.u.control.msg.type = CMSG_CONSOLE;
+ msg.u.control.msg.subtype = CMSG_CONSOLE_DATA;
+ msg.u.control.msg.id = 1;
+
+ len = read(dom->tty_fd, msg.u.control.msg.msg, 60);
+ if (len < 1) {
+ close(dom->tty_fd);
+
+ if (domain_is_valid(dom->domid)) {
+ dom->tty_fd = domain_create_tty(dom);
+ } else {
+ remove_domain(dom);
+ }
+ } else if (domain_is_valid(dom->domid)) {
+ msg.u.control.msg.length = len;
+
+ if (!write_sync(xcs_data_fd, &msg, sizeof(msg))) {
+ dolog(LOG_ERR, "Write to xcs failed: %m");
+ }
+ } else {
+ close(dom->tty_fd);
+ remove_domain(dom);
+ }
+}
+
+static void handle_tty_write(struct domain *dom)
+{
+ ssize_t len;
+
+ len = write(dom->tty_fd, dom->buffer.data, dom->buffer.size);
+ if (len < 1) {
+ close(dom->tty_fd);
+
+ if (domain_is_valid(dom->domid)) {
+ dom->tty_fd = domain_create_tty(dom);
+ } else {
+ remove_domain(dom);
+ }
+ } else {
+ buffer_advance(&dom->buffer, len);
+ }
+}
+
+static void handle_xcs_msg(int fd)
+{
+ xcs_msg_t msg;
+
+ if (!read_sync(fd, &msg, sizeof(msg))) {
+ dolog(LOG_ERR, "read from xcs failed! %m");
+ } else if (msg.type == XCS_REQUEST) {
+ struct domain *dom;
+
+ dom = lookup_domain(msg.u.control.remote_dom);
+ buffer_append(&dom->buffer,
+ msg.u.control.msg.msg,
+ msg.u.control.msg.length);
+ }
+}
+
+static void enum_domains(void)
+{
+ int domid = 0;
+ xc_dominfo_t dominfo;
+
+ while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) {
+ lookup_domain(dominfo.domid);
+ domid = dominfo.domid + 1;
+ }
+}
+
+void handle_io(void)
+{
+ fd_set readfds, writefds;
+ int ret;
+ int max_fd = -1;
+ int num_of_writes = 0;
+
+ do {
+ struct domain *d;
+ struct timeval tv = { 1, 0 };
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+
+ FD_SET(xcs_data_fd, &readfds);
+ max_fd = MAX(xcs_data_fd, max_fd);
+
+ for (d = dom_head; d; d = d->next) {
+ if (d->tty_fd != -1) {
+ FD_SET(d->tty_fd, &readfds);
+ }
+
+ if (d->tty_fd != -1 && !buffer_empty(&d->buffer)) {
+ FD_SET(d->tty_fd, &writefds);
+ }
+
+ max_fd = MAX(d->tty_fd, max_fd);
+ }
+
+ ret = select(max_fd + 1, &readfds, &writefds, 0, &tv);
+ if (tv.tv_sec == 1 && (++num_of_writes % 100) == 0) {
+ /* FIXME */
+ /* This is a nasty hack. xcs does not handle the
+ control channels filling up well at all. We'll
+ throttle ourselves here since we do proper
+ queueing to give the domains a shot at pulling out
+ the data. Fixing xcs is not worth it as it's
+ going away */
+ tv.tv_usec = 1000;
+ select(0, 0, 0, 0, &tv);
+ }
+ enum_domains();
+
+ if (FD_ISSET(xcs_data_fd, &readfds)) {
+ handle_xcs_msg(xcs_data_fd);
+ }
+
+ for (d = dom_head; d; d = d->next) {
+ if (FD_ISSET(d->tty_fd, &readfds)) {
+ handle_tty_read(d);
+ }
+
+ if (FD_ISSET(d->tty_fd, &writefds)) {
+ handle_tty_write(d);
+ }
+ }
+ } while (ret > -1);
+}
diff -r ec1878b6956e -r deff07c1b686 tools/console/daemon/io.h
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/daemon/io.h Sun Aug 7 09:13:39 2005
@@ -0,0 +1,26 @@
+/*\
+ * Copyright (C) International Business Machines Corp., 2005
+ * Author(s): Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ * Xen Console Daemon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+\*/
+
+#ifndef CONSOLED_IO_H
+#define CONSOLED_IO_H
+
+void handle_io(void);
+
+#endif
diff -r ec1878b6956e -r deff07c1b686 tools/console/daemon/main.c
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/daemon/main.c Sun Aug 7 09:13:39 2005
@@ -0,0 +1,93 @@
+/*\
+ * Copyright (C) International Business Machines Corp., 2005
+ * Author(s): Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ * Xen Console Daemon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+\*/
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "xc.h"
+#include "xen/io/domain_controller.h"
+#include "xcs_proto.h"
+
+#include "utils.h"
+#include "io.h"
+
+int main(int argc, char **argv)
+{
+ const char *sopts = "hVvi";
+ struct option lopts[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'V' },
+ { "verbose", 0, 0, 'v' },
+ { "interactive", 0, 0, 'i' },
+ { 0 },
+ };
+ bool is_interactive = false;
+ int ch;
+ int syslog_option = LOG_CONS;
+ int syslog_mask = LOG_WARNING;
+ int opt_ind = 0;
+
+ while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
+ switch (ch) {
+ case 'h':
+ //usage(argv[0]);
+ exit(0);
+ case 'V':
+ //version(argv[0]);
+ exit(0);
+ case 'v':
+ syslog_option |= LOG_PERROR;
+ syslog_mask = LOG_DEBUG;
+ break;
+ case 'i':
+ is_interactive = true;
+ break;
+ case '?':
+ fprintf(stderr,
+ "Try `%s --help' for more information\n",
+ argv[0]);
+ exit(EINVAL);
+ }
+ }
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "%s requires root to run.\n", argv[0]);
+ exit(EPERM);
+ }
+
+ openlog("xenconsoled", syslog_option, LOG_DAEMON);
+ setlogmask(syslog_mask);
+
+ if (!is_interactive) {
+ daemonize("/var/run/xenconsoled.pid");
+ }
+
+ xen_setup();
+
+ handle_io();
+
+ closelog();
+
+ return 0;
+}
diff -r ec1878b6956e -r deff07c1b686 tools/console/daemon/utils.c
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/daemon/utils.c Sun Aug 7 09:13:39 2005
@@ -0,0 +1,251 @@
+/*\
+ * Copyright (C) International Business Machines Corp., 2005
+ * Author(s): Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ * Xen Console Daemon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+\*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+
+#include "xc.h"
+#include "xen/io/domain_controller.h"
+#include "xcs_proto.h"
+
+#include "utils.h"
+
+struct xs_handle *xs;
+int xc;
+
+int xcs_ctrl_fd = -1;
+int xcs_data_fd = -1;
+
+bool _read_write_sync(int fd, void *data, size_t size, bool do_read)
+{
+ size_t offset = 0;
+ ssize_t len;
+
+ while (offset < size) {
+ if (do_read) {
+ len = read(fd, data + offset, size - offset);
+ } else {
+ len = write(fd, data + offset, size - offset);
+ }
+
+ if (len < 1) {
+ if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
+ return false;
+ }
+ } else {
+ offset += len;
+ }
+ }
+
+ return true;
+}
+
+static int open_domain_socket(const char *path)
+{
+ struct sockaddr_un addr;
+ int sock;
+ size_t addr_len;
+
+ if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
+ goto out;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, path);
+ addr_len = sizeof(addr.sun_family) + strlen(XCS_SUN_PATH) + 1;
+
+ if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
+ goto out_close_sock;
+ }
+
+ return sock;
+
+ out_close_sock:
+ close(sock);
+ out:
+ return -1;
+}
+
+static void child_exit(int sig)
+{
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+}
+
+void daemonize(const char *pidfile)
+{
+ pid_t pid;
+ int fd;
+ int len;
+ int i;
+ char buf[100];
+
+ if (getppid() == 1) {
+ return;
+ }
+
+ if ((pid = fork()) > 0) {
+ exit(0);
+ } else if (pid == -1) {
+ err(errno, "fork() failed");
+ }
+
+ setsid();
+
+ /* redirect fd 0,1,2 to /dev/null */
+ if ((fd = open("/dev/null",O_RDWR)) == -1) {
+ exit(1);
+ }
+
+ for (i = 0; i <= 2; i++) {
+ close(i);
+ dup2(fd, i);
+ }
+
+ close(fd);
+
+ umask(027);
+ chdir("/");
+
+ fd = open(pidfile, O_RDWR | O_CREAT);
+ if (fd == -1) {
+ exit(1);
+ }
+
+ if (lockf(fd, F_TLOCK, 0) == -1) {
+ exit(1);
+ }
+
+ len = sprintf(buf, "%d\n", getpid());
+ write(fd, buf, len);
+
+ signal(SIGCHLD, child_exit);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+}
+
+/* synchronized send/recv strictly for setting up xcs */
+/* always use asychronize callbacks any other time */
+static bool xcs_send_recv(int fd, xcs_msg_t *msg)
+{
+ bool ret = false;
+
+ if (!write_sync(fd, msg, sizeof(*msg))) {
+ dolog(LOG_ERR, "Write failed at %s:%s():L%d? Possible bug.",
+ __FILE__, __FUNCTION__, __LINE__);
+ goto out;
+ }
+
+ if (!read_sync(fd, msg, sizeof(*msg))) {
+ dolog(LOG_ERR, "Read failed at %s:%s():L%d? Possible bug.",
+ __FILE__, __FUNCTION__, __LINE__);
+ goto out;
+ }
+
+ ret = true;
+
+ out:
+ return ret;
+}
+
+bool xen_setup(void)
+{
+ int sock;
+ xcs_msg_t msg;
+
+ xs = xs_daemon_open();
+ if (xs == NULL) {
+ dolog(LOG_ERR,
+ "Failed to contact xenstore (%m). Is it running?");
+ goto out;
+ }
+
+ xc = xc_interface_open();
+ if (xc == -1) {
+ dolog(LOG_ERR, "Failed to contact hypervisor (%m)");
+ goto out;
+ }
+
+ sock = open_domain_socket(XCS_SUN_PATH);
+ if (sock == -1) {
+ dolog(LOG_ERR, "Failed to contact xcs (%m). Is it running?");
+ goto out_close_store;
+ }
+
+ xcs_ctrl_fd = sock;
+
+ sock = open_domain_socket(XCS_SUN_PATH);
+ if (sock == -1) {
+ dolog(LOG_ERR, "Failed to contact xcs (%m). Is it running?");
+ goto out_close_ctrl;
+ }
+
+ xcs_data_fd = sock;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = XCS_CONNECT_CTRL;
+ if (!xcs_send_recv(xcs_ctrl_fd, &msg) || msg.result != XCS_RSLT_OK) {
+ dolog(LOG_ERR, "xcs control connect failed. Possible bug.");
+ goto out_close_data;
+ }
+
+ msg.type = XCS_CONNECT_DATA;
+ if (!xcs_send_recv(xcs_data_fd, &msg) || msg.result != XCS_RSLT_OK) {
+ dolog(LOG_ERR, "xcs data connect failed. Possible bug.");
+ goto out_close_data;
+ }
+
+ /* Since the vast majority of control messages are console messages
+ it's just easier to ignore other messages that try to bind to
+ a specific type. */
+ msg.type = XCS_MSG_BIND;
+ msg.u.bind.port = PORT_WILDCARD;
+ msg.u.bind.type = TYPE_WILDCARD;
+ if (!xcs_send_recv(xcs_ctrl_fd, &msg) || msg.result != XCS_RSLT_OK) {
+ dolog(LOG_ERR, "xcs vind failed. Possible bug.");
+ goto out_close_data;
+ }
+
+ return true;
+
+ out_close_data:
+ close(xcs_ctrl_fd);
+ xcs_data_fd = -1;
+ out_close_ctrl:
+ close(xcs_ctrl_fd);
+ xcs_ctrl_fd = -1;
+ out_close_store:
+ xs_daemon_close(xs);
+ out:
+ return false;
+}
+
diff -r ec1878b6956e -r deff07c1b686 tools/console/daemon/utils.h
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/daemon/utils.h Sun Aug 7 09:13:39 2005
@@ -0,0 +1,47 @@
+/*\
+ * Copyright (C) International Business Machines Corp., 2005
+ * Author(s): Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ * Xen Console Daemon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+\*/
+
+#ifndef CONSOLED_UTILS_H
+#define CONSOLED_UTILS_H
+
+#include <stdbool.h>
+#include <syslog.h>
+#include <stdio.h>
+
+#include "xs.h"
+
+void daemonize(const char *pidfile);
+bool xen_setup(void);
+#define read_sync(fd, buffer, size) _read_write_sync(fd, buffer, size, true)
+#define write_sync(fd, buffer, size) _read_write_sync(fd, buffer, size, false)
+bool _read_write_sync(int fd, void *data, size_t size, bool do_read);
+
+extern int xcs_ctrl_fd;
+extern int xcs_data_fd;
+extern struct xs_handle *xs;
+extern int xc;
+
+#if 1
+#define dolog(val, fmt, ...) syslog(val, fmt, ## __VA_ARGS__)
+#else
+#define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
+#endif
+
+#endif
diff -r ec1878b6956e -r deff07c1b686 tools/console/testsuite/Makefile
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/testsuite/Makefile Sun Aug 7 09:13:39 2005
@@ -0,0 +1,11 @@
+CFLAGS=-g -Wall
+CC=gcc
+LDFLAGS=-static
+
+all: console-dom0 console-domU procpipe
+
+console-dom0: console-dom0.o
+console-domU: console-domU.o
+procpipe: procpipe.o
+
+clean:; $(RM) *.o console-domU console-dom0 procpipe
diff -r ec1878b6956e -r deff07c1b686 tools/console/testsuite/README
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/testsuite/README Sun Aug 7 09:13:39 2005
@@ -0,0 +1,29 @@
+ABOUT
+
+This tool uses two programs, one that lives in dom0 and one that lives in domU
+to verify that no data is lost. dom0 and domU share a handshake with each
+other that they use to exchange a random seed.
+
+Both programs then generate a series of random numbers and then writes and
+reads the numbers via the console. Because each side starts with the same seed
+they know what data the other side is generating and therefore what should be
+expected.
+
+RUNNNING
+
+console-domU should be installed within the guest image. It must be launched
+from the client automatically. I use a custom initrd image and put it in the
+/linuxrc.
+
+console-dom0 and console-domU will communicate with each other and stress the
+console code. You can verify it at various levels by invoking it in different
+ways. procpipe is used to connect the two. I use the following command for
+testing:
+
+./procpipe ./console-dom0 'xm create -c /etc/xen/xmexample1'
+
+xmexample1 has no devices and no root set (this is what triggers /linuxrc).
+
+If it freezes, it probably means that console-domU is expecting more data from
+console-dom0 (which means that some data got dropped). I'd like to add
+timeouts in the future to handle this more gracefully.
diff -r ec1878b6956e -r deff07c1b686 tools/console/testsuite/console-dom0.c
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/testsuite/console-dom0.c Sun Aug 7 09:13:39 2005
@@ -0,0 +1,117 @@
+/* Written by Anthony Liguori <aliguori@xxxxxxxxxx> */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+static void generate_random_buffer(char *buffer, size_t size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ buffer[i] = random() & 0xFF;
+ }
+}
+
+static void canonicalize(char *buffer)
+{
+ char *reader, *writer;
+
+ reader = writer = buffer;
+
+ while (*reader) {
+ *writer = *reader;
+ if (*reader != '\r') writer++;
+ reader++;
+ }
+ *writer = *reader;
+}
+
+int main(int argc, char **argv)
+{
+ char buffer[4096];
+ char *line;
+ unsigned int seed;
+ size_t size;
+ int runs;
+ unsigned long long total_bytes = 0;
+ struct termios term;
+
+ tcgetattr(STDIN_FILENO, &term);
+ cfmakeraw(&term);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
+
+ tcgetattr(STDOUT_FILENO, &term);
+ cfmakeraw(&term);
+ tcsetattr(STDOUT_FILENO, TCSAFLUSH, &term);
+
+ while ((line = fgets(buffer, sizeof(buffer), stdin))) {
+ canonicalize(line);
+
+ if (strcmp(line, "!!!XEN Test Begin!!!\n") == 0) {
+ break;
+ } else {
+ fprintf(stderr, "%s", line);
+ }
+ }
+
+ if (line == NULL) {
+ fprintf(stderr, "Client never sent start string.\n");
+ return 1;
+ }
+
+ seed = time(0);
+
+ printf("%u\n", seed); fflush(stdout);
+
+ fprintf(stderr, "Waiting for seed acknowledgement\n");
+ line = fgets(buffer, sizeof(buffer), stdin);
+ if (line == NULL) {
+ fprintf(stderr, "Client never acknowledge seed.\n");
+ return 1;
+ }
+
+ canonicalize(line);
+ if (strcmp(line, "Seed Okay.\n") != 0) {
+ fprintf(stderr, "Incorrect seed acknowledgement.\n");
+ fprintf(stderr, "[%s]", line);
+ return 1;
+ } else {
+ fprintf(stderr, "Processed seed.\n");
+ }
+
+ srandom(seed);
+
+ for (runs = (random() % 100000) + 4096; runs > 0; runs--) {
+
+ size = random() % 4096;
+
+ fprintf(stderr, "Writing %d bytes.\n", size);
+
+ generate_random_buffer(buffer, size);
+ fwrite(buffer, size, 1, stdout);
+ fflush(stdout);
+
+ do {
+ line = fgets(buffer, sizeof(buffer), stdin);
+ if (line == NULL) {
+ fprintf(stderr, "Premature EOF from client.\n");
+ return 1;
+ }
+
+ canonicalize(line);
+ fprintf(stderr, "%s", line);
+ } while (strcmp(line, "Okay.\n") != 0);
+
+ total_bytes += size;
+ }
+
+ fprintf(stderr, "PASS: processed %llu byte(s).\n", total_bytes);
+
+ return 0;
+}
diff -r ec1878b6956e -r deff07c1b686 tools/console/testsuite/console-domU.c
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/testsuite/console-domU.c Sun Aug 7 09:13:39 2005
@@ -0,0 +1,76 @@
+/* Written by Anthony Liguori <aliguori@xxxxxxxxxx> */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <termios.h>
+#include <unistd.h>
+
+static void canonicalize(char *buffer)
+{
+ char *reader, *writer;
+
+ reader = writer = buffer;
+
+ while (*reader) {
+ *writer = *reader;
+ if (*reader != '\r') writer++;
+ reader++;
+ }
+ *writer = *reader;
+}
+
+int main(int argc, char **argv)
+{
+ char buffer[4096];
+ char *line;
+ unsigned int seed;
+ size_t size;
+ int i;
+ int runs;
+ struct termios term;
+
+ tcgetattr(STDIN_FILENO, &term);
+ cfmakeraw(&term);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &term);
+
+ tcgetattr(STDOUT_FILENO, &term);
+ cfmakeraw(&term);
+ tcsetattr(STDOUT_FILENO, TCSAFLUSH, &term);
+
+ printf("!!!XEN Test Begin!!!\n"); fflush(stdout);
+ line = fgets(buffer, sizeof(buffer), stdin);
+ if (line == NULL) {
+ printf("Failure\n"); fflush(stdout);
+ return 1;
+ }
+
+ canonicalize(line);
+ seed = strtoul(line, 0, 0);
+
+ printf("Seed Okay.\n"); fflush(stdout);
+
+ srandom(seed);
+
+ for (runs = (random() % 100000) + 4096; runs > 0; runs--) {
+ size = random() % 4096;
+
+ for (i = 0; i < size; i++) {
+ int ch;
+ int exp;
+
+ ch = fgetc(stdin);
+ exp = random() & 0xFF;
+ if (ch != exp) {
+ printf("Expected %d got %d\n",
+ exp, ch);
+ fflush(stdout);
+ }
+ printf("Got %d/%d good bytes\n", i, size);
+ }
+
+ printf("Okay.\n"); fflush(stdout);
+ }
+
+ return 0;
+}
diff -r ec1878b6956e -r deff07c1b686 tools/console/testsuite/procpipe.c
--- /dev/null Sun Aug 7 09:12:55 2005
+++ b/tools/console/testsuite/procpipe.c Sun Aug 7 09:13:39 2005
@@ -0,0 +1,133 @@
+/* Written by Anthony Liguori <aliguori@xxxxxxxxxx> */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <err.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define PACKAGE_NAME "procpipe"
+#define PACKAGE_VERSION "0.0.1"
+
+#define GPL_SHORT \
+"This is free software; see the source for copying conditions. There is NO\n"\
+"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+#define PACKAGE_BUGS "aliguori@xxxxxxxxxx"
+#define PACKAGE_AUTHOR "Anthony Liguori"
+#define PACKAGE_OWNER "IBM, Corp."
+#define PACKAGE_LICENSE GPL_SHORT
+
+static void usage(const char *name)
+{
+ printf("Usage: %s [OPTIONS]\n"
+ "\n"
+ " -h, --help display this help and exit\n"
+ " -V, --version output version information and exit\n"
+ "\n"
+ "Report bugs to <%s>.\n"
+ , name, PACKAGE_BUGS);
+}
+
+static void version(const char *name)
+{
+ printf("%s (%s) %s\n"
+ "Written by %s.\n"
+ "\n"
+ "Copyright (C) 2005 %s.\n"
+ "%s\n"
+ , name, PACKAGE_NAME, PACKAGE_VERSION,
+ PACKAGE_AUTHOR, PACKAGE_OWNER, PACKAGE_LICENSE);
+}
+
+static pid_t exec(int stdout, int stdin, const char *cmd)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid == 0) {
+ close(STDOUT_FILENO);
+ dup2(stdout, STDOUT_FILENO);
+ close(STDIN_FILENO);
+ dup2(stdin, STDIN_FILENO);
+
+ execlp("/bin/sh", "sh", "-c", cmd, NULL);
+ }
+
+ return pid;
+}
+
+int main(int argc, char **argv)
+{
+ int ch, opt_ind = 0;
+ const char *sopt = "hV";
+ struct option lopt[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'V' },
+ { 0 }
+ };
+ int host_stdout[2];
+ int host_stdin[2];
+ int res;
+ pid_t pid1, pid2;
+ int status;
+
+ while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+ switch (ch) {
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ case 'V':
+ version(argv[0]);
+ exit(0);
+ case '?':
+ errx(EINVAL, "Try `%s --help' for more information.",
+ argv[0]);
+ }
+ }
+
+ if ((argc - optind) != 2) {
+ errx(EINVAL, "Two commands are required.\n"
+ "Try `%s --help' for more information.", argv[0]);
+ }
+
+ res = pipe(host_stdout);
+ if (res == -1) {
+ err(errno, "pipe() failed");
+ }
+
+ res = pipe(host_stdin);
+ if (res == -1) {
+ err(errno, "pipe() failed");
+ }
+
+ pid1 = exec(host_stdout[1], host_stdin[0], argv[optind]);
+ if (pid1 == -1) {
+ err(errno, "exec(%s)", argv[optind]);
+ }
+
+ pid2 = exec(host_stdin[1], host_stdout[0], argv[optind + 1]);
+ if (pid2 == -1) {
+ err(errno, "exec(%s)", argv[optind + 1]);
+ }
+
+ waitpid(pid1, &status, 0);
+ if (WIFEXITED(status)) status = WEXITSTATUS(status);
+
+ if (status != 0) {
+ printf("Child exited with status %d\n", status);
+ }
+
+ waitpid(pid2, &status, 0);
+ if (WIFEXITED(status)) status = WEXITSTATUS(status);
+
+ if (status != 0) {
+ printf("Child2 exited with status %d\n", status);
+ }
+
+ return 0;
+}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|