diff --git a/lib/common/cib_secrets.c b/lib/common/cib_secrets.c index e17d3222f6..9a565bffe8 100644 --- a/lib/common/cib_secrets.c +++ b/lib/common/cib_secrets.c @@ -1,222 +1,209 @@ /* - * cib_secrets.c - * - * Author: Dejan Muhamedagic * Copyright (c) 2011 SUSE, Attachmate + * Author: Dejan Muhamedagic * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static int do_replace_secret_params(char *rsc_id, GHashTable *params, gboolean from_legacy_dir); static int is_magic_value(char *p); static int check_md5_hash(char *hash, char *value); static void add_secret_params(gpointer key, gpointer value, gpointer user_data); static char *read_local_file(char *local_file); #define MAX_VALUE_LEN 255 #define MAGIC "lrm://" static int is_magic_value(char *p) { return !strcmp(p, MAGIC); } static int check_md5_hash(char *hash, char *value) { int rc = FALSE; char *hash2 = NULL; hash2 = crm_md5sum(value); crm_debug("hash: %s, calculated hash: %s", hash, hash2); if (safe_str_eq(hash, hash2)) { rc = TRUE; } free(hash2); return rc; } static char * read_local_file(char *local_file) { FILE *fp = fopen(local_file, "r"); char buf[MAX_VALUE_LEN+1]; char *p; if (!fp) { if (errno != ENOENT) { crm_perror(LOG_ERR, "cannot open %s" , local_file); } return NULL; } if (!fgets(buf, MAX_VALUE_LEN, fp)) { crm_perror(LOG_ERR, "cannot read %s", local_file); return NULL; } /* strip white space */ for (p = buf+strlen(buf)-1; p >= buf && isspace(*p); p--) ; *(p+1) = '\0'; return strdup(buf); } /* * returns 0 on success or no replacements necessary * returns -1 if replacement failed for whatever reasone */ int replace_secret_params(char *rsc_id, GHashTable *params) { if (do_replace_secret_params(rsc_id, params, FALSE) < 0 && do_replace_secret_params(rsc_id, params, TRUE) < 0) { return -1; } return 0; } static int do_replace_secret_params(char *rsc_id, GHashTable *params, gboolean from_legacy_dir) { char local_file[FILENAME_MAX+1], *start_pname; char hash_file[FILENAME_MAX+1], *hash; GList *secret_params = NULL, *l; char *key, *pvalue, *secret_value; int rc = 0; const char *dir_prefix = NULL; if (params == NULL) { return 0; } if (from_legacy_dir) { dir_prefix = LRM_LEGACY_CIBSECRETS_DIR; } else { dir_prefix = LRM_CIBSECRETS_DIR; } /* secret_params could be cached with the resource; * there are also parameters sent with operations * which cannot be cached */ g_hash_table_foreach(params, add_secret_params, &secret_params); if (!secret_params) { /* none found? */ return 0; } crm_debug("replace secret parameters for resource %s", rsc_id); if (snprintf(local_file, FILENAME_MAX, "%s/%s/", dir_prefix, rsc_id) > FILENAME_MAX) { crm_err("filename size exceeded for resource %s", rsc_id); return -1; } start_pname = local_file + strlen(local_file); for (l = g_list_first(secret_params); l; l = g_list_next(l)) { key = (char *)(l->data); pvalue = g_hash_table_lookup(params, key); if (!pvalue) { /* this cannot really happen */ crm_err("odd, no parameter %s for rsc %s found now", key, rsc_id); continue; } if ((strlen(key) + strlen(local_file)) >= FILENAME_MAX-2) { crm_err("%d: parameter name %s too big", key); rc = -1; continue; } strcpy(start_pname, key); secret_value = read_local_file(local_file); if (!secret_value) { if (from_legacy_dir == FALSE) { crm_debug("secret for rsc %s parameter %s not found in %s. " "will try "LRM_LEGACY_CIBSECRETS_DIR, rsc_id, key, dir_prefix); } else { crm_err("secret for rsc %s parameter %s not found in %s", rsc_id, key, dir_prefix); } rc = -1; continue; } strcpy(hash_file, local_file); if (strlen(hash_file) + 5 > FILENAME_MAX) { crm_err("cannot build such a long name " "for the sign file: %s.sign", hash_file); free(secret_value); rc = -1; continue; } else { strncat(hash_file, ".sign", 5); hash = read_local_file(hash_file); if (hash == NULL) { crm_err("md5 sum for rsc %s parameter %s " "cannot be read from %s", rsc_id, key, hash_file); free(secret_value); rc = -1; continue; } else if (!check_md5_hash(hash, secret_value)) { crm_err("md5 sum for rsc %s parameter %s " "does not match", rsc_id, key); free(secret_value); free(hash); rc = -1; continue; } free(hash); } g_hash_table_replace(params, strdup(key), secret_value); } g_list_free(secret_params); return rc; } static void add_secret_params(gpointer key, gpointer value, gpointer user_data) { GList **lp = (GList **)user_data; if (is_magic_value((char *)value)) { *lp = g_list_append(*lp, (char *)key); } } diff --git a/lib/common/watchdog.c b/lib/common/watchdog.c index 31e6c8bb79..0100b90672 100644 --- a/lib/common/watchdog.c +++ b/lib/common/watchdog.c @@ -1,288 +1,277 @@ /* * Copyright (C) 2013 Lars Marowsky-Bree * 2014 Andrew Beekhof * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #ifdef _POSIX_MEMLOCK # include #endif static int sbd_pid = 0; enum pcmk_panic_flags { pcmk_panic_none = 0x00, pcmk_panic_delay = 0x01, pcmk_panic_kdump = 0x02, pcmk_panic_shutdown = 0x04, }; #define SYSRQ "/proc/sys/kernel/sysrq" void sysrq_init(void) { static bool need_init = true; FILE* procf; int c; if(need_init) { need_init = false; } else { return; } procf = fopen(SYSRQ, "r"); if (!procf) { crm_perror(LOG_ERR, "Cannot open "SYSRQ" for read"); return; } if (fscanf(procf, "%d", &c) != 1) { crm_perror(LOG_ERR, "Parsing "SYSRQ" failed"); c = 0; } fclose(procf); if (c == 1) return; /* 8 for debugging dumps of processes, 128 for reboot/poweroff */ c |= 136; procf = fopen(SYSRQ, "w"); if (!procf) { crm_perror(LOG_ERR, "Cannot write to "SYSRQ); return; } fprintf(procf, "%d", c); fclose(procf); return; } static void sysrq_trigger(char t) { FILE *procf; sysrq_init(); procf = fopen("/proc/sysrq-trigger", "a"); if (!procf) { crm_perror(LOG_ERR, "Opening sysrq-trigger failed"); return; } crm_info("sysrq-trigger: %c", t); fprintf(procf, "%c\n", t); fclose(procf); return; } static void pcmk_panic_local(void) { int rc = pcmk_ok; uid_t uid = geteuid(); pid_t ppid = getppid(); if(uid != 0 && ppid > 1) { /* We're a non-root pacemaker daemon (cib, crmd, pengine, * attrd, etc) with the original pacemakerd parent * * Of these, only crmd is likely to be initiating resets */ do_crm_log_always(LOG_EMERG, "Signaling parent %d to panic", ppid); crm_exit(pcmk_err_panic); return; } else if (uid != 0) { /* * No permissions and no pacemakerd parent to escalate to * Track down the new pacakerd process and send a signal instead */ union sigval signal_value; memset(&signal_value, 0, sizeof(signal_value)); ppid = crm_procfs_pid_of("pacemakerd"); do_crm_log_always(LOG_EMERG, "Signaling pacemakerd(%d) to panic", ppid); if(ppid > 1 && sigqueue(ppid, SIGQUIT, signal_value) < 0) { crm_perror(LOG_EMERG, "Cannot signal pacemakerd(%d) to panic", ppid); } /* The best we can do now is die */ crm_exit(pcmk_err_panic); return; } /* We're either pacemakerd, or a pacemaker daemon running as root */ if (strcmp("crash", getenv("PCMK_panic_action")) == 0) { sysrq_trigger('c'); } else { sysrq_trigger('b'); } /* reboot(RB_HALT_SYSTEM); rc = errno; */ reboot(RB_AUTOBOOT); rc = errno; do_crm_log_always(LOG_EMERG, "Reboot failed, escalating to %d: %s (%d)", ppid, pcmk_strerror(rc), rc); if(ppid > 1) { /* child daemon */ exit(pcmk_err_panic); } else { /* pacemakerd or orphan child */ exit(DAEMON_RESPAWN_STOP); } } static void pcmk_panic_sbd(void) { union sigval signal_value; pid_t ppid = getppid(); do_crm_log_always(LOG_EMERG, "Signaling sbd(%d) to panic", sbd_pid); memset(&signal_value, 0, sizeof(signal_value)); /* TODO: Arrange for a slightly less brutal option? */ if(sigqueue(sbd_pid, SIGKILL, signal_value) < 0) { crm_perror(LOG_EMERG, "Cannot signal SBD(%d) to terminate", sbd_pid); pcmk_panic_local(); } if(ppid > 1) { /* child daemon */ exit(pcmk_err_panic); } else { /* pacemakerd or orphan child */ exit(DAEMON_RESPAWN_STOP); } } void pcmk_panic(const char *origin) { static struct qb_log_callsite *panic_cs = NULL; if (panic_cs == NULL) { panic_cs = qb_log_callsite_get(__func__, __FILE__, "panic-delay", LOG_TRACE, __LINE__, crm_trace_nonlog); } /* Ensure sbd_pid is set */ (void)pcmk_locate_sbd(); if (panic_cs && panic_cs->targets) { /* getppid() == 1 means our original parent no longer exists */ do_crm_log_always(LOG_EMERG, "Shutting down instead of panicking the node: origin=%s, sbd=%d, parent=%d", origin, sbd_pid, getppid()); crm_exit(DAEMON_RESPAWN_STOP); return; } if(sbd_pid > 1) { do_crm_log_always(LOG_EMERG, "Signaling sbd(%d) to panic the system: %s", sbd_pid, origin); pcmk_panic_sbd(); } else { do_crm_log_always(LOG_EMERG, "Panicking the system directly: %s", origin); pcmk_panic_local(); } } pid_t pcmk_locate_sbd(void) { char *pidfile = NULL; char *sbd_path = NULL; if(sbd_pid > 1) { return sbd_pid; } /* Look for the pid file */ pidfile = crm_strdup_printf("%s/sbd.pid", HA_STATE_DIR); sbd_path = crm_strdup_printf("%s/sbd", SBINDIR); /* Read the pid file */ CRM_ASSERT(pidfile); sbd_pid = crm_pidfile_inuse(pidfile, 0, sbd_path); if(sbd_pid > 0) { crm_trace("SBD detected at pid=%d (file)", sbd_pid); } else { /* Fall back to /proc for systems that support it */ sbd_pid = crm_procfs_pid_of("sbd"); crm_trace("SBD detected at pid=%d (proc)", sbd_pid); } if(sbd_pid < 0) { sbd_pid = 0; crm_trace("SBD not detected"); } free(pidfile); free(sbd_path); return sbd_pid; } long crm_get_sbd_timeout(void) { const char *env_value = getenv("SBD_WATCHDOG_TIMEOUT"); long sbd_timeout = crm_get_msec(env_value); return sbd_timeout; } gboolean check_sbd_timeout(const char *value) { long sbd_timeout = crm_get_sbd_timeout(); long st_timeout = crm_get_msec(value); if(value == NULL || st_timeout <= 0) { crm_notice("Watchdog may be enabled but stonith-watchdog-timeout is disabled: %s", value); } else if(pcmk_locate_sbd() == 0) { do_crm_log_always(LOG_EMERG, "Shutting down: stonith-watchdog-timeout is configured (%ldms) but SBD is not active", st_timeout); crm_exit(DAEMON_RESPAWN_STOP); return FALSE; } else if(st_timeout < sbd_timeout) { do_crm_log_always(LOG_EMERG, "Shutting down: stonith-watchdog-timeout (%ldms) is too short (must be greater than %ldms)", st_timeout, sbd_timeout); crm_exit(DAEMON_RESPAWN_STOP); return FALSE; } crm_info("Watchdog functionality is consistent: %s delay exceeds timeout of %ldms", value, sbd_timeout); return TRUE; } diff --git a/lib/services/upstart.c b/lib/services/upstart.c index 30573945d2..5651a14707 100644 --- a/lib/services/upstart.c +++ b/lib/services/upstart.c @@ -1,582 +1,564 @@ /* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * File: upstart-dbus.c * Copyright (C) 2010 Senko Rasic * Copyright (c) 2010 Ante Karamatic * - * - * Each exported function is standalone, and creates a new connection to - * the upstart daemon. This is because lrmd plugins fork off for exec, - * and if we try and share the connection, the whole thing blocks - * indefinitely. + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include #define BUS_NAME "com.ubuntu.Upstart" #define BUS_PATH "/com/ubuntu/Upstart" #define UPSTART_06_API BUS_NAME"0_6" #define UPSTART_JOB_IFACE UPSTART_06_API".Job" #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties" /* http://upstart.ubuntu.com/wiki/DBusInterface */ static DBusConnection *upstart_proxy = NULL; static gboolean upstart_init(void) { static int need_init = 1; if (need_init) { need_init = 0; upstart_proxy = pcmk_dbus_connect(); } if (upstart_proxy == NULL) { return FALSE; } return TRUE; } void upstart_cleanup(void) { if (upstart_proxy) { pcmk_dbus_disconnect(upstart_proxy); upstart_proxy = NULL; } } static gboolean upstart_job_by_name(const gchar * arg_name, gchar ** out_unit, int timeout) { /* com.ubuntu.Upstart0_6.GetJobByName (in String name, out ObjectPath job) */ DBusError error; DBusMessage *msg; DBusMessage *reply = NULL; const char *method = "GetJobByName"; if(upstart_init() == FALSE) { return FALSE; } msg = dbus_message_new_method_call(BUS_NAME, // target for the method call BUS_PATH, // object to call on UPSTART_06_API, // interface to call on method); // method name dbus_error_init(&error); CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &arg_name, DBUS_TYPE_INVALID)); reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, timeout); dbus_message_unref(msg); if (dbus_error_is_set(&error)) { crm_err("Could not issue %s for %s: %s", method, arg_name, error.message); dbus_error_free(&error); } else if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) { crm_err("Invalid return type for %s", method); } else { if(out_unit) { char *path = NULL; dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); *out_unit = strdup(path); } dbus_message_unref(reply); return TRUE; } if(reply) { dbus_message_unref(reply); } return FALSE; } static void fix(char *input, const char *search, char replace) { char *match = NULL; int shuffle = strlen(search) - 1; while (TRUE) { int len, lpc; match = strstr(input, search); if (match == NULL) { break; } crm_trace("Found: %s", match); match[0] = replace; len = strlen(match) - shuffle; for (lpc = 1; lpc <= len; lpc++) { match[lpc] = match[lpc + shuffle]; } } } static char * fix_upstart_name(const char *input) { char *output = strdup(input); fix(output, "_2b", '+'); fix(output, "_2c", ','); fix(output, "_2d", '-'); fix(output, "_2e", '.'); fix(output, "_40", '@'); fix(output, "_5f", '_'); return output; } GList * upstart_job_listall(void) { GList *units = NULL; DBusMessageIter args; DBusMessageIter unit; DBusMessage *msg = NULL; DBusMessage *reply = NULL; const char *method = "GetAllJobs"; DBusError error; int lpc = 0; if (upstart_init() == FALSE) { return NULL; } /* com.ubuntu.Upstart0_6.GetAllJobs (out jobs) */ dbus_error_init(&error); msg = dbus_message_new_method_call(BUS_NAME, // target for the method call BUS_PATH, // object to call on UPSTART_06_API, // interface to call on method); // method name CRM_ASSERT(msg != NULL); reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, DBUS_TIMEOUT_USE_DEFAULT); dbus_message_unref(msg); if (dbus_error_is_set(&error)) { crm_err("Call to %s failed: %s", method, error.message); dbus_error_free(&error); return NULL; } else if (!dbus_message_iter_init(reply, &args)) { crm_err("Call to %s failed: Message has no arguments", method); dbus_message_unref(reply); return NULL; } if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) { crm_err("Call to %s failed: Message has invalid arguments", method); dbus_message_unref(reply); return NULL; } dbus_message_iter_recurse(&args, &unit); while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) { DBusBasicValue value; const char *job = NULL; char *path = NULL; if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) { continue; } dbus_message_iter_get_basic(&unit, &value); if(value.str) { int llpc = 0; path = value.str; job = value.str; while (path[llpc] != 0) { if (path[llpc] == '/') { job = path + llpc + 1; } llpc++; } lpc++; crm_trace("%s -> %s", path, job); units = g_list_append(units, fix_upstart_name(job)); } dbus_message_iter_next (&unit); } dbus_message_unref(reply); crm_trace("Found %d upstart jobs", lpc); return units; } gboolean upstart_job_exists(const char *name) { return upstart_job_by_name(name, NULL, DBUS_TIMEOUT_USE_DEFAULT); } static char * get_first_instance(const gchar * job, int timeout) { char *instance = NULL; const char *method = "GetAllInstances"; DBusError error; DBusMessage *msg; DBusMessage *reply; DBusMessageIter args; DBusMessageIter unit; dbus_error_init(&error); msg = dbus_message_new_method_call(BUS_NAME, // target for the method call job, // object to call on UPSTART_JOB_IFACE, // interface to call on method); // method name CRM_ASSERT(msg != NULL); dbus_message_append_args(msg, DBUS_TYPE_INVALID); reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, timeout); dbus_message_unref(msg); if (dbus_error_is_set(&error)) { crm_err("Call to %s failed: %s", method, error.message); dbus_error_free(&error); goto done; } else if(reply == NULL) { crm_err("Call to %s failed: no reply", method); goto done; } else if (!dbus_message_iter_init(reply, &args)) { crm_err("Call to %s failed: Message has no arguments", method); goto done; } if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) { crm_err("Call to %s failed: Message has invalid arguments", method); goto done; } dbus_message_iter_recurse(&args, &unit); if(pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) { DBusBasicValue value; dbus_message_iter_get_basic(&unit, &value); if(value.str) { instance = strdup(value.str); crm_trace("Result: %s", instance); } } done: if(reply) { dbus_message_unref(reply); } return instance; } static void upstart_job_check(const char *name, const char *state, void *userdata) { svc_action_t * op = userdata; if (state && g_strcmp0(state, "running") == 0) { op->rc = PCMK_OCF_OK; /* } else if (g_strcmp0(state, "activating") == 0) { */ /* op->rc = PCMK_OCF_PENDING; */ } else { op->rc = PCMK_OCF_NOT_RUNNING; } if (op->synchronous == FALSE) { services_set_op_pending(op, NULL); operation_finalize(op); } } static char * upstart_job_metadata(const char *name) { return crm_strdup_printf("\n" "\n" "\n" " 1.0\n" " \n" " Upstart agent for controlling the system %s service\n" " \n" " %s upstart agent\n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "\n", name, name, name); } static bool upstart_mask_error(svc_action_t *op, const char *error) { crm_trace("Could not issue %s for %s: %s", op->action, op->rsc, error); if(strstr(error, UPSTART_06_API ".Error.UnknownInstance")) { if(safe_str_eq(op->action, "stop")) { crm_trace("Masking %s failure for %s: unknown services are stopped", op->action, op->rsc); op->rc = PCMK_OCF_OK; } else if(safe_str_eq(op->action, "start")) { crm_trace("Mapping %s failure for %s: unknown services are not installed", op->action, op->rsc); op->rc = PCMK_OCF_NOT_INSTALLED; op->status = PCMK_LRM_OP_NOT_INSTALLED; } return TRUE; } else if (safe_str_eq(op->action, "start") && strstr(error, UPSTART_06_API ".Error.AlreadyStarted")) { crm_trace("Mapping %s failure for %s: starting a started resource is allowed", op->action, op->rsc); op->rc = PCMK_OCF_OK; return TRUE; } return FALSE; } static void upstart_async_dispatch(DBusPendingCall *pending, void *user_data) { DBusError error; DBusMessage *reply = NULL; svc_action_t *op = user_data; dbus_error_init(&error); if(pending) { reply = dbus_pending_call_steal_reply(pending); } if (pcmk_dbus_find_error(pending, reply, &error)) { /* ignore "already started" or "not running" errors */ if (!upstart_mask_error(op, error.name)) { crm_err("%s for %s: %s", op->action, op->rsc, error.message); } dbus_error_free(&error); } else if (!g_strcmp0(op->action, "stop")) { /* No return vaue */ op->rc = PCMK_OCF_OK; } else { if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) { crm_warn("Call to %s passed but return type was unexpected", op->action); op->rc = PCMK_OCF_OK; } else { const char *path = NULL; dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); crm_info("Call to %s passed: %s", op->action, path); op->rc = PCMK_OCF_OK; } } CRM_LOG_ASSERT(pending == op->opaque->pending); services_set_op_pending(op, NULL); operation_finalize(op); if(reply) { dbus_message_unref(reply); } } /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */ /* For a synchronous 'op', returns FALSE if 'op' fails */ gboolean upstart_job_exec(svc_action_t * op, gboolean synchronous) { char *job = NULL; int arg_wait = TRUE; const char *arg_env = "pacemaker=1"; const char *action = op->action; DBusError error; DBusMessage *msg = NULL; DBusMessage *reply = NULL; DBusMessageIter iter, array_iter; op->rc = PCMK_OCF_UNKNOWN_ERROR; CRM_ASSERT(upstart_init()); if (safe_str_eq(op->action, "meta-data")) { op->stdout_data = upstart_job_metadata(op->agent); op->rc = PCMK_OCF_OK; goto cleanup; } if(!upstart_job_by_name(op->agent, &job, op->timeout)) { crm_debug("Could not obtain job named '%s' to %s", op->agent, action); if (!g_strcmp0(action, "stop")) { op->rc = PCMK_OCF_OK; } else { op->rc = PCMK_OCF_NOT_INSTALLED; op->status = PCMK_LRM_OP_NOT_INSTALLED; } goto cleanup; } if (safe_str_eq(op->action, "monitor") || safe_str_eq(action, "status")) { char *path = get_first_instance(job, op->timeout); op->rc = PCMK_OCF_NOT_RUNNING; if(path) { DBusPendingCall *pending = NULL; char *state = pcmk_dbus_get_property( upstart_proxy, BUS_NAME, path, UPSTART_06_API ".Instance", "state", op->synchronous?NULL:upstart_job_check, op, op->synchronous?NULL:&pending, op->timeout); free(job); free(path); if(op->synchronous) { upstart_job_check("state", state, op); free(state); return op->rc == PCMK_OCF_OK; } else if (pending) { services_set_op_pending(op, pending); services_add_inflight_op(op); return TRUE; } return FALSE; } goto cleanup; } else if (!g_strcmp0(action, "start")) { action = "Start"; } else if (!g_strcmp0(action, "stop")) { action = "Stop"; } else if (!g_strcmp0(action, "restart")) { action = "Restart"; } else { op->rc = PCMK_OCF_UNIMPLEMENT_FEATURE; goto cleanup; } crm_debug("Calling %s for %s on %s", action, op->rsc, job); msg = dbus_message_new_method_call(BUS_NAME, // target for the method call job, // object to call on UPSTART_JOB_IFACE, // interface to call on action); // method name CRM_ASSERT(msg != NULL); dbus_message_iter_init_append (msg, &iter); CRM_LOG_ASSERT(dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array_iter)); CRM_LOG_ASSERT(dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING, &arg_env)); CRM_LOG_ASSERT(dbus_message_iter_close_container (&iter, &array_iter)); CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &arg_wait, DBUS_TYPE_INVALID)); if (op->synchronous == FALSE) { DBusPendingCall* pending = pcmk_dbus_send(msg, upstart_proxy, upstart_async_dispatch, op, op->timeout); free(job); if(pending) { services_set_op_pending(op, pending); services_add_inflight_op(op); return TRUE; } return FALSE; } dbus_error_init(&error); reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, op->timeout); if (dbus_error_is_set(&error)) { if(!upstart_mask_error(op, error.name)) { crm_err("Could not issue %s for %s: %s (%s)", action, op->rsc, error.message, job); } dbus_error_free(&error); } else if (!g_strcmp0(op->action, "stop")) { /* No return vaue */ op->rc = PCMK_OCF_OK; } else if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) { crm_warn("Call to %s passed but return type was unexpected", op->action); op->rc = PCMK_OCF_OK; } else { const char *path = NULL; dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); crm_info("Call to %s passed: %s", op->action, path); op->rc = PCMK_OCF_OK; } cleanup: free(job); if(msg) { dbus_message_unref(msg); } if(reply) { dbus_message_unref(reply); } if (op->synchronous == FALSE) { return operation_finalize(op); } return op->rc == PCMK_OCF_OK; }