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
= (void *)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 if (locking_would_block
)
95 ret
= WOULD_HAVE_BLOCKED
;
101 int cmdfd
, responsefd
;
104 /* Do this before doing any tdb stuff. Return handle, or NULL. */
105 struct agent
*prepare_external_agent(void)
108 int command
[2], response
[2];
109 char name
[1+PATH_MAX
];
111 if (pipe(command
) != 0 || pipe(response
) != 0) {
112 fprintf(stderr
, "pipe failed: %s\n", strerror(errno
));
118 fprintf(stderr
, "fork failed: %s\n", strerror(errno
));
123 struct agent
*agent
= malloc(sizeof(*agent
));
127 agent
->cmdfd
= command
[1];
128 agent
->responsefd
= response
[0];
135 /* We want to fail, not block. */
136 nonblocking_locks
= true;
137 log_prefix
= "external: ";
138 while ((ret
= read(command
[0], name
, sizeof(name
))) > 0) {
139 enum agent_return result
;
141 result
= do_operation(name
[0], name
+1);
142 if (write(response
[1], &result
, sizeof(result
))
149 /* Ask the external agent to try to do an operation. */
150 enum agent_return
external_agent_operation(struct agent
*agent
,
154 enum agent_return res
;
160 len
= 1 + strlen(name
) + 1;
161 string
= malloc(len
);
164 strcpy(string
+1, name
);
166 if (write(agent
->cmdfd
, string
, len
) != len
167 || read(agent
->responsefd
, &res
, sizeof(res
)) != sizeof(res
))
174 const char *agent_return_name(enum agent_return ret
)
176 return ret
== SUCCESS
? "SUCCESS"
177 : ret
== WOULD_HAVE_BLOCKED
? "WOULD_HAVE_BLOCKED"
178 : ret
== AGENT_DIED
? "AGENT_DIED"
179 : ret
== FAILED
? "FAILED"
180 : ret
== OTHER_FAILURE
? "OTHER_FAILURE"
184 const char *operation_name(enum operation op
)
187 case OPEN
: return "OPEN";
188 case OPEN_WITH_CLEAR_IF_FIRST
: return "OPEN_WITH_CLEAR_IF_FIRST";
189 case TRANSACTION_START
: return "TRANSACTION_START";
190 case FETCH
: return "FETCH";
191 case STORE
: return "STORE";
192 case TRANSACTION_COMMIT
: return "TRANSACTION_COMMIT";
193 case CHECK
: return "CHECK";
194 case NEEDS_RECOVERY
: return "NEEDS_RECOVERY";
195 case CLOSE
: return "CLOSE";
197 return "**INVALID**";