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