This source file includes following definitions.
- build_arg_context
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/common/cmdline_internal.h>
13 #include <crm/common/output_internal.h>
14
15 #include <stdio.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <libgen.h>
23 #include <glib.h>
24
25 #include <crm/common/xml.h>
26 #include <crm/common/util.h>
27 #include <crm/cib.h>
28 #include <crm/cib/internal.h>
29 #include <crm/pengine/status.h>
30 #include <pacemaker-internal.h>
31
32 const char *SUMMARY = "Check a Pacemaker configuration for errors\n\n"
33 "Check the well-formedness of a complete Pacemaker XML configuration,\n"
34 "its conformance to the configured schema, and the presence of common\n"
35 "misconfigurations. Problems reported as errors must be fixed before the\n"
36 "cluster will work properly. It is left to the administrator to decide\n"
37 "whether to fix problems reported as warnings.";
38
39 struct {
40 char *cib_save;
41 gboolean use_live_cib;
42 char *xml_file;
43 gboolean xml_stdin;
44 char *xml_string;
45 unsigned int verbosity;
46 } options;
47
48 static GOptionEntry data_entries[] = {
49 { "live-check", 'L', 0, G_OPTION_ARG_NONE,
50 &options.use_live_cib, "Check the configuration used by the running cluster",
51 NULL },
52 { "xml-file", 'x', 0, G_OPTION_ARG_FILENAME,
53 &options.xml_file, "Check the configuration in the named file",
54 "FILE" },
55 { "xml-pipe", 'p', 0, G_OPTION_ARG_NONE,
56 &options.xml_stdin, "Check the configuration piped in via stdin",
57 NULL },
58 { "xml-text", 'X', 0, G_OPTION_ARG_STRING,
59 &options.xml_string, "Check the configuration in the supplied string",
60 "XML" },
61
62 { NULL }
63 };
64
65 static GOptionEntry addl_entries[] = {
66 { "save-xml", 'S', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME,
67 &options.cib_save, "Save verified XML to named file (most useful with -L)",
68 "FILE" },
69
70 { NULL }
71 };
72
73 static pcmk__supported_format_t formats[] = {
74 PCMK__SUPPORTED_FORMAT_NONE,
75 PCMK__SUPPORTED_FORMAT_TEXT,
76 PCMK__SUPPORTED_FORMAT_XML,
77 { NULL, NULL, NULL }
78 };
79
80 static GOptionContext *
81 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
82 GOptionContext *context = NULL;
83
84 const char *description = "Examples:\n\n"
85 "Check the consistency of the configuration in the running cluster:\n\n"
86 "\tcrm_verify --live-check\n\n"
87 "Check the consistency of the configuration in a given file and "
88 "produce quiet output:\n\n"
89 "\tcrm_verify --xml-file file.xml --quiet\n\n"
90 "Check the consistency of the configuration in a given file and "
91 "produce verbose output:\n\n"
92 "\tcrm_verify --xml-file file.xml --verbose\n\n";
93
94 GOptionEntry extra_prog_entries[] = {
95 { "quiet", 'q', 0, G_OPTION_ARG_NONE, &(args->quiet),
96 "Don't print verify information",
97 NULL },
98 { NULL }
99 };
100
101 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
102
103 pcmk__add_main_args(context, extra_prog_entries);
104
105 g_option_context_set_description(context, description);
106
107 pcmk__add_arg_group(context, "data", "Data sources:",
108 "Show data options", data_entries);
109 pcmk__add_arg_group(context, "additional", "Additional options:",
110 "Show additional options", addl_entries);
111
112 return context;
113 }
114
115
116
117
118
119
120
121
122
123 G_GNUC_PRINTF(2, 3)
124 static void
125 output_config_error(void *ctx, const char *msg, ...)
126 {
127 va_list ap;
128 char *buf = NULL;
129 pcmk__output_t *out = ctx;
130
131 va_start(ap, msg);
132 pcmk__assert(vasprintf(&buf, msg, ap) > 0);
133 if (options.verbosity > 0) {
134 out->err(out, "error: %s", buf);
135 }
136 va_end(ap);
137 }
138
139
140
141
142
143
144
145
146
147 G_GNUC_PRINTF(2, 3)
148 static void
149 output_config_warning(void *ctx, const char *msg, ...)
150 {
151 va_list ap;
152 char *buf = NULL;
153 pcmk__output_t *out = ctx;
154
155 va_start(ap, msg);
156 pcmk__assert(vasprintf(&buf, msg, ap) > 0);
157 if (options.verbosity > 0) {
158 out->err(out, "warning: %s", buf);
159 }
160 va_end(ap);
161 }
162
163 int
164 main(int argc, char **argv)
165 {
166
167 pcmk_scheduler_t *scheduler = NULL;
168
169 int rc = pcmk_rc_ok;
170 crm_exit_t exit_code = CRM_EX_OK;
171
172 GError *error = NULL;
173
174 pcmk__output_t *out = NULL;
175
176 const char *cib_source = NULL;
177 xmlNode *cib_object = NULL;
178
179 GOptionGroup *output_group = NULL;
180
181 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
182 gchar **processed_args = pcmk__cmdline_preproc(argv, "xSX");
183 GOptionContext *context = build_arg_context(args, &output_group);
184
185 pcmk__register_formats(output_group, formats);
186 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
187 exit_code = CRM_EX_USAGE;
188 goto done;
189 }
190
191 if (args->verbosity > 0) {
192 args->verbosity -= args->quiet;
193 }
194
195 pcmk__cli_init_logging("crm_verify", args->verbosity);
196
197 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
198 if (rc != pcmk_rc_ok) {
199 exit_code = CRM_EX_ERROR;
200 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
201 "Error creating output format %s: %s",
202 args->output_ty, pcmk_rc_str(rc));
203 goto done;
204 }
205
206 if (args->version) {
207 out->version(out, false);
208 goto done;
209 }
210
211 pcmk__register_lib_messages(out);
212
213 pcmk__set_config_error_handler(output_config_error, out);
214 pcmk__set_config_warning_handler(output_config_warning, out);
215
216 if (pcmk__str_eq(args->output_ty, "xml", pcmk__str_none)) {
217 args->verbosity = 1;
218 }
219 options.verbosity = args->verbosity;
220
221 if (options.xml_file != NULL) {
222 cib_source = options.xml_file;
223 } else if (options.xml_string != NULL) {
224 cib_source = options.xml_string;
225 } else if (options.xml_stdin) {
226 cib_source = "-";
227 } else if (options.use_live_cib) {
228 cib_source = NULL;
229 } else {
230 rc = ENODATA;
231 g_set_error(&error, PCMK__RC_ERROR, rc, "No input specified");
232 goto done;
233 }
234
235 rc = pcmk__parse_cib(out, cib_source, &cib_object);
236 if (rc != pcmk_rc_ok) {
237 g_set_error(&error, PCMK__RC_ERROR, rc, "Verification failed: %s",
238 pcmk_rc_str(rc));
239 goto done;
240 }
241
242 if (options.cib_save != NULL) {
243 pcmk__xml_write_file(cib_object, options.cib_save, false);
244 }
245
246 scheduler = pcmk_new_scheduler();
247 if (scheduler == NULL) {
248 rc = errno;
249 g_set_error(&error, PCMK__RC_ERROR, rc,
250 "Could not allocate scheduler data: %s", pcmk_rc_str(rc));
251 goto done;
252 }
253
254 scheduler->priv->out = out;
255
256 rc = pcmk__verify(scheduler, out, &cib_object);
257
258 if ((rc == pcmk_rc_schema_validation) && !args->quiet) {
259 const char *failure_type = "";
260 const char *verbose_hint = "";
261
262 if (pcmk__config_has_error) {
263 failure_type = " (with errors)";
264 } else if (pcmk__config_has_warning) {
265 failure_type = " (with warnings)";
266 }
267 if (options.verbosity == 0) {
268 verbose_hint = " (-V may provide more detail)";
269 }
270 out->err(out, "Configuration invalid%s%s", failure_type, verbose_hint);
271 }
272
273 pcmk_free_scheduler(scheduler);
274
275 done:
276 g_strfreev(processed_args);
277 pcmk__free_arg_context(context);
278 free(options.cib_save);
279 free(options.xml_file);
280 free(options.xml_string);
281
282 if (cib_object != NULL) {
283 pcmk__xml_free(cib_object);
284 }
285
286 if (exit_code == CRM_EX_OK) {
287 exit_code = pcmk_rc2exitc(rc);
288 }
289
290 pcmk__output_and_clear_error(&error, out);
291
292 if (out != NULL) {
293 out->finish(out, exit_code, true, NULL);
294 pcmk__output_free(out);
295 }
296
297 pcmk__unregister_formats();
298 crm_exit(exit_code);
299 }