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 = pe_new_working_set();
247
248 if (scheduler == NULL) {
249 rc = errno;
250 g_set_error(&error, PCMK__RC_ERROR, rc,
251 "Could not allocate scheduler data: %s", pcmk_rc_str(rc));
252 goto done;
253 }
254
255 scheduler->priv->out = out;
256
257 rc = pcmk__verify(scheduler, out, &cib_object);
258
259 if ((rc == pcmk_rc_schema_validation) && !args->quiet) {
260 const char *failure_type = "";
261 const char *verbose_hint = "";
262
263 if (pcmk__config_has_error) {
264 failure_type = " (with errors)";
265 } else if (pcmk__config_has_warning) {
266 failure_type = " (with warnings)";
267 }
268 if (options.verbosity == 0) {
269 verbose_hint = " (-V may provide more detail)";
270 }
271 out->err(out, "Configuration invalid%s%s", failure_type, verbose_hint);
272 }
273
274 pe_free_working_set(scheduler);
275
276 done:
277 g_strfreev(processed_args);
278 pcmk__free_arg_context(context);
279 free(options.cib_save);
280 free(options.xml_file);
281 free(options.xml_string);
282
283 if (cib_object != NULL) {
284 pcmk__xml_free(cib_object);
285 }
286
287 if (exit_code == CRM_EX_OK) {
288 exit_code = pcmk_rc2exitc(rc);
289 }
290
291 pcmk__output_and_clear_error(&error, out);
292
293 if (out != NULL) {
294 out->finish(out, exit_code, true, NULL);
295 pcmk__output_free(out);
296 }
297
298 pcmk__unregister_formats();
299 crm_exit(exit_code);
300 }