Date: Tue, 4 Jul 2017 10:55:02 GMT From: kneitinger@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r324259 - soc2017/kneitinger/libbe-head/lib/libbe Message-ID: <201707041055.v64At296072186@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 <errno.h> +#include <ctype.h> #include <kenv.h> #include <libgen.h> #include <stdio.h> #include <sys/types.h> +#include <time.h> #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); } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201707041055.v64At296072186>
