1 #include "external-transaction.h"
11 #include <ccan/tdb/tdb.h>
12 #include <ccan/tdb/tdb_private.h>
13 #include <ccan/tap/tap.h>
17 static struct tdb_context *tdb;
19 static volatile sig_atomic_t alarmed;
20 static void do_alarm(int signum)
25 static void taplog(struct tdb_context *tdb,
26 enum tdb_debug_level level,
33 vsprintf(line, fmt, ap);
36 diag("external: %s", line);
39 static int do_operation(enum operation op, const char *name)
41 struct tdb_logging_context logctx = { taplog, NULL };
43 TDB_DATA k = { .dptr = (void *)"a", .dsize = 1 };
44 TDB_DATA d = { .dptr = (void *)"b", .dsize = 1 };
46 if (op <= KEEP_OPENED) {
47 tdb = tdb_open_ex(name, 0, op == OPEN_WITH_CLEAR_IF_FIRST ?
48 TDB_CLEAR_IF_FIRST : TDB_DEFAULT, O_RDWR, 0,
54 if (op == KEEP_OPENED) {
56 } else if (op == OPEN || op == OPEN_WITH_CLEAR_IF_FIRST || op == CLOSE) {
60 } else if (op == STORE_KEEP_OPENED) {
61 if (tdb_store(tdb, k, d, 0) != 0)
64 } else if (op == FETCH_KEEP_OPENED) {
66 ret = tdb_fetch(tdb, k);
67 if (ret.dptr == NULL) {
68 if (tdb_error(tdb) == TDB_ERR_NOEXIST)
72 if (ret.dsize != 1 || *(char *)ret.dptr != 'b')
76 } else if (op == CHECK_KEEP_OPENED) {
77 return tdb_check(tdb, NULL, 0) == 0;
78 } else if (op == NEEDS_RECOVERY_KEEP_OPENED) {
79 return tdb_maybe_needs_recovery(tdb);
83 tdb_setalarm_sigptr(tdb, &alarmed);
86 if (tdb_transaction_start(tdb) != 0)
90 if (tdb_store(tdb, k, d, 0) != 0) {
91 tdb_transaction_cancel(tdb);
97 if (tdb_transaction_commit(tdb) == 0) {
99 if (op != TRANSACTION_KEEP_OPENED) {
108 if (op != TRANSACTION_KEEP_OPENED) {
118 int cmdfd, responsefd;
121 /* Do this before doing any tdb stuff. Return handle, or NULL. */
122 struct agent *prepare_external_agent(void)
125 int command[2], response[2];
126 struct sigaction act = { .sa_handler = do_alarm };
127 char name[1+PATH_MAX];
129 if (pipe(command) != 0 || pipe(response) != 0)
137 struct agent *agent = malloc(sizeof(*agent));
141 agent->cmdfd = command[1];
142 agent->responsefd = response[0];
148 sigaction(SIGALRM, &act, NULL);
150 while ((ret = read(command[0], name, sizeof(name))) > 0) {
153 result = do_operation(name[0], name+1);
154 if (write(response[1], &result, sizeof(result))
156 err(1, "Writing response");
158 diag("external: read %i: %s", ret, strerror(errno));
162 /* Ask the external agent to try to do an operation. */
163 int external_agent_operation(struct agent *agent,
164 enum operation op, const char *tdbname)
167 char string[1 + strlen(tdbname) + 1];
170 strcpy(string+1, tdbname);
172 if (write(agent->cmdfd, string, sizeof(string)) != sizeof(string))
173 err(1, "Writing to agent");
175 if (read(agent->responsefd, &res, sizeof(res)) != sizeof(res))
176 err(1, "Reading from agent");
179 errx(1, "Agent returned %u\n", res);
184 void external_agent_operation_start(struct agent *agent,
185 enum operation op, const char *tdbname)
187 char string[1 + strlen(tdbname) + 1];
190 strcpy(string+1, tdbname);
192 if (write(agent->cmdfd, string, sizeof(string)) != sizeof(string))
193 err(1, "Writing to agent");
196 bool external_agent_operation_check(struct agent *agent, bool block, int *res)
198 int flags = fcntl(agent->responsefd, F_GETFL);
201 fcntl(agent->responsefd, F_SETFL, flags & ~O_NONBLOCK);
203 fcntl(agent->responsefd, F_SETFL, flags | O_NONBLOCK);
205 switch (read(agent->responsefd, res, sizeof(*res))) {
209 errx(1, "Agent died?");
211 if (!block && (errno == EAGAIN || errno == EWOULDBLOCK))
213 err(1, "%slocking reading from agent", block ? "B" : "Non-b");
217 errx(1, "Agent returned %u\n", *res);