script/release.sh: fix off by 1 error in announce.${tagname}.mail.txt creation
[Samba.git] / ctdb / client / client_event.c
blob63972595b91aa5640954b4de42bd678ced918417
1 /*
2 Eventd client api
4 Copyright (C) Amitay Isaacs 2016
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"
22 #include "system/network.h"
24 #include <talloc.h>
25 #include <tevent.h>
27 #include "lib/util/debug.h"
28 #include "lib/util/tevent_unix.h"
30 #include "common/logging.h"
31 #include "common/reqid.h"
32 #include "common/comm.h"
34 #include "protocol/protocol_api.h"
36 #include "client/client.h"
38 struct ctdb_event_context {
39 struct reqid_context *idr;
40 struct comm_context *comm;
41 int fd;
43 ctdb_client_callback_func_t callback;
44 void *private_data;
47 static int ctdb_event_connect(struct ctdb_event_context *eclient,
48 struct tevent_context *ev,
49 const char *sockpath);
51 static int ctdb_event_context_destructor(struct ctdb_event_context *eclient);
53 int ctdb_event_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
54 const char *sockpath, struct ctdb_event_context **out)
56 struct ctdb_event_context *eclient;
57 int ret;
59 eclient = talloc_zero(mem_ctx, struct ctdb_event_context);
60 if (eclient == NULL) {
61 DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n"));
62 return ENOMEM;
65 ret = reqid_init(eclient, INT_MAX-200, &eclient->idr);
66 if (ret != 0) {
67 DEBUG(DEBUG_ERR, ("reqid_init() failed, ret=%d\n", ret));
68 talloc_free(eclient);
69 return ret;
72 eclient->fd = -1;
74 ret = ctdb_event_connect(eclient, ev, sockpath);
75 if (ret != 0) {
76 talloc_free(eclient);
77 return ret;
80 talloc_set_destructor(eclient, ctdb_event_context_destructor);
82 *out = eclient;
83 return 0;
86 static int ctdb_event_context_destructor(struct ctdb_event_context *eclient)
88 if (eclient->fd != -1) {
89 close(eclient->fd);
90 eclient->fd = -1;
92 return 0;
95 static void event_read_handler(uint8_t *buf, size_t buflen,
96 void *private_data);
97 static void event_dead_handler(void *private_data);
99 static int ctdb_event_connect(struct ctdb_event_context *eclient,
100 struct tevent_context *ev, const char *sockpath)
102 struct sockaddr_un addr;
103 size_t len;
104 int fd, ret;
106 if (sockpath == NULL) {
107 DEBUG(DEBUG_ERR, ("socket path cannot be NULL\n"));
108 return EINVAL;
111 memset(&addr, 0, sizeof(addr));
112 addr.sun_family = AF_UNIX;
113 len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
114 if (len >= sizeof(addr.sun_path)) {
115 DEBUG(DEBUG_ERR, ("socket path too long, len=%zu\n",
116 strlen(sockpath)));
117 return ENAMETOOLONG;
120 fd = socket(AF_UNIX, SOCK_STREAM, 0);
121 if (fd == -1) {
122 ret = errno;
123 DEBUG(DEBUG_ERR, ("socket() failed, errno=%d\n", ret));
124 return ret;
127 ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
128 if (ret == -1) {
129 ret = errno;
130 DEBUG(DEBUG_ERR, ("connect() failed, errno=%d\n", ret));
131 close(fd);
132 return ret;
134 eclient->fd = fd;
136 ret = comm_setup(eclient, ev, fd, event_read_handler, eclient,
137 event_dead_handler, eclient, &eclient->comm);
138 if (ret != 0) {
139 DEBUG(DEBUG_ERR, ("comm_setup() failed, ret=%d\n", ret));
140 close(fd);
141 eclient->fd = -1;
142 return ret;
145 return 0;
148 static void ctdb_event_msg_reply(struct ctdb_event_context *eclient,
149 uint8_t *buf, size_t buflen);
151 static void event_read_handler(uint8_t *buf, size_t buflen,
152 void *private_data)
154 struct ctdb_event_context *eclient = talloc_get_type_abort(
155 private_data, struct ctdb_event_context);
157 ctdb_event_msg_reply(eclient, buf, buflen);
160 static void event_dead_handler(void *private_data)
162 struct ctdb_event_context *eclient = talloc_get_type_abort(
163 private_data, struct ctdb_event_context);
164 ctdb_client_callback_func_t callback = eclient->callback;
165 void *callback_data = eclient->private_data;
167 talloc_free(eclient);
168 if (callback != NULL) {
169 callback(callback_data);
170 return;
173 DEBUG(DEBUG_NOTICE, ("connection to daemon closed, exiting\n"));
174 exit(1);
177 void ctdb_event_set_disconnect_callback(struct ctdb_event_context *eclient,
178 ctdb_client_callback_func_t callback,
179 void *private_data)
181 eclient->callback = callback;
182 eclient->private_data = private_data;
186 * Handle eventd_request and eventd_reply
189 struct ctdb_event_msg_state {
190 struct ctdb_event_context *eclient;
192 uint32_t reqid;
193 struct tevent_req *req;
194 struct ctdb_event_reply *reply;
197 static int ctdb_event_msg_state_destructor(struct ctdb_event_msg_state *state);
198 static void ctdb_event_msg_done(struct tevent_req *subreq);
200 struct tevent_req *ctdb_event_msg_send(TALLOC_CTX *mem_ctx,
201 struct tevent_context *ev,
202 struct ctdb_event_context *eclient,
203 struct ctdb_event_request *request)
205 struct tevent_req *req, *subreq;
206 struct ctdb_event_msg_state *state;
207 uint8_t *buf;
208 size_t buflen;
209 int ret;
211 req = tevent_req_create(mem_ctx, &state, struct ctdb_event_msg_state);
212 if (req == NULL) {
213 return NULL;
216 state->eclient = eclient;
218 state->reqid = reqid_new(eclient->idr, state);
219 if (state->reqid == REQID_INVALID) {
220 talloc_free(req);
221 return NULL;
223 state->req = req;
225 talloc_set_destructor(state, ctdb_event_msg_state_destructor);
227 ctdb_event_header_fill(&request->header, state->reqid);
229 buflen = ctdb_event_request_len(request);
230 buf = talloc_size(state, buflen);
231 if (tevent_req_nomem(buf, req)) {
232 return tevent_req_post(req, ev);
235 ret = ctdb_event_request_push(request, buf, &buflen);
236 if (ret != 0) {
237 tevent_req_error(req, ret);
238 return tevent_req_post(req, ev);
241 subreq = comm_write_send(state, ev, eclient->comm, buf, buflen);
242 if (tevent_req_nomem(subreq, req)) {
243 return tevent_req_post(req, ev);
245 tevent_req_set_callback(subreq, ctdb_event_msg_done, req);
247 return req;
250 static int ctdb_event_msg_state_destructor(struct ctdb_event_msg_state *state)
252 reqid_remove(state->eclient->idr, state->reqid);
253 return 0;
256 static void ctdb_event_msg_done(struct tevent_req *subreq)
258 struct tevent_req *req = tevent_req_callback_data(
259 subreq, struct tevent_req);
260 int ret;
261 bool status;
263 status = comm_write_recv(subreq, &ret);
264 TALLOC_FREE(subreq);
265 if (! status) {
266 tevent_req_error(req, ret);
267 return;
270 /* Wait for the reply or timeout */
273 static void ctdb_event_msg_reply(struct ctdb_event_context *eclient,
274 uint8_t *buf, size_t buflen)
276 struct ctdb_event_reply *reply;
277 struct ctdb_event_msg_state *state;
278 int ret;
280 reply = talloc_zero(eclient, struct ctdb_event_reply);
281 if (reply == NULL) {
282 D_WARNING("memory allocation error\n");
283 return;
286 ret = ctdb_event_reply_pull(buf, buflen, reply, reply);
287 if (ret != 0) {
288 D_WARNING("Invalid packet received, ret=%d\n", ret);
289 return;
292 state = reqid_find(eclient->idr, reply->header.reqid,
293 struct ctdb_event_msg_state);
294 if (state == NULL) {
295 return;
298 if (reply->header.reqid != state->reqid) {
299 return;
302 state->reply = talloc_steal(state, reply);
303 tevent_req_done(state->req);
306 bool ctdb_event_msg_recv(struct tevent_req *req, int *perr,
307 TALLOC_CTX *mem_ctx,
308 struct ctdb_event_reply **reply)
310 struct ctdb_event_msg_state *state = tevent_req_data(
311 req, struct ctdb_event_msg_state);
312 int ret;
314 if (tevent_req_is_unix_error(req, &ret)) {
315 if (perr != NULL) {
316 *perr = ret;
318 return false;
321 if (reply != NULL) {
322 *reply = talloc_steal(mem_ctx, state->reply);
325 return true;
329 * Run an event
332 struct tevent_req *ctdb_event_run_send(TALLOC_CTX *mem_ctx,
333 struct tevent_context *ev,
334 struct ctdb_event_context *eclient,
335 enum ctdb_event event,
336 uint32_t timeout, const char *arg_str)
338 struct ctdb_event_request request;
339 struct ctdb_event_request_run rdata;
341 rdata.event = event;
342 rdata.timeout = timeout;
343 rdata.arg_str = arg_str;
345 request.rdata.command = CTDB_EVENT_COMMAND_RUN;
346 request.rdata.data.run = &rdata;
348 return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
351 bool ctdb_event_run_recv(struct tevent_req *req, int *perr, int *result)
353 struct ctdb_event_reply *reply;
354 int ret;
355 bool status;
357 status = ctdb_event_msg_recv(req, &ret, req, &reply);
358 if (! status) {
359 if (perr != NULL) {
360 *perr = ret;
362 return false;
365 if (reply->rdata.command != CTDB_EVENT_COMMAND_RUN) {
366 if (perr != NULL) {
367 *perr = EPROTO;
369 talloc_free(reply);
370 return false;
373 if (result != NULL) {
374 *result = reply->rdata.result;
377 talloc_free(reply);
378 return true;
382 * Get event status
385 struct tevent_req *ctdb_event_status_send(TALLOC_CTX *mem_ctx,
386 struct tevent_context *ev,
387 struct ctdb_event_context *eclient,
388 enum ctdb_event event,
389 enum ctdb_event_status_state state)
391 struct ctdb_event_request request;
392 struct ctdb_event_request_status rdata;
394 rdata.event = event;
395 rdata.state = state;
397 request.rdata.command = CTDB_EVENT_COMMAND_STATUS;
398 request.rdata.data.status = &rdata;
400 return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
403 bool ctdb_event_status_recv(struct tevent_req *req, int *perr,
404 int32_t *result, int *event_status,
405 TALLOC_CTX *mem_ctx,
406 struct ctdb_script_list **script_list)
408 struct ctdb_event_reply *reply;
409 int ret;
410 bool status;
412 status = ctdb_event_msg_recv(req, &ret, req, &reply);
413 if (! status) {
414 if (perr != NULL) {
415 *perr = ret;
417 return false;
420 if (reply->rdata.command != CTDB_EVENT_COMMAND_STATUS) {
421 if (perr != NULL) {
422 *perr = EPROTO;
424 talloc_free(reply);
425 return false;
428 if (result != NULL) {
429 *result = reply->rdata.result;
431 if (event_status != NULL) {
432 *event_status = reply->rdata.data.status->status;
434 if (script_list != NULL) {
435 *script_list = talloc_steal(mem_ctx,
436 reply->rdata.data.status->script_list);
439 talloc_free(reply);
440 return true;
444 * Get script list
447 struct tevent_req *ctdb_event_script_list_send(
448 TALLOC_CTX *mem_ctx,
449 struct tevent_context *ev,
450 struct ctdb_event_context *eclient)
452 struct ctdb_event_request request;
454 request.rdata.command = CTDB_EVENT_COMMAND_SCRIPT_LIST;
456 return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
459 bool ctdb_event_script_list_recv(struct tevent_req *req, int *perr,
460 int32_t *result, TALLOC_CTX *mem_ctx,
461 struct ctdb_script_list **script_list)
463 struct ctdb_event_reply *reply;
464 int ret;
465 bool status;
467 status = ctdb_event_msg_recv(req, &ret, req, &reply);
468 if (! status) {
469 if (perr != NULL) {
470 *perr = ret;
472 return false;
475 if (reply->rdata.command != CTDB_EVENT_COMMAND_SCRIPT_LIST) {
476 if (perr != NULL) {
477 *perr = EPROTO;
479 talloc_free(reply);
480 return false;
483 if (result != NULL) {
484 *result = reply->rdata.result;
486 if (script_list != NULL) {
487 *script_list = talloc_steal(mem_ctx,
488 reply->rdata.data.script_list->script_list);
491 talloc_free(reply);
492 return true;
496 * Enable a script
499 struct tevent_req *ctdb_event_script_enable_send(
500 TALLOC_CTX *mem_ctx,
501 struct tevent_context *ev,
502 struct ctdb_event_context *eclient,
503 const char *script_name)
505 struct ctdb_event_request request;
506 struct ctdb_event_request_script_enable rdata;
508 rdata.script_name = script_name;
510 request.rdata.command = CTDB_EVENT_COMMAND_SCRIPT_ENABLE;
511 request.rdata.data.script_enable = &rdata;
513 return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
516 bool ctdb_event_script_enable_recv(struct tevent_req *req, int *perr,
517 int *result)
519 struct ctdb_event_reply *reply;
520 int ret;
521 bool status;
523 status = ctdb_event_msg_recv(req, &ret, req, &reply);
524 if (! status) {
525 if (perr != NULL) {
526 *perr = ret;
528 return false;
531 if (reply->rdata.command != CTDB_EVENT_COMMAND_SCRIPT_ENABLE) {
532 if (perr != NULL) {
533 *perr = EPROTO;
535 talloc_free(reply);
536 return false;
539 if (result != NULL) {
540 *result = reply->rdata.result;
543 talloc_free(reply);
544 return true;
548 * Disable a script
551 struct tevent_req *ctdb_event_script_disable_send(
552 TALLOC_CTX *mem_ctx,
553 struct tevent_context *ev,
554 struct ctdb_event_context *eclient,
555 const char *script_name)
557 struct ctdb_event_request request;
558 struct ctdb_event_request_script_disable rdata;
560 rdata.script_name = script_name;
562 request.rdata.command = CTDB_EVENT_COMMAND_SCRIPT_DISABLE;
563 request.rdata.data.script_disable = &rdata;
565 return ctdb_event_msg_send(mem_ctx, ev, eclient, &request);
568 bool ctdb_event_script_disable_recv(struct tevent_req *req, int *perr,
569 int *result)
571 struct ctdb_event_reply *reply;
572 int ret;
573 bool status;
575 status = ctdb_event_msg_recv(req, &ret, req, &reply);
576 if (! status) {
577 if (perr != NULL) {
578 *perr = ret;
580 return false;
583 if (reply->rdata.command != CTDB_EVENT_COMMAND_SCRIPT_DISABLE) {
584 if (perr != NULL) {
585 *perr = EPROTO;
587 talloc_free(reply);
588 return false;
591 if (result != NULL) {
592 *result = reply->rdata.result;
595 talloc_free(reply);
596 return true;