ctdb-daemon: Shut down if interactive and stdin is closed
authorMartin Schwenke <martin@meltin.net>
Mon, 13 Jan 2020 10:04:54 +0000 (21:04 +1100)
committerMartin Schwenke <martins@samba.org>
Tue, 28 Jan 2020 09:57:32 +0000 (09:57 +0000)
This allows a test environment to simply close its end of a pipe to
cleanly shutdown ctdbd.  Like in smbd, this is only done if stdin is a
pipe or a socket.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/server/ctdb_daemon.c

index cc688b07e9c2383ef8ce1926501b5f28b64fe126..c4ab2dbc3d30e68534918974a5fdbbfc1bfdf0b6 100644 (file)
@@ -1389,6 +1389,56 @@ static void ctdb_set_my_pnn(struct ctdb_context *ctdb)
        D_NOTICE("PNN is %u\n", ctdb->pnn);
 }
 
+static void stdin_handler(struct tevent_context *ev,
+                         struct tevent_fd *fde,
+                         uint16_t flags,
+                         void *private_data)
+{
+       struct ctdb_context *ctdb = talloc_get_type_abort(
+               private_data, struct ctdb_context);
+       ssize_t nread;
+       char c;
+
+       nread = read(STDIN_FILENO, &c, 1);
+       if (nread != 1) {
+               D_ERR("stdin closed, exiting\n");
+               talloc_free(fde);
+               ctdb_shutdown_sequence(ctdb, EPIPE);
+       }
+}
+
+static int setup_stdin_handler(struct ctdb_context *ctdb)
+{
+       struct tevent_fd *fde;
+       struct stat st;
+       int ret;
+
+       ret = fstat(STDIN_FILENO, &st);
+       if (ret != 0) {
+               /* Problem with stdin, ignore... */
+               DBG_INFO("Can't fstat() stdin\n");
+               return 0;
+       }
+
+       if (!S_ISFIFO(st.st_mode)) {
+               DBG_INFO("Not a pipe...\n");
+               return 0;
+       }
+
+       fde = tevent_add_fd(ctdb->ev,
+                           ctdb,
+                           STDIN_FILENO,
+                           TEVENT_FD_READ,
+                           stdin_handler,
+                           ctdb);
+       if (fde == NULL) {
+               return ENOMEM;
+       }
+
+       DBG_INFO("Set up stdin handler\n");
+       return 0;
+}
+
 /*
   start the protocol going as a daemon
 */
@@ -1448,6 +1498,15 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork)
                ctdb_set_child_logging(ctdb);
        }
 
+       /* Exit if stdin is closed */
+       if (!do_fork) {
+               ret = setup_stdin_handler(ctdb);
+               if (ret != 0) {
+                       DBG_ERR("Failed to setup stdin handler\n");
+                       exit(1);
+               }
+       }
+
        TALLOC_FREE(ctdb->srv);
        if (srvid_init(ctdb, &ctdb->srv) != 0) {
                DEBUG(DEBUG_CRIT,("Failed to setup message srvid context\n"));