Date: Mon, 4 Sep 2017 13:22:24 GMT From: kneitinger@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r326784 - in soc2017/kneitinger/libbe-head: lib/libbe sbin/be Message-ID: <201709041322.v84DMOfu054957@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kneitinger Date: Mon Sep 4 13:22:23 2017 New Revision: 326784 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=326784 Log: Mass August commit. Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.c soc2017/kneitinger/libbe-head/lib/libbe/be.h soc2017/kneitinger/libbe-head/lib/libbe/be_access.c soc2017/kneitinger/libbe-head/lib/libbe/be_info.c soc2017/kneitinger/libbe-head/lib/libbe/libbe.3 soc2017/kneitinger/libbe-head/sbin/be/be.c Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be.c Mon Sep 4 10:08:42 2017 (r326783) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.c Mon Sep 4 13:22:23 2017 (r326784) @@ -34,6 +34,7 @@ #include <libgen.h> #include <libzfs_core.h> #include <stdio.h> +#include <stdlib.h> #include <time.h> #include <unistd.h> @@ -49,7 +50,7 @@ { char buf[BE_MAXPATHLEN]; struct stat sb; - dev_t root_dev; + dev_t root_dev, boot_dev; libbe_handle_t *lbh; char *pos; @@ -59,13 +60,17 @@ if (stat("/", &sb) != 0) { return (NULL); } + root_dev = sb.st_dev; if (stat("/boot", &sb) != 0) { return (NULL); } - if (root_dev != sb.st_dev) { + boot_dev = sb.st_dev; + + if (root_dev != boot_dev) { + fprintf(stderr, "/ and /boot not on same device, quitting\n"); return (NULL); } @@ -134,28 +139,82 @@ int err = BE_ERR_SUCCESS; - snprintf(path, BE_MAXPATHLEN, "%s/%s", lbh->root, name); + be_root_concat(lbh, name, path); + printf("path: %s\n", path); if (!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_DATASET)) { return (set_error(lbh, BE_ERR_NOENT)); } - fs = zfs_open(lbh->lzh, p, ZFS_TYPE_DATASET); - - if (strcmp(path, lbh->active) != 0) { + if (strcmp(path, lbh->active) == 0) { return (set_error(lbh, BE_ERR_DESTROYACT)); } + fs = zfs_open(lbh->lzh, p, ZFS_TYPE_DATASET); + if ((mounted = zfs_is_mounted(fs, &p)) && !(force)) { return (set_error(lbh, BE_ERR_DESTROYMNT)); } - // TODO: check dependants + // TODO: account for "force" option by unmounting + + // TODO: convert this to use zfs_iter_children first for deep bes + if ((err = zfs_destroy(fs, false)) != 0) { + fprintf(stderr, "delete failed\n"); + } + + return (err); +} + + +int +be_snapshot(libbe_handle_t *lbh, char *source, char *snap_name, char *result) +{ + char buf[BE_MAXPATHLEN]; + time_t rawtime; + int len, err; + + if (!be_exists(lbh, source)) { + return (BE_ERR_NOENT); + } + + be_root_concat(lbh, source, buf); + + if (snap_name != NULL) { + strcat(buf, "@"); + strcat(buf, snap_name); + if (result != NULL) { + snprintf(result, BE_MAXPATHLEN, "%s@%s", source, + snap_name); + } + } else { + time(&rawtime); + len = strlen(buf); + strftime(buf + len, BE_MAXPATHLEN - len, + "@%F-%T", localtime(&rawtime)); + if (result != NULL) { + strcpy(result, strrchr(buf, '/') + 1); + } + } + + if (err = zfs_snapshot(lbh->lzh, buf, false, NULL) != 0) { + switch (err) { + case EZFS_INVALIDNAME: + return (set_error(lbh, BE_ERR_INVALIDNAME)); + + default: + // TODO: elaborate return codes + return (set_error(lbh, BE_ERR_UNKNOWN)); + } + } - return (0); + return (BE_ERR_SUCCESS); } +// TODO: should be rewritten to just call be_create_from_existing() with +// the current bootenv! + /* * Create the boot environment specified by the name parameter */ @@ -167,6 +226,7 @@ char snap_name[BE_MAXPATHLEN]; time_t rawtime; zfs_handle_t *snap_hdl; + nvlist_t *props; if (be_validate_name(lbh, name)) { return (set_error(lbh, BE_ERR_INVALIDNAME)); @@ -176,13 +236,6 @@ return (set_error(lbh, err)); } - pos = - snprintf(be_path, BE_MAXPATHLEN, "%s/%s", be_root_path(lbh), name); - - if ((pos < 0) || (pos >= BE_MAXPATHLEN)) { - err = set_error(lbh, BE_ERR_PATHLEN); - } - if (zfs_dataset_exists(lbh->lzh, be_path, ZFS_TYPE_DATASET)) { err = set_error(lbh, BE_ERR_EXISTS); return (err); @@ -190,6 +243,7 @@ time(&rawtime); + // TODO: strcat! pos = snprintf(snap_name, BE_MAXPATHLEN, "%s", be_active_path(lbh)); strftime(snap_name + pos, BE_MAXPATHLEN - pos, "@%F-%T", localtime(&rawtime)); @@ -212,6 +266,11 @@ return (set_error(lbh, BE_ERR_ZFSOPEN)); } + nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); + nvlist_add_string(props, "canmount", "noauto"); + nvlist_add_string(props, "mountpoint", "/"); + + if (err = zfs_clone(snap_hdl, be_path, NULL)) { switch (err) { case EZFS_SUCCESS: @@ -223,6 +282,8 @@ } } + nvlist_free(props); + zfs_close(snap_hdl); return (set_error(lbh, err)); @@ -233,19 +294,23 @@ * Create the boot environment from pre-existing snapshot */ int -be_create_from_existing(libbe_handle_t *lbh, char *name, char *snap) +be_create_from_existing_snap(libbe_handle_t *lbh, char *name, char *snap) { - int err, pos; + int err; char be_path[BE_MAXPATHLEN]; - char snap_name[BE_MAXPATHLEN]; - time_t rawtime; + char snap_path[BE_MAXPATHLEN]; zfs_handle_t *snap_hdl; + nvlist_t *props; if (err = be_validate_name(lbh, name)) { return (set_error(lbh, err)); } - if (err = be_validate_snap(lbh, snap)) { + if (err = be_root_concat(lbh, snap, snap_path)) { + return (set_error(lbh, err)); + } + + if (err = be_validate_snap(lbh, snap_path)) { return (set_error(lbh, err)); } @@ -257,10 +322,16 @@ return (set_error(lbh, BE_ERR_EXISTS)); } + if ((snap_hdl = + zfs_open(lbh->lzh, snap_path, ZFS_TYPE_SNAPSHOT)) == NULL) { + return (set_error(lbh, BE_ERR_ZFSOPEN)); + } - snap_hdl = zfs_open(lbh->lzh, snap, ZFS_TYPE_SNAPSHOT); + nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); + nvlist_add_string(props, "canmount", "noauto"); + nvlist_add_string(props, "mountpoint", "/"); - if (err = zfs_clone(snap_hdl, be_path, NULL)) { + if (err = zfs_clone(snap_hdl, be_path, props)) { switch (err) { case EZFS_SUCCESS: err = BE_ERR_SUCCESS; @@ -271,6 +342,7 @@ } } + nvlist_free(props); zfs_close(snap_hdl); return (set_error(lbh, err)); @@ -278,6 +350,36 @@ /* + * Create a copy of an existing boot environment + */ +int +be_create_from_existing(libbe_handle_t *lbh, char *name, char *old) +{ + int err; + char buf[BE_MAXPATHLEN]; + + + long int snap_num = random(); + + be_root_concat(lbh, old, buf); + snprintf(buf + strlen(buf), BE_MAXPATHLEN, "@%ld", snap_num); + + if (err = zfs_snapshot(lbh->lzh, buf, true, NULL)) { + // TODO correct error + return (-1); + } + + snprintf(buf, BE_MAXPATHLEN, "%s@%ld", old, snap_num); + + err = be_create_from_existing_snap(lbh, name, buf); + + // TODO: delete snap + + return (err); +} + + +/* * Verifies that a snapshot has a valid name, exists, and has a mountpoint of * '/'. Returns BE_ERR_SUCCESS (0), upon success, or the relevant BE_ERR_* upon * failure. Does not set the internal library error state. @@ -289,7 +391,7 @@ char buf[BE_MAXPATHLEN]; char *delim_pos; char *mountpoint; - int err = 0; + int err = BE_ERR_SUCCESS; if (strlen(snap_name) >= BE_MAXPATHLEN) { return (BE_ERR_PATHLEN); @@ -326,7 +428,7 @@ zfs_close(zfs_hdl); - return (BE_ERR_SUCCESS); + return (err); } @@ -455,11 +557,17 @@ int be_export(libbe_handle_t *lbh, char *bootenv, int fd) { + char snap_name[BE_MAXPATHLEN]; char buf[BE_MAXPATHLEN]; zfs_handle_t *zfs; int err; - be_root_concat(lbh, bootenv, buf); + if (err = be_snapshot(lbh, bootenv, NULL, snap_name)) { + // TODO error handle + return (-1); + } + + be_root_concat(lbh, snap_name, buf); if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL) { return (BE_ERR_ZFSOPEN); @@ -474,19 +582,245 @@ be_import(libbe_handle_t *lbh, char *bootenv, int fd) { char buf[BE_MAXPATHLEN]; - int err; + time_t rawtime; + nvlist_t *props; + zfs_handle_t *zfs; + int err, len; - if (err = be_root_concat(lbh, bootenv, buf)) { + // TODO: this is a very likely name for someone to already have used + if (err = be_root_concat(lbh, "be_import_temp", buf)) { // TODO error handle return (-1); } + time(&rawtime); + len = strlen(buf); + strftime(buf + len, BE_MAXPATHLEN - len, + "@%F-%T", localtime(&rawtime)); + + // lzc_receive(SNAPNAME, PROPS, ORIGIN, FORCE, fd)) { if (err = lzc_receive(buf, NULL, NULL, false, fd)) { /* TODO: go through libzfs_core's recv_impl and find returned - * errors and set appropriate BE_ERR */ + * errors and set appropriate BE_ERR + * edit: errors are not in libzfs_core, my assumption is + * that they use libzfs errors + * note: 17 is err for dataset already existing */ + return (err); + } + + if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL) { + // TODO correct error + return (-1); + } + + nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); + nvlist_add_string(props, "canmount", "noauto"); + nvlist_add_string(props, "mountpoint", "/"); + + be_root_concat(lbh, bootenv, buf); + + err = zfs_clone(zfs, buf, props); + zfs_close(zfs); + + nvlist_free(props); + + // TODO: recursively delete be_import_temp dataset + + return (err); +} + + +int +be_add_child(libbe_handle_t *lbh, char *child_path, bool cp_if_exists) +{ + char active[BE_MAXPATHLEN]; + char buf[BE_MAXPATHLEN]; + nvlist_t *props; + zfs_handle_t *zfs; + struct stat sb; + int err; + + /* Require absolute paths */ + if (*child_path != '/') { + /* TODO: create appropriate error */ + return (-1); + } + + strncpy(active, be_active_path(lbh), BE_MAXPATHLEN); + strcpy(buf, active); + + /* Create non-mountable parent dataset(s) */ + char *s = child_path; + for (char *p; (p = strchr(s+1, '/')) != NULL; s = p) { + size_t len = p - s; + strncat(buf, s, len); + + nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); + nvlist_add_string(props, "canmount", "off"); + nvlist_add_string(props, "mountpoint", "none"); + zfs_create(lbh->lzh, buf, ZFS_TYPE_DATASET, props); + nvlist_free(props); + } + + + /* Path does not exist as a descendent of / yet */ + int pos = strlen(active); + + /* TODO: Verify that resulting str is less than BE_MAXPATHLEN */ + strncpy(&active[pos], child_path, BE_MAXPATHLEN-pos); + + + if (stat(child_path, &sb) != 0) { + /* Verify that error is ENOENT */ + if (errno != 2) { + /* TODO: create appropriate error */ + return (-1); + } + + nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); + nvlist_add_string(props, "canmount", "noauto"); + nvlist_add_string(props, "mountpoint", child_path); + + // create + if (err = + zfs_create(lbh->lzh, active, ZFS_TYPE_DATASET, props)) { + /* TODO handle error */ + return (-1); + } + nvlist_free(props); + + if ((zfs = + zfs_open(lbh->lzh, active, ZFS_TYPE_DATASET)) == NULL) { + /* TODO handle error */ + return (-1); + } + + // set props + if (err = zfs_prop_set(zfs, "canmount", "noauto")) { + /* TODO handle error */ + return (-1); + } + } else if (cp_if_exists) { + /* Path is already a descendent of / and should be copied */ + + + + // TODO + /* + * Establish if the existing path is a zfs dataset or just + * the subdirectory of one + */ + + + // TODO: use mktemp + long int snap_name = random(); + + snprintf(buf, BE_MAXPATHLEN, "%s@%ld", child_path, snap_name); + + if (err = zfs_snapshot(lbh->lzh, buf, false, NULL)) { + // TODO correct error + return (-1); + } + + // clone + if ((zfs = + zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL) { + // TODO correct error + return (-1); + } + + if (err = zfs_clone(zfs, active, NULL)) { + // TODO correct error + return (-1); + } + + + // set props + } else { + /* TODO: error code for exists, but not cp? */ return (-1); } + return (BE_ERR_SUCCESS); } + + +int +be_activate(libbe_handle_t *lbh, char *bootenv, bool temporary) +{ + char be_path[BE_MAXPATHLEN]; + char buf[BE_MAXPATHLEN]; + zpool_handle_t *zph; + uint64_t pool_guid; + uint64_t vdev_guid; + int zfs_fd; + int len; + 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 (temporary) { + // TODO: give proper attribution to author(s) of zfsbootcfg + // for this snippet + + if (kenv(KENV_GET, "vfs.zfs.boot.primary_pool", buf, + sizeof(buf)) <= 0) { + return (1); + } + pool_guid = strtoumax(buf, NULL, 10); + if (pool_guid == 0) { + return (1); + } + + if (kenv(KENV_GET, "vfs.zfs.boot.primary_vdev", buf, + sizeof(buf)) <= 0) { + return (1); + } + vdev_guid = strtoumax(buf, NULL, 10); + if (vdev_guid == 0) { + return (1); + } + + /* Expected format according to zfsbootcfg(8) man */ + strcpy(buf, "zfs:"); + strcat(buf, be_path); + strcat(buf, ":"); + + if (zpool_nextboot(lbh->lzh, pool_guid, vdev_guid, buf) != 0) { + perror("ZFS_IOC_NEXTBOOT failed"); + return (1); + } + + return (BE_ERR_SUCCESS); + } else { + /* Obtain bootenv zpool */ + strncpy(buf, be_path, BE_MAXPATHLEN); + *(strchr(buf, '/')) = '\0'; + + if ((zph = zpool_open(lbh->lzh, buf)) == NULL) { + // TODO: create error for this + return (-1); + } + printf("asdf\n"); + + err = zpool_set_prop(zph, "bootfs", be_path); + zpool_close(zph); + + switch (err) { + case 0: + return (BE_ERR_SUCCESS); + + default: + // TODO correct errors + return (-1); + } + } +} Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.h ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be.h Mon Sep 4 10:08:42 2017 (r326783) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.h Mon Sep 4 13:22:23 2017 (r326784) @@ -31,7 +31,7 @@ #include <stdbool.h> -#define BE_MAXPATHLEN ZFS_MAX_DATASET_NAME_LEN +#define BE_MAXPATHLEN 512 typedef struct libbe_handle libbe_handle_t; @@ -65,9 +65,13 @@ /* nvlist_t *be_get_bootenv_props(libbe_handle_t *); */ +int be_activate(libbe_handle_t *, char *, bool); + /* Bootenv creation functions */ int be_create(libbe_handle_t *, char *); int be_create_from_existing(libbe_handle_t *, char *, char *); +int be_create_from_existing_snap(libbe_handle_t *, char *, char *); +int be_snapshot(libbe_handle_t *, char *, char *, char *); /* Bootenv manipulation functions */ int be_rename(libbe_handle_t *, char *, char *); @@ -87,7 +91,7 @@ BE_MNT_DEEP = 1 << 1, } be_mount_opt_t; -int be_mount(libbe_handle_t *, char *, char *, int); +int be_mount(libbe_handle_t *, char *, char *, int, char *); int be_unmount(libbe_handle_t *, char *, int); /* Error related functions: be_error.c */ @@ -104,4 +108,6 @@ int be_export(libbe_handle_t *, char *, int fd); int be_import(libbe_handle_t *, char *, int fd); +int be_add_child(libbe_handle_t *, char *, bool); + #endif /* _LIBBE_H */ Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_access.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_access.c Mon Sep 4 10:08:42 2017 (r326783) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_access.c Mon Sep 4 13:22:23 2017 (r326784) @@ -33,21 +33,24 @@ * usage */ int -be_mount(libbe_handle_t *lbh, char *bootenv, char *mountpoint, int flags) +be_mount(libbe_handle_t *lbh, char *bootenv, char *mountpoint, int flags, + char *result_loc) { char be[BE_MAXPATHLEN]; + char mnt_temp[BE_MAXPATHLEN]; zfs_handle_t *zfs_hdl; char *path; int mntflags; int err; - // TODO: handle deep bes - if (err = be_root_concat(lbh, bootenv, be)) { return (set_error(lbh, err)); } // TODO: make sure it exists (in a be_exists fn)! + if (!be_exists(lbh, bootenv)) { + return (set_error(lbh, BE_ERR_NOENT)); + } if (is_mounted(lbh->lzh, be, &path)) { return (set_error(lbh, BE_ERR_MOUNTED)); @@ -56,15 +59,27 @@ mntflags = (flags & BE_MNT_FORCE) ? MNT_FORCE : 0; + if (mountpoint == NULL) { + strcpy(mnt_temp, "/tmp/be_mount.XXXX"); + if (mkdtemp(mnt_temp) == NULL) { + // TODO: create error for this + return (set_error(lbh, BE_ERR_UNKNOWN)); + } + } + char opt = '\0'; - if (err = zmount(be, mountpoint, mntflags, MNTTYPE_ZFS, - NULL, 0, &opt, 1)) { + if (err = zmount(be, (mountpoint == NULL) ? mnt_temp : mountpoint, + mntflags, MNTTYPE_ZFS, NULL, 0, &opt, 1)) { // TODO: zmount returns the nmount error, look into what kind of // errors we can report from that return (set_error(lbh, BE_ERR_UNKNOWN)); } - return (set_error(lbh, BE_ERR_SUCCESS)); + if (result_loc != NULL) { + strcpy(result_loc, mountpoint == NULL ? mnt_temp : mountpoint); + } + + return (BE_ERR_SUCCESS); } Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_info.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Mon Sep 4 10:08:42 2017 (r326783) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Mon Sep 4 13:22:23 2017 (r326784) @@ -235,6 +235,11 @@ bool be_exists(libbe_handle_t *lbh, char *be) { - // TODO - return (true); + char buf[BE_MAXPATHLEN]; + + be_root_concat(lbh, be, buf); + + // TODO: check mountpoint prop and see if its /, AND that result with below + // expression + return (zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_DATASET)); } Modified: soc2017/kneitinger/libbe-head/lib/libbe/libbe.3 ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/libbe.3 Mon Sep 4 10:08:42 2017 (r326783) +++ soc2017/kneitinger/libbe-head/lib/libbe/libbe.3 Mon Sep 4 13:22:23 2017 (r326784) @@ -0,0 +1,192 @@ +.\" +.\" Copyright (c) 2017 Kyle Kneitinger +.\" 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. +.\" +.\" This manual page is based on the mp(3X) manual page from Sun Release +.\" 4.1, dated 7 September 1989. It's an old, crufty, and relatively ugly +.\" manual page, but it does document what appears to be the "traditional" +.\" libmp interface. +.\" +.\" $FreeBSD: soc2017/kneitinger/libbe-head/lib/libmp/libmp.3 189135 2009-02-26 21:43:15Z ed $ +.\" +.Dd August 28, 2017 +.Dt LIBBE 3 +.Os +.Sh NAME +.Nm libbe +.Nd library for creating, destroying and modifying ZFS boot environments. +.Sh SYNOPSIS +.In be.h +.Pp +Function prototypes are given in the main body of the text. +.Pp +Applications using this interface must be linked with +.Fl l Ns Ar be +.Sh DESCRIPTION +.Pp +.Nm +interfaces with libzfs to provide a set of functions for various operations +regarding ZFS boot environments including "deep" boot environments in which +a boot environments has child datasets. +.Pp +A context structure is passed to each function, allowing for a small amount +of state to be retained, such as errors from previous operations. +.\" TODO: describe break on err functionality +.Pp +.Ft "libbe_handle_t *" Ns +.Fn libbe_init "void" ; +.Pp +.Ft void +.Fn libbe_close "libbe_handle_t *" ; +.Pp +.Ft "const char *" Ns +.Fn be_active_name "libbe_handle_t *" ; +.Pp +.Ft "const char *" Ns +.Fn be_active_path "libbe_handle_t *" ; +.Pp +.Ft "const char *" Ns +.Fn be_root_path "libbe_handle_t *" ; +.Pp +.Ft "nvlist_t *" Ns +.Fn libbe_handle_t "libbe_handle_t " ; +.Pp +.Ft int +.Fn be_create "libbe_handle_t *, char *" ; +.Pp +.Ft int +.Fn be_create_from_existing "libbe_handle_t *, char *, char *" ; +.Pp +.Ft int +.Fn be_rename "libbe_handle_t *, char *, char *" ; +.Pp +.\" TODO: Write up of destroy options +.\" typedef enum { +.\" BE_DESTROY_FORCE = 1 << 0, +.\" } be_destroy_opt_t; +.Ft int +.Fn be_destroy "libbe_handle_t *, char *, int" ; +.Pp +.\" TODO: Write up of mount options +.\" typedef enum { +.\" BE_MNT_FORCE = 1 << 0, +.\" BE_MNT_DEEP = 1 << 1, +.\" } be_mount_opt_t; +.Ft int +.Fn be_mount "libbe_handle_t *, char *, char *, int" ; +.Pp +.Ft int +.Fn be_unmount "libbe_handle_t *, char *, int" ; +.Pp +.Ft int +.Fn libbe_errno "libbe_handle_t *" ; +.Pp +.Ft "const char *" Ns +.Fn libbe_error_description "libbe_handle_t *" ; +.Pp +.Ft void +.Fn libbe_print_on_error "libbe_handle_t *, bool" ; +.Pp +.Ft int +.Fn be_root_concat "libbe_handle_t *, char *, char *" ; +.Pp +.Ft int +.Fn be_validate_name "libbe_handle_t *, char *" ; +.Pp +.Ft int +.Fn be_validate_snap "libbe_handle_t *, char *" ; +.Pp +.Ft bool +.Fn be_exists "libbe_handle_t *, char *" ; +.Pp +.Ft int +.Fn be_export "libbe_handle_t *, char *, int fd" ; +.Pp +.Ft int +.Fn be_import "libbe_handle_t *, char *, int fd" ; +.Pp +.Ft int +.Fn be_add_child "libbe_handle_t *, char *, bool" ; +.Pp +.\" .Ft void +.\" .Fn mp_mfree "MINT *mp" ; +.\" .Bd -ragged -offset indent +.\" .Fn mp_itom +.\" returns an +.\" .Vt MINT +.\" with the value of +.\" .Fa n . +.\" .Fn mp_xtom +.\" returns an +.\" .Vt MINT +.\" with the value of +.\" .Fa s , +.\" which is treated to be in hexadecimal. +.\" The return values from +.\" .Fn mp_itom +.\" and +.\" .Fn mp_xtom +.\" must be released with +.\" .Fn mp_mfree +.\" when they are no longer needed. +.\" .Fn mp_mtox +.\" returns a null-terminated hexadecimal string having the value of +.\" .Fa mp ; +.\" its return value must be released with +.\" .Fn free +.\" .Pq Xr free 3 +.\" when it is no longer needed. +.\" .Ed +.\" .Pp +.Sh DIAGNOSTICS +Upon error, one of the following values will be returned. +.\" TODO: make each entry on its own line. +.Bd -ragged -offset indent +BE_ERR_SUCCESS, +BE_ERR_INVALIDNAME, +BE_ERR_EXISTS, +BE_ERR_NOENT, +BE_ERR_PERMS, +BE_ERR_DESTROYACT, +BE_ERR_DESTROYMNT, +BE_ERR_PATHLEN, +BE_ERR_INVORIGIN, +BE_ERR_NOORIGIN, +BE_ERR_MOUNTED, +BE_ERR_NOMOUNT, +BE_ERR_ZFSOPEN, +BE_ERR_ZFSCLONE, +BE_ERR_UNKNOWN +.Ed +.Sh SEE ALSO +.Xr be 1 , +.Sh HISTORY +.Nm +and it's corresponding command, +.Xr be 3 , +were written as a 2017 Google Summer of Code project with Allan Jude serving +as a mentor. +.\" TODO: update when implementation complete. +.\" .Sh BUGS + Modified: soc2017/kneitinger/libbe-head/sbin/be/be.c ============================================================================== --- soc2017/kneitinger/libbe-head/sbin/be/be.c Mon Sep 4 10:08:42 2017 (r326783) +++ soc2017/kneitinger/libbe-head/sbin/be/be.c Mon Sep 4 13:22:23 2017 (r326784) @@ -26,6 +26,10 @@ * SUCH DAMAGE. */ +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/mount.h> +#include <errno.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -40,6 +44,7 @@ static int be_cmd_destroy(int argc, char *argv[]); static int be_cmd_export(int argc, char *argv[]); static int be_cmd_import(int argc, char *argv[]); +static int be_cmd_init(int argc, char *argv[]); static int be_cmd_jail(int argc, char *argv[]); static int be_cmd_list(int argc, char *argv[]); static int be_cmd_mount(int argc, char *argv[]); @@ -57,12 +62,13 @@ fprintf(fp, "usage:\tbe ( -h | -? | subcommand [args...] )\n" "\tbe activate [-t] beName\n" - "\tbe create [-r] [-e nonActiveBe | -e beName@snapshot] beName\n" - "\tbe create [-r] beName@snapshot\n" + "\tbe create [-e nonActiveBe | -e beName@snapshot] beName\n" + "\tbe create beName@snapshot\n" "\tbe destroy [-F] beName | beName@snapshot⟩\n" "\tbe export sourceBe\n" "\tbe import targetBe\n" - "\tbe jail ⟨jailID | jailName⟩ bootenv\n" + "\tbe init (path)*\n" + "\tbe jail bootenv\n" "\tbe list [-a] [-D] [-H] [-s]\n" "\tbe mount beName [mountpoint]\n" "\tbe rename origBeName newBeName\n" @@ -84,17 +90,18 @@ static struct command_map_entry command_map[] = { - { "activate", be_cmd_activate }, - { "create", be_cmd_create }, - { "destroy", be_cmd_destroy }, - { "export", be_cmd_export }, - { "import", be_cmd_import }, - { "jail", be_cmd_jail }, - { "list", be_cmd_list }, - { "mount", be_cmd_mount }, - { "rename", be_cmd_rename }, - { "unjail", be_cmd_unjail }, - { "unmount", be_cmd_unmount }, + { "activate", be_cmd_activate }, + { "create", be_cmd_create }, + { "destroy", be_cmd_destroy }, + { "export", be_cmd_export }, + { "import", be_cmd_import }, + { "init", be_cmd_init }, + { "jail", be_cmd_jail }, + { "list", be_cmd_list }, + { "mount", be_cmd_mount }, + { "rename", be_cmd_rename }, + { "unjail", be_cmd_unjail }, + { "unmount", be_cmd_unmount }, }; static int @@ -116,7 +123,7 @@ static int be_cmd_activate(int argc, char *argv[]) { - int opt; + int err, opt; bool temp; char *bootenv; @@ -141,14 +148,26 @@ return (usage(false)); } - bootenv = argv[0]; /* activate logic goes here */ + if ((err = be_activate(be, argv[0], temp)) != 0) { + // TODO: more specific error msg based on err + printf("did not successfully activate boot environment %s\n", + argv[0]); + } else { + printf("successfully activated boot environment %s\n", argv[0]); + } - return (0); + if (temp) { + printf("for next boot\n"); + } + + return (err); } +// TODO: when only one arg is given, and it contains an "@" the this should +// create that snapshot static int be_cmd_create(int argc, char *argv[]) { @@ -159,14 +178,11 @@ existing = NULL; recursive = false; - while ((opt = getopt(argc, argv, "re:")) != -1) { + while ((opt = getopt(argc, argv, "e:")) != -1) { switch (opt) { case 'e': existing = optarg; break; - case 'r': - recursive = true; - break; default: fprintf(stderr, "be create: unknown option '-%c'\n", optopt); @@ -186,8 +202,12 @@ if (existing != NULL) { - err = be_create_from_existing(be, bootenv, existing); - // TODO: look at err and print useful message + if (strchr(existing, '@') != NULL) { + err = *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709041322.v84DMOfu054957>