1 /*
2 * Copyright 2004-2026 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 <stdbool.h>
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <fcntl.h>
22
23 #include <crm/crm.h>
24 #include <crm/common/ipc.h>
25 #include <crm/common/xml.h>
26
27 #include <pacemaker-controld.h>
28
29 #define SUMMARY "daemon for coordinating a Pacemaker cluster's response " \
30 "to events"
31
32 controld_globals_t controld_globals = {
33 // Automatic initialization to 0, false, or NULL is fine for most members
34 .fsa_state = S_STARTING,
35 .fsa_actions = A_NOTHING,
36 };
37
38 static pcmk__supported_format_t formats[] = {
39 PCMK__SUPPORTED_FORMAT_NONE,
40 PCMK__SUPPORTED_FORMAT_TEXT,
41 PCMK__SUPPORTED_FORMAT_XML,
42 { NULL, NULL, NULL }
43 };
44
45 /* @COMPAT Deprecated since 2.1.8. Use pcmk_list_cluster_options() or
46 * crm_attribute --list-options=cluster instead of querying daemon metadata.
47 *
48 * NOTE: pcs (as of at least 0.11.8) uses this
49 */
50 static int
51 controld_metadata(pcmk__output_t *out)
52 {
53 return pcmk__daemon_metadata(out, PCMK__SERVER_CONTROLD,
54 "Pacemaker controller options",
55 "Cluster options used by Pacemaker's "
56 "controller",
57 pcmk__opt_controld);
58 }
59
60 static GOptionContext *
61 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group)
62 {
63 return pcmk__build_arg_context(args, "text (default), xml", group, NULL);
64 }
65
66 int
67 main(int argc, char **argv)
68 {
69 int rc = pcmk_rc_ok;
70 crm_exit_t exit_code = CRM_EX_OK;
71 bool initialize = true;
72 enum crmd_fsa_state state;
73
74 crm_ipc_t *old_instance = NULL;
75
76 pcmk__output_t *out = NULL;
77
78 GError *error = NULL;
79
80 GOptionGroup *output_group = NULL;
81 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
82 gchar **processed_args = pcmk__cmdline_preproc(argv, NULL);
83 GOptionContext *context = build_arg_context(args, &output_group);
84
85 crm_log_preinit(NULL, argc, argv);
86
87 pcmk__register_formats(output_group, formats);
|
(1) Event path: |
Condition "!g_option_context_parse_strv(context, &processed_args, &error)", taking false branch. |
88 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
89 exit_code = CRM_EX_USAGE;
90 goto done;
91 }
92
93 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
|
(2) Event path: |
Condition "rc != pcmk_rc_ok", taking false branch. |
94 if (rc != pcmk_rc_ok) {
95 exit_code = CRM_EX_ERROR;
96 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
97 "Error creating output format %s: %s",
98 args->output_ty, pcmk_rc_str(rc));
99 goto done;
100 }
101
|
(3) Event path: |
Condition "args->version", taking false branch. |
102 if (args->version) {
103 out->version(out);
104 initialize = false;
105 goto done;
106 }
107
|
(4) Event path: |
Condition "g_strv_length(processed_args) >= 2", taking true branch. |
|
(5) Event path: |
Condition "pcmk__str_eq(processed_args[1], "metadata", pcmk__str_none)", taking false branch. |
108 if ((g_strv_length(processed_args) >= 2)
109 && pcmk__str_eq(processed_args[1], "metadata", pcmk__str_none)) {
110
111 initialize = false;
112 rc = controld_metadata(out);
113 if (rc != pcmk_rc_ok) {
114 exit_code = CRM_EX_FATAL;
115 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
116 "Unable to display metadata: %s", pcmk_rc_str(rc));
117 }
118 goto done;
119 }
120
121 pcmk__cli_init_logging(PCMK__SERVER_CONTROLD, args->verbosity);
122 crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
123 pcmk__notice("Starting Pacemaker controller");
124
125 old_instance = crm_ipc_new(CRM_SYSTEM_CRMD, 0);
|
(6) Event path: |
Condition "old_instance == NULL", taking false branch. |
126 if (old_instance == NULL) {
127 /* crm_ipc_new() will have already logged an error message with
128 * pcmk__err()
129 */
130 exit_code = CRM_EX_FATAL;
131 goto done;
132 }
133
|
(7) Event path: |
Condition "pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok", taking false branch. |
134 if (pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok) {
135 /* IPC end-point already up */
136 crm_ipc_close(old_instance);
137 crm_ipc_destroy(old_instance);
138 pcmk__crit("Aborting start-up because another controller instance is "
139 "already active");
140 initialize = false;
141 goto done;
142 }
143
144 // Not up or not authentic; we'll proceed either way
|
CID (unavailable; MK=16b8281ab56db37c1d30f287957afbb0) (#1 of 1): Inconsistent C union access (INCONSISTENT_UNION_ACCESS): |
|
(8) Event assign_union_field: |
The union field "in" of "_pp" is written. |
|
(9) Event inconsistent_union_field_access: |
In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in". |
145 g_clear_pointer(&old_instance, crm_ipc_destroy);
146
147 if (pcmk__daemon_can_write(PCMK_SCHEDULER_INPUT_DIR, NULL) == FALSE) {
148 exit_code = CRM_EX_FATAL;
149 pcmk__err("Terminating due to bad permissions on "
150 PCMK_SCHEDULER_INPUT_DIR);
151 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
152 "Bad permissions on " PCMK_SCHEDULER_INPUT_DIR
153 " (see logs for details)");
154 goto done;
155
156 } else if (pcmk__daemon_can_write(CRM_CONFIG_DIR, NULL) == FALSE) {
157 exit_code = CRM_EX_FATAL;
158 pcmk__err("Terminating due to bad permissions on " CRM_CONFIG_DIR);
159 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
160 "Bad permissions on " CRM_CONFIG_DIR
161 " (see logs for details)");
162 goto done;
163 }
164
165 if (pcmk__log_output_new(&(controld_globals.logger_out)) != pcmk_rc_ok) {
166 exit_code = CRM_EX_FATAL;
167 goto done;
168 }
169
170 pcmk__output_set_log_level(controld_globals.logger_out, LOG_TRACE);
171
172 done:
173 g_strfreev(processed_args);
174 pcmk__free_arg_context(context);
175
176 // We no longer need output
177 pcmk__output_and_clear_error(&error, out);
178 if (out != NULL) {
179 out->finish(out, exit_code, true, NULL);
180 pcmk__output_free(out);
181 }
182 pcmk__unregister_formats();
183
184 // Exit on error or command-line queries
185 if ((exit_code != CRM_EX_OK) || !initialize) {
186 crm_exit(exit_code);
187 }
188
189 // Initialize FSA
190 controld_fsa_append(C_STARTUP, I_STARTUP, NULL);
191 pcmk__cluster_init_node_caches();
192 state = s_crmd_fsa(C_STARTUP);
193 if ((state != S_PENDING) && (state != S_STARTING)) {
194 pcmk__err("Controller startup failed " QB_XS " FSA state %s",
195 crm_system_name, fsa_state2string(state));
196 crmd_fast_exit(CRM_EX_ERROR); // Does not return
197 }
198
199 // Run mainloop
200 controld_globals.mainloop = g_main_loop_new(NULL, FALSE);
201 g_main_loop_run(controld_globals.mainloop);
202 if (pcmk__is_set(controld_globals.fsa_input_register, R_STAYDOWN)) {
203 pcmk__info("Inhibiting automated respawn");
204 exit_code = CRM_EX_FATAL;
205 }
206 crmd_fast_exit(exit_code);
207 }
208