2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include "libuutil_common.h"
2N/A
2N/A#include <assert.h>
2N/A#include <errno.h>
2N/A#include <libintl.h>
2N/A#include <pthread.h>
2N/A#include <stdarg.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <sys/debug.h>
2N/A#include <thread.h>
2N/A#include <unistd.h>
2N/A#include <ctype.h>
2N/A
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A/*
2N/A * All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
2N/A * is here to enable the building of a native version of
2N/A * libuutil.so when the build machine has not yet been upgraded
2N/A * to a version of libc that provides pthread_key_create_once_np().
2N/A * It should all be deleted when solaris_nevada ships.
2N/A * The code is not MT-safe in a relaxed memory model.
2N/A */
2N/A
2N/A#if defined(PTHREAD_ONCE_KEY_NP)
2N/Astatic pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP;
2N/A#else /* PTHREAD_ONCE_KEY_NP */
2N/Astatic pthread_key_t uu_error_key = 0;
2N/Astatic pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
2N/A#endif /* PTHREAD_ONCE_KEY_NP */
2N/A
2N/Astatic int uu_error_key_setup = 0;
2N/A
2N/Astatic pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
2N/A/* LINTED static unused */
2N/Astatic const char *uu_panic_format;
2N/A/* LINTED static unused */
2N/Astatic va_list uu_panic_args;
2N/Astatic pthread_t uu_panic_thread;
2N/A
2N/Astatic uint32_t _uu_main_error;
2N/A
2N/Avoid
2N/Auu_set_error(uint_t code)
2N/A{
2N/A if (thr_main() != 0) {
2N/A _uu_main_error = code;
2N/A return;
2N/A }
2N/A#if defined(PTHREAD_ONCE_KEY_NP)
2N/A if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
2N/A uu_error_key_setup = -1;
2N/A else
2N/A uu_error_key_setup = 1;
2N/A#else /* PTHREAD_ONCE_KEY_NP */
2N/A if (uu_error_key_setup == 0) {
2N/A (void) pthread_mutex_lock(&uu_key_lock);
2N/A if (uu_error_key_setup == 0) {
2N/A if (pthread_key_create(&uu_error_key, NULL) != 0)
2N/A uu_error_key_setup = -1;
2N/A else
2N/A uu_error_key_setup = 1;
2N/A }
2N/A (void) pthread_mutex_unlock(&uu_key_lock);
2N/A }
2N/A#endif /* PTHREAD_ONCE_KEY_NP */
2N/A if (uu_error_key_setup > 0)
2N/A (void) pthread_setspecific(uu_error_key,
2N/A (void *)(uintptr_t)code);
2N/A}
2N/A
2N/Auint32_t
2N/Auu_error(void)
2N/A{
2N/A if (thr_main() != 0)
2N/A return (_uu_main_error);
2N/A
2N/A if (uu_error_key_setup < 0) /* can't happen? */
2N/A return (UU_ERROR_UNKNOWN);
2N/A
2N/A /*
2N/A * Because UU_ERROR_NONE == 0, if uu_set_error() was
2N/A * never called, then this will return UU_ERROR_NONE:
2N/A */
2N/A return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
2N/A}
2N/A
2N/Aconst char *
2N/Auu_strerror(uint32_t code)
2N/A{
2N/A const char *str;
2N/A
2N/A switch (code) {
2N/A case UU_ERROR_NONE:
2N/A str = dgettext(TEXT_DOMAIN, "No error");
2N/A break;
2N/A
2N/A case UU_ERROR_INVALID_ARGUMENT:
2N/A str = dgettext(TEXT_DOMAIN, "Invalid argument");
2N/A break;
2N/A
2N/A case UU_ERROR_UNKNOWN_FLAG:
2N/A str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
2N/A break;
2N/A
2N/A case UU_ERROR_NO_MEMORY:
2N/A str = dgettext(TEXT_DOMAIN, "Out of memory");
2N/A break;
2N/A
2N/A case UU_ERROR_CALLBACK_FAILED:
2N/A str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
2N/A break;
2N/A
2N/A case UU_ERROR_NOT_SUPPORTED:
2N/A str = dgettext(TEXT_DOMAIN, "Operation not supported");
2N/A break;
2N/A
2N/A case UU_ERROR_EMPTY:
2N/A str = dgettext(TEXT_DOMAIN, "No value provided");
2N/A break;
2N/A
2N/A case UU_ERROR_UNDERFLOW:
2N/A str = dgettext(TEXT_DOMAIN, "Value too small");
2N/A break;
2N/A
2N/A case UU_ERROR_OVERFLOW:
2N/A str = dgettext(TEXT_DOMAIN, "Value too large");
2N/A break;
2N/A
2N/A case UU_ERROR_INVALID_CHAR:
2N/A str = dgettext(TEXT_DOMAIN,
2N/A "Value contains unexpected character");
2N/A break;
2N/A
2N/A case UU_ERROR_INVALID_DIGIT:
2N/A str = dgettext(TEXT_DOMAIN,
2N/A "Value contains digit not in base");
2N/A break;
2N/A
2N/A case UU_ERROR_SYSTEM:
2N/A str = dgettext(TEXT_DOMAIN, "Underlying system error");
2N/A break;
2N/A
2N/A case UU_ERROR_UNKNOWN:
2N/A str = dgettext(TEXT_DOMAIN, "Error status not known");
2N/A break;
2N/A
2N/A default:
2N/A errno = ESRCH;
2N/A str = NULL;
2N/A break;
2N/A }
2N/A return (str);
2N/A}
2N/A
2N/Avoid
2N/Auu_panic(const char *format, ...)
2N/A{
2N/A va_list args;
2N/A
2N/A va_start(args, format);
2N/A
2N/A (void) pthread_mutex_lock(&uu_panic_lock);
2N/A if (uu_panic_thread == 0) {
2N/A uu_panic_thread = pthread_self();
2N/A uu_panic_format = format;
2N/A va_copy(uu_panic_args, args);
2N/A }
2N/A (void) pthread_mutex_unlock(&uu_panic_lock);
2N/A
2N/A (void) vfprintf(stderr, format, args);
2N/A
2N/A if (uu_panic_thread == pthread_self())
2N/A abort();
2N/A else
2N/A for (;;)
2N/A (void) pause();
2N/A}
2N/A
2N/Aint
2N/Aassfail(const char *astring, const char *file, int line)
2N/A{
2N/A __assert(astring, file, line);
2N/A /*NOTREACHED*/
2N/A return (0);
2N/A}
2N/A
2N/Astatic void
2N/Auu_lockup(void)
2N/A{
2N/A (void) pthread_mutex_lock(&uu_panic_lock);
2N/A#if !defined(PTHREAD_ONCE_KEY_NP)
2N/A (void) pthread_mutex_lock(&uu_key_lock);
2N/A#endif
2N/A uu_avl_lockup();
2N/A uu_list_lockup();
2N/A}
2N/A
2N/Astatic void
2N/Auu_release(void)
2N/A{
2N/A (void) pthread_mutex_unlock(&uu_panic_lock);
2N/A#if !defined(PTHREAD_ONCE_KEY_NP)
2N/A (void) pthread_mutex_unlock(&uu_key_lock);
2N/A#endif
2N/A uu_avl_release();
2N/A uu_list_release();
2N/A}
2N/A
2N/Astatic void
2N/Auu_release_child(void)
2N/A{
2N/A uu_panic_format = NULL;
2N/A uu_panic_thread = 0;
2N/A
2N/A uu_release();
2N/A}
2N/A
2N/A#pragma init(uu_init)
2N/Astatic void
2N/Auu_init(void)
2N/A{
2N/A (void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
2N/A}
2N/A
2N/A/*
2N/A * Dump a block of memory in hex+ascii, for debugging
2N/A */
2N/Avoid
2N/Auu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
2N/A{
2N/A const unsigned char *p = buf;
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i += 16) {
2N/A int j;
2N/A
2N/A (void) fprintf(out, "%s", prefix);
2N/A for (j = 0; j < 16 && i + j < len; j++) {
2N/A (void) fprintf(out, "%2.2x ", p[i + j]);
2N/A }
2N/A for (; j < 16; j++) {
2N/A (void) fprintf(out, " ");
2N/A }
2N/A for (j = 0; j < 16 && i + j < len; j++) {
2N/A (void) fprintf(out, "%c",
2N/A isprint(p[i + j]) ? p[i + j] : '.');
2N/A }
2N/A (void) fprintf(out, "\n");
2N/A }
2N/A}