14b8938c1SPoul-Henning Kamp /*- 24b8938c1SPoul-Henning Kamp * Copyright (c) 2003 Poul-Henning Kamp 34b8938c1SPoul-Henning Kamp * All rights reserved. 44b8938c1SPoul-Henning Kamp * 54b8938c1SPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 64b8938c1SPoul-Henning Kamp * modification, are permitted provided that the following conditions 74b8938c1SPoul-Henning Kamp * are met: 84b8938c1SPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 94b8938c1SPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 104b8938c1SPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 114b8938c1SPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 124b8938c1SPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 134b8938c1SPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 144b8938c1SPoul-Henning Kamp * products derived from this software without specific prior written 154b8938c1SPoul-Henning Kamp * permission. 164b8938c1SPoul-Henning Kamp * 174b8938c1SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 184b8938c1SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 194b8938c1SPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 204b8938c1SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 214b8938c1SPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 224b8938c1SPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 234b8938c1SPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 244b8938c1SPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 254b8938c1SPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 264b8938c1SPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 274b8938c1SPoul-Henning Kamp * SUCH DAMAGE. 284b8938c1SPoul-Henning Kamp * 294b8938c1SPoul-Henning Kamp * $FreeBSD$ 304b8938c1SPoul-Henning Kamp */ 314b8938c1SPoul-Henning Kamp 324b8938c1SPoul-Henning Kamp #include <stdio.h> 334b8938c1SPoul-Henning Kamp #include <fcntl.h> 344b8938c1SPoul-Henning Kamp #include <errno.h> 354b8938c1SPoul-Henning Kamp #include <stdint.h> 364b8938c1SPoul-Henning Kamp #include <sys/types.h> 374b8938c1SPoul-Henning Kamp #include <stdarg.h> 3863728c47SPoul-Henning Kamp #include <unistd.h> 394b8938c1SPoul-Henning Kamp #include <string.h> 404b8938c1SPoul-Henning Kamp #include <stdlib.h> 414b8938c1SPoul-Henning Kamp #include <paths.h> 424b8938c1SPoul-Henning Kamp 434b8938c1SPoul-Henning Kamp #include <sys/queue.h> 444b8938c1SPoul-Henning Kamp 4563728c47SPoul-Henning Kamp #define GCTL_TABLE 1 464b8938c1SPoul-Henning Kamp #include <libgeom.h> 474b8938c1SPoul-Henning Kamp 484b8938c1SPoul-Henning Kamp #include <geom/geom_ext.h> 494b8938c1SPoul-Henning Kamp 504b8938c1SPoul-Henning Kamp void 5163728c47SPoul-Henning Kamp gctl_dump(struct gctl_req *req, FILE *f) 524b8938c1SPoul-Henning Kamp { 534b8938c1SPoul-Henning Kamp u_int i; 544b8938c1SPoul-Henning Kamp int j; 5563728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 564b8938c1SPoul-Henning Kamp 574b8938c1SPoul-Henning Kamp if (req == NULL) { 5863728c47SPoul-Henning Kamp fprintf(f, "Dump of gctl request at NULL\n"); 594b8938c1SPoul-Henning Kamp return; 604b8938c1SPoul-Henning Kamp } 6163728c47SPoul-Henning Kamp fprintf(f, "Dump of gctl %s request at %p:\n", req->reqt->name, req); 624b8938c1SPoul-Henning Kamp if (req->error != NULL) 634b8938c1SPoul-Henning Kamp fprintf(f, " error:\t\"%s\"\n", req->error); 644b8938c1SPoul-Henning Kamp else 654b8938c1SPoul-Henning Kamp fprintf(f, " error:\tNULL\n"); 664b8938c1SPoul-Henning Kamp for (i = 0; i < req->narg; i++) { 674b8938c1SPoul-Henning Kamp ap = &req->arg[i]; 684b8938c1SPoul-Henning Kamp if (ap->name != NULL) 694b8938c1SPoul-Henning Kamp fprintf(f, " param:\t\"%s\"", ap->name); 704b8938c1SPoul-Henning Kamp else 714b8938c1SPoul-Henning Kamp fprintf(f, " meta:\t@%jd", (intmax_t)ap->offset); 7263728c47SPoul-Henning Kamp fprintf(f, " [%s%s", 7363728c47SPoul-Henning Kamp ap->flag & GCTL_PARAM_RD ? "R" : "", 7463728c47SPoul-Henning Kamp ap->flag & GCTL_PARAM_WR ? "W" : ""); 754b8938c1SPoul-Henning Kamp fflush(f); 7663728c47SPoul-Henning Kamp if (ap->flag & GCTL_PARAM_ASCII) 7763728c47SPoul-Henning Kamp fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value); 784b8938c1SPoul-Henning Kamp else if (ap->len > 0) { 7963728c47SPoul-Henning Kamp fprintf(f, "%d] = ", ap->len); 804b8938c1SPoul-Henning Kamp fflush(f); 814b8938c1SPoul-Henning Kamp for (j = 0; j < ap->len; j++) { 824b8938c1SPoul-Henning Kamp fprintf(f, " %02x", ((u_char *)ap->value)[j]); 834b8938c1SPoul-Henning Kamp } 844b8938c1SPoul-Henning Kamp } else { 8563728c47SPoul-Henning Kamp fprintf(f, "0] = %p", ap->value); 864b8938c1SPoul-Henning Kamp } 874b8938c1SPoul-Henning Kamp fprintf(f, "\n"); 884b8938c1SPoul-Henning Kamp } 894b8938c1SPoul-Henning Kamp } 904b8938c1SPoul-Henning Kamp 9163728c47SPoul-Henning Kamp /* 9263728c47SPoul-Henning Kamp * Set an error message, if one does not already exist. 9363728c47SPoul-Henning Kamp */ 944b8938c1SPoul-Henning Kamp static void 9563728c47SPoul-Henning Kamp gctl_set_error(struct gctl_req *req, const char *error, ...) 964b8938c1SPoul-Henning Kamp { 974b8938c1SPoul-Henning Kamp va_list ap; 984b8938c1SPoul-Henning Kamp 994b8938c1SPoul-Henning Kamp if (req->error != NULL) 1004b8938c1SPoul-Henning Kamp return; 1014b8938c1SPoul-Henning Kamp va_start(ap, error); 1024b8938c1SPoul-Henning Kamp vasprintf(&req->error, error, ap); 10363728c47SPoul-Henning Kamp va_end(ap); 1044b8938c1SPoul-Henning Kamp } 1054b8938c1SPoul-Henning Kamp 10663728c47SPoul-Henning Kamp /* 10763728c47SPoul-Henning Kamp * Check that a malloc operation succeeded, and set a consistent error 10863728c47SPoul-Henning Kamp * message if not. 10963728c47SPoul-Henning Kamp */ 1104b8938c1SPoul-Henning Kamp static void 11163728c47SPoul-Henning Kamp gctl_check_alloc(struct gctl_req *req, void *ptr) 1124b8938c1SPoul-Henning Kamp { 1134b8938c1SPoul-Henning Kamp if (ptr != NULL) 1144b8938c1SPoul-Henning Kamp return; 11563728c47SPoul-Henning Kamp gctl_set_error(req, "Could not allocate memory"); 11663728c47SPoul-Henning Kamp if (req->error == NULL) 11763728c47SPoul-Henning Kamp req->error = "Could not allocate memory"; 1184b8938c1SPoul-Henning Kamp } 1194b8938c1SPoul-Henning Kamp 12063728c47SPoul-Henning Kamp /* 12163728c47SPoul-Henning Kamp * Allocate a new request handle of the specified type. 12263728c47SPoul-Henning Kamp * XXX: Why bother checking the type ? 12363728c47SPoul-Henning Kamp */ 12463728c47SPoul-Henning Kamp struct gctl_req * 12563728c47SPoul-Henning Kamp gctl_get_handle(enum gctl_request req) 1264b8938c1SPoul-Henning Kamp { 12763728c47SPoul-Henning Kamp struct gctl_req_table *gtp; 12863728c47SPoul-Henning Kamp struct gctl_req *rp; 1294b8938c1SPoul-Henning Kamp 1304b8938c1SPoul-Henning Kamp rp = calloc(1, sizeof *rp); 1314b8938c1SPoul-Henning Kamp if (rp == NULL) 1324b8938c1SPoul-Henning Kamp return (NULL); 1334b8938c1SPoul-Henning Kamp for (gtp = gcrt; gtp->request != req; gtp++) 13463728c47SPoul-Henning Kamp if (gtp->request == GCTL_INVALID_REQUEST) 1354b8938c1SPoul-Henning Kamp break; 1364b8938c1SPoul-Henning Kamp 1374b8938c1SPoul-Henning Kamp rp->request = req; 1384b8938c1SPoul-Henning Kamp rp->reqt = gtp; 13963728c47SPoul-Henning Kamp if (rp->reqt->request == GCTL_INVALID_REQUEST) 14063728c47SPoul-Henning Kamp gctl_set_error(rp, "Invalid request"); 1414b8938c1SPoul-Henning Kamp return (rp); 1424b8938c1SPoul-Henning Kamp } 1434b8938c1SPoul-Henning Kamp 14463728c47SPoul-Henning Kamp /* 14563728c47SPoul-Henning Kamp * Allocate space for another argument. 14663728c47SPoul-Henning Kamp */ 14763728c47SPoul-Henning Kamp static struct gctl_req_arg * 14863728c47SPoul-Henning Kamp gctl_new_arg(struct gctl_req *req) 1494b8938c1SPoul-Henning Kamp { 15063728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1514b8938c1SPoul-Henning Kamp 1524b8938c1SPoul-Henning Kamp req->narg++; 1534b8938c1SPoul-Henning Kamp req->arg = realloc(req->arg, sizeof *ap * req->narg); 15463728c47SPoul-Henning Kamp gctl_check_alloc(req, req->arg); 15563728c47SPoul-Henning Kamp if (req->arg == NULL) { 1564b8938c1SPoul-Henning Kamp req->narg = 0; 15763728c47SPoul-Henning Kamp return (NULL); 15863728c47SPoul-Henning Kamp } 15963728c47SPoul-Henning Kamp ap = req->arg + (req->narg - 1); 16063728c47SPoul-Henning Kamp memset(ap, 0, sizeof *ap); 16163728c47SPoul-Henning Kamp return (ap); 16263728c47SPoul-Henning Kamp } 16363728c47SPoul-Henning Kamp 16463728c47SPoul-Henning Kamp void 16563728c47SPoul-Henning Kamp gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value) 16663728c47SPoul-Henning Kamp { 16763728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 16863728c47SPoul-Henning Kamp 16963728c47SPoul-Henning Kamp if (req == NULL || req->error != NULL) 17063728c47SPoul-Henning Kamp return; 17163728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 17263728c47SPoul-Henning Kamp if (ap == NULL) 17363728c47SPoul-Henning Kamp return; 17463728c47SPoul-Henning Kamp ap->name = strdup(name); 17563728c47SPoul-Henning Kamp gctl_check_alloc(req, ap->name); 17663728c47SPoul-Henning Kamp ap->nlen = strlen(ap->name) + 1; 17763728c47SPoul-Henning Kamp ap->value = __DECONST(void *, value); 17863728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RD; 17963728c47SPoul-Henning Kamp if (len >= 0) 18063728c47SPoul-Henning Kamp ap->len = len; 18163728c47SPoul-Henning Kamp else if (len < 0) { 18263728c47SPoul-Henning Kamp ap->flag |= GCTL_PARAM_ASCII; 18363728c47SPoul-Henning Kamp ap->len = strlen(value) + 1; 1844b8938c1SPoul-Henning Kamp } 1854b8938c1SPoul-Henning Kamp } 1864b8938c1SPoul-Henning Kamp 1874b8938c1SPoul-Henning Kamp void 18863728c47SPoul-Henning Kamp gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value) 1894b8938c1SPoul-Henning Kamp { 19063728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1914b8938c1SPoul-Henning Kamp 1924b8938c1SPoul-Henning Kamp if (req == NULL || req->error != NULL) 1934b8938c1SPoul-Henning Kamp return; 19463728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 19563728c47SPoul-Henning Kamp if (ap == NULL) 1964b8938c1SPoul-Henning Kamp return; 19763728c47SPoul-Henning Kamp ap->name = strdup(name); 19863728c47SPoul-Henning Kamp gctl_check_alloc(req, ap->name); 19963728c47SPoul-Henning Kamp ap->nlen = strlen(ap->name) + 1; 2004b8938c1SPoul-Henning Kamp ap->value = value; 20163728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RW; 20263728c47SPoul-Henning Kamp if (len >= 0) 20363728c47SPoul-Henning Kamp ap->len = len; 20463728c47SPoul-Henning Kamp else if (len < 0) 20563728c47SPoul-Henning Kamp ap->len = strlen(value) + 1; 20663728c47SPoul-Henning Kamp } 20763728c47SPoul-Henning Kamp 20863728c47SPoul-Henning Kamp void 20963728c47SPoul-Henning Kamp gctl_ro_meta(struct gctl_req *req, off_t offset, u_int len, const void* value) 21063728c47SPoul-Henning Kamp { 21163728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 21263728c47SPoul-Henning Kamp 21363728c47SPoul-Henning Kamp if (req == NULL || req->error != NULL) 21463728c47SPoul-Henning Kamp return; 21563728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 21663728c47SPoul-Henning Kamp if (ap == NULL) 21763728c47SPoul-Henning Kamp return; 21863728c47SPoul-Henning Kamp ap->value = __DECONST(void *, value); 21963728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RD; 2204b8938c1SPoul-Henning Kamp ap->offset = offset; 2214b8938c1SPoul-Henning Kamp ap->len = len; 2224b8938c1SPoul-Henning Kamp } 22363728c47SPoul-Henning Kamp 22463728c47SPoul-Henning Kamp void 22563728c47SPoul-Henning Kamp gctl_rw_meta(struct gctl_req *req, off_t offset, u_int len, void* value) 22663728c47SPoul-Henning Kamp { 22763728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 22863728c47SPoul-Henning Kamp 22963728c47SPoul-Henning Kamp if (req == NULL || req->error != NULL) 23063728c47SPoul-Henning Kamp return; 23163728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 23263728c47SPoul-Henning Kamp if (ap == NULL) 23363728c47SPoul-Henning Kamp return; 23463728c47SPoul-Henning Kamp ap->value = value; 23563728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RW; 23663728c47SPoul-Henning Kamp ap->offset = offset; 23763728c47SPoul-Henning Kamp ap->len = len; 2384b8938c1SPoul-Henning Kamp } 2394b8938c1SPoul-Henning Kamp 2404b8938c1SPoul-Henning Kamp const char * 24163728c47SPoul-Henning Kamp gctl_issue(struct gctl_req *req) 2424b8938c1SPoul-Henning Kamp { 2434b8938c1SPoul-Henning Kamp int fd, error; 2444b8938c1SPoul-Henning Kamp 2454b8938c1SPoul-Henning Kamp if (req == NULL) 2464b8938c1SPoul-Henning Kamp return ("NULL request pointer"); 2474b8938c1SPoul-Henning Kamp if (req->error != NULL) 2484b8938c1SPoul-Henning Kamp return (req->error); 2494b8938c1SPoul-Henning Kamp 25063728c47SPoul-Henning Kamp req->version = GCTL_VERSION; 2514b8938c1SPoul-Henning Kamp req->lerror = BUFSIZ; /* XXX: arbitrary number */ 2524b8938c1SPoul-Henning Kamp req->error = malloc(req->lerror); 25363728c47SPoul-Henning Kamp if (req->error == NULL) { 25463728c47SPoul-Henning Kamp gctl_check_alloc(req, req->error); 25563728c47SPoul-Henning Kamp return (req->error); 25663728c47SPoul-Henning Kamp } 2574b8938c1SPoul-Henning Kamp memset(req->error, 0, req->lerror); 2584b8938c1SPoul-Henning Kamp req->lerror--; 2594b8938c1SPoul-Henning Kamp fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY); 2604b8938c1SPoul-Henning Kamp if (fd < 0) 2614b8938c1SPoul-Henning Kamp return(strerror(errno)); 2624b8938c1SPoul-Henning Kamp error = ioctl(fd, GEOM_CTL, req); 26363728c47SPoul-Henning Kamp close(fd); 26463728c47SPoul-Henning Kamp if (req->error[0] != '\0') 2654b8938c1SPoul-Henning Kamp return (req->error); 2664b8938c1SPoul-Henning Kamp if (error != 0) 2674b8938c1SPoul-Henning Kamp return(strerror(errno)); 2684b8938c1SPoul-Henning Kamp return (NULL); 2694b8938c1SPoul-Henning Kamp } 2704b8938c1SPoul-Henning Kamp 2714b8938c1SPoul-Henning Kamp void 27263728c47SPoul-Henning Kamp gctl_free(struct gctl_req *req) 2734b8938c1SPoul-Henning Kamp { 2744b8938c1SPoul-Henning Kamp u_int i; 2754b8938c1SPoul-Henning Kamp 27663728c47SPoul-Henning Kamp if (req == NULL) 27763728c47SPoul-Henning Kamp return; 2784b8938c1SPoul-Henning Kamp for (i = 0; i < req->narg; i++) { 2794b8938c1SPoul-Henning Kamp if (req->arg[i].name != NULL) 2804b8938c1SPoul-Henning Kamp free(req->arg[i].name); 2814b8938c1SPoul-Henning Kamp } 28263728c47SPoul-Henning Kamp free(req->arg); 2834b8938c1SPoul-Henning Kamp if (req->error != NULL) 2844b8938c1SPoul-Henning Kamp free(req->error); 2854b8938c1SPoul-Henning Kamp free(req); 2864b8938c1SPoul-Henning Kamp } 287