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 #include <assert.h> 29 #include <errno.h> 30 #include <libintl.h> 31 #include <pthread.h> 32 #include <stdarg.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/debug.h> 37 #include <thread.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 72 void 73 uu_set_error(uint_t code) 74 { 75 if (thr_main() != 0) { 76 _uu_main_error = code; 77 return; 78 } 79 #if defined(PTHREAD_ONCE_KEY_NP) 80 if (pthread_key_create_once_np(&uu_error_key, NULL) != 0) 81 uu_error_key_setup = -1; 82 else 83 uu_error_key_setup = 1; 84 #else /* PTHREAD_ONCE_KEY_NP */ 85 if (uu_error_key_setup == 0) { 86 (void) pthread_mutex_lock(&uu_key_lock); 87 if (uu_error_key_setup == 0) { 88 if (pthread_key_create(&uu_error_key, NULL) != 0) 89 uu_error_key_setup = -1; 90 else 91 uu_error_key_setup = 1; 92 } 93 (void) pthread_mutex_unlock(&uu_key_lock); 94 } 95 #endif /* PTHREAD_ONCE_KEY_NP */ 96 if (uu_error_key_setup > 0) 97 (void) pthread_setspecific(uu_error_key, 98 (void *)(uintptr_t)code); 99 } 100 101 uint32_t 102 uu_error(void) 103 { 104 if (thr_main() != 0) 105 return (_uu_main_error); 106 107 if (uu_error_key_setup < 0) /* can't happen? */ 108 return (UU_ERROR_UNKNOWN); 109 110 /* 111 * Because UU_ERROR_NONE == 0, if uu_set_error() was 112 * never called, then this will return UU_ERROR_NONE: 113 */ 114 return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key)); 115 } 116 117 const char * 118 uu_strerror(uint32_t code) 119 { 120 const char *str; 121 122 switch (code) { 123 case UU_ERROR_NONE: 124 str = dgettext(TEXT_DOMAIN, "No error"); 125 break; 126 127 case UU_ERROR_INVALID_ARGUMENT: 128 str = dgettext(TEXT_DOMAIN, "Invalid argument"); 129 break; 130 131 case UU_ERROR_UNKNOWN_FLAG: 132 str = dgettext(TEXT_DOMAIN, "Unknown flag passed"); 133 break; 134 135 case UU_ERROR_NO_MEMORY: 136 str = dgettext(TEXT_DOMAIN, "Out of memory"); 137 break; 138 139 case UU_ERROR_CALLBACK_FAILED: 140 str = dgettext(TEXT_DOMAIN, "Callback-initiated failure"); 141 break; 142 143 case UU_ERROR_NOT_SUPPORTED: 144 str = dgettext(TEXT_DOMAIN, "Operation not supported"); 145 break; 146 147 case UU_ERROR_EMPTY: 148 str = dgettext(TEXT_DOMAIN, "No value provided"); 149 break; 150 151 case UU_ERROR_UNDERFLOW: 152 str = dgettext(TEXT_DOMAIN, "Value too small"); 153 break; 154 155 case UU_ERROR_OVERFLOW: 156 str = dgettext(TEXT_DOMAIN, "Value too large"); 157 break; 158 159 case UU_ERROR_INVALID_CHAR: 160 str = dgettext(TEXT_DOMAIN, 161 "Value contains unexpected character"); 162 break; 163 164 case UU_ERROR_INVALID_DIGIT: 165 str = dgettext(TEXT_DOMAIN, 166 "Value contains digit not in base"); 167 break; 168 169 case UU_ERROR_SYSTEM: 170 str = dgettext(TEXT_DOMAIN, "Underlying system error"); 171 break; 172 173 case UU_ERROR_UNKNOWN: 174 str = dgettext(TEXT_DOMAIN, "Error status not known"); 175 break; 176 177 default: 178 errno = ESRCH; 179 str = NULL; 180 break; 181 } 182 return (str); 183 } 184 185 void 186 uu_panic(const char *format, ...) 187 { 188 va_list args; 189 190 va_start(args, format); 191 192 (void) pthread_mutex_lock(&uu_panic_lock); 193 if (uu_panic_thread == 0) { 194 uu_panic_thread = pthread_self(); 195 uu_panic_format = format; 196 va_copy(uu_panic_args, args); 197 } 198 (void) pthread_mutex_unlock(&uu_panic_lock); 199 200 (void) vfprintf(stderr, format, args); 201 202 if (uu_panic_thread == pthread_self()) 203 abort(); 204 else 205 for (;;) 206 (void) pause(); 207 } 208 209 int 210 assfail(const char *astring, const char *file, int line) 211 { 212 __assert(astring, file, line); 213 /*NOTREACHED*/ 214 return (0); 215 } 216 217 static void 218 uu_lockup(void) 219 { 220 (void) pthread_mutex_lock(&uu_panic_lock); 221 #if !defined(PTHREAD_ONCE_KEY_NP) 222 (void) pthread_mutex_lock(&uu_key_lock); 223 #endif 224 uu_avl_lockup(); 225 uu_list_lockup(); 226 } 227 228 static void 229 uu_release(void) 230 { 231 (void) pthread_mutex_unlock(&uu_panic_lock); 232 #if !defined(PTHREAD_ONCE_KEY_NP) 233 (void) pthread_mutex_unlock(&uu_key_lock); 234 #endif 235 uu_avl_release(); 236 uu_list_release(); 237 } 238 239 static void 240 uu_release_child(void) 241 { 242 uu_panic_format = NULL; 243 uu_panic_thread = 0; 244 245 uu_release(); 246 } 247 248 #pragma init(uu_init) 249 static void 250 uu_init(void) 251 { 252 (void) pthread_atfork(uu_lockup, uu_release, uu_release_child); 253 } 254 255 /* 256 * Dump a block of memory in hex+ascii, for debugging 257 */ 258 void 259 uu_dump(FILE *out, const char *prefix, const void *buf, size_t len) 260 { 261 const unsigned char *p = buf; 262 int i; 263 264 for (i = 0; i < len; i += 16) { 265 int j; 266 267 (void) fprintf(out, "%s", prefix); 268 for (j = 0; j < 16 && i + j < len; j++) { 269 (void) fprintf(out, "%2.2x ", p[i + j]); 270 } 271 for (; j < 16; j++) { 272 (void) fprintf(out, " "); 273 } 274 for (j = 0; j < 16 && i + j < len; j++) { 275 (void) fprintf(out, "%c", 276 isprint(p[i + j]) ? p[i + j] : '.'); 277 } 278 (void) fprintf(out, "\n"); 279 } 280 } 281