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) {
80 return tdb_maybe_needs_recovery(tdb);
87 tdb_setalarm_sigptr(tdb, &alarmed);
90 if (tdb_transaction_start(tdb) != 0)
94 if (tdb_store(tdb, k, d, 0) != 0) {
95 tdb_transaction_cancel(tdb);
101 if (tdb_transaction_commit(tdb) == 0) {
103 if (op != TRANSACTION_KEEP_OPENED) {
112 if (op != TRANSACTION_KEEP_OPENED) {
122 int cmdfd, responsefd;
125 /* Do this before doing any tdb stuff. Return handle, or NULL. */
126 struct agent *prepare_external_agent(void)
129 int command[2], response[2];
130 struct sigaction act = { .sa_handler = do_alarm };
131 char name[1+PATH_MAX];
133 if (pipe(command) != 0 || pipe(response) != 0)
141 struct agent *agent = malloc(sizeof(*agent));
145 agent->cmdfd = command[1];
146 agent->responsefd = response[0];
152 sigaction(SIGALRM, &act, NULL);
154 while ((ret = read(command[0], name, sizeof(name))) > 0) {
157 result = do_operation(name[0], name+1);
158 if (write(response[1], &result, sizeof(result))
160 err(1, "Writing response");
162 diag("external: read %i: %s", ret, strerror(errno));
166 /* Ask the external agent to try to do an operation. */
167 int external_agent_operation(struct agent *agent,
168 enum operation op, const char *tdbname)
171 char string[1 + strlen(tdbname) + 1];
174 strcpy(string+1, tdbname);
176 if (write(agent->cmdfd, string, sizeof(string)) != sizeof(string))
177 err(1, "Writing to agent");
179 if (read(agent->responsefd, &res, sizeof(res)) != sizeof(res))
180 err(1, "Reading from agent");
183 errx(1, "Agent returned %u\n", res);
188 void external_agent_operation_start(struct agent *agent,
189 enum operation op, const char *tdbname)
191 char string[1 + strlen(tdbname) + 1];
194 strcpy(string+1, tdbname);
196 if (write(agent->cmdfd, string, sizeof(string)) != sizeof(string))
197 err(1, "Writing to agent");
200 bool external_agent_operation_check(struct agent *agent, bool block, int *res)
202 int flags = fcntl(agent->responsefd, F_GETFL);
205 fcntl(agent->responsefd, F_SETFL, flags & ~O_NONBLOCK);
207 fcntl(agent->responsefd, F_SETFL, flags | O_NONBLOCK);
209 switch (read(agent->responsefd, res, sizeof(*res))) {
213 errx(1, "Agent died?");
215 if (!block && (errno == EAGAIN || errno == EWOULDBLOCK))
217 err(1, "%slocking reading from agent", block ? "B" : "Non-b");
221 errx(1, "Agent returned %u\n", *res);