};
static void sock_daemon_run_started(struct tevent_req *subreq);
+static void sock_daemon_run_startup_done(struct tevent_req *subreq);
static void sock_daemon_run_signal_handler(struct tevent_context *ev,
struct tevent_signal *se,
int signum, int count, void *siginfo,
D_NOTICE("daemon started, pid=%u\n", getpid());
+ if (sockd->funcs != NULL && sockd->funcs->startup_send != NULL &&
+ sockd->funcs->startup_recv != NULL) {
+ subreq = sockd->funcs->startup_send(state, state->ev,
+ sockd->private_data);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, sock_daemon_run_startup_done,
+ req);
+ return;
+ }
+
if (sockd->funcs != NULL && sockd->funcs->startup != NULL) {
int ret;
sock_daemon_run_wait(req);
}
+static void sock_daemon_run_startup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct sock_daemon_run_state *state = tevent_req_data(
+ req, struct sock_daemon_run_state);
+ struct sock_daemon_context *sockd = state->sockd;
+ int ret;
+ bool status;
+
+ status = sockd->funcs->startup_recv(subreq, &ret);
+ TALLOC_FREE(subreq);
+ if (! status) {
+ D_ERR("startup failed, ret=%d\n", ret);
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ D_NOTICE("startup completed succesfully\n");
+
+ status = sock_daemon_run_socket_listen(req);
+ if (! status) {
+ return;
+ }
+ sock_daemon_run_wait(req);
+}
+
static void sock_daemon_run_signal_handler(struct tevent_context *ev,
struct tevent_signal *se,
int signum, int count, void *siginfo,
* startup() should return 0 for success, non-zero value on failure
* On failure, sock_daemon_run() will return error.
*
+ * startup_send()/startup_recv() is the async version of startup()
+ *
* reconfigure() is called when the daemon receives SIGUSR1 or SIGHUP
* reconfigure() should return 0 for success, non-zero value on failure
* On failure, sock_daemon_run() will continue to run.
*/
struct sock_daemon_funcs {
int (*startup)(void *private_data);
+
+ struct tevent_req * (*startup_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ void *private_data);
+ bool (*startup_recv)(struct tevent_req *req, int *perr);
+
int (*reconfigure)(void *private_data);
void (*shutdown)(void *private_data);
test1[PID]: daemon started, pid=PID
test1[PID]: startup failed, ret=1
test1[PID]: daemon started, pid=PID
+test1[PID]: startup failed, ret=2
+test1[PID]: daemon started, pid=PID
test1[PID]: startup completed successfully
test1[PID]: listening on $sockpath
test1[PID]: Shutting down
return 0;
}
+struct test1_startup_state {
+};
+
+static struct tevent_req *test1_startup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ void *private_data)
+{
+ struct tevent_req *req;
+ struct test1_startup_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct test1_startup_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ tevent_req_error(req, 2);
+ return tevent_req_post(req, ev);
+}
+
+static bool test1_startup_recv(struct tevent_req *req, int *perr)
+{
+ if (tevent_req_is_unix_error(req, perr)) {
+ return false;
+ }
+
+ return true;
+}
+
static struct tevent_req *dummy_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sock_client_context *client,
assert(ret == EIO);
talloc_free(sockd);
+ test1_funcs = (struct sock_daemon_funcs){
+ .startup_send = test1_startup_send,
+ .startup_recv = test1_startup_recv,
+ };
+
+ ret = sock_daemon_setup(mem_ctx, "test1", "file:", "NOTICE",
+ &test1_funcs, NULL, &sockd);
+ assert(ret == 0);
+ assert(sockd != NULL);
+
+ ret = stat(pidfile, &st);
+ assert(ret == -1);
+
+ ret = sock_daemon_run(ev, sockd, NULL, false, false, -1);
+ assert(ret == EIO);
+ talloc_free(sockd);
+
test1_funcs = (struct sock_daemon_funcs){
.startup = test1_startup,
.wait_send = dummy_wait_send,