Blame SOURCES/003-return-codes.patch

ed4e54
From 55ebd895ba2c64713c3db2590ffe22c15b8563e3 Mon Sep 17 00:00:00 2001
ed4e54
From: Ken Gaillot <kgaillot@redhat.com>
ed4e54
Date: Fri, 13 Dec 2019 16:05:05 -0600
ed4e54
Subject: [PATCH] Refactor: libcrmcommon: introduce new set of return codes
ed4e54
ed4e54
Since we plan to introduce a high-level public API, it's a good time to
ed4e54
introduce some best practices.
ed4e54
ed4e54
Most Pacemaker API functions currently return an integer return code, such that
ed4e54
its absolute value is either a system error number or a custom pcmk_err_*
ed4e54
number. This is less than ideal because system error numbers are constrained
ed4e54
only to the positive int range, so there's the possibility (though not noticed
ed4e54
in the wild) that system errors and custom errors could collide.
ed4e54
ed4e54
The new method being introduced here still uses an integer return code,
ed4e54
but negative values are from a new enumeration, and positive values are
ed4e54
system error numbers. 0 still represents success.
ed4e54
ed4e54
It is expected that the new method will be used with new functions, and
ed4e54
existing internal functions will be gradually refactored to use it as well.
ed4e54
Existing public API functions can be addressed at the next backward
ed4e54
compatibility break (2.1.0).
ed4e54
---
ed4e54
 include/crm/common/results.h |  59 ++++-
ed4e54
 lib/common/results.c         | 536 ++++++++++++++++++++++++++++++-------------
ed4e54
 tools/crm_error.c            | 100 +++++---
ed4e54
 3 files changed, 493 insertions(+), 202 deletions(-)
ed4e54
ed4e54
diff --git a/include/crm/common/results.h b/include/crm/common/results.h
ed4e54
index 7a32110..b29a016 100644
ed4e54
--- a/include/crm/common/results.h
ed4e54
+++ b/include/crm/common/results.h
ed4e54
@@ -1,5 +1,5 @@
ed4e54
 /*
ed4e54
- * Copyright 2012-2019 the Pacemaker project contributors
ed4e54
+ * Copyright 2012-2020 the Pacemaker project contributors
ed4e54
  *
ed4e54
  * The version control history for this file may have further details.
ed4e54
  *
ed4e54
@@ -49,11 +49,21 @@ extern "C" {
ed4e54
 /*
ed4e54
  * Function return codes
ed4e54
  *
ed4e54
+ * Most Pacemaker API functions return an integer return code. There are two
ed4e54
+ * alternative interpretations. The legacy interpration is that the absolute
ed4e54
+ * value of the return code is either a system error number or a custom
ed4e54
+ * pcmk_err_* number. This is less than ideal because system error numbers are
ed4e54
+ * constrained only to the positive int range, so there's the possibility
ed4e54
+ * (though not noticed in the wild) that system errors and custom errors could
ed4e54
+ * collide. The new intepretation is that negative values are from the pcmk_rc_e
ed4e54
+ * enum, and positive values are system error numbers. Both use 0 for success.
ed4e54
+ *
ed4e54
  * For system error codes, see:
ed4e54
  * - /usr/include/asm-generic/errno.h
ed4e54
  * - /usr/include/asm-generic/errno-base.h
ed4e54
  */
ed4e54
 
ed4e54
+// Legacy custom return codes for Pacemaker API functions (deprecated)
ed4e54
 #  define pcmk_ok                       0
ed4e54
 #  define PCMK_ERROR_OFFSET             190    /* Replacements on non-linux systems, see include/portability.h */
ed4e54
 #  define PCMK_CUSTOM_OFFSET            200    /* Purely custom codes */
ed4e54
@@ -75,6 +85,48 @@ extern "C" {
ed4e54
 #  define pcmk_err_bad_nvpair           216
ed4e54
 #  define pcmk_err_unknown_format       217
ed4e54
 
ed4e54
+/*!
ed4e54
+ * \enum pcmk_rc_e
ed4e54
+ * \brief Return codes for Pacemaker API functions
ed4e54
+ *
ed4e54
+ * Any Pacemaker API function documented as returning a "standard Pacemaker
ed4e54
+ * return code" will return pcmk_rc_ok (0) on success, and one of this
ed4e54
+ * enumeration's other (negative) values or a (positive) system error number
ed4e54
+ * otherwise. The custom codes are at -1001 and lower, so that the caller may
ed4e54
+ * use -1 through -1000 for their own custom values if desired. While generally
ed4e54
+ * referred to as "errors", nonzero values simply indicate a result, which might
ed4e54
+ * or might not be an error depending on the calling context.
ed4e54
+ */
ed4e54
+enum pcmk_rc_e {
ed4e54
+    /* When adding new values, use consecutively lower numbers, update the array
ed4e54
+     * in lib/common/results.c, and test with crm_error.
ed4e54
+     */
ed4e54
+    pcmk_rc_no_quorum           = -1017,
ed4e54
+    pcmk_rc_schema_validation   = -1016,
ed4e54
+    pcmk_rc_schema_unchanged    = -1015,
ed4e54
+    pcmk_rc_transform_failed    = -1014,
ed4e54
+    pcmk_rc_old_data            = -1013,
ed4e54
+    pcmk_rc_diff_failed         = -1012,
ed4e54
+    pcmk_rc_diff_resync         = -1011,
ed4e54
+    pcmk_rc_cib_modified        = -1010,
ed4e54
+    pcmk_rc_cib_backup          = -1009,
ed4e54
+    pcmk_rc_cib_save            = -1008,
ed4e54
+    pcmk_rc_cib_corrupt         = -1007,
ed4e54
+    pcmk_rc_multiple            = -1006,
ed4e54
+    pcmk_rc_node_unknown        = -1005,
ed4e54
+    pcmk_rc_already             = -1004,
ed4e54
+    pcmk_rc_bad_nvpair          = -1003,
ed4e54
+    pcmk_rc_unknown_format      = -1002,
ed4e54
+    // Developers: Use a more specific code than pcmk_rc_error whenever possible
ed4e54
+    pcmk_rc_error               = -1001,
ed4e54
+
ed4e54
+    // Values -1 through -1000 reserved for caller use
ed4e54
+
ed4e54
+    pcmk_rc_ok                  =     0
ed4e54
+
ed4e54
+    // Positive values reserved for system error numbers
ed4e54
+};
ed4e54
+
ed4e54
 /*
ed4e54
  * Exit status codes
ed4e54
  *
ed4e54
@@ -150,6 +202,11 @@ typedef enum crm_exit_e {
ed4e54
     CRM_EX_MAX                  = 255, // ensure crm_exit_t can hold this
ed4e54
 } crm_exit_t;
ed4e54
 
ed4e54
+const char *pcmk_rc_name(int rc);
ed4e54
+const char *pcmk_rc_str(int rc);
ed4e54
+crm_exit_t pcmk_rc2exitc(int rc);
ed4e54
+int pcmk_rc2legacy(int rc);
ed4e54
+int pcmk_legacy2rc(int legacy_rc);
ed4e54
 const char *pcmk_strerror(int rc);
ed4e54
 const char *pcmk_errorname(int rc);
ed4e54
 const char *bz2_strerror(int rc);
ed4e54
diff --git a/lib/common/results.c b/lib/common/results.c
ed4e54
index b80191c..189648f 100644
ed4e54
--- a/lib/common/results.c
ed4e54
+++ b/lib/common/results.c
ed4e54
@@ -1,5 +1,5 @@
ed4e54
 /*
ed4e54
- * Copyright 2004-2019 the Pacemaker project contributors
ed4e54
+ * Copyright 2004-2020 the Pacemaker project contributors
ed4e54
  *
ed4e54
  * The version control history for this file may have further details.
ed4e54
  *
ed4e54
@@ -22,148 +22,14 @@
ed4e54
 #include <crm/common/mainloop.h>
ed4e54
 #include <crm/common/xml.h>
ed4e54
 
ed4e54
+// @COMPAT Legacy function return codes
ed4e54
+
ed4e54
+//! \deprecated Use standard return codes and pcmk_rc_name() instead
ed4e54
 const char *
ed4e54
 pcmk_errorname(int rc)
ed4e54
 {
ed4e54
-    int error = abs(rc);
ed4e54
-
ed4e54
-    switch (error) {
ed4e54
-        case E2BIG: return "E2BIG";
ed4e54
-        case EACCES: return "EACCES";
ed4e54
-        case EADDRINUSE: return "EADDRINUSE";
ed4e54
-        case EADDRNOTAVAIL: return "EADDRNOTAVAIL";
ed4e54
-        case EAFNOSUPPORT: return "EAFNOSUPPORT";
ed4e54
-        case EAGAIN: return "EAGAIN";
ed4e54
-        case EALREADY: return "EALREADY";
ed4e54
-        case EBADF: return "EBADF";
ed4e54
-        case EBADMSG: return "EBADMSG";
ed4e54
-        case EBUSY: return "EBUSY";
ed4e54
-        case ECANCELED: return "ECANCELED";
ed4e54
-        case ECHILD: return "ECHILD";
ed4e54
-        case ECOMM: return "ECOMM";
ed4e54
-        case ECONNABORTED: return "ECONNABORTED";
ed4e54
-        case ECONNREFUSED: return "ECONNREFUSED";
ed4e54
-        case ECONNRESET: return "ECONNRESET";
ed4e54
-        /* case EDEADLK: return "EDEADLK"; */
ed4e54
-        case EDESTADDRREQ: return "EDESTADDRREQ";
ed4e54
-        case EDOM: return "EDOM";
ed4e54
-        case EDQUOT: return "EDQUOT";
ed4e54
-        case EEXIST: return "EEXIST";
ed4e54
-        case EFAULT: return "EFAULT";
ed4e54
-        case EFBIG: return "EFBIG";
ed4e54
-        case EHOSTDOWN: return "EHOSTDOWN";
ed4e54
-        case EHOSTUNREACH: return "EHOSTUNREACH";
ed4e54
-        case EIDRM: return "EIDRM";
ed4e54
-        case EILSEQ: return "EILSEQ";
ed4e54
-        case EINPROGRESS: return "EINPROGRESS";
ed4e54
-        case EINTR: return "EINTR";
ed4e54
-        case EINVAL: return "EINVAL";
ed4e54
-        case EIO: return "EIO";
ed4e54
-        case EISCONN: return "EISCONN";
ed4e54
-        case EISDIR: return "EISDIR";
ed4e54
-        case ELIBACC: return "ELIBACC";
ed4e54
-        case ELOOP: return "ELOOP";
ed4e54
-        case EMFILE: return "EMFILE";
ed4e54
-        case EMLINK: return "EMLINK";
ed4e54
-        case EMSGSIZE: return "EMSGSIZE";
ed4e54
-#ifdef EMULTIHOP // Not available on OpenBSD
ed4e54
-        case EMULTIHOP: return "EMULTIHOP";
ed4e54
-#endif
ed4e54
-        case ENAMETOOLONG: return "ENAMETOOLONG";
ed4e54
-        case ENETDOWN: return "ENETDOWN";
ed4e54
-        case ENETRESET: return "ENETRESET";
ed4e54
-        case ENETUNREACH: return "ENETUNREACH";
ed4e54
-        case ENFILE: return "ENFILE";
ed4e54
-        case ENOBUFS: return "ENOBUFS";
ed4e54
-        case ENODATA: return "ENODATA";
ed4e54
-        case ENODEV: return "ENODEV";
ed4e54
-        case ENOENT: return "ENOENT";
ed4e54
-        case ENOEXEC: return "ENOEXEC";
ed4e54
-        case ENOKEY: return "ENOKEY";
ed4e54
-        case ENOLCK: return "ENOLCK";
ed4e54
-#ifdef ENOLINK // Not available on OpenBSD
ed4e54
-        case ENOLINK: return "ENOLINK";
ed4e54
-#endif
ed4e54
-        case ENOMEM: return "ENOMEM";
ed4e54
-        case ENOMSG: return "ENOMSG";
ed4e54
-        case ENOPROTOOPT: return "ENOPROTOOPT";
ed4e54
-        case ENOSPC: return "ENOSPC";
ed4e54
-        case ENOSR: return "ENOSR";
ed4e54
-        case ENOSTR: return "ENOSTR";
ed4e54
-        case ENOSYS: return "ENOSYS";
ed4e54
-        case ENOTBLK: return "ENOTBLK";
ed4e54
-        case ENOTCONN: return "ENOTCONN";
ed4e54
-        case ENOTDIR: return "ENOTDIR";
ed4e54
-        case ENOTEMPTY: return "ENOTEMPTY";
ed4e54
-        case ENOTSOCK: return "ENOTSOCK";
ed4e54
-        /* case ENOTSUP: return "ENOTSUP"; */
ed4e54
-        case ENOTTY: return "ENOTTY";
ed4e54
-        case ENOTUNIQ: return "ENOTUNIQ";
ed4e54
-        case ENXIO: return "ENXIO";
ed4e54
-        case EOPNOTSUPP: return "EOPNOTSUPP";
ed4e54
-        case EOVERFLOW: return "EOVERFLOW";
ed4e54
-        case EPERM: return "EPERM";
ed4e54
-        case EPFNOSUPPORT: return "EPFNOSUPPORT";
ed4e54
-        case EPIPE: return "EPIPE";
ed4e54
-        case EPROTO: return "EPROTO";
ed4e54
-        case EPROTONOSUPPORT: return "EPROTONOSUPPORT";
ed4e54
-        case EPROTOTYPE: return "EPROTOTYPE";
ed4e54
-        case ERANGE: return "ERANGE";
ed4e54
-        case EREMOTE: return "EREMOTE";
ed4e54
-        case EREMOTEIO: return "EREMOTEIO";
ed4e54
-
ed4e54
-        case EROFS: return "EROFS";
ed4e54
-        case ESHUTDOWN: return "ESHUTDOWN";
ed4e54
-        case ESPIPE: return "ESPIPE";
ed4e54
-        case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
ed4e54
-        case ESRCH: return "ESRCH";
ed4e54
-        case ESTALE: return "ESTALE";
ed4e54
-        case ETIME: return "ETIME";
ed4e54
-        case ETIMEDOUT: return "ETIMEDOUT";
ed4e54
-        case ETXTBSY: return "ETXTBSY";
ed4e54
-        case EUNATCH: return "EUNATCH";
ed4e54
-        case EUSERS: return "EUSERS";
ed4e54
-        /* case EWOULDBLOCK: return "EWOULDBLOCK"; */
ed4e54
-        case EXDEV: return "EXDEV";
ed4e54
-
ed4e54
-#ifdef EBADE
ed4e54
-            /* Not available on OSX */
ed4e54
-        case EBADE: return "EBADE";
ed4e54
-        case EBADFD: return "EBADFD";
ed4e54
-        case EBADSLT: return "EBADSLT";
ed4e54
-        case EDEADLOCK: return "EDEADLOCK";
ed4e54
-        case EBADR: return "EBADR";
ed4e54
-        case EBADRQC: return "EBADRQC";
ed4e54
-        case ECHRNG: return "ECHRNG";
ed4e54
-#ifdef EISNAM /* Not available on Illumos/Solaris */
ed4e54
-        case EISNAM: return "EISNAM";
ed4e54
-        case EKEYEXPIRED: return "EKEYEXPIRED";
ed4e54
-        case EKEYREJECTED: return "EKEYREJECTED";
ed4e54
-        case EKEYREVOKED: return "EKEYREVOKED";
ed4e54
-#endif
ed4e54
-        case EL2HLT: return "EL2HLT";
ed4e54
-        case EL2NSYNC: return "EL2NSYNC";
ed4e54
-        case EL3HLT: return "EL3HLT";
ed4e54
-        case EL3RST: return "EL3RST";
ed4e54
-        case ELIBBAD: return "ELIBBAD";
ed4e54
-        case ELIBMAX: return "ELIBMAX";
ed4e54
-        case ELIBSCN: return "ELIBSCN";
ed4e54
-        case ELIBEXEC: return "ELIBEXEC";
ed4e54
-#ifdef ENOMEDIUM  /* Not available on Illumos/Solaris */
ed4e54
-        case ENOMEDIUM: return "ENOMEDIUM";
ed4e54
-        case EMEDIUMTYPE: return "EMEDIUMTYPE";
ed4e54
-#endif
ed4e54
-        case ENONET: return "ENONET";
ed4e54
-        case ENOPKG: return "ENOPKG";
ed4e54
-        case EREMCHG: return "EREMCHG";
ed4e54
-        case ERESTART: return "ERESTART";
ed4e54
-        case ESTRPIPE: return "ESTRPIPE";
ed4e54
-#ifdef EUCLEAN  /* Not available on Illumos/Solaris */
ed4e54
-        case EUCLEAN: return "EUCLEAN";
ed4e54
-#endif
ed4e54
-        case EXFULL: return "EXFULL";
ed4e54
-#endif
ed4e54
-
ed4e54
+    rc = abs(rc);
ed4e54
+    switch (rc) {
ed4e54
         case pcmk_err_generic: return "pcmk_err_generic";
ed4e54
         case pcmk_err_no_quorum: return "pcmk_err_no_quorum";
ed4e54
         case pcmk_err_schema_validation: return "pcmk_err_schema_validation";
ed4e54
@@ -180,24 +46,26 @@ pcmk_errorname(int rc)
ed4e54
         case pcmk_err_already: return "pcmk_err_already";
ed4e54
         case pcmk_err_bad_nvpair: return "pcmk_err_bad_nvpair";
ed4e54
         case pcmk_err_unknown_format: return "pcmk_err_unknown_format";
ed4e54
+        default: return pcmk_rc_name(rc); // system errno
ed4e54
     }
ed4e54
-    return "Unknown";
ed4e54
 }
ed4e54
 
ed4e54
+//! \deprecated Use standard return codes and pcmk_rc_str() instead
ed4e54
 const char *
ed4e54
 pcmk_strerror(int rc)
ed4e54
 {
ed4e54
-    int error = abs(rc);
ed4e54
-
ed4e54
-    if (error == 0) {
ed4e54
+    if (rc == 0) {
ed4e54
         return "OK";
ed4e54
+    }
ed4e54
 
ed4e54
-    // Of course error > 0 ... unless someone passed INT_MIN as rc
ed4e54
-    } else if ((error > 0) && (error < PCMK_ERROR_OFFSET)) {
ed4e54
-        return strerror(error);
ed4e54
+    rc = abs(rc);
ed4e54
+
ed4e54
+    // Of course rc > 0 ... unless someone passed INT_MIN as rc
ed4e54
+    if ((rc > 0) && (rc < PCMK_ERROR_OFFSET)) {
ed4e54
+        return strerror(rc);
ed4e54
     }
ed4e54
 
ed4e54
-    switch (error) {
ed4e54
+    switch (rc) {
ed4e54
         case pcmk_err_generic:
ed4e54
             return "Generic Pacemaker error";
ed4e54
         case pcmk_err_no_quorum:
ed4e54
@@ -253,11 +121,313 @@ pcmk_strerror(int rc)
ed4e54
         case ENOKEY:
ed4e54
             return "Required key not available";
ed4e54
     }
ed4e54
-
ed4e54
     crm_err("Unknown error code: %d", rc);
ed4e54
     return "Unknown error";
ed4e54
 }
ed4e54
 
ed4e54
+// Standard Pacemaker API return codes
ed4e54
+
ed4e54
+/* This array is used only for nonzero values of pcmk_rc_e. Its values must be
ed4e54
+ * kept in the exact reverse order of the enum value numbering (i.e. add new
ed4e54
+ * values to the end of the array).
ed4e54
+ */
ed4e54
+static struct pcmk__rc_info {
ed4e54
+    const char *name;
ed4e54
+    const char *desc;
ed4e54
+    int legacy_rc;
ed4e54
+} pcmk__rcs[] = {
ed4e54
+    { "pcmk_rc_error",
ed4e54
+      "Error",
ed4e54
+      -pcmk_err_generic,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_unknown_format",
ed4e54
+      "Unknown output format",
ed4e54
+      -pcmk_err_unknown_format,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_bad_nvpair",
ed4e54
+      "Bad name/value pair given",
ed4e54
+      -pcmk_err_bad_nvpair,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_already",
ed4e54
+      "Already in requested state",
ed4e54
+      -pcmk_err_already,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_node_unknown",
ed4e54
+      "Node not found",
ed4e54
+      -pcmk_err_node_unknown,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_multiple",
ed4e54
+      "Resource active on multiple nodes",
ed4e54
+      -pcmk_err_multiple,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_cib_corrupt",
ed4e54
+      "Could not parse on-disk configuration",
ed4e54
+      -pcmk_err_cib_corrupt,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_cib_save",
ed4e54
+      "Could not save new configuration to disk",
ed4e54
+      -pcmk_err_cib_save,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_cib_backup",
ed4e54
+      "Could not archive previous configuration",
ed4e54
+      -pcmk_err_cib_backup,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_cib_modified",
ed4e54
+      "On-disk configuration was manually modified",
ed4e54
+      -pcmk_err_cib_modified,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_diff_resync",
ed4e54
+      "Application of update diff failed, requesting full refresh",
ed4e54
+      -pcmk_err_diff_resync,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_diff_failed",
ed4e54
+      "Application of update diff failed",
ed4e54
+      -pcmk_err_diff_failed,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_old_data",
ed4e54
+      "Update was older than existing configuration",
ed4e54
+      -pcmk_err_old_data,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_transform_failed",
ed4e54
+      "Schema transform failed",
ed4e54
+      -pcmk_err_transform_failed,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_schema_unchanged",
ed4e54
+      "Schema is already the latest available",
ed4e54
+      -pcmk_err_schema_unchanged,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_schema_validation",
ed4e54
+      "Update does not conform to the configured schema",
ed4e54
+      -pcmk_err_schema_validation,
ed4e54
+    },
ed4e54
+    { "pcmk_rc_no_quorum",
ed4e54
+      "Operation requires quorum",
ed4e54
+      -pcmk_err_no_quorum,
ed4e54
+    },
ed4e54
+};
ed4e54
+
ed4e54
+#define PCMK__N_RC (sizeof(pcmk__rcs) / sizeof(struct pcmk__rc_info))
ed4e54
+
ed4e54
+/*!
ed4e54
+ * \brief Get a return code constant name as a string
ed4e54
+ *
ed4e54
+ * \param[in] rc  Integer return code to convert
ed4e54
+ *
ed4e54
+ * \return String of constant name corresponding to rc
ed4e54
+ */
ed4e54
+const char *
ed4e54
+pcmk_rc_name(int rc)
ed4e54
+{
ed4e54
+    if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < PCMK__N_RC)) {
ed4e54
+        return pcmk__rcs[pcmk_rc_error - rc].name;
ed4e54
+    }
ed4e54
+    switch (rc) {
ed4e54
+        case pcmk_rc_ok:        return "pcmk_rc_ok";
ed4e54
+        case E2BIG:             return "E2BIG";
ed4e54
+        case EACCES:            return "EACCES";
ed4e54
+        case EADDRINUSE:        return "EADDRINUSE";
ed4e54
+        case EADDRNOTAVAIL:     return "EADDRNOTAVAIL";
ed4e54
+        case EAFNOSUPPORT:      return "EAFNOSUPPORT";
ed4e54
+        case EAGAIN:            return "EAGAIN";
ed4e54
+        case EALREADY:          return "EALREADY";
ed4e54
+        case EBADF:             return "EBADF";
ed4e54
+        case EBADMSG:           return "EBADMSG";
ed4e54
+        case EBUSY:             return "EBUSY";
ed4e54
+        case ECANCELED:         return "ECANCELED";
ed4e54
+        case ECHILD:            return "ECHILD";
ed4e54
+        case ECOMM:             return "ECOMM";
ed4e54
+        case ECONNABORTED:      return "ECONNABORTED";
ed4e54
+        case ECONNREFUSED:      return "ECONNREFUSED";
ed4e54
+        case ECONNRESET:        return "ECONNRESET";
ed4e54
+        /* case EDEADLK:        return "EDEADLK"; */
ed4e54
+        case EDESTADDRREQ:      return "EDESTADDRREQ";
ed4e54
+        case EDOM:              return "EDOM";
ed4e54
+        case EDQUOT:            return "EDQUOT";
ed4e54
+        case EEXIST:            return "EEXIST";
ed4e54
+        case EFAULT:            return "EFAULT";
ed4e54
+        case EFBIG:             return "EFBIG";
ed4e54
+        case EHOSTDOWN:         return "EHOSTDOWN";
ed4e54
+        case EHOSTUNREACH:      return "EHOSTUNREACH";
ed4e54
+        case EIDRM:             return "EIDRM";
ed4e54
+        case EILSEQ:            return "EILSEQ";
ed4e54
+        case EINPROGRESS:       return "EINPROGRESS";
ed4e54
+        case EINTR:             return "EINTR";
ed4e54
+        case EINVAL:            return "EINVAL";
ed4e54
+        case EIO:               return "EIO";
ed4e54
+        case EISCONN:           return "EISCONN";
ed4e54
+        case EISDIR:            return "EISDIR";
ed4e54
+        case ELIBACC:           return "ELIBACC";
ed4e54
+        case ELOOP:             return "ELOOP";
ed4e54
+        case EMFILE:            return "EMFILE";
ed4e54
+        case EMLINK:            return "EMLINK";
ed4e54
+        case EMSGSIZE:          return "EMSGSIZE";
ed4e54
+#ifdef EMULTIHOP // Not available on OpenBSD
ed4e54
+        case EMULTIHOP:         return "EMULTIHOP";
ed4e54
+#endif
ed4e54
+        case ENAMETOOLONG:      return "ENAMETOOLONG";
ed4e54
+        case ENETDOWN:          return "ENETDOWN";
ed4e54
+        case ENETRESET:         return "ENETRESET";
ed4e54
+        case ENETUNREACH:       return "ENETUNREACH";
ed4e54
+        case ENFILE:            return "ENFILE";
ed4e54
+        case ENOBUFS:           return "ENOBUFS";
ed4e54
+        case ENODATA:           return "ENODATA";
ed4e54
+        case ENODEV:            return "ENODEV";
ed4e54
+        case ENOENT:            return "ENOENT";
ed4e54
+        case ENOEXEC:           return "ENOEXEC";
ed4e54
+        case ENOKEY:            return "ENOKEY";
ed4e54
+        case ENOLCK:            return "ENOLCK";
ed4e54
+#ifdef ENOLINK // Not available on OpenBSD
ed4e54
+        case ENOLINK:           return "ENOLINK";
ed4e54
+#endif
ed4e54
+        case ENOMEM:            return "ENOMEM";
ed4e54
+        case ENOMSG:            return "ENOMSG";
ed4e54
+        case ENOPROTOOPT:       return "ENOPROTOOPT";
ed4e54
+        case ENOSPC:            return "ENOSPC";
ed4e54
+        case ENOSR:             return "ENOSR";
ed4e54
+        case ENOSTR:            return "ENOSTR";
ed4e54
+        case ENOSYS:            return "ENOSYS";
ed4e54
+        case ENOTBLK:           return "ENOTBLK";
ed4e54
+        case ENOTCONN:          return "ENOTCONN";
ed4e54
+        case ENOTDIR:           return "ENOTDIR";
ed4e54
+        case ENOTEMPTY:         return "ENOTEMPTY";
ed4e54
+        case ENOTSOCK:          return "ENOTSOCK";
ed4e54
+#if ENOTSUP != EOPNOTSUPP
ed4e54
+        case ENOTSUP:           return "ENOTSUP";
ed4e54
+#endif
ed4e54
+        case ENOTTY:            return "ENOTTY";
ed4e54
+        case ENOTUNIQ:          return "ENOTUNIQ";
ed4e54
+        case ENXIO:             return "ENXIO";
ed4e54
+        case EOPNOTSUPP:        return "EOPNOTSUPP";
ed4e54
+        case EOVERFLOW:         return "EOVERFLOW";
ed4e54
+        case EPERM:             return "EPERM";
ed4e54
+        case EPFNOSUPPORT:      return "EPFNOSUPPORT";
ed4e54
+        case EPIPE:             return "EPIPE";
ed4e54
+        case EPROTO:            return "EPROTO";
ed4e54
+        case EPROTONOSUPPORT:   return "EPROTONOSUPPORT";
ed4e54
+        case EPROTOTYPE:        return "EPROTOTYPE";
ed4e54
+        case ERANGE:            return "ERANGE";
ed4e54
+        case EREMOTE:           return "EREMOTE";
ed4e54
+        case EREMOTEIO:         return "EREMOTEIO";
ed4e54
+        case EROFS:             return "EROFS";
ed4e54
+        case ESHUTDOWN:         return "ESHUTDOWN";
ed4e54
+        case ESPIPE:            return "ESPIPE";
ed4e54
+        case ESOCKTNOSUPPORT:   return "ESOCKTNOSUPPORT";
ed4e54
+        case ESRCH:             return "ESRCH";
ed4e54
+        case ESTALE:            return "ESTALE";
ed4e54
+        case ETIME:             return "ETIME";
ed4e54
+        case ETIMEDOUT:         return "ETIMEDOUT";
ed4e54
+        case ETXTBSY:           return "ETXTBSY";
ed4e54
+        case EUNATCH:           return "EUNATCH";
ed4e54
+        case EUSERS:            return "EUSERS";
ed4e54
+        /* case EWOULDBLOCK:    return "EWOULDBLOCK"; */
ed4e54
+        case EXDEV:             return "EXDEV";
ed4e54
+
ed4e54
+#ifdef EBADE // Not available on OS X
ed4e54
+        case EBADE:             return "EBADE";
ed4e54
+        case EBADFD:            return "EBADFD";
ed4e54
+        case EBADSLT:           return "EBADSLT";
ed4e54
+        case EDEADLOCK:         return "EDEADLOCK";
ed4e54
+        case EBADR:             return "EBADR";
ed4e54
+        case EBADRQC:           return "EBADRQC";
ed4e54
+        case ECHRNG:            return "ECHRNG";
ed4e54
+#ifdef EISNAM // Not available on OS X, Illumos, Solaris
ed4e54
+        case EISNAM:            return "EISNAM";
ed4e54
+        case EKEYEXPIRED:       return "EKEYEXPIRED";
ed4e54
+        case EKEYREJECTED:      return "EKEYREJECTED";
ed4e54
+        case EKEYREVOKED:       return "EKEYREVOKED";
ed4e54
+#endif
ed4e54
+        case EL2HLT:            return "EL2HLT";
ed4e54
+        case EL2NSYNC:          return "EL2NSYNC";
ed4e54
+        case EL3HLT:            return "EL3HLT";
ed4e54
+        case EL3RST:            return "EL3RST";
ed4e54
+        case ELIBBAD:           return "ELIBBAD";
ed4e54
+        case ELIBMAX:           return "ELIBMAX";
ed4e54
+        case ELIBSCN:           return "ELIBSCN";
ed4e54
+        case ELIBEXEC:          return "ELIBEXEC";
ed4e54
+#ifdef ENOMEDIUM // Not available on OS X, Illumos, Solaris
ed4e54
+        case ENOMEDIUM:         return "ENOMEDIUM";
ed4e54
+        case EMEDIUMTYPE:       return "EMEDIUMTYPE";
ed4e54
+#endif
ed4e54
+        case ENONET:            return "ENONET";
ed4e54
+        case ENOPKG:            return "ENOPKG";
ed4e54
+        case EREMCHG:           return "EREMCHG";
ed4e54
+        case ERESTART:          return "ERESTART";
ed4e54
+        case ESTRPIPE:          return "ESTRPIPE";
ed4e54
+#ifdef EUCLEAN // Not available on OS X, Illumos, Solaris
ed4e54
+        case EUCLEAN:           return "EUCLEAN";
ed4e54
+#endif
ed4e54
+        case EXFULL:            return "EXFULL";
ed4e54
+#endif // EBADE
ed4e54
+        default:                return "Unknown";
ed4e54
+    }
ed4e54
+}
ed4e54
+
ed4e54
+/*!
ed4e54
+ * \brief Get a user-friendly description of a return code
ed4e54
+ *
ed4e54
+ * \param[in] rc  Integer return code to convert
ed4e54
+ *
ed4e54
+ * \return String description of rc
ed4e54
+ */
ed4e54
+const char *
ed4e54
+pcmk_rc_str(int rc)
ed4e54
+{
ed4e54
+    if (rc == pcmk_rc_ok) {
ed4e54
+        return "OK";
ed4e54
+    }
ed4e54
+    if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < PCMK__N_RC)) {
ed4e54
+        return pcmk__rcs[pcmk_rc_error - rc].desc;
ed4e54
+    }
ed4e54
+    if (rc < 0) {
ed4e54
+        return "Unknown error";
ed4e54
+    }
ed4e54
+    return strerror(rc);
ed4e54
+}
ed4e54
+
ed4e54
+// This returns negative values for errors
ed4e54
+//! \deprecated Use standard return codes instead
ed4e54
+int
ed4e54
+pcmk_rc2legacy(int rc)
ed4e54
+{
ed4e54
+    if (rc >= 0) {
ed4e54
+        return -rc; // OK or system errno
ed4e54
+    }
ed4e54
+    if ((rc <= pcmk_rc_error) && ((pcmk_rc_error - rc) < PCMK__N_RC)) {
ed4e54
+        return pcmk__rcs[pcmk_rc_error - rc].legacy_rc;
ed4e54
+    }
ed4e54
+    return -pcmk_err_generic;
ed4e54
+}
ed4e54
+
ed4e54
+//! \deprecated Use standard return codes instead
ed4e54
+int
ed4e54
+pcmk_legacy2rc(int legacy_rc)
ed4e54
+{
ed4e54
+    legacy_rc = abs(legacy_rc);
ed4e54
+    switch (legacy_rc) {
ed4e54
+        case pcmk_err_no_quorum:            return pcmk_rc_no_quorum;
ed4e54
+        case pcmk_err_schema_validation:    return pcmk_rc_schema_validation;
ed4e54
+        case pcmk_err_schema_unchanged:     return pcmk_rc_schema_unchanged;
ed4e54
+        case pcmk_err_transform_failed:     return pcmk_rc_transform_failed;
ed4e54
+        case pcmk_err_old_data:             return pcmk_rc_old_data;
ed4e54
+        case pcmk_err_diff_failed:          return pcmk_rc_diff_failed;
ed4e54
+        case pcmk_err_diff_resync:          return pcmk_rc_diff_resync;
ed4e54
+        case pcmk_err_cib_modified:         return pcmk_rc_cib_modified;
ed4e54
+        case pcmk_err_cib_backup:           return pcmk_rc_cib_backup;
ed4e54
+        case pcmk_err_cib_save:             return pcmk_rc_cib_save;
ed4e54
+        case pcmk_err_cib_corrupt:          return pcmk_rc_cib_corrupt;
ed4e54
+        case pcmk_err_multiple:             return pcmk_rc_multiple;
ed4e54
+        case pcmk_err_node_unknown:         return pcmk_rc_node_unknown;
ed4e54
+        case pcmk_err_already:              return pcmk_rc_already;
ed4e54
+        case pcmk_err_bad_nvpair:           return pcmk_rc_bad_nvpair;
ed4e54
+        case pcmk_err_unknown_format:       return pcmk_rc_unknown_format;
ed4e54
+        case pcmk_err_generic:              return pcmk_rc_error;
ed4e54
+        case pcmk_ok:                       return pcmk_rc_ok;
ed4e54
+        default:                            return legacy_rc; // system errno
ed4e54
+    }
ed4e54
+}
ed4e54
+
ed4e54
+// Exit status codes
ed4e54
+
ed4e54
 const char *
ed4e54
 crm_exit_name(crm_exit_t exit_code)
ed4e54
 {
ed4e54
@@ -347,26 +517,17 @@ crm_exit_str(crm_exit_t exit_code)
ed4e54
         case CRM_EX_TIMEOUT: return "Timeout occurred";
ed4e54
         case CRM_EX_MAX: return "Error occurred";
ed4e54
     }
ed4e54
-    if (exit_code > 128) {
ed4e54
+    if ((exit_code > 128) && (exit_code < CRM_EX_MAX)) {
ed4e54
         return "Interrupted by signal";
ed4e54
     }
ed4e54
     return "Unknown exit status";
ed4e54
 }
ed4e54
 
ed4e54
-/*!
ed4e54
- * \brief Map an errno to a similar exit status
ed4e54
- *
ed4e54
- * \param[in] errno  Error number to map
ed4e54
- *
ed4e54
- * \return Exit status corresponding to errno
ed4e54
- */
ed4e54
+//! \deprecated Use standard return codes and pcmk_rc2exitc() instead
ed4e54
 crm_exit_t
ed4e54
 crm_errno2exit(int rc)
ed4e54
 {
ed4e54
     rc = abs(rc); // Convenience for functions that return -errno
ed4e54
-    if (rc == EOPNOTSUPP) {
ed4e54
-        rc = ENOTSUP; // Values are same on Linux, can't use both in case
ed4e54
-    }
ed4e54
     switch (rc) {
ed4e54
         case pcmk_ok:
ed4e54
             return CRM_EX_OK;
ed4e54
@@ -384,6 +545,48 @@ crm_errno2exit(int rc)
ed4e54
         case pcmk_err_bad_nvpair:
ed4e54
             return CRM_EX_INVALID_PARAM;
ed4e54
 
ed4e54
+        case pcmk_err_already:
ed4e54
+            return CRM_EX_EXISTS;
ed4e54
+
ed4e54
+        case pcmk_err_multiple:
ed4e54
+            return CRM_EX_MULTIPLE;
ed4e54
+
ed4e54
+        case pcmk_err_node_unknown:
ed4e54
+        case pcmk_err_unknown_format:
ed4e54
+            return CRM_EX_NOSUCH;
ed4e54
+
ed4e54
+        default:
ed4e54
+            return pcmk_rc2exitc(rc); // system errno
ed4e54
+    }
ed4e54
+}
ed4e54
+
ed4e54
+/*!
ed4e54
+ * \brief Map a function return code to the most similar exit code
ed4e54
+ *
ed4e54
+ * \param[in] rc  Function return code
ed4e54
+ *
ed4e54
+ * \return Most similar exit code
ed4e54
+ */
ed4e54
+crm_exit_t
ed4e54
+pcmk_rc2exitc(int rc)
ed4e54
+{
ed4e54
+    switch (rc) {
ed4e54
+        case pcmk_rc_ok:
ed4e54
+            return CRM_EX_OK;
ed4e54
+
ed4e54
+        case pcmk_rc_no_quorum:
ed4e54
+            return CRM_EX_QUORUM;
ed4e54
+
ed4e54
+        case pcmk_rc_old_data:
ed4e54
+            return CRM_EX_OLD;
ed4e54
+
ed4e54
+        case pcmk_rc_schema_validation:
ed4e54
+        case pcmk_rc_transform_failed:
ed4e54
+            return CRM_EX_CONFIG;
ed4e54
+
ed4e54
+        case pcmk_rc_bad_nvpair:
ed4e54
+            return CRM_EX_INVALID_PARAM;
ed4e54
+
ed4e54
         case EACCES:
ed4e54
             return CRM_EX_INSUFFICIENT_PRIV;
ed4e54
 
ed4e54
@@ -414,22 +617,25 @@ crm_errno2exit(int rc)
ed4e54
             return CRM_EX_DISCONNECT;
ed4e54
 
ed4e54
         case EEXIST:
ed4e54
-        case pcmk_err_already:
ed4e54
+        case pcmk_rc_already:
ed4e54
             return CRM_EX_EXISTS;
ed4e54
 
ed4e54
         case EIO:
ed4e54
             return CRM_EX_IOERR;
ed4e54
 
ed4e54
         case ENOTSUP:
ed4e54
+#if EOPNOTSUPP != ENOTSUP
ed4e54
+        case EOPNOTSUPP:
ed4e54
+#endif
ed4e54
             return CRM_EX_UNIMPLEMENT_FEATURE;
ed4e54
 
ed4e54
         case ENOTUNIQ:
ed4e54
-        case pcmk_err_multiple:
ed4e54
+        case pcmk_rc_multiple:
ed4e54
             return CRM_EX_MULTIPLE;
ed4e54
 
ed4e54
         case ENXIO:
ed4e54
-        case pcmk_err_node_unknown:
ed4e54
-        case pcmk_err_unknown_format:
ed4e54
+        case pcmk_rc_node_unknown:
ed4e54
+        case pcmk_rc_unknown_format:
ed4e54
             return CRM_EX_NOSUCH;
ed4e54
 
ed4e54
         case ETIME:
ed4e54
@@ -441,6 +647,8 @@ crm_errno2exit(int rc)
ed4e54
     }
ed4e54
 }
ed4e54
 
ed4e54
+// Other functions
ed4e54
+
ed4e54
 const char *
ed4e54
 bz2_strerror(int rc)
ed4e54
 {
ed4e54
diff --git a/tools/crm_error.c b/tools/crm_error.c
ed4e54
index f6dc73c..0dcae05 100644
ed4e54
--- a/tools/crm_error.c
ed4e54
+++ b/tools/crm_error.c
ed4e54
@@ -1,21 +1,10 @@
ed4e54
-/* 
ed4e54
- * Copyright 2012-2018 the Pacemaker project contributors
ed4e54
+/*
ed4e54
+ * Copyright 2012-2020 the Pacemaker project contributors
ed4e54
  *
ed4e54
  * The version control history for this file may have further details.
ed4e54
- * 
ed4e54
- * This program is free software; you can redistribute it and/or
ed4e54
- * modify it under the terms of the GNU General Public
ed4e54
- * License as published by the Free Software Foundation; either
ed4e54
- * version 2 of the License, or (at your option) any later version.
ed4e54
- * 
ed4e54
- * This software is distributed in the hope that it will be useful,
ed4e54
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
ed4e54
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
ed4e54
- * General Public License for more details.
ed4e54
- * 
ed4e54
- * You should have received a copy of the GNU General Public
ed4e54
- * License along with this library; if not, write to the Free Software
ed4e54
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
ed4e54
+ *
ed4e54
+ * This source code is licensed under the GNU General Public License version 2
ed4e54
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
ed4e54
  */
ed4e54
 
ed4e54
 #include <crm_internal.h>
ed4e54
@@ -33,12 +22,31 @@ static struct crm_option long_options[] = {
ed4e54
      "\n\t\t\tUseful for looking for sources of the error in source code"},
ed4e54
 
ed4e54
     {"list",    0, 0, 'l', "\tShow all known errors."},
ed4e54
-    {"exit",    0, 0, 'X', "\tInterpret as exit code rather than function return value"},
ed4e54
+    {"exit",    0, 0, 'X', "\tInterpret as exit code rather than legacy function return value"},
ed4e54
+    {"rc",      0, 0, 'r', "\tInterpret as return code rather than legacy function return value"},
ed4e54
 
ed4e54
     {0, 0, 0, 0}
ed4e54
 };
ed4e54
 /* *INDENT-ON* */
ed4e54
 
ed4e54
+static bool as_exit_code = false;
ed4e54
+static bool as_rc = false;
ed4e54
+
ed4e54
+static void
ed4e54
+get_strings(int rc, const char **name, const char **str)
ed4e54
+{
ed4e54
+    if (as_exit_code) {
ed4e54
+        *str = crm_exit_str((crm_exit_t) rc);
ed4e54
+        *name = crm_exit_name(rc);
ed4e54
+    } else if (as_rc) {
ed4e54
+        *str = pcmk_rc_str(rc);
ed4e54
+        *name = pcmk_rc_name(rc);
ed4e54
+    } else {
ed4e54
+        *str = pcmk_strerror(rc);
ed4e54
+        *name = pcmk_errorname(rc);
ed4e54
+    }
ed4e54
+}
ed4e54
+
ed4e54
 int
ed4e54
 main(int argc, char **argv)
ed4e54
 {
ed4e54
@@ -49,10 +57,12 @@ main(int argc, char **argv)
ed4e54
 
ed4e54
     bool do_list = FALSE;
ed4e54
     bool with_name = FALSE;
ed4e54
-    bool as_exit_code = FALSE;
ed4e54
+
ed4e54
+    const char *name = NULL;
ed4e54
+    const char *desc = NULL;
ed4e54
 
ed4e54
     crm_log_cli_init("crm_error");
ed4e54
-    crm_set_options(NULL, "[options] -- rc", long_options,
ed4e54
+    crm_set_options(NULL, "[options] -- <rc> [...]", long_options,
ed4e54
                     "Tool for displaying the textual name or description of a reported error code");
ed4e54
 
ed4e54
     while (flag >= 0) {
ed4e54
@@ -73,6 +83,9 @@ main(int argc, char **argv)
ed4e54
             case 'l':
ed4e54
                 do_list = TRUE;
ed4e54
                 break;
ed4e54
+            case 'r':
ed4e54
+                as_rc = true;
ed4e54
+                break;
ed4e54
             case 'X':
ed4e54
                 as_exit_code = TRUE;
ed4e54
                 break;
ed4e54
@@ -83,30 +96,43 @@ main(int argc, char **argv)
ed4e54
     }
ed4e54
 
ed4e54
     if(do_list) {
ed4e54
-        for (rc = 0; rc < 256; rc++) {
ed4e54
-            const char *name = as_exit_code? crm_exit_name(rc) : pcmk_errorname(rc);
ed4e54
-            const char *desc = as_exit_code? crm_exit_str(rc) : pcmk_strerror(rc);
ed4e54
+        int start, end, width;
ed4e54
+
ed4e54
+        // 256 is a hacky magic number that "should" be enough
ed4e54
+        if (as_rc) {
ed4e54
+            start = pcmk_rc_error - 256;
ed4e54
+            end = PCMK_CUSTOM_OFFSET;
ed4e54
+            width = 4;
ed4e54
+        } else {
ed4e54
+            start = 0;
ed4e54
+            end = 256;
ed4e54
+            width = 3;
ed4e54
+        }
ed4e54
+
ed4e54
+        for (rc = start; rc < end; rc++) {
ed4e54
+            if (rc == (pcmk_rc_error + 1)) {
ed4e54
+                // Values in between are reserved for callers, no use iterating
ed4e54
+                rc = pcmk_rc_ok;
ed4e54
+            }
ed4e54
+            get_strings(rc, &name, &desc);
ed4e54
             if (!name || !strcmp(name, "Unknown") || !strcmp(name, "CRM_EX_UNKNOWN")) {
ed4e54
-                /* Unknown */
ed4e54
+                // Undefined
ed4e54
             } else if(with_name) {
ed4e54
-                printf("%.3d: %-26s  %s\n", rc, name, desc);
ed4e54
+                printf("% .*d: %-26s  %s\n", width, rc, name, desc);
ed4e54
             } else {
ed4e54
-                printf("%.3d: %s\n", rc, desc);
ed4e54
+                printf("% .*d: %s\n", width, rc, desc);
ed4e54
             }
ed4e54
         }
ed4e54
-        return CRM_EX_OK;
ed4e54
-    }
ed4e54
 
ed4e54
-    for (lpc = optind; lpc < argc; lpc++) {
ed4e54
-        const char *str, *name;
ed4e54
-
ed4e54
-        rc = crm_atoi(argv[lpc], NULL);
ed4e54
-        str = as_exit_code? crm_exit_str(rc) : pcmk_strerror(rc);
ed4e54
-        if(with_name) {
ed4e54
-            name = as_exit_code? crm_exit_name(rc) : pcmk_errorname(rc);
ed4e54
-            printf("%s - %s\n", name, str);
ed4e54
-        } else {
ed4e54
-            printf("%s\n", str);
ed4e54
+    } else {
ed4e54
+        for (lpc = optind; lpc < argc; lpc++) {
ed4e54
+            rc = crm_atoi(argv[lpc], NULL);
ed4e54
+            get_strings(rc, &name, &desc);
ed4e54
+            if (with_name) {
ed4e54
+                printf("%s - %s\n", name, desc);
ed4e54
+            } else {
ed4e54
+                printf("%s\n", desc);
ed4e54
+            }
ed4e54
         }
ed4e54
     }
ed4e54
     return CRM_EX_OK;
ed4e54
-- 
ed4e54
1.8.3.1
ed4e54