1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
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 <limits.h>
40 #include <inttypes.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <strings.h>
44 #include <unistd.h>
45 #include <assert.h>
46 #include <libgeom.h>
47
48 #include "misc/subr.h"
49
50
51 struct std_metadata {
52 char md_magic[16];
53 uint32_t md_version;
54 };
55
56 static void
std_metadata_decode(const unsigned char * data,struct std_metadata * md)57 std_metadata_decode(const unsigned char *data, struct std_metadata *md)
58 {
59
60 bcopy(data, md->md_magic, sizeof(md->md_magic));
61 md->md_version = le32dec(data + 16);
62 }
63
64 /*
65 * Greatest Common Divisor.
66 */
67 static unsigned int
gcd(unsigned int a,unsigned int b)68 gcd(unsigned int a, unsigned int b)
69 {
70 unsigned int c;
71
72 while (b != 0) {
73 c = a;
74 a = b;
75 b = (c % b);
76 }
77 return (a);
78 }
79
80 /*
81 * Least Common Multiple.
82 */
83 unsigned int
g_lcm(unsigned int a,unsigned int b)84 g_lcm(unsigned int a, unsigned int b)
85 {
86
87 return ((a * b) / gcd(a, b));
88 }
89
90 uint32_t
bitcount32(uint32_t x)91 bitcount32(uint32_t x)
92 {
93
94 x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
95 x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
96 x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4);
97 x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8);
98 x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16);
99 return (x);
100 }
101
102 /*
103 * The size of a sector is context specific (i.e. determined by the
104 * media). But when users enter a value with a SI unit, they really
105 * mean the byte-size or byte-offset and not the size or offset in
106 * sectors. We should map the byte-oriented value into a sector-oriented
107 * value when we already know the sector size in bytes. At this time
108 * we can use g_parse_lba() function. It converts user specified
109 * value into sectors with following conditions:
110 * o Sectors size taken as argument from caller.
111 * o When no SI unit is specified the value is in sectors.
112 * o With an SI unit the value is in bytes.
113 * o The 'b' suffix forces byte interpretation and the 's'
114 * suffix forces sector interpretation.
115 *
116 * Thus:
117 * o 2 and 2s mean 2 sectors, and 2b means 2 bytes.
118 * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors.
119 *
120 */
121 int
g_parse_lba(const char * lbastr,unsigned int sectorsize,off_t * sectors)122 g_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors)
123 {
124 off_t number, mult, unit;
125 char *s;
126
127 assert(lbastr != NULL);
128 assert(sectorsize > 0);
129 assert(sectors != NULL);
130
131 number = (off_t)strtoimax(lbastr, &s, 0);
132 if (s == lbastr || number < 0)
133 return (EINVAL);
134
135 mult = 1;
136 unit = sectorsize;
137 if (*s == '\0')
138 goto done;
139 switch (*s) {
140 case 'e': case 'E':
141 mult *= 1024;
142 /* FALLTHROUGH */
143 case 'p': case 'P':
144 mult *= 1024;
145 /* FALLTHROUGH */
146 case 't': case 'T':
147 mult *= 1024;
148 /* FALLTHROUGH */
149 case 'g': case 'G':
150 mult *= 1024;
151 /* FALLTHROUGH */
152 case 'm': case 'M':
153 mult *= 1024;
154 /* FALLTHROUGH */
155 case 'k': case 'K':
156 mult *= 1024;
157 break;
158 default:
159 goto sfx;
160 }
161 unit = 1; /* bytes */
162 s++;
163 if (*s == '\0')
164 goto done;
165 sfx:
166 switch (*s) {
167 case 's': case 'S':
168 unit = sectorsize; /* sector */
169 break;
170 case 'b': case 'B':
171 unit = 1; /* bytes */
172 break;
173 default:
174 return (EINVAL);
175 }
176 s++;
177 if (*s != '\0')
178 return (EINVAL);
179 done:
180 if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number)
181 return (ERANGE);
182 number *= mult * unit;
183 if (number % sectorsize)
184 return (EINVAL);
185 number /= sectorsize;
186 *sectors = number;
187 return (0);
188 }
189
190 off_t
g_get_mediasize(const char * name)191 g_get_mediasize(const char *name)
192 {
193 off_t mediasize;
194 int fd;
195
196 fd = g_open(name, 0);
197 if (fd == -1)
198 return (0);
199 mediasize = g_mediasize(fd);
200 if (mediasize == -1)
201 mediasize = 0;
202 (void)g_close(fd);
203 return (mediasize);
204 }
205
206 unsigned int
g_get_sectorsize(const char * name)207 g_get_sectorsize(const char *name)
208 {
209 ssize_t sectorsize;
210 int fd;
211
212 fd = g_open(name, 0);
213 if (fd == -1)
214 return (0);
215 sectorsize = g_sectorsize(fd);
216 if (sectorsize == -1)
217 sectorsize = 0;
218 (void)g_close(fd);
219 return ((unsigned int)sectorsize);
220 }
221
222 int
g_metadata_read(const char * name,unsigned char * md,size_t size,const char * magic)223 g_metadata_read(const char *name, unsigned char *md, size_t size,
224 const char *magic)
225 {
226 struct std_metadata stdmd;
227 unsigned char *sector;
228 ssize_t sectorsize;
229 off_t mediasize;
230 int error, fd;
231
232 sector = NULL;
233 error = 0;
234
235 fd = g_open(name, 0);
236 if (fd == -1)
237 return (errno);
238 mediasize = g_mediasize(fd);
239 if (mediasize == -1) {
240 error = errno;
241 goto out;
242 }
243 sectorsize = g_sectorsize(fd);
244 if (sectorsize == -1) {
245 error = errno;
246 goto out;
247 }
248 assert(sectorsize >= (ssize_t)size);
249 sector = malloc(sectorsize);
250 if (sector == NULL) {
251 error = ENOMEM;
252 goto out;
253 }
254 if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
255 sectorsize) {
256 error = errno;
257 goto out;
258 }
259 if (magic != NULL) {
260 std_metadata_decode(sector, &stdmd);
261 if (strcmp(stdmd.md_magic, magic) != 0) {
262 error = EINVAL;
263 goto out;
264 }
265 }
266 bcopy(sector, md, size);
267 out:
268 if (sector != NULL)
269 free(sector);
270 g_close(fd);
271 return (error);
272 }
273
274 /*
275 * Actually write the GEOM label to the provider
276 *
277 * @param name GEOM provider's name (ie "ada0")
278 * @param md Pointer to the label data to write
279 * @param size Size of the data pointed to by md
280 */
281 int
g_metadata_store(const char * name,const unsigned char * md,size_t size)282 g_metadata_store(const char *name, const unsigned char *md, size_t size)
283 {
284 unsigned char *sector;
285 ssize_t sectorsize;
286 off_t mediasize;
287 int error, fd;
288
289 sector = NULL;
290 error = 0;
291
292 fd = g_open(name, 1);
293 if (fd == -1)
294 return (errno);
295 mediasize = g_mediasize(fd);
296 if (mediasize == -1) {
297 error = errno;
298 goto out;
299 }
300 sectorsize = g_sectorsize(fd);
301 if (sectorsize == -1) {
302 error = errno;
303 goto out;
304 }
305 assert(sectorsize >= (ssize_t)size);
306 sector = malloc(sectorsize);
307 if (sector == NULL) {
308 error = ENOMEM;
309 goto out;
310 }
311 bcopy(md, sector, size);
312 bzero(sector + size, sectorsize - size);
313 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
314 sectorsize) {
315 error = errno;
316 goto out;
317 }
318 (void)g_flush(fd);
319 out:
320 if (sector != NULL)
321 free(sector);
322 (void)g_close(fd);
323 return (error);
324 }
325
326 int
g_metadata_clear(const char * name,const char * magic)327 g_metadata_clear(const char *name, const char *magic)
328 {
329 struct std_metadata md;
330 unsigned char *sector;
331 ssize_t sectorsize;
332 off_t mediasize;
333 int error, fd;
334
335 sector = NULL;
336 error = 0;
337
338 fd = g_open(name, 1);
339 if (fd == -1)
340 return (errno);
341 mediasize = g_mediasize(fd);
342 if (mediasize == 0) {
343 error = errno;
344 goto out;
345 }
346 sectorsize = g_sectorsize(fd);
347 if (sectorsize <= 0) {
348 error = errno;
349 goto out;
350 }
351 sector = malloc(sectorsize);
352 if (sector == NULL) {
353 error = ENOMEM;
354 goto out;
355 }
356 if (magic != NULL) {
357 if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
358 sectorsize) {
359 error = errno;
360 goto out;
361 }
362 std_metadata_decode(sector, &md);
363 if (strcmp(md.md_magic, magic) != 0) {
364 error = EINVAL;
365 goto out;
366 }
367 }
368 bzero(sector, sectorsize);
369 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
370 sectorsize) {
371 error = errno;
372 goto out;
373 }
374 (void)g_flush(fd);
375 out:
376 free(sector);
377 g_close(fd);
378 return (error);
379 }
380
381 /*
382 * Set an error message, if one does not already exist.
383 */
384 void
gctl_error(struct gctl_req * req,const char * error,...)385 gctl_error(struct gctl_req *req, const char *error, ...)
386 {
387 va_list ap;
388
389 if (req != NULL && req->error != NULL)
390 return;
391 va_start(ap, error);
392 if (req != NULL) {
393 vasprintf(&req->error, error, ap);
394 } else {
395 vfprintf(stderr, error, ap);
396 fprintf(stderr, "\n");
397 }
398 va_end(ap);
399 if (req != NULL && req->nerror == 0)
400 req->nerror = EINVAL;
401 }
402
403 static void *
gctl_get_param(struct gctl_req * req,size_t len,const char * pfmt,va_list ap)404 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
405 {
406 struct gctl_req_arg *argp;
407 char param[256];
408 unsigned int i;
409 void *p;
410
411 vsnprintf(param, sizeof(param), pfmt, ap);
412 for (i = 0; i < req->narg; i++) {
413 argp = &req->arg[i];
414 if (strcmp(param, argp->name))
415 continue;
416 if (!(argp->flag & GCTL_PARAM_RD))
417 continue;
418 p = argp->value;
419 if (len == 0) {
420 /* We are looking for a string. */
421 if (argp->len < 1) {
422 fprintf(stderr, "No length argument (%s).\n",
423 param);
424 abort();
425 }
426 if (((char *)p)[argp->len - 1] != '\0') {
427 fprintf(stderr, "Unterminated argument (%s).\n",
428 param);
429 abort();
430 }
431 } else if ((int)len != argp->len) {
432 fprintf(stderr, "Wrong length %s argument.\n", param);
433 abort();
434 }
435 return (p);
436 }
437 fprintf(stderr, "No such argument (%s).\n", param);
438 abort();
439 }
440
441 int
gctl_get_int(struct gctl_req * req,const char * pfmt,...)442 gctl_get_int(struct gctl_req *req, const char *pfmt, ...)
443 {
444 int *p;
445 va_list ap;
446
447 va_start(ap, pfmt);
448 p = gctl_get_param(req, sizeof(int), pfmt, ap);
449 va_end(ap);
450 return (*p);
451 }
452
453 intmax_t
gctl_get_intmax(struct gctl_req * req,const char * pfmt,...)454 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
455 {
456 intmax_t *p;
457 va_list ap;
458
459 va_start(ap, pfmt);
460 p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
461 va_end(ap);
462 return (*p);
463 }
464
465 const char *
gctl_get_ascii(struct gctl_req * req,const char * pfmt,...)466 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
467 {
468 const char *p;
469 va_list ap;
470
471 va_start(ap, pfmt);
472 p = gctl_get_param(req, 0, pfmt, ap);
473 va_end(ap);
474 return (p);
475 }
476
477 int
gctl_change_param(struct gctl_req * req,const char * name,int len,const void * value)478 gctl_change_param(struct gctl_req *req, const char *name, int len,
479 const void *value)
480 {
481 struct gctl_req_arg *ap;
482 unsigned int i;
483
484 if (req == NULL || req->error != NULL)
485 return (EDOOFUS);
486 for (i = 0; i < req->narg; i++) {
487 ap = &req->arg[i];
488 if (strcmp(ap->name, name) != 0)
489 continue;
490 ap->value = __DECONST(void *, value);
491 if (len >= 0) {
492 ap->flag &= ~GCTL_PARAM_ASCII;
493 ap->len = len;
494 } else if (len < 0) {
495 ap->flag |= GCTL_PARAM_ASCII;
496 ap->len = strlen(value) + 1;
497 }
498 return (0);
499 }
500 return (ENOENT);
501 }
502
503 int
gctl_delete_param(struct gctl_req * req,const char * name)504 gctl_delete_param(struct gctl_req *req, const char *name)
505 {
506 struct gctl_req_arg *ap;
507 unsigned int i;
508
509 if (req == NULL || req->error != NULL)
510 return (EDOOFUS);
511
512 i = 0;
513 while (i < req->narg) {
514 ap = &req->arg[i];
515 if (strcmp(ap->name, name) == 0)
516 break;
517 i++;
518 }
519 if (i == req->narg)
520 return (ENOENT);
521
522 free(ap->name);
523 req->narg--;
524 while (i < req->narg) {
525 req->arg[i] = req->arg[i + 1];
526 i++;
527 }
528 return (0);
529 }
530
531 int
gctl_has_param(struct gctl_req * req,const char * name)532 gctl_has_param(struct gctl_req *req, const char *name)
533 {
534 struct gctl_req_arg *ap;
535 unsigned int i;
536
537 if (req == NULL || req->error != NULL)
538 return (0);
539
540 for (i = 0; i < req->narg; i++) {
541 ap = &req->arg[i];
542 if (strcmp(ap->name, name) == 0)
543 return (1);
544 }
545 return (0);
546 }
547