[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] Fix xenconsole's "Could not read tty from store"
On Wed, Dec 19, 2007 at 12:00:25PM +0000, Samuel Thibault wrote: > > > To my understanding, from the server side tcsetattr should only be > > > performed on the master side (with effect on the slave side too). > > > > Here's another try, what does this do on Linux? > > That one seems to work fine. Excellent. Keir, can you apply? cheers john # HG changeset patch # User john.levon@xxxxxxx # Date 1198003657 28800 # Node ID 6f03f4ec458d4780314c015da214795b7b1cf195 # Parent 539cbabd97b5ff3d335de151636040bb2f4cd629 Fix master/slave handling in xenconsoled and qemu Fix a number of problems with the pty handling: - make openpty() implementation work on Solaris - set raw on the slave fd, not the master, as the master doesn't have a line discipline pushed on Solaris - make sure we don't leak the slave fd returned from openpty() - don't use the 'name' argument of openpty() as it's a security risk - note behaviour of a zero read of the master on Solaris - remove pointless tcget/setattr Signed-off-by: John Levon <john.levon@xxxxxxx> Signed-off-by: Samuel Thibault <samuel.thibault@xxxxxxxxxx> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -36,10 +36,14 @@ #include <stdarg.h> #include <sys/mman.h> #include <sys/time.h> +#include <assert.h> #if defined(__NetBSD__) || defined(__OpenBSD__) #include <util.h> #elif defined(__linux__) || defined(__Linux__) #include <pty.h> +#endif +#if defined(__sun__) +#include <stropts.h> #endif #define MAX(a, b) (((a) > (b)) ? (a) : (b)) @@ -75,7 +79,8 @@ struct domain struct domain { int domid; - int tty_fd; + int master_fd; + int slave_fd; int log_fd; bool is_dead; struct buffer buffer; @@ -227,77 +232,90 @@ static int create_domain_log(struct doma return fd; } +static void domain_close_tty(struct domain *dom) +{ + if (dom->master_fd != -1) { + close(dom->master_fd); + dom->master_fd = -1; + } + + if (dom->slave_fd != -1) { + close(dom->slave_fd); + dom->slave_fd = -1; + } +} + #ifdef __sun__ /* Once Solaris has openpty(), this is going to be removed. */ -int openpty(int *amaster, int *aslave, char *name, - struct termios *termp, struct winsize *winp) +static int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) { - int mfd, sfd; + const char *slave; + int mfd = -1, sfd = -1; *amaster = *aslave = -1; - mfd = sfd = -1; mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (mfd < 0) - goto err0; + goto err; if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) - goto err1; + goto err; - /* This does not match openpty specification, - * but as long as this does not hurt, this is acceptable. - */ - mfd = sfd; + if ((slave = ptsname(mfd)) == NULL) + goto err; - if (termp != NULL && tcgetattr(sfd, termp) < 0) - goto err1; + if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) + goto err; + + if (ioctl(sfd, I_PUSH, "ptem") == -1) + goto err; if (amaster) *amaster = mfd; if (aslave) *aslave = sfd; - if (name) - strlcpy(name, ptsname(mfd), sizeof(slave)); if (winp) ioctl(sfd, TIOCSWINSZ, winp); + assert(name == NULL); + assert(termp == NULL); + return 0; -err1: +err: + if (sfd != -1) + close(sfd); close(mfd); -err0: return -1; } #endif - static int domain_create_tty(struct domain *dom) { - char slave[80]; - struct termios term; + const char *slave; char *path; - int master, slavefd; int err; bool success; char *data; unsigned int len; - if (openpty(&master, &slavefd, slave, &term, NULL) < 0) { - master = -1; + assert(dom->slave_fd == -1); + assert(dom->master_fd == -1); + + if (openpty(&dom->master_fd, &dom->slave_fd, NULL, NULL, NULL) < 0) { err = errno; dolog(LOG_ERR, "Failed to create tty for domain-%d (errno = %i, %s)", dom->domid, err, strerror(err)); - return master; + return 0; } - cfmakeraw(&term); - if (tcsetattr(master, TCSAFLUSH, &term) < 0) { + if ((slave = ptsname(dom->master_fd)) == NULL) { err = errno; - dolog(LOG_ERR, "Failed to set tty attribute for domain-%d (errno = %i, %s)", + dolog(LOG_ERR, "Failed to get slave name for domain-%d (errno = %i, %s)", dom->domid, err, strerror(err)); goto out; } - if (dom->use_consolepath) { success = asprintf(&path, "%s/limit", dom->conspath) != @@ -340,15 +358,15 @@ static int domain_create_tty(struct doma goto out; } - if (fcntl(master, F_SETFL, O_NONBLOCK) == -1) + if (fcntl(dom->master_fd, F_SETFL, O_NONBLOCK) == -1) goto out; - return master; - out: - close(master); - return -1; + return 1; +out: + domain_close_tty(dom); + return 0; } - + /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ int xs_gather(struct xs_handle *xs, const char *dir, ...) { @@ -454,10 +472,8 @@ static int domain_create_ring(struct dom dom->local_port = rc; dom->remote_port = remote_port; - if (dom->tty_fd == -1) { - dom->tty_fd = domain_create_tty(dom); - - if (dom->tty_fd == -1) { + if (dom->master_fd == -1) { + if (!domain_create_tty(dom)) { err = errno; xc_evtchn_close(dom->xce_handle); dom->xce_handle = -1; @@ -535,7 +551,8 @@ static struct domain *create_domain(int dom->conspath = s; strcat(dom->conspath, "/console"); - dom->tty_fd = -1; + dom->master_fd = -1; + dom->slave_fd = -1; dom->log_fd = -1; dom->is_dead = false; @@ -597,14 +614,7 @@ static void remove_domain(struct domain static void cleanup_domain(struct domain *d) { - if (d->tty_fd != -1) { - close(d->tty_fd); - d->tty_fd = -1; - } - if (d->log_fd != -1) { - close(d->log_fd); - d->log_fd = -1; - } + domain_close_tty(d); free(d->buffer.data); d->buffer.data = NULL; @@ -683,13 +693,17 @@ static void handle_tty_read(struct domai if (len > sizeof(msg)) len = sizeof(msg); - len = read(dom->tty_fd, msg, len); - if (len < 1) { - close(dom->tty_fd); - dom->tty_fd = -1; + len = read(dom->master_fd, msg, len); + /* + * Note: on Solaris, len == 0 means the slave closed, and this + * is no problem, but Linux can't handle this usefully, so we + * keep the slave open for the duration. + */ + if (len < 0) { + domain_close_tty(dom); if (domain_is_valid(dom->domid)) { - dom->tty_fd = domain_create_tty(dom); + domain_create_tty(dom); } else { shutdown_domain(dom); } @@ -703,8 +717,7 @@ static void handle_tty_read(struct domai intf->in_prod = prod; xc_evtchn_notify(dom->xce_handle, dom->local_port); } else { - close(dom->tty_fd); - dom->tty_fd = -1; + domain_close_tty(dom); shutdown_domain(dom); } } @@ -716,17 +729,16 @@ static void handle_tty_write(struct doma if (dom->is_dead) return; - len = write(dom->tty_fd, dom->buffer.data + dom->buffer.consumed, + len = write(dom->master_fd, dom->buffer.data + dom->buffer.consumed, dom->buffer.size - dom->buffer.consumed); if (len < 1) { dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n", dom->domid, len, errno); - close(dom->tty_fd); - dom->tty_fd = -1; + domain_close_tty(dom); if (domain_is_valid(dom->domid)) { - dom->tty_fd = domain_create_tty(dom); + domain_create_tty(dom); } else { shutdown_domain(dom); } @@ -895,13 +907,13 @@ void handle_io(void) max_fd = MAX(evtchn_fd, max_fd); } - if (d->tty_fd != -1) { + if (d->master_fd != -1) { if (!d->is_dead && ring_free_bytes(d)) - FD_SET(d->tty_fd, &readfds); + FD_SET(d->master_fd, &readfds); if (!buffer_empty(&d->buffer)) - FD_SET(d->tty_fd, &writefds); - max_fd = MAX(d->tty_fd, max_fd); + FD_SET(d->master_fd, &writefds); + max_fd = MAX(d->master_fd, max_fd); } } @@ -951,10 +963,10 @@ void handle_io(void) handle_ring_read(d); } - if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &readfds)) + if (d->master_fd != -1 && FD_ISSET(d->master_fd, &readfds)) handle_tty_read(d); - if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &writefds)) + if (d->master_fd != -1 && FD_ISSET(d->master_fd, &writefds)) handle_tty_write(d); if (d->is_dead) diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -65,6 +65,9 @@ #include <linux/rtc.h> #include <linux/ppdev.h> #endif +#endif +#if defined(__sun__) +#include <stropts.h> #endif #endif @@ -1801,7 +1804,65 @@ static int store_dev_info(char *devName, return 0; } -#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) +#ifdef __sun__ +/* Once Solaris has openpty(), this is going to be removed. */ +int openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + const char *slave; + int mfd = -1, sfd = -1; + + *amaster = *aslave = -1; + + mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); + if (mfd < 0) + goto err; + + if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) + goto err; + + if ((slave = ptsname(mfd)) == NULL) + goto err; + + if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) + goto err; + + if (ioctl(sfd, I_PUSH, "ptem") == -1 || + (termp != NULL && tcgetattr(sfd, termp) < 0)) + goto err; + + if (amaster) + *amaster = mfd; + if (aslave) + *aslave = sfd; + if (winp) + ioctl(sfd, TIOCSWINSZ, winp); + + return 0; + +err: + if (sfd != -1) + close(sfd); + close(mfd); + return -1; +} + +void cfmakeraw (struct termios *termios_p) +{ + termios_p->c_iflag &= + ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + termios_p->c_oflag &= ~OPOST; + termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + termios_p->c_cflag &= ~(CSIZE|PARENB); + termios_p->c_cflag |= CS8; + + termios_p->c_cc[VMIN] = 0; + termios_p->c_cc[VTIME] = 0; +} + +#endif + +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun__) static CharDriverState *qemu_chr_open_pty(void) { struct termios tty; @@ -1816,6 +1877,8 @@ static CharDriverState *qemu_chr_open_pt cfmakeraw(&tty); tcsetattr(slave_fd, TCSAFLUSH, &tty); + close(slave_fd); + fprintf(stderr, "char device redirected to %s\n", ptsname(master_fd)); return qemu_chr_open_fd(master_fd, master_fd); @@ -2038,7 +2101,7 @@ static CharDriverState *qemu_chr_open_pt { return NULL; } -#endif /* __linux__ || __NetBSD__ || __OpenBSD__ */ +#endif /* __linux__ || __NetBSD__ || __OpenBSD__ || __sun__ */ #endif /* !defined(_WIN32) */ _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |