105c91076SPawel Jakub Dawidek /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 47157a8adSPawel Jakub Dawidek * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 505c91076SPawel Jakub Dawidek * All rights reserved. 605c91076SPawel Jakub Dawidek * 705c91076SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 805c91076SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 905c91076SPawel Jakub Dawidek * are met: 1005c91076SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 1105c91076SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 1205c91076SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 1305c91076SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 1405c91076SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 1505c91076SPawel Jakub Dawidek * 1605c91076SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1705c91076SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1805c91076SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1905c91076SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2005c91076SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2105c91076SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2205c91076SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2305c91076SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2405c91076SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2505c91076SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2605c91076SPawel Jakub Dawidek * SUCH DAMAGE. 2705c91076SPawel Jakub Dawidek */ 2805c91076SPawel Jakub Dawidek 2905c91076SPawel Jakub Dawidek #include <sys/cdefs.h> 3005c91076SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 3105c91076SPawel Jakub Dawidek 3205c91076SPawel Jakub Dawidek #include <sys/param.h> 3305c91076SPawel Jakub Dawidek #include <sys/disk.h> 3405c91076SPawel Jakub Dawidek #include <sys/endian.h> 3505c91076SPawel Jakub Dawidek #include <sys/uio.h> 3605c91076SPawel Jakub Dawidek #include <errno.h> 3705c91076SPawel Jakub Dawidek #include <fcntl.h> 3805c91076SPawel Jakub Dawidek #include <paths.h> 3905c91076SPawel Jakub Dawidek #include <stdio.h> 4005c91076SPawel Jakub Dawidek #include <stdlib.h> 4179d89bb0SAndrey V. Elsukov #include <limits.h> 4279d89bb0SAndrey V. Elsukov #include <inttypes.h> 4305c91076SPawel Jakub Dawidek #include <stdarg.h> 4405c91076SPawel Jakub Dawidek #include <string.h> 4505c91076SPawel Jakub Dawidek #include <strings.h> 4605c91076SPawel Jakub Dawidek #include <unistd.h> 4705c91076SPawel Jakub Dawidek #include <assert.h> 4805c91076SPawel Jakub Dawidek #include <libgeom.h> 4905c91076SPawel Jakub Dawidek 5005c91076SPawel Jakub Dawidek #include "misc/subr.h" 5105c91076SPawel Jakub Dawidek 5205c91076SPawel Jakub Dawidek 5305c91076SPawel Jakub Dawidek struct std_metadata { 5405c91076SPawel Jakub Dawidek char md_magic[16]; 5505c91076SPawel Jakub Dawidek uint32_t md_version; 5605c91076SPawel Jakub Dawidek }; 5705c91076SPawel Jakub Dawidek 5805c91076SPawel Jakub Dawidek static void 597157a8adSPawel Jakub Dawidek std_metadata_decode(const unsigned char *data, struct std_metadata *md) 6005c91076SPawel Jakub Dawidek { 6105c91076SPawel Jakub Dawidek 6205c91076SPawel Jakub Dawidek bcopy(data, md->md_magic, sizeof(md->md_magic)); 6305c91076SPawel Jakub Dawidek md->md_version = le32dec(data + 16); 6405c91076SPawel Jakub Dawidek } 6505c91076SPawel Jakub Dawidek 6609cc9ab6SPawel Jakub Dawidek /* 6709cc9ab6SPawel Jakub Dawidek * Greatest Common Divisor. 6809cc9ab6SPawel Jakub Dawidek */ 697157a8adSPawel Jakub Dawidek static unsigned int 707157a8adSPawel Jakub Dawidek gcd(unsigned int a, unsigned int b) 7109cc9ab6SPawel Jakub Dawidek { 727157a8adSPawel Jakub Dawidek unsigned int c; 7309cc9ab6SPawel Jakub Dawidek 7409cc9ab6SPawel Jakub Dawidek while (b != 0) { 7509cc9ab6SPawel Jakub Dawidek c = a; 7609cc9ab6SPawel Jakub Dawidek a = b; 7709cc9ab6SPawel Jakub Dawidek b = (c % b); 7809cc9ab6SPawel Jakub Dawidek } 7909cc9ab6SPawel Jakub Dawidek return (a); 8009cc9ab6SPawel Jakub Dawidek } 8109cc9ab6SPawel Jakub Dawidek 8209cc9ab6SPawel Jakub Dawidek /* 8309cc9ab6SPawel Jakub Dawidek * Least Common Multiple. 8409cc9ab6SPawel Jakub Dawidek */ 857157a8adSPawel Jakub Dawidek unsigned int 867157a8adSPawel Jakub Dawidek g_lcm(unsigned int a, unsigned int b) 8709cc9ab6SPawel Jakub Dawidek { 8809cc9ab6SPawel Jakub Dawidek 8909cc9ab6SPawel Jakub Dawidek return ((a * b) / gcd(a, b)); 9009cc9ab6SPawel Jakub Dawidek } 9109cc9ab6SPawel Jakub Dawidek 9282978104SPawel Jakub Dawidek uint32_t 9382978104SPawel Jakub Dawidek bitcount32(uint32_t x) 9482978104SPawel Jakub Dawidek { 9582978104SPawel Jakub Dawidek 9682978104SPawel Jakub Dawidek x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 9782978104SPawel Jakub Dawidek x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 9882978104SPawel Jakub Dawidek x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 9982978104SPawel Jakub Dawidek x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 10082978104SPawel Jakub Dawidek x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 10182978104SPawel Jakub Dawidek return (x); 10282978104SPawel Jakub Dawidek } 10382978104SPawel Jakub Dawidek 10479d89bb0SAndrey V. Elsukov /* 10579d89bb0SAndrey V. Elsukov * The size of a sector is context specific (i.e. determined by the 10679d89bb0SAndrey V. Elsukov * media). But when users enter a value with a SI unit, they really 10779d89bb0SAndrey V. Elsukov * mean the byte-size or byte-offset and not the size or offset in 10879d89bb0SAndrey V. Elsukov * sectors. We should map the byte-oriented value into a sector-oriented 10979d89bb0SAndrey V. Elsukov * value when we already know the sector size in bytes. At this time 11079d89bb0SAndrey V. Elsukov * we can use g_parse_lba() function. It converts user specified 11179d89bb0SAndrey V. Elsukov * value into sectors with following conditions: 11279d89bb0SAndrey V. Elsukov * o Sectors size taken as argument from caller. 11379d89bb0SAndrey V. Elsukov * o When no SI unit is specified the value is in sectors. 11479d89bb0SAndrey V. Elsukov * o With an SI unit the value is in bytes. 11579d89bb0SAndrey V. Elsukov * o The 'b' suffix forces byte interpretation and the 's' 11679d89bb0SAndrey V. Elsukov * suffix forces sector interpretation. 11779d89bb0SAndrey V. Elsukov * 11879d89bb0SAndrey V. Elsukov * Thus: 11979d89bb0SAndrey V. Elsukov * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. 12079d89bb0SAndrey V. Elsukov * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. 12179d89bb0SAndrey V. Elsukov * 12279d89bb0SAndrey V. Elsukov */ 12379d89bb0SAndrey V. Elsukov int 1247157a8adSPawel Jakub Dawidek g_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors) 12579d89bb0SAndrey V. Elsukov { 12679d89bb0SAndrey V. Elsukov off_t number, mult, unit; 12779d89bb0SAndrey V. Elsukov char *s; 12879d89bb0SAndrey V. Elsukov 12979d89bb0SAndrey V. Elsukov assert(lbastr != NULL); 13079d89bb0SAndrey V. Elsukov assert(sectorsize > 0); 13179d89bb0SAndrey V. Elsukov assert(sectors != NULL); 13279d89bb0SAndrey V. Elsukov 13379d89bb0SAndrey V. Elsukov number = (off_t)strtoimax(lbastr, &s, 0); 13402fc6609SAndrey V. Elsukov if (s == lbastr || number < 0) 13579d89bb0SAndrey V. Elsukov return (EINVAL); 13679d89bb0SAndrey V. Elsukov 13779d89bb0SAndrey V. Elsukov mult = 1; 13879d89bb0SAndrey V. Elsukov unit = sectorsize; 13979d89bb0SAndrey V. Elsukov if (*s == '\0') 14079d89bb0SAndrey V. Elsukov goto done; 14179d89bb0SAndrey V. Elsukov switch (*s) { 14279d89bb0SAndrey V. Elsukov case 'e': case 'E': 14379d89bb0SAndrey V. Elsukov mult *= 1024; 14479d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 14579d89bb0SAndrey V. Elsukov case 'p': case 'P': 14679d89bb0SAndrey V. Elsukov mult *= 1024; 14779d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 14879d89bb0SAndrey V. Elsukov case 't': case 'T': 14979d89bb0SAndrey V. Elsukov mult *= 1024; 15079d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 15179d89bb0SAndrey V. Elsukov case 'g': case 'G': 15279d89bb0SAndrey V. Elsukov mult *= 1024; 15379d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 15479d89bb0SAndrey V. Elsukov case 'm': case 'M': 15579d89bb0SAndrey V. Elsukov mult *= 1024; 15679d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 15779d89bb0SAndrey V. Elsukov case 'k': case 'K': 15879d89bb0SAndrey V. Elsukov mult *= 1024; 15979d89bb0SAndrey V. Elsukov break; 16079d89bb0SAndrey V. Elsukov default: 16179d89bb0SAndrey V. Elsukov goto sfx; 16279d89bb0SAndrey V. Elsukov } 16379d89bb0SAndrey V. Elsukov unit = 1; /* bytes */ 16479d89bb0SAndrey V. Elsukov s++; 16579d89bb0SAndrey V. Elsukov if (*s == '\0') 16679d89bb0SAndrey V. Elsukov goto done; 16779d89bb0SAndrey V. Elsukov sfx: 16879d89bb0SAndrey V. Elsukov switch (*s) { 16979d89bb0SAndrey V. Elsukov case 's': case 'S': 17079d89bb0SAndrey V. Elsukov unit = sectorsize; /* sector */ 17179d89bb0SAndrey V. Elsukov break; 17279d89bb0SAndrey V. Elsukov case 'b': case 'B': 17379d89bb0SAndrey V. Elsukov unit = 1; /* bytes */ 17479d89bb0SAndrey V. Elsukov break; 17579d89bb0SAndrey V. Elsukov default: 17679d89bb0SAndrey V. Elsukov return (EINVAL); 17779d89bb0SAndrey V. Elsukov } 17879d89bb0SAndrey V. Elsukov s++; 17979d89bb0SAndrey V. Elsukov if (*s != '\0') 18079d89bb0SAndrey V. Elsukov return (EINVAL); 18179d89bb0SAndrey V. Elsukov done: 18202fc6609SAndrey V. Elsukov if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number) 18379d89bb0SAndrey V. Elsukov return (ERANGE); 18479d89bb0SAndrey V. Elsukov number *= mult * unit; 18579d89bb0SAndrey V. Elsukov if (number % sectorsize) 18679d89bb0SAndrey V. Elsukov return (EINVAL); 18779d89bb0SAndrey V. Elsukov number /= sectorsize; 18879d89bb0SAndrey V. Elsukov *sectors = number; 18979d89bb0SAndrey V. Elsukov return (0); 19079d89bb0SAndrey V. Elsukov } 19179d89bb0SAndrey V. Elsukov 19209cc9ab6SPawel Jakub Dawidek off_t 19309cc9ab6SPawel Jakub Dawidek g_get_mediasize(const char *name) 19409cc9ab6SPawel Jakub Dawidek { 19509cc9ab6SPawel Jakub Dawidek off_t mediasize; 19609cc9ab6SPawel Jakub Dawidek int fd; 19709cc9ab6SPawel Jakub Dawidek 1987157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 19909cc9ab6SPawel Jakub Dawidek if (fd == -1) 20009cc9ab6SPawel Jakub Dawidek return (0); 2017157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 2027157a8adSPawel Jakub Dawidek if (mediasize == -1) 2037157a8adSPawel Jakub Dawidek mediasize = 0; 2047157a8adSPawel Jakub Dawidek (void)g_close(fd); 20509cc9ab6SPawel Jakub Dawidek return (mediasize); 20609cc9ab6SPawel Jakub Dawidek } 20709cc9ab6SPawel Jakub Dawidek 2087157a8adSPawel Jakub Dawidek unsigned int 20909cc9ab6SPawel Jakub Dawidek g_get_sectorsize(const char *name) 21009cc9ab6SPawel Jakub Dawidek { 2117157a8adSPawel Jakub Dawidek ssize_t sectorsize; 21209cc9ab6SPawel Jakub Dawidek int fd; 21309cc9ab6SPawel Jakub Dawidek 2147157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 21509cc9ab6SPawel Jakub Dawidek if (fd == -1) 21609cc9ab6SPawel Jakub Dawidek return (0); 2177157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 2187157a8adSPawel Jakub Dawidek if (sectorsize == -1) 2197157a8adSPawel Jakub Dawidek sectorsize = 0; 2207157a8adSPawel Jakub Dawidek (void)g_close(fd); 2217157a8adSPawel Jakub Dawidek return ((unsigned int)sectorsize); 22209cc9ab6SPawel Jakub Dawidek } 22309cc9ab6SPawel Jakub Dawidek 22405c91076SPawel Jakub Dawidek int 2257157a8adSPawel Jakub Dawidek g_metadata_read(const char *name, unsigned char *md, size_t size, 2267157a8adSPawel Jakub Dawidek const char *magic) 22710fa0ebeSPawel Jakub Dawidek { 22810fa0ebeSPawel Jakub Dawidek struct std_metadata stdmd; 2297157a8adSPawel Jakub Dawidek unsigned char *sector; 2307157a8adSPawel Jakub Dawidek ssize_t sectorsize; 23110fa0ebeSPawel Jakub Dawidek off_t mediasize; 23210fa0ebeSPawel Jakub Dawidek int error, fd; 23310fa0ebeSPawel Jakub Dawidek 23410fa0ebeSPawel Jakub Dawidek sector = NULL; 23510fa0ebeSPawel Jakub Dawidek error = 0; 23610fa0ebeSPawel Jakub Dawidek 2377157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 23810fa0ebeSPawel Jakub Dawidek if (fd == -1) 23910fa0ebeSPawel Jakub Dawidek return (errno); 2407157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 2417157a8adSPawel Jakub Dawidek if (mediasize == -1) { 24210fa0ebeSPawel Jakub Dawidek error = errno; 24310fa0ebeSPawel Jakub Dawidek goto out; 24410fa0ebeSPawel Jakub Dawidek } 2457157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 2467157a8adSPawel Jakub Dawidek if (sectorsize == -1) { 24710fa0ebeSPawel Jakub Dawidek error = errno; 24810fa0ebeSPawel Jakub Dawidek goto out; 24910fa0ebeSPawel Jakub Dawidek } 2507157a8adSPawel Jakub Dawidek assert(sectorsize >= (ssize_t)size); 25110fa0ebeSPawel Jakub Dawidek sector = malloc(sectorsize); 25210fa0ebeSPawel Jakub Dawidek if (sector == NULL) { 25310fa0ebeSPawel Jakub Dawidek error = ENOMEM; 25410fa0ebeSPawel Jakub Dawidek goto out; 25510fa0ebeSPawel Jakub Dawidek } 25610fa0ebeSPawel Jakub Dawidek if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 2577157a8adSPawel Jakub Dawidek sectorsize) { 25810fa0ebeSPawel Jakub Dawidek error = errno; 25910fa0ebeSPawel Jakub Dawidek goto out; 26010fa0ebeSPawel Jakub Dawidek } 26110fa0ebeSPawel Jakub Dawidek if (magic != NULL) { 26210fa0ebeSPawel Jakub Dawidek std_metadata_decode(sector, &stdmd); 26310fa0ebeSPawel Jakub Dawidek if (strcmp(stdmd.md_magic, magic) != 0) { 26410fa0ebeSPawel Jakub Dawidek error = EINVAL; 26510fa0ebeSPawel Jakub Dawidek goto out; 26610fa0ebeSPawel Jakub Dawidek } 26710fa0ebeSPawel Jakub Dawidek } 26810fa0ebeSPawel Jakub Dawidek bcopy(sector, md, size); 26910fa0ebeSPawel Jakub Dawidek out: 27010fa0ebeSPawel Jakub Dawidek if (sector != NULL) 27110fa0ebeSPawel Jakub Dawidek free(sector); 2727157a8adSPawel Jakub Dawidek g_close(fd); 27310fa0ebeSPawel Jakub Dawidek return (error); 27410fa0ebeSPawel Jakub Dawidek } 27510fa0ebeSPawel Jakub Dawidek 276*f5b4099eSAlan Somers /* 277*f5b4099eSAlan Somers * Actually write the GEOM label to the provider 278*f5b4099eSAlan Somers * 279*f5b4099eSAlan Somers * @param name GEOM provider's name (ie "ada0") 280*f5b4099eSAlan Somers * @param md Pointer to the label data to write 281*f5b4099eSAlan Somers * @param size Size of the data pointed to by md 282*f5b4099eSAlan Somers */ 28310fa0ebeSPawel Jakub Dawidek int 2847157a8adSPawel Jakub Dawidek g_metadata_store(const char *name, const unsigned char *md, size_t size) 28505c91076SPawel Jakub Dawidek { 2867157a8adSPawel Jakub Dawidek unsigned char *sector; 2877157a8adSPawel Jakub Dawidek ssize_t sectorsize; 28805c91076SPawel Jakub Dawidek off_t mediasize; 28905c91076SPawel Jakub Dawidek int error, fd; 29005c91076SPawel Jakub Dawidek 29105c91076SPawel Jakub Dawidek sector = NULL; 29205c91076SPawel Jakub Dawidek error = 0; 29305c91076SPawel Jakub Dawidek 2947157a8adSPawel Jakub Dawidek fd = g_open(name, 1); 29505c91076SPawel Jakub Dawidek if (fd == -1) 29605c91076SPawel Jakub Dawidek return (errno); 2977157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 2987157a8adSPawel Jakub Dawidek if (mediasize == -1) { 29905c91076SPawel Jakub Dawidek error = errno; 30005c91076SPawel Jakub Dawidek goto out; 30105c91076SPawel Jakub Dawidek } 3027157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 3037157a8adSPawel Jakub Dawidek if (sectorsize == -1) { 30405c91076SPawel Jakub Dawidek error = errno; 30505c91076SPawel Jakub Dawidek goto out; 30605c91076SPawel Jakub Dawidek } 3077157a8adSPawel Jakub Dawidek assert(sectorsize >= (ssize_t)size); 30805c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 30905c91076SPawel Jakub Dawidek if (sector == NULL) { 31005c91076SPawel Jakub Dawidek error = ENOMEM; 31105c91076SPawel Jakub Dawidek goto out; 31205c91076SPawel Jakub Dawidek } 31305c91076SPawel Jakub Dawidek bcopy(md, sector, size); 3140bd816f2SConrad Meyer bzero(sector + size, sectorsize - size); 31505c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 3167157a8adSPawel Jakub Dawidek sectorsize) { 31705c91076SPawel Jakub Dawidek error = errno; 31805c91076SPawel Jakub Dawidek goto out; 31905c91076SPawel Jakub Dawidek } 3207157a8adSPawel Jakub Dawidek (void)g_flush(fd); 32105c91076SPawel Jakub Dawidek out: 32205c91076SPawel Jakub Dawidek if (sector != NULL) 32305c91076SPawel Jakub Dawidek free(sector); 3247157a8adSPawel Jakub Dawidek (void)g_close(fd); 32505c91076SPawel Jakub Dawidek return (error); 32605c91076SPawel Jakub Dawidek } 32705c91076SPawel Jakub Dawidek 32805c91076SPawel Jakub Dawidek int 32905c91076SPawel Jakub Dawidek g_metadata_clear(const char *name, const char *magic) 33005c91076SPawel Jakub Dawidek { 33105c91076SPawel Jakub Dawidek struct std_metadata md; 3327157a8adSPawel Jakub Dawidek unsigned char *sector; 3337157a8adSPawel Jakub Dawidek ssize_t sectorsize; 33405c91076SPawel Jakub Dawidek off_t mediasize; 33505c91076SPawel Jakub Dawidek int error, fd; 33605c91076SPawel Jakub Dawidek 33705c91076SPawel Jakub Dawidek sector = NULL; 33805c91076SPawel Jakub Dawidek error = 0; 33905c91076SPawel Jakub Dawidek 3407157a8adSPawel Jakub Dawidek fd = g_open(name, 1); 34105c91076SPawel Jakub Dawidek if (fd == -1) 34205c91076SPawel Jakub Dawidek return (errno); 3437157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 34409cc9ab6SPawel Jakub Dawidek if (mediasize == 0) { 34505c91076SPawel Jakub Dawidek error = errno; 34605c91076SPawel Jakub Dawidek goto out; 34705c91076SPawel Jakub Dawidek } 3487157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 349fc9437c8SAlan Somers if (sectorsize <= 0) { 35005c91076SPawel Jakub Dawidek error = errno; 35105c91076SPawel Jakub Dawidek goto out; 35205c91076SPawel Jakub Dawidek } 35305c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 35405c91076SPawel Jakub Dawidek if (sector == NULL) { 35505c91076SPawel Jakub Dawidek error = ENOMEM; 35605c91076SPawel Jakub Dawidek goto out; 35705c91076SPawel Jakub Dawidek } 35805c91076SPawel Jakub Dawidek if (magic != NULL) { 35905c91076SPawel Jakub Dawidek if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 3607157a8adSPawel Jakub Dawidek sectorsize) { 36105c91076SPawel Jakub Dawidek error = errno; 36205c91076SPawel Jakub Dawidek goto out; 36305c91076SPawel Jakub Dawidek } 36405c91076SPawel Jakub Dawidek std_metadata_decode(sector, &md); 36505c91076SPawel Jakub Dawidek if (strcmp(md.md_magic, magic) != 0) { 36605c91076SPawel Jakub Dawidek error = EINVAL; 36705c91076SPawel Jakub Dawidek goto out; 36805c91076SPawel Jakub Dawidek } 36905c91076SPawel Jakub Dawidek } 37005c91076SPawel Jakub Dawidek bzero(sector, sectorsize); 37105c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 3727157a8adSPawel Jakub Dawidek sectorsize) { 37305c91076SPawel Jakub Dawidek error = errno; 37405c91076SPawel Jakub Dawidek goto out; 37505c91076SPawel Jakub Dawidek } 3767157a8adSPawel Jakub Dawidek (void)g_flush(fd); 37705c91076SPawel Jakub Dawidek out: 37805c91076SPawel Jakub Dawidek free(sector); 3797157a8adSPawel Jakub Dawidek g_close(fd); 38005c91076SPawel Jakub Dawidek return (error); 38105c91076SPawel Jakub Dawidek } 38205c91076SPawel Jakub Dawidek 38305c91076SPawel Jakub Dawidek /* 38405c91076SPawel Jakub Dawidek * Set an error message, if one does not already exist. 38505c91076SPawel Jakub Dawidek */ 38605c91076SPawel Jakub Dawidek void 38705c91076SPawel Jakub Dawidek gctl_error(struct gctl_req *req, const char *error, ...) 38805c91076SPawel Jakub Dawidek { 38905c91076SPawel Jakub Dawidek va_list ap; 39005c91076SPawel Jakub Dawidek 391275ae453SPawel Jakub Dawidek if (req != NULL && req->error != NULL) 39205c91076SPawel Jakub Dawidek return; 39305c91076SPawel Jakub Dawidek va_start(ap, error); 394275ae453SPawel Jakub Dawidek if (req != NULL) { 39505c91076SPawel Jakub Dawidek vasprintf(&req->error, error, ap); 396275ae453SPawel Jakub Dawidek } else { 397275ae453SPawel Jakub Dawidek vfprintf(stderr, error, ap); 398275ae453SPawel Jakub Dawidek fprintf(stderr, "\n"); 399275ae453SPawel Jakub Dawidek } 40005c91076SPawel Jakub Dawidek va_end(ap); 40105c91076SPawel Jakub Dawidek } 40205c91076SPawel Jakub Dawidek 403f13942a7SPawel Jakub Dawidek static void * 404f13942a7SPawel Jakub Dawidek gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 40505c91076SPawel Jakub Dawidek { 406f13942a7SPawel Jakub Dawidek struct gctl_req_arg *argp; 407f13942a7SPawel Jakub Dawidek char param[256]; 4087157a8adSPawel Jakub Dawidek unsigned int i; 40905c91076SPawel Jakub Dawidek void *p; 41005c91076SPawel Jakub Dawidek 411f13942a7SPawel Jakub Dawidek vsnprintf(param, sizeof(param), pfmt, ap); 41205c91076SPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 413f13942a7SPawel Jakub Dawidek argp = &req->arg[i]; 414f13942a7SPawel Jakub Dawidek if (strcmp(param, argp->name)) 41505c91076SPawel Jakub Dawidek continue; 416f13942a7SPawel Jakub Dawidek if (!(argp->flag & GCTL_PARAM_RD)) 41705c91076SPawel Jakub Dawidek continue; 418f13942a7SPawel Jakub Dawidek p = argp->value; 419f13942a7SPawel Jakub Dawidek if (len == 0) { 420f13942a7SPawel Jakub Dawidek /* We are looking for a string. */ 421f13942a7SPawel Jakub Dawidek if (argp->len < 1) { 422f13942a7SPawel Jakub Dawidek fprintf(stderr, "No length argument (%s).\n", 423f13942a7SPawel Jakub Dawidek param); 424f13942a7SPawel Jakub Dawidek abort(); 42505c91076SPawel Jakub Dawidek } 426f13942a7SPawel Jakub Dawidek if (((char *)p)[argp->len - 1] != '\0') { 427f13942a7SPawel Jakub Dawidek fprintf(stderr, "Unterminated argument (%s).\n", 428f13942a7SPawel Jakub Dawidek param); 429f13942a7SPawel Jakub Dawidek abort(); 430f13942a7SPawel Jakub Dawidek } 431f13942a7SPawel Jakub Dawidek } else if ((int)len != argp->len) { 432f13942a7SPawel Jakub Dawidek fprintf(stderr, "Wrong length %s argument.\n", param); 433f13942a7SPawel Jakub Dawidek abort(); 43405c91076SPawel Jakub Dawidek } 43505c91076SPawel Jakub Dawidek return (p); 43605c91076SPawel Jakub Dawidek } 437f13942a7SPawel Jakub Dawidek fprintf(stderr, "No such argument (%s).\n", param); 438f13942a7SPawel Jakub Dawidek abort(); 43905c91076SPawel Jakub Dawidek } 44005c91076SPawel Jakub Dawidek 441f13942a7SPawel Jakub Dawidek int 442f13942a7SPawel Jakub Dawidek gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 44305c91076SPawel Jakub Dawidek { 444f13942a7SPawel Jakub Dawidek int *p; 445f13942a7SPawel Jakub Dawidek va_list ap; 44605c91076SPawel Jakub Dawidek 447f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 448f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(int), pfmt, ap); 449f13942a7SPawel Jakub Dawidek va_end(ap); 450f13942a7SPawel Jakub Dawidek return (*p); 45105c91076SPawel Jakub Dawidek } 452f13942a7SPawel Jakub Dawidek 453f13942a7SPawel Jakub Dawidek intmax_t 454f13942a7SPawel Jakub Dawidek gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 455f13942a7SPawel Jakub Dawidek { 456f13942a7SPawel Jakub Dawidek intmax_t *p; 457f13942a7SPawel Jakub Dawidek va_list ap; 458f13942a7SPawel Jakub Dawidek 459f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 460f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 461f13942a7SPawel Jakub Dawidek va_end(ap); 462f13942a7SPawel Jakub Dawidek return (*p); 463f13942a7SPawel Jakub Dawidek } 464f13942a7SPawel Jakub Dawidek 465f13942a7SPawel Jakub Dawidek const char * 466f13942a7SPawel Jakub Dawidek gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 467f13942a7SPawel Jakub Dawidek { 468f13942a7SPawel Jakub Dawidek const char *p; 469f13942a7SPawel Jakub Dawidek va_list ap; 470f13942a7SPawel Jakub Dawidek 471f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 472f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, 0, pfmt, ap); 473f13942a7SPawel Jakub Dawidek va_end(ap); 47405c91076SPawel Jakub Dawidek return (p); 47505c91076SPawel Jakub Dawidek } 4761378624cSPawel Jakub Dawidek 4771378624cSPawel Jakub Dawidek int 4781378624cSPawel Jakub Dawidek gctl_change_param(struct gctl_req *req, const char *name, int len, 4791378624cSPawel Jakub Dawidek const void *value) 4801378624cSPawel Jakub Dawidek { 4811378624cSPawel Jakub Dawidek struct gctl_req_arg *ap; 4827157a8adSPawel Jakub Dawidek unsigned int i; 4831378624cSPawel Jakub Dawidek 4841378624cSPawel Jakub Dawidek if (req == NULL || req->error != NULL) 4851378624cSPawel Jakub Dawidek return (EDOOFUS); 4861378624cSPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 4871378624cSPawel Jakub Dawidek ap = &req->arg[i]; 4881378624cSPawel Jakub Dawidek if (strcmp(ap->name, name) != 0) 4891378624cSPawel Jakub Dawidek continue; 4901378624cSPawel Jakub Dawidek ap->value = __DECONST(void *, value); 4911378624cSPawel Jakub Dawidek if (len >= 0) { 4921378624cSPawel Jakub Dawidek ap->flag &= ~GCTL_PARAM_ASCII; 4931378624cSPawel Jakub Dawidek ap->len = len; 4941378624cSPawel Jakub Dawidek } else if (len < 0) { 4951378624cSPawel Jakub Dawidek ap->flag |= GCTL_PARAM_ASCII; 4961378624cSPawel Jakub Dawidek ap->len = strlen(value) + 1; 4971378624cSPawel Jakub Dawidek } 4981378624cSPawel Jakub Dawidek return (0); 4991378624cSPawel Jakub Dawidek } 5001378624cSPawel Jakub Dawidek return (ENOENT); 5011378624cSPawel Jakub Dawidek } 50259458bafSMarcel Moolenaar 50359458bafSMarcel Moolenaar int 50459458bafSMarcel Moolenaar gctl_delete_param(struct gctl_req *req, const char *name) 50559458bafSMarcel Moolenaar { 50659458bafSMarcel Moolenaar struct gctl_req_arg *ap; 50759458bafSMarcel Moolenaar unsigned int i; 50859458bafSMarcel Moolenaar 50959458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 51059458bafSMarcel Moolenaar return (EDOOFUS); 51159458bafSMarcel Moolenaar 51259458bafSMarcel Moolenaar i = 0; 51359458bafSMarcel Moolenaar while (i < req->narg) { 51459458bafSMarcel Moolenaar ap = &req->arg[i]; 51559458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 51659458bafSMarcel Moolenaar break; 51759458bafSMarcel Moolenaar i++; 51859458bafSMarcel Moolenaar } 51959458bafSMarcel Moolenaar if (i == req->narg) 52059458bafSMarcel Moolenaar return (ENOENT); 52159458bafSMarcel Moolenaar 52224609c49SAndrey V. Elsukov free(ap->name); 52359458bafSMarcel Moolenaar req->narg--; 52459458bafSMarcel Moolenaar while (i < req->narg) { 52559458bafSMarcel Moolenaar req->arg[i] = req->arg[i + 1]; 52659458bafSMarcel Moolenaar i++; 52759458bafSMarcel Moolenaar } 52859458bafSMarcel Moolenaar return (0); 52959458bafSMarcel Moolenaar } 53059458bafSMarcel Moolenaar 53159458bafSMarcel Moolenaar int 53259458bafSMarcel Moolenaar gctl_has_param(struct gctl_req *req, const char *name) 53359458bafSMarcel Moolenaar { 53459458bafSMarcel Moolenaar struct gctl_req_arg *ap; 53559458bafSMarcel Moolenaar unsigned int i; 53659458bafSMarcel Moolenaar 53759458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 53859458bafSMarcel Moolenaar return (0); 53959458bafSMarcel Moolenaar 54059458bafSMarcel Moolenaar for (i = 0; i < req->narg; i++) { 54159458bafSMarcel Moolenaar ap = &req->arg[i]; 54259458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 54359458bafSMarcel Moolenaar return (1); 54459458bafSMarcel Moolenaar } 54559458bafSMarcel Moolenaar return (0); 54659458bafSMarcel Moolenaar } 547