2N/A
2N/A/*
2N/A * Copyright 1997 by Massachusetts Institute of Technology
2N/A *
2N/A * Copyright 1987, 1988 by MIT Student Information Processing Board
2N/A *
2N/A * Permission to use, copy, modify, and distribute this software
2N/A * and its documentation for any purpose and without fee is
2N/A * hereby granted, provided that the above copyright notice
2N/A * appear in all copies and that both that copyright notice and
2N/A * this permission notice appear in supporting documentation,
2N/A * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
2N/A * used in advertising or publicity pertaining to distribution
2N/A * of the software without specific, written prior permission.
2N/A * Furthermore if you modify this software you must label
2N/A * your software as modified software and not distribute it in such a
2N/A * fashion that it might be confused with the original M.I.T. software.
2N/A * M.I.T. and the M.I.T. S.I.P.B. make no representations about
2N/A * the suitability of this software for any purpose. It is
2N/A * provided "as is" without express or implied warranty.
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A#include <stdlib.h>
2N/A#include <locale.h>
2N/A
2N/A#include "com_err.h"
2N/A#include "error_table.h"
2N/A
2N/A#if defined(_WIN32)
2N/A#include <io.h>
2N/A#endif
2N/A
2N/Ak5_mutex_t com_err_hook_lock = K5_MUTEX_PARTIAL_INITIALIZER;
2N/A
2N/Astatic void default_com_err_proc
2N/A(const char *whoami, errcode_t code,
2N/A const char *fmt, va_list ap);
2N/A
2N/A#if defined(_WIN32)
2N/ABOOL isGuiApp() {
2N/A DWORD mypid;
2N/A HANDLE myprocess;
2N/A mypid = GetCurrentProcessId();
2N/A myprocess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, mypid);
2N/A return GetGuiResources(myprocess, 1) > 0;
2N/A }
2N/A#endif
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * It is sometimes desirable to have more than a single hook called
2N/A * when com_err() is invoked. A number of new functions have been
2N/A * added which allow hooks to be added and removed:
2N/A * add_com_err_hook()
2N/A * add_default_com_err_hook()
2N/A * remove_com_err_hook()
2N/A * remove_default_com_err_hook()
2N/A * The existing functions:
2N/A * set_com_err_hook()
2N/A * reset_com_err_hook()
2N/A * com_err()
2N/A * have been modified to work with the new scheme. Applications using
2N/A * the original function calls are not affected.
2N/A */
2N/A#define MAX_HOOKS 3
2N/Astatic et_old_error_hook_func com_err_hook[MAX_HOOKS] = { default_com_err_proc,
2N/A NULL, NULL };
2N/Astatic int hook_count = 1;
2N/A
2N/A/* Solaris Kerberos specific fix start --------------------------- */
2N/A
2N/A#define gettext(X) X
2N/A
2N/Astruct msg_map {
2N/A char *msgid;
2N/A char *c_msgstr;
2N/A};
2N/A
2N/Astruct msg_map msgmap[] = {
2N/A
2N/A#define MSG_WHILE 0
2N/A { gettext("%s\n## com_err msg of format: 'while ...'"),
2N/A "%s\n" },
2N/A
2N/A#define MSG_ERROR_MSG 1
2N/A { gettext("%s\n## com_err message of format: 'error msg ...'"),
2N/A "%s\n" },
2N/A
2N/A#define MSG_ERROR_MSG_WHILE 2
2N/A { gettext("%1$s %2$s\n## com_err message of format: "
2N/A "'error msg ... while ...'"),
2N/A "%1$s %2$s\n" },
2N/A
2N/A#define MSG_WHOAMI_WHILE 3
2N/A { gettext("%1$s: %2$s\n## com_err msg of format: 'whoami: while ...'"),
2N/A "%1$s: %2$s\n" },
2N/A
2N/A#define MSG_WHOAMI_ERROR_MSG 4
2N/A { gettext("%1$s: %2$s\n## com_err message of format: "
2N/A "'whoami: error msg ...'"),
2N/A "%1$s: %2$s\n" },
2N/A
2N/A#define MSG_WHOAMI_ERROR_MSG_WHILE 5
2N/A { gettext("%1$s: %2$s %3$s\n## com_err message of format: "
2N/A "'whoami: error msg ... while ...'"),
2N/A "%1$s: %2$s %3$s\n" },
2N/A
2N/A#define MSG_WHOAMI 6
2N/A { gettext("%s:\n ## com_err message of format: "
2N/A "'whoami: with no error msg or while ...'"),
2N/A "%s:\n " }
2N/A};
2N/A
2N/A#undef gettext
2N/A
2N/A/*
2N/A * The idea is that we provide a unique message id that contains extra junk
2N/A * that we never want to display in the C locale. If dgettext() returns
2N/A * a string that is equal to the message id, then we return the c_msgstr,
2N/A * for display in the locale.
2N/A */
2N/Astatic char *
2N/Amy_gettext(int msg_idx)
2N/A{
2N/A char *msgid = msgmap[msg_idx].msgid;
2N/A char *c_msgstr = msgmap[msg_idx].c_msgstr;
2N/A char *msgstr = dgettext(TEXT_DOMAIN, msgid);
2N/A
2N/A if (strcmp(msgstr, msgid) == 0)
2N/A return (c_msgstr);
2N/A else
2N/A return (msgstr);
2N/A}
2N/A
2N/A/* Solaris Kerberos specific fix end --------------------------- */
2N/A
2N/A/* Solaris Kerberos: this code is significantly altered from
2N/A * the MIT 1.2.1 version to work with internationalization */
2N/A
2N/Astatic void default_com_err_proc (const char *whoami, errcode_t code,
2N/A const char *fmt, va_list ap)
2N/A{
2N/A char *whilebuf = NULL;
2N/A
2N/A /*
2N/A * Because 'while ...' message could contain a format string
2N/A * we have to intepret it now, in a buffer. We need to put it
2N/A * into a buffer so that the message can be juxtaposed in a locale
2N/A * meaningful manner. In some natural languages, the 'while ...' phrase
2N/A * must be first.
2N/A */
2N/A if (fmt) {
2N/A vasprintf(&whilebuf, fmt, ap);
2N/A if (whilebuf == NULL)
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * There are 8 possible combinations here depending on whether
2N/A * a whoami string was provided, error code is non-zero, and if a
2N/A * a 'while ...' messge was provided.
2N/A */
2N/A if (!whoami) {
2N/A
2N/A if ((!code) && fmt) {
2N/A
2N/A fprintf(stderr, my_gettext(MSG_WHILE),
2N/A whilebuf);
2N/A
2N/A } else if (code && !fmt) {
2N/A
2N/A fprintf(stderr, my_gettext(MSG_ERROR_MSG),
2N/A error_message(code));
2N/A
2N/A } else if (code && fmt) {
2N/A
2N/A fprintf(stderr, my_gettext(MSG_ERROR_MSG_WHILE),
2N/A error_message(code), whilebuf);
2N/A } else
2N/A return;
2N/A
2N/A } else {
2N/A
2N/A if ((!code) && fmt) {
2N/A
2N/A fprintf(stderr, my_gettext(MSG_WHOAMI_WHILE),
2N/A whoami, whilebuf);
2N/A
2N/A } else if (code && !fmt) {
2N/A
2N/A fprintf(stderr, my_gettext(MSG_WHOAMI_ERROR_MSG),
2N/A whoami, error_message(code));
2N/A
2N/A } else if (code && fmt) {
2N/A
2N/A fprintf(stderr,
2N/A my_gettext(MSG_WHOAMI_ERROR_MSG_WHILE),
2N/A whoami, error_message(code), whilebuf);
2N/A } else {
2N/A
2N/A fprintf(stderr,
2N/A my_gettext(MSG_WHOAMI),
2N/A whoami);
2N/A }
2N/A }
2N/A
2N/A fflush(stderr);
2N/A if (whilebuf != NULL)
2N/A free (whilebuf);
2N/A}
2N/A
2N/Avoid KRB5_CALLCONV com_err_va(const char *whoami,
2N/A errcode_t code,
2N/A const char *fmt,
2N/A va_list ap)
2N/A{
2N/A int err;
2N/A int i;
2N/A err = com_err_finish_init();
2N/A if (err)
2N/A goto best_try;
2N/A err = k5_mutex_lock(&com_err_hook_lock);
2N/A if (err)
2N/A goto best_try;
2N/A for (i = 0; i < hook_count; i++) {
2N/A (com_err_hook[i])(whoami, code, fmt, ap);
2N/A }
2N/A k5_mutex_unlock(&com_err_hook_lock);
2N/A return;
2N/A
2N/Abest_try:
2N/A /* Yikes. Our library initialization failed or we couldn't lock
2N/A the lock we want. We could be in trouble. Gosh, we should
2N/A probably print an error message. Oh, wait. That's what we're
2N/A trying to do. In fact, if we're losing on initialization here,
2N/A there's a good chance it has to do with failed initialization
2N/A of the caller. */
2N/A
2N/A for (i = 0; i < hook_count; i++) {
2N/A (com_err_hook[i])(whoami, code, fmt, ap);
2N/A }
2N/A assert(err == 0);
2N/A abort();
2N/A}
2N/A
2N/A
2N/Avoid KRB5_CALLCONV_C com_err(const char *whoami,
2N/A errcode_t code,
2N/A const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A
2N/A va_start(ap, fmt);
2N/A com_err_va(whoami, code, fmt, ap);
2N/A va_end(ap);
2N/A}
2N/A
2N/A/* Make a separate function because the assert invocations below
2N/A use the macro expansion on some platforms, which may be insanely
2N/A long and incomprehensible. */
2N/Astatic int com_err_lock_hook_handle(void)
2N/A{
2N/A return k5_mutex_lock(&com_err_hook_lock);
2N/A}
2N/A
2N/Aet_old_error_hook_func set_com_err_hook (et_old_error_hook_func new_proc)
2N/A{
2N/A int i;
2N/A et_old_error_hook_func x;
2N/A
2N/A /* Broken initialization? What can we do? */
2N/A assert(com_err_finish_init() == 0);
2N/A assert(com_err_lock_hook_handle() == 0);
2N/A
2N/A x = com_err_hook[0];
2N/A
2N/A for (i = 0; i < hook_count; i++)
2N/A com_err_hook[i] = NULL;
2N/A
2N/A com_err_hook[0] = new_proc;
2N/A hook_count = 1;
2N/A
2N/A k5_mutex_unlock(&com_err_hook_lock);
2N/A return x;
2N/A}
2N/A
2N/Aet_old_error_hook_func reset_com_err_hook ()
2N/A{
2N/A int i;
2N/A et_old_error_hook_func x;
2N/A
2N/A /* Broken initialization? What can we do? */
2N/A assert(com_err_finish_init() == 0);
2N/A assert(com_err_lock_hook_handle() == 0);
2N/A x = com_err_hook[0];
2N/A for (i = 0; i < hook_count; i++)
2N/A com_err_hook[i] = NULL;
2N/A
2N/A com_err_hook[0] = default_com_err_proc;
2N/A hook_count = 1;
2N/A k5_mutex_unlock(&com_err_hook_lock);
2N/A return x;
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Register a hook which will be called every time
2N/A * com_err() is called.
2N/A */
2N/Avoid add_com_err_hook(et_old_error_hook_func f) {
2N/A int i;
2N/A if (hook_count < MAX_HOOKS) {
2N/A for (i = 0; i < hook_count; i++) {
2N/A if (com_err_hook[i] == NULL)
2N/A break;
2N/A }
2N/A com_err_hook[i] = f;
2N/A hook_count++;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Remove a logging hook. The first hook matching 'f' will
2N/A * be removed.
2N/A */
2N/Avoid rem_com_err_hook(et_old_error_hook_func f) {
2N/A int i, j;
2N/A
2N/A for (i = 0; i < hook_count; i++) {
2N/A if (com_err_hook[i] == f) {
2N/A for (j = i; j < hook_count - 1; j++) {
2N/A com_err_hook[j] = com_err_hook[j+1];
2N/A }
2N/A com_err_hook[j] = NULL;
2N/A hook_count--;
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Remove the default hook.
2N/A */
2N/Avoid rem_default_com_err_hook() {
2N/A rem_com_err_hook(default_com_err_proc);
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Add back the default hook
2N/A */
2N/Avoid add_default_com_err_hook() {
2N/A add_com_err_hook(default_com_err_proc);
2N/A}