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