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 <signal.h> // SIGTERM
13 #include <stdbool.h> // true
14 #include <stddef.h> // NULL
15
16 #include <glib.h> // g_set_error, FALSE, G_OPTION_*
17 #include <qb/qblog.h> // LOG_INFO, LOG_TRACE
18
19 #include <crm_config.h> // PCMK_SCHEDULER_INPUT_DIR
20 #include <crm/common/mainloop.h> // mainloop_add_signal
21 #include <crm/common/results.h> // crm_exit_t, CRM_EX_*, pcmk_rc_*
22 #include <crm/pengine/internal.h> // pe__register_messages
23 #include <pacemaker-internal.h> // pcmk__register_lib_messages
24
25 #include "pacemaker-schedulerd.h"
26
27 #define SUMMARY PCMK__SERVER_SCHEDULERD " - daemon for calculating a " \
28 "Pacemaker cluster's response to events"
29
30 struct {
31 gchar **remainder;
32 } options;
33
34 pcmk__output_t *logger_out = NULL;
35
36 static pcmk__output_t *out = NULL;
37 static GMainLoop *mainloop = NULL;
38 static crm_exit_t exit_code = CRM_EX_OK;
39
40 pcmk__supported_format_t formats[] = {
41 PCMK__SUPPORTED_FORMAT_NONE,
42 PCMK__SUPPORTED_FORMAT_TEXT,
43 PCMK__SUPPORTED_FORMAT_XML,
44 { NULL, NULL, NULL }
45 };
46
47 void pengine_shutdown(int nsig);
48
49 /* @COMPAT Deprecated since 2.1.8. Use pcmk_list_cluster_options() or
50 * crm_attribute --list-options=cluster instead of querying daemon metadata.
51 *
52 * NOTE: pcs (as of at least 0.11.8) uses this
53 */
54 static int
55 scheduler_metadata(pcmk__output_t *out)
56 {
57 return pcmk__daemon_metadata(out, PCMK__SERVER_SCHEDULERD,
58 "Pacemaker scheduler options",
59 "Cluster options used by Pacemaker's "
60 "scheduler",
61 pcmk__opt_schedulerd);
62 }
63
64 static GOptionContext *
65 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
66 GOptionContext *context = NULL;
67
68 GOptionEntry extra_prog_entries[] = {
69 { G_OPTION_REMAINING, 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING_ARRAY, &options.remainder,
70 NULL,
71 NULL },
72
73 { NULL }
74 };
75
76 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
77 pcmk__add_main_args(context, extra_prog_entries);
78 return context;
79 }
80
81 int
82 main(int argc, char **argv)
83 {
84 GError *error = NULL;
85 int rc = pcmk_rc_ok;
86
87 GOptionGroup *output_group = NULL;
88 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
89 gchar **processed_args = pcmk__cmdline_preproc(argv, NULL);
90 GOptionContext *context = build_arg_context(args, &output_group);
91
92 crm_log_preinit(NULL, argc, argv);
93 mainloop_add_signal(SIGTERM, pengine_shutdown);
94
95 pcmk__register_formats(output_group, formats);
96 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
97 exit_code = CRM_EX_USAGE;
98 goto done;
99 }
100
101 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
102 if ((rc != pcmk_rc_ok) || (out == NULL)) {
103 exit_code = CRM_EX_FATAL;
104 g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
105 args->output_ty, pcmk_rc_str(rc));
106 goto done;
107 }
108
109 pe__register_messages(out);
110 pcmk__register_lib_messages(out);
111
112 if (options.remainder) {
113 if (g_strv_length(options.remainder) == 1 &&
114 pcmk__str_eq("metadata", options.remainder[0], pcmk__str_casei)) {
115
116 rc = scheduler_metadata(out);
117 if (rc != pcmk_rc_ok) {
118 exit_code = CRM_EX_FATAL;
119 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
120 "Unable to display metadata: %s", pcmk_rc_str(rc));
121 }
122
123 } else {
124 exit_code = CRM_EX_USAGE;
125 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
126 "Unsupported extra command line parameters");
127 }
128 goto done;
129 }
130
131 if (args->version) {
132 out->version(out);
133 goto done;
134 }
135
136 pcmk__cli_init_logging(PCMK__SERVER_SCHEDULERD, args->verbosity);
137 crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
138 pcmk__notice("Starting Pacemaker scheduler");
139
140 if (pcmk__daemon_can_write(PCMK_SCHEDULER_INPUT_DIR, NULL) == FALSE) {
141 pcmk__err("Terminating due to bad permissions on "
142 PCMK_SCHEDULER_INPUT_DIR);
143 exit_code = CRM_EX_FATAL;
144 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
145 "ERROR: Bad permissions on %s (see logs for details)",
146 PCMK_SCHEDULER_INPUT_DIR);
147 goto done;
148 }
149
150 schedulerd_ipc_init();
151
152 if (pcmk__log_output_new(&logger_out) != pcmk_rc_ok) {
153 exit_code = CRM_EX_FATAL;
154 goto done;
155 }
156 pe__register_messages(logger_out);
157 pcmk__register_lib_messages(logger_out);
158 pcmk__output_set_log_level(logger_out, LOG_TRACE);
159
160 /* Create the mainloop and run it... */
161 mainloop = g_main_loop_new(NULL, FALSE);
162 pcmk__notice("Pacemaker scheduler successfully started and accepting "
163 "connections");
164 g_main_loop_run(mainloop);
165
166 done:
167 g_strfreev(options.remainder);
168 g_strfreev(processed_args);
169 pcmk__free_arg_context(context);
170
171 pcmk__output_and_clear_error(&error, out);
172 pengine_shutdown(0);
173 }
174
175 void
176 pengine_shutdown(int nsig)
177 {
178 schedulerd_ipc_cleanup();
179 schedulerd_unregister_handlers();
180
|
(1) Event path: |
Condition "logger_out != NULL", taking true branch. |
181 if (logger_out != NULL) {
182 logger_out->finish(logger_out, exit_code, true, NULL);
|
CID (unavailable; MK=44c9ea685685fbb7a1dcf9712def4f0d) (#1 of 2): Inconsistent C union access (INCONSISTENT_UNION_ACCESS): |
|
(2) Event assign_union_field: |
The union field "in" of "_pp" is written. |
|
(3) Event inconsistent_union_field_access: |
In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in". |
183 g_clear_pointer(&logger_out, pcmk__output_free);
184 }
185
186 if (out != NULL) {
187 out->finish(out, exit_code, true, NULL);
188 g_clear_pointer(&out, pcmk__output_free);
189 }
190
191 pcmk__unregister_formats();
192 crm_exit(exit_code);
193 }
194