root/lib/common/utils.c

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

DEFINITIONS

This source file includes following definitions.
  1. crm_exit
  2. check_time
  3. check_timer
  4. check_boolean
  5. check_number
  6. check_positive_number
  7. check_quorum
  8. check_script
  9. check_utilization
  10. char2score
  11. score2char_stack
  12. score2char
  13. cluster_option
  14. get_cluster_pref
  15. config_metadata
  16. verify_all_options
  17. generate_hash_key
  18. crm_user_lookup
  19. crm_version_helper
  20. compare_version
  21. crm_get_interval
  22. crm_get_msec
  23. crm_abort
  24. crm_pid_active
  25. crm_read_pidfile
  26. crm_pidfile_inuse
  27. crm_lock_pidfile
  28. crm_make_daemon
  29. crm_meta_name
  30. crm_meta_value
  31. crm_create_long_opts
  32. crm_set_options
  33. crm_get_option
  34. crm_get_option_long
  35. crm_help
  36. cib_ipc_servers_init
  37. cib_ipc_servers_destroy
  38. crmd_ipc_server_init
  39. attrd_ipc_server_init
  40. stonith_ipc_server_init
  41. pcmk_acl_required
  42. uid2username
  43. crm_acl_get_set_user
  44. determine_request_user
  45. find_library_function
  46. convert_const_pointer
  47. crm_generate_uuid
  48. crm_is_daemon_name
  49. crm_md5sum
  50. crm_gnutls_global_init
  51. crm_generate_ra_key
  52. crm_provider_required
  53. crm_parse_agent_spec

   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 <dlfcn.h>
  21 
  22 #ifndef _GNU_SOURCE
  23 #  define _GNU_SOURCE
  24 #endif
  25 
  26 #include <sys/types.h>
  27 #include <sys/wait.h>
  28 #include <sys/stat.h>
  29 #include <sys/utsname.h>
  30 
  31 #include <stdio.h>
  32 #include <unistd.h>
  33 #include <string.h>
  34 #include <stdlib.h>
  35 #include <limits.h>
  36 #include <pwd.h>
  37 #include <time.h>
  38 #include <libgen.h>
  39 #include <signal.h>
  40 
  41 #include <qb/qbdefs.h>
  42 
  43 #include <crm/crm.h>
  44 #include <crm/services.h>
  45 #include <crm/msg_xml.h>
  46 #include <crm/cib/internal.h>
  47 #include <crm/common/xml.h>
  48 #include <crm/common/util.h>
  49 #include <crm/common/ipc.h>
  50 #include <crm/common/iso8601.h>
  51 #include <crm/common/mainloop.h>
  52 #include <libxml2/libxml/relaxng.h>
  53 
  54 #ifndef MAXLINE
  55 #  define MAXLINE 512
  56 #endif
  57 
  58 #ifdef HAVE_GETOPT_H
  59 #  include <getopt.h>
  60 #endif
  61 
  62 #ifndef PW_BUFFER_LEN
  63 #  define PW_BUFFER_LEN         500
  64 #endif
  65 
  66 CRM_TRACE_INIT_DATA(common);
  67 
  68 gboolean crm_config_error = FALSE;
  69 gboolean crm_config_warning = FALSE;
  70 char *crm_system_name = NULL;
  71 
  72 int node_score_red = 0;
  73 int node_score_green = 0;
  74 int node_score_yellow = 0;
  75 int node_score_infinity = INFINITY;
  76 
  77 static struct crm_option *crm_long_options = NULL;
  78 static const char *crm_app_description = NULL;
  79 static char *crm_short_options = NULL;
  80 static const char *crm_app_usage = NULL;
  81 
  82 int
  83 crm_exit(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85     mainloop_cleanup();
  86 
  87 #if HAVE_LIBXML2
  88     crm_trace("cleaning up libxml");
  89     crm_xml_cleanup();
  90 #endif
  91 
  92     crm_trace("exit %d", rc);
  93     qb_log_fini();
  94 
  95     free(crm_short_options);
  96     free(crm_system_name);
  97 
  98     exit(ABS(rc)); /* Always exit with a positive value so that it can be passed to crm_error
  99                     *
 100                     * Otherwise the system wraps it around and people
 101                     * have to jump through hoops figuring out what the
 102                     * error was
 103                     */
 104     return rc;     /* Can never happen, but allows return crm_exit(rc)
 105                     * where "return rc" was used previously - which
 106                     * keeps compilers happy.
 107                     */
 108 }
 109 
 110 gboolean
 111 check_time(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113     if (crm_get_msec(value) < 5000) {
 114         return FALSE;
 115     }
 116     return TRUE;
 117 }
 118 
 119 gboolean
 120 check_timer(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122     if (crm_get_msec(value) < 0) {
 123         return FALSE;
 124     }
 125     return TRUE;
 126 }
 127 
 128 gboolean
 129 check_boolean(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131     int tmp = FALSE;
 132 
 133     if (crm_str_to_boolean(value, &tmp) != 1) {
 134         return FALSE;
 135     }
 136     return TRUE;
 137 }
 138 
 139 gboolean
 140 check_number(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 141 {
 142     errno = 0;
 143     if (value == NULL) {
 144         return FALSE;
 145 
 146     } else if (safe_str_eq(value, MINUS_INFINITY_S)) {
 147 
 148     } else if (safe_str_eq(value, INFINITY_S)) {
 149 
 150     } else {
 151         crm_int_helper(value, NULL);
 152     }
 153 
 154     if (errno != 0) {
 155         return FALSE;
 156     }
 157     return TRUE;
 158 }
 159 
 160 gboolean
 161 check_positive_number(const char* value)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163     if (safe_str_eq(value, INFINITY_S) || (crm_int_helper(value, NULL))) {
 164         return TRUE;
 165     }
 166     return FALSE;
 167 }
 168 
 169 gboolean
 170 check_quorum(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172     if (safe_str_eq(value, "stop")) {
 173         return TRUE;
 174 
 175     } else if (safe_str_eq(value, "freeze")) {
 176         return TRUE;
 177 
 178     } else if (safe_str_eq(value, "ignore")) {
 179         return TRUE;
 180 
 181     } else if (safe_str_eq(value, "suicide")) {
 182         return TRUE;
 183     }
 184     return FALSE;
 185 }
 186 
 187 gboolean
 188 check_script(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190     struct stat st;
 191 
 192     if(safe_str_eq(value, "/dev/null")) {
 193         return TRUE;
 194     }
 195 
 196     if(stat(value, &st) != 0) {
 197         crm_err("Script %s does not exist", value);
 198         return FALSE;
 199     }
 200 
 201     if(S_ISREG(st.st_mode) == 0) {
 202         crm_err("Script %s is not a regular file", value);
 203         return FALSE;
 204     }
 205 
 206     if( (st.st_mode & (S_IXUSR | S_IXGRP )) == 0) {
 207         crm_err("Script %s is not executable", value);
 208         return FALSE;
 209     }
 210 
 211     return TRUE;
 212 }
 213 
 214 gboolean
 215 check_utilization(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217     char *end = NULL;
 218     long number = strtol(value, &end, 10);
 219 
 220     if(end && end[0] != '%') {
 221         return FALSE;
 222     } else if(number < 0) {
 223         return FALSE;
 224     }
 225 
 226     return TRUE;
 227 }
 228 
 229 int
 230 char2score(const char *score)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232     int score_f = 0;
 233 
 234     if (score == NULL) {
 235 
 236     } else if (safe_str_eq(score, MINUS_INFINITY_S)) {
 237         score_f = -node_score_infinity;
 238 
 239     } else if (safe_str_eq(score, INFINITY_S)) {
 240         score_f = node_score_infinity;
 241 
 242     } else if (safe_str_eq(score, "+" INFINITY_S)) {
 243         score_f = node_score_infinity;
 244 
 245     } else if (safe_str_eq(score, "red")) {
 246         score_f = node_score_red;
 247 
 248     } else if (safe_str_eq(score, "yellow")) {
 249         score_f = node_score_yellow;
 250 
 251     } else if (safe_str_eq(score, "green")) {
 252         score_f = node_score_green;
 253 
 254     } else {
 255         score_f = crm_parse_int(score, NULL);
 256         if (score_f > 0 && score_f > node_score_infinity) {
 257             score_f = node_score_infinity;
 258 
 259         } else if (score_f < 0 && score_f < -node_score_infinity) {
 260             score_f = -node_score_infinity;
 261         }
 262     }
 263 
 264     return score_f;
 265 }
 266 
 267 char *
 268 score2char_stack(int score, char *buf, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270     if (score >= node_score_infinity) {
 271         strncpy(buf, INFINITY_S, 9);
 272     } else if (score <= -node_score_infinity) {
 273         strncpy(buf, MINUS_INFINITY_S , 10);
 274     } else {
 275         return crm_itoa_stack(score, buf, len);
 276     }
 277 
 278     return buf;
 279 }
 280 
 281 char *
 282 score2char(int score)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284     if (score >= node_score_infinity) {
 285         return strdup(INFINITY_S);
 286 
 287     } else if (score <= -node_score_infinity) {
 288         return strdup("-" INFINITY_S);
 289     }
 290     return crm_itoa(score);
 291 }
 292 
 293 const char *
 294 cluster_option(GHashTable * options, gboolean(*validate) (const char *),
     /* [previous][next][first][last][top][bottom][index][help] */
 295                const char *name, const char *old_name, const char *def_value)
 296 {
 297     const char *value = NULL;
 298     char *new_value = NULL;
 299 
 300     CRM_ASSERT(name != NULL);
 301 
 302     if (options) {
 303         value = g_hash_table_lookup(options, name);
 304 
 305         if ((value == NULL) && old_name) {
 306             value = g_hash_table_lookup(options, old_name);
 307             if (value != NULL) {
 308                 crm_config_warn("Support for legacy name '%s' for cluster option '%s'"
 309                                 " is deprecated and will be removed in a future release",
 310                                 old_name, name);
 311 
 312                 // Inserting copy with current name ensures we only warn once
 313                 new_value = strdup(value);
 314                 g_hash_table_insert(options, strdup(name), new_value);
 315                 value = new_value;
 316             }
 317         }
 318 
 319         if (value && validate && (validate(value) == FALSE)) {
 320             crm_config_err("Resetting cluster option '%s' to default: value '%s' is invalid",
 321                            name, value);
 322             value = NULL;
 323         }
 324 
 325         if (value) {
 326             return value;
 327         }
 328     }
 329 
 330     // No value found, use default
 331     value = def_value;
 332 
 333     if (value == NULL) {
 334         crm_trace("No value or default provided for cluster option '%s'",
 335                   name);
 336         return NULL;
 337     }
 338 
 339     if (validate) {
 340         CRM_CHECK(validate(value) != FALSE,
 341                   crm_err("Bug: default value for cluster option '%s' is invalid", name);
 342                   return NULL);
 343     }
 344 
 345     crm_trace("Using default value '%s' for cluster option '%s'",
 346               value, name);
 347     if (options) {
 348         new_value = strdup(value);
 349         g_hash_table_insert(options, strdup(name), new_value);
 350         value = new_value;
 351     }
 352     return value;
 353 }
 354 
 355 const char *
 356 get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 357 {
 358     const char *value = NULL;
 359 
 360     for (int lpc = 0; lpc < len; lpc++) {
 361         if (safe_str_eq(name, option_list[lpc].name)) {
 362             value = cluster_option(options,
 363                                    option_list[lpc].is_valid,
 364                                    option_list[lpc].name,
 365                                    option_list[lpc].alt_name,
 366                                    option_list[lpc].default_value);
 367             return value;
 368         }
 369     }
 370     CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
 371     return NULL;
 372 }
 373 
 374 void
 375 config_metadata(const char *name, const char *version, const char *desc_short,
     /* [previous][next][first][last][top][bottom][index][help] */
 376                 const char *desc_long, pe_cluster_option * option_list, int len)
 377 {
 378     int lpc = 0;
 379 
 380     fprintf(stdout, "<?xml version=\"1.0\"?>"
 381             "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
 382             "<resource-agent name=\"%s\">\n"
 383             "  <version>%s</version>\n"
 384             "  <longdesc lang=\"en\">%s</longdesc>\n"
 385             "  <shortdesc lang=\"en\">%s</shortdesc>\n"
 386             "  <parameters>\n", name, version, desc_long, desc_short);
 387 
 388     for (lpc = 0; lpc < len; lpc++) {
 389         if (option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) {
 390             continue;
 391         }
 392         fprintf(stdout, "    <parameter name=\"%s\" unique=\"0\">\n"
 393                 "      <shortdesc lang=\"en\">%s</shortdesc>\n"
 394                 "      <content type=\"%s\" default=\"%s\"/>\n"
 395                 "      <longdesc lang=\"en\">%s%s%s</longdesc>\n"
 396                 "    </parameter>\n",
 397                 option_list[lpc].name,
 398                 option_list[lpc].description_short,
 399                 option_list[lpc].type,
 400                 option_list[lpc].default_value,
 401                 option_list[lpc].description_long ? option_list[lpc].
 402                 description_long : option_list[lpc].description_short,
 403                 option_list[lpc].values ? "  Allowed values: " : "",
 404                 option_list[lpc].values ? option_list[lpc].values : "");
 405     }
 406     fprintf(stdout, "  </parameters>\n</resource-agent>\n");
 407 }
 408 
 409 void
 410 verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412     int lpc = 0;
 413 
 414     for (lpc = 0; lpc < len; lpc++) {
 415         cluster_option(options,
 416                        option_list[lpc].is_valid,
 417                        option_list[lpc].name,
 418                        option_list[lpc].alt_name, option_list[lpc].default_value);
 419     }
 420 }
 421 
 422 char *
 423 generate_hash_key(const char *crm_msg_reference, const char *sys)
     /* [previous][next][first][last][top][bottom][index][help] */
 424 {
 425     char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_');
 426 
 427     crm_trace("created hash key: (%s)", hash_key);
 428     return hash_key;
 429 }
 430 
 431 
 432 int
 433 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 434 {
 435     int rc = pcmk_ok;
 436     char *buffer = NULL;
 437     struct passwd pwd;
 438     struct passwd *pwentry = NULL;
 439 
 440     buffer = calloc(1, PW_BUFFER_LEN);
 441     rc = getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
 442     if (pwentry) {
 443         if (uid) {
 444             *uid = pwentry->pw_uid;
 445         }
 446         if (gid) {
 447             *gid = pwentry->pw_gid;
 448         }
 449         crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
 450 
 451     } else {
 452         rc = rc? -rc : -EINVAL;
 453         crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
 454     }
 455 
 456     free(buffer);
 457     return rc;
 458 }
 459 
 460 static int
 461 crm_version_helper(const char *text, char **end_text)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463     int atoi_result = -1;
 464 
 465     CRM_ASSERT(end_text != NULL);
 466 
 467     errno = 0;
 468 
 469     if (text != NULL && text[0] != 0) {
 470         atoi_result = (int)strtol(text, end_text, 10);
 471 
 472         if (errno == EINVAL) {
 473             crm_err("Conversion of '%s' %c failed", text, text[0]);
 474             atoi_result = -1;
 475         }
 476     }
 477     return atoi_result;
 478 }
 479 
 480 /*
 481  * version1 < version2 : -1
 482  * version1 = version2 :  0
 483  * version1 > version2 :  1
 484  */
 485 int
 486 compare_version(const char *version1, const char *version2)
     /* [previous][next][first][last][top][bottom][index][help] */
 487 {
 488     int rc = 0;
 489     int lpc = 0;
 490     char *ver1_copy = NULL, *ver2_copy = NULL;
 491     char *rest1 = NULL, *rest2 = NULL;
 492 
 493     if (version1 == NULL && version2 == NULL) {
 494         return 0;
 495     } else if (version1 == NULL) {
 496         return -1;
 497     } else if (version2 == NULL) {
 498         return 1;
 499     }
 500 
 501     ver1_copy = strdup(version1);
 502     ver2_copy = strdup(version2);
 503     rest1 = ver1_copy;
 504     rest2 = ver2_copy;
 505 
 506     while (1) {
 507         int digit1 = 0;
 508         int digit2 = 0;
 509 
 510         lpc++;
 511 
 512         if (rest1 == rest2) {
 513             break;
 514         }
 515 
 516         if (rest1 != NULL) {
 517             digit1 = crm_version_helper(rest1, &rest1);
 518         }
 519 
 520         if (rest2 != NULL) {
 521             digit2 = crm_version_helper(rest2, &rest2);
 522         }
 523 
 524         if (digit1 < digit2) {
 525             rc = -1;
 526             break;
 527 
 528         } else if (digit1 > digit2) {
 529             rc = 1;
 530             break;
 531         }
 532 
 533         if (rest1 != NULL && rest1[0] == '.') {
 534             rest1++;
 535         }
 536         if (rest1 != NULL && rest1[0] == 0) {
 537             rest1 = NULL;
 538         }
 539 
 540         if (rest2 != NULL && rest2[0] == '.') {
 541             rest2++;
 542         }
 543         if (rest2 != NULL && rest2[0] == 0) {
 544             rest2 = NULL;
 545         }
 546     }
 547 
 548     free(ver1_copy);
 549     free(ver2_copy);
 550 
 551     if (rc == 0) {
 552         crm_trace("%s == %s (%d)", version1, version2, lpc);
 553     } else if (rc < 0) {
 554         crm_trace("%s < %s (%d)", version1, version2, lpc);
 555     } else if (rc > 0) {
 556         crm_trace("%s > %s (%d)", version1, version2, lpc);
 557     }
 558 
 559     return rc;
 560 }
 561 
 562 gboolean do_stderr = FALSE;
 563 
 564 #ifndef NUMCHARS
 565 #  define       NUMCHARS        "0123456789."
 566 #endif
 567 
 568 #ifndef WHITESPACE
 569 #  define       WHITESPACE      " \t\n\r\f"
 570 #endif
 571 
 572 unsigned long long
 573 crm_get_interval(const char *input)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {
 575     unsigned long long msec = 0;
 576 
 577     if (input == NULL) {
 578         return msec;
 579 
 580     } else if (input[0] != 'P') {
 581         long long tmp = crm_get_msec(input);
 582 
 583         if(tmp > 0) {
 584             msec = tmp;
 585         }
 586 
 587     } else {
 588         crm_time_t *interval = crm_time_parse_duration(input);
 589 
 590         msec = 1000 * crm_time_get_seconds(interval);
 591         crm_time_free(interval);
 592     }
 593 
 594     return msec;
 595 }
 596 
 597 long long
 598 crm_get_msec(const char *input)
     /* [previous][next][first][last][top][bottom][index][help] */
 599 {
 600     const char *cp = input;
 601     const char *units;
 602     long long multiplier = 1000;
 603     long long divisor = 1;
 604     long long msec = -1;
 605     char *end_text = NULL;
 606 
 607     /* double dret; */
 608 
 609     if (input == NULL) {
 610         return msec;
 611     }
 612 
 613     cp += strspn(cp, WHITESPACE);
 614     units = cp + strspn(cp, NUMCHARS);
 615     units += strspn(units, WHITESPACE);
 616 
 617     if (strchr(NUMCHARS, *cp) == NULL) {
 618         return msec;
 619     }
 620 
 621     if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) {
 622         multiplier = 1;
 623         divisor = 1;
 624     } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) {
 625         multiplier = 1;
 626         divisor = 1000;
 627     } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) {
 628         multiplier = 1000;
 629         divisor = 1;
 630     } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) {
 631         multiplier = 60 * 1000;
 632         divisor = 1;
 633     } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) {
 634         multiplier = 60 * 60 * 1000;
 635         divisor = 1;
 636     } else if (*units != EOS && *units != '\n' && *units != '\r') {
 637         return msec;
 638     }
 639 
 640     msec = crm_int_helper(cp, &end_text);
 641     if (msec > LLONG_MAX/multiplier) {
 642         /* arithmetics overflow while multiplier/divisor mutually exclusive */
 643         return LLONG_MAX;
 644     }
 645     msec *= multiplier;
 646     msec /= divisor;
 647     /* dret += 0.5; */
 648     /* msec = (long long)dret; */
 649     return msec;
 650 }
 651 
 652 extern bool crm_is_daemon;
 653 
 654 /* coverity[+kill] */
 655 void
 656 crm_abort(const char *file, const char *function, int line,
     /* [previous][next][first][last][top][bottom][index][help] */
 657           const char *assert_condition, gboolean do_core, gboolean do_fork)
 658 {
 659     int rc = 0;
 660     int pid = 0;
 661     int status = 0;
 662 
 663     /* Implied by the parent's error logging below */
 664     /* crm_write_blackbox(0); */
 665 
 666     if(crm_is_daemon == FALSE) {
 667         /* This is a command line tool - do not fork */
 668 
 669         /* crm_add_logfile(NULL);   * Record it to a file? */
 670         crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */
 671         do_fork = FALSE;         /* Just crash if needed */
 672     }
 673 
 674     if (do_core == FALSE) {
 675         crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition);
 676         return;
 677 
 678     } else if (do_fork) {
 679         pid = fork();
 680 
 681     } else {
 682         crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition);
 683     }
 684 
 685     if (pid == -1) {
 686         crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s",
 687                  function, file, line, assert_condition);
 688         return;
 689 
 690     } else if(pid == 0) {
 691         /* Child process */
 692         abort();
 693         return;
 694     }
 695 
 696     /* Parent process */
 697     crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s",
 698             function, pid, file, line, assert_condition);
 699     crm_write_blackbox(SIGTRAP, NULL);
 700 
 701     do {
 702         rc = waitpid(pid, &status, 0);
 703         if(rc == pid) {
 704             return; /* Job done */
 705         }
 706 
 707     } while(errno == EINTR);
 708 
 709     if (errno == ECHILD) {
 710         /* crm_mon does this */
 711         crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid);
 712         return;
 713     }
 714     crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid);
 715 }
 716 
 717 int
 718 crm_pid_active(long pid, const char *daemon)
     /* [previous][next][first][last][top][bottom][index][help] */
 719 {
 720     static int have_proc_pid = 0;
 721 
 722     if(have_proc_pid == 0) {
 723         char proc_path[PATH_MAX], exe_path[PATH_MAX];
 724 
 725         /* check to make sure pid hasn't been reused by another process */
 726         snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", (long unsigned int)getpid());
 727 
 728         have_proc_pid = 1;
 729         if(readlink(proc_path, exe_path, PATH_MAX - 1) < 0) {
 730             have_proc_pid = -1;
 731         }
 732     }
 733 
 734     if (pid <= 0) {
 735         return -1;
 736 
 737     } else if (kill(pid, 0) < 0 && errno == ESRCH) {
 738         return 0;
 739 
 740     } else if(daemon == NULL || have_proc_pid == -1) {
 741         return 1;
 742 
 743     } else {
 744         int rc = 0;
 745         char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX];
 746 
 747         /* check to make sure pid hasn't been reused by another process */
 748         snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", pid);
 749 
 750         rc = readlink(proc_path, exe_path, PATH_MAX - 1);
 751         if (rc < 0 && errno == EACCES) {
 752             crm_perror(LOG_INFO, "Could not read from %s", proc_path);
 753             return 1;
 754         } else if (rc < 0) {
 755             crm_perror(LOG_ERR, "Could not read from %s", proc_path);
 756             return 0;
 757         }
 758         
 759 
 760         exe_path[rc] = 0;
 761 
 762         if(daemon[0] != '/') {
 763             rc = snprintf(myexe_path, sizeof(proc_path), CRM_DAEMON_DIR"/%s", daemon);
 764             myexe_path[rc] = 0;
 765         } else {
 766             rc = snprintf(myexe_path, sizeof(proc_path), "%s", daemon);
 767             myexe_path[rc] = 0;
 768         }
 769         
 770         if (strcmp(exe_path, myexe_path) == 0) {
 771             return 1;
 772         }
 773     }
 774 
 775     return 0;
 776 }
 777 
 778 #define LOCKSTRLEN      11
 779 
 780 long
 781 crm_read_pidfile(const char *filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 782 {
 783     int fd;
 784     struct stat sbuf;
 785     long pid = -ENOENT;
 786     char buf[LOCKSTRLEN + 1];
 787 
 788     if ((fd = open(filename, O_RDONLY)) < 0) {
 789         goto bail;
 790     }
 791 
 792     if (fstat(fd, &sbuf) >= 0 && sbuf.st_size < LOCKSTRLEN) {
 793         sleep(2);           /* if someone was about to create one,
 794                              * give'm a sec to do so
 795                              */
 796     }
 797 
 798     if (read(fd, buf, sizeof(buf)) < 1) {
 799         goto bail;
 800     }
 801 
 802     if (sscanf(buf, "%lu", &pid) > 0) {
 803         if (pid <= 0) {
 804             pid = -ESRCH;
 805         } else {
 806             crm_trace("Got pid %lu from %s\n", pid, filename);
 807         }
 808     }
 809 
 810   bail:
 811     if (fd >= 0) {
 812         close(fd);
 813     }
 814     return pid;
 815 }
 816 
 817 long
 818 crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
     /* [previous][next][first][last][top][bottom][index][help] */
 819 {
 820     long pid = crm_read_pidfile(filename);
 821 
 822     if (pid < 2) {
 823         /* Invalid pid */
 824         pid = -ENOENT;
 825         unlink(filename);
 826 
 827     } else if (mypid && pid == mypid) {
 828         /* In use by us */
 829         pid = pcmk_ok;
 830 
 831     } else if (crm_pid_active(pid, daemon) == FALSE) {
 832         /* Contains a stale value */
 833         unlink(filename);
 834         pid = -ENOENT;
 835 
 836     } else if (mypid && pid != mypid) {
 837         /* locked by existing process - give up */
 838         pid = -EEXIST;
 839     }
 840 
 841     return pid;
 842 }
 843 
 844 static int
 845 crm_lock_pidfile(const char *filename, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 846 {
 847     long mypid = 0;
 848     int fd = 0, rc = 0;
 849     char buf[LOCKSTRLEN + 1];
 850 
 851     mypid = (unsigned long)getpid();
 852 
 853     rc = crm_pidfile_inuse(filename, 0, name);
 854     if (rc == -ENOENT) {
 855         /* exists but the process is not active */
 856 
 857     } else if (rc != pcmk_ok) {
 858         /* locked by existing process - give up */
 859         return rc;
 860     }
 861 
 862     if ((fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644)) < 0) {
 863         /* Hmmh, why did we fail? Anyway, nothing we can do about it */
 864         return -errno;
 865     }
 866 
 867     snprintf(buf, sizeof(buf), "%*lu\n", LOCKSTRLEN - 1, mypid);
 868     rc = write(fd, buf, LOCKSTRLEN);
 869     close(fd);
 870 
 871     if (rc != LOCKSTRLEN) {
 872         crm_perror(LOG_ERR, "Incomplete write to %s", filename);
 873         return -errno;
 874     }
 875 
 876     return crm_pidfile_inuse(filename, mypid, name);
 877 }
 878 
 879 void
 880 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
     /* [previous][next][first][last][top][bottom][index][help] */
 881 {
 882     int rc;
 883     long pid;
 884     const char *devnull = "/dev/null";
 885 
 886     if (daemonize == FALSE) {
 887         return;
 888     }
 889 
 890     /* Check before we even try... */
 891     rc = crm_pidfile_inuse(pidfile, 1, name);
 892     if(rc < pcmk_ok && rc != -ENOENT) {
 893         pid = crm_read_pidfile(pidfile);
 894         crm_err("%s: already running [pid %ld in %s]", name, pid, pidfile);
 895         printf("%s: already running [pid %ld in %s]\n", name, pid, pidfile);
 896         crm_exit(rc);
 897     }
 898 
 899     pid = fork();
 900     if (pid < 0) {
 901         fprintf(stderr, "%s: could not start daemon\n", name);
 902         crm_perror(LOG_ERR, "fork");
 903         crm_exit(EINVAL);
 904 
 905     } else if (pid > 0) {
 906         crm_exit(pcmk_ok);
 907     }
 908 
 909     rc = crm_lock_pidfile(pidfile, name);
 910     if(rc < pcmk_ok) {
 911         crm_err("Could not lock '%s' for %s: %s (%d)", pidfile, name, pcmk_strerror(rc), rc);
 912         printf("Could not lock '%s' for %s: %s (%d)\n", pidfile, name, pcmk_strerror(rc), rc);
 913         crm_exit(rc);
 914     }
 915 
 916     umask(S_IWGRP | S_IWOTH | S_IROTH);
 917 
 918     close(STDIN_FILENO);
 919     (void)open(devnull, O_RDONLY);      /* Stdin:  fd 0 */
 920     close(STDOUT_FILENO);
 921     (void)open(devnull, O_WRONLY);      /* Stdout: fd 1 */
 922     close(STDERR_FILENO);
 923     (void)open(devnull, O_WRONLY);      /* Stderr: fd 2 */
 924 }
 925 
 926 char *
 927 crm_meta_name(const char *field)
     /* [previous][next][first][last][top][bottom][index][help] */
 928 {
 929     int lpc = 0;
 930     int max = 0;
 931     char *crm_name = NULL;
 932 
 933     CRM_CHECK(field != NULL, return NULL);
 934     crm_name = crm_concat(CRM_META, field, '_');
 935 
 936     /* Massage the names so they can be used as shell variables */
 937     max = strlen(crm_name);
 938     for (; lpc < max; lpc++) {
 939         switch (crm_name[lpc]) {
 940             case '-':
 941                 crm_name[lpc] = '_';
 942                 break;
 943         }
 944     }
 945     return crm_name;
 946 }
 947 
 948 const char *
 949 crm_meta_value(GHashTable * hash, const char *field)
     /* [previous][next][first][last][top][bottom][index][help] */
 950 {
 951     char *key = NULL;
 952     const char *value = NULL;
 953 
 954     key = crm_meta_name(field);
 955     if (key) {
 956         value = g_hash_table_lookup(hash, key);
 957         free(key);
 958     }
 959 
 960     return value;
 961 }
 962 
 963 static struct option *
 964 crm_create_long_opts(struct crm_option *long_options)
     /* [previous][next][first][last][top][bottom][index][help] */
 965 {
 966     struct option *long_opts = NULL;
 967 
 968 #ifdef HAVE_GETOPT_H
 969     int index = 0, lpc = 0;
 970 
 971     /*
 972      * A previous, possibly poor, choice of '?' as the short form of --help
 973      * means that getopt_long() returns '?' for both --help and for "unknown option"
 974      *
 975      * This dummy entry allows us to differentiate between the two in crm_get_option()
 976      * and exit with the correct error code
 977      */
 978     long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
 979     long_opts[index].name = "__dummmy__";
 980     long_opts[index].has_arg = 0;
 981     long_opts[index].flag = 0;
 982     long_opts[index].val = '_';
 983     index++;
 984 
 985     for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
 986         if (long_options[lpc].name[0] == '-') {
 987             continue;
 988         }
 989 
 990         long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
 991         /*fprintf(stderr, "Creating %d %s = %c\n", index,
 992          * long_options[lpc].name, long_options[lpc].val);      */
 993         long_opts[index].name = long_options[lpc].name;
 994         long_opts[index].has_arg = long_options[lpc].has_arg;
 995         long_opts[index].flag = long_options[lpc].flag;
 996         long_opts[index].val = long_options[lpc].val;
 997         index++;
 998     }
 999 
1000     /* Now create the list terminator */
1001     long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1002     long_opts[index].name = NULL;
1003     long_opts[index].has_arg = 0;
1004     long_opts[index].flag = 0;
1005     long_opts[index].val = 0;
1006 #endif
1007 
1008     return long_opts;
1009 }
1010 
1011 void
1012 crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options,
     /* [previous][next][first][last][top][bottom][index][help] */
1013                 const char *app_desc)
1014 {
1015     if (short_options) {
1016         crm_short_options = strdup(short_options);
1017 
1018     } else if (long_options) {
1019         int lpc = 0;
1020         int opt_string_len = 0;
1021         char *local_short_options = NULL;
1022 
1023         for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1024             if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
1025                 local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
1026                 local_short_options[opt_string_len++] = long_options[lpc].val;
1027                 /* getopt(3) says: Two colons mean an option takes an optional arg; */
1028                 if (long_options[lpc].has_arg == optional_argument) {
1029                     local_short_options[opt_string_len++] = ':';
1030                 }
1031                 if (long_options[lpc].has_arg >= required_argument) {
1032                     local_short_options[opt_string_len++] = ':';
1033                 }
1034                 local_short_options[opt_string_len] = 0;
1035             }
1036         }
1037         crm_short_options = local_short_options;
1038         crm_trace("Generated short option string: '%s'", local_short_options);
1039     }
1040 
1041     if (long_options) {
1042         crm_long_options = long_options;
1043     }
1044     if (app_desc) {
1045         crm_app_description = app_desc;
1046     }
1047     if (app_usage) {
1048         crm_app_usage = app_usage;
1049     }
1050 }
1051 
1052 int
1053 crm_get_option(int argc, char **argv, int *index)
     /* [previous][next][first][last][top][bottom][index][help] */
1054 {
1055     return crm_get_option_long(argc, argv, index, NULL);
1056 }
1057 
1058 int
1059 crm_get_option_long(int argc, char **argv, int *index, const char **longname)
     /* [previous][next][first][last][top][bottom][index][help] */
1060 {
1061 #ifdef HAVE_GETOPT_H
1062     static struct option *long_opts = NULL;
1063 
1064     if (long_opts == NULL && crm_long_options) {
1065         long_opts = crm_create_long_opts(crm_long_options);
1066     }
1067 
1068     *index = 0;
1069     if (long_opts) {
1070         int flag = getopt_long(argc, argv, crm_short_options, long_opts, index);
1071 
1072         switch (flag) {
1073             case 0:
1074                 if (long_opts[*index].val) {
1075                     return long_opts[*index].val;
1076                 } else if (longname) {
1077                     *longname = long_opts[*index].name;
1078                 } else {
1079                     crm_notice("Unhandled option --%s", long_opts[*index].name);
1080                     return flag;
1081                 }
1082             case -1:           /* End of option processing */
1083                 break;
1084             case ':':
1085                 crm_trace("Missing argument");
1086                 crm_help('?', 1);
1087                 break;
1088             case '?':
1089                 crm_help('?', *index ? 0 : 1);
1090                 break;
1091         }
1092         return flag;
1093     }
1094 #endif
1095 
1096     if (crm_short_options) {
1097         return getopt(argc, argv, crm_short_options);
1098     }
1099 
1100     return -1;
1101 }
1102 
1103 int
1104 crm_help(char cmd, int exit_code)
     /* [previous][next][first][last][top][bottom][index][help] */
1105 {
1106     int i = 0;
1107     FILE *stream = (exit_code ? stderr : stdout);
1108 
1109     if (cmd == 'v' || cmd == '$') {
1110         fprintf(stream, "Pacemaker %s\n", PACEMAKER_VERSION);
1111         fprintf(stream, "Written by Andrew Beekhof\n");
1112         goto out;
1113     }
1114 
1115     if (cmd == '!') {
1116         fprintf(stream, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
1117         goto out;
1118     }
1119 
1120     fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description);
1121 
1122     if (crm_app_usage) {
1123         fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage);
1124     }
1125 
1126     if (crm_long_options) {
1127         fprintf(stream, "Options:\n");
1128         for (i = 0; crm_long_options[i].name != NULL; i++) {
1129             if (crm_long_options[i].flags & pcmk_option_hidden) {
1130 
1131             } else if (crm_long_options[i].flags & pcmk_option_paragraph) {
1132                 fprintf(stream, "%s\n\n", crm_long_options[i].desc);
1133 
1134             } else if (crm_long_options[i].flags & pcmk_option_example) {
1135                 fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc);
1136 
1137             } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) {
1138                 fprintf(stream, "%s\n", crm_long_options[i].desc);
1139 
1140             } else {
1141                 /* is val printable as char ? */
1142                 if (crm_long_options[i].val && crm_long_options[i].val <= UCHAR_MAX) {
1143                     fprintf(stream, " -%c,", crm_long_options[i].val);
1144                 } else {
1145                     fputs("    ", stream);
1146                 }
1147                 fprintf(stream, " --%s%s\t%s\n", crm_long_options[i].name,
1148                         crm_long_options[i].has_arg == optional_argument ? "[=value]" :
1149                         crm_long_options[i].has_arg == required_argument ? "=value" : "",
1150                         crm_long_options[i].desc ? crm_long_options[i].desc : "");
1151             }
1152         }
1153 
1154     } else if (crm_short_options) {
1155         fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description);
1156         for (i = 0; crm_short_options[i] != 0; i++) {
1157             int has_arg = no_argument /* 0 */;
1158 
1159             if (crm_short_options[i + 1] == ':') {
1160                 if (crm_short_options[i + 2] == ':')
1161                     has_arg = optional_argument /* 2 */;
1162                 else
1163                     has_arg = required_argument /* 1 */;
1164             }
1165 
1166             fprintf(stream, " -%c %s\n", crm_short_options[i],
1167                     has_arg == optional_argument ? "[value]" :
1168                     has_arg == required_argument ? "{value}" : "");
1169             i += has_arg;
1170         }
1171     }
1172 
1173     fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT);
1174 
1175   out:
1176     return crm_exit(exit_code);
1177 }
1178 
1179 void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro,
     /* [previous][next][first][last][top][bottom][index][help] */
1180         qb_ipcs_service_t **ipcs_rw,
1181         qb_ipcs_service_t **ipcs_shm,
1182         struct qb_ipcs_service_handlers *ro_cb,
1183         struct qb_ipcs_service_handlers *rw_cb)
1184 {
1185     *ipcs_ro = mainloop_add_ipc_server(cib_channel_ro, QB_IPC_NATIVE, ro_cb);
1186     *ipcs_rw = mainloop_add_ipc_server(cib_channel_rw, QB_IPC_NATIVE, rw_cb);
1187     *ipcs_shm = mainloop_add_ipc_server(cib_channel_shm, QB_IPC_SHM, rw_cb);
1188 
1189     if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) {
1190         crm_err("Failed to create cib servers: exiting and inhibiting respawn.");
1191         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1192         crm_exit(DAEMON_RESPAWN_STOP);
1193     }
1194 }
1195 
1196 void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
     /* [previous][next][first][last][top][bottom][index][help] */
1197         qb_ipcs_service_t *ipcs_rw,
1198         qb_ipcs_service_t *ipcs_shm)
1199 {
1200     qb_ipcs_destroy(ipcs_ro);
1201     qb_ipcs_destroy(ipcs_rw);
1202     qb_ipcs_destroy(ipcs_shm);
1203 }
1204 
1205 qb_ipcs_service_t *
1206 crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
     /* [previous][next][first][last][top][bottom][index][help] */
1207 {
1208     return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb);
1209 }
1210 
1211 void
1212 attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
     /* [previous][next][first][last][top][bottom][index][help] */
1213 {
1214     *ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, cb);
1215 
1216     if (*ipcs == NULL) {
1217         crm_err("Failed to create attrd servers: exiting and inhibiting respawn.");
1218         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1219         crm_exit(DAEMON_RESPAWN_STOP);
1220     }
1221 }
1222 
1223 void
1224 stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
     /* [previous][next][first][last][top][bottom][index][help] */
1225 {
1226     *ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, cb);
1227 
1228     if (*ipcs == NULL) {
1229         crm_err("Failed to create stonith-ng servers: exiting and inhibiting respawn.");
1230         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1231         crm_exit(DAEMON_RESPAWN_STOP);
1232     }
1233 }
1234 
1235 bool
1236 pcmk_acl_required(const char *user) 
     /* [previous][next][first][last][top][bottom][index][help] */
1237 {
1238 #if ENABLE_ACL
1239     if(user == NULL || strlen(user) == 0) {
1240         crm_trace("no user set");
1241         return FALSE;
1242 
1243     } else if (strcmp(user, CRM_DAEMON_USER) == 0) {
1244         return FALSE;
1245 
1246     } else if (strcmp(user, "root") == 0) {
1247         return FALSE;
1248     }
1249     crm_trace("acls required for %s", user);
1250     return TRUE;
1251 #else
1252     crm_trace("acls not supported");
1253     return FALSE;
1254 #endif
1255 }
1256 
1257 #if ENABLE_ACL
1258 char *
1259 uid2username(uid_t uid)
     /* [previous][next][first][last][top][bottom][index][help] */
1260 {
1261     struct passwd *pwent = getpwuid(uid);
1262 
1263     if (pwent == NULL) {
1264         crm_perror(LOG_ERR, "Cannot get password entry of uid: %d", uid);
1265         return NULL;
1266 
1267     } else {
1268         return strdup(pwent->pw_name);
1269     }
1270 }
1271 
1272 const char *
1273 crm_acl_get_set_user(xmlNode * request, const char *field, const char *peer_user)
     /* [previous][next][first][last][top][bottom][index][help] */
1274 {
1275     /* field is only checked for backwards compatibility */
1276     static const char *effective_user = NULL;
1277     const char *requested_user = NULL;
1278     const char *user = NULL;
1279 
1280     if(effective_user == NULL) {
1281         effective_user = uid2username(geteuid());
1282     }
1283 
1284     requested_user = crm_element_value(request, XML_ACL_TAG_USER);
1285     if(requested_user == NULL) {
1286         requested_user = crm_element_value(request, field);
1287     }
1288 
1289     if (is_privileged(effective_user) == FALSE) {
1290         /* We're not running as a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
1291         user = effective_user;
1292 
1293     } else if(peer_user == NULL && requested_user == NULL) {
1294         /* No user known or requested, use 'effective_user' and make sure one is set for the request */
1295         user = effective_user;
1296 
1297     } else if(peer_user == NULL) {
1298         /* No user known, trusting 'requested_user' */
1299         user = requested_user;
1300 
1301     } else if (is_privileged(peer_user) == FALSE) {
1302         /* The peer is not a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
1303         user = peer_user;
1304 
1305     } else if (requested_user == NULL) {
1306         /* Even if we're privileged, make sure there is always a value set */
1307         user = peer_user;
1308 
1309     } else {
1310         /* Legal delegation to 'requested_user' */
1311         user = requested_user;
1312     }
1313 
1314     // This requires pointer comparison, not string comparison
1315     if(user != crm_element_value(request, XML_ACL_TAG_USER)) {
1316         crm_xml_add(request, XML_ACL_TAG_USER, user);
1317     }
1318 
1319     if(field != NULL && user != crm_element_value(request, field)) {
1320         crm_xml_add(request, field, user);
1321     }
1322 
1323     return requested_user;
1324 }
1325 
1326 void
1327 determine_request_user(const char *user, xmlNode * request, const char *field)
     /* [previous][next][first][last][top][bottom][index][help] */
1328 {
1329     /* Get our internal validation out of the way first */
1330     CRM_CHECK(user != NULL && request != NULL && field != NULL, return);
1331 
1332     /* If our peer is a privileged user, we might be doing something on behalf of someone else */
1333     if (is_privileged(user) == FALSE) {
1334         /* We're not a privileged user, set or overwrite any existing value for $field */
1335         crm_xml_replace(request, field, user);
1336 
1337     } else if (crm_element_value(request, field) == NULL) {
1338         /* Even if we're privileged, make sure there is always a value set */
1339         crm_xml_replace(request, field, user);
1340 
1341 /*  } else { Legal delegation */
1342     }
1343 
1344     crm_trace("Processing msg as user '%s'", crm_element_value(request, field));
1345 }
1346 #endif
1347 
1348 void *
1349 find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
     /* [previous][next][first][last][top][bottom][index][help] */
1350 {
1351     char *error;
1352     void *a_function;
1353 
1354     if (*handle == NULL) {
1355         *handle = dlopen(lib, RTLD_LAZY);
1356     }
1357 
1358     if (!(*handle)) {
1359         crm_err("%sCould not open %s: %s", fatal ? "Fatal: " : "", lib, dlerror());
1360         if (fatal) {
1361             crm_exit(DAEMON_RESPAWN_STOP);
1362         }
1363         return NULL;
1364     }
1365 
1366     a_function = dlsym(*handle, fn);
1367     if (a_function == NULL) {
1368         error = dlerror();
1369         crm_err("%sCould not find %s in %s: %s", fatal ? "Fatal: " : "", fn, lib, error);
1370         if (fatal) {
1371             crm_exit(DAEMON_RESPAWN_STOP);
1372         }
1373     }
1374 
1375     return a_function;
1376 }
1377 
1378 void *
1379 convert_const_pointer(const void *ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1380 {
1381     /* Worst function ever */
1382     return (void *)ptr;
1383 }
1384 
1385 #ifdef HAVE_UUID_UUID_H
1386 #  include <uuid/uuid.h>
1387 #endif
1388 
1389 char *
1390 crm_generate_uuid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1391 {
1392     unsigned char uuid[16];
1393     char *buffer = malloc(37);  /* Including NUL byte */
1394 
1395     uuid_generate(uuid);
1396     uuid_unparse(uuid, buffer);
1397     return buffer;
1398 }
1399 
1400 /*!
1401  * \brief Check whether a string represents a cluster daemon name
1402  *
1403  * \param[in] name  String to check
1404  *
1405  * \return TRUE if name is standard client name used by daemons, FALSE otherwise
1406  */
1407 bool
1408 crm_is_daemon_name(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
1409 {
1410     return (name &&
1411             (!strcmp(name, CRM_SYSTEM_CRMD)
1412             || !strcmp(name, CRM_SYSTEM_STONITHD)
1413             || !strcmp(name, T_ATTRD)
1414             || !strcmp(name, CRM_SYSTEM_CIB)
1415             || !strcmp(name, CRM_SYSTEM_MCP)
1416             || !strcmp(name, CRM_SYSTEM_DC)
1417             || !strcmp(name, CRM_SYSTEM_TENGINE)
1418             || !strcmp(name, CRM_SYSTEM_LRMD)));
1419 }
1420 
1421 #include <md5.h>
1422 
1423 char *
1424 crm_md5sum(const char *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
1425 {
1426     int lpc = 0, len = 0;
1427     char *digest = NULL;
1428     unsigned char raw_digest[MD5_DIGEST_SIZE];
1429 
1430     if (buffer == NULL) {
1431         buffer = "";
1432     }
1433     len = strlen(buffer);
1434 
1435     crm_trace("Beginning digest of %d bytes", len);
1436     digest = malloc(2 * MD5_DIGEST_SIZE + 1);
1437     if(digest) {
1438         md5_buffer(buffer, len, raw_digest);
1439         for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
1440             sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
1441         }
1442         digest[(2 * MD5_DIGEST_SIZE)] = 0;
1443         crm_trace("Digest %s.", digest);
1444 
1445     } else {
1446         crm_err("Could not create digest");
1447     }
1448     return digest;
1449 }
1450 
1451 #ifdef HAVE_GNUTLS_GNUTLS_H
1452 void
1453 crm_gnutls_global_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1454 {
1455     signal(SIGPIPE, SIG_IGN);
1456     gnutls_global_init();
1457 }
1458 #endif
1459 
1460 char *
1461 crm_generate_ra_key(const char *class, const char *provider, const char *type)
     /* [previous][next][first][last][top][bottom][index][help] */
1462 {
1463     if (!class && !provider && !type) {
1464         return NULL;
1465     }
1466 
1467     return crm_strdup_printf("%s%s%s:%s",
1468                              (class? class : ""),
1469                              (provider? ":" : ""), (provider? provider : ""),
1470                              (type? type : ""));
1471 }
1472 
1473 /*!
1474  * \brief Check whether a resource standard requires a provider to be specified
1475  *
1476  * \param[in] standard  Standard name
1477  *
1478  * \return TRUE if standard requires a provider, FALSE otherwise
1479  */
1480 bool
1481 crm_provider_required(const char *standard)
     /* [previous][next][first][last][top][bottom][index][help] */
1482 {
1483     CRM_CHECK(standard != NULL, return FALSE);
1484 
1485     /* @TODO
1486      * - this should probably be case-sensitive, but isn't,
1487      *   for backward compatibility
1488      * - it might be nice to keep standards' capabilities (supports provider,
1489      *   master/slave, etc.) as structured data somewhere
1490      */
1491     if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF)) {
1492         return TRUE;
1493     }
1494     return FALSE;
1495 }
1496 
1497 /*!
1498  * \brief Parse a "standard[:provider]:type" agent specification
1499  *
1500  * \param[in]  spec      Agent specification
1501  * \param[out] standard  Newly allocated memory containing agent standard (or NULL)
1502  * \param[out] provider  Newly allocated memory containing agent provider (or NULL)
1503  * \param[put] type      Newly allocated memory containing agent type (or NULL)
1504  *
1505  * \return pcmk_ok if the string could be parsed, -EINVAL otherwise
1506  *
1507  * \note It is acceptable for the type to contain a ':' if the standard supports
1508  *       that. For example, systemd supports the form "systemd:UNIT@A:B".
1509  * \note It is the caller's responsibility to free the returned values.
1510  */
1511 int
1512 crm_parse_agent_spec(const char *spec, char **standard, char **provider,
     /* [previous][next][first][last][top][bottom][index][help] */
1513                      char **type)
1514 {
1515     char *colon;
1516 
1517     CRM_CHECK(spec && standard && provider && type, return -EINVAL);
1518     *standard = NULL;
1519     *provider = NULL;
1520     *type = NULL;
1521 
1522     colon = strchr(spec, ':');
1523     if ((colon == NULL) || (colon == spec)) {
1524         return -EINVAL;
1525     }
1526 
1527     *standard = calloc(colon - spec + 1, sizeof(char));
1528     strncpy(*standard, spec, colon - spec);
1529     spec = colon + 1;
1530 
1531     if (crm_provider_required(*standard)) {
1532         colon = strchr(spec, ':');
1533         if ((colon == NULL) || (colon == spec)) {
1534             free(*standard);
1535             return -EINVAL;
1536         }
1537         *provider = calloc(colon - spec + 1, sizeof(char));
1538         strncpy(*provider, spec, colon - spec);
1539         spec = colon + 1;
1540     }
1541 
1542     if (*spec == '\0') {
1543         free(*standard);
1544         free(*provider);
1545         return -EINVAL;
1546     }
1547 
1548     *type = strdup(spec);
1549     return pcmk_ok;
1550 }

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