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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to