messaging: Remove the "n_sent" arg from message_send_all
[nivanova/samba-autobuild/.git] / source3 / smbd / smbd_cleanupd.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * Copyright (C) Volker Lendecke 2015
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "smbd_cleanupd.h"
22 #include "lib/util_procid.h"
23 #include "lib/util/tevent_ntstatus.h"
24 #include "lib/util/debug.h"
25 #include "smbprofile.h"
26 #include "serverid.h"
27 #include "locking/proto.h"
28 #include "cleanupdb.h"
29
30 struct smbd_cleanupd_state {
31         pid_t parent_pid;
32 };
33
34 static void smbd_cleanupd_shutdown(struct messaging_context *msg,
35                                    void *private_data, uint32_t msg_type,
36                                    struct server_id server_id,
37                                    DATA_BLOB *data);
38 static void smbd_cleanupd_process_exited(struct messaging_context *msg,
39                                          void *private_data, uint32_t msg_type,
40                                          struct server_id server_id,
41                                          DATA_BLOB *data);
42 static void smbd_cleanupd_unlock(struct messaging_context *msg,
43                                  void *private_data, uint32_t msg_type,
44                                  struct server_id server_id,
45                                  DATA_BLOB *data);
46
47 struct tevent_req *smbd_cleanupd_send(TALLOC_CTX *mem_ctx,
48                                       struct tevent_context *ev,
49                                       struct messaging_context *msg,
50                                       pid_t parent_pid)
51 {
52         struct tevent_req *req;
53         struct smbd_cleanupd_state *state;
54         NTSTATUS status;
55
56         req = tevent_req_create(mem_ctx, &state, struct smbd_cleanupd_state);
57         if (req == NULL) {
58                 return NULL;
59         }
60         state->parent_pid = parent_pid;
61
62         status = messaging_register(msg, req, MSG_SHUTDOWN,
63                                     smbd_cleanupd_shutdown);
64         if (tevent_req_nterror(req, status)) {
65                 return tevent_req_post(req, ev);
66         }
67
68         status = messaging_register(msg, req, MSG_SMB_NOTIFY_CLEANUP,
69                                     smbd_cleanupd_process_exited);
70         if (tevent_req_nterror(req, status)) {
71                 return tevent_req_post(req, ev);
72         }
73
74         status = messaging_register(msg, NULL, MSG_SMB_UNLOCK,
75                                     smbd_cleanupd_unlock);
76         if (tevent_req_nterror(req, status)) {
77                 return tevent_req_post(req, ev);
78         }
79
80         return req;
81 }
82
83 static void smbd_cleanupd_shutdown(struct messaging_context *msg,
84                                    void *private_data, uint32_t msg_type,
85                                    struct server_id server_id,
86                                    DATA_BLOB *data)
87 {
88         struct tevent_req *req = talloc_get_type_abort(
89                 private_data, struct tevent_req);
90         tevent_req_done(req);
91 }
92
93 static void smbd_cleanupd_unlock(struct messaging_context *msg,
94                                  void *private_data, uint32_t msg_type,
95                                  struct server_id server_id,
96                                  DATA_BLOB *data)
97 {
98         DBG_WARNING("Cleaning up brl and lock database after unclean "
99                     "shutdown\n");
100
101         message_send_all(msg, MSG_SMB_UNLOCK, NULL, 0);
102
103         brl_revalidate(msg, private_data, msg_type, server_id, data);
104 }
105
106 struct cleanup_child {
107         struct cleanup_child *prev, *next;
108         pid_t pid;
109         bool unclean;
110 };
111
112 struct cleanupdb_traverse_state {
113         TALLOC_CTX *mem_ctx;
114         bool ok;
115         struct cleanup_child *childs;
116 };
117
118 static int cleanupdb_traverse_fn(const pid_t pid,
119                                  const bool unclean,
120                                  void *private_data)
121 {
122         struct cleanupdb_traverse_state *cleanup_state =
123                 (struct cleanupdb_traverse_state *)private_data;
124         struct cleanup_child *child = NULL;
125
126         child = talloc_zero(cleanup_state->mem_ctx, struct cleanup_child);
127         if (child == NULL) {
128                 DBG_ERR("talloc_zero failed\n");
129                 return -1;
130         }
131
132         child->pid = pid;
133         child->unclean = unclean;
134         DLIST_ADD(cleanup_state->childs, child);
135
136         return 0;
137 }
138
139 static void smbd_cleanupd_process_exited(struct messaging_context *msg,
140                                          void *private_data, uint32_t msg_type,
141                                          struct server_id server_id,
142                                          DATA_BLOB *data)
143 {
144         struct tevent_req *req = talloc_get_type_abort(
145                 private_data, struct tevent_req);
146         struct smbd_cleanupd_state *state = tevent_req_data(
147                 req, struct smbd_cleanupd_state);
148         int ret;
149         struct cleanupdb_traverse_state cleanup_state;
150         TALLOC_CTX *frame = talloc_stackframe();
151         struct cleanup_child *child = NULL;
152
153         cleanup_state = (struct cleanupdb_traverse_state) {
154                 .mem_ctx = frame
155         };
156
157         /*
158          * This merely collect childs in a list, whatever we're
159          * supposed to cleanup for every child, it has to take place
160          * *after* the db traverse in a list loop. This is to minimize
161          * locking interaction between the traverse and writers (ie
162          * the parent smbd).
163          */
164         ret = cleanupdb_traverse_read(cleanupdb_traverse_fn, &cleanup_state);
165         if (ret < 0) {
166                 DBG_ERR("cleanupdb_traverse_read failed\n");
167                 TALLOC_FREE(frame);
168                 return;
169         }
170
171         if (ret == 0) {
172                 TALLOC_FREE(frame);
173                 return;
174         }
175
176         for (child = cleanup_state.childs;
177              child != NULL;
178              child = child->next)
179         {
180                 struct server_id child_id;
181                 bool ok;
182
183                 ok = cleanupdb_delete_child(child->pid);
184                 if (!ok) {
185                         DBG_ERR("failed to delete pid %d\n", (int)child->pid);
186                 }
187
188                 /*
189                  * Get child_id before messaging_cleanup which wipes
190                  * the unique_id. Not that it really matters here for
191                  * functionality (the child should have properly
192                  * cleaned up :-)) though, but it looks nicer.
193                  */
194                 child_id = pid_to_procid(child->pid);
195
196                 smbprofile_cleanup(child->pid, state->parent_pid);
197
198                 ret = messaging_cleanup(msg, child->pid);
199
200                 if ((ret != 0) && (ret != ENOENT)) {
201                         DBG_DEBUG("messaging_cleanup returned %s\n",
202                                   strerror(ret));
203                 }
204
205                 if (!serverid_deregister(child_id)) {
206                         DBG_ERR("Could not remove pid %d from serverid.tdb\n",
207                                 (int)child->pid);
208                 }
209
210                 DBG_DEBUG("cleaned up pid %d\n", (int)child->pid);
211         }
212
213         TALLOC_FREE(frame);
214 }
215
216 NTSTATUS smbd_cleanupd_recv(struct tevent_req *req)
217 {
218         return tevent_req_simple_recv_ntstatus(req);
219 }