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
|