File: error.h

package info (click to toggle)
snapd 2.72-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 80,412 kB
  • sloc: sh: 16,506; ansic: 16,211; python: 11,213; makefile: 1,919; exp: 190; awk: 58; xml: 22
file content (199 lines) | stat: -rw-r--r-- 6,832 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
 * Copyright (C) 2016 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef SNAP_CONFINE_ERROR_H
#define SNAP_CONFINE_ERROR_H

#include <stdbool.h>

#define SC_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)

/**
 * The attribute returns_nonnull is only supported by GCC versions >= 4.9.0.
 * Enable building of snap-confine on platforms that are stuck with older
 * GCC versions.
 **/
#if SC_GCC_VERSION >= 40900
#define SC_APPEND_RETURNS_NONNULL , returns_nonnull
#else
#define SC_APPEND_RETURNS_NONNULL
#endif

/**
 * This module defines APIs for simple error management.
 *
 * Errors are allocated objects that can be returned and passed around from
 * functions.  Errors carry a formatted message and optionally a scoped error
 * code. The code is coped with a string "domain" that simply acts as a
 * namespace for various interacting modules.
 **/

/**
 * Error structure.
 **/
typedef struct sc_error {
    // Error domain defines a scope for particular error codes.
    const char *domain;
    // Code differentiates particular errors for the programmer.
    // The code may be zero if the particular meaning is not relevant.
    int code;
    // Message carries a formatted description of the problem.
    char *msg;
} sc_error;

/**
 * Error domain for errors related to system errno.
 **/
#define SC_ERRNO_DOMAIN "errno"

/**
 * Error domain for errors in the libsnap-confine-private library.
 **/
#define SC_LIBSNAP_DOMAIN "libsnap-confine-private"

/** sc_libsnap_error represents distinct error codes used by libsnap-confine-private library. */
typedef enum sc_libsnap_error {
    /** SC_UNSPECIFIED_ERROR indicates an error not worthy of a distinct code. */
    SC_UNSPECIFIED_ERROR = 0,
    /** SC_API_MISUSE indicates that public API was called incorrectly. */
    SC_API_MISUSE,
    /** SC_BUG indicates that private API was called incorrectly. */
    SC_BUG,
} sc_libsnap_error;

/**
 * Initialize a new error object.
 *
 * The domain is a cookie-like string that allows the caller to distinguish
 * between "namespaces" of error codes. It should be a static string that is
 * provided by the caller. Both the domain and the error code can be retrieved
 * later.
 *
 * This function calls die() in case of memory allocation failure.
 **/
__attribute__((warn_unused_result, format(printf, 3, 4) SC_APPEND_RETURNS_NONNULL)) sc_error *sc_error_init(
    const char *domain, int code, const char *msgfmt, ...);

/**
 * Initialize an unspecified error with formatted message.
 *
 * This is just syntactic sugar for sc_error_init(SC_LIBSNAP_ERROR,
 * SC_UNSPECIFIED_ERROR, msgfmt, ...) which is repeated often.
 **/
__attribute__((warn_unused_result, format(printf, 1, 2) SC_APPEND_RETURNS_NONNULL)) sc_error *sc_error_init_simple(
    const char *msgfmt, ...);

/**
 * Initialize an API misuse error with formatted message.
 *
 * This is just syntactic sugar for sc_error_init(SC_LIBSNAP_DOMAIN,
 * SC_API_MISUSE, msgfmt, ...) which is repeated often.
 **/
__attribute__((warn_unused_result, format(printf, 1, 2) SC_APPEND_RETURNS_NONNULL)) sc_error *sc_error_init_api_misuse(
    const char *msgfmt, ...);

/**
 * Initialize an errno-based error.
 *
 * The error carries a copy of errno and a custom error message as designed by
 * the caller. See sc_error_init() for a more complete description.
 *
 * This function calls die() in case of memory allocation failure.
 **/
__attribute__((warn_unused_result, format(printf, 2, 3) SC_APPEND_RETURNS_NONNULL)) sc_error *sc_error_init_from_errno(
    int errno_copy, const char *msgfmt, ...);

/**
 * Get the error domain out of an error object.
 *
 * The error domain acts as a namespace for error codes.
 * No change of ownership takes place.
 **/
__attribute__((warn_unused_result SC_APPEND_RETURNS_NONNULL)) const char *sc_error_domain(sc_error *err);

/**
 * Get the error code out of an error object.
 *
 * The error code is scoped by the error domain.
 *
 * An error code of zero is special-cased to indicate that no particular error
 * code is reserved for this error and it's not something that the programmer
 * can rely on programmatically. This can be used to return an error message
 * without having to allocate a distinct code for each one.
 **/
__attribute__((warn_unused_result)) int sc_error_code(sc_error *err);

/**
 * Get the error message out of an error object.
 *
 * The error message is bound to the life-cycle of the error object.
 * No change of ownership takes place.
 **/
__attribute__((warn_unused_result SC_APPEND_RETURNS_NONNULL)) const char *sc_error_msg(sc_error *err);

/**
 * Free an error object.
 *
 * The error object can be NULL.
 **/
void sc_error_free(sc_error *error);

/**
 * Cleanup an error with sc_error_free()
 *
 * This function is designed to be used with
 * __attribute__((cleanup(sc_cleanup_error))).
 **/
__attribute__((nonnull)) void sc_cleanup_error(sc_error **ptr);

/**
 *
 * Die if there's an error.
 *
 * This function is a correct way to die() if the passed error is not NULL.
 *
 * The error message is derived from the data in the error, using the special
 * errno domain to provide additional information if that is available.
 **/
void sc_die_on_error(sc_error *error);

/**
 * Forward an error to the caller.
 *
 * This tries to forward an error to the caller. If this is impossible because
 * the caller did not provide a location for the error to be stored then the
 * sc_die_on_error() is called as a safety measure.
 *
 * Change of ownership takes place and the error is now stored in the recipient.
 *
 * The return value -1 if error is non-NULL and 0 otherwise. The return value
 * makes it convenient to `return sc_error_forward(err_out, err);` as the last
 * line of a function.
 **/
// NOTE: There's no nonnull(1) attribute as the recipient *can* be NULL. With
// the attribute in place GCC optimizes some things out and tests fail.
int sc_error_forward(sc_error **recipient, sc_error *error);

/**
 * Check if a given error matches the specified domain and code.
 *
 * It is okay to match a NULL error, the function simply returns false in that
 * case. The domain cannot be NULL though.
 **/
__attribute__((warn_unused_result)) bool sc_error_match(sc_error *error, const char *domain, int code);

#endif