Blame src/util/et/error_message.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/*
Packit fd8b60
 * Copyright 1997,2000,2001,2004,2008 by Massachusetts Institute of Technology
Packit fd8b60
 *
Packit fd8b60
 * Copyright 1987, 1988 by MIT Student Information Processing Board
Packit fd8b60
 *
Packit fd8b60
 * Permission to use, copy, modify, and distribute this software
Packit fd8b60
 * and its documentation for any purpose and without fee is
Packit fd8b60
 * hereby granted, provided that the above copyright notice
Packit fd8b60
 * appear in all copies and that both that copyright notice and
Packit fd8b60
 * this permission notice appear in supporting documentation,
Packit fd8b60
 * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
Packit fd8b60
 * used in advertising or publicity pertaining to distribution
Packit fd8b60
 * of the software without specific, written prior permission.
Packit fd8b60
 * Furthermore if you modify this software you must label
Packit fd8b60
 * your software as modified software and not distribute it in such a
Packit fd8b60
 * fashion that it might be confused with the original M.I.T. software.
Packit fd8b60
 * M.I.T. and the M.I.T. S.I.P.B. make no representations about
Packit fd8b60
 * the suitability of this software for any purpose.  It is
Packit fd8b60
 * provided "as is" without express or implied warranty.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#include "k5-platform.h"
Packit fd8b60
#include "com_err.h"
Packit fd8b60
#include "error_table.h"
Packit fd8b60
Packit fd8b60
static struct et_list *et_list;
Packit fd8b60
static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
rpm-build f63851
static int terminated = 0;      /* for safety and finalization debugging */
Packit fd8b60
Packit fd8b60
MAKE_INIT_FUNCTION(com_err_initialize);
Packit fd8b60
MAKE_FINI_FUNCTION(com_err_terminate);
Packit fd8b60
Packit fd8b60
int com_err_initialize(void)
Packit fd8b60
{
Packit fd8b60
    int err;
Packit fd8b60
#ifdef SHOW_INITFINI_FUNCS
Packit fd8b60
    printf("com_err_initialize\n");
Packit fd8b60
#endif
Packit fd8b60
    terminated = 0;
Packit fd8b60
    err = k5_mutex_finish_init(&et_list_lock);
Packit fd8b60
    if (err)
Packit fd8b60
        return err;
Packit fd8b60
    err = k5_mutex_finish_init(&com_err_hook_lock);
Packit fd8b60
    if (err)
Packit fd8b60
        return err;
Packit fd8b60
    err = k5_key_register(K5_KEY_COM_ERR, free);
Packit fd8b60
    if (err)
Packit fd8b60
        return err;
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
void com_err_terminate(void)
Packit fd8b60
{
Packit fd8b60
    struct et_list *e, *enext;
Packit fd8b60
    if (! INITIALIZER_RAN(com_err_initialize) || PROGRAM_EXITING()) {
Packit fd8b60
#ifdef SHOW_INITFINI_FUNCS
Packit fd8b60
        printf("com_err_terminate: skipping\n");
Packit fd8b60
#endif
Packit fd8b60
        return;
Packit fd8b60
    }
Packit fd8b60
#ifdef SHOW_INITFINI_FUNCS
Packit fd8b60
    printf("com_err_terminate\n");
Packit fd8b60
#endif
Packit fd8b60
    k5_key_delete(K5_KEY_COM_ERR);
Packit fd8b60
    k5_mutex_destroy(&com_err_hook_lock);
Packit fd8b60
    k5_mutex_lock(&et_list_lock);
Packit fd8b60
    for (e = et_list; e; e = enext) {
Packit fd8b60
        enext = e->next;
Packit fd8b60
        free(e);
Packit fd8b60
    }
rpm-build f63851
    et_list = NULL;
Packit fd8b60
    k5_mutex_unlock(&et_list_lock);
Packit fd8b60
    k5_mutex_destroy(&et_list_lock);
Packit fd8b60
    terminated = 1;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
#ifndef DEBUG_TABLE_LIST
Packit fd8b60
#define dprintf(X)
Packit fd8b60
#else
Packit fd8b60
#define dprintf(X) printf X
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
static char *
Packit fd8b60
get_thread_buffer ()
Packit fd8b60
{
Packit fd8b60
    char *cp;
Packit fd8b60
    cp = k5_getspecific(K5_KEY_COM_ERR);
Packit fd8b60
    if (cp == NULL) {
Packit fd8b60
        cp = malloc(ET_EBUFSIZ);
Packit fd8b60
        if (cp == NULL) {
Packit fd8b60
            return NULL;
Packit fd8b60
        }
Packit fd8b60
        if (k5_setspecific(K5_KEY_COM_ERR, cp) != 0) {
Packit fd8b60
            free(cp);
Packit fd8b60
            return NULL;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
    return cp;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
const char * KRB5_CALLCONV
Packit fd8b60
error_message(long code)
Packit fd8b60
{
Packit fd8b60
    unsigned long offset;
Packit fd8b60
    unsigned long l_offset;
Packit fd8b60
    struct et_list *e;
Packit fd8b60
    unsigned long table_num;
Packit fd8b60
    int started = 0;
Packit fd8b60
    unsigned int divisor = 100;
Packit fd8b60
    char *cp, *cp1;
Packit fd8b60
    const struct error_table *table;
Packit fd8b60
Packit fd8b60
    if (CALL_INIT_FUNCTION(com_err_initialize))
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    l_offset = (unsigned long)code & ((1<
Packit fd8b60
    offset = l_offset;
Packit fd8b60
    table_num = ((unsigned long)code - l_offset) & ERRCODE_MAX;
Packit fd8b60
    if (table_num == 0
Packit fd8b60
#ifdef __sgi
Packit fd8b60
        /* Irix 6.5 uses a much bigger table than other UNIX
Packit fd8b60
           systems I've looked at, but the table is sparse.  The
Packit fd8b60
           sparse entries start around 500, but sys_nerr is only
Packit fd8b60
           152.  */
Packit fd8b60
        || (code > 0 && code <= 1600)
Packit fd8b60
#endif
Packit fd8b60
    ) {
Packit fd8b60
        if (code == 0)
Packit fd8b60
            goto oops;
Packit fd8b60
Packit fd8b60
        /* This could trip if int is 16 bits.  */
Packit fd8b60
        if ((unsigned long)(int)code != (unsigned long)code)
Packit fd8b60
            abort ();
Packit fd8b60
        cp = get_thread_buffer();
Packit fd8b60
        if (cp && strerror_r(code, cp, ET_EBUFSIZ) == 0)
Packit fd8b60
            return cp;
Packit fd8b60
        return strerror(code);
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    k5_mutex_lock(&et_list_lock);
Packit fd8b60
    dprintf(("scanning list for %x\n", table_num));
Packit fd8b60
    for (e = et_list; e != NULL; e = e->next) {
Packit fd8b60
        dprintf(("\t%x = %s\n", e->table->base & ERRCODE_MAX,
Packit fd8b60
                 e->table->msgs[0]));
Packit fd8b60
        if ((e->table->base & ERRCODE_MAX) == table_num) {
Packit fd8b60
            table = e->table;
Packit fd8b60
            goto found;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
    goto no_table_found;
Packit fd8b60
Packit fd8b60
found:
Packit fd8b60
    k5_mutex_unlock(&et_list_lock);
Packit fd8b60
    dprintf (("found it!\n"));
Packit fd8b60
    /* This is the right table */
Packit fd8b60
Packit fd8b60
    /* This could trip if int is 16 bits.  */
Packit fd8b60
    if ((unsigned long)(unsigned int)offset != offset)
Packit fd8b60
        goto no_table_found;
Packit fd8b60
Packit fd8b60
    if (table->n_msgs <= (unsigned int) offset)
Packit fd8b60
        goto no_table_found;
Packit fd8b60
Packit fd8b60
    /* If there's a string at the end of the table, it's a text domain. */
Packit fd8b60
    if (table->msgs[table->n_msgs] != NULL)
Packit fd8b60
        return dgettext(table->msgs[table->n_msgs], table->msgs[offset]);
Packit fd8b60
    else
Packit fd8b60
        return table->msgs[offset];
Packit fd8b60
Packit fd8b60
no_table_found:
Packit fd8b60
    k5_mutex_unlock(&et_list_lock);
Packit fd8b60
#if defined(_WIN32)
Packit fd8b60
    /*
Packit fd8b60
     * WinSock errors exist in the 10000 and 11000 ranges
Packit fd8b60
     * but might not appear if WinSock is not initialized
Packit fd8b60
     */
Packit fd8b60
    if (code >= WSABASEERR && code < WSABASEERR + 1100) {
Packit fd8b60
        table_num = 0;
Packit fd8b60
        offset = code;
Packit fd8b60
        divisor = WSABASEERR;
Packit fd8b60
    }
Packit fd8b60
#endif
Packit fd8b60
#ifdef _WIN32
Packit fd8b60
    {
Packit fd8b60
        LPVOID msgbuf;
Packit fd8b60
Packit fd8b60
        if (! FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
Packit fd8b60
                             NULL /* lpSource */,
Packit fd8b60
                             (DWORD) code,
Packit fd8b60
                             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
Packit fd8b60
                             (LPTSTR) &msgbuf,
Packit fd8b60
                             (DWORD) 0 /*sizeof(buffer)*/,
Packit fd8b60
                             NULL /* va_list */ )) {
Packit fd8b60
            /*
Packit fd8b60
             * WinSock errors exist in the 10000 and 11000 ranges
Packit fd8b60
             * but might not appear if WinSock is not initialized
Packit fd8b60
             */
Packit fd8b60
            if (code >= WSABASEERR && code < WSABASEERR + 1100) {
Packit fd8b60
                table_num = 0;
Packit fd8b60
                offset = code;
Packit fd8b60
                divisor = 10000;
Packit fd8b60
            }
Packit fd8b60
Packit fd8b60
            goto oops;
Packit fd8b60
        } else {
Packit fd8b60
            char *buffer;
Packit fd8b60
            cp = get_thread_buffer();
Packit fd8b60
            if (cp == NULL)
Packit fd8b60
                return "Unknown error code";
Packit fd8b60
            buffer = cp;
Packit fd8b60
            strncpy(buffer, msgbuf, ET_EBUFSIZ);
Packit fd8b60
            buffer[ET_EBUFSIZ-1] = '\0';
Packit fd8b60
            cp = buffer + strlen(buffer) - 1;
Packit fd8b60
            if (*cp == '\n') *cp-- = '\0';
Packit fd8b60
            if (*cp == '\r') *cp-- = '\0';
Packit fd8b60
            if (*cp == '.') *cp-- = '\0';
Packit fd8b60
Packit fd8b60
            LocalFree(msgbuf);
Packit fd8b60
            return buffer;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
oops:
Packit fd8b60
Packit fd8b60
    cp = get_thread_buffer();
Packit fd8b60
    if (cp == NULL)
Packit fd8b60
        return "Unknown error code";
Packit fd8b60
    cp1 = cp;
Packit fd8b60
    strlcpy(cp, "Unknown code ", ET_EBUFSIZ);
Packit fd8b60
    cp += sizeof("Unknown code ") - 1;
Packit fd8b60
    if (table_num != 0L) {
Packit fd8b60
        (void) error_table_name_r(table_num, cp);
Packit fd8b60
        while (*cp != '\0')
Packit fd8b60
            cp++;
Packit fd8b60
        *cp++ = ' ';
Packit fd8b60
    }
Packit fd8b60
    while (divisor > 1) {
Packit fd8b60
        if (started != 0 || offset >= divisor) {
Packit fd8b60
            *cp++ = '0' + offset / divisor;
Packit fd8b60
            offset %= divisor;
Packit fd8b60
            started++;
Packit fd8b60
        }
Packit fd8b60
        divisor /= 10;
Packit fd8b60
    }
Packit fd8b60
    *cp++ = '0' + offset;
Packit fd8b60
    *cp = '\0';
Packit fd8b60
    return(cp1);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
errcode_t KRB5_CALLCONV
Packit fd8b60
add_error_table(const struct error_table *et)
Packit fd8b60
{
Packit fd8b60
    struct et_list *e;
Packit fd8b60
Packit fd8b60
    if (CALL_INIT_FUNCTION(com_err_initialize))
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    e = malloc(sizeof(struct et_list));
Packit fd8b60
    if (e == NULL)
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    e->table = et;
Packit fd8b60
Packit fd8b60
    k5_mutex_lock(&et_list_lock);
Packit fd8b60
    e->next = et_list;
Packit fd8b60
    et_list = e;
Packit fd8b60
Packit fd8b60
    /* If there are two strings at the end of the table, they are a text domain
Packit fd8b60
     * and locale dir, and we are supposed to call bindtextdomain. */
Packit fd8b60
    if (et->msgs[et->n_msgs] != NULL && et->msgs[et->n_msgs + 1] != NULL)
Packit fd8b60
        bindtextdomain(et->msgs[et->n_msgs], et->msgs[et->n_msgs + 1]);
Packit fd8b60
Packit fd8b60
    k5_mutex_unlock(&et_list_lock);
Packit fd8b60
    return 0;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
errcode_t KRB5_CALLCONV
Packit fd8b60
remove_error_table(const struct error_table *et)
Packit fd8b60
{
Packit fd8b60
    struct et_list **ep, *e;
Packit fd8b60
rpm-build f63851
    /* Safety check in case libraries are finalized in the wrong order. */
rpm-build f63851
    if (terminated)
rpm-build f63851
        return ENOENT;
rpm-build f63851
Packit fd8b60
    if (CALL_INIT_FUNCTION(com_err_initialize))
Packit fd8b60
        return 0;
Packit fd8b60
    k5_mutex_lock(&et_list_lock);
Packit fd8b60
Packit fd8b60
    /* Remove the entry that matches the error table instance. */
Packit fd8b60
    for (ep = &et_list; *ep; ep = &(*ep)->next) {
Packit fd8b60
        if ((*ep)->table == et) {
Packit fd8b60
            e = *ep;
Packit fd8b60
            *ep = e->next;
Packit fd8b60
            free(e);
Packit fd8b60
            k5_mutex_unlock(&et_list_lock);
Packit fd8b60
            return 0;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
    k5_mutex_unlock(&et_list_lock);
Packit fd8b60
    return ENOENT;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
int com_err_finish_init()
Packit fd8b60
{
Packit fd8b60
    return CALL_INIT_FUNCTION(com_err_initialize);
Packit fd8b60
}