1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1997,2000,2001,2004,2008 by Massachusetts Institute of Technology
5 * Copyright 1987, 1988 by MIT Student Information Processing Board
7 * Permission to use, copy, modify, and distribute this software
8 * and its documentation for any purpose and without fee is
9 * hereby granted, provided that the above copyright notice
10 * appear in all copies and that both that copyright notice and
11 * this permission notice appear in supporting documentation,
12 * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
13 * used in advertising or publicity pertaining to distribution
14 * of the software without specific, written prior permission.
15 * Furthermore if you modify this software you must label
16 * your software as modified software and not distribute it in such a
17 * fashion that it might be confused with the original M.I.T. software.
18 * M.I.T. and the M.I.T. S.I.P.B. make no representations about
19 * the suitability of this software for any purpose. It is
20 * provided "as is" without express or implied warranty.
30 #include "error_table.h"
31 #include "k5-platform.h"
33 #if !defined(HAVE_STRERROR) && !defined(SYS_ERRLIST_DECLARED)
34 extern char const * const sys_errlist[];
35 extern const int sys_nerr;
38 static struct et_list *et_list;
39 static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
40 static int terminated = 0; /* for debugging shlib fini sequence errors */
42 MAKE_INIT_FUNCTION(com_err_initialize);
43 MAKE_FINI_FUNCTION(com_err_terminate);
45 int com_err_initialize(void)
48 #ifdef SHOW_INITFINI_FUNCS
49 printf("com_err_initialize\n");
52 err = k5_mutex_finish_init(&et_list_lock);
55 err = k5_mutex_finish_init(&com_err_hook_lock);
58 err = k5_key_register(K5_KEY_COM_ERR, free);
64 void com_err_terminate(void)
66 struct et_list *e, *enext;
67 if (! INITIALIZER_RAN(com_err_initialize) || PROGRAM_EXITING()) {
68 #ifdef SHOW_INITFINI_FUNCS
69 printf("com_err_terminate: skipping\n");
73 #ifdef SHOW_INITFINI_FUNCS
74 printf("com_err_terminate\n");
76 k5_key_delete(K5_KEY_COM_ERR);
77 k5_mutex_destroy(&com_err_hook_lock);
78 if (k5_mutex_lock(&et_list_lock) != 0)
80 for (e = et_list; e; e = enext) {
84 k5_mutex_unlock(&et_list_lock);
85 k5_mutex_destroy(&et_list_lock);
89 #ifndef DEBUG_TABLE_LIST
92 #define dprintf(X) printf X
99 cp = k5_getspecific(K5_KEY_COM_ERR);
101 cp = malloc(ET_EBUFSIZ);
105 if (k5_setspecific(K5_KEY_COM_ERR, cp) != 0) {
113 const char * KRB5_CALLCONV
114 error_message(long code)
116 unsigned long offset;
117 unsigned long l_offset;
119 unsigned long table_num;
121 unsigned int divisor = 100;
123 const struct error_table *table;
126 l_offset = (unsigned long)code & ((1<<ERRCODE_RANGE)-1);
128 table_num = ((unsigned long)code - l_offset) & ERRCODE_MAX;
131 /* Irix 6.5 uses a much bigger table than other UNIX
132 systems I've looked at, but the table is sparse. The
133 sparse entries start around 500, but sys_nerr is only
135 || (code > 0 && code <= 1600)
141 /* This could trip if int is 16 bits. */
142 if ((unsigned long)(int)code != (unsigned long)code)
144 #ifdef HAVE_STRERROR_R
145 cp = get_thread_buffer();
146 if (cp && strerror_r((int) code, cp, ET_EBUFSIZ) == 0)
150 cp = strerror((int) code);
153 #elif defined HAVE_SYS_ERRLIST
154 if (offset < sys_nerr)
155 return(sys_errlist[offset]);
160 if (CALL_INIT_FUNCTION(com_err_initialize))
162 merr = k5_mutex_lock(&et_list_lock);
165 dprintf(("scanning list for %x\n", table_num));
166 for (e = et_list; e != NULL; e = e->next) {
167 dprintf(("\t%x = %s\n", e->table->base & ERRCODE_MAX,
169 if ((e->table->base & ERRCODE_MAX) == table_num) {
177 k5_mutex_unlock(&et_list_lock);
178 dprintf (("found it!\n"));
179 /* This is the right table */
181 /* This could trip if int is 16 bits. */
182 if ((unsigned long)(unsigned int)offset != offset)
185 if (table->n_msgs <= (unsigned int) offset)
188 /* If there's a string at the end of the table, it's a text domain. */
189 if (table->msgs[table->n_msgs] != NULL)
190 return dgettext(table->msgs[table->n_msgs], table->msgs[offset]);
192 return table->msgs[offset];
195 k5_mutex_unlock(&et_list_lock);
198 * WinSock errors exist in the 10000 and 11000 ranges
199 * but might not appear if WinSock is not initialized
201 if (code >= WSABASEERR && code < WSABASEERR + 1100) {
204 divisor = WSABASEERR;
211 if (! FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
214 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
216 (DWORD) 0 /*sizeof(buffer)*/,
217 NULL /* va_list */ )) {
219 * WinSock errors exist in the 10000 and 11000 ranges
220 * but might not appear if WinSock is not initialized
222 if (code >= WSABASEERR && code < WSABASEERR + 1100) {
231 cp = get_thread_buffer();
233 return "Unknown error code";
235 strncpy(buffer, msgbuf, ET_EBUFSIZ);
236 buffer[ET_EBUFSIZ-1] = '\0';
237 cp = buffer + strlen(buffer) - 1;
238 if (*cp == '\n') *cp-- = '\0';
239 if (*cp == '\r') *cp-- = '\0';
240 if (*cp == '.') *cp-- = '\0';
250 cp = get_thread_buffer();
252 return "Unknown error code";
254 strlcpy(cp, "Unknown code ", ET_EBUFSIZ);
255 cp += sizeof("Unknown code ") - 1;
256 if (table_num != 0L) {
257 (void) error_table_name_r(table_num, cp);
262 while (divisor > 1) {
263 if (started != 0 || offset >= divisor) {
264 *cp++ = '0' + offset / divisor;
270 *cp++ = '0' + offset;
275 errcode_t KRB5_CALLCONV
276 add_error_table(const struct error_table *et)
281 if (CALL_INIT_FUNCTION(com_err_initialize))
284 e = malloc(sizeof(struct et_list));
290 merr = k5_mutex_lock(&et_list_lock);
298 /* If there are two strings at the end of the table, they are a text domain
299 * and locale dir, and we are supposed to call bindtextdomain. */
300 if (et->msgs[et->n_msgs] != NULL && et->msgs[et->n_msgs + 1] != NULL)
301 bindtextdomain(et->msgs[et->n_msgs], et->msgs[et->n_msgs + 1]);
303 return k5_mutex_unlock(&et_list_lock);
306 errcode_t KRB5_CALLCONV
307 remove_error_table(const struct error_table *et)
309 struct et_list **ep, *e;
312 if (CALL_INIT_FUNCTION(com_err_initialize))
314 merr = k5_mutex_lock(&et_list_lock);
318 /* Remove the entry that matches the error table instance. */
319 for (ep = &et_list; *ep; ep = &(*ep)->next) {
320 if ((*ep)->table == et) {
324 return k5_mutex_unlock(&et_list_lock);
327 k5_mutex_unlock(&et_list_lock);
331 int com_err_finish_init()
333 return CALL_INIT_FUNCTION(com_err_initialize);