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