MFC@r248830
Approved by: ed (project owner)
This commit is contained in:
commit
3625eb7f3d
@ -30,7 +30,8 @@ contrib/openbsm rwatson Pre-commit review requested.
|
||||
sys/security/audit rwatson Pre-commit review requested.
|
||||
ahc(4) gibbs Pre-commit review requested.
|
||||
ahd(4) gibbs Pre-commit review requested.
|
||||
NEWCARD imp Pre-commit review requested.
|
||||
PC Card imp Pre-commit review requested.
|
||||
CardBus imp Pre-commit review requested.
|
||||
pci bus imp,jhb Pre-commit review requested.
|
||||
cdboot jhb Pre-commit review requested.
|
||||
pxeboot jhb Pre-commit review requested.
|
||||
@ -124,3 +125,6 @@ isci(4) jimharris Pre-commit review requested.
|
||||
cmx daniel@roe.ch Pre-commit review preferred.
|
||||
filemon obrien Pre-commit review preferred.
|
||||
sysdoc trhodes Pre-commit review preferred.
|
||||
sh(1) jilles Pre-commit review requested. This also applies
|
||||
to kill(1), printf(1) and test(1) which are
|
||||
compiled in as builtins.
|
||||
|
@ -1132,7 +1132,8 @@ _lex= usr.bin/lex
|
||||
.endif
|
||||
|
||||
.if ${BOOTSTRAPPING} < 1000013
|
||||
_yacc= usr.bin/yacc
|
||||
_yacc= lib/liby \
|
||||
usr.bin/yacc
|
||||
.endif
|
||||
|
||||
.if ${BOOTSTRAPPING} < 1000026
|
||||
@ -1388,6 +1389,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \
|
||||
lib/libopie lib/libpam ${_lib_libthr} \
|
||||
lib/libradius lib/libsbuf lib/libtacplus \
|
||||
${_cddl_lib_libumem} ${_cddl_lib_libnvpair} \
|
||||
${_cddl_lib_libzfs_core} \
|
||||
lib/libutil ${_lib_libypclnt} lib/libz lib/msun \
|
||||
${_secure_lib_libcrypto} ${_secure_lib_libssh} \
|
||||
${_secure_lib_libssl}
|
||||
@ -1416,7 +1418,9 @@ lib/libopie__L lib/libtacplus__L: lib/libmd__L
|
||||
.if ${MK_CDDL} != "no"
|
||||
_cddl_lib_libumem= cddl/lib/libumem
|
||||
_cddl_lib_libnvpair= cddl/lib/libnvpair
|
||||
_cddl_lib_libzfs_core= cddl/lib/libzfs_core
|
||||
_cddl_lib= cddl/lib
|
||||
cddl/lib/libzfs_core__L: cddl/lib/libnvpair__L
|
||||
.endif
|
||||
|
||||
.if ${MK_CRYPT} != "no"
|
||||
@ -1815,6 +1819,6 @@ _xi-links:
|
||||
../../../../usr/bin/${XDDIR}${OSREL}-$$i; \
|
||||
done
|
||||
.else
|
||||
xdev xdev-buil xdev-install:
|
||||
xdev xdev-build xdev-install:
|
||||
@echo "*** Error: Both XDEV and XDEV_ARCH must be defined for \"${.TARGET}\" target"
|
||||
.endif
|
||||
|
@ -38,6 +38,85 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20130316: vinum.4 removed
|
||||
OLD_FILES+=usr/share/man/man4/vinum.4.gz
|
||||
# 20130312: fortunes-o removed
|
||||
OLD_FILES+=usr/share/games/fortune/fortunes-o
|
||||
OLD_FILES+=usr/share/games/fortune/fortunes-o.dat
|
||||
# 20130311: Ports are no more available via cvsup
|
||||
OLD_FILES+=usr/share/examples/cvsup/ports-supfile
|
||||
OLD_FILES+=usr/share/examples/cvsup/refuse
|
||||
OLD_FILES+=usr/share/examples/cvsup/refuse.README
|
||||
# 20130309: NWFS and NCP supports removed
|
||||
OLD_FILES+=usr/bin/ncplist
|
||||
OLD_FILES+=usr/bin/ncplogin
|
||||
OLD_FILES+=usr/bin/ncplogout
|
||||
OLD_FILES+=usr/include/fs/nwfs/nwfs.h
|
||||
OLD_FILES+=usr/include/fs/nwfs/nwfs_mount.h
|
||||
OLD_FILES+=usr/include/fs/nwfs/nwfs_node.h
|
||||
OLD_FILES+=usr/include/fs/nwfs/nwfs_subr.h
|
||||
OLD_DIRS+=usr/include/fs/nwfs
|
||||
OLD_FILES+=usr/include/netncp/ncp.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_cfg.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_conn.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_file.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_lib.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_ncp.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_nls.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_rcfile.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_rq.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_sock.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_subr.h
|
||||
OLD_FILES+=usr/include/netncp/ncp_user.h
|
||||
OLD_FILES+=usr/include/netncp/ncpio.h
|
||||
OLD_FILES+=usr/include/netncp/nwerror.h
|
||||
OLD_DIRS+=usr/include/netncp
|
||||
OLD_FILES+=usr/lib/libncp.a
|
||||
OLD_FILES+=usr/lib/libncp.so
|
||||
OLD_LIBS+=usr/lib/libncp.so.4
|
||||
OLD_FILES+=usr/lib/libncp_p.a
|
||||
OLD_FILES+=usr/lib32/libncp.a
|
||||
OLD_FILES+=usr/lib32/libncp.so
|
||||
OLD_LIBS+=usr/lib32/libncp.so.4
|
||||
OLD_FILES+=usr/lib32/libncp_p.a
|
||||
OLD_FILES+=usr/sbin/mount_nwfs
|
||||
OLD_FILES+=usr/share/examples/nwclient/dot.nwfsrc
|
||||
OLD_FILES+=usr/share/examples/nwclient/nwfs.sh.sample
|
||||
OLD_DIRS+=usr/share/examples/nwclient
|
||||
OLD_FILES+=usr/share/man/man1/ncplist.1.gz
|
||||
OLD_FILES+=usr/share/man/man1/ncplogin.1.gz
|
||||
OLD_FILES+=usr/share/man/man1/ncplogout.1.gz
|
||||
OLD_FILES+=usr/share/man/man8/mount_nwfs.8.gz
|
||||
# 20130302: NTFS support removed
|
||||
OLD_FILES+=rescue/mount_ntfs
|
||||
OLD_FILES+=sbin/mount_ntfs
|
||||
OLD_FILES+=usr/include/fs/ntfs/ntfs.h
|
||||
OLD_FILES+=usr/include/fs/ntfs/ntfs_compr.h
|
||||
OLD_FILES+=usr/include/fs/ntfs/ntfs_ihash.h
|
||||
OLD_FILES+=usr/include/fs/ntfs/ntfs_inode.h
|
||||
OLD_FILES+=usr/include/fs/ntfs/ntfs_subr.h
|
||||
OLD_FILES+=usr/include/fs/ntfs/ntfs_vfsops.h
|
||||
OLD_FILES+=usr/include/fs/ntfs/ntfsmount.h
|
||||
OLD_DIRS+=usr/include/fs/ntfs
|
||||
OLD_FILES+=usr/share/man/man8/mount_ntfs.8.gz
|
||||
# 20130302: PORTALFS support removed
|
||||
OLD_FILES+=usr/include/fs/portalfs/portal.h
|
||||
OLD_DIRS+=usr/include/fs/portalfs
|
||||
OLD_FILES+=usr/sbin/mount_portalfs
|
||||
OLD_FILES+=usr/share/examples/portal/README
|
||||
OLD_FILES+=usr/share/examples/portal/portal.conf
|
||||
OLD_DIRS+=usr/share/examples/portal
|
||||
OLD_FILES+=usr/share/man/man8/mount_portalfs.8.gz
|
||||
# 20130302: CODAFS support removed
|
||||
OLD_FILES+=usr/share/man/man4/coda.4.gz
|
||||
# 20130302: XFS support removed
|
||||
OLD_FILES+=usr/share/man/man5/xfs.5.gz
|
||||
# 20130302: Capsicum overhaul
|
||||
OLD_FILES+=usr/share/man/man2/cap_getrights.2.gz
|
||||
OLD_FILES+=usr/share/man/man2/cap_new.2.gz
|
||||
# 20130213: OpenSSL 1.0.1e import
|
||||
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_verifyrecover.3.gz
|
||||
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_verifyrecover_init.3.gz
|
||||
# 20130116: removed long unused directories for .1aout section manpages
|
||||
OLD_FILES+=usr/share/man/en.ISO8859-1/man1aout
|
||||
OLD_FILES+=usr/share/man/en.UTF-8/man1aout
|
||||
@ -58,9 +137,10 @@ OLD_DIRS+=var/remote
|
||||
# 20121114: zpool-features manual page moved from section 5 to 7
|
||||
OLD_FILES+=usr/share/man/man5/zpool-features.5.gz
|
||||
# 20121022: remove harp, hfa and idt man page
|
||||
OLD_FILES+=share/man/man4/harp.4
|
||||
OLD_FILES+=share/man/man4/hfa.4
|
||||
OLD_FILES+=share/man/man4/idt.4
|
||||
OLD_FILES+=usr/share/man/man4/harp.4.gz
|
||||
OLD_FILES+=usr/share/man/man4/hfa.4.gz
|
||||
OLD_FILES+=usr/share/man/man4/idt.4.gz
|
||||
OLD_FILES+=usr/share/man/man4/if_idt.4.gz
|
||||
# 20121022: VFS_LOCK_GIANT elimination
|
||||
OLD_FILES+=usr/share/man/man9/VFS_LOCK_GIANT.9.gz
|
||||
OLD_FILES+=usr/share/man/man9/VFS_UNLOCK_GIANT.9.gz
|
||||
|
35
UPDATING
35
UPDATING
@ -26,6 +26,37 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10.x IS SLOW:
|
||||
disable the most expensive debugging functionality run
|
||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
||||
|
||||
20130308:
|
||||
CTL_DISABLE has also been added to the sparc64 GENERIC (for further
|
||||
information, see the respective 20130304 entry).
|
||||
|
||||
20130304:
|
||||
Recent commits to callout(9) changed the size of struct callout,
|
||||
so the KBI is probably heavily disturbed. Also, some functions
|
||||
in callout(9)/sleep(9)/sleepqueue(9)/condvar(9) KPIs were replaced
|
||||
by macros. Every kernel module using it won't load, so rebuild
|
||||
is requested.
|
||||
|
||||
The ctl device has been re-enabled in GENERIC for i386 and amd64,
|
||||
but does not initialize by default (because of the new CTL_DISABLE
|
||||
option) to save memory. To re-enable it, remove the CTL_DISABLE
|
||||
option from the kernel config file or set kern.cam.ctl.disable=0
|
||||
in /boot/loader.conf.
|
||||
|
||||
20130301:
|
||||
The ctl device has been disabled in GENERIC for i386 and amd64.
|
||||
This was done due to the extra memory being allocated at system
|
||||
initialisation time by the ctl driver which was only used if
|
||||
a CAM target device was created. This makes a FreeBSD system
|
||||
unusable on 128MB or less of RAM.
|
||||
|
||||
20130208:
|
||||
A new compression method (lz4) has been merged to -HEAD. Please
|
||||
refer to zpool-features(7) for more information.
|
||||
|
||||
Please refer to the "ZFS notes" section of this file for information
|
||||
on upgrading boot ZFS pools.
|
||||
|
||||
20130129:
|
||||
A BSD-licensed patch(1) variant has been added and is installed
|
||||
as bsdpatch, being the GNU version the default patch.
|
||||
@ -39,8 +70,8 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10.x IS SLOW:
|
||||
unlikely event that -M was the last option on the command line
|
||||
and the command line contained at least two files and a target
|
||||
directory the first file will have logs appended to it. The -M
|
||||
option served little practical purpose in the last decade so it's
|
||||
used expected to be extremely rare.
|
||||
option served little practical purpose in the last decade so its
|
||||
use is expected to be extremely rare.
|
||||
|
||||
20121223:
|
||||
After switching to Clang as the default compiler some users of ZFS
|
||||
|
@ -117,11 +117,7 @@ main(int argc, char *argv[])
|
||||
} else
|
||||
fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
|
||||
|
||||
/* XXX: Why don't chflags and lchflags have compatible prototypes? */
|
||||
if (hflag)
|
||||
change_flags = (int (*)(const char *, unsigned long))lchflags;
|
||||
else
|
||||
change_flags = chflags;
|
||||
change_flags = hflag ? lchflags : chflags;
|
||||
|
||||
flags = *argv;
|
||||
if (*flags >= '0' && *flags <= '7') {
|
||||
|
23
bin/cp/cp.1
23
bin/cp/cp.1
@ -32,7 +32,7 @@
|
||||
.\" @(#)cp.1 8.3 (Berkeley) 4/18/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd September 4, 2012
|
||||
.Dd March 15, 2013
|
||||
.Dt CP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -251,6 +251,27 @@ signal, the current input and output file and the percentage complete
|
||||
will be written to the standard output.
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
Make a copy of file
|
||||
.Pa foo
|
||||
named
|
||||
.Pa bar :
|
||||
.Pp
|
||||
.Dl $ cp foo bar
|
||||
.Pp
|
||||
Copy a group of files to the
|
||||
.Pa /tmp
|
||||
directory:
|
||||
.Pp
|
||||
.Dl $ cp *.txt /tmp
|
||||
.Pp
|
||||
Copy the directory
|
||||
.Pa junk
|
||||
and all of its contents (including any subdirectories) to the
|
||||
.Pa /tmp
|
||||
directory:
|
||||
.Pp
|
||||
.Dl $ cp -R junk /tmp
|
||||
.Sh COMPATIBILITY
|
||||
Historic versions of the
|
||||
.Nm
|
||||
|
@ -71,7 +71,6 @@ __FBSDID("$FreeBSD$");
|
||||
#ifdef DES
|
||||
static DES_cblock ivec; /* initialization vector */
|
||||
static DES_cblock pvec; /* padding vector */
|
||||
#endif
|
||||
|
||||
static char bits[] = { /* used to extract bits from a char */
|
||||
'\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
|
||||
@ -79,13 +78,12 @@ static char bits[] = { /* used to extract bits from a char */
|
||||
|
||||
static int pflag; /* 1 to preserve parity bits */
|
||||
|
||||
#ifdef DES
|
||||
static DES_key_schedule schedule; /* expanded DES key */
|
||||
#endif
|
||||
|
||||
static unsigned char des_buf[8];/* shared buffer for get_des_char/put_des_char */
|
||||
static int des_ct = 0; /* count for get_des_char/put_des_char */
|
||||
static int des_n = 0; /* index for put_des_char/get_des_char */
|
||||
#endif
|
||||
|
||||
/* init_des_cipher: initialize DES */
|
||||
void
|
||||
|
20
bin/ls/ls.1
20
bin/ls/ls.1
@ -32,7 +32,7 @@
|
||||
.\" @(#)ls.1 8.7 (Berkeley) 7/29/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 8, 2012
|
||||
.Dd March 15, 2013
|
||||
.Dt LS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -718,6 +718,24 @@ for more information.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
List the contents of the current working directory in long format:
|
||||
.Pp
|
||||
.Dl $ ls -l
|
||||
.Pp
|
||||
In addition to listing the contents of the current working directory in
|
||||
long format, show inode numbers, file flags (see
|
||||
.Xr chflags 1 ) ,
|
||||
and suffix each filename with a symbol representing its file type:
|
||||
.Pp
|
||||
.Dl $ ls -lioF
|
||||
.Pp
|
||||
List the files in
|
||||
.Pa /var/log ,
|
||||
sorting the output such that the mostly recently modified entries are
|
||||
printed first:
|
||||
.Pp
|
||||
.Dl $ ls -lt /var/log
|
||||
.Sh COMPATIBILITY
|
||||
The group field is now automatically included in the long listing for
|
||||
files in order to be compatible with the
|
||||
|
@ -32,7 +32,7 @@
|
||||
.\" @(#)mkdir.1 8.2 (Berkeley) 1/25/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 25, 1994
|
||||
.Dd March 15, 2013
|
||||
.Dt MKDIR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -87,6 +87,23 @@ Be verbose when creating directories, listing them as they are created.
|
||||
The user must have write permission in the parent directory.
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
Create a directory named
|
||||
.Pa foobar :
|
||||
.Pp
|
||||
.Dl $ mkdir foobar
|
||||
.Pp
|
||||
Create a directory named
|
||||
.Pa foobar
|
||||
and set its file mode to 700:
|
||||
.Pp
|
||||
.Dl $ mkdir -m 700 foobar
|
||||
.Pp
|
||||
Create a directory named
|
||||
.Pa cow/horse/monkey ,
|
||||
creating any non-existent intermediate directories as necessary:
|
||||
.Pp
|
||||
.Dl $ mkdir -p cow/horse/monkey
|
||||
.Sh COMPATIBILITY
|
||||
The
|
||||
.Fl v
|
||||
|
12
bin/mv/mv.1
12
bin/mv/mv.1
@ -32,7 +32,7 @@
|
||||
.\" @(#)mv.1 8.1 (Berkeley) 5/31/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 28, 2012
|
||||
.Dd March 15, 2013
|
||||
.Dt MV 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -155,6 +155,16 @@ rm -rf source_file
|
||||
.Ed
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
Rename file
|
||||
.Pa foo
|
||||
to
|
||||
.Pa bar ,
|
||||
overwriting
|
||||
.Pa bar
|
||||
if it already exists:
|
||||
.Pp
|
||||
.Dl $ mv -f foo bar
|
||||
.Sh COMPATIBILITY
|
||||
The
|
||||
.Fl h ,
|
||||
|
@ -337,7 +337,7 @@ err: if (unlink(to))
|
||||
* on a file that we copied, i.e., that we didn't create.)
|
||||
*/
|
||||
errno = 0;
|
||||
if (fchflags(to_fd, (u_long)sbp->st_flags))
|
||||
if (fchflags(to_fd, sbp->st_flags))
|
||||
if (errno != EOPNOTSUPP || sbp->st_flags != 0)
|
||||
warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 7, 2013
|
||||
.Dd March 15, 2013
|
||||
.Dt PS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -689,6 +689,10 @@ attempts to automatically determine the terminal width.
|
||||
.It Pa /boot/kernel/kernel
|
||||
default system namelist
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Display information on all system processes:
|
||||
.Pp
|
||||
.Dl $ ps -auxw
|
||||
.Sh SEE ALSO
|
||||
.Xr kill 1 ,
|
||||
.Xr pgrep 1 ,
|
||||
|
15
bin/rm/rm.1
15
bin/rm/rm.1
@ -32,7 +32,7 @@
|
||||
.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 31, 2010
|
||||
.Dd March 15, 2013
|
||||
.Dt RM 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -193,6 +193,19 @@ When
|
||||
is specified with
|
||||
.Fl f
|
||||
the file will be overwritten and removed even if it has hard links.
|
||||
.Sh EXAMPLES
|
||||
Recursively remove all files contained within the
|
||||
.Pa foobar
|
||||
directory hierarchy:
|
||||
.Pp
|
||||
.Dl $ rm -rf foobar
|
||||
.Pp
|
||||
Either of these commands will remove the file
|
||||
.Pa -f :
|
||||
.Bd -literal -offset indent
|
||||
$ rm -- -f
|
||||
$ rm ./-f
|
||||
.Ed
|
||||
.Sh COMPATIBILITY
|
||||
The
|
||||
.Nm
|
||||
|
@ -32,7 +32,7 @@
|
||||
.\" @(#)rmdir.1 8.1 (Berkeley) 5/31/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 21, 2004
|
||||
.Dd March 15, 2013
|
||||
.Dt RMDIR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -86,6 +86,18 @@ successfully.
|
||||
.It Li >0
|
||||
An error occurred.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Remove the directory
|
||||
.Pa foobar ,
|
||||
if it is empty:
|
||||
.Pp
|
||||
.Dl $ rmdir foobar
|
||||
.Pp
|
||||
Remove all directories up to and including
|
||||
.Pa cow ,
|
||||
stopping at the first non-empty directory (if any):
|
||||
.Pp
|
||||
.Dl $ rmdir -p cow/horse/monkey
|
||||
.Sh SEE ALSO
|
||||
.Xr rm 1
|
||||
.Sh STANDARDS
|
||||
|
@ -301,7 +301,7 @@ evaltree(union node *n, int flags)
|
||||
} while (n != NULL);
|
||||
out:
|
||||
popstackmark(&smark);
|
||||
if (pendingsigs)
|
||||
if (pendingsig)
|
||||
dotrap();
|
||||
if (eflag && exitstatus != 0 && do_etest)
|
||||
exitshell(exitstatus);
|
||||
|
@ -458,14 +458,15 @@ freejob(struct job *jp)
|
||||
|
||||
|
||||
int
|
||||
waitcmd(int argc, char **argv)
|
||||
waitcmd(int argc __unused, char **argv __unused)
|
||||
{
|
||||
struct job *job;
|
||||
int status, retval;
|
||||
struct job *jp;
|
||||
|
||||
if (argc > 1) {
|
||||
job = getjob(argv[1]);
|
||||
nextopt("");
|
||||
if (*argptr != NULL) {
|
||||
job = getjob(*argptr);
|
||||
} else {
|
||||
job = NULL;
|
||||
}
|
||||
@ -521,7 +522,7 @@ waitcmd(int argc, char **argv)
|
||||
} while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1);
|
||||
in_waitcmd--;
|
||||
|
||||
return 0;
|
||||
return pendingsig + 128;
|
||||
}
|
||||
|
||||
|
||||
|
@ -196,7 +196,7 @@ cmdloop(int top)
|
||||
TRACE(("cmdloop(%d) called\n", top));
|
||||
setstackmark(&smark);
|
||||
for (;;) {
|
||||
if (pendingsigs)
|
||||
if (pendingsig)
|
||||
dotrap();
|
||||
inter = 0;
|
||||
if (iflag && top) {
|
||||
|
15
bin/sh/sh.1
15
bin/sh/sh.1
@ -32,7 +32,7 @@
|
||||
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 22, 2013
|
||||
.Dd March 24, 2013
|
||||
.Dt SH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1061,6 +1061,9 @@ A subshell environment may be implemented as a child process or differently.
|
||||
If job control is enabled in an interactive shell,
|
||||
commands grouped in parentheses can be suspended and continued as a unit.
|
||||
.Pp
|
||||
For compatibility with other shells,
|
||||
two open parentheses in sequence should be separated by whitespace.
|
||||
.Pp
|
||||
The second form never forks another shell,
|
||||
so it is slightly more efficient.
|
||||
Grouping commands together this way allows the user to
|
||||
@ -1618,6 +1621,16 @@ and
|
||||
.Ic times
|
||||
returns information about the same process
|
||||
if they are the only command in a command substitution.
|
||||
.Pp
|
||||
If a command substitution of the
|
||||
.Li $(
|
||||
form begins with a subshell,
|
||||
the
|
||||
.Li $(
|
||||
and
|
||||
.Li (
|
||||
must be separated by whitespace
|
||||
to avoid ambiguity with arithmetic expansion.
|
||||
.Ss Arithmetic Expansion
|
||||
Arithmetic expansion provides a mechanism for evaluating an arithmetic
|
||||
expression and substituting its value.
|
||||
|
@ -73,7 +73,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
|
||||
MKINIT char sigmode[NSIG]; /* current value of signal */
|
||||
int pendingsigs; /* indicates some signal received */
|
||||
volatile sig_atomic_t pendingsig; /* indicates some signal received */
|
||||
int in_dotrap; /* do we execute in a trap handler? */
|
||||
static char *volatile trap[NSIG]; /* trap handler commands */
|
||||
static volatile sig_atomic_t gotsig[NSIG];
|
||||
@ -388,22 +388,25 @@ onsig(int signo)
|
||||
return;
|
||||
}
|
||||
|
||||
if (signo != SIGCHLD || !ignore_sigchld)
|
||||
gotsig[signo] = 1;
|
||||
pendingsigs++;
|
||||
|
||||
/* If we are currently in a wait builtin, prepare to break it */
|
||||
if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0)
|
||||
breakwaitcmd = 1;
|
||||
/*
|
||||
* If a trap is set, not ignored and not the null command, we need
|
||||
* to make sure traps are executed even when a child blocks signals.
|
||||
*/
|
||||
if (Tflag &&
|
||||
trap[signo] != NULL &&
|
||||
! (trap[signo][0] == '\0') &&
|
||||
! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
|
||||
if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) {
|
||||
breakwaitcmd = 1;
|
||||
pendingsig = signo;
|
||||
}
|
||||
|
||||
if (trap[signo] != NULL && trap[signo][0] != '\0' &&
|
||||
(signo != SIGCHLD || !ignore_sigchld)) {
|
||||
gotsig[signo] = 1;
|
||||
pendingsig = signo;
|
||||
|
||||
/*
|
||||
* If a trap is set, not ignored and not the null command, we
|
||||
* need to make sure traps are executed even when a child
|
||||
* blocks signals.
|
||||
*/
|
||||
if (Tflag && !(trap[signo][0] == ':' && trap[signo][1] == '\0'))
|
||||
breakwaitcmd = 1;
|
||||
}
|
||||
|
||||
#ifndef NO_HISTORY
|
||||
if (signo == SIGWINCH)
|
||||
@ -424,7 +427,7 @@ dotrap(void)
|
||||
|
||||
in_dotrap++;
|
||||
for (;;) {
|
||||
pendingsigs = 0;
|
||||
pendingsig = 0;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (gotsig[i]) {
|
||||
gotsig[i] = 0;
|
||||
@ -452,7 +455,6 @@ dotrap(void)
|
||||
last_trapsig = i;
|
||||
savestatus = exitstatus;
|
||||
evalstring(trap[i], 0);
|
||||
exitstatus = savestatus;
|
||||
|
||||
/*
|
||||
* If such a command was not
|
||||
@ -461,9 +463,11 @@ dotrap(void)
|
||||
* trap action to have an effect
|
||||
* outside of it.
|
||||
*/
|
||||
if (prev_evalskip != 0) {
|
||||
if (evalskip == 0 ||
|
||||
prev_evalskip != 0) {
|
||||
evalskip = prev_evalskip;
|
||||
skipcount = prev_skipcount;
|
||||
exitstatus = savestatus;
|
||||
}
|
||||
|
||||
if (i == SIGCHLD)
|
||||
|
@ -33,7 +33,7 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
extern int pendingsigs;
|
||||
extern volatile sig_atomic_t pendingsig;
|
||||
extern int in_dotrap;
|
||||
extern volatile sig_atomic_t gotwinch;
|
||||
|
||||
|
@ -169,15 +169,65 @@ True if
|
||||
.Ar file
|
||||
exists and is a socket.
|
||||
.It Ar file1 Fl nt Ar file2
|
||||
True if
|
||||
True if both
|
||||
.Ar file1
|
||||
exists and is newer than
|
||||
and
|
||||
.Ar file2
|
||||
exist and
|
||||
.Ar file1
|
||||
is newer than
|
||||
.Ar file2 .
|
||||
.It Ar file1 Fl nt Ns Ar X Ns Ar Y Ar file2
|
||||
True if both
|
||||
.Ar file1
|
||||
and
|
||||
.Ar file2
|
||||
exist and
|
||||
.Ar file1
|
||||
has a more recent last access time
|
||||
.Pq Ar X Ns = Ns Cm a ,
|
||||
inode creation time
|
||||
.Pq Ar X Ns = Ns Cm b ,
|
||||
change time
|
||||
.Pq Ar X Ns = Ns Cm c ,
|
||||
or modification time
|
||||
.Pq Ar X Ns = Ns Cm m
|
||||
than the last access time
|
||||
.Pq Ar Y Ns = Ns Cm a ,
|
||||
inode creation time
|
||||
.Pq Ar Y Ns = Ns Cm b ,
|
||||
change time
|
||||
.Pq Ar Y Ns = Ns Cm c ,
|
||||
or modification time
|
||||
.Pq Ar Y Ns = Ns Cm m
|
||||
of
|
||||
.Ar file2 .
|
||||
Note that
|
||||
.Ic -ntmm
|
||||
is equivalent to
|
||||
.Ic -nt .
|
||||
.It Ar file1 Fl ot Ar file2
|
||||
True if
|
||||
True if both
|
||||
.Ar file1
|
||||
exists and is older than
|
||||
and
|
||||
.Ar file2
|
||||
exist and
|
||||
.Ar file1
|
||||
is older than
|
||||
.Ar file2 .
|
||||
Note that
|
||||
.Ar file1
|
||||
.Ic -ot
|
||||
.Ar file2
|
||||
is equivalent to
|
||||
.Ar file2
|
||||
.Ic -nt
|
||||
.Ar file1
|
||||
.It Ar file1 Fl ot Ns Ar X Ns Ar Y Ar file2
|
||||
Equivalent to
|
||||
.Ar file2
|
||||
.Ic -nt Ns Ar Y Ns Ar X
|
||||
.Ar file1 .
|
||||
.It Ar file1 Fl ef Ar file2
|
||||
True if
|
||||
.Ar file1
|
||||
|
184
bin/test/test.c
184
bin/test/test.c
@ -63,7 +63,7 @@ error(const char *msg, ...)
|
||||
"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
|
||||
|
||||
binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
|
||||
"-nt"|"-ot"|"-ef";
|
||||
"-nt"|"-nt[abcm][abcm]"|"-ot"|"-ot[abcm][abcm])"|"-ef";
|
||||
operand ::= <any legal UNIX file name>
|
||||
*/
|
||||
|
||||
@ -85,8 +85,38 @@ enum token {
|
||||
FILSUID,
|
||||
FILSGID,
|
||||
FILSTCK,
|
||||
FILNT,
|
||||
FILOT,
|
||||
FILNTAA,
|
||||
FILNTAB,
|
||||
FILNTAC,
|
||||
FILNTAM,
|
||||
FILNTBA,
|
||||
FILNTBB,
|
||||
FILNTBC,
|
||||
FILNTBM,
|
||||
FILNTCA,
|
||||
FILNTCB,
|
||||
FILNTCC,
|
||||
FILNTCM,
|
||||
FILNTMA,
|
||||
FILNTMB,
|
||||
FILNTMC,
|
||||
FILNTMM,
|
||||
FILOTAA,
|
||||
FILOTAB,
|
||||
FILOTAC,
|
||||
FILOTAM,
|
||||
FILOTBA,
|
||||
FILOTBB,
|
||||
FILOTBC,
|
||||
FILOTBM,
|
||||
FILOTCA,
|
||||
FILOTCB,
|
||||
FILOTCC,
|
||||
FILOTCM,
|
||||
FILOTMA,
|
||||
FILOTMB,
|
||||
FILOTMC,
|
||||
FILOTMM,
|
||||
FILEQ,
|
||||
FILUID,
|
||||
FILGID,
|
||||
@ -118,9 +148,16 @@ enum token_types {
|
||||
PAREN
|
||||
};
|
||||
|
||||
enum time_types {
|
||||
ATIME,
|
||||
BTIME,
|
||||
CTIME,
|
||||
MTIME
|
||||
};
|
||||
|
||||
static struct t_op {
|
||||
char op_text[4];
|
||||
short op_num, op_type;
|
||||
char op_text[6];
|
||||
char op_num, op_type;
|
||||
} const ops [] = {
|
||||
{"-r", FILRD, UNOP},
|
||||
{"-w", FILWR, UNOP},
|
||||
@ -154,8 +191,40 @@ static struct t_op {
|
||||
{"-gt", INTGT, BINOP},
|
||||
{"-le", INTLE, BINOP},
|
||||
{"-lt", INTLT, BINOP},
|
||||
{"-nt", FILNT, BINOP},
|
||||
{"-ot", FILOT, BINOP},
|
||||
{"-nt", FILNTMM, BINOP},
|
||||
{"-ntaa", FILNTAA, BINOP},
|
||||
{"-ntab", FILNTAB, BINOP},
|
||||
{"-ntac", FILNTAC, BINOP},
|
||||
{"-ntam", FILNTAM, BINOP},
|
||||
{"-ntba", FILNTBA, BINOP},
|
||||
{"-ntbb", FILNTBB, BINOP},
|
||||
{"-ntbc", FILNTBC, BINOP},
|
||||
{"-ntbm", FILNTBM, BINOP},
|
||||
{"-ntca", FILNTCA, BINOP},
|
||||
{"-ntcb", FILNTCB, BINOP},
|
||||
{"-ntcc", FILNTCC, BINOP},
|
||||
{"-ntcm", FILNTCM, BINOP},
|
||||
{"-ntma", FILNTMA, BINOP},
|
||||
{"-ntmb", FILNTMB, BINOP},
|
||||
{"-ntmc", FILNTMC, BINOP},
|
||||
{"-ntmm", FILNTMM, BINOP},
|
||||
{"-ot", FILOTMM, BINOP},
|
||||
{"-otaa", FILOTAA, BINOP},
|
||||
{"-otab", FILOTBB, BINOP},
|
||||
{"-otac", FILOTAC, BINOP},
|
||||
{"-otam", FILOTAM, BINOP},
|
||||
{"-otba", FILOTBA, BINOP},
|
||||
{"-otbb", FILOTBB, BINOP},
|
||||
{"-otbc", FILOTBC, BINOP},
|
||||
{"-otbm", FILOTBM, BINOP},
|
||||
{"-otca", FILOTCA, BINOP},
|
||||
{"-otcb", FILOTCB, BINOP},
|
||||
{"-otcc", FILOTCC, BINOP},
|
||||
{"-otcm", FILOTCM, BINOP},
|
||||
{"-otma", FILOTMA, BINOP},
|
||||
{"-otmb", FILOTMB, BINOP},
|
||||
{"-otmc", FILOTMC, BINOP},
|
||||
{"-otmm", FILOTMM, BINOP},
|
||||
{"-ef", FILEQ, BINOP},
|
||||
{"!", UNOT, BUNOP},
|
||||
{"-a", BAND, BBINOP},
|
||||
@ -180,10 +249,10 @@ static int intcmp(const char *, const char *);
|
||||
static int isunopoperand(void);
|
||||
static int islparenoperand(void);
|
||||
static int isrparenoperand(void);
|
||||
static int newerf(const char *, const char *);
|
||||
static int newerf(const char *, const char *, enum time_types,
|
||||
enum time_types);
|
||||
static int nexpr(enum token);
|
||||
static int oexpr(enum token);
|
||||
static int olderf(const char *, const char *);
|
||||
static int primary(enum token);
|
||||
static void syntax(const char *, const char *);
|
||||
static enum token t_lex(char *);
|
||||
@ -353,10 +422,70 @@ binop(void)
|
||||
return intcmp(opnd1, opnd2) <= 0;
|
||||
case INTLT:
|
||||
return intcmp(opnd1, opnd2) < 0;
|
||||
case FILNT:
|
||||
return newerf (opnd1, opnd2);
|
||||
case FILOT:
|
||||
return olderf (opnd1, opnd2);
|
||||
case FILNTAA:
|
||||
return newerf(opnd1, opnd2, ATIME, ATIME);
|
||||
case FILNTAB:
|
||||
return newerf(opnd1, opnd2, ATIME, BTIME);
|
||||
case FILNTAC:
|
||||
return newerf(opnd1, opnd2, ATIME, CTIME);
|
||||
case FILNTAM:
|
||||
return newerf(opnd1, opnd2, ATIME, MTIME);
|
||||
case FILNTBA:
|
||||
return newerf(opnd1, opnd2, BTIME, ATIME);
|
||||
case FILNTBB:
|
||||
return newerf(opnd1, opnd2, BTIME, BTIME);
|
||||
case FILNTBC:
|
||||
return newerf(opnd1, opnd2, BTIME, CTIME);
|
||||
case FILNTBM:
|
||||
return newerf(opnd1, opnd2, BTIME, MTIME);
|
||||
case FILNTCA:
|
||||
return newerf(opnd1, opnd2, CTIME, ATIME);
|
||||
case FILNTCB:
|
||||
return newerf(opnd1, opnd2, CTIME, BTIME);
|
||||
case FILNTCC:
|
||||
return newerf(opnd1, opnd2, CTIME, CTIME);
|
||||
case FILNTCM:
|
||||
return newerf(opnd1, opnd2, CTIME, MTIME);
|
||||
case FILNTMA:
|
||||
return newerf(opnd1, opnd2, MTIME, ATIME);
|
||||
case FILNTMB:
|
||||
return newerf(opnd1, opnd2, MTIME, BTIME);
|
||||
case FILNTMC:
|
||||
return newerf(opnd1, opnd2, MTIME, CTIME);
|
||||
case FILNTMM:
|
||||
return newerf(opnd1, opnd2, MTIME, MTIME);
|
||||
case FILOTAA:
|
||||
return newerf(opnd2, opnd1, ATIME, ATIME);
|
||||
case FILOTAB:
|
||||
return newerf(opnd2, opnd1, BTIME, ATIME);
|
||||
case FILOTAC:
|
||||
return newerf(opnd2, opnd1, CTIME, ATIME);
|
||||
case FILOTAM:
|
||||
return newerf(opnd2, opnd1, MTIME, ATIME);
|
||||
case FILOTBA:
|
||||
return newerf(opnd2, opnd1, ATIME, BTIME);
|
||||
case FILOTBB:
|
||||
return newerf(opnd2, opnd1, BTIME, BTIME);
|
||||
case FILOTBC:
|
||||
return newerf(opnd2, opnd1, CTIME, BTIME);
|
||||
case FILOTBM:
|
||||
return newerf(opnd2, opnd1, MTIME, BTIME);
|
||||
case FILOTCA:
|
||||
return newerf(opnd2, opnd1, ATIME, CTIME);
|
||||
case FILOTCB:
|
||||
return newerf(opnd2, opnd1, BTIME, CTIME);
|
||||
case FILOTCC:
|
||||
return newerf(opnd2, opnd1, CTIME, CTIME);
|
||||
case FILOTCM:
|
||||
return newerf(opnd2, opnd1, MTIME, CTIME);
|
||||
case FILOTMA:
|
||||
return newerf(opnd2, opnd1, ATIME, MTIME);
|
||||
case FILOTMB:
|
||||
return newerf(opnd2, opnd1, BTIME, MTIME);
|
||||
case FILOTMC:
|
||||
return newerf(opnd2, opnd1, CTIME, MTIME);
|
||||
case FILOTMM:
|
||||
return newerf(opnd2, opnd1, MTIME, MTIME);
|
||||
case FILEQ:
|
||||
return equalf (opnd1, opnd2);
|
||||
default:
|
||||
@ -570,25 +699,34 @@ intcmp (const char *s1, const char *s2)
|
||||
}
|
||||
|
||||
static int
|
||||
newerf (const char *f1, const char *f2)
|
||||
newerf (const char *f1, const char *f2, enum time_types t1, enum time_types t2)
|
||||
{
|
||||
struct stat b1, b2;
|
||||
struct timespec *ts1, *ts2;
|
||||
|
||||
if (stat(f1, &b1) != 0 || stat(f2, &b2) != 0)
|
||||
return 0;
|
||||
|
||||
if (b1.st_mtim.tv_sec > b2.st_mtim.tv_sec)
|
||||
switch (t1) {
|
||||
case ATIME: ts1 = &b1.st_atim; break;
|
||||
case BTIME: ts1 = &b1.st_birthtim; break;
|
||||
case CTIME: ts1 = &b1.st_ctim; break;
|
||||
default: ts1 = &b1.st_mtim; break;
|
||||
}
|
||||
|
||||
switch (t2) {
|
||||
case ATIME: ts2 = &b2.st_atim; break;
|
||||
case BTIME: ts2 = &b2.st_birthtim; break;
|
||||
case CTIME: ts2 = &b2.st_ctim; break;
|
||||
default: ts2 = &b2.st_mtim; break;
|
||||
}
|
||||
|
||||
if (ts1->tv_sec > ts2->tv_sec)
|
||||
return 1;
|
||||
if (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec)
|
||||
if (ts1->tv_sec < ts2->tv_sec)
|
||||
return 0;
|
||||
|
||||
return (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec);
|
||||
}
|
||||
|
||||
static int
|
||||
olderf (const char *f1, const char *f2)
|
||||
{
|
||||
return (newerf(f2, f1));
|
||||
return (ts1->tv_nsec > ts2->tv_nsec);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -195,6 +195,13 @@ fatal(const char *fmt, ...)
|
||||
verror(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/*
|
||||
* Close the DTrace handle to ensure that any controlled processes are
|
||||
* correctly restored and continued.
|
||||
*/
|
||||
if (g_dtp)
|
||||
dtrace_close(g_dtp);
|
||||
|
||||
exit(E_ERROR);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
trace(tolower(2152006));
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
trace(toupper(timestamp));
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
trace(tolower());
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
trace(tolower("dory", "eel", "roughy"));
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
trace(toupper());
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
trace(tolower("haino", "tylo"));
|
||||
exit(1);
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
int64_t val[int];
|
||||
|
||||
BEGIN
|
||||
{
|
||||
base = -2;
|
||||
i = 0;
|
||||
val[i++] = -10;
|
||||
val[i++] = -1;
|
||||
val[i++] = 0;
|
||||
val[i++] = 10;
|
||||
val[i++] = 100;
|
||||
val[i++] = 1000;
|
||||
val[i++] = (1LL << 62);
|
||||
maxval = i;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/i < maxval/
|
||||
{
|
||||
printf("base %2d of %20d: ", base, val[i]);
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/i < maxval/
|
||||
{
|
||||
printf(" %s\n", lltostr(val[i], base));
|
||||
}
|
||||
|
||||
ERROR
|
||||
{
|
||||
printf(" <error>\n");
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/i < maxval/
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/i == maxval/
|
||||
{
|
||||
i = 0;
|
||||
base++;
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/base > 40/
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
@ -0,0 +1,302 @@
|
||||
base -2 of -10: <error>
|
||||
base -2 of -1: <error>
|
||||
base -2 of 0: <error>
|
||||
base -2 of 10: <error>
|
||||
base -2 of 100: <error>
|
||||
base -2 of 1000: <error>
|
||||
base -2 of 4611686018427387904: <error>
|
||||
base -1 of -10: <error>
|
||||
base -1 of -1: <error>
|
||||
base -1 of 0: <error>
|
||||
base -1 of 10: <error>
|
||||
base -1 of 100: <error>
|
||||
base -1 of 1000: <error>
|
||||
base -1 of 4611686018427387904: <error>
|
||||
base 0 of -10: <error>
|
||||
base 0 of -1: <error>
|
||||
base 0 of 0: <error>
|
||||
base 0 of 10: <error>
|
||||
base 0 of 100: <error>
|
||||
base 0 of 1000: <error>
|
||||
base 0 of 4611686018427387904: <error>
|
||||
base 1 of -10: <error>
|
||||
base 1 of -1: <error>
|
||||
base 1 of 0: <error>
|
||||
base 1 of 10: <error>
|
||||
base 1 of 100: <error>
|
||||
base 1 of 1000: <error>
|
||||
base 1 of 4611686018427387904: <error>
|
||||
base 2 of -10: 1111111111111111111111111111111111111111111111111111111111110110
|
||||
base 2 of -1: 1111111111111111111111111111111111111111111111111111111111111111
|
||||
base 2 of 0: 0
|
||||
base 2 of 10: 1010
|
||||
base 2 of 100: 1100100
|
||||
base 2 of 1000: 1111101000
|
||||
base 2 of 4611686018427387904: 100000000000000000000000000000000000000000000000000000000000000
|
||||
base 3 of -10: 11112220022122120101211020120210210211120
|
||||
base 3 of -1: 11112220022122120101211020120210210211220
|
||||
base 3 of 0: 0
|
||||
base 3 of 10: 101
|
||||
base 3 of 100: 10201
|
||||
base 3 of 1000: 1101001
|
||||
base 3 of 4611686018427387904: 1010201120122220002201001122110012110111
|
||||
base 4 of -10: 33333333333333333333333333333312
|
||||
base 4 of -1: 33333333333333333333333333333333
|
||||
base 4 of 0: 0
|
||||
base 4 of 10: 22
|
||||
base 4 of 100: 1210
|
||||
base 4 of 1000: 33220
|
||||
base 4 of 4611686018427387904: 10000000000000000000000000000000
|
||||
base 5 of -10: 2214220303114400424121122411
|
||||
base 5 of -1: 2214220303114400424121122430
|
||||
base 5 of 0: 0
|
||||
base 5 of 10: 20
|
||||
base 5 of 100: 400
|
||||
base 5 of 1000: 13000
|
||||
base 5 of 4611686018427387904: 302141200402211214402403104
|
||||
base 6 of -10: 3520522010102100444244410
|
||||
base 6 of -1: 3520522010102100444244423
|
||||
base 6 of 0: 0
|
||||
base 6 of 10: 14
|
||||
base 6 of 100: 244
|
||||
base 6 of 1000: 4344
|
||||
base 6 of 4611686018427387904: 550120301313313111041104
|
||||
base 7 of -10: 45012021522523134134556
|
||||
base 7 of -1: 45012021522523134134601
|
||||
base 7 of 0: 0
|
||||
base 7 of 10: 13
|
||||
base 7 of 100: 202
|
||||
base 7 of 1000: 2626
|
||||
base 7 of 4611686018427387904: 11154003640456024361134
|
||||
base 8 of -10: 01777777777777777777766
|
||||
base 8 of -1: 01777777777777777777777
|
||||
base 8 of 0: 0
|
||||
base 8 of 10: 012
|
||||
base 8 of 100: 0144
|
||||
base 8 of 1000: 01750
|
||||
base 8 of 4611686018427387904: 0400000000000000000000
|
||||
base 9 of -10: 145808576354216723746
|
||||
base 9 of -1: 145808576354216723756
|
||||
base 9 of 0: 0
|
||||
base 9 of 10: 11
|
||||
base 9 of 100: 121
|
||||
base 9 of 1000: 1331
|
||||
base 9 of 4611686018427387904: 33646586081048405414
|
||||
base 10 of -10: -10
|
||||
base 10 of -1: -1
|
||||
base 10 of 0: 0
|
||||
base 10 of 10: 10
|
||||
base 10 of 100: 100
|
||||
base 10 of 1000: 1000
|
||||
base 10 of 4611686018427387904: 4611686018427387904
|
||||
base 11 of -10: 335500516a429071276
|
||||
base 11 of -1: 335500516a429071284
|
||||
base 11 of 0: 0
|
||||
base 11 of 10: a
|
||||
base 11 of 100: 91
|
||||
base 11 of 1000: 82a
|
||||
base 11 of 4611686018427387904: 9140013181078458a4
|
||||
base 12 of -10: 839365134a2a240706
|
||||
base 12 of -1: 839365134a2a240713
|
||||
base 12 of 0: 0
|
||||
base 12 of 10: a
|
||||
base 12 of 100: 84
|
||||
base 12 of 1000: 6b4
|
||||
base 12 of 4611686018427387904: 20b3a733a268670194
|
||||
base 13 of -10: 219505a9511a867b66
|
||||
base 13 of -1: 219505a9511a867b72
|
||||
base 13 of 0: 0
|
||||
base 13 of 10: a
|
||||
base 13 of 100: 79
|
||||
base 13 of 1000: 5bc
|
||||
base 13 of 4611686018427387904: 6c1349246a2881c84
|
||||
base 14 of -10: 8681049adb03db166
|
||||
base 14 of -1: 8681049adb03db171
|
||||
base 14 of 0: 0
|
||||
base 14 of 10: a
|
||||
base 14 of 100: 72
|
||||
base 14 of 1000: 516
|
||||
base 14 of 4611686018427387904: 219038263637dd3c4
|
||||
base 15 of -10: 2c1d56b648c6cd106
|
||||
base 15 of -1: 2c1d56b648c6cd110
|
||||
base 15 of 0: 0
|
||||
base 15 of 10: a
|
||||
base 15 of 100: 6a
|
||||
base 15 of 1000: 46a
|
||||
base 15 of 4611686018427387904: a7e8ce189a933404
|
||||
base 16 of -10: 0xfffffffffffffff6
|
||||
base 16 of -1: 0xffffffffffffffff
|
||||
base 16 of 0: 0x0
|
||||
base 16 of 10: 0xa
|
||||
base 16 of 100: 0x64
|
||||
base 16 of 1000: 0x3e8
|
||||
base 16 of 4611686018427387904: 0x4000000000000000
|
||||
base 17 of -10: 67979g60f5428008
|
||||
base 17 of -1: 67979g60f5428010
|
||||
base 17 of 0: 0
|
||||
base 17 of 10: a
|
||||
base 17 of 100: 5f
|
||||
base 17 of 1000: 37e
|
||||
base 17 of 4611686018427387904: 1a6a6ca03e10a88d
|
||||
base 18 of -10: 2d3fgb0b9cg4bd26
|
||||
base 18 of -1: 2d3fgb0b9cg4bd2f
|
||||
base 18 of 0: 0
|
||||
base 18 of 10: a
|
||||
base 18 of 100: 5a
|
||||
base 18 of 1000: 31a
|
||||
base 18 of 4611686018427387904: c588bdbfgd12ge4
|
||||
base 19 of -10: 141c8786h1ccaag7
|
||||
base 19 of -1: 141c8786h1ccaagg
|
||||
base 19 of 0: 0
|
||||
base 19 of 10: a
|
||||
base 19 of 100: 55
|
||||
base 19 of 1000: 2ec
|
||||
base 19 of 4611686018427387904: 5ecbb6fi9h7ggi9
|
||||
base 20 of -10: b53bjh07be4dj06
|
||||
base 20 of -1: b53bjh07be4dj0f
|
||||
base 20 of 0: 0
|
||||
base 20 of 10: a
|
||||
base 20 of 100: 50
|
||||
base 20 of 1000: 2a0
|
||||
base 20 of 4611686018427387904: 2g5hjj51hib39f4
|
||||
base 21 of -10: 5e8g4ggg7g56di6
|
||||
base 21 of -1: 5e8g4ggg7g56dif
|
||||
base 21 of 0: 0
|
||||
base 21 of 10: a
|
||||
base 21 of 100: 4g
|
||||
base 21 of 1000: 25d
|
||||
base 21 of 4611686018427387904: 18hjgjjjhebh8f4
|
||||
base 22 of -10: 2l4lf104353j8k6
|
||||
base 22 of -1: 2l4lf104353j8kf
|
||||
base 22 of 0: 0
|
||||
base 22 of 10: a
|
||||
base 22 of 100: 4c
|
||||
base 22 of 1000: 21a
|
||||
base 22 of 4611686018427387904: g6g95gc0hha7g4
|
||||
base 23 of -10: 1ddh88h2782i50j
|
||||
base 23 of -1: 1ddh88h2782i515
|
||||
base 23 of 0: 0
|
||||
base 23 of 10: a
|
||||
base 23 of 100: 48
|
||||
base 23 of 1000: 1kb
|
||||
base 23 of 4611686018427387904: 93a22467dc4chd
|
||||
base 24 of -10: l12ee5fn0ji1i6
|
||||
base 24 of -1: l12ee5fn0ji1if
|
||||
base 24 of 0: 0
|
||||
base 24 of 10: a
|
||||
base 24 of 100: 44
|
||||
base 24 of 1000: 1hg
|
||||
base 24 of 4611686018427387904: 566ffd9ni4mcag
|
||||
base 25 of -10: c9c336o0mlb7e6
|
||||
base 25 of -1: c9c336o0mlb7ef
|
||||
base 25 of 0: 0
|
||||
base 25 of 10: a
|
||||
base 25 of 100: 40
|
||||
base 25 of 1000: 1f0
|
||||
base 25 of 4611686018427387904: 32970kc6bo2kg4
|
||||
base 26 of -10: 7b7n2pcniokcg6
|
||||
base 26 of -1: 7b7n2pcniokcgf
|
||||
base 26 of 0: 0
|
||||
base 26 of 10: a
|
||||
base 26 of 100: 3m
|
||||
base 26 of 1000: 1cc
|
||||
base 26 of 4611686018427387904: 1m8c769io65344
|
||||
base 27 of -10: 4eo8hfam6fllmf
|
||||
base 27 of -1: 4eo8hfam6fllmo
|
||||
base 27 of 0: 0
|
||||
base 27 of 10: a
|
||||
base 27 of 100: 3j
|
||||
base 27 of 1000: 1a1
|
||||
base 27 of 4611686018427387904: 13jfho2j1hc5cd
|
||||
base 28 of -10: 2nc6j26l66rho6
|
||||
base 28 of -1: 2nc6j26l66rhof
|
||||
base 28 of 0: 0
|
||||
base 28 of 10: a
|
||||
base 28 of 100: 3g
|
||||
base 28 of 1000: 17k
|
||||
base 28 of 4611686018427387904: jo1ilfj8fkpd4
|
||||
base 29 of -10: 1n3rsh11f098re
|
||||
base 29 of -1: 1n3rsh11f098rn
|
||||
base 29 of 0: 0
|
||||
base 29 of 10: a
|
||||
base 29 of 100: 3d
|
||||
base 29 of 1000: 15e
|
||||
base 29 of 4611686018427387904: d0slim0b029e6
|
||||
base 30 of -10: 14l9lkmo30o406
|
||||
base 30 of -1: 14l9lkmo30o40f
|
||||
base 30 of 0: 0
|
||||
base 30 of 10: a
|
||||
base 30 of 100: 3a
|
||||
base 30 of 1000: 13a
|
||||
base 30 of 4611686018427387904: 8k9rrkl0ml104
|
||||
base 31 of -10: nd075ib45k866
|
||||
base 31 of -1: nd075ib45k86f
|
||||
base 31 of 0: 0
|
||||
base 31 of 10: a
|
||||
base 31 of 100: 37
|
||||
base 31 of 1000: 118
|
||||
base 31 of 4611686018427387904: 5qfh94i8okhh4
|
||||
base 32 of -10: fvvvvvvvvvvvm
|
||||
base 32 of -1: fvvvvvvvvvvvv
|
||||
base 32 of 0: 0
|
||||
base 32 of 10: a
|
||||
base 32 of 100: 34
|
||||
base 32 of 1000: v8
|
||||
base 32 of 4611686018427387904: 4000000000000
|
||||
base 33 of -10: b1w8p7j5q9r66
|
||||
base 33 of -1: b1w8p7j5q9r6f
|
||||
base 33 of 0: 0
|
||||
base 33 of 10: a
|
||||
base 33 of 100: 31
|
||||
base 33 of 1000: ua
|
||||
base 33 of 4611686018427387904: 2p826a4q6ivi4
|
||||
base 34 of -10: 7orp63sh4dph8
|
||||
base 34 of -1: 7orp63sh4dphh
|
||||
base 34 of 0: 0
|
||||
base 34 of 10: a
|
||||
base 34 of 100: 2w
|
||||
base 34 of 1000: te
|
||||
base 34 of 4611686018427387904: 1vnvr0wl9ketu
|
||||
base 35 of -10: 5g24a25twkwf6
|
||||
base 35 of -1: 5g24a25twkwff
|
||||
base 35 of 0: 0
|
||||
base 35 of 10: a
|
||||
base 35 of 100: 2u
|
||||
base 35 of 1000: sk
|
||||
base 35 of 4611686018427387904: 1cqrb9a7gvgu4
|
||||
base 36 of -10: 3w5e11264sgs6
|
||||
base 36 of -1: 3w5e11264sgsf
|
||||
base 36 of 0: 0
|
||||
base 36 of 10: a
|
||||
base 36 of 100: 2s
|
||||
base 36 of 1000: rs
|
||||
base 36 of 4611686018427387904: z1ci99jj7474
|
||||
base 37 of -10: <error>
|
||||
base 37 of -1: <error>
|
||||
base 37 of 0: <error>
|
||||
base 37 of 10: <error>
|
||||
base 37 of 100: <error>
|
||||
base 37 of 1000: <error>
|
||||
base 37 of 4611686018427387904: <error>
|
||||
base 38 of -10: <error>
|
||||
base 38 of -1: <error>
|
||||
base 38 of 0: <error>
|
||||
base 38 of 10: <error>
|
||||
base 38 of 100: <error>
|
||||
base 38 of 1000: <error>
|
||||
base 38 of 4611686018427387904: <error>
|
||||
base 39 of -10: <error>
|
||||
base 39 of -1: <error>
|
||||
base 39 of 0: <error>
|
||||
base 39 of 10: <error>
|
||||
base 39 of 100: <error>
|
||||
base 39 of 1000: <error>
|
||||
base 39 of 4611686018427387904: <error>
|
||||
base 40 of -10: <error>
|
||||
base 40 of -1: <error>
|
||||
base 40 of 0: <error>
|
||||
base 40 of 10: <error>
|
||||
base 40 of 100: <error>
|
||||
base 40 of 1000: <error>
|
||||
base 40 of 4611686018427387904: <error>
|
||||
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
BEGIN
|
||||
{
|
||||
i = 0;
|
||||
|
||||
input[i] = "ahi";
|
||||
expected[i++] = "ahi";
|
||||
|
||||
input[i] = "MaHi!";
|
||||
expected[i++] = "mahi!";
|
||||
|
||||
input[i] = " Nase-5";
|
||||
expected[i++] = " nase-5";
|
||||
|
||||
input[i] = "!@#$%";
|
||||
expected[i++] = "!@#$%";
|
||||
|
||||
i = 0;
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/input[i] != NULL && (this->out = tolower(input[i])) != expected[i]/
|
||||
{
|
||||
printf("expected tolower(\"%s\") to be \"%s\"; found \"%s\"\n",
|
||||
input[i], expected[i], this->out);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/input[i] != NULL/
|
||||
{
|
||||
printf("tolower(\"%s\") is \"%s\", as expected\n",
|
||||
input[i], expected[i]);
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/input[i++] == NULL/
|
||||
{
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
BEGIN
|
||||
{
|
||||
i = 0;
|
||||
|
||||
input[i] = "ahi";
|
||||
expected[i++] = "AHI";
|
||||
|
||||
input[i] = "MaHi!";
|
||||
expected[i++] = "MAHI!";
|
||||
|
||||
input[i] = " dace-9";
|
||||
expected[i++] = " DACE-9";
|
||||
|
||||
input[i] = "!@#$%";
|
||||
expected[i++] = "!@#$%";
|
||||
|
||||
i = 0;
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/input[i] != NULL && (this->out = toupper(input[i])) != expected[i]/
|
||||
{
|
||||
printf("expected toupper(\"%s\") to be \"%s\"; found \"%s\"\n",
|
||||
input[i], expected[i], this->out);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/input[i] != NULL/
|
||||
{
|
||||
printf("toupper(\"%s\") is \"%s\", as expected\n",
|
||||
input[i], expected[i]);
|
||||
}
|
||||
|
||||
tick-1ms
|
||||
/input[i++] == NULL/
|
||||
{
|
||||
exit(0);
|
||||
}
|
@ -24,7 +24,9 @@
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
/*
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ASSERTION:
|
||||
@ -32,44 +34,51 @@
|
||||
* a runtime error.
|
||||
*
|
||||
* SECTION: Pointers and Arrays/Generic Pointers
|
||||
*
|
||||
* NOTES:
|
||||
* This test doesn't apply to x86; for the time being, we're working
|
||||
* around this with the preprocessor.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
int array[3];
|
||||
uintptr_t uptr;
|
||||
#if defined(__i386) || defined(__amd64)
|
||||
#define __x86 1
|
||||
#endif
|
||||
|
||||
int array[2];
|
||||
char *ptr;
|
||||
int *p;
|
||||
int *q;
|
||||
int *r;
|
||||
|
||||
BEGIN
|
||||
{
|
||||
#ifdef __i386
|
||||
array[0] = 0x12345678;
|
||||
array[1] = 0xabcdefff;
|
||||
|
||||
ptr = (char *) &array[0];
|
||||
|
||||
p = (int *) (ptr);
|
||||
q = (int *) (ptr + 2);
|
||||
r = (int *) (ptr + 3);
|
||||
|
||||
printf("*p: 0x%x\n", *p);
|
||||
printf("*q: 0x%x\n", *q);
|
||||
printf("*r: 0x%x\n", *r);
|
||||
|
||||
/*
|
||||
* On x86, the above unaligned memory accesses are allowed and should
|
||||
* not result in the ERROR probe firing.
|
||||
*/
|
||||
#ifdef __x86
|
||||
exit(1);
|
||||
#else
|
||||
array[0] = 20;
|
||||
array[1] = 40;
|
||||
array[2] = 80;
|
||||
|
||||
uptr = (uintptr_t) &array[0];
|
||||
|
||||
p = (int *) (uptr);
|
||||
q = (int *) (uptr + 2);
|
||||
r = (int *) (uptr + 3);
|
||||
|
||||
printf("array[0]: %d\t*p: %d\n", array[0], *p);
|
||||
printf("array[1]: %d\t*q: %d\n", array[1], *q);
|
||||
printf("array[2]: %d\t*r: %d\n", array[2], *r);
|
||||
|
||||
exit(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
ERROR
|
||||
{
|
||||
#ifdef __x86
|
||||
exit(0);
|
||||
#else
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
print(*curpsinfo);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
print((void)`p0);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
print();
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
typedef struct bar {
|
||||
int alpha;
|
||||
} bar_t;
|
||||
|
||||
typedef struct foo {
|
||||
int a[3];
|
||||
char b[30];
|
||||
bar_t c[2];
|
||||
char d[3];
|
||||
} foo_t;
|
||||
|
||||
BEGIN
|
||||
{
|
||||
this->f = (foo_t *)alloca(sizeof (foo_t));
|
||||
|
||||
this->f->a[0] = 1;
|
||||
this->f->a[1] = 2;
|
||||
this->f->a[2] = 3;
|
||||
this->f->b[0] = 'a';
|
||||
this->f->b[1] = 'b';
|
||||
this->f->b[2] = 0;
|
||||
this->f->c[0].alpha = 5;
|
||||
this->f->c[1].alpha = 6;
|
||||
this->f->c[2].alpha = 7;
|
||||
this->f->d[0] = 4;
|
||||
this->f->d[1] = 0;
|
||||
this->f->d[2] = 0;
|
||||
|
||||
print(this->f->a);
|
||||
print(this->f->b);
|
||||
print(this->f->c);
|
||||
print(*this->f);
|
||||
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
int [3] [ 0x1, 0x2, 0x3 ]
|
||||
char [30] "ab"
|
||||
bar_t [2] [
|
||||
bar_t {
|
||||
int alpha = 0x5
|
||||
},
|
||||
bar_t {
|
||||
int alpha = 0x6
|
||||
}
|
||||
]
|
||||
foo_t {
|
||||
int [3] a = [ 0x1, 0x2, 0x3 ]
|
||||
char [30] b = [ "ab" ]
|
||||
bar_t [2] c = [
|
||||
bar_t {
|
||||
int alpha = 0x5
|
||||
},
|
||||
bar_t {
|
||||
int alpha = 0x6
|
||||
}
|
||||
]
|
||||
char [3] d = [ '\004', '\0', '\0' ]
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
typedef struct forward forward_t;
|
||||
|
||||
typedef struct foo {
|
||||
int a:4;
|
||||
int b:7;
|
||||
int c:1;
|
||||
int d:2;
|
||||
} foo_t;
|
||||
|
||||
BEGIN
|
||||
{
|
||||
this->s = (foo_t *)alloca(sizeof (foo_t));
|
||||
|
||||
this->s->a = 1;
|
||||
this->s->b = 5;
|
||||
this->s->c = 0;
|
||||
this->s->d = 2;
|
||||
|
||||
print(*this->s);
|
||||
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
foo_t {
|
||||
int a :4 = 0x1
|
||||
int b :7 = 0x5
|
||||
int c :1 = 0
|
||||
int d :2 = 0x2
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
BEGIN
|
||||
{
|
||||
i = (int)'a';
|
||||
|
||||
printf("\n");
|
||||
|
||||
print((char)'a');
|
||||
print((int)-1);
|
||||
print((unsigned int)23);
|
||||
print((short)456);
|
||||
print((unsigned short)789);
|
||||
print((long)1234);
|
||||
print((ulong_t)56789);
|
||||
print((void *)0x1234);
|
||||
print("hello");
|
||||
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
|
||||
char 'a'
|
||||
int 0xffffffff
|
||||
unsigned int 0x17
|
||||
short 0x1c8
|
||||
unsigned short 0x315
|
||||
long 0x4d2
|
||||
ulong_t 0xddd5
|
||||
void * 0x1234
|
||||
string "hello"
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma D option quiet
|
||||
|
||||
typedef struct forward forward_t;
|
||||
|
||||
typedef struct foo {
|
||||
int a;
|
||||
void *b;
|
||||
struct {
|
||||
uint64_t alpha;
|
||||
uint64_t beta;
|
||||
} c;
|
||||
ushort_t d;
|
||||
int e;
|
||||
forward_t *f;
|
||||
void (*g)();
|
||||
} foo_t;
|
||||
|
||||
BEGIN
|
||||
{
|
||||
this->s = (foo_t *)alloca(sizeof (foo_t));
|
||||
|
||||
this->s->a = 1;
|
||||
this->s->b = (void *)2;
|
||||
this->s->c.alpha = 3;
|
||||
this->s->c.beta = 4;
|
||||
this->s->d = 5;
|
||||
this->s->e = 6;
|
||||
this->s->f = (void *)7;
|
||||
this->s->g = (void *)8;
|
||||
|
||||
print(*this->s);
|
||||
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
foo_t {
|
||||
int a = 0x1
|
||||
void *b = 0x2
|
||||
struct c = {
|
||||
uint64_t alpha = 0x3
|
||||
uint64_t beta = 0x4
|
||||
}
|
||||
ushort_t d = 0x5
|
||||
int e = 0x6
|
||||
forward_t *f = 0x7
|
||||
int (*)() g = 0x8
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
tracemem(`dtrace_zero, 256, 0, "fishpong");
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
BEGIN
|
||||
{
|
||||
tracemem(`dtrace_zero, 256, "fishpong");
|
||||
exit(0);
|
||||
}
|
@ -20,20 +20,26 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
/*
|
||||
* ASSERTION:
|
||||
* Test tracemem() with too many arguments.
|
||||
*
|
||||
* SECTION: Actions and Subroutines/tracemem()
|
||||
*/
|
||||
#pragma D option quiet
|
||||
|
||||
BEGIN
|
||||
{
|
||||
tracemem(123, 456, 789);
|
||||
i = -10;
|
||||
}
|
||||
|
||||
tick-10ms
|
||||
/i++ < 150/
|
||||
{
|
||||
printf("%d:", i);
|
||||
tracemem(`dtrace_zero, 128, i);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
tick-10ms
|
||||
/i >= 150/
|
||||
{
|
||||
exit(0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -57,6 +57,7 @@
|
||||
#include <sys/arc.h>
|
||||
#include <sys/ddt.h>
|
||||
#include <sys/zfeature.h>
|
||||
#include <zfs_comutil.h>
|
||||
#undef ZFS_MAXNAMELEN
|
||||
#undef verify
|
||||
#include <libzfs.h>
|
||||
@ -206,6 +207,27 @@ dump_packed_nvlist(objset_t *os, uint64_t object, void *data, size_t size)
|
||||
nvlist_free(nv);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
dump_history_offsets(objset_t *os, uint64_t object, void *data, size_t size)
|
||||
{
|
||||
spa_history_phys_t *shp = data;
|
||||
|
||||
if (shp == NULL)
|
||||
return;
|
||||
|
||||
(void) printf("\t\tpool_create_len = %llu\n",
|
||||
(u_longlong_t)shp->sh_pool_create_len);
|
||||
(void) printf("\t\tphys_max_off = %llu\n",
|
||||
(u_longlong_t)shp->sh_phys_max_off);
|
||||
(void) printf("\t\tbof = %llu\n",
|
||||
(u_longlong_t)shp->sh_bof);
|
||||
(void) printf("\t\teof = %llu\n",
|
||||
(u_longlong_t)shp->sh_eof);
|
||||
(void) printf("\t\trecords_lost = %llu\n",
|
||||
(u_longlong_t)shp->sh_records_lost);
|
||||
}
|
||||
|
||||
static void
|
||||
zdb_nicenum(uint64_t num, char *buf)
|
||||
{
|
||||
@ -545,7 +567,7 @@ static void
|
||||
dump_metaslab_stats(metaslab_t *msp)
|
||||
{
|
||||
char maxbuf[32];
|
||||
space_map_t *sm = &msp->ms_map;
|
||||
space_map_t *sm = msp->ms_map;
|
||||
avl_tree_t *t = sm->sm_pp_root;
|
||||
int free_pct = sm->sm_space * 100 / sm->sm_size;
|
||||
|
||||
@ -561,7 +583,7 @@ dump_metaslab(metaslab_t *msp)
|
||||
{
|
||||
vdev_t *vd = msp->ms_group->mg_vd;
|
||||
spa_t *spa = vd->vdev_spa;
|
||||
space_map_t *sm = &msp->ms_map;
|
||||
space_map_t *sm = msp->ms_map;
|
||||
space_map_obj_t *smo = &msp->ms_smo;
|
||||
char freebuf[32];
|
||||
|
||||
@ -857,21 +879,22 @@ dump_history(spa_t *spa)
|
||||
for (int i = 0; i < num; i++) {
|
||||
uint64_t time, txg, ievent;
|
||||
char *cmd, *intstr;
|
||||
boolean_t printed = B_FALSE;
|
||||
|
||||
if (nvlist_lookup_uint64(events[i], ZPOOL_HIST_TIME,
|
||||
&time) != 0)
|
||||
continue;
|
||||
goto next;
|
||||
if (nvlist_lookup_string(events[i], ZPOOL_HIST_CMD,
|
||||
&cmd) != 0) {
|
||||
if (nvlist_lookup_uint64(events[i],
|
||||
ZPOOL_HIST_INT_EVENT, &ievent) != 0)
|
||||
continue;
|
||||
goto next;
|
||||
verify(nvlist_lookup_uint64(events[i],
|
||||
ZPOOL_HIST_TXG, &txg) == 0);
|
||||
verify(nvlist_lookup_string(events[i],
|
||||
ZPOOL_HIST_INT_STR, &intstr) == 0);
|
||||
if (ievent >= LOG_END)
|
||||
continue;
|
||||
if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS)
|
||||
goto next;
|
||||
|
||||
(void) snprintf(internalstr,
|
||||
sizeof (internalstr),
|
||||
@ -884,6 +907,14 @@ dump_history(spa_t *spa)
|
||||
(void) localtime_r(&tsec, &t);
|
||||
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
||||
(void) printf("%s %s\n", tbuf, cmd);
|
||||
printed = B_TRUE;
|
||||
|
||||
next:
|
||||
if (dump_opt['h'] > 1) {
|
||||
if (!printed)
|
||||
(void) printf("unrecognized record:\n");
|
||||
dump_nvlist(events[i], 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1189,7 +1220,7 @@ dump_bpobj_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
|
||||
}
|
||||
|
||||
static void
|
||||
dump_bpobj(bpobj_t *bpo, char *name)
|
||||
dump_bpobj(bpobj_t *bpo, char *name, int indent)
|
||||
{
|
||||
char bytes[32];
|
||||
char comp[32];
|
||||
@ -1199,31 +1230,57 @@ dump_bpobj(bpobj_t *bpo, char *name)
|
||||
return;
|
||||
|
||||
zdb_nicenum(bpo->bpo_phys->bpo_bytes, bytes);
|
||||
if (bpo->bpo_havesubobj) {
|
||||
if (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_subobjs != 0) {
|
||||
zdb_nicenum(bpo->bpo_phys->bpo_comp, comp);
|
||||
zdb_nicenum(bpo->bpo_phys->bpo_uncomp, uncomp);
|
||||
(void) printf("\n %s: %llu local blkptrs, %llu subobjs, "
|
||||
"%s (%s/%s comp)\n",
|
||||
name, (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
|
||||
(void) printf(" %*s: object %llu, %llu local blkptrs, "
|
||||
"%llu subobjs, %s (%s/%s comp)\n",
|
||||
indent * 8, name,
|
||||
(u_longlong_t)bpo->bpo_object,
|
||||
(u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
|
||||
(u_longlong_t)bpo->bpo_phys->bpo_num_subobjs,
|
||||
bytes, comp, uncomp);
|
||||
|
||||
for (uint64_t i = 0; i < bpo->bpo_phys->bpo_num_subobjs; i++) {
|
||||
uint64_t subobj;
|
||||
bpobj_t subbpo;
|
||||
int error;
|
||||
VERIFY0(dmu_read(bpo->bpo_os,
|
||||
bpo->bpo_phys->bpo_subobjs,
|
||||
i * sizeof (subobj), sizeof (subobj), &subobj, 0));
|
||||
error = bpobj_open(&subbpo, bpo->bpo_os, subobj);
|
||||
if (error != 0) {
|
||||
(void) printf("ERROR %u while trying to open "
|
||||
"subobj id %llu\n",
|
||||
error, (u_longlong_t)subobj);
|
||||
continue;
|
||||
}
|
||||
dump_bpobj(&subbpo, "subobj", indent + 1);
|
||||
bpobj_close(&subbpo);
|
||||
}
|
||||
} else {
|
||||
(void) printf("\n %s: %llu blkptrs, %s\n",
|
||||
name, (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs, bytes);
|
||||
(void) printf(" %*s: object %llu, %llu blkptrs, %s\n",
|
||||
indent * 8, name,
|
||||
(u_longlong_t)bpo->bpo_object,
|
||||
(u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
|
||||
bytes);
|
||||
}
|
||||
|
||||
if (dump_opt['d'] < 5)
|
||||
return;
|
||||
|
||||
(void) printf("\n");
|
||||
|
||||
(void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
|
||||
if (indent == 0) {
|
||||
(void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
|
||||
(void) printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_deadlist(dsl_deadlist_t *dl)
|
||||
{
|
||||
dsl_deadlist_entry_t *dle;
|
||||
uint64_t unused;
|
||||
char bytes[32];
|
||||
char comp[32];
|
||||
char uncomp[32];
|
||||
@ -1242,14 +1299,24 @@ dump_deadlist(dsl_deadlist_t *dl)
|
||||
|
||||
(void) printf("\n");
|
||||
|
||||
/* force the tree to be loaded */
|
||||
dsl_deadlist_space_range(dl, 0, UINT64_MAX, &unused, &unused, &unused);
|
||||
|
||||
for (dle = avl_first(&dl->dl_tree); dle;
|
||||
dle = AVL_NEXT(&dl->dl_tree, dle)) {
|
||||
(void) printf(" mintxg %llu -> obj %llu\n",
|
||||
(longlong_t)dle->dle_mintxg,
|
||||
(longlong_t)dle->dle_bpobj.bpo_object);
|
||||
if (dump_opt['d'] >= 5) {
|
||||
char buf[128];
|
||||
(void) snprintf(buf, sizeof (buf), "mintxg %llu -> ",
|
||||
(longlong_t)dle->dle_mintxg,
|
||||
(longlong_t)dle->dle_bpobj.bpo_object);
|
||||
|
||||
if (dump_opt['d'] >= 5)
|
||||
dump_bpobj(&dle->dle_bpobj, "");
|
||||
dump_bpobj(&dle->dle_bpobj, buf, 0);
|
||||
} else {
|
||||
(void) printf("mintxg %llu -> obj %llu\n",
|
||||
(longlong_t)dle->dle_mintxg,
|
||||
(longlong_t)dle->dle_bpobj.bpo_object);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1272,7 +1339,7 @@ fuid_table_destroy()
|
||||
* print uid or gid information.
|
||||
* For normal POSIX id just the id is printed in decimal format.
|
||||
* For CIFS files with FUID the fuid is printed in hex followed by
|
||||
* the doman-rid string.
|
||||
* the domain-rid string.
|
||||
*/
|
||||
static void
|
||||
print_idstr(uint64_t id, const char *id_type)
|
||||
@ -1460,7 +1527,7 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES + 1] = {
|
||||
dump_zap, /* other ZAP */
|
||||
dump_zap, /* persistent error log */
|
||||
dump_uint8, /* SPA history */
|
||||
dump_uint64, /* SPA history offsets */
|
||||
dump_history_offsets, /* SPA history offsets */
|
||||
dump_zap, /* Pool properties */
|
||||
dump_zap, /* DSL permissions */
|
||||
dump_acl, /* ZFS ACL */
|
||||
@ -1625,7 +1692,9 @@ dump_dir(objset_t *os)
|
||||
int print_header = 1;
|
||||
int i, error;
|
||||
|
||||
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
|
||||
dmu_objset_fast_stat(os, &dds);
|
||||
dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
|
||||
|
||||
if (dds.dds_type < DMU_OST_NUMTYPES)
|
||||
type = objset_types[dds.dds_type];
|
||||
@ -2034,7 +2103,6 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
|
||||
NULL, NULL, ZIO_PRIORITY_ASYNC_READ, flags, zb));
|
||||
|
||||
free(data);
|
||||
|
||||
if (ioerr && !(flags & ZIO_FLAG_SPECULATIVE)) {
|
||||
zcb->zcb_haderrors = 1;
|
||||
zcb->zcb_errors[ioerr]++;
|
||||
@ -2160,11 +2228,11 @@ zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
|
||||
for (int m = 0; m < vd->vdev_ms_count; m++) {
|
||||
metaslab_t *msp = vd->vdev_ms[m];
|
||||
mutex_enter(&msp->ms_lock);
|
||||
space_map_unload(&msp->ms_map);
|
||||
VERIFY(space_map_load(&msp->ms_map,
|
||||
space_map_unload(msp->ms_map);
|
||||
VERIFY(space_map_load(msp->ms_map,
|
||||
&zdb_space_map_ops, SM_ALLOC, &msp->ms_smo,
|
||||
spa->spa_meta_objset) == 0);
|
||||
msp->ms_map.sm_ppd = vd;
|
||||
msp->ms_map->sm_ppd = vd;
|
||||
mutex_exit(&msp->ms_lock);
|
||||
}
|
||||
}
|
||||
@ -2187,7 +2255,7 @@ zdb_leak_fini(spa_t *spa)
|
||||
for (int m = 0; m < vd->vdev_ms_count; m++) {
|
||||
metaslab_t *msp = vd->vdev_ms[m];
|
||||
mutex_enter(&msp->ms_lock);
|
||||
space_map_unload(&msp->ms_map);
|
||||
space_map_unload(msp->ms_map);
|
||||
mutex_exit(&msp->ms_lock);
|
||||
}
|
||||
}
|
||||
@ -2529,10 +2597,11 @@ dump_zpool(spa_t *spa)
|
||||
if (dump_opt['d'] || dump_opt['i']) {
|
||||
dump_dir(dp->dp_meta_objset);
|
||||
if (dump_opt['d'] >= 3) {
|
||||
dump_bpobj(&spa->spa_deferred_bpobj, "Deferred frees");
|
||||
dump_bpobj(&spa->spa_deferred_bpobj,
|
||||
"Deferred frees", 0);
|
||||
if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
|
||||
dump_bpobj(&spa->spa_dsl_pool->dp_free_bpobj,
|
||||
"Pool snapshot frees");
|
||||
"Pool snapshot frees", 0);
|
||||
}
|
||||
|
||||
if (spa_feature_is_active(spa,
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 10, 2013
|
||||
.Dd March 21, 2013
|
||||
.Dt ZFS 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -65,6 +65,7 @@
|
||||
.Op Fl r
|
||||
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
|
||||
.Ar filesystem@snapname Ns | Ns Ar volume@snapname
|
||||
.Ar filesystem@snapname Ns | Ns Ar volume@snapname Ns ...
|
||||
.Nm
|
||||
.Cm rollback
|
||||
.Op Fl rRf
|
||||
@ -526,6 +527,39 @@ if the snapshot has been marked for deferred destroy by using the
|
||||
.Qq Nm Cm destroy -d
|
||||
command. Otherwise, the property is
|
||||
.Cm off .
|
||||
.It Sy logicalreferenced
|
||||
The amount of space that is
|
||||
.Qq logically
|
||||
accessible by this dataset.
|
||||
See the
|
||||
.Sy referenced
|
||||
property.
|
||||
The logical space ignores the effect of the
|
||||
.Sy compression
|
||||
and
|
||||
.Sy copies
|
||||
properties, giving a quantity closer to the amount of data that applications
|
||||
see.
|
||||
However, it does include space consumed by metadata.
|
||||
.Pp
|
||||
This property can also be referred to by its shortened column name,
|
||||
.Sy lrefer .
|
||||
.It Sy logicalused
|
||||
The amount of space that is
|
||||
.Qq logically
|
||||
consumed by this dataset and all its descendents.
|
||||
See the
|
||||
.Sy used
|
||||
property.
|
||||
The logical space ignores the effect of the
|
||||
.Sy compression
|
||||
and
|
||||
.Sy copies
|
||||
properties, giving a quantity closer to the amount of data that applications
|
||||
see.
|
||||
.Pp
|
||||
This property can also be referred to by its shortened column name,
|
||||
.Sy lused .
|
||||
.It Sy mounted
|
||||
For file systems, indicates whether the file system is currently mounted. This
|
||||
property can be either
|
||||
@ -1584,7 +1618,11 @@ multiple snapshots.
|
||||
Destroy (or mark for deferred deletion) all snapshots with this name in
|
||||
descendent file systems.
|
||||
.It Fl R
|
||||
Recursively destroy all dependents.
|
||||
Recursively destroy all clones of these snapshots, including the clones,
|
||||
snapshots, and children.
|
||||
If this flag is specified, the
|
||||
.Op fl d
|
||||
flag will have no effect.
|
||||
.It Fl n
|
||||
Do a dry-run ("No-op") deletion. No data will be deleted. This is useful in
|
||||
conjunction with the
|
||||
@ -1612,17 +1650,18 @@ behavior for mounted file systems in use.
|
||||
.Op Fl r
|
||||
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
|
||||
.Ar filesystem@snapname Ns | Ns volume@snapname
|
||||
.Ar filesystem@snapname Ns | Ns volume@snapname Ns ...
|
||||
.Xc
|
||||
.Pp
|
||||
Creates a snapshot with the given name. All previous modifications by
|
||||
successful system calls to the file system are part of the snapshot. See the
|
||||
Creates snapshots with the given names. All previous modifications by
|
||||
successful system calls to the file system are part of the snapshots.
|
||||
Snapshots are taken atomically, so that all snapshots correspond to the same
|
||||
moment in time. See the
|
||||
.Qq Sx Snapshots
|
||||
section for details.
|
||||
.Bl -tag -width indent
|
||||
.It Fl r
|
||||
Recursively create snapshots of all descendent datasets. Snapshots are taken
|
||||
atomically, so that all recursive snapshots correspond to the same moment in
|
||||
time.
|
||||
Recursively create snapshots of all descendent datasets
|
||||
.It Fl o Ar property Ns = Ns Ar value
|
||||
Sets the specified property; see
|
||||
.Qq Nm Cm create
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
#include <libzfs_core.h>
|
||||
#include <zfs_prop.h>
|
||||
#include <zfs_deleg.h>
|
||||
#include <libuutil.h>
|
||||
@ -74,6 +75,7 @@ libzfs_handle_t *g_zfs;
|
||||
|
||||
static FILE *mnttab_file;
|
||||
static char history_str[HIS_MAX_RECORD_LEN];
|
||||
static boolean_t log_history = B_TRUE;
|
||||
|
||||
static int zfs_do_clone(int argc, char **argv);
|
||||
static int zfs_do_create(int argc, char **argv);
|
||||
@ -276,7 +278,7 @@ get_usage(zfs_help_t idx)
|
||||
return (gettext("\tshare <-a | filesystem>\n"));
|
||||
case HELP_SNAPSHOT:
|
||||
return (gettext("\tsnapshot [-r] [-o property=value] ... "
|
||||
"<filesystem@snapname|volume@snapname>\n"));
|
||||
"<filesystem@snapname|volume@snapname> ...\n"));
|
||||
case HELP_UNMOUNT:
|
||||
return (gettext("\tunmount [-f] "
|
||||
"<-a | filesystem|mountpoint>\n"));
|
||||
@ -914,11 +916,12 @@ typedef struct destroy_cbdata {
|
||||
boolean_t cb_parsable;
|
||||
boolean_t cb_dryrun;
|
||||
nvlist_t *cb_nvl;
|
||||
nvlist_t *cb_batchedsnaps;
|
||||
|
||||
/* first snap in contiguous run */
|
||||
zfs_handle_t *cb_firstsnap;
|
||||
char *cb_firstsnap;
|
||||
/* previous snap in contiguous run */
|
||||
zfs_handle_t *cb_prevsnap;
|
||||
char *cb_prevsnap;
|
||||
int64_t cb_snapused;
|
||||
char *cb_snapspec;
|
||||
} destroy_cbdata_t;
|
||||
@ -1010,9 +1013,27 @@ destroy_callback(zfs_handle_t *zhp, void *data)
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
if (cb->cb_dryrun) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!cb->cb_dryrun) {
|
||||
if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
|
||||
/*
|
||||
* We batch up all contiguous snapshots (even of different
|
||||
* filesystems) and destroy them with one ioctl. We can't
|
||||
* simply do all snap deletions and then all fs deletions,
|
||||
* because we must delete a clone before its origin.
|
||||
*/
|
||||
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
|
||||
fnvlist_add_boolean(cb->cb_batchedsnaps, name);
|
||||
} else {
|
||||
int error = zfs_destroy_snaps_nvl(g_zfs,
|
||||
cb->cb_batchedsnaps, B_FALSE);
|
||||
fnvlist_free(cb->cb_batchedsnaps);
|
||||
cb->cb_batchedsnaps = fnvlist_alloc();
|
||||
|
||||
if (error != 0 ||
|
||||
zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
|
||||
zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
@ -1032,11 +1053,13 @@ destroy_print_cb(zfs_handle_t *zhp, void *arg)
|
||||
|
||||
if (nvlist_exists(cb->cb_nvl, name)) {
|
||||
if (cb->cb_firstsnap == NULL)
|
||||
cb->cb_firstsnap = zfs_handle_dup(zhp);
|
||||
cb->cb_firstsnap = strdup(name);
|
||||
if (cb->cb_prevsnap != NULL)
|
||||
zfs_close(cb->cb_prevsnap);
|
||||
free(cb->cb_prevsnap);
|
||||
/* this snap continues the current range */
|
||||
cb->cb_prevsnap = zfs_handle_dup(zhp);
|
||||
cb->cb_prevsnap = strdup(name);
|
||||
if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
|
||||
nomem();
|
||||
if (cb->cb_verbose) {
|
||||
if (cb->cb_parsable) {
|
||||
(void) printf("destroy\t%s\n", name);
|
||||
@ -1051,12 +1074,12 @@ destroy_print_cb(zfs_handle_t *zhp, void *arg)
|
||||
} else if (cb->cb_firstsnap != NULL) {
|
||||
/* end of this range */
|
||||
uint64_t used = 0;
|
||||
err = zfs_get_snapused_int(cb->cb_firstsnap,
|
||||
err = lzc_snaprange_space(cb->cb_firstsnap,
|
||||
cb->cb_prevsnap, &used);
|
||||
cb->cb_snapused += used;
|
||||
zfs_close(cb->cb_firstsnap);
|
||||
free(cb->cb_firstsnap);
|
||||
cb->cb_firstsnap = NULL;
|
||||
zfs_close(cb->cb_prevsnap);
|
||||
free(cb->cb_prevsnap);
|
||||
cb->cb_prevsnap = NULL;
|
||||
}
|
||||
zfs_close(zhp);
|
||||
@ -1073,13 +1096,13 @@ destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
|
||||
if (cb->cb_firstsnap != NULL) {
|
||||
uint64_t used = 0;
|
||||
if (err == 0) {
|
||||
err = zfs_get_snapused_int(cb->cb_firstsnap,
|
||||
err = lzc_snaprange_space(cb->cb_firstsnap,
|
||||
cb->cb_prevsnap, &used);
|
||||
}
|
||||
cb->cb_snapused += used;
|
||||
zfs_close(cb->cb_firstsnap);
|
||||
free(cb->cb_firstsnap);
|
||||
cb->cb_firstsnap = NULL;
|
||||
zfs_close(cb->cb_prevsnap);
|
||||
free(cb->cb_prevsnap);
|
||||
cb->cb_prevsnap = NULL;
|
||||
}
|
||||
return (err);
|
||||
@ -1166,8 +1189,10 @@ static int
|
||||
zfs_do_destroy(int argc, char **argv)
|
||||
{
|
||||
destroy_cbdata_t cb = { 0 };
|
||||
int rv = 0;
|
||||
int err = 0;
|
||||
int c;
|
||||
zfs_handle_t *zhp;
|
||||
zfs_handle_t *zhp = NULL;
|
||||
char *at;
|
||||
zfs_type_t type = ZFS_TYPE_DATASET;
|
||||
|
||||
@ -1221,11 +1246,9 @@ zfs_do_destroy(int argc, char **argv)
|
||||
|
||||
at = strchr(argv[0], '@');
|
||||
if (at != NULL) {
|
||||
int err = 0;
|
||||
|
||||
/* Build the list of snaps to destroy in cb_nvl. */
|
||||
if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||
nomem();
|
||||
cb.cb_nvl = fnvlist_alloc();
|
||||
|
||||
*at = '\0';
|
||||
zhp = zfs_open(g_zfs, argv[0],
|
||||
@ -1236,17 +1259,15 @@ zfs_do_destroy(int argc, char **argv)
|
||||
cb.cb_snapspec = at + 1;
|
||||
if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
|
||||
cb.cb_error) {
|
||||
zfs_close(zhp);
|
||||
nvlist_free(cb.cb_nvl);
|
||||
return (1);
|
||||
rv = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nvlist_empty(cb.cb_nvl)) {
|
||||
(void) fprintf(stderr, gettext("could not find any "
|
||||
"snapshots to destroy; check snapshot names.\n"));
|
||||
zfs_close(zhp);
|
||||
nvlist_free(cb.cb_nvl);
|
||||
return (1);
|
||||
rv = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cb.cb_verbose) {
|
||||
@ -1265,18 +1286,26 @@ zfs_do_destroy(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (!cb.cb_dryrun) {
|
||||
if (cb.cb_doclones)
|
||||
if (cb.cb_doclones) {
|
||||
cb.cb_batchedsnaps = fnvlist_alloc();
|
||||
err = destroy_clones(&cb);
|
||||
if (err == 0) {
|
||||
err = zfs_destroy_snaps_nvl(g_zfs,
|
||||
cb.cb_batchedsnaps, B_FALSE);
|
||||
}
|
||||
if (err != 0) {
|
||||
rv = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (err == 0) {
|
||||
err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl,
|
||||
err = zfs_destroy_snaps_nvl(g_zfs, cb.cb_nvl,
|
||||
cb.cb_defer_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
zfs_close(zhp);
|
||||
nvlist_free(cb.cb_nvl);
|
||||
if (err != 0)
|
||||
return (1);
|
||||
rv = 1;
|
||||
} else {
|
||||
/* Open the given dataset */
|
||||
if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
|
||||
@ -1297,8 +1326,8 @@ zfs_do_destroy(int argc, char **argv)
|
||||
zfs_get_name(zhp));
|
||||
(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
|
||||
"to destroy the pool itself\n"), zfs_get_name(zhp));
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
rv = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1308,30 +1337,42 @@ zfs_do_destroy(int argc, char **argv)
|
||||
if (!cb.cb_doclones &&
|
||||
zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
|
||||
&cb) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
rv = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cb.cb_error) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
rv = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cb.cb_batchedsnaps = fnvlist_alloc();
|
||||
if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
|
||||
&cb) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
rv = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the real thing. The callback will close the
|
||||
* handle regardless of whether it succeeds or not.
|
||||
*/
|
||||
if (destroy_callback(zhp, &cb) != 0)
|
||||
return (1);
|
||||
err = destroy_callback(zhp, &cb);
|
||||
zhp = NULL;
|
||||
if (err == 0) {
|
||||
err = zfs_destroy_snaps_nvl(g_zfs,
|
||||
cb.cb_batchedsnaps, cb.cb_defer_destroy);
|
||||
}
|
||||
if (err != 0)
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
out:
|
||||
fnvlist_free(cb.cb_batchedsnaps);
|
||||
fnvlist_free(cb.cb_nvl);
|
||||
if (zhp != NULL)
|
||||
zfs_close(zhp);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
@ -1932,9 +1973,11 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data)
|
||||
/*
|
||||
* If they did "zfs upgrade -a", then we could
|
||||
* be doing ioctls to different pools. We need
|
||||
* to log this history once to each pool.
|
||||
* to log this history once to each pool, and bypass
|
||||
* the normal history logging that happens in main().
|
||||
*/
|
||||
verify(zpool_stage_history(g_zfs, history_str) == 0);
|
||||
(void) zpool_log_history(g_zfs, history_str);
|
||||
log_history = B_FALSE;
|
||||
}
|
||||
if (zfs_prop_set(zhp, "version", verstr) == 0)
|
||||
cb->cb_numupgraded++;
|
||||
@ -3472,6 +3515,32 @@ zfs_do_set(int argc, char **argv)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
typedef struct snap_cbdata {
|
||||
nvlist_t *sd_nvl;
|
||||
boolean_t sd_recursive;
|
||||
const char *sd_snapname;
|
||||
} snap_cbdata_t;
|
||||
|
||||
static int
|
||||
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
snap_cbdata_t *sd = arg;
|
||||
char *name;
|
||||
int rv = 0;
|
||||
int error;
|
||||
|
||||
error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
|
||||
if (error == -1)
|
||||
nomem();
|
||||
fnvlist_add_boolean(sd->sd_nvl, name);
|
||||
free(name);
|
||||
|
||||
if (sd->sd_recursive)
|
||||
rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
|
||||
zfs_close(zhp);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* zfs snapshot [-r] [-o prop=value] ... <fs@snap>
|
||||
*
|
||||
@ -3481,13 +3550,16 @@ zfs_do_set(int argc, char **argv)
|
||||
static int
|
||||
zfs_do_snapshot(int argc, char **argv)
|
||||
{
|
||||
boolean_t recursive = B_FALSE;
|
||||
int ret = 0;
|
||||
char c;
|
||||
nvlist_t *props;
|
||||
snap_cbdata_t sd = { 0 };
|
||||
boolean_t multiple_snaps = B_FALSE;
|
||||
|
||||
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
|
||||
nomem();
|
||||
if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||
nomem();
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, "ro:")) != -1) {
|
||||
@ -3497,7 +3569,8 @@ zfs_do_snapshot(int argc, char **argv)
|
||||
return (1);
|
||||
break;
|
||||
case 'r':
|
||||
recursive = B_TRUE;
|
||||
sd.sd_recursive = B_TRUE;
|
||||
multiple_snaps = B_TRUE;
|
||||
break;
|
||||
case '?':
|
||||
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
||||
@ -3514,18 +3587,35 @@ zfs_do_snapshot(int argc, char **argv)
|
||||
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
|
||||
goto usage;
|
||||
}
|
||||
if (argc > 1) {
|
||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||
goto usage;
|
||||
|
||||
if (argc > 1)
|
||||
multiple_snaps = B_TRUE;
|
||||
for (; argc > 0; argc--, argv++) {
|
||||
char *atp;
|
||||
zfs_handle_t *zhp;
|
||||
|
||||
atp = strchr(argv[0], '@');
|
||||
if (atp == NULL)
|
||||
goto usage;
|
||||
*atp = '\0';
|
||||
sd.sd_snapname = atp + 1;
|
||||
zhp = zfs_open(g_zfs, argv[0],
|
||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
|
||||
if (zhp == NULL)
|
||||
goto usage;
|
||||
if (zfs_snapshot_cb(zhp, &sd) != 0)
|
||||
goto usage;
|
||||
}
|
||||
|
||||
ret = zfs_snapshot(g_zfs, argv[0], recursive, props);
|
||||
ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
|
||||
nvlist_free(sd.sd_nvl);
|
||||
nvlist_free(props);
|
||||
if (ret && recursive)
|
||||
if (ret != 0 && multiple_snaps)
|
||||
(void) fprintf(stderr, gettext("no snapshots were created\n"));
|
||||
return (ret != 0);
|
||||
|
||||
usage:
|
||||
nvlist_free(sd.sd_nvl);
|
||||
nvlist_free(props);
|
||||
usage(B_FALSE);
|
||||
return (-1);
|
||||
@ -5068,28 +5158,12 @@ cleanup2:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* zfs allow [-r] [-t] <tag> <snap> ...
|
||||
*
|
||||
* -r Recursively hold
|
||||
* -t Temporary hold (hidden option)
|
||||
*
|
||||
* Apply a user-hold with the given tag to the list of snapshots.
|
||||
*/
|
||||
static int
|
||||
zfs_do_allow(int argc, char **argv)
|
||||
{
|
||||
return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE));
|
||||
}
|
||||
|
||||
/*
|
||||
* zfs unallow [-r] [-t] <tag> <snap> ...
|
||||
*
|
||||
* -r Recursively hold
|
||||
* -t Temporary hold (hidden option)
|
||||
*
|
||||
* Apply a user-hold with the given tag to the list of snapshots.
|
||||
*/
|
||||
static int
|
||||
zfs_do_unallow(int argc, char **argv)
|
||||
{
|
||||
@ -5103,7 +5177,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
|
||||
int i;
|
||||
const char *tag;
|
||||
boolean_t recursive = B_FALSE;
|
||||
boolean_t temphold = B_FALSE;
|
||||
const char *opts = holding ? "rt" : "r";
|
||||
int c;
|
||||
|
||||
@ -5113,9 +5186,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
|
||||
case 'r':
|
||||
recursive = B_TRUE;
|
||||
break;
|
||||
case 't':
|
||||
temphold = B_TRUE;
|
||||
break;
|
||||
case '?':
|
||||
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
||||
optopt);
|
||||
@ -5164,7 +5234,7 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
|
||||
}
|
||||
if (holding) {
|
||||
if (zfs_hold(zhp, delim+1, tag, recursive,
|
||||
temphold, B_FALSE, -1, 0, 0) != 0)
|
||||
B_FALSE, -1) != 0)
|
||||
++errors;
|
||||
} else {
|
||||
if (zfs_release(zhp, delim+1, tag, recursive) != 0)
|
||||
@ -5180,7 +5250,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
|
||||
* zfs hold [-r] [-t] <tag> <snap> ...
|
||||
*
|
||||
* -r Recursively hold
|
||||
* -t Temporary hold (hidden option)
|
||||
*
|
||||
* Apply a user-hold with the given tag to the list of snapshots.
|
||||
*/
|
||||
@ -6602,8 +6671,7 @@ main(int argc, char **argv)
|
||||
return (1);
|
||||
}
|
||||
|
||||
zpool_set_history_str("zfs", argc, argv, history_str);
|
||||
verify(zpool_stage_history(g_zfs, history_str) == 0);
|
||||
zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
|
||||
|
||||
libzfs_print_on_error(g_zfs, B_TRUE);
|
||||
|
||||
@ -6672,6 +6740,9 @@ main(int argc, char **argv)
|
||||
|
||||
(void) fclose(mnttab_file);
|
||||
|
||||
if (ret == 0 && log_history)
|
||||
(void) zpool_log_history(g_zfs, history_str);
|
||||
|
||||
libzfs_fini(g_zfs);
|
||||
|
||||
/*
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <sys/zio_checksum.h>
|
||||
#include <sys/zio_compress.h>
|
||||
#include <sys/zfeature.h>
|
||||
#include <sys/dmu_tx.h>
|
||||
#undef ZFS_MAXNAMELEN
|
||||
#undef verify
|
||||
#include <libzfs.h>
|
||||
@ -273,12 +274,15 @@ zhack_do_feature_stat(int argc, char **argv)
|
||||
}
|
||||
|
||||
static void
|
||||
feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
feature_enable_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
spa_t *spa = arg1;
|
||||
zfeature_info_t *feature = arg2;
|
||||
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
|
||||
zfeature_info_t *feature = arg;
|
||||
|
||||
spa_feature_enable(spa, feature, tx);
|
||||
spa_history_log_internal(spa, "zhack enable feature", tx,
|
||||
"name=%s can_readonly=%u",
|
||||
feature->fi_guid, feature->fi_can_readonly);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -341,8 +345,8 @@ zhack_do_feature_enable(int argc, char **argv)
|
||||
if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
|
||||
fatal("feature already enabled: %s", feature.fi_guid);
|
||||
|
||||
VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
|
||||
feature_enable_sync, spa, &feature, 5));
|
||||
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
|
||||
feature_enable_sync, &feature, 5));
|
||||
|
||||
spa_close(spa, FTAG);
|
||||
|
||||
@ -350,21 +354,25 @@ zhack_do_feature_enable(int argc, char **argv)
|
||||
}
|
||||
|
||||
static void
|
||||
feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
feature_incr_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
spa_t *spa = arg1;
|
||||
zfeature_info_t *feature = arg2;
|
||||
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
|
||||
zfeature_info_t *feature = arg;
|
||||
|
||||
spa_feature_incr(spa, feature, tx);
|
||||
spa_history_log_internal(spa, "zhack feature incr", tx,
|
||||
"name=%s", feature->fi_guid);
|
||||
}
|
||||
|
||||
static void
|
||||
feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
feature_decr_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
spa_t *spa = arg1;
|
||||
zfeature_info_t *feature = arg2;
|
||||
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
|
||||
zfeature_info_t *feature = arg;
|
||||
|
||||
spa_feature_decr(spa, feature, tx);
|
||||
spa_history_log_internal(spa, "zhack feature decr", tx,
|
||||
"name=%s", feature->fi_guid);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -435,8 +443,8 @@ zhack_do_feature_ref(int argc, char **argv)
|
||||
if (decr && !spa_feature_is_active(spa, &feature))
|
||||
fatal("feature refcount already 0: %s", feature.fi_guid);
|
||||
|
||||
VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
|
||||
decr ? feature_decr_sync : feature_incr_sync, spa, &feature, 5));
|
||||
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
|
||||
decr ? feature_decr_sync : feature_incr_sync, &feature, 5));
|
||||
|
||||
spa_close(spa, FTAG);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <libzfs.h>
|
||||
@ -455,6 +456,20 @@ translate_device(const char *pool, const char *device, err_type_t label_type,
|
||||
&record->zi_guid) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device faults can take on three different forms:
|
||||
* 1). delayed or hanging I/O
|
||||
* 2). zfs label faults
|
||||
* 3). generic disk faults
|
||||
*/
|
||||
if (record->zi_timer != 0) {
|
||||
record->zi_cmd = ZINJECT_DELAY_IO;
|
||||
} else if (label_type != TYPE_INVAL) {
|
||||
record->zi_cmd = ZINJECT_LABEL_FAULT;
|
||||
} else {
|
||||
record->zi_cmd = ZINJECT_DEVICE_FAULT;
|
||||
}
|
||||
|
||||
switch (label_type) {
|
||||
case TYPE_LABEL_UBERBLOCK:
|
||||
record->zi_start = offsetof(vdev_label_t, vl_uberblock[0]);
|
||||
|
@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -603,7 +604,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
while ((c = getopt(argc, argv,
|
||||
":aA:b:d:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
|
||||
":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
flags |= ZINJECT_FLUSH_ARC;
|
||||
@ -629,6 +630,15 @@ main(int argc, char **argv)
|
||||
case 'd':
|
||||
device = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
record.zi_timer = strtoull(optarg, &end, 10);
|
||||
if (errno != 0 || *end != '\0') {
|
||||
(void) fprintf(stderr, "invalid i/o delay "
|
||||
"value: '%s'\n", optarg);
|
||||
usage();
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (strcasecmp(optarg, "io") == 0) {
|
||||
error = EIO;
|
||||
@ -693,6 +703,7 @@ main(int argc, char **argv)
|
||||
case 'p':
|
||||
(void) strlcpy(record.zi_func, optarg,
|
||||
sizeof (record.zi_func));
|
||||
record.zi_cmd = ZINJECT_PANIC;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
@ -766,13 +777,15 @@ main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (record.zi_duration != 0)
|
||||
record.zi_cmd = ZINJECT_IGNORED_WRITES;
|
||||
|
||||
if (cancel != NULL) {
|
||||
/*
|
||||
* '-c' is invalid with any other options.
|
||||
*/
|
||||
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
|
||||
level != 0 || record.zi_func[0] != '\0' ||
|
||||
record.zi_duration != 0) {
|
||||
level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
|
||||
(void) fprintf(stderr, "cancel (-c) incompatible with "
|
||||
"any other options\n");
|
||||
usage();
|
||||
@ -804,8 +817,7 @@ main(int argc, char **argv)
|
||||
* for doing injection, so handle it separately here.
|
||||
*/
|
||||
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
|
||||
level != 0 || record.zi_func[0] != '\0' ||
|
||||
record.zi_duration != 0) {
|
||||
level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
|
||||
(void) fprintf(stderr, "device (-d) incompatible with "
|
||||
"data error injection\n");
|
||||
usage();
|
||||
@ -839,7 +851,7 @@ main(int argc, char **argv)
|
||||
|
||||
} else if (raw != NULL) {
|
||||
if (range != NULL || type != TYPE_INVAL || level != 0 ||
|
||||
record.zi_func[0] != '\0' || record.zi_duration != 0) {
|
||||
record.zi_cmd != ZINJECT_UNINITIALIZED) {
|
||||
(void) fprintf(stderr, "raw (-b) format with "
|
||||
"any other options\n");
|
||||
usage();
|
||||
@ -862,13 +874,14 @@ main(int argc, char **argv)
|
||||
return (1);
|
||||
}
|
||||
|
||||
record.zi_cmd = ZINJECT_DATA_FAULT;
|
||||
if (translate_raw(raw, &record) != 0)
|
||||
return (1);
|
||||
if (!error)
|
||||
error = EIO;
|
||||
} else if (record.zi_func[0] != '\0') {
|
||||
} else if (record.zi_cmd == ZINJECT_PANIC) {
|
||||
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
|
||||
level != 0 || device != NULL || record.zi_duration != 0) {
|
||||
level != 0 || device != NULL) {
|
||||
(void) fprintf(stderr, "panic (-p) incompatible with "
|
||||
"other options\n");
|
||||
usage();
|
||||
@ -886,7 +899,7 @@ main(int argc, char **argv)
|
||||
if (argv[1] != NULL)
|
||||
record.zi_type = atoi(argv[1]);
|
||||
dataset[0] = '\0';
|
||||
} else if (record.zi_duration != 0) {
|
||||
} else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
|
||||
if (nowrites == 0) {
|
||||
(void) fprintf(stderr, "-s or -g meaningless "
|
||||
"without -I (ignore writes)\n");
|
||||
@ -940,6 +953,7 @@ main(int argc, char **argv)
|
||||
return (1);
|
||||
}
|
||||
|
||||
record.zi_cmd = ZINJECT_DATA_FAULT;
|
||||
if (translate_record(type, argv[0], range, level, &record, pool,
|
||||
dataset) != 0)
|
||||
return (1);
|
||||
|
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 15, 2012
|
||||
.Dd March 14, 2013
|
||||
.Dt ZPOOL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1608,14 +1608,15 @@ is specified, the command exits after
|
||||
.Ar count
|
||||
reports are printed.
|
||||
.Pp
|
||||
If a scrub or resilver is in progress, this command reports the percentage done
|
||||
and the estimated time to completion. Both of these are only approximate,
|
||||
If a scrub or resilver is in progress, this command reports the percentage
|
||||
done and the estimated time to completion. Both of these are only approximate,
|
||||
because the amount of data in the pool and the other workloads on the system
|
||||
can change.
|
||||
.Bl -tag -width indent
|
||||
.It Fl x
|
||||
Only display status for pools that are exhibiting errors or are otherwise
|
||||
unavailable.
|
||||
Warnings about pools not using the latest on-disk format will not be included.
|
||||
.It Fl v
|
||||
Displays verbose data error information, printing out a complete list of all
|
||||
data errors since the last complete pool scrub.
|
||||
|
@ -192,9 +192,9 @@ static zpool_command_t command_table[] = {
|
||||
|
||||
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
|
||||
|
||||
zpool_command_t *current_command;
|
||||
static zpool_command_t *current_command;
|
||||
static char history_str[HIS_MAX_RECORD_LEN];
|
||||
|
||||
static boolean_t log_history = B_TRUE;
|
||||
static uint_t timestamp_fmt = NODATE;
|
||||
|
||||
static const char *
|
||||
@ -1093,7 +1093,10 @@ zpool_do_destroy(int argc, char **argv)
|
||||
return (1);
|
||||
}
|
||||
|
||||
ret = (zpool_destroy(zhp) != 0);
|
||||
/* The history must be logged as part of the export */
|
||||
log_history = B_FALSE;
|
||||
|
||||
ret = (zpool_destroy(zhp, history_str) != 0);
|
||||
|
||||
zpool_close(zhp);
|
||||
|
||||
@ -1157,10 +1160,13 @@ zpool_do_export(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The history must be logged as part of the export */
|
||||
log_history = B_FALSE;
|
||||
|
||||
if (hardforce) {
|
||||
if (zpool_export_force(zhp) != 0)
|
||||
if (zpool_export_force(zhp, history_str) != 0)
|
||||
ret = 1;
|
||||
} else if (zpool_export(zhp, force) != 0) {
|
||||
} else if (zpool_export(zhp, force, history_str) != 0) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
@ -4031,7 +4037,10 @@ status_callback(zpool_handle_t *zhp, void *data)
|
||||
* If we were given 'zpool status -x', only report those pools with
|
||||
* problems.
|
||||
*/
|
||||
if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
|
||||
if (cbp->cb_explain &&
|
||||
(reason == ZPOOL_STATUS_OK ||
|
||||
reason == ZPOOL_STATUS_VERSION_OLDER ||
|
||||
reason == ZPOOL_STATUS_FEAT_DISABLED)) {
|
||||
if (!cbp->cb_allpools) {
|
||||
(void) printf(gettext("pool '%s' is healthy\n"),
|
||||
zpool_get_name(zhp));
|
||||
@ -4560,6 +4569,14 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
|
||||
if (count > 0) {
|
||||
cbp->cb_first = B_FALSE;
|
||||
printnl = B_TRUE;
|
||||
/*
|
||||
* If they did "zpool upgrade -a", then we could
|
||||
* be doing ioctls to different pools. We need
|
||||
* to log this history once to each pool, and bypass
|
||||
* the normal history logging that happens in main().
|
||||
*/
|
||||
(void) zpool_log_history(g_zfs, history_str);
|
||||
log_history = B_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4921,8 +4938,8 @@ zpool_do_upgrade(int argc, char **argv)
|
||||
|
||||
typedef struct hist_cbdata {
|
||||
boolean_t first;
|
||||
int longfmt;
|
||||
int internal;
|
||||
boolean_t longfmt;
|
||||
boolean_t internal;
|
||||
} hist_cbdata_t;
|
||||
|
||||
/*
|
||||
@ -4934,21 +4951,8 @@ get_history_one(zpool_handle_t *zhp, void *data)
|
||||
nvlist_t *nvhis;
|
||||
nvlist_t **records;
|
||||
uint_t numrecords;
|
||||
char *cmdstr;
|
||||
char *pathstr;
|
||||
uint64_t dst_time;
|
||||
time_t tsec;
|
||||
struct tm t;
|
||||
char tbuf[30];
|
||||
int ret, i;
|
||||
uint64_t who;
|
||||
struct passwd *pwd;
|
||||
char *hostname;
|
||||
char *zonename;
|
||||
char internalstr[MAXPATHLEN];
|
||||
hist_cbdata_t *cb = (hist_cbdata_t *)data;
|
||||
uint64_t txg;
|
||||
uint64_t ievent;
|
||||
|
||||
cb->first = B_FALSE;
|
||||
|
||||
@ -4960,64 +4964,94 @@ get_history_one(zpool_handle_t *zhp, void *data)
|
||||
verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
|
||||
&records, &numrecords) == 0);
|
||||
for (i = 0; i < numrecords; i++) {
|
||||
if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
|
||||
&dst_time) != 0)
|
||||
continue;
|
||||
nvlist_t *rec = records[i];
|
||||
char tbuf[30] = "";
|
||||
|
||||
/* is it an internal event or a standard event? */
|
||||
if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
|
||||
&cmdstr) != 0) {
|
||||
if (cb->internal == 0)
|
||||
continue;
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
|
||||
time_t tsec;
|
||||
struct tm t;
|
||||
|
||||
if (nvlist_lookup_uint64(records[i],
|
||||
ZPOOL_HIST_INT_EVENT, &ievent) != 0)
|
||||
continue;
|
||||
verify(nvlist_lookup_uint64(records[i],
|
||||
ZPOOL_HIST_TXG, &txg) == 0);
|
||||
verify(nvlist_lookup_string(records[i],
|
||||
ZPOOL_HIST_INT_STR, &pathstr) == 0);
|
||||
if (ievent >= LOG_END)
|
||||
continue;
|
||||
(void) snprintf(internalstr,
|
||||
sizeof (internalstr),
|
||||
"[internal %s txg:%lld] %s",
|
||||
zfs_history_event_names[ievent], txg,
|
||||
pathstr);
|
||||
cmdstr = internalstr;
|
||||
tsec = fnvlist_lookup_uint64(records[i],
|
||||
ZPOOL_HIST_TIME);
|
||||
(void) localtime_r(&tsec, &t);
|
||||
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
||||
}
|
||||
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
|
||||
(void) printf("%s %s", tbuf,
|
||||
fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
|
||||
} else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
|
||||
int ievent =
|
||||
fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
|
||||
if (!cb->internal)
|
||||
continue;
|
||||
if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
|
||||
(void) printf("%s unrecognized record:\n",
|
||||
tbuf);
|
||||
dump_nvlist(rec, 4);
|
||||
continue;
|
||||
}
|
||||
(void) printf("%s [internal %s txg:%lld] %s", tbuf,
|
||||
zfs_history_event_names[ievent],
|
||||
fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
|
||||
fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
|
||||
} else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
|
||||
if (!cb->internal)
|
||||
continue;
|
||||
(void) printf("%s [txg:%lld] %s", tbuf,
|
||||
fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
|
||||
fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
|
||||
(void) printf(" %s (%llu)",
|
||||
fnvlist_lookup_string(rec,
|
||||
ZPOOL_HIST_DSNAME),
|
||||
fnvlist_lookup_uint64(rec,
|
||||
ZPOOL_HIST_DSID));
|
||||
}
|
||||
(void) printf(" %s", fnvlist_lookup_string(rec,
|
||||
ZPOOL_HIST_INT_STR));
|
||||
} else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
|
||||
if (!cb->internal)
|
||||
continue;
|
||||
(void) printf("%s ioctl %s\n", tbuf,
|
||||
fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
|
||||
(void) printf(" input:\n");
|
||||
dump_nvlist(fnvlist_lookup_nvlist(rec,
|
||||
ZPOOL_HIST_INPUT_NVL), 8);
|
||||
}
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
|
||||
(void) printf(" output:\n");
|
||||
dump_nvlist(fnvlist_lookup_nvlist(rec,
|
||||
ZPOOL_HIST_OUTPUT_NVL), 8);
|
||||
}
|
||||
} else {
|
||||
if (!cb->internal)
|
||||
continue;
|
||||
(void) printf("%s unrecognized record:\n", tbuf);
|
||||
dump_nvlist(rec, 4);
|
||||
}
|
||||
tsec = dst_time;
|
||||
(void) localtime_r(&tsec, &t);
|
||||
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
||||
(void) printf("%s %s", tbuf, cmdstr);
|
||||
|
||||
if (!cb->longfmt) {
|
||||
(void) printf("\n");
|
||||
continue;
|
||||
}
|
||||
(void) printf(" [");
|
||||
if (nvlist_lookup_uint64(records[i],
|
||||
ZPOOL_HIST_WHO, &who) == 0) {
|
||||
pwd = getpwuid((uid_t)who);
|
||||
if (pwd)
|
||||
(void) printf("user %s on",
|
||||
pwd->pw_name);
|
||||
else
|
||||
(void) printf("user %d on",
|
||||
(int)who);
|
||||
} else {
|
||||
(void) printf(gettext("no info]\n"));
|
||||
continue;
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
|
||||
uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
|
||||
struct passwd *pwd = getpwuid(who);
|
||||
(void) printf("user %d ", (int)who);
|
||||
if (pwd != NULL)
|
||||
(void) printf("(%s) ", pwd->pw_name);
|
||||
}
|
||||
if (nvlist_lookup_string(records[i],
|
||||
ZPOOL_HIST_HOST, &hostname) == 0) {
|
||||
(void) printf(" %s", hostname);
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
|
||||
(void) printf("on %s",
|
||||
fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
|
||||
}
|
||||
if (nvlist_lookup_string(records[i],
|
||||
ZPOOL_HIST_ZONE, &zonename) == 0) {
|
||||
(void) printf(":%s", zonename);
|
||||
if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
|
||||
(void) printf(":%s",
|
||||
fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
|
||||
}
|
||||
|
||||
(void) printf("]");
|
||||
(void) printf("\n");
|
||||
}
|
||||
@ -5032,8 +5066,6 @@ get_history_one(zpool_handle_t *zhp, void *data)
|
||||
*
|
||||
* Displays the history of commands that modified pools.
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
zpool_do_history(int argc, char **argv)
|
||||
{
|
||||
@ -5046,10 +5078,10 @@ zpool_do_history(int argc, char **argv)
|
||||
while ((c = getopt(argc, argv, "li")) != -1) {
|
||||
switch (c) {
|
||||
case 'l':
|
||||
cbdata.longfmt = 1;
|
||||
cbdata.longfmt = B_TRUE;
|
||||
break;
|
||||
case 'i':
|
||||
cbdata.internal = 1;
|
||||
cbdata.internal = B_TRUE;
|
||||
break;
|
||||
case '?':
|
||||
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
||||
@ -5274,8 +5306,7 @@ main(int argc, char **argv)
|
||||
if (strcmp(cmdname, "-?") == 0)
|
||||
usage(B_TRUE);
|
||||
|
||||
zpool_set_history_str("zpool", argc, argv, history_str);
|
||||
verify(zpool_stage_history(g_zfs, history_str) == 0);
|
||||
zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
|
||||
|
||||
/*
|
||||
* Run the appropriate command.
|
||||
@ -5302,6 +5333,9 @@ main(int argc, char **argv)
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
if (ret == 0 && log_history)
|
||||
(void) zpool_log_history(g_zfs, history_str);
|
||||
|
||||
libzfs_fini(g_zfs);
|
||||
|
||||
/*
|
||||
|
@ -104,10 +104,12 @@
|
||||
#include <sys/metaslab_impl.h>
|
||||
#include <sys/dsl_prop.h>
|
||||
#include <sys/dsl_dataset.h>
|
||||
#include <sys/dsl_destroy.h>
|
||||
#include <sys/dsl_scan.h>
|
||||
#include <sys/zio_checksum.h>
|
||||
#include <sys/refcount.h>
|
||||
#include <sys/zfeature.h>
|
||||
#include <sys/dsl_userhold.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <stdlib.h>
|
||||
@ -367,7 +369,7 @@ ztest_info_t ztest_info[] = {
|
||||
{ ztest_scrub, 1, &zopt_rarely },
|
||||
{ ztest_spa_upgrade, 1, &zopt_rarely },
|
||||
{ ztest_dsl_dataset_promote_busy, 1, &zopt_rarely },
|
||||
{ ztest_vdev_attach_detach, 1, &zopt_rarely },
|
||||
{ ztest_vdev_attach_detach, 1, &zopt_sometimes },
|
||||
{ ztest_vdev_LUN_growth, 1, &zopt_rarely },
|
||||
{ ztest_vdev_add_remove, 1,
|
||||
&ztest_opts.zo_vdevtime },
|
||||
@ -1008,9 +1010,8 @@ ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value,
|
||||
uint64_t curval;
|
||||
int error;
|
||||
|
||||
error = dsl_prop_set(osname, propname,
|
||||
(inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL),
|
||||
sizeof (value), 1, &value);
|
||||
error = dsl_prop_set_int(osname, propname,
|
||||
(inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL), value);
|
||||
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc(FTAG);
|
||||
@ -1018,8 +1019,7 @@ ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value,
|
||||
}
|
||||
ASSERT0(error);
|
||||
|
||||
VERIFY3U(dsl_prop_get(osname, propname, sizeof (curval),
|
||||
1, &curval, setpoint), ==, 0);
|
||||
VERIFY0(dsl_prop_get_integer(osname, propname, &curval, setpoint));
|
||||
|
||||
if (ztest_opts.zo_verbose >= 6) {
|
||||
VERIFY(zfs_prop_index_to_string(prop, curval, &valname) == 0);
|
||||
@ -2332,7 +2332,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
*/
|
||||
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
|
||||
VERIFY3U(ENOENT, ==,
|
||||
spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL));
|
||||
spa_create("ztest_bad_file", nvroot, NULL, NULL));
|
||||
nvlist_free(nvroot);
|
||||
|
||||
/*
|
||||
@ -2340,7 +2340,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
*/
|
||||
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 2, 1);
|
||||
VERIFY3U(ENOENT, ==,
|
||||
spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL));
|
||||
spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
|
||||
nvlist_free(nvroot);
|
||||
|
||||
/*
|
||||
@ -2349,7 +2349,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
*/
|
||||
(void) rw_rdlock(&ztest_name_lock);
|
||||
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
|
||||
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL));
|
||||
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
|
||||
nvlist_free(nvroot);
|
||||
VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
|
||||
VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
|
||||
@ -2407,7 +2407,7 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
|
||||
props = fnvlist_alloc();
|
||||
fnvlist_add_uint64(props,
|
||||
zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
|
||||
VERIFY0(spa_create(name, nvroot, props, NULL, NULL));
|
||||
VERIFY0(spa_create(name, nvroot, props, NULL));
|
||||
fnvlist_free(nvroot);
|
||||
fnvlist_free(props);
|
||||
|
||||
@ -2481,8 +2481,7 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
|
||||
int error;
|
||||
|
||||
VERIFY(mutex_lock(&ztest_vdev_lock) == 0);
|
||||
leaves =
|
||||
MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
|
||||
leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
|
||||
|
||||
spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
|
||||
|
||||
@ -3182,7 +3181,7 @@ ztest_objset_destroy_cb(const char *name, void *arg)
|
||||
/*
|
||||
* Verify that the dataset contains a directory object.
|
||||
*/
|
||||
VERIFY3U(0, ==, dmu_objset_hold(name, FTAG, &os));
|
||||
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, FTAG, &os));
|
||||
error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
|
||||
if (error != ENOENT) {
|
||||
/* We could have crashed in the middle of destroying it */
|
||||
@ -3190,12 +3189,16 @@ ztest_objset_destroy_cb(const char *name, void *arg)
|
||||
ASSERT3U(doi.doi_type, ==, DMU_OT_ZAP_OTHER);
|
||||
ASSERT3S(doi.doi_physical_blocks_512, >=, 0);
|
||||
}
|
||||
dmu_objset_rele(os, FTAG);
|
||||
dmu_objset_disown(os, FTAG);
|
||||
|
||||
/*
|
||||
* Destroy the dataset.
|
||||
*/
|
||||
VERIFY3U(0, ==, dmu_objset_destroy(name, B_FALSE));
|
||||
if (strchr(name, '@') != NULL) {
|
||||
VERIFY0(dsl_destroy_snapshot(name, B_FALSE));
|
||||
} else {
|
||||
VERIFY0(dsl_destroy_head(name));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -3205,17 +3208,17 @@ ztest_snapshot_create(char *osname, uint64_t id)
|
||||
char snapname[MAXNAMELEN];
|
||||
int error;
|
||||
|
||||
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
|
||||
(u_longlong_t)id);
|
||||
(void) snprintf(snapname, sizeof (snapname), "%llu", (u_longlong_t)id);
|
||||
|
||||
error = dmu_objset_snapshot(osname, strchr(snapname, '@') + 1,
|
||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
||||
error = dmu_objset_snapshot_one(osname, snapname);
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc(FTAG);
|
||||
return (B_FALSE);
|
||||
}
|
||||
if (error != 0 && error != EEXIST)
|
||||
fatal(0, "ztest_snapshot_create(%s) = %d", snapname, error);
|
||||
if (error != 0 && error != EEXIST) {
|
||||
fatal(0, "ztest_snapshot_create(%s@%s) = %d", osname,
|
||||
snapname, error);
|
||||
}
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
@ -3228,7 +3231,7 @@ ztest_snapshot_destroy(char *osname, uint64_t id)
|
||||
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
|
||||
(u_longlong_t)id);
|
||||
|
||||
error = dmu_objset_destroy(snapname, B_FALSE);
|
||||
error = dsl_destroy_snapshot(snapname, B_FALSE);
|
||||
if (error != 0 && error != ENOENT)
|
||||
fatal(0, "ztest_snapshot_destroy(%s) = %d", snapname, error);
|
||||
return (B_TRUE);
|
||||
@ -3274,7 +3277,8 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
/*
|
||||
* Verify that the destroyed dataset is no longer in the namespace.
|
||||
*/
|
||||
VERIFY3U(ENOENT, ==, dmu_objset_hold(name, FTAG, &os));
|
||||
VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
|
||||
FTAG, &os));
|
||||
|
||||
/*
|
||||
* Verify that we can create a new dataset.
|
||||
@ -3289,8 +3293,7 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_create(%s) = %d", name, error);
|
||||
}
|
||||
|
||||
VERIFY3U(0, ==,
|
||||
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
|
||||
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
|
||||
|
||||
ztest_zd_init(&zdtmp, NULL, os);
|
||||
|
||||
@ -3366,21 +3369,21 @@ ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
|
||||
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", osname, id);
|
||||
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", clone1name, id);
|
||||
|
||||
error = dmu_objset_destroy(clone2name, B_FALSE);
|
||||
error = dsl_destroy_head(clone2name);
|
||||
if (error && error != ENOENT)
|
||||
fatal(0, "dmu_objset_destroy(%s) = %d", clone2name, error);
|
||||
error = dmu_objset_destroy(snap3name, B_FALSE);
|
||||
fatal(0, "dsl_destroy_head(%s) = %d", clone2name, error);
|
||||
error = dsl_destroy_snapshot(snap3name, B_FALSE);
|
||||
if (error && error != ENOENT)
|
||||
fatal(0, "dmu_objset_destroy(%s) = %d", snap3name, error);
|
||||
error = dmu_objset_destroy(snap2name, B_FALSE);
|
||||
fatal(0, "dsl_destroy_snapshot(%s) = %d", snap3name, error);
|
||||
error = dsl_destroy_snapshot(snap2name, B_FALSE);
|
||||
if (error && error != ENOENT)
|
||||
fatal(0, "dmu_objset_destroy(%s) = %d", snap2name, error);
|
||||
error = dmu_objset_destroy(clone1name, B_FALSE);
|
||||
fatal(0, "dsl_destroy_snapshot(%s) = %d", snap2name, error);
|
||||
error = dsl_destroy_head(clone1name);
|
||||
if (error && error != ENOENT)
|
||||
fatal(0, "dmu_objset_destroy(%s) = %d", clone1name, error);
|
||||
error = dmu_objset_destroy(snap1name, B_FALSE);
|
||||
fatal(0, "dsl_destroy_head(%s) = %d", clone1name, error);
|
||||
error = dsl_destroy_snapshot(snap1name, B_FALSE);
|
||||
if (error && error != ENOENT)
|
||||
fatal(0, "dmu_objset_destroy(%s) = %d", snap1name, error);
|
||||
fatal(0, "dsl_destroy_snapshot(%s) = %d", snap1name, error);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3389,8 +3392,7 @@ ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
|
||||
void
|
||||
ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
{
|
||||
objset_t *clone;
|
||||
dsl_dataset_t *ds;
|
||||
objset_t *os;
|
||||
char snap1name[MAXNAMELEN];
|
||||
char clone1name[MAXNAMELEN];
|
||||
char snap2name[MAXNAMELEN];
|
||||
@ -3409,8 +3411,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", osname, id);
|
||||
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", clone1name, id);
|
||||
|
||||
error = dmu_objset_snapshot(osname, strchr(snap1name, '@')+1,
|
||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
||||
error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1);
|
||||
if (error && error != EEXIST) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc(FTAG);
|
||||
@ -3419,12 +3420,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_take_snapshot(%s) = %d", snap1name, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_hold(snap1name, FTAG, &clone);
|
||||
if (error)
|
||||
fatal(0, "dmu_open_snapshot(%s) = %d", snap1name, error);
|
||||
|
||||
error = dmu_objset_clone(clone1name, dmu_objset_ds(clone), 0);
|
||||
dmu_objset_rele(clone, FTAG);
|
||||
error = dmu_objset_clone(clone1name, snap1name);
|
||||
if (error) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc(FTAG);
|
||||
@ -3433,8 +3429,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_snapshot(clone1name, strchr(snap2name, '@')+1,
|
||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
||||
error = dmu_objset_snapshot_one(clone1name, strchr(snap2name, '@') + 1);
|
||||
if (error && error != EEXIST) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc(FTAG);
|
||||
@ -3443,8 +3438,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_snapshot(clone1name, strchr(snap3name, '@')+1,
|
||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
||||
error = dmu_objset_snapshot_one(clone1name, strchr(snap3name, '@') + 1);
|
||||
if (error && error != EEXIST) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc(FTAG);
|
||||
@ -3453,12 +3447,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_hold(snap3name, FTAG, &clone);
|
||||
if (error)
|
||||
fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
|
||||
|
||||
error = dmu_objset_clone(clone2name, dmu_objset_ds(clone), 0);
|
||||
dmu_objset_rele(clone, FTAG);
|
||||
error = dmu_objset_clone(clone2name, snap3name);
|
||||
if (error) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc(FTAG);
|
||||
@ -3467,14 +3456,14 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
|
||||
}
|
||||
|
||||
error = dsl_dataset_own(snap2name, B_FALSE, FTAG, &ds);
|
||||
error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, FTAG, &os);
|
||||
if (error)
|
||||
fatal(0, "dsl_dataset_own(%s) = %d", snap2name, error);
|
||||
fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
|
||||
error = dsl_dataset_promote(clone2name, NULL);
|
||||
if (error != EBUSY)
|
||||
fatal(0, "dsl_dataset_promote(%s), %d, not EBUSY", clone2name,
|
||||
error);
|
||||
dsl_dataset_disown(ds, FTAG);
|
||||
dmu_objset_disown(os, FTAG);
|
||||
|
||||
out:
|
||||
ztest_dsl_dataset_cleanup(osname, id);
|
||||
@ -4286,7 +4275,7 @@ ztest_zap_parallel(ztest_ds_t *zd, uint64_t id)
|
||||
}
|
||||
|
||||
count = -1ULL;
|
||||
VERIFY(zap_count(os, object, &count) == 0);
|
||||
VERIFY0(zap_count(os, object, &count));
|
||||
ASSERT(count != -1ULL);
|
||||
|
||||
/*
|
||||
@ -4597,6 +4586,22 @@ ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id)
|
||||
(void) rw_unlock(&ztest_name_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
user_release_one(const char *snapname, const char *holdname)
|
||||
{
|
||||
nvlist_t *snaps, *holds;
|
||||
int error;
|
||||
|
||||
snaps = fnvlist_alloc();
|
||||
holds = fnvlist_alloc();
|
||||
fnvlist_add_boolean(holds, holdname);
|
||||
fnvlist_add_nvlist(snaps, snapname, holds);
|
||||
fnvlist_free(holds);
|
||||
error = dsl_dataset_user_release(snaps, NULL);
|
||||
fnvlist_free(snaps);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test snapshot hold/release and deferred destroy.
|
||||
*/
|
||||
@ -4611,29 +4616,36 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
|
||||
char clonename[100];
|
||||
char tag[100];
|
||||
char osname[MAXNAMELEN];
|
||||
nvlist_t *holds;
|
||||
|
||||
(void) rw_rdlock(&ztest_name_lock);
|
||||
|
||||
dmu_objset_name(os, osname);
|
||||
|
||||
(void) snprintf(snapname, 100, "sh1_%llu", id);
|
||||
(void) snprintf(fullname, 100, "%s@%s", osname, snapname);
|
||||
(void) snprintf(clonename, 100, "%s/ch1_%llu", osname, id);
|
||||
(void) snprintf(tag, 100, "%tag_%llu", id);
|
||||
(void) snprintf(snapname, sizeof (snapname), "sh1_%llu", id);
|
||||
(void) snprintf(fullname, sizeof (fullname), "%s@%s", osname, snapname);
|
||||
(void) snprintf(clonename, sizeof (clonename),
|
||||
"%s/ch1_%llu", osname, id);
|
||||
(void) snprintf(tag, sizeof (tag), "tag_%llu", id);
|
||||
|
||||
/*
|
||||
* Clean up from any previous run.
|
||||
*/
|
||||
(void) dmu_objset_destroy(clonename, B_FALSE);
|
||||
(void) dsl_dataset_user_release(osname, snapname, tag, B_FALSE);
|
||||
(void) dmu_objset_destroy(fullname, B_FALSE);
|
||||
error = dsl_destroy_head(clonename);
|
||||
if (error != ENOENT)
|
||||
ASSERT0(error);
|
||||
error = user_release_one(fullname, tag);
|
||||
if (error != ESRCH && error != ENOENT)
|
||||
ASSERT0(error);
|
||||
error = dsl_destroy_snapshot(fullname, B_FALSE);
|
||||
if (error != ENOENT)
|
||||
ASSERT0(error);
|
||||
|
||||
/*
|
||||
* Create snapshot, clone it, mark snap for deferred destroy,
|
||||
* destroy clone, verify snap was also destroyed.
|
||||
*/
|
||||
error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
|
||||
FALSE, -1);
|
||||
error = dmu_objset_snapshot_one(osname, snapname);
|
||||
if (error) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc("dmu_objset_snapshot");
|
||||
@ -4642,12 +4654,7 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_hold(fullname, FTAG, &origin);
|
||||
if (error)
|
||||
fatal(0, "dmu_objset_hold(%s) = %d", fullname, error);
|
||||
|
||||
error = dmu_objset_clone(clonename, dmu_objset_ds(origin), 0);
|
||||
dmu_objset_rele(origin, FTAG);
|
||||
error = dmu_objset_clone(clonename, fullname);
|
||||
if (error) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc("dmu_objset_clone");
|
||||
@ -4656,15 +4663,15 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_clone(%s) = %d", clonename, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_destroy(fullname, B_TRUE);
|
||||
error = dsl_destroy_snapshot(fullname, B_TRUE);
|
||||
if (error) {
|
||||
fatal(0, "dmu_objset_destroy(%s, B_TRUE) = %d",
|
||||
fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
|
||||
fullname, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_destroy(clonename, B_FALSE);
|
||||
error = dsl_destroy_head(clonename);
|
||||
if (error)
|
||||
fatal(0, "dmu_objset_destroy(%s) = %d", clonename, error);
|
||||
fatal(0, "dsl_destroy_head(%s) = %d", clonename, error);
|
||||
|
||||
error = dmu_objset_hold(fullname, FTAG, &origin);
|
||||
if (error != ENOENT)
|
||||
@ -4675,8 +4682,7 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
|
||||
* destroy a held snapshot, mark for deferred destroy,
|
||||
* release hold, verify snapshot was destroyed.
|
||||
*/
|
||||
error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
|
||||
FALSE, -1);
|
||||
error = dmu_objset_snapshot_one(osname, snapname);
|
||||
if (error) {
|
||||
if (error == ENOSPC) {
|
||||
ztest_record_enospc("dmu_objset_snapshot");
|
||||
@ -4685,28 +4691,31 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
|
||||
fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
|
||||
}
|
||||
|
||||
error = dsl_dataset_user_hold(osname, snapname, tag, B_FALSE,
|
||||
B_TRUE, -1);
|
||||
holds = fnvlist_alloc();
|
||||
fnvlist_add_string(holds, fullname, tag);
|
||||
error = dsl_dataset_user_hold(holds, 0, NULL);
|
||||
fnvlist_free(holds);
|
||||
|
||||
if (error)
|
||||
fatal(0, "dsl_dataset_user_hold(%s)", fullname, tag);
|
||||
|
||||
error = dmu_objset_destroy(fullname, B_FALSE);
|
||||
error = dsl_destroy_snapshot(fullname, B_FALSE);
|
||||
if (error != EBUSY) {
|
||||
fatal(0, "dmu_objset_destroy(%s, B_FALSE) = %d",
|
||||
fatal(0, "dsl_destroy_snapshot(%s, B_FALSE) = %d",
|
||||
fullname, error);
|
||||
}
|
||||
|
||||
error = dmu_objset_destroy(fullname, B_TRUE);
|
||||
error = dsl_destroy_snapshot(fullname, B_TRUE);
|
||||
if (error) {
|
||||
fatal(0, "dmu_objset_destroy(%s, B_TRUE) = %d",
|
||||
fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
|
||||
fullname, error);
|
||||
}
|
||||
|
||||
error = dsl_dataset_user_release(osname, snapname, tag, B_FALSE);
|
||||
error = user_release_one(fullname, tag);
|
||||
if (error)
|
||||
fatal(0, "dsl_dataset_user_release(%s)", fullname, tag);
|
||||
fatal(0, "user_release_one(%s)", fullname, tag);
|
||||
|
||||
VERIFY(dmu_objset_hold(fullname, FTAG, &origin) == ENOENT);
|
||||
VERIFY3U(dmu_objset_hold(fullname, FTAG, &origin), ==, ENOENT);
|
||||
|
||||
out:
|
||||
(void) rw_unlock(&ztest_name_lock);
|
||||
@ -4960,8 +4969,12 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id)
|
||||
*/
|
||||
for (int i = 0; i < copies; i++) {
|
||||
uint64_t offset = i * blocksize;
|
||||
VERIFY0(dmu_buf_hold(os, object, offset, FTAG, &db,
|
||||
DMU_READ_NO_PREFETCH));
|
||||
int error = dmu_buf_hold(os, object, offset, FTAG, &db,
|
||||
DMU_READ_NO_PREFETCH);
|
||||
if (error != 0) {
|
||||
fatal(B_FALSE, "dmu_buf_hold(%p, %llu, %llu) = %u",
|
||||
os, (long long)object, (long long) offset, error);
|
||||
}
|
||||
ASSERT(db->db_offset == offset);
|
||||
ASSERT(db->db_size == blocksize);
|
||||
ASSERT(ztest_pattern_match(db->db_data, db->db_size, pattern) ||
|
||||
@ -5172,6 +5185,7 @@ ztest_spa_import_export(char *oldname, char *newname)
|
||||
nvlist_t *config, *newconfig;
|
||||
uint64_t pool_guid;
|
||||
spa_t *spa;
|
||||
int error;
|
||||
|
||||
if (ztest_opts.zo_verbose >= 4) {
|
||||
(void) printf("import/export: old = %s, new = %s\n",
|
||||
@ -5216,7 +5230,12 @@ ztest_spa_import_export(char *oldname, char *newname)
|
||||
/*
|
||||
* Import it under the new name.
|
||||
*/
|
||||
VERIFY3U(0, ==, spa_import(newname, config, NULL, 0));
|
||||
error = spa_import(newname, config, NULL, 0);
|
||||
if (error != 0) {
|
||||
dump_nvlist(config, 0);
|
||||
fatal(B_FALSE, "couldn't import pool %s as %s: error %u",
|
||||
oldname, newname, error);
|
||||
}
|
||||
|
||||
ztest_walk_pool_directory("pools after import");
|
||||
|
||||
@ -5423,7 +5442,7 @@ ztest_dataset_open(int d)
|
||||
}
|
||||
ASSERT(error == 0 || error == EEXIST);
|
||||
|
||||
VERIFY0(dmu_objset_hold(name, zd, &os));
|
||||
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, zd, &os));
|
||||
(void) rw_unlock(&ztest_name_lock);
|
||||
|
||||
ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
|
||||
@ -5464,7 +5483,7 @@ ztest_dataset_close(int d)
|
||||
ztest_ds_t *zd = &ztest_ds[d];
|
||||
|
||||
zil_close(zd->zd_zilog);
|
||||
dmu_objset_rele(zd->zd_os, zd);
|
||||
dmu_objset_disown(zd->zd_os, zd);
|
||||
|
||||
ztest_zd_fini(zd);
|
||||
}
|
||||
@ -5508,13 +5527,14 @@ ztest_run(ztest_shared_t *zs)
|
||||
* Open our pool.
|
||||
*/
|
||||
kernel_init(FREAD | FWRITE);
|
||||
VERIFY(spa_open(ztest_opts.zo_pool, &spa, FTAG) == 0);
|
||||
VERIFY0(spa_open(ztest_opts.zo_pool, &spa, FTAG));
|
||||
spa->spa_debug = B_TRUE;
|
||||
ztest_spa = spa;
|
||||
|
||||
VERIFY3U(0, ==, dmu_objset_hold(ztest_opts.zo_pool, FTAG, &os));
|
||||
VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
|
||||
DMU_OST_ANY, B_TRUE, FTAG, &os));
|
||||
zs->zs_guid = dmu_objset_fsid_guid(os);
|
||||
dmu_objset_rele(os, FTAG);
|
||||
dmu_objset_disown(os, FTAG);
|
||||
|
||||
spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
|
||||
|
||||
@ -5791,8 +5811,7 @@ ztest_init(ztest_shared_t *zs)
|
||||
spa_feature_table[i].fi_uname);
|
||||
VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
|
||||
}
|
||||
VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props,
|
||||
NULL, NULL));
|
||||
VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL));
|
||||
nvlist_free(nvroot);
|
||||
|
||||
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
|
||||
|
@ -22,6 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, Joyent Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -679,13 +680,59 @@ dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
|
||||
ap->dtad_kind = DTRACEACT_DIFEXPR;
|
||||
}
|
||||
|
||||
/*
|
||||
* The print() action behaves identically to trace(), except that it stores the
|
||||
* CTF type of the argument (if present) within the DOF for the DIFEXPR action.
|
||||
* To do this, we set the 'dtsd_strdata' to point to the fully-qualified CTF
|
||||
* type ID for the result of the DIF action. We use the ID instead of the name
|
||||
* to handles complex types like arrays and function pointers that can't be
|
||||
* resolved by ctf_type_lookup(). This is later processed by
|
||||
* dtrace_dof_create() and turned into a reference into the string table so
|
||||
* that we can get the type information when we process the data after the
|
||||
* fact.
|
||||
*/
|
||||
static void
|
||||
dt_action_print(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
|
||||
{
|
||||
dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
|
||||
dt_node_t *dret;
|
||||
size_t len;
|
||||
dt_module_t *dmp;
|
||||
|
||||
if (dt_node_is_void(dnp->dn_args)) {
|
||||
dnerror(dnp->dn_args, D_PRINT_VOID,
|
||||
"print( ) may not be applied to a void expression\n");
|
||||
}
|
||||
|
||||
if (dt_node_is_dynamic(dnp->dn_args)) {
|
||||
dnerror(dnp->dn_args, D_PRINT_DYN,
|
||||
"print( ) may not be applied to a dynamic expression\n");
|
||||
}
|
||||
|
||||
dt_cg(yypcb, dnp->dn_args);
|
||||
|
||||
dret = yypcb->pcb_dret;
|
||||
dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
|
||||
|
||||
len = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;
|
||||
sdp->dtsd_strdata = dt_alloc(dtp, len);
|
||||
if (sdp->dtsd_strdata == NULL)
|
||||
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
|
||||
(void) snprintf(sdp->dtsd_strdata, len, "%s`%ld", dmp->dm_name,
|
||||
dret->dn_type);
|
||||
|
||||
ap->dtad_difo = dt_as(yypcb);
|
||||
ap->dtad_kind = DTRACEACT_DIFEXPR;
|
||||
}
|
||||
|
||||
static void
|
||||
dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
|
||||
{
|
||||
dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
|
||||
|
||||
dt_node_t *addr = dnp->dn_args;
|
||||
dt_node_t *size = dnp->dn_args->dn_list;
|
||||
dt_node_t *max = dnp->dn_args->dn_list;
|
||||
dt_node_t *size;
|
||||
|
||||
char n[DT_TYPE_NAMELEN];
|
||||
|
||||
@ -697,17 +744,37 @@ dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
|
||||
dt_node_type_name(addr, n, sizeof (n)));
|
||||
}
|
||||
|
||||
if (dt_node_is_posconst(size) == 0) {
|
||||
dnerror(size, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
|
||||
if (dt_node_is_posconst(max) == 0) {
|
||||
dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
|
||||
"be a non-zero positive integral constant expression\n");
|
||||
}
|
||||
|
||||
if ((size = max->dn_list) != NULL) {
|
||||
if (size->dn_list != NULL) {
|
||||
dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype "
|
||||
"mismatch: expected at most 3 args\n");
|
||||
}
|
||||
|
||||
if (!dt_node_is_scalar(size)) {
|
||||
dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) "
|
||||
"dynamic size (argument #3) must be of "
|
||||
"scalar type\n");
|
||||
}
|
||||
|
||||
dt_cg(yypcb, size);
|
||||
ap->dtad_difo = dt_as(yypcb);
|
||||
ap->dtad_difo->dtdo_rtype = dt_int_rtype;
|
||||
ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE;
|
||||
|
||||
ap = dt_stmt_action(dtp, sdp);
|
||||
}
|
||||
|
||||
dt_cg(yypcb, addr);
|
||||
ap->dtad_difo = dt_as(yypcb);
|
||||
ap->dtad_kind = DTRACEACT_DIFEXPR;
|
||||
ap->dtad_kind = DTRACEACT_TRACEMEM;
|
||||
|
||||
ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
|
||||
ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value;
|
||||
ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1114,6 +1181,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
|
||||
case DT_ACT_TRACE:
|
||||
dt_action_trace(dtp, dnp->dn_expr, sdp);
|
||||
break;
|
||||
case DT_ACT_PRINT:
|
||||
dt_action_print(dtp, dnp->dn_expr, sdp);
|
||||
break;
|
||||
case DT_ACT_TRACEMEM:
|
||||
dt_action_tracemem(dtp, dnp->dn_expr, sdp);
|
||||
break;
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -832,7 +833,7 @@ dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
|
||||
size_t nbytes, int width, int quiet, int raw)
|
||||
size_t nbytes, int width, int quiet, int forceraw)
|
||||
{
|
||||
/*
|
||||
* If the byte stream is a series of printable characters, followed by
|
||||
@ -845,7 +846,10 @@ dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
|
||||
if (nbytes == 0)
|
||||
return (0);
|
||||
|
||||
if (raw || dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
|
||||
if (forceraw)
|
||||
goto raw;
|
||||
|
||||
if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
|
||||
goto raw;
|
||||
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
@ -2019,6 +2023,7 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
|
||||
int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
|
||||
int rval, i, n;
|
||||
dtrace_epid_t last = DTRACE_EPIDNONE;
|
||||
uint64_t tracememsize = 0;
|
||||
dtrace_probedata_t data;
|
||||
uint64_t drops;
|
||||
caddr_t addr;
|
||||
@ -2187,6 +2192,13 @@ again:
|
||||
}
|
||||
}
|
||||
|
||||
if (act == DTRACEACT_TRACEMEM_DYNSIZE &&
|
||||
rec->dtrd_size == sizeof (uint64_t)) {
|
||||
/* LINTED - alignment */
|
||||
tracememsize = *((unsigned long long *)addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
rval = (*rfunc)(&data, rec, arg);
|
||||
|
||||
if (rval == DTRACE_CONSUME_NEXT)
|
||||
@ -2290,6 +2302,35 @@ again:
|
||||
goto nextrec;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a DIF expression, and the record has a
|
||||
* format set, this indicates we have a CTF type name
|
||||
* associated with the data and we should try to print
|
||||
* it out by type.
|
||||
*/
|
||||
if (act == DTRACEACT_DIFEXPR) {
|
||||
const char *strdata = dt_strdata_lookup(dtp,
|
||||
rec->dtrd_format);
|
||||
if (strdata != NULL) {
|
||||
n = dtrace_print(dtp, fp, strdata,
|
||||
addr, rec->dtrd_size);
|
||||
|
||||
/*
|
||||
* dtrace_print() will return -1 on
|
||||
* error, or return the number of bytes
|
||||
* consumed. It will return 0 if the
|
||||
* type couldn't be determined, and we
|
||||
* should fall through to the normal
|
||||
* trace method.
|
||||
*/
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
|
||||
if (n > 0)
|
||||
goto nextrec;
|
||||
}
|
||||
}
|
||||
|
||||
nofmt:
|
||||
if (act == DTRACEACT_PRINTA) {
|
||||
dt_print_aggdata_t pd;
|
||||
@ -2358,6 +2399,23 @@ nofmt:
|
||||
goto nextrec;
|
||||
}
|
||||
|
||||
if (act == DTRACEACT_TRACEMEM) {
|
||||
if (tracememsize == 0 ||
|
||||
tracememsize > rec->dtrd_size) {
|
||||
tracememsize = rec->dtrd_size;
|
||||
}
|
||||
|
||||
n = dt_print_bytes(dtp, fp, addr,
|
||||
tracememsize, 33, quiet, 1);
|
||||
|
||||
tracememsize = 0;
|
||||
|
||||
if (n < 0)
|
||||
return (-1);
|
||||
|
||||
goto nextrec;
|
||||
}
|
||||
|
||||
switch (rec->dtrd_size) {
|
||||
case sizeof (uint64_t):
|
||||
n = dt_printf(dtp, fp,
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -758,16 +759,23 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
|
||||
dofa[i].dofa_difo = DOF_SECIDX_NONE;
|
||||
|
||||
/*
|
||||
* If the first action in a statement has format data,
|
||||
* add the format string to the global string table.
|
||||
* If the first action in a statement has string data,
|
||||
* add the string to the global string table. This can
|
||||
* be due either to a printf() format string
|
||||
* (dtsd_fmtdata) or a print() type string
|
||||
* (dtsd_strdata).
|
||||
*/
|
||||
if (sdp != NULL && ap == sdp->dtsd_action) {
|
||||
if (sdp->dtsd_fmtdata != NULL) {
|
||||
(void) dtrace_printf_format(dtp,
|
||||
sdp->dtsd_fmtdata, fmt, maxfmt + 1);
|
||||
strndx = dof_add_string(ddo, fmt);
|
||||
} else
|
||||
} else if (sdp->dtsd_strdata != NULL) {
|
||||
strndx = dof_add_string(ddo,
|
||||
sdp->dtsd_strdata);
|
||||
} else {
|
||||
strndx = 0; /* use dtad_arg instead */
|
||||
}
|
||||
|
||||
if ((next = dt_list_next(next)) != NULL)
|
||||
sdp = next->ds_desc;
|
||||
|
@ -24,11 +24,14 @@
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DT_ERRTAGS_H
|
||||
#define _DT_ERRTAGS_H
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -187,8 +190,12 @@ typedef enum {
|
||||
D_PRINTA_AGGPROTO, /* printa() aggregation mismatch */
|
||||
D_TRACE_VOID, /* trace() argument has void type */
|
||||
D_TRACE_DYN, /* trace() argument has dynamic type */
|
||||
D_PRINT_VOID, /* print() argument has void type */
|
||||
D_PRINT_DYN, /* print() argument has dynamic type */
|
||||
D_TRACEMEM_ADDR, /* tracemem() address bad type */
|
||||
D_TRACEMEM_SIZE, /* tracemem() size bad type */
|
||||
D_TRACEMEM_ARGS, /* tracemem() illegal number of args */
|
||||
D_TRACEMEM_DYNSIZE, /* tracemem() dynamic size bad type */
|
||||
D_STACK_PROTO, /* stack() prototype mismatch */
|
||||
D_STACK_SIZE, /* stack() size argument bad type */
|
||||
D_USTACK_FRAMES, /* ustack() frames arg bad type */
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DT_IMPL_H
|
||||
@ -253,6 +254,8 @@ struct dtrace_hdl {
|
||||
dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */
|
||||
int dt_maxformat; /* max format ID */
|
||||
void **dt_formats; /* pointer to format array */
|
||||
int dt_maxstrdata; /* max strdata ID */
|
||||
char **dt_strdata; /* pointer to strdata array */
|
||||
dt_aggregate_t dt_aggregate; /* aggregate */
|
||||
dtrace_bufdesc_t dt_buf; /* staging buffer */
|
||||
struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
|
||||
@ -438,8 +441,9 @@ struct dtrace_hdl {
|
||||
#define DT_ACT_UMOD DT_ACT(26) /* umod() action */
|
||||
#define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */
|
||||
#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
|
||||
#define DT_ACT_PRINTM DT_ACT(29) /* printm() action */
|
||||
#define DT_ACT_PRINTT DT_ACT(30) /* printt() action */
|
||||
#define DT_ACT_PRINT DT_ACT(29) /* print() action */
|
||||
#define DT_ACT_PRINTM DT_ACT(30) /* printm() action */
|
||||
#define DT_ACT_PRINTT DT_ACT(31) /* printt() action */
|
||||
|
||||
/*
|
||||
* Sentinel to tell freopen() to restore the saved stdout. This must not
|
||||
@ -641,6 +645,9 @@ extern void dt_aggid_destroy(dtrace_hdl_t *);
|
||||
extern void *dt_format_lookup(dtrace_hdl_t *, int);
|
||||
extern void dt_format_destroy(dtrace_hdl_t *);
|
||||
|
||||
extern const char *dt_strdata_lookup(dtrace_hdl_t *, int);
|
||||
extern void dt_strdata_destroy(dtrace_hdl_t *);
|
||||
|
||||
extern int dt_print_quantize(dtrace_hdl_t *, FILE *,
|
||||
const void *, size_t, uint64_t);
|
||||
extern int dt_print_lquantize(dtrace_hdl_t *, FILE *,
|
||||
|
@ -23,7 +23,9 @@
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||
/*
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
@ -34,11 +36,82 @@
|
||||
#include <dt_impl.h>
|
||||
#include <dt_printf.h>
|
||||
|
||||
static int
|
||||
dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
|
||||
{
|
||||
int maxformat;
|
||||
dtrace_fmtdesc_t fmt;
|
||||
void *result;
|
||||
|
||||
if (rec->dtrd_format == 0)
|
||||
return (0);
|
||||
|
||||
if (rec->dtrd_format <= *max &&
|
||||
(*data)[rec->dtrd_format - 1] != NULL) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
bzero(&fmt, sizeof (fmt));
|
||||
fmt.dtfd_format = rec->dtrd_format;
|
||||
fmt.dtfd_string = NULL;
|
||||
fmt.dtfd_length = 0;
|
||||
|
||||
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
|
||||
return (dt_set_errno(dtp, errno));
|
||||
|
||||
if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
|
||||
return (dt_set_errno(dtp, EDT_NOMEM));
|
||||
|
||||
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
|
||||
free(fmt.dtfd_string);
|
||||
return (dt_set_errno(dtp, errno));
|
||||
}
|
||||
|
||||
while (rec->dtrd_format > (maxformat = *max)) {
|
||||
int new_max = maxformat ? (maxformat << 1) : 1;
|
||||
size_t nsize = new_max * sizeof (void *);
|
||||
size_t osize = maxformat * sizeof (void *);
|
||||
void **new_data = dt_zalloc(dtp, nsize);
|
||||
|
||||
if (new_data == NULL) {
|
||||
dt_free(dtp, fmt.dtfd_string);
|
||||
return (dt_set_errno(dtp, EDT_NOMEM));
|
||||
}
|
||||
|
||||
bcopy(*data, new_data, osize);
|
||||
free(*data);
|
||||
|
||||
*data = new_data;
|
||||
*max = new_max;
|
||||
}
|
||||
|
||||
switch (rec->dtrd_action) {
|
||||
case DTRACEACT_DIFEXPR:
|
||||
result = fmt.dtfd_string;
|
||||
break;
|
||||
case DTRACEACT_PRINTA:
|
||||
result = dtrace_printa_create(dtp, fmt.dtfd_string);
|
||||
dt_free(dtp, fmt.dtfd_string);
|
||||
break;
|
||||
default:
|
||||
result = dtrace_printf_create(dtp, fmt.dtfd_string);
|
||||
dt_free(dtp, fmt.dtfd_string);
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == NULL)
|
||||
return (-1);
|
||||
|
||||
(*data)[rec->dtrd_format - 1] = result;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
|
||||
{
|
||||
dtrace_id_t max;
|
||||
int rval, i, maxformat;
|
||||
int rval, i;
|
||||
dtrace_eprobedesc_t *enabled, *nenabled;
|
||||
dtrace_probedesc_t *probe;
|
||||
|
||||
@ -132,71 +205,23 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
|
||||
}
|
||||
|
||||
for (i = 0; i < enabled->dtepd_nrecs; i++) {
|
||||
dtrace_fmtdesc_t fmt;
|
||||
dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
|
||||
|
||||
if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
|
||||
continue;
|
||||
|
||||
if (rec->dtrd_format == 0)
|
||||
continue;
|
||||
|
||||
if (rec->dtrd_format <= dtp->dt_maxformat &&
|
||||
dtp->dt_formats[rec->dtrd_format - 1] != NULL)
|
||||
continue;
|
||||
|
||||
bzero(&fmt, sizeof (fmt));
|
||||
fmt.dtfd_format = rec->dtrd_format;
|
||||
fmt.dtfd_string = NULL;
|
||||
fmt.dtfd_length = 0;
|
||||
|
||||
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
|
||||
rval = dt_set_errno(dtp, errno);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
|
||||
rval = dt_set_errno(dtp, EDT_NOMEM);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
|
||||
rval = dt_set_errno(dtp, errno);
|
||||
free(fmt.dtfd_string);
|
||||
goto err;
|
||||
}
|
||||
|
||||
while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
|
||||
int new_max = maxformat ? (maxformat << 1) : 1;
|
||||
size_t nsize = new_max * sizeof (void *);
|
||||
size_t osize = maxformat * sizeof (void *);
|
||||
void **new_formats = malloc(nsize);
|
||||
|
||||
if (new_formats == NULL) {
|
||||
rval = dt_set_errno(dtp, EDT_NOMEM);
|
||||
free(fmt.dtfd_string);
|
||||
if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
|
||||
if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
|
||||
&dtp->dt_maxformat) != 0) {
|
||||
rval = -1;
|
||||
goto err;
|
||||
}
|
||||
} else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
|
||||
if (dt_strdata_add(dtp, rec,
|
||||
(void ***)&dtp->dt_strdata,
|
||||
&dtp->dt_maxstrdata) != 0) {
|
||||
rval = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
bzero(new_formats, nsize);
|
||||
bcopy(dtp->dt_formats, new_formats, osize);
|
||||
free(dtp->dt_formats);
|
||||
|
||||
dtp->dt_formats = new_formats;
|
||||
dtp->dt_maxformat = new_max;
|
||||
}
|
||||
|
||||
dtp->dt_formats[rec->dtrd_format - 1] =
|
||||
rec->dtrd_action == DTRACEACT_PRINTA ?
|
||||
dtrace_printa_create(dtp, fmt.dtfd_string) :
|
||||
dtrace_printf_create(dtp, fmt.dtfd_string);
|
||||
|
||||
free(fmt.dtfd_string);
|
||||
|
||||
if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
|
||||
rval = -1; /* dt_errno is set for us */
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
dtp->dt_pdesc[id] = probe;
|
||||
@ -440,3 +465,28 @@ dt_aggid_destroy(dtrace_hdl_t *dtp)
|
||||
dtp->dt_aggdesc = NULL;
|
||||
dtp->dt_maxagg = 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
|
||||
{
|
||||
if (idx == 0 || idx > dtp->dt_maxstrdata)
|
||||
return (NULL);
|
||||
|
||||
if (dtp->dt_strdata == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (dtp->dt_strdata[idx - 1]);
|
||||
}
|
||||
|
||||
void
|
||||
dt_strdata_destroy(dtrace_hdl_t *dtp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dtp->dt_maxstrdata; i++) {
|
||||
free(dtp->dt_strdata[i]);
|
||||
}
|
||||
|
||||
free(dtp->dt_strdata);
|
||||
dtp->dt_strdata = NULL;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -116,8 +117,12 @@
|
||||
#define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2)
|
||||
#define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3)
|
||||
#define DT_VERS_1_7 DT_VERSION_NUMBER(1, 7, 0)
|
||||
#define DT_VERS_LATEST DT_VERS_1_7
|
||||
#define DT_VERS_STRING "Sun D 1.7"
|
||||
#define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1)
|
||||
#define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0)
|
||||
#define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1)
|
||||
#define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0)
|
||||
#define DT_VERS_LATEST DT_VERS_1_9
|
||||
#define DT_VERS_STRING "Sun D 1.9"
|
||||
|
||||
const dt_version_t _dtrace_versions[] = {
|
||||
DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
|
||||
@ -134,6 +139,10 @@ const dt_version_t _dtrace_versions[] = {
|
||||
DT_VERS_1_6_2, /* D API 1.6.2 */
|
||||
DT_VERS_1_6_3, /* D API 1.6.3 */
|
||||
DT_VERS_1_7, /* D API 1.7 */
|
||||
DT_VERS_1_7_1, /* D API 1.7.1 */
|
||||
DT_VERS_1_8, /* D API 1.8 */
|
||||
DT_VERS_1_8_1, /* D API 1.8.1 */
|
||||
DT_VERS_1_9, /* D API 1.9 */
|
||||
0
|
||||
};
|
||||
|
||||
@ -289,7 +298,7 @@ static const dt_ident_t _dtrace_globals[] = {
|
||||
{ "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_func, "stack(...)" },
|
||||
{ "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_func, "string(int64_t)" },
|
||||
&dt_idops_func, "string(int64_t, [int])" },
|
||||
{ "llquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LLQUANTIZE, DT_ATTR_STABCMN,
|
||||
DT_VERS_1_7, &dt_idops_func,
|
||||
"void(@, int32_t, int32_t, int32_t, int32_t, ...)" },
|
||||
@ -351,6 +360,8 @@ static const dt_ident_t _dtrace_globals[] = {
|
||||
&dt_idops_type, "pid_t" },
|
||||
{ "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_type, "pid_t" },
|
||||
{ "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9,
|
||||
&dt_idops_func, "void(@)" },
|
||||
{ "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_func, "void(@, ...)" },
|
||||
{ "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
@ -457,11 +468,15 @@ static const dt_ident_t _dtrace_globals[] = {
|
||||
{ "timestamp", DT_IDENT_SCALAR, 0, DIF_VAR_TIMESTAMP,
|
||||
DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_type, "uint64_t" },
|
||||
{ "tolower", DT_IDENT_FUNC, 0, DIF_SUBR_TOLOWER, DT_ATTR_STABCMN, DT_VERS_1_8,
|
||||
&dt_idops_func, "string(const char *)" },
|
||||
{ "toupper", DT_IDENT_FUNC, 0, DIF_SUBR_TOUPPER, DT_ATTR_STABCMN, DT_VERS_1_8,
|
||||
&dt_idops_func, "string(const char *)" },
|
||||
{ "trace", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACE, DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_func, "void(@)" },
|
||||
{ "tracemem", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACEMEM,
|
||||
DT_ATTR_STABCMN, DT_VERS_1_0,
|
||||
&dt_idops_func, "void(@, size_t)" },
|
||||
&dt_idops_func, "void(@, size_t, ...)" },
|
||||
{ "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN,
|
||||
DT_VERS_1_0, &dt_idops_func, "void(...)" },
|
||||
{ "typeref", DT_IDENT_FUNC, 0, DIF_SUBR_TYPEREF, DT_ATTR_STABCMN, DT_VERS_1_1,
|
||||
@ -1115,7 +1130,7 @@ alloc:
|
||||
#if defined(sun)
|
||||
dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
|
||||
#else
|
||||
dtp->dt_prcmode = DT_PROC_STOP_MAIN;
|
||||
dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
|
||||
#endif
|
||||
dtp->dt_linkmode = DT_LINK_KERNEL;
|
||||
dtp->dt_linktype = DT_LTYP_ELF;
|
||||
@ -1612,6 +1627,7 @@ dtrace_close(dtrace_hdl_t *dtp)
|
||||
dt_epid_destroy(dtp);
|
||||
dt_aggid_destroy(dtp);
|
||||
dt_format_destroy(dtp);
|
||||
dt_strdata_destroy(dtp);
|
||||
dt_buffered_destroy(dtp);
|
||||
dt_aggregate_destroy(dtp);
|
||||
free(dtp->dt_buf.dtbd_data);
|
||||
|
648
cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
Normal file
648
cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
Normal file
@ -0,0 +1,648 @@
|
||||
/*
|
||||
* 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 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* DTrace print() action
|
||||
*
|
||||
* This file contains the post-processing logic for the print() action. The
|
||||
* print action behaves identically to trace() in that it generates a
|
||||
* DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type
|
||||
* string stored in the DOF string table (similar to printf formats). We
|
||||
* take the result of the trace action and post-process it in the fashion of
|
||||
* MDB's ::print dcmd.
|
||||
*
|
||||
* This implementation differs from MDB's in the following ways:
|
||||
*
|
||||
* - We do not expose any options or flags. The behavior of print() is
|
||||
* equivalent to "::print -tn".
|
||||
*
|
||||
* - MDB will display "holes" in structures (unused padding between
|
||||
* members).
|
||||
*
|
||||
* - When printing arrays of structures, MDB will leave a trailing ','
|
||||
* after the last element.
|
||||
*
|
||||
* - MDB will print time_t types as date and time.
|
||||
*
|
||||
* - MDB will detect when an enum is actually the OR of several flags,
|
||||
* and print it out with the constituent flags separated.
|
||||
*
|
||||
* - For large arrays, MDB will print the first few members and then
|
||||
* print a "..." continuation line.
|
||||
*
|
||||
* - MDB will break and wrap arrays at 80 columns.
|
||||
*
|
||||
* - MDB prints out floats and doubles by hand, as it must run in kmdb
|
||||
* context. We're able to leverage the printf() format strings,
|
||||
* but the result is a slightly different format.
|
||||
*/
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <alloca.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <dt_module.h>
|
||||
#include <dt_printf.h>
|
||||
#include <dt_string.h>
|
||||
#include <dt_impl.h>
|
||||
|
||||
/* determines whether the given integer CTF encoding is a character */
|
||||
#define CTF_IS_CHAR(e) \
|
||||
(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
|
||||
(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
|
||||
/* determines whether the given CTF kind is a struct or union */
|
||||
#define CTF_IS_STRUCTLIKE(k) \
|
||||
((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)
|
||||
|
||||
/*
|
||||
* Print structure passed down recursively through printing algorithm.
|
||||
*/
|
||||
typedef struct dt_printarg {
|
||||
caddr_t pa_addr; /* base address of trace data */
|
||||
ctf_file_t *pa_ctfp; /* CTF container */
|
||||
int pa_depth; /* member depth */
|
||||
int pa_nest; /* nested array depth */
|
||||
FILE *pa_file; /* output file */
|
||||
} dt_printarg_t;
|
||||
|
||||
static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
|
||||
|
||||
/*
|
||||
* Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it
|
||||
* can't resolve the type.
|
||||
*/
|
||||
static void
|
||||
dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)
|
||||
{
|
||||
if (ctf_type_name(ctfp, id, buf, buflen) == NULL)
|
||||
(void) snprintf(buf, buflen, "<%ld>", id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print any necessary trailing braces for structures or unions. We don't get
|
||||
* invoked when a struct or union ends, so we infer the need to print braces
|
||||
* based on the depth the last time we printed something and the new depth.
|
||||
*/
|
||||
static void
|
||||
dt_print_trailing_braces(dt_printarg_t *pap, int depth)
|
||||
{
|
||||
int d;
|
||||
|
||||
for (d = pap->pa_depth; d > depth; d--) {
|
||||
(void) fprintf(pap->pa_file, "%*s}%s",
|
||||
(d + pap->pa_nest - 1) * 4, "",
|
||||
d == depth + 1 ? "" : "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the appropriate amount of indentation given the current depth and
|
||||
* array nesting.
|
||||
*/
|
||||
static void
|
||||
dt_print_indent(dt_printarg_t *pap)
|
||||
{
|
||||
(void) fprintf(pap->pa_file, "%*s",
|
||||
(pap->pa_depth + pap->pa_nest) * 4, "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a bitfield. It's worth noting that the D compiler support for
|
||||
* bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
|
||||
* various D provider files) will produce incorrect results compared to
|
||||
* "genunix`user_desc_t".
|
||||
*/
|
||||
static void
|
||||
print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
|
||||
{
|
||||
FILE *fp = pap->pa_file;
|
||||
caddr_t addr = pap->pa_addr + off / NBBY;
|
||||
uint64_t mask = (1ULL << ep->cte_bits) - 1;
|
||||
uint64_t value = 0;
|
||||
size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
|
||||
uint8_t *buf = (uint8_t *)&value;
|
||||
uint8_t shift;
|
||||
|
||||
/*
|
||||
* On big-endian machines, we need to adjust the buf pointer to refer
|
||||
* to the lowest 'size' bytes in 'value', and we need to shift based on
|
||||
* the offset from the end of the data, not the offset of the start.
|
||||
*/
|
||||
#ifdef _BIG_ENDIAN
|
||||
buf += sizeof (value) - size;
|
||||
off += ep->cte_bits;
|
||||
#endif
|
||||
bcopy(addr, buf, size);
|
||||
shift = off % NBBY;
|
||||
|
||||
/*
|
||||
* Offsets are counted from opposite ends on little- and
|
||||
* big-endian machines.
|
||||
*/
|
||||
#ifdef _BIG_ENDIAN
|
||||
shift = NBBY - shift;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the bits we want do not begin on a byte boundary, shift the data
|
||||
* right so that the value is in the lowest 'cte_bits' of 'value'.
|
||||
*/
|
||||
if (off % NBBY != 0)
|
||||
value >>= shift;
|
||||
value &= mask;
|
||||
|
||||
(void) fprintf(fp, "%#llx", (u_longlong_t)value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump the contents of memory as a fixed-size integer in hex.
|
||||
*/
|
||||
static void
|
||||
dt_print_hex(FILE *fp, caddr_t addr, size_t size)
|
||||
{
|
||||
switch (size) {
|
||||
case sizeof (uint8_t):
|
||||
(void) fprintf(fp, "%#x", *(uint8_t *)addr);
|
||||
break;
|
||||
case sizeof (uint16_t):
|
||||
/* LINTED - alignment */
|
||||
(void) fprintf(fp, "%#x", *(uint16_t *)addr);
|
||||
break;
|
||||
case sizeof (uint32_t):
|
||||
/* LINTED - alignment */
|
||||
(void) fprintf(fp, "%#x", *(uint32_t *)addr);
|
||||
break;
|
||||
case sizeof (uint64_t):
|
||||
(void) fprintf(fp, "%#llx",
|
||||
/* LINTED - alignment */
|
||||
(unsigned long long)*(uint64_t *)addr);
|
||||
break;
|
||||
default:
|
||||
(void) fprintf(fp, "<invalid size %u>", (uint_t)size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print an integer type. Before dumping the contents via dt_print_hex(), we
|
||||
* first check the encoding to see if it's part of a bitfield or a character.
|
||||
*/
|
||||
static void
|
||||
dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
|
||||
{
|
||||
FILE *fp = pap->pa_file;
|
||||
ctf_file_t *ctfp = pap->pa_ctfp;
|
||||
ctf_encoding_t e;
|
||||
size_t size;
|
||||
caddr_t addr = pap->pa_addr + off / NBBY;
|
||||
|
||||
if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
|
||||
(void) fprintf(fp, "<unknown encoding>");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This comes from MDB - it's not clear under what circumstances this
|
||||
* would be found.
|
||||
*/
|
||||
if (e.cte_format & CTF_INT_VARARGS) {
|
||||
(void) fprintf(fp, "...");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We print this as a bitfield if the bit encoding indicates it's not
|
||||
* an even power of two byte size, or is larger than 8 bytes.
|
||||
*/
|
||||
size = e.cte_bits / NBBY;
|
||||
if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
|
||||
print_bitfield(pap, off, &e);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a character, print it out as such.
|
||||
*/
|
||||
if (CTF_IS_CHAR(e)) {
|
||||
char c = *(char *)addr;
|
||||
if (isprint(c))
|
||||
(void) fprintf(fp, "'%c'", c);
|
||||
else if (c == 0)
|
||||
(void) fprintf(fp, "'\\0'");
|
||||
else
|
||||
(void) fprintf(fp, "'\\%03o'", c);
|
||||
return;
|
||||
}
|
||||
|
||||
dt_print_hex(fp, addr, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a floating point (float, double, long double) value.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
|
||||
{
|
||||
FILE *fp = pap->pa_file;
|
||||
ctf_file_t *ctfp = pap->pa_ctfp;
|
||||
ctf_encoding_t e;
|
||||
caddr_t addr = pap->pa_addr + off / NBBY;
|
||||
|
||||
if (ctf_type_encoding(ctfp, base, &e) == 0) {
|
||||
if (e.cte_format == CTF_FP_SINGLE &&
|
||||
e.cte_bits == sizeof (float) * NBBY) {
|
||||
/* LINTED - alignment */
|
||||
(void) fprintf(fp, "%+.7e", *((float *)addr));
|
||||
} else if (e.cte_format == CTF_FP_DOUBLE &&
|
||||
e.cte_bits == sizeof (double) * NBBY) {
|
||||
/* LINTED - alignment */
|
||||
(void) fprintf(fp, "%+.7e", *((double *)addr));
|
||||
} else if (e.cte_format == CTF_FP_LDOUBLE &&
|
||||
e.cte_bits == sizeof (long double) * NBBY) {
|
||||
/* LINTED - alignment */
|
||||
(void) fprintf(fp, "%+.16LE", *((long double *)addr));
|
||||
} else {
|
||||
(void) fprintf(fp, "<unknown encoding>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A pointer is printed as a fixed-size integer. This is used both for
|
||||
* pointers and functions.
|
||||
*/
|
||||
static void
|
||||
dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
|
||||
{
|
||||
FILE *fp = pap->pa_file;
|
||||
ctf_file_t *ctfp = pap->pa_ctfp;
|
||||
caddr_t addr = pap->pa_addr + off / NBBY;
|
||||
size_t size = ctf_type_size(ctfp, base);
|
||||
|
||||
dt_print_hex(fp, addr, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out an array. This is somewhat complex, as we must manually visit
|
||||
* each member, and recursively invoke ctf_type_visit() for each member. If
|
||||
* the members are non-structs, then we print them out directly:
|
||||
*
|
||||
* [ 0x14, 0x2e, 0 ]
|
||||
*
|
||||
* If they are structs, then we print out the necessary leading and trailing
|
||||
* braces, to end up with:
|
||||
*
|
||||
* [
|
||||
* type {
|
||||
* ...
|
||||
* },
|
||||
* type {
|
||||
* ...
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* We also use a heuristic to detect whether the array looks like a character
|
||||
* array. If the encoding indicates it's a character, and we have all
|
||||
* printable characters followed by a null byte, then we display it as a
|
||||
* string:
|
||||
*
|
||||
* [ "string" ]
|
||||
*/
|
||||
static void
|
||||
dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
|
||||
{
|
||||
FILE *fp = pap->pa_file;
|
||||
ctf_file_t *ctfp = pap->pa_ctfp;
|
||||
caddr_t addr = pap->pa_addr + off / NBBY;
|
||||
ctf_arinfo_t car;
|
||||
ssize_t eltsize;
|
||||
ctf_encoding_t e;
|
||||
int i;
|
||||
boolean_t isstring;
|
||||
int kind;
|
||||
ctf_id_t rtype;
|
||||
|
||||
if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
|
||||
(void) fprintf(fp, "0x%p", (void *)addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
|
||||
(rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
|
||||
(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
|
||||
(void) fprintf(fp, "<invalid type %lu>", car.ctr_contents);
|
||||
return;
|
||||
}
|
||||
|
||||
/* see if this looks like a string */
|
||||
isstring = B_FALSE;
|
||||
if (kind == CTF_K_INTEGER &&
|
||||
ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {
|
||||
char c;
|
||||
for (i = 0; i < car.ctr_nelems; i++) {
|
||||
c = *((char *)addr + eltsize * i);
|
||||
if (!isprint(c) || c == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != car.ctr_nelems && c == '\0')
|
||||
isstring = B_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* As a slight aesthetic optimization, if we are a top-level type, then
|
||||
* don't bother printing out the brackets. This lets print("foo") look
|
||||
* like:
|
||||
*
|
||||
* string "foo"
|
||||
*
|
||||
* As D will internally represent this as a char[256] array.
|
||||
*/
|
||||
if (!isstring || pap->pa_depth != 0)
|
||||
(void) fprintf(fp, "[ ");
|
||||
|
||||
if (isstring)
|
||||
(void) fprintf(fp, "\"");
|
||||
|
||||
for (i = 0; i < car.ctr_nelems; i++) {
|
||||
if (isstring) {
|
||||
char c = *((char *)addr + eltsize * i);
|
||||
if (c == '\0')
|
||||
break;
|
||||
(void) fprintf(fp, "%c", c);
|
||||
} else {
|
||||
/*
|
||||
* Recursively invoke ctf_type_visit() on each member.
|
||||
* We setup a new printarg struct with 'pa_nest' set to
|
||||
* indicate that we are within a nested array.
|
||||
*/
|
||||
dt_printarg_t pa = *pap;
|
||||
pa.pa_nest += pap->pa_depth + 1;
|
||||
pa.pa_depth = 0;
|
||||
pa.pa_addr = addr + eltsize * i;
|
||||
(void) ctf_type_visit(ctfp, car.ctr_contents,
|
||||
dt_print_member, &pa);
|
||||
|
||||
dt_print_trailing_braces(&pa, 0);
|
||||
if (i != car.ctr_nelems - 1)
|
||||
(void) fprintf(fp, ", ");
|
||||
else if (CTF_IS_STRUCTLIKE(kind))
|
||||
(void) fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (isstring)
|
||||
(void) fprintf(fp, "\"");
|
||||
|
||||
if (!isstring || pap->pa_depth != 0) {
|
||||
if (CTF_IS_STRUCTLIKE(kind))
|
||||
dt_print_indent(pap);
|
||||
else
|
||||
(void) fprintf(fp, " ");
|
||||
(void) fprintf(fp, "]");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This isued by both structs and unions to print the leading brace.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
|
||||
{
|
||||
(void) fprintf(pap->pa_file, "{");
|
||||
}
|
||||
|
||||
/*
|
||||
* For enums, we try to print the enum name, and fall back to the value if it
|
||||
* can't be determined. We do not do any fancy flag processing like mdb.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
|
||||
{
|
||||
FILE *fp = pap->pa_file;
|
||||
ctf_file_t *ctfp = pap->pa_ctfp;
|
||||
const char *ename;
|
||||
int value = 0;
|
||||
|
||||
if ((ename = ctf_enum_name(ctfp, base, value)) != NULL)
|
||||
(void) fprintf(fp, "%s", ename);
|
||||
else
|
||||
(void) fprintf(fp, "%d", value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward declaration. There's not much to do here without the complete
|
||||
* type information, so just print out this fact and drive on.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
|
||||
{
|
||||
(void) fprintf(pap->pa_file, "<forward decl>");
|
||||
}
|
||||
|
||||
typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
|
||||
|
||||
static dt_printarg_f *const dt_printfuncs[] = {
|
||||
dt_print_int, /* CTF_K_INTEGER */
|
||||
dt_print_float, /* CTF_K_FLOAT */
|
||||
dt_print_ptr, /* CTF_K_POINTER */
|
||||
dt_print_array, /* CTF_K_ARRAY */
|
||||
dt_print_ptr, /* CTF_K_FUNCTION */
|
||||
dt_print_structlike, /* CTF_K_STRUCT */
|
||||
dt_print_structlike, /* CTF_K_UNION */
|
||||
dt_print_enum, /* CTF_K_ENUM */
|
||||
dt_print_tag /* CTF_K_FORWARD */
|
||||
};
|
||||
|
||||
/*
|
||||
* Print one member of a structure. This callback is invoked from
|
||||
* ctf_type_visit() recursively.
|
||||
*/
|
||||
static int
|
||||
dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,
|
||||
void *data)
|
||||
{
|
||||
char type[DT_TYPE_NAMELEN];
|
||||
int kind;
|
||||
dt_printarg_t *pap = data;
|
||||
FILE *fp = pap->pa_file;
|
||||
ctf_file_t *ctfp = pap->pa_ctfp;
|
||||
boolean_t arraymember;
|
||||
boolean_t brief;
|
||||
ctf_encoding_t e;
|
||||
ctf_id_t rtype;
|
||||
|
||||
dt_print_trailing_braces(pap, depth);
|
||||
/*
|
||||
* dt_print_trailing_braces() doesn't include the trailing newline; add
|
||||
* it here if necessary.
|
||||
*/
|
||||
if (depth < pap->pa_depth)
|
||||
(void) fprintf(fp, "\n");
|
||||
pap->pa_depth = depth;
|
||||
|
||||
if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
|
||||
(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
|
||||
kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
|
||||
dt_print_indent(pap);
|
||||
(void) fprintf(fp, "%s = <invalid type %lu>", name, id);
|
||||
return (0);
|
||||
}
|
||||
|
||||
dt_print_type_name(ctfp, id, type, sizeof (type));
|
||||
|
||||
arraymember = (pap->pa_nest != 0 && depth == 0);
|
||||
brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));
|
||||
|
||||
if (!brief) {
|
||||
/*
|
||||
* If this is a direct array member and a struct (otherwise
|
||||
* brief would be true), then print a trailing newline, as the
|
||||
* array printing code doesn't include it because it might be a
|
||||
* simple type.
|
||||
*/
|
||||
if (arraymember)
|
||||
(void) fprintf(fp, "\n");
|
||||
dt_print_indent(pap);
|
||||
|
||||
/* always print the type */
|
||||
(void) fprintf(fp, "%s", type);
|
||||
if (name[0] != '\0') {
|
||||
/*
|
||||
* For aesthetics, we don't include a space between the
|
||||
* type name and member name if the type is a pointer.
|
||||
* This will give us "void *foo =" instead of "void *
|
||||
* foo =". Unions also have the odd behavior that the
|
||||
* type name is returned as "union ", with a trailing
|
||||
* space, so we also avoid printing a space if the type
|
||||
* name already ends with a space.
|
||||
*/
|
||||
if (type[strlen(type) - 1] != '*' &&
|
||||
type[strlen(type) -1] != ' ') {
|
||||
(void) fprintf(fp, " ");
|
||||
}
|
||||
(void) fprintf(fp, "%s", name);
|
||||
|
||||
/*
|
||||
* If this looks like a bitfield, or is an integer not
|
||||
* aligned on a byte boundary, print the number of
|
||||
* bits after the name.
|
||||
*/
|
||||
if (kind == CTF_K_INTEGER &&
|
||||
ctf_type_encoding(ctfp, id, &e) == 0) {
|
||||
ulong_t bits = e.cte_bits;
|
||||
ulong_t size = bits / NBBY;
|
||||
|
||||
if (bits % NBBY != 0 ||
|
||||
off % NBBY != 0 ||
|
||||
size > 8 ||
|
||||
size != ctf_type_size(ctfp, id)) {
|
||||
(void) fprintf(fp, " :%lu", bits);
|
||||
}
|
||||
}
|
||||
|
||||
(void) fprintf(fp, " =");
|
||||
}
|
||||
(void) fprintf(fp, " ");
|
||||
}
|
||||
|
||||
dt_printfuncs[kind - 1](rtype, off, pap);
|
||||
|
||||
/* direct simple array members are not separated by newlines */
|
||||
if (!brief)
|
||||
(void) fprintf(fp, "\n");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main print function invoked by dt_consume_cpu().
|
||||
*/
|
||||
int
|
||||
dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
|
||||
caddr_t addr, size_t len)
|
||||
{
|
||||
const char *s;
|
||||
char *object;
|
||||
dt_printarg_t pa;
|
||||
ctf_id_t id;
|
||||
dt_module_t *dmp;
|
||||
|
||||
/*
|
||||
* Split the fully-qualified type ID (module`id). This should
|
||||
* always be the format, but if for some reason we don't find the
|
||||
* expected value, return 0 to fall back to the generic trace()
|
||||
* behavior.
|
||||
*/
|
||||
for (s = typename; *s != '\0' && *s != '`'; s++)
|
||||
;
|
||||
|
||||
if (*s != '`')
|
||||
return (0);
|
||||
|
||||
object = alloca(s - typename + 1);
|
||||
bcopy(typename, object, s - typename);
|
||||
object[s - typename] = '\0';
|
||||
id = atoi(s + 1);
|
||||
|
||||
/*
|
||||
* Try to get the CTF kind for this id. If something has gone horribly
|
||||
* wrong and we can't resolve the ID, bail out and let trace() do the
|
||||
* work.
|
||||
*/
|
||||
dmp = dt_module_lookup_by_name(dtp, object);
|
||||
if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp),
|
||||
id) == CTF_ERR) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* setup the print structure and kick off the main print routine */
|
||||
pa.pa_addr = addr;
|
||||
pa.pa_ctfp = dt_module_getctf(dtp, dmp);
|
||||
pa.pa_nest = 0;
|
||||
pa.pa_depth = 0;
|
||||
pa.pa_file = fp;
|
||||
(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
|
||||
|
||||
dt_print_trailing_braces(&pa, 0);
|
||||
|
||||
return (len);
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
@ -352,6 +353,7 @@ dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
|
||||
|
||||
if (sdp->dtsd_fmtdata != NULL)
|
||||
dt_printf_destroy(sdp->dtsd_fmtdata);
|
||||
dt_free(dtp, sdp->dtsd_strdata);
|
||||
|
||||
dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
|
||||
dt_free(dtp, sdp);
|
||||
|
@ -154,6 +154,7 @@ typedef struct dtrace_stmtdesc {
|
||||
dtrace_actdesc_t *dtsd_action_last; /* last action in action list */
|
||||
void *dtsd_aggdata; /* aggregation data */
|
||||
void *dtsd_fmtdata; /* type-specific output data */
|
||||
void *dtsd_strdata; /* type-specific string data */
|
||||
void (*dtsd_callback)(void); /* callback function for EPID */
|
||||
void *dtsd_data; /* callback data pointer */
|
||||
dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
|
||||
@ -245,6 +246,18 @@ extern int dtrace_freopen(dtrace_hdl_t *, FILE *, void *,
|
||||
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
|
||||
const void *, size_t);
|
||||
|
||||
/*
|
||||
* Type-specific output printing
|
||||
*
|
||||
* The print() action will associate a string data record that is actually the
|
||||
* fully-qualified type name of the data traced by the DIFEXPR action. This is
|
||||
* stored in the same 'format' record from the kernel, but we know by virtue of
|
||||
* the fact that the action is still DIFEXPR that it is actually a reference to
|
||||
* plain string data.
|
||||
*/
|
||||
extern int dtrace_print(dtrace_hdl_t *, FILE *, const char *,
|
||||
caddr_t, size_t);
|
||||
|
||||
/*
|
||||
* DTrace Work Interface
|
||||
*/
|
||||
|
@ -57,7 +57,8 @@ extern "C" {
|
||||
/*
|
||||
* libzfs errors
|
||||
*/
|
||||
enum {
|
||||
typedef enum zfs_error {
|
||||
EZFS_SUCCESS = 0, /* no error -- success */
|
||||
EZFS_NOMEM = 2000, /* out of memory */
|
||||
EZFS_BADPROP, /* invalid property value */
|
||||
EZFS_PROPREADONLY, /* cannot set readonly property */
|
||||
@ -129,7 +130,7 @@ enum {
|
||||
EZFS_DIFFDATA, /* bad zfs diff data */
|
||||
EZFS_POOLREADONLY, /* pool is in read-only mode */
|
||||
EZFS_UNKNOWN
|
||||
};
|
||||
} zfs_error_t;
|
||||
|
||||
/*
|
||||
* The following data structures are all part
|
||||
@ -185,6 +186,9 @@ extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
|
||||
|
||||
extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
|
||||
|
||||
extern void zfs_save_arguments(int argc, char **, char *, int);
|
||||
extern int zpool_log_history(libzfs_handle_t *, const char *);
|
||||
|
||||
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 *);
|
||||
@ -220,7 +224,7 @@ extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
|
||||
*/
|
||||
extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
|
||||
nvlist_t *, nvlist_t *);
|
||||
extern int zpool_destroy(zpool_handle_t *);
|
||||
extern int zpool_destroy(zpool_handle_t *, const char *);
|
||||
extern int zpool_add(zpool_handle_t *, nvlist_t *);
|
||||
|
||||
typedef struct splitflags {
|
||||
@ -343,8 +347,8 @@ extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
|
||||
/*
|
||||
* Import and export functions
|
||||
*/
|
||||
extern int zpool_export(zpool_handle_t *, boolean_t);
|
||||
extern int zpool_export_force(zpool_handle_t *);
|
||||
extern int zpool_export(zpool_handle_t *, boolean_t, const char *);
|
||||
extern int zpool_export_force(zpool_handle_t *, const char *);
|
||||
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
|
||||
char *altroot);
|
||||
extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
|
||||
@ -378,7 +382,7 @@ extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
|
||||
*/
|
||||
struct zfs_cmd;
|
||||
|
||||
extern const char *zfs_history_event_names[LOG_END];
|
||||
extern const char *zfs_history_event_names[];
|
||||
|
||||
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
|
||||
boolean_t verbose);
|
||||
@ -386,12 +390,9 @@ extern int zpool_upgrade(zpool_handle_t *, uint64_t);
|
||||
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
|
||||
extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
|
||||
nvlist_t ***, uint_t *);
|
||||
extern void zpool_set_history_str(const char *subcommand, int argc,
|
||||
char **argv, char *history_str);
|
||||
extern int zpool_stage_history(libzfs_handle_t *, const char *);
|
||||
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
|
||||
size_t len);
|
||||
extern int zfs_ioctl(libzfs_handle_t *, unsigned long, struct zfs_cmd *);
|
||||
extern int zfs_ioctl(libzfs_handle_t *, int request, struct zfs_cmd *);
|
||||
extern int zpool_get_physpath(zpool_handle_t *, char *, size_t);
|
||||
extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
|
||||
nvlist_t *);
|
||||
@ -441,8 +442,6 @@ extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
|
||||
char *propbuf, int proplen, boolean_t literal);
|
||||
extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname,
|
||||
char *buf, size_t len);
|
||||
extern int zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
|
||||
uint64_t *usedp);
|
||||
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
|
||||
extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
|
||||
extern const char *zfs_prop_values(zfs_prop_t);
|
||||
@ -555,9 +554,11 @@ extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
|
||||
extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
|
||||
extern int zfs_destroy(zfs_handle_t *, boolean_t);
|
||||
extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
|
||||
extern int zfs_destroy_snaps_nvl(zfs_handle_t *, nvlist_t *, boolean_t);
|
||||
extern int zfs_destroy_snaps_nvl(libzfs_handle_t *, nvlist_t *, boolean_t);
|
||||
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
|
||||
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
|
||||
extern int zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps,
|
||||
nvlist_t *props);
|
||||
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
|
||||
|
||||
typedef struct renameflags {
|
||||
@ -609,8 +610,8 @@ extern int zfs_send(zfs_handle_t *, const char *, const char *,
|
||||
sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
|
||||
|
||||
extern int zfs_promote(zfs_handle_t *);
|
||||
extern int zfs_hold(zfs_handle_t *, const char *, const char *, boolean_t,
|
||||
boolean_t, boolean_t, int, uint64_t, uint64_t);
|
||||
extern int zfs_hold(zfs_handle_t *, const char *, const char *,
|
||||
boolean_t, boolean_t, int);
|
||||
extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
|
||||
extern int zfs_get_holds(zfs_handle_t *, nvlist_t **);
|
||||
extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);
|
||||
|
103
cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
Normal file
103
cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* CDDL HEADER SART
|
||||
*
|
||||
* 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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "libzfs_compat.h"
|
||||
|
||||
int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
|
||||
static int zfs_spa_version = -1;
|
||||
|
||||
/*
|
||||
* Get zfs_ioctl_version
|
||||
*/
|
||||
int
|
||||
get_zfs_ioctl_version(void)
|
||||
{
|
||||
size_t ver_size;
|
||||
int ver = ZFS_IOCVER_NONE;
|
||||
|
||||
ver_size = sizeof(ver);
|
||||
sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
|
||||
|
||||
return (ver);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the SPA version
|
||||
*/
|
||||
static int
|
||||
get_zfs_spa_version(void)
|
||||
{
|
||||
size_t ver_size;
|
||||
int ver = 0;
|
||||
|
||||
ver_size = sizeof(ver);
|
||||
sysctlbyname("vfs.zfs.version.spa", &ver, &ver_size, NULL, 0);
|
||||
|
||||
return (ver);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
int
|
||||
zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
|
||||
{
|
||||
size_t oldsize;
|
||||
int ret, cflag = ZFS_CMD_COMPAT_NONE;
|
||||
|
||||
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
|
||||
zfs_ioctl_version = get_zfs_ioctl_version();
|
||||
|
||||
if (zfs_ioctl_version == ZFS_IOCVER_DEADMAN)
|
||||
cflag = ZFS_CMD_COMPAT_DEADMAN;
|
||||
|
||||
/*
|
||||
* If vfs.zfs.version.ioctl is not defined, assume we have v28
|
||||
* compatible binaries and use vfs.zfs.version.spa to test for v15
|
||||
*/
|
||||
if (zfs_ioctl_version < ZFS_IOCVER_DEADMAN) {
|
||||
cflag = ZFS_CMD_COMPAT_V28;
|
||||
|
||||
if (zfs_spa_version < 0)
|
||||
zfs_spa_version = get_zfs_spa_version();
|
||||
|
||||
if (zfs_spa_version == SPA_VERSION_15 ||
|
||||
zfs_spa_version == SPA_VERSION_14 ||
|
||||
zfs_spa_version == SPA_VERSION_13)
|
||||
cflag = ZFS_CMD_COMPAT_V15;
|
||||
}
|
||||
|
||||
oldsize = zc->zc_nvlist_dst_size;
|
||||
ret = zcmd_ioctl_compat(fd, request, zc, cflag);
|
||||
|
||||
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
|
||||
ret = -1;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
44
cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
Normal file
44
cddl/contrib/opensolaris/lib/libzfs/common/libzfs_compat.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* CDDL HEADER SART
|
||||
*
|
||||
* 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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIBZFS_COMPAT_H
|
||||
#define _LIBZFS_COMPAT_H
|
||||
|
||||
#include <zfs_ioctl_compat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int get_zfs_ioctl_version(void);
|
||||
int zcmd_ioctl(int fd, int request, zfs_cmd_t *zc);
|
||||
|
||||
#define ioctl(fd, ioc, zc) zcmd_ioctl((fd), (ioc), (zc))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBZFS_COMPAT_H */
|
@ -1447,7 +1447,6 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
|
||||
nvlist_t *nvl = NULL, *realprops;
|
||||
zfs_prop_t prop;
|
||||
boolean_t do_prefix = B_TRUE;
|
||||
uint64_t idx;
|
||||
int added_resv;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
@ -2017,10 +2016,7 @@ get_clones_cb(zfs_handle_t *zhp, void *arg)
|
||||
NULL, NULL, 0, B_TRUE) != 0)
|
||||
goto out;
|
||||
if (strcmp(gca->buf, gca->origin) == 0) {
|
||||
if (nvlist_add_boolean(gca->value, zfs_get_name(zhp)) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (no_memory(zhp->zfs_hdl));
|
||||
}
|
||||
fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
|
||||
gca->numclones--;
|
||||
}
|
||||
|
||||
@ -2711,25 +2707,6 @@ zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
|
||||
uint64_t *usedp)
|
||||
{
|
||||
int err;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
|
||||
(void) strlcpy(zc.zc_name, lastsnap->zfs_name, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_value, firstsnap->zfs_name, sizeof (zc.zc_value));
|
||||
|
||||
err = ioctl(lastsnap->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_SNAPS, &zc);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
*usedp = zc.zc_cookie;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the name of the given zfs handle.
|
||||
*/
|
||||
@ -2930,7 +2907,6 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
|
||||
*/
|
||||
for (cp = target + prefixlen + 1;
|
||||
cp = strchr(cp, '/'); *cp = '/', cp++) {
|
||||
char *logstr;
|
||||
|
||||
*cp = '\0';
|
||||
|
||||
@ -2941,16 +2917,12 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
|
||||
continue;
|
||||
}
|
||||
|
||||
logstr = hdl->libzfs_log_str;
|
||||
hdl->libzfs_log_str = NULL;
|
||||
if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
|
||||
NULL) != 0) {
|
||||
hdl->libzfs_log_str = logstr;
|
||||
opname = dgettext(TEXT_DOMAIN, "create");
|
||||
goto ancestorerr;
|
||||
}
|
||||
|
||||
hdl->libzfs_log_str = logstr;
|
||||
h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
|
||||
if (h == NULL) {
|
||||
opname = dgettext(TEXT_DOMAIN, "open");
|
||||
@ -3008,12 +2980,12 @@ int
|
||||
zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
||||
nvlist_t *props)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret;
|
||||
uint64_t size = 0;
|
||||
uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
|
||||
char errbuf[1024];
|
||||
uint64_t zoned;
|
||||
dmu_objset_type_t ost;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot create '%s'"), path);
|
||||
@ -3033,17 +3005,16 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
||||
* will return ENOENT, not EEXIST. To prevent this from happening, we
|
||||
* first try to see if the dataset exists.
|
||||
*/
|
||||
(void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
|
||||
if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
|
||||
if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"dataset already exists"));
|
||||
return (zfs_error(hdl, EZFS_EXISTS, errbuf));
|
||||
}
|
||||
|
||||
if (type == ZFS_TYPE_VOLUME)
|
||||
zc.zc_objset_type = DMU_OST_ZVOL;
|
||||
ost = DMU_OST_ZVOL;
|
||||
else
|
||||
zc.zc_objset_type = DMU_OST_ZFS;
|
||||
ost = DMU_OST_ZFS;
|
||||
|
||||
if (props && (props = zfs_valid_proplist(hdl, type, props,
|
||||
zoned, NULL, errbuf)) == 0)
|
||||
@ -3095,14 +3066,9 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
||||
}
|
||||
}
|
||||
|
||||
if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0)
|
||||
return (-1);
|
||||
nvlist_free(props);
|
||||
|
||||
/* create the dataset */
|
||||
ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc);
|
||||
|
||||
zcmd_free_nvlists(&zc);
|
||||
ret = lzc_create(path, ost, props);
|
||||
nvlist_free(props);
|
||||
|
||||
/* check for failure */
|
||||
if (ret != 0) {
|
||||
@ -3228,47 +3194,53 @@ zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
|
||||
dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
|
||||
zhp->zfs_name, snapname);
|
||||
} else {
|
||||
ret = zfs_destroy_snaps_nvl(zhp, dd.nvl, defer);
|
||||
ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
|
||||
}
|
||||
nvlist_free(dd.nvl);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys all the snapshots named in the nvlist. They must be underneath
|
||||
* the zhp (either snapshots of it, or snapshots of its descendants).
|
||||
* Destroys all the snapshots named in the nvlist.
|
||||
*/
|
||||
int
|
||||
zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
|
||||
zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
|
||||
{
|
||||
int ret;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
nvlist_t *errlist;
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) != 0)
|
||||
return (-1);
|
||||
zc.zc_defer_destroy = defer;
|
||||
ret = lzc_destroy_snaps(snaps, defer, &errlist);
|
||||
|
||||
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc);
|
||||
if (ret != 0) {
|
||||
if (ret == 0)
|
||||
return (0);
|
||||
|
||||
if (nvlist_next_nvpair(errlist, NULL) == NULL) {
|
||||
char errbuf[1024];
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot destroy snapshots in %s"), zc.zc_name);
|
||||
ret = zfs_standard_error(hdl, ret, errbuf);
|
||||
}
|
||||
for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
|
||||
pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
|
||||
char errbuf[1024];
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
|
||||
nvpair_name(pair));
|
||||
|
||||
switch (errno) {
|
||||
switch (fnvpair_value_int32(pair)) {
|
||||
case EEXIST:
|
||||
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
|
||||
"snapshot is cloned"));
|
||||
return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf));
|
||||
|
||||
zfs_error_aux(hdl,
|
||||
dgettext(TEXT_DOMAIN, "snapshot is cloned"));
|
||||
ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
|
||||
break;
|
||||
default:
|
||||
return (zfs_standard_error(zhp->zfs_hdl, errno,
|
||||
errbuf));
|
||||
ret = zfs_standard_error(hdl, errno, errbuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3277,12 +3249,10 @@ zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
|
||||
int
|
||||
zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
char parent[ZFS_MAXNAMELEN];
|
||||
int ret;
|
||||
char errbuf[1024];
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
zfs_type_t type;
|
||||
uint64_t zoned;
|
||||
|
||||
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
|
||||
@ -3301,32 +3271,21 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
|
||||
(void) parent_name(target, parent, sizeof (parent));
|
||||
|
||||
/* do the clone */
|
||||
if (ZFS_IS_VOLUME(zhp)) {
|
||||
zc.zc_objset_type = DMU_OST_ZVOL;
|
||||
type = ZFS_TYPE_VOLUME;
|
||||
} else {
|
||||
zc.zc_objset_type = DMU_OST_ZFS;
|
||||
type = ZFS_TYPE_FILESYSTEM;
|
||||
}
|
||||
|
||||
if (props) {
|
||||
zfs_type_t type;
|
||||
if (ZFS_IS_VOLUME(zhp)) {
|
||||
type = ZFS_TYPE_VOLUME;
|
||||
} else {
|
||||
type = ZFS_TYPE_FILESYSTEM;
|
||||
}
|
||||
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
|
||||
zhp, errbuf)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
|
||||
nvlist_free(props);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
nvlist_free(props);
|
||||
}
|
||||
|
||||
(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
|
||||
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc);
|
||||
|
||||
zcmd_free_nvlists(&zc);
|
||||
ret = lzc_clone(target, zhp->zfs_name, props);
|
||||
nvlist_free(props);
|
||||
|
||||
if (ret != 0) {
|
||||
switch (errno) {
|
||||
@ -3411,74 +3370,134 @@ zfs_promote(zfs_handle_t *zhp)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
typedef struct snapdata {
|
||||
nvlist_t *sd_nvl;
|
||||
const char *sd_snapname;
|
||||
} snapdata_t;
|
||||
|
||||
static int
|
||||
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
snapdata_t *sd = arg;
|
||||
char name[ZFS_MAXNAMELEN];
|
||||
int rv = 0;
|
||||
|
||||
(void) snprintf(name, sizeof (name),
|
||||
"%s@%s", zfs_get_name(zhp), sd->sd_snapname);
|
||||
|
||||
fnvlist_add_boolean(sd->sd_nvl, name);
|
||||
|
||||
rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
|
||||
zfs_close(zhp);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes a snapshot of the given dataset.
|
||||
* Creates snapshots. The keys in the snaps nvlist are the snapshots to be
|
||||
* created.
|
||||
*/
|
||||
int
|
||||
zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
|
||||
{
|
||||
int ret;
|
||||
char errbuf[1024];
|
||||
nvpair_t *elem;
|
||||
nvlist_t *errors;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot create snapshots "));
|
||||
|
||||
elem = NULL;
|
||||
while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
|
||||
const char *snapname = nvpair_name(elem);
|
||||
|
||||
/* validate the target name */
|
||||
if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
|
||||
B_TRUE)) {
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot create snapshot '%s'"), snapname);
|
||||
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
|
||||
}
|
||||
}
|
||||
|
||||
if (props != NULL &&
|
||||
(props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
|
||||
props, B_FALSE, NULL, errbuf)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret = lzc_snapshot(snaps, props, &errors);
|
||||
|
||||
if (ret != 0) {
|
||||
boolean_t printed = B_FALSE;
|
||||
for (elem = nvlist_next_nvpair(errors, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(errors, elem)) {
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot create snapshot '%s'"), nvpair_name(elem));
|
||||
(void) zfs_standard_error(hdl,
|
||||
fnvpair_value_int32(elem), errbuf);
|
||||
printed = B_TRUE;
|
||||
}
|
||||
if (!printed) {
|
||||
switch (ret) {
|
||||
case EXDEV:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"multiple snapshots of same "
|
||||
"fs not allowed"));
|
||||
(void) zfs_error(hdl, EZFS_EXISTS, errbuf);
|
||||
|
||||
break;
|
||||
default:
|
||||
(void) zfs_standard_error(hdl, ret, errbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nvlist_free(props);
|
||||
nvlist_free(errors);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
|
||||
nvlist_t *props)
|
||||
{
|
||||
const char *delim;
|
||||
char parent[ZFS_MAXNAMELEN];
|
||||
zfs_handle_t *zhp;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret;
|
||||
snapdata_t sd = { 0 };
|
||||
char fsname[ZFS_MAXNAMELEN];
|
||||
char *cp;
|
||||
zfs_handle_t *zhp;
|
||||
char errbuf[1024];
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot snapshot '%s'"), path);
|
||||
"cannot snapshot %s"), path);
|
||||
|
||||
/* validate the target name */
|
||||
if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
|
||||
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
|
||||
|
||||
if (props) {
|
||||
if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
|
||||
props, B_FALSE, NULL, errbuf)) == NULL)
|
||||
return (-1);
|
||||
(void) strlcpy(fsname, path, sizeof (fsname));
|
||||
cp = strchr(fsname, '@');
|
||||
*cp = '\0';
|
||||
sd.sd_snapname = cp + 1;
|
||||
|
||||
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
|
||||
nvlist_free(props);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
nvlist_free(props);
|
||||
}
|
||||
|
||||
/* make sure the parent exists and is of the appropriate type */
|
||||
delim = strchr(path, '@');
|
||||
(void) strncpy(parent, path, delim - path);
|
||||
parent[delim - path] = '\0';
|
||||
|
||||
if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
|
||||
if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
|
||||
ZFS_TYPE_VOLUME)) == NULL) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
|
||||
if (ZFS_IS_VOLUME(zhp))
|
||||
zc.zc_objset_type = DMU_OST_ZVOL;
|
||||
else
|
||||
zc.zc_objset_type = DMU_OST_ZFS;
|
||||
zc.zc_cookie = recursive;
|
||||
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc);
|
||||
|
||||
zcmd_free_nvlists(&zc);
|
||||
|
||||
/*
|
||||
* if it was recursive, the one that actually failed will be in
|
||||
* zc.zc_name.
|
||||
*/
|
||||
if (ret != 0) {
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
|
||||
(void) zfs_standard_error(hdl, errno, errbuf);
|
||||
verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
|
||||
if (recursive) {
|
||||
(void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
|
||||
} else {
|
||||
fnvlist_add_boolean(sd.sd_nvl, path);
|
||||
}
|
||||
|
||||
ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
|
||||
nvlist_free(sd.sd_nvl);
|
||||
zfs_close(zhp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -3506,17 +3525,13 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
|
||||
zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
|
||||
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
|
||||
cbp->cb_create) {
|
||||
char *logstr;
|
||||
|
||||
cbp->cb_dependent = B_TRUE;
|
||||
cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
|
||||
rollback_destroy, cbp);
|
||||
cbp->cb_dependent = B_FALSE;
|
||||
|
||||
logstr = zhp->zfs_hdl->libzfs_log_str;
|
||||
zhp->zfs_hdl->libzfs_log_str = NULL;
|
||||
cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
|
||||
zhp->zfs_hdl->libzfs_log_str = logstr;
|
||||
}
|
||||
} else {
|
||||
/* We must destroy this clone; first unmount it */
|
||||
@ -4120,7 +4135,7 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
|
||||
|
||||
zc.zc_nvlist_dst_size = sizeof (buf);
|
||||
if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
|
||||
char errbuf[ZFS_MAXNAMELEN + 32];
|
||||
char errbuf[1024];
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN,
|
||||
@ -4142,37 +4157,83 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct holdarg {
|
||||
nvlist_t *nvl;
|
||||
const char *snapname;
|
||||
const char *tag;
|
||||
boolean_t recursive;
|
||||
};
|
||||
|
||||
static int
|
||||
zfs_hold_one(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
struct holdarg *ha = arg;
|
||||
zfs_handle_t *szhp;
|
||||
char name[ZFS_MAXNAMELEN];
|
||||
int rv = 0;
|
||||
|
||||
(void) snprintf(name, sizeof (name),
|
||||
"%s@%s", zhp->zfs_name, ha->snapname);
|
||||
|
||||
szhp = make_dataset_handle(zhp->zfs_hdl, name);
|
||||
if (szhp) {
|
||||
fnvlist_add_string(ha->nvl, name, ha->tag);
|
||||
zfs_close(szhp);
|
||||
}
|
||||
|
||||
if (ha->recursive)
|
||||
rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
|
||||
zfs_close(zhp);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
|
||||
boolean_t recursive, boolean_t temphold, boolean_t enoent_ok,
|
||||
int cleanup_fd, uint64_t dsobj, uint64_t createtxg)
|
||||
boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret;
|
||||
struct holdarg ha;
|
||||
nvlist_t *errors;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
char errbuf[1024];
|
||||
nvpair_t *elem;
|
||||
|
||||
ASSERT(!recursive || dsobj == 0);
|
||||
ha.nvl = fnvlist_alloc();
|
||||
ha.snapname = snapname;
|
||||
ha.tag = tag;
|
||||
ha.recursive = recursive;
|
||||
(void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
|
||||
ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
|
||||
fnvlist_free(ha.nvl);
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string))
|
||||
>= sizeof (zc.zc_string))
|
||||
return (zfs_error(hdl, EZFS_TAGTOOLONG, tag));
|
||||
zc.zc_cookie = recursive;
|
||||
zc.zc_temphold = temphold;
|
||||
zc.zc_cleanup_fd = cleanup_fd;
|
||||
zc.zc_sendobj = dsobj;
|
||||
zc.zc_createtxg = createtxg;
|
||||
if (ret == 0)
|
||||
return (0);
|
||||
|
||||
if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) != 0) {
|
||||
char errbuf[ZFS_MAXNAMELEN+32];
|
||||
if (nvlist_next_nvpair(errors, NULL) == NULL) {
|
||||
/* no hold-specific errors */
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot hold"));
|
||||
switch (ret) {
|
||||
case ENOTSUP:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"pool must be upgraded"));
|
||||
(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
|
||||
break;
|
||||
case EINVAL:
|
||||
(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
|
||||
break;
|
||||
default:
|
||||
(void) zfs_standard_error(hdl, ret, errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if it was recursive, the one that actually failed will be in
|
||||
* zc.zc_name.
|
||||
*/
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot hold '%s@%s'"), zc.zc_name, snapname);
|
||||
switch (errno) {
|
||||
for (elem = nvlist_next_nvpair(errors, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(errors, elem)) {
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot hold snapshot '%s'"), nvpair_name(elem));
|
||||
switch (fnvpair_value_int32(elem)) {
|
||||
case E2BIG:
|
||||
/*
|
||||
* Temporary tags wind up having the ds object id
|
||||
@ -4180,66 +4241,122 @@ zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
|
||||
* above, it's still possible for the tag to wind
|
||||
* up being slightly too long.
|
||||
*/
|
||||
return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf));
|
||||
case ENOTSUP:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"pool must be upgraded"));
|
||||
return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
|
||||
(void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
|
||||
break;
|
||||
case EINVAL:
|
||||
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
|
||||
(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
|
||||
break;
|
||||
case EEXIST:
|
||||
return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf));
|
||||
(void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
|
||||
break;
|
||||
case ENOENT:
|
||||
if (enoent_ok)
|
||||
return (ENOENT);
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
return (zfs_standard_error_fmt(hdl, errno, errbuf));
|
||||
(void) zfs_standard_error(hdl,
|
||||
fnvpair_value_int32(elem), errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
fnvlist_free(errors);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
struct releasearg {
|
||||
nvlist_t *nvl;
|
||||
const char *snapname;
|
||||
const char *tag;
|
||||
boolean_t recursive;
|
||||
};
|
||||
|
||||
static int
|
||||
zfs_release_one(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
struct holdarg *ha = arg;
|
||||
zfs_handle_t *szhp;
|
||||
char name[ZFS_MAXNAMELEN];
|
||||
int rv = 0;
|
||||
|
||||
(void) snprintf(name, sizeof (name),
|
||||
"%s@%s", zhp->zfs_name, ha->snapname);
|
||||
|
||||
szhp = make_dataset_handle(zhp->zfs_hdl, name);
|
||||
if (szhp) {
|
||||
nvlist_t *holds = fnvlist_alloc();
|
||||
fnvlist_add_boolean(holds, ha->tag);
|
||||
fnvlist_add_nvlist(ha->nvl, name, holds);
|
||||
zfs_close(szhp);
|
||||
}
|
||||
|
||||
if (ha->recursive)
|
||||
rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
|
||||
zfs_close(zhp);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
|
||||
boolean_t recursive)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret;
|
||||
struct holdarg ha;
|
||||
nvlist_t *errors;
|
||||
nvpair_t *elem;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string))
|
||||
>= sizeof (zc.zc_string))
|
||||
return (zfs_error(hdl, EZFS_TAGTOOLONG, tag));
|
||||
zc.zc_cookie = recursive;
|
||||
ha.nvl = fnvlist_alloc();
|
||||
ha.snapname = snapname;
|
||||
ha.tag = tag;
|
||||
ha.recursive = recursive;
|
||||
(void) zfs_release_one(zfs_handle_dup(zhp), &ha);
|
||||
ret = lzc_release(ha.nvl, &errors);
|
||||
fnvlist_free(ha.nvl);
|
||||
|
||||
if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) != 0) {
|
||||
char errbuf[ZFS_MAXNAMELEN+32];
|
||||
if (ret == 0)
|
||||
return (0);
|
||||
|
||||
if (nvlist_next_nvpair(errors, NULL) == NULL) {
|
||||
/* no hold-specific errors */
|
||||
char errbuf[1024];
|
||||
|
||||
/*
|
||||
* if it was recursive, the one that actually failed will be in
|
||||
* zc.zc_name.
|
||||
*/
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot release '%s' from '%s@%s'"), tag, zc.zc_name,
|
||||
snapname);
|
||||
"cannot release"));
|
||||
switch (errno) {
|
||||
case ESRCH:
|
||||
return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf));
|
||||
case ENOTSUP:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"pool must be upgraded"));
|
||||
return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
|
||||
case EINVAL:
|
||||
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
|
||||
(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
|
||||
break;
|
||||
default:
|
||||
return (zfs_standard_error_fmt(hdl, errno, errbuf));
|
||||
(void) zfs_standard_error_fmt(hdl, errno, errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
for (elem = nvlist_next_nvpair(errors, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(errors, elem)) {
|
||||
char errbuf[1024];
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot release hold from snapshot '%s'"),
|
||||
nvpair_name(elem));
|
||||
switch (fnvpair_value_int32(elem)) {
|
||||
case ESRCH:
|
||||
(void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
|
||||
break;
|
||||
case EINVAL:
|
||||
(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
|
||||
break;
|
||||
default:
|
||||
(void) zfs_standard_error_fmt(hdl,
|
||||
fnvpair_value_int32(elem), errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
fnvlist_free(errors);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
@ -4250,7 +4367,7 @@ zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
|
||||
int nvsz = 2048;
|
||||
void *nvbuf;
|
||||
int err = 0;
|
||||
char errbuf[ZFS_MAXNAMELEN+32];
|
||||
char errbuf[1024];
|
||||
|
||||
assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
|
||||
zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
|
||||
@ -4315,7 +4432,7 @@ zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
|
||||
zfs_cmd_t zc = { 0 };
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
char *nvbuf;
|
||||
char errbuf[ZFS_MAXNAMELEN+32];
|
||||
char errbuf[1024];
|
||||
size_t nvsz;
|
||||
int err;
|
||||
|
||||
@ -4366,38 +4483,18 @@ zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
|
||||
int
|
||||
zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
int nvsz = 2048;
|
||||
void *nvbuf;
|
||||
int err = 0;
|
||||
char errbuf[ZFS_MAXNAMELEN+32];
|
||||
int err;
|
||||
char errbuf[1024];
|
||||
|
||||
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
|
||||
err = lzc_get_holds(zhp->zfs_name, nvl);
|
||||
|
||||
tryagain:
|
||||
if (err != 0) {
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
|
||||
nvbuf = malloc(nvsz);
|
||||
if (nvbuf == NULL) {
|
||||
err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
zc.zc_nvlist_dst_size = nvsz;
|
||||
zc.zc_nvlist_dst = (uintptr_t)nvbuf;
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN);
|
||||
|
||||
if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) {
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
|
||||
zc.zc_name);
|
||||
switch (errno) {
|
||||
case ENOMEM:
|
||||
free(nvbuf);
|
||||
nvsz = zc.zc_nvlist_dst_size;
|
||||
goto tryagain;
|
||||
|
||||
zhp->zfs_name);
|
||||
switch (err) {
|
||||
case ENOTSUP:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"pool must be upgraded"));
|
||||
@ -4413,19 +4510,8 @@ tryagain:
|
||||
err = zfs_standard_error_fmt(hdl, errno, errbuf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* success */
|
||||
int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
|
||||
if (rc) {
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
|
||||
zc.zc_name);
|
||||
err = zfs_standard_error_fmt(hdl, rc, errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
free(nvbuf);
|
||||
out:
|
||||
return (err);
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,12 @@
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIBFS_IMPL_H
|
||||
#define _LIBFS_IMPL_H
|
||||
#ifndef _LIBZFS_IMPL_H
|
||||
#define _LIBZFS_IMPL_H
|
||||
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
@ -38,8 +39,8 @@
|
||||
#include <libshare.h>
|
||||
#include <libuutil.h>
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "zfs_ioctl_compat.h"
|
||||
#include <libzfs_core.h>
|
||||
#include <libzfs_compat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -69,7 +70,6 @@ struct libzfs_handle {
|
||||
int libzfs_desc_active;
|
||||
char libzfs_action[1024];
|
||||
char libzfs_desc[1024];
|
||||
char *libzfs_log_str;
|
||||
int libzfs_printerr;
|
||||
int libzfs_storeerr; /* stuff error messages into buffer */
|
||||
void *libzfs_sharehdl; /* libshare handle */
|
||||
@ -214,46 +214,8 @@ extern int zfs_unshare_proto(zfs_handle_t *,
|
||||
|
||||
extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
|
||||
|
||||
#ifndef sun
|
||||
static int zfs_kernel_version = 0;
|
||||
|
||||
/*
|
||||
* 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, zfs_kernel_version_size;
|
||||
int version, ret, cflag = ZFS_CMD_COMPAT_NONE;
|
||||
|
||||
zfs_kernel_version_size = sizeof(zfs_kernel_version);
|
||||
if (zfs_kernel_version == 0) {
|
||||
sysctlbyname("vfs.zfs.version.spa", &zfs_kernel_version,
|
||||
&zfs_kernel_version_size, NULL, 0);
|
||||
}
|
||||
|
||||
if (zfs_kernel_version == SPA_VERSION_15 ||
|
||||
zfs_kernel_version == SPA_VERSION_14 ||
|
||||
zfs_kernel_version == SPA_VERSION_13)
|
||||
cflag = ZFS_CMD_COMPAT_V15;
|
||||
|
||||
oldsize = zc->zc_nvlist_dst_size;
|
||||
ret = zcmd_ioctl_compat(fd, cmd, zc, cflag);
|
||||
|
||||
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 /* !sun */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBFS_IMPL_H */
|
||||
#endif /* _LIBZFS_IMPL_H */
|
||||
|
@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
*/
|
||||
@ -308,12 +308,11 @@ int
|
||||
zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
|
||||
zfs_iter_f func, void *arg)
|
||||
{
|
||||
char buf[ZFS_MAXNAMELEN];
|
||||
char *comma_separated, *cp;
|
||||
char *buf, *comma_separated, *cp;
|
||||
int err = 0;
|
||||
int ret = 0;
|
||||
|
||||
(void) strlcpy(buf, spec_orig, sizeof (buf));
|
||||
buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig);
|
||||
cp = buf;
|
||||
|
||||
while ((comma_separated = strsep(&cp, ",")) != NULL) {
|
||||
@ -371,6 +370,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
@ -1237,7 +1238,7 @@ create_failed:
|
||||
* datasets left in the pool.
|
||||
*/
|
||||
int
|
||||
zpool_destroy(zpool_handle_t *zhp)
|
||||
zpool_destroy(zpool_handle_t *zhp, const char *log_str)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
zfs_handle_t *zfp = NULL;
|
||||
@ -1249,6 +1250,7 @@ zpool_destroy(zpool_handle_t *zhp)
|
||||
return (-1);
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
||||
zc.zc_history = (uint64_t)(uintptr_t)log_str;
|
||||
|
||||
if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
|
||||
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
|
||||
@ -1403,8 +1405,9 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
|
||||
* Exports the pool from the system. The caller must ensure that there are no
|
||||
* mounted datasets in the pool.
|
||||
*/
|
||||
int
|
||||
zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
|
||||
static int
|
||||
zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
|
||||
const char *log_str)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
char msg[1024];
|
||||
@ -1415,6 +1418,7 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
|
||||
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
||||
zc.zc_cookie = force;
|
||||
zc.zc_guid = hardforce;
|
||||
zc.zc_history = (uint64_t)(uintptr_t)log_str;
|
||||
|
||||
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
|
||||
switch (errno) {
|
||||
@ -1436,15 +1440,15 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
|
||||
}
|
||||
|
||||
int
|
||||
zpool_export(zpool_handle_t *zhp, boolean_t force)
|
||||
zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
|
||||
{
|
||||
return (zpool_export_common(zhp, force, B_FALSE));
|
||||
return (zpool_export_common(zhp, force, B_FALSE, log_str));
|
||||
}
|
||||
|
||||
int
|
||||
zpool_export_force(zpool_handle_t *zhp)
|
||||
zpool_export_force(zpool_handle_t *zhp, const char *log_str)
|
||||
{
|
||||
return (zpool_export_common(zhp, B_TRUE, B_TRUE));
|
||||
return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3632,40 +3636,30 @@ zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
|
||||
}
|
||||
|
||||
void
|
||||
zpool_set_history_str(const char *subcommand, int argc, char **argv,
|
||||
char *history_str)
|
||||
zfs_save_arguments(int argc, char **argv, char *string, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
(void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strlen(history_str) + 1 + strlen(argv[i]) >
|
||||
HIS_MAX_RECORD_LEN)
|
||||
break;
|
||||
(void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
|
||||
(void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
|
||||
(void) strlcpy(string, basename(argv[0]), len);
|
||||
for (int i = 1; i < argc; i++) {
|
||||
(void) strlcat(string, " ", len);
|
||||
(void) strlcat(string, argv[i], len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stage command history for logging.
|
||||
*/
|
||||
int
|
||||
zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
|
||||
zpool_log_history(libzfs_handle_t *hdl, const char *message)
|
||||
{
|
||||
if (history_str == NULL)
|
||||
return (EINVAL);
|
||||
zfs_cmd_t zc = { 0 };
|
||||
nvlist_t *args;
|
||||
int err;
|
||||
|
||||
if (strlen(history_str) > HIS_MAX_RECORD_LEN)
|
||||
return (EINVAL);
|
||||
|
||||
if (hdl->libzfs_log_str != NULL)
|
||||
free(hdl->libzfs_log_str);
|
||||
|
||||
if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
|
||||
return (no_memory(hdl));
|
||||
|
||||
return (0);
|
||||
args = fnvlist_alloc();
|
||||
fnvlist_add_string(args, "message", message);
|
||||
err = zcmd_write_src_nvlist(hdl, &zc, args);
|
||||
if (err == 0)
|
||||
err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
|
||||
nvlist_free(args);
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -53,6 +53,10 @@
|
||||
#include <sys/zio_checksum.h>
|
||||
#include <sys/ddt.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
extern int zfs_ioctl_version;
|
||||
#endif
|
||||
|
||||
/* in libzfs_dataset.c */
|
||||
extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
|
||||
/* We need to use something for ENODATA. */
|
||||
@ -978,9 +982,7 @@ hold_for_send(zfs_handle_t *zhp, send_dump_data_t *sdd)
|
||||
*/
|
||||
if (pzhp) {
|
||||
error = zfs_hold(pzhp, thissnap, sdd->holdtag,
|
||||
B_FALSE, B_TRUE, B_TRUE, sdd->cleanup_fd,
|
||||
zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID),
|
||||
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG));
|
||||
B_FALSE, B_TRUE, sdd->cleanup_fd);
|
||||
zfs_close(pzhp);
|
||||
}
|
||||
|
||||
@ -1719,12 +1721,11 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
|
||||
err = ENOENT;
|
||||
}
|
||||
|
||||
if (err != 0 && strncmp(name+baselen, "recv-", 5) != 0) {
|
||||
if (err != 0 && strncmp(name + baselen, "recv-", 5) != 0) {
|
||||
seq++;
|
||||
|
||||
(void) strncpy(newname, name, baselen);
|
||||
(void) snprintf(newname+baselen, ZFS_MAXNAMELEN-baselen,
|
||||
"recv-%u-%u", getpid(), seq);
|
||||
(void) snprintf(newname, ZFS_MAXNAMELEN, "%.*srecv-%u-%u",
|
||||
baselen, name, getpid(), seq);
|
||||
(void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));
|
||||
|
||||
if (flags->verbose) {
|
||||
@ -2676,9 +2677,17 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
/*
|
||||
* Determine name of destination snapshot, store in zc_value.
|
||||
*/
|
||||
(void) strcpy(zc.zc_top_ds, tosnap);
|
||||
(void) strcpy(zc.zc_value, tosnap);
|
||||
(void) strncat(zc.zc_value, chopprefix, sizeof (zc.zc_value));
|
||||
#ifdef __FreeBSD__
|
||||
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
|
||||
zfs_ioctl_version = get_zfs_ioctl_version();
|
||||
/*
|
||||
* For forward compatibility hide tosnap in zc_value
|
||||
*/
|
||||
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
|
||||
(void) strcpy(zc.zc_value + strlen(zc.zc_value) + 1, tosnap);
|
||||
#endif
|
||||
free(cp);
|
||||
if (!zfs_name_valid(zc.zc_value, ZFS_TYPE_SNAPSHOT)) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
#include <libzfs_core.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
#include "zfs_prop.h"
|
||||
@ -659,6 +660,14 @@ libzfs_init(void)
|
||||
|
||||
hdl->libzfs_sharetab = fopen(ZFS_EXPORTS_PATH, "r");
|
||||
|
||||
if (libzfs_core_init() != 0) {
|
||||
(void) close(hdl->libzfs_fd);
|
||||
(void) fclose(hdl->libzfs_mnttab);
|
||||
(void) fclose(hdl->libzfs_sharetab);
|
||||
free(hdl);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
zfs_prop_init();
|
||||
zpool_prop_init();
|
||||
zpool_feature_init();
|
||||
@ -676,14 +685,13 @@ libzfs_fini(libzfs_handle_t *hdl)
|
||||
if (hdl->libzfs_sharetab)
|
||||
(void) fclose(hdl->libzfs_sharetab);
|
||||
zfs_uninit_libshare(hdl);
|
||||
if (hdl->libzfs_log_str)
|
||||
(void) free(hdl->libzfs_log_str);
|
||||
zpool_free_handles(hdl);
|
||||
#ifdef sun
|
||||
libzfs_fru_clear(hdl, B_TRUE);
|
||||
#endif
|
||||
namespace_clear(hdl);
|
||||
libzfs_mnttab_fini(hdl);
|
||||
libzfs_core_fini();
|
||||
free(hdl);
|
||||
}
|
||||
|
||||
@ -857,19 +865,9 @@ zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
|
||||
}
|
||||
|
||||
int
|
||||
zfs_ioctl(libzfs_handle_t *hdl, unsigned long request, zfs_cmd_t *zc)
|
||||
zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
|
||||
{
|
||||
int error;
|
||||
|
||||
zc->zc_history = (uint64_t)(uintptr_t)hdl->libzfs_log_str;
|
||||
error = ioctl(hdl->libzfs_fd, request, zc);
|
||||
if (hdl->libzfs_log_str) {
|
||||
free(hdl->libzfs_log_str);
|
||||
hdl->libzfs_log_str = NULL;
|
||||
}
|
||||
zc->zc_history = 0;
|
||||
|
||||
return (error);
|
||||
return (ioctl(hdl->libzfs_fd, request, zc));
|
||||
}
|
||||
|
||||
/*
|
||||
|
618
cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
Normal file
618
cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
Normal file
@ -0,0 +1,618 @@
|
||||
/*
|
||||
* 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) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* LibZFS_Core (lzc) is intended to replace most functionality in libzfs.
|
||||
* It has the following characteristics:
|
||||
*
|
||||
* - Thread Safe. libzfs_core is accessible concurrently from multiple
|
||||
* threads. This is accomplished primarily by avoiding global data
|
||||
* (e.g. caching). Since it's thread-safe, there is no reason for a
|
||||
* process to have multiple libzfs "instances". Therefore, we store
|
||||
* our few pieces of data (e.g. the file descriptor) in global
|
||||
* variables. The fd is reference-counted so that the libzfs_core
|
||||
* library can be "initialized" multiple times (e.g. by different
|
||||
* consumers within the same process).
|
||||
*
|
||||
* - Committed Interface. The libzfs_core interface will be committed,
|
||||
* therefore consumers can compile against it and be confident that
|
||||
* their code will continue to work on future releases of this code.
|
||||
* Currently, the interface is Evolving (not Committed), but we intend
|
||||
* to commit to it once it is more complete and we determine that it
|
||||
* meets the needs of all consumers.
|
||||
*
|
||||
* - Programatic Error Handling. libzfs_core communicates errors with
|
||||
* defined error numbers, and doesn't print anything to stdout/stderr.
|
||||
*
|
||||
* - Thin Layer. libzfs_core is a thin layer, marshaling arguments
|
||||
* to/from the kernel ioctls. There is generally a 1:1 correspondence
|
||||
* between libzfs_core functions and ioctls to /dev/zfs.
|
||||
*
|
||||
* - Clear Atomicity. Because libzfs_core functions are generally 1:1
|
||||
* with kernel ioctls, and kernel ioctls are general atomic, each
|
||||
* libzfs_core function is atomic. For example, creating multiple
|
||||
* snapshots with a single call to lzc_snapshot() is atomic -- it
|
||||
* can't fail with only some of the requested snapshots created, even
|
||||
* in the event of power loss or system crash.
|
||||
*
|
||||
* - Continued libzfs Support. Some higher-level operations (e.g.
|
||||
* support for "zfs send -R") are too complicated to fit the scope of
|
||||
* libzfs_core. This functionality will continue to live in libzfs.
|
||||
* Where appropriate, libzfs will use the underlying atomic operations
|
||||
* of libzfs_core. For example, libzfs may implement "zfs send -R |
|
||||
* zfs receive" by using individual "send one snapshot", rename,
|
||||
* destroy, and "receive one snapshot" operations in libzfs_core.
|
||||
* /sbin/zfs and /zbin/zpool will link with both libzfs and
|
||||
* libzfs_core. Other consumers should aim to use only libzfs_core,
|
||||
* since that will be the supported, stable interface going forwards.
|
||||
*/
|
||||
|
||||
#define _IN_LIBZFS_CORE_
|
||||
|
||||
#include <libzfs_core.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/nvpair.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include "libzfs_core_compat.h"
|
||||
#include "libzfs_compat.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
extern int zfs_ioctl_version;
|
||||
#endif
|
||||
|
||||
static int g_fd;
|
||||
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int g_refcount;
|
||||
|
||||
int
|
||||
libzfs_core_init(void)
|
||||
{
|
||||
(void) pthread_mutex_lock(&g_lock);
|
||||
if (g_refcount == 0) {
|
||||
g_fd = open("/dev/zfs", O_RDWR);
|
||||
if (g_fd < 0) {
|
||||
(void) pthread_mutex_unlock(&g_lock);
|
||||
return (errno);
|
||||
}
|
||||
}
|
||||
g_refcount++;
|
||||
(void) pthread_mutex_unlock(&g_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
libzfs_core_fini(void)
|
||||
{
|
||||
(void) pthread_mutex_lock(&g_lock);
|
||||
ASSERT3S(g_refcount, >, 0);
|
||||
g_refcount--;
|
||||
if (g_refcount == 0)
|
||||
(void) close(g_fd);
|
||||
(void) pthread_mutex_unlock(&g_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
lzc_ioctl(zfs_ioc_t ioc, const char *name,
|
||||
nvlist_t *source, nvlist_t **resultp)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int error = 0;
|
||||
char *packed;
|
||||
#ifdef __FreeBSD__
|
||||
nvlist_t *oldsource;
|
||||
#endif
|
||||
size_t size;
|
||||
|
||||
ASSERT3S(g_refcount, >, 0);
|
||||
|
||||
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
|
||||
zfs_ioctl_version = get_zfs_ioctl_version();
|
||||
|
||||
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
|
||||
oldsource = source;
|
||||
error = lzc_compat_pre(&zc, &ioc, &source);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
#endif
|
||||
|
||||
packed = fnvlist_pack(source, &size);
|
||||
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
|
||||
zc.zc_nvlist_src_size = size;
|
||||
|
||||
if (resultp != NULL) {
|
||||
*resultp = NULL;
|
||||
zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
|
||||
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
malloc(zc.zc_nvlist_dst_size);
|
||||
#ifdef illumos
|
||||
if (zc.zc_nvlist_dst == NULL) {
|
||||
#else
|
||||
if (zc.zc_nvlist_dst == 0) {
|
||||
#endif
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
while (ioctl(g_fd, ioc, &zc) != 0) {
|
||||
if (errno == ENOMEM && resultp != NULL) {
|
||||
free((void *)(uintptr_t)zc.zc_nvlist_dst);
|
||||
zc.zc_nvlist_dst_size *= 2;
|
||||
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
malloc(zc.zc_nvlist_dst_size);
|
||||
#ifdef illumos
|
||||
if (zc.zc_nvlist_dst == NULL) {
|
||||
#else
|
||||
if (zc.zc_nvlist_dst == 0) {
|
||||
#endif
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
error = errno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
|
||||
lzc_compat_post(&zc, ioc);
|
||||
#endif
|
||||
if (zc.zc_nvlist_dst_filled) {
|
||||
*resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
|
||||
zc.zc_nvlist_dst_size);
|
||||
}
|
||||
#ifdef __FreeBSD__
|
||||
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
|
||||
lzc_compat_outnvl(&zc, ioc, resultp);
|
||||
#endif
|
||||
out:
|
||||
#ifdef __FreeBSD__
|
||||
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
|
||||
if (source != oldsource)
|
||||
nvlist_free(source);
|
||||
source = oldsource;
|
||||
}
|
||||
#endif
|
||||
fnvlist_pack_free(packed, size);
|
||||
free((void *)(uintptr_t)zc.zc_nvlist_dst);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props)
|
||||
{
|
||||
int error;
|
||||
nvlist_t *args = fnvlist_alloc();
|
||||
fnvlist_add_int32(args, "type", type);
|
||||
if (props != NULL)
|
||||
fnvlist_add_nvlist(args, "props", props);
|
||||
error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
|
||||
nvlist_free(args);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
lzc_clone(const char *fsname, const char *origin,
|
||||
nvlist_t *props)
|
||||
{
|
||||
int error;
|
||||
nvlist_t *args = fnvlist_alloc();
|
||||
fnvlist_add_string(args, "origin", origin);
|
||||
if (props != NULL)
|
||||
fnvlist_add_nvlist(args, "props", props);
|
||||
error = lzc_ioctl(ZFS_IOC_CLONE, fsname, args, NULL);
|
||||
nvlist_free(args);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates snapshots.
|
||||
*
|
||||
* The keys in the snaps nvlist are the snapshots to be created.
|
||||
* They must all be in the same pool.
|
||||
*
|
||||
* The props nvlist is properties to set. Currently only user properties
|
||||
* are supported. { user:prop_name -> string value }
|
||||
*
|
||||
* The returned results nvlist will have an entry for each snapshot that failed.
|
||||
* The value will be the (int32) error code.
|
||||
*
|
||||
* The return value will be 0 if all snapshots were created, otherwise it will
|
||||
* be the errno of a (unspecified) snapshot that failed.
|
||||
*/
|
||||
int
|
||||
lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist)
|
||||
{
|
||||
nvpair_t *elem;
|
||||
nvlist_t *args;
|
||||
int error;
|
||||
char pool[MAXNAMELEN];
|
||||
|
||||
*errlist = NULL;
|
||||
|
||||
/* determine the pool name */
|
||||
elem = nvlist_next_nvpair(snaps, NULL);
|
||||
if (elem == NULL)
|
||||
return (0);
|
||||
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
|
||||
pool[strcspn(pool, "/@")] = '\0';
|
||||
|
||||
args = fnvlist_alloc();
|
||||
fnvlist_add_nvlist(args, "snaps", snaps);
|
||||
if (props != NULL)
|
||||
fnvlist_add_nvlist(args, "props", props);
|
||||
|
||||
error = lzc_ioctl(ZFS_IOC_SNAPSHOT, pool, args, errlist);
|
||||
nvlist_free(args);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys snapshots.
|
||||
*
|
||||
* The keys in the snaps nvlist are the snapshots to be destroyed.
|
||||
* They must all be in the same pool.
|
||||
*
|
||||
* Snapshots that do not exist will be silently ignored.
|
||||
*
|
||||
* If 'defer' is not set, and a snapshot has user holds or clones, the
|
||||
* destroy operation will fail and none of the snapshots will be
|
||||
* destroyed.
|
||||
*
|
||||
* If 'defer' is set, and a snapshot has user holds or clones, it will be
|
||||
* marked for deferred destruction, and will be destroyed when the last hold
|
||||
* or clone is removed/destroyed.
|
||||
*
|
||||
* The return value will be 0 if all snapshots were destroyed (or marked for
|
||||
* later destruction if 'defer' is set) or didn't exist to begin with.
|
||||
*
|
||||
* Otherwise the return value will be the errno of a (unspecified) snapshot
|
||||
* that failed, no snapshots will be destroyed, and the errlist will have an
|
||||
* entry for each snapshot that failed. The value in the errlist will be
|
||||
* the (int32) error code.
|
||||
*/
|
||||
int
|
||||
lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist)
|
||||
{
|
||||
nvpair_t *elem;
|
||||
nvlist_t *args;
|
||||
int error;
|
||||
char pool[MAXNAMELEN];
|
||||
|
||||
/* determine the pool name */
|
||||
elem = nvlist_next_nvpair(snaps, NULL);
|
||||
if (elem == NULL)
|
||||
return (0);
|
||||
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
|
||||
pool[strcspn(pool, "/@")] = '\0';
|
||||
|
||||
args = fnvlist_alloc();
|
||||
fnvlist_add_nvlist(args, "snaps", snaps);
|
||||
if (defer)
|
||||
fnvlist_add_boolean(args, "defer");
|
||||
|
||||
error = lzc_ioctl(ZFS_IOC_DESTROY_SNAPS, pool, args, errlist);
|
||||
nvlist_free(args);
|
||||
|
||||
return (error);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
|
||||
uint64_t *usedp)
|
||||
{
|
||||
nvlist_t *args;
|
||||
nvlist_t *result;
|
||||
int err;
|
||||
char fs[MAXNAMELEN];
|
||||
char *atp;
|
||||
|
||||
/* determine the fs name */
|
||||
(void) strlcpy(fs, firstsnap, sizeof (fs));
|
||||
atp = strchr(fs, '@');
|
||||
if (atp == NULL)
|
||||
return (EINVAL);
|
||||
*atp = '\0';
|
||||
|
||||
args = fnvlist_alloc();
|
||||
fnvlist_add_string(args, "firstsnap", firstsnap);
|
||||
|
||||
err = lzc_ioctl(ZFS_IOC_SPACE_SNAPS, lastsnap, args, &result);
|
||||
nvlist_free(args);
|
||||
if (err == 0)
|
||||
*usedp = fnvlist_lookup_uint64(result, "used");
|
||||
fnvlist_free(result);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
lzc_exists(const char *dataset)
|
||||
{
|
||||
/*
|
||||
* The objset_stats ioctl is still legacy, so we need to construct our
|
||||
* own zfs_cmd_t rather than using zfsc_ioctl().
|
||||
*/
|
||||
zfs_cmd_t zc = { 0 };
|
||||
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create "user holds" on snapshots. If there is a hold on a snapshot,
|
||||
* the snapshot can not be destroyed. (However, it can be marked for deletion
|
||||
* by lzc_destroy_snaps(defer=B_TRUE).)
|
||||
*
|
||||
* The keys in the nvlist are snapshot names.
|
||||
* The snapshots must all be in the same pool.
|
||||
* The value is the name of the hold (string type).
|
||||
*
|
||||
* If cleanup_fd is not -1, it must be the result of open("/dev/zfs", O_EXCL).
|
||||
* In this case, when the cleanup_fd is closed (including on process
|
||||
* termination), the holds will be released. If the system is shut down
|
||||
* uncleanly, the holds will be released when the pool is next opened
|
||||
* or imported.
|
||||
*
|
||||
* The return value will be 0 if all holds were created. Otherwise the return
|
||||
* value will be the errno of a (unspecified) hold that failed, no holds will
|
||||
* be created, and the errlist will have an entry for each hold that
|
||||
* failed (name = snapshot). The value in the errlist will be the error
|
||||
* code (int32).
|
||||
*/
|
||||
int
|
||||
lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
|
||||
{
|
||||
char pool[MAXNAMELEN];
|
||||
nvlist_t *args;
|
||||
nvpair_t *elem;
|
||||
int error;
|
||||
|
||||
/* determine the pool name */
|
||||
elem = nvlist_next_nvpair(holds, NULL);
|
||||
if (elem == NULL)
|
||||
return (0);
|
||||
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
|
||||
pool[strcspn(pool, "/@")] = '\0';
|
||||
|
||||
args = fnvlist_alloc();
|
||||
fnvlist_add_nvlist(args, "holds", holds);
|
||||
if (cleanup_fd != -1)
|
||||
fnvlist_add_int32(args, "cleanup_fd", cleanup_fd);
|
||||
|
||||
error = lzc_ioctl(ZFS_IOC_HOLD, pool, args, errlist);
|
||||
nvlist_free(args);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release "user holds" on snapshots. If the snapshot has been marked for
|
||||
* deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
|
||||
* any clones, and all the user holds are removed, then the snapshot will be
|
||||
* destroyed.
|
||||
*
|
||||
* The keys in the nvlist are snapshot names.
|
||||
* The snapshots must all be in the same pool.
|
||||
* The value is a nvlist whose keys are the holds to remove.
|
||||
*
|
||||
* The return value will be 0 if all holds were removed.
|
||||
* Otherwise the return value will be the errno of a (unspecified) release
|
||||
* that failed, no holds will be released, and the errlist will have an
|
||||
* entry for each snapshot that has failed releases (name = snapshot).
|
||||
* The value in the errlist will be the error code (int32) of a failed release.
|
||||
*/
|
||||
int
|
||||
lzc_release(nvlist_t *holds, nvlist_t **errlist)
|
||||
{
|
||||
char pool[MAXNAMELEN];
|
||||
nvpair_t *elem;
|
||||
|
||||
/* determine the pool name */
|
||||
elem = nvlist_next_nvpair(holds, NULL);
|
||||
if (elem == NULL)
|
||||
return (0);
|
||||
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
|
||||
pool[strcspn(pool, "/@")] = '\0';
|
||||
|
||||
return (lzc_ioctl(ZFS_IOC_RELEASE, pool, holds, errlist));
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve list of user holds on the specified snapshot.
|
||||
*
|
||||
* On success, *holdsp will be set to a nvlist which the caller must free.
|
||||
* The keys are the names of the holds, and the value is the creation time
|
||||
* of the hold (uint64) in seconds since the epoch.
|
||||
*/
|
||||
int
|
||||
lzc_get_holds(const char *snapname, nvlist_t **holdsp)
|
||||
{
|
||||
int error;
|
||||
nvlist_t *innvl = fnvlist_alloc();
|
||||
error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp);
|
||||
fnvlist_free(innvl);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* If fromsnap is NULL, a full (non-incremental) stream will be sent.
|
||||
*/
|
||||
int
|
||||
lzc_send(const char *snapname, const char *fromsnap, int fd)
|
||||
{
|
||||
nvlist_t *args;
|
||||
int err;
|
||||
|
||||
args = fnvlist_alloc();
|
||||
fnvlist_add_int32(args, "fd", fd);
|
||||
if (fromsnap != NULL)
|
||||
fnvlist_add_string(args, "fromsnap", fromsnap);
|
||||
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
|
||||
nvlist_free(args);
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* If fromsnap is NULL, a full (non-incremental) stream will be estimated.
|
||||
*/
|
||||
int
|
||||
lzc_send_space(const char *snapname, const char *fromsnap, uint64_t *spacep)
|
||||
{
|
||||
nvlist_t *args;
|
||||
nvlist_t *result;
|
||||
int err;
|
||||
|
||||
args = fnvlist_alloc();
|
||||
if (fromsnap != NULL)
|
||||
fnvlist_add_string(args, "fromsnap", fromsnap);
|
||||
err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
|
||||
nvlist_free(args);
|
||||
if (err == 0)
|
||||
*spacep = fnvlist_lookup_uint64(result, "space");
|
||||
nvlist_free(result);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
recv_read(int fd, void *buf, int ilen)
|
||||
{
|
||||
char *cp = buf;
|
||||
int rv;
|
||||
int len = ilen;
|
||||
|
||||
do {
|
||||
rv = read(fd, cp, len);
|
||||
cp += rv;
|
||||
len -= rv;
|
||||
} while (rv > 0);
|
||||
|
||||
if (rv < 0 || len != 0)
|
||||
return (EIO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The simplest receive case: receive from the specified fd, creating the
|
||||
* specified snapshot. Apply the specified properties a "received" properties
|
||||
* (which can be overridden by locally-set properties). If the stream is a
|
||||
* clone, its origin snapshot must be specified by 'origin'. The 'force'
|
||||
* flag will cause the target filesystem to be rolled back or destroyed if
|
||||
* necessary to receive.
|
||||
*
|
||||
* Return 0 on success or an errno on failure.
|
||||
*
|
||||
* Note: this interface does not work on dedup'd streams
|
||||
* (those with DMU_BACKUP_FEATURE_DEDUP).
|
||||
*/
|
||||
int
|
||||
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, int fd)
|
||||
{
|
||||
/*
|
||||
* The receive ioctl is still legacy, so we need to construct our own
|
||||
* zfs_cmd_t rather than using zfsc_ioctl().
|
||||
*/
|
||||
zfs_cmd_t zc = { 0 };
|
||||
char *atp;
|
||||
char *packed = NULL;
|
||||
size_t size;
|
||||
dmu_replay_record_t drr;
|
||||
int error;
|
||||
|
||||
ASSERT3S(g_refcount, >, 0);
|
||||
|
||||
/* zc_name is name of containing filesystem */
|
||||
(void) strlcpy(zc.zc_name, snapname, sizeof (zc.zc_name));
|
||||
atp = strchr(zc.zc_name, '@');
|
||||
if (atp == NULL)
|
||||
return (EINVAL);
|
||||
*atp = '\0';
|
||||
|
||||
/* if the fs does not exist, try its parent. */
|
||||
if (!lzc_exists(zc.zc_name)) {
|
||||
char *slashp = strrchr(zc.zc_name, '/');
|
||||
if (slashp == NULL)
|
||||
return (ENOENT);
|
||||
*slashp = '\0';
|
||||
|
||||
}
|
||||
|
||||
/* zc_value is full name of the snapshot to create */
|
||||
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
|
||||
if (props != NULL) {
|
||||
/* zc_nvlist_src is props to set */
|
||||
packed = fnvlist_pack(props, &size);
|
||||
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
|
||||
zc.zc_nvlist_src_size = size;
|
||||
}
|
||||
|
||||
/* zc_string is name of clone origin (if DRR_FLAG_CLONE) */
|
||||
if (origin != NULL)
|
||||
(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
|
||||
|
||||
/* zc_begin_record is non-byteswapped BEGIN record */
|
||||
error = recv_read(fd, &drr, sizeof (drr));
|
||||
if (error != 0)
|
||||
goto out;
|
||||
zc.zc_begin_record = drr.drr_u.drr_begin;
|
||||
|
||||
/* zc_cookie is fd to read from */
|
||||
zc.zc_cookie = fd;
|
||||
|
||||
/* zc guid is force flag */
|
||||
zc.zc_guid = force;
|
||||
|
||||
/* zc_cleanup_fd is unused */
|
||||
zc.zc_cleanup_fd = -1;
|
||||
|
||||
error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
|
||||
if (error != 0)
|
||||
error = errno;
|
||||
|
||||
out:
|
||||
if (packed != NULL)
|
||||
fnvlist_pack_free(packed, size);
|
||||
free((void*)(uintptr_t)zc.zc_nvlist_dst);
|
||||
return (error);
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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) 2012 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIBZFS_CORE_H
|
||||
#define _LIBZFS_CORE_H
|
||||
|
||||
#include <libnvpair.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int libzfs_core_init(void);
|
||||
void libzfs_core_fini(void);
|
||||
|
||||
int lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist);
|
||||
int lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props);
|
||||
int lzc_clone(const char *fsname, const char *origin, nvlist_t *props);
|
||||
int lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist);
|
||||
|
||||
int lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
|
||||
uint64_t *usedp);
|
||||
|
||||
int lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist);
|
||||
int lzc_release(nvlist_t *holds, nvlist_t **errlist);
|
||||
int lzc_get_holds(const char *snapname, nvlist_t **holdsp);
|
||||
|
||||
int lzc_send(const char *snapname, const char *fromsnap, int fd);
|
||||
int lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, int fd);
|
||||
int lzc_send_space(const char *snapname, const char *fromsnap,
|
||||
uint64_t *result);
|
||||
|
||||
boolean_t lzc_exists(const char *dataset);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBZFS_CORE_H */
|
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <zfs_ioctl_compat.h>
|
||||
#include "libzfs_core_compat.h"
|
||||
|
||||
extern int zfs_ioctl_version;
|
||||
|
||||
int
|
||||
lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
|
||||
{
|
||||
nvlist_t *nvl = NULL;
|
||||
nvpair_t *pair, *hpair;
|
||||
char *buf, *val;
|
||||
zfs_ioc_t vecnum;
|
||||
uint32_t type32;
|
||||
int32_t cleanup_fd;
|
||||
int error = 0;
|
||||
int pos;
|
||||
|
||||
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
|
||||
return (0);
|
||||
|
||||
vecnum = *ioc;
|
||||
|
||||
switch (vecnum) {
|
||||
case ZFS_IOC_CREATE:
|
||||
type32 = fnvlist_lookup_int32(*source, "type");
|
||||
zc->zc_objset_type = (uint64_t)type32;
|
||||
nvlist_lookup_nvlist(*source, "props", &nvl);
|
||||
*source = nvl;
|
||||
break;
|
||||
case ZFS_IOC_CLONE:
|
||||
buf = fnvlist_lookup_string(*source, "origin");
|
||||
strlcpy(zc->zc_value, buf, MAXPATHLEN);
|
||||
nvlist_lookup_nvlist(*source, "props", &nvl);
|
||||
*ioc = ZFS_IOC_CREATE;
|
||||
*source = nvl;
|
||||
break;
|
||||
case ZFS_IOC_SNAPSHOT:
|
||||
nvl = fnvlist_lookup_nvlist(*source, "snaps");
|
||||
pair = nvlist_next_nvpair(nvl, NULL);
|
||||
if (pair != NULL) {
|
||||
buf = nvpair_name(pair);
|
||||
pos = strcspn(buf, "@");
|
||||
strlcpy(zc->zc_name, buf, pos + 1);
|
||||
strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
|
||||
} else
|
||||
error = EINVAL;
|
||||
/* old kernel cannot create multiple snapshots */
|
||||
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
|
||||
error = EOPNOTSUPP;
|
||||
nvlist_free(nvl);
|
||||
nvl = NULL;
|
||||
nvlist_lookup_nvlist(*source, "props", &nvl);
|
||||
*source = nvl;
|
||||
break;
|
||||
case ZFS_IOC_SPACE_SNAPS:
|
||||
buf = fnvlist_lookup_string(*source, "firstsnap");
|
||||
strlcpy(zc->zc_value, buf, MAXPATHLEN);
|
||||
break;
|
||||
case ZFS_IOC_DESTROY_SNAPS:
|
||||
nvl = fnvlist_lookup_nvlist(*source, "snaps");
|
||||
pair = nvlist_next_nvpair(nvl, NULL);
|
||||
if (pair != NULL) {
|
||||
buf = nvpair_name(pair);
|
||||
pos = strcspn(buf, "@");
|
||||
strlcpy(zc->zc_name, buf, pos + 1);
|
||||
} else
|
||||
error = EINVAL;
|
||||
/* old kernel cannot atomically destroy multiple snaps */
|
||||
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
|
||||
error = EOPNOTSUPP;
|
||||
*source = nvl;
|
||||
break;
|
||||
case ZFS_IOC_HOLD:
|
||||
nvl = fnvlist_lookup_nvlist(*source, "holds");
|
||||
pair = nvlist_next_nvpair(nvl, NULL);
|
||||
if (pair != NULL) {
|
||||
buf = nvpair_name(pair);
|
||||
pos = strcspn(buf, "@");
|
||||
strlcpy(zc->zc_name, buf, pos + 1);
|
||||
strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
|
||||
if (nvpair_value_string(pair, &val) == 0)
|
||||
strlcpy(zc->zc_string, val, MAXNAMELEN);
|
||||
else
|
||||
error = EINVAL;
|
||||
} else
|
||||
error = EINVAL;
|
||||
/* old kernel cannot atomically create multiple holds */
|
||||
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
|
||||
error = EOPNOTSUPP;
|
||||
nvlist_free(nvl);
|
||||
if (nvlist_lookup_int32(*source, "cleanup_fd",
|
||||
&cleanup_fd) == 0)
|
||||
zc->zc_cleanup_fd = cleanup_fd;
|
||||
else
|
||||
zc->zc_cleanup_fd = -1;
|
||||
break;
|
||||
case ZFS_IOC_RELEASE:
|
||||
pair = nvlist_next_nvpair(*source, NULL);
|
||||
if (pair != NULL) {
|
||||
buf = nvpair_name(pair);
|
||||
pos = strcspn(buf, "@");
|
||||
strlcpy(zc->zc_name, buf, pos + 1);
|
||||
strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
|
||||
if (nvpair_value_nvlist(pair, &nvl) == 0) {
|
||||
hpair = nvlist_next_nvpair(nvl, NULL);
|
||||
if (hpair != NULL)
|
||||
strlcpy(zc->zc_string,
|
||||
nvpair_name(hpair), MAXNAMELEN);
|
||||
else
|
||||
error = EINVAL;
|
||||
if (!error && nvlist_next_nvpair(nvl,
|
||||
hpair) != NULL)
|
||||
error = EOPNOTSUPP;
|
||||
} else
|
||||
error = EINVAL;
|
||||
} else
|
||||
error = EINVAL;
|
||||
/* old kernel cannot atomically release multiple holds */
|
||||
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
lzc_compat_post(zfs_cmd_t *zc, const zfs_ioc_t ioc)
|
||||
{
|
||||
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
|
||||
return;
|
||||
|
||||
switch (ioc) {
|
||||
case ZFS_IOC_CREATE:
|
||||
case ZFS_IOC_CLONE:
|
||||
case ZFS_IOC_SNAPSHOT:
|
||||
case ZFS_IOC_SPACE_SNAPS:
|
||||
case ZFS_IOC_DESTROY_SNAPS:
|
||||
zc->zc_nvlist_dst_filled = B_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lzc_compat_outnvl(zfs_cmd_t *zc, const zfs_ioc_t ioc, nvlist_t **outnvl)
|
||||
{
|
||||
nvlist_t *nvl;
|
||||
|
||||
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
|
||||
return (0);
|
||||
|
||||
switch (ioc) {
|
||||
case ZFS_IOC_SPACE_SNAPS:
|
||||
nvl = fnvlist_alloc();
|
||||
fnvlist_add_uint64(nvl, "used", zc->zc_cookie);
|
||||
fnvlist_add_uint64(nvl, "compressed", zc->zc_objset_type);
|
||||
fnvlist_add_uint64(nvl, "uncompressed", zc->zc_perm_action);
|
||||
*outnvl = nvl;
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIBZFS_CORE_COMPAT_H
|
||||
#define _LIBZFS_CORE_COMPAT_H
|
||||
|
||||
#include <libnvpair.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int lzc_compat_pre(zfs_cmd_t *, zfs_ioc_t *, nvlist_t **);
|
||||
void lzc_compat_post(zfs_cmd_t *, const zfs_ioc_t);
|
||||
int lzc_compat_outnvl(zfs_cmd_t *, const zfs_ioc_t, nvlist_t **);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBZFS_CORE_COMPAT_H */
|
@ -33,6 +33,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/processor.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/rrwlock.h>
|
||||
#include <sys/zmod.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/systeminfo.h>
|
||||
@ -45,6 +46,9 @@ int aok;
|
||||
uint64_t physmem;
|
||||
vnode_t *rootdir = (vnode_t *)0xabcd1234;
|
||||
char hw_serial[HW_HOSTID_LEN];
|
||||
#ifdef illumos
|
||||
kmutex_t cpu_lock;
|
||||
#endif
|
||||
|
||||
struct utsname utsname = {
|
||||
"userland", "libzpool", "1", "1", "na"
|
||||
@ -842,6 +846,28 @@ ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef illumos
|
||||
/* ARGSUSED */
|
||||
cyclic_id_t
|
||||
cyclic_add(cyc_handler_t *hdlr, cyc_time_t *when)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
cyclic_remove(cyclic_id_t id)
|
||||
{
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
cyclic_reprogram(cyclic_id_t id, hrtime_t expiration)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* kernel emulation setup & teardown
|
||||
@ -860,6 +886,8 @@ umem_out_of_memory(void)
|
||||
void
|
||||
kernel_init(int mode)
|
||||
{
|
||||
extern uint_t rrw_tsd_key;
|
||||
|
||||
umem_nofail_callback(umem_out_of_memory);
|
||||
|
||||
physmem = sysconf(_SC_PHYS_PAGES);
|
||||
@ -875,7 +903,13 @@ kernel_init(int mode)
|
||||
|
||||
system_taskq_init();
|
||||
|
||||
#ifdef illumos
|
||||
mutex_init(&cpu_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
#endif
|
||||
|
||||
spa_init(mode);
|
||||
|
||||
tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
|
||||
}
|
||||
|
||||
void
|
||||
@ -923,6 +957,12 @@ crgetuid(cred_t *cr)
|
||||
return (0);
|
||||
}
|
||||
|
||||
uid_t
|
||||
crgetruid(cred_t *cr)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
gid_t
|
||||
crgetgid(cred_t *cr)
|
||||
{
|
||||
|
@ -60,6 +60,8 @@ extern "C" {
|
||||
#include <umem.h>
|
||||
#include <inttypes.h>
|
||||
#include <fsshare.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/note.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/cred.h>
|
||||
@ -242,6 +244,9 @@ typedef int krw_t;
|
||||
#define RW_WRITE_HELD(x) ((x)->rw_owner == curthread)
|
||||
#define RW_LOCK_HELD(x) rw_lock_held(x)
|
||||
|
||||
#undef RW_LOCK_HELD
|
||||
#define RW_LOCK_HELD(x) (RW_READ_HELD(x) || RW_WRITE_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);
|
||||
@ -252,6 +257,7 @@ extern int rw_lock_held(krwlock_t *rwlp);
|
||||
#define rw_downgrade(rwlp) do { } while (0)
|
||||
|
||||
extern uid_t crgetuid(cred_t *cr);
|
||||
extern uid_t crgetruid(cred_t *cr);
|
||||
extern gid_t crgetgid(cred_t *cr);
|
||||
extern int crgetngroups(cred_t *cr);
|
||||
extern gid_t *crgetgroups(cred_t *cr);
|
||||
@ -270,6 +276,14 @@ 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);
|
||||
|
||||
/*
|
||||
* Thread-specific data
|
||||
*/
|
||||
#define tsd_get(k) pthread_getspecific(k)
|
||||
#define tsd_set(k, v) pthread_setspecific(k, v)
|
||||
#define tsd_create(kp, d) pthread_key_create(kp, d)
|
||||
#define tsd_destroy(kp) /* nothing */
|
||||
|
||||
/*
|
||||
* Kernel memory
|
||||
*/
|
||||
@ -457,6 +471,9 @@ extern vnode_t *rootdir;
|
||||
|
||||
extern void delay(clock_t ticks);
|
||||
|
||||
#define SEC_TO_TICK(sec) ((sec) * hz)
|
||||
#define NSEC_TO_TICK(usec) ((usec) / (NANOSEC / hz))
|
||||
|
||||
#define gethrestime_sec() time(NULL)
|
||||
#define gethrestime(t) \
|
||||
do {\
|
||||
@ -516,7 +533,7 @@ typedef struct callb_cpr {
|
||||
#define INGLOBALZONE(z) (1)
|
||||
|
||||
extern char *kmem_asprintf(const char *fmt, ...);
|
||||
#define strfree(str) kmem_free((str), strlen(str)+1)
|
||||
#define strfree(str) kmem_free((str), strlen(str) + 1)
|
||||
|
||||
/*
|
||||
* Hostname information
|
||||
@ -624,6 +641,36 @@ typedef uint32_t idmap_rid_t;
|
||||
#define ERESTART (-1)
|
||||
#endif
|
||||
|
||||
#ifdef illumos
|
||||
/*
|
||||
* Cyclic information
|
||||
*/
|
||||
extern kmutex_t cpu_lock;
|
||||
|
||||
typedef uintptr_t cyclic_id_t;
|
||||
typedef uint16_t cyc_level_t;
|
||||
typedef void (*cyc_func_t)(void *);
|
||||
|
||||
#define CY_LOW_LEVEL 0
|
||||
#define CY_INFINITY INT64_MAX
|
||||
#define CYCLIC_NONE ((cyclic_id_t)0)
|
||||
|
||||
typedef struct cyc_time {
|
||||
hrtime_t cyt_when;
|
||||
hrtime_t cyt_interval;
|
||||
} cyc_time_t;
|
||||
|
||||
typedef struct cyc_handler {
|
||||
cyc_func_t cyh_func;
|
||||
void *cyh_arg;
|
||||
cyc_level_t cyh_level;
|
||||
} cyc_handler_t;
|
||||
|
||||
extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
|
||||
extern void cyclic_remove(cyclic_id_t);
|
||||
extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
|
||||
#endif /* illumos */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -363,6 +363,7 @@ sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
|
||||
|
||||
for (i = 0; i < nent; i++) {
|
||||
GElf_Sym sym;
|
||||
char *bname;
|
||||
iidesc_t **tolist;
|
||||
GElf_Sym ssym;
|
||||
iidesc_match_t smatch;
|
||||
@ -377,7 +378,8 @@ sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
|
||||
|
||||
switch (GELF_ST_TYPE(sym.st_info)) {
|
||||
case STT_FILE:
|
||||
match.iim_file = match.iim_name;
|
||||
bname = strrchr(match.iim_name, '/');
|
||||
match.iim_file = bname == NULL ? match.iim_name : bname + 1;
|
||||
continue;
|
||||
case STT_OBJECT:
|
||||
tolist = iiburst->iib_objts;
|
||||
|
@ -9,10 +9,12 @@ SUBDIR= ${_drti} \
|
||||
libnvpair \
|
||||
libumem \
|
||||
libuutil \
|
||||
${_libzfs_core} \
|
||||
${_libzfs} \
|
||||
${_libzpool}
|
||||
|
||||
.if ${MK_ZFS} != "no"
|
||||
_libzfs_core= libzfs_core
|
||||
_libzfs= libzfs
|
||||
.if ${MK_LIBTHR} != "no"
|
||||
_libzpool= libzpool
|
||||
|
@ -32,6 +32,7 @@ SRCS= dt_aggregate.c \
|
||||
dt_pcb.c \
|
||||
dt_pid.c \
|
||||
dt_pragma.c \
|
||||
dt_print.c \
|
||||
dt_printf.c \
|
||||
dt_proc.c \
|
||||
dt_program.c \
|
||||
|
@ -6,8 +6,9 @@
|
||||
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
|
||||
|
||||
LIB= zfs
|
||||
DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBUMEM} ${LIBUTIL} ${LIBM} ${LIBNVPAIR}
|
||||
LDADD= -lmd -lpthread -lumem -lutil -lm -lnvpair
|
||||
DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBUMEM} ${LIBUTIL} ${LIBM} ${LIBNVPAIR} \
|
||||
${LIBZFS_CORE}
|
||||
LDADD= -lmd -lpthread -lumem -lutil -lm -lnvpair -lzfs_core
|
||||
|
||||
SRCS= deviceid.c \
|
||||
fsshare.c \
|
||||
@ -17,6 +18,7 @@ SRCS= deviceid.c \
|
||||
zone.c
|
||||
|
||||
SRCS+= libzfs_changelist.c \
|
||||
libzfs_compat.c \
|
||||
libzfs_config.c \
|
||||
libzfs_dataset.c \
|
||||
libzfs_diff.c \
|
||||
@ -54,5 +56,6 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
37
cddl/lib/libzfs_core/Makefile
Normal file
37
cddl/lib/libzfs_core/Makefile
Normal file
@ -0,0 +1,37 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../cddl/compat/opensolaris/misc
|
||||
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
|
||||
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
|
||||
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
|
||||
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
|
||||
|
||||
LIB= zfs_core
|
||||
DPADD= ${LIBNVPAIR}
|
||||
LDADD= -lnvpair
|
||||
|
||||
SRCS= libzfs_core.c \
|
||||
libzfs_core_compat.c
|
||||
|
||||
SRCS+= libzfs_compat.c
|
||||
|
||||
WARNS?= 0
|
||||
CSTD= c99
|
||||
CFLAGS+= -DZFS_NO_ACL
|
||||
CFLAGS+= -I${.CURDIR}/../../../sbin/mount
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/lib/libumem
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
|
||||
|
||||
.include <bsd.lib.mk>
|
@ -14,6 +14,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libumem/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
|
||||
@ -22,7 +23,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
|
||||
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
|
||||
|
||||
DPADD= ${LIBGEOM} ${LIBJAIL} ${LIBNVPAIR} ${LIBUMEM} \
|
||||
${LIBUTIL} ${LIBUUTIL} ${LIBZFS}
|
||||
LDADD= -lgeom -ljail -lnvpair -lumem -lutil -luutil -lzfs
|
||||
${LIBUTIL} ${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS}
|
||||
LDADD= -lgeom -ljail -lnvpair -lumem -lutil -luutil -lzfs_core -lzfs
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -27,7 +27,7 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
|
||||
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/stat/common
|
||||
|
||||
DPADD= ${LIBAVL} ${LIBGEOM} ${LIBNVPAIR} \
|
||||
${LIBUMEM} ${LIBUTIL} ${LIBUUTIL} ${LIBZFS}
|
||||
LDADD= -lavl -lgeom -lnvpair -lumem -lutil -luutil -lzfs
|
||||
${LIBUMEM} ${LIBUTIL} ${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS}
|
||||
LDADD= -lavl -lgeom -lnvpair -lumem -lutil -luutil -lzfs_core -lzfs
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -20,7 +20,7 @@ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
|
||||
CFLAGS+= -I${.CURDIR}/../../lib/libumem
|
||||
|
||||
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBUMEM} ${LIBUUTIL} \
|
||||
${LIBZFS} ${LIBZPOOL}
|
||||
LDADD= -lgeom -lm -lnvpair -lumem -luutil -lzfs -lzpool
|
||||
${LIBZFS_CORE} ${LIBZFS} ${LIBZPOOL}
|
||||
LDADD= -lgeom -lm -lnvpair -lumem -luutil -lzfs_core -lzfs -lzpool
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -19,8 +19,9 @@ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
|
||||
CFLAGS+= -I${.CURDIR}/../../lib/libumem
|
||||
|
||||
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBUMEM} ${LIBZPOOL} \
|
||||
${LIBPTHREAD} ${LIBAVL} ${LIBZFS} ${LIBUUTIL}
|
||||
LDADD= -lgeom -lm -lnvpair -lumem -lzpool -lpthread -lavl -lzfs -luutil
|
||||
${LIBPTHREAD} ${LIBAVL} ${LIBZFS_CORE} ${LIBZFS} ${LIBUUTIL}
|
||||
LDADD= -lgeom -lm -lnvpair -lumem -lzpool -lpthread -lavl -lzfs_core -lzfs \
|
||||
-luutil
|
||||
|
||||
CSTD= c99
|
||||
|
||||
|
@ -24,8 +24,8 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
|
||||
CFLAGS+= -I${.CURDIR}/../../lib/libumem
|
||||
|
||||
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBPTHREAD} ${LIBUMEM} \
|
||||
${LIBUUTIL} ${LIBZFS} ${LIBZPOOL}
|
||||
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs -lzpool
|
||||
${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS} ${LIBZPOOL}
|
||||
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs_core -lzfs -lzpool
|
||||
|
||||
CFLAGS+= -DDEBUG=1
|
||||
#DEBUG_FLAGS+= -g
|
||||
|
@ -23,8 +23,8 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
|
||||
CFLAGS+= -I${.CURDIR}/../../lib/libumem
|
||||
|
||||
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBPTHREAD} ${LIBUMEM} \
|
||||
${LIBUUTIL} ${LIBZFS} ${LIBZPOOL}
|
||||
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs -lzpool
|
||||
${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS} ${LIBZPOOL}
|
||||
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs_core -lzfs -lzpool
|
||||
|
||||
CFLAGS+= -DDEBUG=1
|
||||
#DEBUG_FLAGS+= -g
|
||||
|
@ -1,3 +1,10 @@
|
||||
--- 9.8.4-P2 released ---
|
||||
|
||||
3516. [security] Removed the check for regex.h in configure in order
|
||||
to disable regex syntax checking, as it exposes
|
||||
BIND to a critical flaw in libregex on some
|
||||
platforms. [RT #32688]
|
||||
|
||||
--- 9.8.4-P1 released ---
|
||||
|
||||
3407. [security] Named could die on specific queries with dns64 enabled.
|
||||
|
@ -286,9 +286,6 @@ int sigwait(const unsigned int *set, int *sig);
|
||||
/* Define if your OpenSSL version supports GOST. */
|
||||
#undef HAVE_OPENSSL_GOST
|
||||
|
||||
/* Define to 1 if you have the <regex.h> header file. */
|
||||
#undef HAVE_REGEX_H
|
||||
|
||||
/* Define to 1 if you have the `setegid' function. */
|
||||
#undef HAVE_SETEGID
|
||||
|
||||
|
@ -298,7 +298,7 @@ esac
|
||||
|
||||
AC_HEADER_STDC
|
||||
|
||||
AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h,,,
|
||||
AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h,,,
|
||||
[$ac_includes_default
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
|
@ -7,4 +7,4 @@ MAJORVER=9
|
||||
MINORVER=8
|
||||
PATCHVER=4
|
||||
RELEASETYPE=-P
|
||||
RELEASEVER=1
|
||||
RELEASEVER=2
|
||||
|
@ -633,6 +633,9 @@ read_attribute_value (struct attribute *attr,
|
||||
attr->u.val = read_1_byte (abfd, info_ptr);
|
||||
info_ptr += 1;
|
||||
break;
|
||||
case DW_FORM_flag_present:
|
||||
attr->u.val = 1;
|
||||
break;
|
||||
case DW_FORM_sdata:
|
||||
attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read);
|
||||
info_ptr += bytes_read;
|
||||
|
@ -557,6 +557,7 @@ get_FORM_name (unsigned long form)
|
||||
case DW_FORM_ref8: return "DW_FORM_ref8";
|
||||
case DW_FORM_ref_udata: return "DW_FORM_ref_udata";
|
||||
case DW_FORM_indirect: return "DW_FORM_indirect";
|
||||
case DW_FORM_flag_present: return "DW_FORM_flag_present";
|
||||
default:
|
||||
{
|
||||
static char buffer[100];
|
||||
@ -969,6 +970,10 @@ read_and_display_attr_value (unsigned long attribute,
|
||||
data += offset_size;
|
||||
break;
|
||||
|
||||
case DW_FORM_flag_present:
|
||||
uvalue = 1;
|
||||
break;
|
||||
|
||||
case DW_FORM_ref1:
|
||||
case DW_FORM_flag:
|
||||
case DW_FORM_data1:
|
||||
@ -1030,6 +1035,7 @@ read_and_display_attr_value (unsigned long attribute,
|
||||
printf (" %#lx", uvalue);
|
||||
break;
|
||||
|
||||
case DW_FORM_flag_present:
|
||||
case DW_FORM_flag:
|
||||
case DW_FORM_data1:
|
||||
case DW_FORM_data2:
|
||||
|
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