From owner-svn-src-all@freebsd.org Sun Sep 15 02:36:52 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 03C55DAF9F; Sun, 15 Sep 2019 02:36:52 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46WD6C67vcz3KHR; Sun, 15 Sep 2019 02:36:51 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id B5FE715FB; Sun, 15 Sep 2019 02:36:51 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x8F2apxM006453; Sun, 15 Sep 2019 02:36:51 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x8F2apXf006450; Sun, 15 Sep 2019 02:36:51 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201909150236.x8F2apXf006450@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Sun, 15 Sep 2019 02:36:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r352344 - stable/12/sbin/bectl X-SVN-Group: stable-12 X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: stable/12/sbin/bectl X-SVN-Commit-Revision: 352344 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Sep 2019 02:36:52 -0000 Author: kevans Date: Sun Sep 15 02:36:50 2019 New Revision: 352344 URL: https://svnweb.freebsd.org/changeset/base/352344 Log: MFC r351813, r352092: bectl(8) list sorting MFC r351813: 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' MFC r352092: bectl(8): initialize reverse earlier This turns into a warning in GCC 4.2 that 'reverse' may be used uninitialized in this function. While I don't immediately see where it's deciding this from (there's only two paths that make column != NULL, and they both set reverse), initializing reverse earlier is good for clarity. Modified: stable/12/sbin/bectl/bectl.8 stable/12/sbin/bectl/bectl.c stable/12/sbin/bectl/bectl_list.c Directory Properties: stable/12/ (props changed) Modified: stable/12/sbin/bectl/bectl.8 ============================================================================== --- stable/12/sbin/bectl/bectl.8 Sun Sep 15 02:17:30 2019 (r352343) +++ stable/12/sbin/bectl/bectl.8 Sun Sep 15 02:36:50 2019 (r352344) @@ -18,7 +18,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 9, 2019 +.Dd September 14, 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: stable/12/sbin/bectl/bectl.c ============================================================================== --- stable/12/sbin/bectl/bectl.c Sun Sep 15 02:17:30 2019 (r352343) +++ stable/12/sbin/bectl/bectl.c Sun Sep 15 02:36:50 2019 (r352344) @@ -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: stable/12/sbin/bectl/bectl_list.c ============================================================================== --- stable/12/sbin/bectl/bectl_list.c Sun Sep 15 02:17:30 2019 (r352343) +++ stable/12/sbin/bectl/bectl_list.c Sun Sep 15 02:36:50 2019 (r352344) @@ -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,15 @@ 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) { + reverse = false; + while ((opt = getopt(argc, argv, "aDHsc:C:")) != -1) { switch (opt) { case 'a': pc.show_all_datasets = true; @@ -350,6 +427,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 +463,31 @@ bectl_cmd_list(int argc, char *argv[]) return (1); } + /* List boot environments in alphabetical order by default */ + if (column == NULL) + column = strdup("name"); + + 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);