smb2_server: call smbXsrv_connection_disconnect_transport() early on network errors
[gd/samba-autobuild/.git] / source3 / smbd / smbd_cleanupd.c
index 2f3d19fbf5ad83164c4c32b8ec11e200d7173aab..86c0212e1cced7691032300368005252627a2c27 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "replace.h"
+#include "includes.h"
 #include "smbd_cleanupd.h"
+#include "lib/util_procid.h"
 #include "lib/util/tevent_ntstatus.h"
 #include "lib/util/debug.h"
 #include "smbprofile.h"
+#include "serverid.h"
+#include "locking/proto.h"
+#include "cleanupdb.h"
 
 struct smbd_cleanupd_state {
        pid_t parent_pid;
@@ -76,6 +80,39 @@ static void smbd_cleanupd_shutdown(struct messaging_context *msg,
        tevent_req_done(req);
 }
 
+struct cleanup_child {
+       struct cleanup_child *prev, *next;
+       pid_t pid;
+       bool unclean;
+};
+
+struct cleanupdb_traverse_state {
+       TALLOC_CTX *mem_ctx;
+       bool ok;
+       struct cleanup_child *childs;
+};
+
+static int cleanupdb_traverse_fn(const pid_t pid,
+                                const bool unclean,
+                                void *private_data)
+{
+       struct cleanupdb_traverse_state *cleanup_state =
+               (struct cleanupdb_traverse_state *)private_data;
+       struct cleanup_child *child = NULL;
+
+       child = talloc_zero(cleanup_state->mem_ctx, struct cleanup_child);
+       if (child == NULL) {
+               DBG_ERR("talloc_zero failed\n");
+               return -1;
+       }
+
+       child->pid = pid;
+       child->unclean = unclean;
+       DLIST_ADD(cleanup_state->childs, child);
+
+       return 0;
+}
+
 static void smbd_cleanupd_process_exited(struct messaging_context *msg,
                                         void *private_data, uint32_t msg_type,
                                         struct server_id server_id,
@@ -85,22 +122,58 @@ static void smbd_cleanupd_process_exited(struct messaging_context *msg,
                private_data, struct tevent_req);
        struct smbd_cleanupd_state *state = tevent_req_data(
                req, struct smbd_cleanupd_state);
-       pid_t pid;
-       bool unclean_shutdown;
+       int ret;
+       struct cleanupdb_traverse_state cleanup_state;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct cleanup_child *child = NULL;
+
+       cleanup_state = (struct cleanupdb_traverse_state) {
+               .mem_ctx = frame
+       };
+
+       /*
+        * This merely collect childs in a list, whatever we're
+        * supposed to cleanup for every child, it has to take place
+        * *after* the db traverse in a list loop. This is to minimize
+        * locking interaction between the traverse and writers (ie
+        * the parent smbd).
+        */
+       ret = cleanupdb_traverse_read(cleanupdb_traverse_fn, &cleanup_state);
+       if (ret < 0) {
+               DBG_ERR("cleanupdb_traverse_read failed\n");
+               TALLOC_FREE(frame);
+               return;
+       }
 
-       if (data->length != (sizeof(pid) + sizeof(unclean_shutdown))) {
-               DBG_WARNING("Got invalid length: %zu\n", data->length);
+       if (ret == 0) {
+               TALLOC_FREE(frame);
                return;
        }
 
-       memcpy(&pid, data->data, sizeof(pid));
-       memcpy(&unclean_shutdown, data->data + sizeof(pid),
-              sizeof(unclean_shutdown));
+       for (child = cleanup_state.childs;
+            child != NULL;
+            child = child->next)
+       {
+               bool ok;
 
-       DBG_DEBUG("%d exited %sclean\n", (int)pid,
-                 unclean_shutdown ? "un" : "");
+               ok = cleanupdb_delete_child(child->pid);
+               if (!ok) {
+                       DBG_ERR("failed to delete pid %d\n", (int)child->pid);
+               }
+
+               smbprofile_cleanup(child->pid, state->parent_pid);
+
+               ret = messaging_cleanup(msg, child->pid);
+
+               if ((ret != 0) && (ret != ENOENT)) {
+                       DBG_DEBUG("messaging_cleanup returned %s\n",
+                                 strerror(ret));
+               }
+
+               DBG_DEBUG("cleaned up pid %d\n", (int)child->pid);
+       }
 
-       smbprofile_cleanup(pid, state->parent_pid);
+       TALLOC_FREE(frame);
 }
 
 NTSTATUS smbd_cleanupd_recv(struct tevent_req *req)