diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2015-01-21 17:28:00 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2015-01-21 17:28:00 +0000 |
commit | cc26e14e3ce92f68b1b3936bb0353c03610ce401 (patch) | |
tree | 2b40e151dc4b657db732482d618d780ae6d80551 | |
parent | 7b0ecf805907cc301e42e70ced9b500ab3b0a079 (diff) | |
download | illumos-joyent-cc26e14e3ce92f68b1b3936bb0353c03610ce401.tar.gz |
OS-3727 Would like to be able to selectively close descriptors when using zlogin -I
-rw-r--r-- | usr/src/cmd/zlogin/zlogin.c | 41 | ||||
-rw-r--r-- | usr/src/cmd/zoneadmd/zfd.c | 181 |
2 files changed, 167 insertions, 55 deletions
diff --git a/usr/src/cmd/zlogin/zlogin.c b/usr/src/cmd/zlogin/zlogin.c index b44e0c96b7..a58ef72102 100644 --- a/usr/src/cmd/zlogin/zlogin.c +++ b/usr/src/cmd/zlogin/zlogin.c @@ -282,7 +282,7 @@ get_interactive_master(const char *zname, int notcons) } if (notcons) { - sock_str = "%s/%s.server_sock"; + sock_str = "%s/%s.server_out"; } else { sock_str = "%s/%s.console_sock"; } @@ -351,6 +351,37 @@ bad: return (-1); } +/* + * Create the unix domain stderr socket and connect to the zoneadmd server. + */ +static int +get_interactive_stderr(const char *zname) +{ + int sockfd = -1; + struct sockaddr_un servaddr; + char *sock_str; + + if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + zperror(gettext("could not create socket")); + return (-1); + } + + sock_str = "%s/%s.server_err"; + + bzero(&servaddr, sizeof (servaddr)); + servaddr.sun_family = AF_UNIX; + (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path), + sock_str, ZONES_TMPDIR, zname); + + if (connect(sockfd, (struct sockaddr *)&servaddr, + sizeof (servaddr)) == -1) { + zperror(gettext("Could not connect to zone's stderr")); + (void) close(sockfd); + return (-1); + } + + return (sockfd); +} /* * Routines to handle pty creation upon zone entry and to shuttle I/O back @@ -2033,6 +2064,8 @@ main(int argc, char **argv) * the rest of the code; handle it first. */ if (console) { + int gz_stderr_fd = -1; + /* * Ensure that zoneadmd for this zone is running. */ @@ -2045,6 +2078,10 @@ main(int argc, char **argv) if (get_interactive_master(zonename, imode) == -1) return (1); + if (imode) { + gz_stderr_fd = get_interactive_stderr(zonename); + } + if (!quiet) { if (imode) (void) printf(gettext("[Connected to zone '%s' " @@ -2066,7 +2103,7 @@ main(int argc, char **argv) /* * Run the I/O loop until we get disconnected. */ - doio(masterfd, -1, masterfd, -1, -1, B_FALSE); + doio(masterfd, -1, masterfd, gz_stderr_fd, -1, B_FALSE); if (!imode) reset_tty(); if (!quiet) { diff --git a/usr/src/cmd/zoneadmd/zfd.c b/usr/src/cmd/zoneadmd/zfd.c index b75de81ce6..49e4215654 100644 --- a/usr/src/cmd/zoneadmd/zfd.c +++ b/usr/src/cmd/zoneadmd/zfd.c @@ -84,7 +84,7 @@ static int eventstream[2] = {-1, -1}; #define ZLOG_MODE "zlog-mode" #define ZFDNEX_DEVTREEPATH "/pseudo/zfdnex@2" #define ZFDNEX_FILEPATH "/devices/pseudo/zfdnex@2" -#define SERVER_SOCKPATH ZONES_TMPDIR "/%s.server_sock" +#define SERVER_SOCKPATH ZONES_TMPDIR "/%s.server_%s" #define ZTTY_RETRY 5 typedef enum { @@ -383,48 +383,78 @@ error: } static int -init_server_sock(zlog_t *zlogp) +init_server_socks(zlog_t *zlogp, int *stdoutfd, int *stderrfd) { - int servfd; + int outfd = -1, errfd = -1; struct sockaddr_un servaddr; bzero(&servaddr, sizeof (servaddr)); servaddr.sun_family = AF_UNIX; (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path), - SERVER_SOCKPATH, zone_name); + SERVER_SOCKPATH, zone_name, "out"); - if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + if ((outfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { zerror(zlogp, B_TRUE, "server setup: could not create socket"); - return (-1); + goto err; } (void) unlink(servaddr.sun_path); - if (bind(servfd, (struct sockaddr *)&servaddr, - sizeof (servaddr)) == -1) { + if (bind(outfd, (struct sockaddr *)&servaddr, sizeof (servaddr)) + == -1) { zerror(zlogp, B_TRUE, "server setup: could not bind to socket"); - goto out; + goto err; } - if (listen(servfd, 4) == -1) { + if (listen(outfd, 4) == -1) { zerror(zlogp, B_TRUE, "server setup: could not listen on socket"); - goto out; + goto err; } - return (servfd); -out: + bzero(&servaddr, sizeof (servaddr)); + servaddr.sun_family = AF_UNIX; + (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path), + SERVER_SOCKPATH, zone_name, "err"); + + if ((errfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + zerror(zlogp, B_TRUE, "server setup: could not create socket"); + goto err; + } (void) unlink(servaddr.sun_path); - (void) close(servfd); + + if (bind(errfd, (struct sockaddr *)&servaddr, sizeof (servaddr)) + == -1) { + zerror(zlogp, B_TRUE, + "server setup: could not bind to socket"); + goto err; + } + + if (listen(errfd, 4) == -1) { + zerror(zlogp, B_TRUE, + "server setup: could not listen on socket"); + goto err; + } + + *stdoutfd = outfd; + *stderrfd = errfd; + return (0); + +err: + (void) unlink(servaddr.sun_path); + if (outfd != -1) + (void) close(outfd); + if (errfd != -1) + (void) close(errfd); return (-1); } static void -destroy_server_sock(int servfd) +destroy_server_sock(int servfd, char *nm) { char path[MAXPATHLEN]; - (void) snprintf(path, sizeof (path), SERVER_SOCKPATH, zone_name); + (void) snprintf(path, sizeof (path), SERVER_SOCKPATH, zone_name, nm); (void) unlink(path); (void) shutdown(servfd, SHUT_RDWR); (void) close(servfd); @@ -506,12 +536,14 @@ accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len) connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen); if (connfd == -1) return (-1); - if (get_client_ident(connfd, pid, locale, locale_len) == -1) { - (void) shutdown(connfd, SHUT_RDWR); - (void) close(connfd); - return (-1); + if (pid != NULL) { + if (get_client_ident(connfd, pid, locale, locale_len) == -1) { + (void) shutdown(connfd, SHUT_RDWR); + (void) close(connfd); + return (-1); + } + (void) write(connfd, "OK\n", 3); } - (void) write(connfd, "OK\n", 3); flags = fcntl(connfd, F_GETFD, 0); if (flags != -1) @@ -571,7 +603,7 @@ escape_json(char *sbuf, int slen, char *dbuf, int dlen) bzero(&mbr, sizeof (mbr)); - sbuf[slen - 1] = '\0'; + sbuf[slen] = '\0'; i = 0; while (i < dlen && (sz = mbrtowc(&c, sbuf, MB_CUR_MAX, &mbr)) > 0) { switch (c) { @@ -683,12 +715,13 @@ wr_log_msg(char *buf, int len, int from) * to stdin, we won't get blocked. */ static void -do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) +do_zfd_io(int gzservfd, int gzerrfd, int stdinfd, int stdoutfd, int stderrfd) { - struct pollfd pollfds[5]; - char ibuf[BUFSIZ]; + struct pollfd pollfds[6]; + char ibuf[BUFSIZ + 1]; int cc, ret; int clifd = -1; + int clierrfd = -1; int pollerr = 0; char clilocale[MAXPATHLEN]; pid_t clipid = 0; @@ -706,20 +739,24 @@ do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) pollfds[2].fd = stderrfd; pollfds[2].events = pollfds[0].events; - /* the server socket; watch for events (new connections) */ - pollfds[3].fd = servfd; + /* the server stdin/out socket; watch for events (new connections) */ + pollfds[3].fd = gzservfd; pollfds[3].events = pollfds[0].events; - /* the eventstram; any input means the zone is halting */ - pollfds[4].fd = eventstream[1]; + /* the server stderr socket; watch for events (new connections) */ + pollfds[4].fd = gzerrfd; pollfds[4].events = pollfds[0].events; + /* the eventstream; any input means the zone is halting */ + pollfds[5].fd = eventstream[1]; + pollfds[5].events = pollfds[0].events; + while (!shutting_down) { pollfds[0].revents = pollfds[1].revents = 0; pollfds[2].revents = pollfds[3].revents = 0; - pollfds[4].revents = 0; + pollfds[4].revents = pollfds[5].revents = 0; - ret = poll(pollfds, 5, -1); + ret = poll(pollfds, 6, -1); if (ret == -1 && errno != EINTR) { zerror(zlogp, B_TRUE, "poll failed"); /* we are hosed, close connection */ @@ -760,13 +797,13 @@ do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) break; if (cc > 0) { wr_log_msg(ibuf, cc, 1); - } - /* - * Lose I/O if no one is listening, otherwise - * pass it on. - */ - if (clifd != -1 && cc > 0) { - (void) write(clifd, ibuf, cc); + + /* + * Lose output if no one is listening, + * otherwise pass it on. + */ + if (clifd != -1) + (void) write(clifd, ibuf, cc); } } else { pollerr = pollfds[1].revents; @@ -788,13 +825,14 @@ do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) break; if (cc > 0) { wr_log_msg(ibuf, cc, 2); - } - /* - * Lose I/O if no one is listening, otherwise - * pass it on. - */ - if (clifd != -1 && cc > 0) { - (void) write(clifd, ibuf, cc); + + /* + * Lose output if no one is listening, + * otherwise pass it on. + */ + if (clierrfd != -1) + (void) write(clierrfd, ibuf, + cc); } } else { pollerr = pollfds[2].revents; @@ -805,7 +843,7 @@ do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) } } - /* event from server socket */ + /* event from primary server stdin/out socket */ if (pollfds[3].revents && (pollfds[3].revents & (POLLIN | POLLRDNORM))) { if (clifd != -1) { @@ -822,9 +860,9 @@ do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) break; } /* we're already handling a client */ - reject_client(servfd, clipid); + reject_client(gzservfd, clipid); - } else if ((clifd = accept_client(servfd, &clipid, + } else if ((clifd = accept_client(gzservfd, &clipid, clilocale, sizeof (clilocale))) != -1) { pollfds[0].fd = clifd; @@ -833,13 +871,43 @@ do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) } } + /* connection event from server stderr socket */ + if (pollfds[4].revents && + (pollfds[4].revents & (POLLIN | POLLRDNORM))) { + if (clifd == -1) { + /* + * This shouldn't happen since the client is + * expected to connect on the primary socket + * first. If we see this, tear everything down + * and start over. + */ + zerror(zlogp, B_FALSE, "GZ zfd stderr " + "connection attempt with no GZ primary\n"); + break; + } + + assert(clierrfd == -1); + if ((clierrfd = accept_client(gzerrfd, NULL, NULL, 0)) + != -1) { + /* + * Once connected, we no longer poll on the + * gzerrfd since the CLI handshake takes place + * on the primary gzservfd. + */ + pollfds[4].fd = -1; + + } else { + break; + } + } + /* * Watch for events on the eventstream. This is how we get * notified of the zone halting, etc. It provides us a * "wakeup" from poll when important things happen, which * is good. */ - if (pollfds[4].revents) { + if (pollfds[5].revents) { break; } } @@ -848,6 +916,11 @@ do_zfd_io(int servfd, int stdinfd, int stdoutfd, int stderrfd) (void) shutdown(clifd, SHUT_RDWR); (void) close(clifd); } + + if (clierrfd != -1) { + (void) shutdown(clierrfd, SHUT_RDWR); + (void) close(clierrfd); + } } static int @@ -918,7 +991,8 @@ hup_handler(int i) static void srvr() { - int serverfd = -1; + int gzoutfd = -1; + int gzerrfd = -1; int stdinfd = -1; int stdoutfd = -1; int stderrfd = -1; @@ -946,7 +1020,7 @@ srvr() } while (!shutting_down) { - if ((serverfd = init_server_sock(zlogp)) == -1) { + if (init_server_socks(zlogp, &gzoutfd, &gzerrfd) == -1) { zerror(zlogp, B_FALSE, "server setup: socket initialization failed"); goto death; @@ -1002,9 +1076,10 @@ srvr() } } - do_zfd_io(serverfd, stdinfd, stdoutfd, stderrfd); + do_zfd_io(gzoutfd, gzerrfd, stdinfd, stdoutfd, stderrfd); death: - destroy_server_sock(serverfd); + destroy_server_sock(gzoutfd, "out"); + destroy_server_sock(gzerrfd, "err"); (void) close(stdinfd); (void) close(stdoutfd); |