1 #include "config.h"
2 
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <gettext.h>
7 #include <errno.h>
8 
9 #include "prelude.h"
10 #include "prelude-log.h"
11 #include "prelude-error.h"
12 
13 #include "code-to-errno.h"
14 #include "code-from-errno.h"
15 
16 
17 #define PRELUDE_ERROR_CODE_DIM     65536
18 #define PRELUDE_ERROR_SOURCE_DIM     256
19 
20 #define PRELUDE_ERROR_SOURCE_SHIFT    23
21 #define PRELUDE_ERROR_VERBOSE_SHIFT   22
22 
23 #define PRELUDE_ERROR_CODE_MASK       (PRELUDE_ERROR_CODE_DIM - 1)
24 #define PRELUDE_ERROR_SOURCE_MASK     (PRELUDE_ERROR_SOURCE_DIM - 1)
25 #define PRELUDE_ERROR_VERBOSE_MASK    (1)
26 
27 
28 /**
29  * prelude_error_make:
30  * @source: Error source.
31  * @code: Error code.
32  *
33  * Create a new #prelude_error_t error using @source and @code.
34  *
35  * Returns: The created #prelude_error_t integer.
36  */
prelude_error_make(prelude_error_source_t source,prelude_error_code_t code)37 prelude_error_t prelude_error_make(prelude_error_source_t source, prelude_error_code_t code)
38 {
39         return (code == PRELUDE_ERROR_NO_ERROR) ? code : -((source << PRELUDE_ERROR_SOURCE_SHIFT) | code);
40 }
41 
42 
43 /**
44  * prelude_error_make_from_errno:
45  * @source: Error source.
46  * @err: errno value.
47  *
48  * Create a new #prelude_error_t error using @source and @errno.
49  *
50  * Returns: The created #prelude_error_t integer.
51  */
prelude_error_make_from_errno(prelude_error_source_t source,int err)52 prelude_error_t prelude_error_make_from_errno(prelude_error_source_t source, int err)
53 {
54         prelude_error_code_t code = prelude_error_code_from_errno(err);
55         return prelude_error_make(source, code);
56 }
57 
58 
59 
60 /**
61  * prelude_error_verbose_make_v:
62  * @source: Error source.
63  * @code: Error code.
64  * @fmt: Format string.
65  * @ap: Argument list.
66  *
67  * Create a new error using @source and @code, using the detailed error message
68  * specified within @fmt.
69  *
70  * Returns: The created #prelude_error_t integer.
71  */
prelude_error_verbose_make_v(prelude_error_source_t source,prelude_error_code_t code,const char * fmt,va_list ap)72 prelude_error_t prelude_error_verbose_make_v(prelude_error_source_t source,
73                                              prelude_error_code_t code, const char *fmt, va_list ap)
74 {
75         int ret;
76         prelude_string_t *str;
77 
78         ret = prelude_string_new(&str);
79         if ( ret < 0 )
80                 return ret;
81 
82         ret = prelude_string_vprintf(str, fmt, ap);
83         if ( ret < 0 ) {
84                 prelude_string_destroy(str);
85                 return ret;
86         }
87 
88         ret = _prelude_thread_set_error(prelude_string_get_string(str));
89         prelude_string_destroy(str);
90 
91         if ( ret < 0 )
92                 return ret;
93 
94         ret = prelude_error_make(source, code);
95         ret = -ret;
96         ret |= (1 << PRELUDE_ERROR_VERBOSE_SHIFT);
97 
98         return -ret;
99 }
100 
101 
102 
103 /**
104  * prelude_error_verbose_make:
105  * @source: Error source.
106  * @code: Error code.
107  * @fmt: Format string.
108  * @...: Argument list.
109  *
110  * Create a new error using @source and @code, using the detailed error message
111  * specified within @fmt.
112  *
113  * Returns: The created #prelude_error_t integer.
114  */
prelude_error_verbose_make(prelude_error_source_t source,prelude_error_code_t code,const char * fmt,...)115 prelude_error_t prelude_error_verbose_make(prelude_error_source_t source,
116                                            prelude_error_code_t code, const char *fmt, ...)
117 {
118         int ret;
119         va_list ap;
120 
121         va_start(ap, fmt);
122         ret = prelude_error_verbose_make_v(source, code, fmt, ap);
123         va_end(ap);
124 
125         return ret;
126 }
127 
128 
129 /**
130  * prelude_error_get_code:
131  * @error: A #prelude_error_t return value.
132  *
133  * Returns: the #prelude_code_t code contained within the @prelude_error_t integer.
134  */
prelude_error_get_code(prelude_error_t error)135 prelude_error_code_t prelude_error_get_code(prelude_error_t error)
136 {
137         error = -error;
138         return (prelude_error_code_t) (error & PRELUDE_ERROR_CODE_MASK);
139 }
140 
141 
142 /**
143  * prelude_error_get_source:
144  * @error: A #prelude_error_t return value.
145  *
146  * Returns: the #prelude_source_t source contained within the @prelude_error_t integer.
147  */
prelude_error_get_source(prelude_error_t error)148 prelude_error_source_t prelude_error_get_source(prelude_error_t error)
149 {
150         error = -error;
151         return (prelude_error_source_t) ((error >> PRELUDE_ERROR_SOURCE_SHIFT) & PRELUDE_ERROR_SOURCE_MASK);
152 }
153 
154 
155 /**
156  * prelude_error_is_verbose:
157  * @error: A #prelude_error_t return value.
158  *
159  * Returns: #PRELUDE_BOOL_TRUE if there is a detailed message for this error, #PRELUDE_BOOL_FALSE otherwise.
160  */
prelude_error_is_verbose(prelude_error_t error)161 prelude_bool_t prelude_error_is_verbose(prelude_error_t error)
162 {
163         error = -error;
164         return ((error >> PRELUDE_ERROR_VERBOSE_SHIFT) & PRELUDE_ERROR_VERBOSE_MASK) ? PRELUDE_BOOL_TRUE : PRELUDE_BOOL_FALSE;
165 }
166 
167 
168 /**
169  * prelude_error_code_from_errno:
170  * @err: errno value.
171  *
172  * Returns: the #prelude_error_code_t value corresponding to @err.
173  */
prelude_error_code_from_errno(int err)174 prelude_error_code_t prelude_error_code_from_errno(int err)
175 {
176         int idx;
177 
178         if ( ! err )
179                 return PRELUDE_ERROR_NO_ERROR;
180 
181         idx = errno_to_idx(err);
182         if ( idx < 0 )
183                 return PRELUDE_ERROR_UNKNOWN_ERRNO;
184 
185         return PRELUDE_ERROR_SYSTEM_ERROR | err_code_from_index[idx];
186 }
187 
188 
189 /**
190  * prelude_error_code_to_errno:
191  * @code: Error code.
192  *
193  * Returns: the errno value corresponding to @code.
194  */
prelude_error_code_to_errno(prelude_error_code_t code)195 int prelude_error_code_to_errno(prelude_error_code_t code)
196 {
197         if ( ! (code & PRELUDE_ERROR_SYSTEM_ERROR) )
198                 return 0;
199 
200         code &= ~PRELUDE_ERROR_SYSTEM_ERROR;
201 
202         if ( code < sizeof(err_code_to_errno) / sizeof(err_code_to_errno[0]) )
203                 return err_code_to_errno[code];
204         else
205                 return 0;
206 }
207 
208 
209 
210 /**
211  * prelude_perror:
212  * @error: A #prelude_error_t return value.
213  * @fmt: Format string.
214  * @...: Argument list.
215  *
216  * Print the error to stderr, or to syslog() in case stderr is unavailable.
217  */
prelude_perror(prelude_error_t error,const char * fmt,...)218 void prelude_perror(prelude_error_t error, const char *fmt, ...)
219 {
220         va_list ap;
221         char buf[1024];
222 
223         va_start(ap, fmt);
224         vsnprintf(buf, sizeof(buf), fmt, ap);
225         va_end(ap);
226 
227         if ( prelude_error_get_source(error) )
228                 prelude_log(PRELUDE_LOG_WARN, "%s: %s: %s.\n", prelude_strsource(error), buf, prelude_strerror(error));
229         else
230                 prelude_log(PRELUDE_LOG_WARN, "%s: %s.\n", buf, prelude_strerror(error));
231 }
232