Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Sep 2019 13:59:06 +0000 (UTC)
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r351813 - head/sbin/bectl
Message-ID:  <201909041359.x84Dx6l7023243@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kevans
Date: Wed Sep  4 13:59:06 2019
New Revision: 351813
URL: https://svnweb.freebsd.org/changeset/base/351813

Log:
  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

Modified:
  head/sbin/bectl/bectl.8
  head/sbin/bectl/bectl.c
  head/sbin/bectl/bectl_list.c

Modified: head/sbin/bectl/bectl.8
==============================================================================
--- head/sbin/bectl/bectl.8	Wed Sep  4 13:47:38 2019	(r351812)
+++ head/sbin/bectl/bectl.8	Wed Sep  4 13:59:06 2019	(r351813)
@@ -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

Modified: head/sbin/bectl/bectl.c
==============================================================================
--- head/sbin/bectl/bectl.c	Wed Sep  4 13:47:38 2019	(r351812)
+++ head/sbin/bectl/bectl.c	Wed Sep  4 13:59:06 2019	(r351813)
@@ -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"

Modified: head/sbin/bectl/bectl_list.c
==============================================================================
--- head/sbin/bectl/bectl_list.c	Wed Sep  4 13:47:38 2019	(r351812)
+++ head/sbin/bectl/bectl_list.c	Wed Sep  4 13:59:06 2019	(r351813)
@@ -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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909041359.x84Dx6l7023243>