17c478bd9Sstevel@tonic-gate /*
27c64d375Smp * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
37c478bd9Sstevel@tonic-gate * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate * Copyright 1997 by Massachusetts Institute of Technology
9*55fea89dSDan Cross *
107c478bd9Sstevel@tonic-gate * Copyright 1987, 1988 by MIT Student Information Processing Board
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software
137c478bd9Sstevel@tonic-gate * and its documentation for any purpose and without fee is
147c478bd9Sstevel@tonic-gate * hereby granted, provided that the above copyright notice
157c478bd9Sstevel@tonic-gate * appear in all copies and that both that copyright notice and
167c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation,
177c478bd9Sstevel@tonic-gate * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
187c478bd9Sstevel@tonic-gate * used in advertising or publicity pertaining to distribution
197c478bd9Sstevel@tonic-gate * of the software without specific, written prior permission.
207c478bd9Sstevel@tonic-gate * Furthermore if you modify this software you must label
217c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a
227c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
237c478bd9Sstevel@tonic-gate * M.I.T. and the M.I.T. S.I.P.B. make no representations about
247c478bd9Sstevel@tonic-gate * the suitability of this software for any purpose. It is
257c478bd9Sstevel@tonic-gate * provided "as is" without express or implied warranty.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
30159d09a2SMark Phalan #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <locale.h>
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #include "com_err.h"
347c478bd9Sstevel@tonic-gate #include "error_table.h"
357c478bd9Sstevel@tonic-gate
36159d09a2SMark Phalan #if defined(_WIN32)
377c478bd9Sstevel@tonic-gate #include <io.h>
387c478bd9Sstevel@tonic-gate #endif
39159d09a2SMark Phalan
40159d09a2SMark Phalan k5_mutex_t com_err_hook_lock = K5_MUTEX_PARTIAL_INITIALIZER;
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate static void default_com_err_proc
43505d05c7Sgtb (const char *whoami, errcode_t code,
44505d05c7Sgtb const char *fmt, va_list ap);
457c478bd9Sstevel@tonic-gate
46159d09a2SMark Phalan #if defined(_WIN32)
isGuiApp()47159d09a2SMark Phalan BOOL isGuiApp() {
48159d09a2SMark Phalan DWORD mypid;
49159d09a2SMark Phalan HANDLE myprocess;
50159d09a2SMark Phalan mypid = GetCurrentProcessId();
51159d09a2SMark Phalan myprocess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, mypid);
52159d09a2SMark Phalan return GetGuiResources(myprocess, 1) > 0;
53159d09a2SMark Phalan }
54159d09a2SMark Phalan #endif
55159d09a2SMark Phalan
567c64d375Smp /*
577c64d375Smp * Solaris Kerberos:
587c64d375Smp * It is sometimes desirable to have more than a single hook called
597c64d375Smp * when com_err() is invoked. A number of new functions have been
607c64d375Smp * added which allow hooks to be added and removed:
617c64d375Smp * add_com_err_hook()
627c64d375Smp * add_default_com_err_hook()
637c64d375Smp * remove_com_err_hook()
647c64d375Smp * remove_default_com_err_hook()
657c64d375Smp * The existing functions:
667c64d375Smp * set_com_err_hook()
677c64d375Smp * reset_com_err_hook()
687c64d375Smp * com_err()
697c64d375Smp * have been modified to work with the new scheme. Applications using
707c64d375Smp * the original function calls are not affected.
717c64d375Smp */
727c64d375Smp #define MAX_HOOKS 3
737c64d375Smp static et_old_error_hook_func com_err_hook[MAX_HOOKS] = { default_com_err_proc,
747c64d375Smp NULL, NULL };
757c64d375Smp static int hook_count = 1;
767c64d375Smp
777c478bd9Sstevel@tonic-gate /* Solaris Kerberos specific fix start --------------------------- */
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate #define gettext(X) X
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate struct msg_map {
827c478bd9Sstevel@tonic-gate char *msgid;
837c478bd9Sstevel@tonic-gate char *c_msgstr;
847c478bd9Sstevel@tonic-gate };
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate struct msg_map msgmap[] = {
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate #define MSG_WHILE 0
897c478bd9Sstevel@tonic-gate { gettext("%s\n## com_err msg of format: 'while ...'"),
907c478bd9Sstevel@tonic-gate "%s\n" },
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate #define MSG_ERROR_MSG 1
937c478bd9Sstevel@tonic-gate { gettext("%s\n## com_err message of format: 'error msg ...'"),
947c478bd9Sstevel@tonic-gate "%s\n" },
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate #define MSG_ERROR_MSG_WHILE 2
977c478bd9Sstevel@tonic-gate { gettext("%1$s %2$s\n## com_err message of format: "
987c478bd9Sstevel@tonic-gate "'error msg ... while ...'"),
997c478bd9Sstevel@tonic-gate "%1$s %2$s\n" },
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate #define MSG_WHOAMI_WHILE 3
1027c478bd9Sstevel@tonic-gate { gettext("%1$s: %2$s\n## com_err msg of format: 'whoami: while ...'"),
1037c478bd9Sstevel@tonic-gate "%1$s: %2$s\n" },
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate #define MSG_WHOAMI_ERROR_MSG 4
1067c478bd9Sstevel@tonic-gate { gettext("%1$s: %2$s\n## com_err message of format: "
1077c478bd9Sstevel@tonic-gate "'whoami: error msg ...'"),
1087c478bd9Sstevel@tonic-gate "%1$s: %2$s\n" },
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate #define MSG_WHOAMI_ERROR_MSG_WHILE 5
1117c478bd9Sstevel@tonic-gate { gettext("%1$s: %2$s %3$s\n## com_err message of format: "
1127c478bd9Sstevel@tonic-gate "'whoami: error msg ... while ...'"),
1137c478bd9Sstevel@tonic-gate "%1$s: %2$s %3$s\n" },
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate #define MSG_WHOAMI 6
1167c478bd9Sstevel@tonic-gate { gettext("%s:\n ## com_err message of format: "
1177c478bd9Sstevel@tonic-gate "'whoami: with no error msg or while ...'"),
1187c478bd9Sstevel@tonic-gate "%s:\n " }
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate #undef gettext
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * The idea is that we provide a unique message id that contains extra junk
1257c478bd9Sstevel@tonic-gate * that we never want to display in the C locale. If dgettext() returns
1267c478bd9Sstevel@tonic-gate * a string that is equal to the message id, then we return the c_msgstr,
1277c478bd9Sstevel@tonic-gate * for display in the locale.
1287c478bd9Sstevel@tonic-gate */
1297c478bd9Sstevel@tonic-gate static char *
my_gettext(int msg_idx)1307c478bd9Sstevel@tonic-gate my_gettext(int msg_idx)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate char *msgid = msgmap[msg_idx].msgid;
1337c478bd9Sstevel@tonic-gate char *c_msgstr = msgmap[msg_idx].c_msgstr;
1347c478bd9Sstevel@tonic-gate char *msgstr = dgettext(TEXT_DOMAIN, msgid);
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate if (strcmp(msgstr, msgid) == 0)
1377c478bd9Sstevel@tonic-gate return (c_msgstr);
1387c478bd9Sstevel@tonic-gate else
1397c478bd9Sstevel@tonic-gate return (msgstr);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate /* Solaris Kerberos specific fix end --------------------------- */
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate /* Solaris Kerberos: this code is significantly altered from
1457c478bd9Sstevel@tonic-gate * the MIT 1.2.1 version to work with internationalization */
146159d09a2SMark Phalan
default_com_err_proc(const char * whoami,errcode_t code,const char * fmt,va_list ap)147159d09a2SMark Phalan static void default_com_err_proc (const char *whoami, errcode_t code,
148159d09a2SMark Phalan const char *fmt, va_list ap)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate char whilebuf[1024] = "";
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate *whilebuf = '\0';
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate * Because 'while ...' message could contain a format string
1567c478bd9Sstevel@tonic-gate * we have to intepret it now, in a buffer. We need to put it
1577c478bd9Sstevel@tonic-gate * into a buffer so that the message can be juxtaposed in a locale
1587c478bd9Sstevel@tonic-gate * meaningful manner. In some natural languages, the 'while ...' phrase
1597c478bd9Sstevel@tonic-gate * must be first.
1607c478bd9Sstevel@tonic-gate */
1617c478bd9Sstevel@tonic-gate if (fmt) {
1627c478bd9Sstevel@tonic-gate vsprintf(whilebuf, fmt, ap);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate * There are 8 possible combinations here depending on whether
1677c478bd9Sstevel@tonic-gate * a whoami string was provided, error code is non-zero, and if a
1687c478bd9Sstevel@tonic-gate * a 'while ...' messge was provided.
1697c478bd9Sstevel@tonic-gate */
1707c478bd9Sstevel@tonic-gate if (!whoami) {
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate if ((!code) && fmt) {
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_WHILE),
1757c478bd9Sstevel@tonic-gate whilebuf);
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate } else if (code && !fmt) {
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_ERROR_MSG),
1807c478bd9Sstevel@tonic-gate error_message(code));
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate } else if (code && fmt) {
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_ERROR_MSG_WHILE),
1857c478bd9Sstevel@tonic-gate error_message(code), whilebuf);
1867c478bd9Sstevel@tonic-gate } else
1877c478bd9Sstevel@tonic-gate return;
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate } else {
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate if ((!code) && fmt) {
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_WHOAMI_WHILE),
1947c478bd9Sstevel@tonic-gate whoami, whilebuf);
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate } else if (code && !fmt) {
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate fprintf(stderr, my_gettext(MSG_WHOAMI_ERROR_MSG),
1997c478bd9Sstevel@tonic-gate whoami, error_message(code));
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate } else if (code && fmt) {
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate fprintf(stderr,
2047c478bd9Sstevel@tonic-gate my_gettext(MSG_WHOAMI_ERROR_MSG_WHILE),
2057c478bd9Sstevel@tonic-gate whoami, error_message(code), whilebuf);
2067c478bd9Sstevel@tonic-gate } else {
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate fprintf(stderr,
2097c478bd9Sstevel@tonic-gate my_gettext(MSG_WHOAMI),
2107c478bd9Sstevel@tonic-gate whoami);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate fflush(stderr);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate
com_err_va(const char * whoami,errcode_t code,const char * fmt,va_list ap)217159d09a2SMark Phalan void KRB5_CALLCONV com_err_va(const char *whoami,
218159d09a2SMark Phalan errcode_t code,
219159d09a2SMark Phalan const char *fmt,
220159d09a2SMark Phalan va_list ap)
2217c478bd9Sstevel@tonic-gate {
222159d09a2SMark Phalan int err;
223159d09a2SMark Phalan int i;
224159d09a2SMark Phalan err = com_err_finish_init();
225159d09a2SMark Phalan if (err)
226159d09a2SMark Phalan goto best_try;
227159d09a2SMark Phalan err = k5_mutex_lock(&com_err_hook_lock);
228159d09a2SMark Phalan if (err)
229159d09a2SMark Phalan goto best_try;
230159d09a2SMark Phalan for (i = 0; i < hook_count; i++) {
231159d09a2SMark Phalan (com_err_hook[i])(whoami, code, fmt, ap);
232159d09a2SMark Phalan }
233159d09a2SMark Phalan k5_mutex_unlock(&com_err_hook_lock);
234159d09a2SMark Phalan return;
235159d09a2SMark Phalan
236159d09a2SMark Phalan best_try:
237159d09a2SMark Phalan /* Yikes. Our library initialization failed or we couldn't lock
238159d09a2SMark Phalan the lock we want. We could be in trouble. Gosh, we should
239159d09a2SMark Phalan probably print an error message. Oh, wait. That's what we're
240159d09a2SMark Phalan trying to do. In fact, if we're losing on initialization here,
241159d09a2SMark Phalan there's a good chance it has to do with failed initialization
242159d09a2SMark Phalan of the caller. */
243159d09a2SMark Phalan
244159d09a2SMark Phalan for (i = 0; i < hook_count; i++) {
245159d09a2SMark Phalan (com_err_hook[i])(whoami, code, fmt, ap);
246159d09a2SMark Phalan }
247159d09a2SMark Phalan assert(err == 0);
248159d09a2SMark Phalan abort();
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate
com_err(const char * whoami,errcode_t code,const char * fmt,...)252159d09a2SMark Phalan void KRB5_CALLCONV_C com_err(const char *whoami,
253159d09a2SMark Phalan errcode_t code,
254159d09a2SMark Phalan const char *fmt, ...)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate va_list ap;
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate va_start(ap, fmt);
2597c478bd9Sstevel@tonic-gate com_err_va(whoami, code, fmt, ap);
2607c478bd9Sstevel@tonic-gate va_end(ap);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate
263159d09a2SMark Phalan /* Make a separate function because the assert invocations below
264159d09a2SMark Phalan use the macro expansion on some platforms, which may be insanely
265159d09a2SMark Phalan long and incomprehensible. */
com_err_lock_hook_handle(void)266159d09a2SMark Phalan static int com_err_lock_hook_handle(void)
267159d09a2SMark Phalan {
268159d09a2SMark Phalan return k5_mutex_lock(&com_err_hook_lock);
269159d09a2SMark Phalan }
270159d09a2SMark Phalan
set_com_err_hook(et_old_error_hook_func new_proc)271159d09a2SMark Phalan et_old_error_hook_func set_com_err_hook (et_old_error_hook_func new_proc)
2727c478bd9Sstevel@tonic-gate {
2737c64d375Smp int i;
274159d09a2SMark Phalan et_old_error_hook_func x;
275159d09a2SMark Phalan
276159d09a2SMark Phalan /* Broken initialization? What can we do? */
277159d09a2SMark Phalan assert(com_err_finish_init() == 0);
278159d09a2SMark Phalan assert(com_err_lock_hook_handle() == 0);
279159d09a2SMark Phalan
280159d09a2SMark Phalan x = com_err_hook[0];
2817c64d375Smp
2827c64d375Smp for (i = 0; i < hook_count; i++)
2837c64d375Smp com_err_hook[i] = NULL;
2847c64d375Smp
2857c64d375Smp com_err_hook[0] = new_proc;
2867c64d375Smp hook_count = 1;
2877c478bd9Sstevel@tonic-gate
288159d09a2SMark Phalan k5_mutex_unlock(&com_err_hook_lock);
2897c478bd9Sstevel@tonic-gate return x;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate
reset_com_err_hook()2927c478bd9Sstevel@tonic-gate et_old_error_hook_func reset_com_err_hook ()
2937c478bd9Sstevel@tonic-gate {
2947c64d375Smp int i;
295159d09a2SMark Phalan et_old_error_hook_func x;
2967c64d375Smp
297159d09a2SMark Phalan /* Broken initialization? What can we do? */
298159d09a2SMark Phalan assert(com_err_finish_init() == 0);
299159d09a2SMark Phalan assert(com_err_lock_hook_handle() == 0);
300159d09a2SMark Phalan x = com_err_hook[0];
3017c64d375Smp for (i = 0; i < hook_count; i++)
3027c64d375Smp com_err_hook[i] = NULL;
3037c64d375Smp
3047c64d375Smp com_err_hook[0] = default_com_err_proc;
3057c64d375Smp hook_count = 1;
306159d09a2SMark Phalan k5_mutex_unlock(&com_err_hook_lock);
3077c478bd9Sstevel@tonic-gate return x;
3087c478bd9Sstevel@tonic-gate }
3097c64d375Smp
3107c64d375Smp /*
3117c64d375Smp * Solaris Kerberos:
3127c64d375Smp * Register a hook which will be called every time
3137c64d375Smp * com_err() is called.
3147c64d375Smp */
add_com_err_hook(et_old_error_hook_func f)3157c64d375Smp void add_com_err_hook(et_old_error_hook_func f) {
3167c64d375Smp int i;
3177c64d375Smp if (hook_count < MAX_HOOKS) {
3187c64d375Smp for (i = 0; i < hook_count; i++) {
3197c64d375Smp if (com_err_hook[i] == NULL)
3207c64d375Smp break;
3217c64d375Smp }
3227c64d375Smp com_err_hook[i] = f;
3237c64d375Smp hook_count++;
3247c64d375Smp }
3257c64d375Smp }
3267c64d375Smp
3277c64d375Smp /*
3287c64d375Smp * Solaris Kerberos:
3297c64d375Smp * Remove a logging hook. The first hook matching 'f' will
3307c64d375Smp * be removed.
3317c64d375Smp */
rem_com_err_hook(et_old_error_hook_func f)3327c64d375Smp void rem_com_err_hook(et_old_error_hook_func f) {
3337c64d375Smp int i, j;
3347c64d375Smp
3357c64d375Smp for (i = 0; i < hook_count; i++) {
3367c64d375Smp if (com_err_hook[i] == f) {
3377c64d375Smp for (j = i; j < hook_count - 1; j++) {
3387c64d375Smp com_err_hook[j] = com_err_hook[j+1];
3397c64d375Smp }
3407c64d375Smp com_err_hook[j] = NULL;
3417c64d375Smp hook_count--;
3427c64d375Smp }
3437c64d375Smp }
3447c64d375Smp }
3457c64d375Smp
3467c64d375Smp /*
3477c64d375Smp * Solaris Kerberos:
3487c64d375Smp * Remove the default hook.
3497c64d375Smp */
rem_default_com_err_hook()3507c64d375Smp void rem_default_com_err_hook() {
3517c64d375Smp rem_com_err_hook(default_com_err_proc);
3527c64d375Smp }
3537c64d375Smp
3547c64d375Smp /*
3557c64d375Smp * Solaris Kerberos:
3567c64d375Smp * Add back the default hook
3577c64d375Smp */
add_default_com_err_hook()3587c64d375Smp void add_default_com_err_hook() {
3597c64d375Smp add_com_err_hook(default_com_err_proc);
3607c64d375Smp }
361