diff --git a/lib/geom/mirror/geom_mirror.c b/lib/geom/mirror/geom_mirror.c --- a/lib/geom/mirror/geom_mirror.c +++ b/lib/geom/mirror/geom_mirror.c @@ -440,32 +440,30 @@ struct gconsumer *cp; off_t size; int error, nargs; - const char *name; + const char *name, *g; char ssize[30]; nargs = gctl_get_int(req, "nargs"); - if (nargs < 1) { - gctl_error(req, "Too few arguments."); - return; - } - error = geom_gettree(&mesh); - if (error) - errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); + if (nargs != 1) + errx(EXIT_FAILURE, "Invalid number of arguments."); name = gctl_get_ascii(req, "class"); if (name == NULL) abort(); + g = gctl_get_ascii(req, "arg0"); + if (g == NULL) + abort(); + error = geom_gettree_geom(&mesh, name, g, 1); + if (error) + errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); classp = find_class(&mesh, name); if (classp == NULL) errx(EXIT_FAILURE, "Class %s not found.", name); - name = gctl_get_ascii(req, "arg0"); - if (name == NULL) - abort(); - gp = find_geom(classp, name); + gp = find_geom(classp, g); if (gp == NULL) - errx(EXIT_FAILURE, "No such geom: %s.", name); + errx(EXIT_FAILURE, "No such geom: %s.", g); pp = LIST_FIRST(&gp->lg_provider); if (pp == NULL) - errx(EXIT_FAILURE, "Provider of geom %s not found.", name); + errx(EXIT_FAILURE, "Provider of geom %s not found.", g); size = pp->lg_mediasize; name = gctl_get_ascii(req, "size"); if (name == NULL) diff --git a/lib/geom/part/geom_part.c b/lib/geom/part/geom_part.c --- a/lib/geom/part/geom_part.c +++ b/lib/geom/part/geom_part.c @@ -329,31 +329,31 @@ struct gprovider *pp; off_t last, size, start, new_size; off_t lba, new_lba, alignment, offset; - const char *s; + const char *g, *s; int error, idx, has_alignment; idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX); if (idx < 1) errx(EXIT_FAILURE, "invalid partition index"); - error = geom_gettree(&mesh); - if (error) - return (error); s = gctl_get_ascii(req, "class"); if (s == NULL) abort(); + g = gctl_get_ascii(req, "arg0"); + if (g == NULL) + abort(); + error = geom_gettree_geom(&mesh, s, g, 1); + if (error) + return (error); cp = find_class(&mesh, s); if (cp == NULL) errx(EXIT_FAILURE, "Class %s not found.", s); - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(cp, s); + gp = find_geom(cp, g); if (gp == NULL) - errx(EXIT_FAILURE, "No such geom: %s.", s); + errx(EXIT_FAILURE, "No such geom: %s.", g); pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; if (pp == NULL) - errx(EXIT_FAILURE, "Provider for geom %s not found.", s); + errx(EXIT_FAILURE, "Provider for geom %s not found.", g); s = gctl_get_ascii(req, "alignment"); has_alignment = (*s == '*') ? 0 : 1; @@ -454,7 +454,7 @@ off_t size, start, a_lba; off_t lba, len, alignment, offset; uintmax_t grade; - const char *s; + const char *g, *s; int error, has_size, has_start, has_alignment; s = gctl_get_ascii(req, "verb"); @@ -463,22 +463,22 @@ if (strcmp(s, "add") != 0) return (0); - error = geom_gettree(&mesh); - if (error) - return (error); s = gctl_get_ascii(req, "class"); if (s == NULL) abort(); + g = gctl_get_ascii(req, "arg0"); + if (g == NULL) + abort(); + error = geom_gettree_geom(&mesh, s, g, 1); + if (error) + return (error); cp = find_class(&mesh, s); if (cp == NULL) errx(EXIT_FAILURE, "Class %s not found.", s); - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(cp, s); + gp = find_geom(cp, g); if (gp == NULL) { - if (g_device_path(s) == NULL) { - errx(EXIT_FAILURE, "No such geom %s.", s); + if (g_device_path(g) == NULL) { + errx(EXIT_FAILURE, "No such geom %s.", g); } else { /* * We don't free memory allocated by g_device_path() as @@ -486,12 +486,12 @@ */ errx(EXIT_FAILURE, "No partitioning scheme found on geom %s. Create one first using 'gpart create'.", - s); + g); } } pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; if (pp == NULL) - errx(EXIT_FAILURE, "Provider for geom %s not found.", s); + errx(EXIT_FAILURE, "Provider for geom %s not found.", g); s = gctl_get_ascii(req, "alignment"); has_alignment = (*s == '*') ? 0 : 1; @@ -742,7 +742,12 @@ name = gctl_get_ascii(req, "class"); if (name == NULL) abort(); - error = geom_gettree(&mesh); + nargs = gctl_get_int(req, "nargs"); + if (nargs == 1) { + error = geom_gettree_geom(&mesh, name, + gctl_get_ascii(req, "arg0"), 1); + } else + error = geom_gettree(&mesh); if (error != 0) errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); classp = find_class(&mesh, name); @@ -751,7 +756,6 @@ errx(EXIT_FAILURE, "Class %s not found.", name); } show_providers = gctl_get_int(req, "show_providers"); - nargs = gctl_get_int(req, "nargs"); if (nargs > 0) { for (i = 0; i < nargs; i++) { name = gctl_get_ascii(req, "arg%d", i); @@ -776,34 +780,33 @@ struct gclass *classp; struct gprovider *pp; struct ggeom *gp; - const char *s, *scheme; + const char *g, *s, *scheme; off_t sector, end; off_t length; int error, i, windex, wblocks, wtype; if (gctl_get_int(req, "nargs") != 1) errx(EXIT_FAILURE, "Invalid number of arguments."); - error = geom_gettree(&mesh); - if (error != 0) - errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); s = gctl_get_ascii(req, "class"); if (s == NULL) abort(); + g = gctl_get_ascii(req, "arg0"); + if (g == NULL) + abort(); + error = geom_gettree_geom(&mesh, s, g, 0); + if (error != 0) + errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); classp = find_class(&mesh, s); if (classp == NULL) { geom_deletetree(&mesh); errx(EXIT_FAILURE, "Class %s not found.", s); } - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(classp, s); + gp = find_geom(classp, g); if (gp == NULL) - errx(EXIT_FAILURE, "No such geom: %s.", s); + errx(EXIT_FAILURE, "No such geom: %s.", g); scheme = find_geomcfg(gp, "scheme"); if (scheme == NULL) abort(); - pp = LIST_FIRST(&gp->lg_consumer)->lg_provider; s = find_geomcfg(gp, "last"); if (s == NULL) abort(); @@ -1201,11 +1204,14 @@ struct gmesh mesh; struct gclass *classp; struct ggeom *gp; - const char *s; + const char *g, *s; void *bootcode, *partcode; size_t bootsize, partsize; int error, idx, vtoc8; + if (gctl_get_int(req, "nargs") != 1) + errx(EXIT_FAILURE, "Invalid number of arguments."); + if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) { s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE); bootsize = 800 * 1024; /* Arbitrary limit. */ @@ -1228,7 +1234,10 @@ s = gctl_get_ascii(req, "class"); if (s == NULL) abort(); - error = geom_gettree(&mesh); + g = gctl_get_ascii(req, "arg0"); + if (g == NULL) + abort(); + error = geom_gettree_geom(&mesh, s, g, 0); if (error != 0) errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); classp = find_class(&mesh, s); @@ -1236,14 +1245,9 @@ geom_deletetree(&mesh); errx(EXIT_FAILURE, "Class %s not found.", s); } - if (gctl_get_int(req, "nargs") != 1) - errx(EXIT_FAILURE, "Invalid number of arguments."); - s = gctl_get_ascii(req, "arg0"); - if (s == NULL) - abort(); - gp = find_geom(classp, s); + gp = find_geom(classp, g); if (gp == NULL) - errx(EXIT_FAILURE, "No such geom: %s.", s); + errx(EXIT_FAILURE, "No such geom: %s.", g); s = find_geomcfg(gp, "scheme"); if (s == NULL) errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name); diff --git a/lib/libgeom/geom_getxml.c b/lib/libgeom/geom_getxml.c --- a/lib/libgeom/geom_getxml.c +++ b/lib/libgeom/geom_getxml.c @@ -3,6 +3,7 @@ * * Copyright (c) 2003 Poul-Henning Kamp * All rights reserved. + * Copyright (c) 2022 Alexander Motin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -50,6 +51,13 @@ */ #define GEOM_GETXML_RETRIES 4 +/* + * Size of confxml buffer to request via getxml control request. It is + * expected to be sufficient for single geom and its parents. In case of + * overflow fall back to requesting full confxml via sysctl interface. + */ +#define GEOM_GETXML_BUFFER 65536 + char * geom_getxml(void) { @@ -87,3 +95,36 @@ return (NULL); } + +char * +geom_getxml_geom(const char *class, const char *geom, int parents) +{ + struct gctl_req *r; + char *p; + const char *errstr; + int nargs = 0; + + p = malloc(GEOM_GETXML_BUFFER); + if (p == NULL) + return (NULL); + r = gctl_get_handle(); + gctl_ro_param(r, "class", -1, class); + gctl_ro_param(r, "verb", -1, "getxml"); + gctl_ro_param(r, "parents", sizeof(parents), &parents); + if (geom) { + gctl_ro_param(r, "arg0", -1, geom); + nargs = 1; + } + gctl_ro_param(r, "nargs", sizeof(nargs), &nargs); + p[0] = '\0'; + gctl_add_param(r, "output", GEOM_GETXML_BUFFER, p, + GCTL_PARAM_WR | GCTL_PARAM_ASCII); + errstr = gctl_issue(r); + if (errstr != NULL && errstr[0] != '\0') { + gctl_free(r); + free(p); + return (geom_getxml()); + } + gctl_free(r); + return (p); +} diff --git a/lib/libgeom/geom_xml2tree.c b/lib/libgeom/geom_xml2tree.c --- a/lib/libgeom/geom_xml2tree.c +++ b/lib/libgeom/geom_xml2tree.c @@ -358,6 +358,17 @@ return (NULL); } +static void * +geom_lookupidptr(struct gmesh *gmp, const void *id) +{ + struct gident *gip; + + gip = geom_lookupid(gmp, id); + if (gip) + return (gip->lg_ptr); + return (NULL); +} + int geom_xml2tree(struct gmesh *gmp, char *p) { @@ -430,22 +441,19 @@ /* Substitute all identifiers */ LIST_FOREACH(cl, &gmp->lg_class, lg_class) { LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { - ge->lg_class = - geom_lookupid(gmp, ge->lg_class)->lg_ptr; - LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { - pr->lg_geom = - geom_lookupid(gmp, pr->lg_geom)->lg_ptr; - } + ge->lg_class = geom_lookupidptr(gmp, ge->lg_class); + LIST_FOREACH(pr, &ge->lg_provider, lg_provider) + pr->lg_geom = geom_lookupidptr(gmp, pr->lg_geom); LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { - co->lg_geom = - geom_lookupid(gmp, co->lg_geom)->lg_ptr; + co->lg_geom = geom_lookupidptr(gmp, co->lg_geom); if (co->lg_provider != NULL) { - co->lg_provider = - geom_lookupid(gmp, - co->lg_provider)->lg_ptr; - LIST_INSERT_HEAD( - &co->lg_provider->lg_consumers, - co, lg_consumers); + co->lg_provider = geom_lookupidptr(gmp, + co->lg_provider); + if (co->lg_provider != NULL) { + LIST_INSERT_HEAD( + &co->lg_provider->lg_consumers, + co, lg_consumers); + } } } } @@ -467,6 +475,20 @@ return (error); } +int +geom_gettree_geom(struct gmesh *gmp, const char *c, const char *g, int parents) +{ + char *p; + int error; + + p = geom_getxml_geom(c, g, parents); + if (p == NULL) + return (errno); + error = geom_xml2tree(gmp, p); + free(p); + return (error); +} + static void delete_config(struct gconf *gp) { diff --git a/lib/libgeom/libgeom.h b/lib/libgeom/libgeom.h --- a/lib/libgeom/libgeom.h +++ b/lib/libgeom/libgeom.h @@ -56,6 +56,7 @@ struct devstat *geom_stats_snapshot_next(void *); char *geom_getxml(void); +char *geom_getxml_geom(const char *, const char *, int); /* geom_xml2tree.c */ @@ -137,6 +138,7 @@ struct gident * geom_lookupid(struct gmesh *, const void *); int geom_xml2tree(struct gmesh *, char *); int geom_gettree(struct gmesh *); +int geom_gettree_geom(struct gmesh *, const char *, const char *, int); void geom_deletetree(struct gmesh *); /* geom_ctl.c */ diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c --- a/sbin/geom/core/geom.c +++ b/sbin/geom/core/geom.c @@ -996,7 +996,7 @@ struct gclass *classp; int error; - error = geom_gettree(&mesh); + error = geom_gettree_geom(&mesh, gclass_name, "", 0); if (error != 0) errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); classp = find_class(&mesh, gclass_name); @@ -1015,7 +1015,12 @@ const char *name; int all, error, i, nargs; - error = geom_gettree(&mesh); + nargs = gctl_get_int(req, "nargs"); + if (nargs == 1) { + error = geom_gettree_geom(&mesh, gclass_name, + gctl_get_ascii(req, "arg0"), 1); + } else + error = geom_gettree(&mesh); if (error != 0) errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); classp = find_class(&mesh, gclass_name); @@ -1023,7 +1028,6 @@ geom_deletetree(&mesh); errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name); } - nargs = gctl_get_int(req, "nargs"); all = gctl_get_int(req, "all"); if (nargs > 0) { for (i = 0; i < nargs; i++) { diff --git a/sys/geom/geom.h b/sys/geom/geom.h --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -431,6 +431,7 @@ int gctl_set_param(struct gctl_req *req, const char *param, void const *ptr, int len); void gctl_set_param_err(struct gctl_req *req, const char *param, void const *ptr, int len); void *gctl_get_param(struct gctl_req *req, const char *param, int *len); +void *gctl_get_param_flags(struct gctl_req *req, const char *param, int flags, int *len); char const *gctl_get_asciiparam(struct gctl_req *req, const char *param); void *gctl_get_paraml(struct gctl_req *req, const char *param, int len); void *gctl_get_paraml_opt(struct gctl_req *req, const char *param, int len); diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c --- a/sys/geom/geom_ctl.c +++ b/sys/geom/geom_ctl.c @@ -4,6 +4,7 @@ * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. + * Copyright (c) 2022 Alexander Motin * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. @@ -363,7 +364,7 @@ } void * -gctl_get_param(struct gctl_req *req, const char *param, int *len) +gctl_get_param_flags(struct gctl_req *req, const char *param, int flags, int *len) { u_int i; void *p; @@ -373,7 +374,7 @@ ap = &req->arg[i]; if (strcmp(param, ap->name)) continue; - if (!(ap->flag & GCTL_PARAM_RD)) + if ((ap->flag & flags) != flags) continue; p = ap->kvalue; if (len != NULL) @@ -383,31 +384,31 @@ return (NULL); } +void * +gctl_get_param(struct gctl_req *req, const char *param, int *len) +{ + + return (gctl_get_param_flags(req, param, GCTL_PARAM_RD, len)); +} + char const * gctl_get_asciiparam(struct gctl_req *req, const char *param) { - u_int i; char const *p; - struct gctl_req_arg *ap; + int len; - for (i = 0; i < req->narg; i++) { - ap = &req->arg[i]; - if (strcmp(param, ap->name)) - continue; - if (!(ap->flag & GCTL_PARAM_RD)) - continue; - p = ap->kvalue; - if (ap->len < 1) { - gctl_error(req, "No length argument (%s)", param); - return (NULL); - } - if (p[ap->len - 1] != '\0') { - gctl_error(req, "Unterminated argument (%s)", param); - return (NULL); - } - return (p); + p = gctl_get_param_flags(req, param, GCTL_PARAM_RD, &len); + if (p == NULL) + return (NULL); + if (len < 1) { + gctl_error(req, "Argument without length (%s)", param); + return (NULL); } - return (NULL); + if (p[len - 1] != '\0') { + gctl_error(req, "Unterminated argument (%s)", param); + return (NULL); + } + return (p); } void * @@ -491,6 +492,62 @@ return (NULL); } +static void +g_ctl_getxml(struct gctl_req *req, struct g_class *mp) +{ + const char *name; + char *buf; + struct sbuf *sb; + int len, i = 0, n = 0, *parents; + struct g_geom *gp, **gps; + struct g_consumer *cp; + + parents = gctl_get_paraml(req, "parents", sizeof(*parents)); + if (parents == NULL) + return; + name = gctl_get_asciiparam(req, "arg0"); + n = 0; + LIST_FOREACH(gp, &mp->geom, geom) { + if (name && strcmp(gp->name, name) != 0) + continue; + n++; + if (*parents) { + LIST_FOREACH(cp, &gp->consumer, consumer) + n++; + } + } + gps = g_malloc((n + 1) * sizeof(*gps), M_WAITOK); + i = 0; + LIST_FOREACH(gp, &mp->geom, geom) { + if (name && strcmp(gp->name, name) != 0) + continue; + gps[i++] = gp; + if (*parents) { + LIST_FOREACH(cp, &gp->consumer, consumer) { + if (cp->provider != NULL) + gps[i++] = cp->provider->geom; + } + } + } + KASSERT(i == n, ("different number of geoms found (%d != %d)", + i, n)); + gps[i] = 0; + + buf = gctl_get_param_flags(req, "output", GCTL_PARAM_WR, &len); + if (buf == NULL) { + gctl_error(req, "output parameter missing"); + g_free(gps); + return; + } + sb = sbuf_new(NULL, buf, len, SBUF_FIXEDLEN | SBUF_INCLUDENUL); + g_conf_specific(sb, gps); + gctl_set_param(req, "output", buf, 0); + if (sbuf_error(sb)) + gctl_error(req, "output buffer overflow"); + sbuf_delete(sb); + g_free(gps); +} + static void g_ctl_req(void *arg, int flag __unused) { @@ -503,16 +560,18 @@ mp = gctl_get_class(req, "class"); if (mp == NULL) return; - if (mp->ctlreq == NULL) { - gctl_error(req, "Class takes no requests"); - return; - } verb = gctl_get_param(req, "verb", NULL); if (verb == NULL) { gctl_error(req, "Verb missing"); return; } - mp->ctlreq(req, mp, verb); + if (strcmp(verb, "getxml") == 0) { + g_ctl_getxml(req, mp); + } else if (mp->ctlreq == NULL) { + gctl_error(req, "Class takes no requests"); + } else { + mp->ctlreq(req, mp, verb); + } g_topology_assert(); } diff --git a/sys/geom/geom_dump.c b/sys/geom/geom_dump.c --- a/sys/geom/geom_dump.c +++ b/sys/geom/geom_dump.c @@ -4,6 +4,7 @@ * Copyright (c) 2002 Poul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. + * Copyright (c) 2013-2022 Alexander Motin * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. @@ -242,10 +243,10 @@ } static void -g_conf_geom(struct sbuf *sb, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp) +g_conf_geom(struct sbuf *sb, struct g_geom *gp) { - struct g_consumer *cp2; - struct g_provider *pp2; + struct g_consumer *cp; + struct g_provider *pp; sbuf_printf(sb, " \n", gp); sbuf_printf(sb, " \n", gp->class); @@ -260,48 +261,56 @@ gp->dumpconf(sb, "\t", gp, NULL, NULL); sbuf_cat(sb, " \n"); } - LIST_FOREACH(cp2, &gp->consumer, consumer) { - if (cp != NULL && cp != cp2) - continue; - g_conf_consumer(sb, cp2); - } + LIST_FOREACH(cp, &gp->consumer, consumer) + g_conf_consumer(sb, cp); + LIST_FOREACH(pp, &gp->provider, provider) + g_conf_provider(sb, pp); + sbuf_cat(sb, " \n"); +} - LIST_FOREACH(pp2, &gp->provider, provider) { - if (pp != NULL && pp != pp2) - continue; - g_conf_provider(sb, pp2); +static bool +g_conf_matchgp(struct g_geom *gp, struct g_geom **gps) +{ + + if (gps == NULL) + return (true); + for (; *gps != NULL; gps++) { + if (*gps == gp) + return (true); } - sbuf_cat(sb, " \n"); + return (false); } static void -g_conf_class(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp) +g_conf_class(struct sbuf *sb, struct g_class *mp, struct g_geom **gps) { - struct g_geom *gp2; + struct g_geom *gp; sbuf_printf(sb, " \n", mp); sbuf_cat(sb, " "); g_conf_cat_escaped(sb, mp->name); sbuf_cat(sb, "\n"); - LIST_FOREACH(gp2, &mp->geom, geom) { - if (gp != NULL && gp != gp2) + LIST_FOREACH(gp, &mp->geom, geom) { + if (!g_conf_matchgp(gp, gps)) continue; - g_conf_geom(sb, gp2, pp, cp); + g_conf_geom(sb, gp); + if (sbuf_error(sb)) + break; } sbuf_cat(sb, " \n"); } void -g_conf_specific(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp) +g_conf_specific(struct sbuf *sb, struct g_geom **gps) { struct g_class *mp2; g_topology_assert(); sbuf_cat(sb, "\n"); LIST_FOREACH(mp2, &g_classes, class) { - if (mp != NULL && mp != mp2) - continue; - g_conf_class(sb, mp2, gp, pp, cp); + g_conf_class(sb, mp2, gps); + if (sbuf_error(sb)) + break; } sbuf_cat(sb, "\n"); sbuf_finish(sb); @@ -313,7 +322,7 @@ KASSERT(flag != EV_CANCEL, ("g_confxml was cancelled")); g_topology_assert(); - g_conf_specific(p, NULL, NULL, NULL, NULL); + g_conf_specific(p, NULL); } void diff --git a/sys/geom/geom_int.h b/sys/geom/geom_int.h --- a/sys/geom/geom_int.h +++ b/sys/geom/geom_int.h @@ -46,7 +46,7 @@ /* geom_dump.c */ void g_confxml(void *, int flag); -void g_conf_specific(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp); +void g_conf_specific(struct sbuf *sb, struct g_geom **gps); void g_conf_cat_escaped(struct sbuf *sb, const char *buf); void g_conf_printf_escaped(struct sbuf *sb, const char *fmt, ...); void g_confdot(void *, int flag);