WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-tools

[Xen-tools] [PATCH] xenrconsoled

To: xen-tools@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-tools] [PATCH] xenrconsoled
From: Patrick O'Rourke <porourke@xxxxxxxxxxx>
Date: Fri, 26 Aug 2005 14:02:38 -0400
Delivery-date: Fri, 26 Aug 2005 17:58:44 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-tools-request@lists.xensource.com?subject=help>
List-id: Xen control tools developers <xen-tools.lists.xensource.com>
List-post: <mailto:xen-tools@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-tools>, <mailto:xen-tools-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-tools>, <mailto:xen-tools-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-tools-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mozilla Thunderbird 1.0.6 (X11/20050716)
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
<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-tools] [PATCH] xenrconsoled, Patrick O'Rourke <=