From owner-svn-src-stable@freebsd.org Sun Jan 6 02:13:20 2019 Return-Path: Delivered-To: svn-src-stable@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 672B6142F893; Sun, 6 Jan 2019 02:13:20 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 142CE8325F; Sun, 6 Jan 2019 02:13:20 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 0582421A3A; Sun, 6 Jan 2019 02:13:20 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x062DJKi081970; Sun, 6 Jan 2019 02:13:19 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x062DHNS081954; Sun, 6 Jan 2019 02:13:17 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201901060213.x062DHNS081954@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Sun, 6 Jan 2019 02:13:17 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r342807 - in stable/11: . contrib/mdocml lib lib/libbe sbin sbin/bectl share/mk sys/amd64/conf tools/build/mk usr.sbin/config X-SVN-Group: stable-11 X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: in stable/11: . contrib/mdocml lib lib/libbe sbin sbin/bectl share/mk sys/amd64/conf tools/build/mk usr.sbin/config X-SVN-Commit-Revision: 342807 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 142CE8325F X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.92 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.93)[-0.925,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-0.999,0] X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 06 Jan 2019 02:13:20 -0000 Author: kevans Date: Sun Jan 6 02:13:16 2019 New Revision: 342807 URL: https://svnweb.freebsd.org/changeset/base/342807 Log: MFC r342362-r342363: config(8) duplicate option handling r342362: config(8): Allow duplicate options to be specified config(8)'s option handling has been written to allow duplicate options; if the value changes, then the latest value is used and an informative message is printed to stderr like so: /usr/src/sys/amd64/conf/TEST: option "VERBOSE_SYSINIT" redefined from 0 to 1 Currently, this is only a possibility for cpu types, MAXUSERS, and MACHINE_ARCH. Anything else duplicated in a config file will use the first value set and error about duplicated options on subsequent appearances, which is arguably unfriendly since one could specify: include GENERIC nooptions VERBOSE_SYSINIT options VERBOSE_SYSINIT to redefine the value later anyways. Reported by: mmacy r342363: config(8): Remove all instances of an option when opting out Quick follow-up to r342362: options can appear multiple times now, so clean up all of them as needed. For non-OPTIONS options, this has no effect since they're already de-duplicated. Added: stable/11/lib/libbe/ - copied from r337664, head/lib/libbe/ stable/11/lib/libbe/Makefile - copied, changed from r337995, head/lib/libbe/Makefile stable/11/sbin/bectl/ - copied from r337664, head/sbin/bectl/ Modified: stable/11/Makefile.inc1 stable/11/ObsoleteFiles.inc stable/11/contrib/mdocml/lib.in stable/11/lib/Makefile stable/11/lib/libbe/be.c stable/11/lib/libbe/be.h stable/11/lib/libbe/be_access.c stable/11/lib/libbe/be_error.c stable/11/lib/libbe/be_info.c stable/11/lib/libbe/libbe.3 stable/11/sbin/Makefile stable/11/sbin/bectl/Makefile stable/11/sbin/bectl/bectl.8 stable/11/sbin/bectl/bectl.c stable/11/sbin/bectl/bectl_jail.c stable/11/sbin/bectl/bectl_list.c stable/11/share/mk/bsd.libnames.mk stable/11/share/mk/src.libnames.mk stable/11/sys/amd64/conf/GENERIC stable/11/sys/amd64/conf/MINIMAL stable/11/tools/build/mk/OptionalObsoleteFiles.inc stable/11/usr.sbin/config/config.y Directory Properties: stable/11/ (props changed) Modified: stable/11/Makefile.inc1 ============================================================================== --- stable/11/Makefile.inc1 Sun Jan 6 02:12:55 2019 (r342806) +++ stable/11/Makefile.inc1 Sun Jan 6 02:13:16 2019 (r342807) @@ -2144,7 +2144,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \ ${_cddl_lib_libumem} ${_cddl_lib_libnvpair} \ ${_cddl_lib_libuutil} \ ${_cddl_lib_libavl} \ - ${_cddl_lib_libzfs_core} \ + ${_cddl_lib_libzfs_core} ${_cddl_lib_libzfs} \ ${_cddl_lib_libctf} \ lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \ ${_secure_lib_libcrypto} ${_lib_libldns} \ @@ -2213,7 +2213,15 @@ _cddl_lib_libavl= cddl/lib/libavl _cddl_lib_libuutil= cddl/lib/libuutil .if ${MK_ZFS} != "no" _cddl_lib_libzfs_core= cddl/lib/libzfs_core +_cddl_lib_libzfs= cddl/lib/libzfs + cddl/lib/libzfs_core__L: cddl/lib/libnvpair__L + +cddl/lib/libzfs__L: cddl/lib/libzfs_core__L lib/msun__L lib/libutil__L +cddl/lib/libzfs__L: lib/libthr__L lib/libmd__L lib/libz__L cddl/lib/libumem__L +cddl/lib/libzfs__L: cddl/lib/libuutil__L cddl/lib/libavl__L lib/libgeom__L + +lib/libbe__L: cddl/lib/libzfs__L .endif _cddl_lib_libctf= cddl/lib/libctf _cddl_lib= cddl/lib Modified: stable/11/ObsoleteFiles.inc ============================================================================== --- stable/11/ObsoleteFiles.inc Sun Jan 6 02:12:55 2019 (r342806) +++ stable/11/ObsoleteFiles.inc Sun Jan 6 02:13:16 2019 (r342807) @@ -38,6 +38,8 @@ # xargs -n1 | sort | uniq -d; # done +# 20181115: libbe(3) SHLIBDIR fixed to reflect correct location +OLD_LIBS+=usr/lib/libbe.so.1 # 20180812: move of libmlx5.so.1 and libibverbs.so.1 OLD_LIBS+=usr/lib/libmlx5.so.1 OLD_LIBS+=usr/lib/libibverbs.so.1 Modified: stable/11/contrib/mdocml/lib.in ============================================================================== --- stable/11/contrib/mdocml/lib.in Sun Jan 6 02:12:55 2019 (r342806) +++ stable/11/contrib/mdocml/lib.in Sun Jan 6 02:13:16 2019 (r342807) @@ -28,6 +28,7 @@ LINE("lib80211", "802.11 Wireless Network Management L LINE("libarchive", "Streaming Archive Library (libarchive, \\-larchive)") LINE("libarm", "ARM Architecture Library (libarm, \\-larm)") LINE("libarm32", "ARM32 Architecture Library (libarm32, \\-larm32)") +LINE("libbe", "Boot Environment Library (libbe, \\-lbe)") LINE("libbluetooth", "Bluetooth Library (libbluetooth, \\-lbluetooth)") LINE("libbsm", "Basic Security Module Library (libbsm, \\-lbsm)") LINE("libc", "Standard C\\~Library (libc, \\-lc)") Modified: stable/11/lib/Makefile ============================================================================== --- stable/11/lib/Makefile Sun Jan 6 02:12:55 2019 (r342806) +++ stable/11/lib/Makefile Sun Jan 6 02:13:16 2019 (r342807) @@ -289,6 +289,7 @@ _libproc= libproc _librtld_db= librtld_db .endif SUBDIR.${MK_OFED}+= ofed +SUBDIR.${MK_ZFS}+= libbe .if ${MK_OPENSSL} != "no" _libmp= libmp Copied and modified: stable/11/lib/libbe/Makefile (from r337995, head/lib/libbe/Makefile) ============================================================================== --- head/lib/libbe/Makefile Sat Aug 18 03:20:59 2018 (r337995, copy source) +++ stable/11/lib/libbe/Makefile Sun Jan 6 02:13:16 2019 (r342807) @@ -2,6 +2,7 @@ PACKAGE= lib${LIB} LIB= be +SHLIBDIR?= /lib SHLIB_MAJOR= 1 SHLIB_MINOR= 0 Modified: stable/11/lib/libbe/be.c ============================================================================== --- head/lib/libbe/be.c Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/lib/libbe/be.c Sun Jan 6 02:13:16 2019 (r342807) @@ -64,10 +64,13 @@ be_locate_rootfs(zfs_handle_t *chkds, void *data) if (lbh == NULL) return (1); + mntpoint = NULL; if (zfs_is_mounted(chkds, &mntpoint) && strcmp(mntpoint, "/") == 0) { - strncpy(lbh->rootfs, zfs_get_name(chkds), BE_MAXPATHLEN); + strlcpy(lbh->rootfs, zfs_get_name(chkds), sizeof(lbh->rootfs)); + free(mntpoint); return (1); - } + } else if(mntpoint != NULL) + free(mntpoint); return (0); } @@ -88,7 +91,6 @@ libbe_init(void) lbh = NULL; poolname = pos = NULL; - pnamelen = 0; rootds = NULL; /* Verify that /boot and / are mounted on the same filesystem */ @@ -115,13 +117,14 @@ libbe_init(void) goto err; /* Obtain path to boot environment root */ - if ((kenv(KENV_GET, "zfs_be_root", lbh->root, BE_MAXPATHLEN)) == -1) + if ((kenv(KENV_GET, "zfs_be_root", lbh->root, + sizeof(lbh->root))) == -1) goto err; /* Remove leading 'zfs:' if present, otherwise use value as-is */ if (strcmp(lbh->root, "zfs:") == 0) - strncpy(lbh->root, strchr(lbh->root, ':') + sizeof(char), - BE_MAXPATHLEN); + strlcpy(lbh->root, strchr(lbh->root, ':') + sizeof(char), + sizeof(lbh->root)); if ((pos = strchr(lbh->root, '/')) == NULL) goto err; @@ -131,13 +134,14 @@ libbe_init(void) if (poolname == NULL) goto err; - strncpy(poolname, lbh->root, pnamelen); - poolname[pnamelen] = '\0'; + strlcpy(poolname, lbh->root, pnamelen + 1); if ((lbh->active_phandle = zpool_open(lbh->lzh, poolname)) == NULL) goto err; + free(poolname); + poolname = NULL; if (zpool_get_prop(lbh->active_phandle, ZPOOL_PROP_BOOTFS, lbh->bootfs, - BE_MAXPATHLEN, NULL, true) != 0) + sizeof(lbh->bootfs), NULL, true) != 0) goto err; /* Obtain path to boot environment rootfs (currently booted) */ @@ -160,8 +164,6 @@ err: libzfs_fini(lbh->lzh); free(lbh); } - if (rootds != NULL) - zfs_close(rootds); free(poolname); return (NULL); } @@ -217,7 +219,6 @@ be_destroy(libbe_handle_t *lbh, const char *name, int p = path; force = options & BE_DESTROY_FORCE; - err = BE_ERR_SUCCESS; be_root_concat(lbh, name, path); @@ -269,22 +270,27 @@ be_snapshot(libbe_handle_t *lbh, const char *source, c be_root_concat(lbh, source, buf); - if (!be_exists(lbh, buf)) - return (BE_ERR_NOENT); + if ((err = be_exists(lbh, buf)) != 0) + return (set_error(lbh, err)); if (snap_name != NULL) { - strcat(buf, "@"); - strcat(buf, snap_name); + if (strlcat(buf, "@", sizeof(buf)) >= sizeof(buf)) + return (set_error(lbh, BE_ERR_INVALIDNAME)); + + if (strlcat(buf, snap_name, sizeof(buf)) >= sizeof(buf)) + return (set_error(lbh, BE_ERR_INVALIDNAME)); + if (result != NULL) snprintf(result, BE_MAXPATHLEN, "%s@%s", source, snap_name); } else { time(&rawtime); len = strlen(buf); - strftime(buf + len, BE_MAXPATHLEN - len, + strftime(buf + len, sizeof(buf) - len, "@%F-%T", localtime(&rawtime)); - if (result != NULL) - strcpy(result, strrchr(buf, '/') + 1); + if (result != NULL && strlcpy(result, strrchr(buf, '/') + 1, + sizeof(buf)) >= sizeof(buf)) + return (set_error(lbh, BE_ERR_INVALIDNAME)); } if ((err = zfs_snapshot(lbh->lzh, buf, recursive, NULL)) != 0) { @@ -397,20 +403,16 @@ be_deep_clone(zfs_handle_t *ds, void *data) ZFS_TYPE_FILESYSTEM) == ZPROP_INVAL) return (-1); - if ((err = zfs_clone(snap_hdl, be_path, props)) != 0) { - switch (err) { - case EZFS_SUCCESS: - err = BE_ERR_SUCCESS; - break; - default: - err = BE_ERR_ZFSCLONE; - break; - } - } + if ((err = zfs_clone(snap_hdl, be_path, props)) != 0) + err = BE_ERR_ZFSCLONE; nvlist_free(props); zfs_close(snap_hdl); + /* Failed to clone */ + if (err != BE_ERR_SUCCESS) + return (set_error(isdc->lbh, err)); + sdc.lbh = isdc->lbh; sdc.bename = NULL; sdc.snapname = isdc->snapname; @@ -451,14 +453,13 @@ be_create_from_existing_snap(libbe_handle_t *lbh, cons else bename++; - if ((parentname = strdup(snap_path)) == NULL) { - err = BE_ERR_UNKNOWN; - return (set_error(lbh, err)); - } + if ((parentname = strdup(snap_path)) == NULL) + return (set_error(lbh, BE_ERR_UNKNOWN)); + snapname = strchr(parentname, '@'); if (snapname == NULL) { - err = BE_ERR_UNKNOWN; - return (set_error(lbh, err)); + free(parentname); + return (set_error(lbh, BE_ERR_UNKNOWN)); } *snapname = '\0'; snapname++; @@ -471,6 +472,7 @@ be_create_from_existing_snap(libbe_handle_t *lbh, cons parent_hdl = zfs_open(lbh->lzh, parentname, ZFS_TYPE_DATASET); err = be_deep_clone(parent_hdl, &sdc); + free(parentname); return (set_error(lbh, err)); } @@ -484,7 +486,7 @@ be_create_from_existing(libbe_handle_t *lbh, const cha int err; char buf[BE_MAXPATHLEN]; - if ((err = be_snapshot(lbh, old, NULL, true, (char *)&buf))) + if ((err = be_snapshot(lbh, old, NULL, true, (char *)&buf)) != 0) return (set_error(lbh, err)); err = be_create_from_existing_snap(lbh, name, (char *)buf); @@ -513,7 +515,7 @@ be_validate_snap(libbe_handle_t *lbh, const char *snap ZFS_TYPE_SNAPSHOT)) return (BE_ERR_NOENT); - strncpy(buf, snap_name, BE_MAXPATHLEN); + strlcpy(buf, snap_name, sizeof(buf)); /* Find the base filesystem of the snapshot */ if ((delim_pos = strchr(buf, '@')) == NULL) @@ -524,12 +526,12 @@ be_validate_snap(libbe_handle_t *lbh, const char *snap zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL) return (BE_ERR_NOORIGIN); - if ((err = zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, BE_MAXPATHLEN, - NULL, NULL, 0, 1)) != 0) - err = BE_ERR_INVORIGIN; + if ((err = zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, + sizeof(buf), NULL, NULL, 0, 1)) != 0) + err = BE_ERR_BADMOUNT; - if ((err != 0) && (strncmp(buf, "/", BE_MAXPATHLEN) != 0)) - err = BE_ERR_INVORIGIN; + if ((err != 0) && (strncmp(buf, "/", sizeof(buf)) != 0)) + err = BE_ERR_BADMOUNT; zfs_close(zfs_hdl); @@ -561,7 +563,7 @@ be_root_concat(libbe_handle_t *lbh, const char *name, if (name_len >= BE_MAXPATHLEN) return (BE_ERR_PATHLEN); - strncpy(result, name, BE_MAXPATHLEN); + strlcpy(result, name, BE_MAXPATHLEN); return (BE_ERR_SUCCESS); } else if (name_len + root_len + 1 < BE_MAXPATHLEN) { snprintf(result, BE_MAXPATHLEN, "%s/%s", lbh->root, @@ -575,11 +577,12 @@ be_root_concat(libbe_handle_t *lbh, const char *name, /* * Verifies the validity of a boot environment name (A-Za-z0-9-_.). Returns - * BE_ERR_SUCCESS (0) if name is valid, otherwise returns BE_ERR_INVALIDNAME. + * BE_ERR_SUCCESS (0) if name is valid, otherwise returns BE_ERR_INVALIDNAME + * or BE_ERR_PATHLEN. * Does not set internal library error state. */ int -be_validate_name(libbe_handle_t *lbh __unused, const char *name) +be_validate_name(libbe_handle_t *lbh, const char *name) { for (int i = 0; *name; i++) { char c = *(name++); @@ -588,6 +591,12 @@ be_validate_name(libbe_handle_t *lbh __unused, const c return (BE_ERR_INVALIDNAME); } + /* + * Impose the additional restriction that the entire dataset name must + * not exceed the maximum length of a dataset, i.e. MAXNAMELEN. + */ + if (strlen(lbh->root) + 1 + strlen(name) > MAXNAMELEN) + return (BE_ERR_PATHLEN); return (BE_ERR_SUCCESS); } @@ -603,18 +612,17 @@ be_rename(libbe_handle_t *lbh, const char *old, const zfs_handle_t *zfs_hdl; int err; + /* + * be_validate_name is documented not to set error state, so we should + * do so here. + */ + if ((err = be_validate_name(lbh, new)) != 0) + return (set_error(lbh, err)); if ((err = be_root_concat(lbh, old, full_old)) != 0) return (set_error(lbh, err)); if ((err = be_root_concat(lbh, new, full_new)) != 0) return (set_error(lbh, err)); - if ((err = be_validate_name(lbh, new)) != 0) - return (err); - - /* Check if old is active BE */ - if (strcmp(full_old, be_active_path(lbh)) == 0) - return (set_error(lbh, BE_ERR_MOUNTED)); - if (!zfs_dataset_exists(lbh->lzh, full_old, ZFS_TYPE_DATASET)) return (set_error(lbh, BE_ERR_NOENT)); @@ -625,20 +633,17 @@ be_rename(libbe_handle_t *lbh, const char *old, const ZFS_TYPE_FILESYSTEM)) == NULL) return (set_error(lbh, BE_ERR_ZFSOPEN)); - /* XXX TODO: Allow a force flag */ - if (zfs_is_mounted(zfs_hdl, NULL)) { - zfs_close(zfs_hdl); - return (set_error(lbh, BE_ERR_MOUNTED)); - } - /* recurse, nounmount, forceunmount */ - struct renameflags flags = { 0, 0, 0 }; + struct renameflags flags = { + .nounmount = 1, + }; err = zfs_rename(zfs_hdl, NULL, full_new, flags); zfs_close(zfs_hdl); - - return (set_error(lbh, err)); + if (err != 0) + return (set_error(lbh, BE_ERR_UNKNOWN)); + return (0); } @@ -693,8 +698,7 @@ be_import(libbe_handle_t *lbh, const char *bootenv, in time(&rawtime); len = strlen(buf); - strftime(buf + len, BE_MAXPATHLEN - len, - "@%F-%T", localtime(&rawtime)); + strftime(buf + len, sizeof(buf) - len, "@%F-%T", localtime(&rawtime)); if ((err = lzc_receive(buf, NULL, NULL, false, fd)) != 0) { switch (err) { @@ -720,11 +724,28 @@ be_import(libbe_handle_t *lbh, const char *bootenv, in err = zfs_clone(zfs, buf, props); zfs_close(zfs); - nvlist_free(props); - /* XXX TODO: Figure out how to destroy the ghost... */ - return (BE_ERR_SUCCESS); + if (err != 0) + return (set_error(lbh, BE_ERR_UNKNOWN)); + + /* + * Finally, we open up the dataset we just cloned the snapshot so that + * we may promote it. This is necessary in order to clean up the ghost + * snapshot that doesn't need to be seen after the operation is + * complete. + */ + if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL) + return (set_error(lbh, BE_ERR_ZFSOPEN)); + + err = zfs_promote(zfs); + zfs_close(zfs); + + if (err != 0) + return (set_error(lbh, BE_ERR_UNKNOWN)); + + /* Clean up the temporary snapshot */ + return (be_destroy(lbh, nbuf, 0)); } #if SOON @@ -901,21 +922,38 @@ be_set_nextboot(libbe_handle_t *lbh, nvlist_t *config, return (0); } +/* + * Deactivate old BE dataset; currently just sets canmount=noauto + */ +static int +be_deactivate(libbe_handle_t *lbh, const char *ds) +{ + zfs_handle_t *zfs; + if ((zfs = zfs_open(lbh->lzh, ds, ZFS_TYPE_DATASET)) == NULL) + return (1); + if (zfs_prop_set(zfs, "canmount", "noauto") != 0) + return (1); + zfs_close(zfs); + return (0); +} + int be_activate(libbe_handle_t *lbh, const char *bootenv, bool temporary) { char be_path[BE_MAXPATHLEN]; char buf[BE_MAXPATHLEN]; + nvlist_t *config, *dsprops, *vdevs; + char *origin; uint64_t pool_guid; - nvlist_t *config, *vdevs; + zfs_handle_t *zhp; int err; be_root_concat(lbh, bootenv, be_path); /* Note: be_exists fails if mountpoint is not / */ - if (!be_exists(lbh, be_path)) - return (BE_ERR_NOENT); + if ((err = be_exists(lbh, be_path)) != 0) + return (set_error(lbh, err)); if (temporary) { config = zpool_get_config(lbh->active_phandle, NULL); @@ -929,9 +967,7 @@ be_activate(libbe_handle_t *lbh, const char *bootenv, return (set_error(lbh, BE_ERR_UNKNOWN)); /* Expected format according to zfsbootcfg(8) man */ - strcpy(buf, "zfs:"); - strcat(buf, be_path); - strcat(buf, ":"); + snprintf(buf, sizeof(buf), "zfs:%s:", be_path); /* We have no config tree */ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, @@ -940,16 +976,35 @@ be_activate(libbe_handle_t *lbh, const char *bootenv, return (be_set_nextboot(lbh, vdevs, pool_guid, buf)); } else { + if (be_deactivate(lbh, lbh->bootfs) != 0) + return (-1); + /* Obtain bootenv zpool */ err = zpool_set_prop(lbh->active_phandle, "bootfs", be_path); + if (err) + return (-1); - switch (err) { - case 0: - return (BE_ERR_SUCCESS); + zhp = zfs_open(lbh->lzh, be_path, ZFS_TYPE_FILESYSTEM); + if (zhp == NULL) + return (-1); - default: - /* XXX TODO correct errors */ + if (be_prop_list_alloc(&dsprops) != 0) return (-1); + + if (be_get_dataset_props(lbh, be_path, dsprops) != 0) { + nvlist_free(dsprops); + return (-1); } + + if (nvlist_lookup_string(dsprops, "origin", &origin) == 0) + err = zfs_promote(zhp); + nvlist_free(dsprops); + + zfs_close(zhp); + + if (err) + return (-1); } + + return (BE_ERR_SUCCESS); } Modified: stable/11/lib/libbe/be.h ============================================================================== --- head/lib/libbe/be.h Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/lib/libbe/be.h Sun Jan 6 02:13:16 2019 (r342807) @@ -49,7 +49,7 @@ typedef enum be_error { BE_ERR_BADPATH, /* path not suitable for operation */ BE_ERR_PATHBUSY, /* requested path is busy */ BE_ERR_PATHLEN, /* provided name exceeds maximum length limit */ - BE_ERR_INVORIGIN, /* snapshot origin's mountpoint is not '/' */ + BE_ERR_BADMOUNT, /* mountpoint is not '/' */ BE_ERR_NOORIGIN, /* could not open snapshot's origin */ BE_ERR_MOUNTED, /* boot environment is already mounted */ BE_ERR_NOMOUNT, /* boot environment is not mounted */ @@ -118,7 +118,7 @@ void libbe_print_on_error(libbe_handle_t *, bool); int be_root_concat(libbe_handle_t *, const char *, char *); int be_validate_name(libbe_handle_t * __unused, const char *); int be_validate_snap(libbe_handle_t *, const char *); -bool be_exists(libbe_handle_t *, char *); +int be_exists(libbe_handle_t *, char *); int be_export(libbe_handle_t *, const char *, int fd); int be_import(libbe_handle_t *, const char *, int fd); Modified: stable/11/lib/libbe/be_access.c ============================================================================== --- head/lib/libbe/be_access.c Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/lib/libbe/be_access.c Sun Jan 6 02:13:16 2019 (r342807) @@ -51,8 +51,10 @@ be_mountcheck_cb(zfs_handle_t *zfs_hdl, void *data) return (0); if (strcmp(mountpoint, info->path) == 0) { info->name = strdup(zfs_get_name(zfs_hdl)); + free(mountpoint); return (1); } + free(mountpoint); return (0); } @@ -62,12 +64,12 @@ be_mountcheck_cb(zfs_handle_t *zfs_hdl, void *data) int be_mounted_at(libbe_handle_t *lbh, const char *path, nvlist_t *details) { - char be[BE_MAXPATHLEN + 1]; + char be[BE_MAXPATHLEN]; zfs_handle_t *root_hdl; struct be_mountcheck_info info; prop_data_t propinfo; - bzero(&be, BE_MAXPATHLEN + 1); + bzero(&be, BE_MAXPATHLEN); if ((root_hdl = zfs_open(lbh->lzh, lbh->root, ZFS_TYPE_FILESYSTEM)) == NULL) return (BE_ERR_ZFSOPEN); @@ -106,24 +108,23 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mou { char be[BE_MAXPATHLEN]; char mnt_temp[BE_MAXPATHLEN]; - char *path; int mntflags; int err; if ((err = be_root_concat(lbh, bootenv, be)) != 0) return (set_error(lbh, err)); - if (!be_exists(lbh, bootenv)) - return (set_error(lbh, BE_ERR_NOENT)); + if ((err = be_exists(lbh, bootenv)) != 0) + return (set_error(lbh, err)); - if (is_mounted(lbh->lzh, be, &path)) + if (is_mounted(lbh->lzh, be, NULL)) return (set_error(lbh, BE_ERR_MOUNTED)); mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0; /* Create mountpoint if it is not specified */ if (mountpoint == NULL) { - strcpy(mnt_temp, "/tmp/be_mount.XXXX"); + strlcpy(mnt_temp, "/tmp/be_mount.XXXX", sizeof(mnt_temp)); if (mkdtemp(mnt_temp) == NULL) return (set_error(lbh, BE_ERR_IO)); } @@ -148,7 +149,8 @@ be_mount(libbe_handle_t *lbh, char *bootenv, char *mou } if (result_loc != NULL) - strcpy(result_loc, mountpoint == NULL ? mnt_temp : mountpoint); + strlcpy(result_loc, mountpoint == NULL ? mnt_temp : mountpoint, + BE_MAXPATHLEN); return (BE_ERR_SUCCESS); } Modified: stable/11/lib/libbe/be_error.c ============================================================================== --- head/lib/libbe/be_error.c Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/lib/libbe/be_error.c Sun Jan 6 02:13:16 2019 (r342807) @@ -75,8 +75,8 @@ libbe_error_description(libbe_handle_t *lbh) case BE_ERR_PATHLEN: return ("provided path name exceeds maximum length limit"); - case BE_ERR_INVORIGIN: - return ("snapshot origin's mountpoint is not \"/\""); + case BE_ERR_BADMOUNT: + return ("mountpoint is not \"/\""); case BE_ERR_NOORIGIN: return ("could not open snapshot's origin"); Modified: stable/11/lib/libbe/be_info.c ============================================================================== --- head/lib/libbe/be_info.c Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/lib/libbe/be_info.c Sun Jan 6 02:13:16 2019 (r342807) @@ -285,7 +285,7 @@ be_prop_list_free(nvlist_t *be_list) /* * Usage */ -bool +int be_exists(libbe_handle_t *lbh, char *be) { char buf[BE_MAXPATHLEN]; @@ -296,25 +296,23 @@ be_exists(libbe_handle_t *lbh, char *be) be_root_concat(lbh, be, buf); if (!zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_DATASET)) - return (false); + return (BE_ERR_NOENT); /* Also check if it's mounted at / */ - if (be_prop_list_alloc(&dsprops) != 0) { - set_error(lbh, BE_ERR_UNKNOWN); - return (false); - } + if (be_prop_list_alloc(&dsprops) != 0) + return (BE_ERR_UNKNOWN); if (be_get_dataset_props(lbh, buf, dsprops) != 0) { nvlist_free(dsprops); - return (false); + return (BE_ERR_UNKNOWN); } if (nvlist_lookup_string(dsprops, "mountpoint", &mntpoint) == 0) { valid = (strcmp(mntpoint, "/") == 0); nvlist_free(dsprops); - return (valid); + return (valid ? BE_ERR_SUCCESS : BE_ERR_BADMOUNT); } nvlist_free(dsprops); - return (false); + return (BE_ERR_BADMOUNT); } Modified: stable/11/lib/libbe/libbe.3 ============================================================================== --- head/lib/libbe/libbe.3 Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/lib/libbe/libbe.3 Sun Jan 6 02:13:16 2019 (r342807) @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 10, 2018 +.Dd August 31, 2018 .Dt LIBBE 3 .Os .Sh NAME @@ -111,7 +111,7 @@ .Ft int .Fn be_validate_snap "libbe_handle_t *hdl" "const char *snap" .Pp -.Ft bool +.Ft int .Fn be_exists "libbe_handle_t *hdl" "char *be_name" .Pp .Ft int @@ -222,7 +222,12 @@ snapshot. .Pp The .Fn be_rename -function renames a boot environment. +function renames a boot environment without unmounting it, as if renamed with +the +.Fl u +argument were passed to +.Nm zfs +.Cm rename .Pp The .Fn be_activate @@ -267,6 +272,9 @@ If .Fa result is not .Dv NULL , +it should be large enough to accommodate +.Dv BE_MAXPATHLEN +including the null terminator. the final mount point will be copied into it. Setting the .Dv BE_MNT_FORCE @@ -328,7 +336,9 @@ environment name into .Pp The .Fn be_validate_name -function will validate the given boot environment name. +function will validate the given boot environment name for both length +restrictions as well as valid character restrictions. +This function does not set the internal library error state. .Pp The .Fn be_validate_snap @@ -342,6 +352,8 @@ The function will check whether the given boot environment exists and has a mountpoint of .Pa / . +This function does not set the internal library error state, but will return +the appropriate error. .Pp The .Fn be_export @@ -434,7 +446,7 @@ BE_ERR_DESTROYMNT, BE_ERR_BADPATH, BE_ERR_PATHBUSY, BE_ERR_PATHLEN, -BE_ERR_INVORIGIN, +BE_ERR_BADMOUNT, BE_ERR_NOORIGIN, BE_ERR_MOUNTED, BE_ERR_NOMOUNT, @@ -455,9 +467,3 @@ were written as a 2017 Google Summer of Code project w as a mentor. Later work was done by .An Kyle Evans Aq Mt kevans@FreeBSD.org . -.Sh BUGS -The -.Fn be_import -function does not destroy the temporary boot environment it creates for import, -because the snapshot created to do the import may not be deleted since it is the -origin of the new boot environment. Modified: stable/11/sbin/Makefile ============================================================================== --- stable/11/sbin/Makefile Sun Jan 6 02:12:55 2019 (r342806) +++ stable/11/sbin/Makefile Sun Jan 6 02:13:16 2019 (r342807) @@ -87,6 +87,7 @@ SUBDIR.${MK_PF}+= pfctl SUBDIR.${MK_PF}+= pflogd SUBDIR.${MK_QUOTAS}+= quotacheck SUBDIR.${MK_ROUTED}+= routed +SUBDIR.${MK_ZFS}+= bectl SUBDIR.${MK_ZFS}+= zfsbootcfg SUBDIR.${MK_TESTS}+= tests Modified: stable/11/sbin/bectl/Makefile ============================================================================== --- head/sbin/bectl/Makefile Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/sbin/bectl/Makefile Sun Jan 6 02:13:16 2019 (r342807) @@ -13,7 +13,6 @@ LIBADD+= util CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libzfs/common CFLAGS+= -I${SRCTOP}/sys/cddl/compat/opensolaris CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common -CFLAGS+= -I${SRCTOP}/cddl/contrib/opensolaris/lib/libnvpair CFLAGS+= -DNEED_SOLARIS_BOOLEAN Modified: stable/11/sbin/bectl/bectl.8 ============================================================================== --- head/sbin/bectl/bectl.8 Sun Aug 12 00:00:13 2018 (r337664) +++ stable/11/sbin/bectl/bectl.8 Sun Jan 6 02:13:16 2019 (r342807) @@ -18,7 +18,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 10, 2018 +.Dd August 24, 2018 .Dt BECTL 8 .Os .Sh NAME @@ -26,130 +26,137 @@ .Nd Utility to manage Boot Environments on ZFS .Sh SYNOPSIS .Nm -activate +.Cm activate .Op Fl t -.Ao Ar beName Ac +.Ar beName .Nm -create +.Cm create .Op Fl r -.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot -.Ao Ar beName Ac +.Op Fl e Brq Ar nonActiveBe | beName@snapshot +.Ar beName .Nm -create +.Cm create .Op Fl r -.Ao Ar beName@snapshot Ac +.Ar beName@snapshot .Nm -destroy +.Cm destroy .Op Fl F -.Ao Ar beName | beName@snapshot Ac +.Brq Ar beName | beName@snapshot .Nm -export -.Ao Ar sourceBe Ac +.Cm export +.Ar sourceBe .Nm -import -.Ao Ar targetBe Ac +.Cm import +.Ar targetBe .Nm -jail -.Oo Fl o Ar key Ns = Ns Ar value | Fl u Ar key Oc Ns ... -.Ao Ar jailID | jailName Ac -.Ao Ar bootenv Ac +.Cm jail +.Brq Fl b | Fl U +.Oo Bro Fl o Ar key Ns = Ns Ar value | Fl u Ar key Brc Oc Ns ... +.Brq Ar jailID | jailName +.Ar bootenv +.Op Ar utility Op Ar argument ... .Nm -list -.Op Fl a -.Op Fl D -.Op Fl H -.Op Fl s +.Cm list +.Op Fl DHas .Nm -mount -.Ao Ar beName Ac +.Cm mount +.Ar beName .Op mountpoint .Nm -rename -.Ao Ar origBeName Ac -.Ao Ar newBeName Ac +.Cm rename +.Ar origBeName +.Ar newBeName .Nm -{ ujail | unjail } -.Ao Ar jailID | jailName Ac -.Ao Ar bootenv Ac +.Brq Cm ujail | unjail +.Brq Ar jailID | jailName +.Ar bootenv .Nm -{ umount | unmount } +.Brq Cm umount | unmount .Op Fl f -.Ao Ar beName Ac +.Ar beName .Sh DESCRIPTION The .Nm -command is used to setup and interact with ZFS boot environments, which are bootable clones of datasets. +command is used to setup and interact with ZFS boot environments, which are +bootable clones of datasets. .Pp .Em Boot Environments -allows the system to be upgraded, while preserving the old system environment in a separate ZFS dataset. +allows the system to be upgraded, while preserving the old system environment in +a separate ZFS dataset. .Sh COMMANDS The following commands are supported by .Nm : .Bl -tag -width activate -.It Ic activate +.It Xo +.Cm activate .Op Fl t -.Ar -.Pp +.Ar beName +.Xc Activate the given .Ar beName as the default boot filesystem. If the .Op Fl t flag is given, this takes effect only for the next boot. -.It Ic create +.It Xo +.Cm create .Op Fl r -.Op Fl e Ar nonActiveBe | Fl e Ar beName@snapshot -.Ao Ar beName Ac -.Pp +.Op Fl e Brq Ar nonActiveBe | beName@snapshot +.Ar beName +.Xc Creates a new boot environment named .Ar beName . -If the -e param is specified, the new environment will be cloned from the given -.Ar nonActiveBe | Ar beName@snapshot . If the -.Op Fl r +.Fl e +argument is specified, the new environment will be cloned from the given +.Brq Ar nonActiveBe | Ar beName@snapshot . +If the +.Fl r flag is given, a recursive boot environment will be made. -.It Ic create +.It Xo +.Cm create .Op Fl r -.Ao Ar beName@snapshot Ac -.Pp +.Ar beName@snapshot +.Xc Creates a snapshot of the existing boot environment named .Ar beName . If the -.Op Fl r +.Fl r flag is given, a recursive boot environment will be made. -.It Ic destroy +.It Xo +.Cm destroy .Op Fl F -.Ao Ar beName | beName@snapshot Ac -.Pp +.Brq Ar beName | beName@snapshot +.Xc Destroys the given .Ar beName boot environment or .Ar beName@snapshot -snapshot. +snapshot without confirmation, unlike in +.Nm beadm . Specifying .Fl F will automatically unmount without confirmation. -.It Ic export -.Ao Ar sourceBe Ac -.Pp +.It Cm export Ar sourceBe Export .Ar sourceBe to .Dv stdout . .Dv stdout must be piped or redirected to a file. -.It Ic import -.Ao Ar targetBe Ac -.Pp +.It Cm import Ar targetBe Import .Ar targetBe from .Dv stdin . -.It Ic jail -.Oo Fl o Ar key Ns = Ns Ar value | Fl u Ar key Oc Ns ... -.Ao Ar jailID | jailName Ac +.It Xo +.Cm jail +.Brq Fl b | Fl U +.Oo Bro Fl o Ar key Ns = Ns Ar value | Fl u Ar key Brc Oc Ns ... +.Brq Ar jailID | jailName .Ao Ar bootenv Ac -.Pp +.Op Ar utility Op Ar argument ... +.Xc Creates a jail of the given boot environment. Multiple .Fl o @@ -161,7 +168,27 @@ will set a jail parameter, and .Fl u will unset a jail parameter. .Pp +By default, jails are created in interactive mode and +.Pa /bin/sh +is +executed within the jail. +If +.Ar utility +is specified, it will be executed instead of +.Pa /bin/sh . +The jail will be destroyed and the boot environment unmounted when the command +finishes executing, unless the +.Fl U +argument is specified. +.Pp The +.Fl b +argument enables batch mode, thereby disabling interactive mode. +The +.Fl U +argument will be ignored in batch mode. +.Pp +The .Va name , .Va host.hostname , and @@ -172,66 +199,59 @@ below, if they have been overwritten by .Fl o . .Pp All -.Ar key , -.Ar value +.Ar key Ns = Ns Ar value pairs are interpreted as jail parameters as described in .Xr jail 8 . The following default parameters are provided: -.Bl -tag -width -indent -.It Va allow.mount Ns = Ns Ar true -.It Va allow.mount.devfs Ns = Ns Ar true -.It Va enforce_statfs Ns = Ns Ar 1 -.It Va name Ns = Ns Ar bootenv -.It Va host.hostname Ns = Ns Ar bootenv -.It Va path *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***