diff --git a/lib/common/attrd_client.c b/lib/common/attrd_client.c
index 6439ee6920..ebb184697d 100644
--- a/lib/common/attrd_client.c
+++ b/lib/common/attrd_client.c
@@ -1,334 +1,329 @@
 /*
  * Copyright 2011-2021 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/attrd_internal.h>
 
 /*!
  * \internal
  * \brief Create a generic pacemaker-attrd operation
  *
  * \param[in] user_name  If not NULL, ACL user to set for operation
  *
  * \return XML of pacemaker-attrd operation
  */
 static xmlNode *
 create_attrd_op(const char *user_name)
 {
     xmlNode *attrd_op = create_xml_node(NULL, __func__);
 
     crm_xml_add(attrd_op, F_TYPE, T_ATTRD);
     crm_xml_add(attrd_op, F_ORIG, (crm_system_name? crm_system_name: "unknown"));
     crm_xml_add(attrd_op, PCMK__XA_ATTR_USER, user_name);
 
     return attrd_op;
 }
 
 /*!
  * \internal
  * \brief Send an operation to pacemaker-attrd via IPC
  *
  * \param[in] ipc       Connection to pacemaker-attrd (or create one if NULL)
  * \param[in] attrd_op  XML of pacemaker-attrd operation to send
  *
  * \return Standard Pacemaker return code
  */
 static int
 send_attrd_op(crm_ipc_t *ipc, xmlNode *attrd_op)
 {
     int rc = -ENOTCONN; // initially handled as legacy return code
     int max = 5;
 
     static gboolean connected = TRUE;
     static crm_ipc_t *local_ipc = NULL;
     static enum crm_ipc_flags flags = crm_ipc_flags_none;
 
     if (ipc == NULL && local_ipc == NULL) {
         local_ipc = crm_ipc_new(T_ATTRD, 0);
         pcmk__set_ipc_flags(flags, "client", crm_ipc_client_response);
         connected = FALSE;
     }
 
     if (ipc == NULL) {
         ipc = local_ipc;
     }
 
     while (max > 0) {
         if (connected == FALSE) {
             crm_info("Connecting to cluster... %d retries remaining", max);
             connected = crm_ipc_connect(ipc);
         }
 
         if (connected) {
             rc = crm_ipc_send(ipc, attrd_op, flags, 0, NULL);
         } else {
             crm_perror(LOG_INFO, "Connection to cluster attribute manager failed");
         }
 
         if (ipc != local_ipc) {
             break;
 
         } else if (rc > 0) {
             break;
 
         } else if (rc == -EAGAIN || rc == -EALREADY) {
             sleep(5 - max);
             max--;
 
         } else {
             crm_ipc_close(ipc);
             connected = FALSE;
             sleep(5 - max);
             max--;
         }
     }
 
     if (rc > 0) {
         rc = pcmk_ok;
     }
     return pcmk_legacy2rc(rc);
 }
 
 /*!
  * \internal
  * \brief Send a request to pacemaker-attrd
  *
  * \param[in] ipc      Connection to pacemaker-attrd (or NULL to use a local connection)
  * \param[in] command  A character indicating the type of pacemaker-attrd request:
  *                     U or v: update attribute (or refresh if name is NULL)
  *                     u: update attributes matching regular expression in name
  *                     D: delete attribute (value must be NULL)
  *                     R: refresh
  *                     B: update both attribute and its dampening
  *                     Y: update attribute dampening only
  *                     Q: query attribute
  *                     C: remove peer specified by host
  * \param[in] host     Affect only this host (or NULL for all hosts)
  * \param[in] name     Name of attribute to affect
  * \param[in] value    Attribute value to set
  * \param[in] section  Status or nodes
  * \param[in] set      ID of attribute set to use (or NULL to choose first)
  * \param[in] dampen   Attribute dampening to use with B/Y, and U/v if creating
  * \param[in] user_name ACL user to pass to pacemaker-attrd
  * \param[in] options  Bitmask of pcmk__node_attr_opts
  *
  * \return Standard Pacemaker return code
  */
 int
 pcmk__node_attr_request(crm_ipc_t *ipc, char command, const char *host,
                         const char *name, const char *value,
                         const char *section, const char *set,
                         const char *dampen, const char *user_name, int options)
 {
     int rc = pcmk_rc_ok;
     const char *task = NULL;
     const char *name_as = NULL;
     const char *display_host = (host ? host : "localhost");
     const char *display_command = NULL; /* for commands without name/value */
     xmlNode *update = create_attrd_op(user_name);
 
     /* remap common aliases */
     if (pcmk__str_eq(section, "reboot", pcmk__str_casei)) {
         section = XML_CIB_TAG_STATUS;
 
     } else if (pcmk__str_eq(section, "forever", pcmk__str_casei)) {
         section = XML_CIB_TAG_NODES;
     }
 
     if (name == NULL && command == 'U') {
         command = 'R';
     }
 
     switch (command) {
         case 'u':
             task = PCMK__ATTRD_CMD_UPDATE;
             name_as = PCMK__XA_ATTR_PATTERN;
             break;
         case 'D':
         case 'U':
         case 'v':
             task = PCMK__ATTRD_CMD_UPDATE;
             name_as = PCMK__XA_ATTR_NAME;
             break;
         case 'R':
             task = PCMK__ATTRD_CMD_REFRESH;
             display_command = "refresh";
             break;
         case 'B':
             task = PCMK__ATTRD_CMD_UPDATE_BOTH;
             name_as = PCMK__XA_ATTR_NAME;
             break;
         case 'Y':
             task = PCMK__ATTRD_CMD_UPDATE_DELAY;
             name_as = PCMK__XA_ATTR_NAME;
             break;
         case 'Q':
             task = PCMK__ATTRD_CMD_QUERY;
             name_as = PCMK__XA_ATTR_NAME;
             break;
         case 'C':
             task = PCMK__ATTRD_CMD_PEER_REMOVE;
             display_command = "purge";
             break;
     }
 
     if (name_as != NULL) {
         if (name == NULL) {
             rc = EINVAL;
             goto done;
         }
         crm_xml_add(update, name_as, name);
     }
 
     crm_xml_add(update, PCMK__XA_TASK, task);
     crm_xml_add(update, PCMK__XA_ATTR_VALUE, value);
     crm_xml_add(update, PCMK__XA_ATTR_DAMPENING, dampen);
     crm_xml_add(update, PCMK__XA_ATTR_SECTION, section);
     crm_xml_add(update, PCMK__XA_ATTR_NODE_NAME, host);
     crm_xml_add(update, PCMK__XA_ATTR_SET, set);
     crm_xml_add_int(update, PCMK__XA_ATTR_IS_REMOTE,
                     pcmk_is_set(options, pcmk__node_attr_remote));
     crm_xml_add_int(update, PCMK__XA_ATTR_IS_PRIVATE,
                     pcmk_is_set(options, pcmk__node_attr_private));
 
     rc = send_attrd_op(ipc, update);
 
 done:
     free_xml(update);
 
     if (display_command) {
         crm_debug("Asked pacemaker-attrd to %s %s: %s (%d)",
                   display_command, display_host, pcmk_rc_str(rc), rc);
     } else {
         crm_debug("Asked pacemaker-attrd to update %s=%s for %s: %s (%d)",
                   name, value, display_host, pcmk_rc_str(rc), rc);
     }
     return rc;
 }
 
 /*!
  * \internal
  * \brief Send a request to pacemaker-attrd to clear resource failure
  *
  * \param[in] ipc           Connection to pacemaker-attrd (NULL to use local connection)
  * \param[in] host          Affect only this host (or NULL for all hosts)
  * \param[in] resource      Name of resource to clear (or NULL for all)
  * \param[in] operation     Name of operation to clear (or NULL for all)
  * \param[in] interval_spec If operation is not NULL, its interval
  * \param[in] user_name     ACL user to pass to pacemaker-attrd
  * \param[in] options       Bitmask of pcmk__node_attr_opts
  *
  * \return pcmk_ok if request was successfully submitted to pacemaker-attrd, else -errno
  */
 int
 pcmk__node_attr_request_clear(crm_ipc_t *ipc, const char *host,
                               const char *resource, const char *operation,
                               const char *interval_spec, const char *user_name,
                               int options)
 {
     int rc = pcmk_rc_ok;
     xmlNode *clear_op = create_attrd_op(user_name);
     const char *interval_desc = NULL;
     const char *op_desc = NULL;
 
     crm_xml_add(clear_op, PCMK__XA_TASK, PCMK__ATTRD_CMD_CLEAR_FAILURE);
     crm_xml_add(clear_op, PCMK__XA_ATTR_NODE_NAME, host);
     crm_xml_add(clear_op, PCMK__XA_ATTR_RESOURCE, resource);
     crm_xml_add(clear_op, PCMK__XA_ATTR_OPERATION, operation);
     crm_xml_add(clear_op, PCMK__XA_ATTR_INTERVAL, interval_spec);
     crm_xml_add_int(clear_op, PCMK__XA_ATTR_IS_REMOTE,
                     pcmk_is_set(options, pcmk__node_attr_remote));
 
     rc = send_attrd_op(ipc, clear_op);
     free_xml(clear_op);
 
     if (operation) {
         interval_desc = interval_spec? interval_spec : "nonrecurring";
         op_desc = operation;
     } else {
         interval_desc = "all";
         op_desc = "operations";
     }
     crm_debug("Asked pacemaker-attrd to clear failure of %s %s for %s on %s: %s (%d)",
               interval_desc, op_desc, (resource? resource : "all resources"),
               (host? host : "all nodes"), pcmk_rc_str(rc), rc);
     return rc;
 }
 
 #define LRM_TARGET_ENV "OCF_RESKEY_" CRM_META "_" XML_LRM_ATTR_TARGET
 
 /*!
  * \internal
  */
 const char *
 pcmk__node_attr_target(const char *name)
 {
-    if (pcmk__strcase_any_of(name, "auto", "localhost", NULL)) {
-        name = NULL;
-    }
-
-    if(name != NULL) {
-        return name;
-
-    } else {
+    if (name == NULL || pcmk__strcase_any_of(name, "auto", "localhost", NULL)) {
         char *target_var = crm_meta_name(XML_RSC_ATTR_TARGET);
         char *phys_var = crm_meta_name(PCMK__ENV_PHYSICAL_HOST);
         const char *target = getenv(target_var);
         const char *host_physical = getenv(phys_var);
 
         // It is important to use the name by which the scheduler knows us
         if (host_physical && pcmk__str_eq(target, "host", pcmk__str_casei)) {
             name = host_physical;
 
         } else {
             const char *host_pcmk = getenv(LRM_TARGET_ENV);
 
             if (host_pcmk) {
                 name = host_pcmk;
             }
         }
         free(target_var);
         free(phys_var);
-    }
 
-    // TODO? Call get_local_node_name() if name == NULL
-    // (currently would require linkage against libcrmcluster)
-    return name;
+        // TODO? Call get_local_node_name() if name == NULL
+        // (currently would require linkage against libcrmcluster)
+        return name;
+    } else {
+        return NULL;
+    }
 }
 
 /*!
  * \brief Return the name of the node attribute used as a promotion score
  *
  * \param[in] rsc_id  Resource ID that promotion score is for (or NULL to
  *                    check the OCF_RESOURCE_INSTANCE environment variable)
  *
  * \return Newly allocated string with the node attribute name (or NULL on
  *         error, including no ID or environment variable specified)
  * \note It is the caller's responsibility to free() the result.
  */
 char *
 pcmk_promotion_score_name(const char *rsc_id)
 {
     if (rsc_id == NULL) {
         rsc_id = getenv("OCF_RESOURCE_INSTANCE");
         if (rsc_id == NULL) {
             return NULL;
         }
     }
     return crm_strdup_printf("master-%s", rsc_id);
 }
diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c
index a461ba9550..2a6c471aee 100644
--- a/tools/attrd_updater.c
+++ b/tools/attrd_updater.c
@@ -1,471 +1,476 @@
 /*
  * Copyright 2004-2020 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <libgen.h>
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml_internal.h>
 #include <crm/common/ipc.h>
 
 #include <crm/common/attrd_internal.h>
 
 static pcmk__cli_option_t long_options[] = {
     // long option, argument type, storage, short option, description, flags
     {
         "help", no_argument, NULL, '?',
         "\tThis text", pcmk__option_default
     },
     {
         "version", no_argument, NULL, '$',
         "\tVersion information", pcmk__option_default
     },
     {
         "verbose", no_argument, NULL, 'V',
         "\tIncrease debug output\n", pcmk__option_default
     },
     {
         "name", required_argument, NULL, 'n',
         "The attribute's name", pcmk__option_default
     },
     {
         "-spacer-", no_argument, NULL, '-',
         "\nCommands:", pcmk__option_default
     },
     {
         "update", required_argument, NULL, 'U',
         "Update attribute's value in pacemaker-attrd. If this causes the value "
             "to change, it will also be updated in the cluster configuration.",
         pcmk__option_default
     },
     {
         "update-both", required_argument, NULL, 'B',
         "Update attribute's value and time to wait (dampening) in "
             "pacemaker-attrd. If this causes the value or dampening to change, "
             "the attribute will also be written to the cluster configuration, "
             "so be aware that repeatedly changing the dampening reduces its "
             "effectiveness.",
         pcmk__option_default
     },
     {
         "update-delay", no_argument, NULL, 'Y',
         "Update attribute's dampening in pacemaker-attrd (requires "
             "-d/--delay). If this causes the dampening to change, the "
             "attribute will also be written to the cluster configuration, so "
             "be aware that repeatedly changing the dampening reduces its "
             "effectiveness.",
         pcmk__option_default
     },
     {
         "query", no_argument, NULL, 'Q',
         "\tQuery the attribute's value from pacemaker-attrd",
         pcmk__option_default
     },
     {
         "delete", no_argument, NULL, 'D',
         "\tDelete attribute from pacemaker-attrd. If a value was previously "
             "set, it will also be removed from the cluster configuration",
         pcmk__option_default
     },
     {
         "refresh", no_argument, NULL, 'R',
         "\t(Advanced) Force the pacemaker-attrd daemon to resend all current "
             "values to the CIB",
         pcmk__option_default
     },
 
     {
         "-spacer-", no_argument, NULL, '-',
         "\nAdditional options:", pcmk__option_default
     },
     {
         "delay", required_argument, NULL, 'd',
         "The time to wait (dampening) in seconds for further changes "
             "before writing",
         pcmk__option_default
     },
     {
         "set", required_argument, NULL, 's',
         "(Advanced) The attribute set in which to place the value",
         pcmk__option_default
     },
     {
         "node", required_argument, NULL, 'N',
         "Set the attribute for the named node (instead of the local one)",
         pcmk__option_default
     },
     {
         "all", no_argument, NULL, 'A',
         "Show values of the attribute for all nodes (query only)",
         pcmk__option_default
     },
 
     // @TODO Implement --lifetime
     {
         "lifetime", required_argument, NULL, 'l',
         "(Not yet implemented) Lifetime of the node attribute (silently "
             "ignored by cluster)",
         pcmk__option_default
     },
     {
         "private", no_argument, NULL, 'p',
         "\tIf this creates a new attribute, never write the attribute to CIB",
         pcmk__option_default
     },
 
     /* Legacy options */
     {
         "quiet", no_argument, NULL, 'q',
         NULL, pcmk__option_hidden
     },
     {
         "update", required_argument, NULL, 'v',
         NULL, pcmk__option_hidden
     },
     {
         "section", required_argument, NULL, 'S',
         NULL, pcmk__option_hidden
     },
     { 0, 0, 0, 0 }
 };
 
 static int do_query(const char *attr_name, const char *attr_node, gboolean query_all);
 static int do_update(char command, const char *attr_node, const char *attr_name,
                      const char *attr_value, const char *attr_section,
                      const char *attr_set, const char *attr_dampen, int attr_options);
 
 // Free memory at exit to make analyzers happy
 #define cleanup_memory() \
     free(attr_dampen); \
     free(attr_name); \
     free(attr_node); \
     free(attr_section); \
     free(attr_set);
 
 #define set_option(option_var) \
     if (option_var) { \
         free(option_var); \
     } \
     option_var = strdup(optarg);
 
 int
 main(int argc, char **argv)
 {
     int index = 0;
     int argerr = 0;
     int attr_options = pcmk__node_attr_none;
     int flag;
     crm_exit_t exit_code = CRM_EX_OK;
     char *attr_node = NULL;
     char *attr_name = NULL;
     char *attr_set = NULL;
     char *attr_section = NULL;
     char *attr_dampen = NULL;
     const char *attr_value = NULL;
     char command = 'Q';
 
     gboolean query_all = FALSE;
 
     pcmk__cli_init_logging("attrd_updater", 0);
     pcmk__set_cli_options(NULL, "-n <attribute> <command> [options]",
                           long_options,
                           "query and update Pacemaker node attributes");
 
     if (argc < 2) {
         pcmk__cli_help('?', CRM_EX_USAGE);
     }
 
     while (1) {
         flag = pcmk__next_cli_option(argc, argv, &index, NULL);
         if (flag == -1)
             break;
 
         switch (flag) {
             case 'V':
                 crm_bump_log_level(argc, argv);
                 break;
             case '?':
             case '$':
                 cleanup_memory();
                 pcmk__cli_help(flag, CRM_EX_OK);
                 break;
             case 'n':
                 set_option(attr_name);
                 break;
             case 's':
                 set_option(attr_set);
                 break;
             case 'd':
                 set_option(attr_dampen);
                 break;
             case 'l':
             case 'S':
                 set_option(attr_section);
                 break;
             case 'N':
                 set_option(attr_node);
                 break;
             case 'A':
                 query_all = TRUE;
                 break;
             case 'p':
                 pcmk__set_node_attr_flags(attr_options, pcmk__node_attr_private);
                 break;
             case 'q':
                 break;
             case 'Y':
                 command = flag;
                 crm_log_args(argc, argv); /* Too much? */
                 break;
             case 'Q':
             case 'B':
             case 'R':
             case 'D':
             case 'U':
             case 'v':
                 command = flag;
                 attr_value = optarg;
                 crm_log_args(argc, argv); /* Too much? */
                 break;
             default:
                 ++argerr;
                 break;
         }
     }
 
     if (optind > argc) {
         ++argerr;
     }
 
     if (command != 'R' && attr_name == NULL) {
         ++argerr;
     }
 
     if (argerr) {
         cleanup_memory();
         pcmk__cli_help('?', CRM_EX_USAGE);
     }
 
     if (command == 'Q') {
         exit_code = crm_errno2exit(do_query(attr_name, attr_node, query_all));
     } else {
         /* @TODO We don't know whether the specified node is a Pacemaker Remote
          * node or not, so we can't set pcmk__node_attr_remote when appropriate.
          * However, it's not a big problem, because pacemaker-attrd will learn
          * and remember a node's "remoteness".
          */
+        const char *target = pcmk__node_attr_target(attr_node);
+
         exit_code = pcmk_rc2exitc(do_update(command,
-                                            pcmk__node_attr_target(attr_node),
+                                            target == NULL ? attr_node : target,
                                             attr_name, attr_value,
                                             attr_section, attr_set,
                                             attr_dampen, attr_options));
     }
 
     cleanup_memory();
     crm_exit(exit_code);
 }
 
 /*!
  * \internal
  * \brief Submit a query request to pacemaker-attrd and wait for reply
  *
  * \param[in] name    Name of attribute to query
  * \param[in] host    Query applies to this host only (or all hosts if NULL)
  * \param[out] reply  On success, will be set to new XML tree with reply
  *
  * \return pcmk_ok on success, -errno on error
  * \note On success, caller is responsible for freeing result via free_xml(*reply)
  */
 static int
 send_attrd_query(const char *name, const char *host, xmlNode **reply)
 {
     int rc;
     crm_ipc_t *ipc;
     xmlNode *query;
 
     /* Build the query XML */
     query = create_xml_node(NULL, __func__);
     if (query == NULL) {
         return -ENOMEM;
     }
     crm_xml_add(query, F_TYPE, T_ATTRD);
     crm_xml_add(query, F_ORIG, crm_system_name);
     crm_xml_add(query, PCMK__XA_ATTR_NODE_NAME, host);
     crm_xml_add(query, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY);
     crm_xml_add(query, PCMK__XA_ATTR_NAME, name);
 
     /* Connect to pacemaker-attrd, send query XML and get reply */
     crm_debug("Sending query for value of %s on %s", name, (host? host : "all nodes"));
     ipc = crm_ipc_new(T_ATTRD, 0);
     if (crm_ipc_connect(ipc) == FALSE) {
         crm_perror(LOG_ERR, "Connection to cluster attribute manager failed");
         rc = -ENOTCONN;
     } else {
         rc = crm_ipc_send(ipc, query, crm_ipc_client_response, 0, reply);
         if (rc > 0) {
             rc = pcmk_ok;
         }
         crm_ipc_close(ipc);
     }
     crm_ipc_destroy(ipc);
 
     free_xml(query);
     return(rc);
 }
 
 /*!
  * \brief Validate pacemaker-attrd's XML reply to an query
  *
  * param[in] reply      Root of reply XML tree to validate
  * param[in] attr_name  Name of attribute that was queried
  *
  * \return pcmk_ok on success,
  *         -errno on error (-ENXIO = requested attribute does not exist)
  */
 static int
 validate_attrd_reply(xmlNode *reply, const char *attr_name)
 {
     const char *reply_attr;
 
     if (reply == NULL) {
         fprintf(stderr, "Could not query value of %s: reply did not contain valid XML\n",
                 attr_name);
         return -pcmk_err_schema_validation;
     }
     crm_log_xml_trace(reply, "Reply");
 
     reply_attr = crm_element_value(reply, PCMK__XA_ATTR_NAME);
     if (reply_attr == NULL) {
         fprintf(stderr, "Could not query value of %s: attribute does not exist\n",
                 attr_name);
         return -ENXIO;
     }
 
     if (!pcmk__str_eq(crm_element_value(reply, F_TYPE), T_ATTRD, pcmk__str_casei)
         || (crm_element_value(reply, PCMK__XA_ATTR_VERSION) == NULL)
         || strcmp(reply_attr, attr_name)) {
             fprintf(stderr,
                     "Could not query value of %s: reply did not contain expected identification\n",
                     attr_name);
             return -pcmk_err_schema_validation;
     }
     return pcmk_ok;
 }
 
 /*!
  * \brief Print the attribute values in a pacemaker-attrd XML query reply
  *
  * \param[in] reply     Root of XML tree with query reply
  * \param[in] attr_name Name of attribute that was queried
  *
  * \return TRUE if any values were printed
  */
 static gboolean
 print_attrd_values(xmlNode *reply, const char *attr_name)
 {
     xmlNode *child;
     const char *reply_host, *reply_value;
     gboolean have_values = FALSE;
 
     /* Iterate through reply's XML tags (a node tag for each host-value pair) */
     for (child = pcmk__xml_first_child(reply); child != NULL;
          child = pcmk__xml_next(child)) {
 
         if (!pcmk__str_eq((const char *)child->name, XML_CIB_TAG_NODE,
                           pcmk__str_casei)) {
             crm_warn("Ignoring unexpected %s tag in query reply", child->name);
         } else {
             reply_host = crm_element_value(child, PCMK__XA_ATTR_NODE_NAME);
             reply_value = crm_element_value(child, PCMK__XA_ATTR_VALUE);
 
             if (reply_host == NULL) {
                 crm_warn("Ignoring %s tag without %s attribute in query reply",
                          XML_CIB_TAG_NODE, PCMK__XA_ATTR_NODE_NAME);
             } else {
                 printf("name=\"%s\" host=\"%s\" value=\"%s\"\n",
                        attr_name, reply_host, (reply_value? reply_value : ""));
                 have_values = TRUE;
             }
         }
     }
     return have_values;
 }
 
 /*!
  * \brief Submit a query to pacemaker-attrd and print reply
  *
  * \param[in] attr_name  Name of attribute to be affected by request
  * \param[in] attr_node  Name of host to query for (or NULL for localhost)
  * \param[in] query_all  If TRUE, ignore attr_node and query all nodes instead
  *
  * \return pcmk_ok on success, -errno on error
  */
 static int
 do_query(const char *attr_name, const char *attr_node, gboolean query_all)
 {
     xmlNode *reply = NULL;
     int rc;
 
     /* Decide which node(s) to query */
     if (query_all == TRUE) {
         attr_node = NULL;
     } else {
-        attr_node = pcmk__node_attr_target(attr_node);
+        const char *target = pcmk__node_attr_target(attr_node);
+        if (target != NULL) {
+            attr_node = target;
+        }
     }
 
     /* Build and send pacemaker-attrd request, and get XML reply */
     rc = send_attrd_query(attr_name, attr_node, &reply);
     if (rc != pcmk_ok) {
         fprintf(stderr, "Could not query value of %s: %s (%d)\n", attr_name, pcmk_strerror(rc), rc);
         return rc;
     }
 
     /* Validate the XML reply */
     rc = validate_attrd_reply(reply, attr_name);
     if (rc != pcmk_ok) {
         if (reply != NULL) {
             free_xml(reply);
         }
         return rc;
     }
 
     /* Print the values from the reply */
     if (print_attrd_values(reply, attr_name) == FALSE) {
         fprintf(stderr,
                 "Could not query value of %s: reply had attribute name but no host values\n",
                 attr_name);
         free_xml(reply);
         return -pcmk_err_schema_validation;
     }
 
     return pcmk_ok;
 }
 
 static int
 do_update(char command, const char *attr_node, const char *attr_name,
           const char *attr_value, const char *attr_section,
           const char *attr_set, const char *attr_dampen, int attr_options)
 {
     int rc = pcmk__node_attr_request(NULL, command, attr_node, attr_name,
                                      attr_value, attr_section, attr_set,
                                      attr_dampen, NULL, attr_options);
     if (rc != pcmk_rc_ok) {
         fprintf(stderr, "Could not update %s=%s: %s (%d)\n",
                 attr_name, attr_value, pcmk_rc_str(rc), rc);
     }
     return rc;
 }