geom_ctl.c revision 272461
161981Sbrian/*- 261981Sbrian * Copyright (c) 2003 Poul-Henning Kamp 361981Sbrian * All rights reserved. 461981Sbrian * 561981Sbrian * Redistribution and use in source and binary forms, with or without 661981Sbrian * modification, are permitted provided that the following conditions 761981Sbrian * are met: 861981Sbrian * 1. Redistributions of source code must retain the above copyright 961981Sbrian * notice, this list of conditions and the following disclaimer. 1061981Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1161981Sbrian * notice, this list of conditions and the following disclaimer in the 1261981Sbrian * documentation and/or other materials provided with the distribution. 1361981Sbrian * 3. The names of the authors may not be used to endorse or promote 1461981Sbrian * products derived from this software without specific prior written 1561981Sbrian * permission. 1661981Sbrian * 1761981Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1861981Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1961981Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2061981Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2161981Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2261981Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2361981Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2461981Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565843Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665843Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765843Sbrian * SUCH DAMAGE. 2865843Sbrian * 2965843Sbrian * $FreeBSD: releng/10.1/lib/libgeom/geom_ctl.c 214129 2010-10-21 10:38:14Z pjd $ 3065843Sbrian */ 3165843Sbrian 3265843Sbrian#include <stdio.h> 3365843Sbrian#include <fcntl.h> 3465843Sbrian#include <errno.h> 3561981Sbrian#include <stdint.h> 3661981Sbrian#include <sys/types.h> 3761981Sbrian#include <stdarg.h> 3861981Sbrian#include <unistd.h> 3961981Sbrian#include <string.h> 4061981Sbrian#include <stdlib.h> 4161981Sbrian#include <paths.h> 4261981Sbrian 4361981Sbrian#include <sys/queue.h> 4461981Sbrian 4561981Sbrian#define GCTL_TABLE 1 4661981Sbrian#include <libgeom.h> 4761981Sbrian 4861981Sbrian/* 4961981Sbrian * Global pointer to a string that is used to avoid an errorneous free in 5061981Sbrian * gctl_free. 5161981Sbrian */ 5261981Sbrianstatic char nomemmsg[] = "Could not allocate memory"; 5361981Sbrian 5461981Sbrianvoid 5561981Sbriangctl_dump(struct gctl_req *req, FILE *f) 5661981Sbrian{ 5761981Sbrian unsigned int i; 5861981Sbrian int j; 5961981Sbrian struct gctl_req_arg *ap; 6061981Sbrian 6161981Sbrian if (req == NULL) { 6261981Sbrian fprintf(f, "Dump of gctl request at NULL\n"); 6361981Sbrian return; 6461981Sbrian } 6561981Sbrian fprintf(f, "Dump of gctl request at %p:\n", req); 6661981Sbrian if (req->error != NULL) 6761981Sbrian fprintf(f, " error:\t\"%s\"\n", req->error); 6861981Sbrian else 6961981Sbrian fprintf(f, " error:\tNULL\n"); 7061981Sbrian for (i = 0; i < req->narg; i++) { 7161981Sbrian ap = &req->arg[i]; 7261981Sbrian fprintf(f, " param:\t\"%s\" (%d)", ap->name, ap->nlen); 7361981Sbrian fprintf(f, " [%s%s", 7474314Sbrian ap->flag & GCTL_PARAM_RD ? "R" : "", 7561981Sbrian ap->flag & GCTL_PARAM_WR ? "W" : ""); 7661981Sbrian fflush(f); 7761981Sbrian if (ap->flag & GCTL_PARAM_ASCII) 7861981Sbrian fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value); 7961981Sbrian else if (ap->len > 0) { 8061981Sbrian fprintf(f, "%d] = ", ap->len); 8162054Sbrian fflush(f); 8277496Sbrian for (j = 0; j < ap->len; j++) { 8377492Sbrian fprintf(f, " %02x", ((u_char *)ap->value)[j]); 8461981Sbrian } 8561981Sbrian } else { 8661981Sbrian fprintf(f, "0] = %p", ap->value); 8761981Sbrian } 8861981Sbrian fprintf(f, "\n"); 8961981Sbrian } 9061981Sbrian} 9161981Sbrian 9261981Sbrian/* 9362644Ssheldonh * Set an error message, if one does not already exist. 9461981Sbrian */ 9561981Sbrianstatic void 9661981Sbriangctl_set_error(struct gctl_req *req, const char *error, ...) 9761981Sbrian{ 9861981Sbrian va_list ap; 9961981Sbrian 10061981Sbrian if (req->error != NULL) 10161981Sbrian return; 10261981Sbrian va_start(ap, error); 10361981Sbrian vasprintf(&req->error, error, ap); 10461981Sbrian va_end(ap); 10594342Sgshapiro} 10661981Sbrian 10761981Sbrian/* 10861981Sbrian * Check that a malloc operation succeeded, and set a consistent error 10987514Scjc * message if not. 11061981Sbrian */ 11161981Sbrianstatic void 11261981Sbriangctl_check_alloc(struct gctl_req *req, void *ptr) 11362274Sbrian{ 11461981Sbrian 11575809Sdirk if (ptr != NULL) 11675809Sdirk return; 11775809Sdirk gctl_set_error(req, nomemmsg); 11875809Sdirk if (req->error == NULL) 11972677Speter req->error = nomemmsg; 12072677Speter} 12194342Sgshapiro 12272677Speter/* 12361981Sbrian * Allocate a new request handle of the specified type. 12461981Sbrian * XXX: Why bother checking the type ? 12561981Sbrian */ 12661981Sbrianstruct gctl_req * 12787514Scjcgctl_get_handle(void) 12887514Scjc{ 12987514Scjc 13087514Scjc return (calloc(1, sizeof(struct gctl_req))); 13187514Scjc} 13287514Scjc 13387514Scjc/* 13487514Scjc * Allocate space for another argument. 13587514Scjc */ 13687514Scjcstatic struct gctl_req_arg * 13787514Scjcgctl_new_arg(struct gctl_req *req) 13887514Scjc{ 13987514Scjc struct gctl_req_arg *ap; 14087514Scjc 14187514Scjc req->narg++; 14287514Scjc req->arg = reallocf(req->arg, sizeof *ap * req->narg); 14387514Scjc gctl_check_alloc(req, req->arg); 14487514Scjc if (req->arg == NULL) { 14587514Scjc req->narg = 0; 14687514Scjc return (NULL); 14787514Scjc } 14887514Scjc ap = req->arg + (req->narg - 1); 14987514Scjc memset(ap, 0, sizeof *ap); 15087514Scjc return (ap); 15187514Scjc} 15287514Scjc 15387514Scjcstatic void 15487514Scjcgctl_param_add(struct gctl_req *req, const char *name, int len, void *value, 15587514Scjc int flag) 15687514Scjc{ 15787514Scjc struct gctl_req_arg *ap; 15887514Scjc 15987514Scjc if (req == NULL || req->error != NULL) 16087514Scjc return; 16187514Scjc ap = gctl_new_arg(req); 16287514Scjc if (ap == NULL) 16387514Scjc return; 16487514Scjc ap->name = strdup(name); 16587514Scjc gctl_check_alloc(req, ap->name); 16687514Scjc if (ap->name == NULL) 16787514Scjc return; 16887514Scjc ap->nlen = strlen(ap->name) + 1; 16987514Scjc ap->value = value; 17087514Scjc ap->flag = flag; 17187514Scjc if (len >= 0) 17261981Sbrian ap->len = len; 17361981Sbrian else if (len < 0) { 17465843Sbrian ap->flag |= GCTL_PARAM_ASCII; 17565843Sbrian ap->len = strlen(value) + 1; 17665843Sbrian } 17765843Sbrian} 17865843Sbrian 17965843Sbrianvoid 18065843Sbriangctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value) 18165843Sbrian{ 18265843Sbrian 18365843Sbrian gctl_param_add(req, name, len, __DECONST(void *, value), GCTL_PARAM_RD); 18461981Sbrian} 18561981Sbrian 18661981Sbrianvoid 18761981Sbriangctl_rw_param(struct gctl_req *req, const char *name, int len, void *value) 18861981Sbrian{ 18961981Sbrian 19061981Sbrian gctl_param_add(req, name, len, value, GCTL_PARAM_RW); 19161981Sbrian} 19261981Sbrian 19361981Sbrianconst char * 19461981Sbriangctl_issue(struct gctl_req *req) 19561981Sbrian{ 19661981Sbrian int fd, error; 19761981Sbrian 19861981Sbrian if (req == NULL) 19961981Sbrian return ("NULL request pointer"); 20061981Sbrian if (req->error != NULL) 20161981Sbrian return (req->error); 20262206Sbrian 20362155Sbrian req->version = GCTL_VERSION; 20462155Sbrian req->lerror = BUFSIZ; /* XXX: arbitrary number */ 20561981Sbrian req->error = calloc(1, req->lerror); 20661981Sbrian if (req->error == NULL) { 20761981Sbrian gctl_check_alloc(req, req->error); 20861981Sbrian return (req->error); 20961981Sbrian } 21061981Sbrian req->lerror--; 21165843Sbrian fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY); 21265843Sbrian if (fd < 0) 21365843Sbrian return(strerror(errno)); 21465843Sbrian error = ioctl(fd, GEOM_CTL, req); 21565843Sbrian close(fd); 21665843Sbrian if (req->error[0] != '\0') 21765843Sbrian return (req->error); 21865843Sbrian if (error != 0) 21965843Sbrian return(strerror(errno)); 22065843Sbrian return (NULL); 22161981Sbrian} 22261981Sbrian 22361981Sbrianvoid 22461981Sbriangctl_free(struct gctl_req *req) 22561981Sbrian{ 22661981Sbrian unsigned int i; 22761981Sbrian 22861981Sbrian if (req == NULL) 22961981Sbrian return; 23061981Sbrian for (i = 0; i < req->narg; i++) { 23161981Sbrian if (req->arg[i].name != NULL) 23261981Sbrian free(req->arg[i].name); 23361981Sbrian } 23461981Sbrian free(req->arg); 23561981Sbrian if (req->error != NULL && req->error != nomemmsg) 23661981Sbrian free(req->error); 23761981Sbrian free(req); 23861981Sbrian} 23961981Sbrian