1 /* $NetBSD: result.c,v 1.10 2022/09/23 12:15:33 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <stddef.h> 19 #include <stdlib.h> 20 21 #include <isc/lib.h> 22 #include <isc/once.h> 23 #include <isc/resultclass.h> 24 #include <isc/rwlock.h> 25 #include <isc/util.h> 26 27 typedef struct resulttable { 28 unsigned int base; 29 unsigned int last; 30 const char **text; 31 int set; 32 ISC_LINK(struct resulttable) link; 33 } resulttable; 34 35 typedef ISC_LIST(resulttable) resulttable_list_t; 36 37 static const char *description[ISC_R_NRESULTS] = { 38 "success", /*%< 0 */ 39 "out of memory", /*%< 1 */ 40 "timed out", /*%< 2 */ 41 "no available threads", /*%< 3 */ 42 "address not available", /*%< 4 */ 43 "address in use", /*%< 5 */ 44 "permission denied", /*%< 6 */ 45 "no pending connections", /*%< 7 */ 46 "network unreachable", /*%< 8 */ 47 "host unreachable", /*%< 9 */ 48 "network down", /*%< 10 */ 49 "host down", /*%< 11 */ 50 "connection refused", /*%< 12 */ 51 "not enough free resources", /*%< 13 */ 52 "end of file", /*%< 14 */ 53 "socket already bound", /*%< 15 */ 54 "reload", /*%< 16 */ 55 "lock busy", /*%< 17 */ 56 "already exists", /*%< 18 */ 57 "ran out of space", /*%< 19 */ 58 "operation canceled", /*%< 20 */ 59 "socket is not bound", /*%< 21 */ 60 "shutting down", /*%< 22 */ 61 "not found", /*%< 23 */ 62 "unexpected end of input", /*%< 24 */ 63 "failure", /*%< 25 */ 64 "I/O error", /*%< 26 */ 65 "not implemented", /*%< 27 */ 66 "unbalanced parentheses", /*%< 28 */ 67 "no more", /*%< 29 */ 68 "invalid file", /*%< 30 */ 69 "bad base64 encoding", /*%< 31 */ 70 "unexpected token", /*%< 32 */ 71 "quota reached", /*%< 33 */ 72 "unexpected error", /*%< 34 */ 73 "already running", /*%< 35 */ 74 "ignore", /*%< 36 */ 75 "address mask not contiguous", /*%< 37 */ 76 "file not found", /*%< 38 */ 77 "file already exists", /*%< 39 */ 78 "socket is not connected", /*%< 40 */ 79 "out of range", /*%< 41 */ 80 "out of entropy", /*%< 42 */ 81 "invalid use of multicast address", /*%< 43 */ 82 "not a file", /*%< 44 */ 83 "not a directory", /*%< 45 */ 84 "queue is empty", /*%< 46 */ 85 "address family mismatch", /*%< 47 */ 86 "address family not supported", /*%< 48 */ 87 "bad hex encoding", /*%< 49 */ 88 "too many open files", /*%< 50 */ 89 "not blocking", /*%< 51 */ 90 "unbalanced quotes", /*%< 52 */ 91 "operation in progress", /*%< 53 */ 92 "connection reset", /*%< 54 */ 93 "soft quota reached", /*%< 55 */ 94 "not a valid number", /*%< 56 */ 95 "disabled", /*%< 57 */ 96 "max size", /*%< 58 */ 97 "invalid address format", /*%< 59 */ 98 "bad base32 encoding", /*%< 60 */ 99 "unset", /*%< 61 */ 100 "multiple", /*%< 62 */ 101 "would block", /*%< 63 */ 102 "complete", /*%< 64 */ 103 "crypto failure", /*%< 65 */ 104 "disc quota", /*%< 66 */ 105 "disc full", /*%< 67 */ 106 "default", /*%< 68 */ 107 "IPv4 prefix", /*%< 69 */ 108 "TLS error", /*%< 70 */ 109 "ALPN for HTTP/2 failed" /*%< 71 */ 110 }; 111 112 static const char *identifier[ISC_R_NRESULTS] = { "ISC_R_SUCCESS", 113 "ISC_R_NOMEMORY", 114 "ISC_R_TIMEDOUT", 115 "ISC_R_NOTHREADS", 116 "ISC_R_ADDRNOTAVAIL", 117 "ISC_R_ADDRINUSE", 118 "ISC_R_NOPERM", 119 "ISC_R_NOCONN", 120 "ISC_R_NETUNREACH", 121 "ISC_R_HOSTUNREACH", 122 "ISC_R_NETDOWN", 123 "ISC_R_HOSTDOWN", 124 "ISC_R_CONNREFUSED", 125 "ISC_R_NORESOURCES", 126 "ISC_R_EOF", 127 "ISC_R_BOUND", 128 "ISC_R_RELOAD", 129 "ISC_R_LOCKBUSY", 130 "ISC_R_EXISTS", 131 "ISC_R_NOSPACE", 132 "ISC_R_CANCELED", 133 "ISC_R_NOTBOUND", 134 "ISC_R_SHUTTINGDOWN", 135 "ISC_R_NOTFOUND", 136 "ISC_R_UNEXPECTEDEND", 137 "ISC_R_FAILURE", 138 "ISC_R_IOERROR", 139 "ISC_R_NOTIMPLEMENTED", 140 "ISC_R_UNBALANCED", 141 "ISC_R_NOMORE", 142 "ISC_R_INVALIDFILE", 143 "ISC_R_BADBASE64", 144 "ISC_R_UNEXPECTEDTOKEN", 145 "ISC_R_QUOTA", 146 "ISC_R_UNEXPECTED", 147 "ISC_R_ALREADYRUNNING", 148 "ISC_R_IGNORE", 149 "ISC_R_MASKNONCONTIG", 150 "ISC_R_FILENOTFOUND", 151 "ISC_R_FILEEXISTS", 152 "ISC_R_NOTCONNECTED", 153 "ISC_R_RANGE", 154 "ISC_R_NOENTROPY", 155 "ISC_R_MULTICAST", 156 "ISC_R_NOTFILE", 157 "ISC_R_NOTDIRECTORY", 158 "ISC_R_EMPTY", 159 "ISC_R_FAMILYMISMATCH", 160 "ISC_R_FAMILYNOSUPPORT", 161 "ISC_R_BADHEX", 162 "ISC_R_TOOMANYOPENFILES", 163 "ISC_R_NOTBLOCKING", 164 "ISC_R_UNBALANCEDQUOTES", 165 "ISC_R_INPROGRESS", 166 "ISC_R_CONNECTIONRESET", 167 "ISC_R_SOFTQUOTA", 168 "ISC_R_BADNUMBER", 169 "ISC_R_DISABLED", 170 "ISC_R_MAXSIZE", 171 "ISC_R_BADADDRESSFORM", 172 "ISC_R_BADBASE32", 173 "ISC_R_UNSET", 174 "ISC_R_MULTIPLE", 175 "ISC_R_WOULDBLOCK", 176 "ISC_R_COMPLETE", 177 "ISC_R_CRYPTOFAILURE", 178 "ISC_R_DISCQUOTA", 179 "ISC_R_DISCFULL", 180 "ISC_R_DEFAULT", 181 "ISC_R_IPV4PREFIX", 182 "ISC_R_TLSERROR", 183 "ISC_R_HTTP2ALPNERROR" }; 184 185 #define ISC_RESULT_RESULTSET 2 186 #define ISC_RESULT_UNAVAILABLESET 3 187 188 static isc_once_t once = ISC_ONCE_INIT; 189 static resulttable_list_t description_tables; 190 static resulttable_list_t identifier_tables; 191 static isc_rwlock_t lock; 192 193 static isc_result_t 194 register_table(resulttable_list_t *tables, unsigned int base, 195 unsigned int nresults, const char **text, int set) { 196 resulttable *table; 197 198 REQUIRE(base % ISC_RESULTCLASS_SIZE == 0); 199 REQUIRE(nresults <= ISC_RESULTCLASS_SIZE); 200 REQUIRE(text != NULL); 201 202 /* 203 * We use malloc() here because we we want to be able to use 204 * isc_result_totext() even if there is no memory context. 205 */ 206 table = malloc(sizeof(*table)); 207 if (table == NULL) { 208 return (ISC_R_NOMEMORY); 209 } 210 table->base = base; 211 table->last = base + nresults - 1; 212 table->text = text; 213 table->set = set; 214 ISC_LINK_INIT(table, link); 215 216 RWLOCK(&lock, isc_rwlocktype_write); 217 218 ISC_LIST_APPEND(*tables, table, link); 219 220 RWUNLOCK(&lock, isc_rwlocktype_write); 221 222 return (ISC_R_SUCCESS); 223 } 224 225 static void 226 initialize_action(void) { 227 isc_result_t result; 228 229 isc_rwlock_init(&lock, 0, 0); 230 ISC_LIST_INIT(description_tables); 231 ISC_LIST_INIT(identifier_tables); 232 233 result = register_table(&description_tables, ISC_RESULTCLASS_ISC, 234 ISC_R_NRESULTS, description, 235 ISC_RESULT_RESULTSET); 236 if (result != ISC_R_SUCCESS) { 237 UNEXPECTED_ERROR(__FILE__, __LINE__, 238 "register_table() failed: %u", result); 239 } 240 241 result = register_table(&identifier_tables, ISC_RESULTCLASS_ISC, 242 ISC_R_NRESULTS, identifier, 243 ISC_RESULT_RESULTSET); 244 if (result != ISC_R_SUCCESS) { 245 UNEXPECTED_ERROR(__FILE__, __LINE__, 246 "register_table() failed: %u", result); 247 } 248 } 249 250 static void 251 initialize(void) { 252 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); 253 } 254 255 static const char * 256 isc_result_tomany_helper(resulttable_list_t *tables, isc_result_t result) { 257 resulttable *table; 258 const char *text; 259 int index; 260 261 initialize(); 262 263 RWLOCK(&lock, isc_rwlocktype_read); 264 265 text = NULL; 266 for (table = ISC_LIST_HEAD(*tables); table != NULL; 267 table = ISC_LIST_NEXT(table, link)) 268 { 269 if (result >= table->base && result <= table->last) { 270 index = (int)(result - table->base); 271 text = table->text[index]; 272 break; 273 } 274 } 275 if (text == NULL) { 276 text = "(result code text not available)"; 277 } 278 279 RWUNLOCK(&lock, isc_rwlocktype_read); 280 281 return (text); 282 } 283 284 const char * 285 isc_result_totext(isc_result_t result) { 286 return (isc_result_tomany_helper(&description_tables, result)); 287 } 288 289 const char * 290 isc_result_toid(isc_result_t result) { 291 return (isc_result_tomany_helper(&identifier_tables, result)); 292 } 293 294 isc_result_t 295 isc_result_register(unsigned int base, unsigned int nresults, const char **text, 296 int set) { 297 initialize(); 298 299 return (register_table(&description_tables, base, nresults, text, set)); 300 } 301 302 isc_result_t 303 isc_result_registerids(unsigned int base, unsigned int nresults, 304 const char **ids, int set) { 305 initialize(); 306 307 return (register_table(&identifier_tables, base, nresults, ids, set)); 308 } 309