Path: blob/main/crypto/krb5/src/util/et/error_message.c
34907 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/*2* Copyright 1997,2000,2001,2004,2008 by Massachusetts Institute of Technology3*4* Copyright 1987, 1988 by MIT Student Information Processing Board5*6* Permission to use, copy, modify, and distribute this software7* and its documentation for any purpose and without fee is8* hereby granted, provided that the above copyright notice9* appear in all copies and that both that copyright notice and10* this permission notice appear in supporting documentation,11* and that the names of M.I.T. and the M.I.T. S.I.P.B. not be12* used in advertising or publicity pertaining to distribution13* of the software without specific, written prior permission.14* Furthermore if you modify this software you must label15* your software as modified software and not distribute it in such a16* fashion that it might be confused with the original M.I.T. software.17* M.I.T. and the M.I.T. S.I.P.B. make no representations about18* the suitability of this software for any purpose. It is19* provided "as is" without express or implied warranty.20*/2122#include "k5-platform.h"23#include "com_err.h"24#include "error_table.h"2526static struct et_list *et_list;27static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;28static int terminated = 0; /* for safety and finalization debugging */2930MAKE_INIT_FUNCTION(com_err_initialize);31MAKE_FINI_FUNCTION(com_err_terminate);3233int com_err_initialize(void)34{35int err;36#ifdef SHOW_INITFINI_FUNCS37printf("com_err_initialize\n");38#endif39terminated = 0;40err = k5_mutex_finish_init(&et_list_lock);41if (err)42return err;43err = k5_mutex_finish_init(&com_err_hook_lock);44if (err)45return err;46err = k5_key_register(K5_KEY_COM_ERR, free);47if (err)48return err;49return 0;50}5152void com_err_terminate(void)53{54struct et_list *e, *enext;55if (! INITIALIZER_RAN(com_err_initialize) || PROGRAM_EXITING()) {56#ifdef SHOW_INITFINI_FUNCS57printf("com_err_terminate: skipping\n");58#endif59return;60}61#ifdef SHOW_INITFINI_FUNCS62printf("com_err_terminate\n");63#endif64k5_key_delete(K5_KEY_COM_ERR);65k5_mutex_destroy(&com_err_hook_lock);66k5_mutex_lock(&et_list_lock);67for (e = et_list; e; e = enext) {68enext = e->next;69free(e);70}71et_list = NULL;72k5_mutex_unlock(&et_list_lock);73k5_mutex_destroy(&et_list_lock);74terminated = 1;75}7677#ifndef DEBUG_TABLE_LIST78#define dprintf(X)79#else80#define dprintf(X) printf X81#endif8283static char *84get_thread_buffer(void)85{86char *cp;87cp = k5_getspecific(K5_KEY_COM_ERR);88if (cp == NULL) {89cp = malloc(ET_EBUFSIZ);90if (cp == NULL) {91return NULL;92}93if (k5_setspecific(K5_KEY_COM_ERR, cp) != 0) {94free(cp);95return NULL;96}97}98return cp;99}100101const char * KRB5_CALLCONV102error_message(long code)103{104unsigned long offset;105unsigned long l_offset;106struct et_list *e;107unsigned long table_num;108int started = 0;109unsigned int divisor = 100;110char *cp, *cp1;111const struct error_table *table;112113if (CALL_INIT_FUNCTION(com_err_initialize))114return 0;115116l_offset = (unsigned long)code & ((1<<ERRCODE_RANGE)-1);117offset = l_offset;118table_num = ((unsigned long)code - l_offset) & ERRCODE_MAX;119if (table_num == 0120#ifdef __sgi121/* Irix 6.5 uses a much bigger table than other UNIX122systems I've looked at, but the table is sparse. The123sparse entries start around 500, but sys_nerr is only124152. */125|| (code > 0 && code <= 1600)126#endif127) {128if (code == 0)129goto oops;130131/* This could trip if int is 16 bits. */132if ((unsigned long)(int)code != (unsigned long)code)133abort ();134cp = get_thread_buffer();135if (cp && strerror_r(code, cp, ET_EBUFSIZ) == 0)136return cp;137return strerror(code);138}139140k5_mutex_lock(&et_list_lock);141dprintf(("scanning list for %x\n", table_num));142for (e = et_list; e != NULL; e = e->next) {143dprintf(("\t%x = %s\n", e->table->base & ERRCODE_MAX,144e->table->msgs[0]));145if ((e->table->base & ERRCODE_MAX) == table_num) {146table = e->table;147goto found;148}149}150goto no_table_found;151152found:153k5_mutex_unlock(&et_list_lock);154dprintf (("found it!\n"));155/* This is the right table */156157/* This could trip if int is 16 bits. */158if ((unsigned long)(unsigned int)offset != offset)159goto no_table_found;160161if (table->n_msgs <= (unsigned int) offset)162goto no_table_found;163164/* If there's a string at the end of the table, it's a text domain. */165if (table->msgs[table->n_msgs] != NULL)166return dgettext(table->msgs[table->n_msgs], table->msgs[offset]);167else168return table->msgs[offset];169170no_table_found:171k5_mutex_unlock(&et_list_lock);172#if defined(_WIN32)173/*174* WinSock errors exist in the 10000 and 11000 ranges175* but might not appear if WinSock is not initialized176*/177if (code >= WSABASEERR && code < WSABASEERR + 1100) {178table_num = 0;179offset = code;180divisor = WSABASEERR;181}182#endif183#ifdef _WIN32184{185LPVOID msgbuf;186187if (! FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,188NULL /* lpSource */,189(DWORD) code,190MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),191(LPTSTR) &msgbuf,192(DWORD) 0 /*sizeof(buffer)*/,193NULL /* va_list */ )) {194/*195* WinSock errors exist in the 10000 and 11000 ranges196* but might not appear if WinSock is not initialized197*/198if (code >= WSABASEERR && code < WSABASEERR + 1100) {199table_num = 0;200offset = code;201divisor = 10000;202}203204goto oops;205} else {206char *buffer;207cp = get_thread_buffer();208if (cp == NULL)209return "Unknown error code";210buffer = cp;211strncpy(buffer, msgbuf, ET_EBUFSIZ);212buffer[ET_EBUFSIZ-1] = '\0';213cp = buffer + strlen(buffer) - 1;214if (*cp == '\n') *cp-- = '\0';215if (*cp == '\r') *cp-- = '\0';216if (*cp == '.') *cp-- = '\0';217218LocalFree(msgbuf);219return buffer;220}221}222#endif223224oops:225226cp = get_thread_buffer();227if (cp == NULL)228return "Unknown error code";229cp1 = cp;230strlcpy(cp, "Unknown code ", ET_EBUFSIZ);231cp += sizeof("Unknown code ") - 1;232if (table_num != 0L) {233(void) error_table_name_r(table_num, cp);234while (*cp != '\0')235cp++;236*cp++ = ' ';237}238while (divisor > 1) {239if (started != 0 || offset >= divisor) {240*cp++ = '0' + offset / divisor;241offset %= divisor;242started++;243}244divisor /= 10;245}246*cp++ = '0' + offset;247*cp = '\0';248return(cp1);249}250251errcode_t KRB5_CALLCONV252add_error_table(const struct error_table *et)253{254struct et_list *e;255256if (CALL_INIT_FUNCTION(com_err_initialize))257return 0;258259e = malloc(sizeof(struct et_list));260if (e == NULL)261return ENOMEM;262263e->table = et;264265k5_mutex_lock(&et_list_lock);266e->next = et_list;267et_list = e;268269/* If there are two strings at the end of the table, they are a text domain270* and locale dir, and we are supposed to call bindtextdomain. */271if (et->msgs[et->n_msgs] != NULL && et->msgs[et->n_msgs + 1] != NULL)272bindtextdomain(et->msgs[et->n_msgs], et->msgs[et->n_msgs + 1]);273274k5_mutex_unlock(&et_list_lock);275return 0;276}277278errcode_t KRB5_CALLCONV279remove_error_table(const struct error_table *et)280{281struct et_list **ep, *e;282283/* Safety check in case libraries are finalized in the wrong order. */284if (terminated)285return ENOENT;286287if (CALL_INIT_FUNCTION(com_err_initialize))288return 0;289k5_mutex_lock(&et_list_lock);290291/* Remove the entry that matches the error table instance. */292for (ep = &et_list; *ep; ep = &(*ep)->next) {293if ((*ep)->table == et) {294e = *ep;295*ep = e->next;296free(e);297k5_mutex_unlock(&et_list_lock);298return 0;299}300}301k5_mutex_unlock(&et_list_lock);302return ENOENT;303}304305int com_err_finish_init(void)306{307return CALL_INIT_FUNCTION(com_err_initialize);308}309310311