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