Fix parameter name.
[glibc.git] / dlfcn / dlerror.c
blob0e02ca7d90191486321d58272a3dfc5c4c5c5dd0
1 /* Return error detail for failing <dlfcn.h> functions.
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2002, 2003
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <dlfcn.h>
22 #include <libintl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <bits/libc-lock.h>
28 /* Type for storing results of dynamic loading actions. */
29 struct dl_action_result
31 int errcode;
32 int returned;
33 const char *objname;
34 const char *errstring;
36 static struct dl_action_result last_result;
37 static struct dl_action_result *static_buf;
39 /* This is the key for the thread specific memory. */
40 static __libc_key_t key;
42 /* Destructor for the thread-specific data. */
43 static void init (void);
44 static void free_key_mem (void *mem);
47 char *
48 dlerror (void)
50 char *buf = NULL;
51 struct dl_action_result *result;
53 /* Get error string. */
54 result = (struct dl_action_result *) __libc_getspecific (key);
55 if (result == NULL)
56 result = &last_result;
58 /* Test whether we already returned the string. */
59 if (result->returned != 0)
61 /* We can now free the string. */
62 if (result->errstring != NULL)
64 if (strcmp (result->errstring, "out of memory") != 0)
65 free ((char *) result->errstring);
66 result->errstring = NULL;
69 else if (result->errstring != NULL)
71 buf = (char *) result->errstring;
72 int n;
73 if (result->errcode == 0)
74 n = __asprintf (&buf, "%s%s%s",
75 result->objname,
76 result->objname[0] == '\0' ? "" : ": ",
77 _(result->errstring));
78 else
79 n = __asprintf (&buf, "%s%s%s: %s",
80 result->objname,
81 result->objname[0] == '\0' ? "" : ": ",
82 _(result->errstring),
83 strerror (result->errcode));
84 if (n != -1)
86 /* We don't need the error string anymore. */
87 if (strcmp (result->errstring, "out of memory") != 0)
88 free ((char *) result->errstring);
89 result->errstring = buf;
92 /* Mark the error as returned. */
93 result->returned = 1;
96 return buf;
99 int
100 internal_function
101 _dlerror_run (void (*operate) (void *), void *args)
103 __libc_once_define (static, once);
104 struct dl_action_result *result;
106 /* If we have not yet initialized the buffer do it now. */
107 __libc_once (once, init);
109 /* Get error string and number. */
110 if (static_buf != NULL)
111 result = static_buf;
112 else
114 /* We don't use the static buffer and so we have a key. Use it
115 to get the thread-specific buffer. */
116 result = __libc_getspecific (key);
117 if (result == NULL)
119 result = (struct dl_action_result *) calloc (1, sizeof (*result));
120 if (result == NULL)
121 /* We are out of memory. Since this is no really critical
122 situation we carry on by using the global variable.
123 This might lead to conflicts between the threads but
124 they soon all will have memory problems. */
125 result = &last_result;
126 else
127 /* Set the tsd. */
128 __libc_setspecific (key, result);
132 if (result->errstring != NULL)
134 /* Free the error string from the last failed command. This can
135 happen if `dlerror' was not run after an error was found. */
136 if (strcmp (result->errstring, "out of memory") != 0)
137 free ((char *) result->errstring);
138 result->errstring = NULL;
141 result->errcode = _dl_catch_error (&result->objname, &result->errstring,
142 operate, args);
144 /* If no error we mark that no error string is available. */
145 result->returned = result->errstring == NULL;
147 return result->errstring != NULL;
151 /* Initialize buffers for results. */
152 static void
153 init (void)
155 if (__libc_key_create (&key, free_key_mem))
156 /* Creating the key failed. This means something really went
157 wrong. In any case use a static buffer which is better than
158 nothing. */
159 static_buf = &last_result;
162 static void
163 __attribute__ ((destructor))
164 fini (void)
166 if (last_result.errstring != NULL
167 && strcmp (last_result.errstring, "out of memory") != 0)
168 free ((char *) last_result.errstring);
172 /* Free the thread specific data, this is done if a thread terminates. */
173 static void
174 free_key_mem (void *mem)
176 struct dl_action_result *result = (struct dl_action_result *) mem;
178 if (result->errstring != NULL
179 && strcmp (result->errstring, "out of memory") != 0)
180 free ((char *) result->errstring);
182 free (mem);
183 __libc_setspecific (key, NULL);