]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - cddl/contrib/opensolaris/lib/libuutil/common/uu_misc.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / cddl / contrib / opensolaris / lib / libuutil / common / uu_misc.c
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 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25
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>
39 #include <ctype.h>
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
76 #if defined(PTHREAD_ONCE_KEY_NP)
77         if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
78                 uu_error_key_setup = -1;
79         else
80                 uu_error_key_setup = 1;
81 #else   /* PTHREAD_ONCE_KEY_NP */
82         if (uu_error_key_setup == 0) {
83                 (void) pthread_mutex_lock(&uu_key_lock);
84                 if (uu_error_key_setup == 0) {
85                         if (pthread_key_create(&uu_error_key, NULL) != 0)
86                                 uu_error_key_setup = -1;
87                         else
88                                 uu_error_key_setup = 1;
89                 }
90                 (void) pthread_mutex_unlock(&uu_key_lock);
91         }
92 #endif  /* PTHREAD_ONCE_KEY_NP */
93         if (uu_error_key_setup > 0)
94                 (void) pthread_setspecific(uu_error_key,
95                     (void *)(uintptr_t)code);
96 }
97
98 uint32_t
99 uu_error(void)
100 {
101
102         if (uu_error_key_setup < 0)     /* can't happen? */
103                 return (UU_ERROR_UNKNOWN);
104
105         /*
106          * Because UU_ERROR_NONE == 0, if uu_set_error() was
107          * never called, then this will return UU_ERROR_NONE:
108          */
109         return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
110 }
111
112 const char *
113 uu_strerror(uint32_t code)
114 {
115         const char *str;
116
117         switch (code) {
118         case UU_ERROR_NONE:
119                 str = dgettext(TEXT_DOMAIN, "No error");
120                 break;
121
122         case UU_ERROR_INVALID_ARGUMENT:
123                 str = dgettext(TEXT_DOMAIN, "Invalid argument");
124                 break;
125
126         case UU_ERROR_UNKNOWN_FLAG:
127                 str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
128                 break;
129
130         case UU_ERROR_NO_MEMORY:
131                 str = dgettext(TEXT_DOMAIN, "Out of memory");
132                 break;
133
134         case UU_ERROR_CALLBACK_FAILED:
135                 str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
136                 break;
137
138         case UU_ERROR_NOT_SUPPORTED:
139                 str = dgettext(TEXT_DOMAIN, "Operation not supported");
140                 break;
141
142         case UU_ERROR_EMPTY:
143                 str = dgettext(TEXT_DOMAIN, "No value provided");
144                 break;
145
146         case UU_ERROR_UNDERFLOW:
147                 str = dgettext(TEXT_DOMAIN, "Value too small");
148                 break;
149
150         case UU_ERROR_OVERFLOW:
151                 str = dgettext(TEXT_DOMAIN, "Value too large");
152                 break;
153
154         case UU_ERROR_INVALID_CHAR:
155                 str = dgettext(TEXT_DOMAIN,
156                     "Value contains unexpected character");
157                 break;
158
159         case UU_ERROR_INVALID_DIGIT:
160                 str = dgettext(TEXT_DOMAIN,
161                     "Value contains digit not in base");
162                 break;
163
164         case UU_ERROR_SYSTEM:
165                 str = dgettext(TEXT_DOMAIN, "Underlying system error");
166                 break;
167
168         case UU_ERROR_UNKNOWN:
169                 str = dgettext(TEXT_DOMAIN, "Error status not known");
170                 break;
171
172         default:
173                 errno = ESRCH;
174                 str = NULL;
175                 break;
176         }
177         return (str);
178 }
179
180 void
181 uu_panic(const char *format, ...)
182 {
183         va_list args;
184
185         va_start(args, format);
186
187         (void) pthread_mutex_lock(&uu_panic_lock);
188         if (uu_panic_thread == 0) {
189                 uu_panic_thread = pthread_self();
190                 uu_panic_format = format;
191                 va_copy(uu_panic_args, args);
192         }
193         (void) pthread_mutex_unlock(&uu_panic_lock);
194
195         (void) vfprintf(stderr, format, args);
196
197         if (uu_panic_thread == pthread_self())
198                 abort();
199         else
200                 for (;;)
201                         (void) pause();
202 }
203
204 int
205 assfail(const char *astring, const char *file, int line)
206 {
207         __assert(astring, file, line);
208         /*NOTREACHED*/
209         return (0);
210 }
211
212 static void
213 uu_lockup(void)
214 {
215         (void) pthread_mutex_lock(&uu_panic_lock);
216 #if !defined(PTHREAD_ONCE_KEY_NP)
217         (void) pthread_mutex_lock(&uu_key_lock);
218 #endif
219         uu_avl_lockup();
220         uu_list_lockup();
221 }
222
223 static void
224 uu_release(void)
225 {
226         (void) pthread_mutex_unlock(&uu_panic_lock);
227 #if !defined(PTHREAD_ONCE_KEY_NP)
228         (void) pthread_mutex_unlock(&uu_key_lock);
229 #endif
230         uu_avl_release();
231         uu_list_release();
232 }
233
234 static void
235 uu_release_child(void)
236 {
237         uu_panic_format = NULL;
238         uu_panic_thread = 0;
239
240         uu_release();
241 }
242
243 #pragma init(uu_init)
244 static void
245 uu_init(void)
246 {
247         (void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
248 }
249
250 /*
251  * Dump a block of memory in hex+ascii, for debugging
252  */
253 void
254 uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
255 {
256         const unsigned char *p = buf;
257         int i;
258
259         for (i = 0; i < len; i += 16) {
260                 int j;
261
262                 (void) fprintf(out, "%s", prefix);
263                 for (j = 0; j < 16 && i + j < len; j++) {
264                         (void) fprintf(out, "%2.2x ", p[i + j]);
265                 }
266                 for (; j < 16; j++) {
267                         (void) fprintf(out, "   ");
268                 }
269                 for (j = 0; j < 16 && i + j < len; j++) {
270                         (void) fprintf(out, "%c",
271                             isprint(p[i + j]) ? p[i + j] : '.');
272                 }
273                 (void) fprintf(out, "\n");
274         }
275 }