Remove files that have been repo copied to their new location
in cddl-specific parts of the source tree.
This commit is contained in:
parent
e327f52446
commit
8f0cc58815
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 John Birrell <jb@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_ALLOCA_H_
|
||||
#define _COMPAT_OPENSOLARIS_ALLOCA_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#endif
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_DEVID_H_
|
||||
#define _OPENSOLARIS_DEVID_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/disk.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct ddi_devid {
|
||||
char devid[DISK_IDENT_SIZE];
|
||||
} ddi_devid_t;
|
||||
|
||||
typedef struct devid_nmlist {
|
||||
char devname[MAXPATHLEN];
|
||||
dev_t dev;
|
||||
} devid_nmlist_t;
|
||||
|
||||
int devid_str_decode(char *devidstr, ddi_devid_t *retdevid,
|
||||
char **retminor_name);
|
||||
int devid_deviceid_to_nmlist(char *search_path, ddi_devid_t devid,
|
||||
char *minor_name, devid_nmlist_t **retlist);
|
||||
void devid_str_free(char *str);
|
||||
void devid_free(ddi_devid_t devid);
|
||||
void devid_free_nmlist(devid_nmlist_t *list);
|
||||
int devid_get(int fd, ddi_devid_t *retdevid);
|
||||
int devid_get_minor_name(int fd, char **retminor_name);
|
||||
char *devid_str_encode(ddi_devid_t devid, char *minor_name);
|
||||
|
||||
#endif /* !_OPENSOLARIS_DEVID_H_ */
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 John Birrell <jb@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_FCNTL_H_
|
||||
#define _COMPAT_OPENSOLARIS_FCNTL_H_
|
||||
|
||||
#include_next <fcntl.h>
|
||||
|
||||
#define open64 open
|
||||
|
||||
#endif
|
@ -1,35 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_FSSHARE_H_
|
||||
#define _OPENSOLARIS_FSSHARE_H_
|
||||
|
||||
int fsshare(const char *, const char *, const char *);
|
||||
int fsunshare(const char *, const char *);
|
||||
|
||||
#endif /* !_OPENSOLARIS_FSSHARE_H_ */
|
@ -1,11 +0,0 @@
|
||||
#ifndef _LIBINTL_H_
|
||||
#define _LIBINTL_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define textdomain(domain) 0
|
||||
#define gettext(...) (__VA_ARGS__)
|
||||
#define dgettext(domain, ...) (__VA_ARGS__)
|
||||
|
||||
#endif /* !_SOLARIS_H_ */
|
@ -1,19 +0,0 @@
|
||||
#ifndef _OPENSOLARIS_MNTTAB_H_
|
||||
#define _OPENSOLARIS_MNTTAB_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <paths.h>
|
||||
|
||||
#define MNTTAB _PATH_DEVNULL
|
||||
#define MNT_LINE_MAX 1024
|
||||
|
||||
struct mnttab {
|
||||
char *mnt_special;
|
||||
char *mnt_mountp;
|
||||
char *mnt_fstype;
|
||||
char *mnt_mntopts;
|
||||
};
|
||||
|
||||
int getmntany(FILE *fd, struct mnttab *mgetp, struct mnttab *mrefp);
|
||||
|
||||
#endif /* !_OPENSOLARIS_MNTTAB_H_ */
|
@ -1,18 +0,0 @@
|
||||
#ifndef _OPENSOLARIS_PRIV_H_
|
||||
#define _OPENSOLARIS_PRIV_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define PRIV_SYS_CONFIG 0
|
||||
|
||||
static __inline int
|
||||
priv_ineffect(priv)
|
||||
{
|
||||
|
||||
assert(priv == PRIV_SYS_CONFIG);
|
||||
return (geteuid() == 0);
|
||||
}
|
||||
|
||||
#endif /* !_OPENSOLARIS_PRIV_H_ */
|
@ -1,8 +0,0 @@
|
||||
#ifndef _SOLARIS_H_
|
||||
#define _SOLARIS_H_
|
||||
|
||||
#include <sys/ccompile.h>
|
||||
|
||||
#define dirent64 dirent
|
||||
|
||||
#endif /* !_SOLARIS_H_ */
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 John Birrell <jb@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_STDIO_H_
|
||||
#define _COMPAT_OPENSOLARIS_STDIO_H_
|
||||
|
||||
#include_next <stdio.h>
|
||||
|
||||
#define ftello64 ftello
|
||||
#define lseek64 lseek
|
||||
#define fseeko64 fseeko
|
||||
|
||||
#endif
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 John Birrell <jb@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_STDLIB_H_
|
||||
#define _COMPAT_OPENSOLARIS_STDLIB_H_
|
||||
|
||||
#include_next <stdlib.h>
|
||||
|
||||
#define getexecname getprogname
|
||||
|
||||
#endif
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 John Birrell <jb@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_STRINGS_H_
|
||||
#define _COMPAT_OPENSOLARIS_STRINGS_H_
|
||||
|
||||
#include_next <strings.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#endif
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 John Birrell <jb@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_UNISTD_H_
|
||||
#define _COMPAT_OPENSOLARIS_UNISTD_H_
|
||||
|
||||
#include_next <unistd.h>
|
||||
|
||||
#define fork1 fork
|
||||
#define ftruncate64 ftruncate
|
||||
#define pread64 pread
|
||||
|
||||
#endif
|
@ -1,6 +0,0 @@
|
||||
#ifndef _ZONE_H_
|
||||
#define _ZONE_H_
|
||||
|
||||
#include <sys/zone.h>
|
||||
|
||||
#endif /* !_ZONE_H_ */
|
@ -1,167 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Ricardo Correia. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#include <umem.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static umem_nofail_callback_t *nofail_cb = NULL;
|
||||
|
||||
struct umem_cache {
|
||||
umem_constructor_t *constructor;
|
||||
umem_destructor_t *destructor;
|
||||
void *callback_data;
|
||||
size_t bufsize;
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple stub for umem_alloc(). The callback isn't expected to return.
|
||||
*/
|
||||
void *umem_alloc(size_t size, int flags)
|
||||
{
|
||||
assert(flags == UMEM_DEFAULT || flags == UMEM_NOFAIL);
|
||||
|
||||
if(size == 0)
|
||||
return NULL;
|
||||
|
||||
void *ret = malloc(size);
|
||||
if(ret == NULL) {
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_zalloc().
|
||||
*/
|
||||
void *umem_zalloc(size_t size, int flags)
|
||||
{
|
||||
assert(flags == UMEM_DEFAULT || flags == UMEM_NOFAIL);
|
||||
|
||||
if(size == 0)
|
||||
return NULL;
|
||||
|
||||
void *ret = calloc(1, size);
|
||||
if(ret == NULL) {
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_free().
|
||||
*/
|
||||
void umem_free(void *buf, size_t size)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_nofail_callback().
|
||||
*/
|
||||
void umem_nofail_callback(umem_nofail_callback_t *callback)
|
||||
{
|
||||
nofail_cb = callback;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_create().
|
||||
*/
|
||||
umem_cache_t *umem_cache_create(char *debug_name, size_t bufsize, size_t align, umem_constructor_t *constructor, umem_destructor_t *destructor, umem_reclaim_t *reclaim, void *callback_data, void *source, int cflags)
|
||||
{
|
||||
assert(source == NULL);
|
||||
|
||||
umem_cache_t *cache = malloc(sizeof(umem_cache_t));
|
||||
if(cache == NULL)
|
||||
return NULL;
|
||||
|
||||
cache->constructor = constructor;
|
||||
cache->destructor = destructor;
|
||||
cache->callback_data = callback_data;
|
||||
cache->bufsize = bufsize;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_alloc(). The nofail callback isn't expected to return.
|
||||
*/
|
||||
void *umem_cache_alloc(umem_cache_t *cache, int flags)
|
||||
{
|
||||
void *buf = malloc(cache->bufsize);
|
||||
if(buf == NULL) {
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
|
||||
if(cache->constructor != NULL) {
|
||||
if(cache->constructor(buf, cache->callback_data, flags) != 0) {
|
||||
free(buf);
|
||||
if(!(flags & UMEM_NOFAIL))
|
||||
return NULL;
|
||||
|
||||
if(nofail_cb != NULL)
|
||||
nofail_cb();
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_free().
|
||||
*/
|
||||
void umem_cache_free(umem_cache_t *cache, void *buffer)
|
||||
{
|
||||
if(cache->destructor != NULL)
|
||||
cache->destructor(buffer, cache->callback_data);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple stub for umem_cache_destroy().
|
||||
*/
|
||||
void umem_cache_destroy(umem_cache_t *cache)
|
||||
{
|
||||
free(cache);
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _UMEM_H
|
||||
#define _UMEM_H
|
||||
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define UMEM_DEFAULT 0x0000 /* normal -- may fail */
|
||||
#define UMEM_NOFAIL 0x0100 /* Never fails -- may call exit(2) */
|
||||
|
||||
#define UMEM_FLAGS 0xffff /* all settable umem flags */
|
||||
|
||||
extern void *umem_alloc(size_t, int);
|
||||
extern void *umem_alloc_align(size_t, size_t, int);
|
||||
extern void *umem_zalloc(size_t, int);
|
||||
extern void umem_free(void *, size_t);
|
||||
extern void umem_free_align(void *, size_t);
|
||||
|
||||
/*
|
||||
* Flags for umem_cache_create()
|
||||
*/
|
||||
#define UMC_NOTOUCH 0x00010000
|
||||
#define UMC_NODEBUG 0x00020000
|
||||
#define UMC_NOMAGAZINE 0x00040000
|
||||
#define UMC_NOHASH 0x00080000
|
||||
|
||||
struct umem_cache; /* cache structure is opaque to umem clients */
|
||||
|
||||
typedef struct umem_cache umem_cache_t;
|
||||
typedef int umem_constructor_t(void *, void *, int);
|
||||
typedef void umem_destructor_t(void *, void *);
|
||||
typedef void umem_reclaim_t(void *);
|
||||
|
||||
typedef int umem_nofail_callback_t(void);
|
||||
#define UMEM_CALLBACK_RETRY 0
|
||||
#define UMEM_CALLBACK_EXIT(status) (0x100 | ((status) & 0xFF))
|
||||
|
||||
extern void umem_nofail_callback(umem_nofail_callback_t *);
|
||||
|
||||
extern umem_cache_t *umem_cache_create(char *, size_t,
|
||||
size_t, umem_constructor_t *, umem_destructor_t *, umem_reclaim_t *,
|
||||
void *, void *, int);
|
||||
extern void umem_cache_destroy(umem_cache_t *);
|
||||
|
||||
extern void *umem_cache_alloc(umem_cache_t *, int);
|
||||
extern void umem_cache_free(umem_cache_t *, void *);
|
||||
|
||||
extern void umem_reap(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _UMEM_H */
|
@ -1,119 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libgeom.h>
|
||||
#include <devid.h>
|
||||
|
||||
int
|
||||
devid_str_decode(char *devidstr, ddi_devid_t *retdevid, char **retminor_name)
|
||||
{
|
||||
|
||||
if (strlcpy(retdevid->devid, devidstr, sizeof(retdevid->devid)) >=
|
||||
sizeof(retdevid->devid)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
*retminor_name = strdup("");
|
||||
if (*retminor_name == NULL);
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
devid_deviceid_to_nmlist(char *search_path, ddi_devid_t devid, char *minor_name,
|
||||
devid_nmlist_t **retlist)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
char *dst;
|
||||
|
||||
if (g_get_name(devid.devid, path, sizeof(path)) == -1)
|
||||
return (errno);
|
||||
*retlist = malloc(sizeof(**retlist));
|
||||
if (*retlist == NULL)
|
||||
return (ENOMEM);
|
||||
if (strlcpy((*retlist)[0].devname, path,
|
||||
sizeof((*retlist)[0].devname)) >= sizeof((*retlist)[0].devname)) {
|
||||
free(*retlist);
|
||||
return (ENAMETOOLONG);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
devid_str_free(char *str)
|
||||
{
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
void
|
||||
devid_free(ddi_devid_t devid)
|
||||
{
|
||||
/* Do nothing. */
|
||||
}
|
||||
|
||||
void
|
||||
devid_free_nmlist(devid_nmlist_t *list)
|
||||
{
|
||||
|
||||
free(list);
|
||||
}
|
||||
|
||||
int
|
||||
devid_get(int fd, ddi_devid_t *retdevid)
|
||||
{
|
||||
|
||||
if (ioctl(fd, DIOCGIDENT, retdevid->devid) == -1)
|
||||
return (errno);
|
||||
if (retdevid->devid[0] == '\0')
|
||||
return (ENOENT);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
devid_get_minor_name(int fd, char **retminor_name)
|
||||
{
|
||||
|
||||
*retminor_name = strdup("");
|
||||
if (*retminor_name == NULL)
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
devid_str_encode(ddi_devid_t devid, char *minor_name)
|
||||
{
|
||||
|
||||
return (strdup(devid.devid));
|
||||
}
|
@ -1,259 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
#include <assert.h>
|
||||
#include <pathnames.h> /* _PATH_MOUNTDPID */
|
||||
#include <fsshare.h>
|
||||
|
||||
#define FILE_HEADER "# !!! DO NOT EDIT THIS FILE MANUALLY !!!\n\n"
|
||||
#define OPTSSIZE 1024
|
||||
#define MAXLINESIZE (PATH_MAX + OPTSSIZE)
|
||||
|
||||
static void
|
||||
restart_mountd(void)
|
||||
{
|
||||
struct pidfh *pfh;
|
||||
pid_t mountdpid;
|
||||
|
||||
pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &mountdpid);
|
||||
if (pfh != NULL) {
|
||||
/* Mountd is not running. */
|
||||
pidfile_remove(pfh);
|
||||
return;
|
||||
}
|
||||
if (errno != EEXIST) {
|
||||
/* Cannot open pidfile for some reason. */
|
||||
return;
|
||||
}
|
||||
/* We have mountd(8) PID in mountdpid varible. */
|
||||
kill(mountdpid, SIGHUP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read one line from a file. Skip comments, empty lines and a line with a
|
||||
* mountpoint specified in the 'skip' argument.
|
||||
*/
|
||||
static char *
|
||||
getline(FILE *fd, const char *skip)
|
||||
{
|
||||
static char line[MAXLINESIZE];
|
||||
size_t len, skiplen;
|
||||
char *s, last;
|
||||
|
||||
if (skip != NULL)
|
||||
skiplen = strlen(skip);
|
||||
for (;;) {
|
||||
s = fgets(line, sizeof(line), fd);
|
||||
if (s == NULL)
|
||||
return (NULL);
|
||||
/* Skip empty lines and comments. */
|
||||
if (line[0] == '\n' || line[0] == '#')
|
||||
continue;
|
||||
len = strlen(line);
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
last = line[skiplen];
|
||||
/* Skip the given mountpoint. */
|
||||
if (skip != NULL && strncmp(skip, line, skiplen) == 0 &&
|
||||
(last == '\t' || last == ' ' || last == '\0')) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function translate options to a format acceptable by exports(5), eg.
|
||||
*
|
||||
* -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org 69.147.83.54
|
||||
*
|
||||
* Accepted input formats:
|
||||
*
|
||||
* ro,network=192.168.0.0,mask=255.255.255.0,maproot=0,freefall.freebsd.org
|
||||
* ro network=192.168.0.0 mask=255.255.255.0 maproot=0 freefall.freebsd.org
|
||||
* -ro,-network=192.168.0.0,-mask=255.255.255.0,-maproot=0,freefall.freebsd.org
|
||||
* -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 freefall.freebsd.org
|
||||
*
|
||||
* Recognized keywords:
|
||||
*
|
||||
* ro, maproot, mapall, mask, network, alldirs, public, webnfs, index, quiet
|
||||
*
|
||||
*/
|
||||
static const char *known_opts[] = { "ro", "maproot", "mapall", "mask",
|
||||
"network", "alldirs", "public", "webnfs", "index", "quiet", NULL };
|
||||
static char *
|
||||
translate_opts(const char *shareopts)
|
||||
{
|
||||
static char newopts[OPTSSIZE];
|
||||
char oldopts[OPTSSIZE];
|
||||
char *o, *s = NULL;
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
|
||||
strlcpy(oldopts, shareopts, sizeof(oldopts));
|
||||
newopts[0] = '\0';
|
||||
s = oldopts;
|
||||
while ((o = strsep(&s, "-, ")) != NULL) {
|
||||
if (o[0] == '\0')
|
||||
continue;
|
||||
for (i = 0; known_opts[i] != NULL; i++) {
|
||||
len = strlen(known_opts[i]);
|
||||
if (strncmp(known_opts[i], o, len) == 0 &&
|
||||
(o[len] == '\0' || o[len] == '=')) {
|
||||
strlcat(newopts, "-", sizeof(newopts));
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlcat(newopts, o, sizeof(newopts));
|
||||
strlcat(newopts, " ", sizeof(newopts));
|
||||
}
|
||||
return (newopts);
|
||||
}
|
||||
|
||||
static int
|
||||
fsshare_main(const char *file, const char *mountpoint, const char *shareopts,
|
||||
int share)
|
||||
{
|
||||
char tmpfile[PATH_MAX];
|
||||
char *line;
|
||||
FILE *newfd, *oldfd;
|
||||
int fd, error;
|
||||
|
||||
newfd = oldfd = NULL;
|
||||
error = 0;
|
||||
|
||||
/*
|
||||
* Create temporary file in the same directory, so we can atomically
|
||||
* rename it.
|
||||
*/
|
||||
if (strlcpy(tmpfile, file, sizeof(tmpfile)) >= sizeof(tmpfile))
|
||||
return (ENAMETOOLONG);
|
||||
if (strlcat(tmpfile, ".XXXXXXXX", sizeof(tmpfile)) >= sizeof(tmpfile))
|
||||
return (ENAMETOOLONG);
|
||||
fd = mkstemp(tmpfile);
|
||||
if (fd == -1)
|
||||
return (errno);
|
||||
/*
|
||||
* File name is random, so we don't really need file lock now, but it
|
||||
* will be needed after rename(2).
|
||||
*/
|
||||
error = flock(fd, LOCK_EX);
|
||||
assert(error == 0 || (error == -1 && errno == EOPNOTSUPP));
|
||||
newfd = fdopen(fd, "r+");
|
||||
assert(newfd != NULL);
|
||||
/* Open old exports file. */
|
||||
oldfd = fopen(file, "r");
|
||||
if (oldfd == NULL) {
|
||||
if (share) {
|
||||
if (errno != ENOENT) {
|
||||
error = errno;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* If there is no exports file, ignore the error. */
|
||||
if (errno == ENOENT)
|
||||
errno = 0;
|
||||
error = errno;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
error = flock(fileno(oldfd), LOCK_EX);
|
||||
assert(error == 0 || (error == -1 && errno == EOPNOTSUPP));
|
||||
error = 0;
|
||||
}
|
||||
|
||||
/* Place big, fat warning at the begining of the file. */
|
||||
fprintf(newfd, "%s", FILE_HEADER);
|
||||
while (oldfd != NULL && (line = getline(oldfd, mountpoint)) != NULL)
|
||||
fprintf(newfd, "%s\n", line);
|
||||
if (oldfd != NULL && ferror(oldfd) != 0) {
|
||||
error = ferror(oldfd);
|
||||
goto out;
|
||||
}
|
||||
if (ferror(newfd) != 0) {
|
||||
error = ferror(newfd);
|
||||
goto out;
|
||||
}
|
||||
if (share) {
|
||||
fprintf(newfd, "%s\t%s\n", mountpoint,
|
||||
translate_opts(shareopts));
|
||||
}
|
||||
|
||||
out:
|
||||
if (error != 0)
|
||||
unlink(tmpfile);
|
||||
else {
|
||||
if (rename(tmpfile, file) == -1) {
|
||||
error = errno;
|
||||
unlink(tmpfile);
|
||||
} else {
|
||||
/*
|
||||
* Send SIGHUP to mountd, but unlock exports file later.
|
||||
*/
|
||||
restart_mountd();
|
||||
}
|
||||
}
|
||||
if (oldfd != NULL) {
|
||||
flock(fileno(oldfd), LOCK_UN);
|
||||
fclose(oldfd);
|
||||
}
|
||||
if (newfd != NULL) {
|
||||
flock(fileno(newfd), LOCK_UN);
|
||||
fclose(newfd);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the given mountpoint to the given exports file.
|
||||
*/
|
||||
int
|
||||
fsshare(const char *file, const char *mountpoint, const char *shareopts)
|
||||
{
|
||||
|
||||
return (fsshare_main(file, mountpoint, shareopts, 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the given mountpoint from the given exports file.
|
||||
*/
|
||||
int
|
||||
fsunshare(const char *file, const char *mountpoint)
|
||||
{
|
||||
|
||||
return (fsshare_main(file, mountpoint, NULL, 0));
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
/*
|
||||
* 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 (c) 1988 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "@(#)mkdirp.c 1.15 06/01/04 SMI"
|
||||
|
||||
/*
|
||||
* Creates directory and it's parents if the parents do not
|
||||
* exist yet.
|
||||
*
|
||||
* Returns -1 if fails for reasons other than non-existing
|
||||
* parents.
|
||||
* Does NOT simplify pathnames with . or .. in them.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static char *simplify(const char *str);
|
||||
|
||||
int
|
||||
mkdirp(const char *d, mode_t mode)
|
||||
{
|
||||
char *endptr, *ptr, *slash, *str;
|
||||
|
||||
str = simplify(d);
|
||||
|
||||
/* If space couldn't be allocated for the simplified names, return. */
|
||||
|
||||
if (str == NULL)
|
||||
return (-1);
|
||||
|
||||
/* Try to make the directory */
|
||||
|
||||
if (mkdir(str, mode) == 0) {
|
||||
free(str);
|
||||
return (0);
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
free(str);
|
||||
return (-1);
|
||||
}
|
||||
endptr = strrchr(str, '\0');
|
||||
slash = strrchr(str, '/');
|
||||
|
||||
/* Search upward for the non-existing parent */
|
||||
|
||||
while (slash != NULL) {
|
||||
|
||||
ptr = slash;
|
||||
*ptr = '\0';
|
||||
|
||||
/* If reached an existing parent, break */
|
||||
|
||||
if (access(str, F_OK) == 0)
|
||||
break;
|
||||
|
||||
/* If non-existing parent */
|
||||
|
||||
else {
|
||||
slash = strrchr(str, '/');
|
||||
|
||||
/* If under / or current directory, make it. */
|
||||
|
||||
if (slash == NULL || slash == str) {
|
||||
if (mkdir(str, mode) != 0 && errno != EEXIST) {
|
||||
free(str);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create directories starting from upmost non-existing parent */
|
||||
|
||||
while ((ptr = strchr(str, '\0')) != endptr) {
|
||||
*ptr = '/';
|
||||
if (mkdir(str, mode) != 0 && errno != EEXIST) {
|
||||
/*
|
||||
* If the mkdir fails because str already
|
||||
* exists (EEXIST), then str has the form
|
||||
* "existing-dir/..", and this is really
|
||||
* ok. (Remember, this loop is creating the
|
||||
* portion of the path that didn't exist)
|
||||
*/
|
||||
free(str);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
free(str);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* simplify - given a pathname, simplify that path by removing
|
||||
* duplicate contiguous slashes.
|
||||
*
|
||||
* A simplified copy of the argument is returned to the
|
||||
* caller, or NULL is returned on error.
|
||||
*
|
||||
* The caller should handle error reporting based upon the
|
||||
* returned vlaue, and should free the returned value,
|
||||
* when appropriate.
|
||||
*/
|
||||
|
||||
static char *
|
||||
simplify(const char *str)
|
||||
{
|
||||
int i;
|
||||
size_t mbPathlen; /* length of multi-byte path */
|
||||
size_t wcPathlen; /* length of wide-character path */
|
||||
wchar_t *wptr; /* scratch pointer */
|
||||
wchar_t *wcPath; /* wide-character version of the path */
|
||||
char *mbPath; /* The copy fo the path to be returned */
|
||||
|
||||
/*
|
||||
* bail out if there is nothing there.
|
||||
*/
|
||||
|
||||
if (!str)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Get a copy of the argument.
|
||||
*/
|
||||
|
||||
if ((mbPath = strdup(str)) == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* convert the multi-byte version of the path to a
|
||||
* wide-character rendering, for doing our figuring.
|
||||
*/
|
||||
|
||||
mbPathlen = strlen(mbPath);
|
||||
|
||||
if ((wcPath = calloc(sizeof (wchar_t), mbPathlen+1)) == NULL) {
|
||||
free(mbPath);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) {
|
||||
free(mbPath);
|
||||
free(wcPath);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove duplicate slashes first ("//../" -> "/")
|
||||
*/
|
||||
|
||||
for (wptr = wcPath, i = 0; i < wcPathlen; i++) {
|
||||
*wptr++ = wcPath[i];
|
||||
|
||||
if (wcPath[i] == '/') {
|
||||
i++;
|
||||
|
||||
while (wcPath[i] == '/') {
|
||||
i++;
|
||||
}
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
*wptr = '\0';
|
||||
|
||||
/*
|
||||
* now convert back to the multi-byte format.
|
||||
*/
|
||||
|
||||
if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) {
|
||||
free(mbPath);
|
||||
free(wcPath);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
free(wcPath);
|
||||
return (mbPath);
|
||||
}
|
@ -1,160 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements Solaris compatible getmntany() and hasmntopt()
|
||||
* functions.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static char *
|
||||
mntopt(char **p)
|
||||
{
|
||||
char *cp = *p;
|
||||
char *retstr;
|
||||
|
||||
while (*cp && isspace(*cp))
|
||||
cp++;
|
||||
|
||||
retstr = cp;
|
||||
while (*cp && *cp != ',')
|
||||
cp++;
|
||||
|
||||
if (*cp) {
|
||||
*cp = '\0';
|
||||
cp++;
|
||||
}
|
||||
|
||||
*p = cp;
|
||||
return (retstr);
|
||||
}
|
||||
|
||||
char *
|
||||
hasmntopt(struct mnttab *mnt, char *opt)
|
||||
{
|
||||
char tmpopts[MNT_LINE_MAX];
|
||||
char *f, *opts = tmpopts;
|
||||
|
||||
if (mnt->mnt_mntopts == NULL)
|
||||
return (NULL);
|
||||
(void) strcpy(opts, mnt->mnt_mntopts);
|
||||
f = mntopt(&opts);
|
||||
for (; *f; f = mntopt(&opts)) {
|
||||
if (strncmp(opt, f, strlen(opt)) == 0)
|
||||
return (f - tmpopts + mnt->mnt_mntopts);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
optadd(char *mntopts, size_t size, const char *opt)
|
||||
{
|
||||
|
||||
if (mntopts[0] != '\0')
|
||||
strlcat(mntopts, ",", size);
|
||||
strlcat(mntopts, opt, size);
|
||||
}
|
||||
|
||||
int
|
||||
getmntany(FILE *fd __unused, struct mnttab *mgetp, struct mnttab *mrefp)
|
||||
{
|
||||
static struct statfs *sfs = NULL;
|
||||
static char mntopts[MNTMAXSTR];
|
||||
struct opt *o;
|
||||
long i, n, flags;
|
||||
|
||||
if (sfs != NULL) {
|
||||
free(sfs);
|
||||
sfs = NULL;
|
||||
}
|
||||
mntopts[0] = '\0';
|
||||
|
||||
n = getfsstat(NULL, 0, MNT_NOWAIT);
|
||||
if (n == -1)
|
||||
return (-1);
|
||||
n = sizeof(*sfs) * (n + 8);
|
||||
sfs = malloc(n);
|
||||
if (sfs == NULL)
|
||||
return (-1);
|
||||
n = getfsstat(sfs, n, MNT_WAIT);
|
||||
if (n == -1) {
|
||||
free(sfs);
|
||||
sfs = NULL;
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
if (mrefp->mnt_special != NULL &&
|
||||
strcmp(mrefp->mnt_special, sfs[i].f_mntfromname) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (mrefp->mnt_mountp != NULL &&
|
||||
strcmp(mrefp->mnt_mountp, sfs[i].f_mntonname) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (mrefp->mnt_fstype != NULL &&
|
||||
strcmp(mrefp->mnt_fstype, sfs[i].f_fstypename) != 0) {
|
||||
continue;
|
||||
}
|
||||
flags = sfs[i].f_flags;
|
||||
#define OPTADD(opt) optadd(mntopts, sizeof(mntopts), (opt))
|
||||
if (flags & MNT_RDONLY)
|
||||
OPTADD(MNTOPT_RO);
|
||||
else
|
||||
OPTADD(MNTOPT_RW);
|
||||
if (flags & MNT_NOSUID)
|
||||
OPTADD(MNTOPT_NOSUID);
|
||||
else
|
||||
OPTADD(MNTOPT_SETUID);
|
||||
if (flags & MNT_UPDATE)
|
||||
OPTADD(MNTOPT_REMOUNT);
|
||||
if (flags & MNT_NOATIME)
|
||||
OPTADD(MNTOPT_NOATIME);
|
||||
else
|
||||
OPTADD(MNTOPT_ATIME);
|
||||
OPTADD(MNTOPT_NOXATTR);
|
||||
if (flags & MNT_NOEXEC)
|
||||
OPTADD(MNTOPT_NOEXEC);
|
||||
else
|
||||
OPTADD(MNTOPT_EXEC);
|
||||
#undef OPTADD
|
||||
mgetp->mnt_special = sfs[i].f_mntfromname;
|
||||
mgetp->mnt_mountp = sfs[i].f_mntonname;
|
||||
mgetp->mnt_fstype = sfs[i].f_fstypename;
|
||||
mgetp->mnt_mntopts = mntopts;
|
||||
return (0);
|
||||
}
|
||||
free(sfs);
|
||||
sfs = NULL;
|
||||
return (-1);
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements Solaris compatible zmount() function.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static void
|
||||
build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
|
||||
size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (*iovlen < 0)
|
||||
return;
|
||||
i = *iovlen;
|
||||
*iov = realloc(*iov, sizeof(**iov) * (i + 2));
|
||||
if (*iov == NULL) {
|
||||
*iovlen = -1;
|
||||
return;
|
||||
}
|
||||
(*iov)[i].iov_base = strdup(name);
|
||||
(*iov)[i].iov_len = strlen(name) + 1;
|
||||
i++;
|
||||
(*iov)[i].iov_base = val;
|
||||
if (len == (size_t)-1) {
|
||||
if (val != NULL)
|
||||
len = strlen(val) + 1;
|
||||
else
|
||||
len = 0;
|
||||
}
|
||||
(*iov)[i].iov_len = (int)len;
|
||||
*iovlen = ++i;
|
||||
}
|
||||
|
||||
int
|
||||
zmount(const char *spec, const char *dir, int mflag, char *fstype,
|
||||
char *dataptr, int datalen, char *optptr, int optlen)
|
||||
{
|
||||
struct iovec *iov;
|
||||
char *optstr, *os, *p;
|
||||
int iovlen, rv;
|
||||
|
||||
assert(spec != NULL);
|
||||
assert(dir != NULL);
|
||||
assert(mflag == 0);
|
||||
assert(fstype != NULL);
|
||||
assert(strcmp(fstype, MNTTYPE_ZFS) == 0);
|
||||
assert(dataptr == NULL);
|
||||
assert(datalen == 0);
|
||||
assert(optptr != NULL);
|
||||
assert(optlen > 0);
|
||||
|
||||
optstr = strdup(optptr);
|
||||
assert(optptr != NULL);
|
||||
|
||||
iov = NULL;
|
||||
iovlen = 0;
|
||||
build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, dir),
|
||||
(size_t)-1);
|
||||
build_iovec(&iov, &iovlen, "from", __DECONST(char *, spec), (size_t)-1);
|
||||
for (p = optstr; p != NULL; strsep(&p, ",/ "))
|
||||
build_iovec(&iov, &iovlen, p, NULL, (size_t)-1);
|
||||
rv = nmount(iov, iovlen, 0);
|
||||
free(optstr);
|
||||
return (rv);
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/zone.h>
|
||||
|
||||
int
|
||||
getzoneid(void)
|
||||
{
|
||||
size_t size;
|
||||
int jailid;
|
||||
|
||||
/* Information that we are in jail or not is enough for our needs. */
|
||||
size = sizeof(jailid);
|
||||
if (sysctlbyname("security.jail.jailed", &jailid, &size, NULL, 0) == -1)
|
||||
assert(!"No security.jail.jailed sysctl!");
|
||||
return (jailid);
|
||||
}
|
@ -1,384 +0,0 @@
|
||||
Unless otherwise noted, all files in this distribution are released
|
||||
under the Common Development and Distribution License (CDDL).
|
||||
Exceptions are noted within the associated source files.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
COMMON DEVELOPMENT AND DISTRIBUTION LICENSE Version 1.0
|
||||
|
||||
1. Definitions.
|
||||
|
||||
1.1. "Contributor" means each individual or entity that creates
|
||||
or contributes to the creation of Modifications.
|
||||
|
||||
1.2. "Contributor Version" means the combination of the Original
|
||||
Software, prior Modifications used by a Contributor (if any),
|
||||
and the Modifications made by that particular Contributor.
|
||||
|
||||
1.3. "Covered Software" means (a) the Original Software, or (b)
|
||||
Modifications, or (c) the combination of files containing
|
||||
Original Software with files containing Modifications, in
|
||||
each case including portions thereof.
|
||||
|
||||
1.4. "Executable" means the Covered Software in any form other
|
||||
than Source Code.
|
||||
|
||||
1.5. "Initial Developer" means the individual or entity that first
|
||||
makes Original Software available under this License.
|
||||
|
||||
1.6. "Larger Work" means a work which combines Covered Software or
|
||||
portions thereof with code not governed by the terms of this
|
||||
License.
|
||||
|
||||
1.7. "License" means this document.
|
||||
|
||||
1.8. "Licensable" means having the right to grant, to the maximum
|
||||
extent possible, whether at the time of the initial grant or
|
||||
subsequently acquired, any and all of the rights conveyed
|
||||
herein.
|
||||
|
||||
1.9. "Modifications" means the Source Code and Executable form of
|
||||
any of the following:
|
||||
|
||||
A. Any file that results from an addition to, deletion from or
|
||||
modification of the contents of a file containing Original
|
||||
Software or previous Modifications;
|
||||
|
||||
B. Any new file that contains any part of the Original
|
||||
Software or previous Modifications; or
|
||||
|
||||
C. Any new file that is contributed or otherwise made
|
||||
available under the terms of this License.
|
||||
|
||||
1.10. "Original Software" means the Source Code and Executable
|
||||
form of computer software code that is originally released
|
||||
under this License.
|
||||
|
||||
1.11. "Patent Claims" means any patent claim(s), now owned or
|
||||
hereafter acquired, including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by
|
||||
grantor.
|
||||
|
||||
1.12. "Source Code" means (a) the common form of computer software
|
||||
code in which modifications are made and (b) associated
|
||||
documentation included in or with such code.
|
||||
|
||||
1.13. "You" (or "Your") means an individual or a legal entity
|
||||
exercising rights under, and complying with all of the terms
|
||||
of, this License. For legal entities, "You" includes any
|
||||
entity which controls, is controlled by, or is under common
|
||||
control with You. For purposes of this definition,
|
||||
"control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by
|
||||
contract or otherwise, or (b) ownership of more than fifty
|
||||
percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants.
|
||||
|
||||
2.1. The Initial Developer Grant.
|
||||
|
||||
Conditioned upon Your compliance with Section 3.1 below and
|
||||
subject to third party intellectual property claims, the Initial
|
||||
Developer hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Initial Developer, to use,
|
||||
reproduce, modify, display, perform, sublicense and
|
||||
distribute the Original Software (or portions thereof),
|
||||
with or without Modifications, and/or as part of a Larger
|
||||
Work; and
|
||||
|
||||
(b) under Patent Claims infringed by the making, using or
|
||||
selling of Original Software, to make, have made, use,
|
||||
practice, sell, and offer for sale, and/or otherwise
|
||||
dispose of the Original Software (or portions thereof).
|
||||
|
||||
(c) The licenses granted in Sections 2.1(a) and (b) are
|
||||
effective on the date Initial Developer first distributes
|
||||
or otherwise makes the Original Software available to a
|
||||
third party under the terms of this License.
|
||||
|
||||
(d) Notwithstanding Section 2.1(b) above, no patent license is
|
||||
granted: (1) for code that You delete from the Original
|
||||
Software, or (2) for infringements caused by: (i) the
|
||||
modification of the Original Software, or (ii) the
|
||||
combination of the Original Software with other software
|
||||
or devices.
|
||||
|
||||
2.2. Contributor Grant.
|
||||
|
||||
Conditioned upon Your compliance with Section 3.1 below and
|
||||
subject to third party intellectual property claims, each
|
||||
Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Contributor to use, reproduce,
|
||||
modify, display, perform, sublicense and distribute the
|
||||
Modifications created by such Contributor (or portions
|
||||
thereof), either on an unmodified basis, with other
|
||||
Modifications, as Covered Software and/or as part of a
|
||||
Larger Work; and
|
||||
|
||||
(b) under Patent Claims infringed by the making, using, or
|
||||
selling of Modifications made by that Contributor either
|
||||
alone and/or in combination with its Contributor Version
|
||||
(or portions of such combination), to make, use, sell,
|
||||
offer for sale, have made, and/or otherwise dispose of:
|
||||
(1) Modifications made by that Contributor (or portions
|
||||
thereof); and (2) the combination of Modifications made by
|
||||
that Contributor with its Contributor Version (or portions
|
||||
of such combination).
|
||||
|
||||
(c) The licenses granted in Sections 2.2(a) and 2.2(b) are
|
||||
effective on the date Contributor first distributes or
|
||||
otherwise makes the Modifications available to a third
|
||||
party.
|
||||
|
||||
(d) Notwithstanding Section 2.2(b) above, no patent license is
|
||||
granted: (1) for any code that Contributor has deleted
|
||||
from the Contributor Version; (2) for infringements caused
|
||||
by: (i) third party modifications of Contributor Version,
|
||||
or (ii) the combination of Modifications made by that
|
||||
Contributor with other software (except as part of the
|
||||
Contributor Version) or other devices; or (3) under Patent
|
||||
Claims infringed by Covered Software in the absence of
|
||||
Modifications made by that Contributor.
|
||||
|
||||
3. Distribution Obligations.
|
||||
|
||||
3.1. Availability of Source Code.
|
||||
|
||||
Any Covered Software that You distribute or otherwise make
|
||||
available in Executable form must also be made available in Source
|
||||
Code form and that Source Code form must be distributed only under
|
||||
the terms of this License. You must include a copy of this
|
||||
License with every copy of the Source Code form of the Covered
|
||||
Software You distribute or otherwise make available. You must
|
||||
inform recipients of any such Covered Software in Executable form
|
||||
as to how they can obtain such Covered Software in Source Code
|
||||
form in a reasonable manner on or through a medium customarily
|
||||
used for software exchange.
|
||||
|
||||
3.2. Modifications.
|
||||
|
||||
The Modifications that You create or to which You contribute are
|
||||
governed by the terms of this License. You represent that You
|
||||
believe Your Modifications are Your original creation(s) and/or
|
||||
You have sufficient rights to grant the rights conveyed by this
|
||||
License.
|
||||
|
||||
3.3. Required Notices.
|
||||
|
||||
You must include a notice in each of Your Modifications that
|
||||
identifies You as the Contributor of the Modification. You may
|
||||
not remove or alter any copyright, patent or trademark notices
|
||||
contained within the Covered Software, or any notices of licensing
|
||||
or any descriptive text giving attribution to any Contributor or
|
||||
the Initial Developer.
|
||||
|
||||
3.4. Application of Additional Terms.
|
||||
|
||||
You may not offer or impose any terms on any Covered Software in
|
||||
Source Code form that alters or restricts the applicable version
|
||||
of this License or the recipients' rights hereunder. You may
|
||||
choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of
|
||||
Covered Software. However, you may do so only on Your own behalf,
|
||||
and not on behalf of the Initial Developer or any Contributor.
|
||||
You must make it absolutely clear that any such warranty, support,
|
||||
indemnity or liability obligation is offered by You alone, and You
|
||||
hereby agree to indemnify the Initial Developer and every
|
||||
Contributor for any liability incurred by the Initial Developer or
|
||||
such Contributor as a result of warranty, support, indemnity or
|
||||
liability terms You offer.
|
||||
|
||||
3.5. Distribution of Executable Versions.
|
||||
|
||||
You may distribute the Executable form of the Covered Software
|
||||
under the terms of this License or under the terms of a license of
|
||||
Your choice, which may contain terms different from this License,
|
||||
provided that You are in compliance with the terms of this License
|
||||
and that the license for the Executable form does not attempt to
|
||||
limit or alter the recipient's rights in the Source Code form from
|
||||
the rights set forth in this License. If You distribute the
|
||||
Covered Software in Executable form under a different license, You
|
||||
must make it absolutely clear that any terms which differ from
|
||||
this License are offered by You alone, not by the Initial
|
||||
Developer or Contributor. You hereby agree to indemnify the
|
||||
Initial Developer and every Contributor for any liability incurred
|
||||
by the Initial Developer or such Contributor as a result of any
|
||||
such terms You offer.
|
||||
|
||||
3.6. Larger Works.
|
||||
|
||||
You may create a Larger Work by combining Covered Software with
|
||||
other code not governed by the terms of this License and
|
||||
distribute the Larger Work as a single product. In such a case,
|
||||
You must make sure the requirements of this License are fulfilled
|
||||
for the Covered Software.
|
||||
|
||||
4. Versions of the License.
|
||||
|
||||
4.1. New Versions.
|
||||
|
||||
Sun Microsystems, Inc. is the initial license steward and may
|
||||
publish revised and/or new versions of this License from time to
|
||||
time. Each version will be given a distinguishing version number.
|
||||
Except as provided in Section 4.3, no one other than the license
|
||||
steward has the right to modify this License.
|
||||
|
||||
4.2. Effect of New Versions.
|
||||
|
||||
You may always continue to use, distribute or otherwise make the
|
||||
Covered Software available under the terms of the version of the
|
||||
License under which You originally received the Covered Software.
|
||||
If the Initial Developer includes a notice in the Original
|
||||
Software prohibiting it from being distributed or otherwise made
|
||||
available under any subsequent version of the License, You must
|
||||
distribute and make the Covered Software available under the terms
|
||||
of the version of the License under which You originally received
|
||||
the Covered Software. Otherwise, You may also choose to use,
|
||||
distribute or otherwise make the Covered Software available under
|
||||
the terms of any subsequent version of the License published by
|
||||
the license steward.
|
||||
|
||||
4.3. Modified Versions.
|
||||
|
||||
When You are an Initial Developer and You want to create a new
|
||||
license for Your Original Software, You may create and use a
|
||||
modified version of this License if You: (a) rename the license
|
||||
and remove any references to the name of the license steward
|
||||
(except to note that the license differs from this License); and
|
||||
(b) otherwise make it clear that the license contains terms which
|
||||
differ from this License.
|
||||
|
||||
5. DISCLAIMER OF WARRANTY.
|
||||
|
||||
COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
|
||||
BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
|
||||
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
|
||||
SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
|
||||
PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
|
||||
PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
|
||||
COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
|
||||
INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
|
||||
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
|
||||
WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
|
||||
ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
|
||||
DISCLAIMER.
|
||||
|
||||
6. TERMINATION.
|
||||
|
||||
6.1. This License and the rights granted hereunder will terminate
|
||||
automatically if You fail to comply with terms herein and fail to
|
||||
cure such breach within 30 days of becoming aware of the breach.
|
||||
Provisions which, by their nature, must remain in effect beyond
|
||||
the termination of this License shall survive.
|
||||
|
||||
6.2. If You assert a patent infringement claim (excluding
|
||||
declaratory judgment actions) against Initial Developer or a
|
||||
Contributor (the Initial Developer or Contributor against whom You
|
||||
assert such claim is referred to as "Participant") alleging that
|
||||
the Participant Software (meaning the Contributor Version where
|
||||
the Participant is a Contributor or the Original Software where
|
||||
the Participant is the Initial Developer) directly or indirectly
|
||||
infringes any patent, then any and all rights granted directly or
|
||||
indirectly to You by such Participant, the Initial Developer (if
|
||||
the Initial Developer is not the Participant) and all Contributors
|
||||
under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
|
||||
notice from Participant terminate prospectively and automatically
|
||||
at the expiration of such 60 day notice period, unless if within
|
||||
such 60 day period You withdraw Your claim with respect to the
|
||||
Participant Software against such Participant either unilaterally
|
||||
or pursuant to a written agreement with Participant.
|
||||
|
||||
6.3. In the event of termination under Sections 6.1 or 6.2 above,
|
||||
all end user licenses that have been validly granted by You or any
|
||||
distributor hereunder prior to termination (excluding licenses
|
||||
granted to You by any distributor) shall survive termination.
|
||||
|
||||
7. LIMITATION OF LIABILITY.
|
||||
|
||||
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
|
||||
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
|
||||
INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
|
||||
COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
|
||||
LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
|
||||
CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
|
||||
LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
|
||||
STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
|
||||
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
|
||||
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
|
||||
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
|
||||
INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
|
||||
APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
|
||||
NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
|
||||
APPLY TO YOU.
|
||||
|
||||
8. U.S. GOVERNMENT END USERS.
|
||||
|
||||
The Covered Software is a "commercial item," as that term is
|
||||
defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
|
||||
computer software" (as that term is defined at 48
|
||||
C.F.R. 252.227-7014(a)(1)) and "commercial computer software
|
||||
documentation" as such terms are used in 48 C.F.R. 12.212
|
||||
(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48
|
||||
C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
|
||||
U.S. Government End Users acquire Covered Software with only those
|
||||
rights set forth herein. This U.S. Government Rights clause is in
|
||||
lieu of, and supersedes, any other FAR, DFAR, or other clause or
|
||||
provision that addresses Government rights in computer software
|
||||
under this License.
|
||||
|
||||
9. MISCELLANEOUS.
|
||||
|
||||
This License represents the complete agreement concerning subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. This License shall be governed
|
||||
by the law of the jurisdiction specified in a notice contained
|
||||
within the Original Software (except to the extent applicable law,
|
||||
if any, provides otherwise), excluding such jurisdiction's
|
||||
conflict-of-law provisions. Any litigation relating to this
|
||||
License shall be subject to the jurisdiction of the courts located
|
||||
in the jurisdiction and venue specified in a notice contained
|
||||
within the Original Software, with the losing party responsible
|
||||
for costs, including, without limitation, court costs and
|
||||
reasonable attorneys' fees and expenses. The application of the
|
||||
United Nations Convention on Contracts for the International Sale
|
||||
of Goods is expressly excluded. Any law or regulation which
|
||||
provides that the language of a contract shall be construed
|
||||
against the drafter shall not apply to this License. You agree
|
||||
that You alone are responsible for compliance with the United
|
||||
States export administration regulations (and the export control
|
||||
laws and regulation of any other countries) when You use,
|
||||
distribute or otherwise make available any Covered Software.
|
||||
|
||||
10. RESPONSIBILITY FOR CLAIMS.
|
||||
|
||||
As between Initial Developer and the Contributors, each party is
|
||||
responsible for claims and damages arising, directly or
|
||||
indirectly, out of its utilization of rights under this License
|
||||
and You agree to work with Initial Developer and Contributors to
|
||||
distribute such responsibility on an equitable basis. Nothing
|
||||
herein is intended or shall be deemed to constitute any admission
|
||||
of liability.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND
|
||||
DISTRIBUTION LICENSE (CDDL)
|
||||
|
||||
For Covered Software in this distribution, this License shall
|
||||
be governed by the laws of the State of California (excluding
|
||||
conflict-of-law provisions).
|
||||
|
||||
Any litigation relating to this License shall be subject to the
|
||||
jurisdiction of the Federal Courts of the Northern District of
|
||||
California and the state courts of the State of California, with
|
||||
venue lying in Santa Clara County, California.
|
@ -1,93 +0,0 @@
|
||||
'\" te
|
||||
.\" 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 (c) 2004, Sun Microsystems, Inc. All Rights Reserved.
|
||||
.TH zdb 1M "31 Oct 2005" "SunOS 5.11" "System Administration Commands"
|
||||
.SH NAME
|
||||
zdb \- ZFS debugger
|
||||
.SH SYNOPSIS
|
||||
.LP
|
||||
.nf
|
||||
\fBzdb\fR \fIpool\fR
|
||||
.fi
|
||||
|
||||
.SH DESCRIPTION
|
||||
.LP
|
||||
The \fBzdb\fR command is used by support engineers to diagnose failures and gather statistics. Since the \fBZFS\fR file system is always consistent on disk and is self-repairing, \fBzdb\fR should only be run under the direction by a support engineer.
|
||||
.LP
|
||||
If no arguments are specified, \fBzdb\fR, performs basic consistency checks on the pool and associated datasets, and report any problems detected.
|
||||
.LP
|
||||
Any options supported by this command are internal to Sun and subject to change at any time.
|
||||
.SH EXIT STATUS
|
||||
.LP
|
||||
The following exit values are returned:
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
.na
|
||||
\fB\fB0\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.rt
|
||||
The pool is consistent.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
.na
|
||||
\fB\fB1\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.rt
|
||||
An error was detected.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.mk
|
||||
.na
|
||||
\fB\fB2\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.rt
|
||||
Invalid command line options were specified.
|
||||
.RE
|
||||
|
||||
.SH ATTRIBUTES
|
||||
.LP
|
||||
See \fBattributes\fR(5) for descriptions of the following attributes:
|
||||
.sp
|
||||
|
||||
.sp
|
||||
.TS
|
||||
tab() box;
|
||||
cw(2.75i) |cw(2.75i)
|
||||
lw(2.75i) |lw(2.75i)
|
||||
.
|
||||
ATTRIBUTE TYPEATTRIBUTE VALUE
|
||||
_
|
||||
AvailabilitySUNWzfsu
|
||||
_
|
||||
Interface StabilityUnstable
|
||||
.TE
|
||||
|
||||
.SH SEE ALSO
|
||||
.LP
|
||||
\fBzfs\fR(1M), \fBzpool\fR(1M), \fBattributes\fR(5)
|
File diff suppressed because it is too large
Load Diff
@ -1,354 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Print intent log header and statistics.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/zil.h>
|
||||
#include <sys/zil_impl.h>
|
||||
|
||||
extern uint8_t dump_opt[256];
|
||||
|
||||
static void
|
||||
print_log_bp(const blkptr_t *bp, const char *prefix)
|
||||
{
|
||||
char blkbuf[BP_SPRINTF_LEN];
|
||||
|
||||
sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, bp);
|
||||
(void) printf("%s%s\n", prefix, blkbuf);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_create(zilog_t *zilog, int txtype, lr_create_t *lr)
|
||||
{
|
||||
time_t crtime = lr->lr_crtime[0];
|
||||
char *name = (char *)(lr + 1);
|
||||
char *link = name + strlen(name) + 1;
|
||||
|
||||
if (txtype == TX_SYMLINK)
|
||||
(void) printf("\t\t\t%s -> %s\n", name, link);
|
||||
else
|
||||
(void) printf("\t\t\t%s\n", name);
|
||||
|
||||
(void) printf("\t\t\t%s", ctime(&crtime));
|
||||
(void) printf("\t\t\tdoid %llu, foid %llu, mode %llo\n",
|
||||
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_foid,
|
||||
(longlong_t)lr->lr_mode);
|
||||
(void) printf("\t\t\tuid %llu, gid %llu, gen %llu, rdev 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid,
|
||||
(u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_remove(zilog_t *zilog, int txtype, lr_remove_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tdoid %llu, name %s\n",
|
||||
(u_longlong_t)lr->lr_doid, (char *)(lr + 1));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_link(zilog_t *zilog, int txtype, lr_link_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tdoid %llu, link_obj %llu, name %s\n",
|
||||
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
|
||||
(char *)(lr + 1));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_rename(zilog_t *zilog, int txtype, lr_rename_t *lr)
|
||||
{
|
||||
char *snm = (char *)(lr + 1);
|
||||
char *tnm = snm + strlen(snm) + 1;
|
||||
|
||||
(void) printf("\t\t\tsdoid %llu, tdoid %llu\n",
|
||||
(u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
|
||||
(void) printf("\t\t\tsrc %s tgt %s\n", snm, tnm);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
|
||||
{
|
||||
char *data, *dlimit;
|
||||
blkptr_t *bp = &lr->lr_blkptr;
|
||||
char buf[SPA_MAXBLOCKSIZE];
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
int error;
|
||||
|
||||
(void) printf("\t\t\tfoid %llu, offset 0x%llx,"
|
||||
" length 0x%llx, blkoff 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
|
||||
(u_longlong_t)lr->lr_length, (u_longlong_t)lr->lr_blkoff);
|
||||
|
||||
if (verbose < 5)
|
||||
return;
|
||||
|
||||
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
|
||||
(void) printf("\t\t\thas blkptr, %s\n",
|
||||
bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
|
||||
"will claim" : "won't claim");
|
||||
print_log_bp(bp, "\t\t\t");
|
||||
if (bp->blk_birth == 0) {
|
||||
bzero(buf, sizeof (buf));
|
||||
} else {
|
||||
zbookmark_t zb;
|
||||
|
||||
ASSERT3U(bp->blk_cksum.zc_word[ZIL_ZC_OBJSET], ==,
|
||||
dmu_objset_id(zilog->zl_os));
|
||||
|
||||
zb.zb_objset = bp->blk_cksum.zc_word[ZIL_ZC_OBJSET];
|
||||
zb.zb_object = 0;
|
||||
zb.zb_level = -1;
|
||||
zb.zb_blkid = bp->blk_cksum.zc_word[ZIL_ZC_SEQ];
|
||||
|
||||
error = zio_wait(zio_read(NULL, zilog->zl_spa,
|
||||
bp, buf, BP_GET_LSIZE(bp), NULL, NULL,
|
||||
ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
|
||||
if (error)
|
||||
return;
|
||||
}
|
||||
data = buf + lr->lr_blkoff;
|
||||
} else {
|
||||
data = (char *)(lr + 1);
|
||||
}
|
||||
|
||||
dlimit = data + MIN(lr->lr_length,
|
||||
(verbose < 6 ? 20 : SPA_MAXBLOCKSIZE));
|
||||
|
||||
(void) printf("\t\t\t");
|
||||
while (data < dlimit) {
|
||||
if (isprint(*data))
|
||||
(void) printf("%c ", *data);
|
||||
else
|
||||
(void) printf("%2X", *data);
|
||||
data++;
|
||||
}
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_truncate(zilog_t *zilog, int txtype, lr_truncate_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tfoid %llu, offset 0x%llx, length 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
|
||||
(u_longlong_t)lr->lr_length);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_setattr(zilog_t *zilog, int txtype, lr_setattr_t *lr)
|
||||
{
|
||||
time_t atime = (time_t)lr->lr_atime[0];
|
||||
time_t mtime = (time_t)lr->lr_mtime[0];
|
||||
|
||||
(void) printf("\t\t\tfoid %llu, mask 0x%llx\n",
|
||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
|
||||
|
||||
if (lr->lr_mask & AT_MODE) {
|
||||
(void) printf("\t\t\tAT_MODE %llo\n",
|
||||
(longlong_t)lr->lr_mode);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_UID) {
|
||||
(void) printf("\t\t\tAT_UID %llu\n",
|
||||
(u_longlong_t)lr->lr_uid);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_GID) {
|
||||
(void) printf("\t\t\tAT_GID %llu\n",
|
||||
(u_longlong_t)lr->lr_gid);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_SIZE) {
|
||||
(void) printf("\t\t\tAT_SIZE %llu\n",
|
||||
(u_longlong_t)lr->lr_size);
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_ATIME) {
|
||||
(void) printf("\t\t\tAT_ATIME %llu.%09llu %s",
|
||||
(u_longlong_t)lr->lr_atime[0],
|
||||
(u_longlong_t)lr->lr_atime[1],
|
||||
ctime(&atime));
|
||||
}
|
||||
|
||||
if (lr->lr_mask & AT_MTIME) {
|
||||
(void) printf("\t\t\tAT_MTIME %llu.%09llu %s",
|
||||
(u_longlong_t)lr->lr_mtime[0],
|
||||
(u_longlong_t)lr->lr_mtime[1],
|
||||
ctime(&mtime));
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
zil_prt_rec_acl(zilog_t *zilog, int txtype, lr_acl_t *lr)
|
||||
{
|
||||
(void) printf("\t\t\tfoid %llu, aclcnt %llu\n",
|
||||
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
|
||||
}
|
||||
|
||||
typedef void (*zil_prt_rec_func_t)();
|
||||
typedef struct zil_rec_info {
|
||||
zil_prt_rec_func_t zri_print;
|
||||
char *zri_name;
|
||||
uint64_t zri_count;
|
||||
} zil_rec_info_t;
|
||||
|
||||
static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
|
||||
{ NULL, "Total " },
|
||||
{ zil_prt_rec_create, "TX_CREATE " },
|
||||
{ zil_prt_rec_create, "TX_MKDIR " },
|
||||
{ zil_prt_rec_create, "TX_MKXATTR " },
|
||||
{ zil_prt_rec_create, "TX_SYMLINK " },
|
||||
{ zil_prt_rec_remove, "TX_REMOVE " },
|
||||
{ zil_prt_rec_remove, "TX_RMDIR " },
|
||||
{ zil_prt_rec_link, "TX_LINK " },
|
||||
{ zil_prt_rec_rename, "TX_RENAME " },
|
||||
{ zil_prt_rec_write, "TX_WRITE " },
|
||||
{ zil_prt_rec_truncate, "TX_TRUNCATE" },
|
||||
{ zil_prt_rec_setattr, "TX_SETATTR " },
|
||||
{ zil_prt_rec_acl, "TX_ACL " },
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
|
||||
{
|
||||
int txtype;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
|
||||
txtype = lr->lrc_txtype;
|
||||
|
||||
ASSERT(txtype != 0 && (uint_t)txtype < TX_MAX_TYPE);
|
||||
ASSERT(lr->lrc_txg);
|
||||
|
||||
(void) printf("\t\t%s len %6llu, txg %llu, seq %llu\n",
|
||||
zil_rec_info[txtype].zri_name,
|
||||
(u_longlong_t)lr->lrc_reclen,
|
||||
(u_longlong_t)lr->lrc_txg,
|
||||
(u_longlong_t)lr->lrc_seq);
|
||||
|
||||
if (txtype && verbose >= 3)
|
||||
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
|
||||
|
||||
zil_rec_info[txtype].zri_count++;
|
||||
zil_rec_info[0].zri_count++;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
|
||||
{
|
||||
char blkbuf[BP_SPRINTF_LEN];
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
char *claim;
|
||||
|
||||
if (verbose <= 3)
|
||||
return;
|
||||
|
||||
if (verbose >= 5) {
|
||||
(void) strcpy(blkbuf, ", ");
|
||||
sprintf_blkptr(blkbuf + strlen(blkbuf),
|
||||
BP_SPRINTF_LEN - strlen(blkbuf), bp);
|
||||
} else {
|
||||
blkbuf[0] = '\0';
|
||||
}
|
||||
|
||||
if (claim_txg != 0)
|
||||
claim = "already claimed";
|
||||
else if (bp->blk_birth >= spa_first_txg(zilog->zl_spa))
|
||||
claim = "will claim";
|
||||
else
|
||||
claim = "won't claim";
|
||||
|
||||
(void) printf("\tBlock seqno %llu, %s%s\n",
|
||||
(u_longlong_t)bp->blk_cksum.zc_word[ZIL_ZC_SEQ], claim, blkbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
print_log_stats(int verbose)
|
||||
{
|
||||
int i, w, p10;
|
||||
|
||||
if (verbose > 3)
|
||||
(void) printf("\n");
|
||||
|
||||
if (zil_rec_info[0].zri_count == 0)
|
||||
return;
|
||||
|
||||
for (w = 1, p10 = 10; zil_rec_info[0].zri_count >= p10; p10 *= 10)
|
||||
w++;
|
||||
|
||||
for (i = 0; i < TX_MAX_TYPE; i++)
|
||||
if (zil_rec_info[i].zri_count || verbose >= 3)
|
||||
(void) printf("\t\t%s %*llu\n",
|
||||
zil_rec_info[i].zri_name, w,
|
||||
(u_longlong_t)zil_rec_info[i].zri_count);
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
dump_intent_log(zilog_t *zilog)
|
||||
{
|
||||
const zil_header_t *zh = zilog->zl_header;
|
||||
int verbose = MAX(dump_opt['d'], dump_opt['i']);
|
||||
int i;
|
||||
|
||||
if (zh->zh_log.blk_birth == 0 || verbose < 2)
|
||||
return;
|
||||
|
||||
(void) printf("\n ZIL header: claim_txg %llu, seq %llu\n",
|
||||
(u_longlong_t)zh->zh_claim_txg, (u_longlong_t)zh->zh_replay_seq);
|
||||
|
||||
if (verbose >= 4)
|
||||
print_log_bp(&zh->zh_log, "\n\tfirst block: ");
|
||||
|
||||
for (i = 0; i < TX_MAX_TYPE; i++)
|
||||
zil_rec_info[i].zri_count = 0;
|
||||
|
||||
if (verbose >= 2) {
|
||||
(void) printf("\n");
|
||||
(void) zil_parse(zilog, print_log_block, print_log_record, NULL,
|
||||
zh->zh_claim_txg);
|
||||
print_log_stats(verbose);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,405 +0,0 @@
|
||||
/*
|
||||
* 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 <libintl.h>
|
||||
#include <libuutil.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "zfs_util.h"
|
||||
#include "zfs_iter.h"
|
||||
|
||||
/*
|
||||
* This is a private interface used to gather up all the datasets specified on
|
||||
* the command line so that we can iterate over them in order.
|
||||
*
|
||||
* First, we iterate over all filesystems, gathering them together into an
|
||||
* AVL tree. We report errors for any explicitly specified datasets
|
||||
* that we couldn't open.
|
||||
*
|
||||
* When finished, we have an AVL tree of ZFS handles. We go through and execute
|
||||
* the provided callback for each one, passing whatever data the user supplied.
|
||||
*/
|
||||
|
||||
typedef struct zfs_node {
|
||||
zfs_handle_t *zn_handle;
|
||||
uu_avl_node_t zn_avlnode;
|
||||
} zfs_node_t;
|
||||
|
||||
typedef struct callback_data {
|
||||
uu_avl_t *cb_avl;
|
||||
int cb_recurse;
|
||||
zfs_type_t cb_types;
|
||||
zfs_sort_column_t *cb_sortcol;
|
||||
zfs_proplist_t **cb_proplist;
|
||||
} callback_data_t;
|
||||
|
||||
uu_avl_pool_t *avl_pool;
|
||||
|
||||
/*
|
||||
* Called for each dataset. If the object the object is of an appropriate type,
|
||||
* add it to the avl tree and recurse over any children as necessary.
|
||||
*/
|
||||
int
|
||||
zfs_callback(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
callback_data_t *cb = data;
|
||||
int dontclose = 0;
|
||||
|
||||
/*
|
||||
* If this object is of the appropriate type, add it to the AVL tree.
|
||||
*/
|
||||
if (zfs_get_type(zhp) & cb->cb_types) {
|
||||
uu_avl_index_t idx;
|
||||
zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));
|
||||
|
||||
node->zn_handle = zhp;
|
||||
uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
|
||||
if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
|
||||
&idx) == NULL) {
|
||||
if (cb->cb_proplist &&
|
||||
zfs_expand_proplist(zhp, cb->cb_proplist) != 0) {
|
||||
free(node);
|
||||
return (-1);
|
||||
}
|
||||
uu_avl_insert(cb->cb_avl, node, idx);
|
||||
dontclose = 1;
|
||||
} else {
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recurse if necessary.
|
||||
*/
|
||||
if (cb->cb_recurse && (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM ||
|
||||
(zfs_get_type(zhp) == ZFS_TYPE_VOLUME && (cb->cb_types &
|
||||
ZFS_TYPE_SNAPSHOT))))
|
||||
(void) zfs_iter_children(zhp, zfs_callback, data);
|
||||
|
||||
if (!dontclose)
|
||||
zfs_close(zhp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_add_sort_column(zfs_sort_column_t **sc, const char *name,
|
||||
boolean_t reverse)
|
||||
{
|
||||
zfs_sort_column_t *col;
|
||||
zfs_prop_t prop;
|
||||
|
||||
if ((prop = zfs_name_to_prop(name)) == ZFS_PROP_INVAL &&
|
||||
!zfs_prop_user(name))
|
||||
return (-1);
|
||||
|
||||
col = safe_malloc(sizeof (zfs_sort_column_t));
|
||||
|
||||
col->sc_prop = prop;
|
||||
col->sc_reverse = reverse;
|
||||
if (prop == ZFS_PROP_INVAL) {
|
||||
col->sc_user_prop = safe_malloc(strlen(name) + 1);
|
||||
(void) strcpy(col->sc_user_prop, name);
|
||||
}
|
||||
|
||||
if (*sc == NULL) {
|
||||
col->sc_last = col;
|
||||
*sc = col;
|
||||
} else {
|
||||
(*sc)->sc_last->sc_next = col;
|
||||
(*sc)->sc_last = col;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
zfs_free_sort_columns(zfs_sort_column_t *sc)
|
||||
{
|
||||
zfs_sort_column_t *col;
|
||||
|
||||
while (sc != NULL) {
|
||||
col = sc->sc_next;
|
||||
free(sc->sc_user_prop);
|
||||
free(sc);
|
||||
sc = col;
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zfs_compare(const void *larg, const void *rarg, void *unused)
|
||||
{
|
||||
zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
|
||||
zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
|
||||
const char *lname = zfs_get_name(l);
|
||||
const char *rname = zfs_get_name(r);
|
||||
char *lat, *rat;
|
||||
uint64_t lcreate, rcreate;
|
||||
int ret;
|
||||
|
||||
lat = (char *)strchr(lname, '@');
|
||||
rat = (char *)strchr(rname, '@');
|
||||
|
||||
if (lat != NULL)
|
||||
*lat = '\0';
|
||||
if (rat != NULL)
|
||||
*rat = '\0';
|
||||
|
||||
ret = strcmp(lname, rname);
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* If we're comparing a dataset to one of its snapshots, we
|
||||
* always make the full dataset first.
|
||||
*/
|
||||
if (lat == NULL) {
|
||||
ret = -1;
|
||||
} else if (rat == NULL) {
|
||||
ret = 1;
|
||||
} else {
|
||||
/*
|
||||
* If we have two snapshots from the same dataset, then
|
||||
* we want to sort them according to creation time. We
|
||||
* use the hidden CREATETXG property to get an absolute
|
||||
* ordering of snapshots.
|
||||
*/
|
||||
lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
|
||||
rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
|
||||
|
||||
if (lcreate < rcreate)
|
||||
ret = -1;
|
||||
else if (lcreate > rcreate)
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lat != NULL)
|
||||
*lat = '@';
|
||||
if (rat != NULL)
|
||||
*rat = '@';
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort datasets by specified columns.
|
||||
*
|
||||
* o Numeric types sort in ascending order.
|
||||
* o String types sort in alphabetical order.
|
||||
* o Types inappropriate for a row sort that row to the literal
|
||||
* bottom, regardless of the specified ordering.
|
||||
*
|
||||
* If no sort columns are specified, or two datasets compare equally
|
||||
* across all specified columns, they are sorted alphabetically by name
|
||||
* with snapshots grouped under their parents.
|
||||
*/
|
||||
static int
|
||||
zfs_sort(const void *larg, const void *rarg, void *data)
|
||||
{
|
||||
zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
|
||||
zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
|
||||
zfs_sort_column_t *sc = (zfs_sort_column_t *)data;
|
||||
zfs_sort_column_t *psc;
|
||||
|
||||
for (psc = sc; psc != NULL; psc = psc->sc_next) {
|
||||
char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN];
|
||||
char *lstr, *rstr;
|
||||
uint64_t lnum, rnum;
|
||||
boolean_t lvalid, rvalid;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* We group the checks below the generic code. If 'lstr' and
|
||||
* 'rstr' are non-NULL, then we do a string based comparison.
|
||||
* Otherwise, we compare 'lnum' and 'rnum'.
|
||||
*/
|
||||
lstr = rstr = NULL;
|
||||
if (psc->sc_prop == ZFS_PROP_INVAL) {
|
||||
nvlist_t *luser, *ruser;
|
||||
nvlist_t *lval, *rval;
|
||||
|
||||
luser = zfs_get_user_props(l);
|
||||
ruser = zfs_get_user_props(r);
|
||||
|
||||
lvalid = (nvlist_lookup_nvlist(luser,
|
||||
psc->sc_user_prop, &lval) == 0);
|
||||
rvalid = (nvlist_lookup_nvlist(ruser,
|
||||
psc->sc_user_prop, &rval) == 0);
|
||||
|
||||
if (lvalid)
|
||||
verify(nvlist_lookup_string(lval,
|
||||
ZFS_PROP_VALUE, &lstr) == 0);
|
||||
if (rvalid)
|
||||
verify(nvlist_lookup_string(rval,
|
||||
ZFS_PROP_VALUE, &rstr) == 0);
|
||||
|
||||
} else if (zfs_prop_is_string(psc->sc_prop)) {
|
||||
lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
|
||||
sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
|
||||
rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf,
|
||||
sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0);
|
||||
|
||||
lstr = lbuf;
|
||||
rstr = rbuf;
|
||||
} else {
|
||||
lvalid = zfs_prop_valid_for_type(psc->sc_prop,
|
||||
zfs_get_type(l));
|
||||
rvalid = zfs_prop_valid_for_type(psc->sc_prop,
|
||||
zfs_get_type(r));
|
||||
|
||||
if (lvalid)
|
||||
(void) zfs_prop_get_numeric(l, psc->sc_prop,
|
||||
&lnum, NULL, NULL, 0);
|
||||
if (rvalid)
|
||||
(void) zfs_prop_get_numeric(r, psc->sc_prop,
|
||||
&rnum, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
if (!lvalid && !rvalid)
|
||||
continue;
|
||||
else if (!lvalid)
|
||||
return (1);
|
||||
else if (!rvalid)
|
||||
return (-1);
|
||||
|
||||
if (lstr)
|
||||
ret = strcmp(lstr, rstr);
|
||||
if (lnum < rnum)
|
||||
ret = -1;
|
||||
else if (lnum > rnum)
|
||||
ret = 1;
|
||||
|
||||
if (ret != 0) {
|
||||
if (psc->sc_reverse == B_TRUE)
|
||||
ret = (ret < 0) ? 1 : -1;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
return (zfs_compare(larg, rarg, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
zfs_for_each(int argc, char **argv, boolean_t recurse, zfs_type_t types,
|
||||
zfs_sort_column_t *sortcol, zfs_proplist_t **proplist, zfs_iter_f callback,
|
||||
void *data, boolean_t args_can_be_paths)
|
||||
{
|
||||
callback_data_t cb;
|
||||
int ret = 0;
|
||||
zfs_node_t *node;
|
||||
uu_avl_walk_t *walk;
|
||||
|
||||
avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t),
|
||||
offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT);
|
||||
|
||||
if (avl_pool == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cb.cb_sortcol = sortcol;
|
||||
cb.cb_recurse = recurse;
|
||||
cb.cb_proplist = proplist;
|
||||
cb.cb_types = types;
|
||||
if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
/*
|
||||
* If given no arguments, iterate over all datasets.
|
||||
*/
|
||||
cb.cb_recurse = 1;
|
||||
ret = zfs_iter_root(g_zfs, zfs_callback, &cb);
|
||||
} else {
|
||||
int i;
|
||||
zfs_handle_t *zhp;
|
||||
zfs_type_t argtype;
|
||||
|
||||
/*
|
||||
* If we're recursive, then we always allow filesystems as
|
||||
* arguments. If we also are interested in snapshots, then we
|
||||
* can take volumes as well.
|
||||
*/
|
||||
argtype = types;
|
||||
if (recurse) {
|
||||
argtype |= ZFS_TYPE_FILESYSTEM;
|
||||
if (types & ZFS_TYPE_SNAPSHOT)
|
||||
argtype |= ZFS_TYPE_VOLUME;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (args_can_be_paths) {
|
||||
zhp = zfs_path_to_zhandle(g_zfs, argv[i],
|
||||
argtype);
|
||||
} else {
|
||||
zhp = zfs_open(g_zfs, argv[i], argtype);
|
||||
}
|
||||
if (zhp != NULL)
|
||||
ret |= zfs_callback(zhp, &cb);
|
||||
else
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point we've got our AVL tree full of zfs handles, so iterate
|
||||
* over each one and execute the real user callback.
|
||||
*/
|
||||
for (node = uu_avl_first(cb.cb_avl); node != NULL;
|
||||
node = uu_avl_next(cb.cb_avl, node))
|
||||
ret |= callback(node->zn_handle, data);
|
||||
|
||||
/*
|
||||
* Finally, clean up the AVL tree.
|
||||
*/
|
||||
if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((node = uu_avl_walk_next(walk)) != NULL) {
|
||||
uu_avl_remove(cb.cb_avl, node);
|
||||
zfs_close(node->zn_handle);
|
||||
free(node);
|
||||
}
|
||||
|
||||
uu_avl_walk_end(walk);
|
||||
uu_avl_destroy(cb.cb_avl);
|
||||
uu_avl_pool_destroy(avl_pool);
|
||||
|
||||
return (ret);
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ZFS_ITER_H
|
||||
#define ZFS_ITER_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct zfs_sort_column {
|
||||
struct zfs_sort_column *sc_next;
|
||||
struct zfs_sort_column *sc_last;
|
||||
zfs_prop_t sc_prop;
|
||||
char *sc_user_prop;
|
||||
boolean_t sc_reverse;
|
||||
} zfs_sort_column_t;
|
||||
|
||||
int zfs_for_each(int, char **, boolean_t, zfs_type_t, zfs_sort_column_t *,
|
||||
zfs_proplist_t **, zfs_iter_f, void *, boolean_t);
|
||||
int zfs_add_sort_column(zfs_sort_column_t **, const char *, boolean_t);
|
||||
void zfs_free_sort_columns(zfs_sort_column_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZFS_ITER_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _ZFS_UTIL_H
|
||||
#define _ZFS_UTIL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void * safe_malloc(size_t size);
|
||||
libzfs_handle_t *g_zfs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ZFS_UTIL_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,245 +0,0 @@
|
||||
/*
|
||||
* 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 <solaris.h>
|
||||
#include <libintl.h>
|
||||
#include <libuutil.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "zpool_util.h"
|
||||
|
||||
/*
|
||||
* Private interface for iterating over pools specified on the command line.
|
||||
* Most consumers will call for_each_pool, but in order to support iostat, we
|
||||
* allow fined grained control through the zpool_list_t interface.
|
||||
*/
|
||||
|
||||
typedef struct zpool_node {
|
||||
zpool_handle_t *zn_handle;
|
||||
uu_avl_node_t zn_avlnode;
|
||||
int zn_mark;
|
||||
} zpool_node_t;
|
||||
|
||||
struct zpool_list {
|
||||
boolean_t zl_findall;
|
||||
uu_avl_t *zl_avl;
|
||||
uu_avl_pool_t *zl_pool;
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zpool_compare(const void *larg, const void *rarg, void *unused)
|
||||
{
|
||||
zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
|
||||
zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
|
||||
const char *lname = zpool_get_name(l);
|
||||
const char *rname = zpool_get_name(r);
|
||||
|
||||
return (strcmp(lname, rname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function for pool_list_get(). Adds the given pool to the AVL tree
|
||||
* of known pools.
|
||||
*/
|
||||
static int
|
||||
add_pool(zpool_handle_t *zhp, void *data)
|
||||
{
|
||||
zpool_list_t *zlp = data;
|
||||
zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
|
||||
uu_avl_index_t idx;
|
||||
|
||||
node->zn_handle = zhp;
|
||||
uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
|
||||
if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
|
||||
uu_avl_insert(zlp->zl_avl, node, idx);
|
||||
} else {
|
||||
zpool_close(zhp);
|
||||
free(node);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a list of pools based on the given arguments. If we're given no
|
||||
* arguments, then iterate over all pools in the system and add them to the AVL
|
||||
* tree. Otherwise, add only those pool explicitly specified on the command
|
||||
* line.
|
||||
*/
|
||||
zpool_list_t *
|
||||
pool_list_get(int argc, char **argv, zpool_proplist_t **proplist, int *err)
|
||||
{
|
||||
zpool_list_t *zlp;
|
||||
|
||||
zlp = safe_malloc(sizeof (zpool_list_t));
|
||||
|
||||
zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
|
||||
offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);
|
||||
|
||||
if (zlp->zl_pool == NULL)
|
||||
zpool_no_memory();
|
||||
|
||||
if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
|
||||
UU_DEFAULT)) == NULL)
|
||||
zpool_no_memory();
|
||||
|
||||
if (argc == 0) {
|
||||
(void) zpool_iter(g_zfs, add_pool, zlp);
|
||||
zlp->zl_findall = B_TRUE;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
zpool_handle_t *zhp;
|
||||
|
||||
if ((zhp = zpool_open_canfail(g_zfs,
|
||||
argv[i])) != NULL && add_pool(zhp, zlp) == 0) {
|
||||
if (proplist &&
|
||||
zpool_expand_proplist(zhp, proplist) != 0)
|
||||
*err = B_TRUE;
|
||||
} else
|
||||
*err = B_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return (zlp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for any new pools, adding them to the list. We only add pools when no
|
||||
* options were given on the command line. Otherwise, we keep the list fixed as
|
||||
* those that were explicitly specified.
|
||||
*/
|
||||
void
|
||||
pool_list_update(zpool_list_t *zlp)
|
||||
{
|
||||
if (zlp->zl_findall)
|
||||
(void) zpool_iter(g_zfs, add_pool, zlp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all pools in the list, executing the callback for each
|
||||
*/
|
||||
int
|
||||
pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
|
||||
void *data)
|
||||
{
|
||||
zpool_node_t *node, *next_node;
|
||||
int ret = 0;
|
||||
|
||||
for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
|
||||
next_node = uu_avl_next(zlp->zl_avl, node);
|
||||
if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
|
||||
unavail)
|
||||
ret |= func(node->zn_handle, data);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the given pool from the list. When running iostat, we want to remove
|
||||
* those pools that no longer exist.
|
||||
*/
|
||||
void
|
||||
pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp)
|
||||
{
|
||||
zpool_node_t search, *node;
|
||||
|
||||
search.zn_handle = zhp;
|
||||
if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) {
|
||||
uu_avl_remove(zlp->zl_avl, node);
|
||||
zpool_close(node->zn_handle);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all the handles associated with this list.
|
||||
*/
|
||||
void
|
||||
pool_list_free(zpool_list_t *zlp)
|
||||
{
|
||||
uu_avl_walk_t *walk;
|
||||
zpool_node_t *node;
|
||||
|
||||
if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((node = uu_avl_walk_next(walk)) != NULL) {
|
||||
uu_avl_remove(zlp->zl_avl, node);
|
||||
zpool_close(node->zn_handle);
|
||||
free(node);
|
||||
}
|
||||
|
||||
uu_avl_walk_end(walk);
|
||||
uu_avl_destroy(zlp->zl_avl);
|
||||
uu_avl_pool_destroy(zlp->zl_pool);
|
||||
|
||||
free(zlp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of elements in the pool list.
|
||||
*/
|
||||
int
|
||||
pool_list_count(zpool_list_t *zlp)
|
||||
{
|
||||
return (uu_avl_numnodes(zlp->zl_avl));
|
||||
}
|
||||
|
||||
/*
|
||||
* High level function which iterates over all pools given on the command line,
|
||||
* using the pool_list_* interfaces.
|
||||
*/
|
||||
int
|
||||
for_each_pool(int argc, char **argv, boolean_t unavail,
|
||||
zpool_proplist_t **proplist, zpool_iter_f func, void *data)
|
||||
{
|
||||
zpool_list_t *list;
|
||||
int ret = 0;
|
||||
|
||||
if ((list = pool_list_get(argc, argv, proplist, &ret)) == NULL)
|
||||
return (1);
|
||||
|
||||
if (pool_list_iter(list, unavail, func, data) != 0)
|
||||
ret = 1;
|
||||
|
||||
pool_list_free(list);
|
||||
|
||||
return (ret);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "zpool_util.h"
|
||||
|
||||
/*
|
||||
* Utility function to guarantee malloc() success.
|
||||
*/
|
||||
void *
|
||||
safe_malloc(size_t size)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if ((data = calloc(1, size)) == NULL) {
|
||||
(void) fprintf(stderr, "internal error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as above, but for strdup()
|
||||
*/
|
||||
char *
|
||||
safe_strdup(const char *str)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if ((ret = strdup(str)) == NULL) {
|
||||
(void) fprintf(stderr, "internal error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display an out of memory error message and abort the current program.
|
||||
*/
|
||||
void
|
||||
zpool_no_memory(void)
|
||||
{
|
||||
assert(errno == ENOMEM);
|
||||
(void) fprintf(stderr,
|
||||
gettext("internal error: out of memory\n"));
|
||||
exit(1);
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ZPOOL_UTIL_H
|
||||
#define ZPOOL_UTIL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <libnvpair.h>
|
||||
#include <libzfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Basic utility functions
|
||||
*/
|
||||
void *safe_malloc(size_t);
|
||||
char *safe_strdup(const char *);
|
||||
void zpool_no_memory(void);
|
||||
|
||||
/*
|
||||
* Virtual device functions
|
||||
*/
|
||||
nvlist_t *make_root_vdev(nvlist_t *poolconfig, int force, int check_rep,
|
||||
boolean_t isreplace, int argc, char **argv);
|
||||
|
||||
/*
|
||||
* Pool list functions
|
||||
*/
|
||||
int for_each_pool(int, char **, boolean_t unavail, zpool_proplist_t **,
|
||||
zpool_iter_f, void *);
|
||||
|
||||
typedef struct zpool_list zpool_list_t;
|
||||
|
||||
zpool_list_t *pool_list_get(int, char **, zpool_proplist_t **, int *);
|
||||
void pool_list_update(zpool_list_t *);
|
||||
int pool_list_iter(zpool_list_t *, int unavail, zpool_iter_f, void *);
|
||||
void pool_list_free(zpool_list_t *);
|
||||
int pool_list_count(zpool_list_t *);
|
||||
void pool_list_remove(zpool_list_t *, zpool_handle_t *);
|
||||
|
||||
libzfs_handle_t *g_zfs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZPOOL_UTIL_H */
|
@ -1,883 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* Functions to convert between a list of vdevs and an nvlist representing the
|
||||
* configuration. Each entry in the list can be one of:
|
||||
*
|
||||
* Device vdevs
|
||||
* disk=(path=..., devid=...)
|
||||
* file=(path=...)
|
||||
*
|
||||
* Group vdevs
|
||||
* raidz[1|2]=(...)
|
||||
* mirror=(...)
|
||||
*
|
||||
* Hot spares
|
||||
*
|
||||
* While the underlying implementation supports it, group vdevs cannot contain
|
||||
* other group vdevs. All userland verification of devices is contained within
|
||||
* this file. If successful, the nvlist returned can be passed directly to the
|
||||
* kernel; we've done as much verification as possible in userland.
|
||||
*
|
||||
* Hot spares are a special case, and passed down as an array of disk vdevs, at
|
||||
* the same level as the root of the vdev tree.
|
||||
*
|
||||
* The only function exported by this file is 'get_vdev_spec'. The function
|
||||
* performs several passes:
|
||||
*
|
||||
* 1. Construct the vdev specification. Performs syntax validation and
|
||||
* makes sure each device is valid.
|
||||
* 2. Check for devices in use. Using libdiskmgt, makes sure that no
|
||||
* devices are also in use. Some can be overridden using the 'force'
|
||||
* flag, others cannot.
|
||||
* 3. Check for replication errors if the 'force' flag is not specified.
|
||||
* validates that the replication level is consistent across the
|
||||
* entire pool.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <devid.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <libnvpair.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <paths.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <libgeom.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "zpool_util.h"
|
||||
|
||||
/*
|
||||
* For any given vdev specification, we can have multiple errors. The
|
||||
* vdev_error() function keeps track of whether we have seen an error yet, and
|
||||
* prints out a header if its the first error we've seen.
|
||||
*/
|
||||
boolean_t error_seen;
|
||||
boolean_t is_force;
|
||||
|
||||
/*PRINTFLIKE1*/
|
||||
static void
|
||||
vdev_error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!error_seen) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev specification\n"));
|
||||
if (!is_force)
|
||||
(void) fprintf(stderr, gettext("use '-f' to override "
|
||||
"the following errors:\n"));
|
||||
else
|
||||
(void) fprintf(stderr, gettext("the following errors "
|
||||
"must be manually repaired:\n"));
|
||||
error_seen = B_TRUE;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void) vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate a GEOM provider.
|
||||
*/
|
||||
static int
|
||||
check_provider(const char *name, boolean_t force, boolean_t isspare)
|
||||
{
|
||||
struct gmesh mesh;
|
||||
struct gclass *mp;
|
||||
struct ggeom *gp;
|
||||
struct gprovider *pp;
|
||||
int rv;
|
||||
|
||||
/* XXX: What to do with isspare? */
|
||||
|
||||
if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
|
||||
name += sizeof(_PATH_DEV) - 1;
|
||||
|
||||
rv = geom_gettree(&mesh);
|
||||
assert(rv == 0);
|
||||
|
||||
pp = NULL;
|
||||
LIST_FOREACH(mp, &mesh.lg_class, lg_class) {
|
||||
LIST_FOREACH(gp, &mp->lg_geom, lg_geom) {
|
||||
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
|
||||
if (strcmp(pp->lg_name, name) == 0)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
rv = -1;
|
||||
if (pp == NULL)
|
||||
vdev_error("no such provider %s\n", name);
|
||||
else {
|
||||
int acr, acw, ace;
|
||||
|
||||
VERIFY(sscanf(pp->lg_mode, "r%dw%de%d", &acr, &acw, &ace) == 3);
|
||||
if (acw == 0 && ace == 0)
|
||||
rv = 0;
|
||||
else
|
||||
vdev_error("%s is in use (%s)\n", name, pp->lg_mode);
|
||||
}
|
||||
geom_deletetree(&mesh);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
is_provider(const char *name)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = g_open(name, 0);
|
||||
if (fd >= 0) {
|
||||
g_close(fd);
|
||||
return (B_TRUE);
|
||||
}
|
||||
return (B_FALSE);
|
||||
|
||||
}
|
||||
/*
|
||||
* Create a leaf vdev. Determine if this is a GEOM provider.
|
||||
* Valid forms for a leaf vdev are:
|
||||
*
|
||||
* /dev/xxx Complete path to a GEOM provider
|
||||
* xxx Shorthand for /dev/xxx
|
||||
*/
|
||||
nvlist_t *
|
||||
make_leaf_vdev(const char *arg)
|
||||
{
|
||||
char ident[DISK_IDENT_SIZE], path[MAXPATHLEN];
|
||||
struct stat64 statbuf;
|
||||
nvlist_t *vdev = NULL;
|
||||
char *type = NULL;
|
||||
boolean_t wholedisk = B_FALSE;
|
||||
|
||||
if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
|
||||
strlcpy(path, arg, sizeof (path));
|
||||
else
|
||||
snprintf(path, sizeof (path), "%s%s", _PATH_DEV, arg);
|
||||
|
||||
if (is_provider(path))
|
||||
type = VDEV_TYPE_DISK;
|
||||
else {
|
||||
(void) fprintf(stderr, gettext("cannot use '%s': must be a "
|
||||
"GEOM provider\n"), path);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, we have the complete device or file, and we know that it is
|
||||
* acceptable to use. Construct the nvlist to describe this vdev. All
|
||||
* vdevs have a 'path' element, and devices also have a 'devid' element.
|
||||
*/
|
||||
verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
|
||||
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
|
||||
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
|
||||
if (strcmp(type, VDEV_TYPE_DISK) == 0)
|
||||
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
|
||||
(uint64_t)B_FALSE) == 0);
|
||||
|
||||
/*
|
||||
* For a whole disk, defer getting its devid until after labeling it.
|
||||
*/
|
||||
if (1 || (S_ISBLK(statbuf.st_mode) && !wholedisk)) {
|
||||
/*
|
||||
* Get the devid for the device.
|
||||
*/
|
||||
int fd;
|
||||
ddi_devid_t devid;
|
||||
char *minor = NULL, *devid_str = NULL;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
(void) fprintf(stderr, gettext("cannot open '%s': "
|
||||
"%s\n"), path, strerror(errno));
|
||||
nvlist_free(vdev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (devid_get(fd, &devid) == 0) {
|
||||
if (devid_get_minor_name(fd, &minor) == 0 &&
|
||||
(devid_str = devid_str_encode(devid, minor)) !=
|
||||
NULL) {
|
||||
verify(nvlist_add_string(vdev,
|
||||
ZPOOL_CONFIG_DEVID, devid_str) == 0);
|
||||
}
|
||||
if (devid_str != NULL)
|
||||
devid_str_free(devid_str);
|
||||
if (minor != NULL)
|
||||
devid_str_free(minor);
|
||||
devid_free(devid);
|
||||
}
|
||||
|
||||
(void) close(fd);
|
||||
}
|
||||
|
||||
return (vdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through and verify the replication level of the pool is consistent.
|
||||
* Performs the following checks:
|
||||
*
|
||||
* For the new spec, verifies that devices in mirrors and raidz are the
|
||||
* same size.
|
||||
*
|
||||
* If the current configuration already has inconsistent replication
|
||||
* levels, ignore any other potential problems in the new spec.
|
||||
*
|
||||
* Otherwise, make sure that the current spec (if there is one) and the new
|
||||
* spec have consistent replication levels.
|
||||
*/
|
||||
typedef struct replication_level {
|
||||
char *zprl_type;
|
||||
uint64_t zprl_children;
|
||||
uint64_t zprl_parity;
|
||||
} replication_level_t;
|
||||
|
||||
/*
|
||||
* Given a list of toplevel vdevs, return the current replication level. If
|
||||
* the config is inconsistent, then NULL is returned. If 'fatal' is set, then
|
||||
* an error message will be displayed for each self-inconsistent vdev.
|
||||
*/
|
||||
replication_level_t *
|
||||
get_replication(nvlist_t *nvroot, boolean_t fatal)
|
||||
{
|
||||
nvlist_t **top;
|
||||
uint_t t, toplevels;
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
nvlist_t *nv;
|
||||
char *type;
|
||||
replication_level_t lastrep, rep, *ret;
|
||||
boolean_t dontreport;
|
||||
|
||||
ret = safe_malloc(sizeof (replication_level_t));
|
||||
|
||||
verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
|
||||
&top, &toplevels) == 0);
|
||||
|
||||
lastrep.zprl_type = NULL;
|
||||
for (t = 0; t < toplevels; t++) {
|
||||
nv = top[t];
|
||||
|
||||
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0) {
|
||||
/*
|
||||
* This is a 'file' or 'disk' vdev.
|
||||
*/
|
||||
rep.zprl_type = type;
|
||||
rep.zprl_children = 1;
|
||||
rep.zprl_parity = 0;
|
||||
} else {
|
||||
uint64_t vdev_size;
|
||||
|
||||
/*
|
||||
* This is a mirror or RAID-Z vdev. Go through and make
|
||||
* sure the contents are all the same (files vs. disks),
|
||||
* keeping track of the number of elements in the
|
||||
* process.
|
||||
*
|
||||
* We also check that the size of each vdev (if it can
|
||||
* be determined) is the same.
|
||||
*/
|
||||
rep.zprl_type = type;
|
||||
rep.zprl_children = 0;
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
|
||||
verify(nvlist_lookup_uint64(nv,
|
||||
ZPOOL_CONFIG_NPARITY,
|
||||
&rep.zprl_parity) == 0);
|
||||
assert(rep.zprl_parity != 0);
|
||||
} else {
|
||||
rep.zprl_parity = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'dontreport' variable indicatest that we've
|
||||
* already reported an error for this spec, so don't
|
||||
* bother doing it again.
|
||||
*/
|
||||
type = NULL;
|
||||
dontreport = 0;
|
||||
vdev_size = -1ULL;
|
||||
for (c = 0; c < children; c++) {
|
||||
nvlist_t *cnv = child[c];
|
||||
char *path;
|
||||
struct stat64 statbuf;
|
||||
uint64_t size = -1ULL;
|
||||
char *childtype;
|
||||
int fd, err;
|
||||
|
||||
rep.zprl_children++;
|
||||
|
||||
verify(nvlist_lookup_string(cnv,
|
||||
ZPOOL_CONFIG_TYPE, &childtype) == 0);
|
||||
|
||||
/*
|
||||
* If this is a a replacing or spare vdev, then
|
||||
* get the real first child of the vdev.
|
||||
*/
|
||||
if (strcmp(childtype,
|
||||
VDEV_TYPE_REPLACING) == 0 ||
|
||||
strcmp(childtype, VDEV_TYPE_SPARE) == 0) {
|
||||
nvlist_t **rchild;
|
||||
uint_t rchildren;
|
||||
|
||||
verify(nvlist_lookup_nvlist_array(cnv,
|
||||
ZPOOL_CONFIG_CHILDREN, &rchild,
|
||||
&rchildren) == 0);
|
||||
assert(rchildren == 2);
|
||||
cnv = rchild[0];
|
||||
|
||||
verify(nvlist_lookup_string(cnv,
|
||||
ZPOOL_CONFIG_TYPE,
|
||||
&childtype) == 0);
|
||||
}
|
||||
|
||||
verify(nvlist_lookup_string(cnv,
|
||||
ZPOOL_CONFIG_PATH, &path) == 0);
|
||||
|
||||
/*
|
||||
* If we have a raidz/mirror that combines disks
|
||||
* with files, report it as an error.
|
||||
*/
|
||||
if (!dontreport && type != NULL &&
|
||||
strcmp(type, childtype) != 0) {
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication "
|
||||
"level: %s contains both "
|
||||
"files and devices\n"),
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
dontreport = B_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to stat(2), the value of 'st_size'
|
||||
* is undefined for block devices and character
|
||||
* devices. But there is no effective way to
|
||||
* determine the real size in userland.
|
||||
*
|
||||
* Instead, we'll take advantage of an
|
||||
* implementation detail of spec_size(). If the
|
||||
* device is currently open, then we (should)
|
||||
* return a valid size.
|
||||
*
|
||||
* If we still don't get a valid size (indicated
|
||||
* by a size of 0 or MAXOFFSET_T), then ignore
|
||||
* this device altogether.
|
||||
*/
|
||||
if ((fd = open(path, O_RDONLY)) >= 0) {
|
||||
err = fstat64(fd, &statbuf);
|
||||
(void) close(fd);
|
||||
} else {
|
||||
err = stat64(path, &statbuf);
|
||||
}
|
||||
|
||||
if (err != 0 || statbuf.st_size == 0)
|
||||
continue;
|
||||
|
||||
size = statbuf.st_size;
|
||||
|
||||
/*
|
||||
* Also check the size of each device. If they
|
||||
* differ, then report an error.
|
||||
*/
|
||||
if (!dontreport && vdev_size != -1ULL &&
|
||||
size != vdev_size) {
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"%s contains devices of "
|
||||
"different sizes\n"),
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
dontreport = B_TRUE;
|
||||
}
|
||||
|
||||
type = childtype;
|
||||
vdev_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we have the replication of the last toplevel
|
||||
* vdev in 'rep'. Compare it to 'lastrep' to see if its
|
||||
* different.
|
||||
*/
|
||||
if (lastrep.zprl_type != NULL) {
|
||||
if (strcmp(lastrep.zprl_type, rep.zprl_type) != 0) {
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: "
|
||||
"both %s and %s vdevs are "
|
||||
"present\n"),
|
||||
lastrep.zprl_type, rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
} else if (lastrep.zprl_parity != rep.zprl_parity) {
|
||||
if (ret)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: "
|
||||
"both %llu and %llu device parity "
|
||||
"%s vdevs are present\n"),
|
||||
lastrep.zprl_parity,
|
||||
rep.zprl_parity,
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
} else if (lastrep.zprl_children != rep.zprl_children) {
|
||||
if (ret)
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
if (fatal)
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: "
|
||||
"both %llu-way and %llu-way %s "
|
||||
"vdevs are present\n"),
|
||||
lastrep.zprl_children,
|
||||
rep.zprl_children,
|
||||
rep.zprl_type);
|
||||
else
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
lastrep = rep;
|
||||
}
|
||||
|
||||
if (ret != NULL)
|
||||
*ret = rep;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the replication level of the vdev spec against the current pool. Calls
|
||||
* get_replication() to make sure the new spec is self-consistent. If the pool
|
||||
* has a consistent replication level, then we ignore any errors. Otherwise,
|
||||
* report any difference between the two.
|
||||
*/
|
||||
int
|
||||
check_replication(nvlist_t *config, nvlist_t *newroot)
|
||||
{
|
||||
replication_level_t *current = NULL, *new;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If we have a current pool configuration, check to see if it's
|
||||
* self-consistent. If not, simply return success.
|
||||
*/
|
||||
if (config != NULL) {
|
||||
nvlist_t *nvroot;
|
||||
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
if ((current = get_replication(nvroot, B_FALSE)) == NULL)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the replication level of the new vdev spec, reporting any
|
||||
* inconsistencies found.
|
||||
*/
|
||||
if ((new = get_replication(newroot, B_TRUE)) == NULL) {
|
||||
free(current);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the new vdev spec matches the replication level of
|
||||
* the current pool.
|
||||
*/
|
||||
ret = 0;
|
||||
if (current != NULL) {
|
||||
if (strcmp(current->zprl_type, new->zprl_type) != 0) {
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: pool uses %s "
|
||||
"and new vdev is %s\n"),
|
||||
current->zprl_type, new->zprl_type);
|
||||
ret = -1;
|
||||
} else if (current->zprl_parity != new->zprl_parity) {
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: pool uses %llu "
|
||||
"device parity and new vdev uses %llu\n"),
|
||||
current->zprl_parity, new->zprl_parity);
|
||||
ret = -1;
|
||||
} else if (current->zprl_children != new->zprl_children) {
|
||||
vdev_error(gettext(
|
||||
"mismatched replication level: pool uses %llu-way "
|
||||
"%s and new vdev uses %llu-way %s\n"),
|
||||
current->zprl_children, current->zprl_type,
|
||||
new->zprl_children, new->zprl_type);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(new);
|
||||
if (current != NULL)
|
||||
free(current);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if the given path is a hot spare within the given configuration.
|
||||
*/
|
||||
static boolean_t
|
||||
is_spare(nvlist_t *config, const char *path)
|
||||
{
|
||||
int fd;
|
||||
pool_state_t state;
|
||||
char *name = NULL;
|
||||
nvlist_t *label;
|
||||
uint64_t guid, spareguid;
|
||||
nvlist_t *nvroot;
|
||||
nvlist_t **spares;
|
||||
uint_t i, nspares;
|
||||
boolean_t inuse;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0 ||
|
||||
!inuse ||
|
||||
state != POOL_STATE_SPARE ||
|
||||
zpool_read_label(fd, &label) != 0) {
|
||||
free(name);
|
||||
(void) close(fd);
|
||||
return (B_FALSE);
|
||||
}
|
||||
free(name);
|
||||
|
||||
(void) close(fd);
|
||||
verify(nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) == 0);
|
||||
nvlist_free(label);
|
||||
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
|
||||
&spares, &nspares) == 0) {
|
||||
for (i = 0; i < nspares; i++) {
|
||||
verify(nvlist_lookup_uint64(spares[i],
|
||||
ZPOOL_CONFIG_GUID, &spareguid) == 0);
|
||||
if (spareguid == guid)
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through and find any devices that are in use. We rely on libdiskmgt for
|
||||
* the majority of this task.
|
||||
*/
|
||||
int
|
||||
check_in_use(nvlist_t *config, nvlist_t *nv, int force, int isreplacing,
|
||||
int isspare)
|
||||
{
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
char *type, *path;
|
||||
int ret;
|
||||
char buf[MAXPATHLEN];
|
||||
uint64_t wholedisk;
|
||||
|
||||
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0) {
|
||||
|
||||
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
|
||||
|
||||
/*
|
||||
* As a generic check, we look to see if this is a replace of a
|
||||
* hot spare within the same pool. If so, we allow it
|
||||
* regardless of what libdiskmgt or zpool_in_use() says.
|
||||
*/
|
||||
if (isreplacing) {
|
||||
(void) strlcpy(buf, path, sizeof (buf));
|
||||
if (is_spare(config, buf))
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_DISK) == 0)
|
||||
ret = check_provider(path, force, isspare);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
for (c = 0; c < children; c++)
|
||||
if ((ret = check_in_use(config, child[c], force,
|
||||
isreplacing, B_FALSE)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
|
||||
&child, &children) == 0)
|
||||
for (c = 0; c < children; c++)
|
||||
if ((ret = check_in_use(config, child[c], force,
|
||||
isreplacing, B_TRUE)) != 0)
|
||||
return (ret);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
const char *
|
||||
is_grouping(const char *type, int *mindev)
|
||||
{
|
||||
if (strcmp(type, "raidz") == 0 || strcmp(type, "raidz1") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 2;
|
||||
return (VDEV_TYPE_RAIDZ);
|
||||
}
|
||||
|
||||
if (strcmp(type, "raidz2") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 3;
|
||||
return (VDEV_TYPE_RAIDZ);
|
||||
}
|
||||
|
||||
if (strcmp(type, "mirror") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 2;
|
||||
return (VDEV_TYPE_MIRROR);
|
||||
}
|
||||
|
||||
if (strcmp(type, "spare") == 0) {
|
||||
if (mindev != NULL)
|
||||
*mindev = 1;
|
||||
return (VDEV_TYPE_SPARE);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a syntactically valid vdev specification,
|
||||
* and ensure that all devices and files exist and can be opened.
|
||||
* Note: we don't bother freeing anything in the error paths
|
||||
* because the program is just going to exit anyway.
|
||||
*/
|
||||
nvlist_t *
|
||||
construct_spec(int argc, char **argv)
|
||||
{
|
||||
nvlist_t *nvroot, *nv, **top, **spares;
|
||||
int t, toplevels, mindev, nspares;
|
||||
const char *type;
|
||||
|
||||
top = NULL;
|
||||
toplevels = 0;
|
||||
spares = NULL;
|
||||
nspares = 0;
|
||||
|
||||
while (argc > 0) {
|
||||
nv = NULL;
|
||||
|
||||
/*
|
||||
* If it's a mirror or raidz, the subsequent arguments are
|
||||
* its leaves -- until we encounter the next mirror or raidz.
|
||||
*/
|
||||
if ((type = is_grouping(argv[0], &mindev)) != NULL) {
|
||||
nvlist_t **child = NULL;
|
||||
int c, children = 0;
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
|
||||
spares != NULL) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev "
|
||||
"specification: 'spare' can be "
|
||||
"specified only once\n"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
for (c = 1; c < argc; c++) {
|
||||
if (is_grouping(argv[c], NULL) != NULL)
|
||||
break;
|
||||
children++;
|
||||
child = realloc(child,
|
||||
children * sizeof (nvlist_t *));
|
||||
if (child == NULL)
|
||||
zpool_no_memory();
|
||||
if ((nv = make_leaf_vdev(argv[c])) == NULL)
|
||||
return (NULL);
|
||||
child[children - 1] = nv;
|
||||
}
|
||||
|
||||
if (children < mindev) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev "
|
||||
"specification: %s requires at least %d "
|
||||
"devices\n"), argv[0], mindev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
argc -= c;
|
||||
argv += c;
|
||||
|
||||
if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
|
||||
spares = child;
|
||||
nspares = children;
|
||||
continue;
|
||||
} else {
|
||||
verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
|
||||
0) == 0);
|
||||
verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
|
||||
type) == 0);
|
||||
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
|
||||
verify(nvlist_add_uint64(nv,
|
||||
ZPOOL_CONFIG_NPARITY,
|
||||
mindev - 1) == 0);
|
||||
}
|
||||
verify(nvlist_add_nvlist_array(nv,
|
||||
ZPOOL_CONFIG_CHILDREN, child,
|
||||
children) == 0);
|
||||
|
||||
for (c = 0; c < children; c++)
|
||||
nvlist_free(child[c]);
|
||||
free(child);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We have a device. Pass off to make_leaf_vdev() to
|
||||
* construct the appropriate nvlist describing the vdev.
|
||||
*/
|
||||
if ((nv = make_leaf_vdev(argv[0])) == NULL)
|
||||
return (NULL);
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
toplevels++;
|
||||
top = realloc(top, toplevels * sizeof (nvlist_t *));
|
||||
if (top == NULL)
|
||||
zpool_no_memory();
|
||||
top[toplevels - 1] = nv;
|
||||
}
|
||||
|
||||
if (toplevels == 0 && nspares == 0) {
|
||||
(void) fprintf(stderr, gettext("invalid vdev "
|
||||
"specification: at least one toplevel vdev must be "
|
||||
"specified\n"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, create nvroot and add all top-level vdevs to it.
|
||||
*/
|
||||
verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
|
||||
verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
|
||||
VDEV_TYPE_ROOT) == 0);
|
||||
verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
|
||||
top, toplevels) == 0);
|
||||
if (nspares != 0)
|
||||
verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
|
||||
spares, nspares) == 0);
|
||||
|
||||
for (t = 0; t < toplevels; t++)
|
||||
nvlist_free(top[t]);
|
||||
for (t = 0; t < nspares; t++)
|
||||
nvlist_free(spares[t]);
|
||||
if (spares)
|
||||
free(spares);
|
||||
free(top);
|
||||
|
||||
return (nvroot);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get and validate the contents of the given vdev specification. This ensures
|
||||
* that the nvlist returned is well-formed, that all the devices exist, and that
|
||||
* they are not currently in use by any other known consumer. The 'poolconfig'
|
||||
* parameter is the current configuration of the pool when adding devices
|
||||
* existing pool, and is used to perform additional checks, such as changing the
|
||||
* replication level of the pool. It can be 'NULL' to indicate that this is a
|
||||
* new pool. The 'force' flag controls whether devices should be forcefully
|
||||
* added, even if they appear in use.
|
||||
*/
|
||||
nvlist_t *
|
||||
make_root_vdev(nvlist_t *poolconfig, int force, int check_rep,
|
||||
boolean_t isreplacing, int argc, char **argv)
|
||||
{
|
||||
nvlist_t *newroot;
|
||||
|
||||
is_force = force;
|
||||
|
||||
/*
|
||||
* Construct the vdev specification. If this is successful, we know
|
||||
* that we have a valid specification, and that all devices can be
|
||||
* opened.
|
||||
*/
|
||||
if ((newroot = construct_spec(argc, argv)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Validate each device to make sure that its not shared with another
|
||||
* subsystem. We do this even if 'force' is set, because there are some
|
||||
* uses (such as a dedicated dump device) that even '-f' cannot
|
||||
* override.
|
||||
*/
|
||||
if (check_in_use(poolconfig, newroot, force, isreplacing,
|
||||
B_FALSE) != 0) {
|
||||
nvlist_free(newroot);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the replication level of the given vdevs and report any errors
|
||||
* found. We include the existing pool spec, if any, as we need to
|
||||
* catch changes against the existing replication level.
|
||||
*/
|
||||
if (check_rep && check_replication(poolconfig, newroot) != 0) {
|
||||
nvlist_free(newroot);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (newroot);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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 (c) 1988 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
|
||||
/*
|
||||
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _ASSERT_H
|
||||
#define _ASSERT_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6.1.4 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__STDC__)
|
||||
#if __STDC_VERSION__ - 0 >= 199901L
|
||||
extern void __assert_c99(const char *, const char *, int, const char *);
|
||||
#else
|
||||
extern void __assert(const char *, const char *, int);
|
||||
#endif /* __STDC_VERSION__ - 0 >= 199901L */
|
||||
#else
|
||||
extern void _assert();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ASSERT_H */
|
||||
|
||||
/*
|
||||
* Note that the ANSI C Standard requires all headers to be idempotent except
|
||||
* <assert.h> which is explicitly required not to be idempotent (section 4.1.2).
|
||||
* Therefore, it is by intent that the header guards (#ifndef _ASSERT_H) do
|
||||
* not span this entire file.
|
||||
*/
|
||||
|
||||
#undef assert
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#define assert(EX) ((void)0)
|
||||
|
||||
#else
|
||||
|
||||
#if defined(__STDC__)
|
||||
#if __STDC_VERSION__ - 0 >= 199901L
|
||||
#define assert(EX) (void)((EX) || \
|
||||
(__assert_c99(#EX, __FILE__, __LINE__, __func__), 0))
|
||||
#else
|
||||
#define assert(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC_VERSION__ - 0 >= 199901L */
|
||||
#else
|
||||
#define assert(EX) (void)((EX) || (_assert("EX", __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#endif /* NDEBUG */
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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 _ATOMIC_H
|
||||
#define _ATOMIC_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/atomic.h>
|
||||
|
||||
#endif /* _ATOMIC_H */
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Libintl is a library of advanced internationalization functions. */
|
||||
|
||||
#ifndef _LIBINTL_H
|
||||
#define _LIBINTL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/isa_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* wchar_t is a built-in type in standard C++ and as such is not
|
||||
* defined here when using standard C++. However, the GNU compiler
|
||||
* fixincludes utility nonetheless creates its own version of this
|
||||
* header for use by gcc and g++. In that version it adds a redundant
|
||||
* guard for __cplusplus. To avoid the creation of a gcc/g++ specific
|
||||
* header we need to include the following magic comment:
|
||||
*
|
||||
* we must use the C++ compiler's type
|
||||
*
|
||||
* The above comment should not be removed or changed until GNU
|
||||
* gcc/fixinc/inclhack.def is updated to bypass this header.
|
||||
*/
|
||||
#if !defined(__cplusplus) || (__cplusplus < 199711L && !defined(__GNUG__))
|
||||
#ifndef _WCHAR_T
|
||||
#define _WCHAR_T
|
||||
#if defined(_LP64)
|
||||
typedef int wchar_t;
|
||||
#else
|
||||
typedef long wchar_t;
|
||||
#endif
|
||||
#endif /* !_WCHAR_T */
|
||||
#endif /* !defined(__cplusplus) ... */
|
||||
|
||||
#define TEXTDOMAINMAX 256
|
||||
|
||||
#ifdef __STDC__
|
||||
extern char *dcgettext(const char *, const char *, const int);
|
||||
extern char *dgettext(const char *, const char *);
|
||||
extern char *gettext(const char *);
|
||||
extern char *textdomain(const char *);
|
||||
extern char *bindtextdomain(const char *, const char *);
|
||||
|
||||
/*
|
||||
* LI18NUX 2000 Globalization Specification Version 1.0
|
||||
* with Amendment 2
|
||||
*/
|
||||
extern char *dcngettext(const char *, const char *,
|
||||
const char *, unsigned long int, int);
|
||||
extern char *dngettext(const char *, const char *,
|
||||
const char *, unsigned long int);
|
||||
extern char *ngettext(const char *, const char *, unsigned long int);
|
||||
extern char *bind_textdomain_codeset(const char *, const char *);
|
||||
|
||||
/* Word handling functions --- requires dynamic linking */
|
||||
/* Warning: these are experimental and subject to change. */
|
||||
extern int wdinit(void);
|
||||
extern int wdchkind(wchar_t);
|
||||
extern int wdbindf(wchar_t, wchar_t, int);
|
||||
extern wchar_t *wddelim(wchar_t, wchar_t, int);
|
||||
extern wchar_t mcfiller(void);
|
||||
extern int mcwrap(void);
|
||||
|
||||
#else
|
||||
extern char *dcgettext();
|
||||
extern char *dgettext();
|
||||
extern char *gettext();
|
||||
extern char *textdomain();
|
||||
extern char *bindtextdomain();
|
||||
|
||||
/*
|
||||
* LI18NUX 2000 Globalization Specification Version 1.0
|
||||
* with Amendment 2
|
||||
*/
|
||||
extern char *dcngettext();
|
||||
extern char *dngettext();
|
||||
extern char *ngettext();
|
||||
extern char *bind_textdomain_codeset();
|
||||
|
||||
/* Word handling functions --- requires dynamic linking */
|
||||
/* Warning: these are experimental and subject to change. */
|
||||
extern int wdinit();
|
||||
extern int wdchkind();
|
||||
extern int wdbindf();
|
||||
extern wchar_t *wddelim();
|
||||
extern wchar_t mcfiller();
|
||||
extern int mcwrap();
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBINTL_H */
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _STDIO_EXT_H
|
||||
#define _STDIO_EXT_H
|
||||
|
||||
#define enable_extended_FILE_stdio(x,y) (0)
|
||||
|
||||
#endif
|
@ -1,264 +0,0 @@
|
||||
/*
|
||||
* 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 2003 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYNCH_H
|
||||
#define _SYNCH_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* synch.h:
|
||||
* definitions needed to use the thread synchronization interface
|
||||
*/
|
||||
|
||||
#ifndef _ASM
|
||||
#include <sys/machlock.h>
|
||||
#include <sys/time_impl.h>
|
||||
#include <sys/synch.h>
|
||||
#endif /* _ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _ASM
|
||||
|
||||
/*
|
||||
* Semaphores
|
||||
*/
|
||||
typedef struct _sema {
|
||||
/* this structure must be the same as sem_t in <semaphore.h> */
|
||||
uint32_t count; /* semaphore count */
|
||||
uint16_t type;
|
||||
uint16_t magic;
|
||||
upad64_t pad1[3]; /* reserved for a mutex_t */
|
||||
upad64_t pad2[2]; /* reserved for a cond_t */
|
||||
} sema_t;
|
||||
|
||||
/*
|
||||
* POSIX.1c Note:
|
||||
* POSIX.1c requires that <pthread.h> define the structures pthread_mutex_t
|
||||
* and pthread_cond_t. These structures are identical to mutex_t (lwp_mutex_t)
|
||||
* and cond_t (lwp_cond_t) which are defined in <synch.h>. A nested included
|
||||
* of <synch.h> (to allow a "#typedef mutex_t pthread_mutex_t") would pull in
|
||||
* non-posix symbols/constants violating the namespace restrictions. Hence,
|
||||
* pthread_mutex_t/pthread_cond_t have been redefined in <pthread.h> (actually
|
||||
* in <sys/types.h>). Any modifications done to mutex_t/lwp_mutex_t or
|
||||
* cond_t/lwp_cond_t should also be done to pthread_mutex_t/pthread_cond_t.
|
||||
*/
|
||||
typedef lwp_mutex_t mutex_t;
|
||||
typedef lwp_cond_t cond_t;
|
||||
|
||||
/*
|
||||
* Readers/writer locks
|
||||
*
|
||||
* NOTE: The layout of this structure should be kept in sync with the layout
|
||||
* of the correponding structure of pthread_rwlock_t in sys/types.h.
|
||||
* Also, there is an identical structure for lwp_rwlock_t in <sys/synch.h>.
|
||||
* Because we have to deal with C++, we cannot redefine this one as that one.
|
||||
*/
|
||||
typedef struct _rwlock {
|
||||
int32_t readers; /* -1 == writer else # of readers */
|
||||
uint16_t type;
|
||||
uint16_t magic;
|
||||
mutex_t mutex; /* used to indicate ownership */
|
||||
cond_t readercv; /* unused */
|
||||
cond_t writercv; /* unused */
|
||||
} rwlock_t;
|
||||
|
||||
#ifdef __STDC__
|
||||
int _lwp_mutex_lock(lwp_mutex_t *);
|
||||
int _lwp_mutex_unlock(lwp_mutex_t *);
|
||||
int _lwp_mutex_trylock(lwp_mutex_t *);
|
||||
int _lwp_cond_wait(lwp_cond_t *, lwp_mutex_t *);
|
||||
int _lwp_cond_timedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
|
||||
int _lwp_cond_reltimedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
|
||||
int _lwp_cond_signal(lwp_cond_t *);
|
||||
int _lwp_cond_broadcast(lwp_cond_t *);
|
||||
int _lwp_sema_init(lwp_sema_t *, int);
|
||||
int _lwp_sema_wait(lwp_sema_t *);
|
||||
int _lwp_sema_trywait(lwp_sema_t *);
|
||||
int _lwp_sema_post(lwp_sema_t *);
|
||||
int cond_init(cond_t *, int, void *);
|
||||
int cond_destroy(cond_t *);
|
||||
int cond_wait(cond_t *, mutex_t *);
|
||||
int cond_timedwait(cond_t *, mutex_t *, const timespec_t *);
|
||||
int cond_reltimedwait(cond_t *, mutex_t *, const timespec_t *);
|
||||
int cond_signal(cond_t *);
|
||||
int cond_broadcast(cond_t *);
|
||||
int mutex_init(mutex_t *, int, void *);
|
||||
int mutex_destroy(mutex_t *);
|
||||
int mutex_lock(mutex_t *);
|
||||
int mutex_trylock(mutex_t *);
|
||||
int mutex_unlock(mutex_t *);
|
||||
int rwlock_init(rwlock_t *, int, void *);
|
||||
int rwlock_destroy(rwlock_t *);
|
||||
int rw_rdlock(rwlock_t *);
|
||||
int rw_wrlock(rwlock_t *);
|
||||
int rw_unlock(rwlock_t *);
|
||||
int rw_tryrdlock(rwlock_t *);
|
||||
int rw_trywrlock(rwlock_t *);
|
||||
int sema_init(sema_t *, unsigned int, int, void *);
|
||||
int sema_destroy(sema_t *);
|
||||
int sema_wait(sema_t *);
|
||||
int sema_timedwait(sema_t *, const timespec_t *);
|
||||
int sema_reltimedwait(sema_t *, const timespec_t *);
|
||||
int sema_post(sema_t *);
|
||||
int sema_trywait(sema_t *);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
int _lwp_mutex_lock();
|
||||
int _lwp_mutex_unlock();
|
||||
int _lwp_mutex_trylock();
|
||||
int _lwp_cond_wait();
|
||||
int _lwp_cond_timedwait();
|
||||
int _lwp_cond_reltimedwait();
|
||||
int _lwp_cond_signal();
|
||||
int _lwp_cond_broadcast();
|
||||
int _lwp_sema_init();
|
||||
int _lwp_sema_wait();
|
||||
int _lwp_sema_trywait();
|
||||
int _lwp_sema_post();
|
||||
int cond_init();
|
||||
int cond_destroy();
|
||||
int cond_wait();
|
||||
int cond_timedwait();
|
||||
int cond_reltimedwait();
|
||||
int cond_signal();
|
||||
int cond_broadcast();
|
||||
int mutex_init();
|
||||
int mutex_destroy();
|
||||
int mutex_lock();
|
||||
int mutex_trylock();
|
||||
int mutex_unlock();
|
||||
int rwlock_init();
|
||||
int rwlock_destroy();
|
||||
int rw_rdlock();
|
||||
int rw_wrlock();
|
||||
int rw_unlock();
|
||||
int rw_tryrdlock();
|
||||
int rw_trywrlock();
|
||||
int sema_init();
|
||||
int sema_destroy();
|
||||
int sema_wait();
|
||||
int sema_timedwait();
|
||||
int sema_reltimedwait();
|
||||
int sema_post();
|
||||
int sema_trywait();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#endif /* _ASM */
|
||||
|
||||
/* "Magic numbers" tagging synchronization object types */
|
||||
#define MUTEX_MAGIC _MUTEX_MAGIC
|
||||
#define SEMA_MAGIC _SEMA_MAGIC
|
||||
#define COND_MAGIC _COND_MAGIC
|
||||
#define RWL_MAGIC _RWL_MAGIC
|
||||
|
||||
/*
|
||||
* POSIX.1c Note:
|
||||
* DEFAULTMUTEX is defined same as PTHREAD_MUTEX_INITIALIZER in <pthread.h>.
|
||||
* DEFAULTCV is defined same as PTHREAD_COND_INITIALIZER in <pthread.h>.
|
||||
* DEFAULTRWLOCK is defined same as PTHREAD_RWLOCK_INITIALIZER in <pthread.h>.
|
||||
* Any changes to these macros should be reflected in <pthread.h>
|
||||
*/
|
||||
#define DEFAULTMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define SHAREDMUTEX \
|
||||
{{0, 0, 0, {USYNC_PROCESS}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define RECURSIVEMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD|LOCK_RECURSIVE}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define ERRORCHECKMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD|LOCK_ERRORCHECK}, MUTEX_MAGIC}, \
|
||||
{{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define RECURSIVE_ERRORCHECKMUTEX \
|
||||
{{0, 0, 0, {USYNC_THREAD|LOCK_RECURSIVE|LOCK_ERRORCHECK}, \
|
||||
MUTEX_MAGIC}, {{{0, 0, 0, 0, 0, 0, 0, 0}}}, 0}
|
||||
#define DEFAULTCV \
|
||||
{{{0, 0, 0, 0}, USYNC_THREAD, COND_MAGIC}, 0}
|
||||
#define SHAREDCV \
|
||||
{{{0, 0, 0, 0}, USYNC_PROCESS, COND_MAGIC}, 0}
|
||||
#define DEFAULTSEMA \
|
||||
{0, USYNC_THREAD, SEMA_MAGIC, {0, 0, 0}, {0, 0}}
|
||||
#define SHAREDSEMA \
|
||||
{0, USYNC_PROCESS, SEMA_MAGIC, {0, 0, 0}, {0, 0}}
|
||||
#define DEFAULTRWLOCK \
|
||||
{0, USYNC_THREAD, RWL_MAGIC, DEFAULTMUTEX, DEFAULTCV, DEFAULTCV}
|
||||
#define SHAREDRWLOCK \
|
||||
{0, USYNC_PROCESS, RWL_MAGIC, SHAREDMUTEX, SHAREDCV, SHAREDCV}
|
||||
|
||||
/*
|
||||
* Tests on lock states.
|
||||
*/
|
||||
#define SEMA_HELD(x) _sema_held(x)
|
||||
#define RW_READ_HELD(x) _rw_read_held(x)
|
||||
#define RW_WRITE_HELD(x) _rw_write_held(x)
|
||||
#define RW_LOCK_HELD(x) (RW_READ_HELD(x) || RW_WRITE_HELD(x))
|
||||
#define MUTEX_HELD(x) _mutex_held(x)
|
||||
|
||||
/*
|
||||
* The following definitions are for assertions which can be checked
|
||||
* statically by tools like lock_lint. You can also define your own
|
||||
* run-time test for each. If you don't, we define them to 1 so that
|
||||
* such assertions simply pass.
|
||||
*/
|
||||
#ifndef NO_LOCKS_HELD
|
||||
#define NO_LOCKS_HELD 1
|
||||
#endif
|
||||
#ifndef NO_COMPETING_THREADS
|
||||
#define NO_COMPETING_THREADS 1
|
||||
#endif
|
||||
|
||||
#ifndef _ASM
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
int _sema_held(sema_t *);
|
||||
int _rw_read_held(rwlock_t *);
|
||||
int _rw_write_held(rwlock_t *);
|
||||
int _mutex_held(mutex_t *);
|
||||
|
||||
#else /* __STDC__ */
|
||||
|
||||
int _sema_held();
|
||||
int _rw_read_held();
|
||||
int _rw_write_held();
|
||||
int _mutex_held();
|
||||
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#endif /* _ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYNCH_H */
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _THREAD_H
|
||||
#define _THREAD_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Compatibility thread stuff needed for Solaris -> Linux port
|
||||
*/
|
||||
|
||||
typedef pthread_t thread_t;
|
||||
typedef pthread_mutex_t mutex_t;
|
||||
typedef pthread_cond_t cond_t;
|
||||
typedef pthread_rwlock_t rwlock_t;
|
||||
|
||||
#define USYNC_THREAD 0
|
||||
|
||||
#define thr_self() (unsigned long)pthread_self()
|
||||
#define thr_equal(a,b) pthread_equal(a,b)
|
||||
#define thr_join(t,d,s) pthread_join(t,s)
|
||||
#define thr_exit(r) pthread_exit(r)
|
||||
#define _mutex_init(l,f,a) pthread_mutex_init(l,NULL)
|
||||
#define _mutex_destroy(l) pthread_mutex_destroy(l)
|
||||
#define mutex_lock(l) pthread_mutex_lock(l)
|
||||
#define mutex_trylock(l) pthread_mutex_trylock(l)
|
||||
#define mutex_unlock(l) pthread_mutex_unlock(l)
|
||||
#define rwlock_init(l,f,a) pthread_rwlock_init(l,NULL)
|
||||
#define rwlock_destroy(l) pthread_rwlock_destroy(l)
|
||||
#define rw_rdlock(l) pthread_rwlock_rdlock(l)
|
||||
#define rw_wrlock(l) pthread_rwlock_wrlock(l)
|
||||
#define rw_tryrdlock(l) pthread_rwlock_tryrdlock(l)
|
||||
#define rw_trywrlock(l) pthread_rwlock_trywrlock(l)
|
||||
#define rw_unlock(l) pthread_rwlock_unlock(l)
|
||||
#define cond_init(l,f,a) pthread_cond_init(l,NULL)
|
||||
#define cond_destroy(l) pthread_cond_destroy(l)
|
||||
#define cond_wait(l,m) pthread_cond_wait(l,m)
|
||||
#define cond_signal(l) pthread_cond_signal(l)
|
||||
#define cond_broadcast(l) pthread_cond_broadcast(l)
|
||||
|
||||
#define THR_BOUND 0x00000001 /* = PTHREAD_SCOPE_SYSTEM */
|
||||
#define THR_NEW_LWP 0x00000002
|
||||
#define THR_DETACHED 0x00000040 /* = PTHREAD_CREATE_DETACHED */
|
||||
#define THR_SUSPENDED 0x00000080
|
||||
#define THR_DAEMON 0x00000100
|
||||
|
||||
static __inline int
|
||||
thr_create(void *stack_base, size_t stack_size, void *(*start_func) (void*),
|
||||
void *arg, long flags, thread_t *new_thread_ID)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(stack_base == NULL);
|
||||
assert(stack_size == 0);
|
||||
assert((flags & ~THR_BOUND & ~THR_DETACHED) == 0);
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
if(flags & THR_DETACHED)
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
/* This function ignores the THR_BOUND flag, since NPTL doesn't seem to support PTHREAD_SCOPE_PROCESS */
|
||||
|
||||
ret = pthread_create(new_thread_ID, &attr, start_func, arg);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif /* _THREAD_H */
|
@ -1,266 +0,0 @@
|
||||
/*
|
||||
* 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 <unistd.h>
|
||||
#include <strings.h>
|
||||
#include "libnvpair.h"
|
||||
|
||||
/*
|
||||
* libnvpair - A tools library for manipulating <name, value> pairs.
|
||||
*
|
||||
* This library provides routines packing an unpacking nv pairs
|
||||
* for transporting data across process boundaries, transporting
|
||||
* between kernel and userland, and possibly saving onto disk files.
|
||||
*/
|
||||
|
||||
static void
|
||||
indent(FILE *fp, int depth)
|
||||
{
|
||||
while (depth-- > 0)
|
||||
(void) fprintf(fp, "\t");
|
||||
}
|
||||
|
||||
/*
|
||||
* nvlist_print - Prints elements in an event buffer
|
||||
*/
|
||||
static
|
||||
void
|
||||
nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth)
|
||||
{
|
||||
int i;
|
||||
char *name;
|
||||
uint_t nelem;
|
||||
nvpair_t *nvp;
|
||||
|
||||
if (nvl == NULL)
|
||||
return;
|
||||
|
||||
indent(fp, depth);
|
||||
(void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
|
||||
|
||||
nvp = nvlist_next_nvpair(nvl, NULL);
|
||||
|
||||
while (nvp) {
|
||||
data_type_t type = nvpair_type(nvp);
|
||||
|
||||
indent(fp, depth);
|
||||
name = nvpair_name(nvp);
|
||||
(void) fprintf(fp, "\t%s =", name);
|
||||
nelem = 0;
|
||||
switch (type) {
|
||||
case DATA_TYPE_BOOLEAN: {
|
||||
(void) fprintf(fp, " 1");
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BOOLEAN_VALUE: {
|
||||
boolean_t val;
|
||||
(void) nvpair_value_boolean_value(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BYTE: {
|
||||
uchar_t val;
|
||||
(void) nvpair_value_byte(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%2.2x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT8: {
|
||||
int8_t val;
|
||||
(void) nvpair_value_int8(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT8: {
|
||||
uint8_t val;
|
||||
(void) nvpair_value_uint8(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT16: {
|
||||
int16_t val;
|
||||
(void) nvpair_value_int16(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT16: {
|
||||
uint16_t val;
|
||||
(void) nvpair_value_uint16(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT32: {
|
||||
int32_t val;
|
||||
(void) nvpair_value_int32(nvp, &val);
|
||||
(void) fprintf(fp, " %d", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT32: {
|
||||
uint32_t val;
|
||||
(void) nvpair_value_uint32(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%x", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT64: {
|
||||
int64_t val;
|
||||
(void) nvpair_value_int64(nvp, &val);
|
||||
(void) fprintf(fp, " %lld", (longlong_t)val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT64: {
|
||||
uint64_t val;
|
||||
(void) nvpair_value_uint64(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%llx", (u_longlong_t)val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_STRING: {
|
||||
char *val;
|
||||
(void) nvpair_value_string(nvp, &val);
|
||||
(void) fprintf(fp, " %s", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BOOLEAN_ARRAY: {
|
||||
boolean_t *val;
|
||||
(void) nvpair_value_boolean_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_BYTE_ARRAY: {
|
||||
uchar_t *val;
|
||||
(void) nvpair_value_byte_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%2.2x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT8_ARRAY: {
|
||||
int8_t *val;
|
||||
(void) nvpair_value_int8_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT8_ARRAY: {
|
||||
uint8_t *val;
|
||||
(void) nvpair_value_uint8_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT16_ARRAY: {
|
||||
int16_t *val;
|
||||
(void) nvpair_value_int16_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT16_ARRAY: {
|
||||
uint16_t *val;
|
||||
(void) nvpair_value_uint16_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT32_ARRAY: {
|
||||
int32_t *val;
|
||||
(void) nvpair_value_int32_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %d", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT32_ARRAY: {
|
||||
uint32_t *val;
|
||||
(void) nvpair_value_uint32_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%x", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_INT64_ARRAY: {
|
||||
int64_t *val;
|
||||
(void) nvpair_value_int64_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %lld", (longlong_t)val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_UINT64_ARRAY: {
|
||||
uint64_t *val;
|
||||
(void) nvpair_value_uint64_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " 0x%llx",
|
||||
(u_longlong_t)val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_STRING_ARRAY: {
|
||||
char **val;
|
||||
(void) nvpair_value_string_array(nvp, &val, &nelem);
|
||||
for (i = 0; i < nelem; i++)
|
||||
(void) fprintf(fp, " %s", val[i]);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_HRTIME: {
|
||||
hrtime_t val;
|
||||
(void) nvpair_value_hrtime(nvp, &val);
|
||||
(void) fprintf(fp, " 0x%llx", val);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_NVLIST: {
|
||||
nvlist_t *val;
|
||||
(void) nvpair_value_nvlist(nvp, &val);
|
||||
(void) fprintf(fp, " (embedded nvlist)\n");
|
||||
nvlist_print_with_indent(fp, val, depth + 1);
|
||||
indent(fp, depth + 1);
|
||||
(void) fprintf(fp, "(end %s)\n", name);
|
||||
break;
|
||||
}
|
||||
case DATA_TYPE_NVLIST_ARRAY: {
|
||||
nvlist_t **val;
|
||||
(void) nvpair_value_nvlist_array(nvp, &val, &nelem);
|
||||
(void) fprintf(fp, " (array of embedded nvlists)\n");
|
||||
for (i = 0; i < nelem; i++) {
|
||||
indent(fp, depth + 1);
|
||||
(void) fprintf(fp,
|
||||
"(start %s[%d])\n", name, i);
|
||||
nvlist_print_with_indent(fp, val[i], depth + 1);
|
||||
indent(fp, depth + 1);
|
||||
(void) fprintf(fp, "(end %s[%d])\n", name, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
(void) fprintf(fp, " unknown data type (%d)", type);
|
||||
break;
|
||||
}
|
||||
(void) fprintf(fp, "\n");
|
||||
nvp = nvlist_next_nvpair(nvl, nvp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nvlist_print(FILE *fp, nvlist_t *nvl)
|
||||
{
|
||||
nvlist_print_with_indent(fp, nvl, 0);
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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 _LIBNVPAIR_H
|
||||
#define _LIBNVPAIR_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/nvpair.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void nvlist_print(FILE *, nvlist_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBNVPAIR_H */
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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 <sys/nvpair.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void *
|
||||
nv_alloc_sys(nv_alloc_t *nva, size_t size)
|
||||
{
|
||||
return (malloc(size));
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
nv_free_sys(nv_alloc_t *nva, void *buf, size_t size)
|
||||
{
|
||||
free(buf);
|
||||
}
|
||||
|
||||
const nv_alloc_ops_t system_ops_def = {
|
||||
NULL, /* nv_ao_init() */
|
||||
NULL, /* nv_ao_fini() */
|
||||
nv_alloc_sys, /* nv_ao_alloc() */
|
||||
nv_free_sys, /* nv_ao_free() */
|
||||
NULL /* nv_ao_reset() */
|
||||
};
|
||||
|
||||
nv_alloc_t nv_alloc_nosleep_def = {
|
||||
&system_ops_def,
|
||||
NULL
|
||||
};
|
||||
|
||||
nv_alloc_t *nv_alloc_nosleep = &nv_alloc_nosleep_def;
|
@ -1,384 +0,0 @@
|
||||
/*
|
||||
* 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_H
|
||||
#define _LIBUUTIL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <solaris.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 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 */
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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 2006 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 <solaris.h>
|
||||
|
||||
/*
|
||||
* We don't bind to the internal libc interfaces if this is a
|
||||
* native build.
|
||||
*/
|
||||
#ifndef NATIVE_BUILD
|
||||
#include "c_synonyms.h"
|
||||
#endif
|
||||
|
||||
#include <libuutil.h>
|
||||
#include <libuutil_impl.h>
|
||||
|
||||
#endif /* _LIBUUTIL_COMMON_H */
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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 <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_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);
|
||||
}
|
@ -1,567 +0,0 @@
|
||||
/*
|
||||
* 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 2006 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",
|
||||
sizeof (pp->uap_name), pp->uap_name, 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, np, pp, pp->uap_name, offset,
|
||||
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, np, pp, pp->uap_name, offset,
|
||||
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, np, 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, np, 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", 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",
|
||||
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", 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",
|
||||
ap, elem, idx);
|
||||
if (na[0] == 0)
|
||||
uu_panic("uu_avl_insert(%p, %p, %p): node not "
|
||||
"initialized\n",
|
||||
ap, elem, idx);
|
||||
if (na[0] != POOL_TO_MARKER(pp))
|
||||
uu_panic("uu_avl_insert(%p, %p, %p): node from "
|
||||
"other pool, or corrupt\n",
|
||||
ap, elem, idx);
|
||||
|
||||
if (!INDEX_VALID(ap, idx))
|
||||
uu_panic("uu_avl_insert(%p, %p, %p): %s\n",
|
||||
ap, elem, 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",
|
||||
ap, 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",
|
||||
ap, 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);
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,711 +0,0 @@
|
||||
/*
|
||||
* 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 <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",
|
||||
sizeof (pp->ulp_name), pp->ulp_name, 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, np, pp, pp->ulp_name, offset,
|
||||
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, np, pp, pp->ulp_name, offset,
|
||||
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, np_arg, 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, np_arg, 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",
|
||||
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",
|
||||
lp);
|
||||
}
|
||||
if (lp->ul_numnodes != 0) {
|
||||
uu_panic("uu_list_destroy(%p): numnodes is nonzero, "
|
||||
"but list is empty\n", 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",
|
||||
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", lp, next, 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",
|
||||
lp, NODE_TO_ELEM(lp, np), 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",
|
||||
lp, elem, 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", lp, elem, 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",
|
||||
lp, 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", lp, 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",
|
||||
lp, 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", lp, 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) {
|
||||
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",
|
||||
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", 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", lp,
|
||||
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",
|
||||
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", 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",
|
||||
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", 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);
|
||||
}
|
@ -1,250 +0,0 @@
|
||||
/*
|
||||
* 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 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 (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);
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,205 +0,0 @@
|
||||
/*
|
||||
* 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 = "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);
|
||||
}
|
@ -1,300 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -1,443 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBZFS_H
|
||||
#define _LIBZFS_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <assert.h>
|
||||
#include <libnvpair.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/varargs.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Miscellaneous ZFS constants
|
||||
*/
|
||||
#define ZFS_MAXNAMELEN MAXNAMELEN
|
||||
#define ZPOOL_MAXNAMELEN MAXNAMELEN
|
||||
#define ZFS_MAXPROPLEN MAXPATHLEN
|
||||
|
||||
/*
|
||||
* libzfs errors
|
||||
*/
|
||||
enum {
|
||||
EZFS_NOMEM = 2000, /* out of memory */
|
||||
EZFS_BADPROP, /* invalid property value */
|
||||
EZFS_PROPREADONLY, /* cannot set readonly property */
|
||||
EZFS_PROPTYPE, /* property does not apply to dataset type */
|
||||
EZFS_PROPNONINHERIT, /* property is not inheritable */
|
||||
EZFS_PROPSPACE, /* bad quota or reservation */
|
||||
EZFS_BADTYPE, /* dataset is not of appropriate type */
|
||||
EZFS_BUSY, /* pool or dataset is busy */
|
||||
EZFS_EXISTS, /* pool or dataset already exists */
|
||||
EZFS_NOENT, /* no such pool or dataset */
|
||||
EZFS_BADSTREAM, /* bad backup stream */
|
||||
EZFS_DSREADONLY, /* dataset is readonly */
|
||||
EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */
|
||||
EZFS_VOLHASDATA, /* volume already contains data */
|
||||
EZFS_INVALIDNAME, /* invalid dataset name */
|
||||
EZFS_BADRESTORE, /* unable to restore to destination */
|
||||
EZFS_BADBACKUP, /* backup failed */
|
||||
EZFS_BADTARGET, /* bad attach/detach/replace target */
|
||||
EZFS_NODEVICE, /* no such device in pool */
|
||||
EZFS_BADDEV, /* invalid device to add */
|
||||
EZFS_NOREPLICAS, /* no valid replicas */
|
||||
EZFS_RESILVERING, /* currently resilvering */
|
||||
EZFS_BADVERSION, /* unsupported version */
|
||||
EZFS_POOLUNAVAIL, /* pool is currently unavailable */
|
||||
EZFS_DEVOVERFLOW, /* too many devices in one vdev */
|
||||
EZFS_BADPATH, /* must be an absolute path */
|
||||
EZFS_CROSSTARGET, /* rename or clone across pool or dataset */
|
||||
EZFS_ZONED, /* used improperly in local zone */
|
||||
EZFS_MOUNTFAILED, /* failed to mount dataset */
|
||||
EZFS_UMOUNTFAILED, /* failed to unmount dataset */
|
||||
EZFS_UNSHARENFSFAILED, /* unshare(1M) failed */
|
||||
EZFS_SHARENFSFAILED, /* share(1M) failed */
|
||||
EZFS_DEVLINKS, /* failed to create zvol links */
|
||||
EZFS_PERM, /* permission denied */
|
||||
EZFS_NOSPC, /* out of space */
|
||||
EZFS_IO, /* I/O error */
|
||||
EZFS_INTR, /* signal received */
|
||||
EZFS_ISSPARE, /* device is a hot spare */
|
||||
EZFS_INVALCONFIG, /* invalid vdev configuration */
|
||||
EZFS_RECURSIVE, /* recursive dependency */
|
||||
EZFS_NOHISTORY, /* no history object */
|
||||
EZFS_UNSHAREISCSIFAILED, /* iscsitgtd failed request to unshare */
|
||||
EZFS_SHAREISCSIFAILED, /* iscsitgtd failed request to share */
|
||||
EZFS_POOLPROPS, /* couldn't retrieve pool props */
|
||||
EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */
|
||||
EZFS_POOL_INVALARG, /* invalid argument for this pool operation */
|
||||
EZFS_NAMETOOLONG, /* dataset name is too long */
|
||||
EZFS_UNKNOWN
|
||||
};
|
||||
|
||||
/*
|
||||
* Basic handle types
|
||||
*/
|
||||
typedef struct zfs_handle zfs_handle_t;
|
||||
typedef struct zpool_handle zpool_handle_t;
|
||||
typedef struct libzfs_handle libzfs_handle_t;
|
||||
|
||||
/*
|
||||
* Library initialization
|
||||
*/
|
||||
extern libzfs_handle_t *libzfs_init(void);
|
||||
extern void libzfs_fini(libzfs_handle_t *);
|
||||
|
||||
extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
|
||||
extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
|
||||
|
||||
extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
|
||||
|
||||
extern int libzfs_errno(libzfs_handle_t *);
|
||||
extern const char *libzfs_error_action(libzfs_handle_t *);
|
||||
extern const char *libzfs_error_description(libzfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Basic handle functions
|
||||
*/
|
||||
extern zpool_handle_t *zpool_open(libzfs_handle_t *, const char *);
|
||||
extern zpool_handle_t *zpool_open_canfail(libzfs_handle_t *, const char *);
|
||||
extern void zpool_close(zpool_handle_t *);
|
||||
extern const char *zpool_get_name(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_guid(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_space_used(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_space_total(zpool_handle_t *);
|
||||
extern int zpool_get_root(zpool_handle_t *, char *, size_t);
|
||||
extern int zpool_get_state(zpool_handle_t *);
|
||||
extern uint64_t zpool_get_version(zpool_handle_t *);
|
||||
|
||||
/*
|
||||
* Iterate over all active pools in the system.
|
||||
*/
|
||||
typedef int (*zpool_iter_f)(zpool_handle_t *, void *);
|
||||
extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
|
||||
|
||||
/*
|
||||
* Functions to create and destroy pools
|
||||
*/
|
||||
extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
|
||||
const char *);
|
||||
extern int zpool_destroy(zpool_handle_t *);
|
||||
extern int zpool_add(zpool_handle_t *, nvlist_t *);
|
||||
|
||||
/*
|
||||
* Functions to manipulate pool and vdev state
|
||||
*/
|
||||
extern int zpool_scrub(zpool_handle_t *, pool_scrub_type_t);
|
||||
|
||||
extern int zpool_vdev_online(zpool_handle_t *, const char *);
|
||||
extern int zpool_vdev_offline(zpool_handle_t *, const char *, int);
|
||||
extern int zpool_vdev_attach(zpool_handle_t *, const char *, const char *,
|
||||
nvlist_t *, int);
|
||||
extern int zpool_vdev_detach(zpool_handle_t *, const char *);
|
||||
extern int zpool_vdev_remove(zpool_handle_t *, const char *);
|
||||
extern int zpool_clear(zpool_handle_t *, const char *);
|
||||
extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *);
|
||||
|
||||
/*
|
||||
* Functions to manage pool properties
|
||||
*/
|
||||
extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
|
||||
extern int zpool_get_prop(zpool_handle_t *, zfs_prop_t, char *,
|
||||
size_t proplen, zfs_source_t *);
|
||||
extern const char *zpool_prop_to_name(zpool_prop_t);
|
||||
extern const char *zpool_prop_values(zpool_prop_t);
|
||||
|
||||
/*
|
||||
* Pool health statistics.
|
||||
*/
|
||||
typedef enum {
|
||||
/*
|
||||
* The following correspond to faults as defined in the (fault.fs.zfs.*)
|
||||
* event namespace. Each is associated with a corresponding message ID.
|
||||
*/
|
||||
ZPOOL_STATUS_CORRUPT_CACHE, /* corrupt /kernel/drv/zpool.cache */
|
||||
ZPOOL_STATUS_MISSING_DEV_R, /* missing device with replicas */
|
||||
ZPOOL_STATUS_MISSING_DEV_NR, /* missing device with no replicas */
|
||||
ZPOOL_STATUS_CORRUPT_LABEL_R, /* bad device label with replicas */
|
||||
ZPOOL_STATUS_CORRUPT_LABEL_NR, /* bad device label with no replicas */
|
||||
ZPOOL_STATUS_BAD_GUID_SUM, /* sum of device guids didn't match */
|
||||
ZPOOL_STATUS_CORRUPT_POOL, /* pool metadata is corrupted */
|
||||
ZPOOL_STATUS_CORRUPT_DATA, /* data errors in user (meta)data */
|
||||
ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
|
||||
ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
|
||||
ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */
|
||||
|
||||
/*
|
||||
* The following are not faults per se, but still an error possibly
|
||||
* requiring administrative attention. There is no corresponding
|
||||
* message ID.
|
||||
*/
|
||||
ZPOOL_STATUS_VERSION_OLDER, /* older on-disk version */
|
||||
ZPOOL_STATUS_RESILVERING, /* device being resilvered */
|
||||
ZPOOL_STATUS_OFFLINE_DEV, /* device online */
|
||||
|
||||
/*
|
||||
* Finally, the following indicates a healthy pool.
|
||||
*/
|
||||
ZPOOL_STATUS_OK
|
||||
} zpool_status_t;
|
||||
|
||||
extern zpool_status_t zpool_get_status(zpool_handle_t *, char **);
|
||||
extern zpool_status_t zpool_import_status(nvlist_t *, char **);
|
||||
|
||||
/*
|
||||
* Statistics and configuration functions.
|
||||
*/
|
||||
extern nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
|
||||
extern int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
|
||||
extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
|
||||
|
||||
/*
|
||||
* Import and export functions
|
||||
*/
|
||||
extern int zpool_export(zpool_handle_t *);
|
||||
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
|
||||
const char *);
|
||||
|
||||
/*
|
||||
* Search for pools to import
|
||||
*/
|
||||
extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
|
||||
|
||||
/*
|
||||
* Miscellaneous pool functions
|
||||
*/
|
||||
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *);
|
||||
extern int zpool_upgrade(zpool_handle_t *);
|
||||
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
|
||||
extern void zpool_log_history(libzfs_handle_t *, int, char **, const char *,
|
||||
boolean_t, boolean_t);
|
||||
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
|
||||
size_t len);
|
||||
|
||||
/*
|
||||
* Basic handle manipulations. These functions do not create or destroy the
|
||||
* underlying datasets, only the references to them.
|
||||
*/
|
||||
extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
|
||||
extern void zfs_close(zfs_handle_t *);
|
||||
extern zfs_type_t zfs_get_type(const zfs_handle_t *);
|
||||
extern const char *zfs_get_name(const zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Property management functions. Some functions are shared with the kernel,
|
||||
* and are found in sys/fs/zfs.h.
|
||||
*/
|
||||
extern const char *zfs_prop_to_name(zfs_prop_t);
|
||||
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
|
||||
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
|
||||
zfs_source_t *, char *, size_t, boolean_t);
|
||||
extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
|
||||
zfs_source_t *, char *, size_t);
|
||||
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
|
||||
extern const char *zfs_prop_get_string(zfs_handle_t *, zfs_prop_t);
|
||||
extern int zfs_prop_inherit(zfs_handle_t *, const char *);
|
||||
extern const char *zfs_prop_values(zfs_prop_t);
|
||||
extern int zfs_prop_valid_for_type(zfs_prop_t, int);
|
||||
extern const char *zfs_prop_default_string(zfs_prop_t prop);
|
||||
extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
|
||||
extern int zfs_prop_is_string(zfs_prop_t prop);
|
||||
extern const char *zfs_prop_column_name(zfs_prop_t);
|
||||
extern boolean_t zfs_prop_align_right(zfs_prop_t);
|
||||
extern void nicebool(int value, char *buf, size_t buflen);
|
||||
|
||||
typedef struct zfs_proplist {
|
||||
zfs_prop_t pl_prop;
|
||||
char *pl_user_prop;
|
||||
struct zfs_proplist *pl_next;
|
||||
boolean_t pl_all;
|
||||
size_t pl_width;
|
||||
boolean_t pl_fixed;
|
||||
} zfs_proplist_t;
|
||||
|
||||
typedef zfs_proplist_t zpool_proplist_t;
|
||||
|
||||
extern int zfs_get_proplist(libzfs_handle_t *, char *, zfs_proplist_t **);
|
||||
extern int zpool_get_proplist(libzfs_handle_t *, char *, zpool_proplist_t **);
|
||||
extern int zfs_expand_proplist(zfs_handle_t *, zfs_proplist_t **);
|
||||
extern int zpool_expand_proplist(zpool_handle_t *, zpool_proplist_t **);
|
||||
extern void zfs_free_proplist(zfs_proplist_t *);
|
||||
extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
|
||||
|
||||
#define ZFS_MOUNTPOINT_NONE "none"
|
||||
#define ZFS_MOUNTPOINT_LEGACY "legacy"
|
||||
|
||||
/*
|
||||
* Functions for printing properties from zfs/zpool
|
||||
*/
|
||||
typedef struct libzfs_get_cbdata {
|
||||
int cb_sources;
|
||||
int cb_columns[4];
|
||||
int cb_colwidths[5];
|
||||
boolean_t cb_scripted;
|
||||
boolean_t cb_literal;
|
||||
boolean_t cb_first;
|
||||
zfs_proplist_t *cb_proplist;
|
||||
} libzfs_get_cbdata_t;
|
||||
|
||||
void libzfs_print_one_property(const char *, libzfs_get_cbdata_t *,
|
||||
const char *, const char *, zfs_source_t, const char *);
|
||||
|
||||
#define GET_COL_NAME 1
|
||||
#define GET_COL_PROPERTY 2
|
||||
#define GET_COL_VALUE 3
|
||||
#define GET_COL_SOURCE 4
|
||||
|
||||
/*
|
||||
* Iterator functions.
|
||||
*/
|
||||
typedef int (*zfs_iter_f)(zfs_handle_t *, void *);
|
||||
extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
|
||||
extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
|
||||
|
||||
/*
|
||||
* Functions to create and destroy datasets.
|
||||
*/
|
||||
extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
|
||||
nvlist_t *);
|
||||
extern int zfs_destroy(zfs_handle_t *);
|
||||
extern int zfs_destroy_snaps(zfs_handle_t *, char *);
|
||||
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
|
||||
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t);
|
||||
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, int);
|
||||
extern int zfs_rename(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_send(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_receive(libzfs_handle_t *, const char *, int, int, int,
|
||||
boolean_t, int);
|
||||
extern int zfs_promote(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Miscellaneous functions.
|
||||
*/
|
||||
extern const char *zfs_type_to_name(zfs_type_t);
|
||||
extern void zfs_refresh_properties(zfs_handle_t *);
|
||||
extern int zfs_name_valid(const char *, zfs_type_t);
|
||||
extern int zfs_disable(zfs_handle_t *);
|
||||
extern int zfs_enable(zfs_handle_t *);
|
||||
extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t);
|
||||
|
||||
/*
|
||||
* Mount support functions.
|
||||
*/
|
||||
extern boolean_t is_mounted(libzfs_handle_t *, const char *special, char **);
|
||||
extern boolean_t zfs_is_mounted(zfs_handle_t *, char **);
|
||||
extern int zfs_mount(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_unmount(zfs_handle_t *, const char *, int);
|
||||
extern int zfs_unmountall(zfs_handle_t *, int);
|
||||
|
||||
/*
|
||||
* Share support functions.
|
||||
*/
|
||||
extern boolean_t zfs_is_shared(zfs_handle_t *);
|
||||
extern int zfs_share(zfs_handle_t *);
|
||||
extern int zfs_unshare(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Protocol-specifc share support functions.
|
||||
*/
|
||||
extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
|
||||
extern int zfs_share_nfs(zfs_handle_t *);
|
||||
extern int zfs_unshare_nfs(zfs_handle_t *, const char *);
|
||||
extern int zfs_unshareall_nfs(zfs_handle_t *);
|
||||
extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *);
|
||||
extern int zfs_share_iscsi(zfs_handle_t *);
|
||||
extern int zfs_unshare_iscsi(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* FreeBSD-specific jail support function.
|
||||
*/
|
||||
extern int zfs_jail(zfs_handle_t *, int, int);
|
||||
|
||||
/*
|
||||
* When dealing with nvlists, verify() is extremely useful
|
||||
*/
|
||||
#ifndef verify
|
||||
#ifdef NDEBUG
|
||||
#define verify(EX) ((void)(EX))
|
||||
#else
|
||||
#define verify(EX) assert(EX)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Utility function to convert a number to a human-readable form.
|
||||
*/
|
||||
extern void zfs_nicenum(uint64_t, char *, size_t);
|
||||
extern int zfs_nicestrtonum(libzfs_handle_t *, const char *, uint64_t *);
|
||||
|
||||
/*
|
||||
* Pool destroy special. Remove the device information without destroying
|
||||
* the underlying dataset.
|
||||
*/
|
||||
extern int zfs_remove_link(zfs_handle_t *);
|
||||
|
||||
/*
|
||||
* Given a device or file, determine if it is part of a pool.
|
||||
*/
|
||||
extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
|
||||
boolean_t *);
|
||||
|
||||
/*
|
||||
* ftyp special. Read the label from a given device.
|
||||
*/
|
||||
extern int zpool_read_label(int, nvlist_t **);
|
||||
|
||||
/*
|
||||
* Create and remove zvol /dev links.
|
||||
*/
|
||||
extern int zpool_create_zvol_links(zpool_handle_t *);
|
||||
extern int zpool_remove_zvol_links(zpool_handle_t *);
|
||||
|
||||
/*
|
||||
* Enable and disable datasets within a pool by mounting/unmounting and
|
||||
* sharing/unsharing them.
|
||||
*/
|
||||
extern int zpool_enable_datasets(zpool_handle_t *, const char *, int);
|
||||
extern int zpool_disable_datasets(zpool_handle_t *, boolean_t);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
extern int zmount(const char *, const char *, int, char *, char *, int, char *,
|
||||
int);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBZFS_H */
|
@ -1,599 +0,0 @@
|
||||
/*
|
||||
* 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 <libintl.h>
|
||||
#include <libuutil.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <zone.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
/*
|
||||
* Structure to keep track of dataset state. Before changing the 'sharenfs' or
|
||||
* 'mountpoint' property, we record whether the filesystem was previously
|
||||
* mounted/shared. This prior state dictates whether we remount/reshare the
|
||||
* dataset after the property has been changed.
|
||||
*
|
||||
* The interface consists of the following sequence of functions:
|
||||
*
|
||||
* changelist_gather()
|
||||
* changelist_prefix()
|
||||
* < change property >
|
||||
* changelist_postfix()
|
||||
* changelist_free()
|
||||
*
|
||||
* Other interfaces:
|
||||
*
|
||||
* changelist_remove() - remove a node from a gathered list
|
||||
* changelist_rename() - renames all datasets appropriately when doing a rename
|
||||
* changelist_unshare() - unshares all the nodes in a given changelist
|
||||
* changelist_haszonedchild() - check if there is any child exported to
|
||||
* a local zone
|
||||
*/
|
||||
typedef struct prop_changenode {
|
||||
zfs_handle_t *cn_handle;
|
||||
int cn_shared;
|
||||
int cn_mounted;
|
||||
int cn_zoned;
|
||||
uu_list_node_t cn_listnode;
|
||||
} prop_changenode_t;
|
||||
|
||||
struct prop_changelist {
|
||||
zfs_prop_t cl_prop;
|
||||
zfs_prop_t cl_realprop;
|
||||
uu_list_pool_t *cl_pool;
|
||||
uu_list_t *cl_list;
|
||||
boolean_t cl_waslegacy;
|
||||
boolean_t cl_allchildren;
|
||||
boolean_t cl_alldependents;
|
||||
int cl_flags;
|
||||
boolean_t cl_haszonedchild;
|
||||
boolean_t cl_sorted;
|
||||
};
|
||||
|
||||
/*
|
||||
* If the property is 'mountpoint', go through and unmount filesystems as
|
||||
* necessary. We don't do the same for 'sharenfs', because we can just re-share
|
||||
* with different options without interrupting service.
|
||||
*/
|
||||
int
|
||||
changelist_prefix(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
int ret = 0;
|
||||
|
||||
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT)
|
||||
return (0);
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
/*
|
||||
* If we are in the global zone, but this dataset is exported
|
||||
* to a local zone, do nothing.
|
||||
*/
|
||||
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
|
||||
continue;
|
||||
|
||||
if (ZFS_IS_VOLUME(cn->cn_handle)) {
|
||||
switch (clp->cl_realprop) {
|
||||
case ZFS_PROP_NAME:
|
||||
/*
|
||||
* If this was a rename, unshare the zvol, and
|
||||
* remove the /dev/zvol links.
|
||||
*/
|
||||
(void) zfs_unshare_iscsi(cn->cn_handle);
|
||||
|
||||
if (zvol_remove_link(cn->cn_handle->zfs_hdl,
|
||||
cn->cn_handle->zfs_name) != 0)
|
||||
ret = -1;
|
||||
break;
|
||||
|
||||
case ZFS_PROP_VOLSIZE:
|
||||
/*
|
||||
* If this was a change to the volume size, we
|
||||
* need to unshare and reshare the volume.
|
||||
*/
|
||||
(void) zfs_unshare_iscsi(cn->cn_handle);
|
||||
break;
|
||||
}
|
||||
} else if (zfs_unmount(cn->cn_handle, NULL, clp->cl_flags) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
|
||||
* reshare the filesystems as necessary. In changelist_gather() we recorded
|
||||
* whether the filesystem was previously shared or mounted. The action we take
|
||||
* depends on the previous state, and whether the value was previously 'legacy'.
|
||||
* For non-legacy properties, we only remount/reshare the filesystem if it was
|
||||
* previously mounted/shared. Otherwise, we always remount/reshare the
|
||||
* filesystem.
|
||||
*/
|
||||
int
|
||||
changelist_postfix(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
char shareopts[ZFS_MAXPROPLEN];
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* If we're changing the mountpoint, attempt to destroy the underlying
|
||||
* mountpoint. All other datasets will have inherited from this dataset
|
||||
* (in which case their mountpoints exist in the filesystem in the new
|
||||
* location), or have explicit mountpoints set (in which case they won't
|
||||
* be in the changelist).
|
||||
*/
|
||||
if ((cn = uu_list_last(clp->cl_list)) == NULL)
|
||||
return (0);
|
||||
|
||||
if (clp->cl_prop == ZFS_PROP_MOUNTPOINT)
|
||||
remove_mountpoint(cn->cn_handle);
|
||||
|
||||
/*
|
||||
* We walk the datasets in reverse, because we want to mount any parent
|
||||
* datasets before mounting the children.
|
||||
*/
|
||||
for (cn = uu_list_last(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_prev(clp->cl_list, cn)) {
|
||||
/*
|
||||
* If we are in the global zone, but this dataset is exported
|
||||
* to a local zone, do nothing.
|
||||
*/
|
||||
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
|
||||
continue;
|
||||
|
||||
zfs_refresh_properties(cn->cn_handle);
|
||||
|
||||
if (ZFS_IS_VOLUME(cn->cn_handle)) {
|
||||
/*
|
||||
* If we're doing a rename, recreate the /dev/zvol
|
||||
* links.
|
||||
*/
|
||||
if (clp->cl_realprop == ZFS_PROP_NAME &&
|
||||
zvol_create_link(cn->cn_handle->zfs_hdl,
|
||||
cn->cn_handle->zfs_name) != 0) {
|
||||
ret = -1;
|
||||
} else if (cn->cn_shared ||
|
||||
clp->cl_prop == ZFS_PROP_SHAREISCSI) {
|
||||
if (zfs_prop_get(cn->cn_handle,
|
||||
ZFS_PROP_SHAREISCSI, shareopts,
|
||||
sizeof (shareopts), NULL, NULL, 0,
|
||||
B_FALSE) == 0 &&
|
||||
strcmp(shareopts, "off") == 0) {
|
||||
ret = zfs_unshare_iscsi(cn->cn_handle);
|
||||
} else {
|
||||
ret = zfs_share_iscsi(cn->cn_handle);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((clp->cl_waslegacy || cn->cn_mounted) &&
|
||||
!zfs_is_mounted(cn->cn_handle, NULL) &&
|
||||
zfs_mount(cn->cn_handle, NULL, 0) != 0)
|
||||
ret = -1;
|
||||
|
||||
/*
|
||||
* We always re-share even if the filesystem is currently
|
||||
* shared, so that we can adopt any new options.
|
||||
*/
|
||||
if (cn->cn_shared ||
|
||||
(clp->cl_prop == ZFS_PROP_SHARENFS && clp->cl_waslegacy)) {
|
||||
if (zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
|
||||
shareopts, sizeof (shareopts), NULL, NULL, 0,
|
||||
B_FALSE) == 0 && strcmp(shareopts, "off") == 0) {
|
||||
ret = zfs_unshare_nfs(cn->cn_handle, NULL);
|
||||
} else {
|
||||
ret = zfs_share_nfs(cn->cn_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this "dataset" a child of "parent"?
|
||||
*/
|
||||
static boolean_t
|
||||
isa_child_of(const char *dataset, const char *parent)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(parent);
|
||||
|
||||
if (strncmp(dataset, parent, len) == 0 &&
|
||||
(dataset[len] == '@' || dataset[len] == '/' ||
|
||||
dataset[len] == '\0'))
|
||||
return (B_TRUE);
|
||||
else
|
||||
return (B_FALSE);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* If we rename a filesystem, child filesystem handles are no longer valid
|
||||
* since we identify each dataset by its name in the ZFS namespace. As a
|
||||
* result, we have to go through and fix up all the names appropriately. We
|
||||
* could do this automatically if libzfs kept track of all open handles, but
|
||||
* this is a lot less work.
|
||||
*/
|
||||
void
|
||||
changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
char newname[ZFS_MAXNAMELEN];
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
/*
|
||||
* Do not rename a clone that's not in the source hierarchy.
|
||||
*/
|
||||
if (!isa_child_of(cn->cn_handle->zfs_name, src))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Destroy the previous mountpoint if needed.
|
||||
*/
|
||||
remove_mountpoint(cn->cn_handle);
|
||||
|
||||
(void) strlcpy(newname, dst, sizeof (newname));
|
||||
(void) strcat(newname, cn->cn_handle->zfs_name + strlen(src));
|
||||
|
||||
(void) strlcpy(cn->cn_handle->zfs_name, newname,
|
||||
sizeof (cn->cn_handle->zfs_name));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a gathered changelist for the 'sharenfs' property, unshare all the
|
||||
* datasets in the list.
|
||||
*/
|
||||
int
|
||||
changelist_unshare(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
int ret = 0;
|
||||
|
||||
if (clp->cl_prop != ZFS_PROP_SHARENFS)
|
||||
return (0);
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
if (zfs_unshare_nfs(cn->cn_handle, NULL) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there is any child exported to a local zone in a given changelist.
|
||||
* This information has already been recorded while gathering the changelist
|
||||
* via changelist_gather().
|
||||
*/
|
||||
int
|
||||
changelist_haszonedchild(prop_changelist_t *clp)
|
||||
{
|
||||
return (clp->cl_haszonedchild);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a node from a gathered list.
|
||||
*/
|
||||
void
|
||||
changelist_remove(zfs_handle_t *zhp, prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
|
||||
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||
cn = uu_list_next(clp->cl_list, cn)) {
|
||||
|
||||
if (strcmp(cn->cn_handle->zfs_name, zhp->zfs_name) == 0) {
|
||||
uu_list_remove(clp->cl_list, cn);
|
||||
zfs_close(cn->cn_handle);
|
||||
free(cn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Release any memory associated with a changelist.
|
||||
*/
|
||||
void
|
||||
changelist_free(prop_changelist_t *clp)
|
||||
{
|
||||
prop_changenode_t *cn;
|
||||
void *cookie;
|
||||
|
||||
if (clp->cl_list) {
|
||||
cookie = NULL;
|
||||
while ((cn = uu_list_teardown(clp->cl_list, &cookie)) != NULL) {
|
||||
zfs_close(cn->cn_handle);
|
||||
free(cn);
|
||||
}
|
||||
|
||||
uu_list_destroy(clp->cl_list);
|
||||
}
|
||||
if (clp->cl_pool)
|
||||
uu_list_pool_destroy(clp->cl_pool);
|
||||
|
||||
free(clp);
|
||||
}
|
||||
|
||||
static int
|
||||
change_one(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
prop_changelist_t *clp = data;
|
||||
char property[ZFS_MAXPROPLEN];
|
||||
char where[64];
|
||||
prop_changenode_t *cn;
|
||||
zfs_source_t sourcetype;
|
||||
|
||||
/*
|
||||
* We only want to unmount/unshare those filesystems that may inherit
|
||||
* from the target filesystem. If we find any filesystem with a
|
||||
* locally set mountpoint, we ignore any children since changing the
|
||||
* property will not affect them. If this is a rename, we iterate
|
||||
* over all children regardless, since we need them unmounted in
|
||||
* order to do the rename. Also, if this is a volume and we're doing
|
||||
* a rename, then always add it to the changelist.
|
||||
*/
|
||||
|
||||
if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
|
||||
zfs_prop_get(zhp, clp->cl_prop, property,
|
||||
sizeof (property), &sourcetype, where, sizeof (where),
|
||||
B_FALSE) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (clp->cl_alldependents || clp->cl_allchildren ||
|
||||
sourcetype == ZFS_SRC_DEFAULT || sourcetype == ZFS_SRC_INHERITED) {
|
||||
if ((cn = zfs_alloc(zfs_get_handle(zhp),
|
||||
sizeof (prop_changenode_t))) == NULL) {
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
cn->cn_handle = zhp;
|
||||
cn->cn_mounted = zfs_is_mounted(zhp, NULL);
|
||||
cn->cn_shared = zfs_is_shared(zhp);
|
||||
cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
|
||||
|
||||
/* Indicate if any child is exported to a local zone. */
|
||||
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
|
||||
clp->cl_haszonedchild = B_TRUE;
|
||||
|
||||
uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
|
||||
|
||||
if (clp->cl_sorted) {
|
||||
uu_list_index_t idx;
|
||||
|
||||
(void) uu_list_find(clp->cl_list, cn, NULL,
|
||||
&idx);
|
||||
uu_list_insert(clp->cl_list, cn, idx);
|
||||
} else {
|
||||
ASSERT(!clp->cl_alldependents);
|
||||
verify(uu_list_insert_before(clp->cl_list,
|
||||
uu_list_first(clp->cl_list), cn) == 0);
|
||||
}
|
||||
|
||||
if (!clp->cl_alldependents)
|
||||
return (zfs_iter_children(zhp, change_one, data));
|
||||
} else {
|
||||
zfs_close(zhp);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
compare_mountpoints(const void *a, const void *b, void *unused)
|
||||
{
|
||||
const prop_changenode_t *ca = a;
|
||||
const prop_changenode_t *cb = b;
|
||||
|
||||
char mounta[MAXPATHLEN];
|
||||
char mountb[MAXPATHLEN];
|
||||
|
||||
boolean_t hasmounta, hasmountb;
|
||||
|
||||
/*
|
||||
* When unsharing or unmounting filesystems, we need to do it in
|
||||
* mountpoint order. This allows the user to have a mountpoint
|
||||
* hierarchy that is different from the dataset hierarchy, and still
|
||||
* allow it to be changed. However, if either dataset doesn't have a
|
||||
* mountpoint (because it is a volume or a snapshot), we place it at the
|
||||
* end of the list, because it doesn't affect our change at all.
|
||||
*/
|
||||
hasmounta = (zfs_prop_get(ca->cn_handle, ZFS_PROP_MOUNTPOINT, mounta,
|
||||
sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
|
||||
hasmountb = (zfs_prop_get(cb->cn_handle, ZFS_PROP_MOUNTPOINT, mountb,
|
||||
sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
|
||||
|
||||
if (!hasmounta && hasmountb)
|
||||
return (-1);
|
||||
else if (hasmounta && !hasmountb)
|
||||
return (1);
|
||||
else if (!hasmounta && !hasmountb)
|
||||
return (0);
|
||||
else
|
||||
return (strcmp(mountb, mounta));
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a ZFS handle and a property, construct a complete list of datasets
|
||||
* that need to be modified as part of this process. For anything but the
|
||||
* 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
|
||||
* Otherwise, we iterate over all children and look for any datasets that
|
||||
* inherit the property. For each such dataset, we add it to the list and
|
||||
* mark whether it was shared beforehand.
|
||||
*/
|
||||
prop_changelist_t *
|
||||
changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
|
||||
{
|
||||
prop_changelist_t *clp;
|
||||
prop_changenode_t *cn;
|
||||
zfs_handle_t *temp;
|
||||
char property[ZFS_MAXPROPLEN];
|
||||
uu_compare_fn_t *compare = NULL;
|
||||
|
||||
if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* For mountpoint-related tasks, we want to sort everything by
|
||||
* mountpoint, so that we mount and unmount them in the appropriate
|
||||
* order, regardless of their position in the hierarchy.
|
||||
*/
|
||||
if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
|
||||
prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
|
||||
compare = compare_mountpoints;
|
||||
clp->cl_sorted = B_TRUE;
|
||||
}
|
||||
|
||||
clp->cl_pool = uu_list_pool_create("changelist_pool",
|
||||
sizeof (prop_changenode_t),
|
||||
offsetof(prop_changenode_t, cn_listnode),
|
||||
compare, 0);
|
||||
if (clp->cl_pool == NULL) {
|
||||
assert(uu_error() == UU_ERROR_NO_MEMORY);
|
||||
(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
clp->cl_list = uu_list_create(clp->cl_pool, NULL,
|
||||
clp->cl_sorted ? UU_LIST_SORTED : 0);
|
||||
clp->cl_flags = flags;
|
||||
|
||||
if (clp->cl_list == NULL) {
|
||||
assert(uu_error() == UU_ERROR_NO_MEMORY);
|
||||
(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a rename or the 'zoned' property, we pretend we're
|
||||
* changing the mountpoint and flag it so we can catch all children in
|
||||
* change_one().
|
||||
*
|
||||
* Flag cl_alldependents to catch all children plus the dependents
|
||||
* (clones) that are not in the hierarchy.
|
||||
*/
|
||||
if (prop == ZFS_PROP_NAME) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
clp->cl_alldependents = B_TRUE;
|
||||
} else if (prop == ZFS_PROP_ZONED) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
clp->cl_allchildren = B_TRUE;
|
||||
} else if (prop == ZFS_PROP_CANMOUNT) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
} else if (prop == ZFS_PROP_VOLSIZE) {
|
||||
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
|
||||
} else {
|
||||
clp->cl_prop = prop;
|
||||
}
|
||||
clp->cl_realprop = prop;
|
||||
|
||||
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
|
||||
clp->cl_prop != ZFS_PROP_SHARENFS &&
|
||||
clp->cl_prop != ZFS_PROP_SHAREISCSI)
|
||||
return (clp);
|
||||
|
||||
if (clp->cl_alldependents) {
|
||||
if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
} else if (zfs_iter_children(zhp, change_one, clp) != 0) {
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to re-open ourselves because we auto-close all the handles
|
||||
* and can't tell the difference.
|
||||
*/
|
||||
if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
|
||||
ZFS_TYPE_ANY)) == NULL) {
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Always add ourself to the list. We add ourselves to the end so that
|
||||
* we're the last to be unmounted.
|
||||
*/
|
||||
if ((cn = zfs_alloc(zhp->zfs_hdl,
|
||||
sizeof (prop_changenode_t))) == NULL) {
|
||||
zfs_close(temp);
|
||||
changelist_free(clp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
cn->cn_handle = temp;
|
||||
cn->cn_mounted = zfs_is_mounted(temp, NULL);
|
||||
cn->cn_shared = zfs_is_shared(temp);
|
||||
cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
|
||||
|
||||
uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
|
||||
if (clp->cl_sorted) {
|
||||
uu_list_index_t idx;
|
||||
(void) uu_list_find(clp->cl_list, cn, NULL, &idx);
|
||||
uu_list_insert(clp->cl_list, cn, idx);
|
||||
} else {
|
||||
verify(uu_list_insert_after(clp->cl_list,
|
||||
uu_list_last(clp->cl_list), cn) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the property was previously 'legacy' or 'none', record this fact,
|
||||
* as the behavior of changelist_postfix() will be different.
|
||||
*/
|
||||
if (zfs_prop_get(zhp, prop, property, sizeof (property),
|
||||
NULL, NULL, 0, B_FALSE) == 0 &&
|
||||
(strcmp(property, "legacy") == 0 || strcmp(property, "none") == 0 ||
|
||||
strcmp(property, "off") == 0))
|
||||
clp->cl_waslegacy = B_TRUE;
|
||||
|
||||
return (clp);
|
||||
}
|
@ -1,360 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* The pool configuration repository is stored in /etc/zfs/zpool.cache as a
|
||||
* single packed nvlist. While it would be nice to just read in this
|
||||
* file from userland, this wouldn't work from a local zone. So we have to have
|
||||
* a zpool ioctl to return the complete configuration for all pools. In the
|
||||
* global zone, this will be identical to reading the file and unpacking it in
|
||||
* userland.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
#include <libuutil.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
typedef struct config_node {
|
||||
char *cn_name;
|
||||
nvlist_t *cn_config;
|
||||
uu_avl_node_t cn_avl;
|
||||
} config_node_t;
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
config_node_compare(const void *a, const void *b, void *unused)
|
||||
{
|
||||
int ret;
|
||||
|
||||
const config_node_t *ca = (config_node_t *)a;
|
||||
const config_node_t *cb = (config_node_t *)b;
|
||||
|
||||
ret = strcmp(ca->cn_name, cb->cn_name);
|
||||
|
||||
if (ret < 0)
|
||||
return (-1);
|
||||
else if (ret > 0)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
namespace_clear(libzfs_handle_t *hdl)
|
||||
{
|
||||
if (hdl->libzfs_ns_avl) {
|
||||
config_node_t *cn;
|
||||
void *cookie = NULL;
|
||||
|
||||
while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl,
|
||||
&cookie)) != NULL) {
|
||||
nvlist_free(cn->cn_config);
|
||||
free(cn->cn_name);
|
||||
free(cn);
|
||||
}
|
||||
|
||||
uu_avl_destroy(hdl->libzfs_ns_avl);
|
||||
hdl->libzfs_ns_avl = NULL;
|
||||
}
|
||||
|
||||
if (hdl->libzfs_ns_avlpool) {
|
||||
uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
|
||||
hdl->libzfs_ns_avlpool = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the pool namespace, or re-loads it if the cache has changed.
|
||||
*/
|
||||
static int
|
||||
namespace_reload(libzfs_handle_t *hdl)
|
||||
{
|
||||
nvlist_t *config;
|
||||
config_node_t *cn;
|
||||
nvpair_t *elem;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
void *cookie;
|
||||
|
||||
if (hdl->libzfs_ns_gen == 0) {
|
||||
/*
|
||||
* This is the first time we've accessed the configuration
|
||||
* cache. Initialize the AVL tree and then fall through to the
|
||||
* common code.
|
||||
*/
|
||||
if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
|
||||
sizeof (config_node_t),
|
||||
offsetof(config_node_t, cn_avl),
|
||||
config_node_compare, UU_DEFAULT)) == NULL)
|
||||
return (no_memory(hdl));
|
||||
|
||||
if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
|
||||
NULL, UU_DEFAULT)) == NULL)
|
||||
return (no_memory(hdl));
|
||||
}
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
|
||||
return (-1);
|
||||
|
||||
for (;;) {
|
||||
zc.zc_cookie = hdl->libzfs_ns_gen;
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
|
||||
switch (errno) {
|
||||
case EEXIST:
|
||||
/*
|
||||
* The namespace hasn't changed.
|
||||
*/
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (0);
|
||||
|
||||
case ENOMEM:
|
||||
if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (zfs_standard_error(hdl, errno,
|
||||
dgettext(TEXT_DOMAIN, "failed to read "
|
||||
"pool configuration")));
|
||||
}
|
||||
} else {
|
||||
hdl->libzfs_ns_gen = zc.zc_cookie;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
zcmd_free_nvlists(&zc);
|
||||
|
||||
/*
|
||||
* Clear out any existing configuration information.
|
||||
*/
|
||||
cookie = NULL;
|
||||
while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
|
||||
nvlist_free(cn->cn_config);
|
||||
free(cn->cn_name);
|
||||
free(cn);
|
||||
}
|
||||
|
||||
elem = NULL;
|
||||
while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
|
||||
nvlist_t *child;
|
||||
uu_avl_index_t where;
|
||||
|
||||
if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
|
||||
nvlist_free(config);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((cn->cn_name = zfs_strdup(hdl,
|
||||
nvpair_name(elem))) == NULL) {
|
||||
free(cn);
|
||||
nvlist_free(config);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
verify(nvpair_value_nvlist(elem, &child) == 0);
|
||||
if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
|
||||
free(cn->cn_name);
|
||||
free(cn);
|
||||
nvlist_free(config);
|
||||
return (no_memory(hdl));
|
||||
}
|
||||
verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
|
||||
== NULL);
|
||||
|
||||
uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
|
||||
}
|
||||
|
||||
nvlist_free(config);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the configuration for the given pool. The configuration is a nvlist
|
||||
* describing the vdevs, as well as the statistics associated with each one.
|
||||
*/
|
||||
nvlist_t *
|
||||
zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
|
||||
{
|
||||
if (oldconfig)
|
||||
*oldconfig = zhp->zpool_old_config;
|
||||
return (zhp->zpool_config);
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh the vdev statistics associated with the given pool. This is used in
|
||||
* iostat to show configuration changes and determine the delta from the last
|
||||
* time the function was called. This function can fail, in case the pool has
|
||||
* been destroyed.
|
||||
*/
|
||||
int
|
||||
zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int error;
|
||||
nvlist_t *config;
|
||||
libzfs_handle_t *hdl = zhp->zpool_hdl;
|
||||
|
||||
*missing = B_FALSE;
|
||||
(void) strcpy(zc.zc_name, zhp->zpool_name);
|
||||
|
||||
if (zhp->zpool_config_size == 0)
|
||||
zhp->zpool_config_size = 1 << 16;
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
|
||||
return (-1);
|
||||
|
||||
for (;;) {
|
||||
if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
|
||||
&zc) == 0) {
|
||||
/*
|
||||
* The real error is returned in the zc_cookie field.
|
||||
*/
|
||||
error = zc.zc_cookie;
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == ENOMEM) {
|
||||
if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
zcmd_free_nvlists(&zc);
|
||||
if (errno == ENOENT || errno == EINVAL)
|
||||
*missing = B_TRUE;
|
||||
zhp->zpool_state = POOL_STATE_UNAVAIL;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
zcmd_free_nvlists(&zc);
|
||||
|
||||
zhp->zpool_config_size = zc.zc_nvlist_dst_size;
|
||||
|
||||
if (zhp->zpool_config != NULL) {
|
||||
uint64_t oldtxg, newtxg;
|
||||
|
||||
verify(nvlist_lookup_uint64(zhp->zpool_config,
|
||||
ZPOOL_CONFIG_POOL_TXG, &oldtxg) == 0);
|
||||
verify(nvlist_lookup_uint64(config,
|
||||
ZPOOL_CONFIG_POOL_TXG, &newtxg) == 0);
|
||||
|
||||
if (zhp->zpool_old_config != NULL)
|
||||
nvlist_free(zhp->zpool_old_config);
|
||||
|
||||
if (oldtxg != newtxg) {
|
||||
nvlist_free(zhp->zpool_config);
|
||||
zhp->zpool_old_config = NULL;
|
||||
} else {
|
||||
zhp->zpool_old_config = zhp->zpool_config;
|
||||
}
|
||||
}
|
||||
|
||||
zhp->zpool_config = config;
|
||||
if (error)
|
||||
zhp->zpool_state = POOL_STATE_UNAVAIL;
|
||||
else
|
||||
zhp->zpool_state = POOL_STATE_ACTIVE;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all pools in the system.
|
||||
*/
|
||||
int
|
||||
zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
|
||||
{
|
||||
config_node_t *cn;
|
||||
zpool_handle_t *zhp;
|
||||
int ret;
|
||||
|
||||
if (namespace_reload(hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
||||
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
||||
|
||||
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0)
|
||||
return (-1);
|
||||
|
||||
if (zhp == NULL)
|
||||
continue;
|
||||
|
||||
if ((ret = func(zhp, data)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over root datasets, calling the given function for each. The zfs
|
||||
* handle passed each time must be explicitly closed by the callback.
|
||||
*/
|
||||
int
|
||||
zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
|
||||
{
|
||||
config_node_t *cn;
|
||||
zfs_handle_t *zhp;
|
||||
int ret;
|
||||
|
||||
if (namespace_reload(hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
||||
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
||||
|
||||
if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
|
||||
continue;
|
||||
|
||||
if ((ret = func(zhp, data)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,646 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* Iterate over all children of the current object. This includes the normal
|
||||
* dataset hierarchy, but also arbitrary hierarchies due to clones. We want to
|
||||
* walk all datasets in the pool, and construct a directed graph of the form:
|
||||
*
|
||||
* home
|
||||
* |
|
||||
* +----+----+
|
||||
* | |
|
||||
* v v ws
|
||||
* bar baz |
|
||||
* | |
|
||||
* v v
|
||||
* @yesterday ----> foo
|
||||
*
|
||||
* In order to construct this graph, we have to walk every dataset in the pool,
|
||||
* because the clone parent is stored as a property of the child, not the
|
||||
* parent. The parent only keeps track of the number of clones.
|
||||
*
|
||||
* In the normal case (without clones) this would be rather expensive. To avoid
|
||||
* unnecessary computation, we first try a walk of the subtree hierarchy
|
||||
* starting from the initial node. At each dataset, we construct a node in the
|
||||
* graph and an edge leading from its parent. If we don't see any snapshots
|
||||
* with a non-zero clone count, then we are finished.
|
||||
*
|
||||
* If we do find a cloned snapshot, then we finish the walk of the current
|
||||
* subtree, but indicate that we need to do a complete walk. We then perform a
|
||||
* global walk of all datasets, avoiding the subtree we already processed.
|
||||
*
|
||||
* At the end of this, we'll end up with a directed graph of all relevant (and
|
||||
* possible some irrelevant) datasets in the system. We need to both find our
|
||||
* limiting subgraph and determine a safe ordering in which to destroy the
|
||||
* datasets. We do a topological ordering of our graph starting at our target
|
||||
* dataset, and then walk the results in reverse.
|
||||
*
|
||||
* It's possible for the graph to have cycles if, for example, the user renames
|
||||
* a clone to be the parent of its origin snapshot. The user can request to
|
||||
* generate an error in this case, or ignore the cycle and continue.
|
||||
*
|
||||
* When removing datasets, we want to destroy the snapshots in chronological
|
||||
* order (because this is the most efficient method). In order to accomplish
|
||||
* this, we store the creation transaction group with each vertex and keep each
|
||||
* vertex's edges sorted according to this value. The topological sort will
|
||||
* automatically walk the snapshots in the correct order.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
#include "zfs_namecheck.h"
|
||||
|
||||
#define MIN_EDGECOUNT 4
|
||||
|
||||
/*
|
||||
* Vertex structure. Indexed by dataset name, this structure maintains a list
|
||||
* of edges to other vertices.
|
||||
*/
|
||||
struct zfs_edge;
|
||||
typedef struct zfs_vertex {
|
||||
char zv_dataset[ZFS_MAXNAMELEN];
|
||||
struct zfs_vertex *zv_next;
|
||||
int zv_visited;
|
||||
uint64_t zv_txg;
|
||||
struct zfs_edge **zv_edges;
|
||||
int zv_edgecount;
|
||||
int zv_edgealloc;
|
||||
} zfs_vertex_t;
|
||||
|
||||
enum {
|
||||
VISIT_SEEN = 1,
|
||||
VISIT_SORT_PRE,
|
||||
VISIT_SORT_POST
|
||||
};
|
||||
|
||||
/*
|
||||
* Edge structure. Simply maintains a pointer to the destination vertex. There
|
||||
* is no need to store the source vertex, since we only use edges in the context
|
||||
* of the source vertex.
|
||||
*/
|
||||
typedef struct zfs_edge {
|
||||
zfs_vertex_t *ze_dest;
|
||||
struct zfs_edge *ze_next;
|
||||
} zfs_edge_t;
|
||||
|
||||
#define ZFS_GRAPH_SIZE 1027 /* this could be dynamic some day */
|
||||
|
||||
/*
|
||||
* Graph structure. Vertices are maintained in a hash indexed by dataset name.
|
||||
*/
|
||||
typedef struct zfs_graph {
|
||||
zfs_vertex_t **zg_hash;
|
||||
size_t zg_size;
|
||||
size_t zg_nvertex;
|
||||
} zfs_graph_t;
|
||||
|
||||
/*
|
||||
* Allocate a new edge pointing to the target vertex.
|
||||
*/
|
||||
static zfs_edge_t *
|
||||
zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
|
||||
{
|
||||
zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
|
||||
|
||||
if (zep == NULL)
|
||||
return (NULL);
|
||||
|
||||
zep->ze_dest = dest;
|
||||
|
||||
return (zep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an edge.
|
||||
*/
|
||||
static void
|
||||
zfs_edge_destroy(zfs_edge_t *zep)
|
||||
{
|
||||
free(zep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new vertex with the given name.
|
||||
*/
|
||||
static zfs_vertex_t *
|
||||
zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
|
||||
{
|
||||
zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
|
||||
|
||||
if (zvp == NULL)
|
||||
return (NULL);
|
||||
|
||||
assert(strlen(dataset) < ZFS_MAXNAMELEN);
|
||||
|
||||
(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
|
||||
|
||||
if ((zvp->zv_edges = zfs_alloc(hdl,
|
||||
MIN_EDGECOUNT * sizeof (void *))) == NULL) {
|
||||
free(zvp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
zvp->zv_edgealloc = MIN_EDGECOUNT;
|
||||
|
||||
return (zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a vertex. Frees up any associated edges.
|
||||
*/
|
||||
static void
|
||||
zfs_vertex_destroy(zfs_vertex_t *zvp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < zvp->zv_edgecount; i++)
|
||||
zfs_edge_destroy(zvp->zv_edges[i]);
|
||||
|
||||
free(zvp->zv_edges);
|
||||
free(zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a vertex, add an edge to the destination vertex.
|
||||
*/
|
||||
static int
|
||||
zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
|
||||
zfs_vertex_t *dest)
|
||||
{
|
||||
zfs_edge_t *zep = zfs_edge_create(hdl, dest);
|
||||
|
||||
if (zep == NULL)
|
||||
return (-1);
|
||||
|
||||
if (zvp->zv_edgecount == zvp->zv_edgealloc) {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
|
||||
zvp->zv_edgealloc * sizeof (void *),
|
||||
zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
|
||||
return (-1);
|
||||
|
||||
zvp->zv_edges = ptr;
|
||||
zvp->zv_edgealloc *= 2;
|
||||
}
|
||||
|
||||
zvp->zv_edges[zvp->zv_edgecount++] = zep;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_edge_compare(const void *a, const void *b)
|
||||
{
|
||||
const zfs_edge_t *ea = *((zfs_edge_t **)a);
|
||||
const zfs_edge_t *eb = *((zfs_edge_t **)b);
|
||||
|
||||
if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
|
||||
return (-1);
|
||||
if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the given vertex edges according to the creation txg of each vertex.
|
||||
*/
|
||||
static void
|
||||
zfs_vertex_sort_edges(zfs_vertex_t *zvp)
|
||||
{
|
||||
if (zvp->zv_edgecount == 0)
|
||||
return;
|
||||
|
||||
qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
|
||||
zfs_edge_compare);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a new graph object. We allow the size to be specified as a
|
||||
* parameter so in the future we can size the hash according to the number of
|
||||
* datasets in the pool.
|
||||
*/
|
||||
static zfs_graph_t *
|
||||
zfs_graph_create(libzfs_handle_t *hdl, size_t size)
|
||||
{
|
||||
zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
|
||||
|
||||
if (zgp == NULL)
|
||||
return (NULL);
|
||||
|
||||
zgp->zg_size = size;
|
||||
if ((zgp->zg_hash = zfs_alloc(hdl,
|
||||
size * sizeof (zfs_vertex_t *))) == NULL) {
|
||||
free(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a graph object. We have to iterate over all the hash chains,
|
||||
* destroying each vertex in the process.
|
||||
*/
|
||||
static void
|
||||
zfs_graph_destroy(zfs_graph_t *zgp)
|
||||
{
|
||||
int i;
|
||||
zfs_vertex_t *current, *next;
|
||||
|
||||
for (i = 0; i < zgp->zg_size; i++) {
|
||||
current = zgp->zg_hash[i];
|
||||
while (current != NULL) {
|
||||
next = current->zv_next;
|
||||
zfs_vertex_destroy(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
free(zgp->zg_hash);
|
||||
free(zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Graph hash function. Classic bernstein k=33 hash function, taken from
|
||||
* usr/src/cmd/sgs/tools/common/strhash.c
|
||||
*/
|
||||
static size_t
|
||||
zfs_graph_hash(zfs_graph_t *zgp, const char *str)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++) != 0)
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return (hash % zgp->zg_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a dataset name, finds the associated vertex, creating it if necessary.
|
||||
*/
|
||||
static zfs_vertex_t *
|
||||
zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
|
||||
uint64_t txg)
|
||||
{
|
||||
size_t idx = zfs_graph_hash(zgp, dataset);
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
|
||||
if (strcmp(zvp->zv_dataset, dataset) == 0) {
|
||||
if (zvp->zv_txg == 0)
|
||||
zvp->zv_txg = txg;
|
||||
return (zvp);
|
||||
}
|
||||
}
|
||||
|
||||
if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
zvp->zv_next = zgp->zg_hash[idx];
|
||||
zvp->zv_txg = txg;
|
||||
zgp->zg_hash[idx] = zvp;
|
||||
zgp->zg_nvertex++;
|
||||
|
||||
return (zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given two dataset names, create an edge between them. For the source vertex,
|
||||
* mark 'zv_visited' to indicate that we have seen this vertex, and not simply
|
||||
* created it as a destination of another edge. If 'dest' is NULL, then this
|
||||
* is an individual vertex (i.e. the starting vertex), so don't add an edge.
|
||||
*/
|
||||
static int
|
||||
zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
|
||||
const char *dest, uint64_t txg)
|
||||
{
|
||||
zfs_vertex_t *svp, *dvp;
|
||||
|
||||
if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
|
||||
return (-1);
|
||||
svp->zv_visited = VISIT_SEEN;
|
||||
if (dest != NULL) {
|
||||
dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
|
||||
if (dvp == NULL)
|
||||
return (-1);
|
||||
if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all children of the given dataset, adding any vertices as
|
||||
* necessary. Returns 0 if no cloned snapshots were seen, -1 if there was an
|
||||
* error, or 1 otherwise. This is a simple recursive algorithm - the ZFS
|
||||
* namespace typically is very flat. We manually invoke the necessary ioctl()
|
||||
* calls to avoid the overhead and additional semantics of zfs_open().
|
||||
*/
|
||||
static int
|
||||
iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret = 0, err;
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
/*
|
||||
* Look up the source vertex, and avoid it if we've seen it before.
|
||||
*/
|
||||
zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
|
||||
if (zvp == NULL)
|
||||
return (-1);
|
||||
if (zvp->zv_visited == VISIT_SEEN)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* We check the clone parent here instead of within the loop, so that if
|
||||
* the root dataset has been promoted from a clone, we find its parent
|
||||
* appropriately.
|
||||
*/
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0 &&
|
||||
zc.zc_objset_stats.dds_clone_of[0] != '\0') {
|
||||
if (zfs_graph_add(hdl, zgp, zc.zc_objset_stats.dds_clone_of,
|
||||
zc.zc_name, zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
|
||||
|
||||
/*
|
||||
* Ignore private dataset names.
|
||||
*/
|
||||
if (dataset_name_hidden(zc.zc_name))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Get statistics for this dataset, to determine the type of the
|
||||
* dataset and clone statistics. If this fails, the dataset has
|
||||
* since been removed, and we're pretty much screwed anyway.
|
||||
*/
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add an edge between the parent and the child.
|
||||
*/
|
||||
if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Iterate over all children
|
||||
*/
|
||||
err = iterate_children(hdl, zgp, zc.zc_name);
|
||||
if (err == -1)
|
||||
return (-1);
|
||||
else if (err == 1)
|
||||
ret = 1;
|
||||
|
||||
/*
|
||||
* Indicate if we found a dataset with a non-zero clone count.
|
||||
*/
|
||||
if (zc.zc_objset_stats.dds_num_clones != 0)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now iterate over all snapshots.
|
||||
*/
|
||||
bzero(&zc, sizeof (zc));
|
||||
|
||||
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
|
||||
|
||||
/*
|
||||
* Get statistics for this dataset, to determine the type of the
|
||||
* dataset and clone statistics. If this fails, the dataset has
|
||||
* since been removed, and we're pretty much screwed anyway.
|
||||
*/
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add an edge between the parent and the child.
|
||||
*/
|
||||
if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Indicate if we found a dataset with a non-zero clone count.
|
||||
*/
|
||||
if (zc.zc_objset_stats.dds_num_clones != 0)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
zvp->zv_visited = VISIT_SEEN;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a complete graph of all necessary vertices. First, we iterate over
|
||||
* only our object's children. If we don't find any cloned snapshots, then we
|
||||
* simple return that. Otherwise, we have to start at the pool root and iterate
|
||||
* over all datasets.
|
||||
*/
|
||||
static zfs_graph_t *
|
||||
construct_graph(libzfs_handle_t *hdl, const char *dataset)
|
||||
{
|
||||
zfs_graph_t *zgp = zfs_graph_create(hdl, ZFS_GRAPH_SIZE);
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret = 0;
|
||||
|
||||
if (zgp == NULL)
|
||||
return (zgp);
|
||||
|
||||
/*
|
||||
* We need to explicitly check whether this dataset has clones or not,
|
||||
* since iterate_children() only checks the children.
|
||||
*/
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
(void) ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc);
|
||||
|
||||
if (zc.zc_objset_stats.dds_num_clones != 0 ||
|
||||
(ret = iterate_children(hdl, zgp, dataset)) != 0) {
|
||||
/*
|
||||
* Determine pool name and try again.
|
||||
*/
|
||||
char *pool, *slash;
|
||||
|
||||
if ((slash = strchr(dataset, '/')) != NULL ||
|
||||
(slash = strchr(dataset, '@')) != NULL) {
|
||||
pool = zfs_alloc(hdl, slash - dataset + 1);
|
||||
if (pool == NULL) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
(void) strncpy(pool, dataset, slash - dataset);
|
||||
pool[slash - dataset] = '\0';
|
||||
|
||||
if (iterate_children(hdl, zgp, pool) == -1 ||
|
||||
zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
|
||||
free(pool);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
free(pool);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a graph, do a recursive topological sort into the given array. This is
|
||||
* really just a depth first search, so that the deepest nodes appear first.
|
||||
* hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
|
||||
*/
|
||||
static int
|
||||
topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result,
|
||||
size_t *idx, zfs_vertex_t *zgv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) {
|
||||
/*
|
||||
* If we've already seen this vertex as part of our depth-first
|
||||
* search, then we have a cyclic dependency, and we must return
|
||||
* an error.
|
||||
*/
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"recursive dependency at '%s'"),
|
||||
zgv->zv_dataset);
|
||||
return (zfs_error(hdl, EZFS_RECURSIVE,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot determine dependent datasets")));
|
||||
} else if (zgv->zv_visited >= VISIT_SORT_PRE) {
|
||||
/*
|
||||
* If we've already processed this as part of the topological
|
||||
* sort, then don't bother doing so again.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
zgv->zv_visited = VISIT_SORT_PRE;
|
||||
|
||||
/* avoid doing a search if we don't have to */
|
||||
zfs_vertex_sort_edges(zgv);
|
||||
for (i = 0; i < zgv->zv_edgecount; i++) {
|
||||
if (topo_sort(hdl, allowrecursion, result, idx,
|
||||
zgv->zv_edges[i]->ze_dest) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* we may have visited this in the course of the above */
|
||||
if (zgv->zv_visited == VISIT_SORT_POST)
|
||||
return (0);
|
||||
|
||||
if ((result[*idx] = zfs_alloc(hdl,
|
||||
strlen(zgv->zv_dataset) + 1)) == NULL)
|
||||
return (-1);
|
||||
|
||||
(void) strcpy(result[*idx], zgv->zv_dataset);
|
||||
*idx += 1;
|
||||
zgv->zv_visited = VISIT_SORT_POST;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The only public interface for this file. Do the dirty work of constructing a
|
||||
* child list for the given object. Construct the graph, do the toplogical
|
||||
* sort, and then return the array of strings to the caller.
|
||||
*
|
||||
* The 'allowrecursion' parameter controls behavior when cycles are found. If
|
||||
* it is set, the the cycle is ignored and the results returned as if the cycle
|
||||
* did not exist. If it is not set, then the routine will generate an error if
|
||||
* a cycle is found.
|
||||
*/
|
||||
int
|
||||
get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion,
|
||||
const char *dataset, char ***result, size_t *count)
|
||||
{
|
||||
zfs_graph_t *zgp;
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
if ((zgp = construct_graph(hdl, dataset)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if ((*result = zfs_alloc(hdl,
|
||||
zgp->zg_nvertex * sizeof (char *))) == NULL) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
|
||||
free(*result);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) {
|
||||
free(*result);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get rid of the last entry, which is our starting vertex and not
|
||||
* strictly a dependent.
|
||||
*/
|
||||
assert(*count > 0);
|
||||
free((*result)[*count - 1]);
|
||||
(*count)--;
|
||||
|
||||
zfs_graph_destroy(zgp);
|
||||
|
||||
return (0);
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBFS_IMPL_H
|
||||
#define _LIBFS_IMPL_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <sys/zfs_acl.h>
|
||||
#include <sys/nvpair.h>
|
||||
|
||||
#include <libuutil.h>
|
||||
#include <libzfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct libzfs_handle {
|
||||
int libzfs_error;
|
||||
int libzfs_fd;
|
||||
FILE *libzfs_mnttab;
|
||||
FILE *libzfs_sharetab;
|
||||
uu_avl_pool_t *libzfs_ns_avlpool;
|
||||
uu_avl_t *libzfs_ns_avl;
|
||||
uint64_t libzfs_ns_gen;
|
||||
int libzfs_desc_active;
|
||||
char libzfs_action[1024];
|
||||
char libzfs_desc[1024];
|
||||
int libzfs_printerr;
|
||||
};
|
||||
|
||||
struct zfs_handle {
|
||||
libzfs_handle_t *zfs_hdl;
|
||||
char zfs_name[ZFS_MAXNAMELEN];
|
||||
zfs_type_t zfs_type; /* type including snapshot */
|
||||
zfs_type_t zfs_head_type; /* type excluding snapshot */
|
||||
dmu_objset_stats_t zfs_dmustats;
|
||||
nvlist_t *zfs_props;
|
||||
nvlist_t *zfs_user_props;
|
||||
boolean_t zfs_mntcheck;
|
||||
char *zfs_mntopts;
|
||||
char zfs_root[MAXPATHLEN];
|
||||
};
|
||||
|
||||
/*
|
||||
* This is different from checking zfs_type, because it will also catch
|
||||
* snapshots of volumes.
|
||||
*/
|
||||
#define ZFS_IS_VOLUME(zhp) ((zhp)->zfs_head_type == ZFS_TYPE_VOLUME)
|
||||
|
||||
struct zpool_handle {
|
||||
libzfs_handle_t *zpool_hdl;
|
||||
char zpool_name[ZPOOL_MAXNAMELEN];
|
||||
int zpool_state;
|
||||
size_t zpool_config_size;
|
||||
nvlist_t *zpool_config;
|
||||
nvlist_t *zpool_old_config;
|
||||
nvlist_t *zpool_props;
|
||||
};
|
||||
|
||||
int zfs_error(libzfs_handle_t *, int, const char *);
|
||||
int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
|
||||
void zfs_error_aux(libzfs_handle_t *, const char *, ...);
|
||||
void *zfs_alloc(libzfs_handle_t *, size_t);
|
||||
void *zfs_realloc(libzfs_handle_t *, void *, size_t, size_t);
|
||||
char *zfs_strdup(libzfs_handle_t *, const char *);
|
||||
int no_memory(libzfs_handle_t *);
|
||||
|
||||
int zfs_standard_error(libzfs_handle_t *, int, const char *);
|
||||
int zfs_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
|
||||
int zpool_standard_error(libzfs_handle_t *, int, const char *);
|
||||
int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
|
||||
|
||||
int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
|
||||
size_t *);
|
||||
|
||||
int zfs_expand_proplist_common(libzfs_handle_t *, zfs_proplist_t **,
|
||||
zfs_type_t);
|
||||
int zfs_get_proplist_common(libzfs_handle_t *, char *, zfs_proplist_t **,
|
||||
zfs_type_t);
|
||||
zfs_prop_t zfs_prop_iter_common(zfs_prop_f, void *, zfs_type_t, boolean_t);
|
||||
zfs_prop_t zfs_name_to_prop_common(const char *, zfs_type_t);
|
||||
|
||||
nvlist_t *zfs_validate_properties(libzfs_handle_t *, zfs_type_t, char *,
|
||||
nvlist_t *, uint64_t, zfs_handle_t *zhp, const char *errbuf);
|
||||
|
||||
typedef struct prop_changelist prop_changelist_t;
|
||||
|
||||
int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
|
||||
int zcmd_write_src_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *, size_t *);
|
||||
int zcmd_expand_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *);
|
||||
int zcmd_read_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t **);
|
||||
void zcmd_free_nvlists(zfs_cmd_t *);
|
||||
|
||||
int changelist_prefix(prop_changelist_t *);
|
||||
int changelist_postfix(prop_changelist_t *);
|
||||
void changelist_rename(prop_changelist_t *, const char *, const char *);
|
||||
void changelist_remove(zfs_handle_t *, prop_changelist_t *);
|
||||
void changelist_free(prop_changelist_t *);
|
||||
prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int);
|
||||
int changelist_unshare(prop_changelist_t *);
|
||||
int changelist_haszonedchild(prop_changelist_t *);
|
||||
|
||||
void remove_mountpoint(zfs_handle_t *);
|
||||
|
||||
zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
|
||||
|
||||
int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
|
||||
|
||||
int zvol_create_link(libzfs_handle_t *, const char *);
|
||||
int zvol_remove_link(libzfs_handle_t *, const char *);
|
||||
int zpool_iter_zvol(zpool_handle_t *, int (*)(const char *, void *), void *);
|
||||
|
||||
void namespace_clear(libzfs_handle_t *);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
|
||||
* zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
|
||||
* error is returned zc_nvlist_dst_size won't be updated.
|
||||
*/
|
||||
static __inline int
|
||||
zcmd_ioctl(int fd, unsigned long cmd, zfs_cmd_t *zc)
|
||||
{
|
||||
size_t oldsize;
|
||||
int ret;
|
||||
|
||||
oldsize = zc->zc_nvlist_dst_size;
|
||||
ret = ioctl(fd, cmd, zc);
|
||||
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
|
||||
ret = -1;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#define ioctl(fd, cmd, zc) zcmd_ioctl((fd), (cmd), (zc))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBFS_IMPL_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,986 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* Routines to manage ZFS mounts. We separate all the nasty routines that have
|
||||
* to deal with the OS. The following functions are the main entry points --
|
||||
* they are used by mount and unmount and when changing a filesystem's
|
||||
* mountpoint.
|
||||
*
|
||||
* zfs_is_mounted()
|
||||
* zfs_mount()
|
||||
* zfs_unmount()
|
||||
* zfs_unmountall()
|
||||
*
|
||||
* This file also contains the functions used to manage sharing filesystems via
|
||||
* NFS and iSCSI:
|
||||
*
|
||||
* zfs_is_shared()
|
||||
* zfs_share()
|
||||
* zfs_unshare()
|
||||
*
|
||||
* zfs_is_shared_nfs()
|
||||
* zfs_share_nfs()
|
||||
* zfs_unshare_nfs()
|
||||
* zfs_unshareall_nfs()
|
||||
* zfs_is_shared_iscsi()
|
||||
* zfs_share_iscsi()
|
||||
* zfs_unshare_iscsi()
|
||||
*
|
||||
* The following functions are available for pool consumers, and will
|
||||
* mount/unmount and share/unshare all datasets within pool:
|
||||
*
|
||||
* zpool_enable_datasets()
|
||||
* zpool_disable_datasets()
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <zone.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
static int (*iscsitgt_zfs_share)(const char *);
|
||||
static int (*iscsitgt_zfs_unshare)(const char *);
|
||||
static int (*iscsitgt_zfs_is_shared)(const char *);
|
||||
|
||||
#pragma init(zfs_iscsi_init)
|
||||
static void
|
||||
zfs_iscsi_init(void)
|
||||
{
|
||||
void *libiscsitgt;
|
||||
|
||||
if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1",
|
||||
RTLD_LAZY | RTLD_GLOBAL)) == NULL ||
|
||||
(iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_share")) == NULL ||
|
||||
(iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_unshare")) == NULL ||
|
||||
(iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt,
|
||||
"iscsitgt_zfs_is_shared")) == NULL) {
|
||||
iscsitgt_zfs_share = NULL;
|
||||
iscsitgt_zfs_unshare = NULL;
|
||||
iscsitgt_zfs_is_shared = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the sharetab for the given mountpoint, returning true if it is found.
|
||||
*/
|
||||
static boolean_t
|
||||
is_shared(libzfs_handle_t *hdl, const char *mountpoint)
|
||||
{
|
||||
char buf[MAXPATHLEN], *tab;
|
||||
|
||||
if (hdl->libzfs_sharetab == NULL)
|
||||
return (0);
|
||||
|
||||
(void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
|
||||
|
||||
while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
|
||||
|
||||
/* the mountpoint is the first entry on each line */
|
||||
if ((tab = strchr(buf, '\t')) != NULL) {
|
||||
*tab = '\0';
|
||||
if (strcmp(buf, mountpoint) == 0)
|
||||
return (B_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Returns true if the specified directory is empty. If we can't open the
|
||||
* directory at all, return true so that the mount can fail with a more
|
||||
* informative error message.
|
||||
*/
|
||||
static boolean_t
|
||||
dir_is_empty(const char *dirname)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent64 *dp;
|
||||
|
||||
if ((dirp = opendir(dirname)) == NULL)
|
||||
return (B_TRUE);
|
||||
|
||||
while ((dp = readdir64(dirp)) != NULL) {
|
||||
|
||||
if (strcmp(dp->d_name, ".") == 0 ||
|
||||
strcmp(dp->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
(void) closedir(dirp);
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
(void) closedir(dirp);
|
||||
return (B_TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Checks to see if the mount is active. If the filesystem is mounted, we fill
|
||||
* in 'where' with the current mountpoint, and return 1. Otherwise, we return
|
||||
* 0.
|
||||
*/
|
||||
boolean_t
|
||||
is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
|
||||
{
|
||||
struct mnttab search = { 0 }, entry;
|
||||
|
||||
/*
|
||||
* Search for the entry in /etc/mnttab. We don't bother getting the
|
||||
* mountpoint, as we can just search for the special device. This will
|
||||
* also let us find mounts when the mountpoint is 'legacy'.
|
||||
*/
|
||||
search.mnt_special = (char *)special;
|
||||
search.mnt_fstype = MNTTYPE_ZFS;
|
||||
|
||||
rewind(zfs_hdl->libzfs_mnttab);
|
||||
if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (where != NULL)
|
||||
*where = zfs_strdup(zfs_hdl, entry.mnt_mountp);
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_is_mounted(zfs_handle_t *zhp, char **where)
|
||||
{
|
||||
return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the given dataset is mountable, false otherwise. Returns the
|
||||
* mountpoint in 'buf'.
|
||||
*/
|
||||
static boolean_t
|
||||
zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
|
||||
zfs_source_t *source)
|
||||
{
|
||||
char sourceloc[ZFS_MAXNAMELEN];
|
||||
zfs_source_t sourcetype;
|
||||
|
||||
if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
|
||||
return (B_FALSE);
|
||||
|
||||
verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
|
||||
&sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
|
||||
|
||||
if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
|
||||
strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT))
|
||||
return (B_FALSE);
|
||||
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
|
||||
getzoneid() == GLOBAL_ZONEID)
|
||||
return (B_FALSE);
|
||||
|
||||
if (source)
|
||||
*source = sourcetype;
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount the given filesystem.
|
||||
*/
|
||||
int
|
||||
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
|
||||
{
|
||||
struct stat buf;
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
char mntopts[MNT_LINE_MAX];
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
if (options == NULL)
|
||||
mntopts[0] = '\0';
|
||||
else
|
||||
(void) strlcpy(mntopts, options, sizeof (mntopts));
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
|
||||
return (0);
|
||||
|
||||
/* Create the directory if it doesn't already exist */
|
||||
if (lstat(mountpoint, &buf) != 0) {
|
||||
if (mkdirp(mountpoint, 0755) != 0) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"failed to create mountpoint"));
|
||||
return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
|
||||
mountpoint));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* FreeBSD: overlay mounts are not checked. */
|
||||
/*
|
||||
* Determine if the mountpoint is empty. If so, refuse to perform the
|
||||
* mount. We don't perform this check if MS_OVERLAY is specified, which
|
||||
* would defeat the point. We also avoid this check if 'remount' is
|
||||
* specified.
|
||||
*/
|
||||
if ((flags & MS_OVERLAY) == 0 &&
|
||||
strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
|
||||
!dir_is_empty(mountpoint)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"directory is not empty"));
|
||||
return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* perform the mount */
|
||||
if (zmount(zfs_get_name(zhp), mountpoint, flags,
|
||||
MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
|
||||
/*
|
||||
* Generic errors are nasty, but there are just way too many
|
||||
* from mount(), and they're well-understood. We pick a few
|
||||
* common ones to improve upon.
|
||||
*/
|
||||
if (errno == EBUSY)
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"mountpoint or dataset is busy"));
|
||||
else
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
|
||||
return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
|
||||
zhp->zfs_name));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount a single filesystem.
|
||||
*/
|
||||
static int
|
||||
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
|
||||
{
|
||||
if (unmount(mountpoint, flags) != 0) {
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
|
||||
mountpoint));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount the given filesystem.
|
||||
*/
|
||||
int
|
||||
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
|
||||
{
|
||||
struct mnttab search = { 0 }, entry;
|
||||
|
||||
/* check to see if need to unmount the filesystem */
|
||||
search.mnt_special = zhp->zfs_name;
|
||||
search.mnt_fstype = MNTTYPE_ZFS;
|
||||
rewind(zhp->zfs_hdl->libzfs_mnttab);
|
||||
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
|
||||
getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
|
||||
|
||||
if (mountpoint == NULL)
|
||||
mountpoint = entry.mnt_mountp;
|
||||
|
||||
/*
|
||||
* Unshare and unmount the filesystem
|
||||
*/
|
||||
if (zfs_unshare_nfs(zhp, mountpoint) != 0 ||
|
||||
unmount_one(zhp->zfs_hdl, mountpoint, flags) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount this filesystem and any children inheriting the mountpoint property.
|
||||
* To do this, just act like we're changing the mountpoint property, but don't
|
||||
* remount the filesystems afterwards.
|
||||
*/
|
||||
int
|
||||
zfs_unmountall(zfs_handle_t *zhp, int flags)
|
||||
{
|
||||
prop_changelist_t *clp;
|
||||
int ret;
|
||||
|
||||
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
|
||||
if (clp == NULL)
|
||||
return (-1);
|
||||
|
||||
ret = changelist_prefix(clp);
|
||||
changelist_free(clp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_is_shared(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_is_shared_iscsi(zhp));
|
||||
|
||||
return (zfs_is_shared_nfs(zhp, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
zfs_share(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_share_iscsi(zhp));
|
||||
|
||||
return (zfs_share_nfs(zhp));
|
||||
}
|
||||
|
||||
int
|
||||
zfs_unshare(zfs_handle_t *zhp)
|
||||
{
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
return (zfs_unshare_iscsi(zhp));
|
||||
|
||||
return (zfs_unshare_nfs(zhp, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the filesystem is currently shared.
|
||||
*/
|
||||
boolean_t
|
||||
zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
|
||||
{
|
||||
char *mountpoint;
|
||||
|
||||
if (!zfs_is_mounted(zhp, &mountpoint))
|
||||
return (B_FALSE);
|
||||
|
||||
if (is_shared(zhp->zfs_hdl, mountpoint)) {
|
||||
if (where != NULL)
|
||||
*where = mountpoint;
|
||||
else
|
||||
free(mountpoint);
|
||||
return (B_TRUE);
|
||||
} else {
|
||||
free(mountpoint);
|
||||
return (B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Share the given filesystem according to the options in 'sharenfs'. We rely
|
||||
* on share(1M) to the dirty work for us.
|
||||
*/
|
||||
int
|
||||
zfs_share_nfs(zfs_handle_t *zhp)
|
||||
{
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
char shareopts[ZFS_MAXPROPLEN];
|
||||
char buf[MAXPATHLEN];
|
||||
FILE *fp;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Return success if there are no share options.
|
||||
*/
|
||||
if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
|
||||
NULL, NULL, 0, B_FALSE) != 0 ||
|
||||
strcmp(shareopts, "off") == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If the 'zoned' property is set, then zfs_is_mountable() will have
|
||||
* already bailed out if we are in the global zone. But local
|
||||
* zones cannot be NFS servers, so we ignore it for local zones as well.
|
||||
*/
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
|
||||
return (0);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
{
|
||||
int error;
|
||||
|
||||
if (strcmp(shareopts, "on") == 0)
|
||||
error = fsshare(ZFS_EXPORTS_PATH, mountpoint, "");
|
||||
else
|
||||
error = fsshare(ZFS_EXPORTS_PATH, mountpoint, shareopts);
|
||||
if (error != 0) {
|
||||
zfs_error_aux(hdl, "%s", strerror(error));
|
||||
(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
|
||||
zfs_get_name(zhp));
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Invoke the share(1M) command. We always do this, even if it's
|
||||
* currently shared, as the options may have changed.
|
||||
*/
|
||||
if (strcmp(shareopts, "on") == 0)
|
||||
(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
|
||||
"-F nfs \"%s\" 2>&1", mountpoint);
|
||||
else
|
||||
(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
|
||||
"-F nfs -o \"%s\" \"%s\" 2>&1", shareopts,
|
||||
mountpoint);
|
||||
|
||||
if ((fp = popen(buf, "r")) == NULL)
|
||||
return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
|
||||
zfs_get_name(zhp)));
|
||||
|
||||
/*
|
||||
* share(1M) should only produce output if there is some kind
|
||||
* of error. All output begins with "share_nfs: ", so we trim
|
||||
* this off to get to the real error.
|
||||
*/
|
||||
if (fgets(buf, sizeof (buf), fp) != NULL) {
|
||||
char *colon = strchr(buf, ':');
|
||||
|
||||
while (buf[strlen(buf) - 1] == '\n')
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
if (colon != NULL)
|
||||
zfs_error_aux(hdl, colon + 2);
|
||||
|
||||
(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
|
||||
zfs_get_name(zhp));
|
||||
|
||||
verify(pclose(fp) != 0);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
verify(pclose(fp) == 0);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unshare a filesystem by mountpoint.
|
||||
*/
|
||||
static int
|
||||
unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
|
||||
{
|
||||
char buf[MAXPATHLEN];
|
||||
FILE *fp;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
{
|
||||
int error;
|
||||
|
||||
error = fsunshare(ZFS_EXPORTS_PATH, mountpoint);
|
||||
if (error != 0) {
|
||||
zfs_error_aux(hdl, "%s", strerror(error));
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot unshare '%s'"), name));
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) snprintf(buf, sizeof (buf),
|
||||
"/usr/sbin/unshare \"%s\" 2>&1",
|
||||
mountpoint);
|
||||
|
||||
if ((fp = popen(buf, "r")) == NULL)
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot unshare '%s'"), name));
|
||||
|
||||
/*
|
||||
* unshare(1M) should only produce output if there is
|
||||
* some kind of error. All output begins with "unshare
|
||||
* nfs: ", so we trim this off to get to the real error.
|
||||
*/
|
||||
if (fgets(buf, sizeof (buf), fp) != NULL) {
|
||||
char *colon = strchr(buf, ':');
|
||||
|
||||
while (buf[strlen(buf) - 1] == '\n')
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
if (colon != NULL)
|
||||
zfs_error_aux(hdl, colon + 2);
|
||||
|
||||
verify(pclose(fp) != 0);
|
||||
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot unshare '%s'"), name));
|
||||
}
|
||||
|
||||
verify(pclose(fp) == 0);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unshare the given filesystem.
|
||||
*/
|
||||
int
|
||||
zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
|
||||
{
|
||||
struct mnttab search = { 0 }, entry;
|
||||
|
||||
/* check to see if need to unmount the filesystem */
|
||||
search.mnt_special = (char *)zfs_get_name(zhp);
|
||||
search.mnt_fstype = MNTTYPE_ZFS;
|
||||
rewind(zhp->zfs_hdl->libzfs_mnttab);
|
||||
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
|
||||
getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
|
||||
|
||||
if (mountpoint == NULL)
|
||||
mountpoint = entry.mnt_mountp;
|
||||
|
||||
if (is_shared(zhp->zfs_hdl, mountpoint) &&
|
||||
unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as zfs_unmountall(), but for NFS unshares.
|
||||
*/
|
||||
int
|
||||
zfs_unshareall_nfs(zfs_handle_t *zhp)
|
||||
{
|
||||
prop_changelist_t *clp;
|
||||
int ret;
|
||||
|
||||
clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0);
|
||||
if (clp == NULL)
|
||||
return (-1);
|
||||
|
||||
ret = changelist_unshare(clp);
|
||||
changelist_free(clp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the mountpoint associated with the current dataset, if necessary.
|
||||
* We only remove the underlying directory if:
|
||||
*
|
||||
* - The mountpoint is not 'none' or 'legacy'
|
||||
* - The mountpoint is non-empty
|
||||
* - The mountpoint is the default or inherited
|
||||
* - The 'zoned' property is set, or we're in a local zone
|
||||
*
|
||||
* Any other directories we leave alone.
|
||||
*/
|
||||
void
|
||||
remove_mountpoint(zfs_handle_t *zhp)
|
||||
{
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
zfs_source_t source;
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
|
||||
&source))
|
||||
return;
|
||||
|
||||
if (source == ZFS_SRC_DEFAULT ||
|
||||
source == ZFS_SRC_INHERITED) {
|
||||
/*
|
||||
* Try to remove the directory, silently ignoring any errors.
|
||||
* The filesystem may have since been removed or moved around,
|
||||
* and this error isn't really useful to the administrator in
|
||||
* any way.
|
||||
*/
|
||||
(void) rmdir(mountpoint);
|
||||
}
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_is_shared_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
return (iscsitgt_zfs_is_shared != NULL &&
|
||||
iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_share_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
char shareopts[ZFS_MAXPROPLEN];
|
||||
const char *dataset = zhp->zfs_name;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
/*
|
||||
* Return success if there are no share options.
|
||||
*/
|
||||
if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
|
||||
sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 ||
|
||||
strcmp(shareopts, "off") == 0)
|
||||
return (0);
|
||||
|
||||
/* We don't support iSCSI on FreeBSD yet. */
|
||||
#ifdef TODO
|
||||
if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0)
|
||||
return (zfs_error_fmt(hdl, EZFS_SHAREISCSIFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset));
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_unshare_iscsi(zfs_handle_t *zhp)
|
||||
{
|
||||
const char *dataset = zfs_get_name(zhp);
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
/* We don't support iSCSI on FreeBSD yet. */
|
||||
#ifdef TODO
|
||||
/*
|
||||
* Return if the volume is not shared
|
||||
*/
|
||||
if (!zfs_is_shared_iscsi(zhp))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If this fails with ENODEV it indicates that zvol wasn't shared so
|
||||
* we should return success in that case.
|
||||
*/
|
||||
if (iscsitgt_zfs_unshare == NULL ||
|
||||
(iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV))
|
||||
return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED,
|
||||
dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset));
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef struct mount_cbdata {
|
||||
zfs_handle_t **cb_datasets;
|
||||
int cb_used;
|
||||
int cb_alloc;
|
||||
} mount_cbdata_t;
|
||||
|
||||
static int
|
||||
mount_cb(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
mount_cbdata_t *cbp = data;
|
||||
|
||||
if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (cbp->cb_alloc == cbp->cb_used) {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(zhp->zfs_hdl,
|
||||
cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
|
||||
cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
|
||||
return (-1);
|
||||
cbp->cb_datasets = ptr;
|
||||
|
||||
cbp->cb_alloc *= 2;
|
||||
}
|
||||
|
||||
cbp->cb_datasets[cbp->cb_used++] = zhp;
|
||||
|
||||
return (zfs_iter_children(zhp, mount_cb, cbp));
|
||||
}
|
||||
|
||||
static int
|
||||
dataset_cmp(const void *a, const void *b)
|
||||
{
|
||||
zfs_handle_t **za = (zfs_handle_t **)a;
|
||||
zfs_handle_t **zb = (zfs_handle_t **)b;
|
||||
char mounta[MAXPATHLEN];
|
||||
char mountb[MAXPATHLEN];
|
||||
boolean_t gota, gotb;
|
||||
|
||||
if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
|
||||
verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
|
||||
sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
|
||||
if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
|
||||
verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
|
||||
sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
|
||||
|
||||
if (gota && gotb)
|
||||
return (strcmp(mounta, mountb));
|
||||
|
||||
if (gota)
|
||||
return (-1);
|
||||
if (gotb)
|
||||
return (1);
|
||||
|
||||
return (strcmp(zfs_get_name(a), zfs_get_name(b)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount and share all datasets within the given pool. This assumes that no
|
||||
* datasets within the pool are currently mounted. Because users can create
|
||||
* complicated nested hierarchies of mountpoints, we first gather all the
|
||||
* datasets and mountpoints within the pool, and sort them by mountpoint. Once
|
||||
* we have the list of all filesystems, we iterate over them in order and mount
|
||||
* and/or share each one.
|
||||
*/
|
||||
#pragma weak zpool_mount_datasets = zpool_enable_datasets
|
||||
int
|
||||
zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
|
||||
{
|
||||
mount_cbdata_t cb = { 0 };
|
||||
libzfs_handle_t *hdl = zhp->zpool_hdl;
|
||||
zfs_handle_t *zfsp;
|
||||
int i, ret = -1;
|
||||
|
||||
/*
|
||||
* Gather all datasets within the pool.
|
||||
*/
|
||||
if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL)
|
||||
return (-1);
|
||||
cb.cb_alloc = 4;
|
||||
|
||||
if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_ANY)) == NULL)
|
||||
goto out;
|
||||
|
||||
cb.cb_datasets[0] = zfsp;
|
||||
cb.cb_used = 1;
|
||||
|
||||
if (zfs_iter_children(zfsp, mount_cb, &cb) != 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Sort the datasets by mountpoint.
|
||||
*/
|
||||
qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp);
|
||||
|
||||
/*
|
||||
* And mount all the datasets.
|
||||
*/
|
||||
ret = 0;
|
||||
for (i = 0; i < cb.cb_used; i++) {
|
||||
if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0 ||
|
||||
zfs_share(cb.cb_datasets[i]) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
for (i = 0; i < cb.cb_used; i++)
|
||||
zfs_close(cb.cb_datasets[i]);
|
||||
free(cb.cb_datasets);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
zvol_cb(const char *dataset, void *data)
|
||||
{
|
||||
libzfs_handle_t *hdl = data;
|
||||
zfs_handle_t *zhp;
|
||||
|
||||
/*
|
||||
* Ignore snapshots and ignore failures from non-existant datasets.
|
||||
*/
|
||||
if (strchr(dataset, '@') != NULL ||
|
||||
(zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL)
|
||||
return (0);
|
||||
|
||||
(void) zfs_unshare_iscsi(zhp);
|
||||
|
||||
zfs_close(zhp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mountpoint_compare(const void *a, const void *b)
|
||||
{
|
||||
const char *mounta = *((char **)a);
|
||||
const char *mountb = *((char **)b);
|
||||
|
||||
return (strcmp(mountb, mounta));
|
||||
}
|
||||
|
||||
/*
|
||||
* Unshare and unmount all datasets within the given pool. We don't want to
|
||||
* rely on traversing the DSL to discover the filesystems within the pool,
|
||||
* because this may be expensive (if not all of them are mounted), and can fail
|
||||
* arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and
|
||||
* gather all the filesystems that are currently mounted.
|
||||
*/
|
||||
#pragma weak zpool_unmount_datasets = zpool_disable_datasets
|
||||
int
|
||||
zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
|
||||
{
|
||||
int used, alloc;
|
||||
struct statfs *sfs;
|
||||
size_t namelen;
|
||||
char **mountpoints = NULL;
|
||||
zfs_handle_t **datasets = NULL;
|
||||
libzfs_handle_t *hdl = zhp->zpool_hdl;
|
||||
int i, j, n;
|
||||
int ret = -1;
|
||||
int flags = (force ? MS_FORCE : 0);
|
||||
|
||||
/*
|
||||
* First unshare all zvols.
|
||||
*/
|
||||
if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0)
|
||||
return (-1);
|
||||
|
||||
namelen = strlen(zhp->zpool_name);
|
||||
|
||||
used = alloc = 0;
|
||||
if ((n = getmntinfo(&sfs, MNT_WAIT)) == 0) {
|
||||
fprintf(stderr, "getmntinfo(): %s\n", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
for (j = 0; j < n; j++) {
|
||||
/*
|
||||
* Ignore non-ZFS entries.
|
||||
*/
|
||||
if (strcmp(sfs[j].f_fstypename, MNTTYPE_ZFS) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Ignore filesystems not within this pool.
|
||||
*/
|
||||
if (strncmp(sfs[j].f_mntfromname, zhp->zpool_name, namelen) != 0 ||
|
||||
(sfs[j].f_mntfromname[namelen] != '/' &&
|
||||
sfs[j].f_mntfromname[namelen] != '\0'))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* At this point we've found a filesystem within our pool. Add
|
||||
* it to our growing list.
|
||||
*/
|
||||
if (used == alloc) {
|
||||
if (alloc == 0) {
|
||||
if ((mountpoints = zfs_alloc(hdl,
|
||||
8 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
|
||||
if ((datasets = zfs_alloc(hdl,
|
||||
8 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
|
||||
alloc = 8;
|
||||
} else {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(hdl, mountpoints,
|
||||
alloc * sizeof (void *),
|
||||
alloc * 2 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
mountpoints = ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(hdl, datasets,
|
||||
alloc * sizeof (void *),
|
||||
alloc * 2 * sizeof (void *))) == NULL)
|
||||
goto out;
|
||||
datasets = ptr;
|
||||
|
||||
alloc *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mountpoints[used] = zfs_strdup(hdl,
|
||||
sfs[j].f_mntonname)) == NULL)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* This is allowed to fail, in case there is some I/O error. It
|
||||
* is only used to determine if we need to remove the underlying
|
||||
* mountpoint, so failure is not fatal.
|
||||
*/
|
||||
datasets[used] = make_dataset_handle(hdl, sfs[j].f_mntfromname);
|
||||
|
||||
used++;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we have the entire list of filesystems, so sort it by
|
||||
* mountpoint.
|
||||
*/
|
||||
qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
|
||||
|
||||
/*
|
||||
* Walk through and first unshare everything.
|
||||
*/
|
||||
for (i = 0; i < used; i++) {
|
||||
if (is_shared(hdl, mountpoints[i]) &&
|
||||
unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now unmount everything, removing the underlying directories as
|
||||
* appropriate.
|
||||
*/
|
||||
for (i = 0; i < used; i++) {
|
||||
if (unmount_one(hdl, mountpoints[i], flags) != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < used; i++) {
|
||||
if (datasets[i])
|
||||
remove_mountpoint(datasets[i]);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
for (i = 0; i < used; i++) {
|
||||
if (datasets[i])
|
||||
zfs_close(datasets[i]);
|
||||
free(mountpoints[i]);
|
||||
}
|
||||
free(datasets);
|
||||
free(mountpoints);
|
||||
|
||||
return (ret);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,303 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* This file contains the functions which analyze the status of a pool. This
|
||||
* include both the status of an active pool, as well as the status exported
|
||||
* pools. Returns one of the ZPOOL_STATUS_* defines describing the status of
|
||||
* the pool. This status is independent (to a certain degree) from the state of
|
||||
* the pool. A pool's state descsribes only whether or not it is capable of
|
||||
* providing the necessary fault tolerance for data. The status describes the
|
||||
* overall status of devices. A pool that is online can still have a device
|
||||
* that is experiencing errors.
|
||||
*
|
||||
* Only a subset of the possible faults can be detected using 'zpool status',
|
||||
* and not all possible errors correspond to a FMA message ID. The explanation
|
||||
* is left up to the caller, depending on whether it is a live pool or an
|
||||
* import.
|
||||
*/
|
||||
|
||||
#include <libzfs.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
/*
|
||||
* Message ID table. This must be kep in sync with the ZPOOL_STATUS_* defines
|
||||
* in libzfs.h. Note that there are some status results which go past the end
|
||||
* of this table, and hence have no associated message ID.
|
||||
*/
|
||||
static char *zfs_msgid_table[] = {
|
||||
"ZFS-8000-14",
|
||||
"ZFS-8000-2Q",
|
||||
"ZFS-8000-3C",
|
||||
"ZFS-8000-4J",
|
||||
"ZFS-8000-5E",
|
||||
"ZFS-8000-6X",
|
||||
"ZFS-8000-72",
|
||||
"ZFS-8000-8A",
|
||||
"ZFS-8000-9P",
|
||||
"ZFS-8000-A5",
|
||||
"ZFS-8000-EY"
|
||||
};
|
||||
|
||||
/*
|
||||
* If the pool is active, a certain class of static errors is overridden by the
|
||||
* faults as analayzed by FMA. These faults have separate knowledge articles,
|
||||
* and the article referred to by 'zpool status' must match that indicated by
|
||||
* the syslog error message. We override missing data as well as corrupt pool.
|
||||
*/
|
||||
static char *zfs_msgid_table_active[] = {
|
||||
"ZFS-8000-14",
|
||||
"ZFS-8000-D3", /* overridden */
|
||||
"ZFS-8000-D3", /* overridden */
|
||||
"ZFS-8000-4J",
|
||||
"ZFS-8000-5E",
|
||||
"ZFS-8000-6X",
|
||||
"ZFS-8000-CS", /* overridden */
|
||||
"ZFS-8000-8A",
|
||||
"ZFS-8000-9P",
|
||||
"ZFS-8000-CS", /* overridden */
|
||||
};
|
||||
|
||||
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (state == VDEV_STATE_CANT_OPEN &&
|
||||
aux == VDEV_AUX_OPEN_FAILED);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (errs != 0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_broken(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (state == VDEV_STATE_CANT_OPEN);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
|
||||
{
|
||||
return (state == VDEV_STATE_OFFLINE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect if any leaf devices that have seen errors or could not be opened.
|
||||
*/
|
||||
static boolean_t
|
||||
find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
|
||||
{
|
||||
nvlist_t **child;
|
||||
vdev_stat_t *vs;
|
||||
uint_t c, children;
|
||||
char *type;
|
||||
|
||||
/*
|
||||
* Ignore problems within a 'replacing' vdev, since we're presumably in
|
||||
* the process of repairing any such errors, and don't want to call them
|
||||
* out again. We'll pick up the fact that a resilver is happening
|
||||
* later.
|
||||
*/
|
||||
verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
|
||||
if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
|
||||
return (B_FALSE);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
|
||||
&children) == 0) {
|
||||
for (c = 0; c < children; c++)
|
||||
if (find_vdev_problem(child[c], func))
|
||||
return (B_TRUE);
|
||||
} else {
|
||||
verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_STATS,
|
||||
(uint64_t **)&vs, &c) == 0);
|
||||
|
||||
if (func(vs->vs_state, vs->vs_aux,
|
||||
vs->vs_read_errors +
|
||||
vs->vs_write_errors +
|
||||
vs->vs_checksum_errors))
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Active pool health status.
|
||||
*
|
||||
* To determine the status for a pool, we make several passes over the config,
|
||||
* picking the most egregious error we find. In order of importance, we do the
|
||||
* following:
|
||||
*
|
||||
* - Check for a complete and valid configuration
|
||||
* - Look for any missing devices in a non-replicated config
|
||||
* - Check for any data errors
|
||||
* - Check for any missing devices in a replicated config
|
||||
* - Look for any devices showing errors
|
||||
* - Check for any resilvering devices
|
||||
*
|
||||
* There can obviously be multiple errors within a single pool, so this routine
|
||||
* only picks the most damaging of all the current errors to report.
|
||||
*/
|
||||
static zpool_status_t
|
||||
check_status(nvlist_t *config, boolean_t isimport)
|
||||
{
|
||||
nvlist_t *nvroot;
|
||||
vdev_stat_t *vs;
|
||||
uint_t vsc;
|
||||
uint64_t nerr;
|
||||
uint64_t version;
|
||||
uint64_t stateval;
|
||||
uint64_t hostid = 0;
|
||||
|
||||
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
|
||||
&version) == 0);
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
|
||||
(uint64_t **)&vs, &vsc) == 0);
|
||||
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
|
||||
&stateval) == 0);
|
||||
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
|
||||
|
||||
/*
|
||||
* Pool last accessed by another system.
|
||||
*/
|
||||
if (hostid != 0 && (unsigned long)hostid != gethostid() &&
|
||||
stateval == POOL_STATE_ACTIVE)
|
||||
return (ZPOOL_STATUS_HOSTID_MISMATCH);
|
||||
|
||||
/*
|
||||
* Newer on-disk version.
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
vs->vs_aux == VDEV_AUX_VERSION_NEWER)
|
||||
return (ZPOOL_STATUS_VERSION_NEWER);
|
||||
|
||||
/*
|
||||
* Check that the config is complete.
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
|
||||
return (ZPOOL_STATUS_BAD_GUID_SUM);
|
||||
|
||||
/*
|
||||
* Missing devices in non-replicated config.
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
find_vdev_problem(nvroot, vdev_missing))
|
||||
return (ZPOOL_STATUS_MISSING_DEV_NR);
|
||||
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
find_vdev_problem(nvroot, vdev_broken))
|
||||
return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
|
||||
|
||||
/*
|
||||
* Corrupted pool metadata
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
|
||||
vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
|
||||
return (ZPOOL_STATUS_CORRUPT_POOL);
|
||||
|
||||
/*
|
||||
* Persistent data errors.
|
||||
*/
|
||||
if (!isimport) {
|
||||
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
|
||||
&nerr) == 0 && nerr != 0)
|
||||
return (ZPOOL_STATUS_CORRUPT_DATA);
|
||||
}
|
||||
|
||||
/*
|
||||
* Missing devices in a replicated config.
|
||||
*/
|
||||
if (find_vdev_problem(nvroot, vdev_missing))
|
||||
return (ZPOOL_STATUS_MISSING_DEV_R);
|
||||
if (find_vdev_problem(nvroot, vdev_broken))
|
||||
return (ZPOOL_STATUS_CORRUPT_LABEL_R);
|
||||
|
||||
/*
|
||||
* Devices with errors
|
||||
*/
|
||||
if (!isimport && find_vdev_problem(nvroot, vdev_errors))
|
||||
return (ZPOOL_STATUS_FAILING_DEV);
|
||||
|
||||
/*
|
||||
* Offlined devices
|
||||
*/
|
||||
if (find_vdev_problem(nvroot, vdev_offlined))
|
||||
return (ZPOOL_STATUS_OFFLINE_DEV);
|
||||
|
||||
/*
|
||||
* Currently resilvering
|
||||
*/
|
||||
if (!vs->vs_scrub_complete && vs->vs_scrub_type == POOL_SCRUB_RESILVER)
|
||||
return (ZPOOL_STATUS_RESILVERING);
|
||||
|
||||
/*
|
||||
* Outdated, but usable, version
|
||||
*/
|
||||
if (version < ZFS_VERSION)
|
||||
return (ZPOOL_STATUS_VERSION_OLDER);
|
||||
|
||||
return (ZPOOL_STATUS_OK);
|
||||
}
|
||||
|
||||
zpool_status_t
|
||||
zpool_get_status(zpool_handle_t *zhp, char **msgid)
|
||||
{
|
||||
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE);
|
||||
|
||||
if (ret >= NMSGID)
|
||||
*msgid = NULL;
|
||||
else
|
||||
*msgid = zfs_msgid_table_active[ret];
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
zpool_status_t
|
||||
zpool_import_status(nvlist_t *config, char **msgid)
|
||||
{
|
||||
zpool_status_t ret = check_status(config, B_TRUE);
|
||||
|
||||
if (ret >= NMSGID)
|
||||
*msgid = NULL;
|
||||
else
|
||||
*msgid = zfs_msgid_table[ret];
|
||||
|
||||
return (ret);
|
||||
}
|
@ -1,853 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* Internal utility routines for the ZFS library.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
int
|
||||
libzfs_errno(libzfs_handle_t *hdl)
|
||||
{
|
||||
return (hdl->libzfs_error);
|
||||
}
|
||||
|
||||
const char *
|
||||
libzfs_error_action(libzfs_handle_t *hdl)
|
||||
{
|
||||
return (hdl->libzfs_action);
|
||||
}
|
||||
|
||||
const char *
|
||||
libzfs_error_description(libzfs_handle_t *hdl)
|
||||
{
|
||||
if (hdl->libzfs_desc[0] != '\0')
|
||||
return (hdl->libzfs_desc);
|
||||
|
||||
switch (hdl->libzfs_error) {
|
||||
case EZFS_NOMEM:
|
||||
return (dgettext(TEXT_DOMAIN, "out of memory"));
|
||||
case EZFS_BADPROP:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid property value"));
|
||||
case EZFS_PROPREADONLY:
|
||||
return (dgettext(TEXT_DOMAIN, "read only property"));
|
||||
case EZFS_PROPTYPE:
|
||||
return (dgettext(TEXT_DOMAIN, "property doesn't apply to "
|
||||
"datasets of this type"));
|
||||
case EZFS_PROPNONINHERIT:
|
||||
return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));
|
||||
case EZFS_PROPSPACE:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));
|
||||
case EZFS_BADTYPE:
|
||||
return (dgettext(TEXT_DOMAIN, "operation not applicable to "
|
||||
"datasets of this type"));
|
||||
case EZFS_BUSY:
|
||||
return (dgettext(TEXT_DOMAIN, "pool or dataset is busy"));
|
||||
case EZFS_EXISTS:
|
||||
return (dgettext(TEXT_DOMAIN, "pool or dataset exists"));
|
||||
case EZFS_NOENT:
|
||||
return (dgettext(TEXT_DOMAIN, "no such pool or dataset"));
|
||||
case EZFS_BADSTREAM:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid backup stream"));
|
||||
case EZFS_DSREADONLY:
|
||||
return (dgettext(TEXT_DOMAIN, "dataset is read only"));
|
||||
case EZFS_VOLTOOBIG:
|
||||
return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
|
||||
"this system"));
|
||||
case EZFS_VOLHASDATA:
|
||||
return (dgettext(TEXT_DOMAIN, "volume has data"));
|
||||
case EZFS_INVALIDNAME:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid name"));
|
||||
case EZFS_BADRESTORE:
|
||||
return (dgettext(TEXT_DOMAIN, "unable to restore to "
|
||||
"destination"));
|
||||
case EZFS_BADBACKUP:
|
||||
return (dgettext(TEXT_DOMAIN, "backup failed"));
|
||||
case EZFS_BADTARGET:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid target vdev"));
|
||||
case EZFS_NODEVICE:
|
||||
return (dgettext(TEXT_DOMAIN, "no such device in pool"));
|
||||
case EZFS_BADDEV:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid device"));
|
||||
case EZFS_NOREPLICAS:
|
||||
return (dgettext(TEXT_DOMAIN, "no valid replicas"));
|
||||
case EZFS_RESILVERING:
|
||||
return (dgettext(TEXT_DOMAIN, "currently resilvering"));
|
||||
case EZFS_BADVERSION:
|
||||
return (dgettext(TEXT_DOMAIN, "unsupported version"));
|
||||
case EZFS_POOLUNAVAIL:
|
||||
return (dgettext(TEXT_DOMAIN, "pool is unavailable"));
|
||||
case EZFS_DEVOVERFLOW:
|
||||
return (dgettext(TEXT_DOMAIN, "too many devices in one vdev"));
|
||||
case EZFS_BADPATH:
|
||||
return (dgettext(TEXT_DOMAIN, "must be an absolute path"));
|
||||
case EZFS_CROSSTARGET:
|
||||
return (dgettext(TEXT_DOMAIN, "operation crosses datasets or "
|
||||
"pools"));
|
||||
case EZFS_ZONED:
|
||||
return (dgettext(TEXT_DOMAIN, "dataset in use by local zone"));
|
||||
case EZFS_MOUNTFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "mount failed"));
|
||||
case EZFS_UMOUNTFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "umount failed"));
|
||||
case EZFS_UNSHARENFSFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
|
||||
case EZFS_SHARENFSFAILED:
|
||||
return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
|
||||
case EZFS_DEVLINKS:
|
||||
return (dgettext(TEXT_DOMAIN, "failed to create /dev links"));
|
||||
case EZFS_PERM:
|
||||
return (dgettext(TEXT_DOMAIN, "permission denied"));
|
||||
case EZFS_NOSPC:
|
||||
return (dgettext(TEXT_DOMAIN, "out of space"));
|
||||
case EZFS_IO:
|
||||
return (dgettext(TEXT_DOMAIN, "I/O error"));
|
||||
case EZFS_INTR:
|
||||
return (dgettext(TEXT_DOMAIN, "signal received"));
|
||||
case EZFS_ISSPARE:
|
||||
return (dgettext(TEXT_DOMAIN, "device is reserved as a hot "
|
||||
"spare"));
|
||||
case EZFS_INVALCONFIG:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid vdev configuration"));
|
||||
case EZFS_RECURSIVE:
|
||||
return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));
|
||||
case EZFS_NOHISTORY:
|
||||
return (dgettext(TEXT_DOMAIN, "no history available"));
|
||||
case EZFS_UNSHAREISCSIFAILED:
|
||||
return (dgettext(TEXT_DOMAIN,
|
||||
"iscsitgtd failed request to unshare"));
|
||||
case EZFS_SHAREISCSIFAILED:
|
||||
return (dgettext(TEXT_DOMAIN,
|
||||
"iscsitgtd failed request to share"));
|
||||
case EZFS_POOLPROPS:
|
||||
return (dgettext(TEXT_DOMAIN, "failed to retrieve "
|
||||
"pool properties"));
|
||||
case EZFS_POOL_NOTSUP:
|
||||
return (dgettext(TEXT_DOMAIN, "operation not supported "
|
||||
"on this type of pool"));
|
||||
case EZFS_POOL_INVALARG:
|
||||
return (dgettext(TEXT_DOMAIN, "invalid argument for "
|
||||
"this pool operation"));
|
||||
case EZFS_NAMETOOLONG:
|
||||
return (dgettext(TEXT_DOMAIN, "dataset name is too long"));
|
||||
case EZFS_UNKNOWN:
|
||||
return (dgettext(TEXT_DOMAIN, "unknown error"));
|
||||
default:
|
||||
assert(hdl->libzfs_error == 0);
|
||||
return (dgettext(TEXT_DOMAIN, "no error"));
|
||||
}
|
||||
}
|
||||
|
||||
/*PRINTFLIKE2*/
|
||||
void
|
||||
zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
(void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc),
|
||||
fmt, ap);
|
||||
hdl->libzfs_desc_active = 1;
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap)
|
||||
{
|
||||
(void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action),
|
||||
fmt, ap);
|
||||
hdl->libzfs_error = error;
|
||||
|
||||
if (hdl->libzfs_desc_active)
|
||||
hdl->libzfs_desc_active = 0;
|
||||
else
|
||||
hdl->libzfs_desc[0] = '\0';
|
||||
|
||||
if (hdl->libzfs_printerr) {
|
||||
if (error == EZFS_UNKNOWN) {
|
||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal "
|
||||
"error: %s\n"), libzfs_error_description(hdl));
|
||||
abort();
|
||||
}
|
||||
|
||||
(void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action,
|
||||
libzfs_error_description(hdl));
|
||||
if (error == EZFS_NOMEM)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
zfs_error(libzfs_handle_t *hdl, int error, const char *msg)
|
||||
{
|
||||
return (zfs_error_fmt(hdl, error, "%s", msg));
|
||||
}
|
||||
|
||||
/*PRINTFLIKE3*/
|
||||
int
|
||||
zfs_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
zfs_verror(hdl, error, fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
switch (error) {
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
zfs_verror(hdl, EZFS_PERM, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EIO:
|
||||
zfs_verror(hdl, EZFS_IO, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EINTR:
|
||||
zfs_verror(hdl, EZFS_INTR, fmt, ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
|
||||
{
|
||||
return (zfs_standard_error_fmt(hdl, error, "%s", msg));
|
||||
}
|
||||
|
||||
/*PRINTFLIKE3*/
|
||||
int
|
||||
zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (zfs_common_error(hdl, error, fmt, ap) != 0) {
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
switch (error) {
|
||||
case ENXIO:
|
||||
zfs_verror(hdl, EZFS_IO, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOENT:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"dataset does not exist"));
|
||||
zfs_verror(hdl, EZFS_NOENT, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOSPC:
|
||||
case EDQUOT:
|
||||
zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
|
||||
return (-1);
|
||||
|
||||
case EEXIST:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"dataset already exists"));
|
||||
zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
|
||||
break;
|
||||
|
||||
case EBUSY:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"dataset is busy"));
|
||||
zfs_verror(hdl, EZFS_BUSY, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENAMETOOLONG:
|
||||
zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
|
||||
break;
|
||||
|
||||
default:
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
|
||||
{
|
||||
return (zpool_standard_error_fmt(hdl, error, "%s", msg));
|
||||
}
|
||||
|
||||
/*PRINTFLIKE3*/
|
||||
int
|
||||
zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (zfs_common_error(hdl, error, fmt, ap) != 0) {
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (error) {
|
||||
case ENODEV:
|
||||
zfs_verror(hdl, EZFS_NODEVICE, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOENT:
|
||||
zfs_error_aux(hdl,
|
||||
dgettext(TEXT_DOMAIN, "no such pool or dataset"));
|
||||
zfs_verror(hdl, EZFS_NOENT, fmt, ap);
|
||||
break;
|
||||
|
||||
case EEXIST:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"pool already exists"));
|
||||
zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
|
||||
break;
|
||||
|
||||
case EBUSY:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
|
||||
zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENXIO:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"one or more devices is currently unavailable"));
|
||||
zfs_verror(hdl, EZFS_BADDEV, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENAMETOOLONG:
|
||||
zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap);
|
||||
break;
|
||||
|
||||
case ENOTSUP:
|
||||
zfs_verror(hdl, EZFS_POOL_NOTSUP, fmt, ap);
|
||||
break;
|
||||
|
||||
case EINVAL:
|
||||
zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap);
|
||||
break;
|
||||
|
||||
default:
|
||||
zfs_error_aux(hdl, strerror(error));
|
||||
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display an out of memory error message and abort the current program.
|
||||
*/
|
||||
int
|
||||
no_memory(libzfs_handle_t *hdl)
|
||||
{
|
||||
return (zfs_error(hdl, EZFS_NOMEM, "internal error"));
|
||||
}
|
||||
|
||||
/*
|
||||
* A safe form of malloc() which will die if the allocation fails.
|
||||
*/
|
||||
void *
|
||||
zfs_alloc(libzfs_handle_t *hdl, size_t size)
|
||||
{
|
||||
void *data;
|
||||
|
||||
if ((data = calloc(1, size)) == NULL)
|
||||
(void) no_memory(hdl);
|
||||
|
||||
return (data);
|
||||
}
|
||||
|
||||
/*
|
||||
* A safe form of realloc(), which also zeroes newly allocated space.
|
||||
*/
|
||||
void *
|
||||
zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if ((ret = realloc(ptr, newsize)) == NULL) {
|
||||
(void) no_memory(hdl);
|
||||
free(ptr);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
bzero((char *)ret + oldsize, (newsize - oldsize));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* A safe form of strdup() which will die if the allocation fails.
|
||||
*/
|
||||
char *
|
||||
zfs_strdup(libzfs_handle_t *hdl, const char *str)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if ((ret = strdup(str)) == NULL)
|
||||
(void) no_memory(hdl);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a number to an appropriately human-readable output.
|
||||
*/
|
||||
void
|
||||
zfs_nicenum(uint64_t num, char *buf, size_t buflen)
|
||||
{
|
||||
uint64_t n = num;
|
||||
int index = 0;
|
||||
char u;
|
||||
|
||||
while (n >= 1024) {
|
||||
n /= 1024;
|
||||
index++;
|
||||
}
|
||||
|
||||
u = " KMGTPE"[index];
|
||||
|
||||
if (index == 0) {
|
||||
(void) snprintf(buf, buflen, "%llu", n);
|
||||
} else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
|
||||
/*
|
||||
* If this is an even multiple of the base, always display
|
||||
* without any decimal precision.
|
||||
*/
|
||||
(void) snprintf(buf, buflen, "%llu%c", n, u);
|
||||
} else {
|
||||
/*
|
||||
* We want to choose a precision that reflects the best choice
|
||||
* for fitting in 5 characters. This can get rather tricky when
|
||||
* we have numbers that are very close to an order of magnitude.
|
||||
* For example, when displaying 10239 (which is really 9.999K),
|
||||
* we want only a single place of precision for 10.0K. We could
|
||||
* develop some complex heuristics for this, but it's much
|
||||
* easier just to try each combination in turn.
|
||||
*/
|
||||
int i;
|
||||
for (i = 2; i >= 0; i--) {
|
||||
(void) snprintf(buf, buflen, "%.*f%c", i,
|
||||
(double)num / (1ULL << 10 * index), u);
|
||||
if (strlen(buf) <= 5)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)
|
||||
{
|
||||
hdl->libzfs_printerr = printerr;
|
||||
}
|
||||
|
||||
static int
|
||||
libzfs_load(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (modfind("zfs") < 0) {
|
||||
/* Not present in kernel, try loading it. */
|
||||
if (kldload("zfs") < 0 || modfind("zfs") < 0) {
|
||||
if (errno != EEXIST)
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
libzfs_handle_t *
|
||||
libzfs_init(void)
|
||||
{
|
||||
libzfs_handle_t *hdl;
|
||||
|
||||
if ((hdl = calloc(sizeof (libzfs_handle_t), 1)) == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
|
||||
if (libzfs_load() == 0)
|
||||
hdl->libzfs_fd = open(ZFS_DEV, O_RDWR);
|
||||
if (hdl->libzfs_fd < 0) {
|
||||
free(hdl);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
|
||||
(void) close(hdl->libzfs_fd);
|
||||
free(hdl);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
hdl->libzfs_sharetab = fopen(ZFS_EXPORTS_PATH, "r");
|
||||
|
||||
return (hdl);
|
||||
}
|
||||
|
||||
void
|
||||
libzfs_fini(libzfs_handle_t *hdl)
|
||||
{
|
||||
(void) close(hdl->libzfs_fd);
|
||||
if (hdl->libzfs_mnttab)
|
||||
(void) fclose(hdl->libzfs_mnttab);
|
||||
if (hdl->libzfs_sharetab)
|
||||
(void) fclose(hdl->libzfs_sharetab);
|
||||
namespace_clear(hdl);
|
||||
free(hdl);
|
||||
}
|
||||
|
||||
libzfs_handle_t *
|
||||
zpool_get_handle(zpool_handle_t *zhp)
|
||||
{
|
||||
return (zhp->zpool_hdl);
|
||||
}
|
||||
|
||||
libzfs_handle_t *
|
||||
zfs_get_handle(zfs_handle_t *zhp)
|
||||
{
|
||||
return (zhp->zfs_hdl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a name, determine whether or not it's a valid path
|
||||
* (starts with '/' or "./"). If so, walk the mnttab trying
|
||||
* to match the device number. If not, treat the path as an
|
||||
* fs/vol/snap name.
|
||||
*/
|
||||
zfs_handle_t *
|
||||
zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
|
||||
{
|
||||
struct statfs statbuf;
|
||||
|
||||
if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {
|
||||
/*
|
||||
* It's not a valid path, assume it's a name of type 'argtype'.
|
||||
*/
|
||||
return (zfs_open(hdl, path, argtype));
|
||||
}
|
||||
|
||||
if (statfs(path, &statbuf) != 0) {
|
||||
(void) fprintf(stderr, "%s: %s\n", path, strerror(errno));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (strcmp(statbuf.f_fstypename, MNTTYPE_ZFS) != 0) {
|
||||
(void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
|
||||
path);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (zfs_open(hdl, statbuf.f_mntfromname, ZFS_TYPE_FILESYSTEM));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from
|
||||
* an ioctl().
|
||||
*/
|
||||
int
|
||||
zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
len = 2048;
|
||||
zc->zc_nvlist_dst_size = len;
|
||||
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when an ioctl() which returns an nvlist fails with ENOMEM. This will
|
||||
* expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was
|
||||
* filled in by the kernel to indicate the actual required size.
|
||||
*/
|
||||
int
|
||||
zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
|
||||
{
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_dst);
|
||||
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
zfs_alloc(hdl, zc->zc_nvlist_dst_size))
|
||||
== 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to free the src and dst nvlists stored in the command structure.
|
||||
*/
|
||||
void
|
||||
zcmd_free_nvlists(zfs_cmd_t *zc)
|
||||
{
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_src);
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_dst);
|
||||
}
|
||||
|
||||
int
|
||||
zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl,
|
||||
size_t *size)
|
||||
{
|
||||
char *packed;
|
||||
size_t len;
|
||||
|
||||
verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0);
|
||||
|
||||
if ((packed = zfs_alloc(hdl, len)) == NULL)
|
||||
return (-1);
|
||||
|
||||
verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
|
||||
|
||||
zc->zc_nvlist_src = (uint64_t)(uintptr_t)packed;
|
||||
zc->zc_nvlist_src_size = len;
|
||||
|
||||
if (size)
|
||||
*size = len;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpacks an nvlist from the ZFS ioctl command structure.
|
||||
*/
|
||||
int
|
||||
zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
|
||||
{
|
||||
if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst,
|
||||
zc->zc_nvlist_dst_size, nvlp, 0) != 0)
|
||||
return (no_memory(hdl));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_print_prop_headers(libzfs_get_cbdata_t *cbp)
|
||||
{
|
||||
zfs_proplist_t *pl = cbp->cb_proplist;
|
||||
int i;
|
||||
char *title;
|
||||
size_t len;
|
||||
|
||||
cbp->cb_first = B_FALSE;
|
||||
if (cbp->cb_scripted)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Start with the length of the column headers.
|
||||
*/
|
||||
cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN, "NAME"));
|
||||
cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"PROPERTY"));
|
||||
cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"VALUE"));
|
||||
cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
|
||||
"SOURCE"));
|
||||
|
||||
/*
|
||||
* Go through and calculate the widths for each column. For the
|
||||
* 'source' column, we kludge it up by taking the worst-case scenario of
|
||||
* inheriting from the longest name. This is acceptable because in the
|
||||
* majority of cases 'SOURCE' is the last column displayed, and we don't
|
||||
* use the width anyway. Note that the 'VALUE' column can be oversized,
|
||||
* if the name of the property is much longer the any values we find.
|
||||
*/
|
||||
for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
|
||||
/*
|
||||
* 'PROPERTY' column
|
||||
*/
|
||||
if (pl->pl_prop != ZFS_PROP_INVAL) {
|
||||
len = strlen(zfs_prop_to_name(pl->pl_prop));
|
||||
if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
|
||||
cbp->cb_colwidths[GET_COL_PROPERTY] = len;
|
||||
} else {
|
||||
len = strlen(pl->pl_user_prop);
|
||||
if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
|
||||
cbp->cb_colwidths[GET_COL_PROPERTY] = len;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'VALUE' column
|
||||
*/
|
||||
if ((pl->pl_prop != ZFS_PROP_NAME || !pl->pl_all) &&
|
||||
pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
|
||||
cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
|
||||
|
||||
/*
|
||||
* 'NAME' and 'SOURCE' columns
|
||||
*/
|
||||
if (pl->pl_prop == ZFS_PROP_NAME &&
|
||||
pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
|
||||
cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
|
||||
cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width +
|
||||
strlen(dgettext(TEXT_DOMAIN, "inherited from"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now go through and print the headers.
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
switch (cbp->cb_columns[i]) {
|
||||
case GET_COL_NAME:
|
||||
title = dgettext(TEXT_DOMAIN, "NAME");
|
||||
break;
|
||||
case GET_COL_PROPERTY:
|
||||
title = dgettext(TEXT_DOMAIN, "PROPERTY");
|
||||
break;
|
||||
case GET_COL_VALUE:
|
||||
title = dgettext(TEXT_DOMAIN, "VALUE");
|
||||
break;
|
||||
case GET_COL_SOURCE:
|
||||
title = dgettext(TEXT_DOMAIN, "SOURCE");
|
||||
break;
|
||||
default:
|
||||
title = NULL;
|
||||
}
|
||||
|
||||
if (title != NULL) {
|
||||
if (i == 3 || cbp->cb_columns[i + 1] == 0)
|
||||
(void) printf("%s", title);
|
||||
else
|
||||
(void) printf("%-*s ",
|
||||
cbp->cb_colwidths[cbp->cb_columns[i]],
|
||||
title);
|
||||
}
|
||||
}
|
||||
(void) printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a single line of output, according to the settings in the callback
|
||||
* structure.
|
||||
*/
|
||||
void
|
||||
libzfs_print_one_property(const char *name, libzfs_get_cbdata_t *cbp,
|
||||
const char *propname, const char *value, zfs_source_t sourcetype,
|
||||
const char *source)
|
||||
{
|
||||
int i;
|
||||
const char *str;
|
||||
char buf[128];
|
||||
|
||||
/*
|
||||
* Ignore those source types that the user has chosen to ignore.
|
||||
*/
|
||||
if ((sourcetype & cbp->cb_sources) == 0)
|
||||
return;
|
||||
|
||||
if (cbp->cb_first)
|
||||
zfs_print_prop_headers(cbp);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
switch (cbp->cb_columns[i]) {
|
||||
case GET_COL_NAME:
|
||||
str = name;
|
||||
break;
|
||||
|
||||
case GET_COL_PROPERTY:
|
||||
str = propname;
|
||||
break;
|
||||
|
||||
case GET_COL_VALUE:
|
||||
str = value;
|
||||
break;
|
||||
|
||||
case GET_COL_SOURCE:
|
||||
switch (sourcetype) {
|
||||
case ZFS_SRC_NONE:
|
||||
str = "-";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_DEFAULT:
|
||||
str = "default";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_LOCAL:
|
||||
str = "local";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_TEMPORARY:
|
||||
str = "temporary";
|
||||
break;
|
||||
|
||||
case ZFS_SRC_INHERITED:
|
||||
(void) snprintf(buf, sizeof (buf),
|
||||
"inherited from %s", source);
|
||||
str = buf;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cbp->cb_columns[i + 1] == 0)
|
||||
(void) printf("%s", str);
|
||||
else if (cbp->cb_scripted)
|
||||
(void) printf("%s\t", str);
|
||||
else
|
||||
(void) printf("%-*s ",
|
||||
cbp->cb_colwidths[cbp->cb_columns[i]],
|
||||
str);
|
||||
|
||||
}
|
||||
|
||||
(void) printf("\n");
|
||||
}
|
@ -1,852 +0,0 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/processor.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/zmod.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
/*
|
||||
* Emulation of kernel services in userland.
|
||||
*/
|
||||
|
||||
int hz = 119; /* frequency when using gethrtime() >> 23 for lbolt */
|
||||
uint64_t physmem;
|
||||
vnode_t *rootdir = (vnode_t *)0xabcd1234;
|
||||
char hw_serial[11];
|
||||
|
||||
struct utsname utsname = {
|
||||
"userland", "libzpool", "1", "1", "na"
|
||||
};
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* threads
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
kthread_t *
|
||||
zk_thread_create(void (*func)(), void *arg)
|
||||
{
|
||||
thread_t tid;
|
||||
|
||||
VERIFY(thr_create(0, 0, (void *(*)(void *))func, arg, THR_DETACHED,
|
||||
&tid) == 0);
|
||||
|
||||
return ((void *)(uintptr_t)tid);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kstats
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
kstat_t *
|
||||
kstat_create(char *module, int instance, char *name, char *class,
|
||||
uchar_t type, ulong_t ndata, uchar_t ks_flag)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
kstat_install(kstat_t *ksp)
|
||||
{}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
kstat_delete(kstat_t *ksp)
|
||||
{}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* mutexes
|
||||
* =========================================================================
|
||||
*/
|
||||
void
|
||||
zmutex_init(kmutex_t *mp)
|
||||
{
|
||||
mp->m_owner = NULL;
|
||||
(void) _mutex_init(&mp->m_lock, USYNC_THREAD, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
zmutex_destroy(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner == NULL);
|
||||
(void) _mutex_destroy(&(mp)->m_lock);
|
||||
mp->m_owner = (void *)-1UL;
|
||||
}
|
||||
|
||||
void
|
||||
mutex_enter(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner != (void *)-1UL);
|
||||
ASSERT(mp->m_owner != curthread);
|
||||
VERIFY(mutex_lock(&mp->m_lock) == 0);
|
||||
ASSERT(mp->m_owner == NULL);
|
||||
mp->m_owner = curthread;
|
||||
}
|
||||
|
||||
int
|
||||
mutex_tryenter(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner != (void *)-1UL);
|
||||
if (mutex_trylock(&mp->m_lock) == 0) {
|
||||
ASSERT(mp->m_owner == NULL);
|
||||
mp->m_owner = curthread;
|
||||
return (1);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mutex_exit(kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mp->m_owner == curthread);
|
||||
mp->m_owner = NULL;
|
||||
VERIFY(mutex_unlock(&mp->m_lock) == 0);
|
||||
}
|
||||
|
||||
void *
|
||||
mutex_owner(kmutex_t *mp)
|
||||
{
|
||||
return (mp->m_owner);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* rwlocks
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
rw_init(krwlock_t *rwlp, char *name, int type, void *arg)
|
||||
{
|
||||
rwlock_init(&rwlp->rw_lock, USYNC_THREAD, NULL);
|
||||
rwlp->rw_owner = NULL;
|
||||
rwlp->rw_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
rw_destroy(krwlock_t *rwlp)
|
||||
{
|
||||
rwlock_destroy(&rwlp->rw_lock);
|
||||
rwlp->rw_owner = (void *)-1UL;
|
||||
rwlp->rw_count = -2;
|
||||
}
|
||||
|
||||
void
|
||||
rw_enter(krwlock_t *rwlp, krw_t rw)
|
||||
{
|
||||
//ASSERT(!RW_LOCK_HELD(rwlp));
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
ASSERT(rwlp->rw_owner != curthread);
|
||||
|
||||
if (rw == RW_READER) {
|
||||
(void) rw_rdlock(&rwlp->rw_lock);
|
||||
ASSERT(rwlp->rw_count >= 0);
|
||||
atomic_add_int(&rwlp->rw_count, 1);
|
||||
} else {
|
||||
(void) rw_wrlock(&rwlp->rw_lock);
|
||||
ASSERT(rwlp->rw_count == 0);
|
||||
rwlp->rw_count = -1;
|
||||
rwlp->rw_owner = curthread;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rw_exit(krwlock_t *rwlp)
|
||||
{
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
|
||||
if (rwlp->rw_owner == curthread) {
|
||||
/* Write locked. */
|
||||
ASSERT(rwlp->rw_count == -1);
|
||||
rwlp->rw_count = 0;
|
||||
rwlp->rw_owner = NULL;
|
||||
} else {
|
||||
/* Read locked. */
|
||||
ASSERT(rwlp->rw_count > 0);
|
||||
atomic_add_int(&rwlp->rw_count, -1);
|
||||
}
|
||||
(void) rw_unlock(&rwlp->rw_lock);
|
||||
}
|
||||
|
||||
int
|
||||
rw_tryenter(krwlock_t *rwlp, krw_t rw)
|
||||
{
|
||||
int rv;
|
||||
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
ASSERT(rwlp->rw_owner != curthread);
|
||||
|
||||
if (rw == RW_READER)
|
||||
rv = rw_tryrdlock(&rwlp->rw_lock);
|
||||
else
|
||||
rv = rw_trywrlock(&rwlp->rw_lock);
|
||||
|
||||
if (rv == 0) {
|
||||
ASSERT(rwlp->rw_owner == NULL);
|
||||
if (rw == RW_READER) {
|
||||
ASSERT(rwlp->rw_count >= 0);
|
||||
atomic_add_int(&rwlp->rw_count, 1);
|
||||
} else {
|
||||
ASSERT(rwlp->rw_count == 0);
|
||||
rwlp->rw_count = -1;
|
||||
rwlp->rw_owner = curthread;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
rw_tryupgrade(krwlock_t *rwlp)
|
||||
{
|
||||
ASSERT(rwlp->rw_owner != (void *)-1UL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
rw_lock_held(krwlock_t *rwlp)
|
||||
{
|
||||
|
||||
return (rwlp->rw_count != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* condition variables
|
||||
* =========================================================================
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
cv_init(kcondvar_t *cv, char *name, int type, void *arg)
|
||||
{
|
||||
VERIFY(cond_init(cv, name, NULL) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
cv_destroy(kcondvar_t *cv)
|
||||
{
|
||||
VERIFY(cond_destroy(cv) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
cv_wait(kcondvar_t *cv, kmutex_t *mp)
|
||||
{
|
||||
ASSERT(mutex_owner(mp) == curthread);
|
||||
mp->m_owner = NULL;
|
||||
int ret = cond_wait(cv, &mp->m_lock);
|
||||
VERIFY(ret == 0 || ret == EINTR);
|
||||
mp->m_owner = curthread;
|
||||
}
|
||||
|
||||
clock_t
|
||||
cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
|
||||
{
|
||||
int error;
|
||||
struct timespec ts;
|
||||
struct timeval tv;
|
||||
clock_t delta;
|
||||
|
||||
ASSERT(abstime > 0);
|
||||
top:
|
||||
delta = abstime;
|
||||
if (delta <= 0)
|
||||
return (-1);
|
||||
|
||||
if (gettimeofday(&tv, NULL) != 0)
|
||||
assert(!"gettimeofday() failed");
|
||||
|
||||
ts.tv_sec = tv.tv_sec + delta / hz;
|
||||
ts.tv_nsec = tv.tv_usec * 1000 + (delta % hz) * (NANOSEC / hz);
|
||||
ASSERT(ts.tv_nsec >= 0);
|
||||
|
||||
if(ts.tv_nsec >= NANOSEC) {
|
||||
ts.tv_sec++;
|
||||
ts.tv_nsec -= NANOSEC;
|
||||
}
|
||||
|
||||
ASSERT(mutex_owner(mp) == curthread);
|
||||
mp->m_owner = NULL;
|
||||
error = pthread_cond_timedwait(cv, &mp->m_lock, &ts);
|
||||
mp->m_owner = curthread;
|
||||
|
||||
if (error == EINTR)
|
||||
goto top;
|
||||
|
||||
if (error == ETIMEDOUT)
|
||||
return (-1);
|
||||
|
||||
ASSERT(error == 0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
cv_signal(kcondvar_t *cv)
|
||||
{
|
||||
VERIFY(cond_signal(cv) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
cv_broadcast(kcondvar_t *cv)
|
||||
{
|
||||
VERIFY(cond_broadcast(cv) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* vnode operations
|
||||
* =========================================================================
|
||||
*/
|
||||
/*
|
||||
* Note: for the xxxat() versions of these functions, we assume that the
|
||||
* starting vp is always rootdir (which is true for spa_directory.c, the only
|
||||
* ZFS consumer of these interfaces). We assert this is true, and then emulate
|
||||
* them by adding '/' in front of the path.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
|
||||
{
|
||||
int fd;
|
||||
vnode_t *vp;
|
||||
int old_umask;
|
||||
char realpath[MAXPATHLEN];
|
||||
struct stat64 st;
|
||||
|
||||
/*
|
||||
* If we're accessing a real disk from userland, we need to use
|
||||
* the character interface to avoid caching. This is particularly
|
||||
* important if we're trying to look at a real in-kernel storage
|
||||
* pool from userland, e.g. via zdb, because otherwise we won't
|
||||
* see the changes occurring under the segmap cache.
|
||||
* On the other hand, the stupid character device returns zero
|
||||
* for its size. So -- gag -- we open the block device to get
|
||||
* its size, and remember it for subsequent VOP_GETATTR().
|
||||
*/
|
||||
if (strncmp(path, "/dev/", 5) == 0) {
|
||||
char *dsk;
|
||||
fd = open64(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return (errno);
|
||||
if (fstat64(fd, &st) == -1) {
|
||||
close(fd);
|
||||
return (errno);
|
||||
}
|
||||
close(fd);
|
||||
(void) sprintf(realpath, "%s", path);
|
||||
dsk = strstr(path, "/dsk/");
|
||||
if (dsk != NULL)
|
||||
(void) sprintf(realpath + (dsk - path) + 1, "r%s",
|
||||
dsk + 1);
|
||||
} else {
|
||||
(void) sprintf(realpath, "%s", path);
|
||||
if (!(flags & FCREAT) && stat64(realpath, &st) == -1)
|
||||
return (errno);
|
||||
}
|
||||
|
||||
if (flags & FCREAT)
|
||||
old_umask = umask(0);
|
||||
|
||||
/*
|
||||
* The construct 'flags - FREAD' conveniently maps combinations of
|
||||
* FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
|
||||
*/
|
||||
fd = open64(realpath, flags - FREAD, mode);
|
||||
|
||||
if (flags & FCREAT)
|
||||
(void) umask(old_umask);
|
||||
|
||||
if (fd == -1)
|
||||
return (errno);
|
||||
|
||||
if (fstat64(fd, &st) == -1) {
|
||||
close(fd);
|
||||
return (errno);
|
||||
}
|
||||
|
||||
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
*vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
|
||||
|
||||
vp->v_fd = fd;
|
||||
if (S_ISCHR(st.st_mode))
|
||||
ioctl(fd, DIOCGMEDIASIZE, &vp->v_size);
|
||||
else
|
||||
vp->v_size = st.st_size;
|
||||
vp->v_path = spa_strdup(path);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
|
||||
int x3, vnode_t *startvp)
|
||||
{
|
||||
char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
|
||||
int ret;
|
||||
|
||||
ASSERT(startvp == rootdir);
|
||||
(void) sprintf(realpath, "/%s", path);
|
||||
|
||||
ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
|
||||
|
||||
umem_free(realpath, strlen(path) + 2);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
|
||||
int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
|
||||
{
|
||||
ssize_t iolen, split;
|
||||
|
||||
if (uio == UIO_READ) {
|
||||
iolen = pread64(vp->v_fd, addr, len, offset);
|
||||
} else {
|
||||
/*
|
||||
* To simulate partial disk writes, we split writes into two
|
||||
* system calls so that the process can be killed in between.
|
||||
*/
|
||||
split = (len > 0 ? rand() % len : 0);
|
||||
iolen = pwrite64(vp->v_fd, addr, split, offset);
|
||||
iolen += pwrite64(vp->v_fd, (char *)addr + split,
|
||||
len - split, offset + split);
|
||||
}
|
||||
|
||||
if (iolen == -1)
|
||||
return (errno);
|
||||
if (residp)
|
||||
*residp = len - iolen;
|
||||
else if (iolen != len)
|
||||
return (EIO);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
vn_close(vnode_t *vp)
|
||||
{
|
||||
close(vp->v_fd);
|
||||
spa_strfree(vp->v_path);
|
||||
umem_free(vp, sizeof (vnode_t));
|
||||
}
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* Figure out which debugging statements to print
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
static char *dprintf_string;
|
||||
static int dprintf_print_all;
|
||||
|
||||
int
|
||||
dprintf_find_string(const char *string)
|
||||
{
|
||||
char *tmp_str = dprintf_string;
|
||||
int len = strlen(string);
|
||||
|
||||
/*
|
||||
* Find out if this is a string we want to print.
|
||||
* String format: file1.c,function_name1,file2.c,file3.c
|
||||
*/
|
||||
|
||||
while (tmp_str != NULL) {
|
||||
if (strncmp(tmp_str, string, len) == 0 &&
|
||||
(tmp_str[len] == ',' || tmp_str[len] == '\0'))
|
||||
return (1);
|
||||
tmp_str = strchr(tmp_str, ',');
|
||||
if (tmp_str != NULL)
|
||||
tmp_str++; /* Get rid of , */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dprintf_setup(int *argc, char **argv)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* Debugging can be specified two ways: by setting the
|
||||
* environment variable ZFS_DEBUG, or by including a
|
||||
* "debug=..." argument on the command line. The command
|
||||
* line setting overrides the environment variable.
|
||||
*/
|
||||
|
||||
for (i = 1; i < *argc; i++) {
|
||||
int len = strlen("debug=");
|
||||
/* First look for a command line argument */
|
||||
if (strncmp("debug=", argv[i], len) == 0) {
|
||||
dprintf_string = argv[i] + len;
|
||||
/* Remove from args */
|
||||
for (j = i; j < *argc; j++)
|
||||
argv[j] = argv[j+1];
|
||||
argv[j] = NULL;
|
||||
(*argc)--;
|
||||
}
|
||||
}
|
||||
|
||||
if (dprintf_string == NULL) {
|
||||
/* Look for ZFS_DEBUG environment variable */
|
||||
dprintf_string = getenv("ZFS_DEBUG");
|
||||
}
|
||||
|
||||
/*
|
||||
* Are we just turning on all debugging?
|
||||
*/
|
||||
if (dprintf_find_string("on"))
|
||||
dprintf_print_all = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* debug printfs
|
||||
* =========================================================================
|
||||
*/
|
||||
void
|
||||
__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
|
||||
{
|
||||
const char *newfile;
|
||||
va_list adx;
|
||||
|
||||
/*
|
||||
* Get rid of annoying "../common/" prefix to filename.
|
||||
*/
|
||||
newfile = strrchr(file, '/');
|
||||
if (newfile != NULL) {
|
||||
newfile = newfile + 1; /* Get rid of leading / */
|
||||
} else {
|
||||
newfile = file;
|
||||
}
|
||||
|
||||
if (dprintf_print_all ||
|
||||
dprintf_find_string(newfile) ||
|
||||
dprintf_find_string(func)) {
|
||||
/* Print out just the function name if requested */
|
||||
flockfile(stdout);
|
||||
if (dprintf_find_string("pid"))
|
||||
(void) printf("%d ", getpid());
|
||||
if (dprintf_find_string("tid"))
|
||||
(void) printf("%u ", thr_self());
|
||||
#if 0
|
||||
if (dprintf_find_string("cpu"))
|
||||
(void) printf("%u ", getcpuid());
|
||||
#endif
|
||||
if (dprintf_find_string("time"))
|
||||
(void) printf("%llu ", gethrtime());
|
||||
if (dprintf_find_string("long"))
|
||||
(void) printf("%s, line %d: ", newfile, line);
|
||||
(void) printf("%s: ", func);
|
||||
va_start(adx, fmt);
|
||||
(void) vprintf(fmt, adx);
|
||||
va_end(adx);
|
||||
funlockfile(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ZFS_DEBUG */
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* cmn_err() and panic()
|
||||
* =========================================================================
|
||||
*/
|
||||
static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" };
|
||||
static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" };
|
||||
|
||||
void
|
||||
vpanic(const char *fmt, va_list adx)
|
||||
{
|
||||
(void) fprintf(stderr, "error: ");
|
||||
(void) vfprintf(stderr, fmt, adx);
|
||||
(void) fprintf(stderr, "\n");
|
||||
|
||||
abort(); /* think of it as a "user-level crash dump" */
|
||||
}
|
||||
|
||||
void
|
||||
panic(const char *fmt, ...)
|
||||
{
|
||||
va_list adx;
|
||||
|
||||
va_start(adx, fmt);
|
||||
vpanic(fmt, adx);
|
||||
va_end(adx);
|
||||
}
|
||||
|
||||
void
|
||||
vcmn_err(int ce, const char *fmt, va_list adx)
|
||||
{
|
||||
if (ce == CE_PANIC)
|
||||
vpanic(fmt, adx);
|
||||
if (ce != CE_NOTE) { /* suppress noise in userland stress testing */
|
||||
(void) fprintf(stderr, "%s", ce_prefix[ce]);
|
||||
(void) vfprintf(stderr, fmt, adx);
|
||||
(void) fprintf(stderr, "%s", ce_suffix[ce]);
|
||||
}
|
||||
}
|
||||
|
||||
/*PRINTFLIKE2*/
|
||||
void
|
||||
cmn_err(int ce, const char *fmt, ...)
|
||||
{
|
||||
va_list adx;
|
||||
|
||||
va_start(adx, fmt);
|
||||
vcmn_err(ce, fmt, adx);
|
||||
va_end(adx);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kobj interfaces
|
||||
* =========================================================================
|
||||
*/
|
||||
struct _buf *
|
||||
kobj_open_file(char *name)
|
||||
{
|
||||
struct _buf *file;
|
||||
vnode_t *vp;
|
||||
|
||||
/* set vp as the _fd field of the file */
|
||||
if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir) != 0)
|
||||
return ((void *)-1UL);
|
||||
|
||||
file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL);
|
||||
file->_fd = (intptr_t)vp;
|
||||
return (file);
|
||||
}
|
||||
|
||||
int
|
||||
kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
|
||||
{
|
||||
ssize_t resid;
|
||||
|
||||
vn_rdwr(UIO_READ, (vnode_t *)file->_fd, buf, size, (offset_t)off,
|
||||
UIO_SYSSPACE, 0, 0, 0, &resid);
|
||||
|
||||
return (size - resid);
|
||||
}
|
||||
|
||||
void
|
||||
kobj_close_file(struct _buf *file)
|
||||
{
|
||||
vn_close((vnode_t *)file->_fd);
|
||||
umem_free(file, sizeof (struct _buf));
|
||||
}
|
||||
|
||||
int
|
||||
kobj_get_filesize(struct _buf *file, uint64_t *size)
|
||||
{
|
||||
struct stat64 st;
|
||||
vnode_t *vp = (vnode_t *)file->_fd;
|
||||
|
||||
if (fstat64(vp->v_fd, &st) == -1) {
|
||||
vn_close(vp);
|
||||
return (errno);
|
||||
}
|
||||
*size = st.st_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* misc routines
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
void
|
||||
delay(clock_t ticks)
|
||||
{
|
||||
poll(0, 0, ticks * (1000 / hz));
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Find highest one bit set.
|
||||
* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
|
||||
* High order bit is 31 (or 63 in _LP64 kernel).
|
||||
*/
|
||||
int
|
||||
highbit(ulong_t i)
|
||||
{
|
||||
register int h = 1;
|
||||
|
||||
if (i == 0)
|
||||
return (0);
|
||||
#ifdef _LP64
|
||||
if (i & 0xffffffff00000000ul) {
|
||||
h += 32; i >>= 32;
|
||||
}
|
||||
#endif
|
||||
if (i & 0xffff0000) {
|
||||
h += 16; i >>= 16;
|
||||
}
|
||||
if (i & 0xff00) {
|
||||
h += 8; i >>= 8;
|
||||
}
|
||||
if (i & 0xf0) {
|
||||
h += 4; i >>= 4;
|
||||
}
|
||||
if (i & 0xc) {
|
||||
h += 2; i >>= 2;
|
||||
}
|
||||
if (i & 0x2) {
|
||||
h += 1;
|
||||
}
|
||||
return (h);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
random_get_bytes_common(uint8_t *ptr, size_t len, char *devname)
|
||||
{
|
||||
int fd = open(devname, O_RDONLY);
|
||||
size_t resid = len;
|
||||
ssize_t bytes;
|
||||
|
||||
ASSERT(fd != -1);
|
||||
|
||||
while (resid != 0) {
|
||||
bytes = read(fd, ptr, resid);
|
||||
ASSERT(bytes >= 0);
|
||||
ptr += bytes;
|
||||
resid -= bytes;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
random_get_bytes(uint8_t *ptr, size_t len)
|
||||
{
|
||||
return (random_get_bytes_common(ptr, len, "/dev/random"));
|
||||
}
|
||||
|
||||
int
|
||||
random_get_pseudo_bytes(uint8_t *ptr, size_t len)
|
||||
{
|
||||
return (random_get_bytes_common(ptr, len, "/dev/urandom"));
|
||||
}
|
||||
|
||||
int
|
||||
ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result)
|
||||
{
|
||||
char *end;
|
||||
|
||||
*result = strtoul(hw_serial, &end, base);
|
||||
if (*result == 0)
|
||||
return (errno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kernel emulation setup & teardown
|
||||
* =========================================================================
|
||||
*/
|
||||
static int
|
||||
umem_out_of_memory(void)
|
||||
{
|
||||
char errmsg[] = "out of memory -- generating core dump\n";
|
||||
|
||||
write(fileno(stderr), errmsg, sizeof (errmsg));
|
||||
abort();
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
kernel_init(int mode)
|
||||
{
|
||||
umem_nofail_callback(umem_out_of_memory);
|
||||
|
||||
physmem = sysconf(_SC_PHYS_PAGES);
|
||||
|
||||
dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
|
||||
(double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
|
||||
|
||||
snprintf(hw_serial, sizeof (hw_serial), "%ld", gethostid());
|
||||
|
||||
spa_init(mode);
|
||||
}
|
||||
|
||||
void
|
||||
kernel_fini(void)
|
||||
{
|
||||
spa_fini();
|
||||
}
|
||||
|
||||
int
|
||||
z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
|
||||
{
|
||||
int ret;
|
||||
uLongf len = *dstlen;
|
||||
|
||||
if ((ret = uncompress(dst, &len, src, srclen)) == Z_OK)
|
||||
*dstlen = (size_t)len;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen,
|
||||
int level)
|
||||
{
|
||||
int ret;
|
||||
uLongf len = *dstlen;
|
||||
|
||||
if ((ret = compress2(dst, &len, src, srclen, level)) == Z_OK)
|
||||
*dstlen = (size_t)len;
|
||||
|
||||
return (ret);
|
||||
}
|
@ -1,509 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ZFS_CONTEXT_H
|
||||
#define _SYS_ZFS_CONTEXT_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _SYS_MUTEX_H
|
||||
#define _SYS_RWLOCK_H
|
||||
#define _SYS_CONDVAR_H
|
||||
#define _SYS_SYSTM_H
|
||||
#define _SYS_DEBUG_H
|
||||
#define _SYS_T_LOCK_H
|
||||
#define _SYS_VNODE_H
|
||||
#define _SYS_VFS_H
|
||||
#define _SYS_SUNDDI_H
|
||||
#define _SYS_CALLB_H
|
||||
#define _SYS_SCHED_H_
|
||||
|
||||
#include <solaris.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <thread.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <umem.h>
|
||||
#include <vmem.h>
|
||||
#include <fsshare.h>
|
||||
#include <sys/note.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/bitmap.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <sys/list.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mntent.h>
|
||||
#include <sys/mnttab.h>
|
||||
#include <sys/zfs_debug.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/sdt.h>
|
||||
#include <sys/kstat.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/disk.h>
|
||||
#include <machine/atomic.h>
|
||||
|
||||
#define ZFS_EXPORTS_PATH "/etc/zfs/exports"
|
||||
|
||||
/*
|
||||
* Debugging
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that we are not using the debugging levels.
|
||||
*/
|
||||
|
||||
#define CE_CONT 0 /* continuation */
|
||||
#define CE_NOTE 1 /* notice */
|
||||
#define CE_WARN 2 /* warning */
|
||||
#define CE_PANIC 3 /* panic */
|
||||
#define CE_IGNORE 4 /* print nothing */
|
||||
|
||||
/*
|
||||
* ZFS debugging
|
||||
*/
|
||||
|
||||
#define ZFS_LOG(...) do { } while (0)
|
||||
|
||||
typedef u_longlong_t rlim64_t;
|
||||
#define RLIM64_INFINITY ((rlim64_t)-3)
|
||||
|
||||
#ifdef ZFS_DEBUG
|
||||
extern void dprintf_setup(int *argc, char **argv);
|
||||
#endif /* ZFS_DEBUG */
|
||||
|
||||
extern void cmn_err(int, const char *, ...);
|
||||
extern void vcmn_err(int, const char *, __va_list);
|
||||
extern void panic(const char *, ...);
|
||||
extern void vpanic(const char *, __va_list);
|
||||
|
||||
/* This definition is copied from assert.h. */
|
||||
#if defined(__STDC__)
|
||||
#if __STDC_VERSION__ - 0 >= 199901L
|
||||
#define verify(EX) (void)((EX) || \
|
||||
(__assert_c99(#EX, __FILE__, __LINE__, __func__), 0))
|
||||
#else
|
||||
#define verify(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC_VERSION__ - 0 >= 199901L */
|
||||
#else
|
||||
#define verify(EX) (void)((EX) || (_assert("EX", __FILE__, __LINE__), 0))
|
||||
#endif /* __STDC__ */
|
||||
|
||||
|
||||
#define VERIFY verify
|
||||
#define ASSERT assert
|
||||
|
||||
extern void __assert(const char *, const char *, int);
|
||||
|
||||
#ifdef lint
|
||||
#define VERIFY3_IMPL(x, y, z, t) if (x == z) ((void)0)
|
||||
#else
|
||||
/* BEGIN CSTYLED */
|
||||
#define VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE) do { \
|
||||
const TYPE __left = (TYPE)(LEFT); \
|
||||
const TYPE __right = (TYPE)(RIGHT); \
|
||||
if (!(__left OP __right)) { \
|
||||
char *__buf = alloca(256); \
|
||||
(void) snprintf(__buf, 256, "%s %s %s (0x%llx %s 0x%llx)", \
|
||||
#LEFT, #OP, #RIGHT, \
|
||||
(u_longlong_t)__left, #OP, (u_longlong_t)__right); \
|
||||
__assert(__buf, __FILE__, __LINE__); \
|
||||
} \
|
||||
_NOTE(CONSTCOND) } while (0)
|
||||
/* END CSTYLED */
|
||||
#endif /* lint */
|
||||
|
||||
#define VERIFY3S(x, y, z) VERIFY3_IMPL(x, y, z, int64_t)
|
||||
#define VERIFY3U(x, y, z) VERIFY3_IMPL(x, y, z, uint64_t)
|
||||
#define VERIFY3P(x, y, z) VERIFY3_IMPL(x, y, z, uintptr_t)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT3S(x, y, z) ((void)0)
|
||||
#define ASSERT3U(x, y, z) ((void)0)
|
||||
#define ASSERT3P(x, y, z) ((void)0)
|
||||
#else
|
||||
#define ASSERT3S(x, y, z) VERIFY3S(x, y, z)
|
||||
#define ASSERT3U(x, y, z) VERIFY3U(x, y, z)
|
||||
#define ASSERT3P(x, y, z) VERIFY3P(x, y, z)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dtrace SDT probes have different signatures in userland than they do in
|
||||
* kernel. If they're being used in kernel code, re-define them out of
|
||||
* existence for their counterparts in libzpool.
|
||||
*/
|
||||
|
||||
#ifdef DTRACE_PROBE1
|
||||
#undef DTRACE_PROBE1
|
||||
#define DTRACE_PROBE1(a, b, c) ((void)0)
|
||||
#endif /* DTRACE_PROBE1 */
|
||||
|
||||
#ifdef DTRACE_PROBE2
|
||||
#undef DTRACE_PROBE2
|
||||
#define DTRACE_PROBE2(a, b, c, d, e) ((void)0)
|
||||
#endif /* DTRACE_PROBE2 */
|
||||
|
||||
#ifdef DTRACE_PROBE3
|
||||
#undef DTRACE_PROBE3
|
||||
#define DTRACE_PROBE3(a, b, c, d, e, f, g) ((void)0)
|
||||
#endif /* DTRACE_PROBE3 */
|
||||
|
||||
#ifdef DTRACE_PROBE4
|
||||
#undef DTRACE_PROBE4
|
||||
#define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) ((void)0)
|
||||
#endif /* DTRACE_PROBE4 */
|
||||
|
||||
/*
|
||||
* Threads
|
||||
*/
|
||||
#define curthread ((void *)(uintptr_t)thr_self())
|
||||
|
||||
typedef struct kthread kthread_t;
|
||||
|
||||
#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \
|
||||
zk_thread_create(func, arg)
|
||||
#define thread_exit() thr_exit(NULL)
|
||||
|
||||
extern kthread_t *zk_thread_create(void (*func)(), void *arg);
|
||||
|
||||
#define issig(why) (FALSE)
|
||||
#define ISSIG(thr, why) (FALSE)
|
||||
|
||||
/*
|
||||
* Mutexes
|
||||
*/
|
||||
typedef struct kmutex {
|
||||
void *m_owner;
|
||||
mutex_t m_lock;
|
||||
} kmutex_t;
|
||||
|
||||
#define MUTEX_DEFAULT USYNC_THREAD
|
||||
#undef MUTEX_HELD
|
||||
#define MUTEX_HELD(m) ((m)->m_owner == curthread)
|
||||
|
||||
/*
|
||||
* Argh -- we have to get cheesy here because the kernel and userland
|
||||
* have different signatures for the same routine.
|
||||
*/
|
||||
//extern int _mutex_init(mutex_t *mp, int type, void *arg);
|
||||
//extern int _mutex_destroy(mutex_t *mp);
|
||||
|
||||
#define mutex_init(mp, b, c, d) zmutex_init((kmutex_t *)(mp))
|
||||
#define mutex_destroy(mp) zmutex_destroy((kmutex_t *)(mp))
|
||||
|
||||
extern void zmutex_init(kmutex_t *mp);
|
||||
extern void zmutex_destroy(kmutex_t *mp);
|
||||
extern void mutex_enter(kmutex_t *mp);
|
||||
extern void mutex_exit(kmutex_t *mp);
|
||||
extern int mutex_tryenter(kmutex_t *mp);
|
||||
extern void *mutex_owner(kmutex_t *mp);
|
||||
|
||||
/*
|
||||
* RW locks
|
||||
*/
|
||||
typedef struct krwlock {
|
||||
int rw_count;
|
||||
void *rw_owner;
|
||||
rwlock_t rw_lock;
|
||||
} krwlock_t;
|
||||
|
||||
typedef int krw_t;
|
||||
|
||||
#define RW_READER 0
|
||||
#define RW_WRITER 1
|
||||
#define RW_DEFAULT USYNC_THREAD
|
||||
|
||||
#undef RW_READ_HELD
|
||||
|
||||
#undef RW_WRITE_HELD
|
||||
#define RW_WRITE_HELD(x) ((x)->rw_owner == curthread)
|
||||
#define RW_LOCK_HELD(x) rw_lock_held(x)
|
||||
|
||||
extern void rw_init(krwlock_t *rwlp, char *name, int type, void *arg);
|
||||
extern void rw_destroy(krwlock_t *rwlp);
|
||||
extern void rw_enter(krwlock_t *rwlp, krw_t rw);
|
||||
extern int rw_tryenter(krwlock_t *rwlp, krw_t rw);
|
||||
extern int rw_tryupgrade(krwlock_t *rwlp);
|
||||
extern void rw_exit(krwlock_t *rwlp);
|
||||
extern int rw_lock_held(krwlock_t *rwlp);
|
||||
#define rw_downgrade(rwlp) do { } while (0)
|
||||
|
||||
/*
|
||||
* Condition variables
|
||||
*/
|
||||
typedef cond_t kcondvar_t;
|
||||
|
||||
#define CV_DEFAULT USYNC_THREAD
|
||||
|
||||
extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg);
|
||||
extern void cv_destroy(kcondvar_t *cv);
|
||||
extern void cv_wait(kcondvar_t *cv, kmutex_t *mp);
|
||||
extern clock_t cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime);
|
||||
extern void cv_signal(kcondvar_t *cv);
|
||||
extern void cv_broadcast(kcondvar_t *cv);
|
||||
|
||||
/*
|
||||
* Kernel memory
|
||||
*/
|
||||
#define KM_SLEEP UMEM_NOFAIL
|
||||
#define KM_NOSLEEP UMEM_DEFAULT
|
||||
#define KMC_NODEBUG UMC_NODEBUG
|
||||
#define kmem_alloc(_s, _f) umem_alloc(_s, _f)
|
||||
#define kmem_zalloc(_s, _f) umem_zalloc(_s, _f)
|
||||
#define kmem_free(_b, _s) umem_free(_b, _s)
|
||||
#define kmem_size() (physmem * PAGESIZE)
|
||||
#define kmem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) \
|
||||
umem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i)
|
||||
#define kmem_cache_destroy(_c) umem_cache_destroy(_c)
|
||||
#define kmem_cache_alloc(_c, _f) umem_cache_alloc(_c, _f)
|
||||
#define kmem_cache_free(_c, _b) umem_cache_free(_c, _b)
|
||||
#define kmem_debugging() 0
|
||||
#define kmem_cache_reap_now(c)
|
||||
|
||||
typedef umem_cache_t kmem_cache_t;
|
||||
|
||||
/*
|
||||
* Task queues
|
||||
*/
|
||||
typedef struct taskq taskq_t;
|
||||
typedef uintptr_t taskqid_t;
|
||||
typedef void (task_func_t)(void *);
|
||||
|
||||
#define TASKQ_PREPOPULATE 0x0001
|
||||
#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
|
||||
#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
|
||||
|
||||
#define TQ_SLEEP KM_SLEEP /* Can block for memory */
|
||||
#define TQ_NOSLEEP KM_NOSLEEP /* cannot block for memory; may fail */
|
||||
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
|
||||
|
||||
extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
|
||||
extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
|
||||
extern void taskq_destroy(taskq_t *);
|
||||
extern void taskq_wait(taskq_t *);
|
||||
extern int taskq_member(taskq_t *, void *);
|
||||
|
||||
/*
|
||||
* vnodes
|
||||
*/
|
||||
typedef struct vnode {
|
||||
uint64_t v_size;
|
||||
int v_fd;
|
||||
char *v_path;
|
||||
} vnode_t;
|
||||
|
||||
typedef struct vattr {
|
||||
uint_t va_mask; /* bit-mask of attributes */
|
||||
u_offset_t va_size; /* file size in bytes */
|
||||
} vattr_t;
|
||||
|
||||
#define AT_TYPE 0x0001
|
||||
#define AT_MODE 0x0002
|
||||
#define AT_UID 0x0004
|
||||
#define AT_GID 0x0008
|
||||
#define AT_FSID 0x0010
|
||||
#define AT_NODEID 0x0020
|
||||
#define AT_NLINK 0x0040
|
||||
#define AT_SIZE 0x0080
|
||||
#define AT_ATIME 0x0100
|
||||
#define AT_MTIME 0x0200
|
||||
#define AT_CTIME 0x0400
|
||||
#define AT_RDEV 0x0800
|
||||
#define AT_BLKSIZE 0x1000
|
||||
#define AT_NBLOCKS 0x2000
|
||||
#define AT_SEQ 0x8000
|
||||
|
||||
#define CRCREAT 0
|
||||
|
||||
#define VOP_CLOSE(vp, f, c, o, cr) 0
|
||||
#define VOP_PUTPAGE(vp, of, sz, fl, cr) 0
|
||||
#define VOP_GETATTR(vp, vap, fl, cr) ((vap)->va_size = (vp)->v_size, 0)
|
||||
|
||||
#define VOP_FSYNC(vp, f, cr) fsync((vp)->v_fd)
|
||||
|
||||
#define VN_RELE(vp) vn_close(vp)
|
||||
|
||||
extern int vn_open(char *path, int x1, int oflags, int mode, vnode_t **vpp,
|
||||
int x2, int x3);
|
||||
extern int vn_openat(char *path, int x1, int oflags, int mode, vnode_t **vpp,
|
||||
int x2, int x3, vnode_t *vp);
|
||||
extern int vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len,
|
||||
offset_t offset, int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp);
|
||||
extern void vn_close(vnode_t *vp);
|
||||
|
||||
#define vn_remove(path, x1, x2) remove(path)
|
||||
#define vn_rename(from, to, seg) rename((from), (to))
|
||||
#define vn_is_readonly(vp) B_FALSE
|
||||
|
||||
extern vnode_t *rootdir;
|
||||
|
||||
#include <sys/file.h> /* for FREAD, FWRITE, etc */
|
||||
#define FTRUNC O_TRUNC
|
||||
|
||||
/*
|
||||
* Random stuff
|
||||
*/
|
||||
#define lbolt (gethrtime() >> 23)
|
||||
#define lbolt64 (gethrtime() >> 23)
|
||||
//#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */
|
||||
|
||||
extern void delay(clock_t ticks);
|
||||
|
||||
#define gethrestime_sec() time(NULL)
|
||||
|
||||
#define max_ncpus 64
|
||||
|
||||
#define minclsyspri 60
|
||||
#define maxclsyspri 99
|
||||
|
||||
#define CPU_SEQID (thr_self() & (max_ncpus - 1))
|
||||
|
||||
#define kcred NULL
|
||||
#define CRED() NULL
|
||||
|
||||
extern uint64_t physmem;
|
||||
|
||||
extern int highbit(ulong_t i);
|
||||
extern int random_get_bytes(uint8_t *ptr, size_t len);
|
||||
extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
|
||||
|
||||
extern void kernel_init(int);
|
||||
extern void kernel_fini(void);
|
||||
|
||||
struct spa;
|
||||
extern void nicenum(uint64_t num, char *buf);
|
||||
extern void show_pool_stats(struct spa *);
|
||||
|
||||
typedef struct callb_cpr {
|
||||
kmutex_t *cc_lockp;
|
||||
} callb_cpr_t;
|
||||
|
||||
#define CALLB_CPR_INIT(cp, lockp, func, name) { \
|
||||
(cp)->cc_lockp = lockp; \
|
||||
}
|
||||
|
||||
#define CALLB_CPR_SAFE_BEGIN(cp) { \
|
||||
ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
|
||||
}
|
||||
|
||||
#define CALLB_CPR_SAFE_END(cp, lockp) { \
|
||||
ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
|
||||
}
|
||||
|
||||
#define CALLB_CPR_EXIT(cp) { \
|
||||
ASSERT(MUTEX_HELD((cp)->cc_lockp)); \
|
||||
mutex_exit((cp)->cc_lockp); \
|
||||
}
|
||||
|
||||
#define zone_dataset_visible(x, y) (1)
|
||||
#define INGLOBALZONE(z) (1)
|
||||
|
||||
/*
|
||||
* Hostname information
|
||||
*/
|
||||
extern struct utsname utsname;
|
||||
extern char hw_serial[];
|
||||
extern int ddi_strtoul(const char *str, char **nptr, int base,
|
||||
unsigned long *result);
|
||||
|
||||
/* ZFS Boot Related stuff. */
|
||||
|
||||
struct _buf {
|
||||
intptr_t _fd;
|
||||
};
|
||||
|
||||
struct bootstat {
|
||||
uint64_t st_size;
|
||||
};
|
||||
|
||||
extern struct _buf *kobj_open_file(char *name);
|
||||
extern int kobj_read_file(struct _buf *file, char *buf, unsigned size,
|
||||
unsigned off);
|
||||
extern void kobj_close_file(struct _buf *file);
|
||||
extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
|
||||
/* Random compatibility stuff. */
|
||||
#define lbolt (gethrtime() >> 23)
|
||||
#define lbolt64 (gethrtime() >> 23)
|
||||
|
||||
extern int hz;
|
||||
extern uint64_t physmem;
|
||||
|
||||
#define gethrestime_sec() time(NULL)
|
||||
|
||||
#define pwrite64(d, p, n, o) pwrite(d, p, n, o)
|
||||
#define readdir64(d) readdir(d)
|
||||
#define SIGPENDING(td) (0)
|
||||
#define root_mount_wait() do { } while (0)
|
||||
#define root_mounted() (1)
|
||||
|
||||
struct file {
|
||||
void *dummy;
|
||||
};
|
||||
|
||||
#define FCREAT O_CREAT
|
||||
#define FOFFMAX 0x0
|
||||
|
||||
#define SX_SYSINIT(name, lock, desc)
|
||||
|
||||
#define SYSCTL_DECL(...)
|
||||
#define SYSCTL_NODE(...)
|
||||
#define SYSCTL_INT(...)
|
||||
#define SYSCTL_ULONG(...)
|
||||
#ifdef TUNABLE_INT
|
||||
#undef TUNABLE_INT
|
||||
#undef TUNABLE_ULONG
|
||||
#endif
|
||||
#define TUNABLE_INT(...)
|
||||
#define TUNABLE_ULONG(...)
|
||||
|
||||
/* Errors */
|
||||
|
||||
#ifndef ERESTART
|
||||
#define ERESTART (-1)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_ZFS_CONTEXT_H */
|
@ -1,250 +0,0 @@
|
||||
/*
|
||||
* 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 <sys/zfs_context.h>
|
||||
|
||||
int taskq_now;
|
||||
|
||||
typedef struct task {
|
||||
struct task *task_next;
|
||||
struct task *task_prev;
|
||||
task_func_t *task_func;
|
||||
void *task_arg;
|
||||
} task_t;
|
||||
|
||||
#define TASKQ_ACTIVE 0x00010000
|
||||
|
||||
struct taskq {
|
||||
kmutex_t tq_lock;
|
||||
krwlock_t tq_threadlock;
|
||||
kcondvar_t tq_dispatch_cv;
|
||||
kcondvar_t tq_wait_cv;
|
||||
thread_t *tq_threadlist;
|
||||
int tq_flags;
|
||||
int tq_active;
|
||||
int tq_nthreads;
|
||||
int tq_nalloc;
|
||||
int tq_minalloc;
|
||||
int tq_maxalloc;
|
||||
task_t *tq_freelist;
|
||||
task_t tq_task;
|
||||
};
|
||||
|
||||
static task_t *
|
||||
task_alloc(taskq_t *tq, int tqflags)
|
||||
{
|
||||
task_t *t;
|
||||
|
||||
if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
|
||||
tq->tq_freelist = t->task_next;
|
||||
} else {
|
||||
mutex_exit(&tq->tq_lock);
|
||||
if (tq->tq_nalloc >= tq->tq_maxalloc) {
|
||||
if (!(tqflags & KM_SLEEP)) {
|
||||
mutex_enter(&tq->tq_lock);
|
||||
return (NULL);
|
||||
}
|
||||
/*
|
||||
* We don't want to exceed tq_maxalloc, but we can't
|
||||
* wait for other tasks to complete (and thus free up
|
||||
* task structures) without risking deadlock with
|
||||
* the caller. So, we just delay for one second
|
||||
* to throttle the allocation rate.
|
||||
*/
|
||||
delay(hz);
|
||||
}
|
||||
t = kmem_alloc(sizeof (task_t), tqflags);
|
||||
mutex_enter(&tq->tq_lock);
|
||||
if (t != NULL)
|
||||
tq->tq_nalloc++;
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
|
||||
static void
|
||||
task_free(taskq_t *tq, task_t *t)
|
||||
{
|
||||
if (tq->tq_nalloc <= tq->tq_minalloc) {
|
||||
t->task_next = tq->tq_freelist;
|
||||
tq->tq_freelist = t;
|
||||
} else {
|
||||
tq->tq_nalloc--;
|
||||
mutex_exit(&tq->tq_lock);
|
||||
kmem_free(t, sizeof (task_t));
|
||||
mutex_enter(&tq->tq_lock);
|
||||
}
|
||||
}
|
||||
|
||||
taskqid_t
|
||||
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
|
||||
{
|
||||
task_t *t;
|
||||
|
||||
if (taskq_now) {
|
||||
func(arg);
|
||||
return (1);
|
||||
}
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
ASSERT(tq->tq_flags & TASKQ_ACTIVE);
|
||||
if ((t = task_alloc(tq, tqflags)) == NULL) {
|
||||
mutex_exit(&tq->tq_lock);
|
||||
return (0);
|
||||
}
|
||||
t->task_next = &tq->tq_task;
|
||||
t->task_prev = tq->tq_task.task_prev;
|
||||
t->task_next->task_prev = t;
|
||||
t->task_prev->task_next = t;
|
||||
t->task_func = func;
|
||||
t->task_arg = arg;
|
||||
cv_signal(&tq->tq_dispatch_cv);
|
||||
mutex_exit(&tq->tq_lock);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
taskq_wait(taskq_t *tq)
|
||||
{
|
||||
mutex_enter(&tq->tq_lock);
|
||||
while (tq->tq_task.task_next != &tq->tq_task || tq->tq_active != 0)
|
||||
cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
|
||||
mutex_exit(&tq->tq_lock);
|
||||
}
|
||||
|
||||
static void *
|
||||
taskq_thread(void *arg)
|
||||
{
|
||||
taskq_t *tq = arg;
|
||||
task_t *t;
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
while (tq->tq_flags & TASKQ_ACTIVE) {
|
||||
if ((t = tq->tq_task.task_next) == &tq->tq_task) {
|
||||
if (--tq->tq_active == 0)
|
||||
cv_broadcast(&tq->tq_wait_cv);
|
||||
cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
|
||||
tq->tq_active++;
|
||||
continue;
|
||||
}
|
||||
t->task_prev->task_next = t->task_next;
|
||||
t->task_next->task_prev = t->task_prev;
|
||||
mutex_exit(&tq->tq_lock);
|
||||
|
||||
rw_enter(&tq->tq_threadlock, RW_READER);
|
||||
t->task_func(t->task_arg);
|
||||
rw_exit(&tq->tq_threadlock);
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
task_free(tq, t);
|
||||
}
|
||||
tq->tq_nthreads--;
|
||||
cv_broadcast(&tq->tq_wait_cv);
|
||||
mutex_exit(&tq->tq_lock);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
taskq_t *
|
||||
taskq_create(const char *name, int nthreads, pri_t pri,
|
||||
int minalloc, int maxalloc, uint_t flags)
|
||||
{
|
||||
taskq_t *tq = kmem_zalloc(sizeof (taskq_t), KM_SLEEP);
|
||||
int t;
|
||||
|
||||
rw_init(&tq->tq_threadlock, NULL, RW_DEFAULT, NULL);
|
||||
tq->tq_flags = flags | TASKQ_ACTIVE;
|
||||
tq->tq_active = nthreads;
|
||||
tq->tq_nthreads = nthreads;
|
||||
tq->tq_minalloc = minalloc;
|
||||
tq->tq_maxalloc = maxalloc;
|
||||
tq->tq_task.task_next = &tq->tq_task;
|
||||
tq->tq_task.task_prev = &tq->tq_task;
|
||||
tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
|
||||
|
||||
if (flags & TASKQ_PREPOPULATE) {
|
||||
mutex_enter(&tq->tq_lock);
|
||||
while (minalloc-- > 0)
|
||||
task_free(tq, task_alloc(tq, KM_SLEEP));
|
||||
mutex_exit(&tq->tq_lock);
|
||||
}
|
||||
|
||||
for (t = 0; t < nthreads; t++)
|
||||
(void) thr_create(0, 0, taskq_thread,
|
||||
tq, THR_BOUND, &tq->tq_threadlist[t]);
|
||||
|
||||
return (tq);
|
||||
}
|
||||
|
||||
void
|
||||
taskq_destroy(taskq_t *tq)
|
||||
{
|
||||
int t;
|
||||
int nthreads = tq->tq_nthreads;
|
||||
|
||||
taskq_wait(tq);
|
||||
|
||||
mutex_enter(&tq->tq_lock);
|
||||
|
||||
tq->tq_flags &= ~TASKQ_ACTIVE;
|
||||
cv_broadcast(&tq->tq_dispatch_cv);
|
||||
|
||||
while (tq->tq_nthreads != 0)
|
||||
cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
|
||||
|
||||
tq->tq_minalloc = 0;
|
||||
while (tq->tq_nalloc != 0) {
|
||||
ASSERT(tq->tq_freelist != NULL);
|
||||
task_free(tq, task_alloc(tq, KM_SLEEP));
|
||||
}
|
||||
|
||||
mutex_exit(&tq->tq_lock);
|
||||
|
||||
for (t = 0; t < nthreads; t++)
|
||||
(void) thr_join(tq->tq_threadlist[t], NULL, NULL);
|
||||
|
||||
kmem_free(tq->tq_threadlist, nthreads * sizeof (thread_t));
|
||||
|
||||
rw_destroy(&tq->tq_threadlock);
|
||||
|
||||
kmem_free(tq, sizeof (taskq_t));
|
||||
}
|
||||
|
||||
int
|
||||
taskq_member(taskq_t *tq, void *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (taskq_now)
|
||||
return (1);
|
||||
|
||||
for (i = 0; i < tq->tq_nthreads; i++)
|
||||
if (tq->tq_threadlist[i] == (thread_t)(uintptr_t)t)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/avl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/refcount.h>
|
||||
|
||||
/*
|
||||
* Routines needed by more than one client of libzpool.
|
||||
*/
|
||||
|
||||
void
|
||||
nicenum(uint64_t num, char *buf)
|
||||
{
|
||||
uint64_t n = num;
|
||||
int index = 0;
|
||||
char u;
|
||||
|
||||
while (n >= 1024) {
|
||||
n = (n + (1024 / 2)) / 1024; /* Round up or down */
|
||||
index++;
|
||||
}
|
||||
|
||||
u = " KMGTPE"[index];
|
||||
|
||||
if (index == 0) {
|
||||
(void) sprintf(buf, "%llu", (u_longlong_t)n);
|
||||
} else if (n < 10 && (num & (num - 1)) != 0) {
|
||||
(void) sprintf(buf, "%.2f%c",
|
||||
(double)num / (1ULL << 10 * index), u);
|
||||
} else if (n < 100 && (num & (num - 1)) != 0) {
|
||||
(void) sprintf(buf, "%.1f%c",
|
||||
(double)num / (1ULL << 10 * index), u);
|
||||
} else {
|
||||
(void) sprintf(buf, "%llu%c", (u_longlong_t)n, u);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_vdev_stats(const char *desc, nvlist_t *nv, int indent)
|
||||
{
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
vdev_stat_t *vs;
|
||||
uint64_t sec;
|
||||
char used[6], avail[6];
|
||||
char rops[6], wops[6], rbytes[6], wbytes[6], rerr[6], werr[6], cerr[6];
|
||||
|
||||
if (indent == 0) {
|
||||
(void) printf(" "
|
||||
" capacity operations bandwidth ---- errors ----\n");
|
||||
(void) printf("description "
|
||||
"used avail read write read write read write cksum\n");
|
||||
}
|
||||
|
||||
VERIFY(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
|
||||
(uint64_t **)&vs, &c) == 0);
|
||||
|
||||
sec = MAX(1, vs->vs_timestamp / NANOSEC);
|
||||
|
||||
nicenum(vs->vs_alloc, used);
|
||||
nicenum(vs->vs_space - vs->vs_alloc, avail);
|
||||
nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops);
|
||||
nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops);
|
||||
nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes);
|
||||
nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes);
|
||||
nicenum(vs->vs_read_errors, rerr);
|
||||
nicenum(vs->vs_write_errors, werr);
|
||||
nicenum(vs->vs_checksum_errors, cerr);
|
||||
|
||||
(void) printf("%*s%*s%*s%*s %5s %5s %5s %5s %5s %5s %5s\n",
|
||||
indent, "",
|
||||
indent - 19 - (vs->vs_space ? 0 : 12), desc,
|
||||
vs->vs_space ? 6 : 0, vs->vs_space ? used : "",
|
||||
vs->vs_space ? 6 : 0, vs->vs_space ? avail : "",
|
||||
rops, wops, rbytes, wbytes, rerr, werr, cerr);
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0)
|
||||
return;
|
||||
|
||||
for (c = 0; c < children; c++) {
|
||||
nvlist_t *cnv = child[c];
|
||||
char *cname, *tname;
|
||||
uint64_t np;
|
||||
if (nvlist_lookup_string(cnv, ZPOOL_CONFIG_PATH, &cname) &&
|
||||
nvlist_lookup_string(cnv, ZPOOL_CONFIG_TYPE, &cname))
|
||||
cname = "<unknown>";
|
||||
tname = calloc(1, strlen(cname) + 2);
|
||||
(void) strcpy(tname, cname);
|
||||
if (nvlist_lookup_uint64(cnv, ZPOOL_CONFIG_NPARITY, &np) == 0)
|
||||
tname[strlen(tname)] = '0' + np;
|
||||
show_vdev_stats(tname, cnv, indent + 2);
|
||||
free(tname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
show_pool_stats(spa_t *spa)
|
||||
{
|
||||
nvlist_t *config, *nvroot;
|
||||
char *name;
|
||||
|
||||
spa_config_enter(spa, RW_READER, FTAG);
|
||||
config = spa_config_generate(spa, NULL, -1ULL, B_TRUE);
|
||||
spa_config_exit(spa, FTAG);
|
||||
|
||||
VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
VERIFY(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
|
||||
&name) == 0);
|
||||
|
||||
show_vdev_stats(name, nvroot, 0);
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/atomic.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/kernel.h>
|
||||
|
||||
struct mtx atomic_mtx;
|
||||
MTX_SYSINIT(atomic, &atomic_mtx, "atomic", MTX_DEF);
|
||||
#else
|
||||
#include <pthread.h>
|
||||
|
||||
#define mtx_lock(lock) pthread_mutex_lock(lock)
|
||||
#define mtx_unlock(lock) pthread_mutex_unlock(lock)
|
||||
|
||||
static pthread_mutex_t atomic_mtx;
|
||||
|
||||
static __attribute__((constructor)) void
|
||||
atomic_init(void)
|
||||
{
|
||||
pthread_mutex_init(&atomic_mtx, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __LP64__
|
||||
void
|
||||
atomic_add_64(volatile uint64_t *target, int64_t delta)
|
||||
{
|
||||
|
||||
mtx_lock(&atomic_mtx);
|
||||
*target += delta;
|
||||
mtx_unlock(&atomic_mtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t
|
||||
atomic_add_64_nv(volatile uint64_t *target, int64_t delta)
|
||||
{
|
||||
uint64_t newval;
|
||||
|
||||
mtx_lock(&atomic_mtx);
|
||||
newval = (*target += delta);
|
||||
mtx_unlock(&atomic_mtx);
|
||||
return (newval);
|
||||
}
|
||||
|
||||
#if defined(__sparc64__) || defined(__powerpc__) || defined(__arm__)
|
||||
void
|
||||
atomic_or_8(volatile uint8_t *target, uint8_t value)
|
||||
{
|
||||
mtx_lock(&atomic_mtx);
|
||||
*target |= value;
|
||||
mtx_unlock(&atomic_mtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t
|
||||
atomic_or_8_nv(volatile uint8_t *target, uint8_t value)
|
||||
{
|
||||
uint8_t newval;
|
||||
|
||||
mtx_lock(&atomic_mtx);
|
||||
newval = (*target |= value);
|
||||
mtx_unlock(&atomic_mtx);
|
||||
return (newval);
|
||||
}
|
||||
|
||||
#ifndef __LP64__
|
||||
void *
|
||||
atomic_cas_ptr(volatile void *target, void *cmp, void *newval)
|
||||
{
|
||||
void *oldval, **trg;
|
||||
|
||||
mtx_lock(&atomic_mtx);
|
||||
trg = __DEVOLATILE(void **, target);
|
||||
oldval = *trg;
|
||||
if (oldval == cmp)
|
||||
*trg = newval;
|
||||
mtx_unlock(&atomic_mtx);
|
||||
return (oldval);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __sparc64__
|
||||
uint64_t
|
||||
atomic_cas_64(volatile uint64_t *target, uint64_t cmp, uint64_t newval)
|
||||
{
|
||||
uint64_t oldval;
|
||||
|
||||
mtx_lock(&atomic_mtx);
|
||||
oldval = *target;
|
||||
if (oldval == cmp)
|
||||
*target = newval;
|
||||
mtx_unlock(&atomic_mtx);
|
||||
return (oldval);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
membar_producer(void)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_map.h>
|
||||
|
||||
#ifdef KMEM_DEBUG
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stack.h>
|
||||
#endif
|
||||
|
||||
#ifdef _KERNEL
|
||||
static MALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris");
|
||||
#else
|
||||
#define malloc(size, type, flags) malloc(size)
|
||||
#define free(addr, type) free(addr)
|
||||
#endif
|
||||
|
||||
#ifdef KMEM_DEBUG
|
||||
struct kmem_item {
|
||||
struct stack stack;
|
||||
LIST_ENTRY(kmem_item) next;
|
||||
};
|
||||
static LIST_HEAD(, kmem_item) kmem_items;
|
||||
static struct mtx kmem_items_mtx;
|
||||
MTX_SYSINIT(kmem_items_mtx, &kmem_items_mtx, "kmem_items", MTX_DEF);
|
||||
#endif /* KMEM_DEBUG */
|
||||
|
||||
void *
|
||||
zfs_kmem_alloc(size_t size, int kmflags)
|
||||
{
|
||||
void *p;
|
||||
#ifdef KMEM_DEBUG
|
||||
struct kmem_item *i;
|
||||
|
||||
size += sizeof(struct kmem_item);
|
||||
#endif
|
||||
p = malloc(size, M_SOLARIS, kmflags);
|
||||
#ifndef _KERNEL
|
||||
if (kmflags & KM_SLEEP)
|
||||
assert(p != NULL);
|
||||
#endif
|
||||
#ifdef KMEM_DEBUG
|
||||
if (p != NULL) {
|
||||
i = p;
|
||||
p = (u_char *)p + sizeof(struct kmem_item);
|
||||
stack_save(&i->stack);
|
||||
mtx_lock(&kmem_items_mtx);
|
||||
LIST_INSERT_HEAD(&kmem_items, i, next);
|
||||
mtx_unlock(&kmem_items_mtx);
|
||||
}
|
||||
#endif
|
||||
return (p);
|
||||
}
|
||||
|
||||
void
|
||||
zfs_kmem_free(void *buf, size_t size __unused)
|
||||
{
|
||||
#ifdef KMEM_DEBUG
|
||||
struct kmem_item *i;
|
||||
|
||||
buf = (u_char *)buf - sizeof(struct kmem_item);
|
||||
mtx_lock(&kmem_items_mtx);
|
||||
LIST_FOREACH(i, &kmem_items, next) {
|
||||
if (i == buf)
|
||||
break;
|
||||
}
|
||||
ASSERT(i != NULL);
|
||||
LIST_REMOVE(i, next);
|
||||
mtx_unlock(&kmem_items_mtx);
|
||||
#endif
|
||||
free(buf, M_SOLARIS);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
kmem_size(void)
|
||||
{
|
||||
|
||||
return ((uint64_t)vm_kmem_size);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
kmem_used(void)
|
||||
{
|
||||
|
||||
return ((uint64_t)kmem_map->size);
|
||||
}
|
||||
|
||||
static int
|
||||
kmem_std_constructor(void *mem, int size __unused, void *private, int flags)
|
||||
{
|
||||
struct kmem_cache *cache = private;
|
||||
|
||||
return (cache->kc_constructor(mem, cache->kc_private, flags));
|
||||
}
|
||||
|
||||
static void
|
||||
kmem_std_destructor(void *mem, int size __unused, void *private)
|
||||
{
|
||||
struct kmem_cache *cache = private;
|
||||
|
||||
cache->kc_destructor(mem, cache->kc_private);
|
||||
}
|
||||
|
||||
kmem_cache_t *
|
||||
kmem_cache_create(char *name, size_t bufsize, size_t align,
|
||||
int (*constructor)(void *, void *, int), void (*destructor)(void *, void *),
|
||||
void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags)
|
||||
{
|
||||
kmem_cache_t *cache;
|
||||
|
||||
ASSERT(vmp == NULL);
|
||||
|
||||
cache = kmem_alloc(sizeof(*cache), KM_SLEEP);
|
||||
strlcpy(cache->kc_name, name, sizeof(cache->kc_name));
|
||||
cache->kc_constructor = constructor;
|
||||
cache->kc_destructor = destructor;
|
||||
cache->kc_private = private;
|
||||
#ifdef _KERNEL
|
||||
cache->kc_zone = uma_zcreate(cache->kc_name, bufsize,
|
||||
constructor != NULL ? kmem_std_constructor : NULL,
|
||||
destructor != NULL ? kmem_std_destructor : NULL,
|
||||
NULL, NULL, align > 0 ? align - 1 : 0, cflags);
|
||||
#else
|
||||
cache->kc_size = bufsize;
|
||||
#endif
|
||||
|
||||
return (cache);
|
||||
}
|
||||
|
||||
void
|
||||
kmem_cache_destroy(kmem_cache_t *cache)
|
||||
{
|
||||
uma_zdestroy(cache->kc_zone);
|
||||
kmem_free(cache, sizeof(*cache));
|
||||
}
|
||||
|
||||
void *
|
||||
kmem_cache_alloc(kmem_cache_t *cache, int flags)
|
||||
{
|
||||
#ifdef _KERNEL
|
||||
return (uma_zalloc_arg(cache->kc_zone, cache, flags));
|
||||
#else
|
||||
void *p;
|
||||
|
||||
p = kmem_alloc(cache->kc_size, flags);
|
||||
if (p != NULL) {
|
||||
kmem_std_constructor(p, cache->kc_size, cache->kc_private,
|
||||
flags);
|
||||
}
|
||||
return (p);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
kmem_cache_free(kmem_cache_t *cache, void *buf)
|
||||
{
|
||||
#ifdef _KERNEL
|
||||
uma_zfree_arg(cache->kc_zone, buf, cache);
|
||||
#else
|
||||
kmem_std_destructor(buf, cache->kc_size, cache->kc_private);
|
||||
kmem_free(buf, cache->kc_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern void zone_drain(uma_zone_t zone);
|
||||
void
|
||||
kmem_cache_reap_now(kmem_cache_t *cache)
|
||||
{
|
||||
zone_drain(cache->kc_zone);
|
||||
}
|
||||
|
||||
void
|
||||
kmem_reap(void)
|
||||
{
|
||||
uma_reclaim();
|
||||
}
|
||||
#else
|
||||
void
|
||||
kmem_cache_reap_now(kmem_cache_t *cache __unused)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
kmem_reap(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
kmem_debugging(void)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
void *
|
||||
calloc(size_t n, size_t s)
|
||||
{
|
||||
return (kmem_zalloc(n * s, KM_NOSLEEP));
|
||||
}
|
||||
|
||||
#ifdef KMEM_DEBUG
|
||||
static void
|
||||
kmem_show(void *dummy __unused)
|
||||
{
|
||||
struct kmem_item *i;
|
||||
|
||||
mtx_lock(&kmem_items_mtx);
|
||||
if (LIST_EMPTY(&kmem_items))
|
||||
printf("KMEM_DEBUG: No leaked elements.\n");
|
||||
else {
|
||||
printf("KMEM_DEBUG: Leaked elements:\n\n");
|
||||
LIST_FOREACH(i, &kmem_items, next) {
|
||||
printf("address=%p\n", i);
|
||||
stack_print(&i->stack);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
mtx_unlock(&kmem_items_mtx);
|
||||
}
|
||||
|
||||
SYSUNINIT(sol_kmem, SI_SUB_DRIVERS, SI_ORDER_FIRST, kmem_show, NULL);
|
||||
#endif /* KMEM_DEBUG */
|
@ -1,220 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kthread.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/kobj.h>
|
||||
|
||||
void
|
||||
kobj_free(void *address, size_t size)
|
||||
{
|
||||
|
||||
kmem_free(address, size);
|
||||
}
|
||||
|
||||
void *
|
||||
kobj_alloc(size_t size, int flag)
|
||||
{
|
||||
|
||||
return (kmem_alloc(size, (flag & KM_NOWAIT) ? KM_NOSLEEP : KM_SLEEP));
|
||||
}
|
||||
|
||||
void *
|
||||
kobj_zalloc(size_t size, int flag)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = kobj_alloc(size, flag)) != NULL)
|
||||
bzero(p, size);
|
||||
return (p);
|
||||
}
|
||||
|
||||
static void *
|
||||
kobj_open_file_vnode(const char *file)
|
||||
{
|
||||
struct thread *td = curthread;
|
||||
struct nameidata nd;
|
||||
int error, flags;
|
||||
|
||||
if (td->td_proc->p_fd->fd_rdir == NULL)
|
||||
td->td_proc->p_fd->fd_rdir = rootvnode;
|
||||
if (td->td_proc->p_fd->fd_cdir == NULL)
|
||||
td->td_proc->p_fd->fd_cdir = rootvnode;
|
||||
|
||||
flags = FREAD;
|
||||
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, file, td);
|
||||
error = vn_open_cred(&nd, &flags, 0, curthread->td_ucred, NULL);
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
if (error != 0)
|
||||
return (NULL);
|
||||
/* We just unlock so we hold a reference. */
|
||||
VOP_UNLOCK(nd.ni_vp, 0);
|
||||
return (nd.ni_vp);
|
||||
}
|
||||
|
||||
static void *
|
||||
kobj_open_file_loader(const char *file)
|
||||
{
|
||||
|
||||
return (preload_search_by_name(file));
|
||||
}
|
||||
|
||||
struct _buf *
|
||||
kobj_open_file(const char *file)
|
||||
{
|
||||
struct _buf *out;
|
||||
|
||||
out = kmem_alloc(sizeof(*out), KM_SLEEP);
|
||||
out->mounted = root_mounted();
|
||||
/*
|
||||
* If root is already mounted we read file using file system,
|
||||
* if not, we use loader.
|
||||
*/
|
||||
if (out->mounted)
|
||||
out->ptr = kobj_open_file_vnode(file);
|
||||
else
|
||||
out->ptr = kobj_open_file_loader(file);
|
||||
if (out->ptr == NULL) {
|
||||
kmem_free(out, sizeof(*out));
|
||||
return ((struct _buf *)-1);
|
||||
}
|
||||
return (out);
|
||||
}
|
||||
|
||||
static int
|
||||
kobj_get_filesize_vnode(struct _buf *file, uint64_t *size)
|
||||
{
|
||||
struct vnode *vp = file->ptr;
|
||||
struct thread *td = curthread;
|
||||
struct vattr va;
|
||||
int error;
|
||||
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
error = VOP_GETATTR(vp, &va, td->td_ucred, td);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
if (error == 0)
|
||||
*size = (uint64_t)va.va_size;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
kobj_get_filesize_loader(struct _buf *file, uint64_t *size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = preload_search_info(file->ptr, MODINFO_SIZE);
|
||||
if (ptr == NULL)
|
||||
return (ENOENT);
|
||||
*size = (uint64_t)*(size_t *)ptr;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
kobj_get_filesize(struct _buf *file, uint64_t *size)
|
||||
{
|
||||
|
||||
if (file->mounted)
|
||||
return (kobj_get_filesize_vnode(file, size));
|
||||
else
|
||||
return (kobj_get_filesize_loader(file, size));
|
||||
}
|
||||
|
||||
int
|
||||
kobj_read_file_vnode(struct _buf *file, char *buf, unsigned size, unsigned off)
|
||||
{
|
||||
struct vnode *vp = file->ptr;
|
||||
struct thread *td = curthread;
|
||||
struct uio auio;
|
||||
struct iovec aiov;
|
||||
int error;
|
||||
|
||||
bzero(&aiov, sizeof(aiov));
|
||||
bzero(&auio, sizeof(auio));
|
||||
|
||||
aiov.iov_base = buf;
|
||||
aiov.iov_len = size;
|
||||
|
||||
auio.uio_iov = &aiov;
|
||||
auio.uio_offset = (off_t)off;
|
||||
auio.uio_segflg = UIO_SYSSPACE;
|
||||
auio.uio_rw = UIO_READ;
|
||||
auio.uio_iovcnt = 1;
|
||||
auio.uio_resid = size;
|
||||
auio.uio_td = td;
|
||||
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
error = VOP_READ(vp, &auio, IO_UNIT | IO_SYNC, td->td_ucred);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
return (error != 0 ? -1 : size - auio.uio_resid);
|
||||
}
|
||||
|
||||
int
|
||||
kobj_read_file_loader(struct _buf *file, char *buf, unsigned size, unsigned off)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr = preload_search_info(file->ptr, MODINFO_ADDR);
|
||||
if (ptr == NULL)
|
||||
return (ENOENT);
|
||||
ptr = *(void **)ptr;
|
||||
bcopy(ptr + off, buf, size);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
|
||||
{
|
||||
|
||||
if (file->mounted)
|
||||
return (kobj_read_file_vnode(file, buf, size, off));
|
||||
else
|
||||
return (kobj_read_file_loader(file, buf, size, off));
|
||||
}
|
||||
|
||||
void
|
||||
kobj_close_file(struct _buf *file)
|
||||
{
|
||||
|
||||
if (file->mounted) {
|
||||
struct vnode *vp = file->ptr;
|
||||
struct thread *td = curthread;
|
||||
int flags = FREAD;
|
||||
|
||||
vn_close(vp, flags, td->td_ucred, td);
|
||||
}
|
||||
kmem_free(file, sizeof(*file));
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/kstat.h>
|
||||
|
||||
static MALLOC_DEFINE(M_KSTAT, "kstat_data", "Kernel statistics");
|
||||
|
||||
SYSCTL_NODE(, OID_AUTO, kstat, CTLFLAG_RW, 0, "Kernel statistics");
|
||||
|
||||
kstat_t *
|
||||
kstat_create(char *module, int instance, char *name, char *class, uchar_t type,
|
||||
ulong_t ndata, uchar_t flags)
|
||||
{
|
||||
struct sysctl_oid *root;
|
||||
kstat_t *ksp;
|
||||
|
||||
KASSERT(instance == 0, ("instance=%d", instance));
|
||||
KASSERT(type == KSTAT_TYPE_NAMED, ("type=%hhu", type));
|
||||
KASSERT(flags == KSTAT_FLAG_VIRTUAL, ("flags=%02hhx", flags));
|
||||
|
||||
/*
|
||||
* Allocate the main structure. We don't need to copy module/class/name
|
||||
* stuff in here, because it is only used for sysctl node creation
|
||||
* done in this function.
|
||||
*/
|
||||
ksp = malloc(sizeof(*ksp), M_KSTAT, M_WAITOK);
|
||||
ksp->ks_ndata = ndata;
|
||||
|
||||
/*
|
||||
* Create sysctl tree for those statistics:
|
||||
*
|
||||
* kstat.<module>.<class>.<name>.
|
||||
*/
|
||||
sysctl_ctx_init(&ksp->ks_sysctl_ctx);
|
||||
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
|
||||
SYSCTL_STATIC_CHILDREN(_kstat), OID_AUTO, module, CTLFLAG_RW, 0,
|
||||
"");
|
||||
if (root == NULL) {
|
||||
printf("%s: Cannot create kstat.%s tree!\n", __func__, module);
|
||||
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
|
||||
free(ksp, M_KSTAT);
|
||||
return (NULL);
|
||||
}
|
||||
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root),
|
||||
OID_AUTO, class, CTLFLAG_RW, 0, "");
|
||||
if (root == NULL) {
|
||||
printf("%s: Cannot create kstat.%s.%s tree!\n", __func__,
|
||||
module, class);
|
||||
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
|
||||
free(ksp, M_KSTAT);
|
||||
return (NULL);
|
||||
}
|
||||
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root),
|
||||
OID_AUTO, name, CTLFLAG_RW, 0, "");
|
||||
if (root == NULL) {
|
||||
printf("%s: Cannot create kstat.%s.%s.%s tree!\n", __func__,
|
||||
module, class, name);
|
||||
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
|
||||
free(ksp, M_KSTAT);
|
||||
return (NULL);
|
||||
}
|
||||
ksp->ks_sysctl_root = root;
|
||||
|
||||
return (ksp);
|
||||
}
|
||||
|
||||
static int
|
||||
kstat_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
kstat_named_t *ksent = arg1;
|
||||
uint64_t val;
|
||||
|
||||
val = ksent->value.ui64;
|
||||
return sysctl_handle_quad(oidp, &val, 0, req);
|
||||
}
|
||||
|
||||
void
|
||||
kstat_install(kstat_t *ksp)
|
||||
{
|
||||
kstat_named_t *ksent;
|
||||
u_int i;
|
||||
|
||||
ksent = ksp->ks_data;
|
||||
for (i = 0; i < ksp->ks_ndata; i++, ksent++) {
|
||||
KASSERT(ksent->data_type == KSTAT_DATA_UINT64,
|
||||
("data_type=%d", ksent->data_type));
|
||||
SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
|
||||
SYSCTL_CHILDREN(ksp->ks_sysctl_root), OID_AUTO, ksent->name,
|
||||
CTLTYPE_QUAD | CTLFLAG_RD, ksent, sizeof(*ksent),
|
||||
kstat_sysctl, "QU", "");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kstat_delete(kstat_t *ksp)
|
||||
{
|
||||
|
||||
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
|
||||
free(ksp, M_KSTAT);
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/misc.h>
|
||||
#include <sys/sunddi.h>
|
||||
|
||||
char hw_serial[11] = "0";
|
||||
|
||||
struct opensolaris_utsname utsname = {
|
||||
.nodename = hostname
|
||||
};
|
||||
|
||||
int
|
||||
ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
|
||||
{
|
||||
char *end;
|
||||
|
||||
if (str == hw_serial) {
|
||||
*result = hostid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
*result = strtoul(str, &end, base);
|
||||
if (*result == 0)
|
||||
return (EINVAL);
|
||||
return (0);
|
||||
}
|
@ -1,261 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/policy.h>
|
||||
|
||||
int
|
||||
secpolicy_zfs(struct ucred *cred)
|
||||
{
|
||||
|
||||
return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0));
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_sys_config(struct ucred *cred, int checkonly __unused)
|
||||
{
|
||||
|
||||
return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0));
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_zinject(struct ucred *cred)
|
||||
{
|
||||
|
||||
return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0));
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused)
|
||||
{
|
||||
|
||||
return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* This check is done in kern_link(), so we could just return 0 here.
|
||||
*/
|
||||
extern int hardlink_check_uid;
|
||||
int
|
||||
secpolicy_basic_link(struct ucred *cred)
|
||||
{
|
||||
|
||||
if (!hardlink_check_uid)
|
||||
return (0);
|
||||
return (priv_check_cred(cred, PRIV_VFS_LINK, 0));
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_stky_modify(struct ucred *cred)
|
||||
{
|
||||
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_remove(struct ucred *cred)
|
||||
{
|
||||
|
||||
return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner,
|
||||
int mode)
|
||||
{
|
||||
|
||||
if ((mode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) {
|
||||
return (EACCES);
|
||||
}
|
||||
if ((mode & VWRITE) &&
|
||||
priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) {
|
||||
return (EACCES);
|
||||
}
|
||||
if (mode & VEXEC) {
|
||||
if (vp->v_type == VDIR) {
|
||||
if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) {
|
||||
return (EACCES);
|
||||
}
|
||||
} else {
|
||||
if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) {
|
||||
return (EACCES);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_setdac(struct ucred *cred, uid_t owner)
|
||||
{
|
||||
|
||||
if (owner == cred->cr_uid)
|
||||
return (0);
|
||||
return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
|
||||
const struct vattr *ovap, int flags,
|
||||
int unlocked_access(void *, int, struct ucred *), void *node)
|
||||
{
|
||||
int mask = vap->va_mask;
|
||||
int error;
|
||||
|
||||
if (mask & AT_SIZE) {
|
||||
if (vp->v_type == VDIR)
|
||||
return (EISDIR);
|
||||
error = unlocked_access(node, VWRITE, cred);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
if (mask & AT_MODE) {
|
||||
/*
|
||||
* If not the owner of the file then check privilege
|
||||
* for two things: the privilege to set the mode at all
|
||||
* and, if we're setting setuid, we also need permissions
|
||||
* to add the set-uid bit, if we're not the owner.
|
||||
* In the specific case of creating a set-uid root
|
||||
* file, we need even more permissions.
|
||||
*/
|
||||
error = secpolicy_vnode_setdac(cred, ovap->va_uid);
|
||||
if (error)
|
||||
return (error);
|
||||
error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred);
|
||||
if (error)
|
||||
return (error);
|
||||
} else {
|
||||
vap->va_mode = ovap->va_mode;
|
||||
}
|
||||
if (mask & (AT_UID | AT_GID)) {
|
||||
error = secpolicy_vnode_setdac(cred, ovap->va_uid);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* To change the owner of a file, or change the group of a file to a
|
||||
* group of which we are not a member, the caller must have
|
||||
* privilege.
|
||||
*/
|
||||
if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
|
||||
((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
|
||||
!groupmember(vap->va_gid, cred))) {
|
||||
error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
|
||||
((mask & AT_GID) && vap->va_gid != ovap->va_gid)) {
|
||||
secpolicy_setid_clear(vap, cred);
|
||||
}
|
||||
}
|
||||
if (mask & (AT_ATIME | AT_MTIME)) {
|
||||
/*
|
||||
* From utimes(2):
|
||||
* If times is NULL, ... The caller must be the owner of
|
||||
* the file, have permission to write the file, or be the
|
||||
* super-user.
|
||||
* If times is non-NULL, ... The caller must be the owner of
|
||||
* the file or be the super-user.
|
||||
*/
|
||||
error = secpolicy_vnode_setdac(cred, ovap->va_uid);
|
||||
if (error && (vap->va_vaflags & VA_UTIMES_NULL))
|
||||
error = unlocked_access(node, VWRITE, cred);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_create_gid(struct ucred *cred)
|
||||
{
|
||||
|
||||
return (EPERM);
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_setids_setgids(struct ucred *cred, gid_t gid)
|
||||
{
|
||||
|
||||
if (!groupmember(gid, cred))
|
||||
return (priv_check_cred(cred, PRIV_VFS_SETGID, 0));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_vnode_setid_retain(struct ucred *cred, boolean_t issuidroot __unused)
|
||||
{
|
||||
|
||||
return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0));
|
||||
}
|
||||
|
||||
void
|
||||
secpolicy_setid_clear(struct vattr *vap, struct ucred *cred)
|
||||
{
|
||||
|
||||
if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
|
||||
if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) {
|
||||
vap->va_mask |= AT_MODE;
|
||||
vap->va_mode &= ~(S_ISUID|S_ISGID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
|
||||
const struct vattr *ovap, struct ucred *cred)
|
||||
{
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Privileged processes may set the sticky bit on non-directories,
|
||||
* as well as set the setgid bit on a file with a group that the process
|
||||
* is not a member of. Both of these are allowed in jail(8).
|
||||
*/
|
||||
if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
|
||||
if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
|
||||
return (EFTYPE);
|
||||
}
|
||||
/*
|
||||
* Check for privilege if attempting to set the
|
||||
* group-id bit.
|
||||
*/
|
||||
if ((vap->va_mode & S_ISGID) != 0) {
|
||||
error = secpolicy_vnode_setids_setgids(cred, ovap->va_gid);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
return (0);
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/string.h>
|
||||
|
||||
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
#define IS_ALPHA(c) \
|
||||
(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
|
||||
char *
|
||||
strpbrk(const char *s, const char *b)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
do {
|
||||
for (p = b; *p != '\0' && *p != *s; ++p)
|
||||
;
|
||||
if (*p != '\0')
|
||||
return ((char *)s);
|
||||
} while (*s++);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a string into a valid C identifier by replacing invalid
|
||||
* characters with '_'. Also makes sure the string is nul-terminated
|
||||
* and takes up at most n bytes.
|
||||
*/
|
||||
void
|
||||
strident_canon(char *s, size_t n)
|
||||
{
|
||||
char c;
|
||||
char *end = s + n - 1;
|
||||
|
||||
if ((c = *s) == 0)
|
||||
return;
|
||||
|
||||
if (!IS_ALPHA(c) && c != '_')
|
||||
*s = '_';
|
||||
|
||||
while (s < end && ((c = *(++s)) != 0)) {
|
||||
if (!IS_ALPHA(c) && !IS_DIGIT(c) && c != '_')
|
||||
*s = '_';
|
||||
}
|
||||
*s = 0;
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/cred.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/libkern.h>
|
||||
|
||||
MALLOC_DECLARE(M_MOUNT);
|
||||
|
||||
TAILQ_HEAD(vfsoptlist, vfsopt);
|
||||
struct vfsopt {
|
||||
TAILQ_ENTRY(vfsopt) link;
|
||||
char *name;
|
||||
void *value;
|
||||
int len;
|
||||
};
|
||||
|
||||
void
|
||||
vfs_setmntopt(vfs_t *vfsp, const char *name, const char *arg,
|
||||
int flags __unused)
|
||||
{
|
||||
struct vfsopt *opt;
|
||||
size_t namesize;
|
||||
|
||||
if (vfsp->mnt_opt == NULL) {
|
||||
vfsp->mnt_opt = malloc(sizeof(*vfsp->mnt_opt), M_MOUNT, M_WAITOK);
|
||||
TAILQ_INIT(vfsp->mnt_opt);
|
||||
}
|
||||
|
||||
opt = malloc(sizeof(*opt), M_MOUNT, M_WAITOK);
|
||||
|
||||
namesize = strlen(name) + 1;
|
||||
opt->name = malloc(namesize, M_MOUNT, M_WAITOK);
|
||||
strlcpy(opt->name, name, namesize);
|
||||
|
||||
if (arg == NULL) {
|
||||
opt->value = NULL;
|
||||
opt->len = 0;
|
||||
} else {
|
||||
opt->len = strlen(arg) + 1;
|
||||
opt->value = malloc(opt->len, M_MOUNT, M_WAITOK);
|
||||
bcopy(arg, opt->value, opt->len);
|
||||
}
|
||||
/* TODO: Locking. */
|
||||
TAILQ_INSERT_TAIL(vfsp->mnt_opt, opt, link);
|
||||
}
|
||||
|
||||
void
|
||||
vfs_clearmntopt(vfs_t *vfsp, const char *name)
|
||||
{
|
||||
struct vfsopt *opt;
|
||||
|
||||
if (vfsp->mnt_opt == NULL)
|
||||
return;
|
||||
/* TODO: Locking. */
|
||||
TAILQ_FOREACH(opt, vfsp->mnt_opt, link) {
|
||||
if (strcmp(opt->name, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (opt != NULL) {
|
||||
TAILQ_REMOVE(vfsp->mnt_opt, opt, link);
|
||||
free(opt->name, M_MOUNT);
|
||||
if (opt->value != NULL)
|
||||
free(opt->value, M_MOUNT);
|
||||
free(opt, M_MOUNT);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
vfs_optionisset(const vfs_t *vfsp, const char *opt, char **argp)
|
||||
{
|
||||
struct vfsoptlist *opts = vfsp->mnt_opt;
|
||||
int error;
|
||||
|
||||
if (opts == NULL)
|
||||
return (0);
|
||||
error = vfs_getopt(opts, opt, (void **)argp, NULL);
|
||||
return (error != 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
int
|
||||
traverse(vnode_t **cvpp, int lktype)
|
||||
{
|
||||
kthread_t *td = curthread;
|
||||
vnode_t *cvp;
|
||||
vnode_t *tvp;
|
||||
vfs_t *vfsp;
|
||||
int error;
|
||||
|
||||
cvp = *cvpp;
|
||||
tvp = NULL;
|
||||
|
||||
/*
|
||||
* If this vnode is mounted on, then we transparently indirect
|
||||
* to the vnode which is the root of the mounted file system.
|
||||
* Before we do this we must check that an unmount is not in
|
||||
* progress on this vnode.
|
||||
*/
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Reached the end of the mount chain?
|
||||
*/
|
||||
vfsp = vn_mountedvfs(cvp);
|
||||
if (vfsp == NULL)
|
||||
break;
|
||||
/*
|
||||
* tvp is NULL for *cvpp vnode, which we can't unlock.
|
||||
*/
|
||||
if (tvp != NULL)
|
||||
vput(cvp);
|
||||
else
|
||||
vrele(cvp);
|
||||
|
||||
/*
|
||||
* The read lock must be held across the call to VFS_ROOT() to
|
||||
* prevent a concurrent unmount from destroying the vfs.
|
||||
*/
|
||||
error = VFS_ROOT(vfsp, lktype, &tvp, td);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
cvp = tvp;
|
||||
}
|
||||
|
||||
*cvpp = cvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
domount(kthread_t *td, vnode_t *vp, const char *fstype, char *fspath,
|
||||
char *fspec, int fsflags)
|
||||
{
|
||||
struct mount *mp;
|
||||
struct vfsconf *vfsp;
|
||||
struct ucred *newcr, *oldcr;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Be ultra-paranoid about making sure the type and fspath
|
||||
* variables will fit in our mp buffers, including the
|
||||
* terminating NUL.
|
||||
*/
|
||||
if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN)
|
||||
return (ENAMETOOLONG);
|
||||
|
||||
vfsp = vfs_byname_kld(fstype, td, &error);
|
||||
if (vfsp == NULL)
|
||||
return (ENODEV);
|
||||
|
||||
if (vp->v_type != VDIR)
|
||||
return (ENOTDIR);
|
||||
VI_LOCK(vp);
|
||||
if ((vp->v_iflag & VI_MOUNT) != 0 ||
|
||||
vp->v_mountedhere != NULL) {
|
||||
VI_UNLOCK(vp);
|
||||
return (EBUSY);
|
||||
}
|
||||
vp->v_iflag |= VI_MOUNT;
|
||||
VI_UNLOCK(vp);
|
||||
|
||||
/*
|
||||
* Allocate and initialize the filesystem.
|
||||
*/
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
mp = vfs_mount_alloc(vp, vfsp, fspath, td);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
|
||||
mp->mnt_optnew = NULL;
|
||||
vfs_setmntopt(mp, "from", fspec, 0);
|
||||
mp->mnt_optnew = mp->mnt_opt;
|
||||
mp->mnt_opt = NULL;
|
||||
|
||||
/*
|
||||
* Set the mount level flags.
|
||||
* crdup() can sleep, so do it before acquiring a mutex.
|
||||
*/
|
||||
newcr = crdup(kcred);
|
||||
MNT_ILOCK(mp);
|
||||
if (fsflags & MNT_RDONLY)
|
||||
mp->mnt_flag |= MNT_RDONLY;
|
||||
mp->mnt_flag &=~ MNT_UPDATEMASK;
|
||||
mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS);
|
||||
/*
|
||||
* Unprivileged user can trigger mounting a snapshot, but we don't want
|
||||
* him to unmount it, so we switch to privileged credentials.
|
||||
*/
|
||||
oldcr = mp->mnt_cred;
|
||||
mp->mnt_cred = newcr;
|
||||
mp->mnt_stat.f_owner = mp->mnt_cred->cr_uid;
|
||||
MNT_IUNLOCK(mp);
|
||||
crfree(oldcr);
|
||||
/*
|
||||
* Mount the filesystem.
|
||||
* XXX The final recipients of VFS_MOUNT just overwrite the ndp they
|
||||
* get. No freeing of cn_pnbuf.
|
||||
*/
|
||||
error = VFS_MOUNT(mp, td);
|
||||
|
||||
if (!error) {
|
||||
if (mp->mnt_opt != NULL)
|
||||
vfs_freeopts(mp->mnt_opt);
|
||||
mp->mnt_opt = mp->mnt_optnew;
|
||||
(void)VFS_STATFS(mp, &mp->mnt_stat, td);
|
||||
}
|
||||
/*
|
||||
* Prevent external consumers of mount options from reading
|
||||
* mnt_optnew.
|
||||
*/
|
||||
mp->mnt_optnew = NULL;
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||
/*
|
||||
* Put the new filesystem on the mount list after root.
|
||||
*/
|
||||
#ifdef FREEBSD_NAMECACHE
|
||||
cache_purge(vp);
|
||||
#endif
|
||||
if (!error) {
|
||||
vnode_t *mvp;
|
||||
|
||||
VI_LOCK(vp);
|
||||
vp->v_iflag &= ~VI_MOUNT;
|
||||
VI_UNLOCK(vp);
|
||||
vp->v_mountedhere = mp;
|
||||
mtx_lock(&mountlist_mtx);
|
||||
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
|
||||
mtx_unlock(&mountlist_mtx);
|
||||
vfs_event_signal(NULL, VQ_MOUNT, 0);
|
||||
if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp, td))
|
||||
panic("mount: lost mount");
|
||||
mountcheckdirs(vp, mvp);
|
||||
vput(mvp);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
if ((mp->mnt_flag & MNT_RDONLY) == 0)
|
||||
error = vfs_allocate_syncvnode(mp);
|
||||
vfs_unbusy(mp, td);
|
||||
if (error)
|
||||
vrele(vp);
|
||||
else
|
||||
vfs_mountedfrom(mp, fspec);
|
||||
} else {
|
||||
VI_LOCK(vp);
|
||||
vp->v_iflag &= ~VI_MOUNT;
|
||||
VI_UNLOCK(vp);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
vfs_unbusy(mp, td);
|
||||
vfs_mount_destroy(mp);
|
||||
}
|
||||
return (error);
|
||||
}
|
@ -1,237 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/zone.h>
|
||||
|
||||
static MALLOC_DEFINE(M_ZONES, "zones_data", "Zones data");
|
||||
|
||||
/*
|
||||
* Structure to record list of ZFS datasets exported to a zone.
|
||||
*/
|
||||
typedef struct zone_dataset {
|
||||
LIST_ENTRY(zone_dataset) zd_next;
|
||||
char zd_dataset[0];
|
||||
} zone_dataset_t;
|
||||
|
||||
LIST_HEAD(zone_dataset_head, zone_dataset);
|
||||
|
||||
static struct prison_service *zone_prison_service = NULL;
|
||||
|
||||
int
|
||||
zone_dataset_attach(struct ucred *cred, const char *dataset, int jailid)
|
||||
{
|
||||
struct zone_dataset_head *head;
|
||||
zone_dataset_t *zd, *zd2;
|
||||
struct prison *pr;
|
||||
int error;
|
||||
|
||||
if ((error = priv_check_cred(cred, PRIV_ZFS_JAIL, 0)) != 0)
|
||||
return (error);
|
||||
|
||||
/* Allocate memory before we grab prison's mutex. */
|
||||
zd = malloc(sizeof(*zd) + strlen(dataset) + 1, M_ZONES, M_WAITOK);
|
||||
|
||||
sx_slock(&allprison_lock);
|
||||
pr = prison_find(jailid); /* Locks &pr->pr_mtx. */
|
||||
sx_sunlock(&allprison_lock);
|
||||
if (pr == NULL) {
|
||||
free(zd, M_ZONES);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
head = prison_service_data_get(zone_prison_service, pr);
|
||||
LIST_FOREACH(zd2, head, zd_next) {
|
||||
if (strcmp(dataset, zd2->zd_dataset) == 0) {
|
||||
free(zd, M_ZONES);
|
||||
error = EEXIST;
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
strcpy(zd->zd_dataset, dataset);
|
||||
LIST_INSERT_HEAD(head, zd, zd_next);
|
||||
failure:
|
||||
mtx_unlock(&pr->pr_mtx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zone_dataset_detach(struct ucred *cred, const char *dataset, int jailid)
|
||||
{
|
||||
struct zone_dataset_head *head;
|
||||
zone_dataset_t *zd;
|
||||
struct prison *pr;
|
||||
int error;
|
||||
|
||||
if ((error = priv_check_cred(cred, PRIV_ZFS_JAIL, 0)) != 0)
|
||||
return (error);
|
||||
|
||||
sx_slock(&allprison_lock);
|
||||
pr = prison_find(jailid);
|
||||
sx_sunlock(&allprison_lock);
|
||||
if (pr == NULL)
|
||||
return (ENOENT);
|
||||
head = prison_service_data_get(zone_prison_service, pr);
|
||||
LIST_FOREACH(zd, head, zd_next) {
|
||||
if (strcmp(dataset, zd->zd_dataset) == 0) {
|
||||
LIST_REMOVE(zd, zd_next);
|
||||
free(zd, M_ZONES);
|
||||
goto success;
|
||||
}
|
||||
}
|
||||
error = ENOENT;
|
||||
success:
|
||||
mtx_unlock(&pr->pr_mtx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the named dataset is visible in the current zone.
|
||||
* The 'write' parameter is set to 1 if the dataset is also writable.
|
||||
*/
|
||||
int
|
||||
zone_dataset_visible(const char *dataset, int *write)
|
||||
{
|
||||
struct zone_dataset_head *head;
|
||||
zone_dataset_t *zd;
|
||||
struct prison *pr;
|
||||
size_t len;
|
||||
int ret = 0;
|
||||
|
||||
if (dataset[0] == '\0')
|
||||
return (0);
|
||||
if (INGLOBALZONE(curproc)) {
|
||||
if (write != NULL)
|
||||
*write = 1;
|
||||
return (1);
|
||||
}
|
||||
pr = curthread->td_ucred->cr_prison;
|
||||
mtx_lock(&pr->pr_mtx);
|
||||
head = prison_service_data_get(zone_prison_service, pr);
|
||||
|
||||
/*
|
||||
* Walk the list once, looking for datasets which match exactly, or
|
||||
* specify a dataset underneath an exported dataset. If found, return
|
||||
* true and note that it is writable.
|
||||
*/
|
||||
LIST_FOREACH(zd, head, zd_next) {
|
||||
len = strlen(zd->zd_dataset);
|
||||
if (strlen(dataset) >= len &&
|
||||
bcmp(dataset, zd->zd_dataset, len) == 0 &&
|
||||
(dataset[len] == '\0' || dataset[len] == '/' ||
|
||||
dataset[len] == '@')) {
|
||||
if (write)
|
||||
*write = 1;
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the list a second time, searching for datasets which are parents
|
||||
* of exported datasets. These should be visible, but read-only.
|
||||
*
|
||||
* Note that we also have to support forms such as 'pool/dataset/', with
|
||||
* a trailing slash.
|
||||
*/
|
||||
LIST_FOREACH(zd, head, zd_next) {
|
||||
len = strlen(dataset);
|
||||
if (dataset[len - 1] == '/')
|
||||
len--; /* Ignore trailing slash */
|
||||
if (len < strlen(zd->zd_dataset) &&
|
||||
bcmp(dataset, zd->zd_dataset, len) == 0 &&
|
||||
zd->zd_dataset[len] == '/') {
|
||||
if (write)
|
||||
*write = 0;
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
end:
|
||||
mtx_unlock(&pr->pr_mtx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
zone_create(struct prison_service *psrv, struct prison *pr)
|
||||
{
|
||||
struct zone_dataset_head *head;
|
||||
|
||||
head = malloc(sizeof(*head), M_ZONES, M_WAITOK);
|
||||
LIST_INIT(head);
|
||||
mtx_lock(&pr->pr_mtx);
|
||||
prison_service_data_set(psrv, pr, head);
|
||||
mtx_unlock(&pr->pr_mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
zone_destroy(struct prison_service *psrv, struct prison *pr)
|
||||
{
|
||||
struct zone_dataset_head *head;
|
||||
zone_dataset_t *zd;
|
||||
|
||||
mtx_lock(&pr->pr_mtx);
|
||||
head = prison_service_data_del(psrv, pr);
|
||||
mtx_unlock(&pr->pr_mtx);
|
||||
while ((zd = LIST_FIRST(head)) != NULL) {
|
||||
LIST_REMOVE(zd, zd_next);
|
||||
free(zd, M_ZONES);
|
||||
}
|
||||
free(head, M_ZONES);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
zone_sysinit(void *arg __unused)
|
||||
{
|
||||
|
||||
zone_prison_service = prison_service_register("zfs", zone_create,
|
||||
zone_destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
zone_sysuninit(void *arg __unused)
|
||||
{
|
||||
|
||||
prison_service_deregister(zone_prison_service);
|
||||
}
|
||||
|
||||
SYSINIT(zone_sysinit, SI_SUB_DRIVERS, SI_ORDER_ANY, zone_sysinit, NULL);
|
||||
SYSUNINIT(zone_sysuninit, SI_SUB_DRIVERS, SI_ORDER_ANY, zone_sysuninit, NULL);
|
@ -1,44 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_MACHINE_ENDIAN_H_
|
||||
#define _OPENSOLARIS_MACHINE_ENDIAN_H_
|
||||
|
||||
#include_next <machine/endian.h>
|
||||
|
||||
/*
|
||||
* Solaris defines _LITTLE_ENDIAN or _BIG_ENDIAN, but never both and decides
|
||||
* which architecture it is based on which thing is defined.
|
||||
*/
|
||||
#if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
#undef _BIG_ENDIAN
|
||||
#else
|
||||
#undef _LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif /* !_OPENSOLARIS_MACHINE_ENDIAN_H_ */
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
/*
|
||||
* Portions of this source code were derived from Berkeley 4.3 BSD
|
||||
* under license from the Regents of the University of California.
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_RPC_XDR_H_
|
||||
#define _OPENSOLARIS_RPC_XDR_H_
|
||||
|
||||
#include_next <rpc/xdr.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include_next <rpc/xdr.h>
|
||||
|
||||
/*
|
||||
* Strangely, my glibc version (2.3.6) doesn't have xdr_control(), so
|
||||
* we have to hack it in here (source taken from OpenSolaris).
|
||||
* By the way, it is assumed the xdrmem implementation is used.
|
||||
*/
|
||||
|
||||
#undef xdr_control
|
||||
#define xdr_control(a,b,c) xdrmem_control(a,b,c)
|
||||
|
||||
/*
|
||||
* These are the request arguments to XDR_CONTROL.
|
||||
*
|
||||
* XDR_PEEK - returns the contents of the next XDR unit on the XDR stream.
|
||||
* XDR_SKIPBYTES - skips the next N bytes in the XDR stream.
|
||||
* XDR_RDMAGET - for xdr implementation over RDMA, gets private flags from
|
||||
* the XDR stream being moved over RDMA
|
||||
* XDR_RDMANOCHUNK - for xdr implementaion over RDMA, sets private flags in
|
||||
* the XDR stream moving over RDMA.
|
||||
*/
|
||||
#define XDR_PEEK 2
|
||||
#define XDR_SKIPBYTES 3
|
||||
#define XDR_RDMAGET 4
|
||||
#define XDR_RDMASET 5
|
||||
|
||||
/* FIXME: probably doesn't work */
|
||||
static __inline bool_t
|
||||
xdrmem_control(XDR *xdrs, int request, void *info)
|
||||
{
|
||||
xdr_bytesrec *xptr;
|
||||
int32_t *int32p;
|
||||
int len;
|
||||
|
||||
switch (request) {
|
||||
|
||||
case XDR_GET_BYTES_AVAIL:
|
||||
xptr = (xdr_bytesrec *)info;
|
||||
xptr->xc_is_last_record = TRUE;
|
||||
xptr->xc_num_avail = xdrs->x_handy;
|
||||
return (TRUE);
|
||||
|
||||
case XDR_PEEK:
|
||||
/*
|
||||
* Return the next 4 byte unit in the XDR stream.
|
||||
*/
|
||||
if (xdrs->x_handy < sizeof (int32_t))
|
||||
return (FALSE);
|
||||
int32p = (int32_t *)info;
|
||||
*int32p = (int32_t)ntohl((uint32_t)
|
||||
(*((int32_t *)(xdrs->x_private))));
|
||||
return (TRUE);
|
||||
|
||||
case XDR_SKIPBYTES:
|
||||
/*
|
||||
* Skip the next N bytes in the XDR stream.
|
||||
*/
|
||||
int32p = (int32_t *)info;
|
||||
len = RNDUP((int)(*int32p));
|
||||
if ((xdrs->x_handy -= len) < 0)
|
||||
return (FALSE);
|
||||
xdrs->x_private += len;
|
||||
return (TRUE);
|
||||
|
||||
}
|
||||
return (FALSE);
|
||||
}
|
||||
#endif /* !_KERNEL */
|
||||
|
||||
#endif /* !_OPENSOLARIS_RPC_XDR_H_ */
|
@ -1,241 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_ACL_H_
|
||||
#define _OPENSOLARIS_SYS_ACL_H_
|
||||
|
||||
#include_next <sys/acl.h>
|
||||
|
||||
#define MAX_ACL_ENTRIES (1024) /* max entries of each type */
|
||||
|
||||
typedef struct acl_entry aclent_t;
|
||||
#define a_type ae_tag
|
||||
#define a_id ae_id
|
||||
#define a_perm ae_perm
|
||||
|
||||
typedef struct ace {
|
||||
uid_t a_who; /* uid or gid */
|
||||
uint32_t a_access_mask; /* read,write,... */
|
||||
uint16_t a_flags; /* see below */
|
||||
uint16_t a_type; /* allow or deny */
|
||||
} ace_t;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* The following are Defined types for an aclent_t.
|
||||
*/
|
||||
#define USER_OBJ (0x01) /* object owner */
|
||||
#define USER (0x02) /* additional users */
|
||||
#define GROUP_OBJ (0x04) /* owning group of the object */
|
||||
#define GROUP (0x08) /* additional groups */
|
||||
#define CLASS_OBJ (0x10) /* file group class and mask entry */
|
||||
#define OTHER_OBJ (0x20) /* other entry for the object */
|
||||
#define ACL_DEFAULT (0x1000) /* default flag */
|
||||
/* default object owner */
|
||||
#define DEF_USER_OBJ (ACL_DEFAULT | USER_OBJ)
|
||||
/* defalut additional users */
|
||||
#define DEF_USER (ACL_DEFAULT | USER)
|
||||
/* default owning group */
|
||||
#define DEF_GROUP_OBJ (ACL_DEFAULT | GROUP_OBJ)
|
||||
/* default additional groups */
|
||||
#define DEF_GROUP (ACL_DEFAULT | GROUP)
|
||||
/* default mask entry */
|
||||
#define DEF_CLASS_OBJ (ACL_DEFAULT | CLASS_OBJ)
|
||||
/* default other entry */
|
||||
#define DEF_OTHER_OBJ (ACL_DEFAULT | OTHER_OBJ)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following are defined for ace_t.
|
||||
*/
|
||||
#define ACE_READ_DATA 0x00000001
|
||||
#define ACE_LIST_DIRECTORY 0x00000001
|
||||
#define ACE_WRITE_DATA 0x00000002
|
||||
#define ACE_ADD_FILE 0x00000002
|
||||
#define ACE_APPEND_DATA 0x00000004
|
||||
#define ACE_ADD_SUBDIRECTORY 0x00000004
|
||||
#define ACE_READ_NAMED_ATTRS 0x00000008
|
||||
#define ACE_WRITE_NAMED_ATTRS 0x00000010
|
||||
#define ACE_EXECUTE 0x00000020
|
||||
#define ACE_DELETE_CHILD 0x00000040
|
||||
#define ACE_READ_ATTRIBUTES 0x00000080
|
||||
#define ACE_WRITE_ATTRIBUTES 0x00000100
|
||||
#define ACE_DELETE 0x00010000
|
||||
#define ACE_READ_ACL 0x00020000
|
||||
#define ACE_WRITE_ACL 0x00040000
|
||||
#define ACE_WRITE_OWNER 0x00080000
|
||||
#define ACE_SYNCHRONIZE 0x00100000
|
||||
|
||||
#define ACE_FILE_INHERIT_ACE 0x0001
|
||||
#define ACE_DIRECTORY_INHERIT_ACE 0x0002
|
||||
#define ACE_NO_PROPAGATE_INHERIT_ACE 0x0004
|
||||
#define ACE_INHERIT_ONLY_ACE 0x0008
|
||||
#define ACE_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010
|
||||
#define ACE_FAILED_ACCESS_ACE_FLAG 0x0020
|
||||
#define ACE_IDENTIFIER_GROUP 0x0040
|
||||
#define ACE_OWNER 0x1000
|
||||
#define ACE_GROUP 0x2000
|
||||
#define ACE_EVERYONE 0x4000
|
||||
|
||||
#define ACE_ACCESS_ALLOWED_ACE_TYPE 0x0000
|
||||
#define ACE_ACCESS_DENIED_ACE_TYPE 0x0001
|
||||
#define ACE_SYSTEM_AUDIT_ACE_TYPE 0x0002
|
||||
#define ACE_SYSTEM_ALARM_ACE_TYPE 0x0003
|
||||
|
||||
#define ACE_ALL_PERMS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
|
||||
ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \
|
||||
ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \
|
||||
ACE_WRITE_ATTRIBUTES|ACE_DELETE|ACE_READ_ACL|ACE_WRITE_ACL| \
|
||||
ACE_WRITE_OWNER|ACE_SYNCHRONIZE)
|
||||
|
||||
/*
|
||||
* The following flags are supported by both NFSv4 ACLs and ace_t.
|
||||
*/
|
||||
#define ACE_NFSV4_SUP_FLAGS (ACE_FILE_INHERIT_ACE | \
|
||||
ACE_DIRECTORY_INHERIT_ACE | \
|
||||
ACE_NO_PROPAGATE_INHERIT_ACE | \
|
||||
ACE_INHERIT_ONLY_ACE | \
|
||||
ACE_IDENTIFIER_GROUP)
|
||||
|
||||
#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE|ACE_IDENTIFIER_GROUP)
|
||||
|
||||
#if 0
|
||||
/* cmd args to acl(2) for aclent_t */
|
||||
#define GETACL 1
|
||||
#define SETACL 2
|
||||
#define GETACLCNT 3
|
||||
#endif
|
||||
|
||||
/* cmd's to manipulate ace acls. */
|
||||
#define ACE_GETACL 4
|
||||
#define ACE_SETACL 5
|
||||
#define ACE_GETACLCNT 6
|
||||
|
||||
#if 0
|
||||
/* minimal acl entries from GETACLCNT */
|
||||
#define MIN_ACL_ENTRIES 4
|
||||
|
||||
#if !defined(_KERNEL)
|
||||
|
||||
/* acl check errors */
|
||||
#define GRP_ERROR 1
|
||||
#define USER_ERROR 2
|
||||
#define OTHER_ERROR 3
|
||||
#define CLASS_ERROR 4
|
||||
#define DUPLICATE_ERROR 5
|
||||
#define MISS_ERROR 6
|
||||
#define MEM_ERROR 7
|
||||
#define ENTRY_ERROR 8
|
||||
|
||||
|
||||
/*
|
||||
* similar to ufs_acl.h: changed to char type for user commands (tar, cpio)
|
||||
* Attribute types
|
||||
*/
|
||||
#define UFSD_FREE ('0') /* Free entry */
|
||||
#define UFSD_ACL ('1') /* Access Control Lists */
|
||||
#define UFSD_DFACL ('2') /* reserved for future use */
|
||||
#define ACE_ACL ('3') /* ace_t style acls */
|
||||
|
||||
/*
|
||||
* flag to [f]acl_get()
|
||||
* controls whether a trivial acl should be returned.
|
||||
*/
|
||||
#define ACL_NO_TRIVIAL 0x2
|
||||
|
||||
|
||||
/*
|
||||
* Flags to control acl_totext()
|
||||
*/
|
||||
|
||||
#define ACL_APPEND_ID 0x1 /* append uid/gid to user/group entries */
|
||||
#define ACL_COMPACT_FMT 0x2 /* build ACL in ls -V format */
|
||||
#define ACL_NORESOLVE 0x4 /* don't do name service lookups */
|
||||
|
||||
/*
|
||||
* Legacy aclcheck errors for aclent_t ACLs
|
||||
*/
|
||||
#define EACL_GRP_ERROR GRP_ERROR
|
||||
#define EACL_USER_ERROR USER_ERROR
|
||||
#define EACL_OTHER_ERROR OTHER_ERROR
|
||||
#define EACL_CLASS_ERROR CLASS_ERROR
|
||||
#define EACL_DUPLICATE_ERROR DUPLICATE_ERROR
|
||||
#define EACL_MISS_ERROR MISS_ERROR
|
||||
#define EACL_MEM_ERROR MEM_ERROR
|
||||
#define EACL_ENTRY_ERROR ENTRY_ERROR
|
||||
|
||||
#define EACL_INHERIT_ERROR 9 /* invalid inherit flags */
|
||||
#define EACL_FLAGS_ERROR 10 /* unknown flag value */
|
||||
#define EACL_PERM_MASK_ERROR 11 /* unknown permission */
|
||||
#define EACL_COUNT_ERROR 12 /* invalid acl count */
|
||||
|
||||
#define EACL_INVALID_SLOT 13 /* invalid acl slot */
|
||||
#define EACL_NO_ACL_ENTRY 14 /* Entry doesn't exist */
|
||||
#define EACL_DIFF_TYPE 15 /* acls aren't same type */
|
||||
|
||||
#define EACL_INVALID_USER_GROUP 16 /* need user/group name */
|
||||
#define EACL_INVALID_STR 17 /* invalid acl string */
|
||||
#define EACL_FIELD_NOT_BLANK 18 /* can't have blank field */
|
||||
#define EACL_INVALID_ACCESS_TYPE 19 /* invalid access type */
|
||||
#define EACL_UNKNOWN_DATA 20 /* Unrecognized data in ACL */
|
||||
#define EACL_MISSING_FIELDS 21 /* missing fields in acl */
|
||||
|
||||
#define EACL_INHERIT_NOTDIR 22 /* Need dir for inheritance */
|
||||
|
||||
extern int aclcheck(aclent_t *, int, int *);
|
||||
extern int acltomode(aclent_t *, int, mode_t *);
|
||||
extern int aclfrommode(aclent_t *, int, mode_t *);
|
||||
extern int aclsort(int, int, aclent_t *);
|
||||
extern char *acltotext(aclent_t *, int);
|
||||
extern aclent_t *aclfromtext(char *, int *);
|
||||
extern void acl_free(acl_t *);
|
||||
extern int acl_get(const char *, int, acl_t **);
|
||||
extern int facl_get(int, int, acl_t **);
|
||||
extern int acl_set(const char *, acl_t *acl);
|
||||
extern int facl_set(int, acl_t *acl);
|
||||
extern int acl_strip(const char *, uid_t, gid_t, mode_t);
|
||||
extern int acl_trivial(const char *);
|
||||
extern char *acl_totext(acl_t *, int);
|
||||
extern int acl_fromtext(const char *, acl_t **);
|
||||
extern int acl_check(acl_t *, int);
|
||||
|
||||
#else /* !defined(_KERNEL) */
|
||||
|
||||
extern void ksort(caddr_t, int, int, int (*)(void *, void *));
|
||||
extern int cmp2acls(void *, void *);
|
||||
|
||||
#endif /* !defined(_KERNEL) */
|
||||
|
||||
#if defined(__STDC__)
|
||||
extern int acl(const char *path, int cmd, int cnt, void *buf);
|
||||
extern int facl(int fd, int cmd, int cnt, void *buf);
|
||||
#else /* !__STDC__ */
|
||||
extern int acl();
|
||||
extern int facl();
|
||||
#endif /* defined(__STDC__) */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _OPENSOLARIS_SYS_ACL_H */
|
@ -1,114 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_ATOMIC_H_
|
||||
#define _OPENSOLARIS_SYS_ATOMIC_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/atomic.h>
|
||||
|
||||
#ifndef __LP64__
|
||||
extern void atomic_add_64(volatile uint64_t *target, int64_t delta);
|
||||
extern void *atomic_cas_ptr(volatile void *target, void *cmp, void *newval);
|
||||
#endif
|
||||
#ifndef __sparc64__
|
||||
extern uint64_t atomic_cas_64(volatile uint64_t *target, uint64_t cmp,
|
||||
uint64_t newval);
|
||||
#endif
|
||||
extern uint64_t atomic_add_64_nv(volatile uint64_t *target, int64_t delta);
|
||||
extern uint8_t atomic_or_8_nv(volatile uint8_t *target, uint8_t value);
|
||||
extern void membar_producer(void);
|
||||
|
||||
#if defined(__sparc64__) || defined(__powerpc__) || defined(__arm__)
|
||||
extern void atomic_or_8(volatile uint8_t *target, uint8_t value);
|
||||
#else
|
||||
static __inline void
|
||||
atomic_or_8(volatile uint8_t *target, uint8_t value)
|
||||
{
|
||||
atomic_set_8(target, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
static __inline uint32_t
|
||||
atomic_add_32_nv(volatile uint32_t *target, int32_t delta)
|
||||
{
|
||||
return (atomic_fetchadd_32(target, delta) + delta);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
atomic_add_int_nv(volatile u_int *target, int delta)
|
||||
{
|
||||
return (atomic_add_32_nv(target, delta));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
atomic_dec_32(volatile uint32_t *target)
|
||||
{
|
||||
atomic_subtract_32(target, 1);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
atomic_dec_32_nv(volatile uint32_t *target)
|
||||
{
|
||||
return (atomic_fetchadd_32(target, -1) - 1);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
atomic_inc_32(volatile uint32_t *target)
|
||||
{
|
||||
atomic_add_32(target, 1);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
atomic_inc_32_nv(volatile uint32_t *target)
|
||||
{
|
||||
return (atomic_add_32_nv(target, 1));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
atomic_inc_64(volatile uint64_t *target)
|
||||
{
|
||||
atomic_add_64(target, 1);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
atomic_inc_64_nv(volatile uint64_t *target)
|
||||
{
|
||||
return (atomic_add_64_nv(target, 1));
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
static __inline void *
|
||||
atomic_cas_ptr(volatile void *target, void *cmp, void *newval)
|
||||
{
|
||||
return ((void *)atomic_cas_64((volatile uint64_t *)target, (uint64_t)cmp,
|
||||
(uint64_t)newval));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_OPENSOLARIS_SYS_ATOMIC_H_ */
|
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* 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 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_SYS_BITMAP_H
|
||||
#define _COMPAT_OPENSOLARIS_SYS_BITMAP_H
|
||||
|
||||
#include <sys/atomic.h>
|
||||
|
||||
/*
|
||||
* Operations on bitmaps of arbitrary size
|
||||
* A bitmap is a vector of 1 or more ulong_t's.
|
||||
* The user of the package is responsible for range checks and keeping
|
||||
* track of sizes.
|
||||
*/
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_ULSHIFT 6 /* log base 2 of BT_NBIPUL, to extract word index */
|
||||
#define BT_ULSHIFT32 5 /* log base 2 of BT_NBIPUL, to extract word index */
|
||||
#else
|
||||
#define BT_ULSHIFT 5 /* log base 2 of BT_NBIPUL, to extract word index */
|
||||
#endif
|
||||
|
||||
#define BT_NBIPUL (1 << BT_ULSHIFT) /* n bits per ulong_t */
|
||||
#define BT_ULMASK (BT_NBIPUL - 1) /* to extract bit index */
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_NBIPUL32 (1 << BT_ULSHIFT32) /* n bits per ulong_t */
|
||||
#define BT_ULMASK32 (BT_NBIPUL32 - 1) /* to extract bit index */
|
||||
#define BT_ULMAXMASK 0xffffffffffffffff /* used by bt_getlowbit */
|
||||
#else
|
||||
#define BT_ULMAXMASK 0xffffffff
|
||||
#endif
|
||||
|
||||
/*
|
||||
* bitmap is a ulong_t *, bitindex an index_t
|
||||
*
|
||||
* The macros BT_WIM and BT_BIW internal; there is no need
|
||||
* for users of this package to use them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* word in map
|
||||
*/
|
||||
#define BT_WIM(bitmap, bitindex) \
|
||||
((bitmap)[(bitindex) >> BT_ULSHIFT])
|
||||
/*
|
||||
* bit in word
|
||||
*/
|
||||
#define BT_BIW(bitindex) \
|
||||
(1UL << ((bitindex) & BT_ULMASK))
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_WIM32(bitmap, bitindex) \
|
||||
((bitmap)[(bitindex) >> BT_ULSHIFT32])
|
||||
|
||||
#define BT_BIW32(bitindex) \
|
||||
(1UL << ((bitindex) & BT_ULMASK32))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These are public macros
|
||||
*
|
||||
* BT_BITOUL == n bits to n ulong_t's
|
||||
*/
|
||||
#define BT_BITOUL(nbits) \
|
||||
(((nbits) + BT_NBIPUL - 1l) / BT_NBIPUL)
|
||||
#define BT_SIZEOFMAP(nbits) \
|
||||
(BT_BITOUL(nbits) * sizeof (ulong_t))
|
||||
#define BT_TEST(bitmap, bitindex) \
|
||||
((BT_WIM((bitmap), (bitindex)) & BT_BIW(bitindex)) ? 1 : 0)
|
||||
#define BT_SET(bitmap, bitindex) \
|
||||
{ BT_WIM((bitmap), (bitindex)) |= BT_BIW(bitindex); }
|
||||
#define BT_CLEAR(bitmap, bitindex) \
|
||||
{ BT_WIM((bitmap), (bitindex)) &= ~BT_BIW(bitindex); }
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_BITOUL32(nbits) \
|
||||
(((nbits) + BT_NBIPUL32 - 1l) / BT_NBIPUL32)
|
||||
#define BT_SIZEOFMAP32(nbits) \
|
||||
(BT_BITOUL32(nbits) * sizeof (uint_t))
|
||||
#define BT_TEST32(bitmap, bitindex) \
|
||||
((BT_WIM32((bitmap), (bitindex)) & BT_BIW32(bitindex)) ? 1 : 0)
|
||||
#define BT_SET32(bitmap, bitindex) \
|
||||
{ BT_WIM32((bitmap), (bitindex)) |= BT_BIW32(bitindex); }
|
||||
#define BT_CLEAR32(bitmap, bitindex) \
|
||||
{ BT_WIM32((bitmap), (bitindex)) &= ~BT_BIW32(bitindex); }
|
||||
#endif /* _LP64 */
|
||||
|
||||
#endif /* _COMPAT_OPENSOLARIS_SYS_BITMAP_H */
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
/*
|
||||
* University Copyright- Copyright (c) 1982, 1986, 1988
|
||||
* The Regents of the University of California
|
||||
* All Rights Reserved
|
||||
*
|
||||
* University Acknowledgment- Portions of this document are derived from
|
||||
* software developed by the University of California, Berkeley, and its
|
||||
* contributors.
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_BYTEORDER_H_
|
||||
#define _OPENSOLARIS_SYS_BYTEORDER_H_
|
||||
|
||||
/*
|
||||
* Macros to reverse byte order
|
||||
*/
|
||||
#define BSWAP_8(x) ((x) & 0xff)
|
||||
#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
|
||||
#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
|
||||
#define BSWAP_64(x) ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32))
|
||||
|
||||
#define BMASK_8(x) ((x) & 0xff)
|
||||
#define BMASK_16(x) ((x) & 0xffff)
|
||||
#define BMASK_32(x) ((x) & 0xffffffff)
|
||||
#define BMASK_64(x) (x)
|
||||
|
||||
/*
|
||||
* Macros to convert from a specific byte order to/from native byte order
|
||||
*/
|
||||
#if _BYTE_ORDER == _BIG_ENDIAN
|
||||
#define LE_64(x) BSWAP_64(x)
|
||||
#else
|
||||
#define LE_64(x) BMASK_64(x)
|
||||
#endif
|
||||
|
||||
#endif /* _OPENSOLARIS_SYS_BYTEORDER_H_ */
|
@ -1,217 +0,0 @@
|
||||
/*
|
||||
* 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 _SYS_CALLB_H
|
||||
#define _SYS_CALLB_H
|
||||
|
||||
#pragma ident "@(#)callb.h 1.29 05/06/23 SMI"
|
||||
|
||||
#include <sys/kcondvar.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* definitions of callback classes (c_class)
|
||||
*
|
||||
* Callbacks belong in the same class if (1) their callback routines
|
||||
* do the same kind of processing (ideally, using the same callback function)
|
||||
* and (2) they can/should be executed at the same time in a cpr
|
||||
* suspend/resume operation.
|
||||
*
|
||||
* Note: The DAEMON class, in particular, is for stopping kernel threads
|
||||
* and nothing else. The CALLB_* macros below should be used to deal
|
||||
* with kernel threads, and the callback function should be callb_generic_cpr.
|
||||
* Another idiosyncrasy of the DAEMON class is that if a suspend operation
|
||||
* fails, some of the callback functions may be called with the RESUME
|
||||
* code which were never called with SUSPEND. Not a problem currently,
|
||||
* but see bug 4201851.
|
||||
*/
|
||||
#define CB_CL_CPR_DAEMON 0
|
||||
#define CB_CL_CPR_VM 1
|
||||
#define CB_CL_CPR_CALLOUT 2
|
||||
#define CB_CL_CPR_OBP 3
|
||||
#define CB_CL_CPR_FB 4
|
||||
#define CB_CL_PANIC 5
|
||||
#define CB_CL_CPR_RPC 6
|
||||
#define CB_CL_CPR_PROMPRINTF 7
|
||||
#define CB_CL_UADMIN 8
|
||||
#define CB_CL_CPR_PM 9
|
||||
#define CB_CL_HALT 10
|
||||
#define CB_CL_CPR_DMA 11
|
||||
#define CB_CL_CPR_POST_USER 12
|
||||
#define CB_CL_UADMIN_PRE_VFS 13
|
||||
#define CB_CL_MDBOOT CB_CL_UADMIN
|
||||
#define CB_CL_ENTER_DEBUGGER 14
|
||||
#define CB_CL_CPR_POST_KERNEL 15
|
||||
#define NCBCLASS 16 /* CHANGE ME if classes are added/removed */
|
||||
|
||||
/*
|
||||
* CB_CL_CPR_DAEMON class specific definitions are given below:
|
||||
*/
|
||||
|
||||
/*
|
||||
* code for CPR callb_execute_class
|
||||
*/
|
||||
#define CB_CODE_CPR_CHKPT 0
|
||||
#define CB_CODE_CPR_RESUME 1
|
||||
|
||||
typedef void * callb_id_t;
|
||||
/*
|
||||
* Per kernel thread structure for CPR daemon callbacks.
|
||||
* Must be protected by either a existing lock in the daemon or
|
||||
* a new lock created for such a purpose.
|
||||
*/
|
||||
typedef struct callb_cpr {
|
||||
kmutex_t *cc_lockp; /* lock to protect this struct */
|
||||
char cc_events; /* various events for CPR */
|
||||
callb_id_t cc_id; /* callb id address */
|
||||
kcondvar_t cc_callb_cv; /* cv for callback waiting */
|
||||
kcondvar_t cc_stop_cv; /* cv to checkpoint block */
|
||||
} callb_cpr_t;
|
||||
|
||||
/*
|
||||
* cc_events definitions
|
||||
*/
|
||||
#define CALLB_CPR_START 1 /* a checkpoint request's started */
|
||||
#define CALLB_CPR_SAFE 2 /* thread is safe for CPR */
|
||||
#define CALLB_CPR_ALWAYS_SAFE 4 /* thread is ALWAYS safe for CPR */
|
||||
|
||||
/*
|
||||
* Used when checking that all kernel threads are stopped.
|
||||
*/
|
||||
#define CALLB_MAX_RETRY 3 /* when waiting for kthread to sleep */
|
||||
#define CALLB_THREAD_DELAY 10 /* ticks allowed to reach sleep */
|
||||
#define CPR_KTHREAD_TIMEOUT_SEC 90 /* secs before callback times out -- */
|
||||
/* due to pwr mgmt of disks, make -- */
|
||||
/* big enough for worst spinup time */
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
*
|
||||
* CALLB_CPR_INIT macro is used by kernel threads to add their entry to
|
||||
* the callback table and perform other initialization. It automatically
|
||||
* adds the thread as being in the callback class CB_CL_CPR_DAEMON.
|
||||
*
|
||||
* cp - ptr to the callb_cpr_t structure for this kernel thread
|
||||
*
|
||||
* lockp - pointer to mutex protecting the callb_cpr_t stuct
|
||||
*
|
||||
* func - pointer to the callback function for this kernel thread.
|
||||
* It has the prototype boolean_t <func>(void *arg, int code)
|
||||
* where: arg - ptr to the callb_cpr_t structure
|
||||
* code - not used for this type of callback
|
||||
* returns: B_TRUE if successful; B_FALSE if unsuccessful.
|
||||
*
|
||||
* name - a string giving the name of the kernel thread
|
||||
*
|
||||
* Note: lockp is the lock to protect the callb_cpr_t (cp) structure
|
||||
* later on. No lock held is needed for this initialization.
|
||||
*/
|
||||
#define CALLB_CPR_INIT(cp, lockp, func, name) { \
|
||||
strlcpy(curthread->td_name, (name), \
|
||||
sizeof(curthread->td_name)); \
|
||||
strlcpy(curthread->td_proc->p_comm, (name), \
|
||||
sizeof(curthread->td_proc->p_comm)); \
|
||||
bzero((caddr_t)(cp), sizeof (callb_cpr_t)); \
|
||||
(cp)->cc_lockp = lockp; \
|
||||
(cp)->cc_id = callb_add(func, (void *)(cp), \
|
||||
CB_CL_CPR_DAEMON, name); \
|
||||
}
|
||||
|
||||
#ifndef __lock_lint
|
||||
#define CALLB_CPR_ASSERT(cp) ASSERT(MUTEX_HELD((cp)->cc_lockp));
|
||||
#else
|
||||
#define CALLB_CPR_ASSERT(cp)
|
||||
#endif
|
||||
/*
|
||||
* Some threads (like the idle threads) do not adhere to the callback
|
||||
* protocol and are always considered safe. Such threads must never exit.
|
||||
* They register their presence by calling this macro during their
|
||||
* initialization.
|
||||
*
|
||||
* Args:
|
||||
* t - thread pointer of the client kernel thread
|
||||
* name - a string giving the name of the kernel thread
|
||||
*/
|
||||
#define CALLB_CPR_INIT_SAFE(t, name) { \
|
||||
(void) callb_add_thread(callb_generic_cpr_safe, \
|
||||
(void *) &callb_cprinfo_safe, CB_CL_CPR_DAEMON, \
|
||||
name, t); \
|
||||
}
|
||||
/*
|
||||
* The lock to protect cp's content must be held before
|
||||
* calling the following two macros.
|
||||
*
|
||||
* Any code region between CALLB_CPR_SAFE_BEGIN and CALLB_CPR_SAFE_END
|
||||
* is safe for checkpoint/resume.
|
||||
*/
|
||||
#define CALLB_CPR_SAFE_BEGIN(cp) { \
|
||||
CALLB_CPR_ASSERT(cp) \
|
||||
(cp)->cc_events |= CALLB_CPR_SAFE; \
|
||||
if ((cp)->cc_events & CALLB_CPR_START) \
|
||||
cv_signal(&(cp)->cc_callb_cv); \
|
||||
}
|
||||
#define CALLB_CPR_SAFE_END(cp, lockp) { \
|
||||
CALLB_CPR_ASSERT(cp) \
|
||||
while ((cp)->cc_events & CALLB_CPR_START) \
|
||||
cv_wait(&(cp)->cc_stop_cv, lockp); \
|
||||
(cp)->cc_events &= ~CALLB_CPR_SAFE; \
|
||||
}
|
||||
/*
|
||||
* cv_destroy is nop right now but may be needed in the future.
|
||||
*/
|
||||
#define CALLB_CPR_EXIT(cp) { \
|
||||
CALLB_CPR_ASSERT(cp) \
|
||||
(cp)->cc_events |= CALLB_CPR_SAFE; \
|
||||
if ((cp)->cc_events & CALLB_CPR_START) \
|
||||
cv_signal(&(cp)->cc_callb_cv); \
|
||||
mutex_exit((cp)->cc_lockp); \
|
||||
(void) callb_delete((cp)->cc_id); \
|
||||
cv_destroy(&(cp)->cc_callb_cv); \
|
||||
cv_destroy(&(cp)->cc_stop_cv); \
|
||||
}
|
||||
|
||||
extern callb_cpr_t callb_cprinfo_safe;
|
||||
extern callb_id_t callb_add(boolean_t (*)(void *, int), void *, int, char *);
|
||||
extern callb_id_t callb_add_thread(boolean_t (*)(void *, int),
|
||||
void *, int, char *, kthread_id_t);
|
||||
extern int callb_delete(callb_id_t);
|
||||
extern void callb_execute(callb_id_t, int);
|
||||
extern void *callb_execute_class(int, int);
|
||||
extern boolean_t callb_generic_cpr(void *, int);
|
||||
extern boolean_t callb_generic_cpr_safe(void *, int);
|
||||
extern boolean_t callb_is_stopped(kthread_id_t, caddr_t *);
|
||||
extern void callb_lock_table(void);
|
||||
extern void callb_unlock_table(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CALLB_H */
|
@ -1,90 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_CMN_ERR_H_
|
||||
#define _OPENSOLARIS_SYS_CMN_ERR_H_
|
||||
|
||||
#include <sys/systm.h>
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Common error handling severity levels */
|
||||
|
||||
#define CE_CONT 0 /* continuation */
|
||||
#define CE_NOTE 1 /* notice */
|
||||
#define CE_WARN 2 /* warning */
|
||||
#define CE_PANIC 3 /* panic */
|
||||
#define CE_IGNORE 4 /* print nothing */
|
||||
|
||||
static __inline void
|
||||
vcmn_err(int ce, const char *fmt, va_list adx)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
switch (ce) {
|
||||
case CE_CONT:
|
||||
snprintf(buf, sizeof(buf), "ZFS(cont): %s\n", fmt);
|
||||
break;
|
||||
case CE_NOTE:
|
||||
snprintf(buf, sizeof(buf), "ZFS: NOTICE: %s\n", fmt);
|
||||
break;
|
||||
case CE_WARN:
|
||||
snprintf(buf, sizeof(buf), "ZFS: WARNING: %s\n", fmt);
|
||||
break;
|
||||
case CE_PANIC:
|
||||
snprintf(buf, sizeof(buf), "ZFS(panic): %s\n", fmt);
|
||||
break;
|
||||
case CE_IGNORE:
|
||||
break;
|
||||
default:
|
||||
panic("unknown severity level");
|
||||
}
|
||||
if (ce != CE_IGNORE)
|
||||
vprintf(buf, adx);
|
||||
if (ce == CE_PANIC)
|
||||
panic("ZFS");
|
||||
}
|
||||
|
||||
static __inline void
|
||||
cmn_err(int ce, const char *fmt, ...)
|
||||
{
|
||||
va_list adx;
|
||||
|
||||
va_start(adx, fmt);
|
||||
vcmn_err(ce, fmt, adx);
|
||||
va_end(adx);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _OPENSOLARIS_SYS_CMN_ERR_H_ */
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_SYS_CPUPART_H
|
||||
#define _COMPAT_OPENSOLARIS_SYS_CPUPART_H
|
||||
|
||||
typedef int cpupartid_t;
|
||||
|
||||
typedef struct cpupart {
|
||||
cpupartid_t cp_id; /* partition ID */
|
||||
} cpupart_t;
|
||||
|
||||
#endif /* _COMPAT_OPENSOLARIS_SYS_CPUPART_H */
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_SYS_CPUVAR_H
|
||||
#define _COMPAT_OPENSOLARIS_SYS_CPUVAR_H
|
||||
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
#define CPU_CACHE_COHERENCE_SIZE 64
|
||||
|
||||
/*
|
||||
* The cpu_core structure consists of per-CPU state available in any context.
|
||||
* On some architectures, this may mean that the page(s) containing the
|
||||
* NCPU-sized array of cpu_core structures must be locked in the TLB -- it
|
||||
* is up to the platform to assure that this is performed properly. Note that
|
||||
* the structure is sized to avoid false sharing.
|
||||
*/
|
||||
#define CPUC_SIZE (sizeof (uint16_t) + sizeof (uintptr_t) + \
|
||||
sizeof (kmutex_t))
|
||||
#define CPUC_PADSIZE CPU_CACHE_COHERENCE_SIZE - CPUC_SIZE
|
||||
|
||||
typedef struct cpu_core {
|
||||
uint16_t cpuc_dtrace_flags; /* DTrace flags */
|
||||
uint8_t cpuc_pad[CPUC_PADSIZE]; /* padding */
|
||||
uintptr_t cpuc_dtrace_illval; /* DTrace illegal value */
|
||||
kmutex_t cpuc_pid_lock; /* DTrace pid provider lock */
|
||||
} cpu_core_t;
|
||||
|
||||
extern cpu_core_t cpu_core[];
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
* DTrace flags.
|
||||
*/
|
||||
#define CPU_DTRACE_NOFAULT 0x0001 /* Don't fault */
|
||||
#define CPU_DTRACE_DROP 0x0002 /* Drop this ECB */
|
||||
#define CPU_DTRACE_BADADDR 0x0004 /* DTrace fault: bad address */
|
||||
#define CPU_DTRACE_BADALIGN 0x0008 /* DTrace fault: bad alignment */
|
||||
#define CPU_DTRACE_DIVZERO 0x0010 /* DTrace fault: divide by zero */
|
||||
#define CPU_DTRACE_ILLOP 0x0020 /* DTrace fault: illegal operation */
|
||||
#define CPU_DTRACE_NOSCRATCH 0x0040 /* DTrace fault: out of scratch */
|
||||
#define CPU_DTRACE_KPRIV 0x0080 /* DTrace fault: bad kernel access */
|
||||
#define CPU_DTRACE_UPRIV 0x0100 /* DTrace fault: bad user access */
|
||||
#define CPU_DTRACE_TUPOFLOW 0x0200 /* DTrace fault: tuple stack overflow */
|
||||
#if defined(__sparc)
|
||||
#define CPU_DTRACE_FAKERESTORE 0x0400 /* pid provider hint to getreg */
|
||||
#endif
|
||||
#define CPU_DTRACE_ENTRY 0x0800 /* pid provider hint to ustack() */
|
||||
#define CPU_DTRACE_BADSTACK 0x1000 /* DTrace fault: bad stack */
|
||||
|
||||
#define CPU_DTRACE_FAULT (CPU_DTRACE_BADADDR | CPU_DTRACE_BADALIGN | \
|
||||
CPU_DTRACE_DIVZERO | CPU_DTRACE_ILLOP | \
|
||||
CPU_DTRACE_NOSCRATCH | CPU_DTRACE_KPRIV | \
|
||||
CPU_DTRACE_UPRIV | CPU_DTRACE_TUPOFLOW | \
|
||||
CPU_DTRACE_BADSTACK)
|
||||
#define CPU_DTRACE_ERROR (CPU_DTRACE_FAULT | CPU_DTRACE_DROP)
|
||||
|
||||
typedef enum {
|
||||
CPU_INIT,
|
||||
CPU_CONFIG,
|
||||
CPU_UNCONFIG,
|
||||
CPU_ON,
|
||||
CPU_OFF,
|
||||
CPU_CPUPART_IN,
|
||||
CPU_CPUPART_OUT
|
||||
} cpu_setup_t;
|
||||
|
||||
typedef int cpu_setup_func_t(cpu_setup_t, int, void *);
|
||||
|
||||
|
||||
#endif /* _COMPAT_OPENSOLARIS_SYS_CPUVAR_H */
|
@ -1,51 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_CRED_H_
|
||||
#define _OPENSOLARIS_SYS_CRED_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include_next <sys/ucred.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
typedef struct ucred cred_t;
|
||||
|
||||
#define CRED() (curthread->td_ucred)
|
||||
|
||||
/*
|
||||
* kcred is used when you need all privileges.
|
||||
*/
|
||||
#define kcred (thread0.td_ucred)
|
||||
|
||||
#define crgetuid(cred) ((cred)->cr_uid)
|
||||
#define crgetgid(cred) ((cred)->cr_gid)
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _OPENSOLARIS_SYS_CRED_H_ */
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 John Birrell <jb@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_OPENSOLARIS_SYS_CYCLIC_H_
|
||||
#define _COMPAT_OPENSOLARIS_SYS_CYCLIC_H_
|
||||
|
||||
#ifndef _KERNEL
|
||||
typedef void cpu_t;
|
||||
#endif
|
||||
|
||||
#include_next <sys/cyclic.h>
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_DEBUG_H_
|
||||
#define _OPENSOLARIS_SYS_DEBUG_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/types.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include_next <sys/debug.h>
|
||||
|
||||
#define assfail(a, f, l) \
|
||||
(panic("solaris assert: %s, file: %s, line: %d", (a), (f), (l)), 0)
|
||||
|
||||
#define assfail3(a, lv, op, rv, f, l) \
|
||||
panic("solaris assert: %s (0x%jx %s 0x%jx), file: %s, line: %d", \
|
||||
(a), (uintmax_t)(lv), (op), (uintmax_t)(rv), (f), (l))
|
||||
#else /* !_KERNEL */
|
||||
#include_next <sys/debug.h>
|
||||
#endif
|
||||
|
||||
#endif /* _OPENSOLARIS_SYS_DEBUG_H_ */
|
@ -1,44 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_DIRENT_H_
|
||||
#define _OPENSOLARIS_SYS_DIRENT_H_
|
||||
|
||||
#include_next <sys/dirent.h>
|
||||
|
||||
typedef struct dirent dirent64_t;
|
||||
#define dirent64 dirent
|
||||
#define ino64_t ino_t
|
||||
|
||||
#define d_ino d_fileno
|
||||
|
||||
#define DIRENT64_RECLEN(len) ((sizeof(struct dirent) - \
|
||||
sizeof(((struct dirent *)NULL)->d_name) + \
|
||||
(len) + 1 + 3) & ~3)
|
||||
|
||||
#endif /* !_OPENSOLARIS_SYS_DIRENT_H_ */
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_DKIO_H_
|
||||
#define _OPENSOLARIS_SYS_DKIO_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Disk io control commands
|
||||
* Warning: some other ioctls with the DIOC prefix exist elsewhere.
|
||||
* The Generic DKIOC numbers are from 0 - 50.
|
||||
* The Floppy Driver uses 51 - 100.
|
||||
* The Hard Disk (except SCSI) 101 - 106. (these are obsolete)
|
||||
* The CDROM Driver 151 - 200.
|
||||
* The USCSI ioctl 201 - 250.
|
||||
*/
|
||||
#define DKIOC (0x04 << 8)
|
||||
|
||||
/*
|
||||
* The following ioctls are generic in nature and need to be
|
||||
* suported as appropriate by all disk drivers
|
||||
*/
|
||||
#define DKIOCGGEOM (DKIOC|1) /* Get geometry */
|
||||
#define DKIOCINFO (DKIOC|3) /* Get info */
|
||||
#define DKIOCEJECT (DKIOC|6) /* Generic 'eject' */
|
||||
#define DKIOCGVTOC (DKIOC|11) /* Get VTOC */
|
||||
#define DKIOCSVTOC (DKIOC|12) /* Set VTOC & Write to Disk */
|
||||
|
||||
/*
|
||||
* Disk Cache Controls. These ioctls should be supported by
|
||||
* all disk drivers.
|
||||
*
|
||||
* DKIOCFLUSHWRITECACHE when used from user-mode ignores the ioctl
|
||||
* argument, but it should be passed as NULL to allow for future
|
||||
* reinterpretation. From user-mode, this ioctl request is synchronous.
|
||||
*
|
||||
* When invoked from within the kernel, the arg can be NULL to indicate
|
||||
* a synchronous request or can be the address of a struct dk_callback
|
||||
* to request an asynchronous callback when the flush request is complete.
|
||||
* In this case, the flag to the ioctl must include FKIOCTL and the
|
||||
* dkc_callback field of the pointed to struct must be non-null or the
|
||||
* request is made synchronously.
|
||||
*
|
||||
* In the callback case: if the ioctl returns 0, a callback WILL be performed.
|
||||
* If the ioctl returns non-zero, a callback will NOT be performed.
|
||||
* NOTE: In some cases, the callback may be done BEFORE the ioctl call
|
||||
* returns. The caller's locking strategy should be prepared for this case.
|
||||
*/
|
||||
#define DKIOCFLUSHWRITECACHE (DKIOC|34) /* flush cache to phys medium */
|
||||
|
||||
struct dk_callback {
|
||||
void (*dkc_callback)(void *dkc_cookie, int error);
|
||||
void *dkc_cookie;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _OPENSOLARIS_SYS_DKIO_H_ */
|
@ -1,40 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_DNLC_H_
|
||||
#define _OPENSOLARIS_SYS_DNLC_H_
|
||||
|
||||
#define DNLC_NO_VNODE ((void *)(intptr_t)0xdeadc0de)
|
||||
|
||||
#define dnlc_lookup(dvp, name) (NULL)
|
||||
#define dnlc_update(dvp, name, vp) do { } while (0)
|
||||
#define dnlc_remove(dvp, name) do { } while (0)
|
||||
#define dnlc_purge_vfsp(vfsp, count) (0)
|
||||
#define dnlc_reduce_cache(percent) do { } while (0)
|
||||
|
||||
#endif /* !_OPENSOLARIS_SYS_DNLC_H_ */
|
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
* ELF compatibility definitions for OpenSolaris source.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SYS__ELF_SOLARIS_H_
|
||||
#define _SYS__ELF_SOLARIS_H_
|
||||
|
||||
#include_next <sys/elf.h>
|
||||
|
||||
#define __sElfN(x) typedef __CONCAT(__CONCAT(__CONCAT(Elf,__ELF_WORD_SIZE),_),x) x
|
||||
|
||||
__sElfN(Addr);
|
||||
__sElfN(Cap);
|
||||
__sElfN(Dyn);
|
||||
__sElfN(Ehdr);
|
||||
__sElfN(Move);
|
||||
__sElfN(Off);
|
||||
__sElfN(Phdr);
|
||||
__sElfN(Rel);
|
||||
__sElfN(Rela);
|
||||
__sElfN(Shdr);
|
||||
__sElfN(Sym);
|
||||
__sElfN(Syminfo);
|
||||
__sElfN(Verdaux);
|
||||
__sElfN(Verdef);
|
||||
__sElfN(Vernaux);
|
||||
__sElfN(Verneed);
|
||||
__sElfN(Versym);
|
||||
|
||||
__sElfN(Half);
|
||||
__sElfN(Sword);
|
||||
__sElfN(Word);
|
||||
|
||||
#if __ELF_WORD_SIZE == 32
|
||||
typedef Elf32_Word Xword; /* Xword/Sxword are 32-bits in Elf32 */
|
||||
typedef Elf32_Sword Sxword;
|
||||
#else
|
||||
typedef Elf64_Xword Xword;
|
||||
typedef Elf64_Sxword Sxword;
|
||||
#endif
|
||||
|
||||
#define ELF_M_INFO __ELFN(M_INFO)
|
||||
#define ELF_M_SIZE __ELFN(M_SIZE)
|
||||
#define ELF_M_SYM __ELFN(M_SYM)
|
||||
|
||||
/*
|
||||
* Elf `printf' type-cast macros. These force arguments to be a fixed size
|
||||
* so that Elf32 and Elf64 can share common format strings.
|
||||
*/
|
||||
#define EC_ADDR(a) ((Elf64_Addr)(a)) /* "ull" */
|
||||
#define EC_OFF(a) ((Elf64_Off)(a)) /* "ull" */
|
||||
#define EC_HALF(a) ((Elf64_Half)(a)) /* "d" */
|
||||
#define EC_WORD(a) ((Elf64_Word)(a)) /* "u" */
|
||||
#define EC_SWORD(a) ((Elf64_Sword)(a)) /* "d" */
|
||||
#define EC_XWORD(a) ((Elf64_Xword)(a)) /* "ull" */
|
||||
#define EC_SXWORD(a) ((Elf64_Sxword)(a)) /* "ll" */
|
||||
#define EC_LWORD(a) ((Elf64_Lword)(a)) /* "ull" */
|
||||
|
||||
#define elf_checksum __elfN(checksum)
|
||||
#define elf_fsize __elfN(fsize)
|
||||
#define elf_getehdr __elfN(getehdr)
|
||||
#define elf_getphdr __elfN(getphdr)
|
||||
#define elf_newehdr __elfN(newehdr)
|
||||
#define elf_newphdr __elfN(newphdr)
|
||||
#define elf_getshdr __elfN(getshdr)
|
||||
#define elf_xlatetof __elfN(xlatetof)
|
||||
#define elf_xlatetom __elfN(xlatetom)
|
||||
|
||||
#define Elf_cap_entry __ElfN(cap_entry)
|
||||
#define Elf_cap_title __ElfN(cap_title)
|
||||
#define Elf_demangle_name __ElfN(demangle_name)
|
||||
#define Elf_dyn_entry __ElfN(dyn_entry)
|
||||
#define Elf_dyn_title __ElfN(dyn_title)
|
||||
#define Elf_ehdr __ElfN(ehdr)
|
||||
#define Elf_got_entry __ElfN(got_entry)
|
||||
#define Elf_got_title __ElfN(got_title)
|
||||
#define Elf_reloc_apply_reg __ElfN(reloc_apply_reg)
|
||||
#define Elf_reloc_apply_val __ElfN(reloc_apply_val)
|
||||
#define Elf_reloc_entry_1 __ElfN(reloc_entry_1)
|
||||
#define Elf_reloc_entry_2 __ElfN(reloc_entry_2)
|
||||
#define Elf_reloc_title __ElfN(reloc_title)
|
||||
#define Elf_phdr __ElfN(phdr)
|
||||
#define Elf_shdr __ElfN(shdr)
|
||||
#define Elf_syms_table_entry __ElfN(syms_table_entry)
|
||||
#define Elf_syms_table_title __ElfN(syms_table_title)
|
||||
#define Elf_ver_def_title __ElfN(ver_def_title)
|
||||
#define Elf_ver_line_1 __ElfN(ver_line_1)
|
||||
#define Elf_ver_line_2 __ElfN(ver_line_2)
|
||||
#define Elf_ver_line_3 __ElfN(ver_line_3)
|
||||
#define Elf_ver_line_4 __ElfN(ver_line_4)
|
||||
#define Elf_ver_line_5 __ElfN(ver_line_5)
|
||||
#define Elf_ver_need_title __ElfN(ver_need_title)
|
||||
|
||||
#endif /* !_SYS__ELF_SOLARIS_H_ */
|
@ -1,62 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _OPENSOLARIS_SYS_CONDVAR_H_
|
||||
#define _OPENSOLARIS_SYS_CONDVAR_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
|
||||
typedef struct cv kcondvar_t;
|
||||
|
||||
typedef enum {
|
||||
CV_DEFAULT,
|
||||
CV_DRIVER
|
||||
} kcv_type_t;
|
||||
|
||||
#define zfs_cv_init(cv, name, type, arg) do { \
|
||||
const char *_name; \
|
||||
ASSERT((type) == CV_DEFAULT); \
|
||||
for (_name = #cv; *_name != '\0'; _name++) { \
|
||||
if (*_name >= 'a' && *_name <= 'z') \
|
||||
break; \
|
||||
} \
|
||||
if (*_name == '\0') \
|
||||
_name = #cv; \
|
||||
cv_init((cv), _name); \
|
||||
} while (0)
|
||||
#define cv_init(cv, name, type, arg) zfs_cv_init((cv), (name), (type), (arg))
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _OPENSOLARIS_SYS_CONDVAR_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user