]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sbin/geom/misc/subr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 int
275 g_metadata_store(const char *name, const unsigned char *md, size_t size)
276 {
277         unsigned char *sector;
278         ssize_t sectorsize;
279         off_t mediasize;
280         int error, fd;
281
282         sector = NULL;
283         error = 0;
284
285         fd = g_open(name, 1);
286         if (fd == -1)
287                 return (errno);
288         mediasize = g_mediasize(fd);
289         if (mediasize == -1) {
290                 error = errno;
291                 goto out;
292         }
293         sectorsize = g_sectorsize(fd);
294         if (sectorsize == -1) {
295                 error = errno;
296                 goto out;
297         }
298         assert(sectorsize >= (ssize_t)size);
299         sector = malloc(sectorsize);
300         if (sector == NULL) {
301                 error = ENOMEM;
302                 goto out;
303         }
304         bcopy(md, sector, size);
305         if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
306             sectorsize) {
307                 error = errno;
308                 goto out;
309         }
310         (void)g_flush(fd);
311 out:
312         if (sector != NULL)
313                 free(sector);
314         (void)g_close(fd);
315         return (error);
316 }
317
318 int
319 g_metadata_clear(const char *name, const char *magic)
320 {
321         struct std_metadata md;
322         unsigned char *sector;
323         ssize_t sectorsize;
324         off_t mediasize;
325         int error, fd;
326
327         sector = NULL;
328         error = 0;
329
330         fd = g_open(name, 1);
331         if (fd == -1)
332                 return (errno);
333         mediasize = g_mediasize(fd);
334         if (mediasize == 0) {
335                 error = errno;
336                 goto out;
337         }
338         sectorsize = g_sectorsize(fd);
339         if (sectorsize == 0) {
340                 error = errno;
341                 goto out;
342         }
343         sector = malloc(sectorsize);
344         if (sector == NULL) {
345                 error = ENOMEM;
346                 goto out;
347         }
348         if (magic != NULL) {
349                 if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
350                     sectorsize) {
351                         error = errno;
352                         goto out;
353                 }
354                 std_metadata_decode(sector, &md);
355                 if (strcmp(md.md_magic, magic) != 0) {
356                         error = EINVAL;
357                         goto out;
358                 }
359         }
360         bzero(sector, sectorsize);
361         if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
362             sectorsize) {
363                 error = errno;
364                 goto out;
365         }
366         (void)g_flush(fd);
367 out:
368         if (sector != NULL)
369                 free(sector);
370         g_close(fd);
371         return (error);
372 }
373
374 /*
375  * Set an error message, if one does not already exist.
376  */
377 void
378 gctl_error(struct gctl_req *req, const char *error, ...)
379 {
380         va_list ap;
381
382         if (req->error != NULL)
383                 return;
384         va_start(ap, error);
385         vasprintf(&req->error, error, ap);
386         va_end(ap);
387 }
388
389 static void *
390 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
391 {
392         struct gctl_req_arg *argp;
393         char param[256];
394         unsigned int i;
395         void *p;
396
397         vsnprintf(param, sizeof(param), pfmt, ap);
398         for (i = 0; i < req->narg; i++) {
399                 argp = &req->arg[i];
400                 if (strcmp(param, argp->name))
401                         continue;
402                 if (!(argp->flag & GCTL_PARAM_RD))
403                         continue;
404                 p = argp->value;
405                 if (len == 0) {
406                         /* We are looking for a string. */
407                         if (argp->len < 1) {
408                                 fprintf(stderr, "No length argument (%s).\n",
409                                     param);
410                                 abort();
411                         }
412                         if (((char *)p)[argp->len - 1] != '\0') {
413                                 fprintf(stderr, "Unterminated argument (%s).\n",
414                                     param);
415                                 abort();
416                         }
417                 } else if ((int)len != argp->len) {
418                         fprintf(stderr, "Wrong length %s argument.\n", param);
419                         abort();
420                 }
421                 return (p);
422         }
423         fprintf(stderr, "No such argument (%s).\n", param);
424         abort();
425 }
426
427 int
428 gctl_get_int(struct gctl_req *req, const char *pfmt, ...)
429 {
430         int *p;
431         va_list ap;
432
433         va_start(ap, pfmt);
434         p = gctl_get_param(req, sizeof(int), pfmt, ap);
435         va_end(ap);
436         return (*p);
437 }
438
439 intmax_t
440 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
441 {
442         intmax_t *p;
443         va_list ap;
444
445         va_start(ap, pfmt);
446         p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
447         va_end(ap);
448         return (*p);
449 }
450
451 const char *
452 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
453 {
454         const char *p;
455         va_list ap;
456
457         va_start(ap, pfmt);
458         p = gctl_get_param(req, 0, pfmt, ap);
459         va_end(ap);
460         return (p);
461 }
462
463 int
464 gctl_change_param(struct gctl_req *req, const char *name, int len,
465     const void *value)
466 {
467         struct gctl_req_arg *ap;
468         unsigned int i;
469
470         if (req == NULL || req->error != NULL)
471                 return (EDOOFUS);
472         for (i = 0; i < req->narg; i++) {
473                 ap = &req->arg[i];
474                 if (strcmp(ap->name, name) != 0)
475                         continue;
476                 ap->value = __DECONST(void *, value);
477                 if (len >= 0) {
478                         ap->flag &= ~GCTL_PARAM_ASCII;
479                         ap->len = len;
480                 } else if (len < 0) {
481                         ap->flag |= GCTL_PARAM_ASCII;
482                         ap->len = strlen(value) + 1;
483                 }
484                 return (0);
485         }
486         return (ENOENT);
487 }
488
489 int
490 gctl_delete_param(struct gctl_req *req, const char *name)
491 {
492         struct gctl_req_arg *ap;
493         unsigned int i;
494
495         if (req == NULL || req->error != NULL)
496                 return (EDOOFUS);
497
498         i = 0;
499         while (i < req->narg) {
500                 ap = &req->arg[i];
501                 if (strcmp(ap->name, name) == 0)
502                         break;
503                 i++;
504         }
505         if (i == req->narg)
506                 return (ENOENT);
507
508         free(ap->name);
509         req->narg--;
510         while (i < req->narg) {
511                 req->arg[i] = req->arg[i + 1];
512                 i++;
513         }
514         return (0);
515 }
516
517 int
518 gctl_has_param(struct gctl_req *req, const char *name)
519 {
520         struct gctl_req_arg *ap;
521         unsigned int i;
522
523         if (req == NULL || req->error != NULL)
524                 return (0);
525
526         for (i = 0; i < req->narg; i++) {
527                 ap = &req->arg[i];
528                 if (strcmp(ap->name, name) == 0)
529                         return (1);
530         }
531         return (0);
532 }