LCOV - code coverage report
Current view: top level - source4/samba - process_standard.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 153 223 68.6 %
Date: 2024-02-28 12:06:22 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    process model: standard (1 process per client connection)
       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             :    
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             :    
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             :    
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "lib/events/events.h"
      26             : #include "samba/process_model.h"
      27             : #include "system/filesys.h"
      28             : #include "cluster/cluster.h"
      29             : #include "param/param.h"
      30             : #include "ldb_wrap.h"
      31             : #include "lib/messaging/messaging.h"
      32             : #include "lib/util/debug.h"
      33             : #include "lib/messaging/messages_dgm.h"
      34             : #include "lib/util/util_process.h"
      35             : 
      36             : static unsigned connections_active = 0;
      37             : static unsigned smbd_max_processes = 0;
      38             : 
      39             : struct standard_child_state {
      40             :         const char *name;
      41             :         pid_t pid;
      42             :         int to_parent_fd;
      43             :         int from_child_fd;
      44             :         struct tevent_fd *from_child_fde;
      45             : };
      46             : 
      47             : NTSTATUS process_model_standard_init(TALLOC_CTX *);
      48             : struct process_context {
      49             :         char *name;
      50             :         int from_parent_fd;
      51             :         bool inhibit_fork_on_accept;
      52             :         bool forked_on_accept;
      53             : };
      54             : 
      55             : /*
      56             :   called when the process model is selected
      57             : */
      58          30 : static void standard_model_init(void)
      59             : {
      60          30 : }
      61             : 
      62           0 : static void sighup_signal_handler(struct tevent_context *ev,
      63             :                                 struct tevent_signal *se,
      64             :                                 int signum, int count, void *siginfo,
      65             :                                 void *private_data)
      66             : {
      67           0 :         debug_schedule_reopen_logs();
      68           0 : }
      69             : 
      70           0 : static void sigterm_signal_handler(struct tevent_context *ev,
      71             :                                 struct tevent_signal *se,
      72             :                                 int signum, int count, void *siginfo,
      73             :                                 void *private_data)
      74             : {
      75             : #ifdef HAVE_GETPGRP
      76           0 :         if (getpgrp() == getpid()) {
      77             :                 /*
      78             :                  * We're the process group leader, send
      79             :                  * SIGTERM to our process group.
      80             :                  */
      81           0 :                 DBG_ERR("SIGTERM: killing children\n");
      82           0 :                 kill(-getpgrp(), SIGTERM);
      83             :         }
      84             : #endif
      85           0 :         DBG_ERR("Exiting pid %u on SIGTERM\n", (unsigned int)getpid());
      86           0 :         talloc_free(ev);
      87           0 :         exit(127);
      88             : }
      89             : 
      90             : /*
      91             :   handle EOF on the parent-to-all-children pipe in the child
      92             : */
      93         386 : static void standard_pipe_handler(struct tevent_context *event_ctx, struct tevent_fd *fde, 
      94             :                                   uint16_t flags, void *private_data)
      95             : {
      96         386 :         DBG_DEBUG("Child %d exiting\n", (int)getpid());
      97         386 :         talloc_free(event_ctx);
      98         386 :         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       15348 : static void standard_child_pipe_handler(struct tevent_context *ev,
     109             :                                         struct tevent_fd *fde,
     110             :                                         uint16_t flags,
     111             :                                         void *private_data)
     112             : {
     113           0 :         struct standard_child_state *state
     114       15348 :                 = talloc_get_type_abort(private_data, struct standard_child_state);
     115       15348 :         int status = 0;
     116           0 :         pid_t pid;
     117             : 
     118       15348 :         messaging_dgm_cleanup(state->pid);
     119             : 
     120             :         /* the child has closed the pipe, assume its dead */
     121       15348 :         errno = 0;
     122       15348 :         pid = waitpid(state->pid, &status, 0);
     123             : 
     124       15348 :         if (pid != state->pid) {
     125           0 :                 if (errno == ECHILD) {
     126             :                         /*
     127             :                          * this happens when the
     128             :                          * parent has set SIGCHLD to
     129             :                          * SIG_IGN. In that case we
     130             :                          * can only get error
     131             :                          * information for the child
     132             :                          * via its logging. We should
     133             :                          * stop using SIG_IGN on
     134             :                          * SIGCHLD in the standard
     135             :                          * process model.
     136             :                          */
     137           0 :                         DBG_ERR("Error in waitpid() unexpectedly got ECHILD "
     138             :                                 "for child %d (%s) - %s, someone has set SIGCHLD "
     139             :                                 "to SIG_IGN!\n",
     140             :                                 (int)state->pid, state->name,
     141             :                                 strerror(errno));
     142           0 :                         TALLOC_FREE(state);
     143           0 :                         return;
     144             :                 }
     145           0 :                 DBG_ERR("Error in waitpid() for child %d (%s) - %s \n",
     146             :                         (int)state->pid, state->name, strerror(errno));
     147           0 :                 if (errno == 0) {
     148           0 :                         errno = ECHILD;
     149             :                 }
     150           0 :                 goto done;
     151             :         }
     152       15348 :         if (WIFEXITED(status)) {
     153       15348 :                 status = WEXITSTATUS(status);
     154       15348 :                 if (status != 0) {
     155           0 :                         DBG_ERR("Child %d (%s) exited with status %d\n",
     156             :                                 (int)state->pid, state->name, status);
     157             :                 }
     158           0 :         } else if (WIFSIGNALED(status)) {
     159           0 :                 status = WTERMSIG(status);
     160           0 :                 DBG_ERR("Child %d (%s) terminated with signal %d\n",
     161             :                         (int)state->pid, state->name, status);
     162             :         }
     163           0 : done:
     164       15348 :         TALLOC_FREE(state);
     165       15348 :         if (smbd_max_processes > 0) {
     166          21 :                 if (connections_active < 1) {
     167           0 :                         DBG_ERR("Number of active connections "
     168             :                                 "less than 1 (%d)\n",
     169             :                                 connections_active);
     170           0 :                         connections_active = 1;
     171             :                 }
     172          21 :                 connections_active--;
     173             :         }
     174       15348 :         return;
     175             : }
     176             : 
     177       15762 : static struct standard_child_state *setup_standard_child_pipe(struct tevent_context *ev,
     178             :                                                               const char *name)
     179             : {
     180           0 :         struct standard_child_state *state;
     181           0 :         int parent_child_pipe[2];
     182           0 :         int ret;
     183             : 
     184             :         /*
     185             :          * Prepare a pipe to allow us to know when the child exits,
     186             :          * because it will trigger a read event on this private
     187             :          * pipe.
     188             :          *
     189             :          * We do all this before the accept and fork(), so we can
     190             :          * clean up if it fails.
     191             :          */
     192       15762 :         state = talloc_zero(ev, struct standard_child_state);
     193       15762 :         if (state == NULL) {
     194           0 :                 return NULL;
     195             :         }
     196             : 
     197       15762 :         if (name == NULL) {
     198       15342 :                 name = "";
     199             :         }
     200             : 
     201       15762 :         state->name = talloc_strdup(state, name);
     202       15762 :         if (state->name == NULL) {
     203           0 :                 TALLOC_FREE(state);
     204           0 :                 return NULL;
     205             :         }
     206             : 
     207       15762 :         ret = pipe(parent_child_pipe);
     208       15762 :         if (ret == -1) {
     209           0 :                 DBG_ERR("Failed to create parent-child pipe to handle "
     210             :                         "SIGCHLD to track new process for socket\n");
     211           0 :                 TALLOC_FREE(state);
     212           0 :                 return NULL;
     213             :         }
     214             : 
     215       15762 :         smb_set_close_on_exec(parent_child_pipe[0]);
     216       15762 :         smb_set_close_on_exec(parent_child_pipe[1]);
     217             : 
     218       15762 :         state->from_child_fd = parent_child_pipe[0];
     219       15762 :         state->to_parent_fd = parent_child_pipe[1];
     220             : 
     221             :         /*
     222             :          * The basic purpose of calling this handler is to ensure we
     223             :          * call waitpid() and so avoid zombies (now that we no longer
     224             :          * user SIGIGN on for SIGCHLD), but it also allows us to clean
     225             :          * up other resources in the future.
     226             :          */
     227       15762 :         state->from_child_fde = tevent_add_fd(ev, state,
     228             :                                               state->from_child_fd,
     229             :                                               TEVENT_FD_READ,
     230             :                                               standard_child_pipe_handler,
     231             :                                               state);
     232       15762 :         if (state->from_child_fde == NULL) {
     233           0 :                 TALLOC_FREE(state);
     234           0 :                 return NULL;
     235             :         }
     236       15762 :         tevent_fd_set_auto_close(state->from_child_fde);
     237             : 
     238       15762 :         return state;
     239             : }
     240             : 
     241             : /*
     242             :   called when a listening socket becomes readable. 
     243             : */
     244       52292 : static void standard_accept_connection(
     245             :                 struct tevent_context *ev,
     246             :                 struct loadparm_context *lp_ctx,
     247             :                 struct socket_context *sock,
     248             :                 void (*new_conn)(struct tevent_context *,
     249             :                                 struct loadparm_context *,
     250             :                                 struct socket_context *,
     251             :                                 struct server_id,
     252             :                                 void *,
     253             :                                 void *),
     254             :                 void *private_data,
     255             :                 void *process_context)
     256             : {
     257           0 :         NTSTATUS status;
     258           0 :         struct socket_context *sock2;
     259           0 :         pid_t pid;
     260           0 :         struct socket_address *c, *s;
     261           0 :         struct standard_child_state *state;
     262       52292 :         struct tevent_fd *fde = NULL;
     263       52292 :         struct tevent_signal *se = NULL;
     264       52292 :         struct process_context *proc_ctx = NULL;
     265             : 
     266             : 
     267             :         /* accept an incoming connection. */
     268       52292 :         status = socket_accept(sock, &sock2);
     269       52292 :         if (!NT_STATUS_IS_OK(status)) {
     270           0 :                 DBG_DEBUG("standard_accept_connection: accept: %s\n",
     271             :                           nt_errstr(status));
     272             :                 /* this looks strange, but is correct. We need to throttle
     273             :                  * things until the system clears enough resources to handle
     274             :                  * this new socket
     275             :                  */
     276           0 :                 sleep(1);
     277           0 :                 return;
     278             :         }
     279             : 
     280       52292 :         proc_ctx = talloc_get_type_abort(process_context,
     281             :                                          struct process_context);
     282             : 
     283       52292 :         if (proc_ctx->inhibit_fork_on_accept) {
     284       36949 :                 pid = getpid();
     285             :                 /*
     286             :                  * Service does not support forking a new process on a
     287             :                  * new connection, either it's maintaining shared
     288             :                  * state or the overhead of forking a new process is a
     289             :                  * significant fraction of the response time.
     290             :                  */
     291       36949 :                 talloc_steal(private_data, sock2);
     292       36949 :                 new_conn(ev, lp_ctx, sock2,
     293       36949 :                          cluster_id(pid, socket_get_fd(sock2)), private_data,
     294             :                          process_context);
     295       36949 :                 return;
     296             :         }
     297             : 
     298       15343 :         if (smbd_max_processes > 0) {
     299          22 :                 if (connections_active >= smbd_max_processes) {
     300           1 :                         DBG_ERR("(%d) connections already active, "
     301             :                                 "maximum is (%d). Dropping request\n",
     302             :                                 connections_active,
     303             :                                 smbd_max_processes);
     304             :                         /*
     305             :                          * Drop the connection as we're overloaded at the moment
     306             :                          */
     307           1 :                         talloc_free(sock2);
     308           1 :                         return;
     309             :                 }
     310          21 :                 connections_active++;
     311             :         }
     312             : 
     313       15342 :         state = setup_standard_child_pipe(ev, NULL);
     314       15342 :         if (state == NULL) {
     315           0 :                 return;
     316             :         }
     317       15342 :         pid = fork();
     318             : 
     319       30684 :         if (pid != 0) {
     320       15342 :                 close(state->to_parent_fd);
     321       15342 :                 state->to_parent_fd = -1;
     322             : 
     323       15342 :                 if (pid > 0) {
     324       15342 :                         state->pid = pid;
     325             :                 } else {
     326           0 :                         TALLOC_FREE(state);
     327             :                 }
     328             : 
     329             :                 /* parent or error code ... */
     330       15342 :                 talloc_free(sock2);
     331             :                 /* go back to the event loop */
     332       15342 :                 return;
     333             :         }
     334             : 
     335             :         /* this leaves state->to_parent_fd open */
     336       15342 :         TALLOC_FREE(state);
     337             : 
     338             :         /* Now in the child code so indicate that we forked
     339             :          * so the terminate code knows what to do
     340             :          */
     341       15342 :         proc_ctx->forked_on_accept = true;
     342             : 
     343       15342 :         pid = getpid();
     344             : 
     345       15342 :         process_set_title("%s[work]", "task[%s] standard worker", proc_ctx->name);
     346             : 
     347             :         /* This is now the child code. We need a completely new event_context to work with */
     348             : 
     349       15342 :         if (tevent_re_initialise(ev) != 0) {
     350           0 :                 smb_panic("Failed to re-initialise tevent after fork");
     351             :         }
     352             : 
     353             :         /* this will free all the listening sockets and all state that
     354             :            is not associated with this new connection */
     355       15342 :         talloc_free(sock);
     356             : 
     357             :         /* we don't care if the dup fails, as its only a select()
     358             :            speed optimisation */
     359       15342 :         socket_dup(sock2);
     360             :                         
     361             :         /* tdb needs special fork handling */
     362       15342 :         ldb_wrap_fork_hook();
     363             : 
     364             :         /* Must be done after a fork() to reset messaging contexts. */
     365       15342 :         status = imessaging_reinit_all();
     366       15342 :         if (!NT_STATUS_IS_OK(status)) {
     367           0 :                 smb_panic("Failed to re-initialise imessaging after fork");
     368             :         }
     369             : 
     370       15342 :         fde = tevent_add_fd(ev, ev, proc_ctx->from_parent_fd, TEVENT_FD_READ,
     371             :                       standard_pipe_handler, NULL);
     372       15342 :         if (fde == NULL) {
     373           0 :                 smb_panic("Failed to add fd handler after fork");
     374             :         }
     375             : 
     376       15342 :         se = tevent_add_signal(ev,
     377             :                                 ev,
     378             :                                 SIGHUP,
     379             :                                 0,
     380             :                                 sighup_signal_handler,
     381             :                                 NULL);
     382       15342 :         if (se == NULL) {
     383           0 :                 smb_panic("Failed to add SIGHUP handler after fork");
     384             :         }
     385             : 
     386       15342 :         se = tevent_add_signal(ev,
     387             :                                 ev,
     388             :                                 SIGTERM,
     389             :                                 0,
     390             :                                 sigterm_signal_handler,
     391             :                                 NULL);
     392       15342 :         if (se == NULL) {
     393           0 :                 smb_panic("Failed to add SIGTERM handler after fork");
     394             :         }
     395             : 
     396             :         /* setup the process title */
     397       15342 :         c = socket_get_peer_addr(sock2, ev);
     398       15342 :         s = socket_get_my_addr(sock2, ev);
     399       15342 :         if (s && c) {
     400       15342 :                 setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
     401             :                              c->addr, c->port, s->addr, s->port, (int)pid);
     402             :         }
     403       15342 :         talloc_free(c);
     404       15342 :         talloc_free(s);
     405             : 
     406       15342 :         force_check_log_size();
     407             : 
     408             :         /* setup this new connection.  Cluster ID is PID based for this process model */
     409       15342 :         new_conn(ev, lp_ctx, sock2, cluster_id(pid, 0), private_data,
     410             :                  process_context);
     411             : 
     412             :         /* we can't return to the top level here, as that event context is gone,
     413             :            so we now process events in the new event context until there are no
     414             :            more to process */      
     415       15342 :         tevent_loop_wait(ev);
     416             : 
     417           0 :         talloc_free(ev);
     418           0 :         exit(0);
     419             : }
     420             : 
     421             : /*
     422             :   called to create a new server task
     423             : */
     424         420 : static void standard_new_task(struct tevent_context *ev,
     425             :                               struct loadparm_context *lp_ctx,
     426             :                               const char *service_name,
     427             :                               struct task_server *(*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *, void *),
     428             :                               void *private_data,
     429             :                               const struct service_details *service_details,
     430             :                               int from_parent_fd)
     431             : {
     432           0 :         pid_t pid;
     433           0 :         NTSTATUS status;
     434           0 :         struct standard_child_state *state;
     435         420 :         struct tevent_fd *fde = NULL;
     436         420 :         struct tevent_signal *se = NULL;
     437         420 :         struct process_context *proc_ctx = NULL;
     438         420 :         struct task_server* task = NULL;
     439             : 
     440         420 :         state = setup_standard_child_pipe(ev, service_name);
     441         420 :         if (state == NULL) {
     442           0 :                 return;
     443             :         }
     444             : 
     445         420 :         pid = fork();
     446             : 
     447         840 :         if (pid != 0) {
     448         420 :                 close(state->to_parent_fd);
     449         420 :                 state->to_parent_fd = -1;
     450             : 
     451         420 :                 if (pid > 0) {
     452         420 :                         state->pid = pid;
     453             :                 } else {
     454           0 :                         TALLOC_FREE(state);
     455             :                 }
     456             : 
     457             :                 /* parent or error code ... go back to the event loop */
     458         420 :                 return;
     459             :         }
     460             : 
     461             :         /* this leaves state->to_parent_fd open */
     462         420 :         TALLOC_FREE(state);
     463             : 
     464         420 :         pid = getpid();
     465             : 
     466             :         /* this will free all the listening sockets and all state that
     467             :            is not associated with this new connection */
     468         420 :         if (tevent_re_initialise(ev) != 0) {
     469           0 :                 smb_panic("Failed to re-initialise tevent after fork");
     470             :         }
     471             : 
     472             :         /* ldb/tdb need special fork handling */
     473         420 :         ldb_wrap_fork_hook();
     474             : 
     475             :         /* Must be done after a fork() to reset messaging contexts. */
     476         420 :         status = imessaging_reinit_all();
     477         420 :         if (!NT_STATUS_IS_OK(status)) {
     478           0 :                 smb_panic("Failed to re-initialise imessaging after fork");
     479             :         }
     480             : 
     481         420 :         fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
     482             :                       standard_pipe_handler, NULL);
     483         420 :         if (fde == NULL) {
     484           0 :                 smb_panic("Failed to add fd handler after fork");
     485             :         }
     486             : 
     487         420 :         se = tevent_add_signal(ev,
     488             :                                 ev,
     489             :                                 SIGHUP,
     490             :                                 0,
     491             :                                 sighup_signal_handler,
     492             :                                 NULL);
     493         420 :         if (se == NULL) {
     494           0 :                 smb_panic("Failed to add SIGHUP handler after fork");
     495             :         }
     496             : 
     497         420 :         se = tevent_add_signal(ev,
     498             :                                 ev,
     499             :                                 SIGTERM,
     500             :                                 0,
     501             :                                 sigterm_signal_handler,
     502             :                                 NULL);
     503         420 :         if (se == NULL) {
     504           0 :                 smb_panic("Failed to add SIGTERM handler after fork");
     505             :         }
     506             : 
     507         420 :         process_set_title("%s[task]", "task[%s]", service_name);
     508             : 
     509         420 :         force_check_log_size();
     510             : 
     511             :         /*
     512             :          * Set up the process context to be passed through to the terminate
     513             :          * and accept_connection functions
     514             :          */
     515         420 :         proc_ctx = talloc(ev, struct process_context);
     516         420 :         proc_ctx->name = talloc_strdup(ev, service_name);
     517         420 :         proc_ctx->from_parent_fd = from_parent_fd;
     518         420 :         proc_ctx->inhibit_fork_on_accept  =
     519         420 :                 service_details->inhibit_fork_on_accept;
     520         420 :         proc_ctx->forked_on_accept = false;
     521             : 
     522         420 :         smbd_max_processes = lpcfg_max_smbd_processes(lp_ctx);
     523             : 
     524             :         /* setup this new task.  Cluster ID is PID based for this process model */
     525         420 :         task = new_task(ev, lp_ctx, cluster_id(pid, 0), private_data, proc_ctx);
     526             :         /*
     527             :          * Currently we don't support the post_fork functionality in the
     528             :          * standard model, i.e. it is only called here not after a new process
     529             :          * is forked in standard_accept_connection.
     530             :          */
     531         378 :         if (task != NULL && service_details->post_fork != NULL) {
     532          70 :                 struct process_details pd = initial_process_details;
     533          70 :                 service_details->post_fork(task, &pd);
     534             :         }
     535             : 
     536         378 :         if (task != NULL && service_details->before_loop != NULL) {
     537          24 :                 service_details->before_loop(task);
     538             :         }
     539             : 
     540             :         /* we can't return to the top level here, as that event context is gone,
     541             :            so we now process events in the new event context until there are no
     542             :            more to process */
     543         378 :         tevent_loop_wait(ev);
     544             : 
     545           0 :         talloc_free(ev);
     546           0 :         exit(0);
     547             : }
     548             : 
     549             : 
     550             : /* called when a task goes down */
     551          42 : static void standard_terminate_task(struct tevent_context *ev,
     552             :                                     struct loadparm_context *lp_ctx,
     553             :                                     const char *reason,
     554             :                                     bool fatal,
     555             :                                     void *process_context)
     556             : {
     557          42 :         if (fatal == true) {
     558           0 :                 exit(127);
     559             :         }
     560          42 :         exit(0);
     561             : }
     562             : 
     563             : /* called when a connection terminates*/
     564       52281 : static void standard_terminate_connection(struct tevent_context *ev,
     565             :                                           struct loadparm_context *lp_ctx,
     566             :                                           const char *reason,
     567             :                                           void *process_context)
     568             : {
     569       52281 :         struct process_context *proc_ctx = NULL;
     570             : 
     571       52281 :         DBG_DEBUG("connection terminating reason[%s]\n", reason);
     572       52281 :         if (process_context == NULL) {
     573           0 :                 smb_panic("Panicking process_context is NULL");
     574             :         }
     575             : 
     576       52281 :         proc_ctx = talloc_get_type(process_context, struct process_context);
     577       52281 :         if (proc_ctx->forked_on_accept == false) {
     578             :                 /*
     579             :                  * The current task was not forked on accept, so it needs to
     580             :                  * keep running and process requests from other connections
     581             :                  */
     582       36947 :                 return;
     583             :         }
     584             :         /*
     585             :          * The current process was forked on accept to handle a single
     586             :          * connection/request. That request has now finished and the process
     587             :          * should terminate
     588             :          */
     589             : 
     590             :         /* this reload_charcnv() has the effect of freeing the iconv context memory,
     591             :            which makes leak checking easier */
     592       15334 :         reload_charcnv(lp_ctx);
     593             : 
     594             :         /* Always free event context last before exit. */
     595       15334 :         talloc_free(ev);
     596             : 
     597             :         /* terminate this process */
     598       15334 :         exit(0);
     599             : }
     600             : /* called to set a title of a task or connection */
     601       52666 : static void standard_set_title(struct tevent_context *ev, const char *title) 
     602             : {
     603       52666 :         if (title) {
     604       52666 :                 setproctitle("%s", title);
     605             :         } else {
     606           0 :                 setproctitle(NULL);
     607             :         }
     608       52666 : }
     609             : 
     610             : static const struct model_ops standard_ops = {
     611             :         .name                   = "standard",
     612             :         .model_init             = standard_model_init,
     613             :         .accept_connection      = standard_accept_connection,
     614             :         .new_task               = standard_new_task,
     615             :         .terminate_task         = standard_terminate_task,
     616             :         .terminate_connection   = standard_terminate_connection,
     617             :         .set_title              = standard_set_title,
     618             : };
     619             : 
     620             : /*
     621             :   initialise the standard process model, registering ourselves with the process model subsystem
     622             :  */
     623          68 : NTSTATUS process_model_standard_init(TALLOC_CTX *ctx)
     624             : {
     625          68 :         return register_process_model(&standard_ops);
     626             : }

Generated by: LCOV version 1.14