ERR: special case system errors
[openssl.git] / include / openssl / err.h
index 66a8f480285d9ab54c2130ba16272277cd0e0463..a40d231ea098944ea549dec42bf9802675e1c8e9 100644 (file)
@@ -39,6 +39,7 @@ extern "C" {
 #  endif
 # endif
 
+# include <limits.h>
 # include <errno.h>
 
 # define ERR_TXT_MALLOCED        0x01
@@ -163,43 +164,95 @@ struct err_state_st {
 #  define X509err(f, r) ERR_raise_data(ERR_LIB_X509, (r), NULL)
 # endif
 
-/*
- * The error code currently packs as follows (viewed as hex nibbles):
+/*-
+ * The error code packs differently depending on if it records a system
+ * error or an OpenSSL error.
  *
- * LL rRRRRR
+ * A system error packs like this (we follow POSIX and only allow positive
+ * numbers that fit in an |int|):
  *
- * Where LL is the library code, r is the reason flags, and rRRRRR is the
- * reason code.
- * Do note that the reason flags is part of the reason code, and could as
- * well be seen as a section of all possible reason codes.  We do this for
- * backward compatibility reasons, i.e. how ERR_R_FATAL was implemented.
+ * +-+-------------------------------------------------------------+
+ * |1|                     system error number                     |
+ * +-+-------------------------------------------------------------+
+ *
+ * An OpenSSL error packs like this:
  *
- * System errors (ERR_LIB_SYS) are structured the same way, except they
- * don't have any reason flag.
+ * <---------------------------- 32 bits -------------------------->
+ *    <--- 8 bits ---><------------------ 23 bits ----------------->
+ * +-+---------------+---------------------------------------------+
+ * |0|    library    |                    reason                   |
+ * +-+---------------+---------------------------------------------+
  *
- * LL RRRRRR
+ * A few of the reason bits are reserved as flags with special meaning:
+ *
+ *                    <4 bits><-------------- 19 bits ------------->
+ *                   +-------+-------------------------------------+
+ *                   | rflags|                reason               |
+ *                   +-------+-------------------------------------+
+ *
+ * We have the reason flags being part of the overall reason code for
+ * backward compatibility reasons, i.e. how ERR_R_FATAL was implemented.
  */
-# define ERR_LIB_OFFSET     24L
-# define ERR_LIB_MASK       0xFF
-# define ERR_RFLAGS_OFFSET  20L
-# define ERR_RFLAGS_MASK    0xF
-# define ERR_REASON_MASK    0XFFFFFF
+
+/* Macros to help decode recorded system errors */
+# define ERR_SYSTEM_FLAG                ((unsigned int)INT_MAX + 1)
+# define ERR_SYSTEM_MASK                ((unsigned int)INT_MAX)
+
+/* Macros to help decode recorded OpenSSL errors */
+# define ERR_LIB_OFFSET                 23L
+# define ERR_LIB_MASK                   0xFF
+# define ERR_RFLAGS_OFFSET              19L
+# define ERR_RFLAGS_MASK                0xF
+# define ERR_REASON_MASK                0X7FFFFF
 
 /*
  * Reason flags are defined pre-shifted to easily combine with the reason
  * number.
  */
-# define ERR_RFLAG_FATAL    (0x1 << ERR_RFLAGS_OFFSET)
-
-/* ERR_PACK takes reason flags and reason code combined in |r| */
-# define ERR_PACK(l,f,r)                                                \
-    ( (((unsigned int)(l) & ERR_LIB_MASK) << ERR_LIB_OFFSET) |          \
-      (((unsigned int)(r) & ERR_REASON_MASK)) )
-# define ERR_GET_LIB(l)     (int)(((l) >> ERR_LIB_OFFSET) & ERR_LIB_MASK)
-# define ERR_GET_FUNC(l)    0
-# define ERR_GET_RFLAGS(l)  (int)((l) & (ERR_RFLAGS_MASK << ERR_RFLAGS_OFFSET))
-# define ERR_GET_REASON(l)  (int)((l) & ERR_REASON_MASK)
-# define ERR_FATAL_ERROR(l) (int)((l) & ERR_RFLAG_FATAL)
+# define ERR_RFLAG_FATAL                (0x1 << ERR_RFLAGS_OFFSET)
+
+# define ERR_SYSTEM_ERROR(errcode)      (((errcode) & ERR_SYSTEM_FLAG) != 0)
+
+static ossl_inline int ERR_GET_LIB(unsigned long errcode)
+{
+    if (ERR_SYSTEM_ERROR(errcode))
+        return ERR_LIB_SYS;
+    return (errcode >> ERR_LIB_OFFSET) & ERR_LIB_MASK;
+}
+
+static ossl_inline int ERR_GET_FUNC(unsigned long errcode)
+{
+    return 0;
+}
+
+static ossl_inline int ERR_GET_RFLAGS(unsigned long errcode)
+{
+    if (ERR_SYSTEM_ERROR(errcode))
+        return 0;
+    return errcode & (ERR_RFLAGS_MASK << ERR_RFLAGS_OFFSET);
+}
+
+static ossl_inline int ERR_GET_REASON(unsigned long errcode)
+{
+    if (ERR_SYSTEM_ERROR(errcode))
+        return errcode & ERR_SYSTEM_MASK;
+    return errcode & ERR_REASON_MASK;
+}
+
+static ossl_inline int ERR_FATAL_ERROR(unsigned long errcode)
+{
+    return (ERR_GET_RFLAGS(errcode) & ERR_RFLAG_FATAL) != 0;
+}
+
+/*
+ * ERR_PACK is a helper macro to properly pack OpenSSL error codes and may
+ * only be used for that purpose.  System errors are packed internally.
+ * ERR_PACK takes reason flags and reason code combined in |reason|.
+ * ERR_PACK ignores |func|, that parameter is just legacy from pre-3.0 OpenSSL.
+ */
+# define ERR_PACK(lib,func,reason)                                      \
+    ( (((unsigned long)(lib)    & ERR_LIB_MASK   ) << ERR_LIB_OFFSET) | \
+      (((unsigned long)(reason) & ERR_REASON_MASK)) )
 
 # ifndef OPENSSL_NO_DEPRECATED_3_0
 #  define SYS_F_FOPEN             0