Path: blob/main/sys/contrib/openzfs/lib/libuutil/uu_misc.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* 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.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.24*/2526#include "libuutil_common.h"2728#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 <unistd.h>38#include <ctype.h>3940#if !defined(TEXT_DOMAIN)41#define TEXT_DOMAIN "SYS_TEST"42#endif4344/*45* All of the old code under !defined(PTHREAD_ONCE_KEY_NP)46* is here to enable the building of a native version of47* libuutil.so when the build machine has not yet been upgraded48* to a version of libc that provides pthread_key_create_once_np().49* It should all be deleted when solaris_nevada ships.50* The code is not MT-safe in a relaxed memory model.51*/5253#if defined(PTHREAD_ONCE_KEY_NP)54static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP;55#else /* PTHREAD_ONCE_KEY_NP */56static pthread_key_t uu_error_key = 0;57static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;58#endif /* PTHREAD_ONCE_KEY_NP */5960static int uu_error_key_setup = 0;6162static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;63/* LINTED static unused */64static const char *uu_panic_format;65/* LINTED static unused */66static va_list uu_panic_args;67static pthread_t uu_panic_thread;6869static uint32_t _uu_main_error;70static __thread int _uu_main_thread = 0;7172void73uu_set_error(uint_t code)74{75if (_uu_main_thread) {76_uu_main_error = code;77return;78}79#if defined(PTHREAD_ONCE_KEY_NP)80if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)81uu_error_key_setup = -1;82else83uu_error_key_setup = 1;84#else /* PTHREAD_ONCE_KEY_NP */85if (uu_error_key_setup == 0) {86(void) pthread_mutex_lock(&uu_key_lock);87if (uu_error_key_setup == 0) {88if (pthread_key_create(&uu_error_key, NULL) != 0)89uu_error_key_setup = -1;90else91uu_error_key_setup = 1;92}93(void) pthread_mutex_unlock(&uu_key_lock);94}95#endif /* PTHREAD_ONCE_KEY_NP */96if (uu_error_key_setup > 0)97(void) pthread_setspecific(uu_error_key,98(void *)(uintptr_t)code);99}100101uint32_t102uu_error(void)103{104if (_uu_main_thread)105return (_uu_main_error);106107if (uu_error_key_setup < 0) /* can't happen? */108return (UU_ERROR_UNKNOWN);109110/*111* Because UU_ERROR_NONE == 0, if uu_set_error() was112* never called, then this will return UU_ERROR_NONE:113*/114return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));115}116117const char *118uu_strerror(uint32_t code)119{120const char *str;121122switch (code) {123case UU_ERROR_NONE:124str = dgettext(TEXT_DOMAIN, "No error");125break;126127case UU_ERROR_INVALID_ARGUMENT:128str = dgettext(TEXT_DOMAIN, "Invalid argument");129break;130131case UU_ERROR_UNKNOWN_FLAG:132str = dgettext(TEXT_DOMAIN, "Unknown flag passed");133break;134135case UU_ERROR_NO_MEMORY:136str = dgettext(TEXT_DOMAIN, "Out of memory");137break;138139case UU_ERROR_CALLBACK_FAILED:140str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");141break;142143case UU_ERROR_NOT_SUPPORTED:144str = dgettext(TEXT_DOMAIN, "Operation not supported");145break;146147case UU_ERROR_EMPTY:148str = dgettext(TEXT_DOMAIN, "No value provided");149break;150151case UU_ERROR_UNDERFLOW:152str = dgettext(TEXT_DOMAIN, "Value too small");153break;154155case UU_ERROR_OVERFLOW:156str = dgettext(TEXT_DOMAIN, "Value too large");157break;158159case UU_ERROR_INVALID_CHAR:160str = dgettext(TEXT_DOMAIN,161"Value contains unexpected character");162break;163164case UU_ERROR_INVALID_DIGIT:165str = dgettext(TEXT_DOMAIN,166"Value contains digit not in base");167break;168169case UU_ERROR_SYSTEM:170str = dgettext(TEXT_DOMAIN, "Underlying system error");171break;172173case UU_ERROR_UNKNOWN:174str = dgettext(TEXT_DOMAIN, "Error status not known");175break;176177default:178errno = ESRCH;179str = NULL;180break;181}182return (str);183}184185void186uu_panic(const char *format, ...)187{188va_list args;189190va_start(args, format);191192(void) pthread_mutex_lock(&uu_panic_lock);193if (uu_panic_thread == 0) {194uu_panic_thread = pthread_self();195uu_panic_format = format;196va_copy(uu_panic_args, args);197}198(void) pthread_mutex_unlock(&uu_panic_lock);199200(void) vfprintf(stderr, format, args);201202va_end(args);203204if (uu_panic_thread == pthread_self())205abort();206else207for (;;)208(void) pause();209}210211static void212uu_lockup(void)213{214(void) pthread_mutex_lock(&uu_panic_lock);215#if !defined(PTHREAD_ONCE_KEY_NP)216(void) pthread_mutex_lock(&uu_key_lock);217#endif218uu_avl_lockup();219uu_list_lockup();220}221222static void223uu_release(void)224{225(void) pthread_mutex_unlock(&uu_panic_lock);226#if !defined(PTHREAD_ONCE_KEY_NP)227(void) pthread_mutex_unlock(&uu_key_lock);228#endif229uu_avl_release();230uu_list_release();231}232233static void234uu_release_child(void)235{236uu_panic_format = NULL;237uu_panic_thread = 0;238239uu_release();240}241242#ifdef __GNUC__243static void244uu_init(void) __attribute__((constructor));245#else246#pragma init(uu_init)247#endif248249static void250uu_init(void)251{252_uu_main_thread = 1;253(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);254}255256257