diff options
author | kraxel <kraxel> | 2006-07-03 12:00:31 +0000 |
---|---|---|
committer | kraxel <kraxel> | 2006-07-03 12:00:31 +0000 |
commit | 8f4db7fb5130a0b327154eddc62b161fb66af688 (patch) | |
tree | cb43a91e2fdd769e7285c8f7fa76e0a4e83173fb | |
parent | a27248c91a6a7a48ce794efc4ed51cc9a6e7172b (diff) | |
download | xenwatch-8f4db7fb5130a0b327154eddc62b161fb66af688.tar.gz |
xen screen management tool
-rw-r--r-- | .cvsignore | 1 | ||||
-rw-r--r-- | GNUmakefile | 17 | ||||
-rw-r--r-- | apps-x11.c | 88 | ||||
-rw-r--r-- | apps.c | 94 | ||||
-rw-r--r-- | xenlog.c | 56 | ||||
-rw-r--r-- | xenscreen.c | 273 | ||||
-rw-r--r-- | xenscreenrc | 16 | ||||
-rw-r--r-- | xenstore.c | 60 | ||||
-rw-r--r-- | xenstore.h | 4 |
9 files changed, 471 insertions, 138 deletions
@@ -1,5 +1,6 @@ Make.config xenlog +xenscreen xenwatch mdns-browser mdns-publish-xendom diff --git a/GNUmakefile b/GNUmakefile index cfe8f0e..aa6b11a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -6,11 +6,11 @@ include mk/Variables.mk CFLAGS += -DVERSION='"$(VERSION)"' -DLIB='"$(LIB)"' # build -TARGETS := xenlog +TARGETS := xenlog xenscreen BUILD_GTK := xenwatch mdns-browser BUILD_MDNS := mdns-publish-xendom -NEEDS_XENSTORE := xenlog xenwatch mdns-publish-xendom +NEEDS_XENSTORE := xenlog xenscreen xenwatch mdns-publish-xendom NEEDS_GTK := xenwatch mdns-browser NEEDS_MDNS := xenwatch mdns-browser mdns-publish-xendom @@ -62,8 +62,9 @@ $(NEEDS_XENSTORE) : LDLIBS += -lxenstore build: $(TARGETS) install: build - install -d $(bindir) - install -s $(TARGETS) $(bindir) + $(INSTALL_DIR) -d /etc/xen # $(bindir) + $(INSTALL_DATA) xenscreenrc /etc/xen + $(INSTALL_BINARY) -s $(TARGETS) $(bindir) clean: -rm -f *.o *~ $(depfiles) @@ -74,9 +75,11 @@ realclean distclean: clean ############################################# -xenlog: xenlog.o -xenwatch: xenwatch.o xs_view.o xs_store.o xd_view.o xd_store.o apps.o tcp.o mdns.o -mdns-browser: mdns-browser.o mdns.o apps.o +xenlog: xenlog.o xenstore.o +xenscreen: xenscreen.o xenstore.o apps.o +xenwatch: xenwatch.o xs_view.o xs_store.o xd_view.o xd_store.o \ + apps.o apps-x11.o tcp.o mdns.o +mdns-browser: mdns-browser.o mdns.o apps.o apps-x11.o mdns-publish-xendom: mdns-publish-xendom.o include mk/Compile.mk diff --git a/apps-x11.c b/apps-x11.c new file mode 100644 index 0000000..3ed61dc --- /dev/null +++ b/apps-x11.c @@ -0,0 +1,88 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> +#include <xs.h> + +#include "apps.h" + +/* ------------------------------------------------------------------ */ + +#if 0 +/* check_wm_capability(dpy, root, _NET_SUPPORTED, _NET_WM_whatever); */ +static int +check_wm_capability(Display *dpy, Window root, Atom list, Atom wanted) +{ + Atom type; + int format; + unsigned int i; + unsigned long nitems, bytesafter; + unsigned char *args; + unsigned long *ldata; + char *name; + int retval = -1; + + if (Success != XGetWindowProperty + (dpy, root, list, 0, (65536 / sizeof(long)), False, + AnyPropertyType, &type, &format, &nitems, &bytesafter, &args)) + return -1; + if (type != XA_ATOM) + return -1; + ldata = (unsigned long*)args; + for (i = 0; i < nitems; i++) { + if (ldata[i] == wanted) + retval = 0; + if (debug) { + name = XGetAtomName(dpy,ldata[i]); + fprintf(stderr,"wm cap: %s\n",name); + XFree(name); + } + } + XFree(ldata); + return retval; +} +#endif + +static int +check_atom_present(Display *dpy, Window root, Atom check) +{ + Atom type; + int format; + unsigned long nitems, bytesafter; + unsigned char *args; + + if (Success != XGetWindowProperty + (dpy, root, check, 0, (65536 / sizeof(long)), False, + AnyPropertyType, &type, &format, &nitems, &bytesafter, &args)) + return -1; + if (NULL == args) + return -1; + return 0; +} + +#define INIT_ATOM(dpy,atom) atom = XInternAtom(dpy,#atom,False) +static Atom KWIN_RUNNING; +static Atom _METACITY_SENTINEL; + +void detect_desktop(void) +{ + Display *dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default()); + Window root = DefaultRootWindow(dpy); + + INIT_ATOM(dpy, KWIN_RUNNING); + INIT_ATOM(dpy, _METACITY_SENTINEL); + + if (0 == check_atom_present(dpy, root, KWIN_RUNNING)) { + fprintf(stderr,"Desktop: KDE\n"); + desktop_type = DESKTOP_KDE; + } + if (0 == check_atom_present(dpy, root, _METACITY_SENTINEL)) { + fprintf(stderr,"Desktop: Gnome\n"); + desktop_type = DESKTOP_GNOME; + } +} @@ -1,18 +1,12 @@ #include <stdio.h> #include <stdlib.h> +#include <stdarg.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/wait.h> #include <sys/stat.h> -#include <X11/Xlib.h> -#include <X11/Xatom.h> -#include <gdk/gdk.h> -#include <gdk/gdkx.h> -#include <gtk/gtk.h> -#include <xs.h> - #include "list.h" #include "apps.h" @@ -23,11 +17,11 @@ char app_error[256]; /* ------------------------------------------------------------------ */ -static int debug = 1; +static int debug = 0; struct have_app { char *name; - gboolean present; + int present; struct list_head next; }; static LIST_HEAD(apps); @@ -103,82 +97,6 @@ int have_application(char *name) /* ------------------------------------------------------------------ */ -#if 0 -/* check_wm_capability(dpy, root, _NET_SUPPORTED, _NET_WM_whatever); */ -static int -check_wm_capability(Display *dpy, Window root, Atom list, Atom wanted) -{ - Atom type; - int format; - unsigned int i; - unsigned long nitems, bytesafter; - unsigned char *args; - unsigned long *ldata; - char *name; - int retval = -1; - - if (Success != XGetWindowProperty - (dpy, root, list, 0, (65536 / sizeof(long)), False, - AnyPropertyType, &type, &format, &nitems, &bytesafter, &args)) - return -1; - if (type != XA_ATOM) - return -1; - ldata = (unsigned long*)args; - for (i = 0; i < nitems; i++) { - if (ldata[i] == wanted) - retval = 0; - if (debug) { - name = XGetAtomName(dpy,ldata[i]); - fprintf(stderr,"wm cap: %s\n",name); - XFree(name); - } - } - XFree(ldata); - return retval; -} -#endif - -static int -check_atom_present(Display *dpy, Window root, Atom check) -{ - Atom type; - int format; - unsigned long nitems, bytesafter; - unsigned char *args; - - if (Success != XGetWindowProperty - (dpy, root, check, 0, (65536 / sizeof(long)), False, - AnyPropertyType, &type, &format, &nitems, &bytesafter, &args)) - return -1; - if (NULL == args) - return -1; - return 0; -} - -#define INIT_ATOM(dpy,atom) atom = XInternAtom(dpy,#atom,False) -static Atom KWIN_RUNNING; -static Atom _METACITY_SENTINEL; - -void detect_desktop(void) -{ - Display *dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default()); - Window root = DefaultRootWindow(dpy); - - INIT_ATOM(dpy, KWIN_RUNNING); - INIT_ATOM(dpy, _METACITY_SENTINEL); - - if (0 == check_atom_present(dpy, root, KWIN_RUNNING)) { - fprintf(stderr,"Desktop: KDE\n"); - desktop_type = DESKTOP_KDE; - } - if (0 == check_atom_present(dpy, root, _METACITY_SENTINEL)) { - fprintf(stderr,"Desktop: Gnome\n"); - desktop_type = DESKTOP_GNOME; - } -} - -/* ------------------------------------------------------------------ */ - int run_application_va(int do_wait, const char *app, char **argv) { int status, rc; @@ -335,11 +253,13 @@ int open_vnc_session(char *host, int screen) snprintf(vncurl, sizeof(vncurl), "vnc://%s:%d/", host, 5900 + screen); /* --- try client apps --- */ + if (have_application("vncviewer")) + return run_application(0, "vncviewer", "vncviewer", + "-xrm", "vncviewer*passwordDialog: true", + display, NULL); if (have_application("krdc")) /* KDE remote desktop client */ return run_application(0, "krdc", "krdc", display, NULL); - if (have_application("vncviewer")) - return run_application(0, "vncviewer", "vncviewer", display, NULL); /* --- try web browser (java applet client) --- */ if (DESKTOP_KDE == desktop_type && have_application("kfmclient")) @@ -1,42 +1,21 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <xs.h> +#include "xenstore.h" + /* ------------------------------------------------------------- */ int main(int argc, char *argv[]) { struct xs_handle *xenstore = NULL; - xs_transaction_t xst; - char *xs_value = NULL, **vec; - char *value; - unsigned int count; - - if (NULL == xenstore) { - xenstore = xs_daemon_open_readonly(); - if (NULL == xenstore) - fprintf(stderr,"can't connect to %s\n",xs_daemon_socket_ro()); - else - printf("connected to %s\n", xs_daemon_socket_ro()); - } - - if (NULL == xenstore) { - xenstore = xs_daemon_open(); - if (NULL == xenstore) - fprintf(stderr,"can't connect to %s\n",xs_daemon_socket()); - else - printf("connected to %s\n", xs_daemon_socket()); - } - - if (NULL == xenstore) { - xenstore = xs_domain_open(); - if (NULL == xenstore) - fprintf(stderr, "can't connect to %s\n", xs_domain_dev()); - else - printf("connected to %s\n", xs_domain_dev()); - } + char **vec; + char value[256]; + unsigned int count, rc; + xenstore = xenstore_open(1,1,1,1); if (NULL == xenstore) { fprintf(stderr, "can't access xenstore, exiting\n"); exit(1); @@ -51,29 +30,18 @@ int main(int argc, char *argv[]) } switch (vec[XS_WATCH_PATH][0]) { case '/': - xst = xs_transaction_start(xenstore); - if (xst) { - xs_value = xs_read(xenstore, xst, vec[XS_WATCH_PATH], NULL); - xs_transaction_end(xenstore, xst, 0); - if (NULL == xs_value) - value = "<deleted>"; - else - value = xs_value; - } else { - value = "<error>"; + rc = xenstore_read(xenstore, vec[XS_WATCH_PATH], value, sizeof(value)); + switch (rc) { + case -1: strcpy(value, "<error>"); break; + case -2: strcpy(value, "<deleted>"); break; } break; default: - value = "<null>"; + strcpy(value, "<null>"); break; } printf("%-64s : \"%s\"\n", vec[XS_WATCH_PATH], value); fflush(stdout); - - if (xs_value) { - free(xs_value); - xs_value = NULL; - } free(vec); } } diff --git a/xenscreen.c b/xenscreen.c new file mode 100644 index 0000000..e091976 --- /dev/null +++ b/xenscreen.c @@ -0,0 +1,273 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> + +#include <xs.h> + +#include "list.h" +#include "xenstore.h" +#include "apps.h" + +/* ------------------------------------------------------------- */ + +#define BUFSIZE 64 + +struct dom { + int domid; + char name[BUFSIZE]; + char tty[BUFSIZE]; + int connected; + int destroyed; + struct list_head next; +}; +static LIST_HEAD(doms); +static int domcnt; + +//static char *screenrc = "/etc/xen/xenscreenrc"; +static char *screenrc = "/home/kraxel/projects/xenwatch/xenscreenrc"; +static char *screen_session = "xencon"; +static char *screen_title = "watch"; + +/* ------------------------------------------------------------- */ + +static struct dom *find_dom(int domid) +{ + struct dom *dom; + struct list_head *item; + + list_for_each(item, &doms) { + dom = list_entry(item, struct dom, next); + if (dom->domid == domid) + return dom; + } + return NULL; +} + +static struct dom *get_dom(int domid) +{ + struct dom *dom; + + dom = find_dom(domid); + if (!dom) { + dom = malloc(sizeof(*dom)); + memset(dom,0,sizeof(*dom)); + dom->domid = domid; + list_add_tail(&dom->next, &doms); + } + return dom; +} + +/* ------------------------------------------------------------- */ + +static int termsig; + +static void catchsig(int sig) +{ + termsig = sig; +} + +static void try_attach_screen(struct dom *dom) +{ + int rc; + + if (dom->connected) + return; + if (!strlen(dom->name)) + return; + if (!strlen(dom->tty)) + return; + + fprintf(stderr," conn: %s (%d) @ %s\n", + dom->name, dom->domid, dom->tty); + + if (0 != access(dom->tty, R_OK)) { + fprintf(stderr, " error: no access to tty %s\n", dom->tty); + return; + } + + rc = run_application(1, "fuser", "fuser", "-s", dom->tty, NULL); + if (0 == rc) { + fprintf(stderr," error: tty %s already in use\n", dom->tty); + return; + } + + rc = run_application(1, "screen", "screen", + "-X", "-S", screen_session, + "screen", "-t", dom->name, dom->tty, + NULL); + dom->connected = 1; + domcnt++; +} + +static void try_release_domain(struct dom *dom) +{ + if (!dom->destroyed) + return; + fprintf(stderr," gone: %s (%d)%s\n", dom->name, dom->domid, + dom->connected ? " [conn]" : ""); + if (dom->connected) + domcnt--; + list_del(&dom->next); + free(dom); +} + +/* ------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + struct sigaction act,old; + fd_set set; + struct xs_handle *xenstore = NULL; + xs_transaction_t xst; + char **vec = NULL; + int domid; + char path[BUFSIZE], value[BUFSIZE]; + unsigned int count, i, rc; + struct dom *dom; + time_t last_ctrl_c = 0; + + if (!have_application("screen")) { + fprintf(stderr, "screen not installed, exiting\n"); + exit(1); + } + + if (NULL == getenv("STY") || NULL == strstr(getenv("STY"),screen_session)) { + /* not running inside screen, try to attach */ + rc = run_application(1, "screen", "screen", + "-S", screen_session, + "-r", "-p", "=", + NULL); + if (0 == rc) + exit(0); + /* failing that, start a new screen session */ + rc = run_application(1,"screen", "screen", + "-d", "-m", + "-S", screen_session, + "-c", screenrc, + "-t", screen_title, argv[0], + NULL); + execlp("screen", "screen", + "-S", screen_session, + "-r", "-p", "=", + NULL); + perror("execlp(screen)"); + exit(1); + } + + /* setup signal handler */ + memset(&act,0,sizeof(act)); + sigemptyset(&act.sa_mask); + act.sa_handler = catchsig; + sigaction(SIGTERM,&act,&old); + sigaction(SIGINT,&act,&old); + + fprintf(stderr, + "###\n" + "### Xen consoles in screen\n" + "### This is the watch process\n" + "###\n" + "\n"); + + /* connect to xenstore */ + xenstore = xenstore_open(1,1,1,1); + if (NULL == xenstore) { + fprintf(stderr, "can't access xenstore, exiting\n"); + exit(1); + } + xs_watch(xenstore, "/local/domain", "token"); + + /* look for running domains */ + if (!(xst = xs_transaction_start(xenstore))) { + fprintf(stderr,"Oops, can't start xenstore transaction\n"); + exit(1); + } + vec = xs_directory(xenstore, xst, "/local/domain", &count); + xs_transaction_end(xenstore, xst, 0); + + fprintf(stderr,"looking for existing domains ...\n"); + for (i = 0; i < count; i++) { + domid = atoi(vec[i]); + dom = get_dom(domid); + snprintf(path, sizeof(path), "/local/domain/%d/name", domid); + xenstore_read(xenstore, path, dom->name, sizeof(dom->name)); + snprintf(path, sizeof(path), "/local/domain/%d/console/tty", domid); + xenstore_read(xenstore, path, dom->tty, sizeof(dom->tty)); + try_attach_screen(dom); + } + + /* main loop */ + fprintf(stderr,"... done, watching for new ones appear\n"); + for (;;) { + if (termsig) { + if (!domcnt) + break; + if (time(NULL) - last_ctrl_c < 3) + break; + fprintf(stderr,"Still %d domain(s) active - not quitting.\n", domcnt); + fprintf(stderr,"Better try detach instead (Ctrl-A d).\n"); + fprintf(stderr,"Hit Ctrl-C within 3 secs again to quit nevertheless.\n"); + last_ctrl_c = time(NULL); + termsig = 0; + } + + FD_ZERO(&set); + FD_SET(xs_fileno(xenstore), &set); + switch (select(xs_fileno(xenstore)+1, &set, NULL, NULL, NULL)) { + case -1: + if (EINTR == errno) + continue; /* termsig check */ + perror("select"); + break; + case 0: + fprintf(stderr,"Huh, select() timeout?\n"); + exit(1); + break; + default: + break; + } + + if (vec) + free(vec); + vec = xs_read_watch(xenstore, &count); + if (NULL == vec) { + fprintf(stderr,"xs_read_watch() failed\n"); + exit(1); + } + if (2 != sscanf(vec[XS_WATCH_PATH], "/local/domain/%d/%64s", &domid, path)) { + if (1 != sscanf(vec[XS_WATCH_PATH], "/local/domain/%d", &domid)) + continue; + strcpy(path, ""); + } + dom = get_dom(domid); + + if (0 == strcmp(path,"")) { + rc = xenstore_read(xenstore, vec[XS_WATCH_PATH], value, sizeof(value)); + if (0 != rc) + dom->destroyed = 1; + + } else if (0 == strcmp(path, "console/tty")) { + rc = xenstore_read(xenstore, vec[XS_WATCH_PATH], value, sizeof(value)); + if (0 != rc) + continue; + strcpy(dom->tty, value); + + } else if (0 == strcmp(path, "name")) { + rc = xenstore_read(xenstore, vec[XS_WATCH_PATH], value, sizeof(value)); + if (0 != rc) + continue; + strcpy(dom->name, value); + fprintf(stderr," boot: %s (%d)\n", dom->name, dom->domid); + + } else { + continue; + + } + + try_attach_screen(dom); + try_release_domain(dom); + } + return 0; +} diff --git a/xenscreenrc b/xenscreenrc new file mode 100644 index 0000000..c735310 --- /dev/null +++ b/xenscreenrc @@ -0,0 +1,16 @@ +multiuser on +shell /bin/bash +defscrollback 5000 +compacthist on +defutf8 on +termcapinfo xterm hs@ + +# status line +hardstatus alwayslastline "%{=b bw} xen |%{-} %-w%{= yb} %50>%n* %t %{-}%+w%<" +sorendition =s wb + +# log files +#logfile /var/log/screen/screenlog.%t +#logtstamp string "-- %n:%t -- time-stamp -- %Y-%m-%d %0c:%s --^J" +#logtstamp on + diff --git a/xenstore.c b/xenstore.c new file mode 100644 index 0000000..f43b9d2 --- /dev/null +++ b/xenstore.c @@ -0,0 +1,60 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <xs.h> + +#include "xenstore.h" + +/* ------------------------------------------------------------- */ + +struct xs_handle *xenstore_open(int daemon, int domain, + int readonly_ok, int verbose) +{ + struct xs_handle *xenstore = NULL; + + if (NULL == xenstore && daemon && readonly_ok) { + xenstore = xs_daemon_open_readonly(); + if (NULL == xenstore) + fprintf(stderr,"can't connect to %s\n",xs_daemon_socket_ro()); + else + if (verbose) + printf("connected to %s\n", xs_daemon_socket_ro()); + } + + if (NULL == xenstore && daemon) { + xenstore = xs_daemon_open(); + if (NULL == xenstore) + fprintf(stderr,"can't connect to %s\n",xs_daemon_socket()); + else + if (verbose) + printf("connected to %s\n", xs_daemon_socket()); + } + + if (NULL == xenstore && domain) { + xenstore = xs_domain_open(); + if (NULL == xenstore) + fprintf(stderr, "can't connect to %s\n", xs_domain_dev()); + else + if (verbose) + printf("connected to %s\n", xs_domain_dev()); + } + return xenstore; +} + +int xenstore_read(struct xs_handle *xenstore, char *path, char *dst, size_t size) +{ + xs_transaction_t xst; + char *xs_value = NULL; + + xst = xs_transaction_start(xenstore); + if (!xst) + return -1; + + xs_value = xs_read(xenstore, xst, path, NULL); + xs_transaction_end(xenstore, xst, 0); + if (NULL == xs_value) + return -2; + snprintf(dst, size, "%s", xs_value); + free(xs_value); + return 0; +} diff --git a/xenstore.h b/xenstore.h new file mode 100644 index 0000000..047563b --- /dev/null +++ b/xenstore.h @@ -0,0 +1,4 @@ +struct xs_handle * xenstore_open(int daemon, int domain, + int readonly_ok, int verbose); +int xenstore_read(struct xs_handle *xenstore, char *path, + char *dst, size_t size); |