diff options
author | Renato Botelho <renato@netgate.com> | 2016-12-05 15:52:27 -0200 |
---|---|---|
committer | Renato Botelho <renato@netgate.com> | 2016-12-05 15:52:27 -0200 |
commit | ec84a59afa973e7e021ba2ae8ecae4cb6ba37b1d (patch) | |
tree | d7d40ac77bda3d6fc35814a1a6484eb324b3c7df /sbin | |
parent | ca825f0a56d174ca9d3478d87cdca9f318a50cc6 (diff) | |
parent | 356fbc072920d7e71c42b310d6bfa2d1a3d36f9f (diff) | |
download | FreeBSD-src-ec84a59afa973e7e021ba2ae8ecae4cb6ba37b1d.zip FreeBSD-src-ec84a59afa973e7e021ba2ae8ecae4cb6ba37b1d.tar.gz |
Merge remote-tracking branch 'origin/stable/11' into devel-11
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/Makefile | 1 | ||||
-rw-r--r-- | sbin/dhclient/dispatch.c | 4 | ||||
-rw-r--r-- | sbin/etherswitchcfg/etherswitchcfg.c | 6 | ||||
-rw-r--r-- | sbin/ipfw/ipfw2.c | 13 | ||||
-rw-r--r-- | sbin/ipfw/ipfw2.h | 9 | ||||
-rw-r--r-- | sbin/ipfw/ipv6.c | 23 | ||||
-rw-r--r-- | sbin/swapon/swapon.8 | 8 | ||||
-rw-r--r-- | sbin/swapon/swapon.c | 4 | ||||
-rw-r--r-- | sbin/umount/umount.c | 24 | ||||
-rw-r--r-- | sbin/zfsbootcfg/Makefile | 27 | ||||
-rw-r--r-- | sbin/zfsbootcfg/zfsbootcfg.8 | 112 | ||||
-rw-r--r-- | sbin/zfsbootcfg/zfsbootcfg.c | 98 |
12 files changed, 293 insertions, 36 deletions
diff --git a/sbin/Makefile b/sbin/Makefile index affca8e..4826bc0 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -87,6 +87,7 @@ SUBDIR.${MK_PF}+= pfctl SUBDIR.${MK_PF}+= pflogd SUBDIR.${MK_QUOTAS}+= quotacheck SUBDIR.${MK_ROUTED}+= routed +SUBDIR.${MK_ZFS}+= zfsbootcfg SUBDIR.${MK_TESTS}+= tests diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c index 3ee0cf6..3317ceb 100644 --- a/sbin/dhclient/dispatch.c +++ b/sbin/dhclient/dispatch.c @@ -105,8 +105,8 @@ discover_interfaces(struct interface_info *iface) if (foo.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) continue; if (!iface->ifp) { - int len = IFNAMSIZ + ifa->ifa_addr->sa_len; - if ((tif = malloc(len)) == NULL) + if ((tif = calloc(1, sizeof(struct ifreq))) + == NULL) error("no space to remember ifp"); strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); memcpy(&tif->ifr_addr, ifa->ifa_addr, diff --git a/sbin/etherswitchcfg/etherswitchcfg.c b/sbin/etherswitchcfg/etherswitchcfg.c index f7f117a..0ab110b 100644 --- a/sbin/etherswitchcfg/etherswitchcfg.c +++ b/sbin/etherswitchcfg/etherswitchcfg.c @@ -274,7 +274,8 @@ set_vlangroup_vid(struct cfg *cfg, char *argv[]) { int v; etherswitch_vlangroup_t vg; - + + memset(&vg, 0, sizeof(vg)); v = strtol(argv[1], NULL, 0); if (v < 0 || v > IEEE802DOT1Q_VID_MAX) errx(EX_USAGE, "vlan must be between 0 and %d", IEEE802DOT1Q_VID_MAX); @@ -293,8 +294,9 @@ set_vlangroup_members(struct cfg *cfg, char *argv[]) int member, untagged; char *c, *d; int v; - + member = untagged = 0; + memset(&vg, 0, sizeof(vg)); if (strcmp(argv[1], "none") != 0) { for (c=argv[1]; *c; c=d) { v = strtol(c, &d, 0); diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 42b020a..6a69a43 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -2883,8 +2883,9 @@ pack_table(struct tidx *tstate, char *name) return (pack_object(tstate, name, IPFW_TLV_TBL_NAME)); } -static void -fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate) +void +fill_table(struct _ipfw_insn *cmd, char *av, uint8_t opcode, + struct tidx *tstate) { uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; uint16_t uidx; @@ -3543,7 +3544,7 @@ add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate) if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || inet_pton(AF_INET6, host, &a) == 1) - ret = add_srcip6(cmd, av, cblen); + ret = add_srcip6(cmd, av, cblen, tstate); /* XXX: should check for IPv4, not !IPv6 */ if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || inet_pton(AF_INET6, host, &a) != 1)) @@ -3574,7 +3575,7 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate) if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || inet_pton(AF_INET6, host, &a) == 1) - ret = add_dstip6(cmd, av, cblen); + ret = add_dstip6(cmd, av, cblen, tstate); /* XXX: should check for IPv4, not !IPv6 */ if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || inet_pton(AF_INET6, host, &a) != 1)) @@ -4578,14 +4579,14 @@ read_options: case TOK_SRCIP6: NEED1("missing source IP6"); - if (add_srcip6(cmd, *av, cblen)) { + if (add_srcip6(cmd, *av, cblen, tstate)) { av++; } break; case TOK_DSTIP6: NEED1("missing destination IP6"); - if (add_dstip6(cmd, *av, cblen)) { + if (add_dstip6(cmd, *av, cblen, tstate)) { av++; } break; diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index b7f8c0b..c89a1c5 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -363,8 +363,11 @@ void print_flow6id(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd); void print_icmp6types(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd); void print_ext6hdr(struct buf_pr *bp, struct _ipfw_insn *cmd ); -struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen); -struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen); +struct tidx; +struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen, + struct tidx *tstate); +struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen, + struct tidx *tstate); void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen); void fill_unreach6_code(u_short *codep, char *str); @@ -373,6 +376,8 @@ int fill_ext6hdr(struct _ipfw_insn *cmd, char *av); /* ipfw2.c */ void bp_flush(struct buf_pr *b); +void fill_table(struct _ipfw_insn *cmd, char *av, uint8_t opcode, + struct tidx *tstate); /* tables.c */ struct _ipfw_obj_ctlv; diff --git a/sbin/ipfw/ipv6.c b/sbin/ipfw/ipv6.c index 6d884ee..f6b858d 100644 --- a/sbin/ipfw/ipv6.c +++ b/sbin/ipfw/ipv6.c @@ -334,7 +334,7 @@ lookup_host6 (char *host, struct in6_addr *ip6addr) * Return 1 on success, 0 on failure. */ static int -fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen) +fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen, struct tidx *tstate) { int len = 0; struct in6_addr *d = &(cmd->addr6); @@ -360,18 +360,7 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen) } if (strncmp(av, "table(", 6) == 0) { - char *p = strchr(av + 6, ','); - uint32_t *dm = ((ipfw_insn_u32 *)cmd)->d; - - if (p) - *p++ = '\0'; - cmd->o.opcode = O_IP_DST_LOOKUP; - cmd->o.arg1 = strtoul(av + 6, NULL, 0); - if (p) { - cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); - dm[0] = strtoul(p, NULL, 0); - } else - cmd->o.len |= F_INSN_SIZE(ipfw_insn); + fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate); return (1); } @@ -492,10 +481,10 @@ fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen) } ipfw_insn * -add_srcip6(ipfw_insn *cmd, char *av, int cblen) +add_srcip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate) { - fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen); + fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate); if (cmd->opcode == O_IP_DST_SET) /* set */ cmd->opcode = O_IP_SRC_SET; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ @@ -514,10 +503,10 @@ add_srcip6(ipfw_insn *cmd, char *av, int cblen) } ipfw_insn * -add_dstip6(ipfw_insn *cmd, char *av, int cblen) +add_dstip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate) { - fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen); + fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate); if (cmd->opcode == O_IP_DST_SET) /* set */ ; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8 index c4286d7..51bee68 100644 --- a/sbin/swapon/swapon.8 +++ b/sbin/swapon/swapon.8 @@ -28,7 +28,7 @@ .\" @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd November 22, 2013 +.Dd October 21, 2016 .Dt SWAPON 8 .Os .Sh NAME @@ -96,15 +96,13 @@ option is used, all swap devices in .Pa /etc/fstab will be removed, unless their .Dq noauto -or -.Dq late option is also set. If the .Fl L option is specified, -swap devices with the +only swap devices with the .Dq late -option will be removed as well as ones with no option. +option will be removed. If the .Fl q option is used, diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c index e34cfcf..052fbc7 100644 --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -176,6 +176,10 @@ main(int argc, char **argv) strstr(fsp->fs_mntops, "late") && late == 0) continue; + if (which_prog == SWAPOFF && + strstr(fsp->fs_mntops, "late") == NULL && + late != 0) + continue; swfile = swap_on_off(fsp->fs_spec, 1, fsp->fs_mntops); if (swfile == NULL) { diff --git a/sbin/umount/umount.c b/sbin/umount/umount.c index 20b7804..e6ece31 100644 --- a/sbin/umount/umount.c +++ b/sbin/umount/umount.c @@ -49,6 +49,7 @@ static const char rcsid[] = #include <netdb.h> #include <rpc/rpc.h> #include <rpcsvc/mount.h> +#include <nfs/nfssvc.h> #include <ctype.h> #include <err.h> @@ -323,6 +324,9 @@ umountfs(struct statfs *sfs) CLIENT *clp; char *nfsdirname, *orignfsdirname; char *hostp, *delimp; + char buf[1024]; + struct nfscl_dumpmntopts dumpmntopts; + const char *proto_ptr = NULL; ai = NULL; do_rpc = 0; @@ -361,8 +365,24 @@ umountfs(struct statfs *sfs) * mount from mntfromname that is still mounted. */ if (getmntentry(sfs->f_mntfromname, NULL, NULL, - CHECKUNIQUE) != NULL) + CHECKUNIQUE) != NULL) { do_rpc = 1; + proto_ptr = "udp"; + /* + * Try and find out whether this NFS mount is NFSv4 and + * what protocol is being used. If this fails, the + * default is NFSv2,3 and use UDP for the Unmount RPC. + */ + dumpmntopts.ndmnt_fname = sfs->f_mntonname; + dumpmntopts.ndmnt_buf = buf; + dumpmntopts.ndmnt_blen = sizeof(buf); + if (nfssvc(NFSSVC_DUMPMNTOPTS, &dumpmntopts) >= 0) { + if (strstr(buf, "nfsv4,") != NULL) + do_rpc = 0; + else if (strstr(buf, ",tcp,") != NULL) + proto_ptr = "tcp"; + } + } } if (!namematch(ai)) { @@ -400,7 +420,7 @@ umountfs(struct statfs *sfs) * has been unmounted. */ if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) { - clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS3, "udp"); + clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS3, proto_ptr); if (clp == NULL) { warnx("%s: %s", hostp, clnt_spcreateerror("MOUNTPROG")); diff --git a/sbin/zfsbootcfg/Makefile b/sbin/zfsbootcfg/Makefile new file mode 100644 index 0000000..d485d8d --- /dev/null +++ b/sbin/zfsbootcfg/Makefile @@ -0,0 +1,27 @@ +# @(#)Makefile 8.4 (Berkeley) 6/22/95 +# $FreeBSD$ + +PROG= zfsbootcfg +WARNS?= 1 +MAN= zfsbootcfg.8 + +LIBADD+=zfs +LIBADD+=nvpair +LIBADD+=umem +LIBADD+=uutil +LIBADD+=geom + +CFLAGS+= -I${SRCTOP}/cddl/compat/opensolaris/include +CFLAGS+= -I${SRCTOP}/cddl/compat/opensolaris/lib/libumem +CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libzfs/common +CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libzfs_core/common +CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libzpool/common +CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libnvpair +CFLAGS+= -I${SRCTOP}/sys/cddl/compat/opensolaris +CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common/fs/zfs +CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common +CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/head + +CFLAGS+= -DNEED_SOLARIS_BOOLEAN + +.include <bsd.prog.mk> diff --git a/sbin/zfsbootcfg/zfsbootcfg.8 b/sbin/zfsbootcfg/zfsbootcfg.8 new file mode 100644 index 0000000..aa6201d --- /dev/null +++ b/sbin/zfsbootcfg/zfsbootcfg.8 @@ -0,0 +1,112 @@ +.\" Copyright (c) 2016 Andriy Gapon +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 12, 2016 +.Dt ZFSBOOTCFG 8 +.Os +.Sh NAME +.Nm zfsbootcfg +.Nd "specify zfsboot options for the next boot" +.Sh SYNOPSIS +.Nm +.Ao Ar options Ac +.Sh DESCRIPTION +.Nm +is used to set +.Xr boot.config 5 Ns -style +options to be used by +.Xr zfsboot 8 +or +.Xr gptzfsboot 8 +the next time the machine is booted. +Once +.Xr zfsboot 8 +or +.Xr gptzfsboot 8 +reads the information, it is deleted. +If booting fails, the machine automatically reverts to the previous +boot configuration. +The information is stored in a special reserved area of a ZFS pool. +.Xr zfsboot 8 +or +.Xr gptzfsboot 8 +read the boot option information from the first disk found in the first +ZFS pool found. +.Sh ENVIRONMENT +.Bl -tag -width vfs.zfs.boot.primary_pool -compact +.It Ev vfs.zfs.boot.primary_pool +The +.Xr kenv 1 +variable that identifies a pool for which the options are written. +.It Ev vfs.zfs.boot.primary_vdev +The +.Xr kenv 1 +variable that identifies a disk within the pool where the options +are written. +.El +.Sh EXAMPLES +Try to boot to a new +.Em boot environment +without changing the +.Cm bootfs +property of a pool: +.Pp +.Dl "zfsbootcfg ""zfs:tank/ROOT/newbe:"" +.Pp +To clear the boot options: +.Pp +.Dl "zfsbootcfg """" +.Sh SEE ALSO +.Xr boot.config 5 , +.Xr gptzfsboot 8 , +.Xr zfsboot 8 +.Sh HISTORY +.Nm +appeared in +.Fx 12.0 . +.Sh AUTHORS +This manual page was written by +.An Andriy Gapon Aq Mt avg@FreeBSD.org . +.Sh CAVEATS +At the moment, +.Nm +uses the +.Ev vfs.zfs.boot.primary_pool +and +.Ev vfs.zfs.boot.primary_vdev +.Xr kenv 1 +variables to determine a ZFS pool and a disk in it where the options +are to be stored. +The variables are set by the ZFS boot chain, so there is an assumption +that the same boot disk is going to be used for the next reboot. +There is no +.Nm +option to specify a different pool or a different disk. +.Pp +.Nm +should be extended to install new +.Xr zfsboot 8 +blocks in a ZFS pool. diff --git a/sbin/zfsbootcfg/zfsbootcfg.c b/sbin/zfsbootcfg/zfsbootcfg.c new file mode 100644 index 0000000..096f1a4 --- /dev/null +++ b/sbin/zfsbootcfg/zfsbootcfg.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2016 Andriy Gapon <avg@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <errno.h> +#include <limits.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <kenv.h> + +#include <libzfs.h> + +/* Keep in sync with zfsboot.c. */ +#define MAX_COMMAND_LEN 512 + +int main(int argc, const char * const *argv) +{ + char buf[32]; + libzfs_handle_t *hdl; + uint64_t pool_guid; + uint64_t vdev_guid; + int zfs_fd; + int len; + + if (argc != 2) { + fprintf(stderr, "usage: zfsbootcfg <boot.config(5) options>\n"); + return (1); + } + + len = strlen(argv[1]); + if (len >= MAX_COMMAND_LEN) { + fprintf(stderr, "options string is too long\n"); + return (1); + } + + if (kenv(KENV_GET, "vfs.zfs.boot.primary_pool", buf, sizeof(buf)) <= 0) { + perror("can't get vfs.zfs.boot.primary_pool"); + return (1); + } + pool_guid = strtoumax(buf, NULL, 10); + if (pool_guid == 0) { + perror("can't parse vfs.zfs.boot.primary_pool"); + return (1); + } + + if (kenv(KENV_GET, "vfs.zfs.boot.primary_vdev", buf, sizeof(buf)) <= 0) { + perror("can't get vfs.zfs.boot.primary_vdev"); + return (1); + } + vdev_guid = strtoumax(buf, NULL, 10); + if (vdev_guid == 0) { + perror("can't parse vfs.zfs.boot.primary_vdev"); + return (1); + } + + if ((hdl = libzfs_init()) == NULL) { + (void) fprintf(stderr, "internal error: failed to " + "initialize ZFS library\n"); + return (1); + } + + if (zpool_nextboot(hdl, pool_guid, vdev_guid, argv[1]) != 0) { + perror("ZFS_IOC_NEXTBOOT failed"); + libzfs_fini(hdl); + return (1); + } + + libzfs_fini(hdl); + printf("zfs next boot options are successfully written\n"); + return (0); +} |