1    	/*
2    	 * Copyright 2015-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 Lesser General Public License
7    	 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8    	 */
9    	
10   	#include <crm_internal.h>
11   	#include <crm/crm.h>
12   	#include <crm/lrmd.h>
13   	#include <crm/common/xml.h>
14   	#include <crm/common/alerts_internal.h>
15   	#include <crm/common/cib_internal.h>
16   	#include <crm/common/xml_internal.h>
17   	
18   	/*
19   	 * to allow script compatibility we can have more than one
20   	 * set of environment variables
21   	 */
22   	const char *pcmk__alert_keys[PCMK__ALERT_INTERNAL_KEY_MAX][3] =
23   	{
24   	    [PCMK__alert_key_recipient] = {
25   	        "CRM_notify_recipient",         "CRM_alert_recipient",          NULL
26   	    },
27   	    [PCMK__alert_key_node] = {
28   	        "CRM_notify_node",              "CRM_alert_node",               NULL
29   	    },
30   	    [PCMK__alert_key_nodeid] = {
31   	        "CRM_notify_nodeid",            "CRM_alert_nodeid",             NULL
32   	    },
33   	    [PCMK__alert_key_rsc] = {
34   	        "CRM_notify_rsc",               "CRM_alert_rsc",                NULL
35   	    },
36   	    [PCMK__alert_key_task] = {
37   	        "CRM_notify_task",              "CRM_alert_task",               NULL
38   	    },
39   	    [PCMK__alert_key_interval] = {
40   	        "CRM_notify_interval",          "CRM_alert_interval",           NULL
41   	    },
42   	    [PCMK__alert_key_desc] = {
43   	        "CRM_notify_desc",              "CRM_alert_desc",               NULL
44   	    },
45   	    [PCMK__alert_key_status] = {
46   	        "CRM_notify_status",            "CRM_alert_status",             NULL
47   	    },
48   	    [PCMK__alert_key_target_rc] = {
49   	        "CRM_notify_target_rc",         "CRM_alert_target_rc",          NULL
50   	    },
51   	    [PCMK__alert_key_rc] = {
52   	        "CRM_notify_rc",                "CRM_alert_rc",                 NULL
53   	    },
54   	    [PCMK__alert_key_kind] = {
55   	        "CRM_notify_kind",              "CRM_alert_kind",               NULL
56   	    },
57   	    [PCMK__alert_key_version] = {
58   	        "CRM_notify_version",           "CRM_alert_version",            NULL
59   	    },
60   	    [PCMK__alert_key_node_sequence] = {
61   	        "CRM_notify_node_sequence",     PCMK__ALERT_NODE_SEQUENCE,      NULL
62   	    },
63   	    [PCMK__alert_key_timestamp] = {
64   	        "CRM_notify_timestamp",         "CRM_alert_timestamp",          NULL
65   	    },
66   	    [PCMK__alert_key_attribute_name] = {
67   	        "CRM_notify_attribute_name",    "CRM_alert_attribute_name",     NULL
68   	    },
69   	    [PCMK__alert_key_attribute_value] = {
70   	        "CRM_notify_attribute_value",   "CRM_alert_attribute_value",    NULL
71   	    },
72   	    [PCMK__alert_key_timestamp_epoch] = {
73   	        "CRM_notify_timestamp_epoch",   "CRM_alert_timestamp_epoch",    NULL
74   	    },
75   	    [PCMK__alert_key_timestamp_usec] = {
76   	        "CRM_notify_timestamp_usec",    "CRM_alert_timestamp_usec",     NULL
77   	    },
78   	    [PCMK__alert_key_exec_time] = {
79   	        "CRM_notify_exec_time",         "CRM_alert_exec_time",          NULL
80   	    }
81   	};
82   	
83   	/*!
84   	 * \brief Create a new alert entry structure
85   	 *
86   	 * \param[in] id  ID to use
87   	 * \param[in] path  Path to alert agent executable
88   	 *
89   	 * \return Pointer to newly allocated alert entry
90   	 * \note Non-string fields will be filled in with defaults.
91   	 *       It is the caller's responsibility to free the result,
92   	 *       using pcmk__free_alert().
93   	 */
94   	pcmk__alert_t *
95   	pcmk__alert_new(const char *id, const char *path)
96   	{
97   	    pcmk__alert_t *entry = pcmk__assert_alloc(1, sizeof(pcmk__alert_t));
98   	
99   	    pcmk__assert((id != NULL) && (path != NULL));
100  	    entry->id = pcmk__str_copy(id);
101  	    entry->path = pcmk__str_copy(path);
102  	    entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
103  	    entry->flags = pcmk__alert_default;
104  	    return entry;
105  	}
106  	
107  	void
108  	pcmk__free_alert(pcmk__alert_t *entry)
109  	{
110  	    if (entry) {
111  	        free(entry->id);
112  	        free(entry->path);
113  	        free(entry->tstamp_format);
114  	        free(entry->recipient);
115  	
116  	        g_strfreev(entry->select_attribute_name);
117  	        if (entry->envvars) {
118  	            g_hash_table_destroy(entry->envvars);
119  	        }
120  	        free(entry);
121  	    }
122  	}
123  	
124  	/*!
125  	 * \internal
126  	 * \brief Duplicate an alert entry
127  	 *
128  	 * \param[in] entry  Alert entry to duplicate
129  	 *
130  	 * \return Duplicate of alert entry
131  	 */
132  	pcmk__alert_t *
133  	pcmk__dup_alert(const pcmk__alert_t *entry)
134  	{
135  	    pcmk__alert_t *new_entry = pcmk__alert_new(entry->id, entry->path);
136  	
137  	    new_entry->timeout = entry->timeout;
138  	    new_entry->flags = entry->flags;
139  	    new_entry->envvars = pcmk__str_table_dup(entry->envvars);
140  	    new_entry->tstamp_format = pcmk__str_copy(entry->tstamp_format);
(1) Event alloc_fn: Storage is returned from allocation function "pcmk__str_copy_as". [details]
(2) Event assign: Assigning: "new_entry->recipient" = "pcmk__str_copy_as("alerts.c", <anonymous>, 141U, entry->recipient)".
Also see events: [return_alloc]
141  	    new_entry->recipient = pcmk__str_copy(entry->recipient);
(3) Event path: Condition "entry->select_attribute_name", taking true branch.
142  	    if (entry->select_attribute_name) {
143  	        new_entry->select_attribute_name = g_strdupv(entry->select_attribute_name);
144  	    }
(4) Event return_alloc: Returning "new_entry", where "new_entry->recipient" is allocated memory.
Also see events: [alloc_fn][assign]
145  	    return new_entry;
146  	}
147  	
148  	void
149  	pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name,
150  	                    const char *value)
151  	{
152  	    for (const char **key = pcmk__alert_keys[name]; *key; key++) {
153  	        if (value) {
154  	            crm_trace("Inserting alert key %s = '%s'", *key, value);
155  	            pcmk__insert_dup(table, *key, value);
156  	        } else {
157  	            crm_trace("Removing alert key %s (no value given)", *key);
158  	            g_hash_table_remove(table, *key);
159  	        }
160  	    }
161  	}
162  	
163  	void
164  	pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name,
165  	                        int value)
166  	{
167  	    for (const char **key = pcmk__alert_keys[name]; *key; key++) {
168  	        crm_trace("Inserting alert key %s = %d", *key, value);
169  	        g_hash_table_insert(table, pcmk__str_copy(*key), pcmk__itoa(value));
170  	    }
171  	}
172