]>
Commit | Line | Data |
---|---|---|
34dc7c2f BB |
1 | /* |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
5 | * Common Development and Distribution License (the "License"). | |
6 | * You may not use this file except in compliance with the License. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
13 | * When distributing Covered Code, include this CDDL HEADER in each | |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | * If applicable, add the following below this CDDL HEADER, with the | |
16 | * fields enclosed by brackets "[]" replaced with your own identifying | |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | ||
22 | /* | |
572e2857 | 23 | * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. |
34dc7c2f BB |
24 | */ |
25 | ||
34dc7c2f BB |
26 | #include "libuutil_common.h" |
27 | ||
28 | #include <assert.h> | |
29 | #include <errno.h> | |
30 | #include <libintl.h> | |
31 | #include <pthread.h> | |
32 | #include <stdarg.h> | |
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | #include <string.h> | |
36 | #include <sys/debug.h> | |
37 | #include <thread.h> | |
38 | #include <unistd.h> | |
572e2857 | 39 | #include <ctype.h> |
34dc7c2f BB |
40 | |
41 | #if !defined(TEXT_DOMAIN) | |
42 | #define TEXT_DOMAIN "SYS_TEST" | |
43 | #endif | |
44 | ||
45 | /* | |
46 | * All of the old code under !defined(PTHREAD_ONCE_KEY_NP) | |
47 | * is here to enable the building of a native version of | |
48 | * libuutil.so when the build machine has not yet been upgraded | |
49 | * to a version of libc that provides pthread_key_create_once_np(). | |
50 | * It should all be deleted when solaris_nevada ships. | |
51 | * The code is not MT-safe in a relaxed memory model. | |
52 | */ | |
53 | ||
54 | #if defined(PTHREAD_ONCE_KEY_NP) | |
55 | static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP; | |
56 | #else /* PTHREAD_ONCE_KEY_NP */ | |
57 | static pthread_key_t uu_error_key = 0; | |
58 | static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER; | |
59 | #endif /* PTHREAD_ONCE_KEY_NP */ | |
60 | ||
61 | static int uu_error_key_setup = 0; | |
62 | ||
63 | static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER; | |
64 | /* LINTED static unused */ | |
65 | static const char *uu_panic_format; | |
66 | /* LINTED static unused */ | |
67 | static va_list uu_panic_args; | |
68 | static pthread_t uu_panic_thread; | |
69 | ||
70 | static uint32_t _uu_main_error; | |
71 | ||
72 | void | |
73 | uu_set_error(uint_t code) | |
74 | { | |
75 | if (thr_main() != 0) { | |
76 | _uu_main_error = code; | |
77 | return; | |
78 | } | |
79 | #if defined(PTHREAD_ONCE_KEY_NP) | |
80 | if (pthread_key_create_once_np(&uu_error_key, NULL) != 0) | |
81 | uu_error_key_setup = -1; | |
82 | else | |
83 | uu_error_key_setup = 1; | |
84 | #else /* PTHREAD_ONCE_KEY_NP */ | |
85 | if (uu_error_key_setup == 0) { | |
86 | (void) pthread_mutex_lock(&uu_key_lock); | |
87 | if (uu_error_key_setup == 0) { | |
88 | if (pthread_key_create(&uu_error_key, NULL) != 0) | |
89 | uu_error_key_setup = -1; | |
90 | else | |
91 | uu_error_key_setup = 1; | |
92 | } | |
93 | (void) pthread_mutex_unlock(&uu_key_lock); | |
94 | } | |
95 | #endif /* PTHREAD_ONCE_KEY_NP */ | |
96 | if (uu_error_key_setup > 0) | |
97 | (void) pthread_setspecific(uu_error_key, | |
98 | (void *)(uintptr_t)code); | |
99 | } | |
100 | ||
101 | uint32_t | |
102 | uu_error(void) | |
103 | { | |
104 | if (thr_main() != 0) | |
105 | return (_uu_main_error); | |
106 | ||
107 | if (uu_error_key_setup < 0) /* can't happen? */ | |
108 | return (UU_ERROR_UNKNOWN); | |
109 | ||
110 | /* | |
111 | * Because UU_ERROR_NONE == 0, if uu_set_error() was | |
112 | * never called, then this will return UU_ERROR_NONE: | |
113 | */ | |
114 | return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key)); | |
115 | } | |
116 | ||
117 | const char * | |
118 | uu_strerror(uint32_t code) | |
119 | { | |
120 | const char *str; | |
121 | ||
122 | switch (code) { | |
123 | case UU_ERROR_NONE: | |
124 | str = dgettext(TEXT_DOMAIN, "No error"); | |
125 | break; | |
126 | ||
127 | case UU_ERROR_INVALID_ARGUMENT: | |
128 | str = dgettext(TEXT_DOMAIN, "Invalid argument"); | |
129 | break; | |
130 | ||
131 | case UU_ERROR_UNKNOWN_FLAG: | |
132 | str = dgettext(TEXT_DOMAIN, "Unknown flag passed"); | |
133 | break; | |
134 | ||
135 | case UU_ERROR_NO_MEMORY: | |
136 | str = dgettext(TEXT_DOMAIN, "Out of memory"); | |
137 | break; | |
138 | ||
139 | case UU_ERROR_CALLBACK_FAILED: | |
140 | str = dgettext(TEXT_DOMAIN, "Callback-initiated failure"); | |
141 | break; | |
142 | ||
143 | case UU_ERROR_NOT_SUPPORTED: | |
144 | str = dgettext(TEXT_DOMAIN, "Operation not supported"); | |
145 | break; | |
146 | ||
147 | case UU_ERROR_EMPTY: | |
148 | str = dgettext(TEXT_DOMAIN, "No value provided"); | |
149 | break; | |
150 | ||
151 | case UU_ERROR_UNDERFLOW: | |
152 | str = dgettext(TEXT_DOMAIN, "Value too small"); | |
153 | break; | |
154 | ||
155 | case UU_ERROR_OVERFLOW: | |
156 | str = dgettext(TEXT_DOMAIN, "Value too large"); | |
157 | break; | |
158 | ||
159 | case UU_ERROR_INVALID_CHAR: | |
160 | str = dgettext(TEXT_DOMAIN, | |
161 | "Value contains unexpected character"); | |
162 | break; | |
163 | ||
164 | case UU_ERROR_INVALID_DIGIT: | |
165 | str = dgettext(TEXT_DOMAIN, | |
166 | "Value contains digit not in base"); | |
167 | break; | |
168 | ||
169 | case UU_ERROR_SYSTEM: | |
170 | str = dgettext(TEXT_DOMAIN, "Underlying system error"); | |
171 | break; | |
172 | ||
173 | case UU_ERROR_UNKNOWN: | |
174 | str = dgettext(TEXT_DOMAIN, "Error status not known"); | |
175 | break; | |
176 | ||
177 | default: | |
178 | errno = ESRCH; | |
179 | str = NULL; | |
180 | break; | |
181 | } | |
182 | return (str); | |
183 | } | |
184 | ||
185 | void | |
186 | uu_panic(const char *format, ...) | |
187 | { | |
188 | va_list args; | |
189 | ||
190 | va_start(args, format); | |
191 | ||
192 | (void) pthread_mutex_lock(&uu_panic_lock); | |
193 | if (uu_panic_thread == 0) { | |
194 | uu_panic_thread = pthread_self(); | |
195 | uu_panic_format = format; | |
196 | va_copy(uu_panic_args, args); | |
197 | } | |
198 | (void) pthread_mutex_unlock(&uu_panic_lock); | |
199 | ||
200 | (void) vfprintf(stderr, format, args); | |
201 | ||
202 | if (uu_panic_thread == pthread_self()) | |
203 | abort(); | |
204 | else | |
205 | for (;;) | |
206 | (void) pause(); | |
207 | } | |
208 | ||
209 | int | |
210 | assfail(const char *astring, const char *file, int line) | |
211 | { | |
d6320ddb BB |
212 | #if defined(__STDC__) && __STDC_VERSION__ - 0 >= 199901L |
213 | __assert_c99(astring, file, line, "unknown func"); | |
214 | #else | |
34dc7c2f | 215 | __assert(astring, file, line); |
d6320ddb | 216 | #endif |
34dc7c2f BB |
217 | /*NOTREACHED*/ |
218 | return (0); | |
219 | } | |
220 | ||
221 | static void | |
222 | uu_lockup(void) | |
223 | { | |
224 | (void) pthread_mutex_lock(&uu_panic_lock); | |
225 | #if !defined(PTHREAD_ONCE_KEY_NP) | |
226 | (void) pthread_mutex_lock(&uu_key_lock); | |
227 | #endif | |
228 | uu_avl_lockup(); | |
229 | uu_list_lockup(); | |
230 | } | |
231 | ||
232 | static void | |
233 | uu_release(void) | |
234 | { | |
235 | (void) pthread_mutex_unlock(&uu_panic_lock); | |
236 | #if !defined(PTHREAD_ONCE_KEY_NP) | |
237 | (void) pthread_mutex_unlock(&uu_key_lock); | |
238 | #endif | |
239 | uu_avl_release(); | |
240 | uu_list_release(); | |
241 | } | |
242 | ||
243 | static void | |
244 | uu_release_child(void) | |
245 | { | |
246 | uu_panic_format = NULL; | |
247 | uu_panic_thread = 0; | |
248 | ||
249 | uu_release(); | |
250 | } | |
251 | ||
252 | #pragma init(uu_init) | |
253 | static void | |
254 | uu_init(void) | |
255 | { | |
256 | (void) pthread_atfork(uu_lockup, uu_release, uu_release_child); | |
257 | } | |
572e2857 BB |
258 | |
259 | /* | |
260 | * Dump a block of memory in hex+ascii, for debugging | |
261 | */ | |
262 | void | |
263 | uu_dump(FILE *out, const char *prefix, const void *buf, size_t len) | |
264 | { | |
265 | const unsigned char *p = buf; | |
266 | int i; | |
267 | ||
268 | for (i = 0; i < len; i += 16) { | |
269 | int j; | |
270 | ||
271 | (void) fprintf(out, "%s", prefix); | |
272 | for (j = 0; j < 16 && i + j < len; j++) { | |
273 | (void) fprintf(out, "%2.2x ", p[i + j]); | |
274 | } | |
275 | for (; j < 16; j++) { | |
276 | (void) fprintf(out, " "); | |
277 | } | |
278 | for (j = 0; j < 16 && i + j < len; j++) { | |
279 | (void) fprintf(out, "%c", | |
280 | isprint(p[i + j]) ? p[i + j] : '.'); | |
281 | } | |
282 | (void) fprintf(out, "\n"); | |
283 | } | |
284 | } |