10Sstevel@tonic-gate /*
26426Smp153739 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate
70Sstevel@tonic-gate /*
80Sstevel@tonic-gate * Copyright 1997 by Massachusetts Institute of Technology
9*7934SMark.Phalan@Sun.COM *
100Sstevel@tonic-gate * Copyright 1987, 1988 by MIT Student Information Processing Board
110Sstevel@tonic-gate *
120Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software
130Sstevel@tonic-gate * and its documentation for any purpose and without fee is
140Sstevel@tonic-gate * hereby granted, provided that the above copyright notice
150Sstevel@tonic-gate * appear in all copies and that both that copyright notice and
160Sstevel@tonic-gate * this permission notice appear in supporting documentation,
170Sstevel@tonic-gate * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
180Sstevel@tonic-gate * used in advertising or publicity pertaining to distribution
190Sstevel@tonic-gate * of the software without specific, written prior permission.
200Sstevel@tonic-gate * Furthermore if you modify this software you must label
210Sstevel@tonic-gate * your software as modified software and not distribute it in such a
220Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
230Sstevel@tonic-gate * M.I.T. and the M.I.T. S.I.P.B. make no representations about
240Sstevel@tonic-gate * the suitability of this software for any purpose. It is
250Sstevel@tonic-gate * provided "as is" without express or implied warranty.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <stdio.h>
290Sstevel@tonic-gate #include <string.h>
30*7934SMark.Phalan@Sun.COM #include <stdlib.h>
310Sstevel@tonic-gate #include <locale.h>
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include "com_err.h"
340Sstevel@tonic-gate #include "error_table.h"
350Sstevel@tonic-gate
36*7934SMark.Phalan@Sun.COM #if defined(_WIN32)
370Sstevel@tonic-gate #include <io.h>
380Sstevel@tonic-gate #endif
39*7934SMark.Phalan@Sun.COM
40*7934SMark.Phalan@Sun.COM k5_mutex_t com_err_hook_lock = K5_MUTEX_PARTIAL_INITIALIZER;
410Sstevel@tonic-gate
420Sstevel@tonic-gate static void default_com_err_proc
43781Sgtb (const char *whoami, errcode_t code,
44781Sgtb const char *fmt, va_list ap);
450Sstevel@tonic-gate
46*7934SMark.Phalan@Sun.COM #if defined(_WIN32)
isGuiApp()47*7934SMark.Phalan@Sun.COM BOOL isGuiApp() {
48*7934SMark.Phalan@Sun.COM DWORD mypid;
49*7934SMark.Phalan@Sun.COM HANDLE myprocess;
50*7934SMark.Phalan@Sun.COM mypid = GetCurrentProcessId();
51*7934SMark.Phalan@Sun.COM myprocess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, mypid);
52*7934SMark.Phalan@Sun.COM return GetGuiResources(myprocess, 1) > 0;
53*7934SMark.Phalan@Sun.COM }
54*7934SMark.Phalan@Sun.COM #endif
55*7934SMark.Phalan@Sun.COM
566426Smp153739 /*
576426Smp153739 * Solaris Kerberos:
586426Smp153739 * It is sometimes desirable to have more than a single hook called
596426Smp153739 * when com_err() is invoked. A number of new functions have been
606426Smp153739 * added which allow hooks to be added and removed:
616426Smp153739 * add_com_err_hook()
626426Smp153739 * add_default_com_err_hook()
636426Smp153739 * remove_com_err_hook()
646426Smp153739 * remove_default_com_err_hook()
656426Smp153739 * The existing functions:
666426Smp153739 * set_com_err_hook()
676426Smp153739 * reset_com_err_hook()
686426Smp153739 * com_err()
696426Smp153739 * have been modified to work with the new scheme. Applications using
706426Smp153739 * the original function calls are not affected.
716426Smp153739 */
726426Smp153739 #define MAX_HOOKS 3
736426Smp153739 static et_old_error_hook_func com_err_hook[MAX_HOOKS] = { default_com_err_proc,
746426Smp153739 NULL, NULL };
756426Smp153739 static int hook_count = 1;
766426Smp153739
770Sstevel@tonic-gate /* Solaris Kerberos specific fix start --------------------------- */
780Sstevel@tonic-gate
790Sstevel@tonic-gate #define gettext(X) X
800Sstevel@tonic-gate
810Sstevel@tonic-gate struct msg_map {
820Sstevel@tonic-gate char *msgid;
830Sstevel@tonic-gate char *c_msgstr;
840Sstevel@tonic-gate };
850Sstevel@tonic-gate
860Sstevel@tonic-gate struct msg_map msgmap[] = {
870Sstevel@tonic-gate
880Sstevel@tonic-gate #define MSG_WHILE 0
890Sstevel@tonic-gate { gettext("%s\n## com_err msg of format: 'while ...'"),
900Sstevel@tonic-gate "%s\n" },
910Sstevel@tonic-gate
920Sstevel@tonic-gate #define MSG_ERROR_MSG 1
930Sstevel@tonic-gate { gettext("%s\n## com_err message of format: 'error msg ...'"),
940Sstevel@tonic-gate "%s\n" },
950Sstevel@tonic-gate
960Sstevel@tonic-gate #define MSG_ERROR_MSG_WHILE 2
970Sstevel@tonic-gate { gettext("%1$s %2$s\n## com_err message of format: "
980Sstevel@tonic-gate "'error msg ... while ...'"),
990Sstevel@tonic-gate "%1$s %2$s\n" },
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate #define MSG_WHOAMI_WHILE 3
1020Sstevel@tonic-gate { gettext("%1$s: %2$s\n## com_err msg of format: 'whoami: while ...'"),
1030Sstevel@tonic-gate "%1$s: %2$s\n" },
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate #define MSG_WHOAMI_ERROR_MSG 4
1060Sstevel@tonic-gate { gettext("%1$s: %2$s\n## com_err message of format: "
1070Sstevel@tonic-gate "'whoami: error msg ...'"),
1080Sstevel@tonic-gate "%1$s: %2$s\n" },
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate #define MSG_WHOAMI_ERROR_MSG_WHILE 5
1110Sstevel@tonic-gate { gettext("%1$s: %2$s %3$s\n## com_err message of format: "
1120Sstevel@tonic-gate "'whoami: error msg ... while ...'"),
1130Sstevel@tonic-gate "%1$s: %2$s %3$s\n" },
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate #define MSG_WHOAMI 6
1160Sstevel@tonic-gate { gettext("%s:\n ## com_err message of format: "
1170Sstevel@tonic-gate "'whoami: with no error msg or while ...'"),
1180Sstevel@tonic-gate "%s:\n " }
1190Sstevel@tonic-gate };
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate #undef gettext
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate * The idea is that we provide a unique message id that contains extra junk
1250Sstevel@tonic-gate * that we never want to display in the C locale. If dgettext() returns
1260Sstevel@tonic-gate * a string that is equal to the message id, then we return the c_msgstr,
1270Sstevel@tonic-gate * for display in the locale.
1280Sstevel@tonic-gate */
1290Sstevel@tonic-gate static char *
my_gettext(int msg_idx)1300Sstevel@tonic-gate my_gettext(int msg_idx)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate char *msgid = msgmap[msg_idx].msgid;
1330Sstevel@tonic-gate char *c_msgstr = msgmap[msg_idx].c_msgstr;
1340Sstevel@tonic-gate char *msgstr = dgettext(TEXT_DOMAIN, msgid);
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate if (strcmp(msgstr, msgid) == 0)
1370Sstevel@tonic-gate return (c_msgstr);
1380Sstevel@tonic-gate else
1390Sstevel@tonic-gate return (msgstr);
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /* Solaris Kerberos specific fix end --------------------------- */
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /* Solaris Kerberos: this code is significantly altered from
1450Sstevel@tonic-gate * the MIT 1.2.1 version to work with internationalization */
146*7934SMark.Phalan@Sun.COM
default_com_err_proc(const char * whoami,errcode_t code,const char * fmt,va_list ap)147*7934SMark.Phalan@Sun.COM static void default_com_err_proc (const char *whoami, errcode_t code,
148*7934SMark.Phalan@Sun.COM const char *fmt, va_list ap)
1490Sstevel@tonic-gate {
1500Sstevel@tonic-gate char whilebuf[1024] = "";
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate *whilebuf = '\0';
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate * Because 'while ...' message could contain a format string
1560Sstevel@tonic-gate * we have to intepret it now, in a buffer. We need to put it
1570Sstevel@tonic-gate * into a buffer so that the message can be juxtaposed in a locale
1580Sstevel@tonic-gate * meaningful manner. In some natural languages, the 'while ...' phrase
1590Sstevel@tonic-gate * must be first.
1600Sstevel@tonic-gate */
1610Sstevel@tonic-gate if (fmt) {
1620Sstevel@tonic-gate vsprintf(whilebuf, fmt, ap);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * There are 8 possible combinations here depending on whether
1670Sstevel@tonic-gate * a whoami string was provided, error code is non-zero, and if a
1680Sstevel@tonic-gate * a 'while ...' messge was provided.
1690Sstevel@tonic-gate */
1700Sstevel@tonic-gate if (!whoami) {
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate if ((!code) && fmt) {
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_WHILE),
1750Sstevel@tonic-gate whilebuf);
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate } else if (code && !fmt) {
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_ERROR_MSG),
1800Sstevel@tonic-gate error_message(code));
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate } else if (code && fmt) {
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_ERROR_MSG_WHILE),
1850Sstevel@tonic-gate error_message(code), whilebuf);
1860Sstevel@tonic-gate } else
1870Sstevel@tonic-gate return;
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate } else {
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate if ((!code) && fmt) {
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_WHOAMI_WHILE),
1940Sstevel@tonic-gate whoami, whilebuf);
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate } else if (code && !fmt) {
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_WHOAMI_ERROR_MSG),
1990Sstevel@tonic-gate whoami, error_message(code));
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate } else if (code && fmt) {
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate fprintf(stderr,
2040Sstevel@tonic-gate my_gettext(MSG_WHOAMI_ERROR_MSG_WHILE),
2050Sstevel@tonic-gate whoami, error_message(code), whilebuf);
2060Sstevel@tonic-gate } else {
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate fprintf(stderr,
2090Sstevel@tonic-gate my_gettext(MSG_WHOAMI),
2100Sstevel@tonic-gate whoami);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate fflush(stderr);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate
com_err_va(const char * whoami,errcode_t code,const char * fmt,va_list ap)217*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV com_err_va(const char *whoami,
218*7934SMark.Phalan@Sun.COM errcode_t code,
219*7934SMark.Phalan@Sun.COM const char *fmt,
220*7934SMark.Phalan@Sun.COM va_list ap)
2210Sstevel@tonic-gate {
222*7934SMark.Phalan@Sun.COM int err;
223*7934SMark.Phalan@Sun.COM int i;
224*7934SMark.Phalan@Sun.COM err = com_err_finish_init();
225*7934SMark.Phalan@Sun.COM if (err)
226*7934SMark.Phalan@Sun.COM goto best_try;
227*7934SMark.Phalan@Sun.COM err = k5_mutex_lock(&com_err_hook_lock);
228*7934SMark.Phalan@Sun.COM if (err)
229*7934SMark.Phalan@Sun.COM goto best_try;
230*7934SMark.Phalan@Sun.COM for (i = 0; i < hook_count; i++) {
231*7934SMark.Phalan@Sun.COM (com_err_hook[i])(whoami, code, fmt, ap);
232*7934SMark.Phalan@Sun.COM }
233*7934SMark.Phalan@Sun.COM k5_mutex_unlock(&com_err_hook_lock);
234*7934SMark.Phalan@Sun.COM return;
2356426Smp153739
236*7934SMark.Phalan@Sun.COM best_try:
237*7934SMark.Phalan@Sun.COM /* Yikes. Our library initialization failed or we couldn't lock
238*7934SMark.Phalan@Sun.COM the lock we want. We could be in trouble. Gosh, we should
239*7934SMark.Phalan@Sun.COM probably print an error message. Oh, wait. That's what we're
240*7934SMark.Phalan@Sun.COM trying to do. In fact, if we're losing on initialization here,
241*7934SMark.Phalan@Sun.COM there's a good chance it has to do with failed initialization
242*7934SMark.Phalan@Sun.COM of the caller. */
243*7934SMark.Phalan@Sun.COM
244*7934SMark.Phalan@Sun.COM for (i = 0; i < hook_count; i++) {
245*7934SMark.Phalan@Sun.COM (com_err_hook[i])(whoami, code, fmt, ap);
246*7934SMark.Phalan@Sun.COM }
247*7934SMark.Phalan@Sun.COM assert(err == 0);
248*7934SMark.Phalan@Sun.COM abort();
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate
com_err(const char * whoami,errcode_t code,const char * fmt,...)252*7934SMark.Phalan@Sun.COM void KRB5_CALLCONV_C com_err(const char *whoami,
253*7934SMark.Phalan@Sun.COM errcode_t code,
254*7934SMark.Phalan@Sun.COM const char *fmt, ...)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate va_list ap;
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate va_start(ap, fmt);
2590Sstevel@tonic-gate com_err_va(whoami, code, fmt, ap);
2600Sstevel@tonic-gate va_end(ap);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
263*7934SMark.Phalan@Sun.COM /* Make a separate function because the assert invocations below
264*7934SMark.Phalan@Sun.COM use the macro expansion on some platforms, which may be insanely
265*7934SMark.Phalan@Sun.COM long and incomprehensible. */
com_err_lock_hook_handle(void)266*7934SMark.Phalan@Sun.COM static int com_err_lock_hook_handle(void)
267*7934SMark.Phalan@Sun.COM {
268*7934SMark.Phalan@Sun.COM return k5_mutex_lock(&com_err_hook_lock);
269*7934SMark.Phalan@Sun.COM }
270*7934SMark.Phalan@Sun.COM
set_com_err_hook(et_old_error_hook_func new_proc)271*7934SMark.Phalan@Sun.COM et_old_error_hook_func set_com_err_hook (et_old_error_hook_func new_proc)
2720Sstevel@tonic-gate {
2736426Smp153739 int i;
274*7934SMark.Phalan@Sun.COM et_old_error_hook_func x;
275*7934SMark.Phalan@Sun.COM
276*7934SMark.Phalan@Sun.COM /* Broken initialization? What can we do? */
277*7934SMark.Phalan@Sun.COM assert(com_err_finish_init() == 0);
278*7934SMark.Phalan@Sun.COM assert(com_err_lock_hook_handle() == 0);
279*7934SMark.Phalan@Sun.COM
280*7934SMark.Phalan@Sun.COM x = com_err_hook[0];
2810Sstevel@tonic-gate
2826426Smp153739 for (i = 0; i < hook_count; i++)
2836426Smp153739 com_err_hook[i] = NULL;
2846426Smp153739
2856426Smp153739 com_err_hook[0] = new_proc;
2866426Smp153739 hook_count = 1;
2876426Smp153739
288*7934SMark.Phalan@Sun.COM k5_mutex_unlock(&com_err_hook_lock);
2890Sstevel@tonic-gate return x;
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
reset_com_err_hook()2920Sstevel@tonic-gate et_old_error_hook_func reset_com_err_hook ()
2930Sstevel@tonic-gate {
2946426Smp153739 int i;
295*7934SMark.Phalan@Sun.COM et_old_error_hook_func x;
2960Sstevel@tonic-gate
297*7934SMark.Phalan@Sun.COM /* Broken initialization? What can we do? */
298*7934SMark.Phalan@Sun.COM assert(com_err_finish_init() == 0);
299*7934SMark.Phalan@Sun.COM assert(com_err_lock_hook_handle() == 0);
300*7934SMark.Phalan@Sun.COM x = com_err_hook[0];
3016426Smp153739 for (i = 0; i < hook_count; i++)
3026426Smp153739 com_err_hook[i] = NULL;
3036426Smp153739
3046426Smp153739 com_err_hook[0] = default_com_err_proc;
3056426Smp153739 hook_count = 1;
306*7934SMark.Phalan@Sun.COM k5_mutex_unlock(&com_err_hook_lock);
3070Sstevel@tonic-gate return x;
3080Sstevel@tonic-gate }
3096426Smp153739
3106426Smp153739 /*
3116426Smp153739 * Solaris Kerberos:
3126426Smp153739 * Register a hook which will be called every time
3136426Smp153739 * com_err() is called.
3146426Smp153739 */
add_com_err_hook(et_old_error_hook_func f)3156426Smp153739 void add_com_err_hook(et_old_error_hook_func f) {
3166426Smp153739 int i;
3176426Smp153739 if (hook_count < MAX_HOOKS) {
3186426Smp153739 for (i = 0; i < hook_count; i++) {
3196426Smp153739 if (com_err_hook[i] == NULL)
3206426Smp153739 break;
3216426Smp153739 }
3226426Smp153739 com_err_hook[i] = f;
3236426Smp153739 hook_count++;
3246426Smp153739 }
3256426Smp153739 }
3266426Smp153739
3276426Smp153739 /*
3286426Smp153739 * Solaris Kerberos:
3296426Smp153739 * Remove a logging hook. The first hook matching 'f' will
3306426Smp153739 * be removed.
3316426Smp153739 */
rem_com_err_hook(et_old_error_hook_func f)3326426Smp153739 void rem_com_err_hook(et_old_error_hook_func f) {
3336426Smp153739 int i, j;
3346426Smp153739
3356426Smp153739 for (i = 0; i < hook_count; i++) {
3366426Smp153739 if (com_err_hook[i] == f) {
3376426Smp153739 for (j = i; j < hook_count - 1; j++) {
3386426Smp153739 com_err_hook[j] = com_err_hook[j+1];
3396426Smp153739 }
3406426Smp153739 com_err_hook[j] = NULL;
3416426Smp153739 hook_count--;
3426426Smp153739 }
3436426Smp153739 }
3446426Smp153739 }
3456426Smp153739
3466426Smp153739 /*
3476426Smp153739 * Solaris Kerberos:
3486426Smp153739 * Remove the default hook.
3496426Smp153739 */
rem_default_com_err_hook()3506426Smp153739 void rem_default_com_err_hook() {
3516426Smp153739 rem_com_err_hook(default_com_err_proc);
3526426Smp153739 }
3536426Smp153739
3546426Smp153739 /*
3556426Smp153739 * Solaris Kerberos:
3566426Smp153739 * Add back the default hook
3576426Smp153739 */
add_default_com_err_hook()3586426Smp153739 void add_default_com_err_hook() {
3596426Smp153739 add_com_err_hook(default_com_err_proc);
3606426Smp153739 }
361