1    	/*
2    	 * Copyright 2009-2024 the Pacemaker project contributors
3    	 *
4    	 * The version control history for this file may have further details.
5    	 *
6    	 * This source code is licensed under the GNU General Public License version 2
7    	 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8    	 */
9    	
10   	#include <crm_internal.h>
11   	
12   	#include <sys/param.h>
13   	#include <stdio.h>
14   	#include <sys/types.h>
15   	#include <sys/wait.h>
16   	#include <sys/stat.h>
17   	#include <unistd.h>
18   	#include <sys/utsname.h>
19   	
20   	#include <stdlib.h>
21   	#include <errno.h>
22   	#include <fcntl.h>
23   	#include <ctype.h>
24   	#include <regex.h>
25   	
26   	#include <crm/crm.h>
27   	#include <crm/common/ipc.h>
28   	#include <crm/common/ipc_internal.h>
29   	#include <crm/cluster/internal.h>
30   	
31   	#include <crm/stonith-ng.h>
32   	#include <crm/fencing/internal.h>
33   	#include <crm/common/xml.h>
34   	#include <crm/common/xml_internal.h>
35   	
36   	#include <crm/common/util.h>
37   	#include <pacemaker-fenced.h>
38   	
39   	#define TIMEOUT_MULTIPLY_FACTOR 1.2
40   	
41   	/* When one fencer queries its peers for devices able to handle a fencing
42   	 * request, each peer will reply with a list of such devices available to it.
43   	 * Each reply will be parsed into a peer_device_info_t, with each device's
44   	 * information kept in a device_properties_t.
45   	 */
46   	
47   	typedef struct device_properties_s {
48   	    /* Whether access to this device has been verified */
49   	    gboolean verified;
50   	
51   	    /* The remaining members are indexed by the operation's "phase" */
52   	
53   	    /* Whether this device has been executed in each phase */
54   	    gboolean executed[st_phase_max];
55   	    /* Whether this device is disallowed from executing in each phase */
56   	    gboolean disallowed[st_phase_max];
57   	    /* Action-specific timeout for each phase */
58   	    int custom_action_timeout[st_phase_max];
59   	    /* Action-specific maximum random delay for each phase */
60   	    int delay_max[st_phase_max];
61   	    /* Action-specific base delay for each phase */
62   	    int delay_base[st_phase_max];
63   	    /* Group of enum st_device_flags */
64   	    uint32_t device_support_flags;
65   	} device_properties_t;
66   	
67   	typedef struct {
68   	    /* Name of peer that sent this result */
69   	    char *host;
70   	    /* Only try peers for non-topology based operations once */
71   	    gboolean tried;
72   	    /* Number of entries in the devices table */
73   	    int ndevices;
74   	    /* Devices available to this host that are capable of fencing the target */
75   	    GHashTable *devices;
76   	} peer_device_info_t;
77   	
78   	GHashTable *stonith_remote_op_list = NULL;
79   	
80   	extern xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
81   	                                  int call_options);
82   	
83   	static void request_peer_fencing(remote_fencing_op_t *op,
84   	                                 peer_device_info_t *peer);
85   	static void finalize_op(remote_fencing_op_t *op, xmlNode *data, bool dup);
86   	static void report_timeout_period(remote_fencing_op_t * op, int op_timeout);
87   	static int get_op_total_timeout(const remote_fencing_op_t *op,
88   	                                const peer_device_info_t *chosen_peer);
89   	
90   	static gint
91   	sort_strings(gconstpointer a, gconstpointer b)
92   	{
93   	    return strcmp(a, b);
94   	}
95   	
96   	static void
97   	free_remote_query(gpointer data)
98   	{
99   	    if (data != NULL) {
100  	        peer_device_info_t *peer = data;
101  	
102  	        g_hash_table_destroy(peer->devices);
103  	        free(peer->host);
104  	        free(peer);
105  	    }
106  	}
107  	
108  	void
109  	free_stonith_remote_op_list(void)
110  	{
111  	    if (stonith_remote_op_list != NULL) {
112  	        g_hash_table_destroy(stonith_remote_op_list);
113  	        stonith_remote_op_list = NULL;
114  	    }
115  	}
116  	
117  	struct peer_count_data {
118  	    const remote_fencing_op_t *op;
119  	    gboolean verified_only;
120  	    uint32_t support_action_only;
121  	    int count;
122  	};
123  	
124  	/*!
125  	 * \internal
126  	 * \brief Increment a counter if a device has not been executed yet
127  	 *
128  	 * \param[in]     key        Device ID (ignored)
129  	 * \param[in]     value      Device properties
130  	 * \param[in,out] user_data  Peer count data
131  	 */
132  	static void
133  	count_peer_device(gpointer key, gpointer value, gpointer user_data)
134  	{
135  	    device_properties_t *props = (device_properties_t*)value;
136  	    struct peer_count_data *data = user_data;
137  	
138  	    if (!props->executed[data->op->phase]
139  	        && (!data->verified_only || props->verified)
140  	        && ((data->support_action_only == st_device_supports_none) || pcmk_is_set(props->device_support_flags, data->support_action_only))) {
141  	        ++(data->count);
142  	    }
143  	}
144  	
145  	/*!
146  	 * \internal
147  	 * \brief Check the number of available devices in a peer's query results
148  	 *
149  	 * \param[in] op             Operation that results are for
150  	 * \param[in] peer           Peer to count
151  	 * \param[in] verified_only  Whether to count only verified devices
152  	 * \param[in] support_action_only Whether to count only devices that support action
153  	 *
154  	 * \return Number of devices available to peer that were not already executed
155  	 */
156  	static int
157  	count_peer_devices(const remote_fencing_op_t *op,
158  	                   const peer_device_info_t *peer, gboolean verified_only, uint32_t support_on_action_only)
159  	{
160  	    struct peer_count_data data;
161  	
162  	    data.op = op;
163  	    data.verified_only = verified_only;
164  	    data.support_action_only = support_on_action_only;
165  	    data.count = 0;
166  	    if (peer) {
167  	        g_hash_table_foreach(peer->devices, count_peer_device, &data);
168  	    }
169  	    return data.count;
170  	}
171  	
172  	/*!
173  	 * \internal
174  	 * \brief Search for a device in a query result
175  	 *
176  	 * \param[in] op      Operation that result is for
177  	 * \param[in] peer    Query result for a peer
178  	 * \param[in] device  Device ID to search for
179  	 *
180  	 * \return Device properties if found, NULL otherwise
181  	 */
182  	static device_properties_t *
183  	find_peer_device(const remote_fencing_op_t *op, const peer_device_info_t *peer,
184  	                 const char *device, uint32_t support_action_only)
185  	{
186  	    device_properties_t *props = g_hash_table_lookup(peer->devices, device);
187  	
188  	    if (props && support_action_only != st_device_supports_none && !pcmk_is_set(props->device_support_flags, support_action_only)) {
189  	        return NULL;
190  	    }
191  	    return (props && !props->executed[op->phase]
192  	           && !props->disallowed[op->phase])? props : NULL;
193  	}
194  	
195  	/*!
196  	 * \internal
197  	 * \brief Find a device in a peer's device list and mark it as executed
198  	 *
199  	 * \param[in]     op                     Operation that peer result is for
200  	 * \param[in,out] peer                   Peer with results to search
201  	 * \param[in]     device                 ID of device to mark as done
202  	 * \param[in]     verified_devices_only  Only consider verified devices
203  	 *
204  	 * \return TRUE if device was found and marked, FALSE otherwise
205  	 */
206  	static gboolean
207  	grab_peer_device(const remote_fencing_op_t *op, peer_device_info_t *peer,
208  	                 const char *device, gboolean verified_devices_only)
209  	{
210  	    device_properties_t *props = find_peer_device(op, peer, device,
211  	                                                  fenced_support_flag(op->action));
212  	
213  	    if ((props == NULL) || (verified_devices_only && !props->verified)) {
214  	        return FALSE;
215  	    }
216  	
217  	    crm_trace("Removing %s from %s (%d remaining)",
218  	              device, peer->host, count_peer_devices(op, peer, FALSE, st_device_supports_none));
219  	    props->executed[op->phase] = TRUE;
220  	    return TRUE;
221  	}
222  	
223  	static void
224  	clear_remote_op_timers(remote_fencing_op_t * op)
225  	{
226  	    if (op->query_timer) {
227  	        g_source_remove(op->query_timer);
228  	        op->query_timer = 0;
229  	    }
230  	    if (op->op_timer_total) {
231  	        g_source_remove(op->op_timer_total);
232  	        op->op_timer_total = 0;
233  	    }
234  	    if (op->op_timer_one) {
235  	        g_source_remove(op->op_timer_one);
236  	        op->op_timer_one = 0;
237  	    }
238  	}
239  	
240  	static void
241  	free_remote_op(gpointer data)
242  	{
243  	    remote_fencing_op_t *op = data;
244  	
245  	    crm_log_xml_debug(op->request, "Destroying");
246  	
247  	    clear_remote_op_timers(op);
248  	
249  	    free(op->id);
250  	    free(op->action);
251  	    free(op->delegate);
252  	    free(op->target);
253  	    free(op->client_id);
254  	    free(op->client_name);
255  	    free(op->originator);
256  	
257  	    if (op->query_results) {
258  	        g_list_free_full(op->query_results, free_remote_query);
259  	    }
260  	    if (op->request) {
261  	        pcmk__xml_free(op->request);
262  	        op->request = NULL;
263  	    }
264  	    if (op->devices_list) {
265  	        g_list_free_full(op->devices_list, free);
266  	        op->devices_list = NULL;
267  	    }
268  	    g_list_free_full(op->automatic_list, free);
269  	    g_list_free(op->duplicates);
270  	
271  	    pcmk__reset_result(&op->result);
272  	    free(op);
273  	}
274  	
275  	void
276  	init_stonith_remote_op_hash_table(GHashTable **table)
277  	{
278  	    if (*table == NULL) {
279  	        *table = pcmk__strkey_table(NULL, free_remote_op);
280  	    }
281  	}
282  	
283  	/*!
284  	 * \internal
285  	 * \brief Return an operation's originally requested action (before any remap)
286  	 *
287  	 * \param[in] op  Operation to check
288  	 *
289  	 * \return Operation's original action
290  	 */
291  	static const char *
292  	op_requested_action(const remote_fencing_op_t *op)
293  	{
294  	    return ((op->phase > st_phase_requested)? PCMK_ACTION_REBOOT : op->action);
295  	}
296  	
297  	/*!
298  	 * \internal
299  	 * \brief Remap a "reboot" operation to the "off" phase
300  	 *
301  	 * \param[in,out] op      Operation to remap
302  	 */
303  	static void
304  	op_phase_off(remote_fencing_op_t *op)
305  	{
306  	    crm_info("Remapping multiple-device reboot targeting %s to 'off' "
307  	             QB_XS " id=%.8s", op->target, op->id);
308  	    op->phase = st_phase_off;
309  	
310  	    /* Happily, "off" and "on" are shorter than "reboot", so we can reuse the
311  	     * memory allocation at each phase.
312  	     */
313  	    strcpy(op->action, PCMK_ACTION_OFF);
314  	}
315  	
316  	/*!
317  	 * \internal
318  	 * \brief Advance a remapped reboot operation to the "on" phase
319  	 *
320  	 * \param[in,out] op  Operation to remap
321  	 */
322  	static void
323  	op_phase_on(remote_fencing_op_t *op)
324  	{
325  	    GList *iter = NULL;
326  	
327  	    crm_info("Remapped 'off' targeting %s complete, "
328  	             "remapping to 'on' for %s " QB_XS " id=%.8s",
329  	             op->target, op->client_name, op->id);
330  	    op->phase = st_phase_on;
331  	    strcpy(op->action, PCMK_ACTION_ON);
332  	
333  	    /* Skip devices with automatic unfencing, because the cluster will handle it
334  	     * when the node rejoins.
335  	     */
336  	    for (iter = op->automatic_list; iter != NULL; iter = iter->next) {
337  	        GList *match = g_list_find_custom(op->devices_list, iter->data,
338  	                                            sort_strings);
339  	
340  	        if (match) {
341  	            op->devices_list = g_list_remove(op->devices_list, match->data);
342  	        }
343  	    }
344  	    g_list_free_full(op->automatic_list, free);
345  	    op->automatic_list = NULL;
346  	
347  	    /* Rewind device list pointer */
348  	    op->devices = op->devices_list;
349  	}
350  	
351  	/*!
352  	 * \internal
353  	 * \brief Reset a remapped reboot operation
354  	 *
355  	 * \param[in,out] op  Operation to reset
356  	 */
357  	static void
358  	undo_op_remap(remote_fencing_op_t *op)
359  	{
360  	    if (op->phase > 0) {
361  	        crm_info("Undoing remap of reboot targeting %s for %s "
362  	                 QB_XS " id=%.8s", op->target, op->client_name, op->id);
363  	        op->phase = st_phase_requested;
364  	        strcpy(op->action, PCMK_ACTION_REBOOT);
365  	    }
366  	}
367  	
368  	/*!
369  	 * \internal
370  	 * \brief Create notification data XML for a fencing operation result
371  	 *
372  	 * \param[in,out] parent  Parent XML element for newly created element
373  	 * \param[in]     op      Fencer operation that completed
374  	 *
375  	 * \return Newly created XML to add as notification data
376  	 * \note The caller is responsible for freeing the result.
377  	 */
378  	static xmlNode *
379  	fencing_result2xml(xmlNode *parent, const remote_fencing_op_t *op)
380  	{
381  	    xmlNode *notify_data = pcmk__xe_create(parent, PCMK__XE_ST_NOTIFY_FENCE);
382  	
383  	    crm_xml_add_int(notify_data, PCMK_XA_STATE, op->state);
384  	    crm_xml_add(notify_data, PCMK__XA_ST_TARGET, op->target);
385  	    crm_xml_add(notify_data, PCMK__XA_ST_DEVICE_ACTION, op->action);
386  	    crm_xml_add(notify_data, PCMK__XA_ST_DELEGATE, op->delegate);
387  	    crm_xml_add(notify_data, PCMK__XA_ST_REMOTE_OP, op->id);
388  	    crm_xml_add(notify_data, PCMK__XA_ST_ORIGIN, op->originator);
389  	    crm_xml_add(notify_data, PCMK__XA_ST_CLIENTID, op->client_id);
390  	    crm_xml_add(notify_data, PCMK__XA_ST_CLIENTNAME, op->client_name);
391  	
392  	    return notify_data;
393  	}
394  	
395  	/*!
396  	 * \internal
397  	 * \brief Broadcast a fence result notification to all CPG peers
398  	 *
399  	 * \param[in] op         Fencer operation that completed
400  	 * \param[in] op_merged  Whether this operation is a duplicate of another
401  	 */
402  	void
403  	fenced_broadcast_op_result(const remote_fencing_op_t *op, bool op_merged)
404  	{
405  	    static int count = 0;
406  	    xmlNode *bcast = pcmk__xe_create(NULL, PCMK__XE_ST_REPLY);
407  	    xmlNode *wrapper = NULL;
408  	    xmlNode *notify_data = NULL;
409  	
410  	    count++;
411  	    crm_trace("Broadcasting result to peers");
412  	    crm_xml_add(bcast, PCMK__XA_T, PCMK__VALUE_ST_NOTIFY);
413  	    crm_xml_add(bcast, PCMK__XA_SUBT, PCMK__VALUE_BROADCAST);
414  	    crm_xml_add(bcast, PCMK__XA_ST_OP, STONITH_OP_NOTIFY);
415  	    crm_xml_add_int(bcast, PCMK_XA_COUNT, count);
416  	
417  	    if (op_merged) {
418  	        pcmk__xe_set_bool_attr(bcast, PCMK__XA_ST_OP_MERGED, true);
419  	    }
420  	
421  	    wrapper = pcmk__xe_create(bcast, PCMK__XE_ST_CALLDATA);
422  	    notify_data = fencing_result2xml(wrapper, op);
423  	    stonith__xe_set_result(notify_data, &op->result);
424  	
425  	    pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, bcast);
426  	    pcmk__xml_free(bcast);
427  	
428  	    return;
429  	}
430  	
431  	/*!
432  	 * \internal
433  	 * \brief Reply to a local request originator and notify all subscribed clients
434  	 *
435  	 * \param[in,out] op    Fencer operation that completed
436  	 * \param[in,out] data  Top-level XML to add notification to
437  	 */
438  	static void
439  	handle_local_reply_and_notify(remote_fencing_op_t *op, xmlNode *data)
440  	{
441  	    xmlNode *notify_data = NULL;
442  	    xmlNode *reply = NULL;
443  	    pcmk__client_t *client = NULL;
444  	
445  	    if (op->notify_sent == TRUE) {
446  	        /* nothing to do */
447  	        return;
448  	    }
449  	
450  	    /* Do notification with a clean data object */
451  	    crm_xml_add_int(data, PCMK_XA_STATE, op->state);
452  	    crm_xml_add(data, PCMK__XA_ST_TARGET, op->target);
453  	    crm_xml_add(data, PCMK__XA_ST_OP, op->action);
454  	
455  	    reply = fenced_construct_reply(op->request, data, &op->result);
456  	    crm_xml_add(reply, PCMK__XA_ST_DELEGATE, op->delegate);
457  	
458  	    /* Send fencing OP reply to local client that initiated fencing */
459  	    client = pcmk__find_client_by_id(op->client_id);
460  	    if (client == NULL) {
461  	        crm_trace("Skipping reply to %s: no longer a client", op->client_id);
462  	    } else {
463  	        do_local_reply(reply, client, op->call_options);
464  	    }
465  	
466  	    /* bcast to all local clients that the fencing operation happend */
467  	    notify_data = fencing_result2xml(NULL, op);
468  	    fenced_send_notification(PCMK__VALUE_ST_NOTIFY_FENCE, &op->result,
469  	                             notify_data);
470  	    pcmk__xml_free(notify_data);
471  	    fenced_send_notification(PCMK__VALUE_ST_NOTIFY_HISTORY, NULL, NULL);
472  	
473  	    /* mark this op as having notify's already sent */
474  	    op->notify_sent = TRUE;
475  	    pcmk__xml_free(reply);
476  	}
477  	
478  	/*!
479  	 * \internal
480  	 * \brief Finalize all duplicates of a given fencer operation
481  	 *
482  	 * \param[in,out] op    Fencer operation that completed
483  	 * \param[in,out] data  Top-level XML to add notification to
484  	 */
485  	static void
486  	finalize_op_duplicates(remote_fencing_op_t *op, xmlNode *data)
487  	{
488  	    for (GList *iter = op->duplicates; iter != NULL; iter = iter->next) {
489  	        remote_fencing_op_t *other = iter->data;
490  	
491  	        if (other->state == st_duplicate) {
492  	            other->state = op->state;
493  	            crm_debug("Performing duplicate notification for %s@%s: %s "
494  	                      QB_XS " id=%.8s",
495  	                      other->client_name, other->originator,
496  	                      pcmk_exec_status_str(op->result.execution_status),
497  	                      other->id);
498  	            pcmk__copy_result(&op->result, &other->result);
499  	            finalize_op(other, data, true);
500  	
501  	        } else {
502  	            // Possible if (for example) it timed out already
503  	            crm_err("Skipping duplicate notification for %s@%s "
504  	                    QB_XS " state=%s id=%.8s",
505  	                    other->client_name, other->originator,
506  	                    stonith_op_state_str(other->state), other->id);
507  	        }
508  	    }
509  	}
510  	
511  	static char *
512  	delegate_from_xml(xmlNode *xml)
513  	{
514  	    xmlNode *match = get_xpath_object("//@" PCMK__XA_ST_DELEGATE, xml,
515  	                                      LOG_NEVER);
516  	
517  	    if (match == NULL) {
518  	        return crm_element_value_copy(xml, PCMK__XA_SRC);
519  	    } else {
520  	        return crm_element_value_copy(match, PCMK__XA_ST_DELEGATE);
521  	    }
522  	}
523  	
524  	/*!
525  	 * \internal
526  	 * \brief Finalize a peer fencing operation
527  	 *
528  	 * Clean up after a fencing operation completes. This function has two code
529  	 * paths: the executioner uses it to broadcast the result to CPG peers, and then
530  	 * each peer (including the executioner) uses it to process that broadcast and
531  	 * notify its IPC clients of the result.
532  	 *
533  	 * \param[in,out] op      Fencer operation that completed
534  	 * \param[in,out] data    If not NULL, XML reply of last delegated operation
535  	 * \param[in]     dup     Whether this operation is a duplicate of another
536  	 *                        (in which case, do not broadcast the result)
537  	 *
538  	 *  \note The operation result should be set before calling this function.
539  	 */
540  	static void
541  	finalize_op(remote_fencing_op_t *op, xmlNode *data, bool dup)
542  	{
543  	    int level = LOG_ERR;
544  	    const char *subt = NULL;
545  	    xmlNode *local_data = NULL;
546  	    gboolean op_merged = FALSE;
547  	
548  	    CRM_CHECK((op != NULL), return);
549  	
550  	    // This is a no-op if timers have already been cleared
551  	    clear_remote_op_timers(op);
552  	
553  	    if (op->notify_sent) {
554  	        // Most likely, this is a timed-out action that eventually completed
555  	        crm_notice("Operation '%s'%s%s by %s for %s@%s%s: "
556  	                   "Result arrived too late " QB_XS " id=%.8s",
557  	                   op->action, (op->target? " targeting " : ""),
558  	                   (op->target? op->target : ""),
559  	                   (op->delegate? op->delegate : "unknown node"),
560  	                   op->client_name, op->originator,
561  	                   (op_merged? " (merged)" : ""),
562  	                   op->id);
563  	        return;
564  	    }
565  	
566  	    set_fencing_completed(op);
567  	    undo_op_remap(op);
568  	
569  	    if (data == NULL) {
570  	        data = pcmk__xe_create(NULL, "remote-op");
571  	        local_data = data;
572  	
573  	    } else if (op->delegate == NULL) {
574  	        switch (op->result.execution_status) {
575  	            case PCMK_EXEC_NO_FENCE_DEVICE:
576  	                break;
577  	
578  	            case PCMK_EXEC_INVALID:
579  	                if (op->result.exit_status != CRM_EX_EXPIRED) {
580  	                    op->delegate = delegate_from_xml(data);
581  	                }
582  	                break;
583  	
584  	            default:
585  	                op->delegate = delegate_from_xml(data);
586  	                break;
587  	        }
588  	    }
589  	
590  	    if (dup || (crm_element_value(data, PCMK__XA_ST_OP_MERGED) != NULL)) {
591  	        op_merged = true;
592  	    }
593  	
594  	    /* Tell everyone the operation is done, we will continue
595  	     * with doing the local notifications once we receive
596  	     * the broadcast back. */
597  	    subt = crm_element_value(data, PCMK__XA_SUBT);
598  	    if (!dup && !pcmk__str_eq(subt, PCMK__VALUE_BROADCAST, pcmk__str_none)) {
599  	        /* Defer notification until the bcast message arrives */
600  	        fenced_broadcast_op_result(op, op_merged);
601  	        pcmk__xml_free(local_data);
602  	        return;
603  	    }
604  	
605  	    if (pcmk__result_ok(&op->result) || dup
606  	        || !pcmk__str_eq(op->originator, fenced_get_local_node(),
607  	                         pcmk__str_casei)) {
608  	        level = LOG_NOTICE;
609  	    }
610  	    do_crm_log(level, "Operation '%s'%s%s by %s for %s@%s%s: %s (%s%s%s) "
611  	               QB_XS " id=%.8s", op->action, (op->target? " targeting " : ""),
612  	               (op->target? op->target : ""),
613  	               (op->delegate? op->delegate : "unknown node"),
614  	               op->client_name, op->originator,
615  	               (op_merged? " (merged)" : ""),
616  	               crm_exit_str(op->result.exit_status),
617  	               pcmk_exec_status_str(op->result.execution_status),
618  	               ((op->result.exit_reason == NULL)? "" : ": "),
619  	               ((op->result.exit_reason == NULL)? "" : op->result.exit_reason),
620  	               op->id);
621  	
622  	    handle_local_reply_and_notify(op, data);
623  	
624  	    if (!dup) {
625  	        finalize_op_duplicates(op, data);
626  	    }
627  	
628  	    /* Free non-essential parts of the record
629  	     * Keep the record around so we can query the history
630  	     */
631  	    if (op->query_results) {
632  	        g_list_free_full(op->query_results, free_remote_query);
633  	        op->query_results = NULL;
634  	    }
635  	    if (op->request) {
636  	        pcmk__xml_free(op->request);
637  	        op->request = NULL;
638  	    }
639  	
640  	    pcmk__xml_free(local_data);
641  	}
642  	
643  	/*!
644  	 * \internal
645  	 * \brief Finalize a watchdog fencer op after the waiting time expires
646  	 *
647  	 * \param[in,out] userdata  Fencer operation that completed
648  	 *
649  	 * \return G_SOURCE_REMOVE (which tells glib not to restart timer)
650  	 */
651  	static gboolean
652  	remote_op_watchdog_done(gpointer userdata)
653  	{
654  	    remote_fencing_op_t *op = userdata;
655  	
656  	    op->op_timer_one = 0;
657  	
658  	    crm_notice("Self-fencing (%s) by %s for %s assumed complete "
659  	               QB_XS " id=%.8s",
660  	               op->action, op->target, op->client_name, op->id);
661  	    op->state = st_done;
662  	    pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
663  	    finalize_op(op, NULL, false);
664  	    return G_SOURCE_REMOVE;
665  	}
666  	
667  	static gboolean
668  	remote_op_timeout_one(gpointer userdata)
669  	{
670  	    remote_fencing_op_t *op = userdata;
671  	
672  	    op->op_timer_one = 0;
673  	
674  	    crm_notice("Peer's '%s' action targeting %s for client %s timed out " QB_XS
675  	               " id=%.8s", op->action, op->target, op->client_name, op->id);
676  	    pcmk__set_result(&op->result, CRM_EX_ERROR, PCMK_EXEC_TIMEOUT,
677  	                     "Peer did not return fence result within timeout");
678  	
679  	    // The requested delay has been applied for the first device
680  	    if (op->client_delay > 0) {
681  	        op->client_delay = 0;
682  	        crm_trace("Try another device for '%s' action targeting %s "
683  	                  "for client %s without delay " QB_XS " id=%.8s",
684  	                  op->action, op->target, op->client_name, op->id);
685  	    }
686  	
687  	    // Try another device, if appropriate
688  	    request_peer_fencing(op, NULL);
689  	    return G_SOURCE_REMOVE;
690  	}
691  	
692  	/*!
693  	 * \internal
694  	 * \brief Finalize a remote fencer operation that timed out
695  	 *
696  	 * \param[in,out] op      Fencer operation that timed out
697  	 * \param[in]     reason  Readable description of what step timed out
698  	 */
699  	static void
700  	finalize_timed_out_op(remote_fencing_op_t *op, const char *reason)
701  	{
702  	    crm_debug("Action '%s' targeting %s for client %s timed out "
703  	              QB_XS " id=%.8s",
704  	              op->action, op->target, op->client_name, op->id);
705  	
706  	    if (op->phase == st_phase_on) {
707  	        /* A remapped reboot operation timed out in the "on" phase, but the
708  	         * "off" phase completed successfully, so quit trying any further
709  	         * devices, and return success.
710  	         */
711  	        op->state = st_done;
712  	        pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
713  	    } else {
714  	        op->state = st_failed;
715  	        pcmk__set_result(&op->result, CRM_EX_ERROR, PCMK_EXEC_TIMEOUT, reason);
716  	    }
717  	    finalize_op(op, NULL, false);
718  	}
719  	
720  	/*!
721  	 * \internal
722  	 * \brief Finalize a remote fencer operation that timed out
723  	 *
724  	 * \param[in,out] userdata  Fencer operation that timed out
725  	 *
726  	 * \return G_SOURCE_REMOVE (which tells glib not to restart timer)
727  	 */
728  	static gboolean
729  	remote_op_timeout(gpointer userdata)
730  	{
731  	    remote_fencing_op_t *op = userdata;
732  	
733  	    op->op_timer_total = 0;
734  	
735  	    if (op->state == st_done) {
736  	        crm_debug("Action '%s' targeting %s for client %s already completed "
737  	                  QB_XS " id=%.8s",
738  	                  op->action, op->target, op->client_name, op->id);
739  	    } else {
740  	        finalize_timed_out_op(userdata, "Fencing did not complete within a "
741  	                                        "total timeout based on the "
742  	                                        "configured timeout and retries for "
743  	                                        "any devices attempted");
744  	    }
745  	    return G_SOURCE_REMOVE;
746  	}
747  	
748  	static gboolean
749  	remote_op_query_timeout(gpointer data)
750  	{
751  	    remote_fencing_op_t *op = data;
752  	
753  	    op->query_timer = 0;
754  	
755  	    if (op->state == st_done) {
756  	        crm_debug("Operation %.8s targeting %s already completed",
757  	                  op->id, op->target);
758  	    } else if (op->state == st_exec) {
759  	        crm_debug("Operation %.8s targeting %s already in progress",
760  	                  op->id, op->target);
761  	    } else if (op->query_results) {
762  	        // Query succeeded, so attempt the actual fencing
763  	        crm_debug("Query %.8s targeting %s complete (state=%s)",
764  	                  op->id, op->target, stonith_op_state_str(op->state));
765  	        request_peer_fencing(op, NULL);
766  	    } else {
767  	        crm_debug("Query %.8s targeting %s timed out (state=%s)",
768  	                  op->id, op->target, stonith_op_state_str(op->state));
769  	        finalize_timed_out_op(op, "No capable peers replied to device query "
770  	                                  "within timeout");
771  	    }
772  	
773  	    return G_SOURCE_REMOVE;
774  	}
775  	
776  	static gboolean
777  	topology_is_empty(stonith_topology_t *tp)
778  	{
779  	    int i;
780  	
781  	    if (tp == NULL) {
782  	        return TRUE;
783  	    }
784  	
785  	    for (i = 0; i < ST__LEVEL_COUNT; i++) {
786  	        if (tp->levels[i] != NULL) {
787  	            return FALSE;
788  	        }
789  	    }
790  	    return TRUE;
791  	}
792  	
793  	/*!
794  	 * \internal
795  	 * \brief Add a device to an operation's automatic unfencing list
796  	 *
797  	 * \param[in,out] op      Operation to modify
798  	 * \param[in]     device  Device ID to add
799  	 */
800  	static void
801  	add_required_device(remote_fencing_op_t *op, const char *device)
802  	{
803  	    GList *match  = g_list_find_custom(op->automatic_list, device,
804  	                                         sort_strings);
805  	
806  	    if (!match) {
807  	        op->automatic_list = g_list_prepend(op->automatic_list,
808  	                                            pcmk__str_copy(device));
809  	    }
810  	}
811  	
812  	/*!
813  	 * \internal
814  	 * \brief Remove a device from the automatic unfencing list
815  	 *
816  	 * \param[in,out] op      Operation to modify
817  	 * \param[in]     device  Device ID to remove
818  	 */
819  	static void
820  	remove_required_device(remote_fencing_op_t *op, const char *device)
821  	{
822  	    GList *match = g_list_find_custom(op->automatic_list, device,
823  	                                        sort_strings);
824  	
825  	    if (match) {
826  	        op->automatic_list = g_list_remove(op->automatic_list, match->data);
827  	    }
828  	}
829  	
830  	/* deep copy the device list */
831  	static void
832  	set_op_device_list(remote_fencing_op_t * op, GList *devices)
833  	{
834  	    GList *lpc = NULL;
835  	
836  	    if (op->devices_list) {
837  	        g_list_free_full(op->devices_list, free);
838  	        op->devices_list = NULL;
839  	    }
840  	    for (lpc = devices; lpc != NULL; lpc = lpc->next) {
841  	        const char *device = lpc->data;
842  	
843  	        op->devices_list = g_list_append(op->devices_list,
844  	                                         pcmk__str_copy(device));
845  	    }
846  	    op->devices = op->devices_list;
847  	}
848  	
849  	/*!
850  	 * \internal
851  	 * \brief Check whether a node matches a topology target
852  	 *
853  	 * \param[in] tp    Topology table entry to check
854  	 * \param[in] node  Name of node to check
855  	 *
856  	 * \return TRUE if node matches topology target
857  	 */
858  	static gboolean
859  	topology_matches(const stonith_topology_t *tp, const char *node)
860  	{
861  	    regex_t r_patt;
862  	
863  	    CRM_CHECK(node && tp && tp->target, return FALSE);
864  	    switch (tp->kind) {
865  	        case fenced_target_by_attribute:
866  	            /* This level targets by attribute, so tp->target is a NAME=VALUE pair
867  	             * of a permanent attribute applied to targeted nodes. The test below
868  	             * relies on the locally cached copy of the CIB, so if fencing needs to
869  	             * be done before the initial CIB is received or after a malformed CIB
870  	             * is received, then the topology will be unable to be used.
871  	             */
872  	            if (node_has_attr(node, tp->target_attribute, tp->target_value)) {
873  	                crm_notice("Matched %s with %s by attribute", node, tp->target);
874  	                return TRUE;
875  	            }
876  	            break;
877  	
878  	        case fenced_target_by_pattern:
879  	            /* This level targets node names matching a pattern, so tp->target
880  	             * (and tp->target_pattern) is a regular expression.
881  	             */
882  	            if (regcomp(&r_patt, tp->target_pattern, REG_EXTENDED|REG_NOSUB)) {
883  	                crm_info("Bad regex '%s' for fencing level", tp->target);
884  	            } else {
885  	                int status = regexec(&r_patt, node, 0, NULL, 0);
886  	
887  	                regfree(&r_patt);
888  	                if (status == 0) {
889  	                    crm_notice("Matched %s with %s by name", node, tp->target);
890  	                    return TRUE;
891  	                }
892  	            }
893  	            break;
894  	
895  	        case fenced_target_by_name:
896  	            crm_trace("Testing %s against %s", node, tp->target);
897  	            return pcmk__str_eq(tp->target, node, pcmk__str_casei);
898  	
899  	        default:
900  	            break;
901  	    }
902  	    crm_trace("No match for %s with %s", node, tp->target);
903  	    return FALSE;
904  	}
905  	
906  	stonith_topology_t *
907  	find_topology_for_host(const char *host) 
908  	{
909  	    GHashTableIter tIter;
910  	    stonith_topology_t *tp = g_hash_table_lookup(topology, host);
911  	
912  	    if(tp != NULL) {
913  	        crm_trace("Found %s for %s in %d entries", tp->target, host, g_hash_table_size(topology));
914  	        return tp;
915  	    }
916  	
917  	    g_hash_table_iter_init(&tIter, topology);
918  	    while (g_hash_table_iter_next(&tIter, NULL, (gpointer *) & tp)) {
919  	        if (topology_matches(tp, host)) {
920  	            crm_trace("Found %s for %s in %d entries", tp->target, host, g_hash_table_size(topology));
921  	            return tp;
922  	        }
923  	    }
924  	
925  	    crm_trace("No matches for %s in %d topology entries", host, g_hash_table_size(topology));
926  	    return NULL;
927  	}
928  	
929  	/*!
930  	 * \internal
931  	 * \brief Set fencing operation's device list to target's next topology level
932  	 *
933  	 * \param[in,out] op        Remote fencing operation to modify
934  	 * \param[in]     empty_ok  If true, an operation without a target (i.e.
935  	 *                          queries) or a target without a topology will get a
936  	 *                          pcmk_rc_ok return value instead of ENODEV
937  	 *
938  	 * \return Standard Pacemaker return value
939  	 */
940  	static int
941  	advance_topology_level(remote_fencing_op_t *op, bool empty_ok)
942  	{
943  	    stonith_topology_t *tp = NULL;
944  	
945  	    if (op->target) {
946  	        tp = find_topology_for_host(op->target);
947  	    }
948  	    if (topology_is_empty(tp)) {
949  	        return empty_ok? pcmk_rc_ok : ENODEV;
950  	    }
951  	
952  	    pcmk__assert(tp->levels != NULL);
953  	
954  	    stonith__set_call_options(op->call_options, op->id, st_opt_topology);
955  	
956  	    /* This is a new level, so undo any remapping left over from previous */
957  	    undo_op_remap(op);
958  	
959  	    do {
960  	        op->level++;
961  	
962  	    } while (op->level < ST__LEVEL_COUNT && tp->levels[op->level] == NULL);
963  	
964  	    if (op->level < ST__LEVEL_COUNT) {
965  	        crm_trace("Attempting fencing level %d targeting %s (%d devices) "
966  	                  "for client %s@%s (id=%.8s)",
967  	                  op->level, op->target, g_list_length(tp->levels[op->level]),
968  	                  op->client_name, op->originator, op->id);
969  	        set_op_device_list(op, tp->levels[op->level]);
970  	
971  	        // The requested delay has been applied for the first fencing level
972  	        if ((op->level > 1) && (op->client_delay > 0)) {
973  	            op->client_delay = 0;
974  	        }
975  	
976  	        if ((g_list_next(op->devices_list) != NULL)
977  	            && pcmk__str_eq(op->action, PCMK_ACTION_REBOOT, pcmk__str_none)) {
978  	            /* A reboot has been requested for a topology level with multiple
979  	             * devices. Instead of rebooting the devices sequentially, we will
980  	             * turn them all off, then turn them all on again. (Think about
981  	             * switched power outlets for redundant power supplies.)
982  	             */
983  	            op_phase_off(op);
984  	        }
985  	        return pcmk_rc_ok;
986  	    }
987  	
988  	    crm_info("All %sfencing options targeting %s for client %s@%s failed "
989  	             QB_XS " id=%.8s",
990  	             (stonith_watchdog_timeout_ms > 0)?"non-watchdog ":"",
991  	             op->target, op->client_name, op->originator, op->id);
992  	    return ENODEV;
993  	}
994  	
995  	/*!
996  	 * \internal
997  	 * \brief If fencing operation is a duplicate, merge it into the other one
998  	 *
999  	 * \param[in,out] op  Fencing operation to check
1000 	 */
1001 	static void
1002 	merge_duplicates(remote_fencing_op_t *op)
1003 	{
1004 	    GHashTableIter iter;
1005 	    remote_fencing_op_t *other = NULL;
1006 	
1007 	    time_t now = time(NULL);
1008 	
1009 	    g_hash_table_iter_init(&iter, stonith_remote_op_list);
1010 	    while (g_hash_table_iter_next(&iter, NULL, (void **)&other)) {
1011 	        const char *other_action = op_requested_action(other);
1012 	        pcmk__node_status_t *node = NULL;
1013 	
1014 	        if (!strcmp(op->id, other->id)) {
1015 	            continue; // Don't compare against self
1016 	        }
1017 	        if (other->state > st_exec) {
1018 	            crm_trace("%.8s not duplicate of %.8s: not in progress",
1019 	                      op->id, other->id);
1020 	            continue;
1021 	        }
1022 	        if (!pcmk__str_eq(op->target, other->target, pcmk__str_casei)) {
1023 	            crm_trace("%.8s not duplicate of %.8s: node %s vs. %s",
1024 	                      op->id, other->id, op->target, other->target);
1025 	            continue;
1026 	        }
1027 	        if (!pcmk__str_eq(op->action, other_action, pcmk__str_none)) {
1028 	            crm_trace("%.8s not duplicate of %.8s: action %s vs. %s",
1029 	                      op->id, other->id, op->action, other_action);
1030 	            continue;
1031 	        }
1032 	        if (pcmk__str_eq(op->client_name, other->client_name, pcmk__str_casei)) {
1033 	            crm_trace("%.8s not duplicate of %.8s: same client %s",
1034 	                      op->id, other->id, op->client_name);
1035 	            continue;
1036 	        }
1037 	        if (pcmk__str_eq(other->target, other->originator, pcmk__str_casei)) {
1038 	            crm_trace("%.8s not duplicate of %.8s: self-fencing for %s",
1039 	                      op->id, other->id, other->target);
1040 	            continue;
1041 	        }
1042 	
1043 	        node = pcmk__get_node(0, other->originator, NULL,
1044 	                              pcmk__node_search_cluster_member);
1045 	
1046 	        if (!fencing_peer_active(node)) {
1047 	            crm_notice("Failing action '%s' targeting %s originating from "
1048 	                       "client %s@%s: Originator is dead " QB_XS " id=%.8s",
1049 	                       other->action, other->target, other->client_name,
1050 	                       other->originator, other->id);
1051 	            crm_trace("%.8s not duplicate of %.8s: originator dead",
1052 	                      op->id, other->id);
1053 	            other->state = st_failed;
1054 	            continue;
1055 	        }
1056 	        if ((other->total_timeout > 0)
1057 	            && (now > (other->total_timeout + other->created))) {
1058 	            crm_trace("%.8s not duplicate of %.8s: old (%lld vs. %lld + %ds)",
1059 	                      op->id, other->id, (long long)now, (long long)other->created,
1060 	                      other->total_timeout);
1061 	            continue;
1062 	        }
1063 	
1064 	        /* There is another in-flight request to fence the same host
1065 	         * Piggyback on that instead.  If it fails, so do we.
1066 	         */
1067 	        other->duplicates = g_list_append(other->duplicates, op);
1068 	        if (other->total_timeout == 0) {
1069 	            other->total_timeout = op->total_timeout =
1070 	                TIMEOUT_MULTIPLY_FACTOR * get_op_total_timeout(op, NULL);
1071 	            crm_trace("Best guess as to timeout used for %.8s: %ds",
1072 	                      other->id, other->total_timeout);
1073 	        }
1074 	        crm_notice("Merging fencing action '%s' targeting %s originating from "
1075 	                   "client %s with identical request from %s@%s "
1076 	                   QB_XS " original=%.8s duplicate=%.8s total_timeout=%ds",
1077 	                   op->action, op->target, op->client_name,
1078 	                   other->client_name, other->originator,
1079 	                   op->id, other->id, other->total_timeout);
1080 	        report_timeout_period(op, other->total_timeout);
1081 	        op->state = st_duplicate;
1082 	    }
1083 	}
1084 	
1085 	static uint32_t fencing_active_peers(void)
1086 	{
1087 	    uint32_t count = 0;
1088 	    pcmk__node_status_t *entry = NULL;
1089 	    GHashTableIter gIter;
1090 	
1091 	    g_hash_table_iter_init(&gIter, pcmk__peer_cache);
1092 	    while (g_hash_table_iter_next(&gIter, NULL, (void **)&entry)) {
1093 	        if(fencing_peer_active(entry)) {
1094 	            count++;
1095 	        }
1096 	    }
1097 	    return count;
1098 	}
1099 	
1100 	/*!
1101 	 * \internal
1102 	 * \brief Process a manual confirmation of a pending fence action
1103 	 *
1104 	 * \param[in]     client  IPC client that sent confirmation
1105 	 * \param[in,out] msg     Request XML with manual confirmation
1106 	 *
1107 	 * \return Standard Pacemaker return code
1108 	 */
1109 	int
1110 	fenced_handle_manual_confirmation(const pcmk__client_t *client, xmlNode *msg)
1111 	{
1112 	    remote_fencing_op_t *op = NULL;
1113 	    xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_TARGET, msg, LOG_ERR);
1114 	
1115 	    CRM_CHECK(dev != NULL, return EPROTO);
1116 	
1117 	    crm_notice("Received manual confirmation that %s has been fenced",
1118 	               pcmk__s(crm_element_value(dev, PCMK__XA_ST_TARGET),
1119 	                       "unknown target"));
1120 	    op = initiate_remote_stonith_op(client, msg, TRUE);
1121 	    if (op == NULL) {
1122 	        return EPROTO;
1123 	    }
1124 	    op->state = st_done;
1125 	    op->delegate = pcmk__str_copy("a human");
1126 	
1127 	    // For the fencer's purposes, the fencing operation is done
1128 	    pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
1129 	    finalize_op(op, msg, false);
1130 	
1131 	    /* For the requester's purposes, the operation is still pending. The
1132 	     * actual result will be sent asynchronously via the operation's done_cb().
1133 	     */
1134 	    return EINPROGRESS;
1135 	}
1136 	
1137 	/*!
1138 	 * \internal
1139 	 * \brief Create a new remote stonith operation
1140 	 *
1141 	 * \param[in] client   ID of local stonith client that initiated the operation
1142 	 * \param[in] request  The request from the client that started the operation
1143 	 * \param[in] peer     TRUE if this operation is owned by another stonith peer
1144 	 *                     (an operation owned by one peer is stored on all peers,
1145 	 *                     but only the owner executes it; all nodes get the results
1146 	 *                     once the owner finishes execution)
1147 	 */
1148 	void *
1149 	create_remote_stonith_op(const char *client, xmlNode *request, gboolean peer)
1150 	{
1151 	    remote_fencing_op_t *op = NULL;
1152 	    xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_TARGET, request,
1153 	                                    LOG_NEVER);
1154 	    int rc = pcmk_rc_ok;
1155 	    const char *operation = NULL;
1156 	
1157 	    init_stonith_remote_op_hash_table(&stonith_remote_op_list);
1158 	
1159 	    /* If this operation is owned by another node, check to make
1160 	     * sure we haven't already created this operation. */
1161 	    if (peer && dev) {
1162 	        const char *op_id = crm_element_value(dev, PCMK__XA_ST_REMOTE_OP);
1163 	
1164 	        CRM_CHECK(op_id != NULL, return NULL);
1165 	
1166 	        op = g_hash_table_lookup(stonith_remote_op_list, op_id);
1167 	        if (op) {
1168 	            crm_debug("Reusing existing remote fencing op %.8s for %s",
1169 	                      op_id, ((client == NULL)? "unknown client" : client));
1170 	            return op;
1171 	        }
1172 	    }
1173 	
1174 	    op = pcmk__assert_alloc(1, sizeof(remote_fencing_op_t));
1175 	
1176 	    crm_element_value_int(request, PCMK__XA_ST_TIMEOUT, &(op->base_timeout));
1177 	    // Value -1 means disable any static/random fencing delays
1178 	    crm_element_value_int(request, PCMK__XA_ST_DELAY, &(op->client_delay));
1179 	
1180 	    if (peer && dev) {
1181 	        op->id = crm_element_value_copy(dev, PCMK__XA_ST_REMOTE_OP);
1182 	    } else {
1183 	        op->id = crm_generate_uuid();
1184 	    }
1185 	
1186 	    g_hash_table_replace(stonith_remote_op_list, op->id, op);
1187 	
1188 	    op->state = st_query;
1189 	    op->replies_expected = fencing_active_peers();
1190 	    op->action = crm_element_value_copy(dev, PCMK__XA_ST_DEVICE_ACTION);
1191 	
1192 	    /* The node initiating the stonith operation. If an operation is relayed,
1193 	     * this is the last node the operation lands on. When in standalone mode,
1194 	     * origin is the ID of the client that originated the operation.
1195 	     *
1196 	     * Or may be the name of the function that created the operation.
1197 	     */
1198 	    op->originator = crm_element_value_copy(dev, PCMK__XA_ST_ORIGIN);
1199 	    if (op->originator == NULL) {
1200 	        /* Local or relayed request */
1201 	        op->originator = pcmk__str_copy(fenced_get_local_node());
1202 	    }
1203 	
1204 	    // Delegate may not be set
1205 	    op->delegate = crm_element_value_copy(dev, PCMK__XA_ST_DELEGATE);
1206 	    op->created = time(NULL);
1207 	
1208 	    CRM_LOG_ASSERT(client != NULL);
1209 	    op->client_id = pcmk__str_copy(client);
1210 	
1211 	    /* For a RELAY operation, set fenced on the client. */
1212 	    operation = crm_element_value(request, PCMK__XA_ST_OP);
1213 	
1214 	    if (pcmk__str_eq(operation, STONITH_OP_RELAY, pcmk__str_none)) {
1215 	        op->client_name = crm_strdup_printf("%s.%lu", crm_system_name,
1216 	                                         (unsigned long) getpid());
1217 	    } else {
1218 	        op->client_name = crm_element_value_copy(request,
1219 	                                                 PCMK__XA_ST_CLIENTNAME);
1220 	    }
1221 	
1222 	    op->target = crm_element_value_copy(dev, PCMK__XA_ST_TARGET);
1223 	
1224 	    // @TODO Figure out how to avoid copying XML here
1225 	    op->request = pcmk__xml_copy(NULL, request);
1226 	
1227 	    rc = pcmk__xe_get_flags(request, PCMK__XA_ST_CALLOPT, &(op->call_options),
1228 	                            0U);
1229 	    if (rc != pcmk_rc_ok) {
1230 	        crm_warn("Couldn't parse options from request %s: %s",
1231 	                 op->id, pcmk_rc_str(rc));
1232 	    }
1233 	
1234 	    crm_element_value_int(request, PCMK__XA_ST_CALLID, &(op->client_callid));
1235 	
1236 	    crm_trace("%s new fencing op %s ('%s' targeting %s for client %s, "
1237 	              "base timeout %ds, %u %s expected)",
1238 	              (peer && dev)? "Recorded" : "Generated", op->id, op->action,
1239 	              op->target, op->client_name, op->base_timeout,
1240 	              op->replies_expected,
1241 	              pcmk__plural_alt(op->replies_expected, "reply", "replies"));
1242 	
1243 	    if (op->call_options & st_opt_cs_nodeid) {
1244 	        int nodeid;
1245 	        pcmk__node_status_t *node = NULL;
1246 	
1247 	        pcmk__scan_min_int(op->target, &nodeid, 0);
1248 	        node = pcmk__search_node_caches(nodeid, NULL, NULL,
1249 	                                        pcmk__node_search_any
1250 	                                        |pcmk__node_search_cluster_cib);
1251 	
1252 	        /* Ensure the conversion only happens once */
1253 	        stonith__clear_call_options(op->call_options, op->id, st_opt_cs_nodeid);
1254 	
1255 	        if ((node != NULL) && (node->name != NULL)) {
1256 	            pcmk__str_update(&(op->target), node->name);
1257 	
1258 	        } else {
1259 	            crm_warn("Could not expand nodeid '%s' into a host name", op->target);
1260 	        }
1261 	    }
1262 	
1263 	    /* check to see if this is a duplicate operation of another in-flight operation */
1264 	    merge_duplicates(op);
1265 	
1266 	    if (op->state != st_duplicate) {
1267 	        /* kick history readers */
1268 	        fenced_send_notification(PCMK__VALUE_ST_NOTIFY_HISTORY, NULL, NULL);
1269 	    }
1270 	
1271 	    /* safe to trim as long as that doesn't touch pending ops */
1272 	    stonith_fence_history_trim();
1273 	
1274 	    return op;
1275 	}
1276 	
1277 	/*!
1278 	 * \internal
1279 	 * \brief Create a peer fencing operation from a request, and initiate it
1280 	 *
1281 	 * \param[in] client     IPC client that made request (NULL to get from request)
1282 	 * \param[in] request    Request XML
1283 	 * \param[in] manual_ack Whether this is a manual action confirmation
1284 	 *
1285 	 * \return Newly created operation on success, otherwise NULL
1286 	 */
1287 	remote_fencing_op_t *
1288 	initiate_remote_stonith_op(const pcmk__client_t *client, xmlNode *request,
1289 	                           gboolean manual_ack)
1290 	{
1291 	    int query_timeout = 0;
1292 	    xmlNode *query = NULL;
1293 	    const char *client_id = NULL;
1294 	    remote_fencing_op_t *op = NULL;
1295 	    const char *relay_op_id = NULL;
1296 	    const char *operation = NULL;
1297 	
1298 	    if (client) {
1299 	        client_id = client->id;
1300 	    } else {
1301 	        client_id = crm_element_value(request, PCMK__XA_ST_CLIENTID);
1302 	    }
1303 	
1304 	    CRM_LOG_ASSERT(client_id != NULL);
1305 	    op = create_remote_stonith_op(client_id, request, FALSE);
1306 	    op->owner = TRUE;
1307 	    if (manual_ack) {
1308 	        return op;
1309 	    }
1310 	
1311 	    CRM_CHECK(op->action, return NULL);
1312 	
1313 	    if (advance_topology_level(op, true) != pcmk_rc_ok) {
1314 	        op->state = st_failed;
1315 	    }
1316 	
1317 	    switch (op->state) {
1318 	        case st_failed:
1319 	            // advance_topology_level() exhausted levels
1320 	            pcmk__set_result(&op->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
1321 	                             "All topology levels failed");
1322 	            crm_warn("Could not request peer fencing (%s) targeting %s "
1323 	                     QB_XS " id=%.8s", op->action, op->target, op->id);
1324 	            finalize_op(op, NULL, false);
1325 	            return op;
1326 	
1327 	        case st_duplicate:
1328 	            crm_info("Requesting peer fencing (%s) targeting %s (duplicate) "
1329 	                     QB_XS " id=%.8s", op->action, op->target, op->id);
1330 	            return op;
1331 	
1332 	        default:
1333 	            crm_notice("Requesting peer fencing (%s) targeting %s "
1334 	                       QB_XS " id=%.8s state=%s base_timeout=%ds",
1335 	                       op->action, op->target, op->id,
1336 	                       stonith_op_state_str(op->state), op->base_timeout);
1337 	    }
1338 	
1339 	    query = stonith_create_op(op->client_callid, op->id, STONITH_OP_QUERY,
1340 	                              NULL, op->call_options);
1341 	
1342 	    crm_xml_add(query, PCMK__XA_ST_REMOTE_OP, op->id);
1343 	    crm_xml_add(query, PCMK__XA_ST_TARGET, op->target);
1344 	    crm_xml_add(query, PCMK__XA_ST_DEVICE_ACTION, op_requested_action(op));
1345 	    crm_xml_add(query, PCMK__XA_ST_ORIGIN, op->originator);
1346 	    crm_xml_add(query, PCMK__XA_ST_CLIENTID, op->client_id);
1347 	    crm_xml_add(query, PCMK__XA_ST_CLIENTNAME, op->client_name);
1348 	    crm_xml_add_int(query, PCMK__XA_ST_TIMEOUT, op->base_timeout);
1349 	
1350 	    /* In case of RELAY operation, RELAY information is added to the query to delete the original operation of RELAY. */
1351 	    operation = crm_element_value(request, PCMK__XA_ST_OP);
1352 	    if (pcmk__str_eq(operation, STONITH_OP_RELAY, pcmk__str_none)) {
1353 	        relay_op_id = crm_element_value(request, PCMK__XA_ST_REMOTE_OP);
1354 	        if (relay_op_id) {
1355 	            crm_xml_add(query, PCMK__XA_ST_REMOTE_OP_RELAY, relay_op_id);
1356 	        }
1357 	    }
1358 	
1359 	    pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, query);
1360 	    pcmk__xml_free(query);
1361 	
1362 	    query_timeout = op->base_timeout * TIMEOUT_MULTIPLY_FACTOR;
1363 	    op->query_timer = pcmk__create_timer((1000 * query_timeout), remote_op_query_timeout, op);
1364 	
1365 	    return op;
1366 	}
1367 	
1368 	enum find_best_peer_options {
1369 	    /*! Skip checking the target peer for capable fencing devices */
1370 	    FIND_PEER_SKIP_TARGET = 0x0001,
1371 	    /*! Only check the target peer for capable fencing devices */
1372 	    FIND_PEER_TARGET_ONLY = 0x0002,
1373 	    /*! Skip peers and devices that are not verified */
1374 	    FIND_PEER_VERIFIED_ONLY = 0x0004,
1375 	};
1376 	
1377 	static bool
1378 	is_watchdog_fencing(const remote_fencing_op_t *op, const char *device)
1379 	{
1380 	    return (stonith_watchdog_timeout_ms > 0
1381 	            // Only an explicit mismatch is considered not a watchdog fencing.
1382 	            && pcmk__str_eq(device, STONITH_WATCHDOG_ID, pcmk__str_null_matches)
1383 	            && pcmk__is_fencing_action(op->action)
1384 	            && node_does_watchdog_fencing(op->target));
1385 	}
1386 	
1387 	static peer_device_info_t *
1388 	find_best_peer(const char *device, remote_fencing_op_t * op, enum find_best_peer_options options)
1389 	{
1390 	    GList *iter = NULL;
1391 	    gboolean verified_devices_only = (options & FIND_PEER_VERIFIED_ONLY) ? TRUE : FALSE;
1392 	
1393 	    if (!device && pcmk_is_set(op->call_options, st_opt_topology)) {
1394 	        return NULL;
1395 	    }
1396 	
1397 	    for (iter = op->query_results; iter != NULL; iter = iter->next) {
1398 	        peer_device_info_t *peer = iter->data;
1399 	
1400 	        crm_trace("Testing result from %s targeting %s with %d device%s: %d %x",
1401 	                  peer->host, op->target, peer->ndevices,
1402 	                  pcmk__plural_s(peer->ndevices), peer->tried, options);
1403 	        if ((options & FIND_PEER_SKIP_TARGET) && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) {
1404 	            continue;
1405 	        }
1406 	        if ((options & FIND_PEER_TARGET_ONLY) && !pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) {
1407 	            continue;
1408 	        }
1409 	
1410 	        if (pcmk_is_set(op->call_options, st_opt_topology)) {
1411 	
1412 	            if (grab_peer_device(op, peer, device, verified_devices_only)) {
1413 	                return peer;
1414 	            }
1415 	
1416 	        } else if (!peer->tried
1417 	                   && count_peer_devices(op, peer, verified_devices_only,
1418 	                                         fenced_support_flag(op->action))) {
1419 	            /* No topology: Use the current best peer */
1420 	            crm_trace("Simple fencing");
1421 	            return peer;
1422 	        }
1423 	    }
1424 	
1425 	    return NULL;
1426 	}
1427 	
1428 	static peer_device_info_t *
1429 	stonith_choose_peer(remote_fencing_op_t * op)
1430 	{
1431 	    const char *device = NULL;
1432 	    peer_device_info_t *peer = NULL;
1433 	    uint32_t active = fencing_active_peers();
1434 	
1435 	    do {
1436 	        if (op->devices) {
1437 	            device = op->devices->data;
1438 	            crm_trace("Checking for someone to fence (%s) %s using %s",
1439 	                      op->action, op->target, device);
1440 	        } else {
1441 	            crm_trace("Checking for someone to fence (%s) %s",
1442 	                      op->action, op->target);
1443 	        }
1444 	
1445 	        /* Best choice is a peer other than the target with verified access */
1446 	        peer = find_best_peer(device, op, FIND_PEER_SKIP_TARGET|FIND_PEER_VERIFIED_ONLY);
1447 	        if (peer) {
1448 	            crm_trace("Found verified peer %s for %s", peer->host, device?device:"<any>");
1449 	            return peer;
1450 	        }
1451 	
1452 	        if(op->query_timer != 0 && op->replies < QB_MIN(op->replies_expected, active)) {
1453 	            crm_trace("Waiting before looking for unverified devices to fence %s", op->target);
1454 	            return NULL;
1455 	        }
1456 	
1457 	        /* If no other peer has verified access, next best is unverified access */
1458 	        peer = find_best_peer(device, op, FIND_PEER_SKIP_TARGET);
1459 	        if (peer) {
1460 	            crm_trace("Found best unverified peer %s", peer->host);
1461 	            return peer;
1462 	        }
1463 	
1464 	        /* If no other peer can do it, last option is self-fencing
1465 	         * (which is never allowed for the "on" phase of a remapped reboot)
1466 	         */
1467 	        if (op->phase != st_phase_on) {
1468 	            peer = find_best_peer(device, op, FIND_PEER_TARGET_ONLY);
1469 	            if (peer) {
1470 	                crm_trace("%s will fence itself", peer->host);
1471 	                return peer;
1472 	            }
1473 	        }
1474 	
1475 	        /* Try the next fencing level if there is one (unless we're in the "on"
1476 	         * phase of a remapped "reboot", because we ignore errors in that case)
1477 	         */
1478 	    } while ((op->phase != st_phase_on)
1479 	             && pcmk_is_set(op->call_options, st_opt_topology)
1480 	             && (advance_topology_level(op, false) == pcmk_rc_ok));
1481 	
1482 	    /* With a simple watchdog fencing configuration without a topology,
1483 	     * "device" is NULL here. Consider it should be done with watchdog fencing.
1484 	     */
1485 	    if (is_watchdog_fencing(op, device)) {
1486 	        crm_info("Couldn't contact watchdog-fencing target-node (%s)",
1487 	                 op->target);
1488 	        /* check_watchdog_fencing_and_wait will log additional info */
1489 	    } else {
1490 	        crm_notice("Couldn't find anyone to fence (%s) %s using %s",
1491 	                   op->action, op->target, (device? device : "any device"));
1492 	    }
1493 	    return NULL;
1494 	}
1495 	
1496 	static int
1497 	valid_fencing_timeout(int specified_timeout, bool action_specific,
1498 	                      const remote_fencing_op_t *op, const char *device)
1499 	{
1500 	    int timeout = specified_timeout;
1501 	
1502 	    if (!is_watchdog_fencing(op, device)) {
1503 	        return timeout;
1504 	    }
1505 	
1506 	    timeout = (int) QB_MIN(QB_MAX(specified_timeout,
1507 	                                  pcmk__timeout_ms2s(stonith_watchdog_timeout_ms)),
1508 	                           INT_MAX);
1509 	
1510 	    if (timeout > specified_timeout) {
1511 	        if (action_specific) {
1512 	            crm_warn("pcmk_%s_timeout %ds for %s is too short (must be >= "
1513 	                     PCMK_OPT_STONITH_WATCHDOG_TIMEOUT " %ds), using %ds "
1514 	                     "instead",
1515 	                     op->action, specified_timeout, device? device : "watchdog",
1516 	                     timeout, timeout);
1517 	
1518 	        } else {
1519 	            crm_warn("Fencing timeout %ds is too short (must be >= "
1520 	                     PCMK_OPT_STONITH_WATCHDOG_TIMEOUT " %ds), using %ds "
1521 	                     "instead",
1522 	                     specified_timeout, timeout, timeout);
1523 	        }
1524 	    }
1525 	
1526 	    return timeout;
1527 	}
1528 	
1529 	static int
1530 	get_device_timeout(const remote_fencing_op_t *op,
1531 	                   const peer_device_info_t *peer, const char *device,
1532 	                   bool with_delay)
1533 	{
1534 	    int timeout = op->base_timeout;
1535 	    device_properties_t *props;
1536 	
1537 	    timeout = valid_fencing_timeout(op->base_timeout, false, op, device);
1538 	
1539 	    if (!peer || !device) {
1540 	        return timeout;
1541 	    }
1542 	
1543 	    props = g_hash_table_lookup(peer->devices, device);
1544 	    if (!props) {
1545 	        return timeout;
1546 	    }
1547 	
1548 	    if (props->custom_action_timeout[op->phase]) {
1549 	        timeout = valid_fencing_timeout(props->custom_action_timeout[op->phase],
1550 	                                        true, op, device);
1551 	    }
1552 	
1553 	    // op->client_delay < 0 means disable any static/random fencing delays
1554 	    if (with_delay && (op->client_delay >= 0)) {
1555 	        // delay_base is eventually limited by delay_max
1556 	        timeout += (props->delay_max[op->phase] > 0 ?
1557 	                    props->delay_max[op->phase] : props->delay_base[op->phase]);
1558 	    }
1559 	
1560 	    return timeout;
1561 	}
1562 	
1563 	struct timeout_data {
1564 	    const remote_fencing_op_t *op;
1565 	    const peer_device_info_t *peer;
1566 	    int total_timeout;
1567 	};
1568 	
1569 	/*!
1570 	 * \internal
1571 	 * \brief Add timeout to a total if device has not been executed yet
1572 	 *
1573 	 * \param[in]     key        GHashTable key (device ID)
1574 	 * \param[in]     value      GHashTable value (device properties)
1575 	 * \param[in,out] user_data  Timeout data
1576 	 */
1577 	static void
1578 	add_device_timeout(gpointer key, gpointer value, gpointer user_data)
1579 	{
1580 	    const char *device_id = key;
1581 	    device_properties_t *props = value;
1582 	    struct timeout_data *timeout = user_data;
1583 	
1584 	    if (!props->executed[timeout->op->phase]
1585 	        && !props->disallowed[timeout->op->phase]) {
1586 	        timeout->total_timeout += get_device_timeout(timeout->op, timeout->peer,
1587 	                                                     device_id, true);
1588 	    }
1589 	}
1590 	
1591 	static int
1592 	get_peer_timeout(const remote_fencing_op_t *op, const peer_device_info_t *peer)
1593 	{
1594 	    struct timeout_data timeout;
1595 	
1596 	    timeout.op = op;
1597 	    timeout.peer = peer;
1598 	    timeout.total_timeout = 0;
1599 	
1600 	    g_hash_table_foreach(peer->devices, add_device_timeout, &timeout);
1601 	
1602 	    return (timeout.total_timeout? timeout.total_timeout : op->base_timeout);
1603 	}
1604 	
1605 	static int
1606 	get_op_total_timeout(const remote_fencing_op_t *op,
1607 	                     const peer_device_info_t *chosen_peer)
1608 	{
1609 	    long long total_timeout = 0;
1610 	    stonith_topology_t *tp = find_topology_for_host(op->target);
1611 	
(1) Event path: Condition "pcmk_all_flags_set(op->call_options, st_opt_topology)", taking true branch.
(2) Event path: Condition "tp", taking true branch.
1612 	    if (pcmk_is_set(op->call_options, st_opt_topology) && tp) {
1613 	        int i;
1614 	        GList *device_list = NULL;
1615 	        GList *iter = NULL;
1616 	        GList *auto_list = NULL;
1617 	
(3) Event path: Condition "pcmk__str_eq(op->action, "on", pcmk__str_none)", taking true branch.
(4) Event path: Condition "op->automatic_list != NULL", taking true branch.
1618 	        if (pcmk__str_eq(op->action, PCMK_ACTION_ON, pcmk__str_none)
1619 	            && (op->automatic_list != NULL)) {
1620 	            auto_list = g_list_copy(op->automatic_list);
1621 	        }
1622 	
1623 	        /* Yep, this looks scary, nested loops all over the place.
1624 	         * Here is what is going on.
1625 	         * Loop1: Iterate through fencing levels.
1626 	         * Loop2: If a fencing level has devices, loop through each device
1627 	         * Loop3: For each device in a fencing level, see what peer owns it
1628 	         *        and what that peer has reported the timeout is for the device.
1629 	         */
(5) Event path: Condition "i < 10", taking true branch.
(8) Event path: Condition "i < 10", taking true branch.
(11) Event path: Condition "i < 10", taking true branch.
(38) Event path: Condition "i < 10", taking false branch.
1630 	        for (i = 0; i < ST__LEVEL_COUNT; i++) {
(6) Event path: Condition "!tp->levels[i]", taking true branch.
(9) Event path: Condition "!tp->levels[i]", taking true branch.
(12) Event path: Condition "!tp->levels[i]", taking false branch.
1631 	            if (!tp->levels[i]) {
(7) Event path: Continuing loop.
(10) Event path: Continuing loop.
1632 	                continue;
1633 	            }
(13) Event path: Condition "device_list", taking true branch.
(26) Event path: Condition "device_list", taking true branch.
(36) Event path: Condition "device_list", taking false branch.
1634 	            for (device_list = tp->levels[i]; device_list; device_list = device_list->next) {
1635 	                bool found = false;
1636 	
(14) Event path: Condition "iter != NULL", taking true branch.
(19) Event path: Condition "iter != NULL", taking true branch.
(27) Event path: Condition "iter != NULL", taking true branch.
(32) Event path: Condition "iter != NULL", taking false branch.
1637 	                for (iter = op->query_results; iter != NULL; iter = iter->next) {
1638 	                    const peer_device_info_t *peer = iter->data;
1639 	
(15) Event path: Condition "auto_list", taking true branch.
(20) Event path: Condition "auto_list", taking true branch.
(28) Event path: Condition "auto_list", taking true branch.
1640 	                    if (auto_list) {
1641 	                        GList *match = g_list_find_custom(auto_list, device_list->data,
1642 	                                        sort_strings);
(16) Event path: Condition "match", taking true branch.
(21) Event path: Condition "match", taking true branch.
(29) Event path: Condition "match", taking true branch.
1643 	                        if (match) {
1644 	                            auto_list = g_list_remove(auto_list, match->data);
1645 	                        }
1646 	                    }
1647 	
(17) Event path: Condition "find_peer_device(op, peer, device_list->data, fenced_support_flag(op->action))", taking false branch.
(22) Event path: Condition "find_peer_device(op, peer, device_list->data, fenced_support_flag(op->action))", taking true branch.
(30) Event path: Condition "find_peer_device(op, peer, device_list->data, fenced_support_flag(op->action))", taking false branch.
1648 	                    if (find_peer_device(op, peer, device_list->data,
1649 	                                         fenced_support_flag(op->action))) {
1650 	                        total_timeout += get_device_timeout(op, peer,
1651 	                                                            device_list->data,
1652 	                                                            true);
1653 	                        found = true;
(23) Event path: Breaking from loop.
1654 	                        break;
1655 	                    }
(18) Event path: Jumping back to the beginning of the loop.
(31) Event path: Jumping back to the beginning of the loop.
1656 	                }               /* End Loop3: match device with peer that owns device, find device's timeout period */
1657 	
1658 	                /* in case of watchdog-device we add the timeout to the budget
1659 	                   if didn't get a reply
1660 	                 */
(24) Event path: Condition "!found", taking false branch.
(33) Event path: Condition "!found", taking true branch.
(34) Event path: Condition "is_watchdog_fencing(op, device_list->data)", taking true branch.
1661 	                if (!found && is_watchdog_fencing(op, device_list->data)) {
1662 	                    total_timeout += pcmk__timeout_ms2s(stonith_watchdog_timeout_ms);
1663 	                }
(25) Event path: Jumping back to the beginning of the loop.
(35) Event path: Jumping back to the beginning of the loop.
1664 	            }                   /* End Loop2: iterate through devices at a specific level */
(37) Event path: Jumping back to the beginning of the loop.
1665 	        }                       /*End Loop1: iterate through fencing levels */
1666 	
1667 	        //Add only exists automatic_list device timeout
(39) Event path: Condition "auto_list", taking true branch.
1668 	        if (auto_list) {
(40) Event path: Condition "iter != NULL", taking true branch.
1669 	            for (iter = auto_list; iter != NULL; iter = iter->next) {
1670 	                GList *iter2 = NULL;
1671 	
(41) Event path: Condition "iter2 != NULL", taking true branch.
(44) Event null_field: Reading field "next", which is expected to possibly be "NULL" in "iter2->next" (checked 454 out of 456 times).
(45) Event alias_transfer: Assigning: "iter" = "iter2->next".
(46) Event path: Condition "iter2 != NULL", taking true branch.
Also see events: [dereference][example_checked][example_checked][example_checked][example_checked][example_checked]
1672 	                for (iter2 = op->query_results; iter2 != NULL; iter = iter2->next) {
1673 	                    peer_device_info_t *peer = iter2->data;
CID (unavailable; MK=eb81cf483c48825540e07bbd95bb12d8) (#1 of 1): Dereference of potentially null field (NULL_FIELD):
(42) Event path: Condition "find_peer_device(op, peer, iter->data, st_device_supports_on)", taking false branch.
(47) Event dereference: Dereferencing "iter", which is known to be "NULL".
Also see events: [null_field][alias_transfer][example_checked][example_checked][example_checked][example_checked][example_checked]
1674 	                    if (find_peer_device(op, peer, iter->data, st_device_supports_on)) {
1675 	                        total_timeout += get_device_timeout(op, peer,
1676 	                                                            iter->data, true);
1677 	                        break;
1678 	                    }
(43) Event path: Jumping back to the beginning of the loop.
1679 	                }
1680 	            }
1681 	        }
1682 	
1683 	        g_list_free(auto_list);
1684 	
1685 	    } else if (chosen_peer) {
1686 	        total_timeout = get_peer_timeout(op, chosen_peer);
1687 	
1688 	    } else {
1689 	        total_timeout = valid_fencing_timeout(op->base_timeout, false, op,
1690 	                                              NULL);
1691 	    }
1692 	
1693 	    if (total_timeout <= 0) {
1694 	        total_timeout = op->base_timeout;
1695 	    }
1696 	
1697 	    /* Take any requested fencing delay into account to prevent it from eating
1698 	     * up the total timeout.
1699 	     */
1700 	    if (op->client_delay > 0) {
1701 	        total_timeout += op->client_delay;
1702 	    }
1703 	    return (int) QB_MIN(total_timeout, INT_MAX);
1704 	}
1705 	
1706 	static void
1707 	report_timeout_period(remote_fencing_op_t * op, int op_timeout)
1708 	{
1709 	    GList *iter = NULL;
1710 	    xmlNode *update = NULL;
1711 	    const char *client_node = NULL;
1712 	    const char *client_id = NULL;
1713 	    const char *call_id = NULL;
1714 	
1715 	    if (op->call_options & st_opt_sync_call) {
1716 	        /* There is no reason to report the timeout for a synchronous call. It
1717 	         * is impossible to use the reported timeout to do anything when the client
1718 	         * is blocking for the response.  This update is only important for
1719 	         * async calls that require a callback to report the results in. */
1720 	        return;
1721 	    } else if (!op->request) {
1722 	        return;
1723 	    }
1724 	
1725 	    crm_trace("Reporting timeout for %s (id=%.8s)", op->client_name, op->id);
1726 	    client_node = crm_element_value(op->request, PCMK__XA_ST_CLIENTNODE);
1727 	    call_id = crm_element_value(op->request, PCMK__XA_ST_CALLID);
1728 	    client_id = crm_element_value(op->request, PCMK__XA_ST_CLIENTID);
1729 	    if (!client_node || !call_id || !client_id) {
1730 	        return;
1731 	    }
1732 	
1733 	    if (pcmk__str_eq(client_node, fenced_get_local_node(), pcmk__str_casei)) {
1734 	        // Client is connected to this node, so send update directly to them
1735 	        do_stonith_async_timeout_update(client_id, call_id, op_timeout);
1736 	        return;
1737 	    }
1738 	
1739 	    /* The client is connected to another node, relay this update to them */
1740 	    update = stonith_create_op(op->client_callid, op->id, STONITH_OP_TIMEOUT_UPDATE, NULL, 0);
1741 	    crm_xml_add(update, PCMK__XA_ST_REMOTE_OP, op->id);
1742 	    crm_xml_add(update, PCMK__XA_ST_CLIENTID, client_id);
1743 	    crm_xml_add(update, PCMK__XA_ST_CALLID, call_id);
1744 	    crm_xml_add_int(update, PCMK__XA_ST_TIMEOUT, op_timeout);
1745 	
1746 	    pcmk__cluster_send_message(pcmk__get_node(0, client_node, NULL,
1747 	                                              pcmk__node_search_cluster_member),
1748 	                               pcmk_ipc_fenced, update);
1749 	
1750 	    pcmk__xml_free(update);
1751 	
1752 	    for (iter = op->duplicates; iter != NULL; iter = iter->next) {
1753 	        remote_fencing_op_t *dup = iter->data;
1754 	
1755 	        crm_trace("Reporting timeout for duplicate %.8s to client %s",
1756 	                  dup->id, dup->client_name);
1757 	        report_timeout_period(iter->data, op_timeout);
1758 	    }
1759 	}
1760 	
1761 	/*!
1762 	 * \internal
1763 	 * \brief Advance an operation to the next device in its topology
1764 	 *
1765 	 * \param[in,out] op      Fencer operation to advance
1766 	 * \param[in]     device  ID of device that just completed
1767 	 * \param[in,out] msg     If not NULL, XML reply of last delegated operation
1768 	 */
1769 	static void
1770 	advance_topology_device_in_level(remote_fencing_op_t *op, const char *device,
1771 	                                 xmlNode *msg)
1772 	{
1773 	    /* Advance to the next device at this topology level, if any */
1774 	    if (op->devices) {
1775 	        op->devices = op->devices->next;
1776 	    }
1777 	
1778 	    /* Handle automatic unfencing if an "on" action was requested */
1779 	    if ((op->phase == st_phase_requested)
1780 	        && pcmk__str_eq(op->action, PCMK_ACTION_ON, pcmk__str_none)) {
1781 	        /* If the device we just executed was required, it's not anymore */
1782 	        remove_required_device(op, device);
1783 	
1784 	        /* If there are no more devices at this topology level, run through any
1785 	         * remaining devices with automatic unfencing
1786 	         */
1787 	        if (op->devices == NULL) {
1788 	            op->devices = op->automatic_list;
1789 	        }
1790 	    }
1791 	
1792 	    if ((op->devices == NULL) && (op->phase == st_phase_off)) {
1793 	        /* We're done with this level and with required devices, but we had
1794 	         * remapped "reboot" to "off", so start over with "on". If any devices
1795 	         * need to be turned back on, op->devices will be non-NULL after this.
1796 	         */
1797 	        op_phase_on(op);
1798 	    }
1799 	
1800 	    // This function is only called if the previous device succeeded
1801 	    pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
1802 	
1803 	    if (op->devices) {
1804 	        /* Necessary devices remain, so execute the next one */
1805 	        crm_trace("Next targeting %s on behalf of %s@%s",
1806 	                  op->target, op->client_name, op->originator);
1807 	
1808 	        // The requested delay has been applied for the first device
1809 	        if (op->client_delay > 0) {
1810 	            op->client_delay = 0;
1811 	        }
1812 	
1813 	        request_peer_fencing(op, NULL);
1814 	    } else {
1815 	        /* We're done with all devices and phases, so finalize operation */
1816 	        crm_trace("Marking complex fencing op targeting %s as complete",
1817 	                  op->target);
1818 	        op->state = st_done;
1819 	        finalize_op(op, msg, false);
1820 	    }
1821 	}
1822 	
1823 	static gboolean
1824 	check_watchdog_fencing_and_wait(remote_fencing_op_t * op)
1825 	{
1826 	    if (node_does_watchdog_fencing(op->target)) {
1827 	        guint timeout_ms = QB_MIN(stonith_watchdog_timeout_ms, UINT_MAX);
1828 	
1829 	        crm_notice("Waiting %s for %s to self-fence (%s) for "
1830 	                   "client %s " QB_XS " id=%.8s",
1831 	                   pcmk__readable_interval(timeout_ms), op->target, op->action,
1832 	                   op->client_name, op->id);
1833 	
1834 	        if (op->op_timer_one) {
1835 	            g_source_remove(op->op_timer_one);
1836 	        }
1837 	        op->op_timer_one = pcmk__create_timer(timeout_ms, remote_op_watchdog_done,
1838 	                                              op);
1839 	        return TRUE;
1840 	    } else {
1841 	        crm_debug("Skipping fallback to watchdog-fencing as %s is "
1842 	                 "not in host-list", op->target);
1843 	    }
1844 	    return FALSE;
1845 	}
1846 	
1847 	/*!
1848 	 * \internal
1849 	 * \brief Ask a peer to execute a fencing operation
1850 	 *
1851 	 * \param[in,out] op      Fencing operation to be executed
1852 	 * \param[in,out] peer    If NULL or topology is in use, choose best peer to
1853 	 *                        execute the fencing, otherwise use this peer
1854 	 */
1855 	static void
1856 	request_peer_fencing(remote_fencing_op_t *op, peer_device_info_t *peer)
1857 	{
1858 	    const char *device = NULL;
1859 	    int timeout;
1860 	
1861 	    CRM_CHECK(op != NULL, return);
1862 	
1863 	    crm_trace("Action %.8s targeting %s for %s is %s",
1864 	              op->id, op->target, op->client_name,
1865 	              stonith_op_state_str(op->state));
1866 	
1867 	    if ((op->phase == st_phase_on) && (op->devices != NULL)) {
1868 	        /* We are in the "on" phase of a remapped topology reboot. If this
1869 	         * device has pcmk_reboot_action="off", or doesn't support the "on"
1870 	         * action, skip it.
1871 	         *
1872 	         * We can't check device properties at this point because we haven't
1873 	         * chosen a peer for this stage yet. Instead, we check the local node's
1874 	         * knowledge about the device. If different versions of the fence agent
1875 	         * are installed on different nodes, there's a chance this could be
1876 	         * mistaken, but the worst that could happen is we don't try turning the
1877 	         * node back on when we should.
1878 	         */
1879 	        device = op->devices->data;
1880 	        if (pcmk__str_eq(fenced_device_reboot_action(device), PCMK_ACTION_OFF,
1881 	                         pcmk__str_none)) {
1882 	            crm_info("Not turning %s back on using %s because the device is "
1883 	                     "configured to stay off (pcmk_reboot_action='off')",
1884 	                     op->target, device);
1885 	            advance_topology_device_in_level(op, device, NULL);
1886 	            return;
1887 	        }
1888 	        if (!fenced_device_supports_on(device)) {
1889 	            crm_info("Not turning %s back on using %s because the agent "
1890 	                     "doesn't support 'on'", op->target, device);
1891 	            advance_topology_device_in_level(op, device, NULL);
1892 	            return;
1893 	        }
1894 	    }
1895 	
1896 	    timeout = op->base_timeout;
1897 	    if ((peer == NULL) && !pcmk_is_set(op->call_options, st_opt_topology)) {
1898 	        peer = stonith_choose_peer(op);
1899 	    }
1900 	
1901 	    if (!op->op_timer_total) {
1902 	        op->total_timeout = TIMEOUT_MULTIPLY_FACTOR * get_op_total_timeout(op, peer);
1903 	        op->op_timer_total = pcmk__create_timer(1000 * op->total_timeout, remote_op_timeout, op);
1904 	        report_timeout_period(op, op->total_timeout);
1905 	        crm_info("Total timeout set to %ds for peer's fencing targeting %s for %s "
1906 	                 QB_XS " id=%.8s",
1907 	                 op->total_timeout, op->target, op->client_name, op->id);
1908 	    }
1909 	
1910 	    if (pcmk_is_set(op->call_options, st_opt_topology) && op->devices) {
1911 	        /* Ignore the caller's peer preference if topology is in use, because
1912 	         * that peer might not have access to the required device. With
1913 	         * topology, stonith_choose_peer() removes the device from further
1914 	         * consideration, so the timeout must be calculated beforehand.
1915 	         *
1916 	         * @TODO Basing the total timeout on the caller's preferred peer (above)
1917 	         *       is less than ideal.
1918 	         */
1919 	        peer = stonith_choose_peer(op);
1920 	
1921 	        device = op->devices->data;
1922 	        /* Fencing timeout sent to peer takes no delay into account.
1923 	         * The peer will add a dedicated timer for any delay upon
1924 	         * schedule_stonith_command().
1925 	         */
1926 	        timeout = get_device_timeout(op, peer, device, false);
1927 	    }
1928 	
1929 	    if (peer) {
1930 	        int timeout_one = 0;
1931 	        xmlNode *remote_op = stonith_create_op(op->client_callid, op->id, STONITH_OP_FENCE, NULL, 0);
1932 	        const pcmk__node_status_t *peer_node =
1933 	            pcmk__get_node(0, peer->host, NULL,
1934 	                           pcmk__node_search_cluster_member);
1935 	
1936 	        if (op->client_delay > 0) {
1937 	           /* Take requested fencing delay into account to prevent it from
1938 	            * eating up the timeout.
1939 	            */
1940 	            timeout_one = TIMEOUT_MULTIPLY_FACTOR * op->client_delay;
1941 	        }
1942 	
1943 	        crm_xml_add(remote_op, PCMK__XA_ST_REMOTE_OP, op->id);
1944 	        crm_xml_add(remote_op, PCMK__XA_ST_TARGET, op->target);
1945 	        crm_xml_add(remote_op, PCMK__XA_ST_DEVICE_ACTION, op->action);
1946 	        crm_xml_add(remote_op, PCMK__XA_ST_ORIGIN, op->originator);
1947 	        crm_xml_add(remote_op, PCMK__XA_ST_CLIENTID, op->client_id);
1948 	        crm_xml_add(remote_op, PCMK__XA_ST_CLIENTNAME, op->client_name);
1949 	        crm_xml_add_int(remote_op, PCMK__XA_ST_TIMEOUT, timeout);
1950 	        crm_xml_add_int(remote_op, PCMK__XA_ST_CALLOPT, op->call_options);
1951 	        crm_xml_add_int(remote_op, PCMK__XA_ST_DELAY, op->client_delay);
1952 	
1953 	        if (device) {
1954 	            timeout_one += TIMEOUT_MULTIPLY_FACTOR *
1955 	                           get_device_timeout(op, peer, device, true);
1956 	            crm_notice("Requesting that %s perform '%s' action targeting %s "
1957 	                       "using %s " QB_XS " for client %s (%ds)",
1958 	                       peer->host, op->action, op->target, device,
1959 	                       op->client_name, timeout_one);
1960 	            crm_xml_add(remote_op, PCMK__XA_ST_DEVICE_ID, device);
1961 	
1962 	        } else {
1963 	            timeout_one += TIMEOUT_MULTIPLY_FACTOR * get_peer_timeout(op, peer);
1964 	            crm_notice("Requesting that %s perform '%s' action targeting %s "
1965 	                       QB_XS " for client %s (%ds, %s)",
1966 	                       peer->host, op->action, op->target, op->client_name,
1967 	                       timeout_one,
1968 	                       pcmk__readable_interval(stonith_watchdog_timeout_ms));
1969 	        }
1970 	
1971 	        op->state = st_exec;
1972 	        if (op->op_timer_one) {
1973 	            g_source_remove(op->op_timer_one);
1974 	            op->op_timer_one = 0;
1975 	        }
1976 	
1977 	        if (!is_watchdog_fencing(op, device)
1978 	            || !check_watchdog_fencing_and_wait(op)) {
1979 	
1980 	            /* Some thoughts about self-fencing cases reaching this point:
1981 	               - Actually check in check_watchdog_fencing_and_wait
1982 	                 shouldn't fail if STONITH_WATCHDOG_ID is
1983 	                 chosen as fencing-device and it being present implies
1984 	                 watchdog-fencing is enabled anyway
1985 	               - If watchdog-fencing is disabled either in general or for
1986 	                 a specific target - detected in check_watchdog_fencing_and_wait -
1987 	                 for some other kind of self-fencing we can't expect
1988 	                 a success answer but timeout is fine if the node doesn't
1989 	                 come back in between
1990 	               - Delicate might be the case where we have watchdog-fencing
1991 	                 enabled for a node but the watchdog-fencing-device isn't
1992 	                 explicitly chosen for self-fencing. Local scheduler execution
1993 	                 in sbd might detect the node as unclean and lead to timely
1994 	                 self-fencing. Otherwise the selection of
1995 	                 PCMK_OPT_STONITH_WATCHDOG_TIMEOUT at least is questionable.
1996 	             */
1997 	
1998 	            /* coming here we're not waiting for watchdog timeout -
1999 	               thus engage timer with timout evaluated before */
2000 	            op->op_timer_one = pcmk__create_timer((1000 * timeout_one), remote_op_timeout_one, op);
2001 	        }
2002 	
2003 	        pcmk__cluster_send_message(peer_node, pcmk_ipc_fenced, remote_op);
2004 	        peer->tried = TRUE;
2005 	        pcmk__xml_free(remote_op);
2006 	        return;
2007 	
2008 	    } else if (op->phase == st_phase_on) {
2009 	        /* A remapped "on" cannot be executed, but the node was already
2010 	         * turned off successfully, so ignore the error and continue.
2011 	         */
2012 	        crm_warn("Ignoring %s 'on' failure (no capable peers) targeting %s "
2013 	                 "after successful 'off'", device, op->target);
2014 	        advance_topology_device_in_level(op, device, NULL);
2015 	        return;
2016 	
2017 	    } else if (op->owner == FALSE) {
2018 	        crm_err("Fencing (%s) targeting %s for client %s is not ours to control",
2019 	                op->action, op->target, op->client_name);
2020 	
2021 	    } else if (op->query_timer == 0) {
2022 	        /* We've exhausted all available peers */
2023 	        crm_info("No remaining peers capable of fencing (%s) %s for client %s "
2024 	                 QB_XS " state=%s", op->action, op->target, op->client_name,
2025 	                 stonith_op_state_str(op->state));
2026 	        CRM_CHECK(op->state < st_done, return);
2027 	        finalize_timed_out_op(op, "All nodes failed, or are unable, to "
2028 	                                  "fence target");
2029 	
2030 	    } else if(op->replies >= op->replies_expected || op->replies >= fencing_active_peers()) {
2031 	        /* if the operation never left the query state,
2032 	         * but we have all the expected replies, then no devices
2033 	         * are available to execute the fencing operation. */
2034 	
2035 	        if (is_watchdog_fencing(op, device)
2036 	            && check_watchdog_fencing_and_wait(op)) {
2037 	            /* Consider a watchdog fencing targeting an offline node executing
2038 	             * once it starts waiting for the target to self-fence. So that when
2039 	             * the query timer pops, remote_op_query_timeout() considers the
2040 	             * fencing already in progress.
2041 	             */
2042 	            op->state = st_exec;
2043 	            return;
2044 	        }
2045 	
2046 	        if (op->state == st_query) {
2047 	            crm_info("No peers (out of %d) have devices capable of fencing "
2048 	                     "(%s) %s for client %s " QB_XS " state=%s",
2049 	                     op->replies, op->action, op->target, op->client_name,
2050 	                     stonith_op_state_str(op->state));
2051 	
2052 	            pcmk__reset_result(&op->result);
2053 	            pcmk__set_result(&op->result, CRM_EX_ERROR,
2054 	                             PCMK_EXEC_NO_FENCE_DEVICE, NULL);
2055 	        } else {
2056 	            if (pcmk_is_set(op->call_options, st_opt_topology)) {
2057 	                pcmk__reset_result(&op->result);
2058 	                pcmk__set_result(&op->result, CRM_EX_ERROR,
2059 	                                 PCMK_EXEC_NO_FENCE_DEVICE, NULL);
2060 	            }
2061 	            /* ... else use existing result from previous failed attempt
2062 	             * (topology is not in use, and no devices remain to be attempted).
2063 	             * Overwriting the result with PCMK_EXEC_NO_FENCE_DEVICE would
2064 	             * prevent finalize_op() from setting the correct delegate if
2065 	             * needed.
2066 	             */
2067 	
2068 	            crm_info("No peers (out of %d) are capable of fencing (%s) %s "
2069 	                     "for client %s " QB_XS " state=%s",
2070 	                     op->replies, op->action, op->target, op->client_name,
2071 	                     stonith_op_state_str(op->state));
2072 	        }
2073 	
2074 	        op->state = st_failed;
2075 	        finalize_op(op, NULL, false);
2076 	
2077 	    } else {
2078 	        crm_info("Waiting for additional peers capable of fencing (%s) %s%s%s "
2079 	                 "for client %s " QB_XS " id=%.8s",
2080 	                 op->action, op->target, (device? " using " : ""),
2081 	                 (device? device : ""), op->client_name, op->id);
2082 	    }
2083 	}
2084 	
2085 	/*!
2086 	 * \internal
2087 	 * \brief Comparison function for sorting query results
2088 	 *
2089 	 * \param[in] a  GList item to compare
2090 	 * \param[in] b  GList item to compare
2091 	 *
2092 	 * \return Per the glib documentation, "a negative integer if the first value
2093 	 *         comes before the second, 0 if they are equal, or a positive integer
2094 	 *         if the first value comes after the second."
2095 	 */
2096 	static gint
2097 	sort_peers(gconstpointer a, gconstpointer b)
2098 	{
2099 	    const peer_device_info_t *peer_a = a;
2100 	    const peer_device_info_t *peer_b = b;
2101 	
2102 	    return (peer_b->ndevices - peer_a->ndevices);
2103 	}
2104 	
2105 	/*!
2106 	 * \internal
2107 	 * \brief Determine if all the devices in the topology are found or not
2108 	 *
2109 	 * \param[in] op  Fencing operation with topology to check
2110 	 */
2111 	static gboolean
2112 	all_topology_devices_found(const remote_fencing_op_t *op)
2113 	{
2114 	    GList *device = NULL;
2115 	    GList *iter = NULL;
2116 	    device_properties_t *match = NULL;
2117 	    stonith_topology_t *tp = NULL;
2118 	    gboolean skip_target = FALSE;
2119 	    int i;
2120 	
2121 	    tp = find_topology_for_host(op->target);
2122 	    if (!tp) {
2123 	        return FALSE;
2124 	    }
2125 	    if (pcmk__is_fencing_action(op->action)) {
2126 	        /* Don't count the devices on the target node if we are killing
2127 	         * the target node. */
2128 	        skip_target = TRUE;
2129 	    }
2130 	
2131 	    for (i = 0; i < ST__LEVEL_COUNT; i++) {
2132 	        for (device = tp->levels[i]; device; device = device->next) {
2133 	            match = NULL;
2134 	            for (iter = op->query_results; iter && !match; iter = iter->next) {
2135 	                peer_device_info_t *peer = iter->data;
2136 	
2137 	                if (skip_target && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) {
2138 	                    continue;
2139 	                }
2140 	                match = find_peer_device(op, peer, device->data, st_device_supports_none);
2141 	            }
2142 	            if (!match) {
2143 	                return FALSE;
2144 	            }
2145 	        }
2146 	    }
2147 	
2148 	    return TRUE;
2149 	}
2150 	
2151 	/*!
2152 	 * \internal
2153 	 * \brief Parse action-specific device properties from XML
2154 	 *
2155 	 * \param[in]     xml     XML element containing the properties
2156 	 * \param[in]     peer    Name of peer that sent XML (for logs)
2157 	 * \param[in]     device  Device ID (for logs)
2158 	 * \param[in]     action  Action the properties relate to (for logs)
2159 	 * \param[in,out] op      Fencing operation that properties are being parsed for
2160 	 * \param[in]     phase   Phase the properties relate to
2161 	 * \param[in,out] props   Device properties to update
2162 	 */
2163 	static void
2164 	parse_action_specific(const xmlNode *xml, const char *peer, const char *device,
2165 	                      const char *action, remote_fencing_op_t *op,
2166 	                      enum st_remap_phase phase, device_properties_t *props)
2167 	{
2168 	    props->custom_action_timeout[phase] = 0;
2169 	    crm_element_value_int(xml, PCMK__XA_ST_ACTION_TIMEOUT,
2170 	                          &props->custom_action_timeout[phase]);
2171 	    if (props->custom_action_timeout[phase]) {
2172 	        crm_trace("Peer %s with device %s returned %s action timeout %ds",
2173 	                  peer, device, action, props->custom_action_timeout[phase]);
2174 	    }
2175 	
2176 	    props->delay_max[phase] = 0;
2177 	    crm_element_value_int(xml, PCMK__XA_ST_DELAY_MAX, &props->delay_max[phase]);
2178 	    if (props->delay_max[phase]) {
2179 	        crm_trace("Peer %s with device %s returned maximum of random delay %ds for %s",
2180 	                  peer, device, props->delay_max[phase], action);
2181 	    }
2182 	
2183 	    props->delay_base[phase] = 0;
2184 	    crm_element_value_int(xml, PCMK__XA_ST_DELAY_BASE,
2185 	                          &props->delay_base[phase]);
2186 	    if (props->delay_base[phase]) {
2187 	        crm_trace("Peer %s with device %s returned base delay %ds for %s",
2188 	                  peer, device, props->delay_base[phase], action);
2189 	    }
2190 	
2191 	    /* Handle devices with automatic unfencing */
2192 	    if (pcmk__str_eq(action, PCMK_ACTION_ON, pcmk__str_none)) {
2193 	        int required = 0;
2194 	
2195 	        crm_element_value_int(xml, PCMK__XA_ST_REQUIRED, &required);
2196 	        if (required) {
2197 	            crm_trace("Peer %s requires device %s to execute for action %s",
2198 	                      peer, device, action);
2199 	            add_required_device(op, device);
2200 	        }
2201 	    }
2202 	
2203 	    /* If a reboot is remapped to off+on, it's possible that a node is allowed
2204 	     * to perform one action but not another.
2205 	     */
2206 	    if (pcmk__xe_attr_is_true(xml, PCMK__XA_ST_ACTION_DISALLOWED)) {
2207 	        props->disallowed[phase] = TRUE;
2208 	        crm_trace("Peer %s is disallowed from executing %s for device %s",
2209 	                  peer, action, device);
2210 	    }
2211 	}
2212 	
2213 	/*!
2214 	 * \internal
2215 	 * \brief Parse one device's properties from peer's XML query reply
2216 	 *
2217 	 * \param[in]     xml       XML node containing device properties
2218 	 * \param[in,out] op        Operation that query and reply relate to
2219 	 * \param[in,out] peer      Peer's device information
2220 	 * \param[in]     device    ID of device being parsed
2221 	 */
2222 	static void
2223 	add_device_properties(const xmlNode *xml, remote_fencing_op_t *op,
2224 	                      peer_device_info_t *peer, const char *device)
2225 	{
2226 	    xmlNode *child;
2227 	    int verified = 0;
2228 	    device_properties_t *props =
2229 	        pcmk__assert_alloc(1, sizeof(device_properties_t));
2230 	    int rc = pcmk_rc_ok;
2231 	
2232 	    /* Add a new entry to this peer's devices list */
2233 	    g_hash_table_insert(peer->devices, pcmk__str_copy(device), props);
2234 	
2235 	    /* Peers with verified (monitored) access will be preferred */
2236 	    crm_element_value_int(xml, PCMK__XA_ST_MONITOR_VERIFIED, &verified);
2237 	    if (verified) {
2238 	        crm_trace("Peer %s has confirmed a verified device %s",
2239 	                  peer->host, device);
2240 	        props->verified = TRUE;
2241 	    }
2242 	
2243 	    // Nodes <2.1.5 won't set this, so assume unfencing in that case
2244 	    rc = pcmk__xe_get_flags(xml, PCMK__XA_ST_DEVICE_SUPPORT_FLAGS,
2245 	                            &(props->device_support_flags),
2246 	                            st_device_supports_on);
2247 	    if (rc != pcmk_rc_ok) {
2248 	        crm_warn("Couldn't determine device support for %s "
2249 	                 "(assuming unfencing): %s", device, pcmk_rc_str(rc));
2250 	    }
2251 	
2252 	    /* Parse action-specific device properties */
2253 	    parse_action_specific(xml, peer->host, device, op_requested_action(op),
2254 	                          op, st_phase_requested, props);
2255 	    for (child = pcmk__xe_first_child(xml, NULL, NULL, NULL); child != NULL;
2256 	         child = pcmk__xe_next(child, NULL)) {
2257 	        /* Replies for "reboot" operations will include the action-specific
2258 	         * values for "off" and "on" in child elements, just in case the reboot
2259 	         * winds up getting remapped.
2260 	         */
2261 	        if (pcmk__str_eq(pcmk__xe_id(child), PCMK_ACTION_OFF, pcmk__str_none)) {
2262 	            parse_action_specific(child, peer->host, device, PCMK_ACTION_OFF,
2263 	                                  op, st_phase_off, props);
2264 	
2265 	        } else if (pcmk__str_eq(pcmk__xe_id(child), PCMK_ACTION_ON,
2266 	                                pcmk__str_none)) {
2267 	            parse_action_specific(child, peer->host, device, PCMK_ACTION_ON,
2268 	                                  op, st_phase_on, props);
2269 	        }
2270 	    }
2271 	}
2272 	
2273 	/*!
2274 	 * \internal
2275 	 * \brief Parse a peer's XML query reply and add it to operation's results
2276 	 *
2277 	 * \param[in,out] op        Operation that query and reply relate to
2278 	 * \param[in]     host      Name of peer that sent this reply
2279 	 * \param[in]     ndevices  Number of devices expected in reply
2280 	 * \param[in]     xml       XML node containing device list
2281 	 *
2282 	 * \return Newly allocated result structure with parsed reply
2283 	 */
2284 	static peer_device_info_t *
2285 	add_result(remote_fencing_op_t *op, const char *host, int ndevices,
2286 	           const xmlNode *xml)
2287 	{
2288 	    peer_device_info_t *peer = pcmk__assert_alloc(1,
2289 	                                                  sizeof(peer_device_info_t));
2290 	    xmlNode *child;
2291 	
2292 	    peer->host = pcmk__str_copy(host);
2293 	    peer->devices = pcmk__strkey_table(free, free);
2294 	
2295 	    /* Each child element describes one capable device available to the peer */
2296 	    for (child = pcmk__xe_first_child(xml, NULL, NULL, NULL); child != NULL;
2297 	         child = pcmk__xe_next(child, NULL)) {
2298 	        const char *device = pcmk__xe_id(child);
2299 	
2300 	        if (device) {
2301 	            add_device_properties(child, op, peer, device);
2302 	        }
2303 	    }
2304 	
2305 	    peer->ndevices = g_hash_table_size(peer->devices);
2306 	    CRM_CHECK(ndevices == peer->ndevices,
2307 	              crm_err("Query claimed to have %d device%s but %d found",
2308 	                      ndevices, pcmk__plural_s(ndevices), peer->ndevices));
2309 	
2310 	    op->query_results = g_list_insert_sorted(op->query_results, peer, sort_peers);
2311 	    return peer;
2312 	}
2313 	
2314 	/*!
2315 	 * \internal
2316 	 * \brief Handle a peer's reply to our fencing query
2317 	 *
2318 	 * Parse a query result from XML and store it in the remote operation
2319 	 * table, and when enough replies have been received, issue a fencing request.
2320 	 *
2321 	 * \param[in] msg  XML reply received
2322 	 *
2323 	 * \return pcmk_ok on success, -errno on error
2324 	 *
2325 	 * \note See initiate_remote_stonith_op() for how the XML query was initially
2326 	 *       formed, and stonith_query() for how the peer formed its XML reply.
2327 	 */
2328 	int
2329 	process_remote_stonith_query(xmlNode *msg)
2330 	{
2331 	    int ndevices = 0;
2332 	    gboolean host_is_target = FALSE;
2333 	    gboolean have_all_replies = FALSE;
2334 	    const char *id = NULL;
2335 	    const char *host = NULL;
2336 	    remote_fencing_op_t *op = NULL;
2337 	    peer_device_info_t *peer = NULL;
2338 	    uint32_t replies_expected;
2339 	    xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_REMOTE_OP, msg, LOG_ERR);
2340 	
2341 	    CRM_CHECK(dev != NULL, return -EPROTO);
2342 	
2343 	    id = crm_element_value(dev, PCMK__XA_ST_REMOTE_OP);
2344 	    CRM_CHECK(id != NULL, return -EPROTO);
2345 	
2346 	    dev = get_xpath_object("//@" PCMK__XA_ST_AVAILABLE_DEVICES, msg, LOG_ERR);
2347 	    CRM_CHECK(dev != NULL, return -EPROTO);
2348 	    crm_element_value_int(dev, PCMK__XA_ST_AVAILABLE_DEVICES, &ndevices);
2349 	
2350 	    op = g_hash_table_lookup(stonith_remote_op_list, id);
2351 	    if (op == NULL) {
2352 	        crm_debug("Received query reply for unknown or expired operation %s",
2353 	                  id);
2354 	        return -EOPNOTSUPP;
2355 	    }
2356 	
2357 	    replies_expected = fencing_active_peers();
2358 	    if (op->replies_expected < replies_expected) {
2359 	        replies_expected = op->replies_expected;
2360 	    }
2361 	    if ((++op->replies >= replies_expected) && (op->state == st_query)) {
2362 	        have_all_replies = TRUE;
2363 	    }
2364 	    host = crm_element_value(msg, PCMK__XA_SRC);
2365 	    host_is_target = pcmk__str_eq(host, op->target, pcmk__str_casei);
2366 	
2367 	    crm_info("Query result %d of %d from %s for %s/%s (%d device%s) %s",
2368 	             op->replies, replies_expected, host,
2369 	             op->target, op->action, ndevices, pcmk__plural_s(ndevices), id);
2370 	    if (ndevices > 0) {
2371 	        peer = add_result(op, host, ndevices, dev);
2372 	    }
2373 	
2374 	    pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
2375 	
2376 	    if (pcmk_is_set(op->call_options, st_opt_topology)) {
2377 	        /* If we start the fencing before all the topology results are in,
2378 	         * it is possible fencing levels will be skipped because of the missing
2379 	         * query results. */
2380 	        if (op->state == st_query && all_topology_devices_found(op)) {
2381 	            /* All the query results are in for the topology, start the fencing ops. */
2382 	            crm_trace("All topology devices found");
2383 	            request_peer_fencing(op, peer);
2384 	
2385 	        } else if (have_all_replies) {
2386 	            crm_info("All topology query replies have arrived, continuing (%d expected/%d received) ",
2387 	                     replies_expected, op->replies);
2388 	            request_peer_fencing(op, NULL);
2389 	        }
2390 	
2391 	    } else if (op->state == st_query) {
2392 	        int nverified = count_peer_devices(op, peer, TRUE,
2393 	                                           fenced_support_flag(op->action));
2394 	
2395 	        /* We have a result for a non-topology fencing op that looks promising,
2396 	         * go ahead and start fencing before query timeout */
2397 	        if ((peer != NULL) && !host_is_target && nverified) {
2398 	            /* we have a verified device living on a peer that is not the target */
2399 	            crm_trace("Found %d verified device%s",
2400 	                      nverified, pcmk__plural_s(nverified));
2401 	            request_peer_fencing(op, peer);
2402 	
2403 	        } else if (have_all_replies) {
2404 	            crm_info("All query replies have arrived, continuing (%d expected/%d received) ",
2405 	                     replies_expected, op->replies);
2406 	            request_peer_fencing(op, NULL);
2407 	
2408 	        } else {
2409 	            crm_trace("Waiting for more peer results before launching fencing operation");
2410 	        }
2411 	
2412 	    } else if ((peer != NULL) && (op->state == st_done)) {
2413 	        crm_info("Discarding query result from %s (%d device%s): "
2414 	                 "Operation is %s", peer->host,
2415 	                 peer->ndevices, pcmk__plural_s(peer->ndevices),
2416 	                 stonith_op_state_str(op->state));
2417 	    }
2418 	
2419 	    return pcmk_ok;
2420 	}
2421 	
2422 	/*!
2423 	 * \internal
2424 	 * \brief Handle a peer's reply to a fencing request
2425 	 *
2426 	 * Parse a fencing reply from XML, and either finalize the operation
2427 	 * or attempt another device as appropriate.
2428 	 *
2429 	 * \param[in] msg  XML reply received
2430 	 */
2431 	void
2432 	fenced_process_fencing_reply(xmlNode *msg)
2433 	{
2434 	    const char *id = NULL;
2435 	    const char *device = NULL;
2436 	    remote_fencing_op_t *op = NULL;
2437 	    xmlNode *dev = get_xpath_object("//@" PCMK__XA_ST_REMOTE_OP, msg, LOG_ERR);
2438 	    pcmk__action_result_t result = PCMK__UNKNOWN_RESULT;
2439 	
2440 	    CRM_CHECK(dev != NULL, return);
2441 	
2442 	    id = crm_element_value(dev, PCMK__XA_ST_REMOTE_OP);
2443 	    CRM_CHECK(id != NULL, return);
2444 	
2445 	    dev = stonith__find_xe_with_result(msg);
2446 	    CRM_CHECK(dev != NULL, return);
2447 	
2448 	    stonith__xe_get_result(dev, &result);
2449 	
2450 	    device = crm_element_value(dev, PCMK__XA_ST_DEVICE_ID);
2451 	
2452 	    if (stonith_remote_op_list) {
2453 	        op = g_hash_table_lookup(stonith_remote_op_list, id);
2454 	    }
2455 	
2456 	    if ((op == NULL) && pcmk__result_ok(&result)) {
2457 	        /* Record successful fencing operations */
2458 	        const char *client_id = crm_element_value(dev, PCMK__XA_ST_CLIENTID);
2459 	
2460 	        op = create_remote_stonith_op(client_id, dev, TRUE);
2461 	    }
2462 	
2463 	    if (op == NULL) {
2464 	        /* Could be for an event that began before we started */
2465 	        /* TODO: Record the op for later querying */
2466 	        crm_info("Received peer result of unknown or expired operation %s", id);
2467 	        pcmk__reset_result(&result);
2468 	        return;
2469 	    }
2470 	
2471 	    pcmk__reset_result(&op->result);
2472 	    op->result = result; // The operation takes ownership of the result
2473 	
2474 	    if (op->devices && device && !pcmk__str_eq(op->devices->data, device, pcmk__str_casei)) {
2475 	        crm_err("Received outdated reply for device %s (instead of %s) to "
2476 	                "fence (%s) %s. Operation already timed out at peer level.",
2477 	                device, (const char *) op->devices->data, op->action, op->target);
2478 	        return;
2479 	    }
2480 	
2481 	    if (pcmk__str_eq(crm_element_value(msg, PCMK__XA_SUBT),
2482 	                     PCMK__VALUE_BROADCAST, pcmk__str_none)) {
2483 	
2484 	        if (pcmk__result_ok(&op->result)) {
2485 	            op->state = st_done;
2486 	        } else {
2487 	            op->state = st_failed;
2488 	        }
2489 	        finalize_op(op, msg, false);
2490 	        return;
2491 	
2492 	    } else if (!pcmk__str_eq(op->originator, fenced_get_local_node(),
2493 	                             pcmk__str_casei)) {
2494 	        /* If this isn't a remote level broadcast, and we are not the
2495 	         * originator of the operation, we should not be receiving this msg. */
2496 	        crm_err("Received non-broadcast fencing result for operation %.8s "
2497 	                "we do not own (device %s targeting %s)",
2498 	                op->id, device, op->target);
2499 	        return;
2500 	    }
2501 	
2502 	    if (pcmk_is_set(op->call_options, st_opt_topology)) {
2503 	        const char *device = NULL;
2504 	        const char *reason = op->result.exit_reason;
2505 	
2506 	        /* We own the op, and it is complete. broadcast the result to all nodes
2507 	         * and notify our local clients. */
2508 	        if (op->state == st_done) {
2509 	            finalize_op(op, msg, false);
2510 	            return;
2511 	        }
2512 	
2513 	        device = crm_element_value(msg, PCMK__XA_ST_DEVICE_ID);
2514 	
2515 	        if ((op->phase == 2) && !pcmk__result_ok(&op->result)) {
2516 	            /* A remapped "on" failed, but the node was already turned off
2517 	             * successfully, so ignore the error and continue.
2518 	             */
2519 	            crm_warn("Ignoring %s 'on' failure (%s%s%s) targeting %s "
2520 	                     "after successful 'off'",
2521 	                     device, pcmk_exec_status_str(op->result.execution_status),
2522 	                     (reason == NULL)? "" : ": ",
2523 	                     (reason == NULL)? "" : reason,
2524 	                     op->target);
2525 	            pcmk__set_result(&op->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
2526 	        } else {
2527 	            crm_notice("Action '%s' targeting %s%s%s on behalf of %s@%s: "
2528 	                       "%s%s%s%s",
2529 	                       op->action, op->target,
2530 	                       ((device == NULL)? "" : " using "),
2531 	                       ((device == NULL)? "" : device),
2532 	                       op->client_name,
2533 	                       op->originator,
2534 	                       pcmk_exec_status_str(op->result.execution_status),
2535 	                       (reason == NULL)? "" : " (",
2536 	                       (reason == NULL)? "" : reason,
2537 	                       (reason == NULL)? "" : ")");
2538 	        }
2539 	
2540 	        if (pcmk__result_ok(&op->result)) {
2541 	            /* An operation completed successfully. Try another device if
2542 	             * necessary, otherwise mark the operation as done. */
2543 	            advance_topology_device_in_level(op, device, msg);
2544 	            return;
2545 	        } else {
2546 	            /* This device failed, time to try another topology level. If no other
2547 	             * levels are available, mark this operation as failed and report results. */
2548 	            if (advance_topology_level(op, false) != pcmk_rc_ok) {
2549 	                op->state = st_failed;
2550 	                finalize_op(op, msg, false);
2551 	                return;
2552 	            }
2553 	        }
2554 	
2555 	    } else if (pcmk__result_ok(&op->result) && (op->devices == NULL)) {
2556 	        op->state = st_done;
2557 	        finalize_op(op, msg, false);
2558 	        return;
2559 	
2560 	    } else if ((op->result.execution_status == PCMK_EXEC_TIMEOUT)
2561 	               && (op->devices == NULL)) {
2562 	        /* If the operation timed out don't bother retrying other peers. */
2563 	        op->state = st_failed;
2564 	        finalize_op(op, msg, false);
2565 	        return;
2566 	
2567 	    } else {
2568 	        /* fall-through and attempt other fencing action using another peer */
2569 	    }
2570 	
2571 	    /* Retry on failure */
2572 	    crm_trace("Next for %s on behalf of %s@%s (result was: %s)",
2573 	              op->target, op->originator, op->client_name,
2574 	              pcmk_exec_status_str(op->result.execution_status));
2575 	    request_peer_fencing(op, NULL);
2576 	}
2577 	
2578 	gboolean
2579 	stonith_check_fence_tolerance(int tolerance, const char *target, const char *action)
2580 	{
2581 	    GHashTableIter iter;
2582 	    time_t now = time(NULL);
2583 	    remote_fencing_op_t *rop = NULL;
2584 	
2585 	    if (tolerance <= 0 || !stonith_remote_op_list || target == NULL ||
2586 	        action == NULL) {
2587 	        return FALSE;
2588 	    }
2589 	
2590 	    g_hash_table_iter_init(&iter, stonith_remote_op_list);
2591 	    while (g_hash_table_iter_next(&iter, NULL, (void **)&rop)) {
2592 	        if (strcmp(rop->target, target) != 0) {
2593 	            continue;
2594 	        } else if (rop->state != st_done) {
2595 	            continue;
2596 	        /* We don't have to worry about remapped reboots here
2597 	         * because if state is done, any remapping has been undone
2598 	         */
2599 	        } else if (strcmp(rop->action, action) != 0) {
2600 	            continue;
2601 	        } else if ((rop->completed + tolerance) < now) {
2602 	            continue;
2603 	        }
2604 	
2605 	        crm_notice("Target %s was fenced (%s) less than %ds ago by %s on behalf of %s",
2606 	                   target, action, tolerance, rop->delegate, rop->originator);
2607 	        return TRUE;
2608 	    }
2609 	    return FALSE;
2610 	}
2611