1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5168404Spjd * Common Development and Distribution License (the "License").
6168404Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd
22168404Spjd/*
23219089Spjd * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24168404Spjd */
25168404Spjd
26168404Spjd#include "libuutil_common.h"
27168404Spjd
28243674Smm#define HAVE_ASSFAIL	1
29243674Smm
30168404Spjd#include <assert.h>
31168404Spjd#include <errno.h>
32168404Spjd#include <libintl.h>
33168404Spjd#include <pthread.h>
34168404Spjd#include <stdarg.h>
35168404Spjd#include <stdio.h>
36168404Spjd#include <stdlib.h>
37168404Spjd#include <string.h>
38168404Spjd#include <sys/debug.h>
39168404Spjd#include <thread.h>
40168404Spjd#include <unistd.h>
41219089Spjd#include <ctype.h>
42168404Spjd
43168404Spjd#if !defined(TEXT_DOMAIN)
44168404Spjd#define	TEXT_DOMAIN "SYS_TEST"
45168404Spjd#endif
46168404Spjd
47168404Spjd/*
48168404Spjd * All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
49168404Spjd * is here to enable the building of a native version of
50168404Spjd * libuutil.so when the build machine has not yet been upgraded
51168404Spjd * to a version of libc that provides pthread_key_create_once_np().
52168404Spjd * It should all be deleted when solaris_nevada ships.
53168404Spjd * The code is not MT-safe in a relaxed memory model.
54168404Spjd */
55168404Spjd
56168404Spjd#if defined(PTHREAD_ONCE_KEY_NP)
57168404Spjdstatic pthread_key_t	uu_error_key = PTHREAD_ONCE_KEY_NP;
58168404Spjd#else	/* PTHREAD_ONCE_KEY_NP */
59168404Spjdstatic pthread_key_t	uu_error_key = 0;
60168404Spjdstatic pthread_mutex_t	uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
61168404Spjd#endif	/* PTHREAD_ONCE_KEY_NP */
62168404Spjd
63168404Spjdstatic int		uu_error_key_setup = 0;
64168404Spjd
65168404Spjdstatic pthread_mutex_t	uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
66168404Spjd/* LINTED static unused */
67168404Spjdstatic const char	*uu_panic_format;
68168404Spjd/* LINTED static unused */
69168404Spjdstatic va_list		uu_panic_args;
70168404Spjdstatic pthread_t	uu_panic_thread;
71168404Spjd
72168404Spjdstatic uint32_t		_uu_main_error;
73168404Spjd
74168404Spjdvoid
75168404Spjduu_set_error(uint_t code)
76168404Spjd{
77168404Spjd
78168404Spjd#if defined(PTHREAD_ONCE_KEY_NP)
79168404Spjd	if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
80168404Spjd		uu_error_key_setup = -1;
81168404Spjd	else
82168404Spjd		uu_error_key_setup = 1;
83168404Spjd#else	/* PTHREAD_ONCE_KEY_NP */
84168404Spjd	if (uu_error_key_setup == 0) {
85168404Spjd		(void) pthread_mutex_lock(&uu_key_lock);
86168404Spjd		if (uu_error_key_setup == 0) {
87168404Spjd			if (pthread_key_create(&uu_error_key, NULL) != 0)
88168404Spjd				uu_error_key_setup = -1;
89168404Spjd			else
90168404Spjd				uu_error_key_setup = 1;
91168404Spjd		}
92168404Spjd		(void) pthread_mutex_unlock(&uu_key_lock);
93168404Spjd	}
94168404Spjd#endif	/* PTHREAD_ONCE_KEY_NP */
95168404Spjd	if (uu_error_key_setup > 0)
96168404Spjd		(void) pthread_setspecific(uu_error_key,
97168404Spjd		    (void *)(uintptr_t)code);
98168404Spjd}
99168404Spjd
100168404Spjduint32_t
101168404Spjduu_error(void)
102168404Spjd{
103168404Spjd
104168404Spjd	if (uu_error_key_setup < 0)	/* can't happen? */
105168404Spjd		return (UU_ERROR_UNKNOWN);
106168404Spjd
107168404Spjd	/*
108168404Spjd	 * Because UU_ERROR_NONE == 0, if uu_set_error() was
109168404Spjd	 * never called, then this will return UU_ERROR_NONE:
110168404Spjd	 */
111168404Spjd	return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
112168404Spjd}
113168404Spjd
114168404Spjdconst char *
115168404Spjduu_strerror(uint32_t code)
116168404Spjd{
117168404Spjd	const char *str;
118168404Spjd
119168404Spjd	switch (code) {
120168404Spjd	case UU_ERROR_NONE:
121168404Spjd		str = dgettext(TEXT_DOMAIN, "No error");
122168404Spjd		break;
123168404Spjd
124168404Spjd	case UU_ERROR_INVALID_ARGUMENT:
125168404Spjd		str = dgettext(TEXT_DOMAIN, "Invalid argument");
126168404Spjd		break;
127168404Spjd
128168404Spjd	case UU_ERROR_UNKNOWN_FLAG:
129168404Spjd		str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
130168404Spjd		break;
131168404Spjd
132168404Spjd	case UU_ERROR_NO_MEMORY:
133168404Spjd		str = dgettext(TEXT_DOMAIN, "Out of memory");
134168404Spjd		break;
135168404Spjd
136168404Spjd	case UU_ERROR_CALLBACK_FAILED:
137168404Spjd		str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
138168404Spjd		break;
139168404Spjd
140168404Spjd	case UU_ERROR_NOT_SUPPORTED:
141168404Spjd		str = dgettext(TEXT_DOMAIN, "Operation not supported");
142168404Spjd		break;
143168404Spjd
144168404Spjd	case UU_ERROR_EMPTY:
145168404Spjd		str = dgettext(TEXT_DOMAIN, "No value provided");
146168404Spjd		break;
147168404Spjd
148168404Spjd	case UU_ERROR_UNDERFLOW:
149168404Spjd		str = dgettext(TEXT_DOMAIN, "Value too small");
150168404Spjd		break;
151168404Spjd
152168404Spjd	case UU_ERROR_OVERFLOW:
153168404Spjd		str = dgettext(TEXT_DOMAIN, "Value too large");
154168404Spjd		break;
155168404Spjd
156168404Spjd	case UU_ERROR_INVALID_CHAR:
157168404Spjd		str = dgettext(TEXT_DOMAIN,
158168404Spjd		    "Value contains unexpected character");
159168404Spjd		break;
160168404Spjd
161168404Spjd	case UU_ERROR_INVALID_DIGIT:
162168404Spjd		str = dgettext(TEXT_DOMAIN,
163168404Spjd		    "Value contains digit not in base");
164168404Spjd		break;
165168404Spjd
166168404Spjd	case UU_ERROR_SYSTEM:
167168404Spjd		str = dgettext(TEXT_DOMAIN, "Underlying system error");
168168404Spjd		break;
169168404Spjd
170168404Spjd	case UU_ERROR_UNKNOWN:
171168404Spjd		str = dgettext(TEXT_DOMAIN, "Error status not known");
172168404Spjd		break;
173168404Spjd
174168404Spjd	default:
175168404Spjd		errno = ESRCH;
176168404Spjd		str = NULL;
177168404Spjd		break;
178168404Spjd	}
179168404Spjd	return (str);
180168404Spjd}
181168404Spjd
182168404Spjdvoid
183168404Spjduu_panic(const char *format, ...)
184168404Spjd{
185168404Spjd	va_list args;
186168404Spjd
187168404Spjd	va_start(args, format);
188168404Spjd
189168404Spjd	(void) pthread_mutex_lock(&uu_panic_lock);
190168404Spjd	if (uu_panic_thread == 0) {
191168404Spjd		uu_panic_thread = pthread_self();
192168404Spjd		uu_panic_format = format;
193168404Spjd		va_copy(uu_panic_args, args);
194168404Spjd	}
195168404Spjd	(void) pthread_mutex_unlock(&uu_panic_lock);
196168404Spjd
197168404Spjd	(void) vfprintf(stderr, format, args);
198168404Spjd
199168404Spjd	if (uu_panic_thread == pthread_self())
200168404Spjd		abort();
201168404Spjd	else
202168404Spjd		for (;;)
203168404Spjd			(void) pause();
204168404Spjd}
205168404Spjd
206168404Spjdint
207168404Spjdassfail(const char *astring, const char *file, int line)
208168404Spjd{
209168404Spjd	__assert(astring, file, line);
210168404Spjd	/*NOTREACHED*/
211168404Spjd	return (0);
212168404Spjd}
213168404Spjd
214168404Spjdstatic void
215168404Spjduu_lockup(void)
216168404Spjd{
217168404Spjd	(void) pthread_mutex_lock(&uu_panic_lock);
218168404Spjd#if !defined(PTHREAD_ONCE_KEY_NP)
219168404Spjd	(void) pthread_mutex_lock(&uu_key_lock);
220168404Spjd#endif
221168404Spjd	uu_avl_lockup();
222168404Spjd	uu_list_lockup();
223168404Spjd}
224168404Spjd
225168404Spjdstatic void
226168404Spjduu_release(void)
227168404Spjd{
228168404Spjd	(void) pthread_mutex_unlock(&uu_panic_lock);
229168404Spjd#if !defined(PTHREAD_ONCE_KEY_NP)
230168404Spjd	(void) pthread_mutex_unlock(&uu_key_lock);
231168404Spjd#endif
232168404Spjd	uu_avl_release();
233168404Spjd	uu_list_release();
234168404Spjd}
235168404Spjd
236168404Spjdstatic void
237168404Spjduu_release_child(void)
238168404Spjd{
239168404Spjd	uu_panic_format = NULL;
240168404Spjd	uu_panic_thread = 0;
241168404Spjd
242168404Spjd	uu_release();
243168404Spjd}
244168404Spjd
245168404Spjd#pragma init(uu_init)
246168404Spjdstatic void
247168404Spjduu_init(void)
248168404Spjd{
249168404Spjd	(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
250168404Spjd}
251219089Spjd
252219089Spjd/*
253219089Spjd * Dump a block of memory in hex+ascii, for debugging
254219089Spjd */
255219089Spjdvoid
256219089Spjduu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
257219089Spjd{
258219089Spjd	const unsigned char *p = buf;
259219089Spjd	int i;
260219089Spjd
261219089Spjd	for (i = 0; i < len; i += 16) {
262219089Spjd		int j;
263219089Spjd
264219089Spjd		(void) fprintf(out, "%s", prefix);
265219089Spjd		for (j = 0; j < 16 && i + j < len; j++) {
266219089Spjd			(void) fprintf(out, "%2.2x ", p[i + j]);
267219089Spjd		}
268219089Spjd		for (; j < 16; j++) {
269219089Spjd			(void) fprintf(out, "   ");
270219089Spjd		}
271219089Spjd		for (j = 0; j < 16 && i + j < len; j++) {
272219089Spjd			(void) fprintf(out, "%c",
273219089Spjd			    isprint(p[i + j]) ? p[i + j] : '.');
274219089Spjd		}
275219089Spjd		(void) fprintf(out, "\n");
276219089Spjd	}
277219089Spjd}
278