uu_misc.c revision 219089
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)
55static pthread_key_t	uu_error_key = PTHREAD_ONCE_KEY_NP;
56#else	/* PTHREAD_ONCE_KEY_NP */
57static pthread_key_t	uu_error_key = 0;
58static pthread_mutex_t	uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
59#endif	/* PTHREAD_ONCE_KEY_NP */
60
61static int		uu_error_key_setup = 0;
62
63static pthread_mutex_t	uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
64/* LINTED static unused */
65static const char	*uu_panic_format;
66/* LINTED static unused */
67static va_list		uu_panic_args;
68static pthread_t	uu_panic_thread;
69
70static uint32_t		_uu_main_error;
71
72void
73uu_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
98uint32_t
99uu_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
112const char *
113uu_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
180void
181uu_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
204int
205assfail(const char *astring, const char *file, int line)
206{
207	__assert(astring, file, line);
208	/*NOTREACHED*/
209	return (0);
210}
211
212static void
213uu_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
223static void
224uu_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
234static void
235uu_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)
244static void
245uu_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 */
253void
254uu_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}
276