source: vendor/current/source3/lib/background.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 6.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Regular background jobs as forked helpers
4 Copyright (C) Volker Lendecke 2012
5
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.
10
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.
15
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/>.
18*/
19
20#include "includes.h"
21#include "lib/util/tevent_ntstatus.h"
22#include "lib/async_req/async_sock.h"
23#include "include/messages.h"
24#include "background.h"
25
26struct 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);
33 void *private_data;
34
35 struct tevent_req *wakeup_req;
36 int pipe_fd;
37 struct tevent_req *pipe_req;
38};
39
40static int background_job_state_destructor(struct background_job_state *s);
41static void background_job_waited(struct tevent_req *subreq);
42static void background_job_done(struct tevent_req *subreq);
43static void background_job_trigger(
44 struct messaging_context *msg, void *private_data, uint32_t msg_type,
45 struct server_id server_id, DATA_BLOB *data);
46
47struct tevent_req *background_job_send(TALLOC_CTX *mem_ctx,
48 struct tevent_context *ev,
49 struct messaging_context *msg,
50 uint32_t *trigger_msgs,
51 size_t num_trigger_msgs,
52 time_t initial_wait_sec,
53 int (*fn)(void *private_data),
54 void *private_data)
55{
56 struct tevent_req *req, *subreq;
57 struct background_job_state *state;
58 size_t i;
59
60 req = tevent_req_create(mem_ctx, &state,
61 struct background_job_state);
62 if (req == NULL) {
63 return NULL;
64 }
65
66 state->ev = ev;
67 state->msg = msg;
68
69 if (num_trigger_msgs != 0) {
70 state->trigger_msgs = (uint32_t *)talloc_memdup(
71 state, trigger_msgs,
72 sizeof(uint32_t) * num_trigger_msgs);
73 if (tevent_req_nomem(state->trigger_msgs, req)) {
74 return tevent_req_post(req, ev);
75 }
76 state->num_trigger_msgs = num_trigger_msgs;
77 }
78
79 state->fn = fn;
80 state->private_data = private_data;
81
82 state->pipe_fd = -1;
83 talloc_set_destructor(state, background_job_state_destructor);
84
85 for (i=0; i<num_trigger_msgs; i++) {
86 NTSTATUS status;
87 status = messaging_register(msg, state, trigger_msgs[i],
88 background_job_trigger);
89 if (tevent_req_nterror(req, status)) {
90 return tevent_req_post(req, ev);
91 }
92 }
93
94 subreq = tevent_wakeup_send(
95 state, state->ev, timeval_current_ofs(initial_wait_sec, 0));
96 if (tevent_req_nomem(subreq, req)) {
97 return tevent_req_post(req, ev);
98 }
99 tevent_req_set_callback(subreq, background_job_waited, req);
100 state->wakeup_req = subreq;
101 return req;
102}
103
104static int background_job_state_destructor(struct background_job_state *state)
105{
106 size_t i;
107
108 TALLOC_FREE(state->pipe_req);
109 if (state->pipe_fd != -1) {
110 close(state->pipe_fd);
111 state->pipe_fd = -1;
112 }
113
114 for (i=0; i<state->num_trigger_msgs; i++) {
115 messaging_deregister(state->msg, state->trigger_msgs[i],
116 state);
117 }
118
119 return 0;
120}
121
122static void background_job_trigger(
123 struct messaging_context *msg, void *private_data, uint32_t msg_type,
124 struct server_id server_id, DATA_BLOB *data)
125{
126 struct background_job_state *state = talloc_get_type_abort(
127 private_data, struct background_job_state);
128
129 if (state->wakeup_req == NULL) {
130 return;
131 }
132 if (!tevent_req_set_endtime(state->wakeup_req, state->ev,
133 timeval_zero())) {
134 DEBUG(10, ("tevent_req_set_endtime failed\n"));
135 }
136}
137
138static void background_job_waited(struct tevent_req *subreq)
139{
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);
144 int fds[2];
145 int res;
146 bool ret;
147
148 ret = tevent_wakeup_recv(subreq);
149 TALLOC_FREE(subreq);
150 state->wakeup_req = NULL;
151 if (!ret) {
152 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
153 return;
154 }
155
156 res = pipe(fds);
157 if (res == -1) {
158 tevent_req_nterror(req, map_nt_error_from_unix(errno));
159 return;
160 }
161
162 res = fork();
163 if (res == -1) {
164 int err = errno;
165 close(fds[0]);
166 close(fds[1]);
167 tevent_req_nterror(req, map_nt_error_from_unix(err));
168 return;
169 }
170
171 if (res == 0) {
172 /* child */
173
174 NTSTATUS status;
175 ssize_t written;
176
177 close(fds[0]);
178
179 status = reinit_after_fork(state->msg, state->ev, true, NULL);
180 if (NT_STATUS_IS_OK(status)) {
181 res = state->fn(state->private_data);
182 } else {
183 res = -1;
184 }
185 written = write(fds[1], &res, sizeof(res));
186 if (written == -1) {
187 _exit(1);
188 }
189
190 /*
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
198 * up.
199 */
200 talloc_free(state->msg);
201 _exit(0);
202 }
203
204 /* parent */
205
206 close(fds[1]);
207 state->pipe_fd = fds[0];
208
209 subreq = read_packet_send(state, state->ev, state->pipe_fd,
210 sizeof(int), NULL, NULL);
211 if (tevent_req_nomem(subreq, req)) {
212 return;
213 }
214 tevent_req_set_callback(subreq, background_job_done, req);
215 state->pipe_req = subreq;
216}
217
218static void background_job_done(struct tevent_req *subreq)
219{
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);
224 ssize_t ret;
225 uint8_t *buf;
226 int err;
227 int wait_secs;
228
229 state->pipe_req = NULL;
230
231 ret = read_packet_recv(subreq, talloc_tos(), &buf, &err);
232 TALLOC_FREE(subreq);
233 if (ret == -1) {
234 tevent_req_nterror(req, map_nt_error_from_unix(err));
235 return;
236 }
237 close(state->pipe_fd);
238 state->pipe_fd = -1;
239 memcpy(&wait_secs, buf, sizeof(wait_secs));
240 if (wait_secs == -1) {
241 tevent_req_done(req);
242 return;
243 }
244 subreq = tevent_wakeup_send(
245 state, state->ev, timeval_current_ofs(wait_secs, 0));
246 if (tevent_req_nomem(subreq, req)) {
247 return;
248 }
249 tevent_req_set_callback(subreq, background_job_waited, req);
250 state->wakeup_req = subreq;
251}
252
253NTSTATUS background_job_recv(struct tevent_req *req)
254{
255 return tevent_req_simple_recv_ntstatus(req);
256}
Note: See TracBrowser for help on using the repository browser.