Home | History | Annotate | Line # | Download | only in common
      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
     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
    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 *
    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
    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
    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
    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
    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
    237 uu_release_child(void)
    238 {
    239 	uu_panic_format = NULL;
    240 	uu_panic_thread = 0;
    241 
    242 	(void) pthread_mutex_init(&uu_panic_lock, NULL);
    243 #if !defined(PTHREAD_ONCE_KEY_NP)
    244 	(void) pthread_mutex_init(&uu_key_lock, NULL);
    245 #endif
    246 	uu_avl_release_child();
    247 	uu_list_release_child();
    248 }
    249 
    250 #pragma init(uu_init)
    251 __attribute__((constructor))
    252 static void
    253 uu_init(void)
    254 {
    255 	(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
    256 }
    257 
    258 /*
    259  * Dump a block of memory in hex+ascii, for debugging
    260  */
    261 void
    262 uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
    263 {
    264 	const unsigned char *p = buf;
    265 	int i;
    266 
    267 	for (i = 0; i < len; i += 16) {
    268 		int j;
    269 
    270 		(void) fprintf(out, "%s", prefix);
    271 		for (j = 0; j < 16 && i + j < len; j++) {
    272 			(void) fprintf(out, "%2.2x ", p[i + j]);
    273 		}
    274 		for (; j < 16; j++) {
    275 			(void) fprintf(out, "   ");
    276 		}
    277 		for (j = 0; j < 16 && i + j < len; j++) {
    278 			(void) fprintf(out, "%c",
    279 			    isprint(p[i + j]) ? p[i + j] : '.');
    280 		}
    281 		(void) fprintf(out, "\n");
    282 	}
    283 }
    284