ctdb-tests: Implement control CHECK_PID_SRVID in fake daemon
[Samba.git] / ctdb / tests / src / fake_ctdbd.c
blob850a5920a1a7bcc30cee133a3bc33696084c720d
1 /*
2 Fake CTDB server for testing
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/network.h"
22 #include "system/time.h"
24 #include <popt.h>
25 #include <talloc.h>
26 #include <tevent.h>
27 #include <tdb.h>
29 #include "lib/util/dlinklist.h"
30 #include "lib/util/tevent_unix.h"
31 #include "lib/util/debug.h"
32 #include "lib/util/samba_util.h"
33 #include "lib/async_req/async_sock.h"
35 #include "protocol/protocol.h"
36 #include "protocol/protocol_api.h"
38 #include "common/comm.h"
39 #include "common/system.h"
40 #include "common/logging.h"
41 #include "common/tunable.h"
42 #include "common/srvid.h"
44 #include "ipalloc_read_known_ips.h"
47 #define CTDB_PORT 4379
49 /* A fake flag that is only supported by some functions */
50 #define NODE_FLAGS_FAKE_TIMEOUT 0x80000000
52 struct node {
53 ctdb_sock_addr addr;
54 uint32_t pnn;
55 uint32_t flags;
56 uint32_t capabilities;
57 bool recovery_disabled;
58 void *recovery_substate;
61 struct node_map {
62 uint32_t num_nodes;
63 struct node *node;
64 uint32_t pnn;
65 uint32_t recmaster;
68 struct interface {
69 const char *name;
70 bool link_up;
71 uint32_t references;
74 struct interface_map {
75 int num;
76 struct interface *iface;
79 struct vnn_map {
80 uint32_t recmode;
81 uint32_t generation;
82 uint32_t size;
83 uint32_t *map;
86 struct database {
87 const char *name;
88 uint32_t id;
89 uint8_t flags;
90 uint64_t seq_num;
93 struct database_map {
94 int num_dbs;
95 struct database *db;
98 struct fake_control_failure {
99 struct fake_control_failure *prev, *next;
100 enum ctdb_controls opcode;
101 uint32_t pnn;
102 const char *error;
103 const char *comment;
106 struct ctdb_client {
107 struct ctdb_client *prev, *next;
108 struct ctdbd_context *ctdb;
109 pid_t pid;
110 void *state;
113 struct ctdbd_context {
114 struct node_map *node_map;
115 struct interface_map *iface_map;
116 struct vnn_map *vnn_map;
117 struct database_map *db_map;
118 struct srvid_context *srv;
119 int num_clients;
120 struct timeval start_time;
121 struct timeval recovery_start_time;
122 struct timeval recovery_end_time;
123 bool takeover_disabled;
124 int log_level;
125 enum ctdb_runstate runstate;
126 struct ctdb_tunable_list tun_list;
127 int monitoring_mode;
128 char *reclock;
129 struct ctdb_public_ip_list *known_ips;
130 struct fake_control_failure *control_failures;
131 struct ctdb_client *client_list;
135 * Parse routines
138 static struct node_map *nodemap_init(TALLOC_CTX *mem_ctx)
140 struct node_map *node_map;
142 node_map = talloc_zero(mem_ctx, struct node_map);
143 if (node_map == NULL) {
144 return NULL;
147 node_map->pnn = CTDB_UNKNOWN_PNN;
148 node_map->recmaster = CTDB_UNKNOWN_PNN;
150 return node_map;
153 /* Read a nodemap from stdin. Each line looks like:
154 * <PNN> <FLAGS> [RECMASTER] [CURRENT] [CAPABILITIES]
155 * EOF or a blank line terminates input.
157 * By default, capablities for each node are
158 * CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER. These 2
159 * capabilities can be faked off by adding, for example,
160 * -CTDB_CAP_RECMASTER.
163 static bool nodemap_parse(struct node_map *node_map)
165 char line[1024];
167 while ((fgets(line, sizeof(line), stdin) != NULL)) {
168 uint32_t pnn, flags, capabilities;
169 char *tok, *t;
170 char *ip;
171 ctdb_sock_addr saddr;
172 struct node *node;
174 if (line[0] == '\n') {
175 break;
178 /* Get rid of pesky newline */
179 if ((t = strchr(line, '\n')) != NULL) {
180 *t = '\0';
183 /* Get PNN */
184 tok = strtok(line, " \t");
185 if (tok == NULL) {
186 fprintf(stderr, "bad line (%s) - missing PNN\n", line);
187 continue;
189 pnn = (uint32_t)strtoul(tok, NULL, 0);
191 /* Get IP */
192 tok = strtok(NULL, " \t");
193 if (tok == NULL) {
194 fprintf(stderr, "bad line (%s) - missing IP\n", line);
195 continue;
197 if (!parse_ip(tok, NULL, CTDB_PORT, &saddr)) {
198 fprintf(stderr, "bad line (%s) - invalid IP\n", line);
199 continue;
201 ip = talloc_strdup(node_map, tok);
202 if (ip == NULL) {
203 goto fail;
206 /* Get flags */
207 tok = strtok(NULL, " \t");
208 if (tok == NULL) {
209 fprintf(stderr, "bad line (%s) - missing flags\n",
210 line);
211 continue;
213 flags = (uint32_t)strtoul(tok, NULL, 0);
214 /* Handle deleted nodes */
215 if (flags & NODE_FLAGS_DELETED) {
216 talloc_free(ip);
217 ip = talloc_strdup(node_map, "0.0.0.0");
218 if (ip == NULL) {
219 goto fail;
222 capabilities = CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER;
224 tok = strtok(NULL, " \t");
225 while (tok != NULL) {
226 if (strcmp(tok, "CURRENT") == 0) {
227 node_map->pnn = pnn;
228 } else if (strcmp(tok, "RECMASTER") == 0) {
229 node_map->recmaster = pnn;
230 } else if (strcmp(tok, "-CTDB_CAP_RECMASTER") == 0) {
231 capabilities &= ~CTDB_CAP_RECMASTER;
232 } else if (strcmp(tok, "-CTDB_CAP_LMASTER") == 0) {
233 capabilities &= ~CTDB_CAP_LMASTER;
234 } else if (strcmp(tok, "TIMEOUT") == 0) {
235 /* This can be done with just a flag
236 * value but it is probably clearer
237 * and less error-prone to fake this
238 * with an explicit token */
239 flags |= NODE_FLAGS_FAKE_TIMEOUT;
241 tok = strtok(NULL, " \t");
244 node_map->node = talloc_realloc(node_map, node_map->node,
245 struct node,
246 node_map->num_nodes + 1);
247 if (node_map->node == NULL) {
248 goto fail;
250 node = &node_map->node[node_map->num_nodes];
252 parse_ip(ip, NULL, CTDB_PORT, &node->addr);
253 node->pnn = pnn;
254 node->flags = flags;
255 node->capabilities = capabilities;
256 node->recovery_disabled = false;
257 node->recovery_substate = NULL;
259 node_map->num_nodes += 1;
262 DEBUG(DEBUG_INFO, ("Parsing nodemap done\n"));
263 return true;
265 fail:
266 DEBUG(DEBUG_INFO, ("Parsing nodemap failed\n"));
267 return false;
271 /* Append a node to a node map with given address and flags */
272 static bool node_map_add(struct ctdb_node_map *nodemap,
273 const char *nstr, uint32_t flags)
275 ctdb_sock_addr addr;
276 uint32_t num;
277 struct ctdb_node_and_flags *n;
279 if (! parse_ip(nstr, NULL, CTDB_PORT, &addr)) {
280 fprintf(stderr, "Invalid IP address %s\n", nstr);
281 return false;
284 num = nodemap->num;
285 nodemap->node = talloc_realloc(nodemap, nodemap->node,
286 struct ctdb_node_and_flags, num+1);
287 if (nodemap->node == NULL) {
288 return false;
291 n = &nodemap->node[num];
292 n->addr = addr;
293 n->pnn = num;
294 n->flags = flags;
296 nodemap->num = num+1;
297 return true;
300 /* Read a nodes file into a node map */
301 static struct ctdb_node_map *ctdb_read_nodes_file(TALLOC_CTX *mem_ctx,
302 const char *nlist)
304 char **lines;
305 int nlines;
306 int i;
307 struct ctdb_node_map *nodemap;
309 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
310 if (nodemap == NULL) {
311 return NULL;
314 lines = file_lines_load(nlist, &nlines, 0, mem_ctx);
315 if (lines == NULL) {
316 return NULL;
319 while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) {
320 nlines--;
323 for (i=0; i<nlines; i++) {
324 char *node;
325 uint32_t flags;
326 size_t len;
328 node = lines[i];
329 /* strip leading spaces */
330 while((*node == ' ') || (*node == '\t')) {
331 node++;
334 len = strlen(node);
336 /* strip trailing spaces */
337 while ((len > 1) &&
338 ((node[len-1] == ' ') || (node[len-1] == '\t')))
340 node[len-1] = '\0';
341 len--;
344 if (len == 0) {
345 continue;
347 if (*node == '#') {
348 /* A "deleted" node is a node that is
349 commented out in the nodes file. This is
350 used instead of removing a line, which
351 would cause subsequent nodes to change
352 their PNN. */
353 flags = NODE_FLAGS_DELETED;
354 node = discard_const("0.0.0.0");
355 } else {
356 flags = 0;
358 if (! node_map_add(nodemap, node, flags)) {
359 talloc_free(lines);
360 TALLOC_FREE(nodemap);
361 return NULL;
365 talloc_free(lines);
366 return nodemap;
369 static struct ctdb_node_map *read_nodes_file(TALLOC_CTX *mem_ctx,
370 uint32_t pnn)
372 struct ctdb_node_map *nodemap;
373 char nodepath[PATH_MAX];
374 const char *nodes_list;
376 /* read the nodes file */
377 sprintf(nodepath, "CTDB_NODES_%u", pnn);
378 nodes_list = getenv(nodepath);
379 if (nodes_list == NULL) {
380 nodes_list = getenv("CTDB_NODES");
381 if (nodes_list == NULL) {
382 DEBUG(DEBUG_INFO, ("Nodes file not defined\n"));
383 return NULL;
387 nodemap = ctdb_read_nodes_file(mem_ctx, nodes_list);
388 if (nodemap == NULL) {
389 DEBUG(DEBUG_INFO, ("Failed to read nodes file \"%s\"\n",
390 nodes_list));
391 return NULL;
394 return nodemap;
397 static struct interface_map *interfaces_init(TALLOC_CTX *mem_ctx)
399 struct interface_map *iface_map;
401 iface_map = talloc_zero(mem_ctx, struct interface_map);
402 if (iface_map == NULL) {
403 return NULL;
406 return iface_map;
409 /* Read interfaces information. Same format as "ctdb ifaces -Y"
410 * output:
411 * :Name:LinkStatus:References:
412 * :eth2:1:4294967294
413 * :eth1:1:4294967292
416 static bool interfaces_parse(struct interface_map *iface_map)
418 char line[1024];
420 while ((fgets(line, sizeof(line), stdin) != NULL)) {
421 uint16_t link_state;
422 uint32_t references;
423 char *tok, *t, *name;
424 struct interface *iface;
426 if (line[0] == '\n') {
427 break;
430 /* Get rid of pesky newline */
431 if ((t = strchr(line, '\n')) != NULL) {
432 *t = '\0';
435 if (strcmp(line, ":Name:LinkStatus:References:") == 0) {
436 continue;
439 /* Leading colon... */
440 // tok = strtok(line, ":");
442 /* name */
443 tok = strtok(line, ":");
444 if (tok == NULL) {
445 fprintf(stderr, "bad line (%s) - missing name\n", line);
446 continue;
448 name = tok;
450 /* link_state */
451 tok = strtok(NULL, ":");
452 if (tok == NULL) {
453 fprintf(stderr, "bad line (%s) - missing link state\n",
454 line);
455 continue;
457 link_state = (uint16_t)strtoul(tok, NULL, 0);
459 /* references... */
460 tok = strtok(NULL, ":");
461 if (tok == NULL) {
462 fprintf(stderr, "bad line (%s) - missing references\n",
463 line);
464 continue;
466 references = (uint32_t)strtoul(tok, NULL, 0);
468 iface_map->iface = talloc_realloc(iface_map, iface_map->iface,
469 struct interface,
470 iface_map->num + 1);
471 if (iface_map->iface == NULL) {
472 goto fail;
475 iface = &iface_map->iface[iface_map->num];
477 iface->name = talloc_strdup(iface_map, name);
478 if (iface->name == NULL) {
479 goto fail;
481 iface->link_up = link_state;
482 iface->references = references;
484 iface_map->num += 1;
487 DEBUG(DEBUG_INFO, ("Parsing interfaces done\n"));
488 return true;
490 fail:
491 fprintf(stderr, "Parsing interfaces failed\n");
492 return false;
495 static struct vnn_map *vnnmap_init(TALLOC_CTX *mem_ctx)
497 struct vnn_map *vnn_map;
499 vnn_map = talloc_zero(mem_ctx, struct vnn_map);
500 if (vnn_map == NULL) {
501 fprintf(stderr, "Memory error\n");
502 return NULL;
504 vnn_map->recmode = CTDB_RECOVERY_ACTIVE;
505 vnn_map->generation = INVALID_GENERATION;
507 return vnn_map;
510 /* Read vnn map.
511 * output:
512 * <GENERATION>
513 * <LMASTER0>
514 * <LMASTER1>
515 * ...
518 static bool vnnmap_parse(struct vnn_map *vnn_map)
520 char line[1024];
522 while (fgets(line, sizeof(line), stdin) != NULL) {
523 uint32_t n;
524 char *t;
526 if (line[0] == '\n') {
527 break;
530 /* Get rid of pesky newline */
531 if ((t = strchr(line, '\n')) != NULL) {
532 *t = '\0';
535 n = (uint32_t) strtol(line, NULL, 0);
537 /* generation */
538 if (vnn_map->generation == INVALID_GENERATION) {
539 vnn_map->generation = n;
540 continue;
543 vnn_map->map = talloc_realloc(vnn_map, vnn_map->map, uint32_t,
544 vnn_map->size + 1);
545 if (vnn_map->map == NULL) {
546 fprintf(stderr, "Memory error\n");
547 goto fail;
550 vnn_map->map[vnn_map->size] = n;
551 vnn_map->size += 1;
554 DEBUG(DEBUG_INFO, ("Parsing vnnmap done\n"));
555 return true;
557 fail:
558 fprintf(stderr, "Parsing vnnmap failed\n");
559 return false;
562 static bool reclock_parse(struct ctdbd_context *ctdb)
564 char line[1024];
565 char *t;
567 if (fgets(line, sizeof(line), stdin) == NULL) {
568 goto fail;
571 if (line[0] == '\n') {
572 /* Recovery lock remains unset */
573 goto ok;
576 /* Get rid of pesky newline */
577 if ((t = strchr(line, '\n')) != NULL) {
578 *t = '\0';
581 ctdb->reclock = talloc_strdup(ctdb, line);
582 if (ctdb->reclock == NULL) {
583 goto fail;
586 /* Swallow possible blank line following section. Picky
587 * compiler settings don't allow the return value to be
588 * ignored, so make the compiler happy.
590 if (fgets(line, sizeof(line), stdin) == NULL) {
593 DEBUG(DEBUG_INFO, ("Parsing reclock done\n"));
594 return true;
596 fail:
597 fprintf(stderr, "Parsing reclock failed\n");
598 return false;
601 static struct database_map *dbmap_init(TALLOC_CTX *mem_ctx)
603 struct database_map *db_map;
605 db_map = talloc_zero(mem_ctx, struct database_map);
606 if (db_map == NULL) {
607 return NULL;
610 return db_map;
613 /* Read a database map from stdin. Each line looks like:
614 * <ID> <NAME> [FLAGS] [SEQ_NUM]
615 * EOF or a blank line terminates input.
617 * By default, flags and seq_num are 0
620 static bool dbmap_parse(struct database_map *db_map)
622 char line[1024];
624 while ((fgets(line, sizeof(line), stdin) != NULL)) {
625 uint32_t id;
626 uint8_t flags = 0;
627 uint32_t seq_num = 0;
628 char *tok, *t;
629 char *name;
630 struct database *db;
632 if (line[0] == '\n') {
633 break;
636 /* Get rid of pesky newline */
637 if ((t = strchr(line, '\n')) != NULL) {
638 *t = '\0';
641 /* Get ID */
642 tok = strtok(line, " \t");
643 if (tok == NULL) {
644 fprintf(stderr, "bad line (%s) - missing ID\n", line);
645 continue;
647 id = (uint32_t)strtoul(tok, NULL, 0);
649 /* Get NAME */
650 tok = strtok(NULL, " \t");
651 if (tok == NULL) {
652 fprintf(stderr, "bad line (%s) - missing NAME\n", line);
653 continue;
655 name = talloc_strdup(db_map, tok);
656 if (name == NULL) {
657 goto fail;
660 /* Get flags */
661 tok = strtok(NULL, " \t");
662 while (tok != NULL) {
663 if (strcmp(tok, "PERSISTENT") == 0) {
664 flags |= CTDB_DB_FLAGS_PERSISTENT;
665 } else if (strcmp(tok, "STICKY") == 0) {
666 flags |= CTDB_DB_FLAGS_STICKY;
667 } else if (strcmp(tok, "READONLY") == 0) {
668 flags |= CTDB_DB_FLAGS_READONLY;
669 } else if (strcmp(tok, "REPLICATED") == 0) {
670 flags |= CTDB_DB_FLAGS_REPLICATED;
671 } else if (tok[0] >= '0'&& tok[0] <= '9') {
672 uint8_t nv = CTDB_DB_FLAGS_PERSISTENT |
673 CTDB_DB_FLAGS_REPLICATED;
675 if ((flags & nv) == 0) {
676 fprintf(stderr,
677 "seq_num for volatile db\n");
678 goto fail;
680 seq_num = (uint64_t)strtoull(tok, NULL, 0);
683 tok = strtok(NULL, " \t");
686 db_map->db = talloc_realloc(db_map, db_map->db,
687 struct database,
688 db_map->num_dbs + 1);
689 if (db_map->db == NULL) {
690 goto fail;
692 db = &db_map->db[db_map->num_dbs];
694 db->id = id;
695 db->name = name;
696 db->flags = flags;
697 db->seq_num = seq_num;
699 db_map->num_dbs += 1;
702 DEBUG(DEBUG_INFO, ("Parsing dbmap done\n"));
703 return true;
705 fail:
706 DEBUG(DEBUG_INFO, ("Parsing dbmap failed\n"));
707 return false;
711 static struct database *database_find(struct database_map *map,
712 uint32_t db_id)
714 int i;
716 for (i = 0; i < map->num_dbs; i++) {
717 struct database *db = &map->db[i];
719 if (db->id == db_id) {
720 return db;
724 return NULL;
727 static bool public_ips_parse(struct ctdbd_context *ctdb,
728 uint32_t numnodes)
730 if (numnodes == 0) {
731 D_ERR("Must initialise nodemap before public IPs\n");
732 return false;
735 ctdb->known_ips = ipalloc_read_known_ips(ctdb, numnodes, false);
737 return (ctdb->known_ips != NULL);
740 /* Read information about controls to fail. Format is:
741 * <opcode> <pnn> {ERROR|TIMEOUT} <comment>
743 static bool control_failures_parse(struct ctdbd_context *ctdb)
745 char line[1024];
747 while ((fgets(line, sizeof(line), stdin) != NULL)) {
748 char *tok, *t;
749 enum ctdb_controls opcode;
750 uint32_t pnn;
751 const char *error;
752 const char *comment;
753 struct fake_control_failure *failure = NULL;
755 if (line[0] == '\n') {
756 break;
759 /* Get rid of pesky newline */
760 if ((t = strchr(line, '\n')) != NULL) {
761 *t = '\0';
764 /* Get opcode */
765 tok = strtok(line, " \t");
766 if (tok == NULL) {
767 D_ERR("bad line (%s) - missing opcode\n", line);
768 continue;
770 opcode = (enum ctdb_controls)strtoul(tok, NULL, 0);
772 /* Get PNN */
773 tok = strtok(NULL, " \t");
774 if (tok == NULL) {
775 D_ERR("bad line (%s) - missing PNN\n", line);
776 continue;
778 pnn = (uint32_t)strtoul(tok, NULL, 0);
780 /* Get error */
781 tok = strtok(NULL, " \t");
782 if (tok == NULL) {
783 D_ERR("bad line (%s) - missing errno\n", line);
784 continue;
786 error = talloc_strdup(ctdb, tok);
787 if (error == NULL) {
788 goto fail;
790 if (strcmp(error, "ERROR") != 0 &&
791 strcmp(error, "TIMEOUT") != 0) {
792 D_ERR("bad line (%s) "
793 "- error must be \"ERROR\" or \"TIMEOUT\"\n",
794 line);
795 goto fail;
798 /* Get comment */
799 tok = strtok(NULL, "\n"); /* rest of line */
800 if (tok == NULL) {
801 D_ERR("bad line (%s) - missing comment\n", line);
802 continue;
804 comment = talloc_strdup(ctdb, tok);
805 if (comment == NULL) {
806 goto fail;
809 failure = talloc_zero(ctdb, struct fake_control_failure);
810 if (failure == NULL) {
811 goto fail;
814 failure->opcode = opcode;
815 failure->pnn = pnn;
816 failure->error = error;
817 failure->comment = comment;
819 DLIST_ADD(ctdb->control_failures, failure);
822 D_INFO("Parsing fake control failures done\n");
823 return true;
825 fail:
826 D_INFO("Parsing fake control failures failed\n");
827 return false;
831 * Manage clients
834 static int ctdb_client_destructor(struct ctdb_client *client)
836 DLIST_REMOVE(client->ctdb->client_list, client);
837 return 0;
840 static int client_add(struct ctdbd_context *ctdb, pid_t client_pid,
841 void *client_state)
843 struct ctdb_client *client;
845 client = talloc_zero(client_state, struct ctdb_client);
846 if (client == NULL) {
847 return ENOMEM;
850 client->ctdb = ctdb;
851 client->pid = client_pid;
852 client->state = client_state;
854 DLIST_ADD(ctdb->client_list, client);
855 talloc_set_destructor(client, ctdb_client_destructor);
856 return 0;
859 static void *client_find(struct ctdbd_context *ctdb, pid_t client_pid)
861 struct ctdb_client *client;
863 for (client=ctdb->client_list; client != NULL; client=client->next) {
864 if (client->pid == client_pid) {
865 return client->state;
869 return NULL;
873 * CTDB context setup
876 static uint32_t new_generation(uint32_t old_generation)
878 uint32_t generation;
880 while (1) {
881 generation = random();
882 if (generation != INVALID_GENERATION &&
883 generation != old_generation) {
884 break;
888 return generation;
891 static struct ctdbd_context *ctdbd_setup(TALLOC_CTX *mem_ctx)
893 struct ctdbd_context *ctdb;
894 char line[1024];
895 bool status;
896 int ret;
898 ctdb = talloc_zero(mem_ctx, struct ctdbd_context);
899 if (ctdb == NULL) {
900 return NULL;
903 ctdb->node_map = nodemap_init(ctdb);
904 if (ctdb->node_map == NULL) {
905 goto fail;
908 ctdb->iface_map = interfaces_init(ctdb);
909 if (ctdb->iface_map == NULL) {
910 goto fail;
913 ctdb->vnn_map = vnnmap_init(ctdb);
914 if (ctdb->vnn_map == NULL) {
915 goto fail;
918 ctdb->db_map = dbmap_init(ctdb);
919 if (ctdb->db_map == NULL) {
920 goto fail;
923 ret = srvid_init(ctdb, &ctdb->srv);
924 if (ret != 0) {
925 goto fail;
928 while (fgets(line, sizeof(line), stdin) != NULL) {
929 char *t;
931 if ((t = strchr(line, '\n')) != NULL) {
932 *t = '\0';
935 if (strcmp(line, "NODEMAP") == 0) {
936 status = nodemap_parse(ctdb->node_map);
937 } else if (strcmp(line, "IFACES") == 0) {
938 status = interfaces_parse(ctdb->iface_map);
939 } else if (strcmp(line, "VNNMAP") == 0) {
940 status = vnnmap_parse(ctdb->vnn_map);
941 } else if (strcmp(line, "DBMAP") == 0) {
942 status = dbmap_parse(ctdb->db_map);
943 } else if (strcmp(line, "PUBLICIPS") == 0) {
944 status = public_ips_parse(ctdb,
945 ctdb->node_map->num_nodes);
946 } else if (strcmp(line, "RECLOCK") == 0) {
947 status = reclock_parse(ctdb);
948 } else if (strcmp(line, "CONTROLFAILS") == 0) {
949 status = control_failures_parse(ctdb);
950 } else {
951 fprintf(stderr, "Unknown line %s\n", line);
952 status = false;
955 if (! status) {
956 goto fail;
960 ctdb->start_time = tevent_timeval_current();
961 ctdb->recovery_start_time = tevent_timeval_current();
962 ctdb->vnn_map->recmode = CTDB_RECOVERY_NORMAL;
963 if (ctdb->vnn_map->generation == INVALID_GENERATION) {
964 ctdb->vnn_map->generation =
965 new_generation(ctdb->vnn_map->generation);
967 ctdb->recovery_end_time = tevent_timeval_current();
969 ctdb->log_level = DEBUG_ERR;
970 ctdb->runstate = CTDB_RUNSTATE_RUNNING;
972 ctdb_tunable_set_defaults(&ctdb->tun_list);
974 ctdb->monitoring_mode = CTDB_MONITORING_ENABLED;
976 return ctdb;
978 fail:
979 TALLOC_FREE(ctdb);
980 return NULL;
983 static bool ctdbd_verify(struct ctdbd_context *ctdb)
985 struct node *node;
986 int i;
988 if (ctdb->node_map->num_nodes == 0) {
989 return true;
992 /* Make sure all the nodes are in order */
993 for (i=0; i<ctdb->node_map->num_nodes; i++) {
994 node = &ctdb->node_map->node[i];
995 if (node->pnn != i) {
996 fprintf(stderr, "Expected node %u, found %u\n",
997 i, node->pnn);
998 return false;
1002 node = &ctdb->node_map->node[ctdb->node_map->pnn];
1003 if (node->flags & NODE_FLAGS_DISCONNECTED) {
1004 DEBUG(DEBUG_INFO, ("Node disconnected, exiting\n"));
1005 exit(0);
1008 return true;
1012 * Doing a recovery
1015 struct recover_state {
1016 struct tevent_context *ev;
1017 struct ctdbd_context *ctdb;
1020 static int recover_check(struct tevent_req *req);
1021 static void recover_wait_done(struct tevent_req *subreq);
1022 static void recover_done(struct tevent_req *subreq);
1024 static struct tevent_req *recover_send(TALLOC_CTX *mem_ctx,
1025 struct tevent_context *ev,
1026 struct ctdbd_context *ctdb)
1028 struct tevent_req *req;
1029 struct recover_state *state;
1030 int ret;
1032 req = tevent_req_create(mem_ctx, &state, struct recover_state);
1033 if (req == NULL) {
1034 return NULL;
1037 state->ev = ev;
1038 state->ctdb = ctdb;
1040 ret = recover_check(req);
1041 if (ret != 0) {
1042 tevent_req_error(req, ret);
1043 return tevent_req_post(req, ev);
1046 return req;
1049 static int recover_check(struct tevent_req *req)
1051 struct recover_state *state = tevent_req_data(
1052 req, struct recover_state);
1053 struct ctdbd_context *ctdb = state->ctdb;
1054 struct tevent_req *subreq;
1055 bool recovery_disabled;
1056 int i;
1058 recovery_disabled = false;
1059 for (i=0; i<ctdb->node_map->num_nodes; i++) {
1060 if (ctdb->node_map->node[i].recovery_disabled) {
1061 recovery_disabled = true;
1062 break;
1066 subreq = tevent_wakeup_send(state, state->ev,
1067 tevent_timeval_current_ofs(1, 0));
1068 if (subreq == NULL) {
1069 return ENOMEM;
1072 if (recovery_disabled) {
1073 tevent_req_set_callback(subreq, recover_wait_done, req);
1074 } else {
1075 ctdb->recovery_start_time = tevent_timeval_current();
1076 tevent_req_set_callback(subreq, recover_done, req);
1079 return 0;
1082 static void recover_wait_done(struct tevent_req *subreq)
1084 struct tevent_req *req = tevent_req_callback_data(
1085 subreq, struct tevent_req);
1086 int ret;
1087 bool status;
1089 status = tevent_wakeup_recv(subreq);
1090 TALLOC_FREE(subreq);
1091 if (! status) {
1092 tevent_req_error(req, EIO);
1093 return;
1096 ret = recover_check(req);
1097 if (ret != 0) {
1098 tevent_req_error(req, ret);
1102 static void recover_done(struct tevent_req *subreq)
1104 struct tevent_req *req = tevent_req_callback_data(
1105 subreq, struct tevent_req);
1106 struct recover_state *state = tevent_req_data(
1107 req, struct recover_state);
1108 struct ctdbd_context *ctdb = state->ctdb;
1109 bool status;
1111 status = tevent_wakeup_recv(subreq);
1112 TALLOC_FREE(subreq);
1113 if (! status) {
1114 tevent_req_error(req, EIO);
1115 return;
1118 ctdb->vnn_map->recmode = CTDB_RECOVERY_NORMAL;
1119 ctdb->recovery_end_time = tevent_timeval_current();
1120 ctdb->vnn_map->generation = new_generation(ctdb->vnn_map->generation);
1122 tevent_req_done(req);
1125 static bool recover_recv(struct tevent_req *req, int *perr)
1127 int err;
1129 if (tevent_req_is_unix_error(req, &err)) {
1130 if (perr != NULL) {
1131 *perr = err;
1133 return false;
1136 return true;
1140 * Routines for ctdb_req_header
1143 static void header_fix_pnn(struct ctdb_req_header *header,
1144 struct ctdbd_context *ctdb)
1146 if (header->srcnode == CTDB_CURRENT_NODE) {
1147 header->srcnode = ctdb->node_map->pnn;
1150 if (header->destnode == CTDB_CURRENT_NODE) {
1151 header->destnode = ctdb->node_map->pnn;
1155 static struct ctdb_req_header header_reply_control(
1156 struct ctdb_req_header *header,
1157 struct ctdbd_context *ctdb)
1159 struct ctdb_req_header reply_header;
1161 reply_header = (struct ctdb_req_header) {
1162 .ctdb_magic = CTDB_MAGIC,
1163 .ctdb_version = CTDB_PROTOCOL,
1164 .generation = ctdb->vnn_map->generation,
1165 .operation = CTDB_REPLY_CONTROL,
1166 .destnode = header->srcnode,
1167 .srcnode = header->destnode,
1168 .reqid = header->reqid,
1171 return reply_header;
1174 static struct ctdb_req_header header_reply_message(
1175 struct ctdb_req_header *header,
1176 struct ctdbd_context *ctdb)
1178 struct ctdb_req_header reply_header;
1180 reply_header = (struct ctdb_req_header) {
1181 .ctdb_magic = CTDB_MAGIC,
1182 .ctdb_version = CTDB_PROTOCOL,
1183 .generation = ctdb->vnn_map->generation,
1184 .operation = CTDB_REQ_MESSAGE,
1185 .destnode = header->srcnode,
1186 .srcnode = header->destnode,
1187 .reqid = 0,
1190 return reply_header;
1194 * Client state
1197 struct client_state {
1198 struct tevent_context *ev;
1199 int fd;
1200 struct ctdbd_context *ctdb;
1201 int pnn;
1202 pid_t pid;
1203 struct comm_context *comm;
1204 struct srvid_register_state *rstate;
1205 int status;
1209 * Send replies to controls and messages
1212 static void client_reply_done(struct tevent_req *subreq);
1214 static void client_send_message(struct tevent_req *req,
1215 struct ctdb_req_header *header,
1216 struct ctdb_req_message_data *message)
1218 struct client_state *state = tevent_req_data(
1219 req, struct client_state);
1220 struct ctdbd_context *ctdb = state->ctdb;
1221 struct tevent_req *subreq;
1222 struct ctdb_req_header reply_header;
1223 uint8_t *buf;
1224 size_t datalen, buflen;
1225 int ret;
1227 reply_header = header_reply_message(header, ctdb);
1229 datalen = ctdb_req_message_data_len(&reply_header, message);
1230 ret = ctdb_allocate_pkt(state, datalen, &buf, &buflen);
1231 if (ret != 0) {
1232 tevent_req_error(req, ret);
1233 return;
1236 ret = ctdb_req_message_data_push(&reply_header, message,
1237 buf, &buflen);
1238 if (ret != 0) {
1239 tevent_req_error(req, ret);
1240 return;
1243 DEBUG(DEBUG_INFO, ("message srvid = 0x%"PRIx64"\n", message->srvid));
1245 subreq = comm_write_send(state, state->ev, state->comm, buf, buflen);
1246 if (tevent_req_nomem(subreq, req)) {
1247 return;
1249 tevent_req_set_callback(subreq, client_reply_done, req);
1251 talloc_steal(subreq, buf);
1254 static void client_send_control(struct tevent_req *req,
1255 struct ctdb_req_header *header,
1256 struct ctdb_reply_control *reply)
1258 struct client_state *state = tevent_req_data(
1259 req, struct client_state);
1260 struct ctdbd_context *ctdb = state->ctdb;
1261 struct tevent_req *subreq;
1262 struct ctdb_req_header reply_header;
1263 uint8_t *buf;
1264 size_t datalen, buflen;
1265 int ret;
1267 reply_header = header_reply_control(header, ctdb);
1269 datalen = ctdb_reply_control_len(&reply_header, reply);
1270 ret = ctdb_allocate_pkt(state, datalen, &buf, &buflen);
1271 if (ret != 0) {
1272 tevent_req_error(req, ret);
1273 return;
1276 ret = ctdb_reply_control_push(&reply_header, reply, buf, &buflen);
1277 if (ret != 0) {
1278 tevent_req_error(req, ret);
1279 return;
1282 DEBUG(DEBUG_INFO, ("reply opcode = %u\n", reply->rdata.opcode));
1284 subreq = comm_write_send(state, state->ev, state->comm, buf, buflen);
1285 if (tevent_req_nomem(subreq, req)) {
1286 return;
1288 tevent_req_set_callback(subreq, client_reply_done, req);
1290 talloc_steal(subreq, buf);
1293 static void client_reply_done(struct tevent_req *subreq)
1295 struct tevent_req *req = tevent_req_callback_data(
1296 subreq, struct tevent_req);
1297 int ret;
1298 bool status;
1300 status = comm_write_recv(subreq, &ret);
1301 TALLOC_FREE(subreq);
1302 if (! status) {
1303 tevent_req_error(req, ret);
1308 * Handling protocol - controls
1311 static void control_process_exists(TALLOC_CTX *mem_ctx,
1312 struct tevent_req *req,
1313 struct ctdb_req_header *header,
1314 struct ctdb_req_control *request)
1316 struct client_state *state = tevent_req_data(
1317 req, struct client_state);
1318 struct ctdbd_context *ctdb = state->ctdb;
1319 struct client_state *cstate;
1320 struct ctdb_reply_control reply;
1322 reply.rdata.opcode = request->opcode;
1324 cstate = client_find(ctdb, request->rdata.data.pid);
1325 if (cstate == NULL) {
1326 reply.status = -1;
1327 reply.errmsg = "No client for PID";
1328 } else {
1329 reply.status = kill(request->rdata.data.pid, 0);
1330 reply.errmsg = NULL;
1333 client_send_control(req, header, &reply);
1336 static void control_ping(TALLOC_CTX *mem_ctx,
1337 struct tevent_req *req,
1338 struct ctdb_req_header *header,
1339 struct ctdb_req_control *request)
1341 struct client_state *state = tevent_req_data(
1342 req, struct client_state);
1343 struct ctdbd_context *ctdb = state->ctdb;
1344 struct ctdb_reply_control reply;
1346 reply.rdata.opcode = request->opcode;
1347 reply.status = ctdb->num_clients;
1348 reply.errmsg = NULL;
1350 client_send_control(req, header, &reply);
1353 static void control_getdbpath(TALLOC_CTX *mem_ctx,
1354 struct tevent_req *req,
1355 struct ctdb_req_header *header,
1356 struct ctdb_req_control *request)
1358 struct client_state *state = tevent_req_data(
1359 req, struct client_state);
1360 struct ctdbd_context *ctdb = state->ctdb;
1361 struct ctdb_reply_control reply;
1362 struct database *db;
1364 reply.rdata.opcode = request->opcode;
1366 db = database_find(ctdb->db_map, request->rdata.data.db_id);
1367 if (db == NULL) {
1368 reply.status = ENOENT;
1369 reply.errmsg = "Database not found";
1370 } else {
1371 const char *base;
1372 if (db->flags & CTDB_DB_FLAGS_PERSISTENT) {
1373 base = "/var/lib/ctdb/persistent";
1374 } else {
1375 base = "/var/run/ctdb/DB_DIR";
1377 reply.rdata.data.db_path =
1378 talloc_asprintf(mem_ctx, "%s/%s.%u",
1379 base, db->name, header->destnode);
1380 if (reply.rdata.data.db_path == NULL) {
1381 reply.status = ENOMEM;
1382 reply.errmsg = "Memory error";
1383 } else {
1384 reply.status = 0;
1385 reply.errmsg = NULL;
1389 client_send_control(req, header, &reply);
1392 static void control_getvnnmap(TALLOC_CTX *mem_ctx,
1393 struct tevent_req *req,
1394 struct ctdb_req_header *header,
1395 struct ctdb_req_control *request)
1397 struct client_state *state = tevent_req_data(
1398 req, struct client_state);
1399 struct ctdbd_context *ctdb = state->ctdb;
1400 struct ctdb_reply_control reply;
1401 struct ctdb_vnn_map *vnnmap;
1403 reply.rdata.opcode = request->opcode;
1405 vnnmap = talloc_zero(mem_ctx, struct ctdb_vnn_map);
1406 if (vnnmap == NULL) {
1407 reply.status = ENOMEM;
1408 reply.errmsg = "Memory error";
1409 } else {
1410 vnnmap->generation = ctdb->vnn_map->generation;
1411 vnnmap->size = ctdb->vnn_map->size;
1412 vnnmap->map = ctdb->vnn_map->map;
1414 reply.rdata.data.vnnmap = vnnmap;
1415 reply.status = 0;
1416 reply.errmsg = NULL;
1419 client_send_control(req, header, &reply);
1422 static void control_get_debug(TALLOC_CTX *mem_ctx,
1423 struct tevent_req *req,
1424 struct ctdb_req_header *header,
1425 struct ctdb_req_control *request)
1427 struct client_state *state = tevent_req_data(
1428 req, struct client_state);
1429 struct ctdbd_context *ctdb = state->ctdb;
1430 struct ctdb_reply_control reply;
1432 reply.rdata.opcode = request->opcode;
1433 reply.rdata.data.loglevel = (uint32_t)ctdb->log_level;
1434 reply.status = 0;
1435 reply.errmsg = NULL;
1437 client_send_control(req, header, &reply);
1440 static void control_set_debug(TALLOC_CTX *mem_ctx,
1441 struct tevent_req *req,
1442 struct ctdb_req_header *header,
1443 struct ctdb_req_control *request)
1445 struct client_state *state = tevent_req_data(
1446 req, struct client_state);
1447 struct ctdbd_context *ctdb = state->ctdb;
1448 struct ctdb_reply_control reply;
1450 ctdb->log_level = (int)request->rdata.data.loglevel;
1452 reply.rdata.opcode = request->opcode;
1453 reply.status = 0;
1454 reply.errmsg = NULL;
1456 client_send_control(req, header, &reply);
1459 static void control_get_dbmap(TALLOC_CTX *mem_ctx,
1460 struct tevent_req *req,
1461 struct ctdb_req_header *header,
1462 struct ctdb_req_control *request)
1464 struct client_state *state = tevent_req_data(
1465 req, struct client_state);
1466 struct ctdbd_context *ctdb = state->ctdb;
1467 struct ctdb_reply_control reply;
1468 struct ctdb_dbid_map *dbmap;
1469 int i;
1471 reply.rdata.opcode = request->opcode;
1473 dbmap = talloc_zero(mem_ctx, struct ctdb_dbid_map);
1474 if (dbmap == NULL) {
1475 goto fail;
1478 dbmap->num = ctdb->db_map->num_dbs;
1479 dbmap->dbs = talloc_zero_array(dbmap, struct ctdb_dbid, dbmap->num);
1480 if (dbmap->dbs == NULL) {
1481 goto fail;
1484 for (i = 0; i < dbmap->num; i++) {
1485 struct database *db = &ctdb->db_map->db[i];
1486 dbmap->dbs[i] = (struct ctdb_dbid) {
1487 .db_id = db->id,
1488 .flags = db->flags,
1492 reply.rdata.data.dbmap = dbmap;
1493 reply.status = 0;
1494 reply.errmsg = NULL;
1495 client_send_control(req, header, &reply);
1496 return;
1498 fail:
1499 reply.status = -1;
1500 reply.errmsg = "Memory error";
1501 client_send_control(req, header, &reply);
1504 static void control_get_recmode(TALLOC_CTX *mem_ctx,
1505 struct tevent_req *req,
1506 struct ctdb_req_header *header,
1507 struct ctdb_req_control *request)
1509 struct client_state *state = tevent_req_data(
1510 req, struct client_state);
1511 struct ctdbd_context *ctdb = state->ctdb;
1512 struct ctdb_reply_control reply;
1514 reply.rdata.opcode = request->opcode;
1515 reply.status = ctdb->vnn_map->recmode;
1516 reply.errmsg = NULL;
1518 client_send_control(req, header, &reply);
1521 struct set_recmode_state {
1522 struct tevent_req *req;
1523 struct ctdbd_context *ctdb;
1524 struct ctdb_req_header header;
1525 struct ctdb_reply_control reply;
1528 static void set_recmode_callback(struct tevent_req *subreq)
1530 struct set_recmode_state *substate = tevent_req_callback_data(
1531 subreq, struct set_recmode_state);
1532 bool status;
1533 int ret;
1535 status = recover_recv(subreq, &ret);
1536 TALLOC_FREE(subreq);
1537 if (! status) {
1538 substate->reply.status = ret;
1539 substate->reply.errmsg = "recovery failed";
1540 } else {
1541 substate->reply.status = 0;
1542 substate->reply.errmsg = NULL;
1545 client_send_control(substate->req, &substate->header, &substate->reply);
1546 talloc_free(substate);
1549 static void control_set_recmode(TALLOC_CTX *mem_ctx,
1550 struct tevent_req *req,
1551 struct ctdb_req_header *header,
1552 struct ctdb_req_control *request)
1554 struct client_state *state = tevent_req_data(
1555 req, struct client_state);
1556 struct tevent_req *subreq;
1557 struct ctdbd_context *ctdb = state->ctdb;
1558 struct set_recmode_state *substate;
1559 struct ctdb_reply_control reply;
1561 reply.rdata.opcode = request->opcode;
1563 if (request->rdata.data.recmode == CTDB_RECOVERY_NORMAL) {
1564 reply.status = -1;
1565 reply.errmsg = "Client cannot set recmode to NORMAL";
1566 goto fail;
1569 substate = talloc_zero(ctdb, struct set_recmode_state);
1570 if (substate == NULL) {
1571 reply.status = -1;
1572 reply.errmsg = "Memory error";
1573 goto fail;
1576 substate->req = req;
1577 substate->ctdb = ctdb;
1578 substate->header = *header;
1579 substate->reply.rdata.opcode = request->opcode;
1581 subreq = recover_send(substate, state->ev, state->ctdb);
1582 if (subreq == NULL) {
1583 talloc_free(substate);
1584 goto fail;
1586 tevent_req_set_callback(subreq, set_recmode_callback, substate);
1588 ctdb->vnn_map->recmode = CTDB_RECOVERY_ACTIVE;
1589 return;
1591 fail:
1592 client_send_control(req, header, &reply);
1596 static void srvid_handler(uint64_t srvid, TDB_DATA data, void *private_data)
1598 printf("Received a message for SRVID 0x%"PRIx64"\n", srvid);
1601 static void control_register_srvid(TALLOC_CTX *mem_ctx,
1602 struct tevent_req *req,
1603 struct ctdb_req_header *header,
1604 struct ctdb_req_control *request)
1606 struct client_state *state = tevent_req_data(
1607 req, struct client_state);
1608 struct ctdbd_context *ctdb = state->ctdb;
1609 struct ctdb_reply_control reply;
1610 int ret;
1612 reply.rdata.opcode = request->opcode;
1614 ret = srvid_register(ctdb->srv, state, request->srvid,
1615 srvid_handler, state);
1616 if (ret != 0) {
1617 reply.status = -1;
1618 reply.errmsg = "Memory error";
1619 goto fail;
1622 DEBUG(DEBUG_INFO, ("Register srvid 0x%"PRIx64"\n", request->srvid));
1624 reply.status = 0;
1625 reply.errmsg = NULL;
1627 fail:
1628 client_send_control(req, header, &reply);
1631 static void control_deregister_srvid(TALLOC_CTX *mem_ctx,
1632 struct tevent_req *req,
1633 struct ctdb_req_header *header,
1634 struct ctdb_req_control *request)
1636 struct client_state *state = tevent_req_data(
1637 req, struct client_state);
1638 struct ctdbd_context *ctdb = state->ctdb;
1639 struct ctdb_reply_control reply;
1640 int ret;
1642 reply.rdata.opcode = request->opcode;
1644 ret = srvid_deregister(ctdb->srv, request->srvid, state);
1645 if (ret != 0) {
1646 reply.status = -1;
1647 reply.errmsg = "srvid not registered";
1648 goto fail;
1651 DEBUG(DEBUG_INFO, ("Deregister srvid 0x%"PRIx64"\n", request->srvid));
1653 reply.status = 0;
1654 reply.errmsg = NULL;
1656 fail:
1657 client_send_control(req, header, &reply);
1660 static void control_get_dbname(TALLOC_CTX *mem_ctx,
1661 struct tevent_req *req,
1662 struct ctdb_req_header *header,
1663 struct ctdb_req_control *request)
1665 struct client_state *state = tevent_req_data(
1666 req, struct client_state);
1667 struct ctdbd_context *ctdb = state->ctdb;
1668 struct ctdb_reply_control reply;
1669 struct database *db;
1671 reply.rdata.opcode = request->opcode;
1673 db = database_find(ctdb->db_map, request->rdata.data.db_id);
1674 if (db == NULL) {
1675 reply.status = ENOENT;
1676 reply.errmsg = "Database not found";
1677 } else {
1678 reply.rdata.data.db_name = talloc_strdup(mem_ctx, db->name);
1679 if (reply.rdata.data.db_name == NULL) {
1680 reply.status = ENOMEM;
1681 reply.errmsg = "Memory error";
1682 } else {
1683 reply.status = 0;
1684 reply.errmsg = NULL;
1688 client_send_control(req, header, &reply);
1691 static void control_get_pid(TALLOC_CTX *mem_ctx,
1692 struct tevent_req *req,
1693 struct ctdb_req_header *header,
1694 struct ctdb_req_control *request)
1696 struct ctdb_reply_control reply;
1698 reply.rdata.opcode = request->opcode;
1699 reply.status = getpid();
1700 reply.errmsg = NULL;
1702 client_send_control(req, header, &reply);
1705 static void control_get_recmaster(TALLOC_CTX *mem_ctx,
1706 struct tevent_req *req,
1707 struct ctdb_req_header *header,
1708 struct ctdb_req_control *request)
1710 struct client_state *state = tevent_req_data(
1711 req, struct client_state);
1712 struct ctdbd_context *ctdb = state->ctdb;
1713 struct ctdb_reply_control reply;
1715 reply.rdata.opcode = request->opcode;
1716 reply.status = ctdb->node_map->recmaster;
1717 reply.errmsg = NULL;
1719 client_send_control(req, header, &reply);
1722 static void control_get_pnn(TALLOC_CTX *mem_ctx,
1723 struct tevent_req *req,
1724 struct ctdb_req_header *header,
1725 struct ctdb_req_control *request)
1727 struct ctdb_reply_control reply;
1729 reply.rdata.opcode = request->opcode;
1730 reply.status = header->destnode;
1731 reply.errmsg = NULL;
1733 client_send_control(req, header, &reply);
1736 static void control_shutdown(TALLOC_CTX *mem_ctx,
1737 struct tevent_req *req,
1738 struct ctdb_req_header *hdr,
1739 struct ctdb_req_control *request)
1741 struct client_state *state = tevent_req_data(
1742 req, struct client_state);
1744 state->status = 99;
1747 static void control_get_monmode(TALLOC_CTX *mem_ctx,
1748 struct tevent_req *req,
1749 struct ctdb_req_header *header,
1750 struct ctdb_req_control *request)
1752 struct client_state *state = tevent_req_data(
1753 req, struct client_state);
1754 struct ctdbd_context *ctdb = state->ctdb;
1755 struct ctdb_reply_control reply;
1757 reply.rdata.opcode = request->opcode;
1758 reply.status = ctdb->monitoring_mode;
1759 reply.errmsg = NULL;
1761 client_send_control(req, header, &reply);
1764 static void control_set_tunable(TALLOC_CTX *mem_ctx,
1765 struct tevent_req *req,
1766 struct ctdb_req_header *header,
1767 struct ctdb_req_control *request)
1769 struct client_state *state = tevent_req_data(
1770 req, struct client_state);
1771 struct ctdbd_context *ctdb = state->ctdb;
1772 struct ctdb_reply_control reply;
1773 bool ret, obsolete;
1775 reply.rdata.opcode = request->opcode;
1776 reply.errmsg = NULL;
1778 ret = ctdb_tunable_set_value(&ctdb->tun_list,
1779 request->rdata.data.tunable->name,
1780 request->rdata.data.tunable->value,
1781 &obsolete);
1782 if (! ret) {
1783 reply.status = -1;
1784 } else if (obsolete) {
1785 reply.status = 1;
1786 } else {
1787 reply.status = 0;
1790 client_send_control(req, header, &reply);
1793 static void control_get_tunable(TALLOC_CTX *mem_ctx,
1794 struct tevent_req *req,
1795 struct ctdb_req_header *header,
1796 struct ctdb_req_control *request)
1798 struct client_state *state = tevent_req_data(
1799 req, struct client_state);
1800 struct ctdbd_context *ctdb = state->ctdb;
1801 struct ctdb_reply_control reply;
1802 uint32_t value;
1803 bool ret;
1805 reply.rdata.opcode = request->opcode;
1806 reply.errmsg = NULL;
1808 ret = ctdb_tunable_get_value(&ctdb->tun_list,
1809 request->rdata.data.tun_var, &value);
1810 if (! ret) {
1811 reply.status = -1;
1812 } else {
1813 reply.rdata.data.tun_value = value;
1814 reply.status = 0;
1817 client_send_control(req, header, &reply);
1820 static void control_list_tunables(TALLOC_CTX *mem_ctx,
1821 struct tevent_req *req,
1822 struct ctdb_req_header *header,
1823 struct ctdb_req_control *request)
1825 struct ctdb_reply_control reply;
1826 struct ctdb_var_list *var_list;
1828 reply.rdata.opcode = request->opcode;
1829 reply.errmsg = NULL;
1831 var_list = ctdb_tunable_names(mem_ctx);
1832 if (var_list == NULL) {
1833 reply.status = -1;
1834 } else {
1835 reply.rdata.data.tun_var_list = var_list;
1836 reply.status = 0;
1839 client_send_control(req, header, &reply);
1842 static void control_modify_flags(TALLOC_CTX *mem_ctx,
1843 struct tevent_req *req,
1844 struct ctdb_req_header *header,
1845 struct ctdb_req_control *request)
1847 struct client_state *state = tevent_req_data(
1848 req, struct client_state);
1849 struct ctdbd_context *ctdb = state->ctdb;
1850 struct ctdb_node_flag_change *change = request->rdata.data.flag_change;
1851 struct ctdb_reply_control reply;
1852 struct node *node;
1854 reply.rdata.opcode = request->opcode;
1856 if ((change->old_flags & ~NODE_FLAGS_PERMANENTLY_DISABLED) ||
1857 (change->new_flags & ~NODE_FLAGS_PERMANENTLY_DISABLED) != 0) {
1858 DEBUG(DEBUG_INFO,
1859 ("MODIFY_FLAGS control not for PERMANENTLY_DISABLED\n"));
1860 reply.status = EINVAL;
1861 reply.errmsg = "Failed to MODIFY_FLAGS";
1862 client_send_control(req, header, &reply);
1863 return;
1866 /* There's all sorts of broadcast weirdness here. Only change
1867 * the specified node, not the destination node of the
1868 * control. */
1869 node = &ctdb->node_map->node[change->pnn];
1871 if ((node->flags &
1872 change->old_flags & NODE_FLAGS_PERMANENTLY_DISABLED) == 0 &&
1873 (change->new_flags & NODE_FLAGS_PERMANENTLY_DISABLED) != 0) {
1874 DEBUG(DEBUG_INFO,("Disabling node %d\n", header->destnode));
1875 node->flags |= NODE_FLAGS_PERMANENTLY_DISABLED;
1876 goto done;
1879 if ((node->flags &
1880 change->old_flags & NODE_FLAGS_PERMANENTLY_DISABLED) != 0 &&
1881 (change->new_flags & NODE_FLAGS_PERMANENTLY_DISABLED) == 0) {
1882 DEBUG(DEBUG_INFO,("Enabling node %d\n", header->destnode));
1883 node->flags &= ~NODE_FLAGS_PERMANENTLY_DISABLED;
1884 goto done;
1887 DEBUG(DEBUG_INFO, ("Flags unchanged for node %d\n", header->destnode));
1889 done:
1890 reply.status = 0;
1891 reply.errmsg = NULL;
1892 client_send_control(req, header, &reply);
1895 static void control_get_all_tunables(TALLOC_CTX *mem_ctx,
1896 struct tevent_req *req,
1897 struct ctdb_req_header *header,
1898 struct ctdb_req_control *request)
1900 struct client_state *state = tevent_req_data(
1901 req, struct client_state);
1902 struct ctdbd_context *ctdb = state->ctdb;
1903 struct ctdb_reply_control reply;
1905 reply.rdata.opcode = request->opcode;
1906 reply.rdata.data.tun_list = &ctdb->tun_list;
1907 reply.status = 0;
1908 reply.errmsg = NULL;
1910 client_send_control(req, header, &reply);
1913 static void control_uptime(TALLOC_CTX *mem_ctx,
1914 struct tevent_req *req,
1915 struct ctdb_req_header *header,
1916 struct ctdb_req_control *request)
1918 struct client_state *state = tevent_req_data(
1919 req, struct client_state);
1920 struct ctdbd_context *ctdb = state->ctdb;
1921 struct ctdb_reply_control reply;
1922 struct ctdb_uptime *uptime;;
1924 reply.rdata.opcode = request->opcode;
1926 uptime = talloc_zero(mem_ctx, struct ctdb_uptime);
1927 if (uptime == NULL) {
1928 goto fail;
1931 uptime->current_time = tevent_timeval_current();
1932 uptime->ctdbd_start_time = ctdb->start_time;
1933 uptime->last_recovery_started = ctdb->recovery_start_time;
1934 uptime->last_recovery_finished = ctdb->recovery_end_time;
1936 reply.rdata.data.uptime = uptime;
1937 reply.status = 0;
1938 reply.errmsg = NULL;
1939 client_send_control(req, header, &reply);
1940 return;
1942 fail:
1943 reply.status = -1;
1944 reply.errmsg = "Memory error";
1945 client_send_control(req, header, &reply);
1948 static void control_enable_monitor(TALLOC_CTX *mem_ctx,
1949 struct tevent_req *req,
1950 struct ctdb_req_header *header,
1951 struct ctdb_req_control *request)
1953 struct client_state *state = tevent_req_data(
1954 req, struct client_state);
1955 struct ctdbd_context *ctdb = state->ctdb;
1956 struct ctdb_reply_control reply;
1958 ctdb->monitoring_mode = CTDB_MONITORING_ENABLED;
1960 reply.rdata.opcode = request->opcode;
1961 reply.status = 0;
1962 reply.errmsg = NULL;
1963 client_send_control(req, header, &reply);
1966 static void control_disable_monitor(TALLOC_CTX *mem_ctx,
1967 struct tevent_req *req,
1968 struct ctdb_req_header *header,
1969 struct ctdb_req_control *request)
1971 struct client_state *state = tevent_req_data(
1972 req, struct client_state);
1973 struct ctdbd_context *ctdb = state->ctdb;
1974 struct ctdb_reply_control reply;
1976 ctdb->monitoring_mode = CTDB_MONITORING_DISABLED;
1978 reply.rdata.opcode = request->opcode;
1979 reply.status = 0;
1980 reply.errmsg = NULL;
1981 client_send_control(req, header, &reply);
1984 static void control_reload_nodes_file(TALLOC_CTX *mem_ctx,
1985 struct tevent_req *req,
1986 struct ctdb_req_header *header,
1987 struct ctdb_req_control *request)
1989 struct client_state *state = tevent_req_data(
1990 req, struct client_state);
1991 struct ctdbd_context *ctdb = state->ctdb;
1992 struct ctdb_reply_control reply;
1993 struct ctdb_node_map *nodemap;
1994 struct node_map *node_map = ctdb->node_map;
1995 int i;
1997 reply.rdata.opcode = request->opcode;
1999 nodemap = read_nodes_file(mem_ctx, header->destnode);
2000 if (nodemap == NULL) {
2001 goto fail;
2004 for (i=0; i<nodemap->num; i++) {
2005 struct node *node;
2007 if (i < node_map->num_nodes &&
2008 ctdb_sock_addr_same(&nodemap->node[i].addr,
2009 &node_map->node[i].addr)) {
2010 continue;
2013 if (nodemap->node[i].flags & NODE_FLAGS_DELETED) {
2014 node = &node_map->node[i];
2016 node->flags |= NODE_FLAGS_DELETED;
2017 parse_ip("0.0.0.0", NULL, 0, &node->addr);
2019 continue;
2022 if (i < node_map->num_nodes &&
2023 node_map->node[i].flags & NODE_FLAGS_DELETED) {
2024 node = &node_map->node[i];
2026 node->flags &= ~NODE_FLAGS_DELETED;
2027 node->addr = nodemap->node[i].addr;
2029 continue;
2032 node_map->node = talloc_realloc(node_map, node_map->node,
2033 struct node,
2034 node_map->num_nodes+1);
2035 if (node_map->node == NULL) {
2036 goto fail;
2038 node = &node_map->node[node_map->num_nodes];
2040 node->addr = nodemap->node[i].addr;
2041 node->pnn = nodemap->node[i].pnn;
2042 node->flags = 0;
2043 node->capabilities = CTDB_CAP_DEFAULT;
2044 node->recovery_disabled = false;
2045 node->recovery_substate = NULL;
2047 node_map->num_nodes += 1;
2050 talloc_free(nodemap);
2052 reply.status = 0;
2053 reply.errmsg = NULL;
2054 client_send_control(req, header, &reply);
2055 return;
2057 fail:
2058 reply.status = -1;
2059 reply.errmsg = "Memory error";
2060 client_send_control(req, header, &reply);
2063 static void control_get_capabilities(TALLOC_CTX *mem_ctx,
2064 struct tevent_req *req,
2065 struct ctdb_req_header *header,
2066 struct ctdb_req_control *request)
2068 struct client_state *state = tevent_req_data(
2069 req, struct client_state);
2070 struct ctdbd_context *ctdb = state->ctdb;
2071 struct ctdb_reply_control reply;
2072 struct node *node;
2073 uint32_t caps = 0;
2075 reply.rdata.opcode = request->opcode;
2077 node = &ctdb->node_map->node[header->destnode];
2078 caps = node->capabilities;
2080 if (node->flags & NODE_FLAGS_FAKE_TIMEOUT) {
2081 /* Don't send reply */
2082 return;
2085 reply.rdata.data.caps = caps;
2086 reply.status = 0;
2087 reply.errmsg = NULL;
2089 client_send_control(req, header, &reply);
2092 static void control_release_ip(TALLOC_CTX *mem_ctx,
2093 struct tevent_req *req,
2094 struct ctdb_req_header *header,
2095 struct ctdb_req_control *request)
2097 struct client_state *state = tevent_req_data(
2098 req, struct client_state);
2099 struct ctdbd_context *ctdb = state->ctdb;
2100 struct ctdb_public_ip *ip = request->rdata.data.pubip;
2101 struct ctdb_reply_control reply;
2102 struct ctdb_public_ip_list *ips = NULL;
2103 struct ctdb_public_ip *t = NULL;
2104 int i;
2106 reply.rdata.opcode = request->opcode;
2108 if (ctdb->known_ips == NULL) {
2109 D_INFO("RELEASE_IP %s - not a public IP\n",
2110 ctdb_sock_addr_to_string(mem_ctx, &ip->addr));
2111 goto done;
2114 ips = &ctdb->known_ips[header->destnode];
2116 t = NULL;
2117 for (i = 0; i < ips->num; i++) {
2118 if (ctdb_sock_addr_same_ip(&ips->ip[i].addr, &ip->addr)) {
2119 t = &ips->ip[i];
2120 break;
2123 if (t == NULL) {
2124 D_INFO("RELEASE_IP %s - not a public IP\n",
2125 ctdb_sock_addr_to_string(mem_ctx, &ip->addr));
2126 goto done;
2129 if (t->pnn != header->destnode) {
2130 if (header->destnode == ip->pnn) {
2131 D_ERR("error: RELEASE_IP %s - to TAKE_IP node %d\n",
2132 ctdb_sock_addr_to_string(mem_ctx, &ip->addr),
2133 ip->pnn);
2134 reply.status = -1;
2135 reply.errmsg = "RELEASE_IP to TAKE_IP node";
2136 client_send_control(req, header, &reply);
2137 return;
2140 D_INFO("RELEASE_IP %s - to node %d - redundant\n",
2141 ctdb_sock_addr_to_string(mem_ctx, &ip->addr),
2142 ip->pnn);
2143 t->pnn = ip->pnn;
2144 } else {
2145 D_NOTICE("RELEASE_IP %s - to node %d\n",
2146 ctdb_sock_addr_to_string(mem_ctx, &ip->addr),
2147 ip->pnn);
2148 t->pnn = ip->pnn;
2151 done:
2152 reply.status = 0;
2153 reply.errmsg = NULL;
2154 client_send_control(req, header, &reply);
2157 static void control_takeover_ip(TALLOC_CTX *mem_ctx,
2158 struct tevent_req *req,
2159 struct ctdb_req_header *header,
2160 struct ctdb_req_control *request)
2162 struct client_state *state = tevent_req_data(
2163 req, struct client_state);
2164 struct ctdbd_context *ctdb = state->ctdb;
2165 struct ctdb_public_ip *ip = request->rdata.data.pubip;
2166 struct ctdb_reply_control reply;
2167 struct ctdb_public_ip_list *ips = NULL;
2168 struct ctdb_public_ip *t = NULL;
2169 int i;
2171 reply.rdata.opcode = request->opcode;
2173 if (ctdb->known_ips == NULL) {
2174 D_INFO("TAKEOVER_IP %s - not a public IP\n",
2175 ctdb_sock_addr_to_string(mem_ctx, &ip->addr));
2176 goto done;
2179 ips = &ctdb->known_ips[header->destnode];
2181 t = NULL;
2182 for (i = 0; i < ips->num; i++) {
2183 if (ctdb_sock_addr_same_ip(&ips->ip[i].addr, &ip->addr)) {
2184 t = &ips->ip[i];
2185 break;
2188 if (t == NULL) {
2189 D_INFO("TAKEOVER_IP %s - not a public IP\n",
2190 ctdb_sock_addr_to_string(mem_ctx, &ip->addr));
2191 goto done;
2194 if (t->pnn == header->destnode) {
2195 D_INFO("TAKEOVER_IP %s - redundant\n",
2196 ctdb_sock_addr_to_string(mem_ctx, &ip->addr));
2197 } else {
2198 D_NOTICE("TAKEOVER_IP %s\n",
2199 ctdb_sock_addr_to_string(mem_ctx, &ip->addr));
2200 t->pnn = ip->pnn;
2203 done:
2204 reply.status = 0;
2205 reply.errmsg = NULL;
2206 client_send_control(req, header, &reply);
2209 static void control_get_public_ips(TALLOC_CTX *mem_ctx,
2210 struct tevent_req *req,
2211 struct ctdb_req_header *header,
2212 struct ctdb_req_control *request)
2214 struct client_state *state = tevent_req_data(
2215 req, struct client_state);
2216 struct ctdbd_context *ctdb = state->ctdb;
2217 struct ctdb_reply_control reply;
2218 struct ctdb_public_ip_list *ips = NULL;
2220 reply.rdata.opcode = request->opcode;
2222 if (ctdb->known_ips == NULL) {
2223 /* No IPs defined so create a dummy empty struct and ship it */
2224 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);;
2225 if (ips == NULL) {
2226 reply.status = ENOMEM;
2227 reply.errmsg = "Memory error";
2228 goto done;
2230 goto ok;
2233 ips = &ctdb->known_ips[header->destnode];
2235 if (request->flags & CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE) {
2236 /* If runstate is not RUNNING or a node is then return
2237 * no available IPs. Don't worry about interface
2238 * states here - we're not faking down to that level.
2240 if (ctdb->runstate != CTDB_RUNSTATE_RUNNING) {
2241 /* No available IPs: return dummy empty struct */
2242 ips = talloc_zero(mem_ctx, struct ctdb_public_ip_list);;
2243 if (ips == NULL) {
2244 reply.status = ENOMEM;
2245 reply.errmsg = "Memory error";
2246 goto done;
2252 reply.rdata.data.pubip_list = ips;
2253 reply.status = 0;
2254 reply.errmsg = NULL;
2256 done:
2257 client_send_control(req, header, &reply);
2260 static void control_get_nodemap(TALLOC_CTX *mem_ctx,
2261 struct tevent_req *req,
2262 struct ctdb_req_header *header,
2263 struct ctdb_req_control *request)
2265 struct client_state *state = tevent_req_data(
2266 req, struct client_state);
2267 struct ctdbd_context *ctdb = state->ctdb;
2268 struct ctdb_reply_control reply;
2269 struct ctdb_node_map *nodemap;
2270 struct node *node;
2271 int i;
2273 reply.rdata.opcode = request->opcode;
2275 nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
2276 if (nodemap == NULL) {
2277 goto fail;
2280 nodemap->num = ctdb->node_map->num_nodes;
2281 nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags,
2282 nodemap->num);
2283 if (nodemap->node == NULL) {
2284 goto fail;
2287 for (i=0; i<nodemap->num; i++) {
2288 node = &ctdb->node_map->node[i];
2289 nodemap->node[i] = (struct ctdb_node_and_flags) {
2290 .pnn = node->pnn,
2291 .flags = node->flags,
2292 .addr = node->addr,
2296 reply.rdata.data.nodemap = nodemap;
2297 reply.status = 0;
2298 reply.errmsg = NULL;
2299 client_send_control(req, header, &reply);
2300 return;
2302 fail:
2303 reply.status = -1;
2304 reply.errmsg = "Memory error";
2305 client_send_control(req, header, &reply);
2308 static void control_get_reclock_file(TALLOC_CTX *mem_ctx,
2309 struct tevent_req *req,
2310 struct ctdb_req_header *header,
2311 struct ctdb_req_control *request)
2313 struct client_state *state = tevent_req_data(
2314 req, struct client_state);
2315 struct ctdbd_context *ctdb = state->ctdb;
2316 struct ctdb_reply_control reply;
2318 reply.rdata.opcode = request->opcode;
2320 if (ctdb->reclock != NULL) {
2321 reply.rdata.data.reclock_file =
2322 talloc_strdup(mem_ctx, ctdb->reclock);
2323 if (reply.rdata.data.reclock_file == NULL) {
2324 reply.status = ENOMEM;
2325 reply.errmsg = "Memory error";
2326 goto done;
2328 } else {
2329 reply.rdata.data.reclock_file = NULL;
2332 reply.status = 0;
2333 reply.errmsg = NULL;
2335 done:
2336 client_send_control(req, header, &reply);
2339 static void control_stop_node(TALLOC_CTX *mem_ctx,
2340 struct tevent_req *req,
2341 struct ctdb_req_header *header,
2342 struct ctdb_req_control *request)
2344 struct client_state *state = tevent_req_data(
2345 req, struct client_state);
2346 struct ctdbd_context *ctdb = state->ctdb;
2347 struct ctdb_reply_control reply;
2349 reply.rdata.opcode = request->opcode;
2351 DEBUG(DEBUG_INFO, ("Stopping node\n"));
2352 ctdb->monitoring_mode = CTDB_MONITORING_DISABLED;
2353 ctdb->node_map->node[header->destnode].flags |= NODE_FLAGS_STOPPED;
2355 reply.status = 0;
2356 reply.errmsg = NULL;
2358 client_send_control(req, header, &reply);
2359 return;
2362 static void control_continue_node(TALLOC_CTX *mem_ctx,
2363 struct tevent_req *req,
2364 struct ctdb_req_header *header,
2365 struct ctdb_req_control *request)
2367 struct client_state *state = tevent_req_data(
2368 req, struct client_state);
2369 struct ctdbd_context *ctdb = state->ctdb;
2370 struct ctdb_reply_control reply;
2372 reply.rdata.opcode = request->opcode;
2374 DEBUG(DEBUG_INFO, ("Continue node\n"));
2375 ctdb->node_map->node[header->destnode].flags &= ~NODE_FLAGS_STOPPED;
2377 reply.status = 0;
2378 reply.errmsg = NULL;
2380 client_send_control(req, header, &reply);
2381 return;
2384 static void set_ban_state_callback(struct tevent_req *subreq)
2386 struct node *node = tevent_req_callback_data(
2387 subreq, struct node);
2388 bool status;
2390 status = tevent_wakeup_recv(subreq);
2391 TALLOC_FREE(subreq);
2392 if (! status) {
2393 DEBUG(DEBUG_INFO, ("tevent_wakeup_recv failed\n"));
2396 node->flags &= ~NODE_FLAGS_BANNED;
2399 static void control_set_ban_state(TALLOC_CTX *mem_ctx,
2400 struct tevent_req *req,
2401 struct ctdb_req_header *header,
2402 struct ctdb_req_control *request)
2404 struct client_state *state = tevent_req_data(
2405 req, struct client_state);
2406 struct tevent_req *subreq;
2407 struct ctdbd_context *ctdb = state->ctdb;
2408 struct ctdb_ban_state *ban = request->rdata.data.ban_state;
2409 struct ctdb_reply_control reply;
2410 struct node *node;
2412 reply.rdata.opcode = request->opcode;
2414 if (ban->pnn != header->destnode) {
2415 DEBUG(DEBUG_INFO,
2416 ("SET_BAN_STATE control for PNN %d rejected\n",
2417 ban->pnn));
2418 reply.status = EINVAL;
2419 goto fail;
2422 node = &ctdb->node_map->node[header->destnode];
2424 if (ban->time == 0) {
2425 DEBUG(DEBUG_INFO,("Unbanning this node\n"));
2426 node->flags &= ~NODE_FLAGS_BANNED;
2427 goto done;
2430 subreq = tevent_wakeup_send(ctdb->node_map, state->ev,
2431 tevent_timeval_current_ofs(
2432 ban->time, 0));
2433 if (subreq == NULL) {
2434 reply.status = ENOMEM;
2435 goto fail;
2437 tevent_req_set_callback(subreq, set_ban_state_callback, node);
2439 DEBUG(DEBUG_INFO, ("Banning this node for %d seconds\n", ban->time));
2440 node->flags |= NODE_FLAGS_BANNED;
2441 ctdb->vnn_map->generation = INVALID_GENERATION;
2443 done:
2444 reply.status = 0;
2445 reply.errmsg = NULL;
2447 client_send_control(req, header, &reply);
2448 return;
2450 fail:
2451 reply.errmsg = "Failed to ban node";
2454 static void control_get_db_seqnum(TALLOC_CTX *mem_ctx,
2455 struct tevent_req *req,
2456 struct ctdb_req_header *header,
2457 struct ctdb_req_control *request)
2459 struct client_state *state = tevent_req_data(
2460 req, struct client_state);
2461 struct ctdbd_context *ctdb = state->ctdb;
2462 struct ctdb_reply_control reply;
2463 struct database *db;
2465 reply.rdata.opcode = request->opcode;
2467 db = database_find(ctdb->db_map, request->rdata.data.db_id);
2468 if (db == NULL) {
2469 reply.status = ENOENT;
2470 reply.errmsg = "Database not found";
2471 } else {
2472 reply.rdata.data.seqnum = db->seq_num;
2473 reply.status = 0;
2474 reply.errmsg = NULL;
2477 client_send_control(req, header, &reply);
2480 static void control_db_get_health(TALLOC_CTX *mem_ctx,
2481 struct tevent_req *req,
2482 struct ctdb_req_header *header,
2483 struct ctdb_req_control *request)
2485 struct client_state *state = tevent_req_data(
2486 req, struct client_state);
2487 struct ctdbd_context *ctdb = state->ctdb;
2488 struct ctdb_reply_control reply;
2489 struct database *db;
2491 reply.rdata.opcode = request->opcode;
2493 db = database_find(ctdb->db_map, request->rdata.data.db_id);
2494 if (db == NULL) {
2495 reply.status = ENOENT;
2496 reply.errmsg = "Database not found";
2497 } else {
2498 reply.rdata.data.reason = NULL;
2499 reply.status = 0;
2500 reply.errmsg = NULL;
2503 client_send_control(req, header, &reply);
2506 static struct ctdb_iface_list *get_ctdb_iface_list(TALLOC_CTX *mem_ctx,
2507 struct ctdbd_context *ctdb)
2509 struct ctdb_iface_list *iface_list;
2510 struct interface *iface;
2511 int i;
2513 iface_list = talloc_zero(mem_ctx, struct ctdb_iface_list);
2514 if (iface_list == NULL) {
2515 goto done;
2518 iface_list->num = ctdb->iface_map->num;
2519 iface_list->iface = talloc_array(iface_list, struct ctdb_iface,
2520 iface_list->num);
2521 if (iface_list->iface == NULL) {
2522 TALLOC_FREE(iface_list);
2523 goto done;
2526 for (i=0; i<iface_list->num; i++) {
2527 iface = &ctdb->iface_map->iface[i];
2528 iface_list->iface[i] = (struct ctdb_iface) {
2529 .link_state = iface->link_up,
2530 .references = iface->references,
2532 strlcpy(iface_list->iface[i].name, iface->name,
2533 sizeof(iface_list->iface[i].name));
2536 done:
2537 return iface_list;
2540 static void control_get_public_ip_info(TALLOC_CTX *mem_ctx,
2541 struct tevent_req *req,
2542 struct ctdb_req_header *header,
2543 struct ctdb_req_control *request)
2545 struct client_state *state = tevent_req_data(
2546 req, struct client_state);
2547 struct ctdbd_context *ctdb = state->ctdb;
2548 struct ctdb_reply_control reply;
2549 ctdb_sock_addr *addr = request->rdata.data.addr;
2550 struct ctdb_public_ip_list *known = NULL;
2551 struct ctdb_public_ip_info *info = NULL;
2552 unsigned i;
2554 reply.rdata.opcode = request->opcode;
2556 info = talloc_zero(mem_ctx, struct ctdb_public_ip_info);
2557 if (info == NULL) {
2558 reply.status = ENOMEM;
2559 reply.errmsg = "Memory error";
2560 goto done;
2563 reply.rdata.data.ipinfo = info;
2565 if (ctdb->known_ips != NULL) {
2566 known = &ctdb->known_ips[header->destnode];
2567 } else {
2568 /* No IPs defined so create a dummy empty struct and
2569 * fall through. The given IP won't be matched
2570 * below...
2572 known = talloc_zero(mem_ctx, struct ctdb_public_ip_list);;
2573 if (known == NULL) {
2574 reply.status = ENOMEM;
2575 reply.errmsg = "Memory error";
2576 goto done;
2580 for (i = 0; i < known->num; i++) {
2581 if (ctdb_sock_addr_same_ip(&known->ip[i].addr,
2582 addr)) {
2583 break;
2587 if (i == known->num) {
2588 D_ERR("GET_PUBLIC_IP_INFO: not known public IP %s\n",
2589 ctdb_sock_addr_to_string(mem_ctx, addr));
2590 reply.status = -1;
2591 reply.errmsg = "Unknown address";
2592 goto done;
2595 info->ip = known->ip[i];
2597 /* The fake PUBLICIPS stanza and resulting known_ips data
2598 * don't know anything about interfaces, so completely fake
2599 * this.
2601 info->active_idx = 0;
2603 info->ifaces = get_ctdb_iface_list(mem_ctx, ctdb);
2604 if (info->ifaces == NULL) {
2605 reply.status = ENOMEM;
2606 reply.errmsg = "Memory error";
2607 goto done;
2610 reply.status = 0;
2611 reply.errmsg = NULL;
2613 done:
2614 client_send_control(req, header, &reply);
2617 static void control_get_ifaces(TALLOC_CTX *mem_ctx,
2618 struct tevent_req *req,
2619 struct ctdb_req_header *header,
2620 struct ctdb_req_control *request)
2622 struct client_state *state = tevent_req_data(
2623 req, struct client_state);
2624 struct ctdbd_context *ctdb = state->ctdb;
2625 struct ctdb_reply_control reply;
2626 struct ctdb_iface_list *iface_list;
2628 reply.rdata.opcode = request->opcode;
2630 iface_list = get_ctdb_iface_list(mem_ctx, ctdb);
2631 if (iface_list == NULL) {
2632 goto fail;
2635 reply.rdata.data.iface_list = iface_list;
2636 reply.status = 0;
2637 reply.errmsg = NULL;
2638 client_send_control(req, header, &reply);
2639 return;
2641 fail:
2642 reply.status = -1;
2643 reply.errmsg = "Memory error";
2644 client_send_control(req, header, &reply);
2647 static void control_set_iface_link_state(TALLOC_CTX *mem_ctx,
2648 struct tevent_req *req,
2649 struct ctdb_req_header *header,
2650 struct ctdb_req_control *request)
2652 struct client_state *state = tevent_req_data(
2653 req, struct client_state);
2654 struct ctdbd_context *ctdb = state->ctdb;
2655 struct ctdb_reply_control reply;
2656 struct ctdb_iface *in_iface;
2657 struct interface *iface = NULL;
2658 bool link_up = false;
2659 int i;
2661 reply.rdata.opcode = request->opcode;
2663 in_iface = request->rdata.data.iface;
2665 if (in_iface->name[CTDB_IFACE_SIZE] != '\0') {
2666 reply.errmsg = "interface name not terminated";
2667 goto fail;
2670 switch (in_iface->link_state) {
2671 case 0:
2672 link_up = false;
2673 break;
2675 case 1:
2676 link_up = true;
2677 break;
2679 default:
2680 reply.errmsg = "invalid link state";
2681 goto fail;
2684 if (in_iface->references != 0) {
2685 reply.errmsg = "references should be 0";
2686 goto fail;
2689 for (i=0; i<ctdb->iface_map->num; i++) {
2690 if (strcmp(ctdb->iface_map->iface[i].name,
2691 in_iface->name) == 0) {
2692 iface = &ctdb->iface_map->iface[i];
2693 break;
2697 if (iface == NULL) {
2698 reply.errmsg = "interface not found";
2699 goto fail;
2702 iface->link_up = link_up;
2704 reply.status = 0;
2705 reply.errmsg = NULL;
2706 client_send_control(req, header, &reply);
2707 return;
2709 fail:
2710 reply.status = -1;
2711 client_send_control(req, header, &reply);
2714 static void control_set_db_readonly(TALLOC_CTX *mem_ctx,
2715 struct tevent_req *req,
2716 struct ctdb_req_header *header,
2717 struct ctdb_req_control *request)
2719 struct client_state *state = tevent_req_data(
2720 req, struct client_state);
2721 struct ctdbd_context *ctdb = state->ctdb;
2722 struct ctdb_reply_control reply;
2723 struct database *db;
2725 reply.rdata.opcode = request->opcode;
2727 db = database_find(ctdb->db_map, request->rdata.data.db_id);
2728 if (db == NULL) {
2729 reply.status = ENOENT;
2730 reply.errmsg = "Database not found";
2731 goto done;
2734 if (db->flags & CTDB_DB_FLAGS_PERSISTENT) {
2735 reply.status = EINVAL;
2736 reply.errmsg = "Can not set READONLY on persistent db";
2737 goto done;
2740 db->flags |= CTDB_DB_FLAGS_READONLY;
2741 reply.status = 0;
2742 reply.errmsg = NULL;
2744 done:
2745 client_send_control(req, header, &reply);
2748 static void control_set_db_sticky(TALLOC_CTX *mem_ctx,
2749 struct tevent_req *req,
2750 struct ctdb_req_header *header,
2751 struct ctdb_req_control *request)
2753 struct client_state *state = tevent_req_data(
2754 req, struct client_state);
2755 struct ctdbd_context *ctdb = state->ctdb;
2756 struct ctdb_reply_control reply;
2757 struct database *db;
2759 reply.rdata.opcode = request->opcode;
2761 db = database_find(ctdb->db_map, request->rdata.data.db_id);
2762 if (db == NULL) {
2763 reply.status = ENOENT;
2764 reply.errmsg = "Database not found";
2765 goto done;
2768 if (db->flags & CTDB_DB_FLAGS_PERSISTENT) {
2769 reply.status = EINVAL;
2770 reply.errmsg = "Can not set STICKY on persistent db";
2771 goto done;
2774 db->flags |= CTDB_DB_FLAGS_STICKY;
2775 reply.status = 0;
2776 reply.errmsg = NULL;
2778 done:
2779 client_send_control(req, header, &reply);
2782 static void control_ipreallocated(TALLOC_CTX *mem_ctx,
2783 struct tevent_req *req,
2784 struct ctdb_req_header *header,
2785 struct ctdb_req_control *request)
2787 struct ctdb_reply_control reply;
2789 /* Always succeed */
2790 reply.rdata.opcode = request->opcode;
2791 reply.status = 0;
2792 reply.errmsg = NULL;
2794 client_send_control(req, header, &reply);
2797 static void control_get_runstate(TALLOC_CTX *mem_ctx,
2798 struct tevent_req *req,
2799 struct ctdb_req_header *header,
2800 struct ctdb_req_control *request)
2802 struct client_state *state = tevent_req_data(
2803 req, struct client_state);
2804 struct ctdbd_context *ctdb = state->ctdb;
2805 struct ctdb_reply_control reply;
2807 reply.rdata.opcode = request->opcode;
2808 reply.rdata.data.runstate = ctdb->runstate;
2809 reply.status = 0;
2810 reply.errmsg = NULL;
2812 client_send_control(req, header, &reply);
2815 static void control_get_nodes_file(TALLOC_CTX *mem_ctx,
2816 struct tevent_req *req,
2817 struct ctdb_req_header *header,
2818 struct ctdb_req_control *request)
2820 struct ctdb_reply_control reply;
2821 struct ctdb_node_map *nodemap;
2823 reply.rdata.opcode = request->opcode;
2825 nodemap = read_nodes_file(mem_ctx, header->destnode);
2826 if (nodemap == NULL) {
2827 goto fail;
2830 reply.rdata.data.nodemap = nodemap;
2831 reply.status = 0;
2832 reply.errmsg = NULL;
2833 client_send_control(req, header, &reply);
2834 return;
2836 fail:
2837 reply.status = -1;
2838 reply.errmsg = "Failed to read nodes file";
2839 client_send_control(req, header, &reply);
2842 static void control_check_pid_srvid(TALLOC_CTX *mem_ctx,
2843 struct tevent_req *req,
2844 struct ctdb_req_header *header,
2845 struct ctdb_req_control *request)
2847 struct client_state *state = tevent_req_data(
2848 req, struct client_state);
2849 struct ctdbd_context *ctdb = state->ctdb;
2850 struct client_state *cstate;
2851 struct ctdb_reply_control reply;
2852 int ret;
2854 reply.rdata.opcode = request->opcode;
2856 cstate = client_find(ctdb, request->rdata.data.pid_srvid->pid);
2857 if (cstate == NULL) {
2858 reply.status = -1;
2859 reply.errmsg = "No client for PID";
2860 } else {
2861 ret = srvid_exists(ctdb->srv,
2862 request->rdata.data.pid_srvid->srvid,
2863 cstate);
2864 if (ret != 0) {
2865 reply.status = -1;
2866 reply.errmsg = "No client for PID and SRVID";
2867 } else {
2868 ret = kill(cstate->pid, 0);
2869 if (ret != 0) {
2870 reply.status = ret;
2871 reply.errmsg = strerror(errno);
2872 } else {
2873 reply.status = 0;
2874 reply.errmsg = NULL;
2879 client_send_control(req, header, &reply);
2882 static bool fake_control_failure(TALLOC_CTX *mem_ctx,
2883 struct tevent_req *req,
2884 struct ctdb_req_header *header,
2885 struct ctdb_req_control *request)
2887 struct client_state *state = tevent_req_data(
2888 req, struct client_state);
2889 struct ctdbd_context *ctdb = state->ctdb;
2890 struct ctdb_reply_control reply;
2891 struct fake_control_failure *f = NULL;
2893 D_DEBUG("Checking fake control failure for control %u on node %u\n",
2894 request->opcode, header->destnode);
2895 for (f = ctdb->control_failures; f != NULL; f = f->next) {
2896 if (f->opcode == request->opcode &&
2897 (f->pnn == header->destnode ||
2898 f->pnn == CTDB_UNKNOWN_PNN)) {
2900 reply.rdata.opcode = request->opcode;
2901 if (strcmp(f->error, "TIMEOUT") == 0) {
2902 /* Causes no reply */
2903 D_ERR("Control %u fake timeout on node %u\n",
2904 request->opcode, header->destnode);
2905 return true;
2906 } else if (strcmp(f->error, "ERROR") == 0) {
2907 D_ERR("Control %u fake error on node %u\n",
2908 request->opcode, header->destnode);
2909 reply.status = -1;
2910 reply.errmsg = f->comment;
2911 client_send_control(req, header, &reply);
2912 return true;
2917 return false;
2920 static void control_error(TALLOC_CTX *mem_ctx,
2921 struct tevent_req *req,
2922 struct ctdb_req_header *header,
2923 struct ctdb_req_control *request)
2925 struct ctdb_reply_control reply;
2927 reply.rdata.opcode = request->opcode;
2928 reply.status = -1;
2929 reply.errmsg = "Not implemented";
2931 client_send_control(req, header, &reply);
2935 * Handling protocol - messages
2938 struct disable_recoveries_state {
2939 struct node *node;
2942 static void disable_recoveries_callback(struct tevent_req *subreq)
2944 struct disable_recoveries_state *substate = tevent_req_callback_data(
2945 subreq, struct disable_recoveries_state);
2946 bool status;
2948 status = tevent_wakeup_recv(subreq);
2949 TALLOC_FREE(subreq);
2950 if (! status) {
2951 DEBUG(DEBUG_INFO, ("tevent_wakeup_recv failed\n"));
2954 substate->node->recovery_disabled = false;
2955 TALLOC_FREE(substate->node->recovery_substate);
2958 static void message_disable_recoveries(TALLOC_CTX *mem_ctx,
2959 struct tevent_req *req,
2960 struct ctdb_req_header *header,
2961 struct ctdb_req_message *request)
2963 struct client_state *state = tevent_req_data(
2964 req, struct client_state);
2965 struct tevent_req *subreq;
2966 struct ctdbd_context *ctdb = state->ctdb;
2967 struct disable_recoveries_state *substate;
2968 struct ctdb_disable_message *disable = request->data.disable;
2969 struct ctdb_req_message_data reply;
2970 struct node *node;
2971 int ret = -1;
2972 TDB_DATA data;
2974 node = &ctdb->node_map->node[header->destnode];
2976 if (disable->timeout == 0) {
2977 TALLOC_FREE(node->recovery_substate);
2978 node->recovery_disabled = false;
2979 DEBUG(DEBUG_INFO, ("Enabled recoveries on node %u\n",
2980 header->destnode));
2981 goto done;
2984 substate = talloc_zero(ctdb->node_map,
2985 struct disable_recoveries_state);
2986 if (substate == NULL) {
2987 goto fail;
2990 substate->node = node;
2992 subreq = tevent_wakeup_send(substate, state->ev,
2993 tevent_timeval_current_ofs(
2994 disable->timeout, 0));
2995 if (subreq == NULL) {
2996 talloc_free(substate);
2997 goto fail;
2999 tevent_req_set_callback(subreq, disable_recoveries_callback, substate);
3001 DEBUG(DEBUG_INFO, ("Disabled recoveries for %d seconds on node %u\n",
3002 disable->timeout, header->destnode));
3003 node->recovery_substate = substate;
3004 node->recovery_disabled = true;
3006 done:
3007 ret = header->destnode;
3009 fail:
3010 reply.srvid = disable->srvid;
3011 data.dptr = (uint8_t *)&ret;
3012 data.dsize = sizeof(int);
3013 reply.data = data;
3015 client_send_message(req, header, &reply);
3018 static void message_takeover_run(TALLOC_CTX *mem_ctx,
3019 struct tevent_req *req,
3020 struct ctdb_req_header *header,
3021 struct ctdb_req_message *request)
3023 struct client_state *state = tevent_req_data(
3024 req, struct client_state);
3025 struct ctdbd_context *ctdb = state->ctdb;
3026 struct ctdb_srvid_message *srvid = request->data.msg;
3027 struct ctdb_req_message_data reply;
3028 int ret = -1;
3029 TDB_DATA data;
3031 if (header->destnode != ctdb->node_map->recmaster) {
3032 /* No reply! Only recmaster replies... */
3033 return;
3036 DEBUG(DEBUG_INFO, ("IP takover run on node %u\n",
3037 header->destnode));
3038 ret = header->destnode;
3040 reply.srvid = srvid->srvid;
3041 data.dptr = (uint8_t *)&ret;
3042 data.dsize = sizeof(int);
3043 reply.data = data;
3045 client_send_message(req, header, &reply);
3049 * Handle a single client
3052 static void client_read_handler(uint8_t *buf, size_t buflen,
3053 void *private_data);
3054 static void client_dead_handler(void *private_data);
3055 static void client_process_packet(struct tevent_req *req,
3056 uint8_t *buf, size_t buflen);
3057 static void client_process_message(struct tevent_req *req,
3058 uint8_t *buf, size_t buflen);
3059 static void client_process_control(struct tevent_req *req,
3060 uint8_t *buf, size_t buflen);
3061 static void client_reply_done(struct tevent_req *subreq);
3063 static struct tevent_req *client_send(TALLOC_CTX *mem_ctx,
3064 struct tevent_context *ev,
3065 int fd, struct ctdbd_context *ctdb,
3066 int pnn)
3068 struct tevent_req *req;
3069 struct client_state *state;
3070 struct ucred cr;
3071 socklen_t crl = sizeof(struct ucred);
3072 int ret;
3074 req = tevent_req_create(mem_ctx, &state, struct client_state);
3075 if (req == NULL) {
3076 return NULL;
3079 state->ev = ev;
3080 state->fd = fd;
3081 state->ctdb = ctdb;
3082 state->pnn = pnn;
3084 ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crl);
3085 if (ret != 0) {
3086 tevent_req_error(req, ret);
3087 return tevent_req_post(req, ev);
3089 state->pid = cr.pid;
3091 ret = comm_setup(state, ev, fd, client_read_handler, req,
3092 client_dead_handler, req, &state->comm);
3093 if (ret != 0) {
3094 tevent_req_error(req, ret);
3095 return tevent_req_post(req, ev);
3098 ret = client_add(ctdb, state->pid, state);
3099 if (ret != 0) {
3100 tevent_req_error(req, ret);
3101 return tevent_req_post(req, ev);
3104 DEBUG(DEBUG_INFO, ("New client fd=%d\n", fd));
3106 return req;
3109 static void client_read_handler(uint8_t *buf, size_t buflen,
3110 void *private_data)
3112 struct tevent_req *req = talloc_get_type_abort(
3113 private_data, struct tevent_req);
3114 struct client_state *state = tevent_req_data(
3115 req, struct client_state);
3116 struct ctdbd_context *ctdb = state->ctdb;
3117 struct ctdb_req_header header;
3118 int ret, i;
3120 ret = ctdb_req_header_pull(buf, buflen, &header);
3121 if (ret != 0) {
3122 return;
3125 if (buflen != header.length) {
3126 return;
3129 ret = ctdb_req_header_verify(&header, 0);
3130 if (ret != 0) {
3131 return;
3134 header_fix_pnn(&header, ctdb);
3136 if (header.destnode == CTDB_BROADCAST_ALL) {
3137 for (i=0; i<ctdb->node_map->num_nodes; i++) {
3138 header.destnode = i;
3140 ctdb_req_header_push(&header, buf);
3141 client_process_packet(req, buf, buflen);
3143 return;
3146 if (header.destnode == CTDB_BROADCAST_CONNECTED) {
3147 for (i=0; i<ctdb->node_map->num_nodes; i++) {
3148 if (ctdb->node_map->node[i].flags &
3149 NODE_FLAGS_DISCONNECTED) {
3150 continue;
3153 header.destnode = i;
3155 ctdb_req_header_push(&header, buf);
3156 client_process_packet(req, buf, buflen);
3158 return;
3161 if (header.destnode > ctdb->node_map->num_nodes) {
3162 fprintf(stderr, "Invalid destination pnn 0x%x\n",
3163 header.destnode);
3164 return;
3168 if (ctdb->node_map->node[header.destnode].flags & NODE_FLAGS_DISCONNECTED) {
3169 fprintf(stderr, "Packet for disconnected node pnn %u\n",
3170 header.destnode);
3171 return;
3174 ctdb_req_header_push(&header, buf);
3175 client_process_packet(req, buf, buflen);
3178 static void client_dead_handler(void *private_data)
3180 struct tevent_req *req = talloc_get_type_abort(
3181 private_data, struct tevent_req);
3183 tevent_req_done(req);
3186 static void client_process_packet(struct tevent_req *req,
3187 uint8_t *buf, size_t buflen)
3189 struct ctdb_req_header header;
3190 int ret;
3192 ret = ctdb_req_header_pull(buf, buflen, &header);
3193 if (ret != 0) {
3194 return;
3197 switch (header.operation) {
3198 case CTDB_REQ_MESSAGE:
3199 client_process_message(req, buf, buflen);
3200 break;
3202 case CTDB_REQ_CONTROL:
3203 client_process_control(req, buf, buflen);
3204 break;
3206 default:
3207 break;
3211 static void client_process_message(struct tevent_req *req,
3212 uint8_t *buf, size_t buflen)
3214 struct client_state *state = tevent_req_data(
3215 req, struct client_state);
3216 struct ctdbd_context *ctdb = state->ctdb;
3217 TALLOC_CTX *mem_ctx;
3218 struct ctdb_req_header header;
3219 struct ctdb_req_message request;
3220 uint64_t srvid;
3221 int ret;
3223 mem_ctx = talloc_new(state);
3224 if (tevent_req_nomem(mem_ctx, req)) {
3225 return;
3228 ret = ctdb_req_message_pull(buf, buflen, &header, mem_ctx, &request);
3229 if (ret != 0) {
3230 talloc_free(mem_ctx);
3231 tevent_req_error(req, ret);
3232 return;
3235 header_fix_pnn(&header, ctdb);
3237 if (header.destnode >= ctdb->node_map->num_nodes) {
3238 /* Many messages are not replied to, so just behave as
3239 * though this message was not received */
3240 fprintf(stderr, "Invalid node %d\n", header.destnode);
3241 talloc_free(mem_ctx);
3242 return;
3245 srvid = request.srvid;
3246 DEBUG(DEBUG_INFO, ("request srvid = 0x%"PRIx64"\n", srvid));
3248 if (srvid == CTDB_SRVID_DISABLE_RECOVERIES) {
3249 message_disable_recoveries(mem_ctx, req, &header, &request);
3250 } else if (srvid == CTDB_SRVID_TAKEOVER_RUN) {
3251 message_takeover_run(mem_ctx, req, &header, &request);
3254 /* check srvid */
3255 talloc_free(mem_ctx);
3258 static void client_process_control(struct tevent_req *req,
3259 uint8_t *buf, size_t buflen)
3261 struct client_state *state = tevent_req_data(
3262 req, struct client_state);
3263 struct ctdbd_context *ctdb = state->ctdb;
3264 TALLOC_CTX *mem_ctx;
3265 struct ctdb_req_header header;
3266 struct ctdb_req_control request;
3267 int ret;
3269 mem_ctx = talloc_new(state);
3270 if (tevent_req_nomem(mem_ctx, req)) {
3271 return;
3274 ret = ctdb_req_control_pull(buf, buflen, &header, mem_ctx, &request);
3275 if (ret != 0) {
3276 talloc_free(mem_ctx);
3277 tevent_req_error(req, ret);
3278 return;
3281 header_fix_pnn(&header, ctdb);
3283 if (header.destnode >= ctdb->node_map->num_nodes) {
3284 struct ctdb_reply_control reply;
3286 reply.rdata.opcode = request.opcode;
3287 reply.errmsg = "Invalid node";
3288 reply.status = -1;
3289 client_send_control(req, &header, &reply);
3290 return;
3293 DEBUG(DEBUG_INFO, ("request opcode = %u, reqid = %u\n",
3294 request.opcode, header.reqid));
3296 if (fake_control_failure(mem_ctx, req, &header, &request)) {
3297 goto done;
3300 switch (request.opcode) {
3301 case CTDB_CONTROL_PROCESS_EXISTS:
3302 control_process_exists(mem_ctx, req, &header, &request);
3303 break;
3305 case CTDB_CONTROL_PING:
3306 control_ping(mem_ctx, req, &header, &request);
3307 break;
3309 case CTDB_CONTROL_GETDBPATH:
3310 control_getdbpath(mem_ctx, req, &header, &request);
3311 break;
3313 case CTDB_CONTROL_GETVNNMAP:
3314 control_getvnnmap(mem_ctx, req, &header, &request);
3315 break;
3317 case CTDB_CONTROL_GET_DEBUG:
3318 control_get_debug(mem_ctx, req, &header, &request);
3319 break;
3321 case CTDB_CONTROL_SET_DEBUG:
3322 control_set_debug(mem_ctx, req, &header, &request);
3323 break;
3325 case CTDB_CONTROL_GET_DBMAP:
3326 control_get_dbmap(mem_ctx, req, &header, &request);
3327 break;
3329 case CTDB_CONTROL_GET_RECMODE:
3330 control_get_recmode(mem_ctx, req, &header, &request);
3331 break;
3333 case CTDB_CONTROL_SET_RECMODE:
3334 control_set_recmode(mem_ctx, req, &header, &request);
3335 break;
3337 case CTDB_CONTROL_REGISTER_SRVID:
3338 control_register_srvid(mem_ctx, req, &header, &request);
3339 break;
3341 case CTDB_CONTROL_DEREGISTER_SRVID:
3342 control_deregister_srvid(mem_ctx, req, &header, &request);
3343 break;
3345 case CTDB_CONTROL_GET_DBNAME:
3346 control_get_dbname(mem_ctx, req, &header, &request);
3347 break;
3349 case CTDB_CONTROL_GET_PID:
3350 control_get_pid(mem_ctx, req, &header, &request);
3351 break;
3353 case CTDB_CONTROL_GET_RECMASTER:
3354 control_get_recmaster(mem_ctx, req, &header, &request);
3355 break;
3357 case CTDB_CONTROL_GET_PNN:
3358 control_get_pnn(mem_ctx, req, &header, &request);
3359 break;
3361 case CTDB_CONTROL_SHUTDOWN:
3362 control_shutdown(mem_ctx, req, &header, &request);
3363 break;
3365 case CTDB_CONTROL_GET_MONMODE:
3366 control_get_monmode(mem_ctx, req, &header, &request);
3367 break;
3369 case CTDB_CONTROL_SET_TUNABLE:
3370 control_set_tunable(mem_ctx, req, &header, &request);
3371 break;
3373 case CTDB_CONTROL_GET_TUNABLE:
3374 control_get_tunable(mem_ctx, req, &header, &request);
3375 break;
3377 case CTDB_CONTROL_LIST_TUNABLES:
3378 control_list_tunables(mem_ctx, req, &header, &request);
3379 break;
3381 case CTDB_CONTROL_MODIFY_FLAGS:
3382 control_modify_flags(mem_ctx, req, &header, &request);
3383 break;
3385 case CTDB_CONTROL_GET_ALL_TUNABLES:
3386 control_get_all_tunables(mem_ctx, req, &header, &request);
3387 break;
3389 case CTDB_CONTROL_UPTIME:
3390 control_uptime(mem_ctx, req, &header, &request);
3391 break;
3393 case CTDB_CONTROL_ENABLE_MONITOR:
3394 control_enable_monitor(mem_ctx, req, &header, &request);
3395 break;
3397 case CTDB_CONTROL_DISABLE_MONITOR:
3398 control_disable_monitor(mem_ctx, req, &header, &request);
3399 break;
3401 case CTDB_CONTROL_RELOAD_NODES_FILE:
3402 control_reload_nodes_file(mem_ctx, req, &header, &request);
3403 break;
3405 case CTDB_CONTROL_GET_CAPABILITIES:
3406 control_get_capabilities(mem_ctx, req, &header, &request);
3407 break;
3409 case CTDB_CONTROL_RELEASE_IP:
3410 control_release_ip(mem_ctx, req, &header, &request);
3411 break;
3413 case CTDB_CONTROL_TAKEOVER_IP:
3414 control_takeover_ip(mem_ctx, req, &header, &request);
3415 break;
3417 case CTDB_CONTROL_GET_PUBLIC_IPS:
3418 control_get_public_ips(mem_ctx, req, &header, &request);
3419 break;
3421 case CTDB_CONTROL_GET_NODEMAP:
3422 control_get_nodemap(mem_ctx, req, &header, &request);
3423 break;
3425 case CTDB_CONTROL_GET_RECLOCK_FILE:
3426 control_get_reclock_file(mem_ctx, req, &header, &request);
3427 break;
3429 case CTDB_CONTROL_STOP_NODE:
3430 control_stop_node(mem_ctx, req, &header, &request);
3431 break;
3433 case CTDB_CONTROL_CONTINUE_NODE:
3434 control_continue_node(mem_ctx, req, &header, &request);
3435 break;
3437 case CTDB_CONTROL_SET_BAN_STATE:
3438 control_set_ban_state(mem_ctx, req, &header, &request);
3439 break;
3441 case CTDB_CONTROL_GET_DB_SEQNUM:
3442 control_get_db_seqnum(mem_ctx, req, &header, &request);
3443 break;
3445 case CTDB_CONTROL_DB_GET_HEALTH:
3446 control_db_get_health(mem_ctx, req, &header, &request);
3447 break;
3449 case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
3450 control_get_public_ip_info(mem_ctx, req, &header, &request);
3451 break;
3453 case CTDB_CONTROL_GET_IFACES:
3454 control_get_ifaces(mem_ctx, req, &header, &request);
3455 break;
3457 case CTDB_CONTROL_SET_IFACE_LINK_STATE:
3458 control_set_iface_link_state(mem_ctx, req, &header, &request);
3459 break;
3461 case CTDB_CONTROL_SET_DB_READONLY:
3462 control_set_db_readonly(mem_ctx, req, &header, &request);
3463 break;
3465 case CTDB_CONTROL_SET_DB_STICKY:
3466 control_set_db_sticky(mem_ctx, req, &header, &request);
3467 break;
3469 case CTDB_CONTROL_IPREALLOCATED:
3470 control_ipreallocated(mem_ctx, req, &header, &request);
3471 break;
3473 case CTDB_CONTROL_GET_RUNSTATE:
3474 control_get_runstate(mem_ctx, req, &header, &request);
3475 break;
3477 case CTDB_CONTROL_GET_NODES_FILE:
3478 control_get_nodes_file(mem_ctx, req, &header, &request);
3479 break;
3481 case CTDB_CONTROL_CHECK_PID_SRVID:
3482 control_check_pid_srvid(mem_ctx, req, &header, &request);
3483 break;
3485 default:
3486 if (! (request.flags & CTDB_CTRL_FLAG_NOREPLY)) {
3487 control_error(mem_ctx, req, &header, &request);
3489 break;
3492 done:
3493 talloc_free(mem_ctx);
3496 static int client_recv(struct tevent_req *req, int *perr)
3498 struct client_state *state = tevent_req_data(
3499 req, struct client_state);
3500 int err;
3502 DEBUG(DEBUG_INFO, ("Client done fd=%d\n", state->fd));
3503 close(state->fd);
3505 if (tevent_req_is_unix_error(req, &err)) {
3506 if (perr != NULL) {
3507 *perr = err;
3509 return -1;
3512 return state->status;
3516 * Fake CTDB server
3519 struct server_state {
3520 struct tevent_context *ev;
3521 struct ctdbd_context *ctdb;
3522 int fd;
3525 static void server_new_client(struct tevent_req *subreq);
3526 static void server_client_done(struct tevent_req *subreq);
3528 static struct tevent_req *server_send(TALLOC_CTX *mem_ctx,
3529 struct tevent_context *ev,
3530 struct ctdbd_context *ctdb,
3531 int fd)
3533 struct tevent_req *req, *subreq;
3534 struct server_state *state;
3536 req = tevent_req_create(mem_ctx, &state, struct server_state);
3537 if (req == NULL) {
3538 return NULL;
3541 state->ev = ev;
3542 state->ctdb = ctdb;
3543 state->fd = fd;
3545 subreq = accept_send(state, ev, fd);
3546 if (tevent_req_nomem(subreq, req)) {
3547 return tevent_req_post(req, ev);
3549 tevent_req_set_callback(subreq, server_new_client, req);
3551 return req;
3554 static void server_new_client(struct tevent_req *subreq)
3556 struct tevent_req *req = tevent_req_callback_data(
3557 subreq, struct tevent_req);
3558 struct server_state *state = tevent_req_data(
3559 req, struct server_state);
3560 struct ctdbd_context *ctdb = state->ctdb;
3561 int client_fd;
3562 int ret = 0;
3564 client_fd = accept_recv(subreq, NULL, NULL, &ret);
3565 TALLOC_FREE(subreq);
3566 if (client_fd == -1) {
3567 tevent_req_error(req, ret);
3568 return;
3571 subreq = client_send(state, state->ev, client_fd,
3572 ctdb, ctdb->node_map->pnn);
3573 if (tevent_req_nomem(subreq, req)) {
3574 return;
3576 tevent_req_set_callback(subreq, server_client_done, req);
3578 ctdb->num_clients += 1;
3580 subreq = accept_send(state, state->ev, state->fd);
3581 if (tevent_req_nomem(subreq, req)) {
3582 return;
3584 tevent_req_set_callback(subreq, server_new_client, req);
3587 static void server_client_done(struct tevent_req *subreq)
3589 struct tevent_req *req = tevent_req_callback_data(
3590 subreq, struct tevent_req);
3591 struct server_state *state = tevent_req_data(
3592 req, struct server_state);
3593 struct ctdbd_context *ctdb = state->ctdb;
3594 int ret = 0;
3595 int status;
3597 status = client_recv(subreq, &ret);
3598 TALLOC_FREE(subreq);
3599 if (status < 0) {
3600 tevent_req_error(req, ret);
3601 return;
3604 ctdb->num_clients -= 1;
3606 if (status == 99) {
3607 /* Special status, to shutdown server */
3608 DEBUG(DEBUG_INFO, ("Shutting down server\n"));
3609 tevent_req_done(req);
3613 static bool server_recv(struct tevent_req *req, int *perr)
3615 int err;
3617 if (tevent_req_is_unix_error(req, &err)) {
3618 if (perr != NULL) {
3619 *perr = err;
3621 return false;
3623 return true;
3627 * Main functions
3630 static int socket_init(const char *sockpath)
3632 struct sockaddr_un addr;
3633 size_t len;
3634 int ret, fd;
3636 memset(&addr, 0, sizeof(addr));
3637 addr.sun_family = AF_UNIX;
3639 len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
3640 if (len >= sizeof(addr.sun_path)) {
3641 fprintf(stderr, "path too long: %s\n", sockpath);
3642 return -1;
3645 fd = socket(AF_UNIX, SOCK_STREAM, 0);
3646 if (fd == -1) {
3647 fprintf(stderr, "socket failed - %s\n", sockpath);
3648 return -1;
3651 ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
3652 if (ret != 0) {
3653 fprintf(stderr, "bind failed - %s\n", sockpath);
3654 goto fail;
3657 ret = listen(fd, 10);
3658 if (ret != 0) {
3659 fprintf(stderr, "listen failed\n");
3660 goto fail;
3663 DEBUG(DEBUG_INFO, ("Socket init done\n"));
3665 return fd;
3667 fail:
3668 if (fd != -1) {
3669 close(fd);
3671 return -1;
3674 static struct options {
3675 const char *sockpath;
3676 const char *pidfile;
3677 const char *debuglevel;
3678 } options;
3680 static struct poptOption cmdline_options[] = {
3681 { "socket", 's', POPT_ARG_STRING, &options.sockpath, 0,
3682 "Unix domain socket path", "filename" },
3683 { "pidfile", 'p', POPT_ARG_STRING, &options.pidfile, 0,
3684 "pid file", "filename" } ,
3685 { "debug", 'd', POPT_ARG_STRING, &options.debuglevel, 0,
3686 "debug level", "ERR|WARNING|NOTICE|INFO|DEBUG" } ,
3689 static void cleanup(void)
3691 unlink(options.sockpath);
3692 unlink(options.pidfile);
3695 static void signal_handler(int sig)
3697 cleanup();
3698 exit(0);
3701 static void start_server(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3702 struct ctdbd_context *ctdb, int fd, int pfd)
3704 struct tevent_req *req;
3705 int ret = 0;
3706 ssize_t len;
3708 atexit(cleanup);
3709 signal(SIGTERM, signal_handler);
3711 req = server_send(mem_ctx, ev, ctdb, fd);
3712 if (req == NULL) {
3713 fprintf(stderr, "Memory error\n");
3714 exit(1);
3717 len = write(pfd, &ret, sizeof(ret));
3718 if (len != sizeof(ret)) {
3719 fprintf(stderr, "Failed to send message to parent\n");
3720 exit(1);
3722 close(pfd);
3724 tevent_req_poll(req, ev);
3726 server_recv(req, &ret);
3727 if (ret != 0) {
3728 exit(1);
3732 int main(int argc, const char *argv[])
3734 TALLOC_CTX *mem_ctx;
3735 struct ctdbd_context *ctdb;
3736 struct tevent_context *ev;
3737 poptContext pc;
3738 int opt, fd, ret, pfd[2];
3739 ssize_t len;
3740 pid_t pid;
3741 FILE *fp;
3743 pc = poptGetContext(argv[0], argc, argv, cmdline_options,
3744 POPT_CONTEXT_KEEP_FIRST);
3745 while ((opt = poptGetNextOpt(pc)) != -1) {
3746 fprintf(stderr, "Invalid option %s\n", poptBadOption(pc, 0));
3747 exit(1);
3750 if (options.sockpath == NULL) {
3751 fprintf(stderr, "Please specify socket path\n");
3752 poptPrintHelp(pc, stdout, 0);
3753 exit(1);
3756 if (options.pidfile == NULL) {
3757 fprintf(stderr, "Please specify pid file\n");
3758 poptPrintHelp(pc, stdout, 0);
3759 exit(1);
3762 mem_ctx = talloc_new(NULL);
3763 if (mem_ctx == NULL) {
3764 fprintf(stderr, "Memory error\n");
3765 exit(1);
3768 ret = logging_init(mem_ctx, "file:", options.debuglevel, "fake-ctdbd");
3769 if (ret != 0) {
3770 fprintf(stderr, "Invalid debug level\n");
3771 poptPrintHelp(pc, stdout, 0);
3772 exit(1);
3775 ctdb = ctdbd_setup(mem_ctx);
3776 if (ctdb == NULL) {
3777 exit(1);
3780 if (! ctdbd_verify(ctdb)) {
3781 exit(1);
3784 ev = tevent_context_init(mem_ctx);
3785 if (ev == NULL) {
3786 fprintf(stderr, "Memory error\n");
3787 exit(1);
3790 fd = socket_init(options.sockpath);
3791 if (fd == -1) {
3792 exit(1);
3795 ret = pipe(pfd);
3796 if (ret != 0) {
3797 fprintf(stderr, "Failed to create pipe\n");
3798 cleanup();
3799 exit(1);
3802 pid = fork();
3803 if (pid == -1) {
3804 fprintf(stderr, "Failed to fork\n");
3805 cleanup();
3806 exit(1);
3809 if (pid == 0) {
3810 /* Child */
3811 close(pfd[0]);
3812 start_server(mem_ctx, ev, ctdb, fd, pfd[1]);
3813 exit(1);
3816 /* Parent */
3817 close(pfd[1]);
3819 len = read(pfd[0], &ret, sizeof(ret));
3820 close(pfd[0]);
3821 if (len != sizeof(ret)) {
3822 fprintf(stderr, "len = %zi\n", len);
3823 fprintf(stderr, "Failed to get message from child\n");
3824 kill(pid, SIGTERM);
3825 exit(1);
3828 fp = fopen(options.pidfile, "w");
3829 if (fp == NULL) {
3830 fprintf(stderr, "Failed to open pid file %s\n",
3831 options.pidfile);
3832 kill(pid, SIGTERM);
3833 exit(1);
3835 fprintf(fp, "%d\n", pid);
3836 fclose(fp);
3838 return 0;