From owner-svn-soc-all@freebsd.org Mon Jul 3 11:16:50 2017 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 859879E44F7 for ; Mon, 3 Jul 2017 11:16:50 +0000 (UTC) (envelope-from kneitinger@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 75BB2681E5 for ; Mon, 3 Jul 2017 11:16:50 +0000 (UTC) (envelope-from kneitinger@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.15.2/8.15.2) with ESMTP id v63BGotu078266 for ; Mon, 3 Jul 2017 11:16:50 GMT (envelope-from kneitinger@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id v63BGlKJ078238 for svn-soc-all@FreeBSD.org; Mon, 3 Jul 2017 11:16:47 GMT (envelope-from kneitinger@FreeBSD.org) Date: Mon, 3 Jul 2017 11:16:47 GMT Message-Id: <201707031116.v63BGlKJ078238@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to kneitinger@FreeBSD.org using -f From: kneitinger@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r324213 - in soc2017/kneitinger/libbe-head: lib/libbe sbin/be MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 03 Jul 2017 11:16:50 -0000 Author: kneitinger Date: Mon Jul 3 11:16:47 2017 New Revision: 324213 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=324213 Log: libbe(3): Refactor error reporting system & start work on bootenv destroy function Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.c soc2017/kneitinger/libbe-head/lib/libbe/be.h soc2017/kneitinger/libbe-head/lib/libbe/be_error.c soc2017/kneitinger/libbe-head/lib/libbe/be_impl.h soc2017/kneitinger/libbe-head/lib/libbe/be_info.c 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 Jul 3 10:24:49 2017 (r324212) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.c Mon Jul 3 11:16:47 2017 (r324213) @@ -43,24 +43,23 @@ libbe_init(void) { libbe_handle_t *lbh; - char buf[MAX_PATHLEN]; + char buf[MAXPATHLEN]; if ((lbh = calloc(1, sizeof(libbe_handle_t))) == NULL) { return (NULL); } - if ((lbh->lzh = libzfs_init()) == NULL) { free(lbh); return (NULL); } - libzfs_print_on_error(lbh->lzh, 1); + lbh->print_on_err = true; /* Obtain path to active boot environment */ - if ((kenv(KENV_GET, "zfs_be_active", buf, MAX_PATHLEN)) == -1) { + if ((kenv(KENV_GET, "zfs_be_active", buf, MAXPATHLEN)) == -1) { libzfs_fini(lbh->lzh); free(lbh); return (NULL); @@ -80,7 +79,7 @@ /* Obtain path to boot environment root */ - if ((kenv(KENV_GET, "zfs_be_root", buf, MAX_PATHLEN)) == -1) { + if ((kenv(KENV_GET, "zfs_be_root", buf, MAXPATHLEN)) == -1) { zfs_close(lbh->be_active); libzfs_fini(lbh->lzh); free(lbh); @@ -97,7 +96,6 @@ return (NULL); } - /* TODO: verify that /boot is mounted on the active be */ prop_list_builder(lbh); @@ -116,6 +114,50 @@ zfs_close(lbh->be_active); zfs_close(lbh->be_root); libzfs_fini(lbh->lzh); - /* TODO: clean up property list */ + prop_list_free(lbh); free(lbh); } + + +/* + * Destroy the boot environment specified by the name parameter + * Options are or'd together with the possible values: + * BE_DESTROY_FORCE : forces operation on mounted datasets + * + */ +int +be_destroy(libbe_handle_t *lbh, char *name, int options) +{ + zfs_handle_t *fs; + char path[MAXPATHLEN]; + char *p = path; + int mounted; + int force = options & BE_DESTROY_FORCE; + + int err = BE_ERR_SUCCESS; + + snprintf(path, MAXPATHLEN, "%s/%s", zfs_get_name(lbh->be_root), name); + + if(!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_DATASET)) { + err = set_error(lbh, BE_ERR_NOENT); + return (err); + } + + fs = zfs_open(lbh->lzh, p, ZFS_TYPE_DATASET); + + if(strcmp(path, zfs_get_name(lbh->be_active)) != 0) { + err = set_error(lbh, BE_ERR_DESTROYACT); + return (err); + } + + + //check mounted + if((mounted = zfs_is_mounted(fs, &p)) && !(force)) { + err = set_error(lbh, BE_ERR_DESTROYMNT); + return (err); + } + + // check dependants + + return (0); +} Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.h ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be.h Mon Jul 3 10:24:49 2017 (r324212) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.h Mon Jul 3 11:16:47 2017 (r324213) @@ -30,11 +30,22 @@ #define _LIBBE_H #include - -#define MAX_PATHLEN 512 +#include typedef struct libbe_handle libbe_handle_t; +typedef enum be_error { + BE_ERR_SUCCESS = 0, /* No error */ + BE_ERR_INVALIDNAME, /* invalid boot env name */ + BE_ERR_EXISTS, /* boot env name already taken */ + BE_ERR_NOENT, /* boot env doesn't exist */ + BE_ERR_PERMS, /* insufficient permissions */ + BE_ERR_DESTROYACT, /* cannot destroy active boot env */ + BE_ERR_DESTROYMNT, /* cannot destroy active boot env */ + BE_ERR_UNKNOWN, /* unknown error */ +} be_error_t; + + /* Library handling functions: be.c */ libbe_handle_t *libbe_init(void); void libbe_close(libbe_handle_t *); @@ -53,6 +64,9 @@ int be_rename(libbe_handle_t *, char *, char *); /* Bootenv removal functions */ + +#define BE_DESTROY_FORCE 1 + int be_destroy(libbe_handle_t *, char *, int); /* Bootenv mounting functions */ @@ -65,5 +79,6 @@ /* Error related functions: be_error.c */ int libbe_errno(libbe_handle_t *); const char *libbe_error_description(libbe_handle_t *); +void libbe_print_on_error(libbe_handle_t *, bool); #endif /* _LIBBE_H */ Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_error.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_error.c Mon Jul 3 10:24:49 2017 (r324212) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_error.c Mon Jul 3 11:16:47 2017 (r324213) @@ -44,14 +44,23 @@ { switch (lbh->error) { case BE_ERR_INVALIDNAME: - return ("invalid boot env name"); + return ("invalid boot environment name"); case BE_ERR_EXISTS: - return ("boot env name already taken"); + return ("boot environment name already taken"); + + case BE_ERR_NOENT: + return ("specified boot environment does not exist"); case BE_ERR_PERMS: return ("insufficient permissions"); + case BE_ERR_DESTROYACT: + return ("cannot destroy active boot environment"); + + case BE_ERR_DESTROYMNT: + return ("cannot destroy mounted boot env unless forced"); + case BE_ERR_UNKNOWN: return ("unknown error"); @@ -60,3 +69,24 @@ return ("no error"); } } + +void +libbe_print_on_error(libbe_handle_t *lbh, bool val) +{ + lbh->print_on_err = val; + libzfs_print_on_error(lbh->lzh, val); +} + +int +set_error(libbe_handle_t *lbh, be_error_t err) +{ + // TODO: should the old error be overwritten or no? + + lbh->error = err; + + if(lbh->print_on_err) { + fprintf(stderr, "%s\n", libbe_error_description(lbh)); + } + + return (err); +} Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_impl.h ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_impl.h Mon Jul 3 10:24:49 2017 (r324212) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_impl.h Mon Jul 3 11:16:47 2017 (r324213) @@ -30,14 +30,8 @@ #define _LIBBE_IMPL_H #include +#include "be.h" -typedef enum be_error { - BE_ERR_SUCCESS = 0, /* No error */ - BE_ERR_INVALIDNAME, /* invalid boot env name */ - BE_ERR_EXISTS, /* boot env name already taken */ - BE_ERR_PERMS, /* insufficient permissions */ - BE_ERR_UNKNOWN, /* unknown error */ -} be_error_t; struct libbe_handle { libzfs_handle_t *lzh; @@ -45,9 +39,12 @@ zfs_handle_t *be_active; be_error_t error; nvlist_t *list; + bool print_on_err; }; int prop_list_builder(libbe_handle_t *); void prop_list_free(libbe_handle_t *); +int set_error(libbe_handle_t *, be_error_t); + #endif /* _LIBBE_IMPL_H */ Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_info.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Mon Jul 3 10:24:49 2017 (r324212) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Mon Jul 3 11:16:47 2017 (r324213) @@ -70,6 +70,8 @@ nvlist_t * be_get_bootenv_props(libbe_handle_t *lbh) { + // TODO: Should there be a dirty flag that re-calcs the list if an op + // has changed it? return (lbh->list); } @@ -82,8 +84,13 @@ static int prop_list_builder_cb(zfs_handle_t *zfs_hdl, void *data) { + /* + * TODO: + * some system for defining constants for the nvlist keys + * error checking + */ + boolean_t mounted, active, nextboot; - /* TODO: what type for size? Number bytes as int or long? */ char buf[512]; @@ -159,6 +166,8 @@ /* * Updates the properties of each bootenv in the libbe handle * TODO: rename to be_proplist_update + * TODO: ensure that this is always consistent (run after adds, deletes, + * renames,etc */ int prop_list_builder(libbe_handle_t *lbh) @@ -179,9 +188,28 @@ return (0); } - +/* + * Frees property list and its children + */ void prop_list_free(libbe_handle_t *lbh) { - /* TODO */ + nvlist_t *be_list; + nvlist_t *prop_list; + + if((be_list = lbh->list) == 0) { + return; + } + + nvpair_t *be_pair = nvlist_next_nvpair(be_list, NULL); + + if(nvpair_value_nvlist(be_pair, &prop_list) == 0) { + nvlist_free(prop_list); + } + + while((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) { + if(nvpair_value_nvlist(be_pair, &prop_list) == 0) { + nvlist_free(prop_list); + } + } } Modified: soc2017/kneitinger/libbe-head/sbin/be/be.c ============================================================================== --- soc2017/kneitinger/libbe-head/sbin/be/be.c Mon Jul 3 10:24:49 2017 (r324212) +++ soc2017/kneitinger/libbe-head/sbin/be/be.c Mon Jul 3 11:16:47 2017 (r324213) @@ -476,6 +476,8 @@ be = libbe_init(); + libbe_print_on_error(be, true); + int rc = command_map[command_index].fn(argc-1, argv+1); libbe_close(be); From owner-svn-soc-all@freebsd.org Tue Jul 4 10:55:04 2017 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id D6655D8DD2B for ; Tue, 4 Jul 2017 10:55:04 +0000 (UTC) (envelope-from kneitinger@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C83EB76FEE for ; Tue, 4 Jul 2017 10:55:04 +0000 (UTC) (envelope-from kneitinger@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.15.2/8.15.2) with ESMTP id v64At4Xb072269 for ; Tue, 4 Jul 2017 10:55:04 GMT (envelope-from kneitinger@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id v64At296072186 for svn-soc-all@FreeBSD.org; Tue, 4 Jul 2017 10:55:02 GMT (envelope-from kneitinger@FreeBSD.org) Date: Tue, 4 Jul 2017 10:55:02 GMT Message-Id: <201707041055.v64At296072186@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to kneitinger@FreeBSD.org using -f From: kneitinger@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r324259 - soc2017/kneitinger/libbe-head/lib/libbe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Jul 2017 10:55:04 -0000 Author: kneitinger Date: Tue Jul 4 10:55:02 2017 New Revision: 324259 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=324259 Log: libbe(3): add be_create function Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.c soc2017/kneitinger/libbe-head/lib/libbe/be.h soc2017/kneitinger/libbe-head/lib/libbe/be_error.c soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be.c Tue Jul 4 07:07:08 2017 (r324258) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.c Tue Jul 4 10:55:02 2017 (r324259) @@ -26,11 +26,12 @@ * SUCH DAMAGE. */ -#include +#include #include #include #include #include +#include #include "be.h" #include "be_impl.h" @@ -55,9 +56,6 @@ return (NULL); } - lbh->print_on_err = true; - - /* Obtain path to active boot environment */ if ((kenv(KENV_GET, "zfs_be_active", buf, MAXPATHLEN)) == -1) { libzfs_fini(lbh->lzh); @@ -77,7 +75,6 @@ return (NULL); } - /* Obtain path to boot environment root */ if ((kenv(KENV_GET, "zfs_be_root", buf, MAXPATHLEN)) == -1) { zfs_close(lbh->be_active); @@ -123,7 +120,6 @@ * Destroy the boot environment specified by the name parameter * Options are or'd together with the possible values: * BE_DESTROY_FORCE : forces operation on mounted datasets - * */ int be_destroy(libbe_handle_t *lbh, char *name, int options) @@ -138,26 +134,126 @@ snprintf(path, MAXPATHLEN, "%s/%s", zfs_get_name(lbh->be_root), name); - if(!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_DATASET)) { + if (!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_DATASET)) { err = set_error(lbh, BE_ERR_NOENT); return (err); } fs = zfs_open(lbh->lzh, p, ZFS_TYPE_DATASET); - if(strcmp(path, zfs_get_name(lbh->be_active)) != 0) { + if (strcmp(path, zfs_get_name(lbh->be_active)) != 0) { err = set_error(lbh, BE_ERR_DESTROYACT); return (err); } - - //check mounted - if((mounted = zfs_is_mounted(fs, &p)) && !(force)) { + if ((mounted = zfs_is_mounted(fs, &p)) && !(force)) { err = set_error(lbh, BE_ERR_DESTROYMNT); return (err); } - // check dependants + // TODO: check dependants return (0); } + + +/* + * Create the boot environment specified by the name parameter + */ +int +be_create(libbe_handle_t *lbh, char *name) +{ + int err, pos; + char be_path[MAXPATHLEN]; + char snap_name[MAXPATHLEN]; + time_t rawtime; + zfs_handle_t *snap_hdl; + + if (!(be_valid_name(lbh, name))) { + err = set_error(lbh, BE_ERR_INVALIDNAME); + return (err); + } + + if (err = be_root_concat(lbh, name, be_path)) { + return (err); + } + + pos = snprintf(be_path, MAXPATHLEN, "%s/%s", be_root_path(lbh), name); + + if ((pos < 0) || (pos >= 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); + } + + + time(&rawtime); + pos = snprintf(snap_name, MAXPATHLEN, "%s", be_active_path(lbh)); + strftime(snap_name + pos, MAXPATHLEN - pos, + "@%F-%T", localtime(&rawtime)); + + + // TODO: should any props be in the last arg (nvlist)? + if (err = zfs_snapshot(lbh->lzh, snap_name, true, NULL)) { + // TODO: switch on err to determine correct BE_ERR_* to return + return (-1); + } + + snap_hdl = zfs_open(lbh->lzh, snap_name, ZFS_TYPE_SNAPSHOT); + + // TODO: should any props be in the last arg (nvlist)? + if (err = zfs_clone(snap_hdl, be_path, NULL)) { + // TODO: switch on err to determine correct BE_ERR_* to return + return (-1); + } + + return (err); +} + + +/* + * Appends the name argument on the root boot environment path and copies the + * resulting string into the result buffer. Returns 0 upon success and + * BE_ERR_PATHLEN if the resulting path is longer than MAXPATHLEN + */ +int +be_root_concat(libbe_handle_t *lbh, char *name, char *result) +{ + const char *root = be_root_path(lbh); + int n = snprintf(result, MAXPATHLEN, "%s/%s", root, name); + + if ((n >= 0) && (n < MAXPATHLEN)) { + return (BE_ERR_SUCCESS); + } + + // TODO: reconsider if this, or the caller, should set_error. + return (set_error(lbh, BE_ERR_PATHLEN)); +} + + +/* + * Verifies the validity of a boot environment name (A-Za-z0-9-_.,). Returns 0 + * if the name is valid, otherwise, returns the position of the first offending + * character + */ +int +be_valid_name(libbe_handle_t *lbh, char *name) +{ + for (int i = 0; *name; i++) { + char c = *(name++); + // TODO: beadm allows commas...they seem like a bad idea though + if (isalnum(c) || (c == '-') || (c == '_') || (c == '.') || + (c == ',')) { + // if lbh is not null, the offending char could be + // logged into some field for helpful error reporting + // also, should the set_error happen here, or in the + // caller (probably caller)?? + return (i); + } + } + + return (BE_ERR_SUCCESS); +} Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.h ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be.h Tue Jul 4 07:07:08 2017 (r324258) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.h Tue Jul 4 10:55:02 2017 (r324259) @@ -35,14 +35,15 @@ typedef struct libbe_handle libbe_handle_t; typedef enum be_error { - BE_ERR_SUCCESS = 0, /* No error */ - BE_ERR_INVALIDNAME, /* invalid boot env name */ - BE_ERR_EXISTS, /* boot env name already taken */ - BE_ERR_NOENT, /* boot env doesn't exist */ - BE_ERR_PERMS, /* insufficient permissions */ - BE_ERR_DESTROYACT, /* cannot destroy active boot env */ - BE_ERR_DESTROYMNT, /* cannot destroy active boot env */ - BE_ERR_UNKNOWN, /* unknown error */ + BE_ERR_SUCCESS = 0, /* No error */ + BE_ERR_INVALIDNAME, /* invalid boot env name */ + BE_ERR_EXISTS, /* boot env name already taken */ + BE_ERR_NOENT, /* boot env doesn't exist */ + BE_ERR_PERMS, /* insufficient permissions */ + BE_ERR_DESTROYACT, /* cannot destroy active boot env */ + BE_ERR_DESTROYMNT, /* destroying a mounted be requires force */ + BE_ERR_PATHLEN, /* provided name exceeds maximum length limit */ + BE_ERR_UNKNOWN, /* unknown error */ } be_error_t; @@ -51,9 +52,9 @@ void libbe_close(libbe_handle_t *); /* Bootenv information functions: be_info.c */ -const char *be_get_active_name(libbe_handle_t *); -const char *be_get_active_path(libbe_handle_t *); -const char *be_get_root_path(libbe_handle_t *); +const char *be_active_name(libbe_handle_t *); +const char *be_active_path(libbe_handle_t *); +const char *be_root_path(libbe_handle_t *); nvlist_t *be_get_bootenv_props(libbe_handle_t *); /* Bootenv creation functions */ @@ -65,7 +66,7 @@ /* Bootenv removal functions */ -#define BE_DESTROY_FORCE 1 +#define BE_DESTROY_FORCE 1 int be_destroy(libbe_handle_t *, char *, int); @@ -81,4 +82,8 @@ const char *libbe_error_description(libbe_handle_t *); void libbe_print_on_error(libbe_handle_t *, bool); +/* Utility Functions */ +int be_root_concat(libbe_handle_t *, char *, char *); +int be_valid_name(libbe_handle_t *, char *); + #endif /* _LIBBE_H */ Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_error.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_error.c Tue Jul 4 07:07:08 2017 (r324258) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_error.c Tue Jul 4 10:55:02 2017 (r324259) @@ -61,6 +61,9 @@ case BE_ERR_DESTROYMNT: return ("cannot destroy mounted boot env unless forced"); + case BE_ERR_PATHLEN: + return ("provided path name exceeds maximum length limit"); + case BE_ERR_UNKNOWN: return ("unknown error"); @@ -70,6 +73,7 @@ } } + void libbe_print_on_error(libbe_handle_t *lbh, bool val) { @@ -77,6 +81,7 @@ libzfs_print_on_error(lbh->lzh, val); } + int set_error(libbe_handle_t *lbh, be_error_t err) { @@ -84,7 +89,7 @@ lbh->error = err; - if(lbh->print_on_err) { + if (lbh->print_on_err) { fprintf(stderr, "%s\n", libbe_error_description(lbh)); } Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_info.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Tue Jul 4 07:07:08 2017 (r324258) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Tue Jul 4 10:55:02 2017 (r324259) @@ -35,7 +35,7 @@ * Returns the name of the active boot environment */ const char * -be_get_active_name(libbe_handle_t *lbh) +be_active_name(libbe_handle_t *lbh) { const char *full_path = zfs_get_name(lbh->be_active); @@ -47,7 +47,7 @@ * Returns full path of the active boot environment */ const char * -be_get_active_path(libbe_handle_t *lbh) +be_active_path(libbe_handle_t *lbh) { return (zfs_get_name(lbh->be_active)); } @@ -57,7 +57,7 @@ * Returns the path of the boot environment root dataset */ const char * -be_get_root_path(libbe_handle_t *lbh) +be_root_path(libbe_handle_t *lbh) { return (zfs_get_name(lbh->be_root)); } @@ -86,8 +86,8 @@ { /* * TODO: - * some system for defining constants for the nvlist keys - * error checking + * some system for defining constants for the nvlist keys + * error checking */ boolean_t mounted, active, nextboot; @@ -128,7 +128,7 @@ } nvlist_add_boolean_value(props, "active", - (strcmp(be_get_active_path(lbh), dataset) == 0)); + (strcmp(be_active_path(lbh), dataset) == 0)); if ((zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512, NULL, NULL, 0, 1)) == 0) { @@ -167,7 +167,7 @@ * Updates the properties of each bootenv in the libbe handle * TODO: rename to be_proplist_update * TODO: ensure that this is always consistent (run after adds, deletes, - * renames,etc + * renames,etc */ int prop_list_builder(libbe_handle_t *lbh) @@ -188,6 +188,7 @@ return (0); } + /* * Frees property list and its children */ @@ -197,18 +198,18 @@ nvlist_t *be_list; nvlist_t *prop_list; - if((be_list = lbh->list) == 0) { + if ((be_list = lbh->list) == 0) { return; } nvpair_t *be_pair = nvlist_next_nvpair(be_list, NULL); - if(nvpair_value_nvlist(be_pair, &prop_list) == 0) { + if (nvpair_value_nvlist(be_pair, &prop_list) == 0) { nvlist_free(prop_list); } - while((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) { - if(nvpair_value_nvlist(be_pair, &prop_list) == 0) { + while ((be_pair = nvlist_next_nvpair(be_list, be_pair)) != NULL) { + if (nvpair_value_nvlist(be_pair, &prop_list) == 0) { nvlist_free(prop_list); } } From owner-svn-soc-all@freebsd.org Thu Jul 6 04:03:29 2017 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 160C2D9D26E for ; Thu, 6 Jul 2017 04:03:29 +0000 (UTC) (envelope-from kneitinger@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 07D5B7E67D for ; Thu, 6 Jul 2017 04:03:29 +0000 (UTC) (envelope-from kneitinger@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.15.2/8.15.2) with ESMTP id v6643SNg073429 for ; Thu, 6 Jul 2017 04:03:28 GMT (envelope-from kneitinger@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.15.2/8.15.2/Submit) id v6643Qow073327 for svn-soc-all@FreeBSD.org; Thu, 6 Jul 2017 04:03:26 GMT (envelope-from kneitinger@FreeBSD.org) Date: Thu, 6 Jul 2017 04:03:26 GMT Message-Id: <201707060403.v6643Qow073327@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to kneitinger@FreeBSD.org using -f From: kneitinger@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r324318 - soc2017/kneitinger/libbe-head/lib/libbe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Jul 2017 04:03:29 -0000 Author: kneitinger Date: Thu Jul 6 04:03:25 2017 New Revision: 324318 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=324318 Log: libbe(3): add function to create boot env from exising snapshot Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.c soc2017/kneitinger/libbe-head/lib/libbe/be.h soc2017/kneitinger/libbe-head/lib/libbe/be_error.c soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be.c Thu Jul 6 00:53:12 2017 (r324317) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.c Thu Jul 6 04:03:25 2017 (r324318) @@ -169,7 +169,7 @@ time_t rawtime; zfs_handle_t *snap_hdl; - if (!(be_valid_name(lbh, name))) { + if (be_validate_name(lbh, name)) { err = set_error(lbh, BE_ERR_INVALIDNAME); return (err); } @@ -215,9 +215,114 @@ /* + * Create the boot environment from pre-existing snapshot + */ +int +be_create_from_existing(libbe_handle_t *lbh, char *name, char *snap) +{ + int err, pos; + char be_path[MAXPATHLEN]; + char snap_name[MAXPATHLEN]; + time_t rawtime; + zfs_handle_t *snap_hdl; + + + if (be_validate_name(lbh, name)) { + err = set_error(lbh, BE_ERR_INVALIDNAME); + return (err); + } + + + /* Ensure snap exists and it's parent dataset has mountpoint of '/' */ + if (err = be_validate_snap(lbh, snap)) { + // set correct errs + return (-1); + } + + + if (err = be_root_concat(lbh, name, be_path)) { + return (err); + } + + pos = snprintf(be_path, MAXPATHLEN, "%s/%s", be_root_path(lbh), name); + + if ((pos < 0) || (pos >= 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); + } + + + snap_hdl = zfs_open(lbh->lzh, snap, ZFS_TYPE_SNAPSHOT); + + // TODO: should any props be in the last arg (nvlist)? + if (err = zfs_clone(snap_hdl, be_path, NULL)) { + // TODO: switch on err to determine correct BE_ERR_* to return + return (-1); + } + + zfs_close(snap_hdl); + + 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. + */ +int +be_validate_snap(libbe_handle_t *lbh, char *snap_name) +{ + zfs_handle_t *zfs_hdl; + char buf[MAXPATHLEN]; + char *snap_delim; + char *mountpoint; + int err = 0; + + if (strlen(snap_name) >= MAXPATHLEN) { + return (BE_ERR_PATHLEN); + } + + if (!zfs_dataset_exists(lbh->lzh, snap_name, ZFS_TYPE_SNAPSHOT)) { + return (BE_ERR_NOENT); + } + + strncpy(buf, snap_name, MAXPATHLEN); + + if ((snap_delim = strchr(buf, '@')) == NULL) { + return (BE_ERR_INVALIDNAME); + } + + *snap_delim = '\0'; + + if ((zfs_hdl = zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL) { + return (BE_ERR_NOORIGIN); + } + + if (err = zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN, + NULL, NULL, 0, 1)) { + err = BE_ERR_INVORIGIN; + } + + if ((err != 0) && (strncmp(buf, "/", MAXPATHLEN) != 0)) { + err = BE_ERR_INVORIGIN; + } + + zfs_close(zfs_hdl); + + return (BE_ERR_SUCCESS); +} + + +/* * Appends the name argument on the root boot environment path and copies the * resulting string into the result buffer. Returns 0 upon success and - * BE_ERR_PATHLEN if the resulting path is longer than MAXPATHLEN + * BE_ERR_PATHLEN if the resulting path is longer than MAXPATHLEN. Does not set + * internal library error state. */ int be_root_concat(libbe_handle_t *lbh, char *name, char *result) @@ -229,28 +334,23 @@ return (BE_ERR_SUCCESS); } - // TODO: reconsider if this, or the caller, should set_error. - return (set_error(lbh, BE_ERR_PATHLEN)); + return (BE_ERR_PATHLEN); } /* * Verifies the validity of a boot environment name (A-Za-z0-9-_.,). Returns 0 * if the name is valid, otherwise, returns the position of the first offending - * character + * character. Does not set internal library error state. */ int -be_valid_name(libbe_handle_t *lbh, char *name) +be_validate_name(libbe_handle_t *lbh, char *name) { for (int i = 0; *name; i++) { char c = *(name++); // TODO: beadm allows commas...they seem like a bad idea though if (isalnum(c) || (c == '-') || (c == '_') || (c == '.') || (c == ',')) { - // if lbh is not null, the offending char could be - // logged into some field for helpful error reporting - // also, should the set_error happen here, or in the - // caller (probably caller)?? return (i); } } Modified: soc2017/kneitinger/libbe-head/lib/libbe/be.h ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be.h Thu Jul 6 00:53:12 2017 (r324317) +++ soc2017/kneitinger/libbe-head/lib/libbe/be.h Thu Jul 6 04:03:25 2017 (r324318) @@ -43,6 +43,8 @@ BE_ERR_DESTROYACT, /* cannot destroy active boot env */ BE_ERR_DESTROYMNT, /* destroying a mounted be requires force */ BE_ERR_PATHLEN, /* provided name exceeds maximum length limit */ + BE_ERR_INVORIGIN, /* snapshot origin's mountpoint is not '/' */ + BE_ERR_NOORIGIN, /* could not open snapshot's origin */ BE_ERR_UNKNOWN, /* unknown error */ } be_error_t; @@ -84,6 +86,7 @@ /* Utility Functions */ int be_root_concat(libbe_handle_t *, char *, char *); -int be_valid_name(libbe_handle_t *, char *); +int be_validate_name(libbe_handle_t *, char *); +int be_validate_snap(libbe_handle_t *, char *); #endif /* _LIBBE_H */ Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_error.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_error.c Thu Jul 6 00:53:12 2017 (r324317) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_error.c Thu Jul 6 04:03:25 2017 (r324318) @@ -64,6 +64,12 @@ 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_NOORIGIN: + return ("could not open snapshot's origin"); + case BE_ERR_UNKNOWN: return ("unknown error"); Modified: soc2017/kneitinger/libbe-head/lib/libbe/be_info.c ============================================================================== --- soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Thu Jul 6 00:53:12 2017 (r324317) +++ soc2017/kneitinger/libbe-head/lib/libbe/be_info.c Thu Jul 6 04:03:25 2017 (r324318) @@ -117,41 +117,41 @@ nvlist_add_string(props, "mountpoint", buf); } - if ((zfs_prop_get(zfs_hdl, ZFS_PROP_ORIGIN, buf, 512, - NULL, NULL, 0, 1)) == 0) { + if (zfs_prop_get(zfs_hdl, ZFS_PROP_ORIGIN, buf, 512, + NULL, NULL, 0, 1)) { nvlist_add_string(props, "origin", buf); } - if ((zfs_prop_get(zfs_hdl, ZFS_PROP_CREATION, buf, 512, - NULL, NULL, 0, 1)) == 0) { + if (zfs_prop_get(zfs_hdl, ZFS_PROP_CREATION, buf, 512, + NULL, NULL, 0, 1)) { nvlist_add_string(props, "creation", buf); } nvlist_add_boolean_value(props, "active", (strcmp(be_active_path(lbh), dataset) == 0)); - if ((zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512, - NULL, NULL, 0, 1)) == 0) { + if (zfs_prop_get(zfs_hdl, ZFS_PROP_USED, buf, 512, + NULL, NULL, 0, 1)) { nvlist_add_string(props, "used", buf); } - if ((zfs_prop_get(zfs_hdl, ZFS_PROP_USEDDS, buf, 512, - NULL, NULL, 0, 1)) == 0) { + if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDDS, buf, 512, + NULL, NULL, 0, 1)) { nvlist_add_string(props, "usedds", buf); } - if ((zfs_prop_get(zfs_hdl, ZFS_PROP_USEDSNAP, buf, 512, - NULL, NULL, 0, 1)) == 0) { + if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDSNAP, buf, 512, + NULL, NULL, 0, 1)) { nvlist_add_string(props, "usedsnap", buf); } - if ((zfs_prop_get(zfs_hdl, ZFS_PROP_USEDREFRESERV, buf, 512, - NULL, NULL, 0, 1)) == 0) { + if (zfs_prop_get(zfs_hdl, ZFS_PROP_USEDREFRESERV, buf, 512, + NULL, NULL, 0, 1)) { nvlist_add_string(props, "usedrefreserv", buf); } - if ((zfs_prop_get(zfs_hdl, ZFS_PROP_REFERENCED, buf, 512, - NULL, NULL, 0, 1)) == 0) { + if (zfs_prop_get(zfs_hdl, ZFS_PROP_REFERENCED, buf, 512, + NULL, NULL, 0, 1)) { nvlist_add_string(props, "referenced", buf); }