s3:smbd: rename has_ctdb_public_ip to has_cluster_movable_ip
[Samba.git] / ctdb / event / event_daemon.c
blobb6c01761e91b40338568571184a899d970019849
1 /*
2 CTDB event daemon
4 Copyright (C) Amitay Isaacs 2018
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.
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.
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/>.
20 #include "replace.h"
21 #include "system/filesys.h"
23 #include <popt.h>
24 #include <talloc.h>
25 #include <tevent.h>
27 #include "lib/util/tevent_unix.h"
29 #include "common/logging.h"
30 #include "common/path.h"
31 #include "common/sock_daemon.h"
33 #include "event/event_private.h"
35 struct event_daemon_state {
36 TALLOC_CTX *mem_ctx;
37 char *socket;
38 char *pidfile;
39 struct tevent_context *ev;
40 struct event_config *config;
41 struct sock_daemon_context *sockd;
42 struct event_context *eventd;
45 static int event_daemon_startup(void *private_data)
47 struct event_daemon_state *e_state = talloc_get_type_abort(
48 private_data, struct event_daemon_state);
49 int ret;
51 ret = event_context_init(e_state,
52 e_state->ev,
53 e_state->config,
54 &e_state->eventd);
55 if (ret != 0) {
56 D_ERR("Failed to initialize event context\n");
57 return ret;
60 return 0;
63 static int event_daemon_reconfigure(void *private_data)
65 struct event_daemon_state *e_state = talloc_get_type_abort(
66 private_data, struct event_daemon_state);
67 int ret;
69 ret = event_config_reload(e_state->config);
70 if (ret != 0) {
71 D_WARNING("Configuration reload failed\n");
74 return 0;
77 static void event_daemon_shutdown(void *private_data)
79 struct event_daemon_state *e_state = talloc_get_type_abort(
80 private_data, struct event_daemon_state);
82 TALLOC_FREE(e_state->eventd);
85 static bool event_client_connect(struct sock_client_context *client,
86 pid_t pid,
87 void *private_data)
89 struct event_daemon_state *e_state = talloc_get_type_abort(
90 private_data, struct event_daemon_state);
91 int ret;
93 ret = eventd_client_add(e_state->eventd, client);
94 if (ret != 0) {
95 D_ERR("Failed to register client, ret=%d\n", ret);
96 return false;
99 return true;
102 static void event_client_disconnect(struct sock_client_context *client,
103 void *private_data)
105 struct event_daemon_state *e_state = talloc_get_type_abort(
106 private_data, struct event_daemon_state);
108 eventd_client_del(e_state->eventd, client);
111 struct event_client_state {
112 struct tevent_context *ev;
113 struct event_context *eventd;
114 struct sock_client_context *client;
115 uint8_t *buf;
116 size_t buflen;
119 static void event_client_request_done(struct tevent_req *subreq);
120 static void event_client_reply_done(struct tevent_req *subreq);
122 static struct tevent_req *event_client_send(TALLOC_CTX *mem_ctx,
123 struct tevent_context *ev,
124 struct sock_client_context *client,
125 uint8_t *buf,
126 size_t buflen,
127 void *private_data)
129 struct event_daemon_state *e_state = talloc_get_type_abort(
130 private_data, struct event_daemon_state);
131 struct tevent_req *req, *subreq;
132 struct event_client_state *state;
134 req = tevent_req_create(mem_ctx, &state, struct event_client_state);
135 if (req == NULL) {
136 return NULL;
139 state->ev = ev;
140 state->eventd = e_state->eventd;
141 state->client = client;
143 subreq = event_pkt_send(state, ev, e_state->eventd, buf, buflen);
144 if (tevent_req_nomem(subreq, req)) {
145 return tevent_req_post(req, ev);
147 tevent_req_set_callback(subreq, event_client_request_done, req);
149 return req;
152 static void event_client_request_done(struct tevent_req *subreq)
154 struct tevent_req *req = tevent_req_callback_data(
155 subreq, struct tevent_req);
156 struct event_client_state *state = tevent_req_data(
157 req, struct event_client_state);
158 int ret = 0;
159 bool ok;
161 ok = event_pkt_recv(subreq, &ret, state, &state->buf, &state->buflen);
162 TALLOC_FREE(subreq);
163 if (!ok) {
164 tevent_req_error(req, ret);
165 return;
168 ok = eventd_client_exists(state->eventd, state->client);
169 if (!ok) {
170 /* Client has already disconnected */
171 talloc_free(state->buf);
172 tevent_req_done(req);
173 return;
176 subreq = sock_socket_write_send(state,
177 state->ev,
178 state->client,
179 state->buf,
180 state->buflen);
181 if (tevent_req_nomem(subreq, req)) {
182 talloc_free(state->buf);
183 return;
185 tevent_req_set_callback(subreq, event_client_reply_done, req);
188 static void event_client_reply_done(struct tevent_req *subreq)
190 struct tevent_req *req = tevent_req_callback_data(
191 subreq, struct tevent_req);
192 struct event_client_state *state = tevent_req_data(
193 req, struct event_client_state);
194 int ret = 0;
195 bool ok;
197 talloc_free(state->buf);
199 ok = sock_socket_write_recv(subreq, &ret);
200 TALLOC_FREE(subreq);
201 if (!ok) {
202 D_ERR("Sending reply failed\n");
203 tevent_req_error(req, ret);
204 return;
207 tevent_req_done(req);
210 static bool event_client_recv(struct tevent_req *req, int *perr)
212 if (tevent_req_is_unix_error(req, perr)) {
213 return false;
216 return true;
219 static struct {
220 int pid;
221 int startup_fd;
222 } options = {
223 .pid = -1,
224 .startup_fd = -1,
227 struct poptOption cmdline_options[] = {
228 POPT_AUTOHELP
229 { "pid", 'P', POPT_ARG_INT, &options.pid, 0,
230 "pid to wait for", "PID" },
231 { "startup-fd", 'S', POPT_ARG_INT, &options.startup_fd, 0,
232 "file descriptor to notify of successful start", "FD" },
233 POPT_TABLEEND
236 int main(int argc, const char **argv)
238 poptContext pc;
239 struct event_daemon_state *e_state;
240 struct sock_daemon_funcs daemon_funcs;
241 struct sock_socket_funcs socket_funcs;
242 const char *log_location = "file:";
243 const char *log_level = "NOTICE";
244 const char *t;
245 int interactive = 0;
246 int opt, ret;
247 bool ok;
249 pc = poptGetContext(argv[0],
250 argc,
251 argv,
252 cmdline_options,
254 while ((opt = poptGetNextOpt(pc)) != -1) {
255 D_ERR("Invalid options %s: %s\n",
256 poptBadOption(pc, 0),
257 poptStrerror(opt));
258 exit(1);
261 t = getenv("CTDB_INTERACTIVE");
262 if (t != NULL) {
263 interactive = 1;
266 e_state = talloc_zero(NULL, struct event_daemon_state);
267 if (e_state == NULL) {
268 D_ERR("Memory allocation error\n");
269 ret = 1;
270 goto fail;
273 e_state->mem_ctx = talloc_new(e_state);
274 if (e_state->mem_ctx == NULL) {
275 D_ERR("Memory allocation error\n");
276 ret = 1;
277 goto fail;
280 e_state->socket = path_socket(e_state, "eventd");
281 if (e_state->socket == NULL) {
282 D_ERR("Memory allocation error\n");
283 ret = 1;
284 goto fail;
287 e_state->pidfile = path_pidfile(e_state, "eventd");
288 if (e_state->pidfile == NULL) {
289 D_ERR("Memory allocation error\n");
290 ret = 1;
291 goto fail;
294 ret = event_config_init(e_state, &e_state->config);
295 if (ret != 0) {
296 D_ERR("Failed to initialize event config\n");
297 goto fail;
300 e_state->ev = tevent_context_init(e_state->mem_ctx);
301 if (e_state->ev == NULL) {
302 D_ERR("Failed to initialize tevent\n");
303 ret = 1;
304 goto fail;
307 daemon_funcs = (struct sock_daemon_funcs) {
308 .startup = event_daemon_startup,
309 .reconfigure = event_daemon_reconfigure,
310 .shutdown = event_daemon_shutdown,
313 if (interactive == 0) {
314 log_location = event_config_log_location(e_state->config);
315 log_level = event_config_log_level(e_state->config);
318 ret = sock_daemon_setup(e_state->mem_ctx,
319 "ctdb-eventd",
320 log_location,
321 log_level,
322 &daemon_funcs,
323 e_state,
324 &e_state->sockd);
325 if (ret != 0) {
326 D_ERR("Failed to setup sock daemon\n");
327 goto fail;
330 socket_funcs = (struct sock_socket_funcs) {
331 .connect = event_client_connect,
332 .disconnect = event_client_disconnect,
333 .read_send = event_client_send,
334 .read_recv = event_client_recv,
337 ret = sock_daemon_add_unix(e_state->sockd,
338 e_state->socket,
339 &socket_funcs,
340 e_state);
341 if (ret != 0) {
342 D_ERR("Failed to setup socket %s\n", e_state->socket);
343 goto fail;
346 if (options.startup_fd != -1) {
347 ok = sock_daemon_set_startup_fd(e_state->sockd,
348 options.startup_fd);
349 if (!ok) {
350 goto fail;
354 ret = sock_daemon_run(e_state->ev,
355 e_state->sockd,
356 e_state->pidfile,
357 false,
358 false,
359 options.pid);
360 if (ret == EINTR) {
361 ret = 0;
364 if (t != NULL) {
365 talloc_report_full(e_state->mem_ctx, stderr);
368 fail:
369 talloc_free(e_state);
370 (void)poptFreeContext(pc);
371 exit(ret);