From owner-svn-src-stable@freebsd.org Mon Sep 9 17:56:15 2019 Return-Path: Delivered-To: svn-src-stable@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 40D99DA068; Mon, 9 Sep 2019 17:56:15 +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 46Rwnq113zz4K7Q; Mon, 9 Sep 2019 17:56:15 +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 010811957D; Mon, 9 Sep 2019 17:56:14 +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 x89HuElx095662; Mon, 9 Sep 2019 17:56:14 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x89HuEYJ095660; Mon, 9 Sep 2019 17:56:14 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201909091756.x89HuEYJ095660@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Mon, 9 Sep 2019 17:56:14 +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: r352087 - 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: 352087 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Sep 2019 17:56:15 -0000 Author: kevans Date: Mon Sep 9 17:56:14 2019 New Revision: 352087 URL: https://svnweb.freebsd.org/changeset/base/352087 Log: 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' 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 Mon Sep 9 17:53:15 2019 (r352086) +++ stable/12/sbin/bectl/bectl.8 Mon Sep 9 17:56:14 2019 (r352087) @@ -53,6 +53,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 @@ -230,7 +233,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 @@ -241,21 +249,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 Mon Sep 9 17:53:15 2019 (r352086) +++ stable/12/sbin/bectl/bectl.c Mon Sep 9 17:56:14 2019 (r352087) @@ -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 Mon Sep 9 17:53:15 2019 (r352086) +++ stable/12/sbin/bectl/bectl_list.c Mon Sep 9 17:56:14 2019 (r352087) @@ -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);