xref: /freebsd/sys/contrib/openzfs/lib/libuutil/uu_misc.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
25  */
26 
27 #include "libuutil_common.h"
28 
29 #include <assert.h>
30 #include <errno.h>
31 #include <libintl.h>
32 #include <pthread.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/debug.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 static __thread int	_uu_main_thread = 0;
72 
73 void
uu_set_error(uint_t code)74 uu_set_error(uint_t code)
75 {
76 	if (_uu_main_thread) {
77 		_uu_main_error = code;
78 		return;
79 	}
80 #if defined(PTHREAD_ONCE_KEY_NP)
81 	if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
82 		uu_error_key_setup = -1;
83 	else
84 		uu_error_key_setup = 1;
85 #else	/* PTHREAD_ONCE_KEY_NP */
86 	if (uu_error_key_setup == 0) {
87 		(void) pthread_mutex_lock(&uu_key_lock);
88 		if (uu_error_key_setup == 0) {
89 			if (pthread_key_create(&uu_error_key, NULL) != 0)
90 				uu_error_key_setup = -1;
91 			else
92 				uu_error_key_setup = 1;
93 		}
94 		(void) pthread_mutex_unlock(&uu_key_lock);
95 	}
96 #endif	/* PTHREAD_ONCE_KEY_NP */
97 	if (uu_error_key_setup > 0)
98 		(void) pthread_setspecific(uu_error_key,
99 		    (void *)(uintptr_t)code);
100 }
101 
102 uint32_t
uu_error(void)103 uu_error(void)
104 {
105 	if (_uu_main_thread)
106 		return (_uu_main_error);
107 
108 	if (uu_error_key_setup < 0)	/* can't happen? */
109 		return (UU_ERROR_UNKNOWN);
110 
111 	/*
112 	 * Because UU_ERROR_NONE == 0, if uu_set_error() was
113 	 * never called, then this will return UU_ERROR_NONE:
114 	 */
115 	return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
116 }
117 
118 const char *
uu_strerror(uint32_t code)119 uu_strerror(uint32_t code)
120 {
121 	const char *str;
122 
123 	switch (code) {
124 	case UU_ERROR_NONE:
125 		str = dgettext(TEXT_DOMAIN, "No error");
126 		break;
127 
128 	case UU_ERROR_INVALID_ARGUMENT:
129 		str = dgettext(TEXT_DOMAIN, "Invalid argument");
130 		break;
131 
132 	case UU_ERROR_UNKNOWN_FLAG:
133 		str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
134 		break;
135 
136 	case UU_ERROR_NO_MEMORY:
137 		str = dgettext(TEXT_DOMAIN, "Out of memory");
138 		break;
139 
140 	case UU_ERROR_CALLBACK_FAILED:
141 		str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
142 		break;
143 
144 	case UU_ERROR_NOT_SUPPORTED:
145 		str = dgettext(TEXT_DOMAIN, "Operation not supported");
146 		break;
147 
148 	case UU_ERROR_EMPTY:
149 		str = dgettext(TEXT_DOMAIN, "No value provided");
150 		break;
151 
152 	case UU_ERROR_UNDERFLOW:
153 		str = dgettext(TEXT_DOMAIN, "Value too small");
154 		break;
155 
156 	case UU_ERROR_OVERFLOW:
157 		str = dgettext(TEXT_DOMAIN, "Value too large");
158 		break;
159 
160 	case UU_ERROR_INVALID_CHAR:
161 		str = dgettext(TEXT_DOMAIN,
162 		    "Value contains unexpected character");
163 		break;
164 
165 	case UU_ERROR_INVALID_DIGIT:
166 		str = dgettext(TEXT_DOMAIN,
167 		    "Value contains digit not in base");
168 		break;
169 
170 	case UU_ERROR_SYSTEM:
171 		str = dgettext(TEXT_DOMAIN, "Underlying system error");
172 		break;
173 
174 	case UU_ERROR_UNKNOWN:
175 		str = dgettext(TEXT_DOMAIN, "Error status not known");
176 		break;
177 
178 	default:
179 		errno = ESRCH;
180 		str = NULL;
181 		break;
182 	}
183 	return (str);
184 }
185 
186 void
uu_panic(const char * format,...)187 uu_panic(const char *format, ...)
188 {
189 	va_list args;
190 
191 	va_start(args, format);
192 
193 	(void) pthread_mutex_lock(&uu_panic_lock);
194 	if (uu_panic_thread == 0) {
195 		uu_panic_thread = pthread_self();
196 		uu_panic_format = format;
197 		va_copy(uu_panic_args, args);
198 	}
199 	(void) pthread_mutex_unlock(&uu_panic_lock);
200 
201 	(void) vfprintf(stderr, format, args);
202 
203 	va_end(args);
204 
205 	if (uu_panic_thread == pthread_self())
206 		abort();
207 	else
208 		for (;;)
209 			(void) pause();
210 }
211 
212 static void
uu_lockup(void)213 uu_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 
223 static void
uu_release(void)224 uu_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 
234 static void
uu_release_child(void)235 uu_release_child(void)
236 {
237 	uu_panic_format = NULL;
238 	uu_panic_thread = 0;
239 
240 	uu_release();
241 }
242 
243 #ifdef __GNUC__
244 static void
245 uu_init(void) __attribute__((constructor));
246 #else
247 #pragma init(uu_init)
248 #endif
249 
250 static void
uu_init(void)251 uu_init(void)
252 {
253 	_uu_main_thread = 1;
254 	(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
255 }
256