105c91076SPawel Jakub Dawidek /*- 205c91076SPawel Jakub Dawidek * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 305c91076SPawel Jakub Dawidek * All rights reserved. 405c91076SPawel Jakub Dawidek * 505c91076SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 605c91076SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 705c91076SPawel Jakub Dawidek * are met: 805c91076SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 905c91076SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 1005c91076SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 1105c91076SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 1205c91076SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 1305c91076SPawel Jakub Dawidek * 1405c91076SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1505c91076SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1605c91076SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1705c91076SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1805c91076SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1905c91076SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2005c91076SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2105c91076SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2205c91076SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2305c91076SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2405c91076SPawel Jakub Dawidek * SUCH DAMAGE. 2505c91076SPawel Jakub Dawidek */ 2605c91076SPawel Jakub Dawidek 2705c91076SPawel Jakub Dawidek #include <sys/cdefs.h> 2805c91076SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 2905c91076SPawel Jakub Dawidek 3005c91076SPawel Jakub Dawidek #include <sys/param.h> 3105c91076SPawel Jakub Dawidek #include <sys/disk.h> 3205c91076SPawel Jakub Dawidek #include <sys/endian.h> 3305c91076SPawel Jakub Dawidek #include <sys/uio.h> 3405c91076SPawel Jakub Dawidek #include <errno.h> 3505c91076SPawel Jakub Dawidek #include <fcntl.h> 3605c91076SPawel Jakub Dawidek #include <paths.h> 3705c91076SPawel Jakub Dawidek #include <stdio.h> 3805c91076SPawel Jakub Dawidek #include <stdlib.h> 3905c91076SPawel Jakub Dawidek #include <stdarg.h> 4005c91076SPawel Jakub Dawidek #include <string.h> 4105c91076SPawel Jakub Dawidek #include <strings.h> 4205c91076SPawel Jakub Dawidek #include <unistd.h> 4305c91076SPawel Jakub Dawidek #include <assert.h> 4405c91076SPawel Jakub Dawidek #include <libgeom.h> 4505c91076SPawel Jakub Dawidek 4605c91076SPawel Jakub Dawidek #include "misc/subr.h" 4705c91076SPawel Jakub Dawidek 4805c91076SPawel Jakub Dawidek 4905c91076SPawel Jakub Dawidek struct std_metadata { 5005c91076SPawel Jakub Dawidek char md_magic[16]; 5105c91076SPawel Jakub Dawidek uint32_t md_version; 5205c91076SPawel Jakub Dawidek }; 5305c91076SPawel Jakub Dawidek 5405c91076SPawel Jakub Dawidek static void 5505c91076SPawel Jakub Dawidek std_metadata_decode(const u_char *data, struct std_metadata *md) 5605c91076SPawel Jakub Dawidek { 5705c91076SPawel Jakub Dawidek 5805c91076SPawel Jakub Dawidek bcopy(data, md->md_magic, sizeof(md->md_magic)); 5905c91076SPawel Jakub Dawidek md->md_version = le32dec(data + 16); 6005c91076SPawel Jakub Dawidek } 6105c91076SPawel Jakub Dawidek 6205c91076SPawel Jakub Dawidek static void 6305c91076SPawel Jakub Dawidek pathgen(const char *name, char *path, size_t size) 6405c91076SPawel Jakub Dawidek { 6505c91076SPawel Jakub Dawidek 6605c91076SPawel Jakub Dawidek if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 6705c91076SPawel Jakub Dawidek snprintf(path, size, "%s%s", _PATH_DEV, name); 6805c91076SPawel Jakub Dawidek else 6905c91076SPawel Jakub Dawidek strlcpy(path, name, size); 7005c91076SPawel Jakub Dawidek } 7105c91076SPawel Jakub Dawidek 7209cc9ab6SPawel Jakub Dawidek /* 7309cc9ab6SPawel Jakub Dawidek * Greatest Common Divisor. 7409cc9ab6SPawel Jakub Dawidek */ 7509cc9ab6SPawel Jakub Dawidek static unsigned 7609cc9ab6SPawel Jakub Dawidek gcd(unsigned a, unsigned b) 7709cc9ab6SPawel Jakub Dawidek { 7809cc9ab6SPawel Jakub Dawidek u_int c; 7909cc9ab6SPawel Jakub Dawidek 8009cc9ab6SPawel Jakub Dawidek while (b != 0) { 8109cc9ab6SPawel Jakub Dawidek c = a; 8209cc9ab6SPawel Jakub Dawidek a = b; 8309cc9ab6SPawel Jakub Dawidek b = (c % b); 8409cc9ab6SPawel Jakub Dawidek } 8509cc9ab6SPawel Jakub Dawidek return (a); 8609cc9ab6SPawel Jakub Dawidek } 8709cc9ab6SPawel Jakub Dawidek 8809cc9ab6SPawel Jakub Dawidek /* 8909cc9ab6SPawel Jakub Dawidek * Least Common Multiple. 9009cc9ab6SPawel Jakub Dawidek */ 9109cc9ab6SPawel Jakub Dawidek unsigned 9209cc9ab6SPawel Jakub Dawidek g_lcm(unsigned a, unsigned b) 9309cc9ab6SPawel Jakub Dawidek { 9409cc9ab6SPawel Jakub Dawidek 9509cc9ab6SPawel Jakub Dawidek return ((a * b) / gcd(a, b)); 9609cc9ab6SPawel Jakub Dawidek } 9709cc9ab6SPawel Jakub Dawidek 9809cc9ab6SPawel Jakub Dawidek off_t 9909cc9ab6SPawel Jakub Dawidek g_get_mediasize(const char *name) 10009cc9ab6SPawel Jakub Dawidek { 10109cc9ab6SPawel Jakub Dawidek char path[MAXPATHLEN]; 10209cc9ab6SPawel Jakub Dawidek off_t mediasize; 10309cc9ab6SPawel Jakub Dawidek int fd; 10409cc9ab6SPawel Jakub Dawidek 10509cc9ab6SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 10609cc9ab6SPawel Jakub Dawidek fd = open(path, O_RDONLY); 10709cc9ab6SPawel Jakub Dawidek if (fd == -1) 10809cc9ab6SPawel Jakub Dawidek return (0); 10909cc9ab6SPawel Jakub Dawidek if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 11009cc9ab6SPawel Jakub Dawidek close(fd); 11109cc9ab6SPawel Jakub Dawidek return (0); 11209cc9ab6SPawel Jakub Dawidek } 11309cc9ab6SPawel Jakub Dawidek close(fd); 11409cc9ab6SPawel Jakub Dawidek return (mediasize); 11509cc9ab6SPawel Jakub Dawidek } 11609cc9ab6SPawel Jakub Dawidek 11709cc9ab6SPawel Jakub Dawidek unsigned 11809cc9ab6SPawel Jakub Dawidek g_get_sectorsize(const char *name) 11909cc9ab6SPawel Jakub Dawidek { 12009cc9ab6SPawel Jakub Dawidek char path[MAXPATHLEN]; 12109cc9ab6SPawel Jakub Dawidek unsigned sectorsize; 12209cc9ab6SPawel Jakub Dawidek int fd; 12309cc9ab6SPawel Jakub Dawidek 12409cc9ab6SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 12509cc9ab6SPawel Jakub Dawidek fd = open(path, O_RDONLY); 12609cc9ab6SPawel Jakub Dawidek if (fd == -1) 12709cc9ab6SPawel Jakub Dawidek return (0); 12809cc9ab6SPawel Jakub Dawidek if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 12909cc9ab6SPawel Jakub Dawidek close(fd); 13009cc9ab6SPawel Jakub Dawidek return (0); 13109cc9ab6SPawel Jakub Dawidek } 13209cc9ab6SPawel Jakub Dawidek close(fd); 13309cc9ab6SPawel Jakub Dawidek return (sectorsize); 13409cc9ab6SPawel Jakub Dawidek } 13509cc9ab6SPawel Jakub Dawidek 13605c91076SPawel Jakub Dawidek int 13705c91076SPawel Jakub Dawidek g_metadata_store(const char *name, u_char *md, size_t size) 13805c91076SPawel Jakub Dawidek { 13905c91076SPawel Jakub Dawidek char path[MAXPATHLEN]; 14005c91076SPawel Jakub Dawidek unsigned sectorsize; 14105c91076SPawel Jakub Dawidek off_t mediasize; 14205c91076SPawel Jakub Dawidek u_char *sector; 14305c91076SPawel Jakub Dawidek int error, fd; 14405c91076SPawel Jakub Dawidek 14505c91076SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 14605c91076SPawel Jakub Dawidek sector = NULL; 14705c91076SPawel Jakub Dawidek error = 0; 14805c91076SPawel Jakub Dawidek 14905c91076SPawel Jakub Dawidek fd = open(path, O_WRONLY); 15005c91076SPawel Jakub Dawidek if (fd == -1) 15105c91076SPawel Jakub Dawidek return (errno); 15209cc9ab6SPawel Jakub Dawidek mediasize = g_get_mediasize(name); 15309cc9ab6SPawel Jakub Dawidek if (mediasize == 0) { 15405c91076SPawel Jakub Dawidek error = errno; 15505c91076SPawel Jakub Dawidek goto out; 15605c91076SPawel Jakub Dawidek } 15709cc9ab6SPawel Jakub Dawidek sectorsize = g_get_sectorsize(name); 15809cc9ab6SPawel Jakub Dawidek if (sectorsize == 0) { 15905c91076SPawel Jakub Dawidek error = errno; 16005c91076SPawel Jakub Dawidek goto out; 16105c91076SPawel Jakub Dawidek } 16205c91076SPawel Jakub Dawidek assert(sectorsize >= size); 16305c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 16405c91076SPawel Jakub Dawidek if (sector == NULL) { 16505c91076SPawel Jakub Dawidek error = ENOMEM; 16605c91076SPawel Jakub Dawidek goto out; 16705c91076SPawel Jakub Dawidek } 16805c91076SPawel Jakub Dawidek bcopy(md, sector, size); 16905c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 17005c91076SPawel Jakub Dawidek (ssize_t)sectorsize) { 17105c91076SPawel Jakub Dawidek error = errno; 17205c91076SPawel Jakub Dawidek goto out; 17305c91076SPawel Jakub Dawidek } 17405c91076SPawel Jakub Dawidek out: 17505c91076SPawel Jakub Dawidek if (sector != NULL) 17605c91076SPawel Jakub Dawidek free(sector); 17705c91076SPawel Jakub Dawidek close(fd); 17805c91076SPawel Jakub Dawidek return (error); 17905c91076SPawel Jakub Dawidek } 18005c91076SPawel Jakub Dawidek 18105c91076SPawel Jakub Dawidek int 18205c91076SPawel Jakub Dawidek g_metadata_clear(const char *name, const char *magic) 18305c91076SPawel Jakub Dawidek { 18405c91076SPawel Jakub Dawidek struct std_metadata md; 18505c91076SPawel Jakub Dawidek char path[MAXPATHLEN]; 18605c91076SPawel Jakub Dawidek unsigned sectorsize; 18705c91076SPawel Jakub Dawidek off_t mediasize; 18805c91076SPawel Jakub Dawidek u_char *sector; 18905c91076SPawel Jakub Dawidek int error, fd; 19005c91076SPawel Jakub Dawidek 19105c91076SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 19205c91076SPawel Jakub Dawidek sector = NULL; 19305c91076SPawel Jakub Dawidek error = 0; 19405c91076SPawel Jakub Dawidek 19505c91076SPawel Jakub Dawidek fd = open(path, O_RDWR); 19605c91076SPawel Jakub Dawidek if (fd == -1) 19705c91076SPawel Jakub Dawidek return (errno); 19809cc9ab6SPawel Jakub Dawidek mediasize = g_get_mediasize(name); 19909cc9ab6SPawel Jakub Dawidek if (mediasize == 0) { 20005c91076SPawel Jakub Dawidek error = errno; 20105c91076SPawel Jakub Dawidek goto out; 20205c91076SPawel Jakub Dawidek } 20309cc9ab6SPawel Jakub Dawidek sectorsize = g_get_sectorsize(name); 20409cc9ab6SPawel Jakub Dawidek if (sectorsize == 0) { 20505c91076SPawel Jakub Dawidek error = errno; 20605c91076SPawel Jakub Dawidek goto out; 20705c91076SPawel Jakub Dawidek } 20805c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 20905c91076SPawel Jakub Dawidek if (sector == NULL) { 21005c91076SPawel Jakub Dawidek error = ENOMEM; 21105c91076SPawel Jakub Dawidek goto out; 21205c91076SPawel Jakub Dawidek } 21305c91076SPawel Jakub Dawidek if (magic != NULL) { 21405c91076SPawel Jakub Dawidek if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 21505c91076SPawel Jakub Dawidek (ssize_t)sectorsize) { 21605c91076SPawel Jakub Dawidek error = errno; 21705c91076SPawel Jakub Dawidek goto out; 21805c91076SPawel Jakub Dawidek } 21905c91076SPawel Jakub Dawidek std_metadata_decode(sector, &md); 22005c91076SPawel Jakub Dawidek if (strcmp(md.md_magic, magic) != 0) { 22105c91076SPawel Jakub Dawidek error = EINVAL; 22205c91076SPawel Jakub Dawidek goto out; 22305c91076SPawel Jakub Dawidek } 22405c91076SPawel Jakub Dawidek } 22505c91076SPawel Jakub Dawidek bzero(sector, sectorsize); 22605c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 22705c91076SPawel Jakub Dawidek (ssize_t)sectorsize) { 22805c91076SPawel Jakub Dawidek error = errno; 22905c91076SPawel Jakub Dawidek goto out; 23005c91076SPawel Jakub Dawidek } 23105c91076SPawel Jakub Dawidek out: 23205c91076SPawel Jakub Dawidek if (sector != NULL) 23305c91076SPawel Jakub Dawidek free(sector); 23405c91076SPawel Jakub Dawidek close(fd); 23505c91076SPawel Jakub Dawidek return (error); 23605c91076SPawel Jakub Dawidek } 23705c91076SPawel Jakub Dawidek 23805c91076SPawel Jakub Dawidek /* 23905c91076SPawel Jakub Dawidek * Set an error message, if one does not already exist. 24005c91076SPawel Jakub Dawidek */ 24105c91076SPawel Jakub Dawidek void 24205c91076SPawel Jakub Dawidek gctl_error(struct gctl_req *req, const char *error, ...) 24305c91076SPawel Jakub Dawidek { 24405c91076SPawel Jakub Dawidek va_list ap; 24505c91076SPawel Jakub Dawidek 24605c91076SPawel Jakub Dawidek if (req->error != NULL) 24705c91076SPawel Jakub Dawidek return; 24805c91076SPawel Jakub Dawidek va_start(ap, error); 24905c91076SPawel Jakub Dawidek vasprintf(&req->error, error, ap); 25005c91076SPawel Jakub Dawidek va_end(ap); 25105c91076SPawel Jakub Dawidek } 25205c91076SPawel Jakub Dawidek 25305c91076SPawel Jakub Dawidek void * 25405c91076SPawel Jakub Dawidek gctl_get_param(struct gctl_req *req, const char *param, int *len) 25505c91076SPawel Jakub Dawidek { 25605c91076SPawel Jakub Dawidek unsigned i; 25705c91076SPawel Jakub Dawidek void *p; 25805c91076SPawel Jakub Dawidek struct gctl_req_arg *ap; 25905c91076SPawel Jakub Dawidek 26005c91076SPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 26105c91076SPawel Jakub Dawidek ap = &req->arg[i]; 26205c91076SPawel Jakub Dawidek if (strcmp(param, ap->name)) 26305c91076SPawel Jakub Dawidek continue; 26405c91076SPawel Jakub Dawidek if (!(ap->flag & GCTL_PARAM_RD)) 26505c91076SPawel Jakub Dawidek continue; 26605c91076SPawel Jakub Dawidek p = ap->value; 26705c91076SPawel Jakub Dawidek if (len != NULL) 26805c91076SPawel Jakub Dawidek *len = ap->len; 26905c91076SPawel Jakub Dawidek return (p); 27005c91076SPawel Jakub Dawidek } 27105c91076SPawel Jakub Dawidek return (NULL); 27205c91076SPawel Jakub Dawidek } 27305c91076SPawel Jakub Dawidek 27405c91076SPawel Jakub Dawidek char const * 27505c91076SPawel Jakub Dawidek gctl_get_asciiparam(struct gctl_req *req, const char *param) 27605c91076SPawel Jakub Dawidek { 27705c91076SPawel Jakub Dawidek unsigned i; 27805c91076SPawel Jakub Dawidek char const *p; 27905c91076SPawel Jakub Dawidek struct gctl_req_arg *ap; 28005c91076SPawel Jakub Dawidek 28105c91076SPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 28205c91076SPawel Jakub Dawidek ap = &req->arg[i]; 28305c91076SPawel Jakub Dawidek if (strcmp(param, ap->name)) 28405c91076SPawel Jakub Dawidek continue; 28505c91076SPawel Jakub Dawidek if (!(ap->flag & GCTL_PARAM_RD)) 28605c91076SPawel Jakub Dawidek continue; 28705c91076SPawel Jakub Dawidek p = ap->value; 28805c91076SPawel Jakub Dawidek if (ap->len < 1) { 28905c91076SPawel Jakub Dawidek gctl_error(req, "No length argument (%s)", param); 29005c91076SPawel Jakub Dawidek return (NULL); 29105c91076SPawel Jakub Dawidek } 29205c91076SPawel Jakub Dawidek if (p[ap->len - 1] != '\0') { 29305c91076SPawel Jakub Dawidek gctl_error(req, "Unterminated argument (%s)", param); 29405c91076SPawel Jakub Dawidek return (NULL); 29505c91076SPawel Jakub Dawidek } 29605c91076SPawel Jakub Dawidek return (p); 29705c91076SPawel Jakub Dawidek } 29805c91076SPawel Jakub Dawidek return (NULL); 29905c91076SPawel Jakub Dawidek } 30005c91076SPawel Jakub Dawidek 30105c91076SPawel Jakub Dawidek void * 30205c91076SPawel Jakub Dawidek gctl_get_paraml(struct gctl_req *req, const char *param, int len) 30305c91076SPawel Jakub Dawidek { 30405c91076SPawel Jakub Dawidek int i; 30505c91076SPawel Jakub Dawidek void *p; 30605c91076SPawel Jakub Dawidek 30705c91076SPawel Jakub Dawidek p = gctl_get_param(req, param, &i); 30805c91076SPawel Jakub Dawidek if (p == NULL) 30905c91076SPawel Jakub Dawidek gctl_error(req, "Missing %s argument", param); 31005c91076SPawel Jakub Dawidek else if (i != len) { 31105c91076SPawel Jakub Dawidek p = NULL; 31205c91076SPawel Jakub Dawidek gctl_error(req, "Wrong length %s argument", param); 31305c91076SPawel Jakub Dawidek } 31405c91076SPawel Jakub Dawidek return (p); 31505c91076SPawel Jakub Dawidek } 316