root/lib/common/results.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. G_DEFINE_QUARK
  2. pcmk__result_bounds
  3. pcmk_errorname
  4. pcmk_strerror
  5. pcmk_rc_name
  6. pcmk_rc_str
  7. pcmk_rc2legacy
  8. pcmk_legacy2rc
  9. crm_exit_name
  10. crm_exit_str
  11. pcmk_rc2exitc
  12. pcmk_rc2ocf
  13. bz2_strerror
  14. crm_exit
  15. pcmk__set_result
  16. G_GNUC_PRINTF
  17. pcmk__set_result_output
  18. pcmk__reset_result
  19. pcmk__copy_result
  20. crm_errno2exit

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

/* [previous][next][first][last][top][bottom][index][help] */