err_def.c revision 296465
1/* crypto/err/err_def.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58/* ==================================================================== 59 * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. 60 * 61 * Redistribution and use in source and binary forms, with or without 62 * modification, are permitted provided that the following conditions 63 * are met: 64 * 65 * 1. Redistributions of source code must retain the above copyright 66 * notice, this list of conditions and the following disclaimer. 67 * 68 * 2. Redistributions in binary form must reproduce the above copyright 69 * notice, this list of conditions and the following disclaimer in 70 * the documentation and/or other materials provided with the 71 * distribution. 72 * 73 * 3. All advertising materials mentioning features or use of this 74 * software must display the following acknowledgment: 75 * "This product includes software developed by the OpenSSL Project 76 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 77 * 78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 79 * endorse or promote products derived from this software without 80 * prior written permission. For written permission, please contact 81 * openssl-core@openssl.org. 82 * 83 * 5. Products derived from this software may not be called "OpenSSL" 84 * nor may "OpenSSL" appear in their names without prior written 85 * permission of the OpenSSL Project. 86 * 87 * 6. Redistributions of any form whatsoever must retain the following 88 * acknowledgment: 89 * "This product includes software developed by the OpenSSL Project 90 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 91 * 92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 95 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 103 * OF THE POSSIBILITY OF SUCH DAMAGE. 104 * ==================================================================== 105 * 106 * This product includes cryptographic software written by Eric Young 107 * (eay@cryptsoft.com). This product includes software written by Tim 108 * Hudson (tjh@cryptsoft.com). 109 * 110 */ 111 112#include <stdio.h> 113#include <stdarg.h> 114#include <string.h> 115#include "cryptlib.h" 116#include <openssl/lhash.h> 117#include <openssl/crypto.h> 118#include <openssl/buffer.h> 119#include <openssl/bio.h> 120#include <openssl/err.h> 121 122#define err_clear_data(p,i) \ 123 do { \ 124 if (((p)->err_data[i] != NULL) && \ 125 (p)->err_data_flags[i] & ERR_TXT_MALLOCED) \ 126 { \ 127 OPENSSL_free((p)->err_data[i]); \ 128 (p)->err_data[i]=NULL; \ 129 } \ 130 (p)->err_data_flags[i]=0; \ 131 } while(0) 132 133#define err_clear(p,i) \ 134 do { \ 135 (p)->err_flags[i]=0; \ 136 (p)->err_buffer[i]=0; \ 137 err_clear_data(p,i); \ 138 (p)->err_file[i]=NULL; \ 139 (p)->err_line[i]= -1; \ 140 } while(0) 141 142static void err_load_strings(int lib, ERR_STRING_DATA *str); 143 144static void ERR_STATE_free(ERR_STATE *s); 145 146/* Define the predeclared (but externally opaque) "ERR_FNS" type */ 147struct st_ERR_FNS { 148 /* Works on the "error_hash" string table */ 149 LHASH *(*cb_err_get) (int create); 150 void (*cb_err_del) (void); 151 ERR_STRING_DATA *(*cb_err_get_item) (const ERR_STRING_DATA *); 152 ERR_STRING_DATA *(*cb_err_set_item) (ERR_STRING_DATA *); 153 ERR_STRING_DATA *(*cb_err_del_item) (ERR_STRING_DATA *); 154 /* Works on the "thread_hash" error-state table */ 155 LHASH *(*cb_thread_get) (int create); 156 void (*cb_thread_release) (LHASH **hash); 157 ERR_STATE *(*cb_thread_get_item) (const ERR_STATE *); 158 ERR_STATE *(*cb_thread_set_item) (ERR_STATE *); 159 void (*cb_thread_del_item) (const ERR_STATE *); 160 /* Returns the next available error "library" numbers */ 161 int (*cb_get_next_lib) (void); 162}; 163 164/* Predeclarations of the "err_defaults" functions */ 165static LHASH *int_err_get(int create); 166static void int_err_del(void); 167static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *); 168static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *); 169static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *); 170static LHASH *int_thread_get(int create); 171static void int_thread_release(LHASH **hash); 172static ERR_STATE *int_thread_get_item(const ERR_STATE *); 173static ERR_STATE *int_thread_set_item(ERR_STATE *); 174static void int_thread_del_item(const ERR_STATE *); 175static int int_err_get_next_lib(void); 176/* The static ERR_FNS table using these defaults functions */ 177static const ERR_FNS err_defaults = { 178 int_err_get, 179 int_err_del, 180 int_err_get_item, 181 int_err_set_item, 182 int_err_del_item, 183 int_thread_get, 184 int_thread_release, 185 int_thread_get_item, 186 int_thread_set_item, 187 int_thread_del_item, 188 int_err_get_next_lib 189}; 190 191/* The replacable table of ERR_FNS functions we use at run-time */ 192static const ERR_FNS *err_fns = NULL; 193 194/* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */ 195#define ERRFN(a) err_fns->cb_##a 196 197/* 198 * The internal state used by "err_defaults" - as such, the setting, reading, 199 * creating, and deleting of this data should only be permitted via the 200 * "err_defaults" functions. This way, a linked module can completely defer 201 * all ERR state operation (together with requisite locking) to the 202 * implementations and state in the loading application. 203 */ 204static LHASH *int_error_hash = NULL; 205static LHASH *int_thread_hash = NULL; 206static int int_thread_hash_references = 0; 207static int int_err_library_number = ERR_LIB_USER; 208 209/* 210 * Internal function that checks whether "err_fns" is set and if not, sets it 211 * to the defaults. 212 */ 213static void err_fns_check(void) 214{ 215 if (err_fns) 216 return; 217 218 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 219 if (!err_fns) 220 err_fns = &err_defaults; 221 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 222} 223 224/* API functions to get or set the underlying ERR functions. */ 225 226const ERR_FNS *ERR_get_implementation(void) 227{ 228 err_fns_check(); 229 return err_fns; 230} 231 232int ERR_set_implementation(const ERR_FNS *fns) 233{ 234 int ret = 0; 235 236 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 237 /* 238 * It's too late if 'err_fns' is non-NULL. BTW: not much point setting an 239 * error is there?! 240 */ 241 if (!err_fns) { 242 err_fns = fns; 243 ret = 1; 244 } 245 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 246 return ret; 247} 248 249/* 250 * These are the callbacks provided to "lh_new()" when creating the LHASH 251 * tables internal to the "err_defaults" implementation. 252 */ 253 254/* static unsigned long err_hash(ERR_STRING_DATA *a); */ 255static unsigned long err_hash(const void *a_void); 256/* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b); */ 257static int err_cmp(const void *a_void, const void *b_void); 258/* static unsigned long pid_hash(ERR_STATE *pid); */ 259static unsigned long pid_hash(const void *pid_void); 260/* static int pid_cmp(ERR_STATE *a,ERR_STATE *pid); */ 261static int pid_cmp(const void *a_void, const void *pid_void); 262 263/* The internal functions used in the "err_defaults" implementation */ 264 265static LHASH *int_err_get(int create) 266{ 267 LHASH *ret = NULL; 268 269 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 270 if (!int_error_hash && create) { 271 CRYPTO_push_info("int_err_get (err.c)"); 272 int_error_hash = lh_new(err_hash, err_cmp); 273 CRYPTO_pop_info(); 274 } 275 if (int_error_hash) 276 ret = int_error_hash; 277 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 278 279 return ret; 280} 281 282static void int_err_del(void) 283{ 284 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 285 if (int_error_hash) { 286 lh_free(int_error_hash); 287 int_error_hash = NULL; 288 } 289 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 290} 291 292static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d) 293{ 294 ERR_STRING_DATA *p; 295 LHASH *hash; 296 297 err_fns_check(); 298 hash = ERRFN(err_get) (0); 299 if (!hash) 300 return NULL; 301 302 CRYPTO_r_lock(CRYPTO_LOCK_ERR); 303 p = (ERR_STRING_DATA *)lh_retrieve(hash, d); 304 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); 305 306 return p; 307} 308 309static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d) 310{ 311 ERR_STRING_DATA *p; 312 LHASH *hash; 313 314 err_fns_check(); 315 hash = ERRFN(err_get) (1); 316 if (!hash) 317 return NULL; 318 319 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 320 p = (ERR_STRING_DATA *)lh_insert(hash, d); 321 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 322 323 return p; 324} 325 326static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d) 327{ 328 ERR_STRING_DATA *p; 329 LHASH *hash; 330 331 err_fns_check(); 332 hash = ERRFN(err_get) (0); 333 if (!hash) 334 return NULL; 335 336 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 337 p = (ERR_STRING_DATA *)lh_delete(hash, d); 338 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 339 340 return p; 341} 342 343static LHASH *int_thread_get(int create) 344{ 345 LHASH *ret = NULL; 346 347 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 348 if (!int_thread_hash && create) { 349 CRYPTO_push_info("int_thread_get (err.c)"); 350 int_thread_hash = lh_new(pid_hash, pid_cmp); 351 CRYPTO_pop_info(); 352 } 353 if (int_thread_hash) { 354 int_thread_hash_references++; 355 ret = int_thread_hash; 356 } 357 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 358 return ret; 359} 360 361static void int_thread_release(LHASH **hash) 362{ 363 int i; 364 365 if (hash == NULL || *hash == NULL) 366 return; 367 368 i = CRYPTO_add(&int_thread_hash_references, -1, CRYPTO_LOCK_ERR); 369 370#ifdef REF_PRINT 371 fprintf(stderr, "%4d:%s\n", int_thread_hash_references, "ERR"); 372#endif 373 if (i > 0) 374 return; 375#ifdef REF_CHECK 376 if (i < 0) { 377 fprintf(stderr, "int_thread_release, bad reference count\n"); 378 abort(); /* ok */ 379 } 380#endif 381 *hash = NULL; 382} 383 384static ERR_STATE *int_thread_get_item(const ERR_STATE *d) 385{ 386 ERR_STATE *p; 387 LHASH *hash; 388 389 err_fns_check(); 390 hash = ERRFN(thread_get) (0); 391 if (!hash) 392 return NULL; 393 394 CRYPTO_r_lock(CRYPTO_LOCK_ERR); 395 p = (ERR_STATE *)lh_retrieve(hash, d); 396 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); 397 398 ERRFN(thread_release) (&hash); 399 return p; 400} 401 402static ERR_STATE *int_thread_set_item(ERR_STATE *d) 403{ 404 ERR_STATE *p; 405 LHASH *hash; 406 407 err_fns_check(); 408 hash = ERRFN(thread_get) (1); 409 if (!hash) 410 return NULL; 411 412 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 413 p = (ERR_STATE *)lh_insert(hash, d); 414 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 415 416 ERRFN(thread_release) (&hash); 417 return p; 418} 419 420static void int_thread_del_item(const ERR_STATE *d) 421{ 422 ERR_STATE *p; 423 LHASH *hash; 424 425 err_fns_check(); 426 hash = ERRFN(thread_get) (0); 427 if (!hash) 428 return; 429 430 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 431 p = (ERR_STATE *)lh_delete(hash, d); 432 /* make sure we don't leak memory */ 433 if (int_thread_hash_references == 1 434 && int_thread_hash && (lh_num_items(int_thread_hash) == 0)) { 435 lh_free(int_thread_hash); 436 int_thread_hash = NULL; 437 } 438 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 439 440 ERRFN(thread_release) (&hash); 441 if (p) 442 ERR_STATE_free(p); 443} 444 445static int int_err_get_next_lib(void) 446{ 447 int ret; 448 449 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 450 ret = int_err_library_number++; 451 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 452 453 return ret; 454} 455 456static void ERR_STATE_free(ERR_STATE *s) 457{ 458 int i; 459 460 if (s == NULL) 461 return; 462 463 for (i = 0; i < ERR_NUM_ERRORS; i++) { 464 err_clear_data(s, i); 465 } 466 OPENSSL_free(s); 467} 468 469static void err_load_strings(int lib, ERR_STRING_DATA *str) 470{ 471 while (str->error) { 472 if (lib) 473 str->error |= ERR_PACK(lib, 0, 0); 474 ERRFN(err_set_item) (str); 475 str++; 476 } 477} 478 479void ERR_load_strings(int lib, ERR_STRING_DATA *str) 480{ 481 err_fns_check(); 482 err_load_strings(lib, str); 483} 484 485void ERR_unload_strings(int lib, ERR_STRING_DATA *str) 486{ 487 while (str->error) { 488 if (lib) 489 str->error |= ERR_PACK(lib, 0, 0); 490 ERRFN(err_del_item) (str); 491 str++; 492 } 493} 494 495void ERR_free_strings(void) 496{ 497 err_fns_check(); 498 ERRFN(err_del) (); 499} 500 501LHASH *ERR_get_string_table(void) 502{ 503 err_fns_check(); 504 return ERRFN(err_get) (0); 505} 506 507LHASH *ERR_get_err_state_table(void) 508{ 509 err_fns_check(); 510 return ERRFN(thread_get) (0); 511} 512 513void ERR_release_err_state_table(LHASH **hash) 514{ 515 err_fns_check(); 516 ERRFN(thread_release) (hash); 517} 518 519const char *ERR_lib_error_string(unsigned long e) 520{ 521 ERR_STRING_DATA d, *p; 522 unsigned long l; 523 524 err_fns_check(); 525 l = ERR_GET_LIB(e); 526 d.error = ERR_PACK(l, 0, 0); 527 p = ERRFN(err_get_item) (&d); 528 return ((p == NULL) ? NULL : p->string); 529} 530 531const char *ERR_func_error_string(unsigned long e) 532{ 533 ERR_STRING_DATA d, *p; 534 unsigned long l, f; 535 536 err_fns_check(); 537 l = ERR_GET_LIB(e); 538 f = ERR_GET_FUNC(e); 539 d.error = ERR_PACK(l, f, 0); 540 p = ERRFN(err_get_item) (&d); 541 return ((p == NULL) ? NULL : p->string); 542} 543 544const char *ERR_reason_error_string(unsigned long e) 545{ 546 ERR_STRING_DATA d, *p = NULL; 547 unsigned long l, r; 548 549 err_fns_check(); 550 l = ERR_GET_LIB(e); 551 r = ERR_GET_REASON(e); 552 d.error = ERR_PACK(l, 0, r); 553 p = ERRFN(err_get_item) (&d); 554 if (!p) { 555 d.error = ERR_PACK(0, 0, r); 556 p = ERRFN(err_get_item) (&d); 557 } 558 return ((p == NULL) ? NULL : p->string); 559} 560 561/* static unsigned long err_hash(ERR_STRING_DATA *a) */ 562static unsigned long err_hash(const void *a_void) 563{ 564 unsigned long ret, l; 565 566 l = ((const ERR_STRING_DATA *)a_void)->error; 567 ret = l ^ ERR_GET_LIB(l) ^ ERR_GET_FUNC(l); 568 return (ret ^ ret % 19 * 13); 569} 570 571/* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b) */ 572static int err_cmp(const void *a_void, const void *b_void) 573{ 574 return ((int)(((const ERR_STRING_DATA *)a_void)->error - 575 ((const ERR_STRING_DATA *)b_void)->error)); 576} 577 578/* static unsigned long pid_hash(ERR_STATE *a) */ 579static unsigned long pid_hash(const void *a_void) 580{ 581 return (((const ERR_STATE *)a_void)->pid * 13); 582} 583 584/* static int pid_cmp(ERR_STATE *a, ERR_STATE *b) */ 585static int pid_cmp(const void *a_void, const void *b_void) 586{ 587 return ((int)((long)((const ERR_STATE *)a_void)->pid - 588 (long)((const ERR_STATE *)b_void)->pid)); 589} 590 591#ifdef OPENSSL_FIPS 592static void int_err_remove_state(unsigned long pid) 593#else 594void ERR_remove_state(unsigned long pid) 595#endif 596{ 597 ERR_STATE tmp; 598 599 err_fns_check(); 600 if (pid == 0) 601 pid = (unsigned long)CRYPTO_thread_id(); 602 tmp.pid = pid; 603 /* 604 * thread_del_item automatically destroys the LHASH if the number of 605 * items reaches zero. 606 */ 607 ERRFN(thread_del_item) (&tmp); 608} 609 610#ifdef OPENSSL_FIPS 611static ERR_STATE *int_err_get_state(void) 612#else 613ERR_STATE *ERR_get_state(void) 614#endif 615{ 616 static ERR_STATE fallback; 617 ERR_STATE *ret, tmp, *tmpp = NULL; 618 int i; 619 unsigned long pid; 620 621 err_fns_check(); 622 pid = (unsigned long)CRYPTO_thread_id(); 623 tmp.pid = pid; 624 ret = ERRFN(thread_get_item) (&tmp); 625 626 /* ret == the error state, if NULL, make a new one */ 627 if (ret == NULL) { 628 ret = (ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE)); 629 if (ret == NULL) 630 return (&fallback); 631 ret->pid = pid; 632 ret->top = 0; 633 ret->bottom = 0; 634 for (i = 0; i < ERR_NUM_ERRORS; i++) { 635 ret->err_data[i] = NULL; 636 ret->err_data_flags[i] = 0; 637 } 638 tmpp = ERRFN(thread_set_item) (ret); 639 /* To check if insertion failed, do a get. */ 640 if (ERRFN(thread_get_item) (ret) != ret) { 641 ERR_STATE_free(ret); /* could not insert it */ 642 return (&fallback); 643 } 644 /* 645 * If a race occured in this function and we came second, tmpp is the 646 * first one that we just replaced. 647 */ 648 if (tmpp) 649 ERR_STATE_free(tmpp); 650 } 651 return ret; 652} 653 654#ifdef OPENSSL_FIPS 655void int_ERR_lib_init(void) 656{ 657 int_ERR_set_state_func(int_err_get_state, int_err_remove_state); 658} 659#endif 660 661int ERR_get_next_error_library(void) 662{ 663 err_fns_check(); 664 return ERRFN(get_next_lib) (); 665} 666