Print this page
5700 add zlogin -d option to allow graceful disconnect when zone is halted
Reviewed by: Andrew Gabriel <illumos@cucumber.demon.co.uk>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>

@@ -21,10 +21,11 @@
 
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  * Copyright 2012 Joyent, Inc.  All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  */
 
 /*
  * Console support for zones requires a significant infrastructure.  The
  * core pieces are contained in this file, but other portions of note

@@ -507,11 +508,12 @@
  * Read the "ident" string from the client's descriptor; this routine also
  * tolerates being called with pid=NULL, for times when you want to "eat"
  * the ident string from a client without saving it.
  */
 static int
-get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len)
+get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
+        int *disconnect)
 {
         char buf[BUFSIZ], *bufp;
         size_t buflen = sizeof (buf);
         char c = '\0';
         int i = 0, r;

@@ -547,11 +549,12 @@
                         if (c == '\n')
                                 break;
         }
 
         /*
-         * Parse buffer for message of the form: IDENT <pid> <locale>
+         * Parse buffer for message of the form:
+         * IDENT <pid> <locale> <disconnect flag>
          */
         bufp = buf;
         if (strncmp(bufp, "IDENT ", 6) != 0)
                 return (-1);
         bufp += 6;

@@ -560,27 +563,32 @@
         if (errno != 0)
                 return (-1);
 
         while (*bufp != '\0' && isspace(*bufp))
                 bufp++;
+        buflen = strlen(bufp) - 1;
+        *disconnect = atoi(&bufp[buflen]);
+        bufp[buflen - 1] = '\0';
         (void) strlcpy(locale, bufp, locale_len);
 
         return (0);
 }
 
 static int
-accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len)
+accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len,
+        int *disconnect)
 {
         int connfd;
         struct sockaddr_un cliaddr;
         socklen_t clilen;
 
         clilen = sizeof (cliaddr);
         connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
         if (connfd == -1)
                 return (-1);
-        if (get_client_ident(connfd, pid, locale, locale_len) == -1) {
+        if (get_client_ident(connfd, pid, locale, locale_len,
+            disconnect) == -1) {
                 (void) shutdown(connfd, SHUT_RDWR);
                 (void) close(connfd);
                 return (-1);
         }
         (void) write(connfd, "OK\n", 3);

@@ -599,21 +607,21 @@
         connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
 
         /*
          * After hear its ident string, tell client to get lost.
          */
-        if (get_client_ident(connfd, NULL, NULL, 0) == 0) {
+        if (get_client_ident(connfd, NULL, NULL, 0, NULL) == 0) {
                 (void) snprintf(nak, sizeof (nak), "%lu\n",
                     clientpid);
                 (void) write(connfd, nak, strlen(nak));
         }
         (void) shutdown(connfd, SHUT_RDWR);
         (void) close(connfd);
 }
 
 static void
-event_message(int clifd, char *clilocale, zone_evt_t evt)
+event_message(int clifd, char *clilocale, zone_evt_t evt, int dflag)
 {
         char *str, *lstr = NULL;
         char lmsg[BUFSIZ];
         char outbuf[BUFSIZ];
 

@@ -633,10 +641,13 @@
                 break;
         case Z_EVT_ZONE_READIED:
                 str = "NOTICE: Zone readied";
                 break;
         case Z_EVT_ZONE_HALTED:
+                if (dflag)
+                        str = "NOTICE: Zone halted.  Disconnecting...";
+                else
                 str = "NOTICE: Zone halted";
                 break;
         case Z_EVT_ZONE_REBOOTING:
                 if (*boot_args == '\0') {
                         str = "NOTICE: Zone rebooting";

@@ -649,10 +660,13 @@
                 break;
         case Z_EVT_ZONE_UNINSTALLING:
                 str = "NOTICE: Zone is being uninstalled.  Disconnecting...";
                 break;
         case Z_EVT_ZONE_BOOTFAILED:
+                if (dflag)
+                        str = "NOTICE: Zone boot failed.  Disconnecting...";
+                else
                 str = "NOTICE: Zone boot failed";
                 break;
         case Z_EVT_ZONE_BADARGS:
                 /*LINTED*/
                 (void) snprintf(lmsg, sizeof (lmsg),

@@ -706,10 +720,11 @@
         int cc, ret;
         int clifd = -1;
         int pollerr = 0;
         char clilocale[MAXPATHLEN];
         pid_t clipid = 0;
+        int disconnect = 0;
 
         /* console side, watch for read events */
         pollfds[0].fd = consfd;
         pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
             POLLPRI | POLLERR | POLLHUP | POLLNVAL;

@@ -799,11 +814,12 @@
                                 /* we're already handling a client */
                                 reject_client(servfd, clipid);
 
 
                         } else if ((clifd = accept_client(servfd, &clipid,
-                            clilocale, sizeof (clilocale))) != -1) {
+                            clilocale, sizeof (clilocale),
+                            &disconnect)) != -1) {
                                 pollfds[1].fd = clifd;
 
                         } else {
                                 break;
                         }

@@ -825,11 +841,11 @@
                          * service lap.
                          */
                         if (clifd == -1) {
                                 break;
                         }
-                        event_message(clifd, clilocale, evt);
+                        event_message(clifd, clilocale, evt, disconnect);
                         /*
                          * Special handling for the message that the zone is
                          * uninstalling; we boot the client, then break out
                          * of this function.  When we return to the
                          * serve_console loop, we will see that the zone is

@@ -836,10 +852,18 @@
                          * in a state < READY, and so zoneadmd will shutdown.
                          */
                         if (evt == Z_EVT_ZONE_UNINSTALLING) {
                                 break;
                         }
+                        /*
+                         * Diconnect if -C and -d options were specified and
+                         * zone was halted or failed to boot.
+                         */
+                        if ((evt == Z_EVT_ZONE_HALTED ||
+                            evt == Z_EVT_ZONE_BOOTFAILED) && disconnect) {
+                                break;
+                        }
                 }
 
         }
 
         if (clifd != -1) {