root/daemons/attrd/attrd_utils.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. attrd_shutting_down
  2. attrd_shutdown
  3. attrd_init_mainloop
  4. attrd_run_mainloop
  5. attrd_ipc_accept
  6. attrd_ipc_closed
  7. attrd_ipc_destroy
  8. attrd_init_ipc
  9. attrd_cib_disconnect
  10. attrd_cib_replaced_cb
  11. attrd_value_needs_expansion
  12. attrd_expand_value
  13. attrd_failure_regex

   1 /*
   2  * Copyright 2004-2020 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 <stdio.h>
  13 #include <stdbool.h>
  14 #include <errno.h>
  15 #include <glib.h>
  16 #include <regex.h>
  17 #include <sys/types.h>
  18 
  19 #include <crm/crm.h>
  20 #include <crm/common/ipc_internal.h>
  21 #include <crm/common/mainloop.h>
  22 
  23 #include "pacemaker-attrd.h"
  24 
  25 cib_t *the_cib = NULL;
  26 
  27 static bool shutting_down = FALSE;
  28 static GMainLoop *mloop = NULL;
  29 
  30 /*!
  31  * \internal
  32  * \brief Check whether we're currently shutting down
  33  *
  34  * \return TRUE if shutting down, FALSE otherwise
  35  */
  36 gboolean
  37 attrd_shutting_down()
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39     return shutting_down;
  40 }
  41 
  42 /*!
  43  * \internal
  44  * \brief  Exit (using mainloop or not, as appropriate)
  45  *
  46  * \param[in] nsig  Ignored
  47  */
  48 void
  49 attrd_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51     // Tell various functions not to do anthing
  52     shutting_down = TRUE;
  53 
  54     // Don't respond to signals while shutting down
  55     mainloop_destroy_signal(SIGTERM);
  56     mainloop_destroy_signal(SIGCHLD);
  57     mainloop_destroy_signal(SIGPIPE);
  58     mainloop_destroy_signal(SIGUSR1);
  59     mainloop_destroy_signal(SIGUSR2);
  60     mainloop_destroy_signal(SIGTRAP);
  61 
  62     if ((mloop == NULL) || !g_main_loop_is_running(mloop)) {
  63         /* If there's no main loop active, just exit. This should be possible
  64          * only if we get SIGTERM in brief windows at start-up and shutdown.
  65          */
  66         crm_exit(CRM_EX_OK);
  67     } else {
  68         g_main_loop_quit(mloop);
  69         g_main_loop_unref(mloop);
  70     }
  71 }
  72 
  73 /*!
  74  * \internal
  75  * \brief Create a main loop for attrd
  76  */
  77 void
  78 attrd_init_mainloop()
     /* [previous][next][first][last][top][bottom][index][help] */
  79 {
  80     mloop = g_main_loop_new(NULL, FALSE);
  81 }
  82 
  83 /*!
  84  * \internal
  85  * \brief Run attrd main loop
  86  */
  87 void
  88 attrd_run_mainloop()
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     g_main_loop_run(mloop);
  91 }
  92 
  93 /*!
  94  * \internal
  95  * \brief Accept a new client IPC connection
  96  *
  97  * \param[in] c    New connection
  98  * \param[in] uid  Client user id
  99  * \param[in] gid  Client group id
 100  *
 101  * \return pcmk_ok on success, -errno otherwise
 102  */
 103 static int32_t
 104 attrd_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106     crm_trace("New client connection %p", c);
 107     if (shutting_down) {
 108         crm_info("Ignoring new connection from pid %d during shutdown",
 109                  pcmk__client_pid(c));
 110         return -EPERM;
 111     }
 112 
 113     if (pcmk__new_client(c, uid, gid) == NULL) {
 114         return -EIO;
 115     }
 116     return pcmk_ok;
 117 }
 118 
 119 /*!
 120  * \internal
 121  * \brief Destroy a client IPC connection
 122  *
 123  * \param[in] c  Connection to destroy
 124  *
 125  * \return FALSE (i.e. do not re-run this callback)
 126  */
 127 static int32_t
 128 attrd_ipc_closed(qb_ipcs_connection_t *c)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130     pcmk__client_t *client = pcmk__find_client(c);
 131 
 132     if (client == NULL) {
 133         crm_trace("Ignoring request to clean up unknown connection %p", c);
 134     } else {
 135         crm_trace("Cleaning up closed client connection %p", c);
 136         pcmk__free_client(client);
 137     }
 138     return FALSE;
 139 }
 140 
 141 /*!
 142  * \internal
 143  * \brief Destroy a client IPC connection
 144  *
 145  * \param[in] c  Connection to destroy
 146  *
 147  * \note We handle a destroyed connection the same as a closed one,
 148  *       but we need a separate handler because the return type is different.
 149  */
 150 static void
 151 attrd_ipc_destroy(qb_ipcs_connection_t *c)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153     crm_trace("Destroying client connection %p", c);
 154     attrd_ipc_closed(c);
 155 }
 156 
 157 /*!
 158  * \internal
 159  * \brief Set up attrd IPC communication
 160  *
 161  * \param[out] ipcs         Will be set to newly allocated server connection
 162  * \param[in]  dispatch_fn  Handler for new messages on connection
 163  */
 164 void
 165 attrd_init_ipc(qb_ipcs_service_t **ipcs, qb_ipcs_msg_process_fn dispatch_fn)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167 
 168     static struct qb_ipcs_service_handlers ipc_callbacks = {
 169         .connection_accept = attrd_ipc_accept,
 170         .connection_created = NULL,
 171         .msg_process = NULL,
 172         .connection_closed = attrd_ipc_closed,
 173         .connection_destroyed = attrd_ipc_destroy
 174     };
 175 
 176     ipc_callbacks.msg_process = dispatch_fn;
 177     pcmk__serve_attrd_ipc(ipcs, &ipc_callbacks);
 178 }
 179 
 180 void
 181 attrd_cib_disconnect()
     /* [previous][next][first][last][top][bottom][index][help] */
 182 {
 183     CRM_CHECK(the_cib != NULL, return);
 184     the_cib->cmds->del_notify_callback(the_cib, T_CIB_REPLACE_NOTIFY, attrd_cib_replaced_cb);
 185     the_cib->cmds->del_notify_callback(the_cib, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb); 
 186     the_cib->cmds->signoff(the_cib);
 187     cib_delete(the_cib);
 188     the_cib = NULL;
 189 }
 190 
 191 void
 192 attrd_cib_replaced_cb(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194     if (attrd_shutting_down()) {
 195         return;
 196     }
 197 
 198     if (attrd_election_won()) {
 199         crm_notice("Updating all attributes after %s event", event);
 200         write_attributes(TRUE, FALSE);
 201     }
 202 
 203     // Check for changes in alerts
 204     mainloop_set_trigger(attrd_config_read);
 205 }
 206 
 207 /* strlen("value") */
 208 #define plus_plus_len (5)
 209 
 210 /*!
 211  * \internal
 212  * \brief  Check whether an attribute value should be expanded
 213  *
 214  * \param[in] value  Attribute value to check
 215  *
 216  * \return TRUE if value needs expansion, FALSE otherwise
 217  */
 218 gboolean
 219 attrd_value_needs_expansion(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 220 {
 221     return ((strlen(value) >= (plus_plus_len + 2))
 222            && (value[plus_plus_len] == '+')
 223            && ((value[plus_plus_len + 1] == '+')
 224                || (value[plus_plus_len + 1] == '=')));
 225 }
 226 
 227 /*!
 228  * \internal
 229  * \brief Expand an increment expression into an integer
 230  *
 231  * \param[in] value      Attribute increment expression to expand
 232  * \param[in] old_value  Previous value of attribute
 233  *
 234  * \return Expanded value
 235  */
 236 int
 237 attrd_expand_value(const char *value, const char *old_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239     int offset = 1;
 240     int int_value = char2score(old_value);
 241 
 242     if (value[plus_plus_len + 1] != '+') {
 243         const char *offset_s = value + (plus_plus_len + 2);
 244 
 245         offset = char2score(offset_s);
 246     }
 247     int_value += offset;
 248 
 249     if (int_value > INFINITY) {
 250         int_value = INFINITY;
 251     }
 252     return int_value;
 253 }
 254 
 255 /*!
 256  * \internal
 257  * \brief Create regular expression matching failure-related attributes
 258  *
 259  * \param[out] regex  Where to store created regular expression
 260  * \param[in]  rsc    Name of resource to clear (or NULL for all)
 261  * \param[in]  op     Operation to clear if rsc is specified (or NULL for all)
 262  * \param[in]  interval_ms  Interval of operation to clear if op is specified
 263  *
 264  * \return pcmk_ok on success, -EINVAL if arguments are invalid
 265  *
 266  * \note The caller is responsible for freeing the result with regfree().
 267  */
 268 int
 269 attrd_failure_regex(regex_t *regex, const char *rsc, const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 270                     guint interval_ms)
 271 {
 272     char *pattern = NULL;
 273     int rc;
 274 
 275     /* Create a pattern that matches desired attributes */
 276 
 277     if (rsc == NULL) {
 278         pattern = strdup(ATTRD_RE_CLEAR_ALL);
 279     } else if (op == NULL) {
 280         pattern = crm_strdup_printf(ATTRD_RE_CLEAR_ONE, rsc);
 281     } else {
 282         pattern = crm_strdup_printf(ATTRD_RE_CLEAR_OP, rsc, op, interval_ms);
 283     }
 284 
 285     /* Compile pattern into regular expression */
 286     crm_trace("Clearing attributes matching %s", pattern);
 287     rc = regcomp(regex, pattern, REG_EXTENDED|REG_NOSUB);
 288     free(pattern);
 289 
 290     return (rc == 0)? pcmk_ok : -EINVAL;
 291 }

/* [previous][next][first][last][top][bottom][index][help] */