mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-23 02:44:41 +03:00
Move the world out of /zfs/ and seperate out module build tree
This commit is contained in:
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user