Line data Source code
1 : /*
2 : * Copyright 2004-2024 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 Lesser General Public License
7 : * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 : */
9 :
10 : #include <crm_internal.h>
11 :
12 : #ifndef _GNU_SOURCE
13 : # define _GNU_SOURCE
14 : #endif
15 :
16 : #include <bzlib.h>
17 : #include <errno.h>
18 : #include <netdb.h>
19 : #include <stdlib.h>
20 : #include <string.h>
21 : #include <qb/qbdefs.h>
22 :
23 : #include <crm/common/mainloop.h>
24 : #include <crm/common/xml.h>
25 :
26 0 : G_DEFINE_QUARK(pcmk-rc-error-quark, pcmk__rc_error)
27 0 : G_DEFINE_QUARK(pcmk-exitc-error-quark, pcmk__exitc_error)
28 :
29 : // General (all result code types)
30 :
31 : /*!
32 : * \brief Get the name and description of a given result code
33 : *
34 : * A result code can be interpreted as a member of any one of several families.
35 : *
36 : * \param[in] code The result code to look up
37 : * \param[in] type How \p code should be interpreted
38 : * \param[out] name Where to store the result code's name
39 : * \param[out] desc Where to store the result code's description
40 : *
41 : * \return Standard Pacemaker return code
42 : */
43 : int
44 0 : pcmk_result_get_strings(int code, enum pcmk_result_type type, const char **name,
45 : const char **desc)
46 : {
47 0 : const char *code_name = NULL;
48 0 : const char *code_desc = NULL;
49 :
50 0 : switch (type) {
51 0 : case pcmk_result_legacy:
52 0 : code_name = pcmk_errorname(code);
53 0 : code_desc = pcmk_strerror(code);
54 0 : break;
55 0 : case pcmk_result_rc:
56 0 : code_name = pcmk_rc_name(code);
57 0 : code_desc = pcmk_rc_str(code);
58 0 : break;
59 0 : case pcmk_result_exitcode:
60 0 : code_name = crm_exit_name(code);
61 0 : code_desc = crm_exit_str((crm_exit_t) code);
62 0 : break;
63 0 : default:
64 0 : return pcmk_rc_undetermined;
65 : }
66 :
67 0 : if (name != NULL) {
68 0 : *name = code_name;
69 : }
70 :
71 0 : if (desc != NULL) {
72 0 : *desc = code_desc;
73 : }
74 0 : return pcmk_rc_ok;
75 : }
76 :
77 : /*!
78 : * \internal
79 : * \brief Get the lower and upper bounds of a result code family
80 : *
81 : * \param[in] type Type of result code
82 : * \param[out] lower Where to store the lower bound
83 : * \param[out] upper Where to store the upper bound
84 : *
85 : * \return Standard Pacemaker return code
86 : *
87 : * \note There is no true upper bound on standard Pacemaker return codes or
88 : * legacy return codes. All system \p errno values are valid members of
89 : * these result code families, and there is no global upper limit nor a
90 : * constant by which to refer to the highest \p errno value on a given
91 : * system.
92 : */
93 : int
94 0 : pcmk__result_bounds(enum pcmk_result_type type, int *lower, int *upper)
95 : {
96 0 : CRM_ASSERT((lower != NULL) && (upper != NULL));
97 :
98 0 : switch (type) {
99 0 : case pcmk_result_legacy:
100 0 : *lower = pcmk_ok;
101 0 : *upper = 256; // should be enough for almost any system error code
102 0 : break;
103 0 : case pcmk_result_rc:
104 0 : *lower = pcmk_rc_error - pcmk__n_rc + 1;
105 0 : *upper = 256;
106 0 : break;
107 0 : case pcmk_result_exitcode:
108 0 : *lower = CRM_EX_OK;
109 0 : *upper = CRM_EX_MAX;
110 0 : break;
111 0 : default:
112 0 : *lower = 0;
113 0 : *upper = -1;
114 0 : return pcmk_rc_undetermined;
115 : }
116 0 : return pcmk_rc_ok;
117 : }
118 :
119 : // @COMPAT Legacy function return codes
120 :
121 : //! \deprecated Use standard return codes and pcmk_rc_name() instead
122 : const char *
123 0 : pcmk_errorname(int rc)
124 : {
125 0 : rc = abs(rc);
126 0 : switch (rc) {
127 0 : case pcmk_err_generic: return "pcmk_err_generic";
128 0 : case pcmk_err_no_quorum: return "pcmk_err_no_quorum";
129 0 : case pcmk_err_schema_validation: return "pcmk_err_schema_validation";
130 0 : case pcmk_err_transform_failed: return "pcmk_err_transform_failed";
131 0 : case pcmk_err_old_data: return "pcmk_err_old_data";
132 0 : case pcmk_err_diff_failed: return "pcmk_err_diff_failed";
133 0 : case pcmk_err_diff_resync: return "pcmk_err_diff_resync";
134 0 : case pcmk_err_cib_modified: return "pcmk_err_cib_modified";
135 0 : case pcmk_err_cib_backup: return "pcmk_err_cib_backup";
136 0 : case pcmk_err_cib_save: return "pcmk_err_cib_save";
137 0 : case pcmk_err_cib_corrupt: return "pcmk_err_cib_corrupt";
138 0 : case pcmk_err_multiple: return "pcmk_err_multiple";
139 0 : case pcmk_err_node_unknown: return "pcmk_err_node_unknown";
140 0 : case pcmk_err_already: return "pcmk_err_already";
141 0 : case pcmk_err_bad_nvpair: return "pcmk_err_bad_nvpair";
142 0 : case pcmk_err_unknown_format: return "pcmk_err_unknown_format";
143 0 : default: return pcmk_rc_name(rc); // system errno
144 : }
145 : }
146 :
147 : //! \deprecated Use standard return codes and pcmk_rc_str() instead
148 : const char *
149 0 : pcmk_strerror(int rc)
150 : {
151 0 : return pcmk_rc_str(pcmk_legacy2rc(rc));
152 : }
153 :
154 : // Standard Pacemaker API return codes
155 :
156 : /* This array is used only for nonzero values of pcmk_rc_e. Its values must be
157 : * kept in the exact reverse order of the enum value numbering (i.e. add new
158 : * values to the end of the array).
159 : */
160 : static const struct pcmk__rc_info {
161 : const char *name;
162 : const char *desc;
163 : int legacy_rc;
164 : } pcmk__rcs[] = {
165 : { "pcmk_rc_error",
166 : "Error",
167 : -pcmk_err_generic,
168 : },
169 : { "pcmk_rc_unknown_format",
170 : "Unknown output format",
171 : -pcmk_err_unknown_format,
172 : },
173 : { "pcmk_rc_bad_nvpair",
174 : "Bad name/value pair given",
175 : -pcmk_err_bad_nvpair,
176 : },
177 : { "pcmk_rc_already",
178 : "Already in requested state",
179 : -pcmk_err_already,
180 : },
181 : { "pcmk_rc_node_unknown",
182 : "Node not found",
183 : -pcmk_err_node_unknown,
184 : },
185 : { "pcmk_rc_multiple",
186 : "Resource active on multiple nodes",
187 : -pcmk_err_multiple,
188 : },
189 : { "pcmk_rc_cib_corrupt",
190 : "Could not parse on-disk configuration",
191 : -pcmk_err_cib_corrupt,
192 : },
193 : { "pcmk_rc_cib_save",
194 : "Could not save new configuration to disk",
195 : -pcmk_err_cib_save,
196 : },
197 : { "pcmk_rc_cib_backup",
198 : "Could not archive previous configuration",
199 : -pcmk_err_cib_backup,
200 : },
201 : { "pcmk_rc_cib_modified",
202 : "On-disk configuration was manually modified",
203 : -pcmk_err_cib_modified,
204 : },
205 : { "pcmk_rc_diff_resync",
206 : "Application of update diff failed, requesting full refresh",
207 : -pcmk_err_diff_resync,
208 : },
209 : { "pcmk_rc_diff_failed",
210 : "Application of update diff failed",
211 : -pcmk_err_diff_failed,
212 : },
213 : { "pcmk_rc_old_data",
214 : "Update was older than existing configuration",
215 : -pcmk_err_old_data,
216 : },
217 : { "pcmk_rc_transform_failed",
218 : "Schema transform failed",
219 : -pcmk_err_transform_failed,
220 : },
221 : { "pcmk_rc_schema_unchanged",
222 : "Schema is already the latest available",
223 : -pcmk_err_schema_unchanged,
224 : },
225 : { "pcmk_rc_schema_validation",
226 : "Update does not conform to the configured schema",
227 : -pcmk_err_schema_validation,
228 : },
229 : { "pcmk_rc_no_quorum",
230 : "Operation requires quorum",
231 : -pcmk_err_no_quorum,
232 : },
233 : { "pcmk_rc_ipc_unauthorized",
234 : "IPC server is blocked by unauthorized process",
235 : -pcmk_err_generic,
236 : },
237 : { "pcmk_rc_ipc_unresponsive",
238 : "IPC server is unresponsive",
239 : -pcmk_err_generic,
240 : },
241 : { "pcmk_rc_ipc_pid_only",
242 : "IPC server process is active but not accepting connections",
243 : -pcmk_err_generic,
244 : },
245 : { "pcmk_rc_op_unsatisfied",
246 : "Not applicable under current conditions",
247 : -pcmk_err_generic,
248 : },
249 : { "pcmk_rc_undetermined",
250 : "Result undetermined",
251 : -pcmk_err_generic,
252 : },
253 : { "pcmk_rc_before_range",
254 : "Result occurs before given range",
255 : -pcmk_err_generic,
256 : },
257 : { "pcmk_rc_within_range",
258 : "Result occurs within given range",
259 : -pcmk_err_generic,
260 : },
261 : { "pcmk_rc_after_range",
262 : "Result occurs after given range",
263 : -pcmk_err_generic,
264 : },
265 : { "pcmk_rc_no_output",
266 : "Output message produced no output",
267 : -pcmk_err_generic,
268 : },
269 : { "pcmk_rc_no_input",
270 : "Input file not available",
271 : -pcmk_err_generic,
272 : },
273 : { "pcmk_rc_underflow",
274 : "Value too small to be stored in data type",
275 : -pcmk_err_generic,
276 : },
277 : { "pcmk_rc_dot_error",
278 : "Error writing dot(1) file",
279 : -pcmk_err_generic,
280 : },
281 : { "pcmk_rc_graph_error",
282 : "Error writing graph file",
283 : -pcmk_err_generic,
284 : },
285 : { "pcmk_rc_invalid_transition",
286 : "Cluster simulation produced invalid transition",
287 : -pcmk_err_generic,
288 : },
289 : { "pcmk_rc_unpack_error",
290 : "Unable to parse CIB XML",
291 : -pcmk_err_generic,
292 : },
293 : { "pcmk_rc_duplicate_id",
294 : "Two or more XML elements have the same ID",
295 : -pcmk_err_generic,
296 : },
297 : { "pcmk_rc_disabled",
298 : "Disabled",
299 : -pcmk_err_generic,
300 : },
301 : { "pcmk_rc_bad_input",
302 : "Bad input value provided",
303 : -pcmk_err_generic,
304 : },
305 : { "pcmk_rc_bad_xml_patch",
306 : "Bad XML patch format",
307 : -pcmk_err_generic,
308 : },
309 : { "pcmk_rc_no_transaction",
310 : "No active transaction found",
311 : -pcmk_err_generic,
312 : },
313 : { "pcmk_rc_ns_resolution",
314 : "Nameserver resolution error",
315 : -pcmk_err_generic,
316 : },
317 : { "pcmk_rc_compression",
318 : "Compression/decompression error",
319 : -pcmk_err_generic,
320 : },
321 : };
322 :
323 : /*!
324 : * \internal
325 : * \brief The number of <tt>enum pcmk_rc_e</tt> values, excluding \c pcmk_rc_ok
326 : *
327 : * This constant stores the number of negative standard Pacemaker return codes.
328 : * These represent Pacemaker-custom error codes. The count does not include
329 : * positive system error numbers, nor does it include \c pcmk_rc_ok (success).
330 : */
331 : const size_t pcmk__n_rc = PCMK__NELEM(pcmk__rcs);
332 :
333 : /*!
334 : * \brief Get a return code constant name as a string
335 : *
336 : * \param[in] rc Integer return code to convert
337 : *
338 : * \return String of constant name corresponding to rc
339 : */
340 : const char *
341 4 : pcmk_rc_name(int rc)
342 : {
343 4 : if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < pcmk__n_rc)) {
344 1 : return pcmk__rcs[pcmk_rc_error - rc].name;
345 : }
346 3 : switch (rc) {
347 2 : case pcmk_rc_ok: return "pcmk_rc_ok";
348 0 : case E2BIG: return "E2BIG";
349 0 : case EACCES: return "EACCES";
350 0 : case EADDRINUSE: return "EADDRINUSE";
351 0 : case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
352 0 : case EAFNOSUPPORT: return "EAFNOSUPPORT";
353 0 : case EAGAIN: return "EAGAIN";
354 0 : case EALREADY: return "EALREADY";
355 0 : case EBADF: return "EBADF";
356 0 : case EBADMSG: return "EBADMSG";
357 0 : case EBUSY: return "EBUSY";
358 0 : case ECANCELED: return "ECANCELED";
359 0 : case ECHILD: return "ECHILD";
360 0 : case ECOMM: return "ECOMM";
361 0 : case ECONNABORTED: return "ECONNABORTED";
362 0 : case ECONNREFUSED: return "ECONNREFUSED";
363 0 : case ECONNRESET: return "ECONNRESET";
364 : /* case EDEADLK: return "EDEADLK"; */
365 0 : case EDESTADDRREQ: return "EDESTADDRREQ";
366 0 : case EDOM: return "EDOM";
367 0 : case EDQUOT: return "EDQUOT";
368 0 : case EEXIST: return "EEXIST";
369 0 : case EFAULT: return "EFAULT";
370 0 : case EFBIG: return "EFBIG";
371 0 : case EHOSTDOWN: return "EHOSTDOWN";
372 0 : case EHOSTUNREACH: return "EHOSTUNREACH";
373 0 : case EIDRM: return "EIDRM";
374 0 : case EILSEQ: return "EILSEQ";
375 0 : case EINPROGRESS: return "EINPROGRESS";
376 0 : case EINTR: return "EINTR";
377 0 : case EINVAL: return "EINVAL";
378 0 : case EIO: return "EIO";
379 0 : case EISCONN: return "EISCONN";
380 0 : case EISDIR: return "EISDIR";
381 0 : case ELIBACC: return "ELIBACC";
382 0 : case ELOOP: return "ELOOP";
383 0 : case EMFILE: return "EMFILE";
384 0 : case EMLINK: return "EMLINK";
385 0 : case EMSGSIZE: return "EMSGSIZE";
386 : #ifdef EMULTIHOP // Not available on OpenBSD
387 0 : case EMULTIHOP: return "EMULTIHOP";
388 : #endif
389 0 : case ENAMETOOLONG: return "ENAMETOOLONG";
390 0 : case ENETDOWN: return "ENETDOWN";
391 0 : case ENETRESET: return "ENETRESET";
392 0 : case ENETUNREACH: return "ENETUNREACH";
393 0 : case ENFILE: return "ENFILE";
394 0 : case ENOBUFS: return "ENOBUFS";
395 0 : case ENODATA: return "ENODATA";
396 0 : case ENODEV: return "ENODEV";
397 0 : case ENOENT: return "ENOENT";
398 0 : case ENOEXEC: return "ENOEXEC";
399 0 : case ENOKEY: return "ENOKEY";
400 0 : case ENOLCK: return "ENOLCK";
401 : #ifdef ENOLINK // Not available on OpenBSD
402 0 : case ENOLINK: return "ENOLINK";
403 : #endif
404 0 : case ENOMEM: return "ENOMEM";
405 0 : case ENOMSG: return "ENOMSG";
406 0 : case ENOPROTOOPT: return "ENOPROTOOPT";
407 0 : case ENOSPC: return "ENOSPC";
408 : #ifdef ENOSR
409 0 : case ENOSR: return "ENOSR";
410 : #endif
411 : #ifdef ENOSTR
412 0 : case ENOSTR: return "ENOSTR";
413 : #endif
414 0 : case ENOSYS: return "ENOSYS";
415 0 : case ENOTBLK: return "ENOTBLK";
416 0 : case ENOTCONN: return "ENOTCONN";
417 0 : case ENOTDIR: return "ENOTDIR";
418 0 : case ENOTEMPTY: return "ENOTEMPTY";
419 0 : case ENOTSOCK: return "ENOTSOCK";
420 : #if ENOTSUP != EOPNOTSUPP
421 : case ENOTSUP: return "ENOTSUP";
422 : #endif
423 0 : case ENOTTY: return "ENOTTY";
424 0 : case ENOTUNIQ: return "ENOTUNIQ";
425 0 : case ENXIO: return "ENXIO";
426 0 : case EOPNOTSUPP: return "EOPNOTSUPP";
427 0 : case EOVERFLOW: return "EOVERFLOW";
428 0 : case EPERM: return "EPERM";
429 0 : case EPFNOSUPPORT: return "EPFNOSUPPORT";
430 0 : case EPIPE: return "EPIPE";
431 0 : case EPROTO: return "EPROTO";
432 0 : case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
433 0 : case EPROTOTYPE: return "EPROTOTYPE";
434 0 : case ERANGE: return "ERANGE";
435 0 : case EREMOTE: return "EREMOTE";
436 0 : case EREMOTEIO: return "EREMOTEIO";
437 0 : case EROFS: return "EROFS";
438 0 : case ESHUTDOWN: return "ESHUTDOWN";
439 0 : case ESPIPE: return "ESPIPE";
440 0 : case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
441 0 : case ESRCH: return "ESRCH";
442 0 : case ESTALE: return "ESTALE";
443 0 : case ETIME: return "ETIME";
444 0 : case ETIMEDOUT: return "ETIMEDOUT";
445 0 : case ETXTBSY: return "ETXTBSY";
446 : #ifdef EUNATCH
447 0 : case EUNATCH: return "EUNATCH";
448 : #endif
449 0 : case EUSERS: return "EUSERS";
450 : /* case EWOULDBLOCK: return "EWOULDBLOCK"; */
451 0 : case EXDEV: return "EXDEV";
452 :
453 : #ifdef EBADE // Not available on OS X
454 0 : case EBADE: return "EBADE";
455 0 : case EBADFD: return "EBADFD";
456 0 : case EBADSLT: return "EBADSLT";
457 0 : case EDEADLOCK: return "EDEADLOCK";
458 0 : case EBADR: return "EBADR";
459 0 : case EBADRQC: return "EBADRQC";
460 0 : case ECHRNG: return "ECHRNG";
461 : #ifdef EISNAM // Not available on OS X, Illumos, Solaris
462 0 : case EISNAM: return "EISNAM";
463 0 : case EKEYEXPIRED: return "EKEYEXPIRED";
464 0 : case EKEYREVOKED: return "EKEYREVOKED";
465 : #endif
466 0 : case EKEYREJECTED: return "EKEYREJECTED";
467 0 : case EL2HLT: return "EL2HLT";
468 0 : case EL2NSYNC: return "EL2NSYNC";
469 0 : case EL3HLT: return "EL3HLT";
470 0 : case EL3RST: return "EL3RST";
471 0 : case ELIBBAD: return "ELIBBAD";
472 0 : case ELIBMAX: return "ELIBMAX";
473 0 : case ELIBSCN: return "ELIBSCN";
474 0 : case ELIBEXEC: return "ELIBEXEC";
475 : #ifdef ENOMEDIUM // Not available on OS X, Illumos, Solaris
476 0 : case ENOMEDIUM: return "ENOMEDIUM";
477 0 : case EMEDIUMTYPE: return "EMEDIUMTYPE";
478 : #endif
479 0 : case ENONET: return "ENONET";
480 0 : case ENOPKG: return "ENOPKG";
481 0 : case EREMCHG: return "EREMCHG";
482 0 : case ERESTART: return "ERESTART";
483 0 : case ESTRPIPE: return "ESTRPIPE";
484 : #ifdef EUCLEAN // Not available on OS X, Illumos, Solaris
485 0 : case EUCLEAN: return "EUCLEAN";
486 : #endif
487 0 : case EXFULL: return "EXFULL";
488 : #endif // EBADE
489 1 : default: return "Unknown";
490 : }
491 : }
492 :
493 : /*!
494 : * \brief Get a user-friendly description of a return code
495 : *
496 : * \param[in] rc Integer return code to convert
497 : *
498 : * \return String description of rc
499 : */
500 : const char *
501 15 : pcmk_rc_str(int rc)
502 : {
503 15 : if (rc == pcmk_rc_ok) {
504 1 : return "OK";
505 : }
506 14 : if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < pcmk__n_rc)) {
507 1 : return pcmk__rcs[pcmk_rc_error - rc].desc;
508 : }
509 13 : if (rc < 0) {
510 1 : return "Error";
511 : }
512 :
513 : // Handle values that could be defined by system or by portability.h
514 : switch (rc) {
515 : #ifdef PCMK__ENOTUNIQ
516 : case ENOTUNIQ: return "Name not unique on network";
517 : #endif
518 : #ifdef PCMK__ECOMM
519 : case ECOMM: return "Communication error on send";
520 : #endif
521 : #ifdef PCMK__ELIBACC
522 : case ELIBACC: return "Can not access a needed shared library";
523 : #endif
524 : #ifdef PCMK__EREMOTEIO
525 : case EREMOTEIO: return "Remote I/O error";
526 : #endif
527 : #ifdef PCMK__ENOKEY
528 : case ENOKEY: return "Required key not available";
529 : #endif
530 : #ifdef PCMK__ENODATA
531 : case ENODATA: return "No data available";
532 : #endif
533 : #ifdef PCMK__ETIME
534 : case ETIME: return "Timer expired";
535 : #endif
536 : #ifdef PCMK__EKEYREJECTED
537 : case EKEYREJECTED: return "Key was rejected by service";
538 : #endif
539 12 : default: return strerror(rc);
540 : }
541 : }
542 :
543 : // This returns negative values for errors
544 : //! \deprecated Use standard return codes instead
545 : int
546 0 : pcmk_rc2legacy(int rc)
547 : {
548 0 : if (rc >= 0) {
549 0 : return -rc; // OK or system errno
550 : }
551 0 : if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < pcmk__n_rc)) {
552 0 : return pcmk__rcs[pcmk_rc_error - rc].legacy_rc;
553 : }
554 0 : return -pcmk_err_generic;
555 : }
556 :
557 : //! \deprecated Use standard return codes instead
558 : int
559 0 : pcmk_legacy2rc(int legacy_rc)
560 : {
561 0 : legacy_rc = abs(legacy_rc);
562 0 : switch (legacy_rc) {
563 0 : case pcmk_err_no_quorum: return pcmk_rc_no_quorum;
564 0 : case pcmk_err_schema_validation: return pcmk_rc_schema_validation;
565 0 : case pcmk_err_schema_unchanged: return pcmk_rc_schema_unchanged;
566 0 : case pcmk_err_transform_failed: return pcmk_rc_transform_failed;
567 0 : case pcmk_err_old_data: return pcmk_rc_old_data;
568 0 : case pcmk_err_diff_failed: return pcmk_rc_diff_failed;
569 0 : case pcmk_err_diff_resync: return pcmk_rc_diff_resync;
570 0 : case pcmk_err_cib_modified: return pcmk_rc_cib_modified;
571 0 : case pcmk_err_cib_backup: return pcmk_rc_cib_backup;
572 0 : case pcmk_err_cib_save: return pcmk_rc_cib_save;
573 0 : case pcmk_err_cib_corrupt: return pcmk_rc_cib_corrupt;
574 0 : case pcmk_err_multiple: return pcmk_rc_multiple;
575 0 : case pcmk_err_node_unknown: return pcmk_rc_node_unknown;
576 0 : case pcmk_err_already: return pcmk_rc_already;
577 0 : case pcmk_err_bad_nvpair: return pcmk_rc_bad_nvpair;
578 0 : case pcmk_err_unknown_format: return pcmk_rc_unknown_format;
579 0 : case pcmk_err_generic: return pcmk_rc_error;
580 0 : case pcmk_ok: return pcmk_rc_ok;
581 0 : default: return legacy_rc; // system errno
582 : }
583 : }
584 :
585 : // Exit status codes
586 :
587 : const char *
588 1 : crm_exit_name(crm_exit_t exit_code)
589 : {
590 1 : switch (exit_code) {
591 1 : case CRM_EX_OK: return "CRM_EX_OK";
592 0 : case CRM_EX_ERROR: return "CRM_EX_ERROR";
593 0 : case CRM_EX_INVALID_PARAM: return "CRM_EX_INVALID_PARAM";
594 0 : case CRM_EX_UNIMPLEMENT_FEATURE: return "CRM_EX_UNIMPLEMENT_FEATURE";
595 0 : case CRM_EX_INSUFFICIENT_PRIV: return "CRM_EX_INSUFFICIENT_PRIV";
596 0 : case CRM_EX_NOT_INSTALLED: return "CRM_EX_NOT_INSTALLED";
597 0 : case CRM_EX_NOT_CONFIGURED: return "CRM_EX_NOT_CONFIGURED";
598 0 : case CRM_EX_NOT_RUNNING: return "CRM_EX_NOT_RUNNING";
599 0 : case CRM_EX_PROMOTED: return "CRM_EX_PROMOTED";
600 0 : case CRM_EX_FAILED_PROMOTED: return "CRM_EX_FAILED_PROMOTED";
601 0 : case CRM_EX_USAGE: return "CRM_EX_USAGE";
602 0 : case CRM_EX_DATAERR: return "CRM_EX_DATAERR";
603 0 : case CRM_EX_NOINPUT: return "CRM_EX_NOINPUT";
604 0 : case CRM_EX_NOUSER: return "CRM_EX_NOUSER";
605 0 : case CRM_EX_NOHOST: return "CRM_EX_NOHOST";
606 0 : case CRM_EX_UNAVAILABLE: return "CRM_EX_UNAVAILABLE";
607 0 : case CRM_EX_SOFTWARE: return "CRM_EX_SOFTWARE";
608 0 : case CRM_EX_OSERR: return "CRM_EX_OSERR";
609 0 : case CRM_EX_OSFILE: return "CRM_EX_OSFILE";
610 0 : case CRM_EX_CANTCREAT: return "CRM_EX_CANTCREAT";
611 0 : case CRM_EX_IOERR: return "CRM_EX_IOERR";
612 0 : case CRM_EX_TEMPFAIL: return "CRM_EX_TEMPFAIL";
613 0 : case CRM_EX_PROTOCOL: return "CRM_EX_PROTOCOL";
614 0 : case CRM_EX_NOPERM: return "CRM_EX_NOPERM";
615 0 : case CRM_EX_CONFIG: return "CRM_EX_CONFIG";
616 0 : case CRM_EX_FATAL: return "CRM_EX_FATAL";
617 0 : case CRM_EX_PANIC: return "CRM_EX_PANIC";
618 0 : case CRM_EX_DISCONNECT: return "CRM_EX_DISCONNECT";
619 0 : case CRM_EX_DIGEST: return "CRM_EX_DIGEST";
620 0 : case CRM_EX_NOSUCH: return "CRM_EX_NOSUCH";
621 0 : case CRM_EX_QUORUM: return "CRM_EX_QUORUM";
622 0 : case CRM_EX_UNSAFE: return "CRM_EX_UNSAFE";
623 0 : case CRM_EX_EXISTS: return "CRM_EX_EXISTS";
624 0 : case CRM_EX_MULTIPLE: return "CRM_EX_MULTIPLE";
625 0 : case CRM_EX_EXPIRED: return "CRM_EX_EXPIRED";
626 0 : case CRM_EX_NOT_YET_IN_EFFECT: return "CRM_EX_NOT_YET_IN_EFFECT";
627 0 : case CRM_EX_INDETERMINATE: return "CRM_EX_INDETERMINATE";
628 0 : case CRM_EX_UNSATISFIED: return "CRM_EX_UNSATISFIED";
629 0 : case CRM_EX_OLD: return "CRM_EX_OLD";
630 0 : case CRM_EX_TIMEOUT: return "CRM_EX_TIMEOUT";
631 0 : case CRM_EX_DEGRADED: return "CRM_EX_DEGRADED";
632 0 : case CRM_EX_DEGRADED_PROMOTED: return "CRM_EX_DEGRADED_PROMOTED";
633 0 : case CRM_EX_NONE: return "CRM_EX_NONE";
634 0 : case CRM_EX_MAX: return "CRM_EX_UNKNOWN";
635 : }
636 0 : return "CRM_EX_UNKNOWN";
637 : }
638 :
639 : const char *
640 55 : crm_exit_str(crm_exit_t exit_code)
641 : {
642 55 : switch (exit_code) {
643 29 : case CRM_EX_OK: return "OK";
644 0 : case CRM_EX_ERROR: return "Error occurred";
645 0 : case CRM_EX_INVALID_PARAM: return "Invalid parameter";
646 0 : case CRM_EX_UNIMPLEMENT_FEATURE: return "Unimplemented";
647 4 : case CRM_EX_INSUFFICIENT_PRIV: return "Insufficient privileges";
648 0 : case CRM_EX_NOT_INSTALLED: return "Not installed";
649 0 : case CRM_EX_NOT_CONFIGURED: return "Not configured";
650 0 : case CRM_EX_NOT_RUNNING: return "Not running";
651 0 : case CRM_EX_PROMOTED: return "Promoted";
652 0 : case CRM_EX_FAILED_PROMOTED: return "Failed in promoted role";
653 0 : case CRM_EX_USAGE: return "Incorrect usage";
654 0 : case CRM_EX_DATAERR: return "Invalid data given";
655 0 : case CRM_EX_NOINPUT: return "Input file not available";
656 0 : case CRM_EX_NOUSER: return "User does not exist";
657 0 : case CRM_EX_NOHOST: return "Host does not exist";
658 0 : case CRM_EX_UNAVAILABLE: return "Necessary service unavailable";
659 7 : case CRM_EX_SOFTWARE: return "Internal software bug";
660 0 : case CRM_EX_OSERR: return "Operating system error occurred";
661 0 : case CRM_EX_OSFILE: return "System file not available";
662 0 : case CRM_EX_CANTCREAT: return "Cannot create output file";
663 0 : case CRM_EX_IOERR: return "I/O error occurred";
664 0 : case CRM_EX_TEMPFAIL: return "Temporary failure, try again";
665 0 : case CRM_EX_PROTOCOL: return "Protocol violated";
666 0 : case CRM_EX_NOPERM: return "Insufficient privileges";
667 0 : case CRM_EX_CONFIG: return "Invalid configuration";
668 0 : case CRM_EX_FATAL: return "Fatal error occurred, will not respawn";
669 0 : case CRM_EX_PANIC: return "System panic required";
670 6 : case CRM_EX_DISCONNECT: return "Not connected";
671 0 : case CRM_EX_DIGEST: return "Digest mismatch";
672 6 : case CRM_EX_NOSUCH: return "No such object";
673 0 : case CRM_EX_QUORUM: return "Quorum required";
674 0 : case CRM_EX_UNSAFE: return "Operation not safe";
675 0 : case CRM_EX_EXISTS: return "Requested item already exists";
676 1 : case CRM_EX_MULTIPLE: return "Multiple items match request";
677 0 : case CRM_EX_EXPIRED: return "Requested item has expired";
678 0 : case CRM_EX_NOT_YET_IN_EFFECT: return "Requested item is not yet in effect";
679 0 : case CRM_EX_INDETERMINATE: return "Could not determine status";
680 0 : case CRM_EX_UNSATISFIED: return "Not applicable under current conditions";
681 0 : case CRM_EX_OLD: return "Update was older than existing configuration";
682 0 : case CRM_EX_TIMEOUT: return "Timeout occurred";
683 0 : case CRM_EX_DEGRADED: return "Service is active but might fail soon";
684 0 : case CRM_EX_DEGRADED_PROMOTED: return "Service is promoted but might fail soon";
685 0 : case CRM_EX_NONE: return "No exit status available";
686 0 : case CRM_EX_MAX: return "Error occurred";
687 : }
688 2 : if ((exit_code > 128) && (exit_code < CRM_EX_MAX)) {
689 1 : return "Interrupted by signal";
690 : }
691 1 : return "Unknown exit status";
692 : }
693 :
694 : /*!
695 : * \brief Map a function return code to the most similar exit code
696 : *
697 : * \param[in] rc Function return code
698 : *
699 : * \return Most similar exit code
700 : */
701 : crm_exit_t
702 67 : pcmk_rc2exitc(int rc)
703 : {
704 67 : switch (rc) {
705 31 : case pcmk_rc_ok:
706 : case pcmk_rc_no_output: // quiet mode, or nothing to output
707 31 : return CRM_EX_OK;
708 :
709 0 : case pcmk_rc_no_quorum:
710 0 : return CRM_EX_QUORUM;
711 :
712 0 : case pcmk_rc_old_data:
713 0 : return CRM_EX_OLD;
714 :
715 0 : case pcmk_rc_schema_validation:
716 : case pcmk_rc_transform_failed:
717 : case pcmk_rc_unpack_error:
718 0 : return CRM_EX_CONFIG;
719 :
720 0 : case pcmk_rc_bad_nvpair:
721 0 : return CRM_EX_INVALID_PARAM;
722 :
723 4 : case EACCES:
724 4 : return CRM_EX_INSUFFICIENT_PRIV;
725 :
726 14 : case EBADF:
727 : case EINVAL:
728 : case EFAULT:
729 : case ENOSYS:
730 : case EOVERFLOW:
731 : case pcmk_rc_underflow:
732 : case pcmk_rc_compression:
733 14 : return CRM_EX_SOFTWARE;
734 :
735 0 : case EBADMSG:
736 : case EMSGSIZE:
737 : case ENOMSG:
738 : case ENOPROTOOPT:
739 : case EPROTO:
740 : case EPROTONOSUPPORT:
741 : case EPROTOTYPE:
742 0 : return CRM_EX_PROTOCOL;
743 :
744 0 : case ECOMM:
745 : case ENOMEM:
746 0 : return CRM_EX_OSERR;
747 :
748 10 : case ECONNABORTED:
749 : case ECONNREFUSED:
750 : case ECONNRESET:
751 : case ENOTCONN:
752 10 : return CRM_EX_DISCONNECT;
753 :
754 0 : case EEXIST:
755 : case pcmk_rc_already:
756 0 : return CRM_EX_EXISTS;
757 :
758 0 : case EIO:
759 : case pcmk_rc_dot_error:
760 : case pcmk_rc_graph_error:
761 0 : return CRM_EX_IOERR;
762 :
763 0 : case ENOTSUP:
764 : #if EOPNOTSUPP != ENOTSUP
765 : case EOPNOTSUPP:
766 : #endif
767 0 : return CRM_EX_UNIMPLEMENT_FEATURE;
768 :
769 0 : case ENOTUNIQ:
770 : case pcmk_rc_multiple:
771 0 : return CRM_EX_MULTIPLE;
772 :
773 6 : case ENODEV:
774 : case ENOENT:
775 : case ENXIO:
776 : case pcmk_rc_no_transaction:
777 : case pcmk_rc_unknown_format:
778 6 : return CRM_EX_NOSUCH;
779 :
780 0 : case pcmk_rc_node_unknown:
781 : case pcmk_rc_ns_resolution:
782 0 : return CRM_EX_NOHOST;
783 :
784 0 : case ETIME:
785 : case ETIMEDOUT:
786 0 : return CRM_EX_TIMEOUT;
787 :
788 0 : case EAGAIN:
789 : case EBUSY:
790 0 : return CRM_EX_UNSATISFIED;
791 :
792 0 : case pcmk_rc_before_range:
793 0 : return CRM_EX_NOT_YET_IN_EFFECT;
794 :
795 0 : case pcmk_rc_after_range:
796 0 : return CRM_EX_EXPIRED;
797 :
798 0 : case pcmk_rc_undetermined:
799 0 : return CRM_EX_INDETERMINATE;
800 :
801 0 : case pcmk_rc_op_unsatisfied:
802 0 : return CRM_EX_UNSATISFIED;
803 :
804 0 : case pcmk_rc_within_range:
805 0 : return CRM_EX_OK;
806 :
807 0 : case pcmk_rc_no_input:
808 0 : return CRM_EX_NOINPUT;
809 :
810 1 : case pcmk_rc_duplicate_id:
811 1 : return CRM_EX_MULTIPLE;
812 :
813 0 : case pcmk_rc_bad_input:
814 : case pcmk_rc_bad_xml_patch:
815 0 : return CRM_EX_DATAERR;
816 :
817 1 : default:
818 1 : return CRM_EX_ERROR;
819 : }
820 : }
821 :
822 : /*!
823 : * \brief Map a function return code to the most similar OCF exit code
824 : *
825 : * \param[in] rc Function return code
826 : *
827 : * \return Most similar OCF exit code
828 : */
829 : enum ocf_exitcode
830 0 : pcmk_rc2ocf(int rc)
831 : {
832 0 : switch (rc) {
833 0 : case pcmk_rc_ok:
834 0 : return PCMK_OCF_OK;
835 :
836 0 : case pcmk_rc_bad_nvpair:
837 0 : return PCMK_OCF_INVALID_PARAM;
838 :
839 0 : case EACCES:
840 0 : return PCMK_OCF_INSUFFICIENT_PRIV;
841 :
842 0 : case ENOTSUP:
843 : #if EOPNOTSUPP != ENOTSUP
844 : case EOPNOTSUPP:
845 : #endif
846 0 : return PCMK_OCF_UNIMPLEMENT_FEATURE;
847 :
848 0 : default:
849 0 : return PCMK_OCF_UNKNOWN_ERROR;
850 : }
851 : }
852 :
853 :
854 : // Other functions
855 :
856 : /*!
857 : * \brief Map a getaddrinfo() return code to the most similar Pacemaker
858 : * return code
859 : *
860 : * \param[in] gai getaddrinfo() return code
861 : *
862 : * \return Most similar Pacemaker return code
863 : */
864 : int
865 0 : pcmk__gaierror2rc(int gai)
866 : {
867 0 : switch (gai) {
868 0 : case 0:
869 0 : return pcmk_rc_ok;
870 :
871 0 : case EAI_AGAIN:
872 0 : return EAGAIN;
873 :
874 0 : case EAI_BADFLAGS:
875 : case EAI_SERVICE:
876 0 : return EINVAL;
877 :
878 0 : case EAI_FAMILY:
879 0 : return EAFNOSUPPORT;
880 :
881 0 : case EAI_MEMORY:
882 0 : return ENOMEM;
883 :
884 0 : case EAI_NONAME:
885 0 : return pcmk_rc_node_unknown;
886 :
887 0 : case EAI_SOCKTYPE:
888 0 : return ESOCKTNOSUPPORT;
889 :
890 0 : case EAI_SYSTEM:
891 0 : return errno;
892 :
893 0 : default:
894 0 : return pcmk_rc_ns_resolution;
895 : }
896 : }
897 :
898 : /*!
899 : * \brief Map a bz2 return code to the most similar Pacemaker return code
900 : *
901 : * \param[in] bz2 bz2 return code
902 : *
903 : * \return Most similar Pacemaker return code
904 : */
905 : int
906 0 : pcmk__bzlib2rc(int bz2)
907 : {
908 0 : switch (bz2) {
909 0 : case BZ_OK:
910 : case BZ_RUN_OK:
911 : case BZ_FLUSH_OK:
912 : case BZ_FINISH_OK:
913 : case BZ_STREAM_END:
914 0 : return pcmk_rc_ok;
915 :
916 0 : case BZ_MEM_ERROR:
917 0 : return ENOMEM;
918 :
919 0 : case BZ_DATA_ERROR:
920 : case BZ_DATA_ERROR_MAGIC:
921 : case BZ_UNEXPECTED_EOF:
922 0 : return pcmk_rc_bad_input;
923 :
924 0 : case BZ_IO_ERROR:
925 0 : return EIO;
926 :
927 0 : case BZ_OUTBUFF_FULL:
928 0 : return EFBIG;
929 :
930 0 : default:
931 0 : return pcmk_rc_compression;
932 : }
933 : }
934 :
935 : crm_exit_t
936 0 : crm_exit(crm_exit_t rc)
937 : {
938 : /* A compiler could theoretically use any type for crm_exit_t, but an int
939 : * should always hold it, so cast to int to keep static analysis happy.
940 : */
941 0 : if ((((int) rc) < 0) || (((int) rc) > CRM_EX_MAX)) {
942 0 : rc = CRM_EX_ERROR;
943 : }
944 :
945 0 : mainloop_cleanup();
946 0 : crm_xml_cleanup();
947 :
948 0 : free(pcmk__our_nodename);
949 :
950 0 : if (crm_system_name) {
951 0 : crm_info("Exiting %s " CRM_XS " with status %d", crm_system_name, rc);
952 0 : free(crm_system_name);
953 : } else {
954 0 : crm_trace("Exiting with status %d", rc);
955 : }
956 0 : pcmk__free_common_logger();
957 0 : qb_log_fini(); // Don't log anything after this point
958 :
959 0 : exit(rc);
960 : }
961 :
962 : /*
963 : * External action results
964 : */
965 :
966 : /*!
967 : * \internal
968 : * \brief Set the result of an action
969 : *
970 : * \param[out] result Where to set action result
971 : * \param[in] exit_status OCF exit status to set
972 : * \param[in] exec_status Execution status to set
973 : * \param[in] exit_reason Human-friendly description of event to set
974 : */
975 : void
976 0 : pcmk__set_result(pcmk__action_result_t *result, int exit_status,
977 : enum pcmk_exec_status exec_status, const char *exit_reason)
978 : {
979 0 : if (result == NULL) {
980 0 : return;
981 : }
982 :
983 0 : result->exit_status = exit_status;
984 0 : result->execution_status = exec_status;
985 :
986 0 : if (!pcmk__str_eq(result->exit_reason, exit_reason, pcmk__str_none)) {
987 0 : free(result->exit_reason);
988 0 : result->exit_reason = (exit_reason == NULL)? NULL : strdup(exit_reason);
989 : }
990 : }
991 :
992 :
993 : /*!
994 : * \internal
995 : * \brief Set the result of an action, with a formatted exit reason
996 : *
997 : * \param[out] result Where to set action result
998 : * \param[in] exit_status OCF exit status to set
999 : * \param[in] exec_status Execution status to set
1000 : * \param[in] format printf-style format for a human-friendly
1001 : * description of reason for result
1002 : * \param[in] ... arguments for \p format
1003 : */
1004 : G_GNUC_PRINTF(4, 5)
1005 : void
1006 0 : pcmk__format_result(pcmk__action_result_t *result, int exit_status,
1007 : enum pcmk_exec_status exec_status,
1008 : const char *format, ...)
1009 : {
1010 : va_list ap;
1011 0 : int len = 0;
1012 0 : char *reason = NULL;
1013 :
1014 0 : if (result == NULL) {
1015 0 : return;
1016 : }
1017 :
1018 0 : result->exit_status = exit_status;
1019 0 : result->execution_status = exec_status;
1020 :
1021 0 : if (format != NULL) {
1022 0 : va_start(ap, format);
1023 0 : len = vasprintf(&reason, format, ap);
1024 0 : CRM_ASSERT(len > 0);
1025 0 : va_end(ap);
1026 : }
1027 0 : free(result->exit_reason);
1028 0 : result->exit_reason = reason;
1029 : }
1030 :
1031 : /*!
1032 : * \internal
1033 : * \brief Set the output of an action
1034 : *
1035 : * \param[out] result Action result to set output for
1036 : * \param[in] out Action output to set (must be dynamically
1037 : * allocated)
1038 : * \param[in] err Action error output to set (must be dynamically
1039 : * allocated)
1040 : *
1041 : * \note \p result will take ownership of \p out and \p err, so the caller
1042 : * should not free them.
1043 : */
1044 : void
1045 0 : pcmk__set_result_output(pcmk__action_result_t *result, char *out, char *err)
1046 : {
1047 0 : if (result == NULL) {
1048 0 : return;
1049 : }
1050 :
1051 0 : free(result->action_stdout);
1052 0 : result->action_stdout = out;
1053 :
1054 0 : free(result->action_stderr);
1055 0 : result->action_stderr = err;
1056 : }
1057 :
1058 : /*!
1059 : * \internal
1060 : * \brief Clear a result's exit reason, output, and error output
1061 : *
1062 : * \param[in,out] result Result to reset
1063 : */
1064 : void
1065 0 : pcmk__reset_result(pcmk__action_result_t *result)
1066 : {
1067 0 : if (result == NULL) {
1068 0 : return;
1069 : }
1070 :
1071 0 : free(result->exit_reason);
1072 0 : result->exit_reason = NULL;
1073 :
1074 0 : free(result->action_stdout);
1075 0 : result->action_stdout = NULL;
1076 :
1077 0 : free(result->action_stderr);
1078 0 : result->action_stderr = NULL;
1079 : }
1080 :
1081 : /*!
1082 : * \internal
1083 : * \brief Copy the result of an action
1084 : *
1085 : * \param[in] src Result to copy
1086 : * \param[out] dst Where to copy \p src to
1087 : */
1088 : void
1089 0 : pcmk__copy_result(const pcmk__action_result_t *src, pcmk__action_result_t *dst)
1090 : {
1091 0 : CRM_CHECK((src != NULL) && (dst != NULL), return);
1092 0 : dst->exit_status = src->exit_status;
1093 0 : dst->execution_status = src->execution_status;
1094 0 : dst->exit_reason = pcmk__str_copy(src->exit_reason);
1095 0 : dst->action_stdout = pcmk__str_copy(src->action_stdout);
1096 0 : dst->action_stderr = pcmk__str_copy(src->action_stderr);
1097 : }
1098 :
1099 : // Deprecated functions kept only for backward API compatibility
1100 : // LCOV_EXCL_START
1101 :
1102 : #include <crm/common/results_compat.h>
1103 :
1104 : const char *
1105 : bz2_strerror(int rc)
1106 : {
1107 : // See ftp://sources.redhat.com/pub/bzip2/docs/manual_3.html#SEC17
1108 : switch (rc) {
1109 : case BZ_OK:
1110 : case BZ_RUN_OK:
1111 : case BZ_FLUSH_OK:
1112 : case BZ_FINISH_OK:
1113 : case BZ_STREAM_END:
1114 : return "Ok";
1115 : case BZ_CONFIG_ERROR:
1116 : return "libbz2 has been improperly compiled on your platform";
1117 : case BZ_SEQUENCE_ERROR:
1118 : return "library functions called in the wrong order";
1119 : case BZ_PARAM_ERROR:
1120 : return "parameter is out of range or otherwise incorrect";
1121 : case BZ_MEM_ERROR:
1122 : return "memory allocation failed";
1123 : case BZ_DATA_ERROR:
1124 : return "data integrity error is detected during decompression";
1125 : case BZ_DATA_ERROR_MAGIC:
1126 : return "the compressed stream does not start with the correct magic bytes";
1127 : case BZ_IO_ERROR:
1128 : return "error reading or writing in the compressed file";
1129 : case BZ_UNEXPECTED_EOF:
1130 : return "compressed file finishes before the logical end of stream is detected";
1131 : case BZ_OUTBUFF_FULL:
1132 : return "output data will not fit into the buffer provided";
1133 : }
1134 : return "Data compression error";
1135 : }
1136 :
1137 : crm_exit_t
1138 : crm_errno2exit(int rc)
1139 : {
1140 : return pcmk_rc2exitc(pcmk_legacy2rc(rc));
1141 : }
1142 :
1143 : // LCOV_EXCL_STOP
1144 : // End deprecated API
|