1 /*- 2 * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/disk.h> 32 #include <sys/endian.h> 33 #include <sys/uio.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <paths.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <stdarg.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <unistd.h> 43 #include <assert.h> 44 #include <libgeom.h> 45 46 #include "misc/subr.h" 47 48 49 struct std_metadata { 50 char md_magic[16]; 51 uint32_t md_version; 52 }; 53 54 static void 55 std_metadata_decode(const u_char *data, struct std_metadata *md) 56 { 57 58 bcopy(data, md->md_magic, sizeof(md->md_magic)); 59 md->md_version = le32dec(data + 16); 60 } 61 62 static void 63 pathgen(const char *name, char *path, size_t size) 64 { 65 66 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 67 snprintf(path, size, "%s%s", _PATH_DEV, name); 68 else 69 strlcpy(path, name, size); 70 } 71 72 /* 73 * Greatest Common Divisor. 74 */ 75 static unsigned 76 gcd(unsigned a, unsigned b) 77 { 78 u_int c; 79 80 while (b != 0) { 81 c = a; 82 a = b; 83 b = (c % b); 84 } 85 return (a); 86 } 87 88 /* 89 * Least Common Multiple. 90 */ 91 unsigned 92 g_lcm(unsigned a, unsigned b) 93 { 94 95 return ((a * b) / gcd(a, b)); 96 } 97 98 off_t 99 g_get_mediasize(const char *name) 100 { 101 char path[MAXPATHLEN]; 102 off_t mediasize; 103 int fd; 104 105 pathgen(name, path, sizeof(path)); 106 fd = open(path, O_RDONLY); 107 if (fd == -1) 108 return (0); 109 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 110 close(fd); 111 return (0); 112 } 113 close(fd); 114 return (mediasize); 115 } 116 117 unsigned 118 g_get_sectorsize(const char *name) 119 { 120 char path[MAXPATHLEN]; 121 unsigned sectorsize; 122 int fd; 123 124 pathgen(name, path, sizeof(path)); 125 fd = open(path, O_RDONLY); 126 if (fd == -1) 127 return (0); 128 if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 129 close(fd); 130 return (0); 131 } 132 close(fd); 133 return (sectorsize); 134 } 135 136 int 137 g_metadata_read(const char *name, u_char *md, size_t size, const char *magic) 138 { 139 struct std_metadata stdmd; 140 char path[MAXPATHLEN]; 141 unsigned sectorsize; 142 off_t mediasize; 143 u_char *sector; 144 int error, fd; 145 146 pathgen(name, path, sizeof(path)); 147 sector = NULL; 148 error = 0; 149 150 fd = open(path, O_RDONLY); 151 if (fd == -1) 152 return (errno); 153 mediasize = g_get_mediasize(name); 154 if (mediasize == 0) { 155 error = errno; 156 goto out; 157 } 158 sectorsize = g_get_sectorsize(name); 159 if (sectorsize == 0) { 160 error = errno; 161 goto out; 162 } 163 assert(sectorsize >= size); 164 sector = malloc(sectorsize); 165 if (sector == NULL) { 166 error = ENOMEM; 167 goto out; 168 } 169 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 170 (ssize_t)sectorsize) { 171 error = errno; 172 goto out; 173 } 174 if (magic != NULL) { 175 std_metadata_decode(sector, &stdmd); 176 if (strcmp(stdmd.md_magic, magic) != 0) { 177 error = EINVAL; 178 goto out; 179 } 180 } 181 bcopy(sector, md, size); 182 out: 183 if (sector != NULL) 184 free(sector); 185 close(fd); 186 return (error); 187 } 188 189 int 190 g_metadata_store(const char *name, u_char *md, size_t size) 191 { 192 char path[MAXPATHLEN]; 193 unsigned sectorsize; 194 off_t mediasize; 195 u_char *sector; 196 int error, fd; 197 198 pathgen(name, path, sizeof(path)); 199 sector = NULL; 200 error = 0; 201 202 fd = open(path, O_WRONLY); 203 if (fd == -1) 204 return (errno); 205 mediasize = g_get_mediasize(name); 206 if (mediasize == 0) { 207 error = errno; 208 goto out; 209 } 210 sectorsize = g_get_sectorsize(name); 211 if (sectorsize == 0) { 212 error = errno; 213 goto out; 214 } 215 assert(sectorsize >= size); 216 sector = malloc(sectorsize); 217 if (sector == NULL) { 218 error = ENOMEM; 219 goto out; 220 } 221 bcopy(md, sector, size); 222 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 223 (ssize_t)sectorsize) { 224 error = errno; 225 goto out; 226 } 227 out: 228 if (sector != NULL) 229 free(sector); 230 close(fd); 231 return (error); 232 } 233 234 int 235 g_metadata_clear(const char *name, const char *magic) 236 { 237 struct std_metadata md; 238 char path[MAXPATHLEN]; 239 unsigned sectorsize; 240 off_t mediasize; 241 u_char *sector; 242 int error, fd; 243 244 pathgen(name, path, sizeof(path)); 245 sector = NULL; 246 error = 0; 247 248 fd = open(path, O_RDWR); 249 if (fd == -1) 250 return (errno); 251 mediasize = g_get_mediasize(name); 252 if (mediasize == 0) { 253 error = errno; 254 goto out; 255 } 256 sectorsize = g_get_sectorsize(name); 257 if (sectorsize == 0) { 258 error = errno; 259 goto out; 260 } 261 sector = malloc(sectorsize); 262 if (sector == NULL) { 263 error = ENOMEM; 264 goto out; 265 } 266 if (magic != NULL) { 267 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 268 (ssize_t)sectorsize) { 269 error = errno; 270 goto out; 271 } 272 std_metadata_decode(sector, &md); 273 if (strcmp(md.md_magic, magic) != 0) { 274 error = EINVAL; 275 goto out; 276 } 277 } 278 bzero(sector, sectorsize); 279 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 280 (ssize_t)sectorsize) { 281 error = errno; 282 goto out; 283 } 284 out: 285 if (sector != NULL) 286 free(sector); 287 close(fd); 288 return (error); 289 } 290 291 /* 292 * Set an error message, if one does not already exist. 293 */ 294 void 295 gctl_error(struct gctl_req *req, const char *error, ...) 296 { 297 va_list ap; 298 299 if (req->error != NULL) 300 return; 301 va_start(ap, error); 302 vasprintf(&req->error, error, ap); 303 va_end(ap); 304 } 305 306 void * 307 gctl_get_param(struct gctl_req *req, const char *param, int *len) 308 { 309 unsigned i; 310 void *p; 311 struct gctl_req_arg *ap; 312 313 for (i = 0; i < req->narg; i++) { 314 ap = &req->arg[i]; 315 if (strcmp(param, ap->name)) 316 continue; 317 if (!(ap->flag & GCTL_PARAM_RD)) 318 continue; 319 p = ap->value; 320 if (len != NULL) 321 *len = ap->len; 322 return (p); 323 } 324 return (NULL); 325 } 326 327 char const * 328 gctl_get_asciiparam(struct gctl_req *req, const char *param) 329 { 330 unsigned i; 331 char const *p; 332 struct gctl_req_arg *ap; 333 334 for (i = 0; i < req->narg; i++) { 335 ap = &req->arg[i]; 336 if (strcmp(param, ap->name)) 337 continue; 338 if (!(ap->flag & GCTL_PARAM_RD)) 339 continue; 340 p = ap->value; 341 if (ap->len < 1) { 342 gctl_error(req, "No length argument (%s)", param); 343 return (NULL); 344 } 345 if (p[ap->len - 1] != '\0') { 346 gctl_error(req, "Unterminated argument (%s)", param); 347 return (NULL); 348 } 349 return (p); 350 } 351 return (NULL); 352 } 353 354 void * 355 gctl_get_paraml(struct gctl_req *req, const char *param, int len) 356 { 357 int i; 358 void *p; 359 360 p = gctl_get_param(req, param, &i); 361 if (p == NULL) 362 gctl_error(req, "Missing %s argument", param); 363 else if (i != len) { 364 p = NULL; 365 gctl_error(req, "Wrong length %s argument", param); 366 } 367 return (p); 368 } 369