aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libbe/be.c35
-rw-r--r--lib/libbe/be.h3
-rw-r--r--lib/libbe/libbe.317
3 files changed, 53 insertions, 2 deletions
diff --git a/lib/libbe/be.c b/lib/libbe/be.c
index 249fa2f3361c..fb27d7a2855b 100644
--- a/lib/libbe/be.c
+++ b/lib/libbe/be.c
@@ -229,6 +229,7 @@ be_destroy_cb(zfs_handle_t *zfs_hdl, void *data)
return (0);
}
+#define BE_DESTROY_NEEDORIGIN (BE_DESTROY_ORIGIN | BE_DESTROY_AUTOORIGIN)
/*
* Destroy the boot environment or snapshot specified by the name
* parameter. Options are or'd together with the possible values:
@@ -264,11 +265,24 @@ be_destroy(libbe_handle_t *lbh, const char *name, int options)
if (fs == NULL)
return (set_error(lbh, BE_ERR_ZFSOPEN));
- if ((options & BE_DESTROY_ORIGIN) != 0 &&
+ if ((options & BE_DESTROY_NEEDORIGIN) != 0 &&
zfs_prop_get(fs, ZFS_PROP_ORIGIN, origin, sizeof(origin),
NULL, NULL, 0, 1) != 0)
return (set_error(lbh, BE_ERR_NOORIGIN));
+ /*
+ * If the caller wants auto-origin destruction and the origin
+ * name matches one of our automatically created snapshot names
+ * (i.e. strftime("%F-%T") with a serial at the end), then
+ * we'll set the DESTROY_ORIGIN flag and nuke it
+ * be_is_auto_snapshot_name is exported from libbe(3) so that
+ * the caller can determine if it needs to warn about the origin
+ * not being destroyed or not.
+ */
+ if ((options & BE_DESTROY_AUTOORIGIN) != 0 &&
+ be_is_auto_snapshot_name(lbh, origin))
+ options |= BE_DESTROY_ORIGIN;
+
/* Don't destroy a mounted dataset unless force is specified */
if ((mounted = zfs_is_mounted(fs, NULL)) != 0) {
if (force) {
@@ -343,6 +357,25 @@ be_setup_snapshot_name(libbe_handle_t *lbh, char *buf, size_t buflen)
}
}
+bool
+be_is_auto_snapshot_name(libbe_handle_t *lbh, const char *name)
+{
+ const char *snap;
+ int day, hour, minute, month, second, serial, year;
+
+ if ((snap = strchr(name, '@')) == NULL)
+ return (false);
+ ++snap;
+ /* We'll grab the individual components and do some light validation. */
+ if (sscanf(snap, "%d-%d-%d-%d:%d:%d-%d", &year, &month, &day, &hour,
+ &minute, &second, &serial) != 7)
+ return (false);
+ return (year >= 1970) && (month >= 1 && month <= 12) &&
+ (day >= 1 && day <= 31) && (hour >= 0 && hour <= 23) &&
+ (minute >= 0 && minute <= 59) && (second >= 0 && second <= 60) &&
+ serial >= 0;
+}
+
int
be_snapshot(libbe_handle_t *lbh, const char *source, const char *snap_name,
bool recursive, char *result)
diff --git a/lib/libbe/be.h b/lib/libbe/be.h
index 8fd230853342..84109c8fa243 100644
--- a/lib/libbe/be.h
+++ b/lib/libbe/be.h
@@ -82,6 +82,8 @@ void be_prop_list_free(nvlist_t *be_list);
int be_activate(libbe_handle_t *, const char *, bool);
+bool be_is_auto_snapshot_name(libbe_handle_t *, const char *);
+
/* Bootenv creation functions */
int be_create(libbe_handle_t *, const char *);
int be_create_depth(libbe_handle_t *, const char *, const char *, int);
@@ -97,6 +99,7 @@ int be_rename(libbe_handle_t *, const char *, const char *);
typedef enum {
BE_DESTROY_FORCE = 1 << 0,
BE_DESTROY_ORIGIN = 1 << 1,
+ BE_DESTROY_AUTOORIGIN = 1 << 2,
} be_destroy_opt_t;
int be_destroy(libbe_handle_t *, const char *, int);
diff --git a/lib/libbe/libbe.3 b/lib/libbe/libbe.3
index fe2ddaaf1819..8a63fd52d2ca 100644
--- a/lib/libbe/libbe.3
+++ b/lib/libbe/libbe.3
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 22, 2019
+.Dd October 16, 2019
.Dt LIBBE 3
.Os
.Sh NAME
@@ -59,6 +59,9 @@
.Ft const char * Ns
.Fn be_root_path "libbe_handle_t *hdl"
.Pp
+.Ft bool Ns
+.Fn be_is_auto_snapshot_name "libbe_handle_t *hdl" "const char *snap"
+.Pp
.Ft int
.Fn be_create "libbe_handle_t *hdl" "const char *be_name"
.Pp
@@ -214,6 +217,18 @@ The
function returns the boot environment root path.
.Pp
The
+.Fn be_is_auto_snapshot_name
+function is used to determine if the given snapshot name matches the format that
+the
+.Fn be_snapshot
+function will use by default if it is not given a snapshot name to use.
+It returns
+.Dv true
+if the name matches the format, and
+.Dv false
+if it does not.
+.Pp
+The
.Fn be_create
function creates a boot environment with the given name.
The new boot environment will be created from a recursive snapshot of the