From owner-svn-src-projects@freebsd.org Sat Aug 4 06:14:55 2018 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A94C4105F759 for ; Sat, 4 Aug 2018 06:14:55 +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.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 519F086D11; Sat, 4 Aug 2018 06:14:55 +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 33EF83AD8; Sat, 4 Aug 2018 06:14:55 +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 w746Et3h066224; Sat, 4 Aug 2018 06:14:55 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w746Et3U066223; Sat, 4 Aug 2018 06:14:55 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201808040614.w746Et3U066223@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Sat, 4 Aug 2018 06:14:55 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r337283 - projects/bectl/sbin/bectl X-SVN-Group: projects X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: projects/bectl/sbin/bectl X-SVN-Commit-Revision: 337283 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 04 Aug 2018 06:14:55 -0000 Author: kevans Date: Sat Aug 4 06:14:54 2018 New Revision: 337283 URL: https://svnweb.freebsd.org/changeset/base/337283 Log: bectl(8): Add some relevant `bectl list -a` information bectl list -a should show the boot environment, its relevant dataset, and the snapshot it was created from. The header also changes to indicate the rough order in which these things will show. While here, start doing a little bit of spring cleaning and splitting different bits out. Modified: projects/bectl/sbin/bectl/bectl.c Modified: projects/bectl/sbin/bectl/bectl.c ============================================================================== --- projects/bectl/sbin/bectl/bectl.c Sat Aug 4 02:30:51 2018 (r337282) +++ projects/bectl/sbin/bectl/bectl.c Sat Aug 4 06:14:54 2018 (r337283) @@ -44,16 +44,26 @@ #include #define HEADER_BE "BE" +#define HEADER_BEPLUS "BE/Dataset/Snapshot" #define HEADER_ACTIVE "Active" #define HEADER_MOUNT "Mountpoint" #define HEADER_SPACE "Space" #define HEADER_CREATED "Created" +/* Spaces */ +#define INDENT_INCREMENT 2 + struct printc { - int be_colsz; - int active_colsz_def; - int mount_colsz; - int space_colsz; + int active_colsz_def; + int be_colsz; + int current_indent; + int mount_colsz; + int space_colsz; + bool final_be; + bool hide_headers; + bool show_all_datasets; + bool show_snaps; + bool show_space; }; static int bectl_cmd_activate(int argc, char *argv[]); @@ -63,7 +73,9 @@ static int bectl_cmd_export(int argc, char *argv[]); static int bectl_cmd_import(int argc, char *argv[]); static int bectl_cmd_add(int argc, char *argv[]); static int bectl_cmd_jail(int argc, char *argv[]); -static void print_dataset(nvpair_t *cur, struct printc *pc); +static const char *get_origin_props(nvlist_t *dsprops, nvlist_t **originprops); +static void print_info(const char *name, nvlist_t *dsprops, struct printc *pc); +static void print_headers(nvlist_t *props, struct printc *pc); static int bectl_cmd_list(int argc, char *argv[]); static int bectl_cmd_mount(int argc, char *argv[]); static int bectl_cmd_rename(int argc, char *argv[]); @@ -418,26 +430,71 @@ bectl_cmd_jail(int argc, char *argv[]) return (0); } +/* + * Given a set of dataset properties (for a BE dataset), populate originprops + * with the origin's properties. + */ +static const char * +get_origin_props(nvlist_t *dsprops, nvlist_t **originprops) +{ + char *propstr; + + if (nvlist_lookup_string(dsprops, "origin", &propstr) == 0) { + if (be_prop_list_alloc(originprops) != 0) { + fprintf(stderr, + "bectl list: failed to allocate origin prop nvlist\n"); + return (NULL); + } + if (be_get_snapshot_props(be, propstr, *originprops) != 0) { + /* XXX TODO: Real errors */ + fprintf(stderr, + "bectl list: failed to fetch origin properties\n"); + return (NULL); + } + + return (propstr); + } + return (NULL); +} + + static void -print_dataset(nvpair_t *cur, struct printc *pc) +print_info(const char *name, nvlist_t *dsprops, struct printc *pc) { #define BUFSZ 64 char buf[BUFSZ]; unsigned long long ctimenum, space; - nvlist_t *dsprops, *originprops; + nvlist_t *originprops; + const char *oname; char *propstr; int active_colsz; boolean_t active_now, active_reboot; originprops = NULL; - propstr = nvpair_name(cur); - /* XXX TODO: Some views show snapshots */ - if (strchr(propstr, '@') != NULL) + printf("%*s%*s ", pc->current_indent, "", + pc->be_colsz + pc->current_indent, name); + + /* Recurse at the base level if we're breaking info down */ + if (pc->current_indent == 0 && (pc->show_all_datasets || + pc->show_snaps)) { + printf("\n"); + if (nvlist_lookup_string(dsprops, "dataset", &propstr) != 0) + /* XXX TODO: Error? */ + return; + pc->current_indent += INDENT_INCREMENT; + print_info(propstr, dsprops, pc); + pc->current_indent += INDENT_INCREMENT; + if ((oname = get_origin_props(dsprops, &originprops)) != NULL) { + print_info(oname, originprops, pc); + nvlist_free(originprops); + } + pc->current_indent = 0; + if (!pc->final_be) + printf("\n"); return; - printf("%*s ", pc->be_colsz, propstr); + } active_colsz = pc->active_colsz_def; - nvpair_value_nvlist(cur, &dsprops); if (nvlist_lookup_boolean_value(dsprops, "active", &active_now) == 0 && active_now) { printf("N"); @@ -458,25 +515,13 @@ print_dataset(nvpair_t *cur, struct printc *pc) else printf("%*s ", pc->mount_colsz, "-"); - if (nvlist_lookup_string(dsprops, "origin", &propstr) == 0) { - if (be_prop_list_alloc(&originprops) != 0) { - fprintf(stderr, - "bectl list: failed to allocate origin prop nvlist\n"); - return; - } - if (be_get_snapshot_props(be, propstr, originprops) != 0) { - /* XXX TODO: Real errors */ - fprintf(stderr, - "bectl list: failed to fetch origin properties\n"); - return; - } - } + get_origin_props(dsprops, &originprops); if (nvlist_lookup_string(dsprops, "used", &propstr) == 0) { space = strtoull(propstr, NULL, 10); - if (originprops != NULL && nvlist_lookup_string(originprops, - "used", &propstr) == 0) + if (!pc->show_all_datasets && originprops != NULL && + nvlist_lookup_string(originprops, "used", &propstr) == 0) space += strtoull(propstr, NULL, 10); /* Alas, there's more to it,. */ @@ -494,36 +539,84 @@ print_dataset(nvpair_t *cur, struct printc *pc) } printf("\n"); - if (originprops != NULL) + if (originprops != NULL) { + /*if (pc->show_all_datasets) { + }*/ be_prop_list_free(originprops); + } #undef BUFSZ } +static void +print_headers(nvlist_t *props, struct printc *pc) +{ + const char *chosen_be_header; + nvpair_t *cur; + nvlist_t *dsprops; + char *propstr; + size_t be_maxcol; + + if (pc->show_all_datasets || pc->show_snaps) + chosen_be_header = HEADER_BEPLUS; + else + chosen_be_header = HEADER_BE; + be_maxcol = strlen(chosen_be_header); + for (cur = nvlist_next_nvpair(props, NULL); cur != NULL; + cur = nvlist_next_nvpair(props, cur)) { + be_maxcol = MAX(be_maxcol, strlen(nvpair_name(cur))); + if (!pc->show_all_datasets && !pc->show_snaps) + continue; + nvpair_value_nvlist(cur, &dsprops); + if (nvlist_lookup_string(dsprops, "dataset", &propstr) != 0) + continue; + be_maxcol = MAX(be_maxcol, strlen(propstr) + INDENT_INCREMENT); + if (nvlist_lookup_string(dsprops, "origin", &propstr) != 0) + continue; + be_maxcol = MAX(be_maxcol, + strlen(propstr) + INDENT_INCREMENT * 2); + } + + pc->be_colsz = -be_maxcol; + /* To be made negative after calculating final col sz */ + pc->active_colsz_def = strlen(HEADER_ACTIVE); + pc->mount_colsz = -(int)strlen(HEADER_MOUNT); + pc->space_colsz = -(int)strlen(HEADER_SPACE); + /* XXX TODO: Take -H into account */ + printf("%*s %s %s %s %s\n", pc->be_colsz, chosen_be_header, + HEADER_ACTIVE, HEADER_MOUNT, HEADER_SPACE, HEADER_CREATED); + + /* + * All other invocations in which we aren't using the default header + * will produce quite a bit of input. Throw an extra blank line after + * the header to make it look nicer. + */ + if (chosen_be_header != HEADER_BE) + printf("\n"); +} + static int bectl_cmd_list(int argc, char *argv[]) { struct printc pc; nvpair_t *cur; - nvlist_t *props; - size_t be_maxcol; + nvlist_t *dsprops, *props; int opt; - bool show_all_datasets, show_space, hide_headers, show_snaps; props = NULL; - show_all_datasets = show_space = hide_headers = show_snaps = false; + bzero(&pc, sizeof(pc)); while ((opt = getopt(argc, argv, "aDHs")) != -1) { switch (opt) { case 'a': - show_all_datasets = true; + pc.show_all_datasets = true; break; case 'D': - show_space = true; + pc.show_space = true; break; case 'H': - hide_headers = true; + pc.hide_headers = true; break; case 's': - show_space = true; + pc.show_snaps = true; break; default: fprintf(stderr, "bectl list: unknown option '-%c'\n", @@ -549,22 +642,12 @@ bectl_cmd_list(int argc, char *argv[]) return (1); } - be_maxcol = strlen(HEADER_BE); + print_headers(props, &pc); for (cur = nvlist_next_nvpair(props, NULL); cur != NULL; cur = nvlist_next_nvpair(props, cur)) { - be_maxcol = MAX(be_maxcol, strlen(nvpair_name(cur))); - } - - pc.be_colsz = -be_maxcol; - /* To be made negative after calculating final col sz */ - pc.active_colsz_def = strlen(HEADER_ACTIVE); - pc.mount_colsz = -(int)strlen(HEADER_MOUNT); - pc.space_colsz = -(int)strlen(HEADER_SPACE); - printf("%*s %s %s %s %s\n", pc.be_colsz, HEADER_BE, HEADER_ACTIVE, - HEADER_MOUNT, HEADER_SPACE, HEADER_CREATED); - for (cur = nvlist_next_nvpair(props, NULL); cur != NULL; - cur = nvlist_next_nvpair(props, cur)) { - print_dataset(cur, &pc); + nvpair_value_nvlist(cur, &dsprops); + pc.final_be = nvlist_next_nvpair(props, cur) == NULL; + print_info(nvpair_name(cur), dsprops, &pc); } be_prop_list_free(props);