]>
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> | |
34dc7c2f | 37 | #include <unistd.h> |
572e2857 | 38 | #include <ctype.h> |
34dc7c2f BB |
39 | |
40 | #if !defined(TEXT_DOMAIN) | |
41 | #define TEXT_DOMAIN "SYS_TEST" | |
42 | #endif | |
43 | ||
44 | /* | |
45 | * All of the old code under !defined(PTHREAD_ONCE_KEY_NP) | |
46 | * is here to enable the building of a native version of | |
47 | * libuutil.so when the build machine has not yet been upgraded | |
48 | * to a version of libc that provides pthread_key_create_once_np(). | |
49 | * It should all be deleted when solaris_nevada ships. | |
50 | * The code is not MT-safe in a relaxed memory model. | |
51 | */ | |
52 | ||
53 | #if defined(PTHREAD_ONCE_KEY_NP) | |
54 | static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP; | |
55 | #else /* PTHREAD_ONCE_KEY_NP */ | |
56 | static pthread_key_t uu_error_key = 0; | |
57 | static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER; | |
58 | #endif /* PTHREAD_ONCE_KEY_NP */ | |
59 | ||
60 | static int uu_error_key_setup = 0; | |
61 | ||
62 | static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER; | |
63 | /* LINTED static unused */ | |
64 | static const char *uu_panic_format; | |
65 | /* LINTED static unused */ | |
66 | static va_list uu_panic_args; | |
67 | static pthread_t uu_panic_thread; | |
68 | ||
69 | static uint32_t _uu_main_error; | |
1e33ac1e | 70 | static __thread int _uu_main_thread = 0; |
34dc7c2f BB |
71 | |
72 | void | |
73 | uu_set_error(uint_t code) | |
74 | { | |
1e33ac1e | 75 | if (_uu_main_thread) { |
34dc7c2f BB |
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 | { | |
1e33ac1e | 104 | if (_uu_main_thread) |
34dc7c2f BB |
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 | ||
a64f903b GN |
202 | va_end(args); |
203 | ||
34dc7c2f BB |
204 | if (uu_panic_thread == pthread_self()) |
205 | abort(); | |
206 | else | |
207 | for (;;) | |
208 | (void) pause(); | |
209 | } | |
210 | ||
34dc7c2f BB |
211 | static void |
212 | uu_lockup(void) | |
213 | { | |
214 | (void) pthread_mutex_lock(&uu_panic_lock); | |
215 | #if !defined(PTHREAD_ONCE_KEY_NP) | |
216 | (void) pthread_mutex_lock(&uu_key_lock); | |
217 | #endif | |
218 | uu_avl_lockup(); | |
219 | uu_list_lockup(); | |
220 | } | |
221 | ||
222 | static void | |
223 | uu_release(void) | |
224 | { | |
225 | (void) pthread_mutex_unlock(&uu_panic_lock); | |
226 | #if !defined(PTHREAD_ONCE_KEY_NP) | |
227 | (void) pthread_mutex_unlock(&uu_key_lock); | |
228 | #endif | |
229 | uu_avl_release(); | |
230 | uu_list_release(); | |
231 | } | |
232 | ||
233 | static void | |
234 | uu_release_child(void) | |
235 | { | |
236 | uu_panic_format = NULL; | |
237 | uu_panic_thread = 0; | |
238 | ||
239 | uu_release(); | |
240 | } | |
241 | ||
0ccd9d24 BB |
242 | #ifdef __GNUC__ |
243 | static void | |
244 | uu_init(void) __attribute__((constructor)); | |
245 | #else | |
34dc7c2f | 246 | #pragma init(uu_init) |
0ccd9d24 BB |
247 | #endif |
248 | ||
34dc7c2f BB |
249 | static void |
250 | uu_init(void) | |
251 | { | |
1e33ac1e | 252 | _uu_main_thread = 1; |
34dc7c2f BB |
253 | (void) pthread_atfork(uu_lockup, uu_release, uu_release_child); |
254 | } | |
572e2857 BB |
255 | |
256 | /* | |
257 | * Dump a block of memory in hex+ascii, for debugging | |
258 | */ | |
259 | void | |
260 | uu_dump(FILE *out, const char *prefix, const void *buf, size_t len) | |
261 | { | |
262 | const unsigned char *p = buf; | |
263 | int i; | |
264 | ||
265 | for (i = 0; i < len; i += 16) { | |
266 | int j; | |
267 | ||
268 | (void) fprintf(out, "%s", prefix); | |
269 | for (j = 0; j < 16 && i + j < len; j++) { | |
270 | (void) fprintf(out, "%2.2x ", p[i + j]); | |
271 | } | |
272 | for (; j < 16; j++) { | |
273 | (void) fprintf(out, " "); | |
274 | } | |
275 | for (j = 0; j < 16 && i + j < len; j++) { | |
276 | (void) fprintf(out, "%c", | |
277 | isprint(p[i + j]) ? p[i + j] : '.'); | |
278 | } | |
279 | (void) fprintf(out, "\n"); | |
280 | } | |
281 | } |