--- old/patches/libvirt/least-priv Tue Jul 1 08:16:03 2008 +++ new/patches/libvirt/least-priv Tue Jul 1 08:16:03 2008 @@ -363,63 +363,6 @@ int imode; /* interactive mode? */ int quiet; /* quiet mode */ int debug; /* print debug messages? */ -@@ -464,12 +463,8 @@ static vshCmdOptDef opts_console[] = { - static int - cmdConsole(vshControl * ctl, vshCmd * cmd) - { -- xmlDocPtr xml = NULL; -- xmlXPathObjectPtr obj = NULL; -- xmlXPathContextPtr ctxt = NULL; - virDomainPtr dom; - int ret = FALSE; -- char *doc; - - if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) - return FALSE; -@@ -477,37 +472,16 @@ cmdConsole(vshControl * ctl, vshCmd * cm - if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL))) - return FALSE; - -- doc = virDomainGetXMLDesc(dom, 0); -- if (!doc) -- goto cleanup; -- -- xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL, -- XML_PARSE_NOENT | XML_PARSE_NONET | -- XML_PARSE_NOWARNING); -- free(doc); -- if (!xml) -- goto cleanup; -- ctxt = xmlXPathNewContext(xml); -- if (!ctxt) -- goto cleanup; -+ ret = vshConsole(dom); - -- obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); -- if ((obj != NULL) && ((obj->type == XPATH_STRING) && -- (obj->stringval != NULL) && (obj->stringval[0] != 0))) { -- if (vshRunConsole((const char *)obj->stringval) == 0) -- ret = TRUE; -- } else { -+ if (ret == 0) { - vshPrintExtra(ctl, _("No console available for domain\n")); -+ } else if (ret == -1) { -+ fprintf(stderr, _("unable to open console: %s\n"), -+ strerror(errno)); - } -- xmlXPathFreeObject(obj); - -- cleanup: -- if (ctxt) -- xmlXPathFreeContext(ctxt); -- if (xml) -- xmlFreeDoc(xml); -- virDomainFree(dom); -- return ret; -+ return ret == 1; - } - - #else /* __MINGW32__ */ @@ -4523,22 +4497,11 @@ vshInit(vshControl * ctl) if (ctl->conn) return FALSE; @@ -492,179 +435,4 @@ + vshDeinit(ctl); exit(ret ? EXIT_SUCCESS : EXIT_FAILURE); - } ---- libvirt-0.4.0/src/console.c 2007-12-07 07:00:48.000000000 -0800 -+++ libvirt-new/src/console.c 2008-04-16 16:34:15.533322609 -0700 -@@ -34,6 +34,11 @@ - #include - #include - #include -+#include -+ -+#include -+#include -+#include - - #include "console.h" - #include "internal.h" -@@ -59,8 +64,10 @@ cfmakeraw (struct termios *attr) - } - #endif /* !HAVE_CFMAKERAW */ - --int vshRunConsole(const char *tty) { -- int ttyfd, ret = -1; -+static int -+vshDirectConsole(int ttyfd) -+{ -+ int ret = -1; - struct termios ttyattr, rawattr; - void (*old_sigquit)(int); - void (*old_sigterm)(int); -@@ -68,14 +75,6 @@ int vshRunConsole(const char *tty) { - void (*old_sighup)(int); - void (*old_sigpipe)(int); - -- -- /* We do not want this to become the controlling TTY */ -- if ((ttyfd = open(tty, O_NOCTTY | O_RDWR)) < 0) { -- fprintf(stderr, _("unable to open tty %s: %s\n"), -- tty, strerror(errno)); -- return -1; -- } -- - /* Put STDIN into raw mode so that stuff typed - does not echo to the screen (the TTY reads will - result in it being echoed back already), and -@@ -174,7 +173,7 @@ int vshRunConsole(const char *tty) { - } - } - done: -- ret = 0; -+ ret = 1; - - cleanup: - -@@ -195,6 +194,106 @@ int vshRunConsole(const char *tty) { - return ret; - } - -+/* -+ * Attempt to access the domain via 'xenconsole', which may have -+ * additional privilege to reach the console. -+ */ -+static int -+vshXenConsole(int id) -+{ -+ char arg[100]; -+ char *argv[3]; -+ pid_t pid; -+ -+ if ((pid = fork()) < 0) { -+ return -1; -+ } else if (pid) { -+ int wstat; -+ -+ if (waitpid(pid, &wstat, 0) < 0) -+ return -1; -+ -+ if (WIFSIGNALED(wstat)) -+ return -1; -+ if (WIFEXITED(wstat) && WEXITSTATUS(wstat)) -+ return -1; -+ -+ return 1; -+ } -+ -+ /* child */ -+ -+ if (snprintf(arg, 100, "%d", id) < 0) -+ return -1; -+ -+ argv[0] = "/usr/lib/xen/bin/xenconsole"; -+ argv[1] = arg; -+ argv[2] = NULL; -+ -+ if (execv("/usr/lib/xen/bin/xenconsole", argv)) -+ fprintf(stderr, _("failed to run xenconsole: %s\n"), -+ strerror(errno)); -+ _exit(1); -+} -+ -+/* -+ * Returns 0 if no console is available, 1 if the console was accessed -+ * successfully, or -1 on error. -+ */ -+int vshConsole(virDomainPtr dom) -+{ -+ xmlDocPtr xml = NULL; -+ xmlXPathObjectPtr obj = NULL; -+ xmlXPathContextPtr ctxt = NULL; -+ char *doc; -+ int ttyfd; -+ int ret = -1; -+ -+ doc = virDomainGetXMLDesc(dom, 0); -+ if (!doc) -+ goto cleanup; -+ -+ xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL, -+ XML_PARSE_NOENT | XML_PARSE_NONET | -+ XML_PARSE_NOWARNING); -+ free(doc); -+ if (!xml) -+ goto cleanup; -+ ctxt = xmlXPathNewContext(xml); -+ if (!ctxt) -+ goto cleanup; -+ -+ obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); -+ if (obj == NULL || obj->type != XPATH_STRING || obj->stringval == NULL || -+ obj->stringval[0] == '\0') { -+ ret = 0; -+ goto cleanup; -+ } -+ -+ /* We do not want this to become the controlling TTY */ -+ ttyfd = open((char *)obj->stringval, O_NOCTTY | O_RDWR); -+ -+ if (ttyfd != -1) { -+ ret = vshDirectConsole(ttyfd); -+ goto cleanup; -+ } else if (errno != EACCES) { -+ fprintf(stderr, _("unable to open tty %s: %s\n"), -+ obj->stringval, strerror(errno)); -+ } else { -+ ret = vshXenConsole(virDomainGetID(dom)); -+ } -+ -+ cleanup: -+ if (obj) -+ xmlXPathFreeObject(obj); -+ if (ctxt) -+ xmlXPathFreeContext(ctxt); -+ if (xml) -+ xmlFreeDoc(xml); -+ virDomainFree(dom); -+ return ret; -+} -+ - #endif /* !__MINGW32__ */ - - /* ---- libvirt-0.4.0/src/console.h 2007-12-07 07:00:48.000000000 -0800 -+++ libvirt-new/src/console.h 2008-04-16 08:49:20.165071296 -0700 -@@ -25,11 +25,13 @@ - - #ifndef __MINGW32__ - -+#include "libvirt/libvirt.h" -+ - #ifdef __cplusplus - extern "C" { - #endif - -- int vshRunConsole(const char *tty); -+int vshConsole(virDomainPtr dom); - - #ifdef __cplusplus } --- old/patches/libvirt/series Tue Jul 1 08:16:04 2008 +++ new/patches/libvirt/series Tue Jul 1 08:16:04 2008 @@ -15,6 +15,7 @@ change-resource detach-disk usbmouse-xml +virt-console least-priv verbosity floppy-support --- old/patches/libvirt/solaris-dom0-2 Tue Jul 1 08:16:05 2008 +++ new/patches/libvirt/solaris-dom0-2 Tue Jul 1 08:16:05 2008 @@ -1,20 +1,5 @@ Solaris dom0 support -diff --git a/src/console.c b/src/console.c ---- a/src/console.c -+++ b/src/console.c -@@ -56,6 +56,11 @@ cfmakeraw (struct termios *attr) - attr->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - attr->c_cflag &= ~(CSIZE | PARENB); - attr->c_cflag |= CS8; -+ -+#ifdef __sun -+ attr->c_cc[VMIN] = 0; -+ attr->c_cc[VTIME] = 0; -+#endif - } - #endif /* !HAVE_CFMAKERAW */ - diff --git a/src/xen_internal.c b/src/xen_internal.c --- a/src/xen_internal.c +++ b/src/xen_internal.c --- /dev/null Tue Jul 1 08:16:06 2008 +++ new/patches/libvirt/virt-console Tue Jul 1 08:16:05 2008 @@ -0,0 +1,1230 @@ +--- libvirt-0.4.0/src/util.c 2007-12-07 07:00:48.000000000 -0800 ++++ libvirt-new/src/util.c 2008-06-26 20:33:40.618447489 -0700 +@@ -92,8 +92,9 @@ static int virSetNonBlock(int fd) { + + static int + _virExec(virConnectPtr conn, +- char **argv, +- int *retpid, int infd, int *outfd, int *errfd, int non_block) { ++ char **argv, ++ int *retpid, int infd, int *outfd, int *errfd, ++ int non_block, int usepipe) { + int pid, null; + int pipeout[2] = {-1,-1}; + int pipeerr[2] = {-1,-1}; +@@ -104,8 +105,8 @@ _virExec(virConnectPtr conn, + goto cleanup; + } + +- if ((outfd != NULL && pipe(pipeout) < 0) || +- (errfd != NULL && pipe(pipeerr) < 0)) { ++ if (usepipe && ((outfd != NULL && pipe(pipeout) < 0) || ++ (errfd != NULL && pipe(pipeerr) < 0))) { + ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create pipe : %s", + strerror(errno)); + goto cleanup; +@@ -119,7 +120,7 @@ _virExec(virConnectPtr conn, + + if (pid) { /* parent */ + close(null); +- if (outfd) { ++ if (usepipe && outfd) { + close(pipeout[1]); + if(non_block) + if(virSetNonBlock(pipeout[0]) == -1) +@@ -131,7 +132,7 @@ _virExec(virConnectPtr conn, + "Failed to set close-on-exec file descriptor flag"); + *outfd = pipeout[0]; + } +- if (errfd) { ++ if (usepipe && errfd) { + close(pipeerr[1]); + if(non_block) + if(virSetNonBlock(pipeerr[0]) == -1) +@@ -149,23 +150,26 @@ _virExec(virConnectPtr conn, + + /* child */ + +- if (pipeout[0] > 0 && close(pipeout[0]) < 0) +- _exit(1); +- if (pipeerr[0] > 0 && close(pipeerr[0]) < 0) +- _exit(1); +- +- if (dup2(infd >= 0 ? infd : null, STDIN_FILENO) < 0) +- _exit(1); +- if (dup2(pipeout[1] > 0 ? pipeout[1] : null, STDOUT_FILENO) < 0) +- _exit(1); +- if (dup2(pipeerr[1] > 0 ? pipeerr[1] : null, STDERR_FILENO) < 0) +- _exit(1); ++ if (usepipe) { ++ if (pipeout[0] > 0 && close(pipeout[0]) < 0) ++ _exit(1); ++ if (pipeerr[0] > 0 && close(pipeerr[0]) < 0) ++ _exit(1); ++ ++ if (dup2(infd >= 0 ? infd : null, STDIN_FILENO) < 0) ++ _exit(1); ++ if (dup2(pipeout[1] > 0 ? pipeout[1] : null, STDOUT_FILENO) < 0) ++ _exit(1); ++ if (dup2(pipeerr[1] > 0 ? pipeerr[1] : null, STDERR_FILENO) < 0) ++ _exit(1); ++ ++ if (pipeout[1] > 0) ++ close(pipeout[1]); ++ if (pipeerr[1] > 0) ++ close(pipeerr[1]); ++ } + + close(null); +- if (pipeout[1] > 0) +- close(pipeout[1]); +- if (pipeerr[1] > 0) +- close(pipeerr[1]); + + execvp(argv[0], argv); + +@@ -192,7 +196,7 @@ virExec(virConnectPtr conn, + char **argv, + int *retpid, int infd, int *outfd, int *errfd) { + +- return(_virExec(conn, argv, retpid, infd, outfd, errfd, 0)); ++ return(_virExec(conn, argv, retpid, infd, outfd, errfd, 0, 1)); + } + + int +@@ -200,9 +204,17 @@ virExecNonBlock(virConnectPtr conn, + char **argv, + int *retpid, int infd, int *outfd, int *errfd) { + +- return(_virExec(conn, argv, retpid, infd, outfd, errfd, 1)); ++ return(_virExec(conn, argv, retpid, infd, outfd, errfd, 1, 1)); + } + ++/* ++ * Exec a child, but leave the fd's alone. ++ */ ++int ++virExecNoPipe(virConnectPtr conn, char **argv, int *retpid) { ++ return _virExec(conn, argv, retpid, 0, NULL, NULL, 0, 0); ++} ++ + #else /* __MINGW32__ */ + + int +@@ -229,6 +241,15 @@ virExecNonBlock(virConnectPtr conn, + return -1; + } + ++int ++virExecNoPipe(virConnectPtr conn, ++ char **argv ATTRIBUTE_UNUSED, ++ int *retpid ATTRIBUTE_UNUSED) ++{ ++ ReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__); ++ return -1; ++} ++ + #endif /* __MINGW32__ */ + + /* Like read(), but restarts after EINTR */ +--- libvirt-0.4.0/src/util.h 2007-12-04 05:26:35.000000000 -0800 ++++ libvirt-new/src/util.h 2008-06-26 20:34:04.328530822 -0700 +@@ -28,6 +28,7 @@ + + int virExec(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd); + int virExecNonBlock(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd); ++int virExecNoPipe(virConnectPtr conn, char **argv, int *retpid); + + int saferead(int fd, void *buf, size_t count); + ssize_t safewrite(int fd, const void *buf, size_t count); +--- libvirt-0.4.0/src/Makefile.am 2007-12-17 13:51:09.000000000 -0800 ++++ libvirt-new/src/Makefile.am 2008-06-27 06:01:13.810977020 -0700 +@@ -71,9 +71,14 @@ libvirt_la_LDFLAGS = -Wl,--version-scrip + @CYGWIN_EXTRA_LDFLAGS@ + libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) + +-bin_PROGRAMS = virsh ++bin_PROGRAMS = virsh virt-console + +-virsh_SOURCES = virsh.c console.c console.h ++virt_console_SOURCES = virt-console.c ++virt_console_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_CFLAGS) ++virt_console_DEPENDENCIES = $(DEPS) ++virt_console_LDADD = $(LDADDS) $(VIRSH_LIBS) ++ ++virsh_SOURCES = virsh.c + virsh_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDFLAGS) + virsh_DEPENDENCIES = $(DEPS) + virsh_LDADD = $(LDADDS) $(VIRSH_LIBS) +--- libvirt-0.4.0/src/Makefile.in 2008-06-27 06:17:20.865621099 -0700 ++++ libvirt-1/src/Makefile.in 2008-06-27 06:19:55.983265305 -0700 +@@ -34,7 +34,7 @@ PRE_UNINSTALL = : + POST_UNINSTALL = : + build_triplet = @build@ + host_triplet = @host@ +-bin_PROGRAMS = virsh$(EXEEXT) ++bin_PROGRAMS = virsh$(EXEEXT) virt-console$(EXEEXT) + subdir = src + DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +@@ -131,11 +131,14 @@ libvirt_la_LINK = $(LIBTOOL) --tag=CC $( + $(CFLAGS) $(libvirt_la_LDFLAGS) $(LDFLAGS) -o $@ + binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) + PROGRAMS = $(bin_PROGRAMS) +-am_virsh_OBJECTS = virsh-virsh.$(OBJEXT) virsh-console.$(OBJEXT) ++am_virsh_OBJECTS = virsh-virsh.$(OBJEXT) + virsh_OBJECTS = $(am_virsh_OBJECTS) + am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libvirt.la \ + ../gnulib/lib/libgnu.la + virsh_LINK = $(CCLD) -o $@ $(virsh_LDFLAGS) ++am_virt_console_OBJECTS = virt-console.$(OBJEXT) ++virt_console_OBJECTS = $(am_virt_console_OBJECTS) ++virt_console_LINK = $(CCLD) -o $@ $(virt_console_LDFLAGS) + DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ + depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp + am__depfiles_maybe = depfiles +@@ -148,8 +151,10 @@ CCLD = $(CC) + LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +-SOURCES = $(libvirt_la_SOURCES) $(virsh_SOURCES) +-DIST_SOURCES = $(libvirt_la_SOURCES) $(virsh_SOURCES) ++SOURCES = $(libvirt_la_SOURCES) $(virsh_SOURCES) \ ++ $(virt_console_SOURCES) ++DIST_SOURCES = $(libvirt_la_SOURCES) $(virsh_SOURCES) \ ++ $(virt_console_SOURCES) + confDATA_INSTALL = $(INSTALL_DATA) + DATA = $(conf_DATA) + ETAGS = etags +@@ -582,7 +587,11 @@ libvirt_la_LDFLAGS = -M$(srcdir)/libvirt + @CYGWIN_EXTRA_LDFLAGS@ + + libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) +-virsh_SOURCES = virsh.c console.c console.h ++virt_console_SOURCES = virt-console.c ++virt_console_LDFLAGS = $(LDFLAGS) ++virt_console_DEPENDENCIES = $(DEPS) ++virt_console_LDADD = $(VIRSH_LIBS) -lvirt -lxml2 ++virsh_SOURCES = virsh.c + virsh_LDFLAGS = $(LDFLAGS) + virsh_DEPENDENCIES = $(DEPS) + virsh_LDADD = $(VIRSH_LIBS) -lvirt -lxml2 +@@ -682,6 +691,9 @@ clean-binPROGRAMS: + virsh$(EXEEXT): $(virsh_OBJECTS) $(virsh_DEPENDENCIES) + @rm -f virsh$(EXEEXT) + $(virsh_LINK) $(virsh_OBJECTS) $(virsh_LDADD) $(LIBS) ++virt-console$(EXEEXT): $(virt_console_OBJECTS) $(virt_console_DEPENDENCIES) ++ @rm -f virt-console$(EXEEXT) ++ $(virt_console_LINK) $(virt_console_OBJECTS) $(virt_console_LDADD) $(LIBS) + + mostlyclean-compile: + -rm -f *.$(OBJEXT) +@@ -717,8 +729,8 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvirt_la-xm_internal.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvirt_la-xml.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvirt_la-xs_internal.Plo@am__quote@ +-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virsh-console.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virsh-virsh.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virt-console.Po@am__quote@ + + .c.o: + @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@@ -951,20 +963,6 @@ virsh-virsh.obj: virsh.c + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(virsh_CFLAGS) $(CFLAGS) -c -o virsh-virsh.obj `if test -f 'virsh.c'; then $(CYGPATH_W) 'virsh.c'; else $(CYGPATH_W) '$(srcdir)/virsh.c'; fi` + +-virsh-console.o: console.c +-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(virsh_CFLAGS) $(CFLAGS) -MT virsh-console.o -MD -MP -MF $(DEPDIR)/virsh-console.Tpo -c -o virsh-console.o `test -f 'console.c' || echo '$(srcdir)/'`console.c +-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/virsh-console.Tpo $(DEPDIR)/virsh-console.Po +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='console.c' object='virsh-console.o' libtool=no @AMDEPBACKSLASH@ +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(virsh_CFLAGS) $(CFLAGS) -c -o virsh-console.o `test -f 'console.c' || echo '$(srcdir)/'`console.c +- +-virsh-console.obj: console.c +-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(virsh_CFLAGS) $(CFLAGS) -MT virsh-console.obj -MD -MP -MF $(DEPDIR)/virsh-console.Tpo -c -o virsh-console.obj `if test -f 'console.c'; then $(CYGPATH_W) 'console.c'; else $(CYGPATH_W) '$(srcdir)/console.c'; fi` +-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/virsh-console.Tpo $(DEPDIR)/virsh-console.Po +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='console.c' object='virsh-console.obj' libtool=no @AMDEPBACKSLASH@ +-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(virsh_CFLAGS) $(CFLAGS) -c -o virsh-console.obj `if test -f 'console.c'; then $(CYGPATH_W) 'console.c'; else $(CYGPATH_W) '$(srcdir)/console.c'; fi` +- + mostlyclean-libtool: + -rm -f *.lo + +--- libvirt-0.4.0/src/virsh.c 2008-06-27 13:30:32.395824295 -0700 ++++ libvirt-new/src/virsh.c 2008-06-27 13:29:26.021985284 -0700 +@@ -48,7 +48,7 @@ + #endif + + #include "internal.h" +-#include "console.h" ++#include "util.h" + + static char *progname; + static int sigpipe; +@@ -446,7 +446,7 @@ cmdConnect(vshControl * ctl, vshCmd * cm + * "console" command + */ + static vshCmdInfo info_console[] = { +- {"syntax", "console "}, ++ {"syntax", "console [--verbose] "}, + {"help", gettext_noop("connect to the guest console")}, + {"desc", + gettext_noop("Connect the virtual serial console for the guest")}, +@@ -454,6 +454,7 @@ static vshCmdInfo info_console[] = { + }; + + static vshCmdOptDef opts_console[] = { ++ {"verbose", VSH_OT_BOOL, 0, gettext_noop("verbose console")}, + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")}, + {NULL, 0, 0, NULL} + }; +@@ -463,50 +464,37 @@ static vshCmdOptDef opts_console[] = { + static int + cmdConsole(vshControl * ctl, vshCmd * cmd) + { +- xmlDocPtr xml = NULL; +- xmlXPathObjectPtr obj = NULL; +- xmlXPathContextPtr ctxt = NULL; +- virDomainPtr dom; ++ int verbose = vshCommandOptBool(cmd, "verbose"); ++ char *argv[] = { "/usr/bin/virt-console", NULL, NULL, NULL, NULL }; + int ret = FALSE; +- char *doc; ++ int pid; ++ int argpos = 1; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + +- if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL))) +- return FALSE; +- +- doc = virDomainGetXMLDesc(dom, 0); +- if (!doc) +- goto cleanup; ++ if (verbose) ++ argv[argpos++] = "--verbose"; ++ ++ if (ctl->name != NULL) { ++ argv[argpos++] = "--connect"; ++ argv[argpos++] = ctl->name; ++ } + +- xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL, +- XML_PARSE_NOENT | XML_PARSE_NONET | +- XML_PARSE_NOWARNING); +- free(doc); +- if (!xml) +- goto cleanup; +- ctxt = xmlXPathNewContext(xml); +- if (!ctxt) +- goto cleanup; ++ if (!(argv[argpos] = vshCommandOptString(cmd, "domain", NULL))) { ++ vshError(ctl, FALSE, _("Undefined domain name or id.")); ++ return FALSE; ++ } + +- obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); +- if ((obj != NULL) && ((obj->type == XPATH_STRING) && +- (obj->stringval != NULL) && (obj->stringval[0] != 0))) { +- if (vshRunConsole((const char *)obj->stringval) == 0) +- ret = TRUE; +- } else { +- vshPrintExtra(ctl, _("No console available for domain\n")); ++ ret = virExecNoPipe(ctl->conn, argv, &pid); ++ if (ret == -1) { ++ vshError(ctl, FALSE, _("Couldn't execute /usr/bin/virt-console.")); ++ return FALSE; + } +- xmlXPathFreeObject(obj); + +- cleanup: +- if (ctxt) +- xmlXPathFreeContext(ctxt); +- if (xml) +- xmlFreeDoc(xml); +- virDomainFree(dom); +- return ret; ++ waitpid(pid, NULL, 0); ++ ++ return TRUE; + } + + #else /* __MINGW32__ */ +--- libvirt-0.4.0/src/console.h 2007-12-07 07:00:48.000000000 -0800 ++++ /dev/null 2008-06-27 13:44:26.000000000 -0700 +@@ -1,49 +0,0 @@ +-/* +- * console.c: A dumb serial console client +- * +- * Copyright (C) 2007 Red Hat, Inc. +- * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2.1 of the License, or (at your option) any later version. +- * +- * This library 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 +- * Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public +- * License along with this library; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- * +- * Daniel Berrange +- */ +- +-#ifndef __VIR_CONSOLE_H__ +-#define __VIR_CONSOLE_H__ +- +-#ifndef __MINGW32__ +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +- int vshRunConsole(const char *tty); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* !__MINGW32__ */ +- +-#endif /* __VIR_CONSOLE_H__ */ +- +-/* +- * Local variables: +- * indent-tabs-mode: nil +- * c-indent-level: 4 +- * c-basic-offset: 4 +- * tab-width: 4 +- * End: +- */ +--- libvirt-0.4.0/src/console.c 2007-12-07 07:00:48.000000000 -0800 ++++ /dev/null 2008-06-27 13:44:38.000000000 -0700 +@@ -1,207 +0,0 @@ +-/* +- * console.c: A dumb serial console client +- * +- * Copyright (C) 2007 Red Hat, Inc. +- * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2.1 of the License, or (at your option) any later version. +- * +- * This library 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 +- * Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public +- * License along with this library; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- * +- * Daniel Berrange +- */ +- +-#include "config.h" +- +-#ifndef __MINGW32__ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "console.h" +-#include "internal.h" +- +-/* ie Ctrl-] as per telnet */ +-#define CTRL_CLOSE_BRACKET '\35' +- +-static int got_signal = 0; +-static void do_signal(int sig ATTRIBUTE_UNUSED) { +- got_signal = 1; +-} +- +-#ifndef HAVE_CFMAKERAW +-static void +-cfmakeraw (struct termios *attr) +-{ +- attr->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP +- | INLCR | IGNCR | ICRNL | IXON); +- attr->c_oflag &= ~OPOST; +- attr->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); +- attr->c_cflag &= ~(CSIZE | PARENB); +- attr->c_cflag |= CS8; +-} +-#endif /* !HAVE_CFMAKERAW */ +- +-int vshRunConsole(const char *tty) { +- int ttyfd, ret = -1; +- struct termios ttyattr, rawattr; +- void (*old_sigquit)(int); +- void (*old_sigterm)(int); +- void (*old_sigint)(int); +- void (*old_sighup)(int); +- void (*old_sigpipe)(int); +- +- +- /* We do not want this to become the controlling TTY */ +- if ((ttyfd = open(tty, O_NOCTTY | O_RDWR)) < 0) { +- fprintf(stderr, _("unable to open tty %s: %s\n"), +- tty, strerror(errno)); +- return -1; +- } +- +- /* Put STDIN into raw mode so that stuff typed +- does not echo to the screen (the TTY reads will +- result in it being echoed back already), and +- also ensure Ctrl-C, etc is blocked, and misc +- other bits */ +- if (tcgetattr(STDIN_FILENO, &ttyattr) < 0) { +- fprintf(stderr, _("unable to get tty attributes: %s\n"), +- strerror(errno)); +- goto closetty; +- } +- +- rawattr = ttyattr; +- cfmakeraw(&rawattr); +- +- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) { +- fprintf(stderr, _("unable to set tty attributes: %s\n"), +- strerror(errno)); +- goto closetty; +- } +- +- +- /* Trap all common signals so that we can safely restore +- the original terminal settings on STDIN before the +- process exits - people don't like being left with a +- messed up terminal ! */ +- old_sigquit = signal(SIGQUIT, do_signal); +- old_sigterm = signal(SIGTERM, do_signal); +- old_sigint = signal(SIGINT, do_signal); +- old_sighup = signal(SIGHUP, do_signal); +- old_sigpipe = signal(SIGPIPE, do_signal); +- got_signal = 0; +- +- +- /* Now lets process STDIN & tty forever.... */ +- for (; !got_signal ;) { +- unsigned int i; +- struct pollfd fds[] = { +- { STDIN_FILENO, POLLIN, 0 }, +- { ttyfd, POLLIN, 0 }, +- }; +- +- /* Wait for data to be available for reading on +- STDIN or the tty */ +- if (poll(fds, (sizeof(fds)/sizeof(struct pollfd)), -1) < 0) { +- if (got_signal) +- goto cleanup; +- +- if (errno == EINTR || errno == EAGAIN) +- continue; +- +- fprintf(stderr, _("failure waiting for I/O: %s\n"), +- strerror(errno)); +- goto cleanup; +- } +- +- for (i = 0 ; i < (sizeof(fds)/sizeof(struct pollfd)) ; i++) { +- if (!fds[i].revents) +- continue; +- +- /* Process incoming data available for read */ +- if (fds[i].revents & POLLIN) { +- char buf[4096]; +- int got, sent = 0, destfd; +- +- if ((got = read(fds[i].fd, buf, sizeof(buf))) < 0) { +- fprintf(stderr, _("failure reading input: %s\n"), +- strerror(errno)); +- goto cleanup; +- } +- +- /* Quit if end of file, or we got the Ctrl-] key */ +- if (!got || +- (got == 1 && +- buf[0] == CTRL_CLOSE_BRACKET)) +- goto done; +- +- /* Data from stdin goes to the TTY, +- data from the TTY goes to STDOUT */ +- if (fds[i].fd == STDIN_FILENO) +- destfd = ttyfd; +- else +- destfd = STDOUT_FILENO; +- +- while (sent < got) { +- int done; +- if ((done = write(destfd, buf + sent, got - sent)) <= 0) { +- fprintf(stderr, _("failure writing output: %s\n"), +- strerror(errno)); +- goto cleanup; +- } +- sent += done; +- } +- } else { /* Any other flag from poll is an error condition */ +- goto cleanup; +- } +- } +- } +- done: +- ret = 0; +- +- cleanup: +- +- /* Restore original signal handlers */ +- signal(SIGQUIT, old_sigpipe); +- signal(SIGQUIT, old_sighup); +- signal(SIGQUIT, old_sigint); +- signal(SIGQUIT, old_sigterm); +- signal(SIGQUIT, old_sigquit); +- +- /* Put STDIN back into the (sane?) state we found +- it in before starting */ +- tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr); +- +- closetty: +- close(ttyfd); +- +- return ret; +-} +- +-#endif /* !__MINGW32__ */ +- +-/* +- * Local variables: +- * indent-tabs-mode: nil +- * c-indent-level: 4 +- * c-basic-offset: 4 +- * tab-width: 4 +- * End: +- */ +--- /dev/null 2008-06-30 17:03:12.000000000 -0700 ++++ libvirt-new/src/virt-console.c 2008-06-30 16:58:36.079071463 -0700 +@@ -0,0 +1,612 @@ ++/* ++ * virt-console: client for connecting to domain consoles. ++ * ++ * Copyright (C) 2007 Red Hat, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Daniel Berrange ++ * ++ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "internal.h" ++ ++/* ie Ctrl-] as per telnet */ ++#define CTRL_CLOSE_BRACKET '\35' ++ ++static int got_signal; ++static int verbose; ++static const char *dom_name; ++static const char *conn_name; ++ ++static void ++do_signal(int sig ATTRIBUTE_UNUSED) ++{ ++ got_signal = 1; ++} ++ ++#ifndef HAVE_CFMAKERAW ++static void ++cfmakeraw(struct termios *attr) ++{ ++ attr->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP ++ | INLCR | IGNCR | ICRNL | IXON); ++ attr->c_oflag &= ~OPOST; ++ attr->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); ++ attr->c_cflag &= ~(CSIZE | PARENB); ++ attr->c_cflag |= CS8; ++ ++#ifdef __sun ++ attr->c_cc[VMIN] = 0; ++ attr->c_cc[VTIME] = 0; ++#endif ++} ++#endif /* !HAVE_CFMAKERAW */ ++ ++#ifdef __sun ++#include ++ ++#define PU_RESETGROUPS 0x0001 /* Remove supplemental groups */ ++#define PU_LIMITPRIVS 0x0002 /* L=P */ ++#define PU_INHERITPRIVS 0x0004 /* I=P */ ++#define PU_CLEARLIMITSET 0x0008 /* L=0 */ ++ ++extern int __init_suid_priv(int, ...); ++extern int __priv_bracket(priv_op_t); ++ ++#ifndef PRIV_XVM_CONTROL ++#define PRIV_XVM_CONTROL ((const char *)"xvm_control") ++#endif ++#ifndef PRIV_VIRT_MANAGE ++#define PRIV_VIRT_MANAGE ((const char *)"virt_manage") ++#endif ++ ++/* ++ * Verify that the real user invoking this setuid-root executable has ++ * the needed privilege, then drop root and all the privileges we don't ++ * need before continuing. ++ */ ++static void ++setup_perms(void) ++{ ++ if (seteuid(getuid()) == -1) { ++ perror("seteuid failed"); ++ exit(1); ++ } ++ ++ if (!priv_ineffect(PRIV_VIRT_MANAGE)) { ++ fprintf(stderr, "virt-console: permission denied\n"); ++ exit(1); ++ } ++ ++ if (seteuid(0) == -1) { ++ perror("seteuid failed"); ++ exit(1); ++ } ++ ++ /* ++ * We need to be able to talk to libvirt and open pty's. ++ */ ++ __init_suid_priv(PU_RESETGROUPS | PU_CLEARLIMITSET, ++ PRIV_VIRT_MANAGE, PRIV_FILE_DAC_READ, ++ PRIV_FILE_DAC_WRITE, NULL); ++} ++ ++#else ++#define setup_perms ++#define __priv_bracket ++#endif ++ ++static void ++usage(int exitval) ++{ ++ FILE *f = stderr; ++ ++ if (exitval == EXIT_SUCCESS) ++ f = stdout; ++ ++ fprintf(f, _("usage: virt-console [options] domain\n\n" ++ " options:\n" ++ " -c | --connect hypervisor connection URI\n" ++ " -h | --help this help\n" ++ " -v | --verbose be verbose\n\n")); ++ ++ exit(exitval); ++} ++ ++static void ++parse_args(int argc, char *argv[]) ++{ ++ int idx = 0; ++ int arg; ++ ++ struct option opt[] = { ++ { "connect", 1, 0, 'c' }, ++ { "help", 0, 0, 'h' }, ++ { "verbose", 0, 0, 'v' }, ++ { 0, 0, 0, 0 } ++ }; ++ ++ while ((arg = getopt_long(argc, argv, "c:hv", opt, &idx)) != -1) { ++ switch (arg) { ++ case 'c': ++ conn_name = optarg; ++ break; ++ case 'h': ++ usage(EXIT_SUCCESS); ++ break; ++ case 'v': ++ verbose = 1; ++ break; ++ default: ++ usage(EXIT_FAILURE); ++ break; ++ } ++ } ++ ++ if ((argc - optind) != 1) ++ usage(EXIT_FAILURE); ++ ++ dom_name = argv[optind]; ++ ++ if (conn_name == NULL) ++ conn_name = getenv("VIRSH_DEFAULT_CONNECT_URI"); ++} ++ ++static int ++get_domain(virConnectPtr *conn, virDomainPtr *dom, ++ virDomainInfo *info, int lookup_by_id) ++{ ++ int ret = 0; ++ int id; ++ ++ __priv_bracket(PRIV_ON); ++ ++ *conn = virConnectOpenAuth(conn_name, virConnectAuthPtrDefault, 0); ++ if (*conn == NULL) { ++ fprintf(stderr, _("Failed to connect to the hypervisor")); ++ exit(EXIT_FAILURE); ++ } ++ ++ *dom = virDomainLookupByName(*conn, dom_name); ++ ++ if (*dom == NULL) ++ *dom = virDomainLookupByUUIDString(*conn, dom_name); ++ if (*dom == NULL && lookup_by_id && ++ xstrtol_i(dom_name, NULL, 10, &id) == 0 && id >= 0) ++ *dom = virDomainLookupByID(*conn, id); ++ ++ if (*dom == NULL) ++ goto out; ++ ++ if (info != NULL) { ++ if (virDomainGetInfo(*dom, info) < 0) ++ goto out; ++ } ++ ++ ret = 1; ++ ++out: ++ if (ret == 0) { ++ if (*dom != NULL) ++ virDomainFree(*dom); ++ virConnectClose(conn); ++ } ++ __priv_bracket(PRIV_OFF); ++ return ret; ++} ++ ++static void ++put_domain(virConnectPtr conn, virDomainPtr dom) ++{ ++ __priv_bracket(PRIV_ON); ++ if (dom != NULL) ++ virDomainFree(dom); ++ virConnectClose(conn); ++ __priv_bracket(PRIV_OFF); ++} ++ ++static char * ++get_domain_tty(void) ++{ ++ xmlXPathContextPtr ctxt = NULL; ++ xmlXPathObjectPtr obj = NULL; ++ xmlDocPtr xml = NULL; ++ virConnectPtr conn = NULL; ++ virDomainPtr dom = NULL; ++ char *doc = NULL; ++ char *tty = NULL; ++ ++ if (!get_domain(&conn, &dom, NULL, 1)) { ++ fprintf(stderr, _("Couldn't find domain \"%s\".\n"), dom_name); ++ exit(EXIT_FAILURE); ++ } ++ ++ __priv_bracket(PRIV_ON); ++ doc = virDomainGetXMLDesc(dom, 0); ++ __priv_bracket(PRIV_OFF); ++ ++ put_domain(conn, dom); ++ conn = NULL; ++ dom = NULL; ++ ++ if (doc == NULL) ++ goto cleanup; ++ ++ xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL, ++ XML_PARSE_NOENT | XML_PARSE_NONET | ++ XML_PARSE_NOWARNING); ++ if (xml == NULL) ++ goto cleanup; ++ ++ ctxt = xmlXPathNewContext(xml); ++ if (ctxt == NULL) ++ goto cleanup; ++ ++ obj = xmlXPathEval(BAD_CAST "string(/domain/devices/console/@tty)", ctxt); ++ if (obj == NULL) ++ goto cleanup; ++ if (obj->type != XPATH_STRING) ++ goto cleanup; ++ if (!obj->stringval || obj->stringval[0] == '\0') ++ goto cleanup; ++ ++ tty = strdup((const char *)obj->stringval); ++ ++cleanup: ++ if (obj != NULL) ++ xmlXPathFreeObject(obj); ++ free(doc); ++ if (ctxt != NULL) ++ xmlXPathFreeContext(ctxt); ++ if (xml != NULL) ++ xmlFreeDoc(xml); ++ return tty; ++} ++ ++static int ++domain_is_running(void) ++{ ++ virConnectPtr conn = NULL; ++ virDomainPtr dom = NULL; ++ virDomainInfo info; ++ int ret = -1; ++ ++ if (!get_domain(&conn, &dom, &info, 1)) ++ return -1; ++ ++ switch (info.state) { ++ case VIR_DOMAIN_RUNNING: ++ case VIR_DOMAIN_BLOCKED: ++ case VIR_DOMAIN_PAUSED: ++ ret = 1; ++ break; ++ ++ case VIR_DOMAIN_NOSTATE: ++ case VIR_DOMAIN_CRASHED: ++ case VIR_DOMAIN_SHUTDOWN: ++ case VIR_DOMAIN_SHUTOFF: ++ ret = 0; ++ break; ++ ++ default: ++ break; ++ } ++ ++ put_domain(conn, dom); ++ return ret; ++} ++ ++static int ++check_for_reboot(void) ++{ ++ virConnectPtr conn = NULL; ++ virDomainPtr dom = NULL; ++ virDomainInfo info; ++ int tries = 0; ++ int ret = 0; ++ ++retry: ++ if (dom != NULL) ++ put_domain(conn, dom); ++ ++ /* ++ * Domain ID will vary across reboot, so don't lookup by a given ID. ++ */ ++ if (!get_domain(&conn, &dom, &info, 0)) ++ return 0; ++ ++ switch (info.state) { ++ case VIR_DOMAIN_RUNNING: ++ case VIR_DOMAIN_BLOCKED: ++ case VIR_DOMAIN_PAUSED: ++ ret = 1; ++ goto out; ++ break; ++ ++ case VIR_DOMAIN_CRASHED: ++ if (verbose) ++ fprintf(stderr, _("Domain \"%s\" has crashed."), dom_name); ++ goto out; ++ break; ++ ++ case VIR_DOMAIN_NOSTATE: ++ default: ++ break; ++ ++ case VIR_DOMAIN_SHUTDOWN: ++ if (verbose) ++ fprintf(stderr, _("Domain \"%s\" is shutting down.\n"), dom_name); ++ tries = 0; ++ break; ++ ++ case VIR_DOMAIN_SHUTOFF: ++ if (verbose) ++ fprintf(stderr, _("Domain \"%s\" has shut down."), dom_name); ++ goto out; ++ break; ++ } ++ ++ tries++; ++ if (tries == 1) { ++ goto retry; ++ } else if (tries == 2) { ++ sleep(1); ++ goto retry; ++ } ++ ++out: ++ put_domain(conn, dom); ++ return ret; ++} ++ ++static int ++open_tty(void) ++{ ++ char *tty; ++ int ttyfd; ++ ++ if ((tty = get_domain_tty()) == NULL) { ++ if (domain_is_running() != 1) { ++ fprintf(stderr, _("Domain \"%s\" is not running.\n"), dom_name); ++ exit(EXIT_FAILURE); ++ } ++ ++ fprintf(stderr, ++ _("Couldn't get console for domain \"%s\"\n"), dom_name); ++ exit(EXIT_FAILURE); ++ } ++ ++ __priv_bracket(PRIV_ON); ++ if ((ttyfd = open(tty, O_NOCTTY | O_RDWR)) < 0) { ++ fprintf(stderr, _("Unable to open tty %s: %s\n"), ++ tty, strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (lockf(ttyfd, F_TLOCK, 0) == -1) { ++ if (errno == EACCES || errno == EAGAIN) { ++ fprintf(stderr, ++ _("Console for domain \"%s\" is in use.\n"), dom_name); ++ } else { ++ fprintf(stderr, _("Unable to lock tty %s: %s\n"), ++ tty, strerror(errno)); ++ } ++ exit(EXIT_FAILURE); ++ } ++ __priv_bracket(PRIV_OFF); ++ ++ free(tty); ++ ++ return ttyfd; ++} ++ ++static void ++close_tty(int ttyfd) ++{ ++ lockf(ttyfd, F_ULOCK, 0); ++ close(ttyfd); ++} ++ ++int ++main(int argc, char *argv[]) ++{ ++ struct termios ttyattr, rawattr; ++ void (*old_sigquit)(int); ++ void (*old_sigterm)(int); ++ void (*old_sigint)(int); ++ void (*old_sighup)(int); ++ void (*old_sigpipe)(int); ++ int ret = EXIT_FAILURE; ++ int retrying = 0; ++ int ttyfd; ++ ++ setup_perms(); ++ ++ if (!setlocale(LC_ALL, "")) { ++ perror("setlocale"); ++ return -1; ++ } ++ ++ if (!bindtextdomain(GETTEXT_PACKAGE, LOCALEBASEDIR)) { ++ perror("bindtextdomain"); ++ return -1; ++ } ++ ++ if (!textdomain(GETTEXT_PACKAGE)) { ++ perror("textdomain"); ++ return -1; ++ } ++ ++ parse_args(argc, argv); ++ ++ /* Trap all common signals so that we can safely restore ++ the original terminal settings on STDIN before the ++ process exits - people don't like being left with a ++ messed up terminal ! */ ++ old_sigquit = signal(SIGQUIT, do_signal); ++ old_sigterm = signal(SIGTERM, do_signal); ++ old_sigint = signal(SIGINT, do_signal); ++ old_sighup = signal(SIGHUP, do_signal); ++ old_sigpipe = signal(SIGPIPE, do_signal); ++ ++retry: ++ ++ ttyfd = open_tty(); ++ ++ if (!retrying && verbose) { ++ printf("Connected to domain %s\n", dom_name); ++ printf("Escape character is '^]'\n"); ++ } ++ ++ if (tcgetattr(STDIN_FILENO, &ttyattr) < 0) { ++ fprintf(stderr, _("Unable to get tty attributes: %s\n"), ++ strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ rawattr = ttyattr; ++ cfmakeraw(&rawattr); ++ ++ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) { ++ fprintf(stderr, _("Unable to set tty attributes: %s\n"), ++ strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ ++ /* Now lets process STDIN & tty forever.... */ ++ for (; !got_signal ;) { ++ unsigned int i; ++ struct pollfd fds[] = { ++ { STDIN_FILENO, POLLIN, 0 }, ++ { ttyfd, POLLIN, 0 }, ++ }; ++ ++ /* Wait for data to be available for reading on ++ STDIN or the tty */ ++ if (poll(fds, (sizeof(fds)/sizeof(struct pollfd)), -1) < 0) { ++ if (got_signal) ++ goto cleanup; ++ ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ ++ fprintf(stderr, _("Failure waiting for I/O: %s\n"), ++ strerror(errno)); ++ goto cleanup; ++ } ++ ++ for (i = 0 ; i < (sizeof(fds)/sizeof(struct pollfd)) ; i++) { ++ if (!fds[i].revents) ++ continue; ++ ++ /* Process incoming data available for read */ ++ if (fds[i].revents & POLLIN) { ++ char buf[4096]; ++ int got, sent = 0, destfd; ++ ++ if ((got = read(fds[i].fd, buf, sizeof(buf))) < 0) { ++ fprintf(stderr, _("Failure reading input: %s\n"), ++ strerror(errno)); ++ goto cleanup; ++ } ++ ++ if (!got) { ++ tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr); ++ if (!check_for_reboot()) ++ goto done; ++ close_tty(ttyfd); ++ retrying = 1; ++ goto retry; ++ } ++ ++ if (got == 1 && buf[0] == CTRL_CLOSE_BRACKET) ++ goto done; ++ ++ /* Data from stdin goes to the TTY, ++ data from the TTY goes to STDOUT */ ++ if (fds[i].fd == STDIN_FILENO) ++ destfd = ttyfd; ++ else ++ destfd = STDOUT_FILENO; ++ ++ while (sent < got) { ++ int done; ++ if ((done = write(destfd, buf + sent, got - sent)) <= 0) { ++ fprintf(stderr, _("Failure writing output: %s\n"), ++ strerror(errno)); ++ goto cleanup; ++ } ++ sent += done; ++ } ++ } else if (fds[i].revents & POLLHUP) { ++ tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr); ++ if (!check_for_reboot()) ++ goto done; ++ close_tty(ttyfd); ++ retrying = 1; ++ goto retry; ++ } else { /* Any other flag from poll is an error condition */ ++ goto cleanup; ++ } ++ } ++ } ++ ++done: ++ ret = EXIT_SUCCESS; ++cleanup: ++ tcsetattr(STDIN_FILENO, TCSANOW, &ttyattr); ++ close_tty(ttyfd); ++ ++ /* Restore original signal handlers */ ++ signal(SIGQUIT, old_sigpipe); ++ signal(SIGQUIT, old_sighup); ++ signal(SIGQUIT, old_sigint); ++ signal(SIGQUIT, old_sigterm); ++ signal(SIGQUIT, old_sigquit); ++ ++ if (verbose) ++ printf("\nConnection to domain %s closed.\n", dom_name); ++ ++ exit(ret); ++} ++ ++/* ++ * Local variables: ++ * indent-tabs-mode: nil ++ * c-indent-level: 4 ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * End: ++ */