Fix inaccurate arcstat_l2_hdr_size calculations
[zfs.git] / lib / libuutil / 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 <unistd.h>
38 #include <ctype.h>
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;
70 static __thread int     _uu_main_thread = 0;
71
72 void
73 uu_set_error(uint_t code)
74 {
75         if (_uu_main_thread) {
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 (_uu_main_thread)
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 static void
210 uu_lockup(void)
211 {
212         (void) pthread_mutex_lock(&uu_panic_lock);
213 #if !defined(PTHREAD_ONCE_KEY_NP)
214         (void) pthread_mutex_lock(&uu_key_lock);
215 #endif
216         uu_avl_lockup();
217         uu_list_lockup();
218 }
219
220 static void
221 uu_release(void)
222 {
223         (void) pthread_mutex_unlock(&uu_panic_lock);
224 #if !defined(PTHREAD_ONCE_KEY_NP)
225         (void) pthread_mutex_unlock(&uu_key_lock);
226 #endif
227         uu_avl_release();
228         uu_list_release();
229 }
230
231 static void
232 uu_release_child(void)
233 {
234         uu_panic_format = NULL;
235         uu_panic_thread = 0;
236
237         uu_release();
238 }
239
240 #ifdef __GNUC__
241 static void
242 uu_init(void) __attribute__((constructor));
243 #else
244 #pragma init(uu_init)
245 #endif
246
247 static void
248 uu_init(void)
249 {
250         _uu_main_thread = 1;
251         (void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
252 }
253
254 /*
255  * Dump a block of memory in hex+ascii, for debugging
256  */
257 void
258 uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
259 {
260         const unsigned char *p = buf;
261         int i;
262
263         for (i = 0; i < len; i += 16) {
264                 int j;
265
266                 (void) fprintf(out, "%s", prefix);
267                 for (j = 0; j < 16 && i + j < len; j++) {
268                         (void) fprintf(out, "%2.2x ", p[i + j]);
269                 }
270                 for (; j < 16; j++) {
271                         (void) fprintf(out, "   ");
272                 }
273                 for (j = 0; j < 16 && i + j < len; j++) {
274                         (void) fprintf(out, "%c",
275                             isprint(p[i + j]) ? p[i + j] : '.');
276                 }
277                 (void) fprintf(out, "\n");
278         }
279 }