14b8938c1SPoul-Henning Kamp /*- 25e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 35e53a4f9SPedro F. Giffuni * 44b8938c1SPoul-Henning Kamp * Copyright (c) 2003 Poul-Henning Kamp 54b8938c1SPoul-Henning Kamp * All rights reserved. 64b8938c1SPoul-Henning Kamp * 74b8938c1SPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 84b8938c1SPoul-Henning Kamp * modification, are permitted provided that the following conditions 94b8938c1SPoul-Henning Kamp * are met: 104b8938c1SPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 114b8938c1SPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 124b8938c1SPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 134b8938c1SPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 144b8938c1SPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 154b8938c1SPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 164b8938c1SPoul-Henning Kamp * products derived from this software without specific prior written 174b8938c1SPoul-Henning Kamp * permission. 184b8938c1SPoul-Henning Kamp * 194b8938c1SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 204b8938c1SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 214b8938c1SPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 224b8938c1SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 234b8938c1SPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 244b8938c1SPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 254b8938c1SPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 264b8938c1SPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 274b8938c1SPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 284b8938c1SPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 294b8938c1SPoul-Henning Kamp * SUCH DAMAGE. 304b8938c1SPoul-Henning Kamp * 314b8938c1SPoul-Henning Kamp * $FreeBSD$ 324b8938c1SPoul-Henning Kamp */ 334b8938c1SPoul-Henning Kamp 34f06b2368SEnji Cooper #include <sys/types.h> 35f06b2368SEnji Cooper #include <sys/queue.h> 364b8938c1SPoul-Henning Kamp #include <fcntl.h> 374b8938c1SPoul-Henning Kamp #include <errno.h> 384b8938c1SPoul-Henning Kamp #include <paths.h> 39f06b2368SEnji Cooper #include <stdarg.h> 40f06b2368SEnji Cooper #include <stdint.h> 41f06b2368SEnji Cooper #include <stdio.h> 42f06b2368SEnji Cooper #include <stdlib.h> 43f06b2368SEnji Cooper #include <string.h> 44f06b2368SEnji Cooper #include <unistd.h> 454b8938c1SPoul-Henning Kamp 4663728c47SPoul-Henning Kamp #define GCTL_TABLE 1 474b8938c1SPoul-Henning Kamp #include <libgeom.h> 484b8938c1SPoul-Henning Kamp 497b6942a1SUlf Lilleengen /* 507b6942a1SUlf Lilleengen * Global pointer to a string that is used to avoid an errorneous free in 517b6942a1SUlf Lilleengen * gctl_free. 527b6942a1SUlf Lilleengen */ 537b6942a1SUlf Lilleengen static char nomemmsg[] = "Could not allocate memory"; 547b6942a1SUlf Lilleengen 554b8938c1SPoul-Henning Kamp void 5663728c47SPoul-Henning Kamp gctl_dump(struct gctl_req *req, FILE *f) 574b8938c1SPoul-Henning Kamp { 5891cca30dSPawel Jakub Dawidek unsigned int i; 594b8938c1SPoul-Henning Kamp int j; 6063728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 614b8938c1SPoul-Henning Kamp 624b8938c1SPoul-Henning Kamp if (req == NULL) { 6363728c47SPoul-Henning Kamp fprintf(f, "Dump of gctl request at NULL\n"); 644b8938c1SPoul-Henning Kamp return; 654b8938c1SPoul-Henning Kamp } 667e02e189SPoul-Henning Kamp fprintf(f, "Dump of gctl request at %p:\n", req); 674b8938c1SPoul-Henning Kamp if (req->error != NULL) 684b8938c1SPoul-Henning Kamp fprintf(f, " error:\t\"%s\"\n", req->error); 694b8938c1SPoul-Henning Kamp else 704b8938c1SPoul-Henning Kamp fprintf(f, " error:\tNULL\n"); 714b8938c1SPoul-Henning Kamp for (i = 0; i < req->narg; i++) { 724b8938c1SPoul-Henning Kamp ap = &req->arg[i]; 737e02e189SPoul-Henning Kamp fprintf(f, " param:\t\"%s\" (%d)", ap->name, ap->nlen); 7463728c47SPoul-Henning Kamp fprintf(f, " [%s%s", 7563728c47SPoul-Henning Kamp ap->flag & GCTL_PARAM_RD ? "R" : "", 7663728c47SPoul-Henning Kamp ap->flag & GCTL_PARAM_WR ? "W" : ""); 774b8938c1SPoul-Henning Kamp fflush(f); 7863728c47SPoul-Henning Kamp if (ap->flag & GCTL_PARAM_ASCII) 7963728c47SPoul-Henning Kamp fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value); 804b8938c1SPoul-Henning Kamp else if (ap->len > 0) { 8163728c47SPoul-Henning Kamp fprintf(f, "%d] = ", ap->len); 824b8938c1SPoul-Henning Kamp fflush(f); 834b8938c1SPoul-Henning Kamp for (j = 0; j < ap->len; j++) { 844b8938c1SPoul-Henning Kamp fprintf(f, " %02x", ((u_char *)ap->value)[j]); 854b8938c1SPoul-Henning Kamp } 864b8938c1SPoul-Henning Kamp } else { 8763728c47SPoul-Henning Kamp fprintf(f, "0] = %p", ap->value); 884b8938c1SPoul-Henning Kamp } 894b8938c1SPoul-Henning Kamp fprintf(f, "\n"); 904b8938c1SPoul-Henning Kamp } 914b8938c1SPoul-Henning Kamp } 924b8938c1SPoul-Henning Kamp 9363728c47SPoul-Henning Kamp /* 9463728c47SPoul-Henning Kamp * Set an error message, if one does not already exist. 9563728c47SPoul-Henning Kamp */ 964b8938c1SPoul-Henning Kamp static void 9763728c47SPoul-Henning Kamp gctl_set_error(struct gctl_req *req, const char *error, ...) 984b8938c1SPoul-Henning Kamp { 994b8938c1SPoul-Henning Kamp va_list ap; 1004b8938c1SPoul-Henning Kamp 1014b8938c1SPoul-Henning Kamp if (req->error != NULL) 1024b8938c1SPoul-Henning Kamp return; 1034b8938c1SPoul-Henning Kamp va_start(ap, error); 1044b8938c1SPoul-Henning Kamp vasprintf(&req->error, error, ap); 10563728c47SPoul-Henning Kamp va_end(ap); 1064b8938c1SPoul-Henning Kamp } 1074b8938c1SPoul-Henning Kamp 10863728c47SPoul-Henning Kamp /* 10963728c47SPoul-Henning Kamp * Check that a malloc operation succeeded, and set a consistent error 11063728c47SPoul-Henning Kamp * message if not. 11163728c47SPoul-Henning Kamp */ 1124b8938c1SPoul-Henning Kamp static void 11363728c47SPoul-Henning Kamp gctl_check_alloc(struct gctl_req *req, void *ptr) 1144b8938c1SPoul-Henning Kamp { 1157b6942a1SUlf Lilleengen 1164b8938c1SPoul-Henning Kamp if (ptr != NULL) 1174b8938c1SPoul-Henning Kamp return; 1187b6942a1SUlf Lilleengen gctl_set_error(req, nomemmsg); 11963728c47SPoul-Henning Kamp if (req->error == NULL) 1207b6942a1SUlf Lilleengen req->error = nomemmsg; 1214b8938c1SPoul-Henning Kamp } 1224b8938c1SPoul-Henning Kamp 12363728c47SPoul-Henning Kamp /* 12463728c47SPoul-Henning Kamp * Allocate a new request handle of the specified type. 12563728c47SPoul-Henning Kamp * XXX: Why bother checking the type ? 12663728c47SPoul-Henning Kamp */ 12763728c47SPoul-Henning Kamp struct gctl_req * 1287e02e189SPoul-Henning Kamp gctl_get_handle(void) 1294b8938c1SPoul-Henning Kamp { 1304b8938c1SPoul-Henning Kamp 13191cca30dSPawel Jakub Dawidek return (calloc(1, sizeof(struct gctl_req))); 1324b8938c1SPoul-Henning Kamp } 1334b8938c1SPoul-Henning Kamp 13463728c47SPoul-Henning Kamp /* 13563728c47SPoul-Henning Kamp * Allocate space for another argument. 13663728c47SPoul-Henning Kamp */ 13763728c47SPoul-Henning Kamp static struct gctl_req_arg * 13863728c47SPoul-Henning Kamp gctl_new_arg(struct gctl_req *req) 1394b8938c1SPoul-Henning Kamp { 14063728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1414b8938c1SPoul-Henning Kamp 1424b8938c1SPoul-Henning Kamp req->narg++; 1437b6942a1SUlf Lilleengen req->arg = reallocf(req->arg, sizeof *ap * req->narg); 14463728c47SPoul-Henning Kamp gctl_check_alloc(req, req->arg); 14563728c47SPoul-Henning Kamp if (req->arg == NULL) { 1464b8938c1SPoul-Henning Kamp req->narg = 0; 14763728c47SPoul-Henning Kamp return (NULL); 14863728c47SPoul-Henning Kamp } 14963728c47SPoul-Henning Kamp ap = req->arg + (req->narg - 1); 15063728c47SPoul-Henning Kamp memset(ap, 0, sizeof *ap); 15163728c47SPoul-Henning Kamp return (ap); 15263728c47SPoul-Henning Kamp } 15363728c47SPoul-Henning Kamp 154*2117cdd4SAlexander Motin void 155*2117cdd4SAlexander Motin gctl_add_param(struct gctl_req *req, const char *name, int len, void *value, 15642e2e899SPawel Jakub Dawidek int flag) 1574b8938c1SPoul-Henning Kamp { 15863728c47SPoul-Henning Kamp struct gctl_req_arg *ap; 1594b8938c1SPoul-Henning Kamp 1604b8938c1SPoul-Henning Kamp if (req == NULL || req->error != NULL) 1614b8938c1SPoul-Henning Kamp return; 16263728c47SPoul-Henning Kamp ap = gctl_new_arg(req); 16363728c47SPoul-Henning Kamp if (ap == NULL) 1644b8938c1SPoul-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; 1704b8938c1SPoul-Henning Kamp ap->value = value; 17142e2e899SPawel Jakub Dawidek ap->flag = flag; 17263728c47SPoul-Henning Kamp if (len >= 0) 17363728c47SPoul-Henning Kamp ap->len = len; 17442e2e899SPawel Jakub Dawidek else if (len < 0) { 17542e2e899SPawel Jakub Dawidek ap->flag |= GCTL_PARAM_ASCII; 17663728c47SPoul-Henning Kamp ap->len = strlen(value) + 1; 17763728c47SPoul-Henning Kamp } 17842e2e899SPawel Jakub Dawidek } 17942e2e899SPawel Jakub Dawidek 18042e2e899SPawel Jakub Dawidek void 18142e2e899SPawel Jakub Dawidek gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value) 18242e2e899SPawel Jakub Dawidek { 18342e2e899SPawel Jakub Dawidek 184*2117cdd4SAlexander Motin gctl_add_param(req, name, len, __DECONST(void *, value), GCTL_PARAM_RD); 18542e2e899SPawel Jakub Dawidek } 18642e2e899SPawel Jakub Dawidek 18742e2e899SPawel Jakub Dawidek void 18842e2e899SPawel Jakub Dawidek gctl_rw_param(struct gctl_req *req, const char *name, int len, void *value) 18942e2e899SPawel Jakub Dawidek { 19042e2e899SPawel Jakub Dawidek 191*2117cdd4SAlexander Motin gctl_add_param(req, name, len, value, GCTL_PARAM_RW); 19242e2e899SPawel Jakub Dawidek } 19363728c47SPoul-Henning Kamp 1944b8938c1SPoul-Henning Kamp const char * 19563728c47SPoul-Henning Kamp gctl_issue(struct gctl_req *req) 1964b8938c1SPoul-Henning Kamp { 1974b8938c1SPoul-Henning Kamp int fd, error; 1984b8938c1SPoul-Henning Kamp 1994b8938c1SPoul-Henning Kamp if (req == NULL) 2004b8938c1SPoul-Henning Kamp return ("NULL request pointer"); 2014b8938c1SPoul-Henning Kamp if (req->error != NULL) 2024b8938c1SPoul-Henning Kamp return (req->error); 2034b8938c1SPoul-Henning Kamp 20463728c47SPoul-Henning Kamp req->version = GCTL_VERSION; 2054b8938c1SPoul-Henning Kamp req->lerror = BUFSIZ; /* XXX: arbitrary number */ 2067b6942a1SUlf Lilleengen req->error = calloc(1, req->lerror); 20763728c47SPoul-Henning Kamp if (req->error == NULL) { 20863728c47SPoul-Henning Kamp gctl_check_alloc(req, req->error); 20963728c47SPoul-Henning Kamp return (req->error); 21063728c47SPoul-Henning Kamp } 2114b8938c1SPoul-Henning Kamp req->lerror--; 2124b8938c1SPoul-Henning Kamp fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY); 2134b8938c1SPoul-Henning Kamp if (fd < 0) 2144b8938c1SPoul-Henning Kamp return(strerror(errno)); 2154b8938c1SPoul-Henning Kamp error = ioctl(fd, GEOM_CTL, req); 21663728c47SPoul-Henning Kamp close(fd); 21763728c47SPoul-Henning Kamp if (req->error[0] != '\0') 2184b8938c1SPoul-Henning Kamp return (req->error); 2194b8938c1SPoul-Henning Kamp if (error != 0) 2204b8938c1SPoul-Henning Kamp return(strerror(errno)); 2214b8938c1SPoul-Henning Kamp return (NULL); 2224b8938c1SPoul-Henning Kamp } 2234b8938c1SPoul-Henning Kamp 2244b8938c1SPoul-Henning Kamp void 22563728c47SPoul-Henning Kamp gctl_free(struct gctl_req *req) 2264b8938c1SPoul-Henning Kamp { 22791cca30dSPawel Jakub Dawidek unsigned int i; 2284b8938c1SPoul-Henning Kamp 22963728c47SPoul-Henning Kamp if (req == NULL) 23063728c47SPoul-Henning Kamp return; 2314b8938c1SPoul-Henning Kamp for (i = 0; i < req->narg; i++) { 2324b8938c1SPoul-Henning Kamp if (req->arg[i].name != NULL) 2334b8938c1SPoul-Henning Kamp free(req->arg[i].name); 2344b8938c1SPoul-Henning Kamp } 23563728c47SPoul-Henning Kamp free(req->arg); 2367b6942a1SUlf Lilleengen if (req->error != NULL && req->error != nomemmsg) 2374b8938c1SPoul-Henning Kamp free(req->error); 2384b8938c1SPoul-Henning Kamp free(req); 2394b8938c1SPoul-Henning Kamp } 240