libbe(3): More error handling bits

be_add_child functionality gets split out into separate places as a bonus.
A lot of places here we'll gloss over libzfs errors, because they shouldn't
be happening given the conditions that we're operating under. "Unknown
error" is what I'm intending to use for the moment to indicate an
exceptional circumstance- exceptional enough that we can't tell the consumer
did because we're not so certain that they did anything.
This commit is contained in:
Kyle Evans 2018-08-10 21:23:56 +00:00
parent 6d4b1d241d
commit c65a211146
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/bectl/; revision=337592
3 changed files with 119 additions and 63 deletions

View File

@ -44,6 +44,10 @@ __FBSDID("$FreeBSD$");
#include "be.h"
#include "be_impl.h"
static int be_create_child_noent(libbe_handle_t *lbh, const char *active,
const char *child_path);
static int be_create_child_cloned(libbe_handle_t *lbh, const char *active);
/*
* Iterator function for locating the rootfs amongst the children of the
* zfs_be_root set by loader(8). data is expected to be a libbe_handle_t *.
@ -721,17 +725,111 @@ be_import(libbe_handle_t *lbh, const char *bootenv, int fd)
return (be_destroy(lbh, nbuf, 0));
}
static int
be_create_child_noent(libbe_handle_t *lbh, const char *active,
const char *child_path)
{
nvlist_t *props;
zfs_handle_t *zfs;
int err;
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)) != 0) {
switch (err) {
case EZFS_EXISTS:
return (set_error(lbh, BE_ERR_EXISTS));
case EZFS_NOENT:
return (set_error(lbh, BE_ERR_NOENT));
case EZFS_BADTYPE:
case EZFS_BADVERSION:
return (set_error(lbh, BE_ERR_NOPOOL));
case EZFS_BADPROP:
default:
/* We set something up wrong, probably... */
return (set_error(lbh, BE_ERR_UNKNOWN));
}
}
nvlist_free(props);
if ((zfs = zfs_open(lbh->lzh, active, ZFS_TYPE_DATASET)) == NULL)
return (set_error(lbh, BE_ERR_ZFSOPEN));
/* Set props */
if ((err = zfs_prop_set(zfs, "canmount", "noauto")) != 0) {
zfs_close(zfs);
/*
* Similar to other cases, this shouldn't fail unless we've
* done something wrong. This is a new dataset that shouldn't
* have been mounted anywhere between creation and now.
*/
if (err == EZFS_NOMEM)
return (set_error(lbh, BE_ERR_NOMEM));
return (set_error(lbh, BE_ERR_UNKNOWN));
}
zfs_close(zfs);
return (BE_ERR_SUCCESS);
}
static int
be_create_child_cloned(libbe_handle_t *lbh, const char *active)
{
char buf[BE_MAXPATHLEN];
zfs_handle_t *zfs;
int err;
/* XXX TODO ? */
/*
* Establish if the existing path is a zfs dataset or just
* the subdirectory of one
*/
strlcpy(buf, "/tmp/be_snap.XXXXX", sizeof(buf));
if (mktemp(buf) == NULL)
return (set_error(lbh, BE_ERR_UNKNOWN));
if ((err = zfs_snapshot(lbh->lzh, buf, false, NULL)) != 0) {
switch (err) {
case EZFS_INVALIDNAME:
return (set_error(lbh, BE_ERR_INVALIDNAME));
default:
/*
* The other errors that zfs_ioc_snapshot might return
* shouldn't happen if we've set things up properly, so
* we'll gloss over them and call it UNKNOWN as it will
* require further triage.
*/
if (errno == ENOTSUP)
return (set_error(lbh, BE_ERR_NOPOOL));
return (set_error(lbh, BE_ERR_UNKNOWN));
}
}
/* Clone */
if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL)
return (BE_ERR_ZFSOPEN);
if ((err = zfs_clone(zfs, active, NULL)) != 0)
/* XXX TODO correct error */
return (set_error(lbh, BE_ERR_UNKNOWN));
/* set props */
zfs_close(zfs);
return (BE_ERR_SUCCESS);
}
int
be_add_child(libbe_handle_t *lbh, const char *child_path, bool cp_if_exists)
{
struct stat sb;
char active[BE_MAXPATHLEN];
char buf[BE_MAXPATHLEN];
char active[BE_MAXPATHLEN], buf[BE_MAXPATHLEN];
nvlist_t *props;
const char *s;
zfs_handle_t *zfs;
int err;
/* Require absolute paths */
if (*child_path != '/')
@ -760,60 +858,12 @@ be_add_child(libbe_handle_t *lbh, const char *child_path, bool cp_if_exists)
if (stat(child_path, &sb) != 0) {
/* Verify that error is ENOENT */
if (errno != ENOENT)
return (set_error(lbh, BE_ERR_NOENT));
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)) != 0)
/* XXX TODO handle error */
return (set_error(lbh, BE_ERR_UNKNOWN));
nvlist_free(props);
if ((zfs =
zfs_open(lbh->lzh, active, ZFS_TYPE_DATASET)) == NULL)
return (set_error(lbh, BE_ERR_ZFSOPEN));
/* Set props */
if ((err = zfs_prop_set(zfs, "canmount", "noauto")) != 0)
/* TODO handle error */
return (set_error(lbh, BE_ERR_UNKNOWN));
} else if (cp_if_exists) {
return (be_create_child_noent(lbh, active, child_path));
} else if (cp_if_exists)
/* Path is already a descendent of / and should be copied */
/* XXX TODO ? */
/*
* Establish if the existing path is a zfs dataset or just
* the subdirectory of one
*/
strlcpy(buf, "/tmp/be_snap.XXXXX", sizeof(buf));
if (mktemp(buf) == NULL)
return (set_error(lbh, BE_ERR_UNKNOWN));
if ((err = zfs_snapshot(lbh->lzh, buf, false, NULL)) != 0)
/* XXX TODO correct error */
return (set_error(lbh, BE_ERR_UNKNOWN));
/* Clone */
if ((zfs =
zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL)
return (BE_ERR_ZFSOPEN);
if ((err = zfs_clone(zfs, active, NULL)) != 0)
/* XXX TODO correct error */
return (set_error(lbh, BE_ERR_UNKNOWN));
/* set props */
zfs_close(zfs);
} else
/* TODO: error code for exists, but not cp? */
return (set_error(lbh, BE_ERR_EXISTS));
return (BE_ERR_SUCCESS);
return (be_create_child_cloned(lbh, active));
return (set_error(lbh, BE_ERR_EXISTS));
}
static int
@ -863,22 +913,24 @@ be_activate(libbe_handle_t *lbh, const char *bootenv, bool temporary)
if (temporary) {
config = zpool_get_config(lbh->active_phandle, NULL);
if (config == NULL) {
printf("no config\n");
return (1);
}
if (config == NULL)
/* config should be fetchable... */
return (set_error(lbh, BE_ERR_UNKNOWN));
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
&pool_guid) != 0)
return (1);
/* Similarly, it shouldn't be possible */
return (set_error(lbh, BE_ERR_UNKNOWN));
/* Expected format according to zfsbootcfg(8) man */
strcpy(buf, "zfs:");
strcat(buf, be_path);
strcat(buf, ":");
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &vdevs) != 0)
return (1);
/* We have no config tree */
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&vdevs) != 0)
return (set_error(lbh, BE_ERR_NOPOOL));
return (be_set_nextboot(lbh, vdevs, pool_guid, buf));
} else {

View File

@ -57,6 +57,7 @@ typedef enum be_error {
BE_ERR_ZFSCLONE, /* error when calling zfs_clone to create be */
BE_ERR_IO, /* error when doing some I/O operation */
BE_ERR_NOPOOL, /* operation not supported on this pool */
BE_ERR_NOMEM, /* insufficient memory */
BE_ERR_UNKNOWN, /* unknown error */
} be_error_t;

View File

@ -99,6 +99,9 @@ libbe_error_description(libbe_handle_t *lbh)
case BE_ERR_NOPOOL:
return ("operation not supported on this pool");
case BE_ERR_NOMEM:
return ("insufficient memory");
case BE_ERR_UNKNOWN:
return ("unknown error");