-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy patherrf.h
135 lines (115 loc) · 4.54 KB
/
errf.h
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
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2019, Joyent Inc
* Author: Alex Wilson <[email protected]>
*/
#if !defined(_ERF_H)
#define _ERF_H
#include <stdint.h>
#include <sys/types.h>
#include "utils.h"
/*
* ERF -- annotated chained error objects for C.
*
* The intention is that functions which may produce an error return an errf_t*
* where they normally would return an errno int.
*
* E.g. errf_t *do_something(int arg, int *output);
*
* If this returns NULL (equivalent to ERRF_OK) then this means "no error" (as
* a 0 return value would normally). Otherwise it returns a pointer to an
* errf_t describing the error that occurred.
*
* The errf_t is allocated from the heap (using the errf() family of function
* macros) and belongs to the caller.
*
* You can chain errf_ts together as a "cause chain" to indicate more detailed
* information about the error. This is useful when high up a chain of
* abstraction in order to understand the context where the error happened
* For example, let's say a database couldn't answer your query because while
* it was trying to get data from table X it tried to open file Y and failed due
* to some errno. We could end up with the following cause chain:
*
* QueryError: database was not able to handle query: "SELECT ..."
* Caused by: TableOpenError: failed to open index for table "foobar"
* Caused by: SystemError: open("xxy.idx") returned error 1 (EPERM):
* Permission denied.
*
* This results in clearer bug reports for developers and output for users with
* specific information as well as general information to figure out what's
* going on.
*
* Error objects can be nicely formatted to the console (including their
* cause chain) using perrf() and friends.
*/
struct errf;
typedef struct errf errf_t;
/* Define this here since it's pretty useful for things that return errf_t */
#define MUST_CHECK __attribute__((warn_unused_result))
#define ERRF_OK NULL
extern struct errf *ERRF_NOMEM;
/* Print an errf_t and message to stderr, like warnx/warn */
void warnfx(const struct errf *e, const char *fmt, ...);
/* Print an errf_t and message to stderr and exit, like errx/err */
void errfx(int status, const struct errf *e, const char *fmt, ...);
/* Frees an errf_t and its cause chain. */
void errf_free(struct errf *e);
/*
* Returns B_TRUE if there is an error in the cause chain of "e" which is
* named "name".
*/
boolean_t errf_caused_by(const struct errf *e, const char *name);
/* Accessors for basic information about the error. */
const char *errf_name(const struct errf *e);
const char *errf_message(const struct errf *e);
int errf_errno(const struct errf *e);
const char *errf_function(const struct errf *e);
const char *errf_file(const struct errf *e);
uint errf_line(const struct errf *e);
struct errf *errf_cause(const struct errf *e);
#ifndef LINT
/*
* Basic public interface for constructing an error object.
*
* errf_t *errf(const char *name, errf_t *cause, const char *fmt, ...);
*
* Takes printf-style arguments for "fmt".
*/
#define errf(name, cause, fmt, ...) \
_errf(name, cause, __func__, __FILE__, __LINE__, \
fmt, ##__VA_ARGS__)
/*
* Turn an int errno value into an error object (includes both the macro
* name for the errno if available and the strerror() value).
*
* errf_t *errfno(const char *function, int errno, const char *fmt, ...);
*/
#define errfno(func, eno, fmt, ...) \
_errfno(func, eno, __func__, __FILE__, __LINE__, \
fmt, ##__VA_ARGS__)
/*
* An example error subclass used to report an invalid argument.
*/
#define argerrf(param, mustbe, butis, ...) \
errf("ArgumentError", NULL, \
"Argument " param " must be " mustbe " but is " butis, \
##__VA_ARGS__)
#define funcerrf(cause, fmt, ...) \
errf(__func__, cause, fmt , ##__VA_ARGS__)
#define pcscerrf(call, rv) \
errf("PCSCError", NULL, call " failed: %d (%s)", \
rv, pcsc_stringify_error(rv))
#else
/* smatch and similar don't support varargs macros */
#define errf(name, cause, fmt, ...) \
_errf(name, cause, __func__, __FILE__, __LINE__, fmt)
#endif
/* Internal only -- used by the above macros. */
struct errf *_errf(const char *name, struct errf *cause, const char *func,
const char *file, uint line, const char *fmt, ...);
struct errf *_errfno(const char *enofunc, int eno, const char *func,
const char *file, uint line, const char *fmt, ...);
#endif