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 { 57*91cca30dSPawel Jakub Dawidek unsigned 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 { 1294b8938c1SPoul-Henning Kamp 130*91cca30dSPawel Jakub Dawidek return (calloc(1, sizeof(struct gctl_req))); 1314b8938c1SPoul-Henning Kamp } 1324b8938c1SPoul-Henning Kamp 13363728c47SPoul-Henning Kamp /* 13463728c47SPoul-Henning Kamp * Allocate space for another argument. 13563728c47SPoul-Henning Kamp */ 13663728c47SPoul-Henning Kamp static struct gctl_req_arg * 13763728c47SPoul-Henning Kamp gctl_new_arg(struct gctl_req *req) 1384b8938c1SPoul-Henning Kamp { 13963728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1404b8938c1SPoul-Henning Kamp 1414b8938c1SPoul-Henning Kamp req->narg++; 1427b6942a1SUlf Lilleengen req->arg = reallocf(req->arg, sizeof *ap * req->narg); 14363728c47SPoul-Henning Kamp gctl_check_alloc(req, req->arg); 14463728c47SPoul-Henning Kamp if (req->arg == NULL) { 1454b8938c1SPoul-Henning Kamp req->narg = 0; 14663728c47SPoul-Henning Kamp return (NULL); 14763728c47SPoul-Henning Kamp } 14863728c47SPoul-Henning Kamp ap = req->arg + (req->narg - 1); 14963728c47SPoul-Henning Kamp memset(ap, 0, sizeof *ap); 15063728c47SPoul-Henning Kamp return (ap); 15163728c47SPoul-Henning Kamp } 15263728c47SPoul-Henning Kamp 15363728c47SPoul-Henning Kamp void 15463728c47SPoul-Henning Kamp gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value) 15563728c47SPoul-Henning Kamp { 15663728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 15763728c47SPoul-Henning Kamp 15863728c47SPoul-Henning Kamp if (req == NULL || req->error != NULL) 15963728c47SPoul-Henning Kamp return; 16063728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 16163728c47SPoul-Henning Kamp if (ap == NULL) 16263728c47SPoul-Henning Kamp return; 16363728c47SPoul-Henning Kamp ap->name = strdup(name); 16463728c47SPoul-Henning Kamp gctl_check_alloc(req, ap->name); 1657b6942a1SUlf Lilleengen if (ap->name == NULL) 1667b6942a1SUlf Lilleengen return; 16763728c47SPoul-Henning Kamp ap->nlen = strlen(ap->name) + 1; 16863728c47SPoul-Henning Kamp ap->value = __DECONST(void *, value); 16963728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RD; 17063728c47SPoul-Henning Kamp if (len >= 0) 17163728c47SPoul-Henning Kamp ap->len = len; 17263728c47SPoul-Henning Kamp else if (len < 0) { 17363728c47SPoul-Henning Kamp ap->flag |= GCTL_PARAM_ASCII; 17463728c47SPoul-Henning Kamp ap->len = strlen(value) + 1; 1754b8938c1SPoul-Henning Kamp } 1764b8938c1SPoul-Henning Kamp } 1774b8938c1SPoul-Henning Kamp 1784b8938c1SPoul-Henning Kamp void 17963728c47SPoul-Henning Kamp gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value) 1804b8938c1SPoul-Henning Kamp { 18163728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1824b8938c1SPoul-Henning Kamp 1834b8938c1SPoul-Henning Kamp if (req == NULL || req->error != NULL) 1844b8938c1SPoul-Henning Kamp return; 18563728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 18663728c47SPoul-Henning Kamp if (ap == NULL) 1874b8938c1SPoul-Henning Kamp return; 18863728c47SPoul-Henning Kamp ap->name = strdup(name); 18963728c47SPoul-Henning Kamp gctl_check_alloc(req, ap->name); 1907b6942a1SUlf Lilleengen if (ap->name == NULL) 1917b6942a1SUlf Lilleengen return; 19263728c47SPoul-Henning Kamp ap->nlen = strlen(ap->name) + 1; 1934b8938c1SPoul-Henning Kamp ap->value = value; 19463728c47SPoul-Henning Kamp ap->flag = GCTL_PARAM_RW; 19563728c47SPoul-Henning Kamp if (len >= 0) 19663728c47SPoul-Henning Kamp ap->len = len; 19763728c47SPoul-Henning Kamp else if (len < 0) 19863728c47SPoul-Henning Kamp ap->len = strlen(value) + 1; 19963728c47SPoul-Henning Kamp } 20063728c47SPoul-Henning Kamp 2014b8938c1SPoul-Henning Kamp const char * 20263728c47SPoul-Henning Kamp gctl_issue(struct gctl_req *req) 2034b8938c1SPoul-Henning Kamp { 2044b8938c1SPoul-Henning Kamp int fd, error; 2054b8938c1SPoul-Henning Kamp 2064b8938c1SPoul-Henning Kamp if (req == NULL) 2074b8938c1SPoul-Henning Kamp return ("NULL request pointer"); 2084b8938c1SPoul-Henning Kamp if (req->error != NULL) 2094b8938c1SPoul-Henning Kamp return (req->error); 2104b8938c1SPoul-Henning Kamp 21163728c47SPoul-Henning Kamp req->version = GCTL_VERSION; 2124b8938c1SPoul-Henning Kamp req->lerror = BUFSIZ; /* XXX: arbitrary number */ 2137b6942a1SUlf Lilleengen req->error = calloc(1, req->lerror); 21463728c47SPoul-Henning Kamp if (req->error == NULL) { 21563728c47SPoul-Henning Kamp gctl_check_alloc(req, req->error); 21663728c47SPoul-Henning Kamp return (req->error); 21763728c47SPoul-Henning Kamp } 2184b8938c1SPoul-Henning Kamp req->lerror--; 2194b8938c1SPoul-Henning Kamp fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY); 2204b8938c1SPoul-Henning Kamp if (fd < 0) 2214b8938c1SPoul-Henning Kamp return(strerror(errno)); 2224b8938c1SPoul-Henning Kamp error = ioctl(fd, GEOM_CTL, req); 22363728c47SPoul-Henning Kamp close(fd); 22463728c47SPoul-Henning Kamp if (req->error[0] != '\0') 2254b8938c1SPoul-Henning Kamp return (req->error); 2264b8938c1SPoul-Henning Kamp if (error != 0) 2274b8938c1SPoul-Henning Kamp return(strerror(errno)); 2284b8938c1SPoul-Henning Kamp return (NULL); 2294b8938c1SPoul-Henning Kamp } 2304b8938c1SPoul-Henning Kamp 2314b8938c1SPoul-Henning Kamp void 23263728c47SPoul-Henning Kamp gctl_free(struct gctl_req *req) 2334b8938c1SPoul-Henning Kamp { 234*91cca30dSPawel Jakub Dawidek unsigned int i; 2354b8938c1SPoul-Henning Kamp 23663728c47SPoul-Henning Kamp if (req == NULL) 23763728c47SPoul-Henning Kamp return; 2384b8938c1SPoul-Henning Kamp for (i = 0; i < req->narg; i++) { 2394b8938c1SPoul-Henning Kamp if (req->arg[i].name != NULL) 2404b8938c1SPoul-Henning Kamp free(req->arg[i].name); 2414b8938c1SPoul-Henning Kamp } 24263728c47SPoul-Henning Kamp free(req->arg); 2437b6942a1SUlf Lilleengen if (req->error != NULL && req->error != nomemmsg) 2444b8938c1SPoul-Henning Kamp free(req->error); 2454b8938c1SPoul-Henning Kamp free(req); 2464b8938c1SPoul-Henning Kamp } 247