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 487b6942a1SUlf Lilleengen /* 497b6942a1SUlf Lilleengen * Global pointer to a string that is used to avoid an errorneous free in 507b6942a1SUlf Lilleengen * gctl_free. 517b6942a1SUlf Lilleengen */ 527b6942a1SUlf Lilleengen static char nomemmsg[] = "Could not allocate memory"; 537b6942a1SUlf Lilleengen 544b8938c1SPoul-Henning Kamp void 5563728c47SPoul-Henning Kamp gctl_dump(struct gctl_req *req, FILE *f) 564b8938c1SPoul-Henning Kamp { 574b8938c1SPoul-Henning Kamp u_int i; 584b8938c1SPoul-Henning Kamp int j; 5963728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 604b8938c1SPoul-Henning Kamp 614b8938c1SPoul-Henning Kamp if (req == NULL) { 6263728c47SPoul-Henning Kamp fprintf(f, "Dump of gctl request at NULL\n"); 634b8938c1SPoul-Henning Kamp return; 644b8938c1SPoul-Henning Kamp } 657e02e189SPoul-Henning Kamp fprintf(f, "Dump of gctl request at %p:\n", req); 664b8938c1SPoul-Henning Kamp if (req->error != NULL) 674b8938c1SPoul-Henning Kamp fprintf(f, " error:\t\"%s\"\n", req->error); 684b8938c1SPoul-Henning Kamp else 694b8938c1SPoul-Henning Kamp fprintf(f, " error:\tNULL\n"); 704b8938c1SPoul-Henning Kamp for (i = 0; i < req->narg; i++) { 714b8938c1SPoul-Henning Kamp ap = &req->arg[i]; 727e02e189SPoul-Henning Kamp fprintf(f, " param:\t\"%s\" (%d)", ap->name, ap->nlen); 7363728c47SPoul-Henning Kamp fprintf(f, " [%s%s", 7463728c47SPoul-Henning Kamp ap->flag & GCTL_PARAM_RD ? "R" : "", 7563728c47SPoul-Henning Kamp ap->flag & GCTL_PARAM_WR ? "W" : ""); 764b8938c1SPoul-Henning Kamp fflush(f); 7763728c47SPoul-Henning Kamp if (ap->flag & GCTL_PARAM_ASCII) 7863728c47SPoul-Henning Kamp fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value); 794b8938c1SPoul-Henning Kamp else if (ap->len > 0) { 8063728c47SPoul-Henning Kamp fprintf(f, "%d] = ", ap->len); 814b8938c1SPoul-Henning Kamp fflush(f); 824b8938c1SPoul-Henning Kamp for (j = 0; j < ap->len; j++) { 834b8938c1SPoul-Henning Kamp fprintf(f, " %02x", ((u_char *)ap->value)[j]); 844b8938c1SPoul-Henning Kamp } 854b8938c1SPoul-Henning Kamp } else { 8663728c47SPoul-Henning Kamp fprintf(f, "0] = %p", ap->value); 874b8938c1SPoul-Henning Kamp } 884b8938c1SPoul-Henning Kamp fprintf(f, "\n"); 894b8938c1SPoul-Henning Kamp } 904b8938c1SPoul-Henning Kamp } 914b8938c1SPoul-Henning Kamp 9263728c47SPoul-Henning Kamp /* 9363728c47SPoul-Henning Kamp * Set an error message, if one does not already exist. 9463728c47SPoul-Henning Kamp */ 954b8938c1SPoul-Henning Kamp static void 9663728c47SPoul-Henning Kamp gctl_set_error(struct gctl_req *req, const char *error, ...) 974b8938c1SPoul-Henning Kamp { 984b8938c1SPoul-Henning Kamp va_list ap; 994b8938c1SPoul-Henning Kamp 1004b8938c1SPoul-Henning Kamp if (req->error != NULL) 1014b8938c1SPoul-Henning Kamp return; 1024b8938c1SPoul-Henning Kamp va_start(ap, error); 1034b8938c1SPoul-Henning Kamp vasprintf(&req->error, error, ap); 10463728c47SPoul-Henning Kamp va_end(ap); 1054b8938c1SPoul-Henning Kamp } 1064b8938c1SPoul-Henning Kamp 10763728c47SPoul-Henning Kamp /* 10863728c47SPoul-Henning Kamp * Check that a malloc operation succeeded, and set a consistent error 10963728c47SPoul-Henning Kamp * message if not. 11063728c47SPoul-Henning Kamp */ 1114b8938c1SPoul-Henning Kamp static void 11263728c47SPoul-Henning Kamp gctl_check_alloc(struct gctl_req *req, void *ptr) 1134b8938c1SPoul-Henning Kamp { 1147b6942a1SUlf Lilleengen 1154b8938c1SPoul-Henning Kamp if (ptr != NULL) 1164b8938c1SPoul-Henning Kamp return; 1177b6942a1SUlf Lilleengen gctl_set_error(req, nomemmsg); 11863728c47SPoul-Henning Kamp if (req->error == NULL) 1197b6942a1SUlf Lilleengen req->error = nomemmsg; 1204b8938c1SPoul-Henning Kamp } 1214b8938c1SPoul-Henning Kamp 12263728c47SPoul-Henning Kamp /* 12363728c47SPoul-Henning Kamp * Allocate a new request handle of the specified type. 12463728c47SPoul-Henning Kamp * XXX: Why bother checking the type ? 12563728c47SPoul-Henning Kamp */ 12663728c47SPoul-Henning Kamp struct gctl_req * 1277e02e189SPoul-Henning Kamp gctl_get_handle(void) 1284b8938c1SPoul-Henning Kamp { 12963728c47SPoul-Henning Kamp struct gctl_req *rp; 1304b8938c1SPoul-Henning Kamp 1314b8938c1SPoul-Henning Kamp rp = calloc(1, sizeof *rp); 1324b8938c1SPoul-Henning Kamp return (rp); 1334b8938c1SPoul-Henning Kamp } 1344b8938c1SPoul-Henning Kamp 13563728c47SPoul-Henning Kamp /* 13663728c47SPoul-Henning Kamp * Allocate space for another argument. 13763728c47SPoul-Henning Kamp */ 13863728c47SPoul-Henning Kamp static struct gctl_req_arg * 13963728c47SPoul-Henning Kamp gctl_new_arg(struct gctl_req *req) 1404b8938c1SPoul-Henning Kamp { 14163728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1424b8938c1SPoul-Henning Kamp 1434b8938c1SPoul-Henning Kamp req->narg++; 1447b6942a1SUlf Lilleengen req->arg = reallocf(req->arg, sizeof *ap * req->narg); 14563728c47SPoul-Henning Kamp gctl_check_alloc(req, req->arg); 14663728c47SPoul-Henning Kamp if (req->arg == NULL) { 1474b8938c1SPoul-Henning Kamp req->narg = 0; 14863728c47SPoul-Henning Kamp return (NULL); 14963728c47SPoul-Henning Kamp } 15063728c47SPoul-Henning Kamp ap = req->arg + (req->narg - 1); 15163728c47SPoul-Henning Kamp memset(ap, 0, sizeof *ap); 15263728c47SPoul-Henning Kamp return (ap); 15363728c47SPoul-Henning Kamp } 15463728c47SPoul-Henning Kamp 15563728c47SPoul-Henning Kamp void 15663728c47SPoul-Henning Kamp gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value) 15763728c47SPoul-Henning Kamp { 15863728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 15963728c47SPoul-Henning Kamp 16063728c47SPoul-Henning Kamp if (req == NULL || req->error != NULL) 16163728c47SPoul-Henning Kamp return; 16263728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 16363728c47SPoul-Henning Kamp if (ap == NULL) 16463728c47SPoul-Henning Kamp return; 16563728c47SPoul-Henning Kamp ap->name = strdup(name); 16663728c47SPoul-Henning Kamp gctl_check_alloc(req, ap->name); 1677b6942a1SUlf Lilleengen if (ap->name == NULL) 1687b6942a1SUlf Lilleengen return; 16963728c47SPoul-Henning Kamp ap->nlen = strlen(ap->name) + 1; 17063728c47SPoul-Henning Kamp ap->value = __DECONST(void *, value); 17163728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RD; 17263728c47SPoul-Henning Kamp if (len >= 0) 17363728c47SPoul-Henning Kamp ap->len = len; 17463728c47SPoul-Henning Kamp else if (len < 0) { 17563728c47SPoul-Henning Kamp ap->flag |= GCTL_PARAM_ASCII; 17663728c47SPoul-Henning Kamp ap->len = strlen(value) + 1; 1774b8938c1SPoul-Henning Kamp } 1784b8938c1SPoul-Henning Kamp } 1794b8938c1SPoul-Henning Kamp 1804b8938c1SPoul-Henning Kamp void 18163728c47SPoul-Henning Kamp gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value) 1824b8938c1SPoul-Henning Kamp { 18363728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1844b8938c1SPoul-Henning Kamp 1854b8938c1SPoul-Henning Kamp if (req == NULL || req->error != NULL) 1864b8938c1SPoul-Henning Kamp return; 18763728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 18863728c47SPoul-Henning Kamp if (ap == NULL) 1894b8938c1SPoul-Henning Kamp return; 19063728c47SPoul-Henning Kamp ap->name = strdup(name); 19163728c47SPoul-Henning Kamp gctl_check_alloc(req, ap->name); 1927b6942a1SUlf Lilleengen if (ap->name == NULL) 1937b6942a1SUlf Lilleengen return; 19463728c47SPoul-Henning Kamp ap->nlen = strlen(ap->name) + 1; 1954b8938c1SPoul-Henning Kamp ap->value = value; 19663728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RW; 19763728c47SPoul-Henning Kamp if (len >= 0) 19863728c47SPoul-Henning Kamp ap->len = len; 19963728c47SPoul-Henning Kamp else if (len < 0) 20063728c47SPoul-Henning Kamp ap->len = strlen(value) + 1; 20163728c47SPoul-Henning Kamp } 20263728c47SPoul-Henning Kamp 2034b8938c1SPoul-Henning Kamp const char * 20463728c47SPoul-Henning Kamp gctl_issue(struct gctl_req *req) 2054b8938c1SPoul-Henning Kamp { 2064b8938c1SPoul-Henning Kamp int fd, error; 2074b8938c1SPoul-Henning Kamp 2084b8938c1SPoul-Henning Kamp if (req == NULL) 2094b8938c1SPoul-Henning Kamp return ("NULL request pointer"); 2104b8938c1SPoul-Henning Kamp if (req->error != NULL) 2114b8938c1SPoul-Henning Kamp return (req->error); 2124b8938c1SPoul-Henning Kamp 21363728c47SPoul-Henning Kamp req->version = GCTL_VERSION; 2144b8938c1SPoul-Henning Kamp req->lerror = BUFSIZ; /* XXX: arbitrary number */ 2157b6942a1SUlf Lilleengen req->error = calloc(1, req->lerror); 21663728c47SPoul-Henning Kamp if (req->error == NULL) { 21763728c47SPoul-Henning Kamp gctl_check_alloc(req, req->error); 21863728c47SPoul-Henning Kamp return (req->error); 21963728c47SPoul-Henning Kamp } 2204b8938c1SPoul-Henning Kamp req->lerror--; 2214b8938c1SPoul-Henning Kamp fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY); 2224b8938c1SPoul-Henning Kamp if (fd < 0) 2234b8938c1SPoul-Henning Kamp return(strerror(errno)); 2244b8938c1SPoul-Henning Kamp error = ioctl(fd, GEOM_CTL, req); 22563728c47SPoul-Henning Kamp close(fd); 22663728c47SPoul-Henning Kamp if (req->error[0] != '\0') 2274b8938c1SPoul-Henning Kamp return (req->error); 2284b8938c1SPoul-Henning Kamp if (error != 0) 2294b8938c1SPoul-Henning Kamp return(strerror(errno)); 2304b8938c1SPoul-Henning Kamp return (NULL); 2314b8938c1SPoul-Henning Kamp } 2324b8938c1SPoul-Henning Kamp 2334b8938c1SPoul-Henning Kamp void 23463728c47SPoul-Henning Kamp gctl_free(struct gctl_req *req) 2354b8938c1SPoul-Henning Kamp { 2364b8938c1SPoul-Henning Kamp u_int i; 2374b8938c1SPoul-Henning Kamp 23863728c47SPoul-Henning Kamp if (req == NULL) 23963728c47SPoul-Henning Kamp return; 2404b8938c1SPoul-Henning Kamp for (i = 0; i < req->narg; i++) { 2414b8938c1SPoul-Henning Kamp if (req->arg[i].name != NULL) 2424b8938c1SPoul-Henning Kamp free(req->arg[i].name); 2434b8938c1SPoul-Henning Kamp } 24463728c47SPoul-Henning Kamp free(req->arg); 2457b6942a1SUlf Lilleengen if (req->error != NULL && req->error != nomemmsg) 2464b8938c1SPoul-Henning Kamp free(req->error); 2474b8938c1SPoul-Henning Kamp free(req); 2484b8938c1SPoul-Henning Kamp } 249