diff --git a/sbin/geom/core/geom.8 b/sbin/geom/core/geom.8 index 8cd88cb7792f..298fc2b1d4fd 100644 --- a/sbin/geom/core/geom.8 +++ b/sbin/geom/core/geom.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 13, 2018 +.Dd September 14, 2018 .Dt GEOM 8 .Os .Sh NAME @@ -55,6 +55,8 @@ .Nm .Fl p .Ar provider-name +.Nm +.Fl t .Sh DESCRIPTION The .Nm @@ -111,6 +113,8 @@ Additional options include: .It Fl p Ar provider-name Print detailed information about the geom which provides .Ar provider-name . +.It Fl t +Display geoms hierarchy as a tree. .El .Pp Class-specific commands are implemented as shared libraries which diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c index 9f1655c61a51..e6d6d789908f 100644 --- a/sbin/geom/core/geom.c +++ b/sbin/geom/core/geom.c @@ -66,8 +66,11 @@ static uint32_t *version = NULL; static int verbose = 0; static struct g_command *class_commands = NULL; -#define GEOM_CLASS_CMDS 0x01 -#define GEOM_STD_CMDS 0x02 +#define GEOM_CLASS_CMDS 0x01 +#define GEOM_STD_CMDS 0x02 + +#define GEOM_CLASS_WIDTH 10 + static struct g_command *find_command(const char *cmdstr, int flags); static void list_one_geom_by_provider(const char *provider_name); static int std_available(const char *name); @@ -149,6 +152,7 @@ usage(void) if (class_name == NULL) { fprintf(stderr, "usage: geom [options]\n"); fprintf(stderr, " geom -p \n"); + fprintf(stderr, " geom -t\n"); exit(EXIT_FAILURE); } else { struct g_command *cmd; @@ -672,22 +676,142 @@ find_geom_by_provider(struct gmesh *mesh, const char *name) return (NULL); } +static int +compute_tree_width_geom(struct gmesh *mesh, struct ggeom *gp, int indent) +{ + struct gclass *classp2; + struct ggeom *gp2; + struct gconsumer *cp2; + struct gprovider *pp; + int max_width, width; + + max_width = width = indent + strlen(gp->lg_name); + + LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { + LIST_FOREACH(classp2, &mesh->lg_class, lg_class) { + LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) { + LIST_FOREACH(cp2, + &gp2->lg_consumer, lg_consumer) { + if (pp != cp2->lg_provider) + continue; + width = compute_tree_width_geom(mesh, + gp2, indent + 2); + if (width > max_width) + max_width = width; + } + } + } + } + + return (max_width); +} + +static int +compute_tree_width(struct gmesh *mesh) +{ + struct gclass *classp; + struct ggeom *gp; + int max_width, width; + + max_width = width = 0; + + LIST_FOREACH(classp, &mesh->lg_class, lg_class) { + LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { + if (!LIST_EMPTY(&gp->lg_consumer)) + continue; + width = compute_tree_width_geom(mesh, gp, 0); + if (width > max_width) + max_width = width; + } + } + + return (max_width); +} + +static void +show_tree_geom(struct gmesh *mesh, struct ggeom *gp, int indent, int width) +{ + struct gclass *classp2; + struct ggeom *gp2; + struct gconsumer *cp2; + struct gprovider *pp; + + if (LIST_EMPTY(&gp->lg_provider)) { + printf("%*s%-*.*s %-*.*s\n", indent, "", + width - indent, width - indent, gp->lg_name, + GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name); + return; + } + + LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { + printf("%*s%-*.*s %-*.*s %s\n", indent, "", + width - indent, width - indent, gp->lg_name, + GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name, + pp->lg_name); + + LIST_FOREACH(classp2, &mesh->lg_class, lg_class) { + LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) { + LIST_FOREACH(cp2, + &gp2->lg_consumer, lg_consumer) { + if (pp != cp2->lg_provider) + continue; + show_tree_geom(mesh, gp2, + indent + 2, width); + } + } + } + } +} + +static void +show_tree(void) +{ + struct gmesh mesh; + struct gclass *classp; + struct ggeom *gp; + int error, width; + + error = geom_gettree(&mesh); + if (error != 0) + errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); + + width = compute_tree_width(&mesh); + + printf("%-*.*s %-*.*s %s\n", + width, width, "Geom", + GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, "Class", + "Provider"); + + LIST_FOREACH(classp, &mesh.lg_class, lg_class) { + LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { + if (!LIST_EMPTY(&gp->lg_consumer)) + continue; + show_tree_geom(&mesh, gp, 0, width); + } + } +} + int main(int argc, char *argv[]) { char *provider_name; + bool tflag; int ch; provider_name = NULL; + tflag = false; if (strcmp(getprogname(), "geom") == 0) { - while ((ch = getopt(argc, argv, "hp:")) != -1) { + while ((ch = getopt(argc, argv, "hp:t")) != -1) { switch (ch) { case 'p': provider_name = strdup(optarg); if (provider_name == NULL) err(1, "strdup"); break; + case 't': + tflag = true; + break; case 'h': default: usage(); @@ -699,11 +823,21 @@ main(int argc, char *argv[]) */ } + if (tflag && provider_name != NULL) { + errx(EXIT_FAILURE, + "At most one of -P and -t may be specified."); + } + if (provider_name != NULL) { list_one_geom_by_provider(provider_name); return (0); } + if (tflag) { + show_tree(); + return (0); + } + get_class(&argc, &argv); run_command(argc, argv); /* NOTREACHED */