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
;
37 struct tevent_req
*pipe_req
;
40 static int background_job_state_destructor(struct background_job_state
*s
);
41 static void background_job_waited(struct tevent_req
*subreq
);
42 static void background_job_done(struct tevent_req
*subreq
);
43 static bool background_job_trigger(
44 struct messaging_rec
*rec
, void *private_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
++) {
85 subreq
= messaging_filtered_read_send(
86 state
, ev
, msg
, background_job_trigger
, state
);
87 if (tevent_req_nomem(subreq
, req
)) {
88 return tevent_req_post(req
, ev
);
92 subreq
= tevent_wakeup_send(
93 state
, state
->ev
, timeval_current_ofs(initial_wait_sec
, 0));
94 if (tevent_req_nomem(subreq
, req
)) {
95 return tevent_req_post(req
, ev
);
97 tevent_req_set_callback(subreq
, background_job_waited
, req
);
98 state
->wakeup_req
= subreq
;
102 static int background_job_state_destructor(struct background_job_state
*state
)
104 TALLOC_FREE(state
->pipe_req
);
105 if (state
->pipe_fd
!= -1) {
106 close(state
->pipe_fd
);
113 static bool background_job_trigger(
114 struct messaging_rec
*rec
, void *private_data
)
116 struct background_job_state
*state
= talloc_get_type_abort(
117 private_data
, struct background_job_state
);
120 if (state
->wakeup_req
== NULL
) {
123 for (i
=0; i
<state
->num_trigger_msgs
; i
++) {
124 if (rec
->msg_type
== state
->trigger_msgs
[i
]) {
128 if (i
== state
->num_trigger_msgs
) {
131 if (!tevent_req_set_endtime(state
->wakeup_req
, state
->ev
,
133 DEBUG(10, ("tevent_req_set_endtime failed\n"));
138 static void background_job_waited(struct tevent_req
*subreq
)
140 struct tevent_req
*req
= tevent_req_callback_data(
141 subreq
, struct tevent_req
);
142 struct background_job_state
*state
= tevent_req_data(
143 req
, struct background_job_state
);
148 ret
= tevent_wakeup_recv(subreq
);
150 state
->wakeup_req
= NULL
;
152 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
158 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
167 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
179 status
= reinit_after_fork(state
->msg
, state
->ev
, true);
180 if (NT_STATUS_IS_OK(status
)) {
181 res
= state
->fn(state
->private_data
);
185 written
= write(fds
[1], &res
, sizeof(res
));
191 * No TALLOC_FREE here, messaging_parent_dgm_cleanup_init for
192 * example calls background_job_send with "messaging_context"
193 * as talloc parent. Thus "state" will be freed with the
194 * following talloc_free will have removed "state" when it
195 * returns. TALLOC_FREE will then write a NULL into free'ed
196 * memory. talloc_free() is required although we immediately
197 * exit, the messaging_context's destructor will want to clean
200 talloc_free(state
->msg
);
207 state
->pipe_fd
= fds
[0];
209 subreq
= read_packet_send(state
, state
->ev
, state
->pipe_fd
,
210 sizeof(int), NULL
, NULL
);
211 if (tevent_req_nomem(subreq
, req
)) {
214 tevent_req_set_callback(subreq
, background_job_done
, req
);
215 state
->pipe_req
= subreq
;
218 static void background_job_done(struct tevent_req
*subreq
)
220 struct tevent_req
*req
= tevent_req_callback_data(
221 subreq
, struct tevent_req
);
222 struct background_job_state
*state
= tevent_req_data(
223 req
, struct background_job_state
);
229 state
->pipe_req
= NULL
;
231 ret
= read_packet_recv(subreq
, talloc_tos(), &buf
, &err
);
234 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
237 close(state
->pipe_fd
);
239 memcpy(&wait_secs
, buf
, sizeof(wait_secs
));
240 if (wait_secs
== -1) {
241 tevent_req_done(req
);
244 subreq
= tevent_wakeup_send(
245 state
, state
->ev
, timeval_current_ofs(wait_secs
, 0));
246 if (tevent_req_nomem(subreq
, req
)) {
249 tevent_req_set_callback(subreq
, background_job_waited
, req
);
250 state
->wakeup_req
= subreq
;
253 NTSTATUS
background_job_recv(struct tevent_req
*req
)
255 return tevent_req_simple_recv_ntstatus(req
);