[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-tools] [PATCH] xenrconsoled



We found it convenient to use the TCP console port that was available in Xen 2.0 on our platform. When it went away in 3.0 we created a xenrconsoled daemon that restored the functionality, its usage is as follows:

usage: xenrconsoled: [OPTION]
        -h --help            print this message
        -d --debug           print debug messages
        -f --foreground      run as a foreground process, i.e. not as a daemon
        -s --status          report whether or not daemon is running
        -l --list            list available domids / console ports
        -o --open            <domid> open a socket for a domain's console
        -x --console-port    <port #> use this port domain's for console socket
        -c --close           <domid> close this domain's console socket
        -t --stop            terminate daemon
        -i --ip-address      <ip addr> only listen on this ip address
        -p --port            <port #> listen on this port

EXAMPLES:

        Start daemon on all interfaces, port (default 9600):
        # xenrconsoled

        Start daemon, on lo interface, port 9700:
        # xenrconsoled -i 127.0.0.1 -p 9700

        Print status of daemon:
        # xenrconsoled --status

        Open a socket for domain 2's console on port 9602:
        # xenrconsoled -o 2 -x 9602

        Close socket for domain 2:
        # xenrconsoled -c 2

        List which domains / consoles are available:
        # xenrconsoled -l

We attempted to make it fairly general, but it is geared towards our needs, but hopefully others will find it useful.

Any comments / concerns / suggestions welcome,

Pat

--
Patrick O'Rourke
porourke@xxxxxxxxxxx
diff -u --new-file --recursive xen-unstable-clean/tools/console/Makefile 
xen-unstable-patched/tools/console/Makefile
--- xen-unstable-clean/tools/console/Makefile   2005-08-25 23:57:08.000000000 
-0400
+++ xen-unstable-patched/tools/console/Makefile 2005-08-26 10:33:36.000000000 
-0400
@@ -16,13 +16,13 @@
 CFLAGS  += -I $(XEN_LIBXC)
 CFLAGS  += -I $(XEN_XENSTORE)
 
-BIN      = xenconsoled xenconsole
+BIN      = xenconsoled xenconsole xenrconsoled
 
 all: $(BIN)
 
 clean:
        $(RM) *.a *.so *.o *.rpm $(BIN)
-       $(RM) client/*.o daemon/*.o
+       $(RM) client/*.o daemon/*.o remote/*.o
 
 xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
        $(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
@@ -32,8 +32,13 @@
        $(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
              -lxenctrl -lxenstore
 
+xenrconsoled: $(patsubst %.c,%.o,$(wildcard remote/*.c))
+       $(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
+               -lxenctrl -lxenstore
+
 install: $(BIN)
        $(INSTALL_DIR) -p $(DESTDIR)/$(DAEMON_INSTALL_DIR)
        $(INSTALL_PROG) xenconsoled $(DESTDIR)/$(DAEMON_INSTALL_DIR)
+       $(INSTALL_PROG) xenrconsoled $(DESTDIR)/$(DAEMON_INSTALL_DIR)
        $(INSTALL_DIR) -p $(DESTDIR)/$(CLIENT_INSTALL_DIR)
        $(INSTALL_PROG) xenconsole $(DESTDIR)/$(CLIENT_INSTALL_DIR)
diff -u --new-file --recursive 
xen-unstable-clean/tools/console/remote/network.c 
xen-unstable-patched/tools/console/remote/network.c
--- xen-unstable-clean/tools/console/remote/network.c   1969-12-31 
19:00:00.000000000 -0500
+++ xen-unstable-patched/tools/console/remote/network.c 2005-08-26 
12:36:49.000000000 -0400
@@ -0,0 +1,259 @@
+/*\
+ *  Copyright (C) Egenera, Inc. 2005
+ *  Author(s): Patrick O'Rourke <porourke@xxxxxxxxxxx>
+ *
+ *  Xen Remote 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
+ *
+ * network utility functions...
+ *
+\*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include "utils.h"
+
+/* private functions...*/
+static int get_inet_ssocket(void);
+static int get_host_ip(const char *, struct in_addr *);
+static struct addrinfo *get_sockaddr(char *);
+
+/*
+ * Create an inet stream socket and bind it to specified port...
+ * returns new socket descriptor on success, -1 on error.
+ */
+ int
+inet_stream(const char *ipaddr, const short port)
+{
+       struct sockaddr_in      saddr;
+       int                     sfd;
+  
+       if ((sfd = get_inet_ssocket()) < 0) {
+               return (sfd);
+       }
+
+       if (ipaddr != NULL) {
+               /* fill in our IP address ... */
+               if (get_host_ip(ipaddr, &saddr.sin_addr) != 0) {
+                       printLog("inet_stream: unable to obtain our IP 
address");
+                       close(sfd);
+                       sfd = -1;
+               }
+       } else {
+               saddr.sin_addr.s_addr = htonl(INADDR_ANY);
+       }
+
+       if (sfd != -1) {
+               saddr.sin_family = AF_INET;
+               saddr.sin_port = htons(port);
+
+               /* bind socket to port... */
+               if (bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr))) {
+                       printLog("inet_stream() - bind(2) failed: %s",
+                                getErrnoMsg());
+                       close(sfd);
+                       sfd = -1;
+               } else if (listen(sfd, 5)) {
+                       printLog("inet_stream() - listend(2) failed: %s",
+                                getErrnoMsg());
+                       close(sfd);
+                       sfd = -1;
+               }
+       }
+       return (sfd);
+}
+
+
+/*
+ * Wait for a client to connect on socket 'sfd', put new socket
+ * from accept(2) into *nsfd.
+ *
+ * Returns 0 for success, 1 for interrupted, 2 for error
+ */
+ int
+inet_connection(int sfd, int *nsfd)
+{
+       struct sockaddr_in      client;
+       socklen_t               addrlen;
+       int                     fd;
+       int                       rc = 0;
+
+       addrlen = sizeof(client);
+       fd = accept(sfd, (struct sockaddr *)&client, &addrlen);
+       if (fd < 0) {
+               rc = 1;
+               if (errno != EAGAIN && errno != EINTR) {
+                       rc = 2;
+                       printLog("inet_connection() - accept(2) failed: %s",
+                                getErrnoMsg());
+               }
+       } else {
+               *nsfd = fd;
+       }
+       return (rc);
+}
+
+/*
+ * establish a connection to specified host on specified port.
+ * store newly allocated socket at *sk.
+ *
+ * return connected for success, -1 on error
+ */
+  int
+est_connection(char *server, const short server_port, const int options)
+{
+       struct addrinfo *ai;
+       struct sockaddr_in *saddr;
+       int flags;
+       int sock;
+
+       sock = socket(PF_INET, SOCK_STREAM, 0);
+       if (sock == -1) {
+               printLog("est_connection(): socket failed: %s",
+                        getErrnoMsg());                
+               return sock;
+       }
+
+       ai = get_sockaddr(server);
+       if (ai == NULL) {
+               printLog("est_connection(): get_sockaddr failed: %s",
+                        getErrnoMsg());
+               close(sock);
+               return -1;
+       }
+
+       saddr = (struct sockaddr_in *) ai->ai_addr;
+       saddr->sin_port = htons(server_port);
+       if (connect(sock, (struct sockaddr *)saddr,  sizeof(*saddr))) {
+               printLog("est_connection(): connect error: %s",
+                        getErrnoMsg());
+               close(sock);
+               return -1;
+       } 
+
+       // connect worked, set options...
+       if (options != 0) {
+               int error = 1;          // assume error
+               flags = fcntl(sock, F_GETFL, 0);                
+               if (flags >= 0) {
+                       flags |= options;
+                       if (fcntl(sock, F_SETFL, flags) < 0) {
+                               printLog("est_connection() fcntl: %s",
+                                        getErrnoMsg());
+                       } else {
+                               error = 0;
+                       }
+               }
+               if (error) {
+                       printLog("est_connection: could set options: %s",
+                                getErrnoMsg());
+                       close(sock);
+                       return -1;
+               }
+       }
+
+       return sock;
+}
+
+/*
+ */
+ int
+send_data(int s, char *b, ssize_t size)
+{
+       int rc = 0;
+       if (write(s, b, size) != size) {
+               rc = errno;
+               printLog("send_data() of %d bytes failed on socket %d: %s",
+                        size, s, getErrnoMsg());
+       }
+       return rc;
+}
+
+ int
+read_data(int s, char *b, int nbytes)
+{
+       int nleft;
+       int nread;
+
+       nleft = nbytes;
+       while (nleft > 0) {
+               nread = read(s, b, nleft);
+               printDebug("read_data: read %d bytes from %d", nread, s);
+               if (nread < 0) {
+                       printLog("read_data(): %s", getErrnoMsg());
+                       return (nread);
+               } else if (nread == 0) {
+                       break;
+               }
+               nleft -= nread;
+               b += nread;
+       }
+       return (nbytes - nleft);
+}
+
+/*
+ * get an inet stream socket
+ */
+ static int
+get_inet_ssocket(void)
+{
+       int     sfd;
+       if ((sfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+               printLog("get_inet_ssocket(): %s", getErrnoMsg());
+       }
+       return sfd;
+}
+
+/*
+ * Get ip address of specified host...
+ *
+ * 0 = success
+ * 1 = failure
+ */
+ static int
+get_host_ip(const char *hostname, struct in_addr *in)
+{
+       struct hostent  *host;
+       int             rc = 0;
+
+       host = gethostbyname(hostname);
+       if (host == NULL) {
+               printLog("gethostbyname (%d - %s)",
+                        h_errno, hstrerror(h_errno));
+               rc = h_errno;
+       } else {
+               *in = *((struct in_addr *)host->h_addr_list[0]);
+       }
+       return rc;
+}
+
+ static struct addrinfo *
+get_sockaddr(char *h)
+{
+       struct addrinfo *res;
+       if (getaddrinfo(h, NULL, NULL, &res)) {
+               printLog("get_sockaddr() getaddrinfo failed: %s",
+                        getErrnoMsg());
+               res = NULL;
+       }
+       return res;
+}
diff -u --new-file --recursive 
xen-unstable-clean/tools/console/remote/network.h 
xen-unstable-patched/tools/console/remote/network.h
--- xen-unstable-clean/tools/console/remote/network.h   1969-12-31 
19:00:00.000000000 -0500
+++ xen-unstable-patched/tools/console/remote/network.h 2005-08-26 
12:36:49.000000000 -0400
@@ -0,0 +1,30 @@
+/*\
+ *  Copyright (C) Egenera, Inc. 2005
+ *  Author(s): Patrick O'Rourke <porourke@xxxxxxxxxxx>
+ *
+ *  Xen Remote 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 _NETWORK_H_ 
+#define  NETWORK 1
+
+int inet_stream(const char *, const short);
+int inet_connection(int, int *);
+int est_connection(char *, const short, const int);
+int send_data(int, char *, ssize_t);
+int read_data(int , char *, int);
+
+#endif /* _NETWORK_H_ */
+
diff -u --new-file --recursive 
xen-unstable-clean/tools/console/remote/rconsoled.c 
xen-unstable-patched/tools/console/remote/rconsoled.c
--- xen-unstable-clean/tools/console/remote/rconsoled.c 1969-12-31 
19:00:00.000000000 -0500
+++ xen-unstable-patched/tools/console/remote/rconsoled.c       2005-08-26 
12:36:49.000000000 -0400
@@ -0,0 +1,1053 @@
+/*\
+ *  Copyright (C) Egenera, Inc. 2005
+ *  Author(s): Patrick O'Rourke <porourke@xxxxxxxxxxx>
+ *
+ *  Xen Remote 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 <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+
+// local headers...
+#include "utils.h"
+#include "network.h"
+#include "xs.h"
+
+#define CONSOLE_PORT   9600
+#define CMD_SIZE       80
+#define        OPTIONS         "dhfstlc:i:p:o:x:"
+#define PIDFILE                "/var/run/xenrconsoled.pid"
+#define ESCAPE_CHARACTER 0x1d
+
+// accepted command strings
+#define SHUTDOWN_STR   "terminate"
+#define NEW_STR                "new"
+#define STOP_STR       "stop"
+#define LIST_STR       "list"
+
+typedef struct server {
+       struct server *s_next;
+       pid_t s_pid;
+       int s_domid;
+       int s_port;
+       int s_terminating;
+} server_t;
+
+typedef enum cmd {
+       CMD_UNKNOWN,            /* catch all for bad input */
+       CMD_NEW,                /* make a new server */
+       CMD_STOP,               /* stop an existing one */
+       CMD_SHUTDOWN,           /* shutdown the daemon */
+       CMD_LIST                /* return a list of running domids, ports*/
+} cmd_t;
+
+
+// global state
+char *progname;
+server_t *all_servers = NULL;
+static volatile sig_atomic_t child_exited = 0;
+
+static struct option loptions[] = {
+       { "help",       0, NULL, 'h' },
+       { "debug",      0, NULL, 'd' },
+       { "foreground", 0, NULL, 'f' },
+       { "status",     0, NULL, 's' },
+       { "list",       0, NULL, 'l' },
+       { "open",       1, NULL, 'o' },
+       { "console-port", 1,NULL, 'x' },
+       { "close",      1, NULL, 'c' },
+       { "stop",       0, NULL, 't' },
+       { "ip-address", 1, NULL, 'i' },
+       { "port",       1, NULL, 'p' },
+       { NULL,         0, NULL, 0}
+};
+
+// short descriptions for options, note we rely on the order of
+// options being the same as the help...
+static char *opt_help[] = {
+       "print this message",
+       "print debug messages",
+       "run as a foreground process, i.e. not as a daemon",
+       "report whether or not daemon is running",
+       "list available domids / console ports",
+       "<domid> open a socket for a domain's console",
+       "<port #> use this port domain's for console socket",
+       "<domid> close this domain's console socket",
+       "terminate daemon",
+       "<ip addr> only listen on this ip address",
+       "<port #> listen on this port",
+       NULL
+};
+
+// prototypes...
+static void    usage(int);
+static int     get_console_device(int);
+static int     get_status(void);
+static cmd_t   parse_command(int, int *, int *);
+static void    terminate(void);
+static void    start_server(char *, int, int);
+static void    stop_server(int);
+static void    list_servers(int);
+static void    console_loop(int, int);
+static server_t *alloc_new_server(int, int);
+static void    console_loop(int, int);
+static void    free_server(int);
+static void    signal_init(void);
+static void    handle_sigchild(int);
+static void    reap_children(void);
+static pid_t   reap_child(pid_t);
+static int     print_servers(char *, int);
+static int     stop_daemon(void);
+static int     open_console(char *, int, int, int);
+static int     close_console(char *, int, int);
+static server_t *lookup_server_by_pid(pid_t);
+static server_t *lookup_server_by_domain(int);
+
+ int
+main(int argc, char **argv)
+{
+       int     listenfd;
+       int     dead = 0;
+       int     errors = 0;
+       int     is_debug = 0;
+       int     is_status = 0;
+       int     do_fork = 1;
+       int     is_list = 0;
+       int     is_stop = 0;
+       int     is_open = 0;
+       int     is_close = 0;
+       char    *ipaddr = NULL;
+       int     server_port = CONSOLE_PORT;
+       int     console_port = -1;
+       int     domain = -1;
+       pid_t   pid;
+
+       progname = basename(argv[0]);
+
+       while (!errors) {
+               int c;
+               int optindex = 0;
+
+               c = getopt_long(argc, argv, OPTIONS, loptions, &optindex);
+               if (c == -1) {
+                       /* all done */
+                       break;
+               }
+               switch (c) {
+               case 'c':
+                       is_close = 1;
+                       domain = atoi(optarg);
+                       if (domain <= 0) {
+                               domain = -1;
+                       }
+                       break;
+               case 'd':
+                       is_debug = 1;
+                       break;
+               case 'i':
+                       ipaddr = optarg;
+                       break;
+               case 'f':
+                       do_fork = 0;
+                       break;
+               case 'h':
+                       usage(1);
+                       return 0;
+                       /* NOTREACHED */
+               case 'l':
+                       is_list = 1;
+                       break;
+               case 'o':
+                       is_open = 1;
+                       domain = atoi(optarg);
+                       if (domain <= 0) {
+                               errors++;
+                               domain = -1;
+                       }
+                       break;
+               case 'p':
+                       server_port = atoi(optarg);
+                       if (server_port <= 0) {
+                               server_port = -1;
+                       }
+                       break;
+               case 's':
+                       is_status = 1;
+                       break;
+               case 't':
+                       is_stop = 1;
+                       break;
+               case 'x':
+                       console_port = atoi(optarg);
+                       if (console_port <= 0) {
+                               console_port = -1;
+                       }
+                       break;
+               case ':':
+               case '?':
+                       errors++;
+                       break;
+               default:
+                       printLog("%s: getopt error", progname);
+                       errors = 1;
+                       break;
+               } /* switch */
+       } /* !errors */
+
+       if (errors) {
+               usage(0);
+               return 1;
+       }
+
+       if (is_debug) {
+               debug_enable();
+       }
+
+       // First handle any client requests...
+       if (is_status) {
+               return get_status();
+       }
+
+       if (is_list) {
+               return print_servers(ipaddr, server_port);
+       }
+
+       if (is_stop) {
+               return stop_daemon();           
+       }
+
+       if (is_open) {
+               char *msg = NULL;
+               if (domain == -1) {
+                       msg = "no domain specified";
+               } else if (console_port == -1) {
+                       msg = "no port for domain's console";
+               } else if (server_port == -1) {
+                       msg = "invalid server port";
+               }
+               if (msg != NULL) {
+                       printLog("%s", msg);
+                       usage(0);
+                       return 1;
+               }
+               return open_console(ipaddr, server_port, domain, console_port);
+       }
+
+       if (is_close) {
+               char *msg = NULL;
+               if (domain == -1) {
+                       msg = "no domain specified";
+               } else if (server_port == -1) {
+                       msg = "invalid server port";
+               }
+               if (msg != NULL) {
+                       printLog("%s", msg);
+                       usage(0);
+                       return 1;
+               }
+               return close_console(ipaddr, server_port, domain);
+       }
+
+       // okay, run as a daemon...
+       if ((pid = daemon_alive(PIDFILE)) > 0) {
+               printLog("found instance already running (pid %d)", pid);
+               return 1;
+       }
+
+       setupUtils(progname, HANDLE_TERM_SIGNALS);
+       signal_init();
+
+       if (do_fork) {
+               daemonize(PIDFILE);
+       } else {
+               make_pidfile(PIDFILE);
+       }
+
+       if (ipaddr == NULL) {
+               printLog("(pid %d) running on port %d...", getpid(),
+                        server_port);
+       } else {
+               printLog("(pid %d) running on address: %s, port %d",
+                        getpid(), ipaddr, server_port);
+       }
+
+       if ((listenfd = inet_stream(ipaddr, server_port)) == -1) {
+               printLog("cannot create socket on port: %d", server_port);
+               return 2;
+       }
+
+       // TODO - vet that we are only being connected from specific host?
+       // TODO - throttle?
+       while (!dead && !gotTermSignal()) {
+               int clientfd;
+               int rc;
+               int domain_port;
+               cmd_t command;
+
+               // First deal with any children that may have exited...
+               if (child_exited) {
+                       reap_children();
+               }
+
+               rc = inet_connection(listenfd, &clientfd);
+               if (rc == 2) {
+                       printLog("connect attempt failed");
+                       continue;
+               } else if (rc == 1) {
+                       // interrupted...
+                       continue;
+               }
+    
+               command = parse_command(clientfd, &domain, &domain_port);
+               printDebug("got command: %d, domid == %d, port == %d",
+                          command, domain, domain_port);
+               if (command == CMD_SHUTDOWN) {
+                       dead = 1;
+               } else if (command == CMD_LIST) {
+                       list_servers(clientfd);
+               } else if (command == CMD_STOP) {
+                       stop_server(domain);                    
+               } else if (command == CMD_NEW) {
+                       server_t *s = alloc_new_server(domain, domain_port);
+                       if (s != NULL) {
+                               pid_t p = fork();
+                               if (p == 0) {
+                                       // child...
+                                       close(listenfd);
+                                       close(clientfd);
+                                       start_server(ipaddr,
+                                                    s->s_domid, s->s_port);
+                                       /* NOTREACHED */
+                               } else if (p < 0) {
+                                       printLog("cannot fork server: %s",
+                                                getErrnoMsg());
+                                       free_server(domain);
+                               } else {
+                                       printDebug("%d created child %d",
+                                                  getpid(), p);
+                                       s->s_pid = p;
+                               }
+                       } else {
+                               printLog("unable to handle new server");
+                       }
+               } else {
+                       printDebug("ignoring bogus command");
+               }
+               close(clientfd);
+
+       } /* while */
+
+       terminate();
+       close(listenfd);
+       printDebug("all done");
+       tearDownUtils();
+       return 0;
+}
+
+/**
+ * Print usage info to stderr...
+ */
+ static void 
+usage(int examples)
+{
+       int i;
+       
+       fprintf(stderr, "usage: %s: [OPTION]\n", progname);
+       for (i = 0; loptions[i].name != NULL; i++) {
+               fprintf(stderr, "\t-%c --%-15.15s %s\n",
+                       loptions[i].val, loptions[i].name, opt_help[i]);
+       }
+       fflush(stderr);
+
+       if (!examples) {
+               return;
+       }
+
+       fprintf(stderr, "\nEXAMPLES:\n\n");
+       fprintf(stderr, "\tStart daemon on all interfaces, port (default 
%d):\n",
+               CONSOLE_PORT);
+       fprintf(stderr, "\t# %s\n\n", progname);
+       fprintf(stderr, "\tStart daemon, on lo interface, port 9700:\n");
+       fprintf(stderr, "\t# %s -i 127.0.0.1 -p 9700\n\n", progname);
+       fprintf(stderr, "\tPrint status of daemon:\n");
+       fprintf(stderr, "\t# %s --status\n\n", progname);
+       fprintf(stderr, "\tOpen a socket for domain 2's console on port 
9602:\n");
+       fprintf(stderr, "\t# %s -o 2 -x 9602\n\n", progname);
+       fprintf(stderr, "\tClose socket for domain 2:\n");
+       fprintf(stderr, "\t# %s -c 2\n\n", progname);
+       fprintf(stderr, "\tList which domains / consoles are available:\n");
+       fprintf(stderr, "\t# %s -l\n\n", progname);
+       fflush(stderr);
+}
+
+ static void
+signal_init()
+{
+        struct sigaction sa;
+        bzero(&sa, sizeof(sa));
+        sigfillset(&sa.sa_mask);
+        sa.sa_handler = handle_sigchild;
+        if (sigaction(SIGCHLD, &sa, NULL) < 0) {
+                printLog("cannot establish SIGCHLD handler: %s",
+                         getErrnoMsg());
+                exit(1);
+        }
+        sa.sa_handler = SIG_IGN;
+        if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+                printLog("cannot ignore SIGPIPE: %s", getErrnoMsg());
+                exit(1);
+        }
+}
+
+ static void
+handle_sigchild(int sig)
+{
+        child_exited = 1;
+}
+
+ static void
+reap_children()
+{
+       pid_t p;
+       int reaped = 0;
+       printDebug("reaping children...");
+       do {
+               child_exited = 0;
+               p = reap_child(-1);
+               if (p > 0) {
+                       server_t *s = lookup_server_by_pid(p);
+                       if (s == NULL) {
+                               printLog("no server for pid %d?", p);
+                               continue;
+                       } else {
+                               free_server(s->s_domid);
+                       }
+                       reaped++;
+               } else {
+                       // It is possible for the wait to have already
+                       // occurred, if we were doing an explicit stop,
+                       // that could have caught the wait for another
+                       // process.
+                       printDebug("no children to wait for");
+               }
+       } while (child_exited || p > 0);
+       printDebug("reaped %d children", reaped);
+}
+
+/**
+ * After a connection is accepted, read what the user wants us
+ * to do and return the appropriate command type.  If the command
+ * has an arg, of which the only one specified is a port (to start
+ * listening on, or to stop listening on), pass that back in the
+ * 'port' parameter.
+ */
+ static cmd_t
+parse_command(int fd, int *domid, int *port)
+{
+       cmd_t command = CMD_UNKNOWN;
+       char  buffer[CMD_SIZE + 1];
+       int   p = -1;
+       int   d = -1;
+
+       *domid = -1; 
+       *port = -1;
+
+       int bytes = read(fd, buffer, CMD_SIZE);
+       if (bytes <= 0) {
+               printDebug("parse_command: no bytes read");
+               return command;
+       }
+
+       buffer[bytes] = '\0';
+       printDebug("parse_command - read <%s>", buffer);
+
+       if (strstr(buffer, SHUTDOWN_STR) != NULL) {
+               command = CMD_SHUTDOWN;
+               return command;
+       }
+
+       if (strstr(buffer, LIST_STR) != NULL) {
+               command = CMD_LIST;
+               return command;
+       }
+
+       // must be new or stop
+       if ((strstr(buffer, NEW_STR) != NULL) &&
+           (strlen(NEW_STR) < strlen(buffer)-1)) {
+               char *temp = buffer + strlen(NEW_STR);
+               int rc = sscanf(temp, "%d %d", &d, &p);
+               if (rc == 2) {
+                       command = CMD_NEW;
+                       *domid = d;
+                       *port = p;
+               }
+       } else if ((strstr(buffer, STOP_STR) != NULL) &&
+                  (strlen(STOP_STR) < strlen(buffer)-1)) {
+               char *temp = buffer + strlen(STOP_STR);
+               int rc = sscanf(temp, "%d", &d);
+               if (rc == 1) {
+                       command = CMD_STOP;
+                       *domid = d;
+               }
+       }
+   
+       // all done
+       return command;
+}
+
+ static void
+terminate()
+{
+       server_t *s;
+       printDebug("terminate: stopping all console servers");
+       while ((s = all_servers) != NULL) {
+               // will remove server from list when done....
+               stop_server(s->s_domid);
+       }
+}
+
+/***
+ */
+ static void 
+list_servers(int fd)
+{
+       server_t *s = all_servers;
+       char    buf[81];
+       char    *title_fmt = "%-8s %-8s %-8s\n";
+       char    *data_fmt = "%-8d %-8d %-8d\n";
+
+       printDebug("listing servers");
+
+       sprintf(buf, title_fmt, "domid", "port", "pid");
+       send_data(fd, buf, strlen(buf));
+       sprintf(buf, title_fmt, "-----", "----", "---");
+       send_data(fd, buf, strlen(buf));
+
+       while (s != NULL) {
+               sprintf(buf, data_fmt, s->s_domid, s->s_port, s->s_pid);
+               send_data(fd, buf, strlen(buf));
+               bzero(buf, sizeof(buf));
+               s = s->s_next;
+       }
+}
+
+/**
+ * Runs as a child process of the main daemon.  We just listen on
+ * the port specified, awaiting a console connection request.  We do
+ * not return from here.
+ *
+ * TODO - what happens if domain is shutdown / destroyed?
+ */
+ static void
+start_server(char *host, int domain, int port)
+{
+       int console_fd;
+       int listenfd;
+       int nconnections = 0;
+
+       printLog("console server (%d) listening for domain %d on port %d...",
+                getpid(), domain, port);
+
+       console_fd = get_console_device(domain);
+       // open tty device
+       if (console_fd == -1) {
+               printLog("cannot start console for domain %d on port %d",
+                        domain, port);
+               exit(1);
+       }
+       // create a socket...
+       listenfd = inet_stream(host, port);
+       if (listenfd == -1) {
+               printLog("unable to create socket for domain %d, port %d",
+                        domain, port);
+               exit(1);
+       }
+       while (!gotTermSignal()) {
+               int foo;
+               int rc = inet_connection(listenfd, &foo);
+               if (rc == 2) {
+                       break;
+               } else if (rc == 1) {
+                       continue;
+               }
+               printDebug("console server (%d) accepted connection %d",
+                          getpid(), ++nconnections);
+               console_loop(console_fd, foo);
+               printDebug("console server (%d) closing connection", getpid());
+               close(foo);
+       }
+       close(console_fd);
+       printLog("console server (%d) exiting: domain %d, port %d, conns %d",
+                getpid(), domain, port, nconnections);
+       exit(0);
+}
+
+ static void
+stop_server(int domid)
+{
+        server_t *s;
+        pid_t waited_pid;
+        pid_t pid_to_kill;
+        int waits = 0;
+
+        printLog("stop_server: domain %d...", domid);
+
+        s = lookup_server_by_domain(domid);
+        if (s == NULL) {
+                printDebug("stop_server: domain %d not found", domid);
+                return;
+        }
+        s->s_terminating = 1;
+        pid_to_kill = s->s_pid;
+
+        printDebug("stop_server: ending process: %d", pid_to_kill);
+
+        if (kill(pid_to_kill, SIGTERM) < 0) {
+                printLog("stop_server: cannot terminate pid %d: %s",
+                         pid_to_kill, getErrnoMsg());
+        }
+
+        // Give the child 5 seconds to exit...
+        do {
+                waits++;
+                waited_pid = reap_child(pid_to_kill);
+                if (waited_pid > 0) {
+                        s = lookup_server_by_pid(waited_pid);
+                        if (s == NULL) {
+                                printLog("stop_server: orphaned pid %d?",
+                                         waited_pid);
+                        } else {
+                                free_server(s->s_domid);
+                        }
+                } else {
+                        sleep(1);
+                }
+        } while (waits < 5 && waited_pid != pid_to_kill);
+
+        // did we get the pid we wanted?
+        if (waited_pid != pid_to_kill) {
+                printLog("stop_server: SIGKILL'ing pid %d for domain %d",
+                         pid_to_kill, domid);
+                if (kill(pid_to_kill, SIGKILL) < 0) {
+                        printLog("stop_server: cannot SIGKILL process %d",
+                                 pid_to_kill);
+                }
+                waits = 0;
+                do {
+                        waits++;
+                        waited_pid = reap_child(pid_to_kill);
+                        if (waited_pid > 0) {
+                                s = lookup_server_by_pid(waited_pid);
+                                if (s == NULL) {
+                                        printLog("stop_server: orphan pid: %d",
+                                                 waited_pid);
+                                } else {
+                                        free_server(s->s_domid);
+                                }
+                        }
+                } while (waits < 10 && waited_pid != pid_to_kill);
+
+                if (waited_pid != pid_to_kill) {
+                        printLog("stop_server: forced stop of %d, domain %d",
+                                 pid_to_kill, domid);
+                }
+        }
+}
+
+/**
+ * Find / open the tty device for the specified domain.  Returns the 
+ * file descriptor for the domain, -1 on error.
+ */
+ static int
+get_console_device(int domid)
+{
+       struct xs_handle *xs;
+       char tty_path[1024];
+       char *tty_device;
+       unsigned int length;
+       int tty_fd = -1;
+   
+       printDebug("get_console_device: connecting to XenStore");
+       if ((xs = xs_daemon_open()) == NULL) {
+               printLog("xs_daemon_open error: %s", getErrnoMsg());
+               return tty_fd;
+       }
+   
+       printDebug("get_console_device: reading tty from store...");
+       sprintf(tty_path, "/console/%d/tty", domid);
+   
+       tty_device = xs_read(xs, tty_path, &length);
+       if (tty_device == NULL) {
+               printLog("cannot get tty device: %s", getErrnoMsg());
+               xs_daemon_close(xs);
+               return tty_fd;
+       }
+   
+       printDebug("get_console_device: dom %d's tty == %s", domid, tty_device);
+
+       tty_fd = open(tty_device,  O_RDWR | O_NOCTTY);
+       if (tty_fd == -1) {
+               printLog("unable to open tty %s for domain %d: %s",
+                       tty_device, domid, getErrnoMsg());
+       }
+       xs_daemon_close(xs);
+       return tty_fd;
+}
+
+ static void
+console_loop(int console, int socket)
+{
+        int fds_open = 1;
+        do {
+                int ret;
+                fd_set fds;
+                int last_fd = (console > socket) ? console : socket;
+
+                FD_ZERO(&fds);
+                FD_SET(console, &fds);
+                FD_SET(socket, &fds);
+
+                ret = select(last_fd + 1, &fds, NULL, NULL, NULL);
+                if (ret == -1) {
+                        if (errno == EINTR || errno == EAGAIN) {
+                                continue;
+                        }
+                        printLog("console_loop: error %s", getErrnoMsg());
+                }
+
+                if (FD_ISSET(socket, &fds)) {
+                        ssize_t len;
+                        char msg[60];
+                        len = read(socket, msg, sizeof(msg));
+                        if (len == 0) {
+                                fds_open = 0;
+                        } else if (len > 0) {
+                                if (len == 1 && msg[0] == ESCAPE_CHARACTER) {
+                                        return;
+                                }
+                                send_data(console, msg, len);
+                        } else {
+                                fds_open = 0;
+                                printDebug("console_loop: socket read: %s",
+                                           getErrnoMsg());
+                        }
+                }
+
+                if (FD_ISSET(console, &fds)) {
+                        ssize_t len;
+                        char msg[512];
+                        len = read(console, msg, sizeof(msg));
+                        if (len == 0) {
+                                fds_open = 0;
+                        } else if (len > 0) {
+                                send_data(socket, msg, len);
+                        } else {
+                                fds_open = 0;
+                                printDebug("console_loop: console read: %s",
+                                           getErrnoMsg());
+                        }
+                }
+        } while (fds_open && !gotTermSignal());
+}
+
+/**
+ * Called upon receipt of a SIGCHLD, do a wait to see which ones
+ * have exited and clean up their state. Returns pid of child that
+ * exited.
+ */
+ static pid_t
+reap_child(pid_t expected_pid)
+{
+        int status;
+        pid_t child = waitpid(expected_pid, &status, WNOHANG);
+
+        if (child == 0) {
+                printDebug("reap_child: no child found to have exited?");
+                return child;
+        }
+
+        if (child < 0) {
+                printDebug("reap_child: wait error: %s", getErrnoMsg());
+                return child;
+        }
+
+        if (isDebug()) {
+                if (WIFEXITED(status)) {
+                        int exit_code = WEXITSTATUS(status);
+                        printDebug("reap_child: pid %d exited with %d",
+                                   child, exit_code);
+                } else if (WIFSIGNALED(status)) {
+                        int exit_signal = WTERMSIG(status);
+                        printDebug("reap_child: pid %d exited from signal %d",
+                                   child, exit_signal);
+                } else {
+                        printDebug("reap_child: child %d bad exit status %d?",
+                                   child, status);
+                }
+        }
+        return child;
+}
+
+ static server_t *
+alloc_new_server(int domain, int port)
+{
+        server_t *s = all_servers;
+
+        // first verify that we do not have a server for this port/domain
+         while (s != NULL) {
+                 if (s->s_domid == domain || s->s_port == port) {
+                         break;
+                 }
+                 s = s->s_next;
+         }
+
+        if (s == NULL) {
+                s = malloc(sizeof(*s));
+                if (s != NULL) {
+                        bzero(s, sizeof(s));
+                        s->s_domid = domain;
+                        s->s_port = port;
+                        s->s_next = all_servers;
+                        all_servers = s;
+                        printDebug("alloc_new_server: %lx: id: %d, port: %d",
+                                   s, s->s_domid, s->s_port);
+                } else {
+                        printLog("alloc_new_server: malloc %s",
+                                 getErrnoMsg());
+                }
+        } else {
+                // complain about why we failed...
+                char *func = "alloc_new_server";
+                char *msg = "already exists for";
+                if (s->s_domid == domain) {
+                        printLog("%s: server (%d) %s domain %d",
+                                 func, s->s_pid, msg, domain);
+                } else {
+                        printLog("%s: server (%d) %s port %d",
+                                 func, s->s_pid, msg, port);
+                }
+                s = NULL;
+        }
+
+        return s;
+}
+
+ static void
+free_server(int domid)
+{
+       int found = 0;
+       server_t *temp = all_servers;
+       server_t **prev = &all_servers;
+
+       while (temp != NULL && !found) {
+               if (temp->s_domid == domid) {
+                       found = 1;
+                       *prev = temp->s_next;
+                       printDebug("freeing server: domain %d, port %d",
+                                  temp->s_domid, temp->s_port);
+                       free(temp);
+                       continue;
+               }
+               prev = &temp->s_next;
+               temp = temp->s_next;
+       }
+}
+
+ static server_t *
+lookup_server_by_pid(pid_t p)
+{
+        server_t *ans = NULL;
+        server_t *temp = all_servers;
+        while (temp != NULL) {
+                if (temp->s_pid == p) {
+                        ans = temp;
+                        break;
+                }
+                temp = temp->s_next;
+        }
+        return ans;
+}
+
+ static server_t *
+lookup_server_by_domain(int domid)
+{
+        server_t *ans = NULL;
+        server_t *temp = all_servers;
+        while (temp != NULL) {
+                if (temp->s_domid == domid) {
+                        ans = temp;
+                        break;
+                }
+                temp = temp->s_next;
+        }
+        return ans;
+}
+
+ static int
+get_status()
+{
+       pid_t pid = daemon_alive(PIDFILE);
+       int status;
+
+       if (pid < 0) {
+               fprintf(stdout, "%s: unable to determine daemon status\n",
+                       progname);
+               status = 1;
+       } else if (pid == 0) {
+               fprintf(stdout, "%s not running\n", progname);
+               status = 2;
+       } else {
+               fprintf(stdout, "%s, pid %d, is running\n", progname, pid);
+               status = 0;
+       }
+
+       fflush(stdout);
+       return status;
+}
+
+ static int
+print_servers(char *host, int port)
+{
+       int rc = 1;
+       int sock;
+
+       printDebug("print servers");
+
+       if (host == NULL) {
+               host = "localhost";
+       }
+       sock = est_connection(host, port, 0);
+       if (sock >= 0) {
+               char buf[81];
+               int  nread;
+               // tell daemon we want a list of active console ports
+               if (send_data(sock, LIST_STR, strlen(LIST_STR)) == 0) {
+                       do {
+                               if ((nread = read(sock, buf, 80)) > 0) {
+                                       buf[nread] = '\0';
+                                       fprintf(stdout, "%s", buf);
+                               } else if (nread < 0) { 
+                                       printDebug(" read: %s", getErrnoMsg());
+                               }
+                       } while (nread > 0);
+                       rc = 0;
+               } else {
+                       printLog("cannot talk to daemon");
+               }
+               close(sock);
+       } else {
+               printLog("could not connect to %s, port %d", host, port);
+       }
+       return rc;
+}
+
+ static int
+stop_daemon()
+{
+       int rc = 1;
+       pid_t pid;
+
+       printDebug("stopping daemon...");
+       pid = daemon_alive(PIDFILE);
+       if (pid > 0) {
+               printDebug("killing %d...", pid);
+               if (kill(pid, SIGTERM) < 0) {
+                       fprintf(stderr, "cannot kill %d: %s\n",
+                               pid, getErrnoMsg());
+               } else {
+                       sleep(1);
+                       if (kill(pid, 0) == 0) {
+                               fprintf(stderr, "could not kill %d\n", pid);
+                       } else if (errno == ESRCH) {
+                               fprintf(stdout, "stopped daemon process %d\n",
+                                       pid);
+                               rc = 0;
+                       } else {
+                               fprintf(stderr,
+                                       "could not verify daemon stopped: %s",
+                                       getErrnoMsg());
+                       }
+               }
+       } else {
+               fprintf(stderr, "%s: daemon not running\n", progname);
+       }
+
+       return rc;
+}
+
+ static int
+open_console(char *ip, int sp, int domid, int cp)
+{
+       int rc = 1;
+       int sock;
+
+       if (ip == NULL) {
+               ip = "localhost";
+       }
+
+       printDebug("open_console (%s.%d): domain = %d, port = %d",
+                  ip, sp, domid, cp);
+
+       sock = est_connection(ip, sp, 0);
+       if (sock >= 0) {
+               char buf[81];
+               sprintf(buf,"%s %d %d", NEW_STR, domid, cp);
+               if (send_data(sock, buf, strlen(buf)) == 0) {
+                       rc = 0;
+               } else {
+                       printLog("cannot talk to daemon");
+               }
+       } else {
+               printLog("could not connect to: %s, port %d", ip, sp);
+       }
+       return rc;
+}
+
+ static int
+close_console(char *ip, int sp, int domid)
+{
+       int rc = 1;
+       int sock;
+
+       if (ip == NULL) {
+               ip = "localhost";
+       }
+
+       printDebug("close_console (%s.%d): domain = %d", ip, sp, domid);
+
+       sock = est_connection(ip, sp, 0);
+       if (sock >= 0) {
+               char buf[81];
+               sprintf(buf,"%s %d", STOP_STR, domid);
+               if (send_data(sock, buf, strlen(buf)) == 0) {
+                       rc = 0;
+               } else {
+                       printLog("cannot talk to daemon");
+               }
+       } else {
+               printLog("could not connect to: %s, port %d", ip, sp);
+       }
+       return rc;
+}
diff -u --new-file --recursive xen-unstable-clean/tools/console/remote/utils.c 
xen-unstable-patched/tools/console/remote/utils.c
--- xen-unstable-clean/tools/console/remote/utils.c     1969-12-31 
19:00:00.000000000 -0500
+++ xen-unstable-patched/tools/console/remote/utils.c   2005-08-26 
12:36:49.000000000 -0400
@@ -0,0 +1,335 @@
+/*\
+ *  Copyright (C) Egenera, Inc. 2005
+ *  Author(s): Patrick O'Rourke <porourke@xxxxxxxxxxx>
+ *
+ *  Xen Remote 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/resource.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+static void printDate(void);
+static void setupTermSignals(void);
+static void handler(int);
+
+static char* service_name = NULL;
+static int debug = 0;
+static int logging_enabled = 0;
+static volatile sig_atomic_t term_signal = 0;
+
+#define        ROOT_DIR        "/"
+
+ void
+setupUtils(char *svc, int do_signals)
+{
+       service_name = svc;
+       if (do_signals) {
+               setupTermSignals();
+       }
+}
+
+ void
+tearDownUtils()
+{
+       printLog("shutting down...");
+       closelog();
+}
+
+ int
+gotTermSignal()
+{
+       return term_signal;
+}
+
+ void
+setupTermSignals()
+{
+       struct sigaction sa;
+       bzero(&sa, sizeof(sa));
+       sigfillset(&sa.sa_mask);
+       sa.sa_handler = handler;
+       sigaction(SIGTERM, &sa, NULL);
+       sigaction(SIGQUIT, &sa, NULL);
+       sigaction(SIGINT, &sa, NULL);
+}
+
+ void
+handler(int sig)
+{
+       switch (sig) {
+       case SIGINT:
+       case SIGTERM:
+       case SIGQUIT:
+               term_signal = 1;
+               break;
+       }
+}
+
+ void
+debug_enable()
+{
+       debug = 1;
+}
+
+ void
+debug_disable()
+{
+       debug = 0;
+}
+
+ int
+isDebug()
+{
+       return debug;
+}
+
+/**
+ * Make calling process a daemon process, assumes logging has
+ * already been configurd.  Either succeeds or exits.
+ */
+ void
+daemonize(char *pidfile)
+{
+       int             i;
+       int             fd0, fd1, fd2;
+       struct rlimit   r1;
+       pid_t           pid;
+       struct sigaction sa;
+
+       umask(0);
+
+       if (getrlimit(RLIMIT_NOFILE, &r1) < 0) {
+               printLog("cannot get file limit: %s", getErrnoMsg());
+               exit(1);
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               printLog("fork failed: %s", getErrnoMsg());
+               exit(1);
+       } else if (pid != 0) {
+               // have parent exit...
+               exit(0);
+       }
+       setsid();
+
+       bzero(&sa, sizeof(sa));
+       sa.sa_handler = SIG_IGN;
+       sa.sa_flags = 0;
+       if (sigaction(SIGHUP, &sa, NULL) < 0) {
+               printLog("cannot ignore SIGHUP: %s", getErrnoMsg());
+               exit(1);
+       }
+       pid = fork();
+       if (pid < 0) {
+               printLog("second fork failed: %s", getErrnoMsg());
+               exit(1);
+       } else if (pid != 0) {
+               exit(0);
+       }
+
+       if (chdir(ROOT_DIR) < 0) {
+               printLog("cannot change to root '%s' - %s",
+                        ROOT_DIR, getErrnoMsg());
+               exit(1);
+       }
+
+       if (r1.rlim_max == RLIM_INFINITY) {
+               r1.rlim_max = 1024;
+       }
+       for (i = 0; i < r1.rlim_max; i++) {
+               close(i);
+       }
+
+       fd0 = open("/dev/null", O_RDWR);
+       fd1 = dup(0);
+       fd2 = dup(0);
+
+       openlog(service_name, LOG_CONS|LOG_PID, LOG_DAEMON);
+       logging_enabled = 1;
+       if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
+               printLog("unexpected file descriptors: %d %d %d",
+                        fd0, fd1, fd2);
+               exit(1);
+       }
+
+       make_pidfile(pidfile);
+}
+
+ void
+make_pidfile(char *pidfile)
+{
+       int     pidfd;
+       char    buf[80];
+       int     bytes;
+       /* create pid file... */
+       pidfd = open(pidfile, O_RDWR | O_CREAT);
+       if (pidfd == -1) {
+               printLog("cannot create pidfile %s: %s",
+                        pidfile, getErrnoMsg());
+               exit(1);
+       }
+       if (lockf(pidfd, F_TLOCK, 0) == -1) {
+               printLog("cannot lock pidfile %s: %s",
+                        pidfile, getErrnoMsg());
+               exit(1);
+       }
+       bytes = sprintf(buf, "%d", getpid());
+       if (write(pidfd, buf, bytes) != bytes) {
+               printLog("cannot write to pidfile %s: %s",
+                        pidfile, getErrnoMsg());
+               exit(1);
+       }
+}
+
+/**
+ * Helper function for printing log messages which will be prefixed
+ * with the date and our identity, if it is known
+ */
+ void 
+printLog(char *format, ...)
+{
+       va_list ap;
+       va_start(ap, format);
+       if (logging_enabled) {
+               vsyslog(LOG_NOTICE, format, ap);
+       } else {
+               printDate();
+               if (service_name != NULL) {
+                       printf("%s: ", service_name);
+               } else {
+                       printf(": ");
+               }
+               vprintf(format, ap);
+               printf("\n");
+               fflush(NULL);
+       }
+       va_end(ap);
+}
+
+/**
+ * Print specified msg, if debug is on
+ */
+ void
+printDebug(char *format, ...)
+{
+       if (debug) {
+               va_list ap;
+               va_start(ap, format);
+               if (logging_enabled) {
+                       vsyslog(LOG_NOTICE, format, ap);
+               } else {
+                       printDate();
+                       if (service_name != NULL) {
+                               printf("%s DEBUG: ", service_name);
+                       } else {
+                               printf("DEBUG: ");
+                       }       
+                       vprintf(format, ap);
+                       printf("\n");
+                       fflush(NULL);
+               }
+               va_end(ap);
+       }
+}
+
+/**
+ * Obtain / print date, used for logging.
+ */
+ static void
+printDate()
+{
+       struct tm       *brokenTime;
+       time_t          t;
+       char*           fullDateString;
+       char*           dateString;
+       size_t          dateLen;
+
+       t = time(NULL);
+       brokenTime = localtime(&t);
+       fullDateString = asctime(brokenTime);
+       dateLen = strlen(fullDateString) +1;
+       dateString = (char*) malloc(dateLen);
+       if (dateString != NULL) {
+               strncpy(dateString, fullDateString, dateLen-1);
+               dateString[dateLen-2] = '\0';
+               printf("%s ", dateString);
+               fflush(NULL);
+               free(dateString);
+       }
+}
+
+/**
+ * Obtain the corresponding errno message on error, only valid
+ * for last system call
+ */ 
+ char *
+getErrnoMsg()
+{
+       char *msg = strerror(errno);
+       if (msg == NULL) {
+               msg = "unknown error";
+       } 
+       return msg;
+}
+
+/**
+ * Is there an instance of the specified daemon already running?
+ *
+ * returns: pid of a running daemon, 0 if not, -1 on error
+ */
+ pid_t
+daemon_alive(char *pidfile)
+{
+       pid_t pid = -1;
+       int fd;
+
+        if ((fd = open(pidfile, O_RDONLY)) == -1) {
+                printDebug("pidfile %s open: %s", pidfile, getErrnoMsg());
+        } else {
+                char buf[81];
+                int bytes;
+                bytes = read(fd, buf, 80);
+                if (bytes > 0) {
+                        buf[bytes] = '\0';
+                        sscanf(buf,"%d", &pid);
+                        if ( (pid > 0) && (kill(pid, 0) == 0)) {
+                               printDebug("pid %d, is running", pid);
+                       } else {
+                               if (errno != ESRCH) {
+                                       printDebug("kill(2) error: %s",
+                                                  getErrnoMsg());
+                               }
+                               pid = 0;
+                        }
+                }
+                close(fd);
+        }
+
+        return pid;
+}
diff -u --new-file --recursive xen-unstable-clean/tools/console/remote/utils.h 
xen-unstable-patched/tools/console/remote/utils.h
--- xen-unstable-clean/tools/console/remote/utils.h     1969-12-31 
19:00:00.000000000 -0500
+++ xen-unstable-patched/tools/console/remote/utils.h   2005-08-26 
12:36:49.000000000 -0400
@@ -0,0 +1,39 @@
+/*\
+ *  Copyright (C) Egenera, Inc. 2005
+ *  Author(s): Patrick O'Rourke <porourke@xxxxxxxxxxx>
+ *
+ *  Xen Remote 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 _UTILS_H_
+#define _UTILS_H_ 1
+
+#define HANDLE_TERM_SIGNALS    1
+#define SKIP_TERM_SIGNALS      0
+
+void   debug_disable(void);
+void   debug_enable(void);
+void   daemonize(char *);
+pid_t  daemon_alive(char *);
+char   *getErrnoMsg(void);
+int    gotTermSignal(void);
+int    isDebug(void);
+void   printDebug(char *, ...);
+void   printLog(char *, ...);
+void   setupUtils(char *, int);
+void   tearDownUtils(void);
+void   make_pidfile(char *);
+
+#endif /* _UTILS_H */
_______________________________________________
Xen-tools mailing list
Xen-tools@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-tools

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.