2 * Copyright (c) 2015-2020 Red Hat, Inc.
6 * Author: Jan Friesse (jfriesse@redhat.com)
8 * This software licensed under BSD license, the text of which follows:
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
40 #include "dynar-str.h"
41 #include "dynar-getopt-lex.h"
43 #include "qdevice-advanced-settings.h"
44 #include "qdevice-config.h"
45 #include "qdevice-cmap.h"
46 #include "qdevice-heuristics.h"
47 #include "qdevice-ipc.h"
48 #include "qdevice-log.h"
49 #include "qdevice-model.h"
50 #include "qdevice-votequorum.h"
53 #ifdef HAVE_LIBSYSTEMD
54 #include <systemd/sd-daemon.h>
57 struct qdevice_instance
*global_instance
;
60 signal_int_handler(int sig
)
62 log(LOG_DEBUG
, "SIGINT received - closing local unix socket");
63 qdevice_ipc_close(global_instance
);
67 signal_term_handler(int sig
)
69 log(LOG_DEBUG
, "SIGTERM received - closing local unix socket");
70 qdevice_ipc_close(global_instance
);
74 signal_handlers_register(void)
78 act
.sa_handler
= signal_int_handler
;
79 sigemptyset(&act
.sa_mask
);
80 act
.sa_flags
= SA_RESTART
;
82 sigaction(SIGINT
, &act
, NULL
);
84 act
.sa_handler
= signal_term_handler
;
85 sigemptyset(&act
.sa_mask
);
86 act
.sa_flags
= SA_RESTART
;
88 sigaction(SIGTERM
, &act
, NULL
);
90 act
.sa_handler
= SIG_DFL
;
91 sigemptyset(&act
.sa_mask
);
92 act
.sa_flags
= SA_RESTART
;
94 sigaction(SIGCHLD
, &act
, NULL
);
96 act
.sa_handler
= SIG_IGN
;
97 sigemptyset(&act
.sa_mask
);
98 act
.sa_flags
= SA_RESTART
;
100 sigaction(SIGPIPE
, &act
, NULL
);
107 printf("usage: %s [-dfh] [-S option=value[,option2=value2,...]]\n", QDEVICE_PROGRAM_NAME
);
111 cli_parse_long_opt(struct qdevice_advanced_settings
*advanced_settings
, const char *long_opt
)
113 struct dynar_getopt_lex lex
;
114 struct dynar dynar_long_opt
;
119 dynar_init(&dynar_long_opt
, strlen(long_opt
) + 1);
120 if (dynar_str_cpy(&dynar_long_opt
, long_opt
) != 0) {
121 errx(EXIT_FAILURE
, "Can't alloc memory for long option");
124 dynar_getopt_lex_init(&lex
, &dynar_long_opt
);
126 while (dynar_getopt_lex_token_next(&lex
) == 0 && strcmp(dynar_data(&lex
.option
), "") != 0) {
127 opt
= dynar_data(&lex
.option
);
128 val
= dynar_data(&lex
.value
);
130 res
= qdevice_advanced_settings_set(advanced_settings
, opt
, val
);
133 errx(EXIT_FAILURE
, "Unknown option '%s'", opt
);
136 errx(EXIT_FAILURE
, "Invalid value '%s' for option '%s'", val
, opt
);
141 dynar_getopt_lex_destroy(&lex
);
142 dynar_destroy(&dynar_long_opt
);
146 cli_parse(int argc
, char * const argv
[], int *foreground
, int *force_debug
, int *bump_log_priority
,
147 struct qdevice_advanced_settings
*advanced_settings
)
153 *bump_log_priority
= 0;
155 while ((ch
= getopt(argc
, argv
, "dfhS:")) != -1) {
159 *bump_log_priority
= 1;
167 cli_parse_long_opt(advanced_settings
, optarg
);
179 main(int argc
, char * const argv
[])
181 struct qdevice_instance instance
;
182 struct qdevice_advanced_settings advanced_settings
;
185 int bump_log_priority
;
187 int another_instance_running
;
190 if (qdevice_advanced_settings_init(&advanced_settings
) != 0) {
191 errx(EXIT_FAILURE
, "Can't alloc memory for advanced settings");
194 cli_parse(argc
, argv
, &foreground
, &force_debug
, &bump_log_priority
, &advanced_settings
);
196 qdevice_instance_init(&instance
, &advanced_settings
);
198 qdevice_heuristics_init(&instance
.heuristics_instance
, &advanced_settings
);
199 instance
.heuristics_instance
.qdevice_instance_ptr
= &instance
;
201 qdevice_cmap_init(&instance
);
202 if (qdevice_log_init(&instance
, foreground
, force_debug
, bump_log_priority
) == -1) {
203 errx(EXIT_FAILURE
, "Can't initialize logging");
213 if ((lock_file
= utils_flock(advanced_settings
.lock_file
, getpid(),
214 &another_instance_running
)) == -1) {
215 if (another_instance_running
) {
216 log(LOG_ERR
, "Another instance is running");
218 log_err(LOG_ERR
, "Can't acquire lock");
221 return (EXIT_FAILURE
);
224 log(LOG_DEBUG
, "Initializing votequorum");
225 qdevice_votequorum_init(&instance
);
227 log(LOG_DEBUG
, "Initializing local socket");
228 if (qdevice_ipc_init(&instance
) != 0) {
229 return (EXIT_FAILURE
);
232 log(LOG_DEBUG
, "Registering qdevice models");
233 qdevice_model_register_all();
235 log(LOG_DEBUG
, "Configuring qdevice");
236 if (qdevice_instance_configure_from_cmap(&instance
) != 0) {
237 return (EXIT_FAILURE
);
240 log(LOG_DEBUG
, "Configuring master_wins");
241 if (qdevice_votequorum_master_wins(&instance
, (advanced_settings
.master_wins
==
242 QDEVICE_ADVANCED_SETTINGS_MASTER_WINS_FORCE_ON
? 1 : 0)) != 0) {
243 return (EXIT_FAILURE
);
246 log(LOG_DEBUG
, "Getting configuration node list");
247 if (qdevice_cmap_store_config_node_list(&instance
) != 0) {
248 return (EXIT_FAILURE
);
251 log(LOG_DEBUG
, "Initializing qdevice model");
252 if (qdevice_model_init(&instance
) != 0) {
253 return (EXIT_FAILURE
);
256 log(LOG_DEBUG
, "Initializing cmap tracking");
257 if (qdevice_cmap_add_track(&instance
) != 0) {
258 return (EXIT_FAILURE
);
261 log(LOG_DEBUG
, "Waiting for ring id");
262 if (qdevice_votequorum_wait_for_ring_id(&instance
) != 0) {
263 return (EXIT_FAILURE
);
266 log(LOG_DEBUG
, "Waiting for initial heuristics exec result");
267 if (qdevice_heuristics_wait_for_initial_exec_result(&instance
.heuristics_instance
) != 0) {
268 return (EXIT_FAILURE
);
271 global_instance
= &instance
;
272 signal_handlers_register();
274 log(LOG_DEBUG
, "Running qdevice model");
275 #ifdef HAVE_LIBSYSTEMD
276 sd_notify (0, "READY=1");
278 model_run_res
= qdevice_model_run(&instance
);
280 log(LOG_DEBUG
, "Removing cmap tracking");
282 * Ignore error intentionally
284 (void)qdevice_cmap_del_track(&instance
);
286 log(LOG_DEBUG
, "Destroying qdevice model");
287 qdevice_model_destroy(&instance
);
289 log(LOG_DEBUG
, "Destroying qdevice ipc");
290 qdevice_ipc_destroy(&instance
);
292 log(LOG_DEBUG
, "Destroying votequorum and cmap");
293 qdevice_votequorum_destroy(&instance
);
294 qdevice_cmap_destroy(&instance
);
296 log(LOG_DEBUG
, "Destroying heuristics");
297 qdevice_heuristics_destroy(&instance
.heuristics_instance
, foreground
);
299 log(LOG_DEBUG
, "Closing log");
300 qdevice_log_close(&instance
);
302 qdevice_instance_destroy(&instance
);
304 qdevice_advanced_settings_destroy(&advanced_settings
);
306 return (model_run_res
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);