105c91076SPawel Jakub Dawidek /*- 2*7157a8adSPawel 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 57*7157a8adSPawel 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 */ 67*7157a8adSPawel Jakub Dawidek static unsigned int 68*7157a8adSPawel Jakub Dawidek gcd(unsigned int a, unsigned int b) 6909cc9ab6SPawel Jakub Dawidek { 70*7157a8adSPawel 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 */ 83*7157a8adSPawel Jakub Dawidek unsigned int 84*7157a8adSPawel 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 122*7157a8adSPawel 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 196*7157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 19709cc9ab6SPawel Jakub Dawidek if (fd == -1) 19809cc9ab6SPawel Jakub Dawidek return (0); 199*7157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 200*7157a8adSPawel Jakub Dawidek if (mediasize == -1) 201*7157a8adSPawel Jakub Dawidek mediasize = 0; 202*7157a8adSPawel Jakub Dawidek (void)g_close(fd); 20309cc9ab6SPawel Jakub Dawidek return (mediasize); 20409cc9ab6SPawel Jakub Dawidek } 20509cc9ab6SPawel Jakub Dawidek 206*7157a8adSPawel Jakub Dawidek unsigned int 20709cc9ab6SPawel Jakub Dawidek g_get_sectorsize(const char *name) 20809cc9ab6SPawel Jakub Dawidek { 209*7157a8adSPawel Jakub Dawidek ssize_t sectorsize; 21009cc9ab6SPawel Jakub Dawidek int fd; 21109cc9ab6SPawel Jakub Dawidek 212*7157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 21309cc9ab6SPawel Jakub Dawidek if (fd == -1) 21409cc9ab6SPawel Jakub Dawidek return (0); 215*7157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 216*7157a8adSPawel Jakub Dawidek if (sectorsize == -1) 217*7157a8adSPawel Jakub Dawidek sectorsize = 0; 218*7157a8adSPawel Jakub Dawidek (void)g_close(fd); 219*7157a8adSPawel Jakub Dawidek return ((unsigned int)sectorsize); 22009cc9ab6SPawel Jakub Dawidek } 22109cc9ab6SPawel Jakub Dawidek 22205c91076SPawel Jakub Dawidek int 223*7157a8adSPawel Jakub Dawidek g_metadata_read(const char *name, unsigned char *md, size_t size, 224*7157a8adSPawel Jakub Dawidek const char *magic) 22510fa0ebeSPawel Jakub Dawidek { 22610fa0ebeSPawel Jakub Dawidek struct std_metadata stdmd; 227*7157a8adSPawel Jakub Dawidek unsigned char *sector; 228*7157a8adSPawel 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 235*7157a8adSPawel Jakub Dawidek fd = g_open(name, 0); 23610fa0ebeSPawel Jakub Dawidek if (fd == -1) 23710fa0ebeSPawel Jakub Dawidek return (errno); 238*7157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 239*7157a8adSPawel Jakub Dawidek if (mediasize == -1) { 24010fa0ebeSPawel Jakub Dawidek error = errno; 24110fa0ebeSPawel Jakub Dawidek goto out; 24210fa0ebeSPawel Jakub Dawidek } 243*7157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 244*7157a8adSPawel Jakub Dawidek if (sectorsize == -1) { 24510fa0ebeSPawel Jakub Dawidek error = errno; 24610fa0ebeSPawel Jakub Dawidek goto out; 24710fa0ebeSPawel Jakub Dawidek } 248*7157a8adSPawel 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) != 255*7157a8adSPawel 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); 270*7157a8adSPawel Jakub Dawidek g_close(fd); 27110fa0ebeSPawel Jakub Dawidek return (error); 27210fa0ebeSPawel Jakub Dawidek } 27310fa0ebeSPawel Jakub Dawidek 27410fa0ebeSPawel Jakub Dawidek int 275*7157a8adSPawel Jakub Dawidek g_metadata_store(const char *name, const unsigned char *md, size_t size) 27605c91076SPawel Jakub Dawidek { 277*7157a8adSPawel Jakub Dawidek unsigned char *sector; 278*7157a8adSPawel 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 285*7157a8adSPawel Jakub Dawidek fd = g_open(name, 1); 28605c91076SPawel Jakub Dawidek if (fd == -1) 28705c91076SPawel Jakub Dawidek return (errno); 288*7157a8adSPawel Jakub Dawidek mediasize = g_mediasize(fd); 289*7157a8adSPawel Jakub Dawidek if (mediasize == -1) { 29005c91076SPawel Jakub Dawidek error = errno; 29105c91076SPawel Jakub Dawidek goto out; 29205c91076SPawel Jakub Dawidek } 293*7157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 294*7157a8adSPawel Jakub Dawidek if (sectorsize == -1) { 29505c91076SPawel Jakub Dawidek error = errno; 29605c91076SPawel Jakub Dawidek goto out; 29705c91076SPawel Jakub Dawidek } 298*7157a8adSPawel 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) != 306*7157a8adSPawel Jakub Dawidek sectorsize) { 30705c91076SPawel Jakub Dawidek error = errno; 30805c91076SPawel Jakub Dawidek goto out; 30905c91076SPawel Jakub Dawidek } 310*7157a8adSPawel Jakub Dawidek (void)g_flush(fd); 31105c91076SPawel Jakub Dawidek out: 31205c91076SPawel Jakub Dawidek if (sector != NULL) 31305c91076SPawel Jakub Dawidek free(sector); 314*7157a8adSPawel 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; 322*7157a8adSPawel Jakub Dawidek unsigned char *sector; 323*7157a8adSPawel 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 330*7157a8adSPawel Jakub Dawidek fd = g_open(name, 1); 33105c91076SPawel Jakub Dawidek if (fd == -1) 33205c91076SPawel Jakub Dawidek return (errno); 333*7157a8adSPawel 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 } 338*7157a8adSPawel Jakub Dawidek sectorsize = g_sectorsize(fd); 33909cc9ab6SPawel Jakub Dawidek 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) != 350*7157a8adSPawel 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) != 362*7157a8adSPawel Jakub Dawidek sectorsize) { 36305c91076SPawel Jakub Dawidek error = errno; 36405c91076SPawel Jakub Dawidek goto out; 36505c91076SPawel Jakub Dawidek } 366*7157a8adSPawel Jakub Dawidek (void)g_flush(fd); 36705c91076SPawel Jakub Dawidek out: 36805c91076SPawel Jakub Dawidek if (sector != NULL) 36905c91076SPawel Jakub Dawidek free(sector); 370*7157a8adSPawel Jakub Dawidek g_close(fd); 37105c91076SPawel Jakub Dawidek return (error); 37205c91076SPawel Jakub Dawidek } 37305c91076SPawel Jakub Dawidek 37405c91076SPawel Jakub Dawidek /* 37505c91076SPawel Jakub Dawidek * Set an error message, if one does not already exist. 37605c91076SPawel Jakub Dawidek */ 37705c91076SPawel Jakub Dawidek void 37805c91076SPawel Jakub Dawidek gctl_error(struct gctl_req *req, const char *error, ...) 37905c91076SPawel Jakub Dawidek { 38005c91076SPawel Jakub Dawidek va_list ap; 38105c91076SPawel Jakub Dawidek 38205c91076SPawel Jakub Dawidek if (req->error != NULL) 38305c91076SPawel Jakub Dawidek return; 38405c91076SPawel Jakub Dawidek va_start(ap, error); 38505c91076SPawel Jakub Dawidek vasprintf(&req->error, error, ap); 38605c91076SPawel Jakub Dawidek va_end(ap); 38705c91076SPawel Jakub Dawidek } 38805c91076SPawel Jakub Dawidek 389f13942a7SPawel Jakub Dawidek static void * 390f13942a7SPawel Jakub Dawidek gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 39105c91076SPawel Jakub Dawidek { 392f13942a7SPawel Jakub Dawidek struct gctl_req_arg *argp; 393f13942a7SPawel Jakub Dawidek char param[256]; 394*7157a8adSPawel Jakub Dawidek unsigned int i; 39505c91076SPawel Jakub Dawidek void *p; 39605c91076SPawel Jakub Dawidek 397f13942a7SPawel Jakub Dawidek vsnprintf(param, sizeof(param), pfmt, ap); 39805c91076SPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 399f13942a7SPawel Jakub Dawidek argp = &req->arg[i]; 400f13942a7SPawel Jakub Dawidek if (strcmp(param, argp->name)) 40105c91076SPawel Jakub Dawidek continue; 402f13942a7SPawel Jakub Dawidek if (!(argp->flag & GCTL_PARAM_RD)) 40305c91076SPawel Jakub Dawidek continue; 404f13942a7SPawel Jakub Dawidek p = argp->value; 405f13942a7SPawel Jakub Dawidek if (len == 0) { 406f13942a7SPawel Jakub Dawidek /* We are looking for a string. */ 407f13942a7SPawel Jakub Dawidek if (argp->len < 1) { 408f13942a7SPawel Jakub Dawidek fprintf(stderr, "No length argument (%s).\n", 409f13942a7SPawel Jakub Dawidek param); 410f13942a7SPawel Jakub Dawidek abort(); 41105c91076SPawel Jakub Dawidek } 412f13942a7SPawel Jakub Dawidek if (((char *)p)[argp->len - 1] != '\0') { 413f13942a7SPawel Jakub Dawidek fprintf(stderr, "Unterminated argument (%s).\n", 414f13942a7SPawel Jakub Dawidek param); 415f13942a7SPawel Jakub Dawidek abort(); 416f13942a7SPawel Jakub Dawidek } 417f13942a7SPawel Jakub Dawidek } else if ((int)len != argp->len) { 418f13942a7SPawel Jakub Dawidek fprintf(stderr, "Wrong length %s argument.\n", param); 419f13942a7SPawel Jakub Dawidek abort(); 42005c91076SPawel Jakub Dawidek } 42105c91076SPawel Jakub Dawidek return (p); 42205c91076SPawel Jakub Dawidek } 423f13942a7SPawel Jakub Dawidek fprintf(stderr, "No such argument (%s).\n", param); 424f13942a7SPawel Jakub Dawidek abort(); 42505c91076SPawel Jakub Dawidek } 42605c91076SPawel Jakub Dawidek 427f13942a7SPawel Jakub Dawidek int 428f13942a7SPawel Jakub Dawidek gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 42905c91076SPawel Jakub Dawidek { 430f13942a7SPawel Jakub Dawidek int *p; 431f13942a7SPawel Jakub Dawidek va_list ap; 43205c91076SPawel Jakub Dawidek 433f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 434f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(int), pfmt, ap); 435f13942a7SPawel Jakub Dawidek va_end(ap); 436f13942a7SPawel Jakub Dawidek return (*p); 43705c91076SPawel Jakub Dawidek } 438f13942a7SPawel Jakub Dawidek 439f13942a7SPawel Jakub Dawidek intmax_t 440f13942a7SPawel Jakub Dawidek gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 441f13942a7SPawel Jakub Dawidek { 442f13942a7SPawel Jakub Dawidek intmax_t *p; 443f13942a7SPawel Jakub Dawidek va_list ap; 444f13942a7SPawel Jakub Dawidek 445f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 446f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 447f13942a7SPawel Jakub Dawidek va_end(ap); 448f13942a7SPawel Jakub Dawidek return (*p); 449f13942a7SPawel Jakub Dawidek } 450f13942a7SPawel Jakub Dawidek 451f13942a7SPawel Jakub Dawidek const char * 452f13942a7SPawel Jakub Dawidek gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 453f13942a7SPawel Jakub Dawidek { 454f13942a7SPawel Jakub Dawidek const char *p; 455f13942a7SPawel Jakub Dawidek va_list ap; 456f13942a7SPawel Jakub Dawidek 457f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 458f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, 0, pfmt, ap); 459f13942a7SPawel Jakub Dawidek va_end(ap); 46005c91076SPawel Jakub Dawidek return (p); 46105c91076SPawel Jakub Dawidek } 4621378624cSPawel Jakub Dawidek 4631378624cSPawel Jakub Dawidek int 4641378624cSPawel Jakub Dawidek gctl_change_param(struct gctl_req *req, const char *name, int len, 4651378624cSPawel Jakub Dawidek const void *value) 4661378624cSPawel Jakub Dawidek { 4671378624cSPawel Jakub Dawidek struct gctl_req_arg *ap; 468*7157a8adSPawel Jakub Dawidek unsigned int i; 4691378624cSPawel Jakub Dawidek 4701378624cSPawel Jakub Dawidek if (req == NULL || req->error != NULL) 4711378624cSPawel Jakub Dawidek return (EDOOFUS); 4721378624cSPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 4731378624cSPawel Jakub Dawidek ap = &req->arg[i]; 4741378624cSPawel Jakub Dawidek if (strcmp(ap->name, name) != 0) 4751378624cSPawel Jakub Dawidek continue; 4761378624cSPawel Jakub Dawidek ap->value = __DECONST(void *, value); 4771378624cSPawel Jakub Dawidek if (len >= 0) { 4781378624cSPawel Jakub Dawidek ap->flag &= ~GCTL_PARAM_ASCII; 4791378624cSPawel Jakub Dawidek ap->len = len; 4801378624cSPawel Jakub Dawidek } else if (len < 0) { 4811378624cSPawel Jakub Dawidek ap->flag |= GCTL_PARAM_ASCII; 4821378624cSPawel Jakub Dawidek ap->len = strlen(value) + 1; 4831378624cSPawel Jakub Dawidek } 4841378624cSPawel Jakub Dawidek return (0); 4851378624cSPawel Jakub Dawidek } 4861378624cSPawel Jakub Dawidek return (ENOENT); 4871378624cSPawel Jakub Dawidek } 48859458bafSMarcel Moolenaar 48959458bafSMarcel Moolenaar int 49059458bafSMarcel Moolenaar gctl_delete_param(struct gctl_req *req, const char *name) 49159458bafSMarcel Moolenaar { 49259458bafSMarcel Moolenaar struct gctl_req_arg *ap; 49359458bafSMarcel Moolenaar unsigned int i; 49459458bafSMarcel Moolenaar 49559458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 49659458bafSMarcel Moolenaar return (EDOOFUS); 49759458bafSMarcel Moolenaar 49859458bafSMarcel Moolenaar i = 0; 49959458bafSMarcel Moolenaar while (i < req->narg) { 50059458bafSMarcel Moolenaar ap = &req->arg[i]; 50159458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 50259458bafSMarcel Moolenaar break; 50359458bafSMarcel Moolenaar i++; 50459458bafSMarcel Moolenaar } 50559458bafSMarcel Moolenaar if (i == req->narg) 50659458bafSMarcel Moolenaar return (ENOENT); 50759458bafSMarcel Moolenaar 50824609c49SAndrey V. Elsukov free(ap->name); 50959458bafSMarcel Moolenaar req->narg--; 51059458bafSMarcel Moolenaar while (i < req->narg) { 51159458bafSMarcel Moolenaar req->arg[i] = req->arg[i + 1]; 51259458bafSMarcel Moolenaar i++; 51359458bafSMarcel Moolenaar } 51459458bafSMarcel Moolenaar return (0); 51559458bafSMarcel Moolenaar } 51659458bafSMarcel Moolenaar 51759458bafSMarcel Moolenaar int 51859458bafSMarcel Moolenaar gctl_has_param(struct gctl_req *req, const char *name) 51959458bafSMarcel Moolenaar { 52059458bafSMarcel Moolenaar struct gctl_req_arg *ap; 52159458bafSMarcel Moolenaar unsigned int i; 52259458bafSMarcel Moolenaar 52359458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 52459458bafSMarcel Moolenaar return (0); 52559458bafSMarcel Moolenaar 52659458bafSMarcel Moolenaar for (i = 0; i < req->narg; i++) { 52759458bafSMarcel Moolenaar ap = &req->arg[i]; 52859458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 52959458bafSMarcel Moolenaar return (1); 53059458bafSMarcel Moolenaar } 53159458bafSMarcel Moolenaar return (0); 53259458bafSMarcel Moolenaar } 533