]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sbin/geom/misc/subr.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 <stdarg.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <unistd.h>
43 #include <assert.h>
44 #include <libgeom.h>
45
46 #include "misc/subr.h"
47
48
49 struct std_metadata {
50         char            md_magic[16];
51         uint32_t        md_version;
52 };
53
54 static void
55 std_metadata_decode(const u_char *data, struct std_metadata *md)
56 {
57
58         bcopy(data, md->md_magic, sizeof(md->md_magic));
59         md->md_version = le32dec(data + 16);
60 }
61
62 static void
63 pathgen(const char *name, char *path, size_t size)
64 {
65
66         if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
67                 snprintf(path, size, "%s%s", _PATH_DEV, name);
68         else
69                 strlcpy(path, name, size);
70 }
71
72 /*
73  * Greatest Common Divisor.
74  */
75 static unsigned
76 gcd(unsigned a, unsigned b)
77 {
78         u_int c;
79
80         while (b != 0) {
81                 c = a;
82                 a = b;
83                 b = (c % b);
84         }
85         return (a);
86 }
87
88 /*
89  * Least Common Multiple.
90  */
91 unsigned
92 g_lcm(unsigned a, unsigned b)
93 {
94
95         return ((a * b) / gcd(a, b));
96 }
97
98 uint32_t
99 bitcount32(uint32_t x)
100 {
101
102         x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
103         x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
104         x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4);
105         x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8);
106         x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16);
107         return (x);
108 }
109
110 off_t
111 g_get_mediasize(const char *name)
112 {
113         char path[MAXPATHLEN];
114         off_t mediasize;
115         int fd;
116
117         pathgen(name, path, sizeof(path));
118         fd = open(path, O_RDONLY);
119         if (fd == -1)
120                 return (0);
121         if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
122                 close(fd);
123                 return (0);
124         }
125         close(fd);
126         return (mediasize);
127 }
128
129 unsigned
130 g_get_sectorsize(const char *name)
131 {
132         char path[MAXPATHLEN];
133         unsigned sectorsize;
134         int fd;
135
136         pathgen(name, path, sizeof(path));
137         fd = open(path, O_RDONLY);
138         if (fd == -1)
139                 return (0);
140         if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
141                 close(fd);
142                 return (0);
143         }
144         close(fd);
145         return (sectorsize);
146 }
147
148 int
149 g_metadata_read(const char *name, u_char *md, size_t size, const char *magic)
150 {
151         struct std_metadata stdmd;
152         char path[MAXPATHLEN];
153         unsigned sectorsize;
154         off_t mediasize;
155         u_char *sector;
156         int error, fd;
157
158         pathgen(name, path, sizeof(path));
159         sector = NULL;
160         error = 0;
161
162         fd = open(path, O_RDONLY);
163         if (fd == -1)
164                 return (errno);
165         mediasize = g_get_mediasize(name);
166         if (mediasize == 0) {
167                 error = errno;
168                 goto out;
169         }
170         sectorsize = g_get_sectorsize(name);
171         if (sectorsize == 0) {
172                 error = errno;
173                 goto out;
174         }
175         assert(sectorsize >= size);
176         sector = malloc(sectorsize);
177         if (sector == NULL) {
178                 error = ENOMEM;
179                 goto out;
180         }
181         if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
182             (ssize_t)sectorsize) {
183                 error = errno;
184                 goto out;
185         }
186         if (magic != NULL) {
187                 std_metadata_decode(sector, &stdmd);
188                 if (strcmp(stdmd.md_magic, magic) != 0) {
189                         error = EINVAL;
190                         goto out;
191                 }
192         }
193         bcopy(sector, md, size);
194 out:
195         if (sector != NULL)
196                 free(sector);
197         close(fd);
198         return (error);
199 }
200
201 int
202 g_metadata_store(const char *name, u_char *md, size_t size)
203 {
204         char path[MAXPATHLEN];
205         unsigned sectorsize;
206         off_t mediasize;
207         u_char *sector;
208         int error, fd;
209
210         pathgen(name, path, sizeof(path));
211         sector = NULL;
212         error = 0;
213
214         fd = open(path, O_WRONLY);
215         if (fd == -1)
216                 return (errno);
217         mediasize = g_get_mediasize(name);
218         if (mediasize == 0) {
219                 error = errno;
220                 goto out;
221         }
222         sectorsize = g_get_sectorsize(name);
223         if (sectorsize == 0) {
224                 error = errno;
225                 goto out;
226         }
227         assert(sectorsize >= size);
228         sector = malloc(sectorsize);
229         if (sector == NULL) {
230                 error = ENOMEM;
231                 goto out;
232         }
233         bcopy(md, sector, size);
234         if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
235             (ssize_t)sectorsize) {
236                 error = errno;
237                 goto out;
238         }
239         (void)ioctl(fd, DIOCGFLUSH, NULL);
240 out:
241         if (sector != NULL)
242                 free(sector);
243         close(fd);
244         return (error);
245 }
246
247 int
248 g_metadata_clear(const char *name, const char *magic)
249 {
250         struct std_metadata md;
251         char path[MAXPATHLEN];
252         unsigned sectorsize;
253         off_t mediasize;
254         u_char *sector;
255         int error, fd;
256
257         pathgen(name, path, sizeof(path));
258         sector = NULL;
259         error = 0;
260
261         fd = open(path, O_RDWR);
262         if (fd == -1)
263                 return (errno);
264         mediasize = g_get_mediasize(name);
265         if (mediasize == 0) {
266                 error = errno;
267                 goto out;
268         }
269         sectorsize = g_get_sectorsize(name);
270         if (sectorsize == 0) {
271                 error = errno;
272                 goto out;
273         }
274         sector = malloc(sectorsize);
275         if (sector == NULL) {
276                 error = ENOMEM;
277                 goto out;
278         }
279         if (magic != NULL) {
280                 if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
281                     (ssize_t)sectorsize) {
282                         error = errno;
283                         goto out;
284                 }
285                 std_metadata_decode(sector, &md);
286                 if (strcmp(md.md_magic, magic) != 0) {
287                         error = EINVAL;
288                         goto out;
289                 }
290         }
291         bzero(sector, sectorsize);
292         if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
293             (ssize_t)sectorsize) {
294                 error = errno;
295                 goto out;
296         }
297         (void)ioctl(fd, DIOCGFLUSH, NULL);
298 out:
299         if (sector != NULL)
300                 free(sector);
301         close(fd);
302         return (error);
303 }
304
305 /*
306  * Set an error message, if one does not already exist.
307  */
308 void
309 gctl_error(struct gctl_req *req, const char *error, ...)
310 {
311         va_list ap;
312
313         if (req->error != NULL)
314                 return;
315         va_start(ap, error);
316         vasprintf(&req->error, error, ap);
317         va_end(ap);
318 }
319
320 static void *
321 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
322 {
323         struct gctl_req_arg *argp;
324         char param[256];
325         void *p;
326         unsigned i;
327
328         vsnprintf(param, sizeof(param), pfmt, ap);
329         for (i = 0; i < req->narg; i++) {
330                 argp = &req->arg[i];
331                 if (strcmp(param, argp->name))
332                         continue;
333                 if (!(argp->flag & GCTL_PARAM_RD))
334                         continue;
335                 p = argp->value;
336                 if (len == 0) {
337                         /* We are looking for a string. */
338                         if (argp->len < 1) {
339                                 fprintf(stderr, "No length argument (%s).\n",
340                                     param);
341                                 abort();
342                         }
343                         if (((char *)p)[argp->len - 1] != '\0') {
344                                 fprintf(stderr, "Unterminated argument (%s).\n",
345                                     param);
346                                 abort();
347                         }
348                 } else if ((int)len != argp->len) {
349                         fprintf(stderr, "Wrong length %s argument.\n", param);
350                         abort();
351                 }
352                 return (p);
353         }
354         fprintf(stderr, "No such argument (%s).\n", param);
355         abort();
356 }
357
358 int
359 gctl_get_int(struct gctl_req *req, const char *pfmt, ...)
360 {
361         int *p;
362         va_list ap;
363
364         va_start(ap, pfmt);
365         p = gctl_get_param(req, sizeof(int), pfmt, ap);
366         va_end(ap);
367         return (*p);
368 }
369
370 intmax_t
371 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
372 {
373         intmax_t *p;
374         va_list ap;
375
376         va_start(ap, pfmt);
377         p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
378         va_end(ap);
379         return (*p);
380 }
381
382 const char *
383 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
384 {
385         const char *p;
386         va_list ap;
387
388         va_start(ap, pfmt);
389         p = gctl_get_param(req, 0, pfmt, ap);
390         va_end(ap);
391         return (p);
392 }
393
394 int
395 gctl_change_param(struct gctl_req *req, const char *name, int len,
396     const void *value)
397 {
398         struct gctl_req_arg *ap;
399         unsigned i;
400
401         if (req == NULL || req->error != NULL)
402                 return (EDOOFUS);
403         for (i = 0; i < req->narg; i++) {
404                 ap = &req->arg[i];
405                 if (strcmp(ap->name, name) != 0)
406                         continue;
407                 ap->value = __DECONST(void *, value);
408                 if (len >= 0) {
409                         ap->flag &= ~GCTL_PARAM_ASCII;
410                         ap->len = len;
411                 } else if (len < 0) {
412                         ap->flag |= GCTL_PARAM_ASCII;
413                         ap->len = strlen(value) + 1;
414                 }
415                 return (0);
416         }
417         return (ENOENT);
418 }
419
420 int
421 gctl_delete_param(struct gctl_req *req, const char *name)
422 {
423         struct gctl_req_arg *ap;
424         unsigned int i;
425
426         if (req == NULL || req->error != NULL)
427                 return (EDOOFUS);
428
429         i = 0;
430         while (i < req->narg) {
431                 ap = &req->arg[i];
432                 if (strcmp(ap->name, name) == 0)
433                         break;
434                 i++;
435         }
436         if (i == req->narg)
437                 return (ENOENT);
438
439         req->narg--;
440         while (i < req->narg) {
441                 req->arg[i] = req->arg[i + 1];
442                 i++;
443         }
444         return (0);
445 }
446
447 int
448 gctl_has_param(struct gctl_req *req, const char *name)
449 {
450         struct gctl_req_arg *ap;
451         unsigned int i;
452
453         if (req == NULL || req->error != NULL)
454                 return (0);
455
456         for (i = 0; i < req->narg; i++) {
457                 ap = &req->arg[i];
458                 if (strcmp(ap->name, name) == 0)
459                         return (1);
460         }
461         return (0);
462 }