diff options
Diffstat (limited to 'lib/libgeom')
-rw-r--r-- | lib/libgeom/Makefile | 36 | ||||
-rw-r--r-- | lib/libgeom/geom_ctl.c | 238 | ||||
-rw-r--r-- | lib/libgeom/geom_getxml.c | 66 | ||||
-rw-r--r-- | lib/libgeom/geom_stats.c | 185 | ||||
-rw-r--r-- | lib/libgeom/geom_xml2tree.c | 441 | ||||
-rw-r--r-- | lib/libgeom/libgeom.3 | 258 | ||||
-rw-r--r-- | lib/libgeom/libgeom.h | 149 |
7 files changed, 1373 insertions, 0 deletions
diff --git a/lib/libgeom/Makefile b/lib/libgeom/Makefile new file mode 100644 index 0000000..c64ce50 --- /dev/null +++ b/lib/libgeom/Makefile @@ -0,0 +1,36 @@ +# $FreeBSD$ + +LIB= geom +SHLIBDIR?= /lib +SRCS+= geom_getxml.c +SRCS+= geom_stats.c +SRCS+= geom_xml2tree.c +SRCS+= geom_ctl.c +INCS= libgeom.h + +CFLAGS += -I${.CURDIR} + +WARNS?= 3 + +DPADD= ${LIBBSDXML} ${LIBSBUF} +LDADD= -lbsdxml -lsbuf + +MAN= libgeom.3 + +MLINKS+= \ + libgeom.3 geom_stats_open.3 \ + libgeom.3 geom_stats_close.3 \ + libgeom.3 geom_stats_resync.3 \ + libgeom.3 geom_stats_snapshot_get.3 \ + libgeom.3 geom_stats_snapshot_free.3 \ + libgeom.3 geom_stats_snapshot_timestamp.3 \ + libgeom.3 geom_stats_snapshot_reset.3 \ + libgeom.3 geom_stats_snapshot_next.3 \ + libgeom.3 gctl_get_handle.3 \ + libgeom.3 gctl_ro_param.3 \ + libgeom.3 gctl_rw_param.3 \ + libgeom.3 gctl_issue.3 \ + libgeom.3 gctl_free.3 \ + libgeom.3 gctl_dump.3 + +.include <bsd.lib.mk> diff --git a/lib/libgeom/geom_ctl.c b/lib/libgeom/geom_ctl.c new file mode 100644 index 0000000..d308849 --- /dev/null +++ b/lib/libgeom/geom_ctl.c @@ -0,0 +1,238 @@ +/*- + * Copyright (c) 2003 Poul-Henning Kamp + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <stdint.h> +#include <sys/types.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <paths.h> + +#include <sys/queue.h> + +#define GCTL_TABLE 1 +#include <libgeom.h> + +void +gctl_dump(struct gctl_req *req, FILE *f) +{ + u_int i; + int j; + struct gctl_req_arg *ap; + + if (req == NULL) { + fprintf(f, "Dump of gctl request at NULL\n"); + return; + } + fprintf(f, "Dump of gctl request at %p:\n", req); + if (req->error != NULL) + fprintf(f, " error:\t\"%s\"\n", req->error); + else + fprintf(f, " error:\tNULL\n"); + for (i = 0; i < req->narg; i++) { + ap = &req->arg[i]; + fprintf(f, " param:\t\"%s\" (%d)", ap->name, ap->nlen); + fprintf(f, " [%s%s", + ap->flag & GCTL_PARAM_RD ? "R" : "", + ap->flag & GCTL_PARAM_WR ? "W" : ""); + fflush(f); + if (ap->flag & GCTL_PARAM_ASCII) + fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value); + else if (ap->len > 0) { + fprintf(f, "%d] = ", ap->len); + fflush(f); + for (j = 0; j < ap->len; j++) { + fprintf(f, " %02x", ((u_char *)ap->value)[j]); + } + } else { + fprintf(f, "0] = %p", ap->value); + } + fprintf(f, "\n"); + } +} + +/* + * Set an error message, if one does not already exist. + */ +static void +gctl_set_error(struct gctl_req *req, const char *error, ...) +{ + va_list ap; + + if (req->error != NULL) + return; + va_start(ap, error); + vasprintf(&req->error, error, ap); + va_end(ap); +} + +/* + * Check that a malloc operation succeeded, and set a consistent error + * message if not. + */ +static void +gctl_check_alloc(struct gctl_req *req, void *ptr) +{ + if (ptr != NULL) + return; + gctl_set_error(req, "Could not allocate memory"); + if (req->error == NULL) + req->error = "Could not allocate memory"; +} + +/* + * Allocate a new request handle of the specified type. + * XXX: Why bother checking the type ? + */ +struct gctl_req * +gctl_get_handle(void) +{ + struct gctl_req *rp; + + rp = calloc(1, sizeof *rp); + return (rp); +} + +/* + * Allocate space for another argument. + */ +static struct gctl_req_arg * +gctl_new_arg(struct gctl_req *req) +{ + struct gctl_req_arg *ap; + + req->narg++; + req->arg = realloc(req->arg, sizeof *ap * req->narg); + gctl_check_alloc(req, req->arg); + if (req->arg == NULL) { + req->narg = 0; + return (NULL); + } + ap = req->arg + (req->narg - 1); + memset(ap, 0, sizeof *ap); + return (ap); +} + +void +gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value) +{ + struct gctl_req_arg *ap; + + if (req == NULL || req->error != NULL) + return; + ap = gctl_new_arg(req); + if (ap == NULL) + return; + ap->name = strdup(name); + gctl_check_alloc(req, ap->name); + ap->nlen = strlen(ap->name) + 1; + ap->value = __DECONST(void *, value); + ap->flag = GCTL_PARAM_RD; + if (len >= 0) + ap->len = len; + else if (len < 0) { + ap->flag |= GCTL_PARAM_ASCII; + ap->len = strlen(value) + 1; + } +} + +void +gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value) +{ + struct gctl_req_arg *ap; + + if (req == NULL || req->error != NULL) + return; + ap = gctl_new_arg(req); + if (ap == NULL) + return; + ap->name = strdup(name); + gctl_check_alloc(req, ap->name); + ap->nlen = strlen(ap->name) + 1; + ap->value = value; + ap->flag = GCTL_PARAM_RW; + if (len >= 0) + ap->len = len; + else if (len < 0) + ap->len = strlen(value) + 1; +} + +const char * +gctl_issue(struct gctl_req *req) +{ + int fd, error; + + if (req == NULL) + return ("NULL request pointer"); + if (req->error != NULL) + return (req->error); + + req->version = GCTL_VERSION; + req->lerror = BUFSIZ; /* XXX: arbitrary number */ + req->error = malloc(req->lerror); + if (req->error == NULL) { + gctl_check_alloc(req, req->error); + return (req->error); + } + memset(req->error, 0, req->lerror); + req->lerror--; + fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY); + if (fd < 0) + return(strerror(errno)); + error = ioctl(fd, GEOM_CTL, req); + close(fd); + if (req->error[0] != '\0') + return (req->error); + if (error != 0) + return(strerror(errno)); + return (NULL); +} + +void +gctl_free(struct gctl_req *req) +{ + u_int i; + + if (req == NULL) + return; + for (i = 0; i < req->narg; i++) { + if (req->arg[i].name != NULL) + free(req->arg[i].name); + } + free(req->arg); + if (req->error != NULL) + free(req->error); + free(req); +} diff --git a/lib/libgeom/geom_getxml.c b/lib/libgeom/geom_getxml.c new file mode 100644 index 0000000..fbc9cb8 --- /dev/null +++ b/lib/libgeom/geom_getxml.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2003 Poul-Henning Kamp + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <stdlib.h> +#include <string.h> +#include "libgeom.h" + +char * +geom_getxml() +{ + char *p; + size_t l; + int i; + + l = 1024 * 1024; /* Start big, realloc back */ + p = malloc(l); + if (p) { + i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0); + if (i == 0) { + p = realloc(p, strlen(p) + 1); + return (p); + } + free(p); + } + l = 0; + i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0); + if (i != 0) + return (NULL); + p = malloc(l + 4096); + i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0); + if (i == 0) { + p = realloc(p, strlen(p) + 1); + return (p); + } + return (NULL); +} diff --git a/lib/libgeom/geom_stats.c b/lib/libgeom/geom_stats.c new file mode 100644 index 0000000..14f9b22 --- /dev/null +++ b/lib/libgeom/geom_stats.c @@ -0,0 +1,185 @@ +/*- + * Copyright (c) 2003 Poul-Henning Kamp + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <paths.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <libgeom.h> + +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/devicestat.h> + + +/************************************************************/ +static uint npages, pagesize, spp; +static int statsfd = -1; +static u_char *statp; + +void +geom_stats_close(void) +{ + if (statsfd == -1) + return; + munmap(statp, npages *pagesize); + statp = NULL; + close (statsfd); + statsfd = -1; +} + +void +geom_stats_resync(void) +{ + void *p; + + if (statsfd == -1) + return; + for (;;) { + p = mmap(statp, (npages + 1) * pagesize, + PROT_READ, 0, statsfd, 0); + if (p == MAP_FAILED) + break; + else + statp = p; + npages++; + } +} + +int +geom_stats_open(void) +{ + int error; + void *p; + + if (statsfd != -1) + return (EBUSY); + statsfd = open(_PATH_DEV DEVSTAT_DEVICE_NAME, O_RDONLY); + if (statsfd < 0) + return (errno); + pagesize = getpagesize(); + spp = pagesize / sizeof(struct devstat); + p = mmap(NULL, pagesize, PROT_READ, 0, statsfd, 0); + if (p == MAP_FAILED) { + error = errno; + close(statsfd); + statsfd = -1; + errno = error; + return (error); + } + statp = p; + npages = 1; + geom_stats_resync(); + return (0); +} + +struct snapshot { + u_char *ptr; + uint pages; + uint pagesize; + uint perpage; + struct timespec time; + /* used by getnext: */ + uint u, v; +}; + +void * +geom_stats_snapshot_get(void) +{ + struct snapshot *sp; + + sp = malloc(sizeof *sp); + if (sp == NULL) + return (NULL); + memset(sp, 0, sizeof *sp); + sp->ptr = malloc(pagesize * npages); + if (sp->ptr == NULL) { + free(sp); + return (NULL); + } + memset(sp->ptr, 0, pagesize * npages); /* page in, cache */ + clock_gettime(CLOCK_REALTIME, &sp->time); + memset(sp->ptr, 0, pagesize * npages); /* page in, cache */ + memcpy(sp->ptr, statp, pagesize * npages); + sp->pages = npages; + sp->perpage = spp; + sp->pagesize = pagesize; + return (sp); +} + +void +geom_stats_snapshot_free(void *arg) +{ + struct snapshot *sp; + + sp = arg; + free(sp->ptr); + free(sp); +} + +void +geom_stats_snapshot_timestamp(void *arg, struct timespec *tp) +{ + struct snapshot *sp; + + sp = arg; + *tp = sp->time; +} + +void +geom_stats_snapshot_reset(void *arg) +{ + struct snapshot *sp; + + sp = arg; + sp->u = sp->v = 0; +} + +struct devstat * +geom_stats_snapshot_next(void *arg) +{ + struct devstat *gsp; + struct snapshot *sp; + + sp = arg; + gsp = (struct devstat *) + (sp->ptr + sp->u * pagesize + sp->v * sizeof *gsp); + if (++sp->v >= sp->perpage) { + if (++sp->u >= sp->pages) + return (NULL); + else + sp->v = 0; + } + return (gsp); +} diff --git a/lib/libgeom/geom_xml2tree.c b/lib/libgeom/geom_xml2tree.c new file mode 100644 index 0000000..7798f44 --- /dev/null +++ b/lib/libgeom/geom_xml2tree.c @@ -0,0 +1,441 @@ +/*- + * Copyright (c) 2003 Poul-Henning Kamp + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <stdio.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/queue.h> +#include <sys/sbuf.h> +#include <sys/sysctl.h> +#include <err.h> +#include <bsdxml.h> +#include <libgeom.h> + +struct mystate { + struct gmesh *mesh; + struct gclass *class; + struct ggeom *geom; + struct gprovider *provider; + struct gconsumer *consumer; + int level; + struct sbuf *sbuf[20]; + struct gconf *config; + int nident; +}; + +static void +StartElement(void *userData, const char *name, const char **attr) +{ + struct mystate *mt; + void *id; + void *ref; + int i; + + mt = userData; + mt->level++; + mt->sbuf[mt->level] = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + id = NULL; + ref = NULL; + for (i = 0; attr[i] != NULL; i += 2) { + if (!strcmp(attr[i], "id")) { + id = (void *)strtoul(attr[i + 1], NULL, 0); + mt->nident++; + } else if (!strcmp(attr[i], "ref")) { + ref = (void *)strtoul(attr[i + 1], NULL, 0); + } else + printf("%*.*s[%s = %s]\n", + mt->level + 1, mt->level + 1, "", + attr[i], attr[i + 1]); + } + if (!strcmp(name, "class") && mt->class == NULL) { + mt->class = calloc(1, sizeof *mt->class); + mt->class->lg_id = id; + LIST_INSERT_HEAD(&mt->mesh->lg_class, mt->class, lg_class); + LIST_INIT(&mt->class->lg_geom); + LIST_INIT(&mt->class->lg_config); + return; + } + if (!strcmp(name, "geom") && mt->geom == NULL) { + mt->geom = calloc(1, sizeof *mt->geom); + mt->geom->lg_id = id; + LIST_INSERT_HEAD(&mt->class->lg_geom, mt->geom, lg_geom); + LIST_INIT(&mt->geom->lg_provider); + LIST_INIT(&mt->geom->lg_consumer); + LIST_INIT(&mt->geom->lg_config); + return; + } + if (!strcmp(name, "class") && mt->geom != NULL) { + mt->geom->lg_class = ref; + return; + } + if (!strcmp(name, "consumer") && mt->consumer == NULL) { + mt->consumer = calloc(1, sizeof *mt->consumer); + mt->consumer->lg_id = id; + LIST_INSERT_HEAD(&mt->geom->lg_consumer, mt->consumer, + lg_consumer); + LIST_INIT(&mt->consumer->lg_config); + return; + } + if (!strcmp(name, "geom") && mt->consumer != NULL) { + mt->consumer->lg_geom = ref; + return; + } + if (!strcmp(name, "provider") && mt->consumer != NULL) { + mt->consumer->lg_provider = ref; + return; + } + if (!strcmp(name, "provider") && mt->provider == NULL) { + mt->provider = calloc(1, sizeof *mt->provider); + mt->provider->lg_id = id; + LIST_INSERT_HEAD(&mt->geom->lg_provider, mt->provider, + lg_provider); + LIST_INIT(&mt->provider->lg_consumers); + LIST_INIT(&mt->provider->lg_config); + return; + } + if (!strcmp(name, "geom") && mt->provider != NULL) { + mt->provider->lg_geom = ref; + return; + } + if (!strcmp(name, "config")) { + if (mt->provider != NULL) { + mt->config = &mt->provider->lg_config; + return; + } + if (mt->consumer != NULL) { + mt->config = &mt->consumer->lg_config; + return; + } + if (mt->geom != NULL) { + mt->config = &mt->geom->lg_config; + return; + } + if (mt->class != NULL) { + mt->config = &mt->class->lg_config; + return; + } + } +} + +static void +EndElement(void *userData, const char *name) +{ + struct mystate *mt; + struct gconfig *gc; + char *p; + + mt = userData; + sbuf_finish(mt->sbuf[mt->level]); + p = strdup(sbuf_data(mt->sbuf[mt->level])); + sbuf_delete(mt->sbuf[mt->level]); + mt->sbuf[mt->level] = NULL; + mt->level--; + if (strlen(p) == 0) { + free(p); + p = NULL; + } + + if (!strcmp(name, "name")) { + if (mt->provider != NULL) { + mt->provider->lg_name = p; + return; + } else if (mt->geom != NULL) { + mt->geom->lg_name = p; + return; + } else if (mt->class != NULL) { + mt->class->lg_name = p; + return; + } + } + if (!strcmp(name, "rank") && mt->geom != NULL) { + mt->geom->lg_rank = strtoul(p, NULL, 0); + free(p); + return; + } + if (!strcmp(name, "mode") && mt->provider != NULL) { + mt->provider->lg_mode = p; + return; + } + if (!strcmp(name, "mode") && mt->consumer != NULL) { + mt->consumer->lg_mode = p; + return; + } + if (!strcmp(name, "mediasize") && mt->provider != NULL) { + mt->provider->lg_mediasize = strtoumax(p, NULL, 0); + free(p); + return; + } + if (!strcmp(name, "sectorsize") && mt->provider != NULL) { + mt->provider->lg_sectorsize = strtoul(p, NULL, 0); + free(p); + return; + } + + if (!strcmp(name, "config")) { + mt->config = NULL; + return; + } + + if (mt->config != NULL) { + gc = calloc(sizeof *gc, 1); + gc->lg_name = strdup(name); + gc->lg_val = p; + LIST_INSERT_HEAD(mt->config, gc, lg_config); + return; + } + + if (p != NULL) { + printf("Unexpected XML: name=%s data=\"%s\"\n", name, p); + free(p); + } + + if (!strcmp(name, "consumer") && mt->consumer != NULL) { + mt->consumer = NULL; + return; + } + if (!strcmp(name, "provider") && mt->provider != NULL) { + mt->provider = NULL; + return; + } + if (!strcmp(name, "geom") && mt->consumer != NULL) { + return; + } + if (!strcmp(name, "geom") && mt->provider != NULL) { + return; + } + if (!strcmp(name, "geom") && mt->geom != NULL) { + mt->geom = NULL; + return; + } + if (!strcmp(name, "class") && mt->geom != NULL) { + return; + } + if (!strcmp(name, "class") && mt->class != NULL) { + mt->class = NULL; + return; + } +} + +static void +CharData(void *userData , const XML_Char *s , int len) +{ + struct mystate *mt; + const char *b, *e; + + mt = userData; + + b = s; + e = s + len - 1; + while (isspace(*b) && b < e) + b++; + while (isspace(*e) && e > b) + e--; + if (e != b || (*b && !isspace(*b))) + sbuf_bcat(mt->sbuf[mt->level], b, e - b + 1); +} + +struct gident * +geom_lookupid(struct gmesh *gmp, const void *id) +{ + struct gident *gip; + + for (gip = gmp->lg_ident; gip->lg_id != NULL; gip++) + if (gip->lg_id == id) + return (gip); + return (NULL); +} + +int +geom_xml2tree(struct gmesh *gmp, char *p) +{ + XML_Parser parser; + struct mystate *mt; + struct gclass *cl; + struct ggeom *ge; + struct gprovider *pr; + struct gconsumer *co; + int i; + + memset(gmp, 0, sizeof *gmp); + LIST_INIT(&gmp->lg_class); + parser = XML_ParserCreate(NULL); + mt = calloc(1, sizeof *mt); + if (mt == NULL) + return (ENOMEM); + mt->mesh = gmp; + XML_SetUserData(parser, mt); + XML_SetElementHandler(parser, StartElement, EndElement); + XML_SetCharacterDataHandler(parser, CharData); + i = XML_Parse(parser, p, strlen(p), 1); + if (i != 1) + return (-1); + XML_ParserFree(parser); + gmp->lg_ident = calloc(sizeof *gmp->lg_ident, mt->nident + 1); + if (gmp->lg_ident == NULL) + return (ENOMEM); + free(mt); + i = 0; + /* Collect all identifiers */ + LIST_FOREACH(cl, &gmp->lg_class, lg_class) { + gmp->lg_ident[i].lg_id = cl->lg_id; + gmp->lg_ident[i].lg_ptr = cl; + gmp->lg_ident[i].lg_what = ISCLASS; + i++; + LIST_FOREACH(ge, &cl->lg_geom, lg_geom) { + gmp->lg_ident[i].lg_id = ge->lg_id; + gmp->lg_ident[i].lg_ptr = ge; + gmp->lg_ident[i].lg_what = ISGEOM; + i++; + LIST_FOREACH(pr, &ge->lg_provider, lg_provider) { + gmp->lg_ident[i].lg_id = pr->lg_id; + gmp->lg_ident[i].lg_ptr = pr; + gmp->lg_ident[i].lg_what = ISPROVIDER; + i++; + } + LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { + gmp->lg_ident[i].lg_id = co->lg_id; + gmp->lg_ident[i].lg_ptr = co; + gmp->lg_ident[i].lg_what = ISCONSUMER; + i++; + } + } + } + /* 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; + } + LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) { + co->lg_geom = + geom_lookupid(gmp, co->lg_geom)->lg_ptr; + 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); + } + } + } + } + return (0); +} + +int +geom_gettree(struct gmesh *gmp) +{ + char *p; + int error; + + p = geom_getxml(); + if (p == NULL) + return (errno); + error = geom_xml2tree(gmp, p); + free(p); + return (error); +} + +static void +delete_config(struct gconf *gp) +{ + struct gconfig *cf; + + for (;;) { + cf = LIST_FIRST(gp); + if (cf == NULL) + return; + LIST_REMOVE(cf, lg_config); + free(cf->lg_name); + free(cf->lg_val); + free(cf); + } +} + +void +geom_deletetree(struct gmesh *gmp) +{ + struct gclass *cl; + struct ggeom *ge; + struct gprovider *pr; + struct gconsumer *co; + + free(gmp->lg_ident); + gmp->lg_ident = NULL; + for (;;) { + cl = LIST_FIRST(&gmp->lg_class); + if (cl == NULL) + break; + LIST_REMOVE(cl, lg_class); + delete_config(&cl->lg_config); + if (cl->lg_name) free(cl->lg_name); + for (;;) { + ge = LIST_FIRST(&cl->lg_geom); + if (ge == NULL) + break; + LIST_REMOVE(ge, lg_geom); + delete_config(&ge->lg_config); + if (ge->lg_name) free(ge->lg_name); + for (;;) { + pr = LIST_FIRST(&ge->lg_provider); + if (pr == NULL) + break; + LIST_REMOVE(pr, lg_provider); + delete_config(&pr->lg_config); + if (pr->lg_name) free(pr->lg_name); + if (pr->lg_mode) free(pr->lg_mode); + free(pr); + } + for (;;) { + co = LIST_FIRST(&ge->lg_consumer); + if (co == NULL) + break; + LIST_REMOVE(co, lg_consumer); + delete_config(&co->lg_config); + if (co->lg_mode) free(co->lg_mode); + free(co); + } + free(ge); + } + free(cl); + } +} diff --git a/lib/libgeom/libgeom.3 b/lib/libgeom/libgeom.3 new file mode 100644 index 0000000..9172a00 --- /dev/null +++ b/lib/libgeom/libgeom.3 @@ -0,0 +1,258 @@ +.\" Copyright (c) 2003 Poul-Henning Kamp +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The names of the authors may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd March 7, 2004 +.Dt LIBGEOM 3 +.Os +.Sh NAME +.Nm geom_stats_open , +.Nm geom_stats_close , +.Nm geom_stats_resync , +.Nm geom_stats_snapshot_get , +.Nm geom_stats_snapshot_free , +.Nm geom_stats_snapshot_timestamp , +.Nm geom_stats_snapshot_reset , +.Nm geom_stats_snapshot_next , +.Nm gctl_get_handle , +.Nm gctl_ro_param , +.Nm gctl_rw_param , +.Nm gctl_issue , +.Nm gctl_free , +.Nm gctl_dump +.Nd userland API library for kernel GEOM subsystem +.Sh LIBRARY +.Lb libgeom +.Sh SYNOPSIS +.In libgeom.h +.Ss "Statistics Functions" +.Ft void +.Fn geom_stats_close void +.Ft int +.Fn geom_stats_open void +.Ft void +.Fn geom_stats_resync void +.Ft "void *" +.Fn geom_stats_snapshot_get void +.Ft void +.Fn geom_stats_snapshot_free "void *arg" +.Ft void +.Fn geom_stats_snapshot_timestamp "void *arg" "struct timespec *tp" +.Ft void +.Fn geom_stats_snapshot_reset "void *arg" +.Ft "struct devstat *" +.Fn geom_stats_snapshot_next "void *arg" +.Ss "Control Functions" +.Ft "struct gctl_req *" +.Fn gctl_get_handle "void" +.Ft void +.Fn gctl_ro_param "struct gctl_req *req" "const char *name" "int len" "const void *value" +.Ft void +.Fn gctl_rw_param "struct gctl_req *req" "const char *name" "int len" "void *value" +.Ft "const char *" +.Fn gctl_issue "struct gctl_req *req" +.Ft void +.Fn gctl_free "struct gctl_req *req" +.Ft void +.Fn gctl_dump "struct gctl_req *req" "FILE *f" +.Sh DESCRIPTION +The +.Nm geom +library contains the official and publicized API for +interacting with the GEOM subsystem in the kernel. +.Ss "Statistics Functions" +GEOM collects statistics data for all consumers and providers, but does +not perform any normalization or presentation on the raw data, this is +left as an excercize for user-land presentation utilities. +.Pp +The +.Fn geom_stats_open +and +.Fn geom_stats_close +functions open and close the necessary pathways to access the raw +statistics information in the kernel. +These functions are likely to +open one or more files and cache the file descriptors locally. +The +.Fn geom_stats_open +function returns zero on success, and sets +.Va errno +if not. +.Pp +The +.Fn geom_stats_resync +function will check if more statistics collection points have been +added in the kernel since +.Fn geom_stats_open +or the previous call to +.Fn geom_stats_resync . +.Pp +The +.Fn geom_stats_snapshot_get +function +will acquire a snapshot of the raw data from the kernel, and while a +reasonable effort is made to make this snapshot as atomic and consistent +as possible, no guarantee is given that it will actually be so. +The snapshot must be freed again using the +.Fn geom_stats_snapshot_free +function. +The +.Fn geom_stats_snapshot_get +function returns +.Dv NULL +on failure. +.Pp +The +.Fn geom_stats_snapshot_timestamp +function +provides access to the timestamp acquired in the snapshot. +.Pp +The +.Fn geom_stats_snapshot_reset +and +.Fn geom_stats_snapshot_next +functions +provide an iterator over the statistics slots in the snapshot. +The +.Fn geom_stats_snapshot_reset +function +forces the internal pointer in the snapshot back to before the first item. +The +.Fn geom_stats_snapshot_next +function +returns the next item, and +.Dv NULL +if there are no more items in the snapshot. +.Ss "Control Functions" +The +.Fn gctl_* +functions are used to send requests to GEOM classes. +In order for a GEOM +class to actually be able to receive these requests, it must have defined a +"ctlreq" method. +.Pp +A +.Vt "struct gctl_req *" , +obtained with +.Fn gctl_get_handle , +can hold any number of parameters, which must be added to it with +.Fn gctl_ro_param +(for read-only parameters) or +.Fn gctl_rw_param +(for read/write parameters). +.Pp +Both +.Fn gctl_ro_param +and +.Fn gctl_rw_param +take a string +.Fa name , +which is used to identify the parameter, and a +.Fa value , +which contains, in the read-only case, the data to be passed to the +GEOM class, or, in the read/write case, a pointer to preallocated memory +that the GEOM class should fill with the desired data. +If +.Fa len +is negative, it is assumed that +.Fa value +is an +.Tn ASCII +string and the actual length is taken from the string length of +.Fa value ; +otherwise it must hold the size of +.Fa value . +.Pp +A parameter with a +.Fa name +containing the string +.Qq Li class +is mandatory for each request, and the +corresponding +.Fa value +must hold the name of the GEOM class where the request should be sent to. +.Pp +Also mandatory for each request is a parameter with a +.Fa name +called +.Qq Li verb , +and the corresponding +.Fa value +needs to hold the command string that the GEOM class should react upon. +.Pp +Once all desired parameters are filled in, the request must be sent to +the GEOM subsystem with +.Fn gctl_issue , +which returns +.Dv NULL +on success, or a string containing the error message +on failure. +.Pp +After the request is finished, the allocated memory should be released with +.Fn gctl_free . +.Pp +The +.Fn gctl_dump +function +can be used to format the contents of +.Fa req +to the open file handle pointed to by +.Fa f , +for debugging purposes. +.Pp +Error handling for the control functions is postponed until the call +to +.Fn gctl_issue , +which returns +.Dv NULL +on success, or an error message corresponding to the +first error which happened. +.Sh EXAMPLES +Create a request that is to be sent to the CCD class, and tell +it to destroy a specific geom: +.Bd -literal -offset indent +H = gctl_get_handle(); +gctl_ro_param(H, "verb", -1, "destroy geom"); +gctl_ro_param(H, "class", -1, "CCD"); +sprintf(buf, "ccd%d", ccd); +gctl_ro_param(H, "geom", -1, buf); +errstr = gctl_issue(H); +if (errstr != NULL) + err(1, "could not destroy ccd: %s", errstr); +gctl_free(H); +.Ed +.Sh SEE ALSO +.Pa http://ezine.daemonnews.org/200308/blueprints.html +.Sh HISTORY +The +.Nm geom +library appeared in +.Fx 5.1 . +.Sh AUTHORS +.An Poul-Henning Kamp Aq phk@FreeBSD.org +.An Lukas Ertl Aq le@FreeBSD.org diff --git a/lib/libgeom/libgeom.h b/lib/libgeom/libgeom.h new file mode 100644 index 0000000..2cdb037 --- /dev/null +++ b/lib/libgeom/libgeom.h @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 2003 Poul-Henning Kamp + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef _LIBGEOM_H_ +#define _LIBGEOM_H_ + +#include <sys/cdefs.h> + +#include <sys/queue.h> +#include <sys/time.h> + +#include <geom/geom_ctl.h> + +__BEGIN_DECLS + +void geom_stats_close(void); +void geom_stats_resync(void); +int geom_stats_open(void); +void *geom_stats_snapshot_get(void); +void geom_stats_snapshot_free(void *arg); +void geom_stats_snapshot_timestamp(void *arg, struct timespec *tp); +void geom_stats_snapshot_reset(void *arg); +struct devstat *geom_stats_snapshot_next(void *arg); + +char *geom_getxml(void); + +/* geom_xml2tree.c */ + +/* + * These structs are used to build the tree based on the XML. + * they're named as the kernel variant without the first '_'. + */ + +struct gclass; +struct ggeom; +struct gconsumer; +struct gprovider; + +LIST_HEAD(gconf, gconfig); + +struct gident { + void *lg_id; + void *lg_ptr; + enum { ISCLASS, + ISGEOM, + ISPROVIDER, + ISCONSUMER } lg_what; +}; + +struct gmesh { + LIST_HEAD(, gclass) lg_class; + struct gident *lg_ident; +}; + +struct gconfig { + LIST_ENTRY(gconfig) lg_config; + char *lg_name; + char *lg_val; +}; + +struct gclass { + void *lg_id; + char *lg_name; + LIST_ENTRY(gclass) lg_class; + LIST_HEAD(, ggeom) lg_geom; + struct gconf lg_config; +}; + +struct ggeom { + void *lg_id; + struct gclass *lg_class; + char *lg_name; + u_int lg_rank; + LIST_ENTRY(ggeom) lg_geom; + LIST_HEAD(, gconsumer) lg_consumer; + LIST_HEAD(, gprovider) lg_provider; + struct gconf lg_config; +}; + +struct gconsumer { + void *lg_id; + struct ggeom *lg_geom; + LIST_ENTRY(gconsumer) lg_consumer; + struct gprovider *lg_provider; + LIST_ENTRY(gconsumer) lg_consumers; + char *lg_mode; + struct gconf lg_config; +}; + +struct gprovider { + void *lg_id; + char *lg_name; + struct ggeom *lg_geom; + LIST_ENTRY(gprovider) lg_provider; + LIST_HEAD(, gconsumer) lg_consumers; + char *lg_mode; + off_t lg_mediasize; + u_int lg_sectorsize; + struct gconf lg_config; +}; + +struct gident * geom_lookupid(struct gmesh *gmp, const void *id); +int geom_xml2tree(struct gmesh *gmp, char *p); +int geom_gettree(struct gmesh *gmp); +void geom_deletetree(struct gmesh *gmp); + +/* geom_ctl.c */ + +struct gctl_req; + +#ifdef _STDIO_H_ /* limit #include pollution */ +void gctl_dump(struct gctl_req *req, FILE *f); +#endif +void gctl_free(struct gctl_req *req); +struct gctl_req *gctl_get_handle(void); +const char *gctl_issue(struct gctl_req *req); +void gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* val); +void gctl_rw_param(struct gctl_req *req, const char *name, int len, void* val); + +__END_DECLS + +#endif /* _LIBGEOM_H_ */ |