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-2023 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     { "pcmk_rc_disabled",
 297       "Disabled",
 298       -pcmk_err_generic,
 299     },
 300     { "pcmk_rc_bad_input",
 301       "Bad input value provided",
 302       -pcmk_err_generic,
 303     },
 304     { "pcmk_rc_bad_xml_patch",
 305       "Bad XML patch format",
 306       -pcmk_err_generic,
 307     },
 308 };
 309 
 310 /*!
 311  * \internal
 312  * \brief The number of <tt>enum pcmk_rc_e</tt> values, excluding \c pcmk_rc_ok
 313  *
 314  * This constant stores the number of negative standard Pacemaker return codes.
 315  * These represent Pacemaker-custom error codes. The count does not include
 316  * positive system error numbers, nor does it include \c pcmk_rc_ok (success).
 317  */
 318 const size_t pcmk__n_rc = PCMK__NELEM(pcmk__rcs);
 319 
 320 /*!
 321  * \brief Get a return code constant name as a string
 322  *
 323  * \param[in] rc  Integer return code to convert
 324  *
 325  * \return String of constant name corresponding to rc
 326  */
 327 const char *
 328 pcmk_rc_name(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 329 {
 330     if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < pcmk__n_rc)) {
 331         return pcmk__rcs[pcmk_rc_error - rc].name;
 332     }
 333     switch (rc) {
 334         case pcmk_rc_ok:        return "pcmk_rc_ok";
 335         case E2BIG:             return "E2BIG";
 336         case EACCES:            return "EACCES";
 337         case EADDRINUSE:        return "EADDRINUSE";
 338         case EADDRNOTAVAIL:     return "EADDRNOTAVAIL";
 339         case EAFNOSUPPORT:      return "EAFNOSUPPORT";
 340         case EAGAIN:            return "EAGAIN";
 341         case EALREADY:          return "EALREADY";
 342         case EBADF:             return "EBADF";
 343         case EBADMSG:           return "EBADMSG";
 344         case EBUSY:             return "EBUSY";
 345         case ECANCELED:         return "ECANCELED";
 346         case ECHILD:            return "ECHILD";
 347         case ECOMM:             return "ECOMM";
 348         case ECONNABORTED:      return "ECONNABORTED";
 349         case ECONNREFUSED:      return "ECONNREFUSED";
 350         case ECONNRESET:        return "ECONNRESET";
 351         /* case EDEADLK:        return "EDEADLK"; */
 352         case EDESTADDRREQ:      return "EDESTADDRREQ";
 353         case EDOM:              return "EDOM";
 354         case EDQUOT:            return "EDQUOT";
 355         case EEXIST:            return "EEXIST";
 356         case EFAULT:            return "EFAULT";
 357         case EFBIG:             return "EFBIG";
 358         case EHOSTDOWN:         return "EHOSTDOWN";
 359         case EHOSTUNREACH:      return "EHOSTUNREACH";
 360         case EIDRM:             return "EIDRM";
 361         case EILSEQ:            return "EILSEQ";
 362         case EINPROGRESS:       return "EINPROGRESS";
 363         case EINTR:             return "EINTR";
 364         case EINVAL:            return "EINVAL";
 365         case EIO:               return "EIO";
 366         case EISCONN:           return "EISCONN";
 367         case EISDIR:            return "EISDIR";
 368         case ELIBACC:           return "ELIBACC";
 369         case ELOOP:             return "ELOOP";
 370         case EMFILE:            return "EMFILE";
 371         case EMLINK:            return "EMLINK";
 372         case EMSGSIZE:          return "EMSGSIZE";
 373 #ifdef EMULTIHOP // Not available on OpenBSD
 374         case EMULTIHOP:         return "EMULTIHOP";
 375 #endif
 376         case ENAMETOOLONG:      return "ENAMETOOLONG";
 377         case ENETDOWN:          return "ENETDOWN";
 378         case ENETRESET:         return "ENETRESET";
 379         case ENETUNREACH:       return "ENETUNREACH";
 380         case ENFILE:            return "ENFILE";
 381         case ENOBUFS:           return "ENOBUFS";
 382         case ENODATA:           return "ENODATA";
 383         case ENODEV:            return "ENODEV";
 384         case ENOENT:            return "ENOENT";
 385         case ENOEXEC:           return "ENOEXEC";
 386         case ENOKEY:            return "ENOKEY";
 387         case ENOLCK:            return "ENOLCK";
 388 #ifdef ENOLINK // Not available on OpenBSD
 389         case ENOLINK:           return "ENOLINK";
 390 #endif
 391         case ENOMEM:            return "ENOMEM";
 392         case ENOMSG:            return "ENOMSG";
 393         case ENOPROTOOPT:       return "ENOPROTOOPT";
 394         case ENOSPC:            return "ENOSPC";
 395 #ifdef ENOSR
 396         case ENOSR:             return "ENOSR";
 397 #endif
 398 #ifdef ENOSTR
 399         case ENOSTR:            return "ENOSTR";
 400 #endif
 401         case ENOSYS:            return "ENOSYS";
 402         case ENOTBLK:           return "ENOTBLK";
 403         case ENOTCONN:          return "ENOTCONN";
 404         case ENOTDIR:           return "ENOTDIR";
 405         case ENOTEMPTY:         return "ENOTEMPTY";
 406         case ENOTSOCK:          return "ENOTSOCK";
 407 #if ENOTSUP != EOPNOTSUPP
 408         case ENOTSUP:           return "ENOTSUP";
 409 #endif
 410         case ENOTTY:            return "ENOTTY";
 411         case ENOTUNIQ:          return "ENOTUNIQ";
 412         case ENXIO:             return "ENXIO";
 413         case EOPNOTSUPP:        return "EOPNOTSUPP";
 414         case EOVERFLOW:         return "EOVERFLOW";
 415         case EPERM:             return "EPERM";
 416         case EPFNOSUPPORT:      return "EPFNOSUPPORT";
 417         case EPIPE:             return "EPIPE";
 418         case EPROTO:            return "EPROTO";
 419         case EPROTONOSUPPORT:   return "EPROTONOSUPPORT";
 420         case EPROTOTYPE:        return "EPROTOTYPE";
 421         case ERANGE:            return "ERANGE";
 422         case EREMOTE:           return "EREMOTE";
 423         case EREMOTEIO:         return "EREMOTEIO";
 424         case EROFS:             return "EROFS";
 425         case ESHUTDOWN:         return "ESHUTDOWN";
 426         case ESPIPE:            return "ESPIPE";
 427         case ESOCKTNOSUPPORT:   return "ESOCKTNOSUPPORT";
 428         case ESRCH:             return "ESRCH";
 429         case ESTALE:            return "ESTALE";
 430         case ETIME:             return "ETIME";
 431         case ETIMEDOUT:         return "ETIMEDOUT";
 432         case ETXTBSY:           return "ETXTBSY";
 433 #ifdef EUNATCH
 434         case EUNATCH:           return "EUNATCH";
 435 #endif
 436         case EUSERS:            return "EUSERS";
 437         /* case EWOULDBLOCK:    return "EWOULDBLOCK"; */
 438         case EXDEV:             return "EXDEV";
 439 
 440 #ifdef EBADE // Not available on OS X
 441         case EBADE:             return "EBADE";
 442         case EBADFD:            return "EBADFD";
 443         case EBADSLT:           return "EBADSLT";
 444         case EDEADLOCK:         return "EDEADLOCK";
 445         case EBADR:             return "EBADR";
 446         case EBADRQC:           return "EBADRQC";
 447         case ECHRNG:            return "ECHRNG";
 448 #ifdef EISNAM // Not available on OS X, Illumos, Solaris
 449         case EISNAM:            return "EISNAM";
 450         case EKEYEXPIRED:       return "EKEYEXPIRED";
 451         case EKEYREVOKED:       return "EKEYREVOKED";
 452 #endif
 453         case EKEYREJECTED:      return "EKEYREJECTED";
 454         case EL2HLT:            return "EL2HLT";
 455         case EL2NSYNC:          return "EL2NSYNC";
 456         case EL3HLT:            return "EL3HLT";
 457         case EL3RST:            return "EL3RST";
 458         case ELIBBAD:           return "ELIBBAD";
 459         case ELIBMAX:           return "ELIBMAX";
 460         case ELIBSCN:           return "ELIBSCN";
 461         case ELIBEXEC:          return "ELIBEXEC";
 462 #ifdef ENOMEDIUM // Not available on OS X, Illumos, Solaris
 463         case ENOMEDIUM:         return "ENOMEDIUM";
 464         case EMEDIUMTYPE:       return "EMEDIUMTYPE";
 465 #endif
 466         case ENONET:            return "ENONET";
 467         case ENOPKG:            return "ENOPKG";
 468         case EREMCHG:           return "EREMCHG";
 469         case ERESTART:          return "ERESTART";
 470         case ESTRPIPE:          return "ESTRPIPE";
 471 #ifdef EUCLEAN // Not available on OS X, Illumos, Solaris
 472         case EUCLEAN:           return "EUCLEAN";
 473 #endif
 474         case EXFULL:            return "EXFULL";
 475 #endif // EBADE
 476         default:                return "Unknown";
 477     }
 478 }
 479 
 480 /*!
 481  * \brief Get a user-friendly description of a return code
 482  *
 483  * \param[in] rc  Integer return code to convert
 484  *
 485  * \return String description of rc
 486  */
 487 const char *
 488 pcmk_rc_str(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490     if (rc == pcmk_rc_ok) {
 491         return "OK";
 492     }
 493     if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < pcmk__n_rc)) {
 494         return pcmk__rcs[pcmk_rc_error - rc].desc;
 495     }
 496     if (rc < 0) {
 497         return "Error";
 498     }
 499 
 500     // Handle values that could be defined by system or by portability.h
 501     switch (rc) {
 502 #ifdef PCMK__ENOTUNIQ
 503         case ENOTUNIQ:      return "Name not unique on network";
 504 #endif
 505 #ifdef PCMK__ECOMM
 506         case ECOMM:         return "Communication error on send";
 507 #endif
 508 #ifdef PCMK__ELIBACC
 509         case ELIBACC:       return "Can not access a needed shared library";
 510 #endif
 511 #ifdef PCMK__EREMOTEIO
 512         case EREMOTEIO:     return "Remote I/O error";
 513 #endif
 514 #ifdef PCMK__ENOKEY
 515         case ENOKEY:        return "Required key not available";
 516 #endif
 517 #ifdef PCMK__ENODATA
 518         case ENODATA:       return "No data available";
 519 #endif
 520 #ifdef PCMK__ETIME
 521         case ETIME:         return "Timer expired";
 522 #endif
 523 #ifdef PCMK__EKEYREJECTED
 524         case EKEYREJECTED:  return "Key was rejected by service";
 525 #endif
 526         default:            return strerror(rc);
 527     }
 528 }
 529 
 530 // This returns negative values for errors
 531 //! \deprecated Use standard return codes instead
 532 int
 533 pcmk_rc2legacy(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 534 {
 535     if (rc >= 0) {
 536         return -rc; // OK or system errno
 537     }
 538     if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < pcmk__n_rc)) {
 539         return pcmk__rcs[pcmk_rc_error - rc].legacy_rc;
 540     }
 541     return -pcmk_err_generic;
 542 }
 543 
 544 //! \deprecated Use standard return codes instead
 545 int
 546 pcmk_legacy2rc(int legacy_rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 547 {
 548     legacy_rc = abs(legacy_rc);
 549     switch (legacy_rc) {
 550         case pcmk_err_no_quorum:            return pcmk_rc_no_quorum;
 551         case pcmk_err_schema_validation:    return pcmk_rc_schema_validation;
 552         case pcmk_err_schema_unchanged:     return pcmk_rc_schema_unchanged;
 553         case pcmk_err_transform_failed:     return pcmk_rc_transform_failed;
 554         case pcmk_err_old_data:             return pcmk_rc_old_data;
 555         case pcmk_err_diff_failed:          return pcmk_rc_diff_failed;
 556         case pcmk_err_diff_resync:          return pcmk_rc_diff_resync;
 557         case pcmk_err_cib_modified:         return pcmk_rc_cib_modified;
 558         case pcmk_err_cib_backup:           return pcmk_rc_cib_backup;
 559         case pcmk_err_cib_save:             return pcmk_rc_cib_save;
 560         case pcmk_err_cib_corrupt:          return pcmk_rc_cib_corrupt;
 561         case pcmk_err_multiple:             return pcmk_rc_multiple;
 562         case pcmk_err_node_unknown:         return pcmk_rc_node_unknown;
 563         case pcmk_err_already:              return pcmk_rc_already;
 564         case pcmk_err_bad_nvpair:           return pcmk_rc_bad_nvpair;
 565         case pcmk_err_unknown_format:       return pcmk_rc_unknown_format;
 566         case pcmk_err_generic:              return pcmk_rc_error;
 567         case pcmk_ok:                       return pcmk_rc_ok;
 568         default:                            return legacy_rc; // system errno
 569     }
 570 }
 571 
 572 // Exit status codes
 573 
 574 const char *
 575 crm_exit_name(crm_exit_t exit_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 576 {
 577     switch (exit_code) {
 578         case CRM_EX_OK: return "CRM_EX_OK";
 579         case CRM_EX_ERROR: return "CRM_EX_ERROR";
 580         case CRM_EX_INVALID_PARAM: return "CRM_EX_INVALID_PARAM";
 581         case CRM_EX_UNIMPLEMENT_FEATURE: return "CRM_EX_UNIMPLEMENT_FEATURE";
 582         case CRM_EX_INSUFFICIENT_PRIV: return "CRM_EX_INSUFFICIENT_PRIV";
 583         case CRM_EX_NOT_INSTALLED: return "CRM_EX_NOT_INSTALLED";
 584         case CRM_EX_NOT_CONFIGURED: return "CRM_EX_NOT_CONFIGURED";
 585         case CRM_EX_NOT_RUNNING: return "CRM_EX_NOT_RUNNING";
 586         case CRM_EX_PROMOTED: return "CRM_EX_PROMOTED";
 587         case CRM_EX_FAILED_PROMOTED: return "CRM_EX_FAILED_PROMOTED";
 588         case CRM_EX_USAGE: return "CRM_EX_USAGE";
 589         case CRM_EX_DATAERR: return "CRM_EX_DATAERR";
 590         case CRM_EX_NOINPUT: return "CRM_EX_NOINPUT";
 591         case CRM_EX_NOUSER: return "CRM_EX_NOUSER";
 592         case CRM_EX_NOHOST: return "CRM_EX_NOHOST";
 593         case CRM_EX_UNAVAILABLE: return "CRM_EX_UNAVAILABLE";
 594         case CRM_EX_SOFTWARE: return "CRM_EX_SOFTWARE";
 595         case CRM_EX_OSERR: return "CRM_EX_OSERR";
 596         case CRM_EX_OSFILE: return "CRM_EX_OSFILE";
 597         case CRM_EX_CANTCREAT: return "CRM_EX_CANTCREAT";
 598         case CRM_EX_IOERR: return "CRM_EX_IOERR";
 599         case CRM_EX_TEMPFAIL: return "CRM_EX_TEMPFAIL";
 600         case CRM_EX_PROTOCOL: return "CRM_EX_PROTOCOL";
 601         case CRM_EX_NOPERM: return "CRM_EX_NOPERM";
 602         case CRM_EX_CONFIG: return "CRM_EX_CONFIG";
 603         case CRM_EX_FATAL: return "CRM_EX_FATAL";
 604         case CRM_EX_PANIC: return "CRM_EX_PANIC";
 605         case CRM_EX_DISCONNECT: return "CRM_EX_DISCONNECT";
 606         case CRM_EX_DIGEST: return "CRM_EX_DIGEST";
 607         case CRM_EX_NOSUCH: return "CRM_EX_NOSUCH";
 608         case CRM_EX_QUORUM: return "CRM_EX_QUORUM";
 609         case CRM_EX_UNSAFE: return "CRM_EX_UNSAFE";
 610         case CRM_EX_EXISTS: return "CRM_EX_EXISTS";
 611         case CRM_EX_MULTIPLE: return "CRM_EX_MULTIPLE";
 612         case CRM_EX_EXPIRED: return "CRM_EX_EXPIRED";
 613         case CRM_EX_NOT_YET_IN_EFFECT: return "CRM_EX_NOT_YET_IN_EFFECT";
 614         case CRM_EX_INDETERMINATE: return "CRM_EX_INDETERMINATE";
 615         case CRM_EX_UNSATISFIED: return "CRM_EX_UNSATISFIED";
 616         case CRM_EX_OLD: return "CRM_EX_OLD";
 617         case CRM_EX_TIMEOUT: return "CRM_EX_TIMEOUT";
 618         case CRM_EX_DEGRADED: return "CRM_EX_DEGRADED";
 619         case CRM_EX_DEGRADED_PROMOTED: return "CRM_EX_DEGRADED_PROMOTED";
 620         case CRM_EX_NONE: return "CRM_EX_NONE";
 621         case CRM_EX_MAX: return "CRM_EX_UNKNOWN";
 622     }
 623     return "CRM_EX_UNKNOWN";
 624 }
 625 
 626 const char *
 627 crm_exit_str(crm_exit_t exit_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 628 {
 629     switch (exit_code) {
 630         case CRM_EX_OK: return "OK";
 631         case CRM_EX_ERROR: return "Error occurred";
 632         case CRM_EX_INVALID_PARAM: return "Invalid parameter";
 633         case CRM_EX_UNIMPLEMENT_FEATURE: return "Unimplemented";
 634         case CRM_EX_INSUFFICIENT_PRIV: return "Insufficient privileges";
 635         case CRM_EX_NOT_INSTALLED: return "Not installed";
 636         case CRM_EX_NOT_CONFIGURED: return "Not configured";
 637         case CRM_EX_NOT_RUNNING: return "Not running";
 638         case CRM_EX_PROMOTED: return "Promoted";
 639         case CRM_EX_FAILED_PROMOTED: return "Failed in promoted role";
 640         case CRM_EX_USAGE: return "Incorrect usage";
 641         case CRM_EX_DATAERR: return "Invalid data given";
 642         case CRM_EX_NOINPUT: return "Input file not available";
 643         case CRM_EX_NOUSER: return "User does not exist";
 644         case CRM_EX_NOHOST: return "Host does not exist";
 645         case CRM_EX_UNAVAILABLE: return "Necessary service unavailable";
 646         case CRM_EX_SOFTWARE: return "Internal software bug";
 647         case CRM_EX_OSERR: return "Operating system error occurred";
 648         case CRM_EX_OSFILE: return "System file not available";
 649         case CRM_EX_CANTCREAT: return "Cannot create output file";
 650         case CRM_EX_IOERR: return "I/O error occurred";
 651         case CRM_EX_TEMPFAIL: return "Temporary failure, try again";
 652         case CRM_EX_PROTOCOL: return "Protocol violated";
 653         case CRM_EX_NOPERM: return "Insufficient privileges";
 654         case CRM_EX_CONFIG: return "Invalid configuration";
 655         case CRM_EX_FATAL: return "Fatal error occurred, will not respawn";
 656         case CRM_EX_PANIC: return "System panic required";
 657         case CRM_EX_DISCONNECT: return "Not connected";
 658         case CRM_EX_DIGEST: return "Digest mismatch";
 659         case CRM_EX_NOSUCH: return "No such object";
 660         case CRM_EX_QUORUM: return "Quorum required";
 661         case CRM_EX_UNSAFE: return "Operation not safe";
 662         case CRM_EX_EXISTS: return "Requested item already exists";
 663         case CRM_EX_MULTIPLE: return "Multiple items match request";
 664         case CRM_EX_EXPIRED: return "Requested item has expired";
 665         case CRM_EX_NOT_YET_IN_EFFECT: return "Requested item is not yet in effect";
 666         case CRM_EX_INDETERMINATE: return "Could not determine status";
 667         case CRM_EX_UNSATISFIED: return "Not applicable under current conditions";
 668         case CRM_EX_OLD: return "Update was older than existing configuration";
 669         case CRM_EX_TIMEOUT: return "Timeout occurred";
 670         case CRM_EX_DEGRADED: return "Service is active but might fail soon";
 671         case CRM_EX_DEGRADED_PROMOTED: return "Service is promoted but might fail soon";
 672         case CRM_EX_NONE: return "No exit status available";
 673         case CRM_EX_MAX: return "Error occurred";
 674     }
 675     if ((exit_code > 128) && (exit_code < CRM_EX_MAX)) {
 676         return "Interrupted by signal";
 677     }
 678     return "Unknown exit status";
 679 }
 680 
 681 /*!
 682  * \brief Map a function return code to the most similar exit code
 683  *
 684  * \param[in] rc  Function return code
 685  *
 686  * \return Most similar exit code
 687  */
 688 crm_exit_t
 689 pcmk_rc2exitc(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 690 {
 691     switch (rc) {
 692         case pcmk_rc_ok:
 693         case pcmk_rc_no_output: // quiet mode, or nothing to output
 694             return CRM_EX_OK;
 695 
 696         case pcmk_rc_no_quorum:
 697             return CRM_EX_QUORUM;
 698 
 699         case pcmk_rc_old_data:
 700             return CRM_EX_OLD;
 701 
 702         case pcmk_rc_schema_validation:
 703         case pcmk_rc_transform_failed:
 704         case pcmk_rc_unpack_error:
 705             return CRM_EX_CONFIG;
 706 
 707         case pcmk_rc_bad_nvpair:
 708             return CRM_EX_INVALID_PARAM;
 709 
 710         case EACCES:
 711             return CRM_EX_INSUFFICIENT_PRIV;
 712 
 713         case EBADF:
 714         case EINVAL:
 715         case EFAULT:
 716         case ENOSYS:
 717         case EOVERFLOW:
 718         case pcmk_rc_underflow:
 719             return CRM_EX_SOFTWARE;
 720 
 721         case EBADMSG:
 722         case EMSGSIZE:
 723         case ENOMSG:
 724         case ENOPROTOOPT:
 725         case EPROTO:
 726         case EPROTONOSUPPORT:
 727         case EPROTOTYPE:
 728             return CRM_EX_PROTOCOL;
 729 
 730         case ECOMM:
 731         case ENOMEM:
 732             return CRM_EX_OSERR;
 733 
 734         case ECONNABORTED:
 735         case ECONNREFUSED:
 736         case ECONNRESET:
 737         case ENOTCONN:
 738             return CRM_EX_DISCONNECT;
 739 
 740         case EEXIST:
 741         case pcmk_rc_already:
 742             return CRM_EX_EXISTS;
 743 
 744         case EIO:
 745         case pcmk_rc_dot_error:
 746         case pcmk_rc_graph_error:
 747             return CRM_EX_IOERR;
 748 
 749         case ENOTSUP:
 750 #if EOPNOTSUPP != ENOTSUP
 751         case EOPNOTSUPP:
 752 #endif
 753             return CRM_EX_UNIMPLEMENT_FEATURE;
 754 
 755         case ENOTUNIQ:
 756         case pcmk_rc_multiple:
 757             return CRM_EX_MULTIPLE;
 758 
 759         case ENODEV:
 760         case ENOENT:
 761         case ENXIO:
 762         case pcmk_rc_unknown_format:
 763             return CRM_EX_NOSUCH;
 764 
 765         case pcmk_rc_node_unknown:
 766             return CRM_EX_NOHOST;
 767 
 768         case ETIME:
 769         case ETIMEDOUT:
 770             return CRM_EX_TIMEOUT;
 771 
 772         case EAGAIN:
 773         case EBUSY:
 774             return CRM_EX_UNSATISFIED;
 775 
 776         case pcmk_rc_before_range:
 777             return CRM_EX_NOT_YET_IN_EFFECT;
 778 
 779         case pcmk_rc_after_range:
 780             return CRM_EX_EXPIRED;
 781 
 782         case pcmk_rc_undetermined:
 783             return CRM_EX_INDETERMINATE;
 784 
 785         case pcmk_rc_op_unsatisfied:
 786             return CRM_EX_UNSATISFIED;
 787 
 788         case pcmk_rc_within_range:
 789             return CRM_EX_OK;
 790 
 791         case pcmk_rc_no_input:
 792             return CRM_EX_NOINPUT;
 793 
 794         case pcmk_rc_duplicate_id:
 795             return CRM_EX_MULTIPLE;
 796 
 797         case pcmk_rc_bad_input:
 798         case pcmk_rc_bad_xml_patch:
 799             return CRM_EX_DATAERR;
 800 
 801         default:
 802             return CRM_EX_ERROR;
 803     }
 804 }
 805 
 806 /*!
 807  * \brief Map a function return code to the most similar OCF exit code
 808  *
 809  * \param[in] rc  Function return code
 810  *
 811  * \return Most similar OCF exit code
 812  */
 813 enum ocf_exitcode
 814 pcmk_rc2ocf(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 815 {
 816     switch (rc) {
 817         case pcmk_rc_ok:
 818             return PCMK_OCF_OK;
 819 
 820         case pcmk_rc_bad_nvpair:
 821             return PCMK_OCF_INVALID_PARAM;
 822 
 823         case EACCES:
 824             return PCMK_OCF_INSUFFICIENT_PRIV;
 825 
 826         case ENOTSUP:
 827 #if EOPNOTSUPP != ENOTSUP
 828         case EOPNOTSUPP:
 829 #endif
 830             return PCMK_OCF_UNIMPLEMENT_FEATURE;
 831 
 832         default:
 833             return PCMK_OCF_UNKNOWN_ERROR;
 834     }
 835 }
 836 
 837 
 838 // Other functions
 839 
 840 const char *
 841 bz2_strerror(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 842 {
 843     // See ftp://sources.redhat.com/pub/bzip2/docs/manual_3.html#SEC17
 844     switch (rc) {
 845         case BZ_OK:
 846         case BZ_RUN_OK:
 847         case BZ_FLUSH_OK:
 848         case BZ_FINISH_OK:
 849         case BZ_STREAM_END:
 850             return "Ok";
 851         case BZ_CONFIG_ERROR:
 852             return "libbz2 has been improperly compiled on your platform";
 853         case BZ_SEQUENCE_ERROR:
 854             return "library functions called in the wrong order";
 855         case BZ_PARAM_ERROR:
 856             return "parameter is out of range or otherwise incorrect";
 857         case BZ_MEM_ERROR:
 858             return "memory allocation failed";
 859         case BZ_DATA_ERROR:
 860             return "data integrity error is detected during decompression";
 861         case BZ_DATA_ERROR_MAGIC:
 862             return "the compressed stream does not start with the correct magic bytes";
 863         case BZ_IO_ERROR:
 864             return "error reading or writing in the compressed file";
 865         case BZ_UNEXPECTED_EOF:
 866             return "compressed file finishes before the logical end of stream is detected";
 867         case BZ_OUTBUFF_FULL:
 868             return "output data will not fit into the buffer provided";
 869     }
 870     return "Data compression error";
 871 }
 872 
 873 crm_exit_t
 874 crm_exit(crm_exit_t rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 875 {
 876     /* A compiler could theoretically use any type for crm_exit_t, but an int
 877      * should always hold it, so cast to int to keep static analysis happy.
 878      */
 879     if ((((int) rc) < 0) || (((int) rc) > CRM_EX_MAX)) {
 880         rc = CRM_EX_ERROR;
 881     }
 882 
 883     mainloop_cleanup();
 884     crm_xml_cleanup();
 885 
 886     free(pcmk__our_nodename);
 887 
 888     if (crm_system_name) {
 889         crm_info("Exiting %s " CRM_XS " with status %d", crm_system_name, rc);
 890         free(crm_system_name);
 891     } else {
 892         crm_trace("Exiting with status %d", rc);
 893     }
 894     pcmk__free_common_logger();
 895     qb_log_fini(); // Don't log anything after this point
 896 
 897     exit(rc);
 898 }
 899 
 900 /*
 901  * External action results
 902  */
 903 
 904 /*!
 905  * \internal
 906  * \brief Set the result of an action
 907  *
 908  * \param[out] result        Where to set action result
 909  * \param[in]  exit_status   OCF exit status to set
 910  * \param[in]  exec_status   Execution status to set
 911  * \param[in]  exit_reason   Human-friendly description of event to set
 912  */
 913 void
 914 pcmk__set_result(pcmk__action_result_t *result, int exit_status,
     /* [previous][next][first][last][top][bottom][index][help] */
 915                  enum pcmk_exec_status exec_status, const char *exit_reason)
 916 {
 917     if (result == NULL) {
 918         return;
 919     }
 920 
 921     result->exit_status = exit_status;
 922     result->execution_status = exec_status;
 923 
 924     if (!pcmk__str_eq(result->exit_reason, exit_reason, pcmk__str_none)) {
 925         free(result->exit_reason);
 926         result->exit_reason = (exit_reason == NULL)? NULL : strdup(exit_reason);
 927     }
 928 }
 929 
 930 
 931 /*!
 932  * \internal
 933  * \brief Set the result of an action, with a formatted exit reason
 934  *
 935  * \param[out] result        Where to set action result
 936  * \param[in]  exit_status   OCF exit status to set
 937  * \param[in]  exec_status   Execution status to set
 938  * \param[in]  format        printf-style format for a human-friendly
 939  *                           description of reason for result
 940  * \param[in]  ...           arguments for \p format
 941  */
 942 G_GNUC_PRINTF(4, 5)
     /* [previous][next][first][last][top][bottom][index][help] */
 943 void
 944 pcmk__format_result(pcmk__action_result_t *result, int exit_status,
 945                     enum pcmk_exec_status exec_status,
 946                     const char *format, ...)
 947 {
 948     va_list ap;
 949     int len = 0;
 950     char *reason = NULL;
 951 
 952     if (result == NULL) {
 953         return;
 954     }
 955 
 956     result->exit_status = exit_status;
 957     result->execution_status = exec_status;
 958 
 959     if (format != NULL) {
 960         va_start(ap, format);
 961         len = vasprintf(&reason, format, ap);
 962         CRM_ASSERT(len > 0);
 963         va_end(ap);
 964     }
 965     free(result->exit_reason);
 966     result->exit_reason = reason;
 967 }
 968 
 969 /*!
 970  * \internal
 971  * \brief Set the output of an action
 972  *
 973  * \param[out] result         Action result to set output for
 974  * \param[in]  out            Action output to set (must be dynamically
 975  *                            allocated)
 976  * \param[in]  err            Action error output to set (must be dynamically
 977  *                            allocated)
 978  *
 979  * \note \p result will take ownership of \p out and \p err, so the caller
 980  *       should not free them.
 981  */
 982 void
 983 pcmk__set_result_output(pcmk__action_result_t *result, char *out, char *err)
     /* [previous][next][first][last][top][bottom][index][help] */
 984 {
 985     if (result == NULL) {
 986         return;
 987     }
 988 
 989     free(result->action_stdout);
 990     result->action_stdout = out;
 991 
 992     free(result->action_stderr);
 993     result->action_stderr = err;
 994 }
 995 
 996 /*!
 997  * \internal
 998  * \brief Clear a result's exit reason, output, and error output
 999  *
1000  * \param[in,out] result  Result to reset
1001  */
1002 void
1003 pcmk__reset_result(pcmk__action_result_t *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1004 {
1005     if (result == NULL) {
1006         return;
1007     }
1008 
1009     free(result->exit_reason);
1010     result->exit_reason = NULL;
1011 
1012     free(result->action_stdout);
1013     result->action_stdout = NULL;
1014 
1015     free(result->action_stderr);
1016     result->action_stderr = NULL;
1017 }
1018 
1019 /*!
1020  * \internal
1021  * \brief Copy the result of an action
1022  *
1023  * \param[in]  src  Result to copy
1024  * \param[out] dst  Where to copy \p src to
1025  */
1026 void
1027 pcmk__copy_result(const pcmk__action_result_t *src, pcmk__action_result_t *dst)
     /* [previous][next][first][last][top][bottom][index][help] */
1028 {
1029     CRM_CHECK((src != NULL) && (dst != NULL), return);
1030     dst->exit_status = src->exit_status;
1031     dst->execution_status = src->execution_status;
1032     pcmk__str_update(&dst->exit_reason, src->exit_reason);
1033     pcmk__str_update(&dst->action_stdout, src->action_stdout);
1034     pcmk__str_update(&dst->action_stderr, src->action_stderr);
1035 }
1036 
1037 // Deprecated functions kept only for backward API compatibility
1038 // LCOV_EXCL_START
1039 
1040 #include <crm/common/results_compat.h>
1041 
1042 crm_exit_t
1043 crm_errno2exit(int rc)
     /* [previous][next][first][last][top][bottom][index][help] */
1044 {
1045     return pcmk_rc2exitc(pcmk_legacy2rc(rc));
1046 }
1047 
1048 // LCOV_EXCL_STOP
1049 // End deprecated API

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