| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <crm_internal.h> |
| |
| #ifndef _GNU_SOURCE |
| # define _GNU_SOURCE |
| #endif |
| |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <sys/stat.h> |
| #include <sys/utsname.h> |
| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <limits.h> |
| #include <pwd.h> |
| #include <time.h> |
| #include <libgen.h> |
| #include <signal.h> |
| |
| #include <qb/qbdefs.h> |
| |
| #include <crm/crm.h> |
| #include <crm/services.h> |
| #include <crm/msg_xml.h> |
| #include <crm/cib/internal.h> |
| #include <crm/common/xml.h> |
| #include <crm/common/util.h> |
| #include <crm/common/ipc.h> |
| #include <crm/common/iso8601.h> |
| #include <crm/common/mainloop.h> |
| #include <libxml2/libxml/relaxng.h> |
| |
| #include "crmcommon_private.h" |
| |
| #ifndef PW_BUFFER_LEN |
| # define PW_BUFFER_LEN 500 |
| #endif |
| |
| CRM_TRACE_INIT_DATA(common); |
| |
| bool pcmk__config_error = false; |
| bool pcmk__config_warning = false; |
| char *crm_system_name = NULL; |
| |
| int pcmk__score_red = 0; |
| int pcmk__score_green = 0; |
| int pcmk__score_yellow = 0; |
| |
| int |
| char2score(const char *score) |
| { |
| int score_f = 0; |
| |
| if (score == NULL) { |
| |
| } else if (pcmk_str_is_minus_infinity(score)) { |
| score_f = -CRM_SCORE_INFINITY; |
| |
| } else if (pcmk_str_is_infinity(score)) { |
| score_f = CRM_SCORE_INFINITY; |
| |
| } else if (pcmk__str_eq(score, "red", pcmk__str_casei)) { |
| score_f = pcmk__score_red; |
| |
| } else if (pcmk__str_eq(score, "yellow", pcmk__str_casei)) { |
| score_f = pcmk__score_yellow; |
| |
| } else if (pcmk__str_eq(score, "green", pcmk__str_casei)) { |
| score_f = pcmk__score_green; |
| |
| } else { |
| score_f = crm_parse_int(score, NULL); |
| if (score_f > 0 && score_f > CRM_SCORE_INFINITY) { |
| score_f = CRM_SCORE_INFINITY; |
| |
| } else if (score_f < 0 && score_f < -CRM_SCORE_INFINITY) { |
| score_f = -CRM_SCORE_INFINITY; |
| } |
| } |
| |
| return score_f; |
| } |
| |
| char * |
| score2char_stack(int score, char *buf, size_t len) |
| { |
| if (score >= CRM_SCORE_INFINITY) { |
| strncpy(buf, CRM_INFINITY_S, 9); |
| } else if (score <= -CRM_SCORE_INFINITY) { |
| strncpy(buf, CRM_MINUS_INFINITY_S , 10); |
| } else { |
| return crm_itoa_stack(score, buf, len); |
| } |
| |
| return buf; |
| } |
| |
| char * |
| score2char(int score) |
| { |
| if (score >= CRM_SCORE_INFINITY) { |
| return strdup(CRM_INFINITY_S); |
| |
| } else if (score <= -CRM_SCORE_INFINITY) { |
| return strdup(CRM_MINUS_INFINITY_S); |
| } |
| return crm_itoa(score); |
| } |
| |
| int |
| crm_user_lookup(const char *name, uid_t * uid, gid_t * gid) |
| { |
| int rc = pcmk_ok; |
| char *buffer = NULL; |
| struct passwd pwd; |
| struct passwd *pwentry = NULL; |
| |
| buffer = calloc(1, PW_BUFFER_LEN); |
| if (buffer == NULL) { |
| return -ENOMEM; |
| } |
| |
| rc = getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry); |
| if (pwentry) { |
| if (uid) { |
| *uid = pwentry->pw_uid; |
| } |
| if (gid) { |
| *gid = pwentry->pw_gid; |
| } |
| crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid); |
| |
| } else { |
| rc = rc? -rc : -EINVAL; |
| crm_info("User %s lookup: %s", name, pcmk_strerror(rc)); |
| } |
| |
| free(buffer); |
| return rc; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int |
| pcmk_daemon_user(uid_t *uid, gid_t *gid) |
| { |
| static uid_t daemon_uid; |
| static gid_t daemon_gid; |
| static bool found = false; |
| int rc = pcmk_err_generic; |
| |
| if (!found) { |
| rc = crm_user_lookup(CRM_DAEMON_USER, &daemon_uid, &daemon_gid); |
| if (rc == pcmk_ok) { |
| found = true; |
| } |
| } |
| if (found) { |
| if (uid) { |
| *uid = daemon_uid; |
| } |
| if (gid) { |
| *gid = daemon_gid; |
| } |
| } |
| return rc; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| static int |
| version_helper(const char *text, const char **end_text) |
| { |
| int atoi_result = -1; |
| |
| CRM_ASSERT(end_text != NULL); |
| |
| errno = 0; |
| |
| if (text != NULL && text[0] != 0) { |
| |
| |
| |
| |
| |
| |
| atoi_result = (int) strtol(text, (char **) end_text, 10); |
| |
| if (errno == EINVAL) { |
| crm_err("Conversion of '%s' %c failed", text, text[0]); |
| atoi_result = -1; |
| } |
| } |
| return atoi_result; |
| } |
| |
| |
| |
| |
| |
| |
| int |
| compare_version(const char *version1, const char *version2) |
| { |
| int rc = 0; |
| int lpc = 0; |
| const char *ver1_iter, *ver2_iter; |
| |
| if (version1 == NULL && version2 == NULL) { |
| return 0; |
| } else if (version1 == NULL) { |
| return -1; |
| } else if (version2 == NULL) { |
| return 1; |
| } |
| |
| ver1_iter = version1; |
| ver2_iter = version2; |
| |
| while (1) { |
| int digit1 = 0; |
| int digit2 = 0; |
| |
| lpc++; |
| |
| if (ver1_iter == ver2_iter) { |
| break; |
| } |
| |
| if (ver1_iter != NULL) { |
| digit1 = version_helper(ver1_iter, &ver1_iter); |
| } |
| |
| if (ver2_iter != NULL) { |
| digit2 = version_helper(ver2_iter, &ver2_iter); |
| } |
| |
| if (digit1 < digit2) { |
| rc = -1; |
| break; |
| |
| } else if (digit1 > digit2) { |
| rc = 1; |
| break; |
| } |
| |
| if (ver1_iter != NULL && *ver1_iter == '.') { |
| ver1_iter++; |
| } |
| if (ver1_iter != NULL && *ver1_iter == '\0') { |
| ver1_iter = NULL; |
| } |
| |
| if (ver2_iter != NULL && *ver2_iter == '.') { |
| ver2_iter++; |
| } |
| if (ver2_iter != NULL && *ver2_iter == 0) { |
| ver2_iter = NULL; |
| } |
| } |
| |
| if (rc == 0) { |
| crm_trace("%s == %s (%d)", version1, version2, lpc); |
| } else if (rc < 0) { |
| crm_trace("%s < %s (%d)", version1, version2, lpc); |
| } else if (rc > 0) { |
| crm_trace("%s > %s (%d)", version1, version2, lpc); |
| } |
| |
| return rc; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| guint |
| crm_parse_interval_spec(const char *input) |
| { |
| long long msec = -1; |
| |
| errno = 0; |
| if (input == NULL) { |
| return 0; |
| |
| } else if (input[0] == 'P') { |
| crm_time_t *period_s = crm_time_parse_duration(input); |
| |
| if (period_s) { |
| msec = 1000 * crm_time_get_seconds(period_s); |
| crm_time_free(period_s); |
| } |
| |
| } else { |
| msec = crm_get_msec(input); |
| } |
| |
| if (msec < 0) { |
| crm_warn("Using 0 instead of '%s'", input); |
| errno = EINVAL; |
| return 0; |
| } |
| return (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec; |
| } |
| |
| |
| void |
| crm_abort(const char *file, const char *function, int line, |
| const char *assert_condition, gboolean do_core, gboolean do_fork) |
| { |
| int rc = 0; |
| int pid = 0; |
| int status = 0; |
| |
| |
| |
| |
| if (!pcmk__is_daemon) { |
| |
| |
| |
| crm_enable_stderr(TRUE); |
| do_fork = FALSE; |
| } |
| |
| if (do_core == FALSE) { |
| crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition); |
| return; |
| |
| } else if (do_fork) { |
| pid = fork(); |
| |
| } else { |
| crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition); |
| } |
| |
| if (pid == -1) { |
| crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s", |
| function, file, line, assert_condition); |
| return; |
| |
| } else if(pid == 0) { |
| |
| abort(); |
| return; |
| } |
| |
| |
| crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s", |
| function, pid, file, line, assert_condition); |
| crm_write_blackbox(SIGTRAP, NULL); |
| |
| do { |
| rc = waitpid(pid, &status, 0); |
| if(rc == pid) { |
| return; |
| } |
| |
| } while(errno == EINTR); |
| |
| if (errno == ECHILD) { |
| |
| crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid); |
| return; |
| } |
| crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void |
| pcmk__daemonize(const char *name, const char *pidfile) |
| { |
| int rc; |
| pid_t pid; |
| |
| |
| rc = pcmk__pidfile_matches(pidfile, 1, name, &pid); |
| if ((rc != pcmk_rc_ok) && (rc != ENOENT)) { |
| crm_err("%s: already running [pid %lld in %s]", |
| name, (long long) pid, pidfile); |
| printf("%s: already running [pid %lld in %s]\n", |
| name, (long long) pid, pidfile); |
| crm_exit(CRM_EX_ERROR); |
| } |
| |
| pid = fork(); |
| if (pid < 0) { |
| fprintf(stderr, "%s: could not start daemon\n", name); |
| crm_perror(LOG_ERR, "fork"); |
| crm_exit(CRM_EX_OSERR); |
| |
| } else if (pid > 0) { |
| crm_exit(CRM_EX_OK); |
| } |
| |
| rc = pcmk__lock_pidfile(pidfile, name); |
| if (rc != pcmk_rc_ok) { |
| crm_err("Could not lock '%s' for %s: %s " CRM_XS " rc=%d", |
| pidfile, name, pcmk_rc_str(rc), rc); |
| printf("Could not lock '%s' for %s: %s (%d)\n", |
| pidfile, name, pcmk_rc_str(rc), rc); |
| crm_exit(CRM_EX_ERROR); |
| } |
| |
| umask(S_IWGRP | S_IWOTH | S_IROTH); |
| |
| close(STDIN_FILENO); |
| pcmk__open_devnull(O_RDONLY); |
| |
| close(STDOUT_FILENO); |
| pcmk__open_devnull(O_WRONLY); |
| |
| close(STDERR_FILENO); |
| pcmk__open_devnull(O_WRONLY); |
| } |
| |
| char * |
| crm_meta_name(const char *field) |
| { |
| int lpc = 0; |
| int max = 0; |
| char *crm_name = NULL; |
| |
| CRM_CHECK(field != NULL, return NULL); |
| crm_name = crm_strdup_printf(CRM_META "_%s", field); |
| |
| |
| max = strlen(crm_name); |
| for (; lpc < max; lpc++) { |
| switch (crm_name[lpc]) { |
| case '-': |
| crm_name[lpc] = '_'; |
| break; |
| } |
| } |
| return crm_name; |
| } |
| |
| const char * |
| crm_meta_value(GHashTable * hash, const char *field) |
| { |
| char *key = NULL; |
| const char *value = NULL; |
| |
| key = crm_meta_name(field); |
| if (key) { |
| value = g_hash_table_lookup(hash, key); |
| free(key); |
| } |
| |
| return value; |
| } |
| |
| #ifdef HAVE_UUID_UUID_H |
| # include <uuid/uuid.h> |
| #endif |
| |
| char * |
| crm_generate_uuid(void) |
| { |
| unsigned char uuid[16]; |
| char *buffer = malloc(37); |
| |
| uuid_generate(uuid); |
| uuid_unparse(uuid, buffer); |
| return buffer; |
| } |
| |
| #ifdef HAVE_GNUTLS_GNUTLS_H |
| void |
| crm_gnutls_global_init(void) |
| { |
| signal(SIGPIPE, SIG_IGN); |
| gnutls_global_init(); |
| } |
| #endif |
| |
| |
| |
| |
| |
| |
| char * |
| pcmk_hostname() |
| { |
| struct utsname hostinfo; |
| |
| return (uname(&hostinfo) < 0)? NULL : strdup(hostinfo.nodename); |
| } |
| |
| bool |
| pcmk_str_is_infinity(const char *s) { |
| return pcmk__str_any_of(s, CRM_INFINITY_S, CRM_PLUS_INFINITY_S, NULL); |
| } |
| |
| bool |
| pcmk_str_is_minus_infinity(const char *s) { |
| return pcmk__str_eq(s, CRM_MINUS_INFINITY_S, pcmk__str_none); |
| } |