105c91076SPawel Jakub Dawidek /*- 27157a8adSPawel Jakub Dawidek * Copyright (c) 2004-2010 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> 3979d89bb0SAndrey V. Elsukov #include <limits.h> 4079d89bb0SAndrey V. Elsukov #include <inttypes.h> 4105c91076SPawel Jakub Dawidek #include <stdarg.h> 4205c91076SPawel Jakub Dawidek #include <string.h> 4305c91076SPawel Jakub Dawidek #include <strings.h> 4405c91076SPawel Jakub Dawidek #include <unistd.h> 4505c91076SPawel Jakub Dawidek #include <assert.h> 4605c91076SPawel Jakub Dawidek #include <libgeom.h> 4705c91076SPawel Jakub Dawidek 4805c91076SPawel Jakub Dawidek #include "misc/subr.h" 4905c91076SPawel Jakub Dawidek 5005c91076SPawel Jakub Dawidek 5105c91076SPawel Jakub Dawidek struct std_metadata { 5205c91076SPawel Jakub Dawidek char md_magic[16]; 5305c91076SPawel Jakub Dawidek uint32_t md_version; 5405c91076SPawel Jakub Dawidek }; 5505c91076SPawel Jakub Dawidek 5605c91076SPawel Jakub Dawidek static void 577157a8adSPawel Jakub Dawidek std_metadata_decode(const unsigned char *data, struct std_metadata *md) 5805c91076SPawel Jakub Dawidek { 5905c91076SPawel Jakub Dawidek 6005c91076SPawel Jakub Dawidek bcopy(data, md->md_magic, sizeof(md->md_magic)); 6105c91076SPawel Jakub Dawidek md->md_version = le32dec(data + 16); 6205c91076SPawel Jakub Dawidek } 6305c91076SPawel Jakub Dawidek 6409cc9ab6SPawel Jakub Dawidek /* 6509cc9ab6SPawel Jakub Dawidek * Greatest Common Divisor. 6609cc9ab6SPawel Jakub Dawidek */ 677157a8adSPawel Jakub Dawidek static unsigned int 687157a8adSPawel Jakub Dawidek gcd(unsigned int a, unsigned int b) 6909cc9ab6SPawel Jakub Dawidek { 707157a8adSPawel Jakub Dawidek unsigned int c; 7109cc9ab6SPawel Jakub Dawidek 7209cc9ab6SPawel Jakub Dawidek while (b != 0) { 7309cc9ab6SPawel Jakub Dawidek c = a; 7409cc9ab6SPawel Jakub Dawidek a = b; 7509cc9ab6SPawel Jakub Dawidek b = (c % b); 7609cc9ab6SPawel Jakub Dawidek } 7709cc9ab6SPawel Jakub Dawidek return (a); 7809cc9ab6SPawel Jakub Dawidek } 7909cc9ab6SPawel Jakub Dawidek 8009cc9ab6SPawel Jakub Dawidek /* 8109cc9ab6SPawel Jakub Dawidek * Least Common Multiple. 8209cc9ab6SPawel Jakub Dawidek */ 837157a8adSPawel Jakub Dawidek unsigned int 847157a8adSPawel Jakub Dawidek g_lcm(unsigned int a, unsigned int b) 8509cc9ab6SPawel Jakub Dawidek { 8609cc9ab6SPawel Jakub Dawidek 8709cc9ab6SPawel Jakub Dawidek return ((a * b) / gcd(a, b)); 8809cc9ab6SPawel Jakub Dawidek } 8909cc9ab6SPawel Jakub Dawidek 9082978104SPawel Jakub Dawidek uint32_t 9182978104SPawel Jakub Dawidek bitcount32(uint32_t x) 9282978104SPawel Jakub Dawidek { 9382978104SPawel Jakub Dawidek 9482978104SPawel Jakub Dawidek x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 9582978104SPawel Jakub Dawidek x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 9682978104SPawel Jakub Dawidek x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 9782978104SPawel Jakub Dawidek x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 9882978104SPawel Jakub Dawidek x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 9982978104SPawel Jakub Dawidek return (x); 10082978104SPawel Jakub Dawidek } 10182978104SPawel Jakub Dawidek 10279d89bb0SAndrey V. Elsukov /* 10379d89bb0SAndrey V. Elsukov * The size of a sector is context specific (i.e. determined by the 10479d89bb0SAndrey V. Elsukov * media). But when users enter a value with a SI unit, they really 10579d89bb0SAndrey V. Elsukov * mean the byte-size or byte-offset and not the size or offset in 10679d89bb0SAndrey V. Elsukov * sectors. We should map the byte-oriented value into a sector-oriented 10779d89bb0SAndrey V. Elsukov * value when we already know the sector size in bytes. At this time 10879d89bb0SAndrey V. Elsukov * we can use g_parse_lba() function. It converts user specified 10979d89bb0SAndrey V. Elsukov * value into sectors with following conditions: 11079d89bb0SAndrey V. Elsukov * o Sectors size taken as argument from caller. 11179d89bb0SAndrey V. Elsukov * o When no SI unit is specified the value is in sectors. 11279d89bb0SAndrey V. Elsukov * o With an SI unit the value is in bytes. 11379d89bb0SAndrey V. Elsukov * o The 'b' suffix forces byte interpretation and the 's' 11479d89bb0SAndrey V. Elsukov * suffix forces sector interpretation. 11579d89bb0SAndrey V. Elsukov * 11679d89bb0SAndrey V. Elsukov * Thus: 11779d89bb0SAndrey V. Elsukov * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. 11879d89bb0SAndrey V. Elsukov * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. 11979d89bb0SAndrey V. Elsukov * 12079d89bb0SAndrey V. Elsukov */ 12179d89bb0SAndrey V. Elsukov int 1227157a8adSPawel Jakub Dawidek g_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors) 12379d89bb0SAndrey V. Elsukov { 12479d89bb0SAndrey V. Elsukov off_t number, mult, unit; 12579d89bb0SAndrey V. Elsukov char *s; 12679d89bb0SAndrey V. Elsukov 12779d89bb0SAndrey V. Elsukov assert(lbastr != NULL); 12879d89bb0SAndrey V. Elsukov assert(sectorsize > 0); 12979d89bb0SAndrey V. Elsukov assert(sectors != NULL); 13079d89bb0SAndrey V. Elsukov 13179d89bb0SAndrey V. Elsukov number = (off_t)strtoimax(lbastr, &s, 0); 13202fc6609SAndrey V. Elsukov if (s == lbastr || number < 0) 13379d89bb0SAndrey V. Elsukov return (EINVAL); 13479d89bb0SAndrey V. Elsukov 13579d89bb0SAndrey V. Elsukov mult = 1; 13679d89bb0SAndrey V. Elsukov unit = sectorsize; 13779d89bb0SAndrey V. Elsukov if (*s == '\0') 13879d89bb0SAndrey V. Elsukov goto done; 13979d89bb0SAndrey V. Elsukov switch (*s) { 14079d89bb0SAndrey V. Elsukov case 'e': case 'E': 14179d89bb0SAndrey V. Elsukov mult *= 1024; 14279d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 14379d89bb0SAndrey V. Elsukov case 'p': case 'P': 14479d89bb0SAndrey V. Elsukov mult *= 1024; 14579d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 14679d89bb0SAndrey V. Elsukov case 't': case 'T': 14779d89bb0SAndrey V. Elsukov mult *= 1024; 14879d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 14979d89bb0SAndrey V. Elsukov case 'g': case 'G': 15079d89bb0SAndrey V. Elsukov mult *= 1024; 15179d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 15279d89bb0SAndrey V. Elsukov case 'm': case 'M': 15379d89bb0SAndrey V. Elsukov mult *= 1024; 15479d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 15579d89bb0SAndrey V. Elsukov case 'k': case 'K': 15679d89bb0SAndrey V. Elsukov mult *= 1024; 15779d89bb0SAndrey V. Elsukov break; 15879d89bb0SAndrey V. Elsukov default: 15979d89bb0SAndrey V. Elsukov goto sfx; 16079d89bb0SAndrey V. Elsukov } 16179d89bb0SAndrey V. Elsukov unit = 1; /* bytes */ 16279d89bb0SAndrey V. Elsukov s++; 16379d89bb0SAndrey V. Elsukov if (*s == '\0') 16479d89bb0SAndrey V. Elsukov goto done; 16579d89bb0SAndrey V. Elsukov sfx: 16679d89bb0SAndrey V. Elsukov switch (*s) { 16779d89bb0SAndrey V. Elsukov case 's': case 'S': 16879d89bb0SAndrey V. Elsukov unit = sectorsize; /* sector */ 16979d89bb0SAndrey V. Elsukov break; 17079d89bb0SAndrey V. Elsukov case 'b': case 'B': 17179d89bb0SAndrey V. Elsukov unit = 1; /* bytes */ 17279d89bb0SAndrey V. Elsukov break; 17379d89bb0SAndrey V. Elsukov default: 17479d89bb0SAndrey V. Elsukov return (EINVAL); 17579d89bb0SAndrey V. Elsukov } 17679d89bb0SAndrey V. Elsukov s++; 17779d89bb0SAndrey V. Elsukov if (*s != '\0') 17879d89bb0SAndrey V. Elsukov return (EINVAL); 17979d89bb0SAndrey V. Elsukov done: 18002fc6609SAndrey V. Elsukov if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number) 18179d89bb0SAndrey V. Elsukov return (ERANGE); 18279d89bb0SAndrey V. Elsukov number *= mult * unit; 18379d89bb0SAndrey V. Elsukov if (number % sectorsize) 18479d89bb0SAndrey V. Elsukov return (EINVAL); 18579d89bb0SAndrey V. Elsukov number /= sectorsize; 18679d89bb0SAndrey V. Elsukov *sectors = number; 18779d89bb0SAndrey V. Elsukov return (0); 18879d89bb0SAndrey V. Elsukov } 18979d89bb0SAndrey V. Elsukov 19009cc9ab6SPawel Jakub Dawidek off_t 19109cc9ab6SPawel Jakub Dawidek g_get_mediasize(const char *name) 19209cc9ab6SPawel Jakub Dawidek { 19309cc9ab6SPawel Jakub Dawidek off_t mediasize; 19409cc9ab6SPawel Jakub Dawidek int fd; 19509cc9ab6SPawel Jakub Dawidek 1967157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 19709cc9ab6SPawel Jakub Dawidek if (fd == -1) 19809cc9ab6SPawel Jakub Dawidek return (0); 1997157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 2007157a8adSPawel Jakub Dawidek if (mediasize == -1) 2017157a8adSPawel Jakub Dawidek mediasize = 0; 2027157a8adSPawel Jakub Dawidek (void)g_close(fd); 20309cc9ab6SPawel Jakub Dawidek return (mediasize); 20409cc9ab6SPawel Jakub Dawidek } 20509cc9ab6SPawel Jakub Dawidek 2067157a8adSPawel Jakub Dawidek unsigned int 20709cc9ab6SPawel Jakub Dawidek g_get_sectorsize(const char *name) 20809cc9ab6SPawel Jakub Dawidek { 2097157a8adSPawel Jakub Dawidek ssize_t sectorsize; 21009cc9ab6SPawel Jakub Dawidek int fd; 21109cc9ab6SPawel Jakub Dawidek 2127157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 21309cc9ab6SPawel Jakub Dawidek if (fd == -1) 21409cc9ab6SPawel Jakub Dawidek return (0); 2157157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 2167157a8adSPawel Jakub Dawidek if (sectorsize == -1) 2177157a8adSPawel Jakub Dawidek sectorsize = 0; 2187157a8adSPawel Jakub Dawidek (void)g_close(fd); 2197157a8adSPawel Jakub Dawidek return ((unsigned int)sectorsize); 22009cc9ab6SPawel Jakub Dawidek } 22109cc9ab6SPawel Jakub Dawidek 22205c91076SPawel Jakub Dawidek int 2237157a8adSPawel Jakub Dawidek g_metadata_read(const char *name, unsigned char *md, size_t size, 2247157a8adSPawel Jakub Dawidek const char *magic) 22510fa0ebeSPawel Jakub Dawidek { 22610fa0ebeSPawel Jakub Dawidek struct std_metadata stdmd; 2277157a8adSPawel Jakub Dawidek unsigned char *sector; 2287157a8adSPawel Jakub Dawidek ssize_t sectorsize; 22910fa0ebeSPawel Jakub Dawidek off_t mediasize; 23010fa0ebeSPawel Jakub Dawidek int error, fd; 23110fa0ebeSPawel Jakub Dawidek 23210fa0ebeSPawel Jakub Dawidek sector = NULL; 23310fa0ebeSPawel Jakub Dawidek error = 0; 23410fa0ebeSPawel Jakub Dawidek 2357157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 23610fa0ebeSPawel Jakub Dawidek if (fd == -1) 23710fa0ebeSPawel Jakub Dawidek return (errno); 2387157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 2397157a8adSPawel Jakub Dawidek if (mediasize == -1) { 24010fa0ebeSPawel Jakub Dawidek error = errno; 24110fa0ebeSPawel Jakub Dawidek goto out; 24210fa0ebeSPawel Jakub Dawidek } 2437157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 2447157a8adSPawel Jakub Dawidek if (sectorsize == -1) { 24510fa0ebeSPawel Jakub Dawidek error = errno; 24610fa0ebeSPawel Jakub Dawidek goto out; 24710fa0ebeSPawel Jakub Dawidek } 2487157a8adSPawel Jakub Dawidek assert(sectorsize >= (ssize_t)size); 24910fa0ebeSPawel Jakub Dawidek sector = malloc(sectorsize); 25010fa0ebeSPawel Jakub Dawidek if (sector == NULL) { 25110fa0ebeSPawel Jakub Dawidek error = ENOMEM; 25210fa0ebeSPawel Jakub Dawidek goto out; 25310fa0ebeSPawel Jakub Dawidek } 25410fa0ebeSPawel Jakub Dawidek if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 2557157a8adSPawel Jakub Dawidek sectorsize) { 25610fa0ebeSPawel Jakub Dawidek error = errno; 25710fa0ebeSPawel Jakub Dawidek goto out; 25810fa0ebeSPawel Jakub Dawidek } 25910fa0ebeSPawel Jakub Dawidek if (magic != NULL) { 26010fa0ebeSPawel Jakub Dawidek std_metadata_decode(sector, &stdmd); 26110fa0ebeSPawel Jakub Dawidek if (strcmp(stdmd.md_magic, magic) != 0) { 26210fa0ebeSPawel Jakub Dawidek error = EINVAL; 26310fa0ebeSPawel Jakub Dawidek goto out; 26410fa0ebeSPawel Jakub Dawidek } 26510fa0ebeSPawel Jakub Dawidek } 26610fa0ebeSPawel Jakub Dawidek bcopy(sector, md, size); 26710fa0ebeSPawel Jakub Dawidek out: 26810fa0ebeSPawel Jakub Dawidek if (sector != NULL) 26910fa0ebeSPawel Jakub Dawidek free(sector); 2707157a8adSPawel Jakub Dawidek g_close(fd); 27110fa0ebeSPawel Jakub Dawidek return (error); 27210fa0ebeSPawel Jakub Dawidek } 27310fa0ebeSPawel Jakub Dawidek 27410fa0ebeSPawel Jakub Dawidek int 2757157a8adSPawel Jakub Dawidek g_metadata_store(const char *name, const unsigned char *md, size_t size) 27605c91076SPawel Jakub Dawidek { 2777157a8adSPawel Jakub Dawidek unsigned char *sector; 2787157a8adSPawel Jakub Dawidek ssize_t sectorsize; 27905c91076SPawel Jakub Dawidek off_t mediasize; 28005c91076SPawel Jakub Dawidek int error, fd; 28105c91076SPawel Jakub Dawidek 28205c91076SPawel Jakub Dawidek sector = NULL; 28305c91076SPawel Jakub Dawidek error = 0; 28405c91076SPawel Jakub Dawidek 2857157a8adSPawel Jakub Dawidek fd = g_open(name, 1); 28605c91076SPawel Jakub Dawidek if (fd == -1) 28705c91076SPawel Jakub Dawidek return (errno); 2887157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 2897157a8adSPawel Jakub Dawidek if (mediasize == -1) { 29005c91076SPawel Jakub Dawidek error = errno; 29105c91076SPawel Jakub Dawidek goto out; 29205c91076SPawel Jakub Dawidek } 2937157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 2947157a8adSPawel Jakub Dawidek if (sectorsize == -1) { 29505c91076SPawel Jakub Dawidek error = errno; 29605c91076SPawel Jakub Dawidek goto out; 29705c91076SPawel Jakub Dawidek } 2987157a8adSPawel Jakub Dawidek assert(sectorsize >= (ssize_t)size); 29905c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 30005c91076SPawel Jakub Dawidek if (sector == NULL) { 30105c91076SPawel Jakub Dawidek error = ENOMEM; 30205c91076SPawel Jakub Dawidek goto out; 30305c91076SPawel Jakub Dawidek } 30405c91076SPawel Jakub Dawidek bcopy(md, sector, size); 30505c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 3067157a8adSPawel Jakub Dawidek sectorsize) { 30705c91076SPawel Jakub Dawidek error = errno; 30805c91076SPawel Jakub Dawidek goto out; 30905c91076SPawel Jakub Dawidek } 3107157a8adSPawel Jakub Dawidek (void)g_flush(fd); 31105c91076SPawel Jakub Dawidek out: 31205c91076SPawel Jakub Dawidek if (sector != NULL) 31305c91076SPawel Jakub Dawidek free(sector); 3147157a8adSPawel Jakub Dawidek (void)g_close(fd); 31505c91076SPawel Jakub Dawidek return (error); 31605c91076SPawel Jakub Dawidek } 31705c91076SPawel Jakub Dawidek 31805c91076SPawel Jakub Dawidek int 31905c91076SPawel Jakub Dawidek g_metadata_clear(const char *name, const char *magic) 32005c91076SPawel Jakub Dawidek { 32105c91076SPawel Jakub Dawidek struct std_metadata md; 3227157a8adSPawel Jakub Dawidek unsigned char *sector; 3237157a8adSPawel Jakub Dawidek ssize_t sectorsize; 32405c91076SPawel Jakub Dawidek off_t mediasize; 32505c91076SPawel Jakub Dawidek int error, fd; 32605c91076SPawel Jakub Dawidek 32705c91076SPawel Jakub Dawidek sector = NULL; 32805c91076SPawel Jakub Dawidek error = 0; 32905c91076SPawel Jakub Dawidek 3307157a8adSPawel Jakub Dawidek fd = g_open(name, 1); 33105c91076SPawel Jakub Dawidek if (fd == -1) 33205c91076SPawel Jakub Dawidek return (errno); 3337157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 33409cc9ab6SPawel Jakub Dawidek if (mediasize == 0) { 33505c91076SPawel Jakub Dawidek error = errno; 33605c91076SPawel Jakub Dawidek goto out; 33705c91076SPawel Jakub Dawidek } 3387157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 339*fc9437c8SAlan Somers if (sectorsize <= 0) { 34005c91076SPawel Jakub Dawidek error = errno; 34105c91076SPawel Jakub Dawidek goto out; 34205c91076SPawel Jakub Dawidek } 34305c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 34405c91076SPawel Jakub Dawidek if (sector == NULL) { 34505c91076SPawel Jakub Dawidek error = ENOMEM; 34605c91076SPawel Jakub Dawidek goto out; 34705c91076SPawel Jakub Dawidek } 34805c91076SPawel Jakub Dawidek if (magic != NULL) { 34905c91076SPawel Jakub Dawidek if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 3507157a8adSPawel Jakub Dawidek sectorsize) { 35105c91076SPawel Jakub Dawidek error = errno; 35205c91076SPawel Jakub Dawidek goto out; 35305c91076SPawel Jakub Dawidek } 35405c91076SPawel Jakub Dawidek std_metadata_decode(sector, &md); 35505c91076SPawel Jakub Dawidek if (strcmp(md.md_magic, magic) != 0) { 35605c91076SPawel Jakub Dawidek error = EINVAL; 35705c91076SPawel Jakub Dawidek goto out; 35805c91076SPawel Jakub Dawidek } 35905c91076SPawel Jakub Dawidek } 36005c91076SPawel Jakub Dawidek bzero(sector, sectorsize); 36105c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 3627157a8adSPawel Jakub Dawidek sectorsize) { 36305c91076SPawel Jakub Dawidek error = errno; 36405c91076SPawel Jakub Dawidek goto out; 36505c91076SPawel Jakub Dawidek } 3667157a8adSPawel Jakub Dawidek (void)g_flush(fd); 36705c91076SPawel Jakub Dawidek out: 36805c91076SPawel Jakub Dawidek free(sector); 3697157a8adSPawel Jakub Dawidek g_close(fd); 37005c91076SPawel Jakub Dawidek return (error); 37105c91076SPawel Jakub Dawidek } 37205c91076SPawel Jakub Dawidek 37305c91076SPawel Jakub Dawidek /* 37405c91076SPawel Jakub Dawidek * Set an error message, if one does not already exist. 37505c91076SPawel Jakub Dawidek */ 37605c91076SPawel Jakub Dawidek void 37705c91076SPawel Jakub Dawidek gctl_error(struct gctl_req *req, const char *error, ...) 37805c91076SPawel Jakub Dawidek { 37905c91076SPawel Jakub Dawidek va_list ap; 38005c91076SPawel Jakub Dawidek 381275ae453SPawel Jakub Dawidek if (req != NULL && req->error != NULL) 38205c91076SPawel Jakub Dawidek return; 38305c91076SPawel Jakub Dawidek va_start(ap, error); 384275ae453SPawel Jakub Dawidek if (req != NULL) { 38505c91076SPawel Jakub Dawidek vasprintf(&req->error, error, ap); 386275ae453SPawel Jakub Dawidek } else { 387275ae453SPawel Jakub Dawidek vfprintf(stderr, error, ap); 388275ae453SPawel Jakub Dawidek fprintf(stderr, "\n"); 389275ae453SPawel Jakub Dawidek } 39005c91076SPawel Jakub Dawidek va_end(ap); 39105c91076SPawel Jakub Dawidek } 39205c91076SPawel Jakub Dawidek 393f13942a7SPawel Jakub Dawidek static void * 394f13942a7SPawel Jakub Dawidek gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 39505c91076SPawel Jakub Dawidek { 396f13942a7SPawel Jakub Dawidek struct gctl_req_arg *argp; 397f13942a7SPawel Jakub Dawidek char param[256]; 3987157a8adSPawel Jakub Dawidek unsigned int i; 39905c91076SPawel Jakub Dawidek void *p; 40005c91076SPawel Jakub Dawidek 401f13942a7SPawel Jakub Dawidek vsnprintf(param, sizeof(param), pfmt, ap); 40205c91076SPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 403f13942a7SPawel Jakub Dawidek argp = &req->arg[i]; 404f13942a7SPawel Jakub Dawidek if (strcmp(param, argp->name)) 40505c91076SPawel Jakub Dawidek continue; 406f13942a7SPawel Jakub Dawidek if (!(argp->flag & GCTL_PARAM_RD)) 40705c91076SPawel Jakub Dawidek continue; 408f13942a7SPawel Jakub Dawidek p = argp->value; 409f13942a7SPawel Jakub Dawidek if (len == 0) { 410f13942a7SPawel Jakub Dawidek /* We are looking for a string. */ 411f13942a7SPawel Jakub Dawidek if (argp->len < 1) { 412f13942a7SPawel Jakub Dawidek fprintf(stderr, "No length argument (%s).\n", 413f13942a7SPawel Jakub Dawidek param); 414f13942a7SPawel Jakub Dawidek abort(); 41505c91076SPawel Jakub Dawidek } 416f13942a7SPawel Jakub Dawidek if (((char *)p)[argp->len - 1] != '\0') { 417f13942a7SPawel Jakub Dawidek fprintf(stderr, "Unterminated argument (%s).\n", 418f13942a7SPawel Jakub Dawidek param); 419f13942a7SPawel Jakub Dawidek abort(); 420f13942a7SPawel Jakub Dawidek } 421f13942a7SPawel Jakub Dawidek } else if ((int)len != argp->len) { 422f13942a7SPawel Jakub Dawidek fprintf(stderr, "Wrong length %s argument.\n", param); 423f13942a7SPawel Jakub Dawidek abort(); 42405c91076SPawel Jakub Dawidek } 42505c91076SPawel Jakub Dawidek return (p); 42605c91076SPawel Jakub Dawidek } 427f13942a7SPawel Jakub Dawidek fprintf(stderr, "No such argument (%s).\n", param); 428f13942a7SPawel Jakub Dawidek abort(); 42905c91076SPawel Jakub Dawidek } 43005c91076SPawel Jakub Dawidek 431f13942a7SPawel Jakub Dawidek int 432f13942a7SPawel Jakub Dawidek gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 43305c91076SPawel Jakub Dawidek { 434f13942a7SPawel Jakub Dawidek int *p; 435f13942a7SPawel Jakub Dawidek va_list ap; 43605c91076SPawel Jakub Dawidek 437f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 438f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(int), pfmt, ap); 439f13942a7SPawel Jakub Dawidek va_end(ap); 440f13942a7SPawel Jakub Dawidek return (*p); 44105c91076SPawel Jakub Dawidek } 442f13942a7SPawel Jakub Dawidek 443f13942a7SPawel Jakub Dawidek intmax_t 444f13942a7SPawel Jakub Dawidek gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 445f13942a7SPawel Jakub Dawidek { 446f13942a7SPawel Jakub Dawidek intmax_t *p; 447f13942a7SPawel Jakub Dawidek va_list ap; 448f13942a7SPawel Jakub Dawidek 449f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 450f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 451f13942a7SPawel Jakub Dawidek va_end(ap); 452f13942a7SPawel Jakub Dawidek return (*p); 453f13942a7SPawel Jakub Dawidek } 454f13942a7SPawel Jakub Dawidek 455f13942a7SPawel Jakub Dawidek const char * 456f13942a7SPawel Jakub Dawidek gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 457f13942a7SPawel Jakub Dawidek { 458f13942a7SPawel Jakub Dawidek const char *p; 459f13942a7SPawel Jakub Dawidek va_list ap; 460f13942a7SPawel Jakub Dawidek 461f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 462f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, 0, pfmt, ap); 463f13942a7SPawel Jakub Dawidek va_end(ap); 46405c91076SPawel Jakub Dawidek return (p); 46505c91076SPawel Jakub Dawidek } 4661378624cSPawel Jakub Dawidek 4671378624cSPawel Jakub Dawidek int 4681378624cSPawel Jakub Dawidek gctl_change_param(struct gctl_req *req, const char *name, int len, 4691378624cSPawel Jakub Dawidek const void *value) 4701378624cSPawel Jakub Dawidek { 4711378624cSPawel Jakub Dawidek struct gctl_req_arg *ap; 4727157a8adSPawel Jakub Dawidek unsigned int i; 4731378624cSPawel Jakub Dawidek 4741378624cSPawel Jakub Dawidek if (req == NULL || req->error != NULL) 4751378624cSPawel Jakub Dawidek return (EDOOFUS); 4761378624cSPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 4771378624cSPawel Jakub Dawidek ap = &req->arg[i]; 4781378624cSPawel Jakub Dawidek if (strcmp(ap->name, name) != 0) 4791378624cSPawel Jakub Dawidek continue; 4801378624cSPawel Jakub Dawidek ap->value = __DECONST(void *, value); 4811378624cSPawel Jakub Dawidek if (len >= 0) { 4821378624cSPawel Jakub Dawidek ap->flag &= ~GCTL_PARAM_ASCII; 4831378624cSPawel Jakub Dawidek ap->len = len; 4841378624cSPawel Jakub Dawidek } else if (len < 0) { 4851378624cSPawel Jakub Dawidek ap->flag |= GCTL_PARAM_ASCII; 4861378624cSPawel Jakub Dawidek ap->len = strlen(value) + 1; 4871378624cSPawel Jakub Dawidek } 4881378624cSPawel Jakub Dawidek return (0); 4891378624cSPawel Jakub Dawidek } 4901378624cSPawel Jakub Dawidek return (ENOENT); 4911378624cSPawel Jakub Dawidek } 49259458bafSMarcel Moolenaar 49359458bafSMarcel Moolenaar int 49459458bafSMarcel Moolenaar gctl_delete_param(struct gctl_req *req, const char *name) 49559458bafSMarcel Moolenaar { 49659458bafSMarcel Moolenaar struct gctl_req_arg *ap; 49759458bafSMarcel Moolenaar unsigned int i; 49859458bafSMarcel Moolenaar 49959458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 50059458bafSMarcel Moolenaar return (EDOOFUS); 50159458bafSMarcel Moolenaar 50259458bafSMarcel Moolenaar i = 0; 50359458bafSMarcel Moolenaar while (i < req->narg) { 50459458bafSMarcel Moolenaar ap = &req->arg[i]; 50559458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 50659458bafSMarcel Moolenaar break; 50759458bafSMarcel Moolenaar i++; 50859458bafSMarcel Moolenaar } 50959458bafSMarcel Moolenaar if (i == req->narg) 51059458bafSMarcel Moolenaar return (ENOENT); 51159458bafSMarcel Moolenaar 51224609c49SAndrey V. Elsukov free(ap->name); 51359458bafSMarcel Moolenaar req->narg--; 51459458bafSMarcel Moolenaar while (i < req->narg) { 51559458bafSMarcel Moolenaar req->arg[i] = req->arg[i + 1]; 51659458bafSMarcel Moolenaar i++; 51759458bafSMarcel Moolenaar } 51859458bafSMarcel Moolenaar return (0); 51959458bafSMarcel Moolenaar } 52059458bafSMarcel Moolenaar 52159458bafSMarcel Moolenaar int 52259458bafSMarcel Moolenaar gctl_has_param(struct gctl_req *req, const char *name) 52359458bafSMarcel Moolenaar { 52459458bafSMarcel Moolenaar struct gctl_req_arg *ap; 52559458bafSMarcel Moolenaar unsigned int i; 52659458bafSMarcel Moolenaar 52759458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 52859458bafSMarcel Moolenaar return (0); 52959458bafSMarcel Moolenaar 53059458bafSMarcel Moolenaar for (i = 0; i < req->narg; i++) { 53159458bafSMarcel Moolenaar ap = &req->arg[i]; 53259458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 53359458bafSMarcel Moolenaar return (1); 53459458bafSMarcel Moolenaar } 53559458bafSMarcel Moolenaar return (0); 53659458bafSMarcel Moolenaar } 537