s4:smbd: Add missing unistd.h include to fix build of process_prefork
[metze/samba/wip.git] / source4 / smbd / process_prefork.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    process model: prefork (n client connections per process)
5
6    Copyright (C) Andrew Tridgell 1992-2005
7    Copyright (C) James J Myers 2003 <myersjj@samba.org>
8    Copyright (C) Stefan (metze) Metzmacher 2004
9    Copyright (C) Andrew Bartlett 2008 <abartlet@samba.org>
10    Copyright (C) David Disseldorp 2008 <ddiss@sgi.com>
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include <unistd.h>
28
29 #include "lib/events/events.h"
30 #include "lib/messaging/messaging.h"
31 #include "lib/socket/socket.h"
32 #include "smbd/process_model.h"
33 #include "cluster/cluster.h"
34 #include "param/param.h"
35 #include "ldb_wrap.h"
36 #include "lib/util/tfork.h"
37
38 NTSTATUS process_model_prefork_init(void);
39
40 static void sighup_signal_handler(struct tevent_context *ev,
41                                 struct tevent_signal *se,
42                                 int signum, int count, void *siginfo,
43                                 void *private_data)
44 {
45         debug_schedule_reopen_logs();
46 }
47
48 static void sigterm_signal_handler(struct tevent_context *ev,
49                                 struct tevent_signal *se,
50                                 int signum, int count, void *siginfo,
51                                 void *private_data)
52 {
53 #if HAVE_GETPGRP
54         if (getpgrp() == getpid()) {
55                 /*
56                  * We're the process group leader, send
57                  * SIGTERM to our process group.
58                  */
59                 DBG_NOTICE("SIGTERM: killing children\n");
60                 kill(-getpgrp(), SIGTERM);
61         }
62 #endif
63         DBG_NOTICE("Exiting pid %d on SIGTERM\n", getpid());
64         talloc_free(ev);
65         exit(127);
66 }
67
68 /*
69   called when the process model is selected
70 */
71 static void prefork_model_init(void)
72 {
73 }
74
75 static void prefork_reload_after_fork(void)
76 {
77         NTSTATUS status;
78
79         ldb_wrap_fork_hook();
80         /* Must be done after a fork() to reset messaging contexts. */
81         status = imessaging_reinit_all();
82         if (!NT_STATUS_IS_OK(status)) {
83                 smb_panic("Failed to re-initialise imessaging after fork");
84         }
85 }
86
87 /*
88   handle EOF on the parent-to-all-children pipe in the child
89 */
90 static void prefork_pipe_handler(struct tevent_context *event_ctx,
91                                  struct tevent_fd *fde, uint16_t flags,
92                                  void *private_data)
93 {
94         /* free the fde which removes the event and stops it firing again */
95         TALLOC_FREE(fde);
96         DBG_NOTICE("Child %d exiting\n", getpid());
97         talloc_free(event_ctx);
98         exit(0);
99 }
100
101 /*
102   handle EOF on the child pipe in the parent, so we know when a
103   process terminates without using SIGCHLD or waiting on all possible pids.
104
105   We need to ensure we do not ignore SIGCHLD because we need it to
106   work to get a valid error code from samba_runcmd_*().
107  */
108 static void prefork_child_pipe_handler(struct tevent_context *ev,
109                                        struct tevent_fd *fde,
110                                        uint16_t flags,
111                                        void *private_data)
112 {
113         struct tfork *t = NULL;
114         int status = 0;
115         pid_t pid = 0;
116
117         /* free the fde which removes the event and stops it firing again */
118         TALLOC_FREE(fde);
119
120         /* the child has closed the pipe, assume its dead */
121
122         /* tfork allocates tfork structures with malloc  */
123         t = (struct tfork*)private_data;
124         pid = tfork_child_pid(t);
125         errno = 0;
126         status = tfork_status(&t, false);
127         if (status == -1) {
128                 DBG_ERR("Parent %d, Child %d terminated, "
129                         "unable to get status code from tfork\n",
130                         getpid(), pid);
131         } else if (WIFEXITED(status)) {
132                 status = WEXITSTATUS(status);
133                 DBG_ERR("Parent %d, Child %d exited with status %d\n",
134                          getpid(), pid,  status);
135         } else if (WIFSIGNALED(status)) {
136                 status = WTERMSIG(status);
137                 DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
138                         getpid(), pid, status);
139         }
140         /* tfork allocates tfork structures with malloc */
141         free(t);
142         return;
143 }
144
145 /*
146   called when a listening socket becomes readable.
147 */
148 static void prefork_accept_connection(
149         struct tevent_context *ev,
150         struct loadparm_context *lp_ctx,
151         struct socket_context *listen_socket,
152         void (*new_conn)(struct tevent_context *,
153                         struct loadparm_context *,
154                         struct socket_context *,
155                         struct server_id,
156                         void *,
157                         void *),
158         void *private_data,
159         void *process_context)
160 {
161         NTSTATUS status;
162         struct socket_context *connected_socket;
163         pid_t pid = getpid();
164
165         /* accept an incoming connection. */
166         status = socket_accept(listen_socket, &connected_socket);
167         if (!NT_STATUS_IS_OK(status)) {
168                 /*
169                  * For prefork we can ignore STATUS_MORE_ENTRIES, as  once a
170                  * connection becomes available all waiting processes are
171                  * woken, but only one gets work to  process.
172                  * AKA the thundering herd.
173                  * In the short term this should not be an issue as the number
174                  * of workers should be a small multiple of the number of cpus
175                  * In the longer term socket_accept needs to implement a
176                  * mutex/semaphore (like apache does) to serialise the accepts
177                  */
178                 if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
179                         DBG_ERR("Worker process (%d), error in accept [%s]\n",
180                                 getpid(), nt_errstr(status));
181                 }
182                 return;
183         }
184
185         talloc_steal(private_data, connected_socket);
186
187         new_conn(ev, lp_ctx, connected_socket,
188                  cluster_id(pid, socket_get_fd(connected_socket)),
189                  private_data, process_context);
190 }
191
192 static void setup_handlers(struct tevent_context *ev, int from_parent_fd) {
193         struct tevent_fd *fde = NULL;
194         struct tevent_signal *se = NULL;
195
196         fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
197                       prefork_pipe_handler, NULL);
198         if (fde == NULL) {
199                 smb_panic("Failed to add fd handler after fork");
200         }
201
202         se = tevent_add_signal(ev,
203                                ev,
204                                SIGHUP,
205                                0,
206                                sighup_signal_handler,
207                                NULL);
208         if (se == NULL) {
209                 smb_panic("Failed to add SIGHUP handler after fork");
210         }
211
212         se = tevent_add_signal(ev,
213                                ev,
214                                SIGTERM,
215                                0,
216                                sigterm_signal_handler,
217                                NULL);
218         if (se == NULL) {
219                 smb_panic("Failed to add SIGTERM handler after fork");
220         }
221 }
222
223 /*
224  * called to create a new server task
225  */
226 static void prefork_new_task(
227         struct tevent_context *ev,
228         struct loadparm_context *lp_ctx,
229         const char *service_name,
230         void (*new_task_fn)(struct tevent_context *,
231                             struct loadparm_context *lp_ctx,
232                             struct server_id , void *, void *),
233         void *private_data,
234         const struct service_details *service_details,
235         int from_parent_fd)
236 {
237         pid_t pid;
238         struct tfork* t = NULL;
239         int i, num_children;
240
241         struct tevent_context *ev2;
242
243         t = tfork_create();
244         if (t == NULL) {
245                 smb_panic("failure in tfork\n");
246         }
247
248         pid = tfork_child_pid(t);
249         if (pid != 0) {
250                 struct tevent_fd *fde = NULL;
251                 int fd = tfork_event_fd(t);
252
253                 /* Register a pipe handler that gets called when the prefork
254                  * master process terminates.
255                  */
256                 fde = tevent_add_fd(ev, ev, fd, TEVENT_FD_READ,
257                                     prefork_child_pipe_handler, t);
258                 if (fde == NULL) {
259                         smb_panic("Failed to add child pipe handler, "
260                                   "after fork");
261                 }
262                 tevent_fd_set_auto_close(fde);
263                 return;
264         }
265
266         pid = getpid();
267         setproctitle("task[%s] pre-fork master", service_name);
268
269         /*
270          * this will free all the listening sockets and all state that
271          * is not associated with this new connection
272          */
273         if (tevent_re_initialise(ev) != 0) {
274                 smb_panic("Failed to re-initialise tevent after fork");
275         }
276         prefork_reload_after_fork();
277         setup_handlers(ev, from_parent_fd);
278
279         if (service_details->inhibit_pre_fork) {
280                 new_task_fn(ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
281                 /* The task does not support pre-fork */
282                 tevent_loop_wait(ev);
283                 TALLOC_FREE(ev);
284                 exit(0);
285         }
286
287         /*
288          * This is now the child code. We need a completely new event_context
289          * to work with
290          */
291         ev2 = s4_event_context_init(NULL);
292
293         /* setup this new connection: process will bind to it's sockets etc
294          *
295          * While we can use ev for the child, which has been re-initialised
296          * above we must run the new task under ev2 otherwise the children would
297          * be listening on the sockets.  Also we don't want the top level
298          * process accepting and handling requests, it's responsible for
299          * monitoring and controlling the child work processes.
300          */
301         new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
302
303         {
304                 int default_children;
305                 default_children = lpcfg_prefork_children(lp_ctx);
306                 num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children",
307                                               service_name, default_children);
308         }
309         if (num_children == 0) {
310                 DBG_WARNING("Number of pre-fork children for %s is zero, "
311                             "NO worker processes will be started for %s\n",
312                             service_name, service_name);
313         }
314         DBG_NOTICE("Forking %d %s worker processes\n",
315                    num_children, service_name);
316         /* We are now free to spawn some worker processes */
317         for (i=0; i < num_children; i++) {
318                 struct tfork* w = NULL;
319
320                 w = tfork_create();
321                 if (t == NULL) {
322                         smb_panic("failure in tfork\n");
323                 }
324
325                 pid = tfork_child_pid(w);
326                 if (pid != 0) {
327                         struct tevent_fd *fde = NULL;
328                         int fd = tfork_event_fd(w);
329
330                         fde = tevent_add_fd(ev, ev, fd, TEVENT_FD_READ,
331                                             prefork_child_pipe_handler, w);
332                         if (fde == NULL) {
333                                 smb_panic("Failed to add child pipe handler, "
334                                           "after fork");
335                         }
336                         tevent_fd_set_auto_close(fde);
337                 } else {
338                         /* tfork uses malloc */
339                         free(w);
340
341                         TALLOC_FREE(ev);
342                         pid = getpid();
343                         setproctitle("task[%s] pre-forked worker",
344                                      service_name);
345                         prefork_reload_after_fork();
346                         setup_handlers(ev2, from_parent_fd);
347                         tevent_loop_wait(ev2);
348                         talloc_free(ev2);
349                         exit(0);
350                 }
351         }
352
353         /* Don't listen on the sockets we just gave to the children */
354         tevent_loop_wait(ev);
355         TALLOC_FREE(ev);
356         /* We need to keep ev2 until we're finished for the messaging to work */
357         TALLOC_FREE(ev2);
358         exit(0);
359
360 }
361
362
363 /* called when a task goes down */
364 static void prefork_terminate(struct tevent_context *ev,
365                               struct loadparm_context *lp_ctx,
366                               const char *reason,
367                               void *process_context)
368 {
369         DBG_DEBUG("called with reason[%s]\n", reason);
370 }
371
372 /* called to set a title of a task or connection */
373 static void prefork_set_title(struct tevent_context *ev, const char *title)
374 {
375 }
376
377 static const struct model_ops prefork_ops = {
378         .name                   = "prefork",
379         .model_init             = prefork_model_init,
380         .accept_connection      = prefork_accept_connection,
381         .new_task               = prefork_new_task,
382         .terminate              = prefork_terminate,
383         .set_title              = prefork_set_title,
384 };
385
386 /*
387  * initialise the prefork process model, registering ourselves with the
388  * process model subsystem
389  */
390 NTSTATUS process_model_prefork_init(void)
391 {
392         return register_process_model(&prefork_ops);
393 }