root/crmd/subsystems.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. crmd_child_exit
  2. stop_subsystem
  3. start_subsystem

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This software is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  */
  18 
  19 #include <crm_internal.h>
  20 
  21 #include <errno.h>
  22 #include <fcntl.h>   /* open */
  23 #include <sys/resource.h>  /* getrlimit */
  24 #include <sys/stat.h>  /* open, stat */
  25 #include <sys/time.h>  /* getrlimit */
  26 #include <unistd.h>  /* access, fork, pid_t, setpgid */
  27 
  28 #include <crm/common/util.h>
  29 #include <crm/crm.h>  /* DAEMON_RESPAWN_STOP */
  30 
  31 #include <crmd_fsa.h>  /* fsa_input_register */
  32 
  33 
  34 static void
  35 crmd_child_exit(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37     /* struct crm_subsystem_s *the_subsystem = mainloop_child_userdata(p); */
  38     const char *name = mainloop_child_name(p);
  39 
  40     if (signo) {
  41         crm_notice("Child process %s terminated with signal %d (pid=%d, core=%d)",
  42                    name, signo, pid, core);
  43 
  44     } else {
  45         do_crm_log(exitcode == 0 ? LOG_INFO : LOG_ERR,
  46                    "Child process %s exited (pid=%d, rc=%d)", name,
  47                    pid, exitcode);
  48     }
  49 }
  50 
  51 gboolean
  52 stop_subsystem(struct crm_subsystem_s *the_subsystem, gboolean force_quit)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54     int quit_signal = SIGTERM;
  55 
  56     crm_trace("Stopping sub-system \"%s\"", the_subsystem->name);
  57     clear_bit(fsa_input_register, the_subsystem->flag_required);
  58 
  59     if (the_subsystem->pid <= 0) {
  60         crm_trace("Client %s not running", the_subsystem->name);
  61         return FALSE;
  62 
  63     }
  64 
  65     if (is_set(fsa_input_register, the_subsystem->flag_connected) == FALSE) {
  66         /* running but not yet connected */
  67         crm_debug("Stopping %s before it had connected", the_subsystem->name);
  68     }
  69 /*
  70         if(force_quit && the_subsystem->sent_kill == FALSE) {
  71                 quit_signal = SIGKILL;
  72 
  73         } else if(force_quit) {
  74                 crm_debug("Already sent -KILL to %s: [%d]",
  75                           the_subsystem->name, the_subsystem->pid);
  76         }
  77 */
  78     errno = 0;
  79     if (kill(the_subsystem->pid, quit_signal) == 0) {
  80         crm_info("Sent -TERM to %s: [%d]", the_subsystem->name, the_subsystem->pid);
  81         the_subsystem->sent_kill = TRUE;
  82 
  83     } else {
  84         crm_perror(LOG_ERR, "Sent -TERM to %s: [%d]", the_subsystem->name, the_subsystem->pid);
  85     }
  86 
  87     return TRUE;
  88 }
  89 
  90 gboolean
  91 start_subsystem(struct crm_subsystem_s * the_subsystem)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93     pid_t pid;
  94     struct stat buf;
  95     int s_res;
  96     unsigned int j;
  97     struct rlimit oflimits;
  98     const char *devnull = "/dev/null";
  99 
 100     crm_info("Starting sub-system \"%s\"", the_subsystem->name);
 101 
 102     if (the_subsystem->pid > 0) {
 103         crm_warn("Client %s already running as pid %d",
 104                  the_subsystem->name, (int)the_subsystem->pid);
 105 
 106         /* starting a started X is not an error */
 107         return TRUE;
 108     }
 109 
 110     /*
 111      * We want to ensure that the exec will succeed before
 112      * we bother forking.
 113      */
 114 
 115     if (access(the_subsystem->path, F_OK | X_OK) != 0) {
 116         crm_perror(LOG_ERR, "Cannot (access) exec %s", the_subsystem->path);
 117         return FALSE;
 118     }
 119 
 120     s_res = stat(the_subsystem->command, &buf);
 121     if (s_res != 0) {
 122         crm_perror(LOG_ERR, "Cannot (stat) exec %s", the_subsystem->command);
 123         return FALSE;
 124     }
 125 
 126     /* We need to fork so we can make child procs not real time */
 127     switch (pid = fork()) {
 128         case -1:
 129             crm_err("Cannot fork.");
 130             return FALSE;
 131 
 132         default:               /* Parent */
 133             mainloop_child_add(pid, 0, the_subsystem->name, the_subsystem, crmd_child_exit);
 134             crm_trace("Client %s is has pid: %d", the_subsystem->name, pid);
 135             the_subsystem->pid = pid;
 136             return TRUE;
 137 
 138         case 0:                /* Child */
 139             /* create a new process group to avoid
 140              * being interrupted by heartbeat
 141              */
 142             setpgid(0, 0);
 143             break;
 144     }
 145 
 146     crm_debug("Executing \"%s (%s)\" (pid %d)",
 147               the_subsystem->command, the_subsystem->name, (int)getpid());
 148 
 149     /* A precautionary measure */
 150     getrlimit(RLIMIT_NOFILE, &oflimits);
 151     for (j = 0; j < oflimits.rlim_cur; ++j) {
 152         close(j);
 153     }
 154 
 155     (void)open(devnull, O_RDONLY);      /* Stdin:  fd 0 */
 156     (void)open(devnull, O_WRONLY);      /* Stdout: fd 1 */
 157     (void)open(devnull, O_WRONLY);      /* Stderr: fd 2 */
 158 
 159     {
 160         char *opts[2];
 161 
 162         opts[0] = strdup(the_subsystem->command);
 163         opts[1] = NULL;
 164 
 165         /* coverity[toctou] The call to stat() is a fail-fast, not a race */
 166         (void)execvp(the_subsystem->command, opts);
 167     }
 168 
 169     /* Should not happen */
 170     crm_perror(LOG_ERR, "FATAL: Cannot exec %s", the_subsystem->command);
 171 
 172     return crm_exit(DAEMON_RESPAWN_STOP);             /* Suppress respawning */
 173 }

/* [previous][next][first][last][top][bottom][index][help] */