pyldb: avoid segfault when adding an element with no name
[nivanova/samba-autobuild/.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  * The pre-fork process model distributes the server workload amongst several
27  * designated worker threads (e.g. 'prefork-worker-ldap-0',
28  * 'prefork-worker-ldap-1', etc). The number of worker threads is controlled
29  * by the 'prefork children' conf setting. The worker threads are controlled
30  * by a prefork master process (e.g. 'prefork-master-ldap'). The prefork master
31  * doesn't handle the server workload (i.e. processing messages) itself, but is
32  * responsible for restarting workers if they exit unexpectedly. The top-level
33  * samba process is responsible for restarting the master process if it exits.
34  */
35 #include "includes.h"
36 #include <unistd.h>
37
38 #include "lib/events/events.h"
39 #include "lib/messaging/messaging.h"
40 #include "lib/socket/socket.h"
41 #include "smbd/process_model.h"
42 #include "cluster/cluster.h"
43 #include "param/param.h"
44 #include "ldb_wrap.h"
45 #include "lib/util/tfork.h"
46 #include "lib/messaging/irpc.h"
47
48 #define min(a, b) (((a) < (b)) ? (a) : (b))
49
50 NTSTATUS process_model_prefork_init(void);
51 static void prefork_new_task(
52     struct tevent_context *ev,
53     struct loadparm_context *lp_ctx,
54     const char *service_name,
55     struct task_server *(*new_task_fn)(struct tevent_context *,
56                                        struct loadparm_context *lp_ctx,
57                                        struct server_id,
58                                        void *,
59                                        void *),
60     void *private_data,
61     const struct service_details *service_details,
62     int from_parent_fd);
63 static void prefork_fork_worker(struct task_server *task,
64                                 struct tevent_context *ev,
65                                 struct tevent_context *ev2,
66                                 struct loadparm_context *lp_ctx,
67                                 const struct service_details *service_details,
68                                 const char *service_name,
69                                 int control_pipe[2],
70                                 unsigned restart_delay,
71                                 struct process_details *pd);
72 static void prefork_child_pipe_handler(struct tevent_context *ev,
73                                        struct tevent_fd *fde,
74                                        uint16_t flags,
75                                        void *private_data);
76 static void setup_handlers(struct tevent_context *ev,
77                            struct loadparm_context *lp_ctx,
78                            int from_parent_fd);
79
80 /*
81  * State needed to restart the master process or a worker process if they
82  * terminate early.
83  */
84 struct master_restart_context {
85         struct task_server *(*new_task_fn)(struct tevent_context *,
86                                            struct loadparm_context *lp_ctx,
87                                            struct server_id,
88                                            void *,
89                                            void *);
90         void *private_data;
91 };
92
93 struct worker_restart_context {
94         unsigned int instance;
95         struct task_server *task;
96         struct tevent_context *ev2;
97         int control_pipe[2];
98 };
99
100 struct restart_context {
101         struct loadparm_context *lp_ctx;
102         struct tfork *t;
103         int from_parent_fd;
104         const struct service_details *service_details;
105         const char *service_name;
106         unsigned restart_delay;
107         struct master_restart_context *master;
108         struct worker_restart_context *worker;
109 };
110
111 static void sighup_signal_handler(struct tevent_context *ev,
112                                 struct tevent_signal *se,
113                                 int signum, int count, void *siginfo,
114                                 void *private_data)
115 {
116         debug_schedule_reopen_logs();
117 }
118
119 static void sigterm_signal_handler(struct tevent_context *ev,
120                                 struct tevent_signal *se,
121                                 int signum, int count, void *siginfo,
122                                 void *private_data)
123 {
124 #ifdef HAVE_GETPGRP
125         if (getpgrp() == getpid()) {
126                 /*
127                  * We're the process group leader, send
128                  * SIGTERM to our process group.
129                  */
130                 DBG_NOTICE("SIGTERM: killing children\n");
131                 kill(-getpgrp(), SIGTERM);
132         }
133 #endif
134         DBG_NOTICE("Exiting pid %d on SIGTERM\n", getpid());
135         TALLOC_FREE(ev);
136         exit(127);
137 }
138
139 /*
140   called when the process model is selected
141 */
142 static void prefork_model_init(void)
143 {
144 }
145
146 static void prefork_reload_after_fork(void)
147 {
148         NTSTATUS status;
149
150         ldb_wrap_fork_hook();
151         /* Must be done after a fork() to reset messaging contexts. */
152         status = imessaging_reinit_all();
153         if (!NT_STATUS_IS_OK(status)) {
154                 smb_panic("Failed to re-initialise imessaging after fork");
155         }
156 }
157
158 /*
159  * clean up any messaging associated with the old process.
160  *
161  */
162 static void irpc_cleanup(
163         struct loadparm_context *lp_ctx,
164         struct tevent_context *ev,
165         pid_t pid)
166 {
167         TALLOC_CTX *mem_ctx = talloc_new(NULL);
168         struct imessaging_context *msg_ctx = NULL;
169         NTSTATUS status = NT_STATUS_OK;
170
171         if (mem_ctx == NULL) {
172                 DBG_ERR("OOM cleaning up irpc\n");
173                 return;
174         }
175         msg_ctx = imessaging_client_init(mem_ctx, lp_ctx, ev);
176         if (msg_ctx == NULL) {
177                 DBG_ERR("Unable to create imessaging_context\n");
178                 TALLOC_FREE(mem_ctx);
179                 return;
180         }
181         status = imessaging_process_cleanup(msg_ctx, pid);
182         if (!NT_STATUS_IS_OK(status)) {
183                 DBG_ERR("imessaging_process_cleanup returned (%s)\n",
184                         nt_errstr(status));
185                 TALLOC_FREE(mem_ctx);
186                 return;
187         }
188
189         TALLOC_FREE(mem_ctx);
190 }
191
192 /*
193  * handle EOF on the parent-to-all-children pipe in the child, i.e.
194  * the parent has died and its end of the pipe has been closed.
195  * The child handles this by exiting as well.
196  */
197 static void prefork_pipe_handler(struct tevent_context *event_ctx,
198                                  struct tevent_fd *fde, uint16_t flags,
199                                  void *private_data)
200 {
201         struct loadparm_context *lp_ctx = NULL;
202         pid_t pid;
203
204         /*
205          * free the fde which removes the event and stops it firing again
206          */
207         TALLOC_FREE(fde);
208
209         /*
210          * Clean up any irpc end points this process had.
211          */
212         pid = getpid();
213         lp_ctx = talloc_get_type_abort(private_data, struct loadparm_context);
214         irpc_cleanup(lp_ctx, event_ctx, pid);
215
216         DBG_NOTICE("Child %d exiting\n", getpid());
217         TALLOC_FREE(event_ctx);
218         exit(0);
219 }
220
221
222 /*
223  * Called by the top-level samba process to create a new prefork master process
224  */
225 static void prefork_fork_master(
226     struct tevent_context *ev,
227     struct loadparm_context *lp_ctx,
228     const char *service_name,
229     struct task_server *(*new_task_fn)(struct tevent_context *,
230                                        struct loadparm_context *lp_ctx,
231                                        struct server_id,
232                                        void *,
233                                        void *),
234     void *private_data,
235     const struct service_details *service_details,
236     unsigned restart_delay,
237     int from_parent_fd)
238 {
239         pid_t pid;
240         struct tfork* t = NULL;
241         int i, num_children;
242
243         struct tevent_context *ev2;
244         struct task_server *task = NULL;
245         struct process_details pd = initial_process_details;
246         int control_pipe[2];
247
248         t = tfork_create();
249         if (t == NULL) {
250                 smb_panic("failure in tfork\n");
251         }
252
253         DBG_NOTICE("Forking [%s] pre-fork master process\n", service_name);
254         pid = tfork_child_pid(t);
255         if (pid != 0) {
256                 struct tevent_fd *fde = NULL;
257                 int fd = tfork_event_fd(t);
258                 struct restart_context *rc = NULL;
259
260                 /* Register a pipe handler that gets called when the prefork
261                  * master process terminates.
262                  */
263                 rc = talloc_zero(ev, struct restart_context);
264                 if (rc == NULL) {
265                         smb_panic("OOM allocating restart context\n");
266                 }
267                 rc->t = t;
268                 rc->lp_ctx = lp_ctx;
269                 rc->service_name = service_name;
270                 rc->service_details = service_details;
271                 rc->from_parent_fd = from_parent_fd;
272                 rc->restart_delay = restart_delay;
273                 rc->master = talloc_zero(rc, struct master_restart_context);
274                 if (rc->master == NULL) {
275                         smb_panic("OOM allocating master restart context\n");
276                 }
277
278                 rc->master->new_task_fn = new_task_fn;
279                 rc->master->private_data = private_data;
280
281                 fde = tevent_add_fd(
282                     ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
283                 if (fde == NULL) {
284                         smb_panic("Failed to add child pipe handler, "
285                                   "after fork");
286                 }
287                 tevent_fd_set_auto_close(fde);
288                 return;
289         }
290
291         pid = getpid();
292         setproctitle("task[%s] pre-fork master", service_name);
293
294         /*
295          * this will free all the listening sockets and all state that
296          * is not associated with this new connection
297          */
298         if (tevent_re_initialise(ev) != 0) {
299                 smb_panic("Failed to re-initialise tevent after fork");
300         }
301         prefork_reload_after_fork();
302         setup_handlers(ev, lp_ctx, from_parent_fd);
303
304         if (service_details->inhibit_pre_fork) {
305                 task = new_task_fn(
306                     ev, lp_ctx, cluster_id(pid, 0), private_data, NULL);
307                 /*
308                  * The task does not support pre-fork
309                  */
310                 if (task != NULL && service_details->post_fork != NULL) {
311                         service_details->post_fork(task, &pd);
312                 }
313                 tevent_loop_wait(ev);
314                 TALLOC_FREE(ev);
315                 exit(0);
316         }
317
318         /*
319          * This is now the child code. We need a completely new event_context
320          * to work with
321          */
322         ev2 = s4_event_context_init(NULL);
323
324         /* setup this new connection: process will bind to it's sockets etc
325          *
326          * While we can use ev for the child, which has been re-initialised
327          * above we must run the new task under ev2 otherwise the children would
328          * be listening on the sockets.  Also we don't want the top level
329          * process accepting and handling requests, it's responsible for
330          * monitoring and controlling the child work processes.
331          */
332         task = new_task_fn(ev2, lp_ctx, cluster_id(pid, 0), private_data, NULL);
333         if (task == NULL) {
334                 TALLOC_FREE(ev);
335                 TALLOC_FREE(ev2);
336                 exit(127);
337         }
338
339         /*
340          * Register an irpc name that can be used by the samba-tool processes
341          * command
342          */
343         {
344                 struct talloc_ctx *ctx = talloc_new(NULL);
345                 char *name = NULL;
346                 if (ctx == NULL) {
347                         DBG_ERR("Out of memory");
348                         exit(127);
349                 }
350                 name = talloc_asprintf(ctx, "prefork-master-%s", service_name);
351                 irpc_add_name(task->msg_ctx, name);
352                 TALLOC_FREE(ctx);
353         }
354
355         {
356                 int default_children;
357                 default_children = lpcfg_prefork_children(lp_ctx);
358                 num_children = lpcfg_parm_int(lp_ctx, NULL, "prefork children",
359                                               service_name, default_children);
360         }
361         if (num_children == 0) {
362                 DBG_WARNING("Number of pre-fork children for %s is zero, "
363                             "NO worker processes will be started for %s\n",
364                             service_name, service_name);
365         }
366         DBG_NOTICE("Forking %d %s worker processes\n",
367                    num_children, service_name);
368
369         /*
370          * the prefork master creates its own control pipe, so the prefork
371          * workers can detect if the master exits (in which case an EOF gets
372          * written). (Whereas from_parent_fd is the control pipe from the
373          * top-level process that the prefork master listens on)
374          */
375         {
376                 int ret;
377                 ret = pipe(control_pipe);
378                 if (ret != 0) {
379                         smb_panic("Unable to create worker control pipe\n");
380                 }
381                 smb_set_close_on_exec(control_pipe[0]);
382                 smb_set_close_on_exec(control_pipe[1]);
383         }
384
385         /*
386          * We are now free to spawn some worker processes
387          */
388         for (i=0; i < num_children; i++) {
389                 prefork_fork_worker(task,
390                                     ev,
391                                     ev2,
392                                     lp_ctx,
393                                     service_details,
394                                     service_name,
395                                     control_pipe,
396                                     0,
397                                     &pd);
398                 pd.instances++;
399         }
400
401         /* Don't listen on the sockets we just gave to the children */
402         tevent_loop_wait(ev);
403         TALLOC_FREE(ev);
404         /* We need to keep ev2 until we're finished for the messaging to work */
405         TALLOC_FREE(ev2);
406         exit(0);
407 }
408
409 /*
410  * Restarts a child process if it exits unexpectedly
411  */
412 static void prefork_restart(struct tevent_context *ev,
413                             struct restart_context *rc)
414 {
415         unsigned max_backoff = 0;
416         unsigned backoff = 0;
417         unsigned restart_delay = rc->restart_delay;
418         unsigned default_value = 0;
419
420         /*
421          * If the child process is constantly exiting, then restarting it can
422          * consume a lot of resources. In which case, we want to backoff a bit
423          * before respawning it
424          */
425         default_value = lpcfg_prefork_backoff_increment(rc->lp_ctx);
426         backoff = lpcfg_parm_int(rc->lp_ctx,
427                                  NULL,
428                                  "prefork backoff increment",
429                                  rc->service_name,
430                                  default_value);
431
432         default_value = lpcfg_prefork_maximum_backoff(rc->lp_ctx);
433         max_backoff = lpcfg_parm_int(rc->lp_ctx,
434                                      NULL,
435                                      "prefork maximum backoff",
436                                      rc->service_name,
437                                      default_value);
438
439         if (restart_delay > 0) {
440                 DBG_ERR("Restarting [%s] pre-fork %s in (%d) seconds\n",
441                         rc->service_name,
442                         (rc->master == NULL) ? "worker" : "master",
443                         restart_delay);
444                 sleep(restart_delay);
445         }
446         restart_delay += backoff;
447         restart_delay = min(restart_delay, max_backoff);
448
449         if (rc->master != NULL) {
450                 DBG_ERR("Restarting [%s] pre-fork master\n", rc->service_name);
451                 prefork_fork_master(ev,
452                                     rc->lp_ctx,
453                                     rc->service_name,
454                                     rc->master->new_task_fn,
455                                     rc->master->private_data,
456                                     rc->service_details,
457                                     restart_delay,
458                                     rc->from_parent_fd);
459         } else if (rc->worker != NULL) {
460                 struct process_details pd = initial_process_details;
461                 DBG_ERR("Restarting [%s] pre-fork worker(%d)\n",
462                         rc->service_name,
463                         rc->worker->instance);
464                 pd.instances = rc->worker->instance;
465                 prefork_fork_worker(rc->worker->task,
466                                     ev,
467                                     rc->worker->ev2,
468                                     rc->lp_ctx,
469                                     rc->service_details,
470                                     rc->service_name,
471                                     rc->worker->control_pipe,
472                                     restart_delay,
473                                     &pd);
474         }
475 }
476
477 /*
478   handle EOF on the child pipe in the parent, so we know when a
479   process terminates without using SIGCHLD or waiting on all possible pids.
480
481   We need to ensure we do not ignore SIGCHLD because we need it to
482   work to get a valid error code from samba_runcmd_*().
483  */
484 static void prefork_child_pipe_handler(struct tevent_context *ev,
485                                        struct tevent_fd *fde,
486                                        uint16_t flags,
487                                        void *private_data)
488 {
489         struct restart_context *rc = NULL;
490         int status = 0;
491         pid_t pid = 0;
492
493         /* free the fde which removes the event and stops it firing again */
494         TALLOC_FREE(fde);
495
496         /* the child has closed the pipe, assume its dead */
497
498         rc = talloc_get_type_abort(private_data, struct restart_context);
499         pid = tfork_child_pid(rc->t);
500         errno = 0;
501
502         irpc_cleanup(rc->lp_ctx, ev, pid);
503         status = tfork_status(&rc->t, false);
504         if (status == -1) {
505                 DBG_ERR("Parent %d, Child %d terminated, "
506                         "unable to get status code from tfork\n",
507                         getpid(), pid);
508                 prefork_restart(ev, rc);
509         } else if (WIFEXITED(status)) {
510                 status = WEXITSTATUS(status);
511                 DBG_ERR("Parent %d, Child %d exited with status %d\n",
512                          getpid(), pid,  status);
513                 if (status != 0) {
514                         prefork_restart(ev, rc);
515                 }
516         } else if (WIFSIGNALED(status)) {
517                 status = WTERMSIG(status);
518                 DBG_ERR("Parent %d, Child %d terminated with signal %d\n",
519                         getpid(), pid, status);
520                 if (status == SIGABRT || status == SIGBUS || status == SIGFPE ||
521                     status == SIGILL || status == SIGSYS || status == SIGSEGV) {
522
523                         prefork_restart(ev, rc);
524                 }
525         }
526         /* tfork allocates tfork structures with malloc */
527         tfork_destroy(&rc->t);
528         free(rc->t);
529         TALLOC_FREE(rc);
530         return;
531 }
532
533 /*
534   called when a listening socket becomes readable.
535 */
536 static void prefork_accept_connection(
537         struct tevent_context *ev,
538         struct loadparm_context *lp_ctx,
539         struct socket_context *listen_socket,
540         void (*new_conn)(struct tevent_context *,
541                         struct loadparm_context *,
542                         struct socket_context *,
543                         struct server_id,
544                         void *,
545                         void *),
546         void *private_data,
547         void *process_context)
548 {
549         NTSTATUS status;
550         struct socket_context *connected_socket;
551         pid_t pid = getpid();
552
553         /* accept an incoming connection. */
554         status = socket_accept(listen_socket, &connected_socket);
555         if (!NT_STATUS_IS_OK(status)) {
556                 /*
557                  * For prefork we can ignore STATUS_MORE_ENTRIES, as  once a
558                  * connection becomes available all waiting processes are
559                  * woken, but only one gets work to  process.
560                  * AKA the thundering herd.
561                  * In the short term this should not be an issue as the number
562                  * of workers should be a small multiple of the number of cpus
563                  * In the longer term socket_accept needs to implement a
564                  * mutex/semaphore (like apache does) to serialise the accepts
565                  */
566                 if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
567                         DBG_ERR("Worker process (%d), error in accept [%s]\n",
568                                 getpid(), nt_errstr(status));
569                 }
570                 return;
571         }
572
573         talloc_steal(private_data, connected_socket);
574
575         new_conn(ev, lp_ctx, connected_socket,
576                  cluster_id(pid, socket_get_fd(connected_socket)),
577                  private_data, process_context);
578 }
579
580 static void setup_handlers(
581         struct tevent_context *ev,
582         struct loadparm_context *lp_ctx,
583         int from_parent_fd)
584 {
585         struct tevent_fd *fde = NULL;
586         struct tevent_signal *se = NULL;
587
588         fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
589                       prefork_pipe_handler, lp_ctx);
590         if (fde == NULL) {
591                 smb_panic("Failed to add fd handler after fork");
592         }
593
594         se = tevent_add_signal(ev,
595                                ev,
596                                SIGHUP,
597                                0,
598                                sighup_signal_handler,
599                                NULL);
600         if (se == NULL) {
601                 smb_panic("Failed to add SIGHUP handler after fork");
602         }
603
604         se = tevent_add_signal(ev,
605                                ev,
606                                SIGTERM,
607                                0,
608                                sigterm_signal_handler,
609                                NULL);
610         if (se == NULL) {
611                 smb_panic("Failed to add SIGTERM handler after fork");
612         }
613 }
614
615 /*
616  * Called by the prefork master to create a new prefork worker process
617  */
618 static void prefork_fork_worker(struct task_server *task,
619                                 struct tevent_context *ev,
620                                 struct tevent_context *ev2,
621                                 struct loadparm_context *lp_ctx,
622                                 const struct service_details *service_details,
623                                 const char *service_name,
624                                 int control_pipe[2],
625                                 unsigned restart_delay,
626                                 struct process_details *pd)
627 {
628         struct tfork *w = NULL;
629         pid_t pid;
630
631         w = tfork_create();
632         if (w == NULL) {
633                 smb_panic("failure in tfork\n");
634         }
635
636         pid = tfork_child_pid(w);
637         if (pid != 0) {
638                 struct tevent_fd *fde = NULL;
639                 int fd = tfork_event_fd(w);
640                 struct restart_context *rc = NULL;
641
642                 /*
643                  * we're the parent (prefork master), so store enough info to
644                  * restart the worker/child if it exits unexpectedly
645                  */
646                 rc = talloc_zero(ev, struct restart_context);
647                 if (rc == NULL) {
648                         smb_panic("OOM allocating restart context\n");
649                 }
650                 rc->t = w;
651                 rc->lp_ctx = lp_ctx;
652                 rc->service_name = service_name;
653                 rc->service_details = service_details;
654                 rc->restart_delay = restart_delay;
655                 rc->master = NULL;
656                 rc->worker = talloc_zero(rc, struct worker_restart_context);
657                 if (rc->worker == NULL) {
658                         smb_panic("OOM allocating master restart context\n");
659                 }
660                 rc->worker->ev2 = ev2;
661                 rc->worker->instance = pd->instances;
662                 rc->worker->task = task;
663                 rc->worker->control_pipe[0] = control_pipe[0];
664                 rc->worker->control_pipe[1] = control_pipe[1];
665
666                 fde = tevent_add_fd(
667                     ev, ev, fd, TEVENT_FD_READ, prefork_child_pipe_handler, rc);
668                 if (fde == NULL) {
669                         smb_panic("Failed to add child pipe handler, "
670                                   "after fork");
671                 }
672                 tevent_fd_set_auto_close(fde);
673         } else {
674
675                 /*
676                  * we're the child (prefork-worker). We never write to the
677                  * control pipe, but listen on the read end in case our parent
678                  * (the pre-fork master) exits
679                  */
680                 close(control_pipe[1]);
681                 setup_handlers(ev2, lp_ctx, control_pipe[0]);
682
683                 /*
684                  * tfork uses malloc
685                  */
686                 free(w);
687
688                 TALLOC_FREE(ev);
689                 setproctitle("task[%s] pre-forked worker(%d)",
690                              service_name,
691                              pd->instances);
692                 prefork_reload_after_fork();
693                 if (service_details->post_fork != NULL) {
694                         service_details->post_fork(task, pd);
695                 }
696                 {
697                         struct talloc_ctx *ctx = talloc_new(NULL);
698                         char *name = NULL;
699                         if (ctx == NULL) {
700                                 smb_panic("OOM allocating talloc context\n");
701                         }
702                         name = talloc_asprintf(ctx,
703                                                "prefork-worker-%s-%d",
704                                                service_name,
705                                                pd->instances);
706                         irpc_add_name(task->msg_ctx, name);
707                         TALLOC_FREE(ctx);
708                 }
709                 tevent_loop_wait(ev2);
710                 talloc_free(ev2);
711                 exit(0);
712         }
713 }
714 /*
715  * called to create a new server task
716  */
717 static void prefork_new_task(
718         struct tevent_context *ev,
719         struct loadparm_context *lp_ctx,
720         const char *service_name,
721         struct task_server *(*new_task_fn)(struct tevent_context *,
722                             struct loadparm_context *lp_ctx,
723                             struct server_id , void *, void *),
724         void *private_data,
725         const struct service_details *service_details,
726         int from_parent_fd)
727 {
728         prefork_fork_master(ev,
729                             lp_ctx,
730                             service_name,
731                             new_task_fn,
732                             private_data,
733                             service_details,
734                             0,
735                             from_parent_fd);
736
737 }
738
739 /*
740  * called when a task terminates
741  */
742 static void prefork_terminate_task(struct tevent_context *ev,
743                                    struct loadparm_context *lp_ctx,
744                                    const char *reason,
745                                    bool fatal,
746                                    void *process_context)
747 {
748         DBG_DEBUG("called with reason[%s]\n", reason);
749         TALLOC_FREE(ev);
750         if (fatal == true) {
751                 exit(127);
752         } else {
753                 exit(0);
754         }
755 }
756
757 /*
758  * called when a connection completes
759  */
760 static void prefork_terminate_connection(struct tevent_context *ev,
761                                          struct loadparm_context *lp_ctx,
762                                          const char *reason,
763                                          void *process_context)
764 {
765 }
766
767 /* called to set a title of a task or connection */
768 static void prefork_set_title(struct tevent_context *ev, const char *title)
769 {
770 }
771
772 static const struct model_ops prefork_ops = {
773         .name                   = "prefork",
774         .model_init             = prefork_model_init,
775         .accept_connection      = prefork_accept_connection,
776         .new_task               = prefork_new_task,
777         .terminate_task         = prefork_terminate_task,
778         .terminate_connection   = prefork_terminate_connection,
779         .set_title              = prefork_set_title,
780 };
781
782 /*
783  * initialise the prefork process model, registering ourselves with the
784  * process model subsystem
785  */
786 NTSTATUS process_model_prefork_init(void)
787 {
788         return register_process_model(&prefork_ops);
789 }