All of lore.kernel.org
 help / color / mirror / Atom feed
* RE: [PATCH] Console Daemon
@ 2005-08-02 17:45 Ian Pratt
  2005-08-02 17:49 ` Anthony Liguori
  2005-08-02 17:55 ` Christian Limpach
  0 siblings, 2 replies; 22+ messages in thread
From: Ian Pratt @ 2005-08-02 17:45 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: xen-devel, Rusty Russell, Ian Pratt, Christian Limpach,
	Robert Read


> What I was thinking is having the following layout in the store:
> 
> /domain/<uuid>/console/tty
> /domain/<uuid>/console/limit
> /domain/<uuid>/console/history
> 
> tty is obviously the tty for the domain (if tty doesn't 
> exist, it means someone is connected already)
> 
> limit is the maximum amount of data (in bytes) that will be buffered
> 
> history is the amount of history (in bytes) that will be 
> saved.  When a client reconnects, they will first receive 
> whatever's in the history.
> 
> Does this seem agreeable?

Having 'history' when you reconnect seems a bit over the top -- I'd make
this a 'phase 2' thing.

However, having a parameter which indicates the amount of history that
will be logged to disk might be useful. (whenever the file reaches size
X, throw away the first 20%.)

> >Please can you explain how tty's get allocated.
> >  
> In the current scheme, a tty is allocated for each domain 
> whenever data arrives for the domain or if consoled detects a 
> new domain was created.  
> It currently polls to see if new domains were created every 
> second.  You can avoid the race condition by signalling 
> consoled which will break it out of it's select loop.  Not 
> very pretty but it solves the problem of something like xm create -c.

We definitely need xenstore support for registering watchers for items
that don't exist yet. Having to poll is daft.


Ian

^ permalink raw reply	[flat|nested] 22+ messages in thread
* RE: [PATCH] Console Daemon
@ 2005-08-03 11:13 Ian Pratt
  2005-08-03 12:41 ` Keir Fraser
  0 siblings, 1 reply; 22+ messages in thread
From: Ian Pratt @ 2005-08-03 11:13 UTC (permalink / raw)
  To: Rusty Russell; +Cc: xen-devel, Ian Pratt, Robert Read, Christian Limpach

> 	I don't think externally-supplied pages are necessary.  
> I was thinking of writing the page (or pages) into the store 
> immediately (since we don't need locks, or to wait for a 
> reply).  

We want to be able to get console output very early on, before xenbus
has come up.

However, it makes sense for xenbus to learn about the console buffer
once its up, as we'll want to use it (in future) for establishing
multiple tty's etc.

> I think we want more than one page because my boot 
> messages almost hit 8k to the first login prompt, and the 
> idea of requiring a console daemon repulses me.

It only really needs to be big enough to absorb all the messages before
Linux's console buffering code comes up, which isn't very much,
certainly <4KB.

My view is that we should continue using the same buffer once xenbus
comes up, hence there should be a simple multiplexing protocol.  

Ian

^ permalink raw reply	[flat|nested] 22+ messages in thread
* RE: [PATCH] Console Daemon
@ 2005-08-03  9:32 Ian Pratt
  2005-08-03 10:58 ` Rusty Russell
  0 siblings, 1 reply; 22+ messages in thread
From: Ian Pratt @ 2005-08-03  9:32 UTC (permalink / raw)
  To: Rusty Russell, Anthony Liguori
  Cc: xen-devel, Ian Pratt, Christian Limpach, Robert Read

 > On Tue, 2005-08-02 at 11:30 -0500, Anthony Liguori wrote:
> > What I was thinking is having the following layout in the store:
> > 
> > /domain/<uuid>/console/tty
> > /domain/<uuid>/console/limit
> > /domain/<uuid>/console/history
> 
> Interesting question.  None of this is actually useful to the 
> domain, although it's clearly related to the domain.
> 
> A better place might be:
> 
> 	/tool/consoled/<uuid>/
> 
> I was thinking of a console rewrite which puts the list of 
> shared pages in /domain/<uuid>/console/.  I'll be looking at 
> this once the rest of the store stuff is merged (soon, at the 
> rate Christian is working).

Synchornize with Robert Read, who's working up a patch to move the
console onto it's own ring buffer. This will be set up by the domain
builder so we can get immediate start of day console access, rather than
being boot strapped via xenbus.

Thanks,
Ian

^ permalink raw reply	[flat|nested] 22+ messages in thread
* RE: [PATCH] Console Daemon
@ 2005-08-02 15:59 Ian Pratt
  2005-08-02 16:30 ` Anthony Liguori
  0 siblings, 1 reply; 22+ messages in thread
From: Ian Pratt @ 2005-08-02 15:59 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: xen-devel, Rusty Russell, Ian Pratt, Christian Limpach,
	Robert Read

 
> Today it buffers N bytes worth of data in memory regardless 
> of whether the tty is connected (or reading from).  How much 
> it buffers is configurable via the store (by default the 
> buffer has no limit so ensure console data is never lost).

If you connect and disconnect do you continue from where you left off or
get sent the last N bytes again?

I think the former behaviour is definitely preferable, or at the very
least should be a configuration option.

Please can you explain how tty's get allocated.

Thanks,
Ian 
 
> Keeping a history wouldn't be a hard change.  I'll submit 
> some patches.
> 
> Regards,
> 
> Anthony Liguori
> 
> >Thanks,
> >Ian
> >
> >  
> >
> 
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread
* RE: [PATCH] Console Daemon
@ 2005-08-02 14:45 Ian Pratt
  2005-08-02 15:05 ` Anthony Liguori
  0 siblings, 1 reply; 22+ messages in thread
From: Ian Pratt @ 2005-08-02 14:45 UTC (permalink / raw)
  To: Keir Fraser, Anthony Liguori
  Cc: xen-devel, Rusty Russell, Ian Pratt, Christian Limpach,
	Robert Read

 
> > This is the first patch to move the console code out of 
> Xend and into 
> > a separate daemon.  In this patch I've included the daemon and a 
> > front-end.  I've also have the console code removed from 
> Xend locally 
> > but I wanted to clarify a few things first before submitting that.
> 
> I checked in consoled. Can you send any further fixes, and 
> code to plumb through xend?
> 
> Is it possible to make it configurable where console i/o goes 
> (e.g., tcp socket as an option instead of tty?).

I guess it would be nice to have tcp sockets as an option (with a
optional restriction to localhost access), but not a huge deal. In any
event, xend needs to know of, or prefereable be in control of, which tty
or port gets allocated.

What I'd really like to see this console deamon do is to implement a
FIFO buffer of the last N megabytes of console output, hence providing
buffering while the tty is disconnected. Regardless of whether the tty
is connected, it would be good to keep the last M megabytes stored on
disk in /var/log/xen-myvmname.

Thanks,
Ian

^ permalink raw reply	[flat|nested] 22+ messages in thread
* [PATCH] Console Daemon
@ 2005-07-26  4:09 Anthony Liguori
  2005-07-26  9:29 ` aq
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Anthony Liguori @ 2005-07-26  4:09 UTC (permalink / raw)
  To: xen-devel; +Cc: Christian Limpach, Ian Pratt, Rusty Russell, Robert Read

[-- Attachment #1: Type: text/plain, Size: 1887 bytes --]

Howdy,

This is the first patch to move the console code out of Xend and into a 
separate daemon.  In this patch I've included the daemon and a 
front-end.  I've also have the console code removed from Xend locally 
but I wanted to clarify a few things first before submitting that.

Here's how it works:

1) Daemon sits on control channel (via xcs) waiting for console messages
2) Buffers all console data received
3) Publishes the location of a tty that can be used for reading in 
/console/<domid>/tty
4) Reads a value from the store to determine what the limit of console 
data should be (/console/<domid>/limit) to prevent DoS attacks

Using it is quite simple, just run consoled and use the xc_console 
program to connect to the console.  It uses syslog for logging.

My current Xend patch just removes all of the console handling code from 
Xend and executes /usr/libexec/xen/xc_console with the right domid for 
the xm console command.  I choose to use an external program instead of 
the existing console_client.py because I already had the code and 
thought it would be useful to have an exec'able program so we could drop 
privileges.  Happy to use the console_client.py code though if that's 
desired.

The only current issue is that I'd like to store the tty info in 
<home>/console/tty since it's just another device.  However, Xend uses 
UUIDs so figuring out the home path is difficult.  Are we going to stick 
with this home path convention?  It would be a lot nicer if we used 
domids in the home path so that we could easily lookup info without 
having to search the whole /domain directory.  We can still keep UUIDs 
within the home path.  I'll add that to my patch if that's agreeable.

It will be easy to modify consoled to support the new kernel console 
driver when it's ready too.

Regards,

Anthony Liguori

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

[-- Attachment #2: consoled.diff --]
[-- Type: text/x-patch, Size: 25541 bytes --]

diff -r 48aed1403fe3 tools/Makefile
--- a/tools/Makefile	Fri Jul 22 16:44:33 2005
+++ b/tools/Makefile	Mon Jul 25 22:54:28 2005
@@ -13,6 +13,7 @@
 SUBDIRS += pygrub
 SUBDIRS += firmware
 SUBDIRS += policy
+SUBDIRS += consoled
 
 .PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
 
diff -r 48aed1403fe3 tools/Rules.mk
--- a/tools/Rules.mk	Fri Jul 22 16:44:33 2005
+++ b/tools/Rules.mk	Mon Jul 25 22:54:28 2005
@@ -4,6 +4,8 @@
 
 XEN_XC             = $(XEN_ROOT)/tools/python/xen/lowlevel/xc
 XEN_LIBXC          = $(XEN_ROOT)/tools/libxc
+XEN_XCS            = $(XEN_ROOT)/tools/xcs
+XEN_XENSTORE       = $(XEN_ROOT)/tools/xenstore
 
 ifeq ($(XEN_TARGET_ARCH),x86_32)
 CFLAGS  += -m32 -march=i686
diff -r 48aed1403fe3 tools/consoled/Makefile
--- /dev/null	Fri Jul 22 16:44:33 2005
+++ b/tools/consoled/Makefile	Mon Jul 25 22:54:28 2005
@@ -0,0 +1,48 @@
+# Makefile for consoled
+# based on xcs Makefile
+# Anthony Liguori 2005
+
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CONSOLED_INSTALL_DIR = /usr/sbin
+XC_CONSOLE_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)
+
+SRCS    :=
+SRCS    += main.c utils.c io.c
+
+HDRS     = $(wildcard *.h)
+OBJS     = $(patsubst %.c,%.o,$(SRCS))
+BIN      = consoled
+
+all: $(BIN) xc_console
+
+clean:
+	$(RM) *.a *.so *.o *.rpm $(BIN) xc_console
+
+$(BIN): $(OBJS)
+	$(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
+              -lxc -lxenstore
+
+xc_console: xc_console.o
+	$(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
+	      -lxc -lxenstore
+
+$(OBJS): $(HDRS)
+
+install: $(BIN)
+	$(INSTALL_DIR) -p $(DESTDIR)/$(CONSOLED_INSTALL_DIR)
+	$(INSTALL_PROG) $(BIN) $(DESTDIR)/$(CONSOLED_INSTALL_DIR)
+	$(INSTALL_DIR) -p $(DESTDIR)/$(XC_CONSOLE_INSTALL_DIR)
+	$(INSTALL_PROG) xc_console $(DESTDIR)/$(XC_CONSOLE_INSTALL_DIR)
diff -r 48aed1403fe3 tools/consoled/io.c
--- /dev/null	Fri Jul 22 16:44:33 2005
+++ b/tools/consoled/io.c	Mon Jul 25 22:54:28 2005
@@ -0,0 +1,328 @@
+/*\
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  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;
+};
+
+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;
+	}
+}
+
+bool buffer_empty(struct buffer *buffer)
+{
+	return buffer->size == 0;
+}
+
+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;
+
+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;
+}
+
+int domain_create_tty(int domid)
+{
+	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", domid);
+		master = -1;
+	} else {
+		const char *slave = ptsname(master);
+		struct termios term;
+
+		if (tcgetattr(master, &term) != -1) {
+			cfmakeraw(&term);
+			tcsetattr(master, TCSAFLUSH, &term);
+		}
+
+		xs_mkdir(xs, "/console");
+		snprintf(path, sizeof(path), "/console/%d", domid);
+		xs_mkdir(xs, path);
+		strcat(path, "/tty");
+
+		xs_write(xs, path, slave, strlen(slave), O_CREAT);
+	}
+
+	return master;
+}
+
+struct domain *create_domain(int domid)
+{
+	struct domain *dom;
+	char *data;
+	unsigned int len;
+	char path[1024];
+
+	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(domid);
+	dom->buffer.data = 0;
+	dom->buffer.size = 0;
+	dom->buffer.capacity = 0;
+	dom->buffer.max_capacity = 0;
+
+	snprintf(path, sizeof(path), "/console/%d/limit", domid);
+	data = xs_read(xs, path, &len);
+	if (data) {
+		dom->buffer.max_capacity = strtoul(data, 0, 0);
+		free(data);
+	}
+
+	dolog(LOG_DEBUG, "New domain %d", domid);
+
+	return dom;
+}
+
+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;
+}
+
+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;
+			free(d);
+			break;
+		}
+	}
+}
+
+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->domid);
+		} 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);
+	}
+}
+
+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->domid);
+		} else {
+			remove_domain(dom);
+		}
+	} else {
+		buffer_advance(&dom->buffer, len);
+	}
+}
+
+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;
+
+	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);
+		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 48aed1403fe3 tools/consoled/io.h
--- /dev/null	Fri Jul 22 16:44:33 2005
+++ b/tools/consoled/io.h	Mon Jul 25 22:54:28 2005
@@ -0,0 +1,26 @@
+/*\
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  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 48aed1403fe3 tools/consoled/main.c
--- /dev/null	Fri Jul 22 16:44:33 2005
+++ b/tools/consoled/main.c	Mon Jul 25 22:54:28 2005
@@ -0,0 +1,93 @@
+/*\
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  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("consoled", syslog_option, LOG_DAEMON);
+	setlogmask(syslog_mask);
+
+	if (!is_interactive) {
+		daemonize("/var/run/consoled.pid");
+	}
+
+	xen_setup();
+
+	handle_io();
+
+	closelog();
+
+	return 0;
+}
diff -r 48aed1403fe3 tools/consoled/utils.c
--- /dev/null	Fri Jul 22 16:44:33 2005
+++ b/tools/consoled/utils.c	Mon Jul 25 22:54:28 2005
@@ -0,0 +1,251 @@
+/*\
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  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 48aed1403fe3 tools/consoled/utils.h
--- /dev/null	Fri Jul 22 16:44:33 2005
+++ b/tools/consoled/utils.h	Mon Jul 25 22:54:28 2005
@@ -0,0 +1,47 @@
+/*\
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  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 48aed1403fe3 tools/consoled/xc_console.c
--- /dev/null	Fri Jul 22 16:44:33 2005
+++ b/tools/consoled/xc_console.c	Mon Jul 25 22:54:28 2005
@@ -0,0 +1,236 @@
+/*\
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  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) {
+		perror("tcgetattr() failed");
+		return;
+	}
+
+	new_term = *old;
+	cfmakeraw(&new_term);
+
+	if (tcsetattr(fd, TCSAFLUSH, &new_term) == -1) {
+		perror("tcsetattr() failed");
+	}
+}
+
+static void restore_term(int fd, struct termios *old)
+{
+	if (tcsetattr(fd, TCSAFLUSH, old) == -1) {
+		perror("tcsetattr() failed");
+	}
+}
+
+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;
+			}
+			perror("select() failed");
+			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;
+				}
+				perror("select() failed");
+				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;
+				}
+				perror("select() failed");
+				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;
+ }

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2005-08-03 12:41 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-02 17:45 [PATCH] Console Daemon Ian Pratt
2005-08-02 17:49 ` Anthony Liguori
2005-08-02 18:06   ` Christian Limpach
2005-08-02 18:58     ` Anthony Liguori
2005-08-03  2:21       ` Rusty Russell
2005-08-02 17:55 ` Christian Limpach
  -- strict thread matches above, loose matches on Subject: below --
2005-08-03 11:13 Ian Pratt
2005-08-03 12:41 ` Keir Fraser
2005-08-03  9:32 Ian Pratt
2005-08-03 10:58 ` Rusty Russell
2005-08-03 11:08   ` Keir Fraser
2005-08-02 15:59 Ian Pratt
2005-08-02 16:30 ` Anthony Liguori
2005-08-03  2:11   ` Rusty Russell
2005-08-02 14:45 Ian Pratt
2005-08-02 15:05 ` Anthony Liguori
2005-07-26  4:09 Anthony Liguori
2005-07-26  9:29 ` aq
2005-07-26 13:56   ` Anthony Liguori
2005-08-02 12:25 ` Keir Fraser
2005-08-02 15:06   ` Anthony Liguori
2005-08-02 12:26 ` Keir Fraser

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.