]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sbin/geom/misc/subr.c
MFC r323314, r323338, r328849
[FreeBSD/stable/10.git] / sbin / geom / misc / subr.c
1 /*-
2  * Copyright (c) 2004-2010 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 <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
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
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
84 g_lcm(unsigned int a, unsigned int b)
85 {
86
87         return ((a * b) / gcd(a, b));
88 }
89
90 uint32_t
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
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
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
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
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
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
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
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 }
400
401 static void *
402 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
403 {
404         struct gctl_req_arg *argp;
405         char param[256];
406         unsigned int i;
407         void *p;
408
409         vsnprintf(param, sizeof(param), pfmt, ap);
410         for (i = 0; i < req->narg; i++) {
411                 argp = &req->arg[i];
412                 if (strcmp(param, argp->name))
413                         continue;
414                 if (!(argp->flag & GCTL_PARAM_RD))
415                         continue;
416                 p = argp->value;
417                 if (len == 0) {
418                         /* We are looking for a string. */
419                         if (argp->len < 1) {
420                                 fprintf(stderr, "No length argument (%s).\n",
421                                     param);
422                                 abort();
423                         }
424                         if (((char *)p)[argp->len - 1] != '\0') {
425                                 fprintf(stderr, "Unterminated argument (%s).\n",
426                                     param);
427                                 abort();
428                         }
429                 } else if ((int)len != argp->len) {
430                         fprintf(stderr, "Wrong length %s argument.\n", param);
431                         abort();
432                 }
433                 return (p);
434         }
435         fprintf(stderr, "No such argument (%s).\n", param);
436         abort();
437 }
438
439 int
440 gctl_get_int(struct gctl_req *req, const char *pfmt, ...)
441 {
442         int *p;
443         va_list ap;
444
445         va_start(ap, pfmt);
446         p = gctl_get_param(req, sizeof(int), pfmt, ap);
447         va_end(ap);
448         return (*p);
449 }
450
451 intmax_t
452 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
453 {
454         intmax_t *p;
455         va_list ap;
456
457         va_start(ap, pfmt);
458         p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
459         va_end(ap);
460         return (*p);
461 }
462
463 const char *
464 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
465 {
466         const char *p;
467         va_list ap;
468
469         va_start(ap, pfmt);
470         p = gctl_get_param(req, 0, pfmt, ap);
471         va_end(ap);
472         return (p);
473 }
474
475 int
476 gctl_change_param(struct gctl_req *req, const char *name, int len,
477     const void *value)
478 {
479         struct gctl_req_arg *ap;
480         unsigned int i;
481
482         if (req == NULL || req->error != NULL)
483                 return (EDOOFUS);
484         for (i = 0; i < req->narg; i++) {
485                 ap = &req->arg[i];
486                 if (strcmp(ap->name, name) != 0)
487                         continue;
488                 ap->value = __DECONST(void *, value);
489                 if (len >= 0) {
490                         ap->flag &= ~GCTL_PARAM_ASCII;
491                         ap->len = len;
492                 } else if (len < 0) {
493                         ap->flag |= GCTL_PARAM_ASCII;
494                         ap->len = strlen(value) + 1;
495                 }
496                 return (0);
497         }
498         return (ENOENT);
499 }
500
501 int
502 gctl_delete_param(struct gctl_req *req, const char *name)
503 {
504         struct gctl_req_arg *ap;
505         unsigned int i;
506
507         if (req == NULL || req->error != NULL)
508                 return (EDOOFUS);
509
510         i = 0;
511         while (i < req->narg) {
512                 ap = &req->arg[i];
513                 if (strcmp(ap->name, name) == 0)
514                         break;
515                 i++;
516         }
517         if (i == req->narg)
518                 return (ENOENT);
519
520         free(ap->name);
521         req->narg--;
522         while (i < req->narg) {
523                 req->arg[i] = req->arg[i + 1];
524                 i++;
525         }
526         return (0);
527 }
528
529 int
530 gctl_has_param(struct gctl_req *req, const char *name)
531 {
532         struct gctl_req_arg *ap;
533         unsigned int i;
534
535         if (req == NULL || req->error != NULL)
536                 return (0);
537
538         for (i = 0; i < req->narg; i++) {
539                 ap = &req->arg[i];
540                 if (strcmp(ap->name, name) == 0)
541                         return (1);
542         }
543         return (0);
544 }