1 #include "external-agent.h"
2 #include "lock-tracking.h"
13 #include "../common/tdb_private.h"
14 #include "tap-interface.h"
18 static struct tdb_context
*tdb
;
20 static enum agent_return
do_operation(enum operation op
, const char *name
)
23 enum agent_return ret
;
26 if (op
!= OPEN
&& op
!= OPEN_WITH_CLEAR_IF_FIRST
&& !tdb
) {
27 diag("external: No tdb open!");
31 k
.dptr
= (void *)name
;
32 k
.dsize
= strlen(name
);
34 locking_would_block
= 0;
38 diag("Already have tdb %s open", tdb_name(tdb
));
41 tdb
= tdb_open_ex(name
, 0, TDB_DEFAULT
, O_RDWR
, 0,
44 if (!locking_would_block
)
45 diag("Opening tdb gave %s", strerror(errno
));
50 case OPEN_WITH_CLEAR_IF_FIRST
:
53 tdb
= tdb_open_ex(name
, 0, TDB_CLEAR_IF_FIRST
, O_RDWR
, 0,
55 ret
= tdb
? SUCCESS
: OTHER_FAILURE
;
57 case TRANSACTION_START
:
58 ret
= tdb_transaction_start(tdb
) == 0 ? SUCCESS
: OTHER_FAILURE
;
61 data
= tdb_fetch(tdb
, k
);
62 if (data
.dptr
== NULL
) {
63 if (tdb_error(tdb
) == TDB_ERR_NOEXIST
)
67 } else if (data
.dsize
!= k
.dsize
68 || memcmp(data
.dptr
, k
.dptr
, k
.dsize
) != 0) {
76 ret
= tdb_store(tdb
, k
, k
, 0) == 0 ? SUCCESS
: OTHER_FAILURE
;
78 case TRANSACTION_COMMIT
:
79 ret
= tdb_transaction_commit(tdb
)==0 ? SUCCESS
: OTHER_FAILURE
;
82 ret
= tdb_check(tdb
, NULL
, NULL
) == 0 ? SUCCESS
: OTHER_FAILURE
;
85 ret
= tdb_needs_recovery(tdb
) ? SUCCESS
: FAILED
;
88 ret
= tdb_close(tdb
) == 0 ? SUCCESS
: OTHER_FAILURE
;
95 if (locking_would_block
)
96 ret
= WOULD_HAVE_BLOCKED
;
102 int cmdfd
, responsefd
;
105 /* Do this before doing any tdb stuff. Return handle, or NULL. */
106 struct agent
*prepare_external_agent(void)
109 int command
[2], response
[2];
110 char name
[1+PATH_MAX
];
112 if (pipe(command
) != 0 || pipe(response
) != 0)
120 struct agent
*agent
= malloc(sizeof(*agent
));
124 agent
->cmdfd
= command
[1];
125 agent
->responsefd
= response
[0];
132 /* We want to fail, not block. */
133 nonblocking_locks
= true;
134 log_prefix
= "external: ";
135 while ((ret
= read(command
[0], name
, sizeof(name
))) > 0) {
136 enum agent_return result
;
138 result
= do_operation(name
[0], name
+1);
139 if (write(response
[1], &result
, sizeof(result
))
141 err(1, "Writing response");
146 /* Ask the external agent to try to do an operation. */
147 enum agent_return
external_agent_operation(struct agent
*agent
,
151 enum agent_return res
;
157 len
= 1 + strlen(name
) + 1;
158 string
= malloc(len
);
161 strcpy(string
+1, name
);
163 if (write(agent
->cmdfd
, string
, len
) != len
164 || read(agent
->responsefd
, &res
, sizeof(res
)) != sizeof(res
))
171 const char *agent_return_name(enum agent_return ret
)
173 return ret
== SUCCESS
? "SUCCESS"
174 : ret
== WOULD_HAVE_BLOCKED
? "WOULD_HAVE_BLOCKED"
175 : ret
== AGENT_DIED
? "AGENT_DIED"
176 : ret
== FAILED
? "FAILED"
177 : ret
== OTHER_FAILURE
? "OTHER_FAILURE"
181 const char *operation_name(enum operation op
)
184 case OPEN
: return "OPEN";
185 case OPEN_WITH_CLEAR_IF_FIRST
: return "OPEN_WITH_CLEAR_IF_FIRST";
186 case TRANSACTION_START
: return "TRANSACTION_START";
187 case FETCH
: return "FETCH";
188 case STORE
: return "STORE";
189 case TRANSACTION_COMMIT
: return "TRANSACTION_COMMIT";
190 case CHECK
: return "CHECK";
191 case NEEDS_RECOVERY
: return "NEEDS_RECOVERY";
192 case CLOSE
: return "CLOSE";
194 return "**INVALID**";