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