This source file includes following definitions.
- pcmk__is_user_in_group
 
- crm_user_lookup
 
- pcmk_daemon_user
 
- version_helper
 
- compare_version
 
- crm_parse_interval_spec
 
- log_assertion_as
 
- abort_as
 
- fail_assert_as
 
- crm_abort
 
- pcmk__daemonize
 
- crm_meta_name
 
- crm_meta_value
 
- crm_generate_uuid
 
- crm_gnutls_global_init
 
- pcmk_hostname
 
- pcmk_str_is_infinity
 
- pcmk_str_is_minus_infinity
 
- pcmk__sleep_ms
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 
  12 #ifndef _GNU_SOURCE
  13 #  define _GNU_SOURCE
  14 #endif
  15 
  16 #include <sys/types.h>
  17 #include <sys/wait.h>
  18 #include <sys/stat.h>
  19 #include <sys/utsname.h>
  20 
  21 #include <stdio.h>
  22 #include <unistd.h>
  23 #include <string.h>
  24 #include <stdlib.h>
  25 #include <limits.h>
  26 #include <pwd.h>
  27 #include <time.h>
  28 #include <libgen.h>
  29 #include <signal.h>
  30 #include <grp.h>
  31 
  32 #include <qb/qbdefs.h>
  33 
  34 #include <crm/crm.h>
  35 #include <crm/services.h>
  36 #include <crm/msg_xml.h>
  37 #include <crm/cib/internal.h>
  38 #include <crm/common/xml.h>
  39 #include <crm/common/util.h>
  40 #include <crm/common/ipc.h>
  41 #include <crm/common/iso8601.h>
  42 #include <crm/common/mainloop.h>
  43 #include <libxml2/libxml/relaxng.h>
  44 
  45 #include "crmcommon_private.h"
  46 
  47 CRM_TRACE_INIT_DATA(common);
  48 
  49 gboolean crm_config_error = FALSE;
  50 gboolean crm_config_warning = FALSE;
  51 char *crm_system_name = NULL;
  52 
  53 bool
  54 pcmk__is_user_in_group(const char *user, const char *group)
     
  55 {
  56     struct group *grent;
  57     char **gr_mem;
  58 
  59     if (user == NULL || group == NULL) {
  60         return false;
  61     }
  62     
  63     setgrent();
  64     while ((grent = getgrent()) != NULL) {
  65         if (grent->gr_mem == NULL) {
  66             continue;
  67         }
  68 
  69         if(strcmp(group, grent->gr_name) != 0) {
  70             continue;
  71         }
  72 
  73         gr_mem = grent->gr_mem;
  74         while (*gr_mem != NULL) {
  75             if (!strcmp(user, *gr_mem++)) {
  76                 endgrent();
  77                 return true;
  78             }
  79         }
  80     }
  81     endgrent();
  82     return false;
  83 }
  84 
  85 int
  86 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
     
  87 {
  88     int rc = pcmk_ok;
  89     char *buffer = NULL;
  90     struct passwd pwd;
  91     struct passwd *pwentry = NULL;
  92 
  93     buffer = calloc(1, PCMK__PW_BUFFER_LEN);
  94     if (buffer == NULL) {
  95         return -ENOMEM;
  96     }
  97 
  98     rc = getpwnam_r(name, &pwd, buffer, PCMK__PW_BUFFER_LEN, &pwentry);
  99     if (pwentry) {
 100         if (uid) {
 101             *uid = pwentry->pw_uid;
 102         }
 103         if (gid) {
 104             *gid = pwentry->pw_gid;
 105         }
 106         crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
 107 
 108     } else {
 109         rc = rc? -rc : -EINVAL;
 110         crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
 111     }
 112 
 113     free(buffer);
 114     return rc;
 115 }
 116 
 117 
 118 
 119 
 120 
 121 
 122 
 123 
 124 
 125 int
 126 pcmk_daemon_user(uid_t *uid, gid_t *gid)
     
 127 {
 128     static uid_t daemon_uid;
 129     static gid_t daemon_gid;
 130     static bool found = false;
 131     int rc = pcmk_ok;
 132 
 133     if (!found) {
 134         rc = crm_user_lookup(CRM_DAEMON_USER, &daemon_uid, &daemon_gid);
 135         if (rc == pcmk_ok) {
 136             found = true;
 137         }
 138     }
 139     if (found) {
 140         if (uid) {
 141             *uid = daemon_uid;
 142         }
 143         if (gid) {
 144             *gid = daemon_gid;
 145         }
 146     }
 147     return rc;
 148 }
 149 
 150 
 151 
 152 
 153 
 154 
 155 
 156 
 157 static int
 158 version_helper(const char *text, const char **end_text)
     
 159 {
 160     int atoi_result = -1;
 161 
 162     CRM_ASSERT(end_text != NULL);
 163 
 164     errno = 0;
 165 
 166     if (text != NULL && text[0] != 0) {
 167         
 168 
 169 
 170 
 171 
 172 
 173         atoi_result = (int) strtol(text, (char **) end_text, 10);
 174 
 175         if (errno == EINVAL) {
 176             crm_err("Conversion of '%s' %c failed", text, text[0]);
 177             atoi_result = -1;
 178         }
 179     }
 180     return atoi_result;
 181 }
 182 
 183 
 184 
 185 
 186 
 187 
 188 int
 189 compare_version(const char *version1, const char *version2)
     
 190 {
 191     int rc = 0;
 192     int lpc = 0;
 193     const char *ver1_iter, *ver2_iter;
 194 
 195     if (version1 == NULL && version2 == NULL) {
 196         return 0;
 197     } else if (version1 == NULL) {
 198         return -1;
 199     } else if (version2 == NULL) {
 200         return 1;
 201     }
 202 
 203     ver1_iter = version1;
 204     ver2_iter = version2;
 205 
 206     while (1) {
 207         int digit1 = 0;
 208         int digit2 = 0;
 209 
 210         lpc++;
 211 
 212         if (ver1_iter == ver2_iter) {
 213             break;
 214         }
 215 
 216         if (ver1_iter != NULL) {
 217             digit1 = version_helper(ver1_iter, &ver1_iter);
 218         }
 219 
 220         if (ver2_iter != NULL) {
 221             digit2 = version_helper(ver2_iter, &ver2_iter);
 222         }
 223 
 224         if (digit1 < digit2) {
 225             rc = -1;
 226             break;
 227 
 228         } else if (digit1 > digit2) {
 229             rc = 1;
 230             break;
 231         }
 232 
 233         if (ver1_iter != NULL && *ver1_iter == '.') {
 234             ver1_iter++;
 235         }
 236         if (ver1_iter != NULL && *ver1_iter == '\0') {
 237             ver1_iter = NULL;
 238         }
 239 
 240         if (ver2_iter != NULL && *ver2_iter == '.') {
 241             ver2_iter++;
 242         }
 243         if (ver2_iter != NULL && *ver2_iter == 0) {
 244             ver2_iter = NULL;
 245         }
 246     }
 247 
 248     if (rc == 0) {
 249         crm_trace("%s == %s (%d)", version1, version2, lpc);
 250     } else if (rc < 0) {
 251         crm_trace("%s < %s (%d)", version1, version2, lpc);
 252     } else if (rc > 0) {
 253         crm_trace("%s > %s (%d)", version1, version2, lpc);
 254     }
 255 
 256     return rc;
 257 }
 258 
 259 
 260 
 261 
 262 
 263 
 264 
 265 
 266 
 267 
 268 
 269 
 270 guint
 271 crm_parse_interval_spec(const char *input)
     
 272 {
 273     long long msec = -1;
 274 
 275     errno = 0;
 276     if (input == NULL) {
 277         return 0;
 278 
 279     } else if (input[0] == 'P') {
 280         crm_time_t *period_s = crm_time_parse_duration(input);
 281 
 282         if (period_s) {
 283             msec = 1000 * crm_time_get_seconds(period_s);
 284             crm_time_free(period_s);
 285         }
 286 
 287     } else {
 288         msec = crm_get_msec(input);
 289     }
 290 
 291     if (msec < 0) {
 292         crm_warn("Using 0 instead of '%s'", input);
 293         errno = EINVAL;
 294         return 0;
 295     }
 296     return (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
 297 }
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 static void
 309 log_assertion_as(const char *file, const char *function, int line,
     
 310                  const char *assert_condition)
 311 {
 312     if (!pcmk__is_daemon) {
 313         crm_enable_stderr(TRUE); 
 314     }
 315     crm_err("%s: Triggered fatal assertion at %s:%d : %s",
 316             function, file, line, assert_condition);
 317 }
 318 
 319 
 320 
 321 
 322 
 323 
 324 
 325 
 326 
 327 
 328 
 329 
 330 
 331 static _Noreturn void
 332 abort_as(const char *file, const char *function, int line,
     
 333          const char *assert_condition)
 334 {
 335     log_assertion_as(file, function, line, assert_condition);
 336     abort();
 337 }
 338 
 339 
 340 
 341 
 342 
 343 
 344 
 345 
 346 
 347 
 348 
 349 
 350 
 351 
 352 static void
 353 fail_assert_as(const char *file, const char *function, int line,
     
 354                const char *assert_condition)
 355 {
 356     int status = 0;
 357     pid_t pid = 0;
 358 
 359     if (!pcmk__is_daemon) {
 360         abort_as(file, function, line, assert_condition); 
 361     }
 362 
 363     pid = fork();
 364     switch (pid) {
 365         case -1: 
 366             crm_warn("%s: Cannot dump core for non-fatal assertion at %s:%d "
 367                      ": %s", function, file, line, assert_condition);
 368             break;
 369 
 370         case 0: 
 371             abort();
 372             break;
 373 
 374         default: 
 375             crm_err("%s: Forked child [%d] to record non-fatal assertion at "
 376                     "%s:%d : %s", function, pid, file, line, assert_condition);
 377             crm_write_blackbox(SIGTRAP, NULL);
 378             do {
 379                 if (waitpid(pid, &status, 0) == pid) {
 380                     return; 
 381                 }
 382             } while (errno == EINTR);
 383             if (errno == ECHILD) {
 384                 
 385                 crm_trace("Cannot wait on forked child [%d] "
 386                           "(SIGCHLD is probably ignored)", pid);
 387             } else {
 388                 crm_err("Cannot wait on forked child [%d]: %s",
 389                         pid, pcmk_rc_str(errno));
 390             }
 391             break;
 392     }
 393 }
 394 
 395 
 396 void
 397 crm_abort(const char *file, const char *function, int line,
     
 398           const char *assert_condition, gboolean do_core, gboolean do_fork)
 399 {
 400     if (!do_fork) {
 401         abort_as(file, function, line, assert_condition);
 402     } else if (do_core) {
 403         fail_assert_as(file, function, line, assert_condition);
 404     } else {
 405         log_assertion_as(file, function, line, assert_condition);
 406     }
 407 }
 408 
 409 
 410 
 411 
 412 
 413 
 414 
 415 
 416 
 417 
 418 
 419 
 420 void
 421 pcmk__daemonize(const char *name, const char *pidfile)
     
 422 {
 423     int rc;
 424     pid_t pid;
 425 
 426     
 427     rc = pcmk__pidfile_matches(pidfile, 1, name, &pid);
 428     if ((rc != pcmk_rc_ok) && (rc != ENOENT)) {
 429         crm_err("%s: already running [pid %lld in %s]",
 430                 name, (long long) pid, pidfile);
 431         printf("%s: already running [pid %lld in %s]\n",
 432                name, (long long) pid, pidfile);
 433         crm_exit(CRM_EX_ERROR);
 434     }
 435 
 436     pid = fork();
 437     if (pid < 0) {
 438         fprintf(stderr, "%s: could not start daemon\n", name);
 439         crm_perror(LOG_ERR, "fork");
 440         crm_exit(CRM_EX_OSERR);
 441 
 442     } else if (pid > 0) {
 443         crm_exit(CRM_EX_OK);
 444     }
 445 
 446     rc = pcmk__lock_pidfile(pidfile, name);
 447     if (rc != pcmk_rc_ok) {
 448         crm_err("Could not lock '%s' for %s: %s " CRM_XS " rc=%d",
 449                 pidfile, name, pcmk_rc_str(rc), rc);
 450         printf("Could not lock '%s' for %s: %s (%d)\n",
 451                pidfile, name, pcmk_rc_str(rc), rc);
 452         crm_exit(CRM_EX_ERROR);
 453     }
 454 
 455     umask(S_IWGRP | S_IWOTH | S_IROTH);
 456 
 457     close(STDIN_FILENO);
 458     pcmk__open_devnull(O_RDONLY);   
 459 
 460     close(STDOUT_FILENO);
 461     pcmk__open_devnull(O_WRONLY);   
 462 
 463     close(STDERR_FILENO);
 464     pcmk__open_devnull(O_WRONLY);   
 465 }
 466 
 467 char *
 468 crm_meta_name(const char *field)
     
 469 {
 470     int lpc = 0;
 471     int max = 0;
 472     char *crm_name = NULL;
 473 
 474     CRM_CHECK(field != NULL, return NULL);
 475     crm_name = crm_strdup_printf(CRM_META "_%s", field);
 476 
 477     
 478     max = strlen(crm_name);
 479     for (; lpc < max; lpc++) {
 480         switch (crm_name[lpc]) {
 481             case '-':
 482                 crm_name[lpc] = '_';
 483                 break;
 484         }
 485     }
 486     return crm_name;
 487 }
 488 
 489 const char *
 490 crm_meta_value(GHashTable * hash, const char *field)
     
 491 {
 492     char *key = NULL;
 493     const char *value = NULL;
 494 
 495     key = crm_meta_name(field);
 496     if (key) {
 497         value = g_hash_table_lookup(hash, key);
 498         free(key);
 499     }
 500 
 501     return value;
 502 }
 503 
 504 #ifdef HAVE_UUID_UUID_H
 505 #  include <uuid/uuid.h>
 506 #endif
 507 
 508 char *
 509 crm_generate_uuid(void)
     
 510 {
 511     unsigned char uuid[16];
 512     char *buffer = malloc(37);  
 513 
 514     CRM_ASSERT(buffer != NULL);
 515     uuid_generate(uuid);
 516     uuid_unparse(uuid, buffer);
 517     return buffer;
 518 }
 519 
 520 #ifdef HAVE_GNUTLS_GNUTLS_H
 521 void
 522 crm_gnutls_global_init(void)
     
 523 {
 524     signal(SIGPIPE, SIG_IGN);
 525     gnutls_global_init();
 526 }
 527 #endif
 528 
 529 
 530 
 531 
 532 
 533 
 534 char *
 535 pcmk_hostname(void)
     
 536 {
 537     struct utsname hostinfo;
 538 
 539     return (uname(&hostinfo) < 0)? NULL : strdup(hostinfo.nodename);
 540 }
 541 
 542 bool
 543 pcmk_str_is_infinity(const char *s) {
     
 544     return pcmk__str_any_of(s, CRM_INFINITY_S, CRM_PLUS_INFINITY_S, NULL);
 545 }
 546 
 547 bool
 548 pcmk_str_is_minus_infinity(const char *s) {
     
 549     return pcmk__str_eq(s, CRM_MINUS_INFINITY_S, pcmk__str_none);
 550 }
 551 
 552 
 553 
 554 
 555 
 556 
 557 
 558 
 559 
 560 void
 561 pcmk__sleep_ms(unsigned int ms)
     
 562 {
 563     
 564     
 565 
 566     
 567     if (ms >= 1000) {
 568         sleep(ms / 1000);
 569         ms -= ms / 1000;
 570     }
 571 
 572     if (ms == 0) {
 573         return;
 574     }
 575 
 576 #if defined(HAVE_NANOSLEEP)
 577     
 578     {
 579         struct timespec req = { .tv_sec = 0, .tv_nsec = (long) (ms * 1000000) };
 580 
 581         nanosleep(&req, NULL);
 582     }
 583 #elif defined(HAVE_USLEEP)
 584     
 585     usleep((useconds_t) ms);
 586 #else
 587     
 588     {
 589         struct timeval tv = { .tv_sec = 0, .tv_usec = (suseconds_t) ms };
 590 
 591         select(0, NULL, NULL, NULL, &tv);
 592     }
 593 #endif
 594 }