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