tdb: Add overflow-checking tdb_add_off_t
[Samba/wip.git] / source3 / lib / background.c
blob6a9178376c6701f05beb0fc0be15649d4259e01d
1 /*
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/>.
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"
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);
33 void *private_data;
35 struct tevent_req *wakeup_req;
36 int pipe_fd;
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),
53 void *private_data)
55 struct tevent_req *req, *subreq;
56 struct background_job_state *state;
57 size_t i;
59 req = tevent_req_create(mem_ctx, &state,
60 struct background_job_state);
61 if (req == NULL) {
62 return NULL;
65 state->ev = ev;
66 state->msg = msg;
68 if (num_trigger_msgs != 0) {
69 state->trigger_msgs = (uint32_t *)talloc_memdup(
70 state, trigger_msgs,
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;
78 state->fn = fn;
79 state->private_data = private_data;
81 state->pipe_fd = -1;
82 talloc_set_destructor(state, background_job_state_destructor);
84 for (i=0; i<num_trigger_msgs; i++) {
85 NTSTATUS status;
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;
100 return req;
103 static int background_job_state_destructor(struct background_job_state *state)
105 size_t i;
106 if (state->pipe_fd != -1) {
107 close(state->pipe_fd);
108 state->pipe_fd = -1;
110 for (i=0; i<state->num_trigger_msgs; i++) {
111 messaging_deregister(state->msg, state->trigger_msgs[i],
112 state);
114 return 0;
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) {
125 return;
127 if (!tevent_req_set_endtime(state->wakeup_req, state->ev,
128 timeval_zero())) {
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);
139 int fds[2];
140 int res;
141 bool ret;
143 ret = tevent_wakeup_recv(subreq);
144 TALLOC_FREE(subreq);
145 state->wakeup_req = NULL;
146 if (!ret) {
147 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
148 return;
151 res = pipe(fds);
152 if (res == -1) {
153 tevent_req_nterror(req, map_nt_error_from_unix(errno));
154 return;
157 res = fork();
158 if (res == -1) {
159 int err = errno;
160 close(fds[0]);
161 close(fds[1]);
162 tevent_req_nterror(req, map_nt_error_from_unix(err));
163 return;
166 if (res == 0) {
167 /* child */
169 NTSTATUS status;
170 ssize_t written;
172 close(fds[0]);
174 status = reinit_after_fork(state->msg, state->ev, true);
175 if (NT_STATUS_IS_OK(status)) {
176 res = state->fn(state->private_data);
177 } else {
178 res = -1;
180 written = write(fds[1], &res, sizeof(res));
181 if (written == -1) {
182 _exit(1);
184 _exit(0);
187 /* parent */
189 close(fds[1]);
190 state->pipe_fd = fds[0];
192 subreq = read_packet_send(state, state->ev, state->pipe_fd,
193 sizeof(int), NULL, NULL);
194 if (tevent_req_nomem(subreq, req)) {
195 return;
197 tevent_req_set_callback(subreq, background_job_done, req);
200 static void background_job_done(struct tevent_req *subreq)
202 struct tevent_req *req = tevent_req_callback_data(
203 subreq, struct tevent_req);
204 struct background_job_state *state = tevent_req_data(
205 req, struct background_job_state);
206 ssize_t ret;
207 uint8_t *buf;
208 int err;
209 int wait_secs;
211 ret = read_packet_recv(subreq, talloc_tos(), &buf, &err);
212 TALLOC_FREE(subreq);
213 if (ret == -1) {
214 tevent_req_nterror(req, map_nt_error_from_unix(err));
215 return;
217 close(state->pipe_fd);
218 state->pipe_fd = -1;
219 memcpy(&wait_secs, buf, sizeof(wait_secs));
220 if (wait_secs == -1) {
221 tevent_req_done(req);
222 return;
224 subreq = tevent_wakeup_send(
225 state, state->ev, timeval_current_ofs(wait_secs, 0));
226 if (tevent_req_nomem(subreq, req)) {
227 return;
229 tevent_req_set_callback(subreq, background_job_waited, req);
230 state->wakeup_req = subreq;
233 NTSTATUS background_job_recv(struct tevent_req *req)
235 return tevent_req_simple_recv_ntstatus(req);