1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "error.h"
30
31 #include <assert.h>
32 #include <err.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38
39 /// Generic hook to format an error that does not have a format callback.
40 ///
41 /// \param error Error for which to generate a message.
42 /// \param output_buffer Buffer to hold the generated message.
43 /// \param output_size Length of output_buffer.
44 static int
generic_format_callback(const kyua_error_t error,char * const output_buffer,size_t output_size)45 generic_format_callback(const kyua_error_t error, char* const output_buffer,
46 size_t output_size)
47 {
48 assert(error != NULL);
49 return snprintf(output_buffer, output_size, "Error '%s'", error->type_name);
50 }
51
52
53 /// Initializes an error object.
54 ///
55 /// \param error Error for which to generate a message.
56 /// \param type_name Name of the error type.
57 /// \param data Opaque data that belongs to the error, for usage by
58 /// error-specific methods like format_callback.
59 /// \param data_size Size of the opaque data object.
60 /// \param format_callback Type-specific method to generate a user
61 /// representation of the error.
62 ///
63 /// \return True if the initialization succeeds; false otherwise. If
64 /// false, the error object passed in has not been modified.
65 static bool
error_init(kyua_error_t const error,const char * const type_name,void * const data,const size_t data_size,const kyua_error_format_callback format_callback)66 error_init(kyua_error_t const error, const char* const type_name,
67 void* const data, const size_t data_size,
68 const kyua_error_format_callback format_callback)
69 {
70 assert(data != NULL || data_size == 0);
71 assert(data_size != 0 || data == NULL);
72
73 bool ok;
74
75 if (data == NULL) {
76 error->data = NULL;
77 error->needs_free = false;
78 ok = true;
79 } else {
80 void* new_data = malloc(data_size);
81 if (new_data == NULL) {
82 ok = false;
83 } else {
84 memcpy(new_data, data, data_size);
85 error->data = new_data;
86 ok = true;
87 }
88 }
89
90 if (ok) {
91 error->type_name = type_name;
92 error->format_callback = (format_callback == NULL) ?
93 generic_format_callback : format_callback;
94 }
95
96 return ok;
97 }
98
99
100 /// Allocates and initializes a new error.
101 ///
102 /// \param type_name Name of the error type.
103 /// \param data Opaque data that belongs to the error, for usage by
104 /// error-specific methods like format_callback.
105 /// \param data_size Size of the opaque data object.
106 /// \param format_callback Type-specific method to generate a user
107 /// representation of the error.
108 ///
109 /// \return The newly initialized error, or an out of memory error.
110 kyua_error_t
kyua_error_new(const char * const type_name,void * const data,const size_t data_size,const kyua_error_format_callback format_callback)111 kyua_error_new(const char* const type_name, void* const data,
112 const size_t data_size,
113 const kyua_error_format_callback format_callback)
114 {
115 assert(data != NULL || data_size == 0);
116 assert(data_size != 0 || data == NULL);
117
118 kyua_error_t error = malloc(sizeof(struct kyua_error));
119 if (error == NULL)
120 error = kyua_oom_error_new();
121 else {
122 if (!error_init(error, type_name, data, data_size, format_callback)) {
123 free(error);
124 error = kyua_oom_error_new();
125 } else {
126 error->needs_free = true;
127 }
128 }
129
130 assert(error != NULL);
131 return error;
132 }
133
134
135 /// Releases an error.
136 ///
137 /// \param error The error object to release.
138 void
kyua_error_free(kyua_error_t error)139 kyua_error_free(kyua_error_t error)
140 {
141 assert(error != NULL);
142
143 const bool needs_free = error->needs_free;
144
145 if (error->data != NULL)
146 free(error->data);
147 if (needs_free)
148 free(error);
149 }
150
151
152 /// Returns the "most important" of two errors.
153 ///
154 /// "Most important" is defined as: the primary error is returned if set,
155 /// otherwise the secondary error is returned.
156 ///
157 /// It is the responsibility of the caller to free the *resulting* error of this
158 /// call. The original errors passed in should not be consulted any longer,
159 /// because it is impossible to know which one was chosen.
160 ///
161 /// \param primary The primary error to compare.
162 /// \param [in,out] secondary The secondary error to compare. This is freed if
163 /// the primary error is set.
164 ///
165 /// \return Either primary or secondary.
166 kyua_error_t
kyua_error_subsume(kyua_error_t primary,kyua_error_t secondary)167 kyua_error_subsume(kyua_error_t primary, kyua_error_t secondary)
168 {
169 if (kyua_error_is_set(primary)) {
170 if (kyua_error_is_set(secondary))
171 kyua_error_free(secondary);
172 return primary;
173 } else {
174 return secondary;
175 }
176 }
177
178
179 /// Constructor for a no-error condition.
180 ///
181 /// \return Opaque representation of a no-error condition.
182 kyua_error_t
kyua_error_ok(void)183 kyua_error_ok(void)
184 {
185 return NULL;
186 }
187
188
189 /// Checks if the given error object represents an error or not.
190 ///
191 /// \param error The error to check.
192 ///
193 /// \return True if the error is set.
194 bool
kyua_error_is_set(const kyua_error_t error)195 kyua_error_is_set(const kyua_error_t error)
196 {
197 return error != NULL;
198 }
199
200
201 /// Checks if the given error object is of a specific type.
202 ///
203 /// \pre The error must be set.
204 ///
205 /// \param error The error to check.
206 /// \param type_name The type of the expected error.
207 ///
208 /// \return True if the error is of type type_name.
209 bool
kyua_error_is_type(const kyua_error_t error,const char * type_name)210 kyua_error_is_type(const kyua_error_t error, const char* type_name)
211 {
212 assert(error != NULL);
213
214 return strcmp(error->type_name, type_name) == 0;
215 }
216
217
218 /// Returns a pointer to the error-specific data.
219 ///
220 /// \pre The error must be set.
221 ///
222 /// \param error The error to query.
223 ///
224 /// \return An opaque pointer to the error data. This should only be
225 /// dereferenced by the methods of the error class that created it.
226 const void*
kyua_error_data(const kyua_error_t error)227 kyua_error_data(const kyua_error_t error)
228 {
229 assert(error != NULL);
230
231 return error->data;
232 }
233
234
235 /// Generates a user-friendly representation of the error.
236 ///
237 /// This cannot fail, but it is possible that the generated error does not
238 /// fit in the provided buffer.
239 ///
240 /// \pre The error must be set.
241 ///
242 /// \param error Error for which to generate a message.
243 /// \param output_buffer Buffer to hold the generated message.
244 /// \param output_size Length of output_buffer.
245 ///
246 /// \return The number of bytes written to output_buffer, or a negative value if
247 /// there was an error.
248 int
kyua_error_format(const kyua_error_t error,char * const output_buffer,const size_t output_size)249 kyua_error_format(const kyua_error_t error, char* const output_buffer,
250 const size_t output_size)
251 {
252 assert(kyua_error_is_set(error));
253 return error->format_callback(error, output_buffer, output_size);
254 }
255
256
257 /// Formats a string and appends an error code to it.
258 ///
259 /// \param error Error to append to the formatted message.
260 /// \param format User-specified message, as a formatting string.
261 /// \param ap List of arguments to the format string.
262 /// \param [out] output_buffer Buffer into which to write the message.
263 /// \param output_size Length of the output_buffer.
264 ///
265 /// \return The number of bytes written to output_buffer, or a negative value if
266 /// there was an error.
267 static int
format_user_message(const kyua_error_t error,const char * format,va_list ap,char * const output_buffer,const size_t output_size)268 format_user_message(const kyua_error_t error, const char* format, va_list ap,
269 char* const output_buffer, const size_t output_size)
270 {
271 assert(kyua_error_is_set(error));
272
273 va_list ap2;
274 va_copy(ap2, ap);
275 size_t written = vsnprintf(output_buffer, output_size, format, ap2);
276 va_end(ap2);
277 if (written >= output_size)
278 return -1;
279
280 written += snprintf(output_buffer + written, output_size - written, ": ");
281 if (written >= output_size)
282 return -1;
283
284 return kyua_error_format(error, output_buffer + written,
285 output_size - written);
286 }
287
288
289 /// Version of err(3) that works with kyua_error_t objects.
290 ///
291 /// \param exit_code Error code with which to terminate the execution.
292 /// \param error Error to append to the output.
293 /// \param format User-specified message, as a formatting string.
294 /// \param ... Positional arguments to the format string.
295 ///
296 /// \post Execution terminates with exit_code.
297 void
kyua_error_err(const int exit_code,const kyua_error_t error,const char * format,...)298 kyua_error_err(const int exit_code, const kyua_error_t error,
299 const char* format, ...)
300 {
301 char buffer[2048];
302
303 va_list ap;
304 va_start(ap, format);
305 (void)format_user_message(error, format, ap, buffer, sizeof(buffer));
306 va_end(ap);
307 kyua_error_free(error);
308
309 errx(exit_code, "%s", buffer);
310 }
311
312
313 /// Writes an error to a file stream.
314 ///
315 /// \param stream Stream to which to write the message.
316 /// \param error Error to append to the output. This is not released.
317 /// \param format User-specified message, as a formatting string.
318 /// \param ... Positional arguments to the format string.
319 void
kyua_error_fprintf(FILE * stream,const kyua_error_t error,const char * format,...)320 kyua_error_fprintf(FILE* stream, const kyua_error_t error,
321 const char* format, ...)
322 {
323 char buffer[2048];
324
325 va_list ap;
326 va_start(ap, format);
327 (void)format_user_message(error, format, ap, buffer, sizeof(buffer));
328 va_end(ap);
329
330 fprintf(stream, "%s", buffer);
331 }
332
333
334 /// Version of warn(3) that works with kyua_error_t objects.
335 ///
336 /// \param error Error to append to the output. This is not released.
337 /// \param format User-specified message, as a formatting string.
338 /// \param ... Positional arguments to the format string.
339 void
kyua_error_warn(const kyua_error_t error,const char * format,...)340 kyua_error_warn(const kyua_error_t error, const char* format, ...)
341 {
342 char buffer[2048];
343
344 va_list ap;
345 va_start(ap, format);
346 (void)format_user_message(error, format, ap, buffer, sizeof(buffer));
347 va_end(ap);
348
349 warnx("%s", buffer);
350 }
351
352
353 /// Name of an generic error type.
354 const char* const kyua_generic_error_type = "generic";
355
356
357 /// Generates a user-friendly representation of the error.
358 ///
359 /// \pre The error must be set.
360 ///
361 /// \param error Error for which to generate a message.
362 /// \param output_buffer Buffer to hold the generated message.
363 /// \param output_size Length of output_buffer.
364 ///
365 /// \return The number of bytes written to output_buffer, or a negative value if
366 /// there was an error.
367 static int
generic_format(const kyua_error_t error,char * const output_buffer,const size_t output_size)368 generic_format(const kyua_error_t error, char* const output_buffer,
369 const size_t output_size)
370 {
371 assert(kyua_error_is_type(error, kyua_generic_error_type));
372
373 const char* message = kyua_error_data(error);
374 return snprintf(output_buffer, output_size, "%s", message);
375 }
376
377
378 /// Constructs a new generic error.
379 ///
380 /// \param message Textual description of the problem.
381 /// \param ... Positional arguments for the description.
382 ///
383 /// \return The generated error.
384 kyua_error_t
kyua_generic_error_new(const char * message,...)385 kyua_generic_error_new(const char* message, ...)
386 {
387 char formatted[1024];
388 va_list ap;
389
390 va_start(ap, message);
391 (void)vsnprintf(formatted, sizeof(formatted), message, ap);
392 va_end(ap);
393
394 return kyua_error_new(kyua_generic_error_type, formatted, sizeof(formatted),
395 generic_format);
396 }
397
398
399 /// Name of a libc type.
400 const char* const kyua_libc_error_type = "libc";
401
402
403 /// Representation of a libc error.
404 struct libc_error_data {
405 /// Value of the errno captured during the error creation.
406 int original_errno;
407
408 /// Explanation of the problem that lead to the error.
409 char description[4096];
410 };
411 /// Shorthand for a libc_error_data structure.
412 typedef struct libc_error_data libc_error_data_t;
413
414
415 /// Generates a user-friendly representation of the error.
416 ///
417 /// \pre The error must be set.
418 ///
419 /// \param error Error for which to generate a message.
420 /// \param output_buffer Buffer to hold the generated message.
421 /// \param output_size Length of output_buffer.
422 ///
423 /// \return The number of bytes written to output_buffer, or a negative value if
424 /// there was an error.
425 static int
libc_format(const kyua_error_t error,char * const output_buffer,const size_t output_size)426 libc_format(const kyua_error_t error, char* const output_buffer,
427 const size_t output_size)
428 {
429 assert(kyua_error_is_type(error, kyua_libc_error_type));
430
431 const libc_error_data_t* data = kyua_error_data(error);
432 return snprintf(output_buffer, output_size, "%s: %s", data->description,
433 strerror(data->original_errno));
434 }
435
436
437 /// Constructs a new libc error.
438 ///
439 /// \param original_errno libc error code for this error.
440 /// \param description Textual description of the problem.
441 /// \param ... Positional arguments for the description.
442 ///
443 /// \return The generated error.
444 kyua_error_t
kyua_libc_error_new(const int original_errno,const char * description,...)445 kyua_libc_error_new(const int original_errno, const char* description, ...)
446 {
447 va_list ap;
448
449 const size_t data_size = sizeof(libc_error_data_t);
450 libc_error_data_t* data = (libc_error_data_t*)malloc(data_size);
451 if (data == NULL)
452 return kyua_oom_error_new();
453
454 data->original_errno = original_errno;
455 va_start(ap, description);
456 (void)vsnprintf(data->description, sizeof(data->description),
457 description, ap);
458 va_end(ap);
459
460 return kyua_error_new(kyua_libc_error_type, data, data_size, libc_format);
461 }
462
463
464 /// Extracts the original errno of a libc error.
465 ///
466 /// \pre error must have been constructed by kyua_libc_error_new.
467 ///
468 /// \param error The error object to access.
469 ///
470 /// \return The libc error code.
471 int
kyua_libc_error_errno(const kyua_error_t error)472 kyua_libc_error_errno(const kyua_error_t error)
473 {
474 assert(kyua_error_is_type(error, kyua_libc_error_type));
475
476 const struct libc_error_data* data = kyua_error_data(error);
477 return data->original_errno;
478 }
479
480
481 /// Name of an OOM type.
482 const char* const kyua_oom_error_type = "oom";
483
484
485 /// Data of an out of memory error.
486 ///
487 /// All error types are allocated in dynamic memory. However, doing so for
488 /// an out of memory error is not possible because, when we are out of
489 /// memory, we probably cannot allocate more memory to generate an error.
490 /// Therefore, we just keep a single static instance of the out of memory
491 /// error around all the time.
492 static struct kyua_error oom_error;
493
494
495 /// Generates a user-friendly representation of the error.
496 ///
497 /// \pre The error must be set.
498 ///
499 /// \param error Error for which to generate a message.
500 /// \param output_buffer Buffer to hold the generated message.
501 /// \param output_size Length of output_buffer.
502 ///
503 /// \return The number of bytes written to output_buffer, or a negative value if
504 /// there was an error.
505 static int
oom_format(const kyua_error_t error,char * const output_buffer,const size_t output_size)506 oom_format(const kyua_error_t error, char* const output_buffer,
507 const size_t output_size)
508 {
509 assert(kyua_error_is_type(error, kyua_oom_error_type));
510
511 return snprintf(output_buffer, output_size, "Not enough memory");
512 }
513
514
515 /// Constructs a new out-of-memory error.
516 ///
517 /// This will always succeed because we just return a reference to the
518 /// statically-allocated oom_error.
519 ///
520 /// \return An error representing an out of memory condition.
521 kyua_error_t
kyua_oom_error_new(void)522 kyua_oom_error_new(void)
523 {
524 // This is idempotent; no need to ensure that we call it only once.
525 #if defined(__minix) && !defined(NDEBUG)
526 const bool ok =
527 #endif /* defined(__minix) && !defined(NDEBUG) */
528 error_init(&oom_error, kyua_oom_error_type, NULL, 0, oom_format);
529 assert(ok);
530
531 return &oom_error;
532 }
533
534
535 /// Name of an usage error type.
536 const char* const kyua_usage_error_type = "usage";
537
538
539 /// Generates a user-friendly representation of the error.
540 ///
541 /// \pre The error must be set.
542 ///
543 /// \param error Error for which to generate a message.
544 /// \param output_buffer Buffer to hold the generated message.
545 /// \param output_size Length of output_buffer.
546 ///
547 /// \return The number of bytes written to output_buffer, or a negative value if
548 /// there was an error.
549 static int
usage_format(const kyua_error_t error,char * const output_buffer,const size_t output_size)550 usage_format(const kyua_error_t error, char* const output_buffer,
551 const size_t output_size)
552 {
553 assert(kyua_error_is_type(error, kyua_usage_error_type));
554
555 const char* message = kyua_error_data(error);
556 return snprintf(output_buffer, output_size, "%s", message);
557 }
558
559
560 /// Constructs a new usage error.
561 ///
562 /// \param message Textual description of the problem.
563 /// \param ... Positional arguments for the description.
564 ///
565 /// \return The generated error.
566 kyua_error_t
kyua_usage_error_new(const char * message,...)567 kyua_usage_error_new(const char* message, ...)
568 {
569 char formatted[1024];
570 va_list ap;
571
572 va_start(ap, message);
573 (void)vsnprintf(formatted, sizeof(formatted), message, ap);
574 va_end(ap);
575
576 return kyua_error_new(kyua_usage_error_type, formatted, sizeof(formatted),
577 usage_format);
578 }
579