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