build: Remove --extra-python
[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_BRL_VALIDATE,
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         brl_revalidate(msg, private_data, msg_type, server_id, data);
102 }
103
104 struct cleanup_child {
105         struct cleanup_child *prev, *next;
106         pid_t pid;
107         bool unclean;
108 };
109
110 struct cleanupdb_traverse_state {
111         TALLOC_CTX *mem_ctx;
112         bool ok;
113         struct cleanup_child *childs;
114 };
115
116 static int cleanupdb_traverse_fn(const pid_t pid,
117                                  const bool unclean,
118                                  void *private_data)
119 {
120         struct cleanupdb_traverse_state *cleanup_state =
121                 (struct cleanupdb_traverse_state *)private_data;
122         struct cleanup_child *child = NULL;
123
124         child = talloc_zero(cleanup_state->mem_ctx, struct cleanup_child);
125         if (child == NULL) {
126                 DBG_ERR("talloc_zero failed\n");
127                 return -1;
128         }
129
130         child->pid = pid;
131         child->unclean = unclean;
132         DLIST_ADD(cleanup_state->childs, child);
133
134         return 0;
135 }
136
137 static void smbd_cleanupd_process_exited(struct messaging_context *msg,
138                                          void *private_data, uint32_t msg_type,
139                                          struct server_id server_id,
140                                          DATA_BLOB *data)
141 {
142         struct tevent_req *req = talloc_get_type_abort(
143                 private_data, struct tevent_req);
144         struct smbd_cleanupd_state *state = tevent_req_data(
145                 req, struct smbd_cleanupd_state);
146         int ret;
147         struct cleanupdb_traverse_state cleanup_state;
148         TALLOC_CTX *frame = talloc_stackframe();
149         struct cleanup_child *child = NULL;
150
151         cleanup_state = (struct cleanupdb_traverse_state) {
152                 .mem_ctx = frame
153         };
154
155         /*
156          * This merely collect childs in a list, whatever we're
157          * supposed to cleanup for every child, it has to take place
158          * *after* the db traverse in a list loop. This is to minimize
159          * locking interaction between the traverse and writers (ie
160          * the parent smbd).
161          */
162         ret = cleanupdb_traverse_read(cleanupdb_traverse_fn, &cleanup_state);
163         if (ret < 0) {
164                 DBG_ERR("cleanupdb_traverse_read failed\n");
165                 TALLOC_FREE(frame);
166                 return;
167         }
168
169         if (ret == 0) {
170                 TALLOC_FREE(frame);
171                 return;
172         }
173
174         for (child = cleanup_state.childs;
175              child != NULL;
176              child = child->next)
177         {
178                 bool ok;
179
180                 ok = cleanupdb_delete_child(child->pid);
181                 if (!ok) {
182                         DBG_ERR("failed to delete pid %d\n", (int)child->pid);
183                 }
184
185                 smbprofile_cleanup(child->pid, state->parent_pid);
186
187                 ret = messaging_cleanup(msg, child->pid);
188
189                 if ((ret != 0) && (ret != ENOENT)) {
190                         DBG_DEBUG("messaging_cleanup returned %s\n",
191                                   strerror(ret));
192                 }
193
194                 DBG_DEBUG("cleaned up pid %d\n", (int)child->pid);
195         }
196
197         TALLOC_FREE(frame);
198 }
199
200 NTSTATUS smbd_cleanupd_recv(struct tevent_req *req)
201 {
202         return tevent_req_simple_recv_ntstatus(req);
203 }