github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/cmd/libsnap-confine-private/error.h (about) 1 /* 2 * Copyright (C) 2016 Canonical Ltd 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 */ 17 18 #ifndef SNAP_CONFINE_ERROR_H 19 #define SNAP_CONFINE_ERROR_H 20 21 #include <stdbool.h> 22 23 #define SC_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 24 25 /** 26 * The attribute returns_nonnull is only supported by GCC versions >= 4.9.0. 27 * Enable building of snap-confine on platforms that are stuck with older 28 * GCC versions. 29 **/ 30 #if SC_GCC_VERSION >= 40900 31 #define SC_APPEND_RETURNS_NONNULL , returns_nonnull 32 #else 33 #define SC_APPEND_RETURNS_NONNULL 34 #endif 35 36 /** 37 * This module defines APIs for simple error management. 38 * 39 * Errors are allocated objects that can be returned and passed around from 40 * functions. Errors carry a formatted message and optionally a scoped error 41 * code. The code is coped with a string "domain" that simply acts as a 42 * namespace for various interacting modules. 43 **/ 44 45 /** 46 * Error structure. 47 **/ 48 typedef struct sc_error { 49 // Error domain defines a scope for particular error codes. 50 const char *domain; 51 // Code differentiates particular errors for the programmer. 52 // The code may be zero if the particular meaning is not relevant. 53 int code; 54 // Message carries a formatted description of the problem. 55 char *msg; 56 } sc_error; 57 58 /** 59 * Error domain for errors related to system errno. 60 **/ 61 #define SC_ERRNO_DOMAIN "errno" 62 63 /** 64 * Error domain for errors in the libsnap-confine-private library. 65 **/ 66 #define SC_LIBSNAP_DOMAIN "libsnap-confine-private" 67 68 /** sc_libsnap_error represents distinct error codes used by libsnap-confine-private library. */ 69 typedef enum sc_libsnap_error { 70 /** SC_UNSPECIFIED_ERROR indicates an error not worthy of a distinct code. */ 71 SC_UNSPECIFIED_ERROR = 0, 72 /** SC_API_MISUSE indicates that public API was called incorrectly. */ 73 SC_API_MISUSE, 74 /** SC_BUG indicates that private API was called incorrectly. */ 75 SC_BUG, 76 } sc_libsnap_error; 77 78 /** 79 * Initialize a new error object. 80 * 81 * The domain is a cookie-like string that allows the caller to distinguish 82 * between "namespaces" of error codes. It should be a static string that is 83 * provided by the caller. Both the domain and the error code can be retrieved 84 * later. 85 * 86 * This function calls die() in case of memory allocation failure. 87 **/ 88 __attribute__((warn_unused_result, 89 format(printf, 3, 4) SC_APPEND_RETURNS_NONNULL)) 90 sc_error *sc_error_init(const char *domain, int code, const char *msgfmt, ...); 91 92 /** 93 * Initialize an unspecified error with formatted message. 94 * 95 * This is just syntactic sugar for sc_error_init(SC_LIBSNAP_ERROR, 96 * SC_UNSPECIFIED_ERROR, msgfmt, ...) which is repeated often. 97 **/ 98 __attribute__((warn_unused_result, 99 format(printf, 1, 2) SC_APPEND_RETURNS_NONNULL)) 100 sc_error *sc_error_init_simple(const char *msgfmt, ...); 101 102 /** 103 * Initialize an API misuse error with formatted message. 104 * 105 * This is just syntactic sugar for sc_error_init(SC_LIBSNAP_DOMAIN, 106 * SC_API_MISUSE, msgfmt, ...) which is repeated often. 107 **/ 108 __attribute__((warn_unused_result, 109 format(printf, 1, 2) SC_APPEND_RETURNS_NONNULL)) 110 sc_error *sc_error_init_api_misuse(const char *msgfmt, ...); 111 112 /** 113 * Initialize an errno-based error. 114 * 115 * The error carries a copy of errno and a custom error message as designed by 116 * the caller. See sc_error_init() for a more complete description. 117 * 118 * This function calls die() in case of memory allocation failure. 119 **/ 120 __attribute__((warn_unused_result, 121 format(printf, 2, 3) SC_APPEND_RETURNS_NONNULL)) 122 sc_error *sc_error_init_from_errno(int errno_copy, const char *msgfmt, ...); 123 124 /** 125 * Get the error domain out of an error object. 126 * 127 * The error domain acts as a namespace for error codes. 128 * No change of ownership takes place. 129 **/ 130 __attribute__((warn_unused_result SC_APPEND_RETURNS_NONNULL)) 131 const char *sc_error_domain(sc_error * err); 132 133 /** 134 * Get the error code out of an error object. 135 * 136 * The error code is scoped by the error domain. 137 * 138 * An error code of zero is special-cased to indicate that no particular error 139 * code is reserved for this error and it's not something that the programmer 140 * can rely on programmatically. This can be used to return an error message 141 * without having to allocate a distinct code for each one. 142 **/ 143 __attribute__((warn_unused_result)) 144 int sc_error_code(sc_error * err); 145 146 /** 147 * Get the error message out of an error object. 148 * 149 * The error message is bound to the life-cycle of the error object. 150 * No change of ownership takes place. 151 **/ 152 __attribute__((warn_unused_result SC_APPEND_RETURNS_NONNULL)) 153 const char *sc_error_msg(sc_error * err); 154 155 /** 156 * Free an error object. 157 * 158 * The error object can be NULL. 159 **/ 160 void sc_error_free(sc_error * error); 161 162 /** 163 * Cleanup an error with sc_error_free() 164 * 165 * This function is designed to be used with 166 * __attribute__((cleanup(sc_cleanup_error))). 167 **/ 168 __attribute__((nonnull)) 169 void sc_cleanup_error(sc_error ** ptr); 170 171 /** 172 * 173 * Die if there's an error. 174 * 175 * This function is a correct way to die() if the passed error is not NULL. 176 * 177 * The error message is derived from the data in the error, using the special 178 * errno domain to provide additional information if that is available. 179 **/ 180 void sc_die_on_error(sc_error * error); 181 182 /** 183 * Forward an error to the caller. 184 * 185 * This tries to forward an error to the caller. If this is impossible because 186 * the caller did not provide a location for the error to be stored then the 187 * sc_die_on_error() is called as a safety measure. 188 * 189 * Change of ownership takes place and the error is now stored in the recipient. 190 * 191 * The return value -1 if error is non-NULL and 0 otherwise. The return value 192 * makes it convenient to `return sc_error_forward(err_out, err);` as the last 193 * line of a function. 194 **/ 195 // NOTE: There's no nonnull(1) attribute as the recipient *can* be NULL. With 196 // the attribute in place GCC optimizes some things out and tests fail. 197 int sc_error_forward(sc_error ** recipient, sc_error * error); 198 199 /** 200 * Check if a given error matches the specified domain and code. 201 * 202 * It is okay to match a NULL error, the function simply returns false in that 203 * case. The domain cannot be NULL though. 204 **/ 205 __attribute__((warn_unused_result)) 206 bool sc_error_match(sc_error * error, const char *domain, int code); 207 208 #endif