summaryrefslogtreecommitdiffstats
path: root/lib/libuutil
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2008-12-11 11:08:09 -0800
committerBrian Behlendorf <[email protected]>2008-12-11 11:08:09 -0800
commit172bb4bd5e4afef721dd4d2972d8680d983f144b (patch)
tree18ab1e97e5e409150066c529b5a981ecf600ef80 /lib/libuutil
parent9e8b1e836caa454586797f771a7ad1817ebae315 (diff)
Move the world out of /zfs/ and seperate out module build tree
Diffstat (limited to 'lib/libuutil')
-rw-r--r--lib/libuutil/include/libuutil.h381
-rw-r--r--lib/libuutil/include/libuutil_common.h35
-rw-r--r--lib/libuutil/include/libuutil_impl.h181
-rw-r--r--lib/libuutil/uu_alloc.c98
-rw-r--r--lib/libuutil/uu_avl.c569
-rw-r--r--lib/libuutil/uu_dprintf.c128
-rw-r--r--lib/libuutil/uu_ident.c122
-rw-r--r--lib/libuutil/uu_list.c718
-rw-r--r--lib/libuutil/uu_misc.c255
-rw-r--r--lib/libuutil/uu_open.c70
-rw-r--r--lib/libuutil/uu_pname.c207
-rw-r--r--lib/libuutil/uu_strtoint.c300
12 files changed, 3064 insertions, 0 deletions
diff --git a/lib/libuutil/include/libuutil.h b/lib/libuutil/include/libuutil.h
new file mode 100644
index 000000000..ccd46b977
--- /dev/null
+++ b/lib/libuutil/include/libuutil.h
@@ -0,0 +1,381 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBUUTIL_H
+#define _LIBUUTIL_H
+
+#include <sys/types.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Standard flags codes.
+ */
+#define UU_DEFAULT 0
+
+/*
+ * Standard error codes.
+ */
+#define UU_ERROR_NONE 0 /* no error */
+#define UU_ERROR_INVALID_ARGUMENT 1 /* invalid argument */
+#define UU_ERROR_UNKNOWN_FLAG 2 /* passed flag invalid */
+#define UU_ERROR_NO_MEMORY 3 /* out of memory */
+#define UU_ERROR_CALLBACK_FAILED 4 /* callback-initiated error */
+#define UU_ERROR_NOT_SUPPORTED 5 /* operation not supported */
+#define UU_ERROR_EMPTY 6 /* no value provided */
+#define UU_ERROR_UNDERFLOW 7 /* value is too small */
+#define UU_ERROR_OVERFLOW 8 /* value is too value */
+#define UU_ERROR_INVALID_CHAR 9 /* value contains unexpected char */
+#define UU_ERROR_INVALID_DIGIT 10 /* value contains digit not in base */
+
+#define UU_ERROR_SYSTEM 99 /* underlying system error */
+#define UU_ERROR_UNKNOWN 100 /* error status not known */
+
+/*
+ * Standard program exit codes.
+ */
+#define UU_EXIT_OK (*(uu_exit_ok()))
+#define UU_EXIT_FATAL (*(uu_exit_fatal()))
+#define UU_EXIT_USAGE (*(uu_exit_usage()))
+
+/*
+ * Exit status profiles.
+ */
+#define UU_PROFILE_DEFAULT 0
+#define UU_PROFILE_LAUNCHER 1
+
+/*
+ * Error reporting functions.
+ */
+uint32_t uu_error(void);
+const char *uu_strerror(uint32_t);
+
+/*
+ * Program notification functions.
+ */
+extern void uu_alt_exit(int);
+extern const char *uu_setpname(char *);
+extern const char *uu_getpname(void);
+/*PRINTFLIKE1*/
+extern void uu_warn(const char *, ...);
+extern void uu_vwarn(const char *, va_list);
+/*PRINTFLIKE1*/
+extern void uu_die(const char *, ...) __NORETURN;
+extern void uu_vdie(const char *, va_list) __NORETURN;
+/*PRINTFLIKE2*/
+extern void uu_xdie(int, const char *, ...) __NORETURN;
+extern void uu_vxdie(int, const char *, va_list) __NORETURN;
+
+/*
+ * Exit status functions (not to be used directly)
+ */
+extern int *uu_exit_ok(void);
+extern int *uu_exit_fatal(void);
+extern int *uu_exit_usage(void);
+
+/*
+ * string->number conversions
+ */
+extern int uu_strtoint(const char *, void *, size_t, int, int64_t, int64_t);
+extern int uu_strtouint(const char *, void *, size_t, int, uint64_t, uint64_t);
+
+/*
+ * Debug print facility functions.
+ */
+typedef struct uu_dprintf uu_dprintf_t;
+
+typedef enum {
+ UU_DPRINTF_SILENT,
+ UU_DPRINTF_FATAL,
+ UU_DPRINTF_WARNING,
+ UU_DPRINTF_NOTICE,
+ UU_DPRINTF_INFO,
+ UU_DPRINTF_DEBUG
+} uu_dprintf_severity_t;
+
+extern uu_dprintf_t *uu_dprintf_create(const char *, uu_dprintf_severity_t,
+ uint_t);
+/*PRINTFLIKE3*/
+extern void uu_dprintf(uu_dprintf_t *, uu_dprintf_severity_t,
+ const char *, ...);
+extern void uu_dprintf_destroy(uu_dprintf_t *);
+extern const char *uu_dprintf_getname(uu_dprintf_t *);
+
+/*
+ * Identifier test flags and function.
+ */
+#define UU_NAME_DOMAIN 0x1 /* allow SUNW, or com.sun, prefix */
+#define UU_NAME_PATH 0x2 /* allow '/'-delimited paths */
+
+int uu_check_name(const char *, uint_t);
+
+/*
+ * File creation functions.
+ */
+extern int uu_open_tmp(const char *dir, uint_t uflags);
+
+/*
+ * Convenience functions.
+ */
+/*PRINTFLIKE1*/
+extern char *uu_msprintf(const char *format, ...);
+extern void *uu_zalloc(size_t);
+extern char *uu_strdup(const char *);
+extern void uu_free(void *);
+
+/*
+ * Comparison function type definition.
+ * Developers should be careful in their use of the _private argument. If you
+ * break interface guarantees, you get undefined behavior.
+ */
+typedef int uu_compare_fn_t(const void *__left, const void *__right,
+ void *__private);
+
+/*
+ * Walk variant flags.
+ * A data structure need not provide support for all variants and
+ * combinations. Refer to the appropriate documentation.
+ */
+#define UU_WALK_ROBUST 0x00000001 /* walk can survive removes */
+#define UU_WALK_REVERSE 0x00000002 /* reverse walk order */
+
+#define UU_WALK_PREORDER 0x00000010 /* walk tree in pre-order */
+#define UU_WALK_POSTORDER 0x00000020 /* walk tree in post-order */
+
+/*
+ * Walk callback function return codes.
+ */
+#define UU_WALK_ERROR -1
+#define UU_WALK_NEXT 0
+#define UU_WALK_DONE 1
+
+/*
+ * Walk callback function type definition.
+ */
+typedef int uu_walk_fn_t(void *_elem, void *_private);
+
+/*
+ * lists: opaque structures
+ */
+typedef struct uu_list_pool uu_list_pool_t;
+typedef struct uu_list uu_list_t;
+
+typedef struct uu_list_node {
+ uintptr_t uln_opaque[2];
+} uu_list_node_t;
+
+typedef struct uu_list_walk uu_list_walk_t;
+
+typedef uintptr_t uu_list_index_t;
+
+/*
+ * lists: interface
+ *
+ * basic usage:
+ * typedef struct foo {
+ * ...
+ * uu_list_node_t foo_node;
+ * ...
+ * } foo_t;
+ *
+ * static int
+ * foo_compare(void *l_arg, void *r_arg, void *private)
+ * {
+ * foo_t *l = l_arg;
+ * foo_t *r = r_arg;
+ *
+ * if (... l greater than r ...)
+ * return (1);
+ * if (... l less than r ...)
+ * return (-1);
+ * return (0);
+ * }
+ *
+ * ...
+ * // at initialization time
+ * foo_pool = uu_list_pool_create("foo_pool",
+ * sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
+ * debugging? 0 : UU_AVL_POOL_DEBUG);
+ * ...
+ */
+uu_list_pool_t *uu_list_pool_create(const char *, size_t, size_t,
+ uu_compare_fn_t *, uint32_t);
+#define UU_LIST_POOL_DEBUG 0x00000001
+
+void uu_list_pool_destroy(uu_list_pool_t *);
+
+/*
+ * usage:
+ *
+ * foo_t *a;
+ * a = malloc(sizeof(*a));
+ * uu_list_node_init(a, &a->foo_list, pool);
+ * ...
+ * uu_list_node_fini(a, &a->foo_list, pool);
+ * free(a);
+ */
+void uu_list_node_init(void *, uu_list_node_t *, uu_list_pool_t *);
+void uu_list_node_fini(void *, uu_list_node_t *, uu_list_pool_t *);
+
+uu_list_t *uu_list_create(uu_list_pool_t *, void *_parent, uint32_t);
+#define UU_LIST_DEBUG 0x00000001
+#define UU_LIST_SORTED 0x00000002 /* list is sorted */
+
+void uu_list_destroy(uu_list_t *); /* list must be empty */
+
+size_t uu_list_numnodes(uu_list_t *);
+
+void *uu_list_first(uu_list_t *);
+void *uu_list_last(uu_list_t *);
+
+void *uu_list_next(uu_list_t *, void *);
+void *uu_list_prev(uu_list_t *, void *);
+
+int uu_list_walk(uu_list_t *, uu_walk_fn_t *, void *, uint32_t);
+
+uu_list_walk_t *uu_list_walk_start(uu_list_t *, uint32_t);
+void *uu_list_walk_next(uu_list_walk_t *);
+void uu_list_walk_end(uu_list_walk_t *);
+
+void *uu_list_find(uu_list_t *, void *, void *, uu_list_index_t *);
+void uu_list_insert(uu_list_t *, void *, uu_list_index_t);
+
+void *uu_list_nearest_next(uu_list_t *, uu_list_index_t);
+void *uu_list_nearest_prev(uu_list_t *, uu_list_index_t);
+
+void *uu_list_teardown(uu_list_t *, void **);
+
+void uu_list_remove(uu_list_t *, void *);
+
+/*
+ * lists: interfaces for non-sorted lists only
+ */
+int uu_list_insert_before(uu_list_t *, void *_target, void *_elem);
+int uu_list_insert_after(uu_list_t *, void *_target, void *_elem);
+
+/*
+ * avl trees: opaque structures
+ */
+typedef struct uu_avl_pool uu_avl_pool_t;
+typedef struct uu_avl uu_avl_t;
+
+typedef struct uu_avl_node {
+#ifdef _LP64
+ uintptr_t uan_opaque[3];
+#else
+ uintptr_t uan_opaque[4];
+#endif
+} uu_avl_node_t;
+
+typedef struct uu_avl_walk uu_avl_walk_t;
+
+typedef uintptr_t uu_avl_index_t;
+
+/*
+ * avl trees: interface
+ *
+ * basic usage:
+ * typedef struct foo {
+ * ...
+ * uu_avl_node_t foo_node;
+ * ...
+ * } foo_t;
+ *
+ * static int
+ * foo_compare(void *l_arg, void *r_arg, void *private)
+ * {
+ * foo_t *l = l_arg;
+ * foo_t *r = r_arg;
+ *
+ * if (... l greater than r ...)
+ * return (1);
+ * if (... l less than r ...)
+ * return (-1);
+ * return (0);
+ * }
+ *
+ * ...
+ * // at initialization time
+ * foo_pool = uu_avl_pool_create("foo_pool",
+ * sizeof (foo_t), offsetof(foo_t, foo_node), foo_compare,
+ * debugging? 0 : UU_AVL_POOL_DEBUG);
+ * ...
+ */
+uu_avl_pool_t *uu_avl_pool_create(const char *, size_t, size_t,
+ uu_compare_fn_t *, uint32_t);
+#define UU_AVL_POOL_DEBUG 0x00000001
+
+void uu_avl_pool_destroy(uu_avl_pool_t *);
+
+/*
+ * usage:
+ *
+ * foo_t *a;
+ * a = malloc(sizeof(*a));
+ * uu_avl_node_init(a, &a->foo_avl, pool);
+ * ...
+ * uu_avl_node_fini(a, &a->foo_avl, pool);
+ * free(a);
+ */
+void uu_avl_node_init(void *, uu_avl_node_t *, uu_avl_pool_t *);
+void uu_avl_node_fini(void *, uu_avl_node_t *, uu_avl_pool_t *);
+
+uu_avl_t *uu_avl_create(uu_avl_pool_t *, void *_parent, uint32_t);
+#define UU_AVL_DEBUG 0x00000001
+
+void uu_avl_destroy(uu_avl_t *); /* list must be empty */
+
+size_t uu_avl_numnodes(uu_avl_t *);
+
+void *uu_avl_first(uu_avl_t *);
+void *uu_avl_last(uu_avl_t *);
+
+void *uu_avl_next(uu_avl_t *, void *);
+void *uu_avl_prev(uu_avl_t *, void *);
+
+int uu_avl_walk(uu_avl_t *, uu_walk_fn_t *, void *, uint32_t);
+
+uu_avl_walk_t *uu_avl_walk_start(uu_avl_t *, uint32_t);
+void *uu_avl_walk_next(uu_avl_walk_t *);
+void uu_avl_walk_end(uu_avl_walk_t *);
+
+void *uu_avl_find(uu_avl_t *, void *, void *, uu_avl_index_t *);
+void uu_avl_insert(uu_avl_t *, void *, uu_avl_index_t);
+
+void *uu_avl_nearest_next(uu_avl_t *, uu_avl_index_t);
+void *uu_avl_nearest_prev(uu_avl_t *, uu_avl_index_t);
+
+void *uu_avl_teardown(uu_avl_t *, void **);
+
+void uu_avl_remove(uu_avl_t *, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBUUTIL_H */
diff --git a/lib/libuutil/include/libuutil_common.h b/lib/libuutil/include/libuutil_common.h
new file mode 100644
index 000000000..9ebaaedfd
--- /dev/null
+++ b/lib/libuutil/include/libuutil_common.h
@@ -0,0 +1,35 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBUUTIL_COMMON_H
+#define _LIBUUTIL_COMMON_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libuutil.h>
+#include <libuutil_impl.h>
+
+#endif /* _LIBUUTIL_COMMON_H */
diff --git a/lib/libuutil/include/libuutil_impl.h b/lib/libuutil/include/libuutil_impl.h
new file mode 100644
index 000000000..9466e5974
--- /dev/null
+++ b/lib/libuutil/include/libuutil_impl.h
@@ -0,0 +1,181 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBUUTIL_IMPL_H
+#define _LIBUUTIL_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libuutil.h>
+#include <pthread.h>
+
+#include <sys/avl_impl.h>
+#include <sys/byteorder.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void uu_set_error(uint_t);
+#pragma rarely_called(uu_set_error)
+
+/*PRINTFLIKE1*/
+void uu_panic(const char *format, ...);
+#pragma rarely_called(uu_panic)
+
+struct uu_dprintf {
+ char *uud_name;
+ uu_dprintf_severity_t uud_severity;
+ uint_t uud_flags;
+};
+
+/*
+ * For debugging purposes, libuutil keeps around linked lists of all uu_lists
+ * and uu_avls, along with pointers to their parents. These can cause false
+ * negatives when looking for memory leaks, so we encode the pointers by
+ * storing them with swapped endianness; this is not perfect, but it's about
+ * the best we can do without wasting a lot of space.
+ */
+#ifdef _LP64
+#define UU_PTR_ENCODE(ptr) BSWAP_64((uintptr_t)(void *)(ptr))
+#else
+#define UU_PTR_ENCODE(ptr) BSWAP_32((uintptr_t)(void *)(ptr))
+#endif
+
+#define UU_PTR_DECODE(ptr) ((void *)UU_PTR_ENCODE(ptr))
+
+/*
+ * uu_list structures
+ */
+typedef struct uu_list_node_impl {
+ struct uu_list_node_impl *uln_next;
+ struct uu_list_node_impl *uln_prev;
+} uu_list_node_impl_t;
+
+struct uu_list_walk {
+ uu_list_walk_t *ulw_next;
+ uu_list_walk_t *ulw_prev;
+
+ uu_list_t *ulw_list;
+ int8_t ulw_dir;
+ uint8_t ulw_robust;
+ uu_list_node_impl_t *ulw_next_result;
+};
+
+struct uu_list {
+ uintptr_t ul_next_enc;
+ uintptr_t ul_prev_enc;
+
+ uu_list_pool_t *ul_pool;
+ uintptr_t ul_parent_enc; /* encoded parent pointer */
+ size_t ul_offset;
+ size_t ul_numnodes;
+ uint8_t ul_debug;
+ uint8_t ul_sorted;
+ uint8_t ul_index; /* mark for uu_list_index_ts */
+
+ uu_list_node_impl_t ul_null_node;
+ uu_list_walk_t ul_null_walk; /* for robust walkers */
+};
+
+#define UU_LIST_PTR(ptr) ((uu_list_t *)UU_PTR_DECODE(ptr))
+
+#define UU_LIST_POOL_MAXNAME 64
+
+struct uu_list_pool {
+ uu_list_pool_t *ulp_next;
+ uu_list_pool_t *ulp_prev;
+
+ char ulp_name[UU_LIST_POOL_MAXNAME];
+ size_t ulp_nodeoffset;
+ size_t ulp_objsize;
+ uu_compare_fn_t *ulp_cmp;
+ uint8_t ulp_debug;
+ uint8_t ulp_last_index;
+ pthread_mutex_t ulp_lock; /* protects null_list */
+ uu_list_t ulp_null_list;
+};
+
+/*
+ * uu_avl structures
+ */
+typedef struct avl_node uu_avl_node_impl_t;
+
+struct uu_avl_walk {
+ uu_avl_walk_t *uaw_next;
+ uu_avl_walk_t *uaw_prev;
+
+ uu_avl_t *uaw_avl;
+ void *uaw_next_result;
+ int8_t uaw_dir;
+ uint8_t uaw_robust;
+};
+
+struct uu_avl {
+ uintptr_t ua_next_enc;
+ uintptr_t ua_prev_enc;
+
+ uu_avl_pool_t *ua_pool;
+ uintptr_t ua_parent_enc;
+ uint8_t ua_debug;
+ uint8_t ua_index; /* mark for uu_avl_index_ts */
+
+ struct avl_tree ua_tree;
+ uu_avl_walk_t ua_null_walk;
+};
+
+#define UU_AVL_PTR(x) ((uu_avl_t *)UU_PTR_DECODE(x))
+
+#define UU_AVL_POOL_MAXNAME 64
+
+struct uu_avl_pool {
+ uu_avl_pool_t *uap_next;
+ uu_avl_pool_t *uap_prev;
+
+ char uap_name[UU_AVL_POOL_MAXNAME];
+ size_t uap_nodeoffset;
+ size_t uap_objsize;
+ uu_compare_fn_t *uap_cmp;
+ uint8_t uap_debug;
+ uint8_t uap_last_index;
+ pthread_mutex_t uap_lock; /* protects null_avl */
+ uu_avl_t uap_null_avl;
+};
+
+/*
+ * atfork() handlers
+ */
+void uu_avl_lockup(void);
+void uu_avl_release(void);
+
+void uu_list_lockup(void);
+void uu_list_release(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBUUTIL_IMPL_H */
diff --git a/lib/libuutil/uu_alloc.c b/lib/libuutil/uu_alloc.c
new file mode 100644
index 000000000..05d862287
--- /dev/null
+++ b/lib/libuutil/uu_alloc.c
@@ -0,0 +1,98 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "libuutil_common.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *
+uu_zalloc(size_t n)
+{
+ void *p = malloc(n);
+
+ if (p == NULL) {
+ uu_set_error(UU_ERROR_SYSTEM);
+ return (NULL);
+ }
+
+ (void) memset(p, 0, n);
+
+ return (p);
+}
+
+void
+uu_free(void *p)
+{
+ free(p);
+}
+
+char *
+uu_strdup(const char *str)
+{
+ char *buf = NULL;
+
+ if (str != NULL) {
+ size_t sz;
+
+ sz = strlen(str) + 1;
+ buf = uu_zalloc(sz);
+ if (buf != NULL)
+ (void) memcpy(buf, str, sz);
+ }
+ return (buf);
+}
+
+char *
+uu_msprintf(const char *format, ...)
+{
+ va_list args;
+ char attic[1];
+ uint_t M, m;
+ char *b;
+
+ va_start(args, format);
+ M = vsnprintf(attic, 1, format, args);
+ va_end(args);
+
+ for (;;) {
+ m = M;
+ if ((b = uu_zalloc(m + 1)) == NULL)
+ return (NULL);
+
+ va_start(args, format);
+ M = vsnprintf(b, m + 1, format, args);
+ va_end(args);
+
+ if (M == m)
+ break; /* sizes match */
+
+ uu_free(b);
+ }
+
+ return (b);
+}
diff --git a/lib/libuutil/uu_avl.c b/lib/libuutil/uu_avl.c
new file mode 100644
index 000000000..308e9208f
--- /dev/null
+++ b/lib/libuutil/uu_avl.c
@@ -0,0 +1,569 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/avl.h>
+
+static uu_avl_pool_t uu_null_apool = { &uu_null_apool, &uu_null_apool };
+static pthread_mutex_t uu_apool_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * The index mark change on every insert and delete, to catch stale
+ * references.
+ *
+ * We leave the low bit alone, since the avl code uses it.
+ */
+#define INDEX_MAX (sizeof (uintptr_t) - 2)
+#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 2 : ((m) + 2) & INDEX_MAX)
+
+#define INDEX_DECODE(i) ((i) & ~INDEX_MAX)
+#define INDEX_ENCODE(p, n) (((n) & ~INDEX_MAX) | (p)->ua_index)
+#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ua_index)
+#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
+
+/*
+ * When an element is inactive (not in a tree), we keep a marked pointer to
+ * its containing pool in its first word, and a NULL pointer in its second.
+ *
+ * On insert, we use these to verify that it comes from the correct pool.
+ */
+#define NODE_ARRAY(p, n) ((uintptr_t *)((uintptr_t)(n) + \
+ (pp)->uap_nodeoffset))
+
+#define POOL_TO_MARKER(pp) (((uintptr_t)(pp) | 1))
+
+#define DEAD_MARKER 0xc4
+
+uu_avl_pool_t *
+uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset,
+ uu_compare_fn_t *compare_func, uint32_t flags)
+{
+ uu_avl_pool_t *pp, *next, *prev;
+
+ if (name == NULL ||
+ uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
+ nodeoffset + sizeof (uu_avl_node_t) > objsize ||
+ compare_func == NULL) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (NULL);
+ }
+
+ if (flags & ~UU_AVL_POOL_DEBUG) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ pp = uu_zalloc(sizeof (uu_avl_pool_t));
+ if (pp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ (void) strlcpy(pp->uap_name, name, sizeof (pp->uap_name));
+ pp->uap_nodeoffset = nodeoffset;
+ pp->uap_objsize = objsize;
+ pp->uap_cmp = compare_func;
+ if (flags & UU_AVL_POOL_DEBUG)
+ pp->uap_debug = 1;
+ pp->uap_last_index = 0;
+
+ (void) pthread_mutex_init(&pp->uap_lock, NULL);
+
+ pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
+ pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
+
+ (void) pthread_mutex_lock(&uu_apool_list_lock);
+ pp->uap_next = next = &uu_null_apool;
+ pp->uap_prev = prev = next->uap_prev;
+ next->uap_prev = pp;
+ prev->uap_next = pp;
+ (void) pthread_mutex_unlock(&uu_apool_list_lock);
+
+ return (pp);
+}
+
+void
+uu_avl_pool_destroy(uu_avl_pool_t *pp)
+{
+ if (pp->uap_debug) {
+ if (pp->uap_null_avl.ua_next_enc !=
+ UU_PTR_ENCODE(&pp->uap_null_avl) ||
+ pp->uap_null_avl.ua_prev_enc !=
+ UU_PTR_ENCODE(&pp->uap_null_avl)) {
+ uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has "
+ "outstanding avls, or is corrupt.\n",
+ (int)sizeof (pp->uap_name), pp->uap_name,
+ (void *)pp);
+ }
+ }
+ (void) pthread_mutex_lock(&uu_apool_list_lock);
+ pp->uap_next->uap_prev = pp->uap_prev;
+ pp->uap_prev->uap_next = pp->uap_next;
+ (void) pthread_mutex_unlock(&uu_apool_list_lock);
+ pp->uap_prev = NULL;
+ pp->uap_next = NULL;
+ uu_free(pp);
+}
+
+void
+uu_avl_node_init(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
+{
+ uintptr_t *na = (uintptr_t *)np;
+
+ if (pp->uap_debug) {
+ uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
+ if (offset + sizeof (*np) > pp->uap_objsize) {
+ uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't fit in object (size %ld)\n",
+ base, (void *)np, (void *)pp, pp->uap_name,
+ (long)offset, (long)pp->uap_objsize);
+ }
+ if (offset != pp->uap_nodeoffset) {
+ uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't match pool's offset (%ld)\n",
+ base, (void *)np, (void *)pp, pp->uap_name,
+ (long)offset, (long)pp->uap_objsize);
+ }
+ }
+
+ na[0] = POOL_TO_MARKER(pp);
+ na[1] = 0;
+}
+
+void
+uu_avl_node_fini(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
+{
+ uintptr_t *na = (uintptr_t *)np;
+
+ if (pp->uap_debug) {
+ if (na[0] == DEAD_MARKER && na[1] == DEAD_MARKER) {
+ uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
+ "node already finied\n",
+ base, (void *)np, (void *)pp, pp->uap_name);
+ }
+ if (na[0] != POOL_TO_MARKER(pp) || na[1] != 0) {
+ uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
+ "node corrupt, in tree, or in different pool\n",
+ base, (void *)np, (void *)pp, pp->uap_name);
+ }
+ }
+
+ na[0] = DEAD_MARKER;
+ na[1] = DEAD_MARKER;
+ na[2] = DEAD_MARKER;
+}
+
+struct uu_avl_node_compare_info {
+ uu_compare_fn_t *ac_compare;
+ void *ac_private;
+ void *ac_right;
+ void *ac_found;
+};
+
+static int
+uu_avl_node_compare(const void *l, const void *r)
+{
+ struct uu_avl_node_compare_info *info =
+ (struct uu_avl_node_compare_info *)l;
+
+ int res = info->ac_compare(r, info->ac_right, info->ac_private);
+
+ if (res == 0) {
+ if (info->ac_found == NULL)
+ info->ac_found = (void *)r;
+ return (-1);
+ }
+ if (res < 0)
+ return (1);
+ return (-1);
+}
+
+uu_avl_t *
+uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
+{
+ uu_avl_t *ap, *next, *prev;
+
+ if (flags & ~UU_AVL_DEBUG) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ ap = uu_zalloc(sizeof (*ap));
+ if (ap == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ ap->ua_pool = pp;
+ ap->ua_parent_enc = UU_PTR_ENCODE(parent);
+ ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG);
+ ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index));
+
+ avl_create(&ap->ua_tree, &uu_avl_node_compare, pp->uap_objsize,
+ pp->uap_nodeoffset);
+
+ ap->ua_null_walk.uaw_next = &ap->ua_null_walk;
+ ap->ua_null_walk.uaw_prev = &ap->ua_null_walk;
+
+ (void) pthread_mutex_lock(&pp->uap_lock);
+ next = &pp->uap_null_avl;
+ prev = UU_PTR_DECODE(next->ua_prev_enc);
+ ap->ua_next_enc = UU_PTR_ENCODE(next);
+ ap->ua_prev_enc = UU_PTR_ENCODE(prev);
+ next->ua_prev_enc = UU_PTR_ENCODE(ap);
+ prev->ua_next_enc = UU_PTR_ENCODE(ap);
+ (void) pthread_mutex_unlock(&pp->uap_lock);
+
+ return (ap);
+}
+
+void
+uu_avl_destroy(uu_avl_t *ap)
+{
+ uu_avl_pool_t *pp = ap->ua_pool;
+
+ if (ap->ua_debug) {
+ if (avl_numnodes(&ap->ua_tree) != 0) {
+ uu_panic("uu_avl_destroy(%p): tree not empty\n",
+ (void *)ap);
+ }
+ if (ap->ua_null_walk.uaw_next != &ap->ua_null_walk ||
+ ap->ua_null_walk.uaw_prev != &ap->ua_null_walk) {
+ uu_panic("uu_avl_destroy(%p): outstanding walkers\n",
+ (void *)ap);
+ }
+ }
+ (void) pthread_mutex_lock(&pp->uap_lock);
+ UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc;
+ UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc;
+ (void) pthread_mutex_unlock(&pp->uap_lock);
+ ap->ua_prev_enc = UU_PTR_ENCODE(NULL);
+ ap->ua_next_enc = UU_PTR_ENCODE(NULL);
+
+ ap->ua_pool = NULL;
+ avl_destroy(&ap->ua_tree);
+
+ uu_free(ap);
+}
+
+size_t
+uu_avl_numnodes(uu_avl_t *ap)
+{
+ return (avl_numnodes(&ap->ua_tree));
+}
+
+void *
+uu_avl_first(uu_avl_t *ap)
+{
+ return (avl_first(&ap->ua_tree));
+}
+
+void *
+uu_avl_last(uu_avl_t *ap)
+{
+ return (avl_last(&ap->ua_tree));
+}
+
+void *
+uu_avl_next(uu_avl_t *ap, void *node)
+{
+ return (AVL_NEXT(&ap->ua_tree, node));
+}
+
+void *
+uu_avl_prev(uu_avl_t *ap, void *node)
+{
+ return (AVL_PREV(&ap->ua_tree, node));
+}
+
+static void
+_avl_walk_init(uu_avl_walk_t *wp, uu_avl_t *ap, uint32_t flags)
+{
+ uu_avl_walk_t *next, *prev;
+
+ int robust = (flags & UU_WALK_ROBUST);
+ int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
+
+ (void) memset(wp, 0, sizeof (*wp));
+ wp->uaw_avl = ap;
+ wp->uaw_robust = robust;
+ wp->uaw_dir = direction;
+
+ if (direction > 0)
+ wp->uaw_next_result = avl_first(&ap->ua_tree);
+ else
+ wp->uaw_next_result = avl_last(&ap->ua_tree);
+
+ if (ap->ua_debug || robust) {
+ wp->uaw_next = next = &ap->ua_null_walk;
+ wp->uaw_prev = prev = next->uaw_prev;
+ next->uaw_prev = wp;
+ prev->uaw_next = wp;
+ }
+}
+
+static void *
+_avl_walk_advance(uu_avl_walk_t *wp, uu_avl_t *ap)
+{
+ void *np = wp->uaw_next_result;
+
+ avl_tree_t *t = &ap->ua_tree;
+
+ if (np == NULL)
+ return (NULL);
+
+ wp->uaw_next_result = (wp->uaw_dir > 0)? AVL_NEXT(t, np) :
+ AVL_PREV(t, np);
+
+ return (np);
+}
+
+static void
+_avl_walk_fini(uu_avl_walk_t *wp)
+{
+ if (wp->uaw_next != NULL) {
+ wp->uaw_next->uaw_prev = wp->uaw_prev;
+ wp->uaw_prev->uaw_next = wp->uaw_next;
+ wp->uaw_next = NULL;
+ wp->uaw_prev = NULL;
+ }
+ wp->uaw_avl = NULL;
+ wp->uaw_next_result = NULL;
+}
+
+uu_avl_walk_t *
+uu_avl_walk_start(uu_avl_t *ap, uint32_t flags)
+{
+ uu_avl_walk_t *wp;
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ wp = uu_zalloc(sizeof (*wp));
+ if (wp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ _avl_walk_init(wp, ap, flags);
+ return (wp);
+}
+
+void *
+uu_avl_walk_next(uu_avl_walk_t *wp)
+{
+ return (_avl_walk_advance(wp, wp->uaw_avl));
+}
+
+void
+uu_avl_walk_end(uu_avl_walk_t *wp)
+{
+ _avl_walk_fini(wp);
+ uu_free(wp);
+}
+
+int
+uu_avl_walk(uu_avl_t *ap, uu_walk_fn_t *func, void *private, uint32_t flags)
+{
+ void *e;
+ uu_avl_walk_t my_walk;
+
+ int status = UU_WALK_NEXT;
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (-1);
+ }
+
+ _avl_walk_init(&my_walk, ap, flags);
+ while (status == UU_WALK_NEXT &&
+ (e = _avl_walk_advance(&my_walk, ap)) != NULL)
+ status = (*func)(e, private);
+ _avl_walk_fini(&my_walk);
+
+ if (status >= 0)
+ return (0);
+ uu_set_error(UU_ERROR_CALLBACK_FAILED);
+ return (-1);
+}
+
+void
+uu_avl_remove(uu_avl_t *ap, void *elem)
+{
+ uu_avl_walk_t *wp;
+ uu_avl_pool_t *pp = ap->ua_pool;
+ uintptr_t *na = NODE_ARRAY(pp, elem);
+
+ if (ap->ua_debug) {
+ /*
+ * invalidate outstanding uu_avl_index_ts.
+ */
+ ap->ua_index = INDEX_NEXT(ap->ua_index);
+ }
+
+ /*
+ * Robust walkers most be advanced, if we are removing the node
+ * they are currently using. In debug mode, non-robust walkers
+ * are also on the walker list.
+ */
+ for (wp = ap->ua_null_walk.uaw_next; wp != &ap->ua_null_walk;
+ wp = wp->uaw_next) {
+ if (wp->uaw_robust) {
+ if (elem == wp->uaw_next_result)
+ (void) _avl_walk_advance(wp, ap);
+ } else if (wp->uaw_next_result != NULL) {
+ uu_panic("uu_avl_remove(%p, %p): active non-robust "
+ "walker\n", (void *)ap, elem);
+ }
+ }
+
+ avl_remove(&ap->ua_tree, elem);
+
+ na[0] = POOL_TO_MARKER(pp);
+ na[1] = 0;
+}
+
+void *
+uu_avl_teardown(uu_avl_t *ap, void **cookie)
+{
+ void *elem = avl_destroy_nodes(&ap->ua_tree, cookie);
+
+ if (elem != NULL) {
+ uu_avl_pool_t *pp = ap->ua_pool;
+ uintptr_t *na = NODE_ARRAY(pp, elem);
+
+ na[0] = POOL_TO_MARKER(pp);
+ na[1] = 0;
+ }
+ return (elem);
+}
+
+void *
+uu_avl_find(uu_avl_t *ap, void *elem, void *private, uu_avl_index_t *out)
+{
+ struct uu_avl_node_compare_info info;
+ void *result;
+
+ info.ac_compare = ap->ua_pool->uap_cmp;
+ info.ac_private = private;
+ info.ac_right = elem;
+ info.ac_found = NULL;
+
+ result = avl_find(&ap->ua_tree, &info, out);
+ if (out != NULL)
+ *out = INDEX_ENCODE(ap, *out);
+
+ if (ap->ua_debug && result != NULL)
+ uu_panic("uu_avl_find: internal error: avl_find succeeded\n");
+
+ return (info.ac_found);
+}
+
+void
+uu_avl_insert(uu_avl_t *ap, void *elem, uu_avl_index_t idx)
+{
+ if (ap->ua_debug) {
+ uu_avl_pool_t *pp = ap->ua_pool;
+ uintptr_t *na = NODE_ARRAY(pp, elem);
+
+ if (na[1] != 0)
+ uu_panic("uu_avl_insert(%p, %p, %p): node already "
+ "in tree, or corrupt\n",
+ (void *)ap, elem, (void *)idx);
+ if (na[0] == 0)
+ uu_panic("uu_avl_insert(%p, %p, %p): node not "
+ "initialized\n",
+ (void *)ap, elem, (void *)idx);
+ if (na[0] != POOL_TO_MARKER(pp))
+ uu_panic("uu_avl_insert(%p, %p, %p): node from "
+ "other pool, or corrupt\n",
+ (void *)ap, elem, (void *)idx);
+
+ if (!INDEX_VALID(ap, idx))
+ uu_panic("uu_avl_insert(%p, %p, %p): %s\n",
+ (void *)ap, elem, (void *)idx,
+ INDEX_CHECK(idx)? "outdated index" :
+ "invalid index");
+
+ /*
+ * invalidate outstanding uu_avl_index_ts.
+ */
+ ap->ua_index = INDEX_NEXT(ap->ua_index);
+ }
+ avl_insert(&ap->ua_tree, elem, INDEX_DECODE(idx));
+}
+
+void *
+uu_avl_nearest_next(uu_avl_t *ap, uu_avl_index_t idx)
+{
+ if (ap->ua_debug && !INDEX_VALID(ap, idx))
+ uu_panic("uu_avl_nearest_next(%p, %p): %s\n",
+ (void *)ap, (void *)idx, INDEX_CHECK(idx)?
+ "outdated index" : "invalid index");
+ return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_AFTER));
+}
+
+void *
+uu_avl_nearest_prev(uu_avl_t *ap, uu_avl_index_t idx)
+{
+ if (ap->ua_debug && !INDEX_VALID(ap, idx))
+ uu_panic("uu_avl_nearest_prev(%p, %p): %s\n",
+ (void *)ap, (void *)idx, INDEX_CHECK(idx)?
+ "outdated index" : "invalid index");
+ return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_BEFORE));
+}
+
+/*
+ * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
+ */
+void
+uu_avl_lockup(void)
+{
+ uu_avl_pool_t *pp;
+
+ (void) pthread_mutex_lock(&uu_apool_list_lock);
+ for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
+ pp = pp->uap_next)
+ (void) pthread_mutex_lock(&pp->uap_lock);
+}
+
+void
+uu_avl_release(void)
+{
+ uu_avl_pool_t *pp;
+
+ for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
+ pp = pp->uap_next)
+ (void) pthread_mutex_unlock(&pp->uap_lock);
+ (void) pthread_mutex_unlock(&uu_apool_list_lock);
+}
diff --git a/lib/libuutil/uu_dprintf.c b/lib/libuutil/uu_dprintf.c
new file mode 100644
index 000000000..5b990a52b
--- /dev/null
+++ b/lib/libuutil/uu_dprintf.c
@@ -0,0 +1,128 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <errno.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#define FACILITY_FMT "%s (%s): "
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+static const char *
+strseverity(uu_dprintf_severity_t severity)
+{
+ switch (severity) {
+ case UU_DPRINTF_SILENT:
+ return (dgettext(TEXT_DOMAIN, "silent"));
+ case UU_DPRINTF_FATAL:
+ return (dgettext(TEXT_DOMAIN, "FATAL"));
+ case UU_DPRINTF_WARNING:
+ return (dgettext(TEXT_DOMAIN, "WARNING"));
+ case UU_DPRINTF_NOTICE:
+ return (dgettext(TEXT_DOMAIN, "note"));
+ case UU_DPRINTF_INFO:
+ return (dgettext(TEXT_DOMAIN, "info"));
+ case UU_DPRINTF_DEBUG:
+ return (dgettext(TEXT_DOMAIN, "debug"));
+ default:
+ return (dgettext(TEXT_DOMAIN, "unspecified"));
+ }
+}
+
+uu_dprintf_t *
+uu_dprintf_create(const char *name, uu_dprintf_severity_t severity,
+ uint_t flags)
+{
+ uu_dprintf_t *D;
+
+ if (uu_check_name(name, UU_NAME_DOMAIN) == -1) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (NULL);
+ }
+
+ if ((D = uu_zalloc(sizeof (uu_dprintf_t))) == NULL)
+ return (NULL);
+
+ if (name != NULL) {
+ D->uud_name = strdup(name);
+ if (D->uud_name == NULL) {
+ uu_free(D);
+ return (NULL);
+ }
+ } else {
+ D->uud_name = NULL;
+ }
+
+ D->uud_severity = severity;
+ D->uud_flags = flags;
+
+ return (D);
+}
+
+/*PRINTFLIKE3*/
+void
+uu_dprintf(uu_dprintf_t *D, uu_dprintf_severity_t severity,
+ const char *format, ...)
+{
+ va_list alist;
+
+ /* XXX Assert that severity is not UU_DPRINTF_SILENT. */
+
+ if (severity > D->uud_severity)
+ return;
+
+ (void) fprintf(stderr, FACILITY_FMT, D->uud_name,
+ strseverity(severity));
+
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+}
+
+void
+uu_dprintf_destroy(uu_dprintf_t *D)
+{
+ if (D->uud_name)
+ free(D->uud_name);
+
+ uu_free(D);
+}
+
+const char *
+uu_dprintf_getname(uu_dprintf_t *D)
+{
+ return (D->uud_name);
+}
diff --git a/lib/libuutil/uu_ident.c b/lib/libuutil/uu_ident.c
new file mode 100644
index 000000000..9a643845f
--- /dev/null
+++ b/lib/libuutil/uu_ident.c
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <string.h>
+
+/*
+ * We require names of the form:
+ * [provider,]identifier[/[provider,]identifier]...
+ *
+ * Where provider is either a stock symbol (SUNW) or a java-style reversed
+ * domain name (com.sun).
+ *
+ * Both providers and identifiers must start with a letter, and may
+ * only contain alphanumerics, dashes, and underlines. Providers
+ * may also contain periods.
+ *
+ * Note that we do _not_ use the macros in <ctype.h>, since they are affected
+ * by the current locale settings.
+ */
+
+#define IS_ALPHA(c) \
+ (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+
+#define IS_DIGIT(c) \
+ ((c) >= '0' && (c) <= '9')
+
+static int
+is_valid_ident(const char *s, const char *e, int allowdot)
+{
+ char c;
+
+ if (s >= e)
+ return (0); /* name is empty */
+
+ c = *s++;
+ if (!IS_ALPHA(c))
+ return (0); /* does not start with letter */
+
+ while (s < e && (c = *s++) != 0) {
+ if (IS_ALPHA(c) || IS_DIGIT(c) || c == '-' || c == '_' ||
+ (allowdot && c == '.'))
+ continue;
+ return (0); /* invalid character */
+ }
+ return (1);
+}
+
+static int
+is_valid_component(const char *b, const char *e, uint_t flags)
+{
+ char *sp;
+
+ if (flags & UU_NAME_DOMAIN) {
+ sp = strchr(b, ',');
+ if (sp != NULL && sp < e) {
+ if (!is_valid_ident(b, sp, 1))
+ return (0);
+ b = sp + 1;
+ }
+ }
+
+ return (is_valid_ident(b, e, 0));
+}
+
+int
+uu_check_name(const char *name, uint_t flags)
+{
+ const char *end = name + strlen(name);
+ const char *p;
+
+ if (flags & ~(UU_NAME_DOMAIN | UU_NAME_PATH)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (-1);
+ }
+
+ if (!(flags & UU_NAME_PATH)) {
+ if (!is_valid_component(name, end, flags))
+ goto bad;
+ return (0);
+ }
+
+ while ((p = strchr(name, '/')) != NULL) {
+ if (!is_valid_component(name, p - 1, flags))
+ goto bad;
+ name = p + 1;
+ }
+ if (!is_valid_component(name, end, flags))
+ goto bad;
+
+ return (0);
+
+bad:
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+}
diff --git a/lib/libuutil/uu_list.c b/lib/libuutil/uu_list.c
new file mode 100644
index 000000000..35c7ba800
--- /dev/null
+++ b/lib/libuutil/uu_list.c
@@ -0,0 +1,718 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define ELEM_TO_NODE(lp, e) \
+ ((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
+
+#define NODE_TO_ELEM(lp, n) \
+ ((void *)((uintptr_t)(n) - (lp)->ul_offset))
+
+/*
+ * uu_list_index_ts define a location for insertion. They are simply a
+ * pointer to the object after the insertion point. We store a mark
+ * in the low-bits of the index, to help prevent mistakes.
+ *
+ * When debugging, the index mark changes on every insert and delete, to
+ * catch stale references.
+ */
+#define INDEX_MAX (sizeof (uintptr_t) - 1)
+#define INDEX_NEXT(m) (((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
+
+#define INDEX_TO_NODE(i) ((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
+#define NODE_TO_INDEX(p, n) (((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
+#define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ul_index)
+#define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
+
+#define POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
+
+static uu_list_pool_t uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
+static pthread_mutex_t uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+uu_list_pool_t *
+uu_list_pool_create(const char *name, size_t objsize,
+ size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
+{
+ uu_list_pool_t *pp, *next, *prev;
+
+ if (name == NULL ||
+ uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
+ nodeoffset + sizeof (uu_list_node_t) > objsize) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (NULL);
+ }
+
+ if (flags & ~UU_LIST_POOL_DEBUG) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ pp = uu_zalloc(sizeof (uu_list_pool_t));
+ if (pp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ (void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
+ pp->ulp_nodeoffset = nodeoffset;
+ pp->ulp_objsize = objsize;
+ pp->ulp_cmp = compare_func;
+ if (flags & UU_LIST_POOL_DEBUG)
+ pp->ulp_debug = 1;
+ pp->ulp_last_index = 0;
+
+ (void) pthread_mutex_init(&pp->ulp_lock, NULL);
+
+ pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
+ pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
+
+ (void) pthread_mutex_lock(&uu_lpool_list_lock);
+ pp->ulp_next = next = &uu_null_lpool;
+ pp->ulp_prev = prev = next->ulp_prev;
+ next->ulp_prev = pp;
+ prev->ulp_next = pp;
+ (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+
+ return (pp);
+}
+
+void
+uu_list_pool_destroy(uu_list_pool_t *pp)
+{
+ if (pp->ulp_debug) {
+ if (pp->ulp_null_list.ul_next_enc !=
+ UU_PTR_ENCODE(&pp->ulp_null_list) ||
+ pp->ulp_null_list.ul_prev_enc !=
+ UU_PTR_ENCODE(&pp->ulp_null_list)) {
+ uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
+ "outstanding lists, or is corrupt.\n",
+ (int)sizeof (pp->ulp_name), pp->ulp_name,
+ (void *)pp);
+ }
+ }
+ (void) pthread_mutex_lock(&uu_lpool_list_lock);
+ pp->ulp_next->ulp_prev = pp->ulp_prev;
+ pp->ulp_prev->ulp_next = pp->ulp_next;
+ (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+ pp->ulp_prev = NULL;
+ pp->ulp_next = NULL;
+ uu_free(pp);
+}
+
+void
+uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
+{
+ uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
+
+ if (pp->ulp_debug) {
+ uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
+ if (offset + sizeof (*np) > pp->ulp_objsize) {
+ uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't fit in object (size %ld)\n",
+ base, (void *)np, (void *)pp, pp->ulp_name,
+ (long)offset, (long)pp->ulp_objsize);
+ }
+ if (offset != pp->ulp_nodeoffset) {
+ uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
+ "offset %ld doesn't match pool's offset (%ld)\n",
+ base, (void *)np, (void *)pp, pp->ulp_name,
+ (long)offset, (long)pp->ulp_objsize);
+ }
+ }
+ np->uln_next = POOL_TO_MARKER(pp);
+ np->uln_prev = NULL;
+}
+
+void
+uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
+{
+ uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
+
+ if (pp->ulp_debug) {
+ if (np->uln_next == NULL &&
+ np->uln_prev == NULL) {
+ uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
+ "node already finied\n",
+ base, (void *)np_arg, (void *)pp, pp->ulp_name);
+ }
+ if (np->uln_next != POOL_TO_MARKER(pp) ||
+ np->uln_prev != NULL) {
+ uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
+ "node corrupt or on list\n",
+ base, (void *)np_arg, (void *)pp, pp->ulp_name);
+ }
+ }
+ np->uln_next = NULL;
+ np->uln_prev = NULL;
+}
+
+uu_list_t *
+uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
+{
+ uu_list_t *lp, *next, *prev;
+
+ if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
+ if (pp->ulp_debug)
+ uu_panic("uu_list_create(%p, ...): requested "
+ "UU_LIST_SORTED, but pool has no comparison func\n",
+ (void *)pp);
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (NULL);
+ }
+
+ lp = uu_zalloc(sizeof (*lp));
+ if (lp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ lp->ul_pool = pp;
+ lp->ul_parent_enc = UU_PTR_ENCODE(parent);
+ lp->ul_offset = pp->ulp_nodeoffset;
+ lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
+ lp->ul_sorted = (flags & UU_LIST_SORTED);
+ lp->ul_numnodes = 0;
+ lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
+
+ lp->ul_null_node.uln_next = &lp->ul_null_node;
+ lp->ul_null_node.uln_prev = &lp->ul_null_node;
+
+ lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
+ lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
+
+ (void) pthread_mutex_lock(&pp->ulp_lock);
+ next = &pp->ulp_null_list;
+ prev = UU_PTR_DECODE(next->ul_prev_enc);
+ lp->ul_next_enc = UU_PTR_ENCODE(next);
+ lp->ul_prev_enc = UU_PTR_ENCODE(prev);
+ next->ul_prev_enc = UU_PTR_ENCODE(lp);
+ prev->ul_next_enc = UU_PTR_ENCODE(lp);
+ (void) pthread_mutex_unlock(&pp->ulp_lock);
+
+ return (lp);
+}
+
+void
+uu_list_destroy(uu_list_t *lp)
+{
+ uu_list_pool_t *pp = lp->ul_pool;
+
+ if (lp->ul_debug) {
+ if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
+ lp->ul_null_node.uln_prev != &lp->ul_null_node) {
+ uu_panic("uu_list_destroy(%p): list not empty\n",
+ (void *)lp);
+ }
+ if (lp->ul_numnodes != 0) {
+ uu_panic("uu_list_destroy(%p): numnodes is nonzero, "
+ "but list is empty\n", (void *)lp);
+ }
+ if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
+ lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
+ uu_panic("uu_list_destroy(%p): outstanding walkers\n",
+ (void *)lp);
+ }
+ }
+
+ (void) pthread_mutex_lock(&pp->ulp_lock);
+ UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
+ UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
+ (void) pthread_mutex_unlock(&pp->ulp_lock);
+ lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
+ lp->ul_next_enc = UU_PTR_ENCODE(NULL);
+ lp->ul_pool = NULL;
+ uu_free(lp);
+}
+
+static void
+list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
+ uu_list_node_impl_t *next)
+{
+ if (lp->ul_debug) {
+ if (next->uln_prev != prev || prev->uln_next != next)
+ uu_panic("insert(%p): internal error: %p and %p not "
+ "neighbors\n", (void *)lp, (void *)next,
+ (void *)prev);
+
+ if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
+ np->uln_prev != NULL) {
+ uu_panic("insert(%p): elem %p node %p corrupt, "
+ "not initialized, or already in a list.\n",
+ (void *)lp, NODE_TO_ELEM(lp, np), (void *)np);
+ }
+ /*
+ * invalidate outstanding uu_list_index_ts.
+ */
+ lp->ul_index = INDEX_NEXT(lp->ul_index);
+ }
+ np->uln_next = next;
+ np->uln_prev = prev;
+ next->uln_prev = np;
+ prev->uln_next = np;
+
+ lp->ul_numnodes++;
+}
+
+void
+uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
+{
+ uu_list_node_impl_t *np;
+
+ np = INDEX_TO_NODE(idx);
+ if (np == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (!INDEX_VALID(lp, idx))
+ uu_panic("uu_list_insert(%p, %p, %p): %s\n",
+ (void *)lp, elem, (void *)idx,
+ INDEX_CHECK(idx)? "outdated index" :
+ "invalid index");
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
+ "index\n", (void *)lp, elem, (void *)idx);
+ }
+
+ list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
+}
+
+void *
+uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
+{
+ int sorted = lp->ul_sorted;
+ uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
+ uu_list_node_impl_t *np;
+
+ if (func == NULL) {
+ if (out != NULL)
+ *out = 0;
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (NULL);
+ }
+ for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
+ np = np->uln_next) {
+ void *ep = NODE_TO_ELEM(lp, np);
+ int cmp = func(ep, elem, private);
+ if (cmp == 0) {
+ if (out != NULL)
+ *out = NODE_TO_INDEX(lp, np);
+ return (ep);
+ }
+ if (sorted && cmp > 0) {
+ if (out != NULL)
+ *out = NODE_TO_INDEX(lp, np);
+ return (NULL);
+ }
+ }
+ if (out != NULL)
+ *out = NODE_TO_INDEX(lp, 0);
+ return (NULL);
+}
+
+void *
+uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
+{
+ uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
+
+ if (np == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (!INDEX_VALID(lp, idx))
+ uu_panic("uu_list_nearest_next(%p, %p): %s\n",
+ (void *)lp, (void *)idx,
+ INDEX_CHECK(idx)? "outdated index" :
+ "invalid index");
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
+ "index\n", (void *)lp, (void *)idx);
+ }
+
+ if (np == &lp->ul_null_node)
+ return (NULL);
+ else
+ return (NODE_TO_ELEM(lp, np));
+}
+
+void *
+uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
+{
+ uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
+
+ if (np == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (!INDEX_VALID(lp, idx))
+ uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
+ (void *)lp, (void *)idx, INDEX_CHECK(idx)?
+ "outdated index" : "invalid index");
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
+ "index\n", (void *)lp, (void *)idx);
+ }
+
+ if ((np = np->uln_prev) == &lp->ul_null_node)
+ return (NULL);
+ else
+ return (NODE_TO_ELEM(lp, np));
+}
+
+static void
+list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
+{
+ uu_list_walk_t *next, *prev;
+
+ int robust = (flags & UU_WALK_ROBUST);
+ int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
+
+ (void) memset(wp, 0, sizeof (*wp));
+ wp->ulw_list = lp;
+ wp->ulw_robust = robust;
+ wp->ulw_dir = direction;
+ if (direction > 0)
+ wp->ulw_next_result = lp->ul_null_node.uln_next;
+ else
+ wp->ulw_next_result = lp->ul_null_node.uln_prev;
+
+ if (lp->ul_debug || robust) {
+ /*
+ * Add this walker to the list's list of walkers so
+ * uu_list_remove() can advance us if somebody tries to
+ * remove ulw_next_result.
+ */
+ wp->ulw_next = next = &lp->ul_null_walk;
+ wp->ulw_prev = prev = next->ulw_prev;
+ next->ulw_prev = wp;
+ prev->ulw_next = wp;
+ }
+}
+
+static uu_list_node_impl_t *
+list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
+{
+ uu_list_node_impl_t *np = wp->ulw_next_result;
+ uu_list_node_impl_t *next;
+
+ if (np == &lp->ul_null_node)
+ return (NULL);
+
+ next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
+
+ wp->ulw_next_result = next;
+ return (np);
+}
+
+static void
+list_walk_fini(uu_list_walk_t *wp)
+{
+ /* GLXXX debugging? */
+ if (wp->ulw_next != NULL) {
+ wp->ulw_next->ulw_prev = wp->ulw_prev;
+ wp->ulw_prev->ulw_next = wp->ulw_next;
+ wp->ulw_next = NULL;
+ wp->ulw_prev = NULL;
+ }
+ wp->ulw_list = NULL;
+ wp->ulw_next_result = NULL;
+}
+
+uu_list_walk_t *
+uu_list_walk_start(uu_list_t *lp, uint32_t flags)
+{
+ uu_list_walk_t *wp;
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (NULL);
+ }
+
+ wp = uu_zalloc(sizeof (*wp));
+ if (wp == NULL) {
+ uu_set_error(UU_ERROR_NO_MEMORY);
+ return (NULL);
+ }
+
+ list_walk_init(wp, lp, flags);
+ return (wp);
+}
+
+void *
+uu_list_walk_next(uu_list_walk_t *wp)
+{
+ uu_list_t *lp = wp->ulw_list;
+ uu_list_node_impl_t *np = list_walk_advance(wp, lp);
+
+ if (np == NULL)
+ return (NULL);
+
+ return (NODE_TO_ELEM(lp, np));
+}
+
+void
+uu_list_walk_end(uu_list_walk_t *wp)
+{
+ list_walk_fini(wp);
+ uu_free(wp);
+}
+
+int
+uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
+{
+ uu_list_node_impl_t *np;
+
+ int status = UU_WALK_NEXT;
+
+ int robust = (flags & UU_WALK_ROBUST);
+ int reverse = (flags & UU_WALK_REVERSE);
+
+ if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+ uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+ return (-1);
+ }
+
+ if (lp->ul_debug || robust) {
+ uu_list_walk_t my_walk;
+ void *e;
+
+ list_walk_init(&my_walk, lp, flags);
+ while (status == UU_WALK_NEXT &&
+ (e = uu_list_walk_next(&my_walk)) != NULL)
+ status = (*func)(e, private);
+ list_walk_fini(&my_walk);
+ } else {
+ if (!reverse) {
+ for (np = lp->ul_null_node.uln_next;
+ status == UU_WALK_NEXT && np != &lp->ul_null_node;
+ np = np->uln_next) {
+ status = (*func)(NODE_TO_ELEM(lp, np), private);
+ }
+ } else {
+ for (np = lp->ul_null_node.uln_prev;
+ status == UU_WALK_NEXT && np != &lp->ul_null_node;
+ np = np->uln_prev) {
+ status = (*func)(NODE_TO_ELEM(lp, np), private);
+ }
+ }
+ }
+ if (status >= 0)
+ return (0);
+ uu_set_error(UU_ERROR_CALLBACK_FAILED);
+ return (-1);
+}
+
+void
+uu_list_remove(uu_list_t *lp, void *elem)
+{
+ uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
+ uu_list_walk_t *wp;
+
+ if (lp->ul_debug) {
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_remove(%p, %p): elem not on list\n",
+ (void *)lp, elem);
+ /*
+ * invalidate outstanding uu_list_index_ts.
+ */
+ lp->ul_index = INDEX_NEXT(lp->ul_index);
+ }
+
+ /*
+ * robust walkers must be advanced. In debug mode, non-robust
+ * walkers are also on the list. If there are any, it's an error.
+ */
+ for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
+ wp = wp->ulw_next) {
+ if (wp->ulw_robust) {
+ if (np == wp->ulw_next_result)
+ (void) list_walk_advance(wp, lp);
+ } else if (wp->ulw_next_result != NULL) {
+ uu_panic("uu_list_remove(%p, %p): active non-robust "
+ "walker\n", (void *)lp, elem);
+ }
+ }
+
+ np->uln_next->uln_prev = np->uln_prev;
+ np->uln_prev->uln_next = np->uln_next;
+
+ lp->ul_numnodes--;
+
+ np->uln_next = POOL_TO_MARKER(lp->ul_pool);
+ np->uln_prev = NULL;
+}
+
+void *
+uu_list_teardown(uu_list_t *lp, void **cookie)
+{
+ void *ep;
+
+ /*
+ * XXX: disable list modification until list is empty
+ */
+ if (lp->ul_debug && *cookie != NULL)
+ uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n",
+ (void *)lp, (void *)cookie);
+
+ ep = uu_list_first(lp);
+ if (ep)
+ uu_list_remove(lp, ep);
+ return (ep);
+}
+
+int
+uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
+{
+ uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
+
+ if (target == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
+ "not currently on a list\n",
+ (void *)lp, target, elem, target);
+ }
+ if (lp->ul_sorted) {
+ if (lp->ul_debug)
+ uu_panic("uu_list_insert_before(%p, ...): list is "
+ "UU_LIST_SORTED\n", (void *)lp);
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (-1);
+ }
+
+ list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
+ return (0);
+}
+
+int
+uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
+{
+ uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
+
+ if (target == NULL)
+ np = &lp->ul_null_node;
+
+ if (lp->ul_debug) {
+ if (np->uln_prev == NULL)
+ uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
+ "not currently on a list\n",
+ (void *)lp, target, elem, target);
+ }
+ if (lp->ul_sorted) {
+ if (lp->ul_debug)
+ uu_panic("uu_list_insert_after(%p, ...): list is "
+ "UU_LIST_SORTED\n", (void *)lp);
+ uu_set_error(UU_ERROR_NOT_SUPPORTED);
+ return (-1);
+ }
+
+ list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
+ return (0);
+}
+
+size_t
+uu_list_numnodes(uu_list_t *lp)
+{
+ return (lp->ul_numnodes);
+}
+
+void *
+uu_list_first(uu_list_t *lp)
+{
+ uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_last(uu_list_t *lp)
+{
+ uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_next(uu_list_t *lp, void *elem)
+{
+ uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
+
+ n = n->uln_next;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_prev(uu_list_t *lp, void *elem)
+{
+ uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
+
+ n = n->uln_prev;
+ if (n == &lp->ul_null_node)
+ return (NULL);
+ return (NODE_TO_ELEM(lp, n));
+}
+
+/*
+ * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
+ */
+void
+uu_list_lockup(void)
+{
+ uu_list_pool_t *pp;
+
+ (void) pthread_mutex_lock(&uu_lpool_list_lock);
+ for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
+ pp = pp->ulp_next)
+ (void) pthread_mutex_lock(&pp->ulp_lock);
+}
+
+void
+uu_list_release(void)
+{
+ uu_list_pool_t *pp;
+
+ for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
+ pp = pp->ulp_next)
+ (void) pthread_mutex_unlock(&pp->ulp_lock);
+ (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+}
diff --git a/lib/libuutil/uu_misc.c b/lib/libuutil/uu_misc.c
new file mode 100644
index 000000000..74ec177c1
--- /dev/null
+++ b/lib/libuutil/uu_misc.c
@@ -0,0 +1,255 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <libintl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/debug.h>
+#include <thread.h>
+#include <unistd.h>
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*
+ * All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
+ * is here to enable the building of a native version of
+ * libuutil.so when the build machine has not yet been upgraded
+ * to a version of libc that provides pthread_key_create_once_np().
+ * It should all be deleted when solaris_nevada ships.
+ * The code is not MT-safe in a relaxed memory model.
+ */
+
+#if defined(PTHREAD_ONCE_KEY_NP)
+static pthread_key_t uu_error_key = PTHREAD_ONCE_KEY_NP;
+#else /* PTHREAD_ONCE_KEY_NP */
+static pthread_key_t uu_error_key = 0;
+static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif /* PTHREAD_ONCE_KEY_NP */
+
+static int uu_error_key_setup = 0;
+
+static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
+/* LINTED static unused */
+static const char *uu_panic_format;
+/* LINTED static unused */
+static va_list uu_panic_args;
+static pthread_t uu_panic_thread;
+
+static uint32_t _uu_main_error;
+
+void
+uu_set_error(uint_t code)
+{
+ if (thr_main() != 0) {
+ _uu_main_error = code;
+ return;
+ }
+#if defined(PTHREAD_ONCE_KEY_NP)
+ if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
+ uu_error_key_setup = -1;
+ else
+ uu_error_key_setup = 1;
+#else /* PTHREAD_ONCE_KEY_NP */
+ if (uu_error_key_setup == 0) {
+ (void) pthread_mutex_lock(&uu_key_lock);
+ if (uu_error_key_setup == 0) {
+ if (pthread_key_create(&uu_error_key, NULL) != 0)
+ uu_error_key_setup = -1;
+ else
+ uu_error_key_setup = 1;
+ }
+ (void) pthread_mutex_unlock(&uu_key_lock);
+ }
+#endif /* PTHREAD_ONCE_KEY_NP */
+ if (uu_error_key_setup > 0)
+ (void) pthread_setspecific(uu_error_key,
+ (void *)(uintptr_t)code);
+}
+
+uint32_t
+uu_error(void)
+{
+ if (thr_main() != 0)
+ return (_uu_main_error);
+
+ if (uu_error_key_setup < 0) /* can't happen? */
+ return (UU_ERROR_UNKNOWN);
+
+ /*
+ * Because UU_ERROR_NONE == 0, if uu_set_error() was
+ * never called, then this will return UU_ERROR_NONE:
+ */
+ return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
+}
+
+const char *
+uu_strerror(uint32_t code)
+{
+ const char *str;
+
+ switch (code) {
+ case UU_ERROR_NONE:
+ str = dgettext(TEXT_DOMAIN, "No error");
+ break;
+
+ case UU_ERROR_INVALID_ARGUMENT:
+ str = dgettext(TEXT_DOMAIN, "Invalid argument");
+ break;
+
+ case UU_ERROR_UNKNOWN_FLAG:
+ str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
+ break;
+
+ case UU_ERROR_NO_MEMORY:
+ str = dgettext(TEXT_DOMAIN, "Out of memory");
+ break;
+
+ case UU_ERROR_CALLBACK_FAILED:
+ str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
+ break;
+
+ case UU_ERROR_NOT_SUPPORTED:
+ str = dgettext(TEXT_DOMAIN, "Operation not supported");
+ break;
+
+ case UU_ERROR_EMPTY:
+ str = dgettext(TEXT_DOMAIN, "No value provided");
+ break;
+
+ case UU_ERROR_UNDERFLOW:
+ str = dgettext(TEXT_DOMAIN, "Value too small");
+ break;
+
+ case UU_ERROR_OVERFLOW:
+ str = dgettext(TEXT_DOMAIN, "Value too large");
+ break;
+
+ case UU_ERROR_INVALID_CHAR:
+ str = dgettext(TEXT_DOMAIN,
+ "Value contains unexpected character");
+ break;
+
+ case UU_ERROR_INVALID_DIGIT:
+ str = dgettext(TEXT_DOMAIN,
+ "Value contains digit not in base");
+ break;
+
+ case UU_ERROR_SYSTEM:
+ str = dgettext(TEXT_DOMAIN, "Underlying system error");
+ break;
+
+ case UU_ERROR_UNKNOWN:
+ str = dgettext(TEXT_DOMAIN, "Error status not known");
+ break;
+
+ default:
+ errno = ESRCH;
+ str = NULL;
+ break;
+ }
+ return (str);
+}
+
+void
+uu_panic(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+
+ (void) pthread_mutex_lock(&uu_panic_lock);
+ if (uu_panic_thread == 0) {
+ uu_panic_thread = pthread_self();
+ uu_panic_format = format;
+ va_copy(uu_panic_args, args);
+ }
+ (void) pthread_mutex_unlock(&uu_panic_lock);
+
+ (void) vfprintf(stderr, format, args);
+
+ if (uu_panic_thread == pthread_self())
+ abort();
+ else
+ for (;;)
+ (void) pause();
+}
+
+int
+assfail(const char *astring, const char *file, int line)
+{
+ __assert(astring, file, line);
+ /*NOTREACHED*/
+ return (0);
+}
+
+static void
+uu_lockup(void)
+{
+ (void) pthread_mutex_lock(&uu_panic_lock);
+#if !defined(PTHREAD_ONCE_KEY_NP)
+ (void) pthread_mutex_lock(&uu_key_lock);
+#endif
+ uu_avl_lockup();
+ uu_list_lockup();
+}
+
+static void
+uu_release(void)
+{
+ (void) pthread_mutex_unlock(&uu_panic_lock);
+#if !defined(PTHREAD_ONCE_KEY_NP)
+ (void) pthread_mutex_unlock(&uu_key_lock);
+#endif
+ uu_avl_release();
+ uu_list_release();
+}
+
+static void
+uu_release_child(void)
+{
+ uu_panic_format = NULL;
+ uu_panic_thread = 0;
+
+ uu_release();
+}
+
+#pragma init(uu_init)
+static void
+uu_init(void)
+{
+ (void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
+}
diff --git a/lib/libuutil/uu_open.c b/lib/libuutil/uu_open.c
new file mode 100644
index 000000000..7256662e3
--- /dev/null
+++ b/lib/libuutil/uu_open.c
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef _LP64
+#define TMPPATHFMT "%s/uu%ld"
+#else /* _LP64 */
+#define TMPPATHFMT "%s/uu%lld"
+#endif /* _LP64 */
+
+/*ARGSUSED*/
+int
+uu_open_tmp(const char *dir, uint_t uflags)
+{
+ int f;
+ char *fname = uu_zalloc(PATH_MAX);
+
+ if (fname == NULL)
+ return (-1);
+
+ for (;;) {
+ (void) snprintf(fname, PATH_MAX, "%s/uu%lld", dir, gethrtime());
+
+ f = open(fname, O_CREAT | O_EXCL | O_RDWR, 0600);
+
+ if (f >= 0 || errno != EEXIST)
+ break;
+ }
+
+ if (f >= 0)
+ (void) unlink(fname);
+
+ uu_free(fname);
+
+ return (f);
+}
diff --git a/lib/libuutil/uu_pname.c b/lib/libuutil/uu_pname.c
new file mode 100644
index 000000000..3307a26dc
--- /dev/null
+++ b/lib/libuutil/uu_pname.c
@@ -0,0 +1,207 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <libintl.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <wchar.h>
+#include <unistd.h>
+
+static const char PNAME_FMT[] = "%s: ";
+static const char ERRNO_FMT[] = ": %s\n";
+
+static const char *pname;
+
+static void
+uu_die_internal(int status, const char *format, va_list alist) __NORETURN;
+
+int uu_exit_ok_value = EXIT_SUCCESS;
+int uu_exit_fatal_value = EXIT_FAILURE;
+int uu_exit_usage_value = 2;
+
+int *
+uu_exit_ok(void)
+{
+ return (&uu_exit_ok_value);
+}
+
+int *
+uu_exit_fatal(void)
+{
+ return (&uu_exit_fatal_value);
+}
+
+int *
+uu_exit_usage(void)
+{
+ return (&uu_exit_usage_value);
+}
+
+void
+uu_alt_exit(int profile)
+{
+ switch (profile) {
+ case UU_PROFILE_DEFAULT:
+ uu_exit_ok_value = EXIT_SUCCESS;
+ uu_exit_fatal_value = EXIT_FAILURE;
+ uu_exit_usage_value = 2;
+ break;
+ case UU_PROFILE_LAUNCHER:
+ uu_exit_ok_value = EXIT_SUCCESS;
+ uu_exit_fatal_value = 124;
+ uu_exit_usage_value = 125;
+ break;
+ }
+}
+
+static void
+uu_warn_internal(int err, const char *format, va_list alist)
+{
+ if (pname != NULL)
+ (void) fprintf(stderr, PNAME_FMT, pname);
+
+ (void) vfprintf(stderr, format, alist);
+
+ if (strrchr(format, '\n') == NULL)
+ (void) fprintf(stderr, ERRNO_FMT, strerror(err));
+}
+
+void
+uu_vwarn(const char *format, va_list alist)
+{
+ uu_warn_internal(errno, format, alist);
+}
+
+/*PRINTFLIKE1*/
+void
+uu_warn(const char *format, ...)
+{
+ va_list alist;
+ va_start(alist, format);
+ uu_warn_internal(errno, format, alist);
+ va_end(alist);
+}
+
+static void
+uu_die_internal(int status, const char *format, va_list alist)
+{
+ uu_warn_internal(errno, format, alist);
+#ifdef DEBUG
+ {
+ char *cp;
+
+ if (!issetugid()) {
+ cp = getenv("UU_DIE_ABORTS");
+ if (cp != NULL && *cp != '\0')
+ abort();
+ }
+ }
+#endif
+ exit(status);
+}
+
+void
+uu_vdie(const char *format, va_list alist)
+{
+ uu_die_internal(UU_EXIT_FATAL, format, alist);
+}
+
+/*PRINTFLIKE1*/
+void
+uu_die(const char *format, ...)
+{
+ va_list alist;
+ va_start(alist, format);
+ uu_die_internal(UU_EXIT_FATAL, format, alist);
+ va_end(alist);
+}
+
+void
+uu_vxdie(int status, const char *format, va_list alist)
+{
+ uu_die_internal(status, format, alist);
+}
+
+/*PRINTFLIKE2*/
+void
+uu_xdie(int status, const char *format, ...)
+{
+ va_list alist;
+ va_start(alist, format);
+ uu_die_internal(status, format, alist);
+ va_end(alist);
+}
+
+const char *
+uu_setpname(char *arg0)
+{
+ /*
+ * Having a NULL argv[0], while uncommon, is possible. It
+ * makes more sense to handle this event in uu_setpname rather
+ * than in each of its consumers.
+ */
+ if (arg0 == NULL) {
+ pname = getexecname();
+ if (pname == NULL)
+ pname = "unknown_command";
+ return (pname);
+ }
+
+ /*
+ * Guard against '/' at end of command invocation.
+ */
+ for (;;) {
+ char *p = strrchr(arg0, '/');
+ if (p == NULL) {
+ pname = arg0;
+ break;
+ } else {
+ if (*(p + 1) == '\0') {
+ *p = '\0';
+ continue;
+ }
+
+ pname = p + 1;
+ break;
+ }
+ }
+
+ return (pname);
+}
+
+const char *
+uu_getpname(void)
+{
+ return (pname);
+}
diff --git a/lib/libuutil/uu_strtoint.c b/lib/libuutil/uu_strtoint.c
new file mode 100644
index 000000000..8fd114836
--- /dev/null
+++ b/lib/libuutil/uu_strtoint.c
@@ -0,0 +1,300 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libuutil_common.h"
+
+#include <limits.h>
+#include <ctype.h>
+
+#define MAX_BASE 36
+
+#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9')
+
+#define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \
+ ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A')
+
+static int
+strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign)
+{
+ const unsigned char *s = (const unsigned char *)s_arg;
+
+ uint64_t val = 0;
+ uint64_t multmax;
+
+ unsigned c, i;
+
+ int neg = 0;
+
+ int bad_digit = 0;
+ int bad_char = 0;
+ int overflow = 0;
+
+ if (s == NULL || base == 1 || base > MAX_BASE) {
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+ }
+
+ while ((c = *s) != 0 && isspace(c))
+ s++;
+
+ switch (c) {
+ case '-':
+ if (!sign)
+ overflow = 1; /* becomes underflow below */
+ neg = 1;
+ /*FALLTHRU*/
+ case '+':
+ c = *++s;
+ break;
+ default:
+ break;
+ }
+
+ if (c == '\0') {
+ uu_set_error(UU_ERROR_EMPTY);
+ return (-1);
+ }
+
+ if (base == 0) {
+ if (c != '0')
+ base = 10;
+ else if (s[1] == 'x' || s[1] == 'X')
+ base = 16;
+ else
+ base = 8;
+ }
+
+ if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X'))
+ c = *(s += 2);
+
+ if ((val = CTOI(c)) >= base) {
+ if (IS_DIGIT(c))
+ bad_digit = 1;
+ else
+ bad_char = 1;
+ val = 0;
+ }
+
+ multmax = (uint64_t)UINT64_MAX / (uint64_t)base;
+
+ for (c = *++s; c != '\0'; c = *++s) {
+ if ((i = CTOI(c)) >= base) {
+ if (isspace(c))
+ break;
+ if (IS_DIGIT(c))
+ bad_digit = 1;
+ else
+ bad_char = 1;
+ i = 0;
+ }
+
+ if (val > multmax)
+ overflow = 1;
+
+ val *= base;
+ if ((uint64_t)UINT64_MAX - val < (uint64_t)i)
+ overflow = 1;
+
+ val += i;
+ }
+
+ while ((c = *s) != 0) {
+ if (!isspace(c))
+ bad_char = 1;
+ s++;
+ }
+
+ if (sign) {
+ if (neg) {
+ if (val > -(uint64_t)INT64_MIN)
+ overflow = 1;
+ } else {
+ if (val > INT64_MAX)
+ overflow = 1;
+ }
+ }
+
+ if (neg)
+ val = -val;
+
+ if (bad_char | bad_digit | overflow) {
+ if (bad_char)
+ uu_set_error(UU_ERROR_INVALID_CHAR);
+ else if (bad_digit)
+ uu_set_error(UU_ERROR_INVALID_DIGIT);
+ else if (overflow) {
+ if (neg)
+ uu_set_error(UU_ERROR_UNDERFLOW);
+ else
+ uu_set_error(UU_ERROR_OVERFLOW);
+ }
+ return (-1);
+ }
+
+ *out = val;
+ return (0);
+}
+
+int
+uu_strtoint(const char *s, void *v, size_t sz, int base,
+ int64_t min, int64_t max)
+{
+ uint64_t val_u;
+ int64_t val;
+
+ if (min > max)
+ goto bad_argument;
+
+ switch (sz) {
+ case 1:
+ if (max > INT8_MAX || min < INT8_MIN)
+ goto bad_argument;
+ break;
+ case 2:
+ if (max > INT16_MAX || min < INT16_MIN)
+ goto bad_argument;
+ break;
+ case 4:
+ if (max > INT32_MAX || min < INT32_MIN)
+ goto bad_argument;
+ break;
+ case 8:
+ if (max > INT64_MAX || min < INT64_MIN)
+ goto bad_argument;
+ break;
+ default:
+ goto bad_argument;
+ }
+
+ if (min == 0 && max == 0) {
+ min = -(1ULL << (8 * sz - 1));
+ max = (1ULL << (8 * sz - 1)) - 1;
+ }
+
+ if (strtoint(s, &val_u, base, 1) == -1)
+ return (-1);
+
+ val = (int64_t)val_u;
+
+ if (val < min) {
+ uu_set_error(UU_ERROR_UNDERFLOW);
+ return (-1);
+ } else if (val > max) {
+ uu_set_error(UU_ERROR_OVERFLOW);
+ return (-1);
+ }
+
+ switch (sz) {
+ case 1:
+ *(int8_t *)v = val;
+ return (0);
+ case 2:
+ *(int16_t *)v = val;
+ return (0);
+ case 4:
+ *(int32_t *)v = val;
+ return (0);
+ case 8:
+ *(int64_t *)v = val;
+ return (0);
+ default:
+ break; /* fall through to bad_argument */
+ }
+
+bad_argument:
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+}
+
+int
+uu_strtouint(const char *s, void *v, size_t sz, int base,
+ uint64_t min, uint64_t max)
+{
+ uint64_t val;
+
+ if (min > max)
+ goto bad_argument;
+
+ switch (sz) {
+ case 1:
+ if (max > UINT8_MAX)
+ goto bad_argument;
+ break;
+ case 2:
+ if (max > UINT16_MAX)
+ goto bad_argument;
+ break;
+ case 4:
+ if (max > UINT32_MAX)
+ goto bad_argument;
+ break;
+ case 8:
+ if (max > UINT64_MAX)
+ goto bad_argument;
+ break;
+ default:
+ goto bad_argument;
+ }
+
+ if (min == 0 && max == 0) {
+ /* we have to be careful, since << can overflow */
+ max = (1ULL << (8 * sz - 1)) * 2 - 1;
+ }
+
+ if (strtoint(s, &val, base, 0) == -1)
+ return (-1);
+
+ if (val < min) {
+ uu_set_error(UU_ERROR_UNDERFLOW);
+ return (-1);
+ } else if (val > max) {
+ uu_set_error(UU_ERROR_OVERFLOW);
+ return (-1);
+ }
+
+ switch (sz) {
+ case 1:
+ *(uint8_t *)v = val;
+ return (0);
+ case 2:
+ *(uint16_t *)v = val;
+ return (0);
+ case 4:
+ *(uint32_t *)v = val;
+ return (0);
+ case 8:
+ *(uint64_t *)v = val;
+ return (0);
+ default:
+ break; /* shouldn't happen, fall through */
+ }
+
+bad_argument:
+ uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+ return (-1);
+}