/src/krb5/src/util/et/error_message.c
Line | Count | Source |
1 | | /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | | /* |
3 | | * Copyright 1997,2000,2001,2004,2008 by Massachusetts Institute of Technology |
4 | | * |
5 | | * Copyright 1987, 1988 by MIT Student Information Processing Board |
6 | | * |
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. |
21 | | */ |
22 | | |
23 | | #include "k5-platform.h" |
24 | | #include "com_err.h" |
25 | | #include "error_table.h" |
26 | | |
27 | | static struct et_list *et_list; |
28 | | static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER; |
29 | | static int terminated = 0; /* for safety and finalization debugging */ |
30 | | |
31 | | MAKE_INIT_FUNCTION(com_err_initialize); |
32 | | MAKE_FINI_FUNCTION(com_err_terminate); |
33 | | |
34 | | int com_err_initialize(void) |
35 | 14 | { |
36 | 14 | int err; |
37 | | #ifdef SHOW_INITFINI_FUNCS |
38 | | printf("com_err_initialize\n"); |
39 | | #endif |
40 | 14 | terminated = 0; |
41 | 14 | err = k5_mutex_finish_init(&et_list_lock); |
42 | 14 | if (err) |
43 | 0 | return err; |
44 | 14 | err = k5_mutex_finish_init(&com_err_hook_lock); |
45 | 14 | if (err) |
46 | 0 | return err; |
47 | 14 | err = k5_key_register(K5_KEY_COM_ERR, free); |
48 | 14 | if (err) |
49 | 0 | return err; |
50 | 14 | return 0; |
51 | 14 | } |
52 | | |
53 | | void com_err_terminate(void) |
54 | 0 | { |
55 | 0 | struct et_list *e, *enext; |
56 | 0 | if (! INITIALIZER_RAN(com_err_initialize) || PROGRAM_EXITING()) { |
57 | 0 | #ifdef SHOW_INITFINI_FUNCS |
58 | 0 | printf("com_err_terminate: skipping\n"); |
59 | 0 | #endif |
60 | 0 | return; |
61 | 0 | } |
62 | 0 | #ifdef SHOW_INITFINI_FUNCS |
63 | 0 | printf("com_err_terminate\n"); |
64 | 0 | #endif |
65 | 0 | k5_key_delete(K5_KEY_COM_ERR); |
66 | 0 | k5_mutex_destroy(&com_err_hook_lock); |
67 | 0 | k5_mutex_lock(&et_list_lock); |
68 | 0 | for (e = et_list; e; e = enext) { |
69 | 0 | enext = e->next; |
70 | 0 | free(e); |
71 | 0 | } |
72 | 0 | et_list = NULL; |
73 | 0 | k5_mutex_unlock(&et_list_lock); |
74 | 0 | k5_mutex_destroy(&et_list_lock); |
75 | 0 | terminated = 1; |
76 | 0 | } |
77 | | |
78 | | #ifndef DEBUG_TABLE_LIST |
79 | | #define dprintf(X) |
80 | | #else |
81 | | #define dprintf(X) printf X |
82 | | #endif |
83 | | |
84 | | static char * |
85 | | get_thread_buffer(void) |
86 | 0 | { |
87 | 0 | char *cp; |
88 | 0 | cp = k5_getspecific(K5_KEY_COM_ERR); |
89 | 0 | if (cp == NULL) { |
90 | 0 | cp = malloc(ET_EBUFSIZ); |
91 | 0 | if (cp == NULL) { |
92 | 0 | return NULL; |
93 | 0 | } |
94 | 0 | if (k5_setspecific(K5_KEY_COM_ERR, cp) != 0) { |
95 | 0 | free(cp); |
96 | 0 | return NULL; |
97 | 0 | } |
98 | 0 | } |
99 | 0 | return cp; |
100 | 0 | } |
101 | | |
102 | | const char * KRB5_CALLCONV |
103 | | error_message(long code) |
104 | 1.33k | { |
105 | 1.33k | unsigned long offset; |
106 | 1.33k | unsigned long l_offset; |
107 | 1.33k | struct et_list *e; |
108 | 1.33k | unsigned long table_num; |
109 | 1.33k | int started = 0; |
110 | 1.33k | unsigned int divisor = 100; |
111 | 1.33k | char *cp, *cp1; |
112 | 1.33k | const struct error_table *table; |
113 | | |
114 | 1.33k | if (CALL_INIT_FUNCTION(com_err_initialize)) |
115 | 0 | return 0; |
116 | | |
117 | 1.33k | l_offset = (unsigned long)code & ((1<<ERRCODE_RANGE)-1); |
118 | 1.33k | offset = l_offset; |
119 | 1.33k | table_num = ((unsigned long)code - l_offset) & ERRCODE_MAX; |
120 | 1.33k | if (table_num == 0 |
121 | | #ifdef __sgi |
122 | | /* Irix 6.5 uses a much bigger table than other UNIX |
123 | | systems I've looked at, but the table is sparse. The |
124 | | sparse entries start around 500, but sys_nerr is only |
125 | | 152. */ |
126 | | || (code > 0 && code <= 1600) |
127 | | #endif |
128 | 1.33k | ) { |
129 | 0 | if (code == 0) |
130 | 0 | goto oops; |
131 | | |
132 | | /* This could trip if int is 16 bits. */ |
133 | 0 | if ((unsigned long)(int)code != (unsigned long)code) |
134 | 0 | abort (); |
135 | 0 | cp = get_thread_buffer(); |
136 | 0 | if (cp && strerror_r(code, cp, ET_EBUFSIZ) == 0) |
137 | 0 | return cp; |
138 | 0 | return strerror(code); |
139 | 0 | } |
140 | | |
141 | 1.33k | k5_mutex_lock(&et_list_lock); |
142 | 1.33k | dprintf(("scanning list for %x\n", table_num)); |
143 | 9.32k | for (e = et_list; e != NULL; e = e->next) { |
144 | 9.32k | dprintf(("\t%x = %s\n", e->table->base & ERRCODE_MAX, |
145 | 9.32k | e->table->msgs[0])); |
146 | 9.32k | if ((e->table->base & ERRCODE_MAX) == table_num) { |
147 | 1.33k | table = e->table; |
148 | 1.33k | goto found; |
149 | 1.33k | } |
150 | 9.32k | } |
151 | 0 | goto no_table_found; |
152 | | |
153 | 1.33k | found: |
154 | 1.33k | k5_mutex_unlock(&et_list_lock); |
155 | 1.33k | dprintf (("found it!\n")); |
156 | | /* This is the right table */ |
157 | | |
158 | | /* This could trip if int is 16 bits. */ |
159 | 1.33k | if ((unsigned long)(unsigned int)offset != offset) |
160 | 0 | goto no_table_found; |
161 | | |
162 | 1.33k | if (table->n_msgs <= (unsigned int) offset) |
163 | 0 | goto no_table_found; |
164 | | |
165 | | /* If there's a string at the end of the table, it's a text domain. */ |
166 | 1.33k | if (table->msgs[table->n_msgs] != NULL) |
167 | 1.33k | return dgettext(table->msgs[table->n_msgs], table->msgs[offset]); |
168 | 0 | else |
169 | 0 | return table->msgs[offset]; |
170 | | |
171 | 0 | no_table_found: |
172 | 0 | k5_mutex_unlock(&et_list_lock); |
173 | | #if defined(_WIN32) |
174 | | /* |
175 | | * WinSock errors exist in the 10000 and 11000 ranges |
176 | | * but might not appear if WinSock is not initialized |
177 | | */ |
178 | | if (code >= WSABASEERR && code < WSABASEERR + 1100) { |
179 | | table_num = 0; |
180 | | offset = code; |
181 | | divisor = WSABASEERR; |
182 | | } |
183 | | #endif |
184 | | #ifdef _WIN32 |
185 | | { |
186 | | LPVOID msgbuf; |
187 | | |
188 | | if (! FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
189 | | NULL /* lpSource */, |
190 | | (DWORD) code, |
191 | | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
192 | | (LPTSTR) &msgbuf, |
193 | | (DWORD) 0 /*sizeof(buffer)*/, |
194 | | NULL /* va_list */ )) { |
195 | | /* |
196 | | * WinSock errors exist in the 10000 and 11000 ranges |
197 | | * but might not appear if WinSock is not initialized |
198 | | */ |
199 | | if (code >= WSABASEERR && code < WSABASEERR + 1100) { |
200 | | table_num = 0; |
201 | | offset = code; |
202 | | divisor = 10000; |
203 | | } |
204 | | |
205 | | goto oops; |
206 | | } else { |
207 | | char *buffer; |
208 | | cp = get_thread_buffer(); |
209 | | if (cp == NULL) |
210 | | return "Unknown error code"; |
211 | | buffer = cp; |
212 | | strncpy(buffer, msgbuf, ET_EBUFSIZ); |
213 | | buffer[ET_EBUFSIZ-1] = '\0'; |
214 | | cp = buffer + strlen(buffer) - 1; |
215 | | if (*cp == '\n') *cp-- = '\0'; |
216 | | if (*cp == '\r') *cp-- = '\0'; |
217 | | if (*cp == '.') *cp-- = '\0'; |
218 | | |
219 | | LocalFree(msgbuf); |
220 | | return buffer; |
221 | | } |
222 | | } |
223 | | #endif |
224 | |
|
225 | 0 | oops: |
226 | |
|
227 | 0 | cp = get_thread_buffer(); |
228 | 0 | if (cp == NULL) |
229 | 0 | return "Unknown error code"; |
230 | 0 | cp1 = cp; |
231 | 0 | strlcpy(cp, "Unknown code ", ET_EBUFSIZ); |
232 | 0 | cp += sizeof("Unknown code ") - 1; |
233 | 0 | if (table_num != 0L) { |
234 | 0 | (void) error_table_name_r(table_num, cp); |
235 | 0 | while (*cp != '\0') |
236 | 0 | cp++; |
237 | 0 | *cp++ = ' '; |
238 | 0 | } |
239 | 0 | while (divisor > 1) { |
240 | 0 | if (started != 0 || offset >= divisor) { |
241 | 0 | *cp++ = '0' + offset / divisor; |
242 | 0 | offset %= divisor; |
243 | 0 | started++; |
244 | 0 | } |
245 | 0 | divisor /= 10; |
246 | 0 | } |
247 | 0 | *cp++ = '0' + offset; |
248 | 0 | *cp = '\0'; |
249 | 0 | return(cp1); |
250 | 0 | } |
251 | | |
252 | | errcode_t KRB5_CALLCONV |
253 | | add_error_table(const struct error_table *et) |
254 | 1.08k | { |
255 | 1.08k | struct et_list *e; |
256 | | |
257 | 1.08k | if (CALL_INIT_FUNCTION(com_err_initialize)) |
258 | 0 | return 0; |
259 | | |
260 | 1.08k | e = malloc(sizeof(struct et_list)); |
261 | 1.08k | if (e == NULL) |
262 | 0 | return ENOMEM; |
263 | | |
264 | 1.08k | e->table = et; |
265 | | |
266 | 1.08k | k5_mutex_lock(&et_list_lock); |
267 | 1.08k | e->next = et_list; |
268 | 1.08k | et_list = e; |
269 | | |
270 | | /* If there are two strings at the end of the table, they are a text domain |
271 | | * and locale dir, and we are supposed to call bindtextdomain. */ |
272 | 1.08k | if (et->msgs[et->n_msgs] != NULL && et->msgs[et->n_msgs + 1] != NULL) |
273 | 0 | bindtextdomain(et->msgs[et->n_msgs], et->msgs[et->n_msgs + 1]); |
274 | | |
275 | 1.08k | k5_mutex_unlock(&et_list_lock); |
276 | 1.08k | return 0; |
277 | 1.08k | } |
278 | | |
279 | | errcode_t KRB5_CALLCONV |
280 | | remove_error_table(const struct error_table *et) |
281 | 0 | { |
282 | 0 | struct et_list **ep, *e; |
283 | | |
284 | | /* Safety check in case libraries are finalized in the wrong order. */ |
285 | 0 | if (terminated) |
286 | 0 | return ENOENT; |
287 | | |
288 | 0 | if (CALL_INIT_FUNCTION(com_err_initialize)) |
289 | 0 | return 0; |
290 | 0 | k5_mutex_lock(&et_list_lock); |
291 | | |
292 | | /* Remove the entry that matches the error table instance. */ |
293 | 0 | for (ep = &et_list; *ep; ep = &(*ep)->next) { |
294 | 0 | if ((*ep)->table == et) { |
295 | 0 | e = *ep; |
296 | 0 | *ep = e->next; |
297 | 0 | free(e); |
298 | 0 | k5_mutex_unlock(&et_list_lock); |
299 | 0 | return 0; |
300 | 0 | } |
301 | 0 | } |
302 | 0 | k5_mutex_unlock(&et_list_lock); |
303 | 0 | return ENOENT; |
304 | 0 | } |
305 | | |
306 | | int com_err_finish_init(void) |
307 | 0 | { |
308 | 0 | return CALL_INIT_FUNCTION(com_err_initialize); |
309 | 0 | } |