root/lib/ais/utils.c

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

DEFINITIONS

This source file includes following definitions.
  1. log_ais_message
  2. ais_string_to_boolean
  3. pcmk_setscheduler
  4. spawn_child
  5. stop_child
  6. destroy_ais_node
  7. update_member
  8. delete_member
  9. member_uname
  10. append_member
  11. swap_sender
  12. get_ais_data
  13. send_plugin_msg
  14. send_client_ipc
  15. send_client_msg
  16. ais_concat
  17. config_find_init
  18. config_find_next
  19. config_find_done
  20. get_config_opt
  21. ais_get_boolean
  22. ais_get_int
  23. pcmk_user_lookup

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  *
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  */
  18 
  19 #include <crm_internal.h>
  20 #include <crm/cluster/internal.h>
  21 #include <sys/types.h>
  22 #include <stdlib.h>
  23 #include <unistd.h>
  24 #include <fcntl.h>
  25 #include <errno.h>
  26 #include <stdio.h>
  27 #include <signal.h>
  28 #include <sys/types.h>
  29 #include <sys/time.h>
  30 #include <sys/resource.h>
  31 
  32 #include <pwd.h>
  33 #include <glib.h>
  34 #include <bzlib.h>
  35 #include <grp.h>
  36 
  37 #include "./utils.h"
  38 #include "./plugin.h"
  39 
  40 struct pcmk_env_s pcmk_env;
  41 
  42 void
  43 log_ais_message(int level, const AIS_Message * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45     char *data = get_ais_data(msg);
  46 
  47     qb_log_from_external_source(__func__, __FILE__,
  48                                 "Msg[%d] (dest=%s:%s, from=%s:%s.%d, remote=%s, size=%d): %.90s",
  49                                 level, __LINE__, 0,
  50                                 msg->id, ais_dest(&(msg->host)), msg_type2text(msg->host.type),
  51                                 ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
  52                                 msg->sender.pid,
  53                                 msg->sender.uname == local_uname ? "false" : "true",
  54                                 ais_data_len(msg), data);
  55 /*     do_ais_log(level, */
  56 /*             "Msg[%d] (dest=%s:%s, from=%s:%s.%d, remote=%s, size=%d): %.90s", */
  57 /*             msg->id, ais_dest(&(msg->host)), msg_type2text(msg->host.type), */
  58 /*             ais_dest(&(msg->sender)), msg_type2text(msg->sender.type), */
  59 /*             msg->sender.pid, */
  60 /*             msg->sender.uname==local_uname?"false":"true", */
  61 /*             ais_data_len(msg), data); */
  62     ais_free(data);
  63 }
  64 
  65 /*
  66 static gboolean ghash_find_by_uname(gpointer key, gpointer value, gpointer user_data)
  67 {
  68     crm_node_t *node = value;
  69     int id = GPOINTER_TO_INT(user_data);
  70 
  71     if (node->id == id) {
  72         return TRUE;
  73     }
  74     return FALSE;
  75 }
  76 */
  77 
  78 static int
  79 ais_string_to_boolean(const char *s)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81     int rc = 0;
  82 
  83     if (s == NULL) {
  84         return rc;
  85     }
  86 
  87     if (strcasecmp(s, "true") == 0
  88         || strcasecmp(s, "on") == 0
  89         || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
  90         rc = 1;
  91     }
  92     return rc;
  93 }
  94 
  95 static char *opts_default[] = { NULL, NULL };
  96 static char *opts_vgrind[] = { NULL, NULL, NULL, NULL, NULL };
  97 
  98 static void
  99 pcmk_setscheduler(crm_child_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101 #if defined(HAVE_SCHED_SETSCHEDULER)
 102     int policy = sched_getscheduler(0);
 103 
 104     if (policy == -1) {
 105         ais_perror("Could not get scheduling policy for %s", child->name);
 106 
 107     } else {
 108         int priority = -10;
 109 
 110         if (policy != SCHED_OTHER) {
 111             struct sched_param sp;
 112 
 113             policy = SCHED_OTHER;
 114 #  if defined(SCHED_RESET_ON_FORK)
 115             policy |= SCHED_RESET_ON_FORK;
 116 #  endif
 117             memset(&sp, 0, sizeof(sp));
 118             sp.sched_priority = 0;
 119 
 120             if (sched_setscheduler(0, policy, &sp) == -1) {
 121                 ais_perror("Could not reset scheduling policy to SCHED_OTHER for %s", child->name);
 122                 return;
 123             }
 124         }
 125 
 126         if (setpriority(PRIO_PROCESS, 0, priority) == -1) {
 127             ais_perror("Could not reset process priority to %d for %s", priority, child->name);
 128         }
 129     }
 130 #else
 131     ais_info("The platform is missing process priority setting features. Leaving at default.");
 132 #endif
 133 }
 134 
 135 gboolean
 136 spawn_child(crm_child_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138     int lpc = 0;
 139     uid_t uid = 0;
 140     gid_t gid = 0;
 141     struct rlimit oflimits;
 142     gboolean use_valgrind = FALSE;
 143     gboolean use_callgrind = FALSE;
 144     const char *devnull = "/dev/null";
 145     const char *env_valgrind = getenv("PCMK_valgrind_enabled");
 146     const char *env_callgrind = getenv("PCMK_callgrind_enabled");
 147 
 148     if (child->command == NULL) {
 149         ais_info("Nothing to do for child \"%s\"", child->name);
 150         return TRUE;
 151     }
 152 
 153     if (ais_string_to_boolean(env_callgrind)) {
 154         use_callgrind = TRUE;
 155         use_valgrind = TRUE;
 156 
 157     } else if (env_callgrind != NULL && strstr(env_callgrind, child->name)) {
 158         use_callgrind = TRUE;
 159         use_valgrind = TRUE;
 160 
 161     } else if (ais_string_to_boolean(env_valgrind)) {
 162         use_valgrind = TRUE;
 163 
 164     } else if (env_valgrind != NULL && strstr(env_valgrind, child->name)) {
 165         use_valgrind = TRUE;
 166     }
 167 
 168     if (use_valgrind && strlen(VALGRIND_BIN) == 0) {
 169         ais_warn("Cannot enable valgrind for %s:"
 170                  " The location of the valgrind binary is unknown", child->name);
 171         use_valgrind = FALSE;
 172     }
 173 
 174     if (child->uid) {
 175         if (pcmk_user_lookup(child->uid, &uid, &gid) < 0) {
 176             ais_err("Invalid uid (%s) specified for %s", child->uid, child->name);
 177             return FALSE;
 178         }
 179         ais_info("Using uid=%u and group=%u for process %s", uid, gid, child->name);
 180     }
 181 
 182     child->pid = fork();
 183     AIS_ASSERT(child->pid != -1);
 184 
 185     if (child->pid > 0) {
 186         /* parent */
 187         ais_info("Forked child %d for process %s%s", child->pid, child->name,
 188                  use_valgrind ? " (valgrind enabled: " VALGRIND_BIN ")" : "");
 189 
 190     } else {
 191         pcmk_setscheduler(child);
 192 
 193         /* Setup the two alternate arg arrays */
 194         opts_vgrind[0] = ais_strdup(VALGRIND_BIN);
 195         if (use_callgrind) {
 196             opts_vgrind[1] = ais_strdup("--tool=callgrind");
 197             opts_vgrind[2] = ais_strdup("--callgrind-out-file=" CRM_STATE_DIR "/callgrind.out.%p");
 198             opts_vgrind[3] = ais_strdup(child->command);
 199             opts_vgrind[4] = NULL;
 200         } else {
 201             opts_vgrind[1] = ais_strdup(child->command);
 202             opts_vgrind[2] = NULL;
 203             opts_vgrind[3] = NULL;
 204             opts_vgrind[4] = NULL;
 205         }
 206         opts_default[0] = ais_strdup(child->command);
 207 
 208         if (uid && initgroups(child->uid, gid) < 0) {
 209             ais_perror("Cannot initialize groups for %s", child->uid);
 210         }
 211 
 212         if (uid && setuid(uid) < 0) {
 213             ais_perror("Could not set user to %d (%s)", uid, child->uid);
 214         }
 215 
 216         /* Close all open file descriptors */
 217         getrlimit(RLIMIT_NOFILE, &oflimits);
 218         for (; lpc < oflimits.rlim_cur; lpc++) {
 219             close(lpc);
 220         }
 221 
 222         (void)open(devnull, O_RDONLY);  /* Stdin:  fd 0 */
 223         (void)open(devnull, O_WRONLY);  /* Stdout: fd 1 */
 224         (void)open(devnull, O_WRONLY);  /* Stderr: fd 2 */
 225 
 226 /* *INDENT-OFF* */
 227         setenv("HA_COMPRESSION",        "bz2",             1);
 228         setenv("HA_cluster_type",       "openais",         1);
 229         setenv("HA_debug",              pcmk_env.debug,    1);
 230         setenv("HA_logfacility",        pcmk_env.syslog,   1);
 231         setenv("HA_LOGFACILITY",        pcmk_env.syslog,   1);
 232         setenv("HA_use_logd",           pcmk_env.use_logd, 1);
 233         setenv("HA_quorum_type",        pcmk_env.quorum,   1);
 234 /* *INDENT-ON* */
 235 
 236         if (pcmk_env.logfile) {
 237             setenv("HA_logfile", pcmk_env.logfile, 1);
 238         }
 239 
 240         if (use_valgrind) {
 241             (void)execvp(VALGRIND_BIN, opts_vgrind);
 242         } else {
 243             (void)execvp(child->command, opts_default);
 244         }
 245         ais_perror("FATAL: Cannot exec %s", child->command);
 246         exit(100);
 247     }
 248     return TRUE;
 249 }
 250 
 251 gboolean
 252 stop_child(crm_child_t * child, int signal)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254     if (signal == 0) {
 255         signal = SIGTERM;
 256     }
 257 
 258     if (child->command == NULL) {
 259         ais_info("Nothing to do for child \"%s\"", child->name);
 260         return TRUE;
 261     }
 262 
 263     ais_debug("Stopping CRM child \"%s\"", child->name);
 264 
 265     if (child->pid <= 0) {
 266         ais_trace("Client %s not running", child->name);
 267         return TRUE;
 268     }
 269 
 270     errno = 0;
 271     if (kill(child->pid, signal) == 0) {
 272         ais_notice("Sent -%d to %s: [%d]", signal, child->name, child->pid);
 273 
 274     } else {
 275         ais_perror("Sent -%d to %s: [%d]", signal, child->name, child->pid);
 276     }
 277 
 278     return TRUE;
 279 }
 280 
 281 void
 282 destroy_ais_node(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284     crm_node_t *node = data;
 285 
 286     ais_info("Destroying entry for node %u", node->id);
 287 
 288     ais_free(node->addr);
 289     ais_free(node->uname);
 290     ais_free(node->state);
 291     ais_free(node);
 292 }
 293 
 294 int
 295 update_member(unsigned int id, uint64_t born, uint64_t seq, int32_t votes,
     /* [previous][next][first][last][top][bottom][index][help] */
 296               uint32_t procs, const char *uname, const char *state, const char *version)
 297 {
 298     int changed = 0;
 299     crm_node_t *node = NULL;
 300 
 301     node = g_hash_table_lookup(membership_list, GUINT_TO_POINTER(id));
 302 
 303     if (node == NULL) {
 304         ais_malloc0(node, sizeof(crm_node_t));
 305         ais_info("Creating entry for node %u born on " U64T "", id, seq);
 306         node->id = id;
 307         node->addr = NULL;
 308         node->state = ais_strdup("unknown");
 309 
 310         g_hash_table_insert(membership_list, GUINT_TO_POINTER(id), node);
 311         node = g_hash_table_lookup(membership_list, GUINT_TO_POINTER(id));
 312     }
 313     AIS_ASSERT(node != NULL);
 314 
 315     if (seq != 0) {
 316         node->last_seen = seq;
 317     }
 318 
 319     if (born != 0 && node->born != born) {
 320         changed = TRUE;
 321         node->born = born;
 322         ais_info("%p Node %u (%s) born on: " U64T, node, id, uname, born);
 323     }
 324 
 325     if (version != NULL) {
 326         ais_free(node->version);
 327         node->version = ais_strdup(version);
 328     }
 329 
 330     if (uname != NULL) {
 331         if (node->uname == NULL || ais_str_eq(node->uname, uname) == FALSE) {
 332             ais_info("%p Node %u now known as %s (was: %s)", node, id, uname, node->uname);
 333             ais_free(node->uname);
 334             node->uname = ais_strdup(uname);
 335             changed = TRUE;
 336         }
 337     }
 338 
 339     if (procs != 0 && procs != node->processes) {
 340         ais_info("Node %s now has process list: %.32x (%u)", node->uname, procs, procs);
 341         node->processes = procs;
 342         changed = TRUE;
 343     }
 344 
 345     if (votes >= 0 && votes != node->votes) {
 346         ais_info("Node %s now has %d quorum votes (was %d)", node->uname, votes, node->votes);
 347         node->votes = votes;
 348         changed = TRUE;
 349     }
 350 
 351     if (state != NULL) {
 352         if (node->state == NULL || ais_str_eq(node->state, state) == FALSE) {
 353             ais_free(node->state);
 354             node->state = ais_strdup(state);
 355             ais_info("Node %u/%s is now: %s", id, node->uname ? node->uname : "unknown", state);
 356             changed = TRUE;
 357         }
 358     }
 359 
 360     return changed;
 361 }
 362 
 363 void
 364 delete_member(uint32_t id, const char *uname)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366     if (uname == NULL) {
 367         g_hash_table_remove(membership_list, GUINT_TO_POINTER(id));
 368         return;
 369     }
 370     ais_err("Deleting by uname is not yet supported");
 371 }
 372 
 373 const char *
 374 member_uname(uint32_t id)
     /* [previous][next][first][last][top][bottom][index][help] */
 375 {
 376     crm_node_t *node = g_hash_table_lookup(membership_list, GUINT_TO_POINTER(id));
 377 
 378     if (node == NULL) {
 379         return ".unknown.";
 380     }
 381     if (node->uname == NULL) {
 382         return ".pending.";
 383     }
 384     return node->uname;
 385 }
 386 
 387 char *
 388 append_member(char *data, crm_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
 389 {
 390     int size = 1;               /* nul */
 391     int offset = 0;
 392     static int fixed_len = 4 + 8 + 7 + 6 + 6 + 7 + 11;
 393 
 394     if (data) {
 395         size = strlen(data);
 396     }
 397     offset = size;
 398 
 399     size += fixed_len;
 400     size += 32;                 /* node->id */
 401     size += 100;                /* node->seq, node->born */
 402     size += strlen(node->state);
 403     if (node->uname) {
 404         size += (7 + strlen(node->uname));
 405     }
 406     if (node->addr) {
 407         size += (6 + strlen(node->addr));
 408     }
 409     if (node->version) {
 410         size += (9 + strlen(node->version));
 411     }
 412     data = realloc_safe(data, size);
 413 
 414     offset += snprintf(data + offset, size - offset, "<node id=\"%u\" ", node->id);
 415     if (node->uname) {
 416         offset += snprintf(data + offset, size - offset, "uname=\"%s\" ", node->uname);
 417     }
 418     offset += snprintf(data + offset, size - offset, "state=\"%s\" ", node->state);
 419     offset += snprintf(data + offset, size - offset, "born=\"" U64T "\" ", node->born);
 420     offset += snprintf(data + offset, size - offset, "seen=\"" U64T "\" ", node->last_seen);
 421     offset += snprintf(data + offset, size - offset, "votes=\"%d\" ", node->votes);
 422     offset += snprintf(data + offset, size - offset, "processes=\"%u\" ", node->processes);
 423     if (node->addr) {
 424         offset += snprintf(data + offset, size - offset, "addr=\"%s\" ", node->addr);
 425     }
 426     if (node->version) {
 427         offset += snprintf(data + offset, size - offset, "version=\"%s\" ", node->version);
 428     }
 429     offset += snprintf(data + offset, size - offset, "/>");
 430 
 431     return data;
 432 }
 433 
 434 void
 435 swap_sender(AIS_Message * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437     int tmp = 0;
 438     char tmp_s[256];
 439 
 440     tmp = msg->host.type;
 441     msg->host.type = msg->sender.type;
 442     msg->sender.type = tmp;
 443 
 444     tmp = msg->host.type;
 445     msg->host.size = msg->sender.type;
 446     msg->sender.type = tmp;
 447 
 448     memcpy(tmp_s, msg->host.uname, 256);
 449     memcpy(msg->host.uname, msg->sender.uname, 256);
 450     memcpy(msg->sender.uname, tmp_s, 256);
 451 }
 452 
 453 char *
 454 get_ais_data(const AIS_Message * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 455 {
 456     int rc = BZ_OK;
 457     char *uncompressed = NULL;
 458     unsigned int new_size = msg->size + 1;
 459 
 460     if (msg->is_compressed == FALSE) {
 461         uncompressed = strdup(msg->data);
 462 
 463     } else {
 464         ais_malloc0(uncompressed, new_size);
 465 
 466         rc = BZ2_bzBuffToBuffDecompress(uncompressed, &new_size, (char *)msg->data,
 467                                         msg->compressed_size, 1, 0);
 468         if (rc != BZ_OK) {
 469             ais_info("rc=%d, new=%u expected=%u", rc, new_size, msg->size);
 470         }
 471         AIS_ASSERT(rc == BZ_OK);
 472         AIS_ASSERT(new_size == msg->size);
 473     }
 474 
 475     return uncompressed;
 476 }
 477 
 478 int
 479 send_plugin_msg(enum crm_ais_msg_types type, const char *host, const char *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 480 {
 481     int rc = 0;
 482     int data_len = 0;
 483     AIS_Message *ais_msg = NULL;
 484     int total_size = sizeof(AIS_Message);
 485 
 486     AIS_ASSERT(local_nodeid != 0);
 487 
 488     if (data != NULL) {
 489         data_len = 1 + strlen(data);
 490         total_size += data_len;
 491     }
 492     ais_malloc0(ais_msg, total_size);
 493 
 494     ais_msg->header.size = total_size;
 495     ais_msg->header.error = CS_OK;
 496     ais_msg->header.id = 0;
 497 
 498     ais_msg->size = data_len;
 499     ais_msg->sender.type = crm_msg_ais;
 500     if (data != NULL) {
 501         memcpy(ais_msg->data, data, data_len);
 502     }
 503 
 504     ais_msg->host.type = type;
 505     ais_msg->host.id = 0;
 506     if (host) {
 507         ais_msg->host.size = strlen(host);
 508         memset(ais_msg->host.uname, 0, MAX_NAME);
 509         memcpy(ais_msg->host.uname, host, ais_msg->host.size);
 510 /*      ais_msg->host.id = nodeid_lookup(host); */
 511 
 512     } else {
 513         ais_msg->host.type = type;
 514         ais_msg->host.size = 0;
 515         memset(ais_msg->host.uname, 0, MAX_NAME);
 516     }
 517 
 518     rc = send_plugin_msg_raw(ais_msg);
 519     ais_free(ais_msg);
 520 
 521     return rc;
 522 }
 523 
 524 extern struct corosync_api_v1 *pcmk_api;
 525 
 526 int
 527 send_client_ipc(void *conn, const AIS_Message * ais_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 528 {
 529     int rc = -1;
 530 
 531     if (conn == NULL) {
 532         rc = -2;
 533 
 534     } else if (!libais_connection_active(conn)) {
 535         ais_warn("Connection no longer active");
 536         rc = -3;
 537 
 538 /*      } else if ((queue->size - 1) == queue->used) { */
 539 /*          ais_err("Connection is throttled: %d", queue->size); */
 540 
 541     } else {
 542 #if SUPPORT_COROSYNC
 543         rc = pcmk_api->ipc_dispatch_send(conn, ais_msg, ais_msg->header.size);
 544 #endif
 545     }
 546     return rc;
 547 }
 548 
 549 int
 550 send_client_msg(void *conn, enum crm_ais_msg_class class, enum crm_ais_msg_types type,
     /* [previous][next][first][last][top][bottom][index][help] */
 551                 const char *data)
 552 {
 553     int rc = 0;
 554     int data_len = 0;
 555     int total_size = sizeof(AIS_Message);
 556     AIS_Message *ais_msg = NULL;
 557     static int msg_id = 0;
 558 
 559     AIS_ASSERT(local_nodeid != 0);
 560 
 561     msg_id++;
 562     AIS_ASSERT(msg_id != 0 /* wrap-around */ );
 563 
 564     if (data != NULL) {
 565         data_len = 1 + strlen(data);
 566     }
 567     total_size += data_len;
 568 
 569     ais_malloc0(ais_msg, total_size);
 570 
 571     ais_msg->id = msg_id;
 572     ais_msg->header.id = class;
 573     ais_msg->header.size = total_size;
 574     ais_msg->header.error = CS_OK;
 575 
 576     ais_msg->size = data_len;
 577     if (data != NULL) {
 578         memcpy(ais_msg->data, data, data_len);
 579     }
 580 
 581     ais_msg->host.size = 0;
 582     ais_msg->host.type = type;
 583     memset(ais_msg->host.uname, 0, MAX_NAME);
 584     ais_msg->host.id = 0;
 585 
 586     ais_msg->sender.type = crm_msg_ais;
 587     ais_msg->sender.size = local_uname_len;
 588     memset(ais_msg->sender.uname, 0, MAX_NAME);
 589     memcpy(ais_msg->sender.uname, local_uname, ais_msg->sender.size);
 590     ais_msg->sender.id = local_nodeid;
 591 
 592     rc = send_client_ipc(conn, ais_msg);
 593 
 594     if (rc != 0) {
 595         ais_warn("Sending message to %s failed: %d", msg_type2text(type), rc);
 596         log_ais_message(LOG_DEBUG, ais_msg);
 597     }
 598 
 599     ais_free(ais_msg);
 600     return rc;
 601 }
 602 
 603 char *
 604 ais_concat(const char *prefix, const char *suffix, char join)
     /* [previous][next][first][last][top][bottom][index][help] */
 605 {
 606     int len = 0;
 607     char *new_str = NULL;
 608 
 609     AIS_ASSERT(prefix != NULL);
 610     AIS_ASSERT(suffix != NULL);
 611     len = strlen(prefix) + strlen(suffix) + 2;
 612 
 613     ais_malloc0(new_str, (len));
 614     sprintf(new_str, "%s%c%s", prefix, join, suffix);
 615     new_str[len - 1] = 0;
 616     return new_str;
 617 }
 618 
 619 hdb_handle_t
 620 config_find_init(struct corosync_api_v1 * config, char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 621 {
 622     hdb_handle_t local_handle = 0;
 623 
 624 #if SUPPORT_COROSYNC
 625     config->object_find_create(OBJECT_PARENT_HANDLE, name, strlen(name), &local_handle);
 626     ais_info("Local handle: %lld for %s", (long long)local_handle, name);
 627 #endif
 628 
 629     return local_handle;
 630 }
 631 
 632 hdb_handle_t
 633 config_find_next(struct corosync_api_v1 * config, char *name, hdb_handle_t top_handle)
     /* [previous][next][first][last][top][bottom][index][help] */
 634 {
 635     int rc = 0;
 636     hdb_handle_t local_handle = 0;
 637 
 638 #if SUPPORT_COROSYNC
 639     rc = config->object_find_next(top_handle, &local_handle);
 640 #endif
 641 
 642     if (rc < 0) {
 643         ais_info("No additional configuration supplied for: %s", name);
 644         local_handle = 0;
 645     } else {
 646         ais_info("Processing additional %s options...", name);
 647     }
 648     return local_handle;
 649 }
 650 
 651 void
 652 config_find_done(struct corosync_api_v1 *config, hdb_handle_t local_handle)
     /* [previous][next][first][last][top][bottom][index][help] */
 653 {
 654 #if SUPPORT_COROSYNC
 655     config->object_find_destroy(local_handle);
 656 #endif
 657 }
 658 
 659 int
 660 get_config_opt(struct corosync_api_v1 *config,
     /* [previous][next][first][last][top][bottom][index][help] */
 661                hdb_handle_t object_service_handle, char *key, char **value, const char *fallback)
 662 {
 663     char *env_key = NULL;
 664 
 665     *value = NULL;
 666 
 667     if (object_service_handle > 0) {
 668         config->object_key_get(object_service_handle, key, strlen(key), (void **)value, NULL);
 669     }
 670 
 671     if (*value) {
 672         ais_info("Found '%s' for option: %s", *value, key);
 673         return 0;
 674     }
 675 
 676     env_key = ais_concat("HA", key, '_');
 677     *value = getenv(env_key);
 678     ais_free(env_key);
 679 
 680     if (*value) {
 681         ais_info("Found '%s' in ENV for option: %s", *value, key);
 682         return 0;
 683     }
 684 
 685     if (fallback) {
 686         ais_info("Defaulting to '%s' for option: %s", fallback, key);
 687         *value = ais_strdup(fallback);
 688 
 689     } else {
 690         ais_info("No default for option: %s", key);
 691     }
 692 
 693     return -1;
 694 }
 695 
 696 int
 697 ais_get_boolean(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 698 {
 699     if (value == NULL) {
 700         return 0;
 701 
 702     } else if (strcasecmp(value, "true") == 0
 703                || strcasecmp(value, "on") == 0
 704                || strcasecmp(value, "yes") == 0
 705                || strcasecmp(value, "y") == 0 || strcasecmp(value, "1") == 0) {
 706         return 1;
 707     }
 708     return 0;
 709 }
 710 
 711 long long
 712 ais_get_int(const char *text, char **end_text)
     /* [previous][next][first][last][top][bottom][index][help] */
 713 {
 714     long long result = -1;
 715     char *local_end_text = NULL;
 716 
 717     errno = 0;
 718 
 719     if (text != NULL) {
 720 #ifdef ANSI_ONLY
 721         if (end_text != NULL) {
 722             result = strtol(text, end_text, 10);
 723         } else {
 724             result = strtol(text, &local_end_text, 10);
 725         }
 726 #else
 727         if (end_text != NULL) {
 728             result = strtoll(text, end_text, 10);
 729         } else {
 730             result = strtoll(text, &local_end_text, 10);
 731         }
 732 #endif
 733 
 734         if (errno == EINVAL) {
 735             ais_err("Conversion of %s failed", text);
 736             result = -1;
 737 
 738         } else if (errno == ERANGE) {
 739             ais_err("Conversion of %s was clipped: %lld", text, result);
 740 
 741         } else if (errno != 0) {
 742             ais_perror("Conversion of %s failed:", text);
 743         }
 744 
 745         if (local_end_text != NULL && local_end_text[0] != '\0') {
 746             ais_err("Characters left over after parsing '%s': '%s'", text, local_end_text);
 747         }
 748     }
 749     return result;
 750 }
 751 
 752 #define PW_BUFFER_LEN 500
 753 
 754 int
 755 pcmk_user_lookup(const char *name, uid_t * uid, gid_t * gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 756 {
 757     int rc = -1;
 758     char *buffer = NULL;
 759     struct passwd pwd;
 760     struct passwd *pwentry = NULL;
 761 
 762     ais_malloc0(buffer, PW_BUFFER_LEN);
 763     getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
 764     if (pwentry) {
 765         rc = 0;
 766         if (uid) {
 767             *uid = pwentry->pw_uid;
 768         }
 769         if (gid) {
 770             *gid = pwentry->pw_gid;
 771         }
 772         ais_debug("Cluster user %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
 773 
 774     } else {
 775         ais_err("Cluster user %s does not exist", name);
 776     }
 777 
 778     ais_free(buffer);
 779     return rc;
 780 }

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