1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 25 */ 26 27 #include "libuutil_common.h" 28 29 #include <assert.h> 30 #include <errno.h> 31 #include <libintl.h> 32 #include <pthread.h> 33 #include <stdarg.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sys/debug.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 static __thread int _uu_main_thread = 0; 72 73 void 74 uu_set_error(uint_t code) 75 { 76 if (_uu_main_thread) { 77 _uu_main_error = code; 78 return; 79 } 80 #if defined(PTHREAD_ONCE_KEY_NP) 81 if (pthread_key_create_once_np(&uu_error_key, NULL) != 0) 82 uu_error_key_setup = -1; 83 else 84 uu_error_key_setup = 1; 85 #else /* PTHREAD_ONCE_KEY_NP */ 86 if (uu_error_key_setup == 0) { 87 (void) pthread_mutex_lock(&uu_key_lock); 88 if (uu_error_key_setup == 0) { 89 if (pthread_key_create(&uu_error_key, NULL) != 0) 90 uu_error_key_setup = -1; 91 else 92 uu_error_key_setup = 1; 93 } 94 (void) pthread_mutex_unlock(&uu_key_lock); 95 } 96 #endif /* PTHREAD_ONCE_KEY_NP */ 97 if (uu_error_key_setup > 0) 98 (void) pthread_setspecific(uu_error_key, 99 (void *)(uintptr_t)code); 100 } 101 102 uint32_t 103 uu_error(void) 104 { 105 if (_uu_main_thread) 106 return (_uu_main_error); 107 108 if (uu_error_key_setup < 0) /* can't happen? */ 109 return (UU_ERROR_UNKNOWN); 110 111 /* 112 * Because UU_ERROR_NONE == 0, if uu_set_error() was 113 * never called, then this will return UU_ERROR_NONE: 114 */ 115 return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key)); 116 } 117 118 const char * 119 uu_strerror(uint32_t code) 120 { 121 const char *str; 122 123 switch (code) { 124 case UU_ERROR_NONE: 125 str = dgettext(TEXT_DOMAIN, "No error"); 126 break; 127 128 case UU_ERROR_INVALID_ARGUMENT: 129 str = dgettext(TEXT_DOMAIN, "Invalid argument"); 130 break; 131 132 case UU_ERROR_UNKNOWN_FLAG: 133 str = dgettext(TEXT_DOMAIN, "Unknown flag passed"); 134 break; 135 136 case UU_ERROR_NO_MEMORY: 137 str = dgettext(TEXT_DOMAIN, "Out of memory"); 138 break; 139 140 case UU_ERROR_CALLBACK_FAILED: 141 str = dgettext(TEXT_DOMAIN, "Callback-initiated failure"); 142 break; 143 144 case UU_ERROR_NOT_SUPPORTED: 145 str = dgettext(TEXT_DOMAIN, "Operation not supported"); 146 break; 147 148 case UU_ERROR_EMPTY: 149 str = dgettext(TEXT_DOMAIN, "No value provided"); 150 break; 151 152 case UU_ERROR_UNDERFLOW: 153 str = dgettext(TEXT_DOMAIN, "Value too small"); 154 break; 155 156 case UU_ERROR_OVERFLOW: 157 str = dgettext(TEXT_DOMAIN, "Value too large"); 158 break; 159 160 case UU_ERROR_INVALID_CHAR: 161 str = dgettext(TEXT_DOMAIN, 162 "Value contains unexpected character"); 163 break; 164 165 case UU_ERROR_INVALID_DIGIT: 166 str = dgettext(TEXT_DOMAIN, 167 "Value contains digit not in base"); 168 break; 169 170 case UU_ERROR_SYSTEM: 171 str = dgettext(TEXT_DOMAIN, "Underlying system error"); 172 break; 173 174 case UU_ERROR_UNKNOWN: 175 str = dgettext(TEXT_DOMAIN, "Error status not known"); 176 break; 177 178 default: 179 errno = ESRCH; 180 str = NULL; 181 break; 182 } 183 return (str); 184 } 185 186 void 187 uu_panic(const char *format, ...) 188 { 189 va_list args; 190 191 va_start(args, format); 192 193 (void) pthread_mutex_lock(&uu_panic_lock); 194 if (uu_panic_thread == 0) { 195 uu_panic_thread = pthread_self(); 196 uu_panic_format = format; 197 va_copy(uu_panic_args, args); 198 } 199 (void) pthread_mutex_unlock(&uu_panic_lock); 200 201 (void) vfprintf(stderr, format, args); 202 203 va_end(args); 204 205 if (uu_panic_thread == pthread_self()) 206 abort(); 207 else 208 for (;;) 209 (void) pause(); 210 } 211 212 static void 213 uu_lockup(void) 214 { 215 (void) pthread_mutex_lock(&uu_panic_lock); 216 #if !defined(PTHREAD_ONCE_KEY_NP) 217 (void) pthread_mutex_lock(&uu_key_lock); 218 #endif 219 uu_avl_lockup(); 220 uu_list_lockup(); 221 } 222 223 static void 224 uu_release(void) 225 { 226 (void) pthread_mutex_unlock(&uu_panic_lock); 227 #if !defined(PTHREAD_ONCE_KEY_NP) 228 (void) pthread_mutex_unlock(&uu_key_lock); 229 #endif 230 uu_avl_release(); 231 uu_list_release(); 232 } 233 234 static void 235 uu_release_child(void) 236 { 237 uu_panic_format = NULL; 238 uu_panic_thread = 0; 239 240 uu_release(); 241 } 242 243 #ifdef __GNUC__ 244 static void 245 uu_init(void) __attribute__((constructor)); 246 #else 247 #pragma init(uu_init) 248 #endif 249 250 static void 251 uu_init(void) 252 { 253 _uu_main_thread = 1; 254 (void) pthread_atfork(uu_lockup, uu_release, uu_release_child); 255 } 256