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