xref: /netbsd-src/external/cddl/osnet/dist/lib/libuutil/common/uu_misc.c (revision ba2539a9805a0544ff82c0003cc02fe1eee5603d)
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 #define HAVE_ASSFAIL	1
29 
30 #include <assert.h>
31 #include <errno.h>
32 #include <libintl.h>
33 #include <pthread.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/debug.h>
39 #include <thread.h>
40 #include <unistd.h>
41 #include <ctype.h>
42 
43 #if !defined(TEXT_DOMAIN)
44 #define	TEXT_DOMAIN "SYS_TEST"
45 #endif
46 
47 /*
48  * All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
49  * is here to enable the building of a native version of
50  * libuutil.so when the build machine has not yet been upgraded
51  * to a version of libc that provides pthread_key_create_once_np().
52  * It should all be deleted when solaris_nevada ships.
53  * The code is not MT-safe in a relaxed memory model.
54  */
55 
56 #if defined(PTHREAD_ONCE_KEY_NP)
57 static pthread_key_t	uu_error_key = PTHREAD_ONCE_KEY_NP;
58 #else	/* PTHREAD_ONCE_KEY_NP */
59 static pthread_key_t	uu_error_key = 0;
60 static pthread_mutex_t	uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
61 #endif	/* PTHREAD_ONCE_KEY_NP */
62 
63 static int		uu_error_key_setup = 0;
64 
65 static pthread_mutex_t	uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
66 /* LINTED static unused */
67 static const char	*uu_panic_format;
68 /* LINTED static unused */
69 static va_list		uu_panic_args;
70 static pthread_t	uu_panic_thread;
71 
72 static uint32_t		_uu_main_error;
73 
74 void
uu_set_error(uint_t code)75 uu_set_error(uint_t code)
76 {
77 
78 #if defined(PTHREAD_ONCE_KEY_NP)
79 	if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
80 		uu_error_key_setup = -1;
81 	else
82 		uu_error_key_setup = 1;
83 #else	/* PTHREAD_ONCE_KEY_NP */
84 	if (uu_error_key_setup == 0) {
85 		(void) pthread_mutex_lock(&uu_key_lock);
86 		if (uu_error_key_setup == 0) {
87 			if (pthread_key_create(&uu_error_key, NULL) != 0)
88 				uu_error_key_setup = -1;
89 			else
90 				uu_error_key_setup = 1;
91 		}
92 		(void) pthread_mutex_unlock(&uu_key_lock);
93 	}
94 #endif	/* PTHREAD_ONCE_KEY_NP */
95 	if (uu_error_key_setup > 0)
96 		(void) pthread_setspecific(uu_error_key,
97 		    (void *)(uintptr_t)code);
98 }
99 
100 uint32_t
uu_error(void)101 uu_error(void)
102 {
103 
104 	if (uu_error_key_setup < 0)	/* can't happen? */
105 		return (UU_ERROR_UNKNOWN);
106 
107 	/*
108 	 * Because UU_ERROR_NONE == 0, if uu_set_error() was
109 	 * never called, then this will return UU_ERROR_NONE:
110 	 */
111 	return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
112 }
113 
114 const char *
uu_strerror(uint32_t code)115 uu_strerror(uint32_t code)
116 {
117 	const char *str;
118 
119 	switch (code) {
120 	case UU_ERROR_NONE:
121 		str = dgettext(TEXT_DOMAIN, "No error");
122 		break;
123 
124 	case UU_ERROR_INVALID_ARGUMENT:
125 		str = dgettext(TEXT_DOMAIN, "Invalid argument");
126 		break;
127 
128 	case UU_ERROR_UNKNOWN_FLAG:
129 		str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
130 		break;
131 
132 	case UU_ERROR_NO_MEMORY:
133 		str = dgettext(TEXT_DOMAIN, "Out of memory");
134 		break;
135 
136 	case UU_ERROR_CALLBACK_FAILED:
137 		str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
138 		break;
139 
140 	case UU_ERROR_NOT_SUPPORTED:
141 		str = dgettext(TEXT_DOMAIN, "Operation not supported");
142 		break;
143 
144 	case UU_ERROR_EMPTY:
145 		str = dgettext(TEXT_DOMAIN, "No value provided");
146 		break;
147 
148 	case UU_ERROR_UNDERFLOW:
149 		str = dgettext(TEXT_DOMAIN, "Value too small");
150 		break;
151 
152 	case UU_ERROR_OVERFLOW:
153 		str = dgettext(TEXT_DOMAIN, "Value too large");
154 		break;
155 
156 	case UU_ERROR_INVALID_CHAR:
157 		str = dgettext(TEXT_DOMAIN,
158 		    "Value contains unexpected character");
159 		break;
160 
161 	case UU_ERROR_INVALID_DIGIT:
162 		str = dgettext(TEXT_DOMAIN,
163 		    "Value contains digit not in base");
164 		break;
165 
166 	case UU_ERROR_SYSTEM:
167 		str = dgettext(TEXT_DOMAIN, "Underlying system error");
168 		break;
169 
170 	case UU_ERROR_UNKNOWN:
171 		str = dgettext(TEXT_DOMAIN, "Error status not known");
172 		break;
173 
174 	default:
175 		errno = ESRCH;
176 		str = NULL;
177 		break;
178 	}
179 	return (str);
180 }
181 
182 void
uu_panic(const char * format,...)183 uu_panic(const char *format, ...)
184 {
185 	va_list args;
186 
187 	va_start(args, format);
188 
189 	(void) pthread_mutex_lock(&uu_panic_lock);
190 	if (uu_panic_thread == 0) {
191 		uu_panic_thread = pthread_self();
192 		uu_panic_format = format;
193 		va_copy(uu_panic_args, args);
194 	}
195 	(void) pthread_mutex_unlock(&uu_panic_lock);
196 
197 	(void) vfprintf(stderr, format, args);
198 
199 	if (uu_panic_thread == pthread_self())
200 		abort();
201 	else
202 		for (;;)
203 			(void) pause();
204 }
205 
206 int
assfail(const char * astring,const char * file,int line)207 assfail(const char *astring, const char *file, int line)
208 {
209 	__assert(file, line, astring);
210 	/*NOTREACHED*/
211 	return (0);
212 }
213 
214 static void
uu_lockup(void)215 uu_lockup(void)
216 {
217 	(void) pthread_mutex_lock(&uu_panic_lock);
218 #if !defined(PTHREAD_ONCE_KEY_NP)
219 	(void) pthread_mutex_lock(&uu_key_lock);
220 #endif
221 	uu_avl_lockup();
222 	uu_list_lockup();
223 }
224 
225 static void
uu_release(void)226 uu_release(void)
227 {
228 	(void) pthread_mutex_unlock(&uu_panic_lock);
229 #if !defined(PTHREAD_ONCE_KEY_NP)
230 	(void) pthread_mutex_unlock(&uu_key_lock);
231 #endif
232 	uu_avl_release();
233 	uu_list_release();
234 }
235 
236 static void
uu_release_child(void)237 uu_release_child(void)
238 {
239 	uu_panic_format = NULL;
240 	uu_panic_thread = 0;
241 
242 	uu_release();
243 }
244 
245 #pragma init(uu_init)
246 __attribute__((constructor))
247 static void
uu_init(void)248 uu_init(void)
249 {
250 	(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
251 }
252 
253 /*
254  * Dump a block of memory in hex+ascii, for debugging
255  */
256 void
uu_dump(FILE * out,const char * prefix,const void * buf,size_t len)257 uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
258 {
259 	const unsigned char *p = buf;
260 	int i;
261 
262 	for (i = 0; i < len; i += 16) {
263 		int j;
264 
265 		(void) fprintf(out, "%s", prefix);
266 		for (j = 0; j < 16 && i + j < len; j++) {
267 			(void) fprintf(out, "%2.2x ", p[i + j]);
268 		}
269 		for (; j < 16; j++) {
270 			(void) fprintf(out, "   ");
271 		}
272 		for (j = 0; j < 16 && i + j < len; j++) {
273 			(void) fprintf(out, "%c",
274 			    isprint(p[i + j]) ? p[i + j] : '.');
275 		}
276 		(void) fprintf(out, "\n");
277 	}
278 }
279