root/daemons/attrd/attrd_utils.c

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

DEFINITIONS

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

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