LCOV - code coverage report
Current view: top level - source4/samba - process_standard.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 155 211 73.5 %
Date: 2021-09-23 10: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         390 : static void standard_pipe_handler(struct tevent_context *event_ctx, struct tevent_fd *fde, 
      94             :                                   uint16_t flags, void *private_data)
      95             : {
      96         390 :         DBG_DEBUG("Child %d exiting\n", (int)getpid());
      97         390 :         talloc_free(event_ctx);
      98         390 :         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       11695 : 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        7514 :         struct standard_child_state *state
     114        4181 :                 = talloc_get_type_abort(private_data, struct standard_child_state);
     115       11695 :         int status = 0;
     116             :         pid_t pid;
     117             : 
     118       11695 :         messaging_dgm_cleanup(state->pid);
     119             : 
     120             :         /* the child has closed the pipe, assume its dead */
     121       11695 :         errno = 0;
     122       11695 :         pid = waitpid(state->pid, &status, 0);
     123             : 
     124       11695 :         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       11695 :         if (WIFEXITED(status)) {
     153       11695 :                 status = WEXITSTATUS(status);
     154       11695 :                 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        7514 : done:
     164       11695 :         TALLOC_FREE(state);
     165       11695 :         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       11695 :         return;
     175             : }
     176             : 
     177       12093 : static struct standard_child_state *setup_standard_child_pipe(struct tevent_context *ev,
     178             :                                                               const char *name)
     179             : {
     180             :         struct standard_child_state *state;
     181             :         int parent_child_pipe[2];
     182             :         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       12093 :         state = talloc_zero(ev, struct standard_child_state);
     193       12093 :         if (state == NULL) {
     194           0 :                 return NULL;
     195             :         }
     196             : 
     197       12093 :         if (name == NULL) {
     198       11673 :                 name = "";
     199             :         }
     200             : 
     201       12093 :         state->name = talloc_strdup(state, name);
     202       12093 :         if (state->name == NULL) {
     203           0 :                 TALLOC_FREE(state);
     204           0 :                 return NULL;
     205             :         }
     206             : 
     207       12093 :         ret = pipe(parent_child_pipe);
     208       12093 :         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       12093 :         smb_set_close_on_exec(parent_child_pipe[0]);
     216       12093 :         smb_set_close_on_exec(parent_child_pipe[1]);
     217             : 
     218       12093 :         state->from_child_fd = parent_child_pipe[0];
     219       12093 :         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       12093 :         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       12093 :         if (state->from_child_fde == NULL) {
     233           0 :                 TALLOC_FREE(state);
     234           0 :                 return NULL;
     235             :         }
     236       12093 :         tevent_fd_set_auto_close(state->from_child_fde);
     237             : 
     238       12093 :         return state;
     239             : }
     240             : 
     241             : /*
     242             :   called when a listening socket becomes readable. 
     243             : */
     244       46930 : 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             :         NTSTATUS status;
     258             :         struct socket_context *sock2;
     259             :         pid_t pid;
     260             :         struct socket_address *c, *s;
     261             :         struct standard_child_state *state;
     262       46930 :         struct tevent_fd *fde = NULL;
     263       46930 :         struct tevent_signal *se = NULL;
     264       46930 :         struct process_context *proc_ctx = NULL;
     265             : 
     266             : 
     267             :         /* accept an incoming connection. */
     268       46930 :         status = socket_accept(sock, &sock2);
     269       46930 :         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       46930 :         proc_ctx = talloc_get_type_abort(process_context,
     281             :                                          struct process_context);
     282             : 
     283       46930 :         if (proc_ctx->inhibit_fork_on_accept) {
     284       35256 :                 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       35256 :                 talloc_steal(private_data, sock2);
     292       35256 :                 new_conn(ev, lp_ctx, sock2,
     293       35256 :                          cluster_id(pid, socket_get_fd(sock2)), private_data,
     294             :                          process_context);
     295       35256 :                 return;
     296             :         }
     297             : 
     298       11674 :         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       11673 :         state = setup_standard_child_pipe(ev, NULL);
     314       11673 :         if (state == NULL) {
     315           0 :                 return;
     316             :         }
     317       11673 :         pid = fork();
     318             : 
     319       23346 :         if (pid != 0) {
     320       11673 :                 close(state->to_parent_fd);
     321       11673 :                 state->to_parent_fd = -1;
     322             : 
     323       11673 :                 if (pid > 0) {
     324       11673 :                         state->pid = pid;
     325             :                 } else {
     326           0 :                         TALLOC_FREE(state);
     327             :                 }
     328             : 
     329             :                 /* parent or error code ... */
     330       11673 :                 talloc_free(sock2);
     331             :                 /* go back to the event loop */
     332       11673 :                 return;
     333             :         }
     334             : 
     335             :         /* this leaves state->to_parent_fd open */
     336       11673 :         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       11673 :         proc_ctx->forked_on_accept = true;
     342             : 
     343       11673 :         pid = getpid();
     344       11673 :         setproctitle("task[%s] standard worker", proc_ctx->name);
     345             : 
     346             :         /*
     347             :          * We must fit within 15 chars of text or we will truncate, so
     348             :          * we put the constant part last
     349             :          */
     350       11673 :         prctl_set_comment("%s[work]", proc_ctx->name);
     351             : 
     352             :         /* This is now the child code. We need a completely new event_context to work with */
     353             : 
     354       11673 :         if (tevent_re_initialise(ev) != 0) {
     355           0 :                 smb_panic("Failed to re-initialise tevent after fork");
     356             :         }
     357             : 
     358             :         /* this will free all the listening sockets and all state that
     359             :            is not associated with this new connection */
     360       11673 :         talloc_free(sock);
     361             : 
     362             :         /* we don't care if the dup fails, as its only a select()
     363             :            speed optimisation */
     364       11673 :         socket_dup(sock2);
     365             :                         
     366             :         /* tdb needs special fork handling */
     367       11673 :         ldb_wrap_fork_hook();
     368             : 
     369             :         /* Must be done after a fork() to reset messaging contexts. */
     370       11673 :         status = imessaging_reinit_all();
     371       11673 :         if (!NT_STATUS_IS_OK(status)) {
     372           0 :                 smb_panic("Failed to re-initialise imessaging after fork");
     373             :         }
     374             : 
     375       11673 :         fde = tevent_add_fd(ev, ev, proc_ctx->from_parent_fd, TEVENT_FD_READ,
     376             :                       standard_pipe_handler, NULL);
     377       11673 :         if (fde == NULL) {
     378           0 :                 smb_panic("Failed to add fd handler after fork");
     379             :         }
     380             : 
     381       11673 :         se = tevent_add_signal(ev,
     382             :                                 ev,
     383             :                                 SIGHUP,
     384             :                                 0,
     385             :                                 sighup_signal_handler,
     386             :                                 NULL);
     387       11673 :         if (se == NULL) {
     388           0 :                 smb_panic("Failed to add SIGHUP handler after fork");
     389             :         }
     390             : 
     391       11673 :         se = tevent_add_signal(ev,
     392             :                                 ev,
     393             :                                 SIGTERM,
     394             :                                 0,
     395             :                                 sigterm_signal_handler,
     396             :                                 NULL);
     397       11673 :         if (se == NULL) {
     398           0 :                 smb_panic("Failed to add SIGTERM handler after fork");
     399             :         }
     400             : 
     401             :         /* setup the process title */
     402       11673 :         c = socket_get_peer_addr(sock2, ev);
     403       11673 :         s = socket_get_my_addr(sock2, ev);
     404       11673 :         if (s && c) {
     405       11673 :                 setproctitle("conn c[%s:%u] s[%s:%u] server_id[%d]",
     406             :                              c->addr, c->port, s->addr, s->port, (int)pid);
     407             :         }
     408       11673 :         talloc_free(c);
     409       11673 :         talloc_free(s);
     410             : 
     411       11673 :         force_check_log_size();
     412             : 
     413             :         /* setup this new connection.  Cluster ID is PID based for this process model */
     414       11673 :         new_conn(ev, lp_ctx, sock2, cluster_id(pid, 0), private_data,
     415             :                  process_context);
     416             : 
     417             :         /* we can't return to the top level here, as that event context is gone,
     418             :            so we now process events in the new event context until there are no
     419             :            more to process */      
     420       11673 :         tevent_loop_wait(ev);
     421             : 
     422           0 :         talloc_free(ev);
     423           0 :         exit(0);
     424             : }
     425             : 
     426             : /*
     427             :   called to create a new server task
     428             : */
     429         420 : static void standard_new_task(struct tevent_context *ev,
     430             :                               struct loadparm_context *lp_ctx,
     431             :                               const char *service_name,
     432             :                               struct task_server *(*new_task)(struct tevent_context *, struct loadparm_context *lp_ctx, struct server_id , void *, void *),
     433             :                               void *private_data,
     434             :                               const struct service_details *service_details,
     435             :                               int from_parent_fd)
     436             : {
     437             :         pid_t pid;
     438             :         NTSTATUS status;
     439             :         struct standard_child_state *state;
     440         420 :         struct tevent_fd *fde = NULL;
     441         420 :         struct tevent_signal *se = NULL;
     442         420 :         struct process_context *proc_ctx = NULL;
     443         420 :         struct task_server* task = NULL;
     444             : 
     445         420 :         state = setup_standard_child_pipe(ev, service_name);
     446         420 :         if (state == NULL) {
     447           0 :                 return;
     448             :         }
     449             : 
     450         420 :         pid = fork();
     451             : 
     452         840 :         if (pid != 0) {
     453         420 :                 close(state->to_parent_fd);
     454         420 :                 state->to_parent_fd = -1;
     455             : 
     456         420 :                 if (pid > 0) {
     457         420 :                         state->pid = pid;
     458             :                 } else {
     459           0 :                         TALLOC_FREE(state);
     460             :                 }
     461             : 
     462             :                 /* parent or error code ... go back to the event loop */
     463         420 :                 return;
     464             :         }
     465             : 
     466             :         /* this leaves state->to_parent_fd open */
     467         420 :         TALLOC_FREE(state);
     468             : 
     469         420 :         pid = getpid();
     470             : 
     471             :         /* this will free all the listening sockets and all state that
     472             :            is not associated with this new connection */
     473         420 :         if (tevent_re_initialise(ev) != 0) {
     474           0 :                 smb_panic("Failed to re-initialise tevent after fork");
     475             :         }
     476             : 
     477             :         /* ldb/tdb need special fork handling */
     478         420 :         ldb_wrap_fork_hook();
     479             : 
     480             :         /* Must be done after a fork() to reset messaging contexts. */
     481         420 :         status = imessaging_reinit_all();
     482         420 :         if (!NT_STATUS_IS_OK(status)) {
     483           0 :                 smb_panic("Failed to re-initialise imessaging after fork");
     484             :         }
     485             : 
     486         420 :         fde = tevent_add_fd(ev, ev, from_parent_fd, TEVENT_FD_READ,
     487             :                       standard_pipe_handler, NULL);
     488         420 :         if (fde == NULL) {
     489           0 :                 smb_panic("Failed to add fd handler after fork");
     490             :         }
     491             : 
     492         420 :         se = tevent_add_signal(ev,
     493             :                                 ev,
     494             :                                 SIGHUP,
     495             :                                 0,
     496             :                                 sighup_signal_handler,
     497             :                                 NULL);
     498         420 :         if (se == NULL) {
     499           0 :                 smb_panic("Failed to add SIGHUP handler after fork");
     500             :         }
     501             : 
     502         420 :         se = tevent_add_signal(ev,
     503             :                                 ev,
     504             :                                 SIGTERM,
     505             :                                 0,
     506             :                                 sigterm_signal_handler,
     507             :                                 NULL);
     508         420 :         if (se == NULL) {
     509           0 :                 smb_panic("Failed to add SIGTERM handler after fork");
     510             :         }
     511             : 
     512         420 :         setproctitle("task[%s]", service_name);
     513             :         /*
     514             :          * We must fit within 15 chars of text or we will truncate, so
     515             :          * we put the constant part last
     516             :          */
     517         420 :         prctl_set_comment("%s[task]", service_name);
     518             : 
     519         420 :         force_check_log_size();
     520             : 
     521             :         /*
     522             :          * Set up the process context to be passed through to the terminate
     523             :          * and accept_connection functions
     524             :          */
     525         420 :         proc_ctx = talloc(ev, struct process_context);
     526         420 :         proc_ctx->name = talloc_strdup(ev, service_name);
     527         420 :         proc_ctx->from_parent_fd = from_parent_fd;
     528         420 :         proc_ctx->inhibit_fork_on_accept  =
     529         420 :                 service_details->inhibit_fork_on_accept;
     530         420 :         proc_ctx->forked_on_accept = false;
     531             : 
     532         420 :         smbd_max_processes = lpcfg_max_smbd_processes(lp_ctx);
     533             : 
     534             :         /* setup this new task.  Cluster ID is PID based for this process model */
     535         420 :         task = new_task(ev, lp_ctx, cluster_id(pid, 0), private_data, proc_ctx);
     536             :         /*
     537             :          * Currently we don't support the post_fork functionality in the
     538             :          * standard model, i.e. it is only called here not after a new process
     539             :          * is forked in standard_accept_connection.
     540             :          */
     541         378 :         if (task != NULL && service_details->post_fork != NULL) {
     542          70 :                 struct process_details pd = initial_process_details;
     543          70 :                 service_details->post_fork(task, &pd);
     544             :         }
     545             : 
     546             : 
     547             :         /* we can't return to the top level here, as that event context is gone,
     548             :            so we now process events in the new event context until there are no
     549             :            more to process */
     550         378 :         tevent_loop_wait(ev);
     551             : 
     552           0 :         talloc_free(ev);
     553           0 :         exit(0);
     554             : }
     555             : 
     556             : 
     557             : /* called when a task goes down */
     558          42 : static void standard_terminate_task(struct tevent_context *ev,
     559             :                                     struct loadparm_context *lp_ctx,
     560             :                                     const char *reason,
     561             :                                     bool fatal,
     562             :                                     void *process_context)
     563             : {
     564          42 :         if (fatal == true) {
     565           0 :                 exit(127);
     566             :         }
     567          42 :         exit(0);
     568             : }
     569             : 
     570             : /* called when a connection terminates*/
     571       46910 : static void standard_terminate_connection(struct tevent_context *ev,
     572             :                                           struct loadparm_context *lp_ctx,
     573             :                                           const char *reason,
     574             :                                           void *process_context)
     575             : {
     576       46910 :         struct process_context *proc_ctx = NULL;
     577             : 
     578       46910 :         DBG_DEBUG("connection terminating reason[%s]\n", reason);
     579       46910 :         if (process_context == NULL) {
     580           0 :                 smb_panic("Panicking process_context is NULL");
     581             :         }
     582             : 
     583       46910 :         proc_ctx = talloc_get_type(process_context, struct process_context);
     584       46910 :         if (proc_ctx->forked_on_accept == false) {
     585             :                 /*
     586             :                  * The current task was not forked on accept, so it needs to
     587             :                  * keep running and process requests from other connections
     588             :                  */
     589       70068 :                 return;
     590             :         }
     591             :         /*
     592             :          * The current process was forked on accept to handle a single
     593             :          * connection/request. That request has now finished and the process
     594             :          * should terminate
     595             :          */
     596             : 
     597             :         /* this reload_charcnv() has the effect of freeing the iconv context memory,
     598             :            which makes leak checking easier */
     599       11661 :         reload_charcnv(lp_ctx);
     600             : 
     601             :         /* Always free event context last before exit. */
     602       11661 :         talloc_free(ev);
     603             : 
     604             :         /* terminate this process */
     605       11661 :         exit(0);
     606             : }
     607             : /* called to set a title of a task or connection */
     608       47304 : static void standard_set_title(struct tevent_context *ev, const char *title) 
     609             : {
     610       47304 :         if (title) {
     611       47304 :                 setproctitle("%s", title);
     612             :         } else {
     613           0 :                 setproctitle(NULL);
     614             :         }
     615       47304 : }
     616             : 
     617             : static const struct model_ops standard_ops = {
     618             :         .name                   = "standard",
     619             :         .model_init             = standard_model_init,
     620             :         .accept_connection      = standard_accept_connection,
     621             :         .new_task               = standard_new_task,
     622             :         .terminate_task         = standard_terminate_task,
     623             :         .terminate_connection   = standard_terminate_connection,
     624             :         .set_title              = standard_set_title,
     625             : };
     626             : 
     627             : /*
     628             :   initialise the standard process model, registering ourselves with the process model subsystem
     629             :  */
     630          66 : NTSTATUS process_model_standard_init(TALLOC_CTX *ctx)
     631             : {
     632          66 :         return register_process_model(&standard_ops);
     633             : }

Generated by: LCOV version 1.13