xref: /illumos-gate/usr/src/lib/libuutil/common/uu_misc.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "libuutil_common.h"
30 
31 #include <assert.h>
32 #include <errno.h>
33 #include <libintl.h>
34 #include <pthread.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/debug.h>
40 #include <thread.h>
41 #include <unistd.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
75 uu_set_error(uint_t code)
76 {
77 	if (thr_main() != 0) {
78 		_uu_main_error = code;
79 		return;
80 	}
81 #if defined(PTHREAD_ONCE_KEY_NP)
82 	if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
83 		uu_error_key_setup = -1;
84 	else
85 		uu_error_key_setup = 1;
86 #else	/* PTHREAD_ONCE_KEY_NP */
87 	if (uu_error_key_setup == 0) {
88 		(void) pthread_mutex_lock(&uu_key_lock);
89 		if (uu_error_key_setup == 0) {
90 			if (pthread_key_create(&uu_error_key, NULL) != 0)
91 				uu_error_key_setup = -1;
92 			else
93 				uu_error_key_setup = 1;
94 		}
95 		(void) pthread_mutex_unlock(&uu_key_lock);
96 	}
97 #endif	/* PTHREAD_ONCE_KEY_NP */
98 	if (uu_error_key_setup > 0)
99 		(void) pthread_setspecific(uu_error_key,
100 		    (void *)(uintptr_t)code);
101 }
102 
103 uint32_t
104 uu_error(void)
105 {
106 	if (thr_main() != 0)
107 		return (_uu_main_error);
108 
109 	if (uu_error_key_setup < 0)	/* can't happen? */
110 		return (UU_ERROR_UNKNOWN);
111 
112 	/*
113 	 * Because UU_ERROR_NONE == 0, if uu_set_error() was
114 	 * never called, then this will return UU_ERROR_NONE:
115 	 */
116 	return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
117 }
118 
119 const char *
120 uu_strerror(uint32_t code)
121 {
122 	const char *str;
123 
124 	switch (code) {
125 	case UU_ERROR_NONE:
126 		str = dgettext(TEXT_DOMAIN, "No error");
127 		break;
128 
129 	case UU_ERROR_INVALID_ARGUMENT:
130 		str = dgettext(TEXT_DOMAIN, "Invalid argument");
131 		break;
132 
133 	case UU_ERROR_UNKNOWN_FLAG:
134 		str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
135 		break;
136 
137 	case UU_ERROR_NO_MEMORY:
138 		str = dgettext(TEXT_DOMAIN, "Out of memory");
139 		break;
140 
141 	case UU_ERROR_CALLBACK_FAILED:
142 		str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
143 		break;
144 
145 	case UU_ERROR_NOT_SUPPORTED:
146 		str = dgettext(TEXT_DOMAIN, "Operation not supported");
147 		break;
148 
149 	case UU_ERROR_EMPTY:
150 		str = dgettext(TEXT_DOMAIN, "No value provided");
151 		break;
152 
153 	case UU_ERROR_UNDERFLOW:
154 		str = dgettext(TEXT_DOMAIN, "Value too small");
155 		break;
156 
157 	case UU_ERROR_OVERFLOW:
158 		str = dgettext(TEXT_DOMAIN, "Value too large");
159 		break;
160 
161 	case UU_ERROR_INVALID_CHAR:
162 		str = dgettext(TEXT_DOMAIN,
163 		    "Value contains unexpected character");
164 		break;
165 
166 	case UU_ERROR_INVALID_DIGIT:
167 		str = dgettext(TEXT_DOMAIN,
168 		    "Value contains digit not in base");
169 		break;
170 
171 	case UU_ERROR_SYSTEM:
172 		str = dgettext(TEXT_DOMAIN, "Underlying system error");
173 		break;
174 
175 	case UU_ERROR_UNKNOWN:
176 		str = dgettext(TEXT_DOMAIN, "Error status not known");
177 		break;
178 
179 	default:
180 		errno = ESRCH;
181 		str = NULL;
182 		break;
183 	}
184 	return (str);
185 }
186 
187 void
188 uu_panic(const char *format, ...)
189 {
190 	va_list args;
191 
192 	va_start(args, format);
193 
194 	(void) pthread_mutex_lock(&uu_panic_lock);
195 	if (uu_panic_thread == 0) {
196 		uu_panic_thread = pthread_self();
197 		uu_panic_format = format;
198 		va_copy(uu_panic_args, args);
199 	}
200 	(void) pthread_mutex_unlock(&uu_panic_lock);
201 
202 	(void) vfprintf(stderr, format, args);
203 
204 	if (uu_panic_thread == pthread_self())
205 		abort();
206 	else
207 		for (;;)
208 			(void) pause();
209 }
210 
211 int
212 assfail(const char *astring, const char *file, int line)
213 {
214 	__assert(astring, file, line);
215 	/*NOTREACHED*/
216 	return (0);
217 }
218 
219 static void
220 uu_lockup(void)
221 {
222 	(void) pthread_mutex_lock(&uu_panic_lock);
223 #if !defined(PTHREAD_ONCE_KEY_NP)
224 	(void) pthread_mutex_lock(&uu_key_lock);
225 #endif
226 	uu_avl_lockup();
227 	uu_list_lockup();
228 }
229 
230 static void
231 uu_release(void)
232 {
233 	(void) pthread_mutex_unlock(&uu_panic_lock);
234 #if !defined(PTHREAD_ONCE_KEY_NP)
235 	(void) pthread_mutex_unlock(&uu_key_lock);
236 #endif
237 	uu_avl_release();
238 	uu_list_release();
239 }
240 
241 static void
242 uu_release_child(void)
243 {
244 	uu_panic_format = NULL;
245 	uu_panic_thread = 0;
246 
247 	uu_release();
248 }
249 
250 #pragma init(uu_init)
251 static void
252 uu_init(void)
253 {
254 	(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
255 }
256