]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * $Header$ | |
3 | * $Source$ | |
4 | * $Locker$ | |
5 | * | |
6 | * Copyright 1987 by the Student Information Processing Board | |
7 | * of the Massachusetts Institute of Technology | |
8 | * | |
06cefee5 TT |
9 | * Permission to use, copy, modify, and distribute this software and |
10 | * its documentation for any purpose is hereby granted, provided that | |
11 | * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in | |
12 | * advertising or publicity pertaining to distribution of the software | |
13 | * without specific, written prior permission. M.I.T. and the | |
14 | * M.I.T. S.I.P.B. make no representations about the suitability of | |
15 | * this software for any purpose. It is provided "as is" without | |
16 | * express or implied warranty. | |
3839e657 TT |
17 | */ |
18 | ||
d1154eb4 | 19 | #include "config.h" |
3839e657 | 20 | #include <stdio.h> |
91835c15 | 21 | #include <stdlib.h> |
3839e657 | 22 | #include <string.h> |
f3db3566 | 23 | #include <errno.h> |
ec84b746 TT |
24 | #ifdef HAVE_SYS_PRCTL_H |
25 | #include <sys/prctl.h> | |
26 | #else | |
27 | #define PR_GET_DUMPABLE 3 | |
28 | #endif | |
29 | #if (!defined(HAVE_PRCTL) && defined(linux)) | |
30 | #include <sys/syscall.h> | |
31 | #endif | |
d7f45af8 TT |
32 | #ifdef HAVE_SEMAPHORE_H |
33 | #include <semaphore.h> | |
34 | #endif | |
de8f3a76 AD |
35 | #if HAVE_UNISTD_H |
36 | #include <unistd.h> | |
37 | #endif | |
f47f3195 | 38 | #if HAVE_FCNTL |
902be4ab | 39 | #include <fcntl.h> |
f47f3195 | 40 | #endif |
de8f3a76 AD |
41 | #if HAVE_SYS_TYPES_H |
42 | #include <sys/types.h> | |
43 | #endif | |
f3db3566 | 44 | #include "com_err.h" |
3839e657 | 45 | #include "error_table.h" |
3839e657 TT |
46 | #include "internal.h" |
47 | ||
47526e35 TT |
48 | #ifdef TLS |
49 | #define THREAD_LOCAL static TLS | |
50 | #else | |
51 | #define THREAD_LOCAL static | |
52 | #endif | |
53 | ||
54 | THREAD_LOCAL char buffer[25]; | |
3839e657 TT |
55 | |
56 | struct et_list * _et_list = (struct et_list *) NULL; | |
d51b819e | 57 | struct et_list * _et_dynamic_list = (struct et_list *) NULL; |
3839e657 | 58 | |
d7f45af8 TT |
59 | #ifdef __GNUC__ |
60 | #define COMERR_ATTR(x) __attribute__(x) | |
61 | #else | |
62 | #define COMERR_ATTR(x) | |
63 | #endif | |
64 | ||
65 | #ifdef HAVE_SEM_INIT | |
66 | static sem_t _et_lock; | |
98e9fb9d | 67 | static int _et_lock_initialized; |
d7f45af8 | 68 | |
98e9fb9d | 69 | static void COMERR_ATTR((constructor)) setup_et_lock(void) |
d7f45af8 TT |
70 | { |
71 | sem_init(&_et_lock, 0, 1); | |
72 | _et_lock_initialized = 1; | |
73 | } | |
74 | ||
98e9fb9d | 75 | static void COMERR_ATTR((destructor)) fini_et_lock(void) |
d7f45af8 TT |
76 | { |
77 | sem_destroy(&_et_lock); | |
78 | _et_lock_initialized = 0; | |
79 | } | |
80 | #endif | |
81 | ||
82 | ||
98e9fb9d | 83 | int et_list_lock(void) |
d7f45af8 TT |
84 | { |
85 | #ifdef HAVE_SEM_INIT | |
86 | if (!_et_lock_initialized) | |
87 | setup_et_lock(); | |
88 | return sem_wait(&_et_lock); | |
89 | #else | |
90 | return 0; | |
91 | #endif | |
92 | } | |
93 | ||
98e9fb9d | 94 | int et_list_unlock(void) |
d7f45af8 TT |
95 | { |
96 | #ifdef HAVE_SEM_INIT | |
97 | if (_et_lock_initialized) | |
98 | return sem_post(&_et_lock); | |
99 | #endif | |
100 | return 0; | |
101 | } | |
f3db3566 | 102 | |
42590520 TT |
103 | typedef char *(*gettextf) (const char *); |
104 | ||
299a1e8e | 105 | static gettextf com_err_gettext = NULL; |
42590520 | 106 | |
f404167d | 107 | gettextf set_com_err_gettext(gettextf new_proc) |
42590520 TT |
108 | { |
109 | gettextf x = com_err_gettext; | |
110 | ||
111 | com_err_gettext = new_proc; | |
112 | ||
113 | return x; | |
114 | } | |
115 | ||
116 | ||
f3db3566 | 117 | const char * error_message (errcode_t code) |
3839e657 TT |
118 | { |
119 | int offset; | |
120 | struct et_list *et; | |
a47b66ee | 121 | errcode_t table_num; |
3839e657 TT |
122 | int started = 0; |
123 | char *cp; | |
124 | ||
a47b66ee | 125 | offset = (int) (code & ((1<<ERRCODE_RANGE)-1)); |
3839e657 TT |
126 | table_num = code - offset; |
127 | if (!table_num) { | |
f3db3566 | 128 | #ifdef HAS_SYS_ERRLIST |
3839e657 TT |
129 | if (offset < sys_nerr) |
130 | return(sys_errlist[offset]); | |
131 | else | |
132 | goto oops; | |
f3db3566 TT |
133 | #else |
134 | cp = strerror(offset); | |
135 | if (cp) | |
136 | return(cp); | |
137 | else | |
138 | goto oops; | |
139 | #endif | |
3839e657 | 140 | } |
d7f45af8 | 141 | et_list_lock(); |
3839e657 | 142 | for (et = _et_list; et; et = et->next) { |
6b6c27fb | 143 | if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) { |
3839e657 | 144 | /* This is the right table */ |
d7f45af8 TT |
145 | if (et->table->n_msgs <= offset) { |
146 | break; | |
147 | } else { | |
148 | const char *msg = et->table->msgs[offset]; | |
149 | et_list_unlock(); | |
42590520 TT |
150 | if (com_err_gettext) |
151 | return (*com_err_gettext)(msg); | |
152 | else | |
153 | return msg; | |
d7f45af8 | 154 | } |
3839e657 TT |
155 | } |
156 | } | |
d51b819e | 157 | for (et = _et_dynamic_list; et; et = et->next) { |
6b6c27fb | 158 | if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) { |
d51b819e | 159 | /* This is the right table */ |
d7f45af8 TT |
160 | if (et->table->n_msgs <= offset) { |
161 | break; | |
162 | } else { | |
163 | const char *msg = et->table->msgs[offset]; | |
164 | et_list_unlock(); | |
42590520 TT |
165 | if (com_err_gettext) |
166 | return (*com_err_gettext)(msg); | |
167 | else | |
168 | return msg; | |
d7f45af8 | 169 | } |
d51b819e TT |
170 | } |
171 | } | |
d7f45af8 | 172 | et_list_unlock(); |
3839e657 TT |
173 | oops: |
174 | strcpy (buffer, "Unknown code "); | |
175 | if (table_num) { | |
176 | strcat (buffer, error_table_name (table_num)); | |
177 | strcat (buffer, " "); | |
178 | } | |
179 | for (cp = buffer; *cp; cp++) | |
180 | ; | |
181 | if (offset >= 100) { | |
182 | *cp++ = '0' + offset / 100; | |
183 | offset %= 100; | |
184 | started++; | |
185 | } | |
186 | if (started || offset >= 10) { | |
187 | *cp++ = '0' + offset / 10; | |
188 | offset %= 10; | |
189 | } | |
190 | *cp++ = '0' + offset; | |
191 | *cp = '\0'; | |
192 | return(buffer); | |
193 | } | |
00aba967 | 194 | |
ec84b746 TT |
195 | /* |
196 | * This routine will only return a value if the we are not running as | |
197 | * a privileged process. | |
198 | */ | |
199 | static char *safe_getenv(const char *arg) | |
200 | { | |
f47f3195 | 201 | #if !defined(_WIN32) |
ec84b746 TT |
202 | if ((getuid() != geteuid()) || (getgid() != getegid())) |
203 | return NULL; | |
f47f3195 | 204 | #endif |
ec84b746 TT |
205 | #if HAVE_PRCTL |
206 | if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) | |
207 | return NULL; | |
208 | #else | |
209 | #if (defined(linux) && defined(SYS_prctl)) | |
210 | if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) | |
211 | return NULL; | |
212 | #endif | |
213 | #endif | |
214 | ||
1ad3174a TT |
215 | #if defined(HAVE_SECURE_GETENV) |
216 | return secure_getenv(arg); | |
217 | #elif defined(HAVE___SECURE_GETENV) | |
ec84b746 TT |
218 | return __secure_getenv(arg); |
219 | #else | |
220 | return getenv(arg); | |
221 | #endif | |
222 | } | |
223 | ||
224 | #define DEBUG_INIT 0x8000 | |
225 | #define DEBUG_ADDREMOVE 0x0001 | |
226 | ||
227 | static int debug_mask = 0; | |
228 | static FILE *debug_f = 0; | |
229 | ||
230 | static void init_debug(void) | |
231 | { | |
902be4ab TT |
232 | char *dstr, *fn, *tmp; |
233 | int fd, flags; | |
ec84b746 TT |
234 | |
235 | if (debug_mask & DEBUG_INIT) | |
236 | return; | |
237 | ||
238 | dstr = getenv("COMERR_DEBUG"); | |
902be4ab TT |
239 | if (dstr) { |
240 | debug_mask = strtoul(dstr, &tmp, 0); | |
241 | if (*tmp || errno) | |
242 | debug_mask = 0; | |
243 | } | |
244 | ||
245 | debug_mask |= DEBUG_INIT; | |
246 | if (debug_mask == DEBUG_INIT) | |
247 | return; | |
ec84b746 TT |
248 | |
249 | fn = safe_getenv("COMERR_DEBUG_FILE"); | |
250 | if (fn) | |
251 | debug_f = fopen(fn, "a"); | |
252 | if (!debug_f) | |
253 | debug_f = fopen("/dev/tty", "a"); | |
902be4ab TT |
254 | if (debug_f) { |
255 | fd = fileno(debug_f); | |
f47f3195 | 256 | #if defined(HAVE_FCNTL) |
902be4ab TT |
257 | if (fd >= 0) { |
258 | flags = fcntl(fd, F_GETFD); | |
259 | if (flags >= 0) | |
038e5385 TT |
260 | flags = fcntl(fd, F_SETFD, flags | FD_CLOEXEC); |
261 | if (flags < 0) { | |
262 | fprintf(debug_f, "Couldn't set FD_CLOEXEC " | |
263 | "on debug FILE: %s\n", strerror(errno)); | |
264 | fclose(debug_f); | |
265 | debug_f = NULL; | |
266 | debug_mask = DEBUG_INIT; | |
267 | } | |
902be4ab | 268 | } |
f47f3195 | 269 | #endif |
902be4ab TT |
270 | } else |
271 | debug_mask = DEBUG_INIT; | |
ec84b746 | 272 | |
ec84b746 TT |
273 | } |
274 | ||
00aba967 TT |
275 | /* |
276 | * New interface provided by krb5's com_err library | |
277 | */ | |
91835c15 | 278 | errcode_t add_error_table(const struct error_table * et) |
00aba967 | 279 | { |
d51b819e | 280 | struct et_list *el; |
00aba967 TT |
281 | |
282 | if (!(el = (struct et_list *) malloc(sizeof(struct et_list)))) | |
283 | return ENOMEM; | |
284 | ||
d7f45af8 TT |
285 | if (et_list_lock() != 0) { |
286 | free(el); | |
287 | return errno; | |
288 | } | |
289 | ||
00aba967 | 290 | el->table = et; |
d51b819e TT |
291 | el->next = _et_dynamic_list; |
292 | _et_dynamic_list = el; | |
00aba967 | 293 | |
ec84b746 TT |
294 | init_debug(); |
295 | if (debug_mask & DEBUG_ADDREMOVE) | |
296 | fprintf(debug_f, "add_error_table: %s (0x%p)\n", | |
297 | error_table_name(et->base), | |
298 | (const void *) et); | |
299 | ||
d7f45af8 | 300 | et_list_unlock(); |
00aba967 TT |
301 | return 0; |
302 | } | |
303 | ||
304 | /* | |
305 | * New interface provided by krb5's com_err library | |
306 | */ | |
91835c15 | 307 | errcode_t remove_error_table(const struct error_table * et) |
00aba967 | 308 | { |
d7f45af8 | 309 | struct et_list *el; |
00aba967 TT |
310 | struct et_list *el2 = 0; |
311 | ||
d7f45af8 TT |
312 | if (et_list_lock() != 0) |
313 | return ENOENT; | |
314 | ||
315 | el = _et_dynamic_list; | |
ec84b746 | 316 | init_debug(); |
00aba967 TT |
317 | while (el) { |
318 | if (el->table->base == et->base) { | |
319 | if (el2) /* Not the beginning of the list */ | |
320 | el2->next = el->next; | |
321 | else | |
d51b819e | 322 | _et_dynamic_list = el->next; |
00aba967 | 323 | (void) free(el); |
ec84b746 TT |
324 | if (debug_mask & DEBUG_ADDREMOVE) |
325 | fprintf(debug_f, | |
326 | "remove_error_table: %s (0x%p)\n", | |
327 | error_table_name(et->base), | |
328 | (const void *) et); | |
d7f45af8 | 329 | et_list_unlock(); |
00aba967 TT |
330 | return 0; |
331 | } | |
332 | el2 = el; | |
333 | el = el->next; | |
334 | } | |
ec84b746 TT |
335 | if (debug_mask & DEBUG_ADDREMOVE) |
336 | fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n", | |
337 | error_table_name(et->base), | |
338 | (const void *) et); | |
d7f45af8 | 339 | et_list_unlock(); |
00aba967 TT |
340 | return ENOENT; |
341 | } | |
342 | ||
343 | /* | |
344 | * Variant of the interface provided by Heimdal's com_err library | |
345 | */ | |
346 | void | |
347 | add_to_error_table(struct et_list *new_table) | |
348 | { | |
349 | add_error_table(new_table->table); | |
350 | } |