github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/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