github.com/rigado/snapd@v2.42.5-go-mod+incompatible/cmd/libsnap-confine-private/error.c (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 #include "error.h" 18 19 // To get vasprintf 20 #define _GNU_SOURCE 21 22 #include "utils.h" 23 24 #include <errno.h> 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 static sc_error *sc_error_initv(const char *domain, int code, 30 const char *msgfmt, va_list ap) 31 { 32 sc_error *err = calloc(1, sizeof *err); 33 if (err == NULL) { 34 die("cannot allocate memory for error object"); 35 } 36 err->domain = domain; 37 err->code = code; 38 if (vasprintf(&err->msg, msgfmt, ap) == -1) { 39 die("cannot format error message"); 40 } 41 return err; 42 } 43 44 sc_error *sc_error_init(const char *domain, int code, const char *msgfmt, ...) 45 { 46 va_list ap; 47 va_start(ap, msgfmt); 48 sc_error *err = sc_error_initv(domain, code, msgfmt, ap); 49 va_end(ap); 50 return err; 51 } 52 53 sc_error *sc_error_init_from_errno(int errno_copy, const char *msgfmt, ...) 54 { 55 va_list ap; 56 va_start(ap, msgfmt); 57 sc_error *err = sc_error_initv(SC_ERRNO_DOMAIN, errno_copy, msgfmt, ap); 58 va_end(ap); 59 return err; 60 } 61 62 sc_error *sc_error_init_simple(const char *msgfmt, ...) 63 { 64 va_list ap; 65 va_start(ap, msgfmt); 66 sc_error *err = sc_error_initv(SC_LIBSNAP_DOMAIN, 67 SC_UNSPECIFIED_ERROR, msgfmt, ap); 68 va_end(ap); 69 return err; 70 } 71 72 sc_error *sc_error_init_api_misuse(const char *msgfmt, ...) 73 { 74 va_list ap; 75 va_start(ap, msgfmt); 76 sc_error *err = sc_error_initv(SC_LIBSNAP_DOMAIN, 77 SC_API_MISUSE, msgfmt, ap); 78 va_end(ap); 79 return err; 80 } 81 82 const char *sc_error_domain(sc_error * err) 83 { 84 if (err == NULL) { 85 die("cannot obtain error domain from NULL error"); 86 } 87 return err->domain; 88 } 89 90 int sc_error_code(sc_error * err) 91 { 92 if (err == NULL) { 93 die("cannot obtain error code from NULL error"); 94 } 95 return err->code; 96 } 97 98 const char *sc_error_msg(sc_error * err) 99 { 100 if (err == NULL) { 101 die("cannot obtain error message from NULL error"); 102 } 103 return err->msg; 104 } 105 106 void sc_error_free(sc_error * err) 107 { 108 if (err != NULL) { 109 free(err->msg); 110 err->msg = NULL; 111 free(err); 112 } 113 } 114 115 void sc_cleanup_error(sc_error ** ptr) 116 { 117 sc_error_free(*ptr); 118 *ptr = NULL; 119 } 120 121 void sc_die_on_error(sc_error * error) 122 { 123 if (error != NULL) { 124 if (strcmp(sc_error_domain(error), SC_ERRNO_DOMAIN) == 0) { 125 fprintf(stderr, "%s: %s\n", sc_error_msg(error), strerror(sc_error_code(error))); 126 } else { 127 fprintf(stderr, "%s\n", sc_error_msg(error)); 128 } 129 sc_error_free(error); 130 exit(1); 131 } 132 } 133 134 int sc_error_forward(sc_error ** recipient, sc_error * error) 135 { 136 if (recipient != NULL) { 137 *recipient = error; 138 } else { 139 sc_die_on_error(error); 140 } 141 return error != NULL ? -1 : 0; 142 } 143 144 bool sc_error_match(sc_error * error, const char *domain, int code) 145 { 146 if (domain == NULL) { 147 die("cannot match error to a NULL domain"); 148 } 149 if (error == NULL) { 150 return false; 151 } 152 return strcmp(sc_error_domain(error), domain) == 0 153 && sc_error_code(error) == code; 154 }