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> 39*79d89bb0SAndrey V. Elsukov #include <limits.h> 40*79d89bb0SAndrey 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 5705c91076SPawel Jakub Dawidek std_metadata_decode(const u_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 6405c91076SPawel Jakub Dawidek static void 6505c91076SPawel Jakub Dawidek pathgen(const char *name, char *path, size_t size) 6605c91076SPawel Jakub Dawidek { 6705c91076SPawel Jakub Dawidek 6805c91076SPawel Jakub Dawidek if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 6905c91076SPawel Jakub Dawidek snprintf(path, size, "%s%s", _PATH_DEV, name); 7005c91076SPawel Jakub Dawidek else 7105c91076SPawel Jakub Dawidek strlcpy(path, name, size); 7205c91076SPawel Jakub Dawidek } 7305c91076SPawel Jakub Dawidek 7409cc9ab6SPawel Jakub Dawidek /* 7509cc9ab6SPawel Jakub Dawidek * Greatest Common Divisor. 7609cc9ab6SPawel Jakub Dawidek */ 7709cc9ab6SPawel Jakub Dawidek static unsigned 7809cc9ab6SPawel Jakub Dawidek gcd(unsigned a, unsigned b) 7909cc9ab6SPawel Jakub Dawidek { 8009cc9ab6SPawel Jakub Dawidek u_int c; 8109cc9ab6SPawel Jakub Dawidek 8209cc9ab6SPawel Jakub Dawidek while (b != 0) { 8309cc9ab6SPawel Jakub Dawidek c = a; 8409cc9ab6SPawel Jakub Dawidek a = b; 8509cc9ab6SPawel Jakub Dawidek b = (c % b); 8609cc9ab6SPawel Jakub Dawidek } 8709cc9ab6SPawel Jakub Dawidek return (a); 8809cc9ab6SPawel Jakub Dawidek } 8909cc9ab6SPawel Jakub Dawidek 9009cc9ab6SPawel Jakub Dawidek /* 9109cc9ab6SPawel Jakub Dawidek * Least Common Multiple. 9209cc9ab6SPawel Jakub Dawidek */ 9309cc9ab6SPawel Jakub Dawidek unsigned 9409cc9ab6SPawel Jakub Dawidek g_lcm(unsigned a, unsigned b) 9509cc9ab6SPawel Jakub Dawidek { 9609cc9ab6SPawel Jakub Dawidek 9709cc9ab6SPawel Jakub Dawidek return ((a * b) / gcd(a, b)); 9809cc9ab6SPawel Jakub Dawidek } 9909cc9ab6SPawel Jakub Dawidek 10082978104SPawel Jakub Dawidek uint32_t 10182978104SPawel Jakub Dawidek bitcount32(uint32_t x) 10282978104SPawel Jakub Dawidek { 10382978104SPawel Jakub Dawidek 10482978104SPawel Jakub Dawidek x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 10582978104SPawel Jakub Dawidek x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 10682978104SPawel Jakub Dawidek x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 10782978104SPawel Jakub Dawidek x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 10882978104SPawel Jakub Dawidek x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 10982978104SPawel Jakub Dawidek return (x); 11082978104SPawel Jakub Dawidek } 11182978104SPawel Jakub Dawidek 112*79d89bb0SAndrey V. Elsukov /* 113*79d89bb0SAndrey V. Elsukov * The size of a sector is context specific (i.e. determined by the 114*79d89bb0SAndrey V. Elsukov * media). But when users enter a value with a SI unit, they really 115*79d89bb0SAndrey V. Elsukov * mean the byte-size or byte-offset and not the size or offset in 116*79d89bb0SAndrey V. Elsukov * sectors. We should map the byte-oriented value into a sector-oriented 117*79d89bb0SAndrey V. Elsukov * value when we already know the sector size in bytes. At this time 118*79d89bb0SAndrey V. Elsukov * we can use g_parse_lba() function. It converts user specified 119*79d89bb0SAndrey V. Elsukov * value into sectors with following conditions: 120*79d89bb0SAndrey V. Elsukov * o Sectors size taken as argument from caller. 121*79d89bb0SAndrey V. Elsukov * o When no SI unit is specified the value is in sectors. 122*79d89bb0SAndrey V. Elsukov * o With an SI unit the value is in bytes. 123*79d89bb0SAndrey V. Elsukov * o The 'b' suffix forces byte interpretation and the 's' 124*79d89bb0SAndrey V. Elsukov * suffix forces sector interpretation. 125*79d89bb0SAndrey V. Elsukov * 126*79d89bb0SAndrey V. Elsukov * Thus: 127*79d89bb0SAndrey V. Elsukov * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. 128*79d89bb0SAndrey V. Elsukov * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. 129*79d89bb0SAndrey V. Elsukov * 130*79d89bb0SAndrey V. Elsukov */ 131*79d89bb0SAndrey V. Elsukov int 132*79d89bb0SAndrey V. Elsukov g_parse_lba(const char *lbastr, unsigned sectorsize, off_t *sectors) 133*79d89bb0SAndrey V. Elsukov { 134*79d89bb0SAndrey V. Elsukov off_t number, mult, unit; 135*79d89bb0SAndrey V. Elsukov char *s; 136*79d89bb0SAndrey V. Elsukov 137*79d89bb0SAndrey V. Elsukov assert(lbastr != NULL); 138*79d89bb0SAndrey V. Elsukov assert(sectorsize > 0); 139*79d89bb0SAndrey V. Elsukov assert(sectors != NULL); 140*79d89bb0SAndrey V. Elsukov 141*79d89bb0SAndrey V. Elsukov number = (off_t)strtoimax(lbastr, &s, 0); 142*79d89bb0SAndrey V. Elsukov if (s == lbastr) 143*79d89bb0SAndrey V. Elsukov return (EINVAL); 144*79d89bb0SAndrey V. Elsukov 145*79d89bb0SAndrey V. Elsukov mult = 1; 146*79d89bb0SAndrey V. Elsukov unit = sectorsize; 147*79d89bb0SAndrey V. Elsukov if (*s == '\0') 148*79d89bb0SAndrey V. Elsukov goto done; 149*79d89bb0SAndrey V. Elsukov switch (*s) { 150*79d89bb0SAndrey V. Elsukov case 'e': case 'E': 151*79d89bb0SAndrey V. Elsukov mult *= 1024; 152*79d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 153*79d89bb0SAndrey V. Elsukov case 'p': case 'P': 154*79d89bb0SAndrey V. Elsukov mult *= 1024; 155*79d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 156*79d89bb0SAndrey V. Elsukov case 't': case 'T': 157*79d89bb0SAndrey V. Elsukov mult *= 1024; 158*79d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 159*79d89bb0SAndrey V. Elsukov case 'g': case 'G': 160*79d89bb0SAndrey V. Elsukov mult *= 1024; 161*79d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 162*79d89bb0SAndrey V. Elsukov case 'm': case 'M': 163*79d89bb0SAndrey V. Elsukov mult *= 1024; 164*79d89bb0SAndrey V. Elsukov /* FALLTHROUGH */ 165*79d89bb0SAndrey V. Elsukov case 'k': case 'K': 166*79d89bb0SAndrey V. Elsukov mult *= 1024; 167*79d89bb0SAndrey V. Elsukov break; 168*79d89bb0SAndrey V. Elsukov default: 169*79d89bb0SAndrey V. Elsukov goto sfx; 170*79d89bb0SAndrey V. Elsukov } 171*79d89bb0SAndrey V. Elsukov unit = 1; /* bytes */ 172*79d89bb0SAndrey V. Elsukov s++; 173*79d89bb0SAndrey V. Elsukov if (*s == '\0') 174*79d89bb0SAndrey V. Elsukov goto done; 175*79d89bb0SAndrey V. Elsukov sfx: 176*79d89bb0SAndrey V. Elsukov switch (*s) { 177*79d89bb0SAndrey V. Elsukov case 's': case 'S': 178*79d89bb0SAndrey V. Elsukov unit = sectorsize; /* sector */ 179*79d89bb0SAndrey V. Elsukov break; 180*79d89bb0SAndrey V. Elsukov case 'b': case 'B': 181*79d89bb0SAndrey V. Elsukov unit = 1; /* bytes */ 182*79d89bb0SAndrey V. Elsukov break; 183*79d89bb0SAndrey V. Elsukov default: 184*79d89bb0SAndrey V. Elsukov return (EINVAL); 185*79d89bb0SAndrey V. Elsukov } 186*79d89bb0SAndrey V. Elsukov s++; 187*79d89bb0SAndrey V. Elsukov if (*s != '\0') 188*79d89bb0SAndrey V. Elsukov return (EINVAL); 189*79d89bb0SAndrey V. Elsukov done: 190*79d89bb0SAndrey V. Elsukov if (mult * unit < mult || number * mult * unit < number) 191*79d89bb0SAndrey V. Elsukov return (ERANGE); 192*79d89bb0SAndrey V. Elsukov number *= mult * unit; 193*79d89bb0SAndrey V. Elsukov if (number % sectorsize) 194*79d89bb0SAndrey V. Elsukov return (EINVAL); 195*79d89bb0SAndrey V. Elsukov number /= sectorsize; 196*79d89bb0SAndrey V. Elsukov *sectors = number; 197*79d89bb0SAndrey V. Elsukov return (0); 198*79d89bb0SAndrey V. Elsukov } 199*79d89bb0SAndrey V. Elsukov 20009cc9ab6SPawel Jakub Dawidek off_t 20109cc9ab6SPawel Jakub Dawidek g_get_mediasize(const char *name) 20209cc9ab6SPawel Jakub Dawidek { 20309cc9ab6SPawel Jakub Dawidek char path[MAXPATHLEN]; 20409cc9ab6SPawel Jakub Dawidek off_t mediasize; 20509cc9ab6SPawel Jakub Dawidek int fd; 20609cc9ab6SPawel Jakub Dawidek 20709cc9ab6SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 20809cc9ab6SPawel Jakub Dawidek fd = open(path, O_RDONLY); 20909cc9ab6SPawel Jakub Dawidek if (fd == -1) 21009cc9ab6SPawel Jakub Dawidek return (0); 21109cc9ab6SPawel Jakub Dawidek if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 21209cc9ab6SPawel Jakub Dawidek close(fd); 21309cc9ab6SPawel Jakub Dawidek return (0); 21409cc9ab6SPawel Jakub Dawidek } 21509cc9ab6SPawel Jakub Dawidek close(fd); 21609cc9ab6SPawel Jakub Dawidek return (mediasize); 21709cc9ab6SPawel Jakub Dawidek } 21809cc9ab6SPawel Jakub Dawidek 21909cc9ab6SPawel Jakub Dawidek unsigned 22009cc9ab6SPawel Jakub Dawidek g_get_sectorsize(const char *name) 22109cc9ab6SPawel Jakub Dawidek { 22209cc9ab6SPawel Jakub Dawidek char path[MAXPATHLEN]; 22309cc9ab6SPawel Jakub Dawidek unsigned sectorsize; 22409cc9ab6SPawel Jakub Dawidek int fd; 22509cc9ab6SPawel Jakub Dawidek 22609cc9ab6SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 22709cc9ab6SPawel Jakub Dawidek fd = open(path, O_RDONLY); 22809cc9ab6SPawel Jakub Dawidek if (fd == -1) 22909cc9ab6SPawel Jakub Dawidek return (0); 23009cc9ab6SPawel Jakub Dawidek if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 23109cc9ab6SPawel Jakub Dawidek close(fd); 23209cc9ab6SPawel Jakub Dawidek return (0); 23309cc9ab6SPawel Jakub Dawidek } 23409cc9ab6SPawel Jakub Dawidek close(fd); 23509cc9ab6SPawel Jakub Dawidek return (sectorsize); 23609cc9ab6SPawel Jakub Dawidek } 23709cc9ab6SPawel Jakub Dawidek 23805c91076SPawel Jakub Dawidek int 23910fa0ebeSPawel Jakub Dawidek g_metadata_read(const char *name, u_char *md, size_t size, const char *magic) 24010fa0ebeSPawel Jakub Dawidek { 24110fa0ebeSPawel Jakub Dawidek struct std_metadata stdmd; 24210fa0ebeSPawel Jakub Dawidek char path[MAXPATHLEN]; 24310fa0ebeSPawel Jakub Dawidek unsigned sectorsize; 24410fa0ebeSPawel Jakub Dawidek off_t mediasize; 24510fa0ebeSPawel Jakub Dawidek u_char *sector; 24610fa0ebeSPawel Jakub Dawidek int error, fd; 24710fa0ebeSPawel Jakub Dawidek 24810fa0ebeSPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 24910fa0ebeSPawel Jakub Dawidek sector = NULL; 25010fa0ebeSPawel Jakub Dawidek error = 0; 25110fa0ebeSPawel Jakub Dawidek 25210fa0ebeSPawel Jakub Dawidek fd = open(path, O_RDONLY); 25310fa0ebeSPawel Jakub Dawidek if (fd == -1) 25410fa0ebeSPawel Jakub Dawidek return (errno); 25510fa0ebeSPawel Jakub Dawidek mediasize = g_get_mediasize(name); 25610fa0ebeSPawel Jakub Dawidek if (mediasize == 0) { 25710fa0ebeSPawel Jakub Dawidek error = errno; 25810fa0ebeSPawel Jakub Dawidek goto out; 25910fa0ebeSPawel Jakub Dawidek } 26010fa0ebeSPawel Jakub Dawidek sectorsize = g_get_sectorsize(name); 26110fa0ebeSPawel Jakub Dawidek if (sectorsize == 0) { 26210fa0ebeSPawel Jakub Dawidek error = errno; 26310fa0ebeSPawel Jakub Dawidek goto out; 26410fa0ebeSPawel Jakub Dawidek } 26510fa0ebeSPawel Jakub Dawidek assert(sectorsize >= size); 26610fa0ebeSPawel Jakub Dawidek sector = malloc(sectorsize); 26710fa0ebeSPawel Jakub Dawidek if (sector == NULL) { 26810fa0ebeSPawel Jakub Dawidek error = ENOMEM; 26910fa0ebeSPawel Jakub Dawidek goto out; 27010fa0ebeSPawel Jakub Dawidek } 27110fa0ebeSPawel Jakub Dawidek if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 27210fa0ebeSPawel Jakub Dawidek (ssize_t)sectorsize) { 27310fa0ebeSPawel Jakub Dawidek error = errno; 27410fa0ebeSPawel Jakub Dawidek goto out; 27510fa0ebeSPawel Jakub Dawidek } 27610fa0ebeSPawel Jakub Dawidek if (magic != NULL) { 27710fa0ebeSPawel Jakub Dawidek std_metadata_decode(sector, &stdmd); 27810fa0ebeSPawel Jakub Dawidek if (strcmp(stdmd.md_magic, magic) != 0) { 27910fa0ebeSPawel Jakub Dawidek error = EINVAL; 28010fa0ebeSPawel Jakub Dawidek goto out; 28110fa0ebeSPawel Jakub Dawidek } 28210fa0ebeSPawel Jakub Dawidek } 28310fa0ebeSPawel Jakub Dawidek bcopy(sector, md, size); 28410fa0ebeSPawel Jakub Dawidek out: 28510fa0ebeSPawel Jakub Dawidek if (sector != NULL) 28610fa0ebeSPawel Jakub Dawidek free(sector); 28710fa0ebeSPawel Jakub Dawidek close(fd); 28810fa0ebeSPawel Jakub Dawidek return (error); 28910fa0ebeSPawel Jakub Dawidek } 29010fa0ebeSPawel Jakub Dawidek 29110fa0ebeSPawel Jakub Dawidek int 29205c91076SPawel Jakub Dawidek g_metadata_store(const char *name, u_char *md, size_t size) 29305c91076SPawel Jakub Dawidek { 29405c91076SPawel Jakub Dawidek char path[MAXPATHLEN]; 29505c91076SPawel Jakub Dawidek unsigned sectorsize; 29605c91076SPawel Jakub Dawidek off_t mediasize; 29705c91076SPawel Jakub Dawidek u_char *sector; 29805c91076SPawel Jakub Dawidek int error, fd; 29905c91076SPawel Jakub Dawidek 30005c91076SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 30105c91076SPawel Jakub Dawidek sector = NULL; 30205c91076SPawel Jakub Dawidek error = 0; 30305c91076SPawel Jakub Dawidek 304db2bf4b0SUlf Lilleengen fd = open(path, O_WRONLY); 30505c91076SPawel Jakub Dawidek if (fd == -1) 30605c91076SPawel Jakub Dawidek return (errno); 30709cc9ab6SPawel Jakub Dawidek mediasize = g_get_mediasize(name); 30809cc9ab6SPawel Jakub Dawidek if (mediasize == 0) { 30905c91076SPawel Jakub Dawidek error = errno; 31005c91076SPawel Jakub Dawidek goto out; 31105c91076SPawel Jakub Dawidek } 31209cc9ab6SPawel Jakub Dawidek sectorsize = g_get_sectorsize(name); 31309cc9ab6SPawel Jakub Dawidek if (sectorsize == 0) { 31405c91076SPawel Jakub Dawidek error = errno; 31505c91076SPawel Jakub Dawidek goto out; 31605c91076SPawel Jakub Dawidek } 31705c91076SPawel Jakub Dawidek assert(sectorsize >= size); 31805c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 31905c91076SPawel Jakub Dawidek if (sector == NULL) { 32005c91076SPawel Jakub Dawidek error = ENOMEM; 32105c91076SPawel Jakub Dawidek goto out; 32205c91076SPawel Jakub Dawidek } 32305c91076SPawel Jakub Dawidek bcopy(md, sector, size); 32405c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 32505c91076SPawel Jakub Dawidek (ssize_t)sectorsize) { 32605c91076SPawel Jakub Dawidek error = errno; 32705c91076SPawel Jakub Dawidek goto out; 32805c91076SPawel Jakub Dawidek } 32954ddff9dSPawel Jakub Dawidek (void)ioctl(fd, DIOCGFLUSH, NULL); 33005c91076SPawel Jakub Dawidek out: 33105c91076SPawel Jakub Dawidek if (sector != NULL) 33205c91076SPawel Jakub Dawidek free(sector); 33305c91076SPawel Jakub Dawidek close(fd); 33405c91076SPawel Jakub Dawidek return (error); 33505c91076SPawel Jakub Dawidek } 33605c91076SPawel Jakub Dawidek 33705c91076SPawel Jakub Dawidek int 33805c91076SPawel Jakub Dawidek g_metadata_clear(const char *name, const char *magic) 33905c91076SPawel Jakub Dawidek { 34005c91076SPawel Jakub Dawidek struct std_metadata md; 34105c91076SPawel Jakub Dawidek char path[MAXPATHLEN]; 34205c91076SPawel Jakub Dawidek unsigned sectorsize; 34305c91076SPawel Jakub Dawidek off_t mediasize; 34405c91076SPawel Jakub Dawidek u_char *sector; 34505c91076SPawel Jakub Dawidek int error, fd; 34605c91076SPawel Jakub Dawidek 34705c91076SPawel Jakub Dawidek pathgen(name, path, sizeof(path)); 34805c91076SPawel Jakub Dawidek sector = NULL; 34905c91076SPawel Jakub Dawidek error = 0; 35005c91076SPawel Jakub Dawidek 35105c91076SPawel Jakub Dawidek fd = open(path, O_RDWR); 35205c91076SPawel Jakub Dawidek if (fd == -1) 35305c91076SPawel Jakub Dawidek return (errno); 35409cc9ab6SPawel Jakub Dawidek mediasize = g_get_mediasize(name); 35509cc9ab6SPawel Jakub Dawidek if (mediasize == 0) { 35605c91076SPawel Jakub Dawidek error = errno; 35705c91076SPawel Jakub Dawidek goto out; 35805c91076SPawel Jakub Dawidek } 35909cc9ab6SPawel Jakub Dawidek sectorsize = g_get_sectorsize(name); 36009cc9ab6SPawel Jakub Dawidek if (sectorsize == 0) { 36105c91076SPawel Jakub Dawidek error = errno; 36205c91076SPawel Jakub Dawidek goto out; 36305c91076SPawel Jakub Dawidek } 36405c91076SPawel Jakub Dawidek sector = malloc(sectorsize); 36505c91076SPawel Jakub Dawidek if (sector == NULL) { 36605c91076SPawel Jakub Dawidek error = ENOMEM; 36705c91076SPawel Jakub Dawidek goto out; 36805c91076SPawel Jakub Dawidek } 36905c91076SPawel Jakub Dawidek if (magic != NULL) { 37005c91076SPawel Jakub Dawidek if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 37105c91076SPawel Jakub Dawidek (ssize_t)sectorsize) { 37205c91076SPawel Jakub Dawidek error = errno; 37305c91076SPawel Jakub Dawidek goto out; 37405c91076SPawel Jakub Dawidek } 37505c91076SPawel Jakub Dawidek std_metadata_decode(sector, &md); 37605c91076SPawel Jakub Dawidek if (strcmp(md.md_magic, magic) != 0) { 37705c91076SPawel Jakub Dawidek error = EINVAL; 37805c91076SPawel Jakub Dawidek goto out; 37905c91076SPawel Jakub Dawidek } 38005c91076SPawel Jakub Dawidek } 38105c91076SPawel Jakub Dawidek bzero(sector, sectorsize); 38205c91076SPawel Jakub Dawidek if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 38305c91076SPawel Jakub Dawidek (ssize_t)sectorsize) { 38405c91076SPawel Jakub Dawidek error = errno; 38505c91076SPawel Jakub Dawidek goto out; 38605c91076SPawel Jakub Dawidek } 38754ddff9dSPawel Jakub Dawidek (void)ioctl(fd, DIOCGFLUSH, NULL); 38805c91076SPawel Jakub Dawidek out: 38905c91076SPawel Jakub Dawidek if (sector != NULL) 39005c91076SPawel Jakub Dawidek free(sector); 39105c91076SPawel Jakub Dawidek close(fd); 39205c91076SPawel Jakub Dawidek return (error); 39305c91076SPawel Jakub Dawidek } 39405c91076SPawel Jakub Dawidek 39505c91076SPawel Jakub Dawidek /* 39605c91076SPawel Jakub Dawidek * Set an error message, if one does not already exist. 39705c91076SPawel Jakub Dawidek */ 39805c91076SPawel Jakub Dawidek void 39905c91076SPawel Jakub Dawidek gctl_error(struct gctl_req *req, const char *error, ...) 40005c91076SPawel Jakub Dawidek { 40105c91076SPawel Jakub Dawidek va_list ap; 40205c91076SPawel Jakub Dawidek 40305c91076SPawel Jakub Dawidek if (req->error != NULL) 40405c91076SPawel Jakub Dawidek return; 40505c91076SPawel Jakub Dawidek va_start(ap, error); 40605c91076SPawel Jakub Dawidek vasprintf(&req->error, error, ap); 40705c91076SPawel Jakub Dawidek va_end(ap); 40805c91076SPawel Jakub Dawidek } 40905c91076SPawel Jakub Dawidek 410f13942a7SPawel Jakub Dawidek static void * 411f13942a7SPawel Jakub Dawidek gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 41205c91076SPawel Jakub Dawidek { 413f13942a7SPawel Jakub Dawidek struct gctl_req_arg *argp; 414f13942a7SPawel Jakub Dawidek char param[256]; 41505c91076SPawel Jakub Dawidek void *p; 41605c91076SPawel Jakub Dawidek unsigned i; 41705c91076SPawel Jakub Dawidek 418f13942a7SPawel Jakub Dawidek vsnprintf(param, sizeof(param), pfmt, ap); 41905c91076SPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 420f13942a7SPawel Jakub Dawidek argp = &req->arg[i]; 421f13942a7SPawel Jakub Dawidek if (strcmp(param, argp->name)) 42205c91076SPawel Jakub Dawidek continue; 423f13942a7SPawel Jakub Dawidek if (!(argp->flag & GCTL_PARAM_RD)) 42405c91076SPawel Jakub Dawidek continue; 425f13942a7SPawel Jakub Dawidek p = argp->value; 426f13942a7SPawel Jakub Dawidek if (len == 0) { 427f13942a7SPawel Jakub Dawidek /* We are looking for a string. */ 428f13942a7SPawel Jakub Dawidek if (argp->len < 1) { 429f13942a7SPawel Jakub Dawidek fprintf(stderr, "No length argument (%s).\n", 430f13942a7SPawel Jakub Dawidek param); 431f13942a7SPawel Jakub Dawidek abort(); 43205c91076SPawel Jakub Dawidek } 433f13942a7SPawel Jakub Dawidek if (((char *)p)[argp->len - 1] != '\0') { 434f13942a7SPawel Jakub Dawidek fprintf(stderr, "Unterminated argument (%s).\n", 435f13942a7SPawel Jakub Dawidek param); 436f13942a7SPawel Jakub Dawidek abort(); 437f13942a7SPawel Jakub Dawidek } 438f13942a7SPawel Jakub Dawidek } else if ((int)len != argp->len) { 439f13942a7SPawel Jakub Dawidek fprintf(stderr, "Wrong length %s argument.\n", param); 440f13942a7SPawel Jakub Dawidek abort(); 44105c91076SPawel Jakub Dawidek } 44205c91076SPawel Jakub Dawidek return (p); 44305c91076SPawel Jakub Dawidek } 444f13942a7SPawel Jakub Dawidek fprintf(stderr, "No such argument (%s).\n", param); 445f13942a7SPawel Jakub Dawidek abort(); 44605c91076SPawel Jakub Dawidek } 44705c91076SPawel Jakub Dawidek 448f13942a7SPawel Jakub Dawidek int 449f13942a7SPawel Jakub Dawidek gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 45005c91076SPawel Jakub Dawidek { 451f13942a7SPawel Jakub Dawidek int *p; 452f13942a7SPawel Jakub Dawidek va_list ap; 45305c91076SPawel Jakub Dawidek 454f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 455f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(int), pfmt, ap); 456f13942a7SPawel Jakub Dawidek va_end(ap); 457f13942a7SPawel Jakub Dawidek return (*p); 45805c91076SPawel Jakub Dawidek } 459f13942a7SPawel Jakub Dawidek 460f13942a7SPawel Jakub Dawidek intmax_t 461f13942a7SPawel Jakub Dawidek gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 462f13942a7SPawel Jakub Dawidek { 463f13942a7SPawel Jakub Dawidek intmax_t *p; 464f13942a7SPawel Jakub Dawidek va_list ap; 465f13942a7SPawel Jakub Dawidek 466f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 467f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 468f13942a7SPawel Jakub Dawidek va_end(ap); 469f13942a7SPawel Jakub Dawidek return (*p); 470f13942a7SPawel Jakub Dawidek } 471f13942a7SPawel Jakub Dawidek 472f13942a7SPawel Jakub Dawidek const char * 473f13942a7SPawel Jakub Dawidek gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 474f13942a7SPawel Jakub Dawidek { 475f13942a7SPawel Jakub Dawidek const char *p; 476f13942a7SPawel Jakub Dawidek va_list ap; 477f13942a7SPawel Jakub Dawidek 478f13942a7SPawel Jakub Dawidek va_start(ap, pfmt); 479f13942a7SPawel Jakub Dawidek p = gctl_get_param(req, 0, pfmt, ap); 480f13942a7SPawel Jakub Dawidek va_end(ap); 48105c91076SPawel Jakub Dawidek return (p); 48205c91076SPawel Jakub Dawidek } 4831378624cSPawel Jakub Dawidek 4841378624cSPawel Jakub Dawidek int 4851378624cSPawel Jakub Dawidek gctl_change_param(struct gctl_req *req, const char *name, int len, 4861378624cSPawel Jakub Dawidek const void *value) 4871378624cSPawel Jakub Dawidek { 4881378624cSPawel Jakub Dawidek struct gctl_req_arg *ap; 4891378624cSPawel Jakub Dawidek unsigned i; 4901378624cSPawel Jakub Dawidek 4911378624cSPawel Jakub Dawidek if (req == NULL || req->error != NULL) 4921378624cSPawel Jakub Dawidek return (EDOOFUS); 4931378624cSPawel Jakub Dawidek for (i = 0; i < req->narg; i++) { 4941378624cSPawel Jakub Dawidek ap = &req->arg[i]; 4951378624cSPawel Jakub Dawidek if (strcmp(ap->name, name) != 0) 4961378624cSPawel Jakub Dawidek continue; 4971378624cSPawel Jakub Dawidek ap->value = __DECONST(void *, value); 4981378624cSPawel Jakub Dawidek if (len >= 0) { 4991378624cSPawel Jakub Dawidek ap->flag &= ~GCTL_PARAM_ASCII; 5001378624cSPawel Jakub Dawidek ap->len = len; 5011378624cSPawel Jakub Dawidek } else if (len < 0) { 5021378624cSPawel Jakub Dawidek ap->flag |= GCTL_PARAM_ASCII; 5031378624cSPawel Jakub Dawidek ap->len = strlen(value) + 1; 5041378624cSPawel Jakub Dawidek } 5051378624cSPawel Jakub Dawidek return (0); 5061378624cSPawel Jakub Dawidek } 5071378624cSPawel Jakub Dawidek return (ENOENT); 5081378624cSPawel Jakub Dawidek } 50959458bafSMarcel Moolenaar 51059458bafSMarcel Moolenaar int 51159458bafSMarcel Moolenaar gctl_delete_param(struct gctl_req *req, const char *name) 51259458bafSMarcel Moolenaar { 51359458bafSMarcel Moolenaar struct gctl_req_arg *ap; 51459458bafSMarcel Moolenaar unsigned int i; 51559458bafSMarcel Moolenaar 51659458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 51759458bafSMarcel Moolenaar return (EDOOFUS); 51859458bafSMarcel Moolenaar 51959458bafSMarcel Moolenaar i = 0; 52059458bafSMarcel Moolenaar while (i < req->narg) { 52159458bafSMarcel Moolenaar ap = &req->arg[i]; 52259458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 52359458bafSMarcel Moolenaar break; 52459458bafSMarcel Moolenaar i++; 52559458bafSMarcel Moolenaar } 52659458bafSMarcel Moolenaar if (i == req->narg) 52759458bafSMarcel Moolenaar return (ENOENT); 52859458bafSMarcel Moolenaar 52924609c49SAndrey V. Elsukov free(ap->name); 53059458bafSMarcel Moolenaar req->narg--; 53159458bafSMarcel Moolenaar while (i < req->narg) { 53259458bafSMarcel Moolenaar req->arg[i] = req->arg[i + 1]; 53359458bafSMarcel Moolenaar i++; 53459458bafSMarcel Moolenaar } 53559458bafSMarcel Moolenaar return (0); 53659458bafSMarcel Moolenaar } 53759458bafSMarcel Moolenaar 53859458bafSMarcel Moolenaar int 53959458bafSMarcel Moolenaar gctl_has_param(struct gctl_req *req, const char *name) 54059458bafSMarcel Moolenaar { 54159458bafSMarcel Moolenaar struct gctl_req_arg *ap; 54259458bafSMarcel Moolenaar unsigned int i; 54359458bafSMarcel Moolenaar 54459458bafSMarcel Moolenaar if (req == NULL || req->error != NULL) 54559458bafSMarcel Moolenaar return (0); 54659458bafSMarcel Moolenaar 54759458bafSMarcel Moolenaar for (i = 0; i < req->narg; i++) { 54859458bafSMarcel Moolenaar ap = &req->arg[i]; 54959458bafSMarcel Moolenaar if (strcmp(ap->name, name) == 0) 55059458bafSMarcel Moolenaar return (1); 55159458bafSMarcel Moolenaar } 55259458bafSMarcel Moolenaar return (0); 55359458bafSMarcel Moolenaar } 554