diff --git a/.gitignore b/.gitignore index f6ddb00ef0..bccbd12016 100644 --- a/.gitignore +++ b/.gitignore @@ -100,6 +100,7 @@ tools/blktap2/vhd/vhd-update tools/blktap2/vhd/vhd-util tools/console/xenconsole tools/console/xenconsoled +tools/console/client/_paths.h tools/debugger/gdb/gdb-6.2.1-linux-i386-xen/* tools/debugger/gdb/gdb-6.2.1/* tools/debugger/gdb/gdb-6.2.1.tar.bz2 diff --git a/tools/console/Makefile b/tools/console/Makefile index 71f80880b1..77e8f299c0 100644 --- a/tools/console/Makefile +++ b/tools/console/Makefile @@ -21,6 +21,7 @@ all: $(BIN) clean: $(RM) *.a *.so *.o *.rpm $(BIN) $(DEPS) $(RM) client/*.o daemon/*.o + $(RM) client/_paths.h .PHONY: distclean distclean: clean @@ -28,9 +29,12 @@ distclean: clean xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c)) $(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_xenconsoled) $(APPEND_LDFLAGS) -xenconsole: $(patsubst %.c,%.o,$(wildcard client/*.c)) +xenconsole: client/_paths.h $(patsubst %.c,%.o,$(wildcard client/*.c)) $(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_xenconsole) $(APPEND_LDFLAGS) +genpath-target = $(call buildmakevars2header,client/_paths.h) +$(eval $(genpath-target)) + .PHONY: install install: $(BIN) $(INSTALL_DIR) $(DESTDIR)/$(sbindir) diff --git a/tools/console/client/main.c b/tools/console/client/main.c index 753b3aaab1..ff9ac7d104 100644 --- a/tools/console/client/main.c +++ b/tools/console/client/main.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*/ +#include #include +#include #include #include #include @@ -40,10 +42,13 @@ #include #include "xenctrl.h" +#include "_paths.h" #define ESCAPE_CHARACTER 0x1d static volatile sig_atomic_t received_signal = 0; +static char lockfile[sizeof (XEN_LOCK_DIR "/xenconsole.") + 8] = { 0 }; +static int lockfd = -1; static void sighandler(int signum) { @@ -267,6 +272,53 @@ static void restore_term_stdin(void) restore_term(STDIN_FILENO, &stdin_old_attr); } +/* The following locking strategy is based on that from + * libxl__domain_userdata_lock(), with the difference that we want to fail if we + * cannot acquire the lock rather than wait indefinitely. + */ +static void console_lock(int domid) +{ + struct stat stab, fstab; + int fd; + + snprintf(lockfile, sizeof lockfile, "%s%d", XEN_LOCK_DIR "/xenconsole.", domid); + + while (true) { + fd = open(lockfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) + err(errno, "Could not open %s", lockfile); + + while (flock(fd, LOCK_EX | LOCK_NB)) { + if (errno == EINTR) + continue; + else + err(errno, "Could not lock %s", lockfile); + } + if (fstat(fd, &fstab)) + err(errno, "Could not fstat %s", lockfile); + if (stat(lockfile, &stab)) { + if (errno != ENOENT) + err(errno, "Could not stat %s", lockfile); + } else { + if (stab.st_dev == fstab.st_dev && stab.st_ino == fstab.st_ino) + break; + } + + close(fd); + } + + lockfd = fd; + return; +} + +static void console_unlock(void) +{ + if (lockfile[0] && lockfd != -1) { + unlink(lockfile); + close(lockfd); + } +} + int main(int argc, char **argv) { struct termios attr; @@ -382,6 +434,9 @@ int main(int argc, char **argv) exit(EINVAL); } + console_lock(domid); + atexit(console_unlock); + /* Set a watch on this domain's console pty */ if (!xs_watch(xs, path, "")) err(errno, "Can't set watch for console pty");