1 #include "external-agent.h"
2 #include "lock-tracking.h"
12 #include "../common/tdb_private.h"
13 #include "tap-interface.h"
17 static struct tdb_context
*tdb
;
19 static enum agent_return
do_operation(enum operation op
, const char *name
)
22 enum agent_return ret
;
25 if (op
!= OPEN
&& op
!= OPEN_WITH_CLEAR_IF_FIRST
&& !tdb
) {
26 diag("external: No tdb open!");
30 k
.dptr
= discard_const_p(uint8_t, name
);
31 k
.dsize
= strlen(name
);
33 locking_would_block
= 0;
37 diag("Already have tdb %s open", tdb_name(tdb
));
40 tdb
= tdb_open_ex(name
, 0, TDB_DEFAULT
, O_RDWR
, 0,
43 if (!locking_would_block
)
44 diag("Opening tdb gave %s", strerror(errno
));
49 case OPEN_WITH_CLEAR_IF_FIRST
:
52 tdb
= tdb_open_ex(name
, 0, TDB_CLEAR_IF_FIRST
, O_RDWR
, 0,
54 ret
= tdb
? SUCCESS
: OTHER_FAILURE
;
56 case TRANSACTION_START
:
57 ret
= tdb_transaction_start(tdb
) == 0 ? SUCCESS
: OTHER_FAILURE
;
60 data
= tdb_fetch(tdb
, k
);
61 if (data
.dptr
== NULL
) {
62 if (tdb_error(tdb
) == TDB_ERR_NOEXIST
)
66 } else if (data
.dsize
!= k
.dsize
67 || memcmp(data
.dptr
, k
.dptr
, k
.dsize
) != 0) {
75 ret
= tdb_store(tdb
, k
, k
, 0) == 0 ? SUCCESS
: OTHER_FAILURE
;
77 case TRANSACTION_COMMIT
:
78 ret
= tdb_transaction_commit(tdb
)==0 ? SUCCESS
: OTHER_FAILURE
;
81 ret
= tdb_check(tdb
, NULL
, NULL
) == 0 ? SUCCESS
: OTHER_FAILURE
;
84 ret
= tdb_needs_recovery(tdb
) ? SUCCESS
: FAILED
;
87 ret
= tdb_close(tdb
) == 0 ? SUCCESS
: OTHER_FAILURE
;
94 ret
= tdb_munmap(tdb
) == 0 ? SUCCESS
: OTHER_FAILURE
;
96 tdb
->flags
|= TDB_NOMMAP
;
103 if (locking_would_block
)
104 ret
= WOULD_HAVE_BLOCKED
;
110 int cmdfd
, responsefd
;
114 /* Do this before doing any tdb stuff. Return handle, or NULL. */
115 struct agent
*prepare_external_agent(void)
118 int command
[2], response
[2];
119 char name
[1+PATH_MAX
];
120 struct agent
*agent
= malloc(sizeof(*agent
));
122 if (pipe(command
) != 0 || pipe(response
) != 0) {
123 fprintf(stderr
, "pipe failed: %s\n", strerror(errno
));
128 if (agent
->pid
< 0) {
129 fprintf(stderr
, "fork failed: %s\n", strerror(errno
));
133 if (agent
->pid
!= 0) {
136 agent
->cmdfd
= command
[1];
137 agent
->responsefd
= response
[0];
144 /* We want to fail, not block. */
145 nonblocking_locks
= true;
146 log_prefix
= "external: ";
147 while ((ret
= read(command
[0], name
, sizeof(name
))) > 0) {
148 enum agent_return result
;
150 result
= do_operation(name
[0], name
+1);
151 if (write(response
[1], &result
, sizeof(result
))
158 void shutdown_agent(struct agent
*agent
)
163 close(agent
->responsefd
);
164 p
= waitpid(agent
->pid
, NULL
, WNOHANG
);
166 kill(agent
->pid
, SIGKILL
);
168 waitpid(agent
->pid
, NULL
, 0);
172 /* Ask the external agent to try to do an operation. */
173 enum agent_return
external_agent_operation(struct agent
*agent
,
177 enum agent_return res
;
183 len
= 1 + strlen(name
) + 1;
184 string
= malloc(len
);
187 strcpy(string
+1, name
);
189 if (write(agent
->cmdfd
, string
, len
) != len
190 || read(agent
->responsefd
, &res
, sizeof(res
)) != sizeof(res
))
197 const char *agent_return_name(enum agent_return ret
)
199 return ret
== SUCCESS
? "SUCCESS"
200 : ret
== WOULD_HAVE_BLOCKED
? "WOULD_HAVE_BLOCKED"
201 : ret
== AGENT_DIED
? "AGENT_DIED"
202 : ret
== FAILED
? "FAILED"
203 : ret
== OTHER_FAILURE
? "OTHER_FAILURE"
207 const char *operation_name(enum operation op
)
210 case OPEN
: return "OPEN";
211 case OPEN_WITH_CLEAR_IF_FIRST
: return "OPEN_WITH_CLEAR_IF_FIRST";
212 case TRANSACTION_START
: return "TRANSACTION_START";
213 case FETCH
: return "FETCH";
214 case STORE
: return "STORE";
215 case TRANSACTION_COMMIT
: return "TRANSACTION_COMMIT";
216 case CHECK
: return "CHECK";
217 case NEEDS_RECOVERY
: return "NEEDS_RECOVERY";
218 case CLOSE
: return "CLOSE";
219 case PING
: return "PING";
220 case UNMAP
: return "UNMAP";
222 return "**INVALID**";