]> git.proxmox.com Git - mirror_corosync-qdevice.git/blob - qdevices/corosync-qdevice.c
b322c93574b541714b85f8b0311ad7e217192db1
[mirror_corosync-qdevice.git] / qdevices / corosync-qdevice.c
1 /*
2 * Copyright (c) 2015-2020 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
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.
21 *
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.
33 */
34
35 #include <err.h>
36 #include <signal.h>
37 #include <stdio.h>
38
39 #include "dynar.h"
40 #include "dynar-str.h"
41 #include "dynar-getopt-lex.h"
42 #include "log.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"
51 #include "utils.h"
52
53 #ifdef HAVE_LIBSYSTEMD
54 #include <systemd/sd-daemon.h>
55 #endif
56
57 struct qdevice_instance *global_instance;
58
59 static void
60 signal_int_handler(int sig)
61 {
62 log(LOG_DEBUG, "SIGINT received - closing local unix socket");
63 qdevice_ipc_close(global_instance);
64 }
65
66 static void
67 signal_term_handler(int sig)
68 {
69 log(LOG_DEBUG, "SIGTERM received - closing local unix socket");
70 qdevice_ipc_close(global_instance);
71 }
72
73 static void
74 signal_handlers_register(void)
75 {
76 struct sigaction act;
77
78 act.sa_handler = signal_int_handler;
79 sigemptyset(&act.sa_mask);
80 act.sa_flags = SA_RESTART;
81
82 sigaction(SIGINT, &act, NULL);
83
84 act.sa_handler = signal_term_handler;
85 sigemptyset(&act.sa_mask);
86 act.sa_flags = SA_RESTART;
87
88 sigaction(SIGTERM, &act, NULL);
89
90 act.sa_handler = SIG_DFL;
91 sigemptyset(&act.sa_mask);
92 act.sa_flags = SA_RESTART;
93
94 sigaction(SIGCHLD, &act, NULL);
95
96 act.sa_handler = SIG_IGN;
97 sigemptyset(&act.sa_mask);
98 act.sa_flags = SA_RESTART;
99
100 sigaction(SIGPIPE, &act, NULL);
101 }
102
103 static void
104 usage(void)
105 {
106
107 printf("usage: %s [-dfh] [-S option=value[,option2=value2,...]]\n", QDEVICE_PROGRAM_NAME);
108 }
109
110 static void
111 cli_parse_long_opt(struct qdevice_advanced_settings *advanced_settings, const char *long_opt)
112 {
113 struct dynar_getopt_lex lex;
114 struct dynar dynar_long_opt;
115 const char *opt;
116 const char *val;
117 int res;
118
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");
122 }
123
124 dynar_getopt_lex_init(&lex, &dynar_long_opt);
125
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);
129
130 res = qdevice_advanced_settings_set(advanced_settings, opt, val);
131 switch (res) {
132 case -1:
133 errx(EXIT_FAILURE, "Unknown option '%s'", opt);
134 break;
135 case -2:
136 errx(EXIT_FAILURE, "Invalid value '%s' for option '%s'", val, opt);
137 break;
138 }
139 }
140
141 dynar_getopt_lex_destroy(&lex);
142 dynar_destroy(&dynar_long_opt);
143 }
144
145 static void
146 cli_parse(int argc, char * const argv[], int *foreground, int *force_debug, int *bump_log_priority,
147 struct qdevice_advanced_settings *advanced_settings)
148 {
149 int ch;
150
151 *foreground = 0;
152 *force_debug = 0;
153 *bump_log_priority = 0;
154
155 while ((ch = getopt(argc, argv, "dfhS:")) != -1) {
156 switch (ch) {
157 case 'd':
158 if (*force_debug) {
159 *bump_log_priority = 1;
160 }
161 *force_debug = 1;
162 break;
163 case 'f':
164 *foreground = 1;
165 break;
166 case 'S':
167 cli_parse_long_opt(advanced_settings, optarg);
168 break;
169 case 'h':
170 case '?':
171 usage();
172 exit(EXIT_FAILURE);
173 break;
174 }
175 }
176 }
177
178 int
179 main(int argc, char * const argv[])
180 {
181 struct qdevice_instance instance;
182 struct qdevice_advanced_settings advanced_settings;
183 int foreground;
184 int force_debug;
185 int bump_log_priority;
186 int lock_file;
187 int another_instance_running;
188 int model_run_res;
189
190 if (qdevice_advanced_settings_init(&advanced_settings) != 0) {
191 errx(EXIT_FAILURE, "Can't alloc memory for advanced settings");
192 }
193
194 cli_parse(argc, argv, &foreground, &force_debug, &bump_log_priority, &advanced_settings);
195
196 qdevice_instance_init(&instance, &advanced_settings);
197
198 qdevice_heuristics_init(&instance.heuristics_instance, &advanced_settings);
199 instance.heuristics_instance.qdevice_instance_ptr = &instance;
200
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");
204 }
205
206 /*
207 * Daemonize
208 */
209 if (!foreground) {
210 utils_tty_detach();
211 }
212
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");
217 } else {
218 log_err(LOG_ERR, "Can't acquire lock");
219 }
220
221 return (EXIT_FAILURE);
222 }
223
224 log(LOG_DEBUG, "Initializing votequorum");
225 qdevice_votequorum_init(&instance);
226
227 log(LOG_DEBUG, "Initializing local socket");
228 if (qdevice_ipc_init(&instance) != 0) {
229 return (EXIT_FAILURE);
230 }
231
232 log(LOG_DEBUG, "Registering qdevice models");
233 qdevice_model_register_all();
234
235 log(LOG_DEBUG, "Configuring qdevice");
236 if (qdevice_instance_configure_from_cmap(&instance) != 0) {
237 return (EXIT_FAILURE);
238 }
239
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);
244 }
245
246 log(LOG_DEBUG, "Getting configuration node list");
247 if (qdevice_cmap_store_config_node_list(&instance) != 0) {
248 return (EXIT_FAILURE);
249 }
250
251 log(LOG_DEBUG, "Initializing qdevice model");
252 if (qdevice_model_init(&instance) != 0) {
253 return (EXIT_FAILURE);
254 }
255
256 log(LOG_DEBUG, "Initializing cmap tracking");
257 if (qdevice_cmap_add_track(&instance) != 0) {
258 return (EXIT_FAILURE);
259 }
260
261 log(LOG_DEBUG, "Waiting for ring id");
262 if (qdevice_votequorum_wait_for_ring_id(&instance) != 0) {
263 return (EXIT_FAILURE);
264 }
265
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);
269 }
270
271 global_instance = &instance;
272 signal_handlers_register();
273
274 log(LOG_DEBUG, "Running qdevice model");
275 #ifdef HAVE_LIBSYSTEMD
276 sd_notify (0, "READY=1");
277 #endif
278 model_run_res = qdevice_model_run(&instance);
279
280 log(LOG_DEBUG, "Removing cmap tracking");
281 /*
282 * Ignore error intentionally
283 */
284 (void)qdevice_cmap_del_track(&instance);
285
286 log(LOG_DEBUG, "Destroying qdevice model");
287 qdevice_model_destroy(&instance);
288
289 log(LOG_DEBUG, "Destroying qdevice ipc");
290 qdevice_ipc_destroy(&instance);
291
292 log(LOG_DEBUG, "Destroying votequorum and cmap");
293 qdevice_votequorum_destroy(&instance);
294 qdevice_cmap_destroy(&instance);
295
296 log(LOG_DEBUG, "Destroying heuristics");
297 qdevice_heuristics_destroy(&instance.heuristics_instance, foreground);
298
299 log(LOG_DEBUG, "Closing log");
300 qdevice_log_close(&instance);
301
302 qdevice_instance_destroy(&instance);
303
304 qdevice_advanced_settings_destroy(&advanced_settings);
305
306 return (model_run_res == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
307 }