2 Unix SMB/CIFS implementation.
3 Regular background jobs as forked helpers
4 Copyright (C) Volker Lendecke 2012
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "lib/util/tevent_ntstatus.h"
22 #include "lib/async_req/async_sock.h"
23 #include "include/messages.h"
24 #include "background.h"
26 struct background_job_state
{
27 struct tevent_context
*ev
;
28 struct messaging_context
*msg
;
29 uint32_t *trigger_msgs
;
30 size_t num_trigger_msgs
;
31 bool parent_longlived
;
32 int (*fn
)(void *private_data
);
35 struct tevent_req
*wakeup_req
;
39 static int background_job_state_destructor(struct background_job_state
*s
);
40 static void background_job_waited(struct tevent_req
*subreq
);
41 static void background_job_done(struct tevent_req
*subreq
);
42 static void background_job_trigger(
43 struct messaging_context
*msg
, void *private_data
, uint32_t msg_type
,
44 struct server_id server_id
, DATA_BLOB
*data
);
46 struct tevent_req
*background_job_send(TALLOC_CTX
*mem_ctx
,
47 struct tevent_context
*ev
,
48 struct messaging_context
*msg
,
49 uint32_t *trigger_msgs
,
50 size_t num_trigger_msgs
,
51 time_t initial_wait_sec
,
52 int (*fn
)(void *private_data
),
55 struct tevent_req
*req
, *subreq
;
56 struct background_job_state
*state
;
59 req
= tevent_req_create(mem_ctx
, &state
,
60 struct background_job_state
);
68 if (num_trigger_msgs
!= 0) {
69 state
->trigger_msgs
= (uint32_t *)talloc_memdup(
71 sizeof(uint32_t) * num_trigger_msgs
);
72 if (tevent_req_nomem(state
->trigger_msgs
, req
)) {
73 return tevent_req_post(req
, ev
);
75 state
->num_trigger_msgs
= num_trigger_msgs
;
79 state
->private_data
= private_data
;
82 talloc_set_destructor(state
, background_job_state_destructor
);
84 for (i
=0; i
<num_trigger_msgs
; i
++) {
86 status
= messaging_register(msg
, state
, trigger_msgs
[i
],
87 background_job_trigger
);
88 if (tevent_req_nterror(req
, status
)) {
89 return tevent_req_post(req
, ev
);
93 subreq
= tevent_wakeup_send(
94 state
, state
->ev
, timeval_current_ofs(initial_wait_sec
, 0));
95 if (tevent_req_nomem(subreq
, req
)) {
96 return tevent_req_post(req
, ev
);
98 tevent_req_set_callback(subreq
, background_job_waited
, req
);
99 state
->wakeup_req
= subreq
;
103 static int background_job_state_destructor(struct background_job_state
*state
)
106 if (state
->pipe_fd
!= -1) {
107 close(state
->pipe_fd
);
110 for (i
=0; i
<state
->num_trigger_msgs
; i
++) {
111 messaging_deregister(state
->msg
, state
->trigger_msgs
[i
],
117 static void background_job_trigger(
118 struct messaging_context
*msg
, void *private_data
, uint32_t msg_type
,
119 struct server_id server_id
, DATA_BLOB
*data
)
121 struct background_job_state
*state
= talloc_get_type_abort(
122 private_data
, struct background_job_state
);
124 if (state
->wakeup_req
== NULL
) {
127 if (!tevent_req_set_endtime(state
->wakeup_req
, state
->ev
,
129 DEBUG(10, ("tevent_req_set_endtime failed\n"));
133 static void background_job_waited(struct tevent_req
*subreq
)
135 struct tevent_req
*req
= tevent_req_callback_data(
136 subreq
, struct tevent_req
);
137 struct background_job_state
*state
= tevent_req_data(
138 req
, struct background_job_state
);
143 ret
= tevent_wakeup_recv(subreq
);
145 state
->wakeup_req
= NULL
;
147 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
153 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
162 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
174 status
= reinit_after_fork(state
->msg
, state
->ev
, true);
175 if (NT_STATUS_IS_OK(status
)) {
176 res
= state
->fn(state
->private_data
);
180 written
= write(fds
[1], &res
, sizeof(res
));
186 * No TALLOC_FREE here, messaging_parent_dgm_cleanup_init for
187 * example calls background_job_send with "messaging_context"
188 * as talloc parent. Thus "state" will be freed with the
189 * following talloc_free will have removed "state" when it
190 * returns. TALLOC_FREE will then write a NULL into free'ed
191 * memory. talloc_free() is required although we immediately
192 * exit, the messaging_context's destructor will want to clean
195 talloc_free(state
->msg
);
202 state
->pipe_fd
= fds
[0];
204 subreq
= read_packet_send(state
, state
->ev
, state
->pipe_fd
,
205 sizeof(int), NULL
, NULL
);
206 if (tevent_req_nomem(subreq
, req
)) {
209 tevent_req_set_callback(subreq
, background_job_done
, req
);
212 static void background_job_done(struct tevent_req
*subreq
)
214 struct tevent_req
*req
= tevent_req_callback_data(
215 subreq
, struct tevent_req
);
216 struct background_job_state
*state
= tevent_req_data(
217 req
, struct background_job_state
);
223 ret
= read_packet_recv(subreq
, talloc_tos(), &buf
, &err
);
226 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
229 close(state
->pipe_fd
);
231 memcpy(&wait_secs
, buf
, sizeof(wait_secs
));
232 if (wait_secs
== -1) {
233 tevent_req_done(req
);
236 subreq
= tevent_wakeup_send(
237 state
, state
->ev
, timeval_current_ofs(wait_secs
, 0));
238 if (tevent_req_nomem(subreq
, req
)) {
241 tevent_req_set_callback(subreq
, background_job_waited
, req
);
242 state
->wakeup_req
= subreq
;
245 NTSTATUS
background_job_recv(struct tevent_req
*req
)
247 return tevent_req_simple_recv_ntstatus(req
);