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