xref: /illumos-gate/usr/src/lib/libuutil/common/uu_misc.c (revision b210e77709da8e42dfe621e10ccf4be504206058)
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 	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 {
212 	__assert(astring, file, line);
213 	/*NOTREACHED*/
214 	return (0);
215 }
216 
217 static void
218 uu_lockup(void)
219 {
220 	(void) pthread_mutex_lock(&uu_panic_lock);
221 #if !defined(PTHREAD_ONCE_KEY_NP)
222 	(void) pthread_mutex_lock(&uu_key_lock);
223 #endif
224 	uu_avl_lockup();
225 	uu_list_lockup();
226 }
227 
228 static void
229 uu_release(void)
230 {
231 	(void) pthread_mutex_unlock(&uu_panic_lock);
232 #if !defined(PTHREAD_ONCE_KEY_NP)
233 	(void) pthread_mutex_unlock(&uu_key_lock);
234 #endif
235 	uu_avl_release();
236 	uu_list_release();
237 }
238 
239 static void
240 uu_release_child(void)
241 {
242 	uu_panic_format = NULL;
243 	uu_panic_thread = 0;
244 
245 	uu_release();
246 }
247 
248 #pragma init(uu_init)
249 static void
250 uu_init(void)
251 {
252 	(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
253 }
254 
255 /*
256  * Dump a block of memory in hex+ascii, for debugging
257  */
258 void
259 uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
260 {
261 	const unsigned char *p = buf;
262 	int i;
263 
264 	for (i = 0; i < len; i += 16) {
265 		int j;
266 
267 		(void) fprintf(out, "%s", prefix);
268 		for (j = 0; j < 16 && i + j < len; j++) {
269 			(void) fprintf(out, "%2.2x ", p[i + j]);
270 		}
271 		for (; j < 16; j++) {
272 			(void) fprintf(out, "   ");
273 		}
274 		for (j = 0; j < 16 && i + j < len; j++) {
275 			(void) fprintf(out, "%c",
276 			    isprint(p[i + j]) ? p[i + j] : '.');
277 		}
278 		(void) fprintf(out, "\n");
279 	}
280 }
281