"Fossies" - the Fresh Open Source Software Archive

Member "Heartbeat-3-0-958e11be8686/heartbeat/config.c" (9 Feb 2015, 69779 Bytes) of package /linux/misc/Heartbeat-3-0-STABLE-3.0.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "config.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3-0-STABLE-3.0.5_vs_3-0-STABLE-3.0.6.

    1 /*
    2  * Parse various heartbeat configuration files...
    3  *
    4  * Copyright (C) 2000 Alan Robertson <alanr@unix.sh>
    5  *  portions (c) 1999,2000 Mitja Sarp
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2 of the License, or
   10  * (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
   20  */
   21 
   22 #include <lha_internal.h>
   23 
   24 #include <stdio.h>
   25 #include <stdlib.h>
   26 #include <stdarg.h>
   27 #include <ctype.h>
   28 #include <string.h>
   29 #include <sys/types.h>
   30 #include <sys/stat.h>
   31 #include <errno.h>
   32 #include <time.h>
   33 #include <sys/time.h>
   34 #include <unistd.h>
   35 #include <dirent.h>
   36 #include <dlfcn.h>
   37 #include <fcntl.h>
   38 #include <pwd.h>
   39 #include <grp.h>
   40 #include <netdb.h>
   41 #include <sched.h>
   42 #include <sys/wait.h>
   43 #include <sys/utsname.h>
   44 #include <sys/stat.h>
   45 #include <sys/resource.h>
   46 
   47 #include <heartbeat.h>
   48 #include <heartbeat_private.h>
   49 #include <ha_msg.h>
   50 #include <pils/plugin.h>
   51 #include <clplumbing/realtime.h>
   52 #include <clplumbing/netstring.h>
   53 #include <clplumbing/coredumps.h>
   54 #include <stonith/stonith.h>
   55 #include <HBcomm.h>
   56 #include <compress.h>
   57 #include <hb_module.h>
   58 #include <hb_api.h>
   59 #include <hb_config.h>
   60 #include <hb_api_core.h>
   61 #include <clplumbing/cl_syslog.h>
   62 #include <clplumbing/cl_misc.h>
   63 #include <ha_version.h>
   64 
   65 #define DIRTYALIASKLUDGE
   66 
   67 void dellist_destroy(void);
   68 int dellist_add(const char* nodename);
   69 const char *get_hg_version(void);
   70 
   71 static int set_cluster_name(const char * value);
   72 static int add_normal_node(const char *);
   73 static int set_hopfudge(const char *);
   74 static int set_keepalive_ms(const char *);
   75 static int set_deadtime_ms(const char *);
   76 static int set_deadping_ms(const char *);
   77 static int set_initial_deadtime_ms(const char *);
   78 static int set_watchdogdev(const char *);
   79 static int set_baudrate(const char *);
   80 static int set_udpport(const char *);
   81 static int set_facility(const char *);
   82 static int set_logfile(const char *);
   83 static int set_dbgfile(const char *);
   84 static int set_nice_failback(const char *);
   85 static int set_auto_failback(const char *);
   86 static int set_warntime_ms(const char *);
   87 static int set_stonith_info(const char *);
   88 static int set_stonith_host_info(const char *);
   89 static int set_realtime_prio(const char *);
   90 static int add_client_child(const char *);
   91 static int add_failfast_child(const char *);
   92 static int set_compression(const char *);
   93 static int set_compression_threshold(const char *);
   94 static int set_traditional_compression(const char *);
   95 static int set_env(const char *);
   96 static int set_max_rexmit_delay(const char *);
   97 static int set_generation_method(const char *);
   98 static int set_realtime(const char *);
   99 static int set_debuglevel(const char *);
  100 static int set_api_authorization(const char *);
  101 static int set_msgfmt(const char*);
  102 static int set_logdaemon(const char*);
  103 static int set_logdconntime(const char *);
  104 static int set_register_to_apphbd(const char *);
  105 static int set_badpack_warn(const char*);
  106 static int set_coredump(const char*);
  107 static int set_corerootdir(const char*);
  108 static int set_crm_daemon_dir(const char*);
  109 static int set_pengine_by_crm(const char*);
  110 static int set_release2mode(const char*);
  111 static int set_pcmk_support(const char*);
  112 static int set_autojoin(const char*);
  113 static int set_uuidfrom(const char*);
  114 static int ha_config_check_boolean(const char *);
  115 static int set_memreserve(const char *);
  116 static int set_quorum_server(const char * value);
  117 static int set_syslog_logfilefmt(const char * value);
  118 #ifdef ALLOWPOLLCHOICE
  119   static int set_normalpoll(const char *);
  120 #endif
  121 
  122 
  123 void hb_set_max_rexmit_delay(int);
  124 /*
  125  * Each of these parameters is is automatically recorded by
  126  * SetParameterValue().  They are then passed to the plugins
  127  * for their use later.  This avoids coupling through global
  128  * variables.
  129  */
  130 struct directive {
  131     const char *    name;
  132     int     (*add_func) (const char *);
  133     int     record_value;
  134     const char *    defaultvalue;
  135     const char *    explanation;
  136 }Directives[] =
  137 { {KEY_CLUSTER, set_cluster_name, TRUE, "linux-ha", "the name of cluster"}
  138 , {KEY_HOST,    add_normal_node, FALSE, NULL, NULL}
  139 , {KEY_HOPS,    set_hopfudge, TRUE, "1", "# of hops above cluster size"}
  140 , {KEY_KEEPALIVE, set_keepalive_ms, TRUE, "1000ms", "keepalive time"}
  141 , {KEY_DEADTIME,  set_deadtime_ms,  TRUE, "30000ms", "node deadtime"}
  142 , {KEY_DEADPING,  set_deadping_ms,  TRUE, NULL, "ping deadtime"}
  143 , {KEY_INITDEAD,  set_initial_deadtime_ms, TRUE, NULL, "initial deadtime"}
  144 , {KEY_WARNTIME,  set_warntime_ms, TRUE, NULL, "warning time"}
  145 , {KEY_WATCHDOG,  set_watchdogdev, TRUE, NULL, "watchdog device"}
  146 , {KEY_BAUDRATE,  set_baudrate, TRUE, "19200", "baud rate"}
  147 , {KEY_UDPPORT,   set_udpport, TRUE, NULL, "UDP port number"}
  148 , {KEY_FACILITY,  set_facility, TRUE, NULL, "syslog log facility"}
  149 , {KEY_LOGFILE,   set_logfile, TRUE, NULL, "log file"}
  150 , {KEY_DBGFILE,   set_dbgfile, TRUE, NULL, "debug file"}
  151 , {KEY_FAILBACK,  set_nice_failback, FALSE, NULL, NULL}
  152 , {KEY_AUTOFAIL,  set_auto_failback, TRUE, "legacy","auto failback"}
  153 , {KEY_RT_PRIO,   set_realtime_prio, TRUE, NULL, "realtime priority"}
  154 , {KEY_GEN_METH,  set_generation_method, TRUE, "file", "protocol generation computation method"}
  155 , {KEY_REALTIME,  set_realtime, TRUE, "true", "enable realtime behavior?"}
  156 , {KEY_DEBUGLEVEL,set_debuglevel, TRUE, NULL, "debug level"}
  157 #ifdef ALLOWPOLLCHOICE
  158 , {KEY_NORMALPOLL,set_normalpoll, TRUE, "true", "Use system poll(2) function?"}
  159 #endif
  160 , {KEY_MSGFMT,    set_msgfmt, TRUE, "classic", "message format in the wire"}
  161 , {KEY_LOGDAEMON, set_logdaemon, TRUE, NULL, "use logging daemon"}  
  162 , {KEY_CONNINTVAL,set_logdconntime, TRUE, "60", "the interval to reconnect to logd"}  
  163 , {KEY_REGAPPHBD, set_register_to_apphbd, FALSE, NULL, "register with apphbd"}
  164 , {KEY_BADPACK,   set_badpack_warn, TRUE, "true", "warn about bad packets"}
  165 , {KEY_SYSLOGFMT, set_syslog_logfilefmt, TRUE, "true", "log to files in syslog format"}
  166 , {KEY_COREDUMP,  set_coredump, TRUE, "true", "enable Linux-HA core dumps"}
  167 , {KEY_COREROOTDIR,set_corerootdir, TRUE, NULL, "set root directory of core dump area"}
  168 , {KEY_CRM_DAEMON_DIR, set_crm_daemon_dir, TRUE, NULL, "location for Pacemaker daemons"}
  169 , {KEY_PENGINE_BY_CRM, set_pengine_by_crm, TRUE, NULL, "should pengine be spawned directly by heartbeat"}
  170 , {KEY_REL2,      set_release2mode, FALSE, NULL, "historical alias for '"KEY_PACEMAKER"'"}
  171 , {KEY_PACEMAKER, set_pcmk_support, TRUE, "false", "enable Pacemaker resource management"}
  172 , {KEY_AUTOJOIN,  set_autojoin, TRUE, "none" ,  "set automatic join mode/style"}
  173 , {KEY_UUIDFROM,  set_uuidfrom, TRUE, "file" ,  "set the source for uuid"}
  174 ,{KEY_COMPRESSION,   set_compression, TRUE ,"zlib", "set compression module"}
  175 ,{KEY_COMPRESSION_THRESHOLD, set_compression_threshold, TRUE, "2", "set compression threshold"}
  176 ,{KEY_TRADITIONAL_COMPRESSION, set_traditional_compression, TRUE, "no", "set traditional_compression"}
  177 ,{KEY_ENV, set_env, FALSE, NULL, "set environment variable for respawn clients"}
  178 ,{KEY_MAX_REXMIT_DELAY, set_max_rexmit_delay, TRUE,"250", "set the maximum rexmit delay time"}
  179 ,{KEY_LOG_CONFIG_CHANGES, ha_config_check_boolean, TRUE,"on", "record changes to the cib (valid only with: "KEY_PACEMAKER" on)"}
  180 ,{KEY_LOG_PENGINE_INPUTS, ha_config_check_boolean, TRUE,"on", "record the input used by the policy engine (valid only with: "KEY_PACEMAKER" on)"}
  181 ,{KEY_CONFIG_WRITES_ENABLED, ha_config_check_boolean, TRUE,"on", "write configuration changes to disk (valid only with: "KEY_PACEMAKER" on)"}
  182 ,{KEY_MEMRESERVE, set_memreserve, TRUE, "6500", "number of kbytes to preallocate in heartbeat"}
  183 ,{KEY_QSERVER,set_quorum_server, TRUE, NULL, "the name or ip of quorum server"}
  184 };
  185 
  186 
  187 static const struct WholeLineDirective {
  188     const char * type;
  189     int (*parse) (const char *line);
  190 }WLdirectives[] =
  191 {   {KEY_STONITH,      set_stonith_info}
  192 ,   {KEY_STONITHHOST,  set_stonith_host_info}
  193 ,   {KEY_APIPERM,      set_api_authorization}
  194 ,   {KEY_CLIENT_CHILD, add_client_child}
  195 ,   {KEY_FAILFAST,     add_failfast_child}
  196 };
  197 
  198 extern const char *         cmdname;
  199 extern int              parse_only;
  200 extern struct hb_media*         sysmedia[MAXMEDIA];
  201 extern struct sys_config *      config;
  202 extern struct sys_config        config_init_value;
  203 extern volatile struct pstat_shm *  procinfo;
  204 extern volatile struct process_info *   curproc;
  205 extern char *               watchdogdev;
  206 extern int              nummedia;
  207 extern int                              nice_failback;
  208 extern int                              auto_failback;
  209 extern int              DoManageResources;
  210 extern int              hb_realtime_prio;
  211 extern PILPluginUniv*           PluginLoadingSystem;
  212 extern GHashTable*          CommFunctions;
  213 extern GHashTable*          CompressFuncs;
  214 GHashTable*             APIAuthorization = NULL;
  215 extern struct node_info *               curnode;
  216 extern int                  timebasedgenno;
  217 int                     enable_realtime = TRUE;
  218 extern int                  debug_level;
  219 int                 netstring_format = FALSE;
  220 extern int              UseApphbd;
  221 GSList*                 del_node_list;
  222 
  223 
  224 static int  islegaldirective(const char *directive);
  225 static int  parse_config(const char * cfgfile, char *nodename);
  226 static int  add_option(const char * option, const char * value);
  227 
  228 
  229 int num_hb_media_types;
  230 static gboolean any_media_statements_yet = FALSE;
  231 
  232 struct hb_media_fns**   hbmedia_types;
  233 
  234 
  235 #ifdef IRIX
  236     void setenv(const char *name, const char * value, int);
  237 #endif
  238 
  239 
  240 const char
  241 *get_hg_version(void) 
  242 {               
  243     /* limit this #define's use to a single file to avoid
  244      * rebuilding more than necessary */
  245     return HA_HG_VERSION;
  246 }
  247 
  248 static void
  249 check_logd_usage(int* errcount)
  250 {
  251     const char* value;
  252     int truefalse = FALSE;
  253 
  254     /*we set uselogd to TRUE here so the next message can be logged*/
  255     value = GetParameterValue(KEY_LOGDAEMON);
  256     if (value != NULL){
  257         if(cl_str_to_boolean(value, &truefalse) == HA_FAIL){
  258             cl_log(LOG_ERR, "cl_str_to_boolean failed[%s]", value);
  259             (*errcount)++;
  260             return;
  261         }
  262         
  263     }
  264     
  265     if (*(config->logfile) == EOS 
  266         && *(config->dbgfile) == EOS
  267         && config->log_facility <= 0){
  268         cl_log_set_uselogd(TRUE);
  269         if (value == NULL){
  270             cl_log(LOG_INFO, "No log entry found in ha.cf -- use logd");
  271             add_option(KEY_LOGDAEMON,"yes");
  272             return;
  273         }
  274         
  275         if (truefalse == FALSE){
  276             (*errcount)++;
  277             cl_log(LOG_ERR, "No log entry found in ha.cf "
  278                    "and use_logd is set to off");               
  279             return;
  280         }       
  281     }else if (value == NULL || truefalse == FALSE){
  282         cl_log(LOG_WARNING, "Logging daemon is disabled --"
  283                "enabling logging daemon is recommended");
  284     }else{
  285         cl_log(LOG_WARNING, "logd is enabled but %s%s%s is still"
  286                " configured in ha.cf",
  287                config->logfile?"logfile":"",
  288                config->dbgfile?"/debugfile":"",
  289                config->log_facility > 0?"/logfacility":""
  290                );
  291     }
  292 }
  293 
  294 static gboolean
  295 r1_style_valid(void)
  296 {
  297     /* we cannot set autojoin to HB_JOIN_ANY or HB_JOIN_OTHER
  298      * in R1 style
  299      */
  300     
  301     if (!DoManageResources){
  302         return TRUE;
  303     }
  304     
  305     if (config->rtjoinconfig == HB_JOIN_NONE){
  306         return TRUE;
  307     }
  308 
  309     cl_log(LOG_ERR, "R1 style resource management conflicts with "
  310            " autojoin set");
  311     cl_log(LOG_ERR, "You need either unset autojoin or enable crm");
  312     return FALSE;
  313 }
  314 
  315 /*
  316  *  Read in and validate the configuration file.
  317  *  Act accordingly.
  318  */
  319 
  320 int
  321 init_config(const char * cfgfile)
  322 {
  323     int errcount = 0;
  324     int j;
  325     int err;
  326 
  327 /*
  328  *  'Twould be good to move this to a shared memory segment
  329  *  Then we could share this information with others
  330  */
  331     /* config = (struct sys_config *)calloc(1
  332     ,   sizeof(struct sys_config)); */
  333     memset(&config_init_value, 0, sizeof(config_init_value));
  334     config = &config_init_value;
  335     if (config == NULL) {
  336         ha_log(LOG_ERR, "Heartbeat not started: "
  337             "Out of memory during configuration");
  338         return(HA_FAIL);
  339     }
  340     config->format_vers = 100;
  341     config->heartbeat_ms = 1000;
  342     config->deadtime_ms = 30000;
  343     config->initial_deadtime_ms = -1;
  344     config->deadping_ms = -1;
  345     config->hopfudge = 1;
  346     config->log_facility = -1;
  347     config->client_list = NULL;
  348     config->last_client = NULL;
  349     config->uuidfromname = FALSE;
  350     
  351     curnode = NULL;
  352 
  353     if (!parse_config(cfgfile, localnodename)) {
  354         err = errno;
  355         ha_log(LOG_ERR, "Heartbeat not started: configuration error.");
  356         errno=err;
  357         return(HA_FAIL);
  358     }
  359     if (parse_authfile() != HA_OK) {
  360         err = errno;
  361         ha_log(LOG_ERR, "Authentication configuration error.");
  362         errno=err;
  363         return(HA_FAIL);
  364     }
  365     if (config->log_facility >= 0) {
  366         cl_log_set_entity(cmdname);
  367         cl_log_set_facility(config->log_facility);
  368     }
  369 
  370 
  371     /* Set any "fixed" defaults */
  372     for (j=0; j < DIMOF(Directives); ++j) {
  373         if (!Directives[j].defaultvalue
  374         ||  GetParameterValue(Directives[j].name)) {
  375             continue;
  376         }
  377         add_option(Directives[j].name, Directives[j].defaultvalue);
  378         
  379     }
  380 
  381     if (GetParameterValue(KEY_DEBUGLEVEL) == NULL) {
  382         char    debugstr[10];
  383         snprintf(debugstr, sizeof(debugstr), "%d", debug_level);
  384         add_option(KEY_DEBUGLEVEL, debugstr);
  385     }
  386 
  387     if (nummedia < 1) {
  388         ha_log(LOG_ERR, "No heartbeat media defined");
  389         ++errcount;
  390     }
  391 
  392     if (config->warntime_ms <= 0) {
  393         char tmp[32];
  394         config->warntime_ms = config->deadtime_ms/2;
  395         snprintf(tmp, sizeof(tmp), "%ldms", config->warntime_ms);
  396         SetParameterValue(KEY_WARNTIME, tmp);
  397     }
  398     
  399     /* We should probably complain if there aren't at least two... */
  400     if (config->nodecount < 1 && config->rtjoinconfig != HB_JOIN_ANY) {
  401         ha_log(LOG_ERR, "no nodes defined");
  402         ++errcount;
  403     }
  404     if (config->authmethod == NULL) {
  405         ha_log(LOG_ERR, "No authentication specified.");
  406         ++errcount;
  407     }
  408     if (access(HOSTUUIDCACHEFILE, R_OK) >= 0) {
  409         if (read_cache_file(config) != HA_OK) {
  410             cl_log(LOG_ERR
  411             ,   "Invalid host/uuid map file [%s] - removed."
  412             ,   HOSTUUIDCACHEFILE);
  413             if (unlink(HOSTUUIDCACHEFILE) < 0) {
  414                 cl_perror("unlink(%s) failed"
  415                 ,   HOSTUUIDCACHEFILE);
  416             }
  417         }
  418         write_cache_file(config);
  419     }
  420     if ((curnode = lookup_node(localnodename)) == NULL) {
  421         if (config->rtjoinconfig == HB_JOIN_ANY) {
  422             add_normal_node(localnodename);
  423             curnode = lookup_node(localnodename);
  424             ha_log(LOG_NOTICE, "Current node [%s] added to configuration."
  425             ,   localnodename);
  426             write_cache_file(config);
  427         }else{
  428             ha_log(LOG_ERR, "Current node [%s] not in configuration!"
  429             ,   localnodename);
  430             ha_log(LOG_INFO, "By default, cluster nodes are named"
  431             " by `uname -n` and must be declared with a 'node'"
  432             " directive in the ha.cf file.");
  433             ha_log(LOG_INFO, "See also: " HAURL("Ha.cf#node_directive"));
  434             ++errcount;
  435         }
  436     }
  437     setenv(CURHOSTENV, localnodename, 1);
  438     if (config->deadtime_ms <= 2 * config->heartbeat_ms) {
  439         ha_log(LOG_ERR
  440         ,   "Dead time [%ld] is too small compared to keeplive [%ld]"
  441         ,   config->deadtime_ms, config->heartbeat_ms);
  442         ++errcount;
  443     }
  444     if (config->initial_deadtime_ms < 0) {
  445         char tmp[32];
  446         if (config->deadtime_ms > 10000) {
  447             config->initial_deadtime_ms = config->deadtime_ms;
  448         }else{
  449             if (config->deadtime_ms < 6000) {
  450                 config->initial_deadtime_ms = 12000;
  451             }else{
  452                 config->initial_deadtime_ms = 
  453                     2 * config->deadtime_ms;
  454             }
  455         }
  456         snprintf(tmp, sizeof(tmp), "%ldms"
  457         ,   config->initial_deadtime_ms);
  458         SetParameterValue(KEY_INITDEAD, tmp);
  459     }
  460 
  461     /* Check deadtime parameters */
  462     if (config->initial_deadtime_ms < config->deadtime_ms) {
  463         ha_log(LOG_ERR
  464         ,   "Initial dead time [%ld] is smaller than"
  465             " deadtime [%ld]"
  466         ,   config->initial_deadtime_ms, config->deadtime_ms);
  467         ++errcount;
  468     }else if (config->initial_deadtime_ms < 10000) {
  469         ha_log(LOG_WARNING, "Initial dead time [%ld ms] may be too small!"
  470         ,   config->initial_deadtime_ms);
  471         ha_log(LOG_INFO
  472         , "Initial dead time accounts for slow network startup time");
  473         ha_log(LOG_INFO
  474         , "It should be >= deadtime and >= 10 seconds");
  475     }
  476     if (config->deadping_ms < 0 ){
  477         char tmp[32];
  478         config->deadping_ms = config->deadtime_ms;
  479         snprintf(tmp, sizeof(tmp), "%ldms", config->deadping_ms);
  480         SetParameterValue(KEY_DEADPING, tmp);
  481     }else if (config->deadping_ms <= 2 * config->heartbeat_ms) {
  482         ha_log(LOG_ERR
  483         ,   "Ping dead time [%ld] is too small"
  484         " compared to keeplive [%ld]"
  485         ,   config->deadping_ms, config->heartbeat_ms);
  486         ++errcount;
  487     }
  488     if (GetParameterValue(KEY_UDPPORT) == NULL) {
  489         struct servent* service;
  490         int     tmpudpport;
  491         char        tmp[32];
  492         /* If our service name is in /etc/services, then use it */
  493         if ((service=getservbyname(HA_SERVICENAME, "udp")) != NULL){
  494             tmpudpport = ntohs(service->s_port);
  495         }else{
  496             tmpudpport = UDPPORT;
  497         }
  498         snprintf(tmp, (sizeof(tmp)-1), "%d", tmpudpport);
  499         SetParameterValue(KEY_UDPPORT, tmp);
  500     }
  501 
  502     if (!nice_failback && DoManageResources) {
  503         ha_log(LOG_WARNING
  504         ,   "Deprecated 'legacy' auto_failback option selected.");
  505         ha_log(LOG_WARNING
  506         ,   "Please convert to 'auto_failback on'.");
  507         ha_log(LOG_WARNING
  508         ,   "See documentation for conversion details.");
  509     }
  510 
  511     check_logd_usage(&errcount);
  512 
  513     /*
  514      * If we are supposed to use syslog,
  515      * and no logfiles have been set,
  516      * implicitly set to DEVNULL,
  517      * to override any default-if-unset
  518      * some stray script may have.
  519      */
  520     if (config->log_facility > 0) {
  521         if (*(config->logfile) == EOS)
  522             SetParameterValue(KEY_LOGFILE, DEVNULL);
  523         if (*(config->dbgfile) == EOS)
  524             SetParameterValue(KEY_DBGFILE, DEVNULL);
  525         }
  526     
  527     if ( !r1_style_valid()){
  528         errcount++;
  529     }
  530     
  531     if (!RestartRequested && errcount == 0 && !parse_only) {
  532         ha_log(LOG_INFO, "**************************");
  533         ha_log(LOG_INFO, "Configuration validated."
  534         " Starting heartbeat %s", VERSION);
  535     }
  536     for (j=0; j < config->nodecount; ++j) {
  537         config->nodes[j].has_resources = DoManageResources;
  538         if (config->nodes[j].nodetype == PINGNODE_I) {
  539             config->nodes[j].dead_ticks
  540             =   msto_longclock(config->deadping_ms);
  541         }else{
  542             config->nodes[j].dead_ticks
  543             =   msto_longclock(config->deadtime_ms);
  544         }
  545     }
  546 
  547     if (errcount == 0 && DoManageResources) {
  548         init_resource_module();
  549     }
  550     
  551     return(errcount ? HA_FAIL : HA_OK);
  552 }
  553 
  554 static void
  555 init_node_link_info(struct node_info *   node)
  556 {
  557     longclock_t cticks = time_longclock();
  558     int     j;
  559 
  560     if (node->nodetype == PINGNODE_I) {
  561         node->nlinks = 1;
  562         for (j=0; j < nummedia; j++) {
  563             struct link *lnk = &node->links[0];
  564             if (!sysmedia[j]->vf->isping()
  565             ||  strcmp(node->nodename
  566             ,   sysmedia[j]->name) != 0) {
  567                 continue;
  568             }
  569             lnk->name = node->nodename;
  570             lnk->lastupdate = cticks;
  571             strncpy(lnk->status, DEADSTATUS
  572             ,   sizeof(lnk->status));
  573             lnk[1].name = NULL;
  574             break;
  575         }
  576         return;
  577     }
  578     node->nlinks = 0;
  579     for (j=0; j < nummedia; j++) {
  580         int nc = node->nlinks;
  581         struct link *lnk = &node->links[nc];
  582         if (sysmedia[j]->vf->isping()) {
  583             continue;
  584         }
  585         lnk->name = sysmedia[j]->name;
  586         lnk->lastupdate = cticks;
  587         strncpy(lnk->status, DEADSTATUS, sizeof(lnk->status));
  588         lnk[1].name = NULL;
  589         ++node->nlinks;
  590     }
  591 }
  592 
  593 #if 0
  594 /*
  595  * This code does _not_ (permanently) affect the value of nummedia
  596  * This can be seen as an advantage, or a disadvantage ;-)
  597  * This 
  598  */
  599 
  600 static int
  601 create_medium(const char * directive, const char * optionstring, int mediaslot)
  602 {
  603     struct hb_media* mp = NULL;
  604     int         retval=1;
  605     char*           type;
  606     char*           descr;
  607     struct hb_media_fns*    funs;
  608 
  609     /* Load the medium plugin if its not already loaded... */
  610 
  611     if ((funs=g_hash_table_lookup(CommFunctions, directive)) == NULL) {
  612         if (PILPluginExists(PluginLoadingSystem
  613         ,   HB_COMM_TYPE_S, directive) == PIL_OK) {
  614             PIL_rc rc;
  615             if ((rc = PILLoadPlugin(PluginLoadingSystem
  616             ,   HB_COMM_TYPE_S, directive, NULL))
  617             !=  PIL_OK) {
  618                 ha_log(LOG_ERR, "Cannot load comm"
  619                 " plugin %s [%s]", directive
  620                 ,   PIL_strerror(rc));
  621             }
  622 
  623             funs=g_hash_table_lookup(CommFunctions
  624             ,   directive);
  625         }
  626     }else{
  627         PILIncrIFRefCount(PluginLoadingSystem
  628         ,   HB_COMM_TYPE_S, directive, +1);
  629     }
  630     if ((funs=g_hash_table_lookup(CommFunctions, directive)) == NULL) {
  631         return -1;
  632     }
  633 
  634     if (funs->new != NULL) {
  635         mp = funs->new(optionstring);
  636         if (mp) {
  637             sysmedia[mediaslot]=mp;
  638         }
  639     }else if (funs->parse)  {
  640         int savenummedia = nummedia;
  641         nummedia=mediaslot;
  642         if (funs->parse(optionstring) == HA_OK) {
  643             mp=NULL;
  644         }else{
  645             mp=sysmedia[mediaslot];
  646             nummedia=savenummedia;
  647             retval = (nummedia > mediaslot)? 1 : -1;
  648         }
  649     }
  650 
  651     funs->descr(&descr);
  652     funs->mtype(&type);
  653 
  654     if (mp == NULL) {
  655         ha_log(LOG_ERR, "Illegal %s [%s] in config file [%s]"
  656         ,   type, descr, optionstring);
  657         PILIncrIFRefCount(PluginLoadingSystem
  658         ,   HB_COMM_TYPE_S, directive, -1);
  659         /* By default, PILS modules use g_malloc and g_free */
  660         g_free(descr); descr = NULL;
  661         g_free(type);  type = NULL;
  662         return -1;
  663     }
  664     mp->vf =        funs;
  665     mp->type =      type;
  666     mp->description =   descr;
  667     g_assert(mp->type);
  668     g_assert(mp->description);
  669     g_assert(mp->type[0] != '(');
  670     g_assert(mp->description[0] != '(');
  671 
  672     if (!mp->name) {
  673         mp->name = strdup(directive);
  674     }
  675     PILIncrIFRefCount(PluginLoadingSystem
  676     ,   HB_COMM_TYPE_S, directive, +1);
  677 }
  678 #endif
  679 
  680 
  681 /*
  682  *  Parse the configuration file and stash away the data
  683  */
  684 static int
  685 parse_config(const char * cfgfile, char *nodename)
  686 {
  687     FILE    *   f;
  688     char        buf[MAXLINE];
  689     char *      cp;
  690     char        directive[MAXLINE];
  691     size_t      dirlength;
  692     char        option[MAXLINE];
  693     size_t      optionlength;
  694     int     errcount = 0;
  695     int     j;
  696     int     i;
  697     struct stat sbuf;
  698     struct DefServices {
  699         const char *    name;
  700         const char *    authspec;
  701     } defserv[] = 
  702     {   {"ipfail",  "uid=" HA_CCMUSER}
  703     ,   {"ccm",     "uid=" HA_CCMUSER}
  704     ,   {"ping",    "gid=" HA_APIGROUP}
  705     ,   {"lha-snmpagent","uid=root"}
  706     ,   {"anon",    "uid=root gid=" HA_APIGROUP}
  707     };
  708 
  709     if ((f = fopen(cfgfile, "r")) == NULL) {
  710         ha_log(LOG_ERR, "Cannot open config file [%s]", cfgfile);
  711         ha_log(LOG_INFO
  712         ,       "An annotated sample %s file is provided in"
  713         " the documentation."
  714         ,       cfgfile);
  715         ha_log(LOG_INFO
  716         ,       "Please copy it to %s, read it, customize it"
  717         ", and try again."
  718         ,       cfgfile);
  719 
  720         return(HA_FAIL);
  721     }
  722     APIAuthorization = g_hash_table_new(g_str_hash, g_str_equal);
  723 
  724     fstat(fileno(f), &sbuf);
  725     config->cfg_time = sbuf.st_mtime;
  726 
  727     /* It's ugly, but effective  */
  728 
  729     while (fgets(buf, MAXLINE, f) != NULL) {
  730         char *  bp = buf; 
  731         int IsOptionDirective=1;
  732         struct hb_media_fns*    funs = NULL;
  733 
  734         /* Skip over white space */
  735         bp += strspn(bp, WHITESPACE);
  736 
  737         /* Zap comments on the line */
  738         if ((cp = strchr(bp, COMMENTCHAR)) != NULL)  {
  739             *cp = EOS;
  740         }
  741 
  742         /* Strip '\n' and '\r' chars */
  743         if ((cp = strpbrk(bp, CRLF)) != NULL) {
  744             *cp = EOS;
  745         }
  746 
  747         /* Ignore blank (and comment) lines */
  748         if (*bp == EOS) {
  749             continue;
  750         }
  751 
  752         /* Now we expect a directive name */
  753 
  754         dirlength = strcspn(bp, WHITESPACE);
  755         strncpy(directive, bp, dirlength);
  756         directive[dirlength] = EOS;
  757 #ifdef DIRTYALIASKLUDGE
  758         if (strcmp(directive, "udp") == 0) {
  759             ha_log(LOG_WARNING
  760             ,   "WARNING: directive 'udp' replaced by 'bcast'");
  761             strncpy(directive, "bcast", sizeof("bcast"));
  762         }
  763 #endif
  764         if (!islegaldirective(directive)) {
  765             ha_log(LOG_ERR, "Illegal directive [%s] in %s"
  766             ,   directive, cfgfile);
  767             ++errcount;
  768             continue;
  769         }
  770 
  771         bp += dirlength;
  772 
  773         /* Skip over Delimiters */
  774         bp += strspn(bp, DELIMS);
  775 
  776         /* Load the medium plugin if its not already loaded... */
  777         if ((funs=g_hash_table_lookup(CommFunctions, directive))
  778         ==  NULL) {
  779             if (PILPluginExists(PluginLoadingSystem
  780             ,   HB_COMM_TYPE_S, directive) == PIL_OK) {
  781                 PIL_rc rc;
  782                 if ((rc = PILLoadPlugin(PluginLoadingSystem
  783                 ,   HB_COMM_TYPE_S, directive, NULL))
  784                 !=  PIL_OK) {
  785                     ha_log(LOG_ERR, "Cannot load comm"
  786                     " plugin %s [%s]", directive
  787                     ,   PIL_strerror(rc));
  788                     continue;
  789                 }
  790                 
  791                 funs=g_hash_table_lookup(CommFunctions
  792                 ,   directive);
  793             }
  794         }else{
  795             PILIncrIFRefCount(PluginLoadingSystem
  796             ,   HB_COMM_TYPE_S, directive, +1);
  797         }
  798 
  799 
  800         /* Check first for whole line media-type  directives */
  801         if (funs && funs->parse)  {
  802             int num_save = nummedia;
  803             IsOptionDirective=0;
  804             if (funs->parse(bp) != HA_OK) {
  805                 PILIncrIFRefCount(PluginLoadingSystem
  806                 ,   HB_COMM_TYPE_S, directive, -1);
  807                 errcount++;
  808                 *bp = EOS;  /* Stop parsing now */
  809                 continue;
  810             }
  811             sysmedia[num_save]->vf = funs;
  812             if(!sysmedia[num_save]->name) {
  813                 char *      pname = strdup(bp);
  814                 sysmedia[num_save]->name = pname;
  815             }
  816             funs->mtype(&sysmedia[num_save]->type);
  817             funs->descr(&sysmedia[num_save]->description);
  818             g_assert(sysmedia[num_save]->type);
  819             g_assert(sysmedia[num_save]->description);
  820             any_media_statements_yet = TRUE;
  821 
  822             *bp = EOS;
  823         }
  824 
  825         /* Check for "parse" type (whole line) directives */
  826 
  827         for (j=0; j < DIMOF(WLdirectives); ++j) {
  828             if (WLdirectives[j].parse == NULL)  {
  829                 continue;
  830             }
  831             if (strcmp(directive, WLdirectives[j].type) == 0) {
  832                 IsOptionDirective=0;
  833                 if (WLdirectives[j].parse(bp) != HA_OK) {
  834                     errcount++;
  835                 }
  836                 *bp = EOS;
  837                 any_media_statements_yet = TRUE;
  838             }
  839         }
  840         /* Now Check for  the options-list stuff */
  841         while (IsOptionDirective && *bp != EOS) {
  842             optionlength = strcspn(bp, DELIMS);
  843             strncpy(option, bp, optionlength);
  844             option[optionlength] = EOS;
  845             bp += optionlength;
  846             if (add_option(directive, option) != HA_OK) {
  847                 errcount++;
  848             }
  849 
  850             /* Skip over Delimiters */
  851             bp += strspn(bp, DELIMS);
  852         }
  853     }
  854 
  855     /* Provide default authorization information for well-known services */
  856     for (i=0; i < DIMOF(defserv); ++i) {
  857         char    buf[100];
  858         /* Allow users to override our defaults... */
  859         if (g_hash_table_lookup(APIAuthorization, defserv[i].name)
  860          == NULL) {
  861             snprintf(buf, sizeof(buf), "%s %s"
  862             ,   defserv[i].name
  863             ,   defserv[i].authspec);
  864             set_api_authorization(buf);
  865         }
  866     }
  867 
  868 
  869     for (i=0; i < config->nodecount; ++i) {
  870         /*
  871          * We need to re-do this now, after all the
  872          * media directives were parsed.
  873          */
  874         init_node_link_info(&config->nodes[i]);
  875     }
  876 
  877 
  878     fclose(f);
  879     return(errcount ? HA_FAIL : HA_OK);
  880 }
  881 
  882 /*
  883  *  Dump the configuration file - as a configuration file :-)
  884  *
  885  *  This does not include every directive at this point.
  886  */
  887 void
  888 dump_config(void)
  889 {
  890     int j;
  891     struct node_info *  hip;
  892 
  893 
  894     printf("#\n#    Linux-HA heartbeat configuration (on %s)\n#\n"
  895     ,   localnodename);
  896 
  897     printf("\n#---------------------------------------------------\n");
  898 
  899     printf("#\n#    HA configuration and status\n#\n");
  900 
  901     for (j=0; j < DIMOF(Directives); ++j) {
  902         const char *    v;
  903         if (!Directives[j].record_value
  904         ||  (v = GetParameterValue(Directives[j].name)) == NULL) {
  905             continue;
  906         }
  907         printf("%s\t%s", Directives[j].name, v);
  908         if (Directives[j].explanation) {
  909             printf("\t#\t%s", Directives[j].explanation);
  910         }
  911         printf("\n");
  912             
  913     }
  914 
  915     printf("#\n");
  916     printf("#\tHA Cluster nodes:\n");
  917     printf("#\n");
  918 
  919     for (j=0; j < config->nodecount; ++j) {
  920         hip = &config->nodes[j];
  921         printf("%s %s\t#\t current status: %s\n"
  922         ,   KEY_HOST
  923         ,   hip->nodename
  924         ,   hip->status);
  925     }
  926 
  927     printf("#\n");
  928     printf("#\tCommunications media:\n");
  929     for(j=0; j < nummedia; ++j) {
  930         g_assert(sysmedia[j]->type);
  931         g_assert(sysmedia[j]->description);
  932         puts("#");
  933         printf("# %s heartbeat channel -------------\n"
  934         ,   sysmedia[j]->description);
  935         printf("%s %s\n", sysmedia[j]->type
  936         ,   sysmedia[j]->name);
  937     }
  938     printf("#---------------------------------------------------\n");
  939 }
  940 
  941 
  942 /*
  943  *  Dump the default configuration file values for those directives that
  944  *  have them
  945  *
  946  *  This does not include every directive at this point.
  947  */
  948 void
  949 dump_default_config(int wikiout)
  950 {
  951     int     j, k, lmaxlen = 0, cmaxlen = 0, rmaxlen = 0;
  952     const char *    dashes = "----------------------------------------"
  953                  "----------------------------------------";
  954     const char *    lcolhdr = "Directive";
  955     const char *    ccolhdr = "Default";
  956     const char *    rcolhdr = "Description";
  957 
  958     /* First determine max name lens to help make things look nice */
  959     for (j=0; j < DIMOF(Directives); ++j) {
  960         struct directive * pdir = &Directives[j];
  961         if (pdir->defaultvalue != NULL) {
  962             if ((k = strlen(pdir->name)) > lmaxlen) {
  963                 lmaxlen = k;
  964             }
  965             if ((k = strlen(pdir->defaultvalue)) > cmaxlen) {
  966                 cmaxlen = k;
  967             }
  968             if ((pdir->explanation != NULL)
  969             && ((k = strlen(pdir->explanation)) > rmaxlen)) {
  970                 rmaxlen = k;
  971             }
  972         }
  973     }
  974 
  975     /* Don't do anything if there are no default values */
  976     if (!lmaxlen) {
  977         printf("There are no default values for ha.cf directives\n");
  978         return;
  979     }
  980 
  981     if (wikiout) {
  982         printf("##Put this output in the ha.cf/DefaultValues"
  983         " page\n");
  984         printf("The [wiki:ha.cf ha.cf] directives with default"
  985         " values are shown below - along with a brief description.\n");
  986         printf("This was produced by {{{heartbeat -DW}}}"
  987         " ''# (version %s)''\n\n"
  988         ,   VERSION);
  989 
  990         printf("||\'\'%s\'\'||\'\'%s\'\'||\'\'%s\'\'||\n"
  991         ,   lcolhdr, ccolhdr, rcolhdr);
  992 
  993         for (j=0; j < DIMOF(Directives); ++j) {
  994             char    WikiName[lmaxlen+1];
  995             char *  pch;
  996 
  997             if (Directives[j].defaultvalue) {
  998                 strcpy(WikiName, Directives[j].name);
  999                 WikiName[0] = toupper(WikiName[0]);
 1000 
 1001                 /* wiki convention is to remove underscores,
 1002                    slide chars to left, and capitalize */
 1003                 while ((pch = strchr(WikiName, '_')) != NULL) {
 1004                     char *pchplus1 = pch + 1;
 1005                     *pch = toupper(*pchplus1);
 1006                     while (*pchplus1) {
 1007                         *++pch = *++pchplus1;
 1008                     }
 1009                 }
 1010 
 1011                 printf("||[wiki:ha.cf/%sDirective"
 1012                 " %s]||%s||%s||\n"
 1013                 ,   WikiName
 1014                 ,   Directives[j].name
 1015                 ,   Directives[j].defaultvalue
 1016                 ,   Directives[j].explanation
 1017                 ?   Directives[j].explanation : "");
 1018             }
 1019         }
 1020     } else {
 1021         if ((k = strlen(lcolhdr)) > lmaxlen) {
 1022             lmaxlen = k;
 1023         }
 1024         if ((k = strlen(ccolhdr)) > cmaxlen) {
 1025             cmaxlen = k;
 1026         }
 1027         if ((k = strlen(rcolhdr)) > rmaxlen) {
 1028             rmaxlen = k;
 1029         }
 1030 
 1031         printf("%-*.*s  %-*.*s  %s\n", lmaxlen, lmaxlen, lcolhdr
 1032         ,   cmaxlen, cmaxlen, ccolhdr, rcolhdr);
 1033         /* this 4 comes from the pair of 2 blanks between columns */
 1034         printf("%-*.*s\n", (int)sizeof(dashes)
 1035         ,   lmaxlen + cmaxlen + rmaxlen + 4, dashes);
 1036 
 1037         for (j=0; j < DIMOF(Directives); ++j) {
 1038             if (Directives[j].defaultvalue) {
 1039                 printf("%-*.*s  %-*.*s  %s\n"
 1040                 ,   lmaxlen, lmaxlen
 1041                 ,   Directives[j].name
 1042                 ,   cmaxlen, cmaxlen
 1043                 ,   Directives[j].defaultvalue
 1044                 ,   Directives[j].explanation
 1045                 ?   Directives[j].explanation : "");
 1046             }
 1047         }
 1048     }
 1049 }
 1050 
 1051 
 1052 /*
 1053  *  Check the /etc/ha.d/haresources file
 1054  *
 1055  *  All we check for now is the set of node names.
 1056  *
 1057  *  It would be good to check the resource names, too...
 1058  *
 1059  *  And for that matter, to compute an md5 checksum of the haresources
 1060  *  file so we can complain if they're different.
 1061  */
 1062 int
 1063 parse_ha_resources(const char * cfgfile)
 1064 {
 1065     char        buf[MAXLINE];
 1066     struct stat sbuf;
 1067     int     rc = HA_OK;
 1068     FILE *      f;
 1069 
 1070     if ((f = fopen(cfgfile, "r")) == NULL) {
 1071         ha_log(LOG_ERR, "Cannot open resources file [%s]", cfgfile);
 1072         ha_log(LOG_INFO
 1073         ,       "An annotated sample %s file is provided in the"
 1074         " documentation.", cfgfile);
 1075         ha_log(LOG_INFO
 1076         ,       "Please copy it to %s, read it, customize it"
 1077         ", and try again."
 1078         ,       cfgfile);
 1079         return(HA_FAIL);
 1080     }
 1081 
 1082     fstat(fileno(f), &sbuf);
 1083     config->rsc_time = sbuf.st_mtime;
 1084     
 1085     while (fgets(buf, MAXLINE-1, f) != NULL) {
 1086         char *  bp = buf;
 1087         char *  endp;
 1088         char    token[MAXLINE];
 1089 
 1090         /* Skip over white space */
 1091         bp += strspn(bp, WHITESPACE);
 1092 
 1093         if (*bp == COMMENTCHAR) {
 1094             continue;
 1095         }
 1096         
 1097         if (*bp == EOS) {
 1098             continue;
 1099         }
 1100         endp = bp + strcspn(bp, WHITESPACE);
 1101         strncpy(token, bp, endp - bp);
 1102         token[endp-bp] = EOS;
 1103         if (lookup_node(token) == NULL) {
 1104             ha_log(LOG_ERR, "Bad nodename in %s [%s]", cfgfile
 1105             ,   token);
 1106             rc = HA_FAIL;
 1107             break;
 1108         }
 1109 
 1110         /*
 1111          * FIXME: Really ought to deal with very long lines
 1112          * correctly.
 1113          */
 1114         while (buf[strlen(buf)-2]=='\\') {
 1115             if (fgets(buf, MAXLINE-1, f)==NULL)
 1116                 break;
 1117         }
 1118     }
 1119     fclose(f);
 1120     return(rc);
 1121 }
 1122 
 1123 /*
 1124  *  Is this a legal directive name?
 1125  */
 1126 static int
 1127 islegaldirective(const char *directive)
 1128 {
 1129     int j;
 1130 
 1131     /*
 1132      * We have four kinds of directives to deal with:
 1133      *
 1134      *  1) Builtin directives which are keyword value value value...
 1135      *      "Directives[]"
 1136      *  2) Builtin directives which are one per line...
 1137      *      WLdirectives[]
 1138      *  3) media declarations which are media value value value
 1139      *      These are dynamically loaded plugins...
 1140      *      of type HBcomm
 1141      *  4) media declarations which are media rest-of-line
 1142      *      These are dynamically loaded plugins...
 1143      *      of type HBcomm
 1144      *
 1145      */
 1146     for (j=0; j < DIMOF(Directives); ++j) {
 1147         if (DEBUGDETAILS) {
 1148             ha_log(LOG_DEBUG
 1149             ,   "Comparing directive [%s] against [%s]"
 1150             ,    directive, Directives[j].name);
 1151         }
 1152 
 1153         if (strcmp(directive, Directives[j].name) == 0) {
 1154             return(HA_OK);
 1155         }
 1156     }
 1157     for (j=0; j < DIMOF(WLdirectives); ++j) {
 1158         if (DEBUGDETAILS) {
 1159             ha_log(LOG_DEBUG
 1160             , "Comparing directive [%s] against WLdirective[%s]"
 1161             ,    directive, WLdirectives[j].type);
 1162         }
 1163         if (strcmp(directive, WLdirectives[j].type) == 0) {
 1164             return(HA_OK);
 1165         }
 1166     }
 1167     if (PILPluginExists(PluginLoadingSystem,  HB_COMM_TYPE_S, directive)
 1168     == PIL_OK){
 1169         return HA_OK;
 1170     }
 1171     return(HA_FAIL);
 1172 }
 1173 
 1174 /*
 1175  *  Add the given option/value pair to the configuration
 1176  */
 1177 static int
 1178 add_option(const char * option, const char * value)
 1179 {
 1180     int j;
 1181     struct hb_media_fns*    funs = NULL;
 1182 
 1183     if (ANYDEBUG)  {
 1184         ha_log(LOG_DEBUG, "add_option(%s,%s)", option, value);
 1185     }
 1186 
 1187     for (j=0; j < DIMOF(Directives); ++j) {
 1188         if (strcmp(option, Directives[j].name) == 0) {
 1189             int rc;
 1190             rc = ((*Directives[j].add_func)(value));
 1191             if (rc == HA_OK && Directives[j].record_value) {
 1192                 SetParameterValue(option, value);
 1193             }
 1194             return rc;
 1195         }
 1196     }
 1197 
 1198     if ((funs=g_hash_table_lookup(CommFunctions, option)) != NULL
 1199         &&  funs->new != NULL) {
 1200         struct hb_media* mp = funs->new(value);
 1201         char*       type;
 1202         char*       descr;
 1203 
 1204         funs->descr(&descr);
 1205         funs->mtype(&type);
 1206 
 1207         if (nummedia >= MAXMEDIA) {
 1208             cl_log(LOG_ERR, "Too many media specified (> %d)"
 1209             ,   MAXMEDIA);
 1210             cl_log(LOG_INFO, "Offending command: %s %s"
 1211             ,   option, value);
 1212             return HA_FAIL;
 1213         }
 1214 
 1215         sysmedia[nummedia] = mp;
 1216         if (mp == NULL) {
 1217             ha_log(LOG_ERR, "Illegal %s [%s] in config file [%s]"
 1218             ,   type, descr, value);
 1219             PILIncrIFRefCount(PluginLoadingSystem
 1220             ,   HB_COMM_TYPE_S, option, -1);
 1221             /* Does this come from malloc? FIXME!! */
 1222             g_free(descr); descr = NULL;
 1223             g_free(type);  type = NULL;
 1224             return(HA_FAIL);
 1225         }else{
 1226             mp->type = type;
 1227             mp->description = descr;
 1228             g_assert(mp->type);
 1229             g_assert(mp->description);
 1230             g_assert(mp->type[0] != '(');
 1231             g_assert(mp->description[0] != '(');
 1232             mp->vf = funs;
 1233             if (!mp->name)
 1234                 mp->name = strdup(value);
 1235             ++nummedia;
 1236             PILIncrIFRefCount(PluginLoadingSystem
 1237             ,   HB_COMM_TYPE_S, option, +1);
 1238         }
 1239         g_assert(sysmedia[nummedia-1]->type);
 1240         g_assert(sysmedia[nummedia-1]->description);
 1241         return(HA_OK);
 1242     }
 1243     ha_log(LOG_ERR, "Illegal configuration directive [%s]", option);
 1244     return(HA_FAIL);
 1245 }
 1246 
 1247 
 1248 void 
 1249 dellist_destroy(void){
 1250     
 1251     GSList* list = del_node_list;
 1252 
 1253     while (list != NULL){
 1254         free(list->data);
 1255         list->data=NULL;
 1256         list= list->next;
 1257     }
 1258 
 1259     g_slist_free(del_node_list);
 1260     del_node_list = NULL;
 1261     return;
 1262 }
 1263 
 1264 static void
 1265 dellist_append(struct node_info* hip)
 1266 {
 1267     struct node_info* dup_hip;
 1268     
 1269     dup_hip = malloc(sizeof(struct node_info));
 1270     if (dup_hip == NULL){
 1271         cl_log(LOG_ERR, "%s: malloc failed",
 1272                __FUNCTION__);
 1273         return;
 1274     }
 1275 
 1276     memcpy(dup_hip, hip, sizeof(struct node_info));
 1277     
 1278     del_node_list = g_slist_append(del_node_list, dup_hip);
 1279     
 1280     
 1281 }
 1282 int 
 1283 dellist_add(const char* nodename){
 1284     struct node_info node;
 1285     int i;
 1286 
 1287     for (i=0; i < config->nodecount; i++){
 1288         if (strncmp(nodename, config->nodes[i].nodename,HOSTLENG) == 0){
 1289             dellist_append(&config->nodes[i]);
 1290             return HA_OK;
 1291         }
 1292     }
 1293     
 1294     memset(&node, 0, sizeof(struct node_info));
 1295     strncpy(node.nodename, nodename, HOSTLENG);
 1296     
 1297     dellist_append(&node);
 1298     return HA_OK;
 1299 }
 1300 
 1301 static gint
 1302 dellist_match(gconstpointer data, gconstpointer nodename)
 1303 {
 1304     const struct node_info* node = (const struct node_info*) data;
 1305     
 1306     if (data == NULL){
 1307         /* the list is empty,i.e. not found*/
 1308         return 1;
 1309     }
 1310     return strncasecmp(node->nodename,nodename, HOSTLENG);
 1311 }
 1312 
 1313 void
 1314 remove_from_dellist( const char* nodename)
 1315 {
 1316     GSList* listitem;
 1317     
 1318     listitem = g_slist_find_custom(del_node_list, nodename, dellist_match);
 1319     
 1320     if (listitem!= NULL){
 1321         if (listitem->data){
 1322             free(listitem->data);
 1323         }
 1324         del_node_list = g_slist_delete_link(del_node_list, listitem);
 1325     }
 1326     
 1327     return;
 1328     
 1329 }
 1330 
 1331 
 1332 
 1333 /*
 1334  * For reliability reasons, we should probably require nodename
 1335  * to be in /etc/hosts, so we don't lose our mind if (when) DNS goes out...
 1336  * This would also give us an additional sanity check for the config file.
 1337  *
 1338  * This is only the administrative interface, whose IP address never moves
 1339  * around.
 1340  */
 1341 
 1342 /* Process a node declaration */
 1343 int
 1344 add_node(const char * value, int nodetype)
 1345 {
 1346     struct node_info *  hip;
 1347     
 1348     if (config->nodecount >= MAXNODE) {
 1349         return(HA_FAIL);
 1350     }
 1351     
 1352     remove_from_dellist(value);
 1353     
 1354     hip = &config->nodes[config->nodecount];
 1355     memset(hip, 0, sizeof(*hip));
 1356     ++config->nodecount;
 1357     strncpy(hip->status, INITSTATUS, sizeof(hip->status));
 1358     strncpy(hip->nodename, value, sizeof(hip->nodename));
 1359     inplace_ascii_strdown(hip->nodename);
 1360     cl_uuid_clear(&hip->uuid);
 1361     hip->rmt_lastupdate = 0L;
 1362     hip->has_resources = TRUE;
 1363     hip->anypacketsyet  = 0;
 1364     hip->local_lastupdate = time_longclock();
 1365     hip->track.nmissing = 0;
 1366     hip->track.last_seq = NOSEQUENCE;
 1367     hip->track.ackseq = 0;
 1368     hip->weight = 100;
 1369     /* srand() done in init_config() already,
 1370      * and probably still too many places throughout the code */
 1371     hip->track.ack_trigger = rand()%ACK_MSG_DIV;
 1372     hip->nodetype = nodetype;
 1373     add_nametable(hip->nodename, hip);
 1374     init_node_link_info(hip);
 1375     if (nodetype == PINGNODE_I) {
 1376         hip->dead_ticks
 1377             =   msto_longclock(config->deadping_ms);
 1378     }else{
 1379         hip->dead_ticks
 1380             =   msto_longclock(config->deadtime_ms);
 1381     }
 1382     return(HA_OK);
 1383 }
 1384 
 1385 int 
 1386 set_node_weight(const char* value, int weight)
 1387 {
 1388     int i;
 1389     struct node_info * hip = NULL;
 1390 
 1391     if (value == NULL){
 1392         cl_log(LOG_ERR, "%s: invalid nodename",
 1393                __FUNCTION__);
 1394         return HA_FAIL;
 1395     }
 1396     
 1397     for (i = 0; i < config->nodecount; i++){
 1398         hip = &config->nodes[i];
 1399         if (strncasecmp(hip->nodename, value, sizeof(hip->nodename)) ==0){
 1400             break;
 1401         }
 1402     }
 1403 
 1404     if (i == config->nodecount){
 1405         cl_log(LOG_DEBUG,"set weight to non-existing node %s", value);
 1406         return HA_FAIL;
 1407     }
 1408     
 1409     hip->weight = weight;
 1410     return HA_OK;   
 1411 }
 1412 
 1413 int 
 1414 set_node_site(const char* value, const char* site)
 1415 {
 1416     int i;
 1417     struct node_info * hip = NULL;
 1418     
 1419     if (value == NULL){
 1420         cl_log(LOG_ERR, "%s: invalid nodename",
 1421                __FUNCTION__);
 1422         return HA_FAIL;
 1423     }
 1424     
 1425     for (i = 0; i < config->nodecount; i++){
 1426         hip = &config->nodes[i];
 1427         if (strncasecmp(hip->nodename, value, sizeof(hip->nodename)) ==0){
 1428             break;
 1429         }
 1430     }
 1431 
 1432     if (i == config->nodecount){
 1433         cl_log(LOG_DEBUG,"set site to non-existing node %s", value);
 1434         return HA_FAIL;
 1435     }
 1436     strncpy(hip->site, site, sizeof(hip->site));
 1437     return HA_OK;   
 1438 }
 1439 
 1440 int 
 1441 remove_node(const char* value, int deletion)
 1442 {
 1443     int i;
 1444     struct node_info *  hip = NULL;
 1445     int j;
 1446 
 1447     if (value == NULL){
 1448         cl_log(LOG_ERR, "%s: invalid nodename",
 1449                __FUNCTION__);
 1450         return HA_FAIL;
 1451     }
 1452     
 1453     for (i = 0; i < config->nodecount; i++){
 1454         hip = &config->nodes[i];
 1455         if (strncasecmp(hip->nodename, value, sizeof(hip->nodename)) ==0){
 1456             break;
 1457         }
 1458     }
 1459     
 1460 
 1461     if (i == config->nodecount){
 1462         if (deletion){
 1463             cl_log(LOG_DEBUG,"Adding node(%s) to deletion list", value);
 1464             dellist_add(value);
 1465         }   
 1466         
 1467         return HA_OK;
 1468     }
 1469 
 1470     
 1471     if (STRNCMP_CONST(hip->status, DEADSTATUS) != 0
 1472         && STRNCMP_CONST(hip->status, INITSTATUS) != 0){
 1473         cl_log(LOG_ERR, "%s: node %s is %s. Cannot remove alive node",
 1474                __FUNCTION__, value, hip->status);
 1475         return HA_FAIL;
 1476     }
 1477     
 1478     if (deletion){
 1479         cl_log(LOG_DEBUG,"Adding this node to deletion list");
 1480         dellist_append(hip);
 1481     }
 1482 
 1483     for (j = i; j < config->nodecount; j++){
 1484         memcpy(&config->nodes[j], &config->nodes[j + 1], 
 1485                sizeof(config->nodes[0]));
 1486     }
 1487     
 1488     config->nodecount -- ;
 1489 
 1490     tables_remove(hip->nodename, &hip->uuid);       
 1491     
 1492     curnode = lookup_node(localnodename);
 1493     if (!curnode){
 1494         cl_log(LOG_ERR, "localnode not found");
 1495     }
 1496 
 1497     return(HA_OK);  
 1498     
 1499 }
 1500 /* Set the name of cluster */
 1501 static int 
 1502 set_cluster_name(const char * value)
 1503 {
 1504     strncpy(config->cluster, value, PATH_MAX);
 1505     return(HA_OK);
 1506 }
 1507 /* Set the quorum server */
 1508 static int 
 1509 set_quorum_server(const char * value)
 1510 {
 1511     strncpy(config->cluster, value, PATH_MAX);
 1512     strncpy(config->quorum_server, value, PATH_MAX);
 1513     return(HA_OK);
 1514 }
 1515 
 1516 /* Process a node declaration */
 1517 static int
 1518 add_normal_node(const char * value)
 1519 {
 1520     return add_node(value, NORMALNODE_I);
 1521 }
 1522 
 1523 
 1524 
 1525 /* Set the hopfudge variable */
 1526 static int
 1527 set_hopfudge(const char * value)
 1528 {
 1529     config->hopfudge = atoi(value);
 1530 
 1531     if (config->hopfudge >= 0 && config->hopfudge < 256) {
 1532         return(HA_OK);
 1533     }
 1534     return(HA_FAIL);
 1535 }
 1536 
 1537 /* Set the keepalive time */
 1538 static int
 1539 set_keepalive_ms(const char * value)
 1540 {
 1541     config->heartbeat_ms = cl_get_msec(value);
 1542 
 1543     if (config->heartbeat_ms > 0) {
 1544         return(HA_OK);
 1545     }
 1546     return(HA_FAIL);
 1547 
 1548 }
 1549 
 1550 /* Set the dead timeout */
 1551 static int
 1552 set_deadtime_ms(const char * value)
 1553 {
 1554     config->deadtime_ms = cl_get_msec(value);
 1555     if (config->deadtime_ms >= 0) {
 1556         return(HA_OK);
 1557     }
 1558     return(HA_FAIL);
 1559 }
 1560 
 1561 /* Set the dead ping timeout */
 1562 static int
 1563 set_deadping_ms(const char * value)
 1564 {
 1565     config->deadping_ms = cl_get_msec(value);
 1566     if (config->deadping_ms >= 0) {
 1567         return(HA_OK);
 1568     }
 1569     return(HA_FAIL);
 1570 }
 1571 
 1572 /* Set the initial dead timeout */
 1573 static int
 1574 set_initial_deadtime_ms(const char * value)
 1575 {
 1576     config->initial_deadtime_ms = cl_get_msec(value);
 1577     if (config->initial_deadtime_ms >= 0) {
 1578         return(HA_OK);
 1579     }
 1580     return(HA_FAIL);
 1581 }
 1582 
 1583 /* Set the watchdog device */
 1584 static int
 1585 set_watchdogdev(const char * value)
 1586 {
 1587 
 1588     if (watchdogdev != NULL) {
 1589         fprintf(stderr, "%s: Watchdog device multiply specified.\n"
 1590         ,   cmdname);
 1591         return(HA_FAIL);
 1592     }
 1593     if ((watchdogdev = strdup(value)) == NULL) {
 1594         fprintf(stderr, "%s: Out of memory for watchdog device\n"
 1595         ,   cmdname);
 1596         return(HA_FAIL);
 1597     }
 1598     return(HA_OK);
 1599 }
 1600 
 1601 int
 1602 StringToBaud(const char * baudstr)
 1603 {
 1604     int baud;
 1605 
 1606     baud = atoi(baudstr);
 1607     switch(baud)  {
 1608         case 9600:  return  B9600;
 1609         case 19200: return  B19200;
 1610 #ifdef B38400
 1611         case 38400: return  B38400;
 1612 #endif
 1613 #ifdef B57600
 1614         case 57600: return  B57600;
 1615 #endif
 1616 #ifdef B115200
 1617         case 115200:    return  B115200;
 1618 #endif
 1619 #ifdef B230400
 1620         case 230400:    return  B230400;
 1621 #endif
 1622 #ifdef B460800
 1623         case 460800:    return  B460800;
 1624 #endif
 1625         default:    return 0;
 1626     }
 1627 }
 1628 
 1629 /*
 1630  * All we do here is *validate* the baudrate.
 1631  * This parameter is automatically recorded by SetParameterValue()
 1632  * for later use by the plugins.
 1633  */
 1634 static int
 1635 set_baudrate(const char * value)
 1636 {
 1637     static int  baudset = 0;
 1638     int     serial_baud =  0;
 1639     if (baudset) {
 1640         fprintf(stderr, "%s: Baudrate multiply specified.\n"
 1641         ,   cmdname);
 1642         return(HA_FAIL);
 1643     }
 1644     ++baudset;
 1645     serial_baud = StringToBaud(value);
 1646     if (serial_baud <= 0) {
 1647         fprintf(stderr, "%s: invalid baudrate [%s] specified.\n"
 1648         ,   cmdname, value);
 1649         return(HA_FAIL);
 1650     }
 1651     if (any_media_statements_yet) {
 1652         fprintf(stderr
 1653         ,   "%s: baudrate setting must precede media statements"
 1654         ,   cmdname);
 1655         
 1656     }
 1657     return(HA_OK);
 1658 }
 1659 
 1660 /*
 1661  * All we do here is *validate* the udpport number.
 1662  * This parameter is automatically recorded by SetParameterValue()
 1663  * for later use by the plugins.
 1664  */
 1665 static int
 1666 set_udpport(const char * value)
 1667 {
 1668     int     port = atoi(value);
 1669     struct servent* service;
 1670 
 1671     if (port <= 0) {
 1672         fprintf(stderr, "%s: invalid port [%s] specified.\n"
 1673         ,   cmdname, value);
 1674         return(HA_FAIL);
 1675     }
 1676 
 1677     /* Make sure this port isn't reserved for something else */
 1678     if ((service=getservbyport(htons(port), "udp")) != NULL) {
 1679         if (strcmp(service->s_name, HA_SERVICENAME) != 0) {
 1680             ha_log(LOG_WARNING
 1681             ,   "%s: udp port %s reserved for service \"%s\"."
 1682             ,   cmdname, value, service->s_name);
 1683         }
 1684     }
 1685     endservent();
 1686     fprintf(stderr
 1687     ,   "%s: udpport setting must precede media statements"
 1688     ,   cmdname);
 1689     return(HA_OK);
 1690 }
 1691 
 1692 /* set syslog facility config variable */
 1693 static int
 1694 set_facility(const char * value)
 1695 {
 1696     int     i;
 1697 
 1698     i = cl_syslogfac_str2int(value);
 1699     if (i >= 0) {
 1700         config->log_facility = i;
 1701         strncpy(config->facilityname, value,
 1702           sizeof(config->facilityname)-1);
 1703         config->facilityname[sizeof(config->facilityname)-1] = EOS;
 1704         cl_log_set_facility(config->log_facility);
 1705         return(HA_OK);
 1706     }else {
 1707         ha_log(LOG_ERR, "Log facility(%s) not valid", value);
 1708         return(HA_FAIL);
 1709     }
 1710 }
 1711 
 1712 /* set syslog facility config variable */
 1713 static int
 1714 set_dbgfile(const char * value)
 1715 {
 1716     strncpy(config->dbgfile, value, PATH_MAX);
 1717     cl_log_set_debugfile(config->dbgfile);
 1718     config->use_dbgfile = strcmp(value, DEVNULL);
 1719     return(HA_OK);
 1720 }
 1721 
 1722 /* set syslog facility config variable */
 1723 static int
 1724 set_logfile(const char * value)
 1725 {
 1726     strncpy(config->logfile, value, PATH_MAX);
 1727     cl_log_set_logfile(config->logfile);
 1728     config->use_logfile = strcmp(value, DEVNULL);
 1729     return(HA_OK);
 1730 }
 1731 
 1732 /* sets nice_failback behavior on/off */
 1733 static int
 1734 set_nice_failback(const char * value)
 1735 {
 1736     int rc;
 1737     int failback = 0;
 1738 
 1739     rc = cl_str_to_boolean(value, &failback);
 1740 
 1741     cl_log(LOG_ERR, "nice_failback flag is obsolete."
 1742     ". Use auto_failback {on, off, legacy} instead.");
 1743 
 1744     if (rc) {
 1745         if (nice_failback) {
 1746             cl_log(LOG_ERR
 1747             ,   "'%s %s' has been changed to '%s off'"
 1748             ,   KEY_FAILBACK, value, KEY_AUTOFAIL);
 1749             set_auto_failback("off");
 1750         }else{
 1751             cl_log(LOG_ERR
 1752             ,   "%s %s has been strictly interpreted as"
 1753             " '%s legacy'"
 1754             ,   KEY_FAILBACK, value, KEY_AUTOFAIL);
 1755             cl_log(LOG_ERR
 1756             ,   "Consider converting to '%s on'."
 1757             ,   KEY_AUTOFAIL);
 1758             cl_log(LOG_ERR
 1759             ,   "When you do, then you can use ipfail"
 1760             ", and hb_standby");
 1761             set_auto_failback("legacy");
 1762         }
 1763     }
 1764     cl_log(LOG_ERR, "See documentation for details.");
 1765     return rc;
 1766 }
 1767 
 1768 /* sets auto_failback behavior on/off */
 1769 static int
 1770 set_auto_failback(const char * value)
 1771 {
 1772     int rc;
 1773     rc = cl_str_to_boolean(value, &auto_failback);
 1774     if (rc == HA_FAIL) {
 1775         if (strcasecmp(value, "legacy") == 0) {
 1776             nice_failback = FALSE;
 1777             auto_failback = FALSE;
 1778             rc = HA_OK;
 1779         }
 1780     }else{
 1781         nice_failback = TRUE;
 1782     }
 1783     return rc;
 1784 }
 1785 
 1786 static int 
 1787 set_register_to_apphbd(const char * value)
 1788 {
 1789     return cl_str_to_boolean(value, &UseApphbd);
 1790 }
 1791 
 1792 
 1793 
 1794 /* Set warntime interval */
 1795 static int
 1796 set_warntime_ms(const char * value)
 1797 {
 1798     long    warntime;
 1799     warntime = cl_get_msec(value);
 1800 
 1801     if (warntime <= 0) {
 1802         fprintf(stderr, "Warn time [%s] is invalid.\n", value);
 1803         return(HA_FAIL);
 1804     }
 1805     config->warntime_ms = warntime;
 1806     return(HA_OK);
 1807 }
 1808 /*
 1809  * Set Stonith information
 1810  * 
 1811  * Expect a line that looks like:
 1812  * stonith <type> <configfile>
 1813  *
 1814  */
 1815 static int
 1816 set_stonith_info(const char * value)
 1817 {
 1818     const char *    vp = value;
 1819     const char *    evp;
 1820     Stonith *   s;
 1821     char        StonithType [MAXLINE];
 1822     char        StonithFile [MAXLINE];
 1823     size_t      tlen;
 1824     int     rc;
 1825 
 1826     vp += strspn(vp, WHITESPACE);
 1827     tlen = strcspn(vp, WHITESPACE);
 1828 
 1829     evp = vp + tlen;
 1830 
 1831     if (tlen < 1) {
 1832         ha_log(LOG_ERR, "No Stonith type given");
 1833         return(HA_FAIL);
 1834     }
 1835     if (tlen >= sizeof(StonithType)) {
 1836         ha_log(LOG_ERR, "Stonith type too long");
 1837         return(HA_FAIL);
 1838     }
 1839 
 1840     strncpy(StonithType, vp, tlen);
 1841     StonithType[tlen] = EOS;
 1842 
 1843     if ((s = stonith_new(StonithType)) == NULL) {
 1844         ha_log(LOG_ERR, "Invalid Stonith type [%s]", StonithType);
 1845         return(HA_FAIL);
 1846     }
 1847 
 1848     vp = evp + strspn(evp, WHITESPACE);
 1849     if (sscanf(vp, "%[^\r\n]",  StonithFile) <= 0) {
 1850     };
 1851 
 1852     switch ((rc=stonith_set_config_file(s, StonithFile))) {
 1853         case S_OK:
 1854             /* This will have to change to a list !!! */
 1855             config->stonith = s;
 1856             stonith_get_status(s);
 1857             return(HA_OK);
 1858 
 1859         case S_BADCONFIG:
 1860             ha_log(LOG_ERR, "Invalid Stonith config file [%s]"
 1861             ,   StonithFile);
 1862             break;
 1863         
 1864 
 1865         default:
 1866             ha_log(LOG_ERR, "Unknown Stonith config error [%s] [%d]"
 1867             ,   StonithFile, rc);
 1868             break;
 1869     }
 1870     return(HA_FAIL);
 1871 }
 1872 
 1873 
 1874 /*
 1875  * Set Stonith information
 1876  * 
 1877  * Expect a line that looks like:
 1878  * stonith_host <hostname> <type> <params...>
 1879  *
 1880  */
 1881 static int
 1882 set_stonith_host_info(const char * value)
 1883 {
 1884     const char *    vp = value; /* points to the current token */
 1885     const char *    evp;        /* points to the next token */
 1886     Stonith *   s;
 1887     char        StonithType [MAXLINE];
 1888     char        StonithHost [HOSTLENG];
 1889     size_t      tlen;
 1890     int     rc;
 1891     
 1892     vp += strspn(vp, WHITESPACE);
 1893     tlen = strcspn(vp, WHITESPACE);
 1894 
 1895     /* Save the pointer just past the hostname field */
 1896     evp = vp + tlen;
 1897 
 1898     /* Grab the hostname */
 1899     if (tlen < 1) {
 1900         ha_log(LOG_ERR, "No Stonith hostname argument given");
 1901         return(HA_FAIL);
 1902     }   
 1903     if (tlen >= sizeof(StonithHost)) {
 1904         ha_log(LOG_ERR, "Stonith hostname too long");
 1905         return(HA_FAIL);
 1906     }
 1907     strncpy(StonithHost, vp, tlen);
 1908     StonithHost[tlen] = EOS;
 1909     inplace_ascii_strdown(StonithHost);
 1910 
 1911     /* Verify that this host is valid to create this stonith
 1912      *  object.  Expect the hostname listed to match this host or '*'
 1913      */
 1914     
 1915     if (strcmp ("*", StonithHost) != 0 
 1916     &&  strcmp (localnodename, StonithHost)) {
 1917         /* This directive is not valid for this host */
 1918         return HA_OK;
 1919     }
 1920     
 1921     /* Grab the next field */
 1922     vp = evp + strspn(evp, WHITESPACE);
 1923     tlen = strcspn(vp, WHITESPACE);
 1924     
 1925     /* Save the pointer just past the stonith type field */
 1926     evp = vp + tlen;
 1927     
 1928     /* Grab the stonith type */
 1929     if (tlen < 1) {
 1930         ha_log(LOG_ERR, "No Stonith type given");
 1931         return(HA_FAIL);
 1932     }
 1933     if (tlen >= sizeof(StonithType)) {
 1934         ha_log(LOG_ERR, "Stonith type too long");
 1935         return(HA_FAIL);
 1936     }
 1937     
 1938     strncpy(StonithType, vp, tlen);
 1939     StonithType[tlen] = EOS;
 1940 
 1941     if ((s = stonith_new(StonithType)) == NULL) {
 1942         ha_log(LOG_ERR, "Invalid Stonith type [%s]", StonithType);
 1943         return(HA_FAIL);
 1944     }
 1945 
 1946     /* Grab the parameters list */
 1947     vp = evp;
 1948     vp += strspn(vp, WHITESPACE);
 1949     
 1950     switch ((rc=stonith_set_config_info(s, vp))) {
 1951         case S_OK:
 1952             /* This will have to change to a list !!! */
 1953             config->stonith = s;
 1954             stonith_get_status(s);
 1955             return(HA_OK);
 1956 
 1957         case S_BADCONFIG:
 1958             ha_log(LOG_ERR
 1959             ,   "Invalid Stonith configuration parameter [%s]"
 1960             ,   evp);
 1961             break;
 1962         
 1963 
 1964         default:
 1965             ha_log(LOG_ERR
 1966             ,   "Unknown Stonith config error parsing [%s] [%d]"
 1967             ,   evp, rc);
 1968             break;
 1969     }
 1970     return(HA_FAIL);
 1971 }
 1972 static int
 1973 set_realtime_prio(const char * value)
 1974 {
 1975 #ifdef _POSIX_PRIORITY_SCHEDULING
 1976     int foo;
 1977     foo = atoi(value);
 1978 
 1979     if (    foo < sched_get_priority_min(SCHED_FIFO)
 1980     ||  foo > sched_get_priority_max(SCHED_FIFO)) {
 1981         ha_log(LOG_ERR, "Illegal realtime priority [%s]", value);
 1982         return HA_FAIL;
 1983     }
 1984     hb_realtime_prio = foo;
 1985 #else
 1986     ha_log(LOG_WARNING
 1987     ,   "Realtime scheduling not supported on this platform.");
 1988 #endif
 1989     return HA_OK;
 1990 }
 1991 static int
 1992 set_generation_method(const char * value)
 1993 {
 1994     if (strcmp(value, "file") == 0) {
 1995         timebasedgenno = FALSE;
 1996         return HA_OK;
 1997     }
 1998     if (strcmp(value, "time") != 0) {
 1999         ha_log(LOG_ERR, "Illegal hb generation method [%s]", value);
 2000         return HA_FAIL;
 2001     }
 2002     timebasedgenno = TRUE;
 2003     return HA_OK;
 2004 }
 2005 static int
 2006 set_realtime(const char * value)
 2007 {
 2008     int ret = cl_str_to_boolean(value, &enable_realtime);
 2009     if (ret == HA_OK) {
 2010         if (enable_realtime) {
 2011             cl_enable_realtime();
 2012 #ifndef _POSIX_PRIORITY_SCHEDULING
 2013             ha_log(LOG_WARNING
 2014             ,   "Realtime scheduling not supported on this platform.");
 2015 #endif
 2016         }else{
 2017             cl_disable_realtime();
 2018         }
 2019     }
 2020     return ret;
 2021         
 2022 }
 2023 
 2024 static int
 2025 set_debuglevel(const char * value)
 2026 {
 2027     debug_level = atoi(value);
 2028     if (debug_level >= 0 && debug_level < 256) {
 2029         if (debug_level > 0) {
 2030             static char cdebug[8];
 2031             snprintf(cdebug, sizeof(debug_level), "%d", debug_level);
 2032             setenv(HADEBUGVAL, cdebug, TRUE);
 2033         }
 2034         return(HA_OK);
 2035     }
 2036     return(HA_FAIL);
 2037 }
 2038 
 2039 #ifdef ALLOWPOLLCHOICE
 2040 static int
 2041 set_normalpoll(const char * value)
 2042 {
 2043     int normalpoll=TRUE;
 2044     int ret = cl_str_to_boolean(value, &normalpoll);
 2045     if (ret == HA_OK) {
 2046         extern int UseOurOwnPoll;
 2047         UseOurOwnPoll = !normalpoll;
 2048     }
 2049     return ret;
 2050 }
 2051 #endif
 2052 static int
 2053 set_msgfmt(const char* value)
 2054 {
 2055     if( strcmp(value, "classic") ==0 ){
 2056         netstring_format = FALSE;
 2057         cl_set_msg_format(MSGFMT_NVPAIR);
 2058         return HA_OK;
 2059     }
 2060     if( strcmp(value,"netstring") == 0){
 2061         netstring_format = TRUE;
 2062         cl_set_msg_format(MSGFMT_NETSTRING);
 2063         return HA_OK;
 2064     }
 2065     
 2066     return HA_FAIL;
 2067 }
 2068 
 2069 static int
 2070 set_logdaemon(const char * value)
 2071 {
 2072     int rc;
 2073     int uselogd;
 2074     rc = cl_str_to_boolean(value, &uselogd);
 2075     
 2076     cl_log_set_uselogd(uselogd);
 2077     
 2078     if (!uselogd){
 2079         cl_log(LOG_WARNING, "Logging daemon is disabled --"
 2080                "enabling logging daemon is recommended");
 2081     }else{
 2082         cl_log(LOG_INFO, "Enabling logging daemon ");
 2083         cl_log(LOG_INFO, "logfile and debug file are those specified "
 2084                "in logd config file (default /etc/logd.cf)");
 2085     }
 2086     
 2087     return rc;
 2088 }
 2089 
 2090 static int
 2091 set_logdconntime(const char * value)
 2092 {
 2093     int logdtime;
 2094     logdtime = cl_get_msec(value);
 2095     
 2096     cl_log_set_logdtime(logdtime);
 2097     
 2098     if (logdtime > 0) {
 2099         return(HA_OK);
 2100     }
 2101     return(HA_FAIL);
 2102 
 2103 }
 2104 
 2105 static int
 2106 set_badpack_warn(const char* value)
 2107 {
 2108     int warnme = TRUE;
 2109     int rc;
 2110     rc = cl_str_to_boolean(value, &warnme);
 2111 
 2112     if (HA_OK == rc) {
 2113         cl_msg_quiet_fmterr = !warnme;
 2114     }
 2115     return rc;
 2116 }
 2117 
 2118 static int
 2119 add_client_child_base(const char * directive, gboolean failfast)
 2120 {
 2121     struct client_child*    child;
 2122     const char *        uidp;
 2123     const char *        cmdp;
 2124     char            chuid[64];
 2125     size_t          uidlen;
 2126     size_t          cmdlen;
 2127     size_t          pathlen;
 2128     char*           command;
 2129     char*           path;
 2130     struct passwd*      pw;
 2131 
 2132     if (ANYDEBUG) {
 2133         ha_log(LOG_INFO, "%s %s",
 2134             failfast ? KEY_FAILFAST : KEY_CLIENT_CHILD,
 2135             directive);
 2136     }
 2137 
 2138     /* Skip over initial white space, so we can get the uid */
 2139     uidp = directive;
 2140     uidp += strspn(uidp, WHITESPACE);
 2141     uidlen = strcspn(uidp, WHITESPACE);
 2142 
 2143     cmdp = uidp + uidlen+1;
 2144 
 2145     /* Skip over white space, find the command */
 2146     cmdp += strspn(cmdp, WHITESPACE);
 2147     cmdlen = strcspn(cmdp, CRLF);
 2148     pathlen = strcspn(cmdp, WHITESPACE);
 2149     
 2150     if (uidlen >= sizeof(chuid)) {
 2151         ha_log(LOG_ERR
 2152         ,   "UID specified for client child is too long");
 2153         return HA_FAIL;
 2154     }
 2155     memcpy(chuid, uidp, uidlen);
 2156     chuid[uidlen] = EOS;
 2157 
 2158     if ((pw = getpwnam(chuid)) == NULL) {
 2159         ha_log(LOG_ERR
 2160         ,   "Invalid uid [%s] specified for client child"
 2161         ,   chuid);
 2162         return HA_FAIL;
 2163     }
 2164 
 2165     if (*cmdp != '/') {
 2166         ha_log(LOG_ERR
 2167         ,   "Client child command [%s] is not full pathname"
 2168         ,   cmdp);
 2169         return HA_FAIL;
 2170     }
 2171 
 2172     command = malloc(cmdlen+1);
 2173     if (command == NULL) {
 2174         ha_log(LOG_ERR, "Out of memory in add_client_child (command)");
 2175         return HA_FAIL;
 2176     }
 2177     memcpy(command, cmdp, cmdlen);
 2178     command[cmdlen] = EOS;
 2179 
 2180     path = malloc(pathlen+1);
 2181     if (path == NULL) {
 2182         ha_log(LOG_ERR, "Out of memory in add_client_child "
 2183                 "(path)");
 2184         free(command); command=NULL;
 2185         return HA_FAIL;
 2186     }
 2187     memcpy(path, cmdp, pathlen);
 2188     path[pathlen] = EOS;
 2189 
 2190     if (access(path, X_OK|F_OK) < 0) {
 2191         ha_log(LOG_ERR
 2192         ,   "Client child command [%s] is not executable"
 2193         ,   path);
 2194         free(command); command=NULL;
 2195         free(path); path=NULL;
 2196         return HA_FAIL;
 2197     }
 2198 
 2199     child = MALLOCT(struct client_child);
 2200     if (child == NULL) {
 2201         ha_log(LOG_ERR, "Out of memory in add_client_child (child)");
 2202         free(command); command=NULL;
 2203         free(path); path=NULL;
 2204         return HA_FAIL;
 2205     }
 2206     memset(child, 0, sizeof(*child));
 2207     child->respawn = 1;
 2208     child->rebootifitdies = failfast;
 2209     child->u_runas = pw->pw_uid;
 2210     child->g_runas = pw->pw_gid;
 2211     child->command = command;
 2212     child->path = path;
 2213     config->client_list = g_list_append(config->client_list, child);
 2214     config->last_client = g_list_last(config->client_list);
 2215 
 2216     return HA_OK;
 2217 }
 2218 static int
 2219 add_client_child(const char * directive)
 2220 {
 2221     return add_client_child_base(directive, FALSE);
 2222 }
 2223 static int
 2224 add_failfast_child(const char * directive)
 2225 {
 2226     return add_client_child_base(directive, TRUE);
 2227 }
 2228 
 2229 static int
 2230 set_compression(const char * directive)
 2231 {       
 2232     return cl_set_compress_fns(directive);
 2233 }
 2234 
 2235 static int
 2236 set_compression_threshold(const char * value)
 2237 {       
 2238     int threshold = atoi(value);
 2239     
 2240     if (threshold <=0){
 2241         cl_log(LOG_ERR, "%s: compress_threshhold(%s)"
 2242                " invalid",
 2243                __FUNCTION__,
 2244                value);
 2245         return HA_FAIL;
 2246     }
 2247 
 2248     cl_set_compression_threshold(threshold *1024);
 2249     
 2250     return HA_OK;
 2251 }
 2252 
 2253 
 2254 static int
 2255 set_traditional_compression(const char * value)
 2256 {       
 2257     int result;
 2258 
 2259     if (value == NULL){
 2260         cl_log(LOG_ERR, "%s: NULL pointer",
 2261                __FUNCTION__);
 2262         return HA_FAIL;
 2263     }
 2264     if (cl_str_to_boolean(value, &result)!= HA_OK){
 2265         cl_log(LOG_ERR, "%s:Invalid directive value %s", 
 2266                __FUNCTION__,value);
 2267         return HA_FAIL;
 2268     }
 2269     
 2270     cl_set_traditional_compression(result);
 2271     
 2272     return HA_OK;
 2273 }
 2274 
 2275 static int
 2276 set_env(const char * nvpair)
 2277 {       
 2278 
 2279     int nlen;
 2280     int vlen;
 2281     char* env_name;
 2282     char*   value;
 2283 
 2284     nlen = strcspn(nvpair, "=");
 2285     if (nlen >= MAXLINE || nlen <=0){
 2286         cl_log(LOG_ERR, "%s: invalid nvpair(%s)",
 2287                __FUNCTION__, nvpair);
 2288         return HA_FAIL;
 2289     }
 2290     
 2291     env_name = malloc(nlen + 4);
 2292     if (env_name == NULL){
 2293         cl_log(LOG_ERR, "%s: malloc failed",
 2294                __FUNCTION__);
 2295         return HA_FAIL;
 2296     }
 2297     
 2298     memcpy(env_name, "HA_", 3);
 2299     memcpy(env_name + 3, nvpair, nlen);
 2300     env_name[nlen + 3] = 0;
 2301     
 2302     vlen = strlen(nvpair + nlen + 1);
 2303     if (vlen >= MAXLINE || nlen <=0){
 2304         cl_log(LOG_ERR, "%s: invalid value(%s)",
 2305                __FUNCTION__, nvpair);
 2306         return HA_FAIL;
 2307     }
 2308     
 2309     value = malloc(vlen + 1);
 2310     if (value == NULL){
 2311         cl_log(LOG_ERR, "%s: malloc failed for value",
 2312                __FUNCTION__);
 2313         return HA_FAIL;
 2314     }   
 2315     memcpy(value, nvpair+nlen +1  , vlen);
 2316     value[vlen] = 0;
 2317     /*
 2318      * It is unclear whether any given version of setenv
 2319      * makes a copy of the name or value, or both.
 2320      * Therefore it is UNSAFE to free either one.
 2321      * Fortunately the size of the resulting potential memory leak
 2322      * is small for this particular situation.
 2323      */
 2324     setenv(env_name, value, 1);
 2325     if (ANYDEBUG){
 2326         cl_log(LOG_DEBUG, "setting env(%s=%s), nvpair(%s)", env_name, value,nvpair);
 2327     }
 2328     
 2329     return HA_OK;
 2330 }
 2331 static int
 2332 set_max_rexmit_delay(const char * value)
 2333 {
 2334     int foo;
 2335 
 2336     foo =  atoi(value);
 2337     if (foo <= 0){
 2338         cl_log(LOG_ERR, "Invalid max_rexmit_delay time(%s)",
 2339                value);
 2340         return HA_FAIL;
 2341     }
 2342     
 2343     hb_set_max_rexmit_delay(foo);
 2344 
 2345     return HA_OK;
 2346 }
 2347 
 2348 #if 0
 2349 static void
 2350 id_table_dump(gpointer key, gpointer value, gpointer user_data)
 2351 {
 2352     unsigned int    ikey = GPOINTER_TO_UINT(key);
 2353 
 2354     cl_log(LOG_DEBUG, "%s %u"
 2355     ,   (const char *)user_data, ikey);
 2356     if (value == NULL) {
 2357         cl_log(LOG_ERR, "Key %u has NULL data!!", ikey);
 2358     }
 2359 }
 2360 
 2361 static void
 2362 dump_auth_tables(struct IPC_AUTH* auth, const char * clientname)
 2363 {
 2364     char    uid [] = "uid = ";
 2365     char    gid [] = "gid = ";
 2366 
 2367 
 2368     if (auth->uid ) {
 2369         cl_log(LOG_DEBUG, "Dumping uid authorization info for client %s"
 2370         ,   clientname);
 2371         g_hash_table_foreach(auth->uid, id_table_dump, uid);
 2372     }
 2373     if (auth->gid) {
 2374         cl_log(LOG_DEBUG, "Dumping gid authorization info for client %s"
 2375         ,   clientname);
 2376         g_hash_table_foreach(auth->gid, id_table_dump, gid);
 2377     }
 2378 }
 2379 #endif
 2380 
 2381 
 2382 
 2383 /*
 2384  * apiauth client-name gid=gidlist uid=uidlist
 2385  *
 2386  * Record API permissions for use in API client authorization
 2387  */
 2388 
 2389 static int
 2390 set_api_authorization(const char * directive)
 2391 {
 2392     const char *        bp;
 2393     const char *        client;
 2394     int         clientlen;
 2395     const char *        gidlist = NULL;
 2396     int         gidlen = 0;
 2397     const char *        uidlist = NULL;
 2398     int         uidlen = 0;
 2399     struct IPC_AUTH*    auth = NULL;
 2400     char*           clname = NULL;
 2401     client_proc_t   dummy;
 2402     
 2403 
 2404     /* String processing in 'C' is *so* ugly...   */
 2405     
 2406     /* Skip over any initial white space -- to the client name */
 2407     bp = directive;
 2408     bp += strspn(bp, WHITESPACE);
 2409     if (*bp == EOS) {
 2410         goto baddirective;
 2411     }
 2412     client = bp;
 2413     clientlen = strcspn(bp, WHITESPACE);
 2414 
 2415     if (clientlen <= 0) {
 2416         goto baddirective;
 2417     }
 2418     if (clientlen >= (int)sizeof(dummy.client_id)) {
 2419         cl_log(LOG_ERR, "client name [%*s] too long"
 2420         ,   clientlen, client);
 2421         goto baddirective;
 2422     }
 2423     clname = malloc(clientlen+1);
 2424     if (clname == NULL) {
 2425         cl_log(LOG_ERR, "out of memory for client name");
 2426         goto baddirective;
 2427     }
 2428     strncpy(clname, client, clientlen);
 2429     clname[clientlen] = EOS;
 2430 
 2431     bp += clientlen;
 2432 
 2433     bp += strspn(bp, WHITESPACE);
 2434 
 2435     while (*bp != EOS) {
 2436 
 2437         bp += strspn(bp, WHITESPACE);
 2438 
 2439         if (strncmp(bp, "uid=", 4) == 0) {
 2440             if (uidlist != NULL) {
 2441                 cl_log(LOG_ERR 
 2442                 ,   "Duplicate uid list in " KEY_APIPERM);
 2443                 goto baddirective;
 2444             }
 2445             bp += 4;
 2446             uidlist=bp;
 2447             uidlen = strcspn(bp, WHITESPACE);
 2448             bp += uidlen;
 2449         }else if (strncmp(bp, "gid=", 4) == 0) {
 2450             if (gidlist != NULL) {
 2451                 cl_log(LOG_ERR 
 2452                 ,   "Duplicate gid list in " KEY_APIPERM);
 2453                 goto baddirective;
 2454             }
 2455             bp += 4;
 2456             gidlist=bp;
 2457             gidlen = strcspn(bp, WHITESPACE);
 2458             bp += gidlen;
 2459         }else if (*bp != EOS) {
 2460             cl_log(LOG_ERR 
 2461             ,   "Missing uid or gid in " KEY_APIPERM);
 2462             goto baddirective;
 2463         }
 2464     }
 2465 
 2466     if (uidlist == NULL && gidlist == NULL) {
 2467         goto baddirective;
 2468     }
 2469 
 2470     if (ANYDEBUG) {
 2471         cl_log(LOG_DEBUG, "%s %s uid=%s, gid=%s"
 2472         ,   KEY_APIPERM, clname
 2473         ,   (uidlist == NULL ? "<null>" : uidlist)
 2474         ,   (gidlist == NULL ? "<null>" : gidlist));
 2475     }
 2476     auth = ipc_str_to_auth(uidlist, uidlen, gidlist, gidlen);
 2477     if (auth == NULL){
 2478         goto baddirective;
 2479     }
 2480 
 2481     if (g_hash_table_lookup(APIAuthorization, clname) != NULL) {
 2482         cl_log(LOG_ERR
 2483         ,   "Duplicate %s directive for API client %s: [%s]"
 2484         ,   KEY_APIPERM, clname, directive);
 2485         goto baddirective;
 2486     }
 2487     g_hash_table_insert(APIAuthorization, clname, auth);
 2488     if (DEBUGDETAILS) {
 2489         cl_log(LOG_DEBUG
 2490         ,   "Creating authentication: uidptr=0x%lx gidptr=0x%lx"
 2491         ,   (unsigned long)auth->uid, (unsigned long)auth->gid);
 2492     }
 2493     
 2494     return HA_OK;
 2495     
 2496  baddirective:
 2497     cl_log(LOG_ERR, "Invalid %s directive [%s]", KEY_APIPERM, directive);
 2498     cl_log(LOG_INFO, "Syntax: %s client [uid=uidlist] [gid=gidlist]"
 2499     ,   KEY_APIPERM);
 2500     cl_log(LOG_INFO, "Where uidlist is a comma-separated list of uids,");
 2501     cl_log(LOG_INFO, "and gidlist is a comma-separated list of gids");
 2502     cl_log(LOG_INFO, "One or the other must be specified.");
 2503     if (auth != NULL) {
 2504         if (auth->uid) {
 2505             /* Ought to destroy the strings too */
 2506             g_hash_table_destroy(auth->uid);
 2507             auth->uid = NULL;
 2508         }
 2509         if (auth->gid) {
 2510             /* Ought destroy the strings too */
 2511             g_hash_table_destroy(auth->gid);
 2512             auth->gid = NULL;
 2513         }
 2514         memset(auth, 0, sizeof(*auth));
 2515         free(auth);
 2516         auth = NULL;
 2517     }
 2518     if (clname) {
 2519         free(clname);
 2520         clname = NULL;
 2521     }
 2522     return HA_FAIL;
 2523 
 2524 }
 2525 
 2526 static int
 2527 set_coredump(const char* value)
 2528 {
 2529     gboolean    docore;
 2530     int     rc;
 2531     if ((rc = cl_str_to_boolean(value, &docore)) == HA_OK) {
 2532         if (cl_enable_coredumps(docore) < 0 ) {
 2533             rc = HA_FAIL;
 2534         }
 2535     }
 2536     return rc;
 2537 }
 2538 static int
 2539 set_syslog_logfilefmt(const char * value)
 2540 {
 2541     gboolean    dosyslogfmt = HA_OK;
 2542     int     rc;
 2543     if ((rc = cl_str_to_boolean(value, &dosyslogfmt)) == HA_OK) {
 2544         cl_log_enable_syslog_filefmt(dosyslogfmt);
 2545     }
 2546     return rc;
 2547 }
 2548 
 2549 static int
 2550 set_corerootdir(const char* value)
 2551 {
 2552     if (cl_set_corerootdir(value) < 0) {
 2553         cl_perror("Invalid core directory [%s]", value);
 2554         return HA_FAIL;
 2555     }
 2556     return HA_OK;
 2557 }
 2558 
 2559 static int fail_if_after_pacemaker(const char *directive)
 2560 {
 2561     if (GetParameterValue(KEY_PACEMAKER)) {
 2562         cl_log(LOG_ERR, "If you specify %s, it must come before the %s directive\n",
 2563             directive, KEY_PACEMAKER);
 2564         return HA_FAIL;
 2565     }
 2566     return HA_OK;
 2567 }
 2568 
 2569 static int
 2570 set_crm_daemon_dir(const char* value)
 2571 {
 2572     if (fail_if_after_pacemaker(value))
 2573         return HA_FAIL;
 2574     /* Nothing more to do here; add_option() will add it
 2575      * to the parameters hash table, that is good enough. */
 2576     return HA_OK;
 2577 }
 2578 
 2579 static int set_pengine_by_crm(const char* value)
 2580 {
 2581     if (HA_OK != fail_if_after_pacemaker(value))
 2582         return HA_FAIL;
 2583     return ha_config_check_boolean(value);
 2584 }
 2585 
 2586 /*
 2587  *  Enable all these flags when  KEY_PACEMAKER is enabled...
 2588  *  apiauth lrmd        uid=root
 2589  *  apiauth stonithd    uid=root
 2590  *  apiauth stonith-ng  uid=root
 2591  *  apiauth crmd        uid=hacluster
 2592  *  apiauth cib     uid=hacluster
 2593  *  respawn root        /usr/lib/heartbeat/lrmd
 2594  *  respawn root        /usr/lib/heartbeat/stonithd
 2595  *  respawn hacluster       /usr/lib/heartbeat/ccm
 2596  *  respawn hacluster       /usr/lib/heartbeat/cib
 2597  *  respawn hacluster       /usr/lib/heartbeat/crmd
 2598  */
 2599 
 2600 enum pcmk_directive_value { OFF = 0, AUTO = 1, MINIMAL, RESPAWN, VALGRIND, CCM_ONLY };
 2601 
 2602 struct pcmk_child {
 2603     const gboolean skip_if_minimal;
 2604     const gboolean use_valgrind_on_request;
 2605     const gboolean failfast[5];
 2606     const char *user;
 2607     const gboolean try_crm_daemon_dir_first;
 2608     const char *command;
 2609     const char *hb_args;
 2610     /* const char *pcmk_args; */
 2611 };
 2612 
 2613 static char *path_command_ok(const char *path, const char *basename)
 2614 {
 2615     char *command;
 2616     int c;
 2617 
 2618     ha_log(LOG_DEBUG, "Checking access of: %s/%s", path, basename);
 2619     c = asprintf(&command, "%s/%s", path, basename);
 2620     if (c < 0)
 2621         return NULL;
 2622 
 2623     if (access(command, X_OK) < 0) {
 2624         free(command);
 2625         command = NULL;
 2626     }
 2627     return command;
 2628 }
 2629 
 2630 static int add_pcmk_client_child(struct pcmk_child *p, enum pcmk_directive_value onoff)
 2631 {
 2632     char *fake_directive = NULL;
 2633     char *command = NULL;
 2634     const char *args = NULL;
 2635     const char *valgrind = NULL;
 2636     const char *crm_daemon_dir;
 2637     int failfast_index = onoff - 1;
 2638     int c;
 2639 
 2640     if (failfast_index >= DIMOF(p->failfast))
 2641         return HA_FAIL;
 2642 
 2643     crm_daemon_dir = GetParameterValue(KEY_CRM_DAEMON_DIR) ?: CRM_DAEMON_DIR;
 2644 
 2645     if (p->try_crm_daemon_dir_first)
 2646         command = path_command_ok(crm_daemon_dir, p->command);
 2647     if (!command) {
 2648         /* Not started from pacemaker directory, use the "hb_args".
 2649          * Right now only used for lrmd. */
 2650         args = p->hb_args;
 2651         command = path_command_ok(HA_DAEMON_DIR, p->command);
 2652 
 2653         /* lrmd may still not be found. Try the historical location as well. */
 2654         if (!command)
 2655             command = path_command_ok(HA_LIBHBDIR, p->command);
 2656         if (!command) {
 2657             ha_log(LOG_ERR, "Failed to add pacemaker client child \"%s\"", p->command);
 2658             return HA_FAIL;
 2659         }
 2660     }
 2661     if (p->use_valgrind_on_request && onoff == VALGRIND)
 2662         valgrind = VALGRIND_BIN;
 2663 
 2664     c = asprintf(&fake_directive,
 2665             "%s %s %s%s%s", p->user,
 2666             valgrind ?: "",
 2667             command,
 2668             args ? " " : "", args ?: "");
 2669     free(command);
 2670     command = NULL;
 2671 
 2672     if (c < 0)
 2673         return HA_FAIL;
 2674 
 2675     c = add_client_child_base(fake_directive, p->failfast[failfast_index]);
 2676     free(fake_directive);
 2677 
 2678     return c;
 2679 }
 2680 
 2681 static int
 2682 set_release2mode(const char* value)
 2683 {
 2684     /* alias KEY_REL2 to KEY_PACEMAKER */
 2685     return add_option(KEY_PACEMAKER, value);
 2686 }
 2687 
 2688 static int
 2689 set_pcmk_support(const char *value)
 2690 {
 2691     /* CCM apiauth already implicit elsewhere.
 2692      * LRMd is not a heartbeat API client.
 2693      * Stonith "NG" registered (for some pacemaker versions) as stonith-ng,
 2694      * but the name of the binary is still the same: stonithd. */
 2695 
 2696     const char *api_auth[] = {
 2697         "cib        uid=" HA_CCMUSER,
 2698         "crmd       uid=" HA_CCMUSER,
 2699 
 2700         /* break if minimal */
 2701         "stonithd   uid=root",
 2702         "stonith-ng uid=root",
 2703         "attrd      uid=" HA_CCMUSER,
 2704         "pingd      uid=root"
 2705     };
 2706 
 2707     /* Note: order matters. Started in order, stopped in reverse.
 2708      * CRMD must be last, which means it will be stopped first.
 2709      * For "best practices" start order,
 2710      * see pacemaker:mcp/pacemaker.c, pcmk_children[]
 2711      */
 2712     struct pcmk_child pcmk_children[] = {
 2713         { 0, 0, { 1, 1, 0, 0, 0 }, HA_CCMUSER, FALSE, "ccm",       },
 2714 
 2715         { 0, 1, { 1, 1, 0, 0, 0 }, HA_CCMUSER, TRUE,  "cib",       },
 2716         { 1, 0, { 0, 0, 0, 0, 0 }, "root",     TRUE,  "stonithd",  },
 2717         { 0, 0, { 0, 0, 0, 0, 0 }, "root",     TRUE,  "lrmd", "-r" },
 2718         { 1, 1, { 0, 0, 0, 0, 0 }, HA_CCMUSER, TRUE,  "attrd",     },
 2719         { 1, 1, { 1, 1, 0, 0, 0 }, HA_CCMUSER, TRUE,  "pengine",   },
 2720         { 0, 1, { 1, 1, 0, 0, 0 }, HA_CCMUSER, TRUE,  "crmd",      },
 2721         /* Don't 'respawn' pingd - it's a resource agent */
 2722     };
 2723     const int pengine_idx = 5; /* see above */
 2724 
 2725     enum pcmk_directive_value pcmk_directive;
 2726     int rc;
 2727     int j;
 2728     gboolean crmd_spawns_pengine = TRUE;
 2729     gboolean pacemaker_on;
 2730 
 2731     static gboolean already_called = FALSE;
 2732 
 2733     if (already_called) {
 2734         /* pacemaker directive can appear only *once* */
 2735         cl_log(LOG_ERR, "pacemaker/crm directive used multiple times!");
 2736         return HA_FAIL;
 2737     }
 2738     already_called = TRUE;
 2739 
 2740     cl_log(LOG_INFO, "Pacemaker support: %s", value);
 2741     if (!strcasecmp("minimal", value) || !strcasecmp("manual", value)) {
 2742         pcmk_directive = MINIMAL;
 2743     } else if (!strcasecmp("respawn", value)) {
 2744         pcmk_directive = RESPAWN;
 2745     } else if (!strcasecmp("ccm-only", value)) {
 2746         pcmk_directive = CCM_ONLY;
 2747     } else if (!strcasecmp("valgrind", value)) {
 2748         pcmk_directive = VALGRIND;
 2749         setenv("HA_VALGRIND_ENABLED", "1", 1);
 2750         cl_log(LOG_INFO, "Enabling Valgrind on selected components");
 2751     } else if ((rc = cl_str_to_boolean(value, &pacemaker_on)) == HA_OK) {
 2752         if (!pacemaker_on)
 2753             return HA_OK;
 2754         pcmk_directive = AUTO;
 2755     } else {
 2756         return rc;
 2757     }
 2758 
 2759     DoManageResources = FALSE;
 2760     setenv("HA_cluster_type", "heartbeat", 1);
 2761 
 2762     if (cl_file_exists(RESOURCE_CFG)) {
 2763         cl_log(LOG_WARNING, "File %s exists.", RESOURCE_CFG);
 2764         cl_log(LOG_WARNING, "This file is not used because "KEY_PACEMAKER" is enabled");
 2765     }
 2766 
 2767     for (j = 0; j < DIMOF(api_auth); j++) {
 2768         if (pcmk_directive == MINIMAL && j == 2)
 2769             break;
 2770         if (set_api_authorization(api_auth[j]) == HA_OK)
 2771             continue;
 2772         cl_log(LOG_ERR, "failed: apiauth %s", api_auth[j]);
 2773         return HA_FAIL;
 2774     }
 2775 
 2776     cl_str_to_boolean(GetParameterValue(KEY_PENGINE_BY_CRM), &crmd_spawns_pengine);
 2777     for (j = 0; j < DIMOF(pcmk_children); ++j) {
 2778         struct pcmk_child *p = &pcmk_children[j];
 2779         /* In CCM_ONLY mode, pacemakerd is supposed to be started from its
 2780          * own init script, and will then start all of its daemons
 2781          * itself.
 2782          * (Or you may specify explicit failfast/respawn directives) */
 2783         if (pcmk_directive == CCM_ONLY && j > 0)
 2784             break;
 2785         if (pcmk_directive == MINIMAL && p->skip_if_minimal)
 2786             continue;
 2787         if (j == pengine_idx && crmd_spawns_pengine)
 2788             continue;
 2789         if (HA_OK != add_pcmk_client_child(p, pcmk_directive))
 2790             return HA_FAIL;
 2791     }
 2792     return HA_OK;
 2793 }
 2794 
 2795 static int
 2796 set_autojoin(const char* value)
 2797 {
 2798     if (strcasecmp(value, "none") == 0) {
 2799         config->rtjoinconfig = HB_JOIN_NONE;
 2800         return HA_OK;
 2801     }
 2802     if (strcasecmp(value, "other") == 0) {
 2803         config->rtjoinconfig = HB_JOIN_OTHER;
 2804         return HA_OK;
 2805     }
 2806     if (strcasecmp(value, "any") == 0) {
 2807         config->rtjoinconfig = HB_JOIN_ANY;
 2808         return HA_OK;
 2809     }
 2810     cl_log(LOG_ERR, "Invalid %s directive [%s]", KEY_AUTOJOIN, value);
 2811     return HA_FAIL;
 2812 }
 2813 
 2814 
 2815 static int
 2816 set_uuidfrom(const char* value)
 2817 {
 2818     if (strcmp(value, "file") == 0) {
 2819         config->uuidfromname = FALSE;
 2820         return HA_OK;
 2821     }
 2822     if (strcmp(value, "nodename") == 0) {
 2823         config->uuidfromname =  TRUE;
 2824         return HA_OK;
 2825     }
 2826     cl_log(LOG_ERR, "Invalid %s directive [%s]", KEY_UUIDFROM, value);
 2827     return HA_FAIL;
 2828 }
 2829 /* Set the memory reserve amount for heartbeat (in kbytes) */
 2830 static int
 2831 set_memreserve(const char * value)
 2832 {
 2833     config->memreserve = atoi(value);
 2834 
 2835     if (config->memreserve > 0) {
 2836         return(HA_OK);
 2837     }
 2838     return(HA_FAIL);
 2839 }
 2840 
 2841 static int
 2842 ha_config_check_boolean(const char *value)
 2843 {
 2844     int result;
 2845 
 2846     if (value == NULL){
 2847         cl_log(LOG_ERR, "%s: NULL pointer",
 2848                __FUNCTION__);
 2849         return HA_FAIL;
 2850     }
 2851 
 2852     if (cl_str_to_boolean(value, &result)!= HA_OK){
 2853         cl_log(LOG_ERR, "%s:Invalid directive value %s", 
 2854                __FUNCTION__,value);
 2855         return HA_FAIL;
 2856     }
 2857     
 2858     return HA_OK;
 2859 }
 2860