aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2019-09-04 13:59:06 +0000
committerKyle Evans <kevans@FreeBSD.org>2019-09-04 13:59:06 +0000
commitf0298be018ffcc871e40d6f6df22d25a69152d48 (patch)
treea8a6486600a459bdc5e3b19efd372b6176ae2810 /sbin
parentc2a13d6f24ed9e1a450c8dc1da6f2b8acf65a8d4 (diff)
downloadsrc-f0298be018ffcc871e40d6f6df22d25a69152d48.tar.gz
src-f0298be018ffcc871e40d6f6df22d25a69152d48.zip
bectl(8): implement sorting for 'bectl list' output
Allow 'bectl list' to sort output by a given property name. The property name is passed in using a command-line flag, '-c' for ascending order and '-C' for descending order. The properties allowed to sort by are: - name (the default output, even if '-c' or '-C' are not used) - creation - origin - used - usedds - usedsnap - usedrefreserv The default output for 'bectl list' is now ascending alphabetical order of BE name. To sort by creation time from earliest to latest, the command would be 'bectl list -c creation' Submitted by: Rob Fairbanks <rob.fx907 gmail com> Reviewed by: ler MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D20818
Notes
Notes: svn path=/head/; revision=351813
Diffstat (limited to 'sbin')
-rw-r--r--sbin/bectl/bectl.859
-rw-r--r--sbin/bectl/bectl.c2
-rw-r--r--sbin/bectl/bectl_list.c127
3 files changed, 148 insertions, 40 deletions
diff --git a/sbin/bectl/bectl.8 b/sbin/bectl/bectl.8
index 544a24ba25c8..36e7cfffda65 100644
--- a/sbin/bectl/bectl.8
+++ b/sbin/bectl/bectl.8
@@ -18,7 +18,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 12, 2019
+.Dd September 4, 2019
.Dt BECTL 8
.Os
.Sh NAME
@@ -57,6 +57,9 @@
.Nm
.Cm list
.Op Fl aDHs
+.Op Fl c Ar property
+.Op Fl C Ar property
+.Oo Bro Fl c Ar property | Fl C Ar property Brc Oc
.Nm
.Cm mount
.Ar beName
@@ -234,7 +237,12 @@ generated by
.El
.Pp
All default parameters may be overwritten.
-.It Cm list Op Fl aDHs
+.It Xo
+.Cm list
+.Op Fl DHas
+.Oo Bro Fl c Ar property | Fl C Ar property Brc Oc
+.Xc
+.Pp
Display all boot environments.
The
.Em Active
@@ -245,21 +253,44 @@ active on reboot
or both
.Pq Em \&NR .
.Pp
-If
-.Fl a
-is used, display all datasets.
-If
-.Fl D
-is used, display the full space usage for each boot environment, assuming all
+.Bl -tag -width indent
+.It Fl a
+Display all datasets.
+.It Fl D
+Display the full space usage for each boot environment, assuming all
other boot environments were destroyed.
-The
-.Fl H
-option is used for scripting.
-It does not print headers and separate fields by a single tab instead of
+.It Fl H
+Used for scripting.
+Do not print headers and separate fields by a single tab instead of
arbitrary white space.
-If
+.It Fl s
+Display all snapshots as well.
+.It Fl c Ar property
+Sort boot environments by given property name.
+The following properties are supported:
+.Pp
+.Bl -tag -width 4n -offset indent -compact
+.It name (default output)
+.It creation
+.It origin
+.It used
+.It usedds
+.It usedsnap
+.It usedrefreserv
+.El
+.It Fl C Ar property
+Same as the
+.Fl c
+option, but displays in descending order.
+.El
+.Pp
+The
+.Fl D
+option is ignored when either the
.Fl s
-is used, display all snapshots as well.
+or
+.Fl a
+option is used.
.It Cm mount Ar beName Op Ar mountpoint
Temporarily mount the boot environment.
Mount at the specified
diff --git a/sbin/bectl/bectl.c b/sbin/bectl/bectl.c
index 5119759deb97..f8eab1aa9ef6 100644
--- a/sbin/bectl/bectl.c
+++ b/sbin/bectl/bectl.c
@@ -80,7 +80,7 @@ usage(bool explicit)
"\tbectl jail {-b | -U} [{-o key=value | -u key}]... "
"{jailID | jailName}\n"
"\t bootenv [utility [argument ...]]\n"
- "\tbectl list [-DHas]\n"
+ "\tbectl list [-DHas] [{-c property | -C property}]\n"
"\tbectl mount beName [mountpoint]\n"
"\tbectl rename origBeName newBeName\n"
"\tbectl {ujail | unjail} {jailID | jailName} bootenv\n"
diff --git a/sbin/bectl/bectl_list.c b/sbin/bectl/bectl_list.c
index 2276ac8a21a5..620888a9fa00 100644
--- a/sbin/bectl/bectl_list.c
+++ b/sbin/bectl/bectl_list.c
@@ -38,6 +38,12 @@ __FBSDID("$FreeBSD$");
#include "bectl.h"
+struct sort_column {
+ char *name;
+ char *val;
+ nvlist_t *nvl;
+};
+
struct printc {
int active_colsz_def;
int be_colsz;
@@ -324,6 +330,74 @@ print_headers(nvlist_t *props, struct printc *pc)
printf("\n");
}
+/*
+ * Sort the given nvlist of boot environments by property.
+ */
+static int
+prop_list_sort(nvlist_t *props, char *property, bool reverse)
+{
+ nvpair_t *nvp;
+ nvlist_t *nvl;
+ int i, nvp_count;
+ uint64_t lval, rval;
+ struct sort_column sc_prev, sc_next;
+
+ /* a temporary list to work with */
+ nvlist_dup(props, &nvl, 0);
+
+ nvp_count = fnvlist_num_pairs(nvl);
+ for (i = 0; i < nvp_count; i++) {
+
+ nvp = nvlist_next_nvpair(nvl, NULL);
+ nvpair_value_nvlist(nvp, &sc_prev.nvl);
+ nvlist_lookup_string(sc_prev.nvl, "name", &sc_prev.name);
+ nvlist_lookup_string(sc_prev.nvl, property, &sc_prev.val);
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+
+ nvpair_value_nvlist(nvp, &sc_next.nvl);
+ nvlist_lookup_string(sc_next.nvl, "name", &sc_next.name);
+ nvlist_lookup_string(sc_next.nvl, property, &sc_next.val);
+
+ /* properties that use numerical comparison */
+ if (strcmp(property, "creation") == 0 ||
+ strcmp(property, "used") == 0 ||
+ strcmp(property, "usedds") == 0 ||
+ strcmp(property, "usedsnap") == 0 ||
+ strcmp(property, "usedrefreserv") == 0) {
+
+ lval = strtoull(sc_prev.val, NULL, 10);
+ rval = strtoull(sc_next.val, NULL, 10);
+
+ if ((lval < rval && reverse) ||
+ (lval > rval && !reverse))
+ sc_prev = sc_next;
+ }
+
+ /* properties that use string comparison */
+ else if (strcmp(property, "name") == 0 ||
+ strcmp(property, "origin") == 0) {
+ if ((strcmp(sc_prev.val, sc_next.val) < 0 && reverse) ||
+ (strcmp(sc_prev.val, sc_next.val) > 0 && !reverse))
+ sc_prev = sc_next;
+ }
+ }
+
+ /*
+ * The 'props' nvlist has been created to only have unique names.
+ * When a name is added, any existing nvlist's with the same name
+ * will be removed. Eventually, all existing nvlist's are replaced
+ * in sorted order.
+ */
+ nvlist_add_nvlist(props, sc_prev.name, sc_prev.nvl);
+ nvlist_remove_all(nvl, sc_prev.name);
+ }
+
+ be_prop_list_free(nvl);
+
+ return 0;
+}
+
int
bectl_cmd_list(int argc, char *argv[])
{
@@ -331,12 +405,14 @@ bectl_cmd_list(int argc, char *argv[])
nvpair_t *cur;
nvlist_t *dsprops, *props;
int opt, printed;
- boolean_t active_now, active_reboot;
+ char *column;
+ bool reverse;
+ column = NULL;
props = NULL;
printed = 0;
bzero(&pc, sizeof(pc));
- while ((opt = getopt(argc, argv, "aDHs")) != -1) {
+ while ((opt = getopt(argc, argv, "aDHsc:C:")) != -1) {
switch (opt) {
case 'a':
pc.show_all_datasets = true;
@@ -350,6 +426,18 @@ bectl_cmd_list(int argc, char *argv[])
case 's':
pc.show_snaps = true;
break;
+ case 'c':
+ if (column != NULL)
+ free(column);
+ column = strdup(optarg);
+ reverse = false;
+ break;
+ case 'C':
+ if (column != NULL)
+ free(column);
+ column = strdup(optarg);
+ reverse = true;
+ break;
default:
fprintf(stderr, "bectl list: unknown option '-%c'\n",
optopt);
@@ -374,44 +462,33 @@ bectl_cmd_list(int argc, char *argv[])
return (1);
}
+ /* List boot environments in alphabetical order by default */
+ if (column == NULL) {
+ column = strdup("name");
+ reverse = false;
+ }
+
+ prop_list_sort(props, column, reverse);
+
/* Force -D off if either -a or -s are specified */
if (pc.show_all_datasets || pc.show_snaps)
pc.show_space = false;
if (!pc.script_fmt)
print_headers(props, &pc);
- /* Do a first pass to print active and next active first */
- for (cur = nvlist_next_nvpair(props, NULL); cur != NULL;
- cur = nvlist_next_nvpair(props, cur)) {
- nvpair_value_nvlist(cur, &dsprops);
- active_now = active_reboot = false;
- nvlist_lookup_boolean_value(dsprops, "active", &active_now);
- nvlist_lookup_boolean_value(dsprops, "nextboot",
- &active_reboot);
- if (!active_now && !active_reboot)
- continue;
- if (printed > 0 && (pc.show_all_datasets || pc.show_snaps))
- printf("\n");
- print_info(nvpair_name(cur), dsprops, &pc);
- printed++;
- }
-
- /* Now pull everything else */
+ /* Print boot environments */
for (cur = nvlist_next_nvpair(props, NULL); cur != NULL;
cur = nvlist_next_nvpair(props, cur)) {
nvpair_value_nvlist(cur, &dsprops);
- active_now = active_reboot = false;
- nvlist_lookup_boolean_value(dsprops, "active", &active_now);
- nvlist_lookup_boolean_value(dsprops, "nextboot",
- &active_reboot);
- if (active_now || active_reboot)
- continue;
if (printed > 0 && (pc.show_all_datasets || pc.show_snaps))
printf("\n");
+
print_info(nvpair_name(cur), dsprops, &pc);
printed++;
}
+
+ free(column);
be_prop_list_free(props);
return (0);