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 uu_release(); 243 } 244 245 #pragma init(uu_init) 246 __attribute__((constructor)) 247 static void 248 uu_init(void) 249 { 250 (void) pthread_atfork(uu_lockup, uu_release, uu_release_child); 251 } 252 253 /* 254 * Dump a block of memory in hex+ascii, for debugging 255 */ 256 void 257 uu_dump(FILE *out, const char *prefix, const void *buf, size_t len) 258 { 259 const unsigned char *p = buf; 260 int i; 261 262 for (i = 0; i < len; i += 16) { 263 int j; 264 265 (void) fprintf(out, "%s", prefix); 266 for (j = 0; j < 16 && i + j < len; j++) { 267 (void) fprintf(out, "%2.2x ", p[i + j]); 268 } 269 for (; j < 16; j++) { 270 (void) fprintf(out, " "); 271 } 272 for (j = 0; j < 16 && i + j < len; j++) { 273 (void) fprintf(out, "%c", 274 isprint(p[i + j]) ? p[i + j] : '.'); 275 } 276 (void) fprintf(out, "\n"); 277 } 278 } 279