2 * Copyright (c) 2004 Lukas Ertl
3 * Copyright (c) 1997, 1998, 1999
4 * Nan Yang Computer Services Limited. All rights reserved.
6 * Parts written by Greg Lehey
8 * This software is distributed under the so-called ``Berkeley
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Nan Yang Computer
23 * 4. Neither the name of the Company nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * This software is provided ``as is'', and any express or implied
28 * warranties, including, but not limited to, the implied warranties of
29 * merchantability and fitness for a particular purpose are disclaimed.
30 * In no event shall the company or contributors be liable for any
31 * direct, indirect, incidental, special, exemplary, or consequential
32 * damages (including, but not limited to, procurement of substitute
33 * goods or services; loss of use, data, or profits; or business
34 * interruption) however caused and on any theory of liability, whether
35 * in contract, strict liability, or tort (including negligence or
36 * otherwise) arising in any way out of the use of this software, even if
37 * advised of the possibility of such damage.
41 /* This file is shared between kernel and userland. */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
46 #include <sys/param.h>
50 #include <sys/kernel.h>
51 #include <sys/kthread.h>
52 #include <sys/malloc.h>
53 #include <sys/systm.h>
55 #include <geom/geom.h>
56 #define iswhite(c) (((c) == ' ') || ((c) == '\t'))
62 #define iswhite isspace
67 #include <sys/mutex.h>
68 #include <sys/queue.h>
70 #include <geom/vinum/geom_vinum_var.h>
71 #include <geom/vinum/geom_vinum_share.h>
74 * Take a blank separated list of tokens and turn it into a list of
75 * individual nul-delimited strings. Build a list of pointers at
76 * token, which must have enough space for the tokens. Return the
77 * number of tokens, or -1 on error (typically a missing string
81 gv_tokenize(char *cptr, char *token[], int maxtoken)
83 int tokennr; /* Index of this token. */
84 char delim; /* Delimiter for searching for the partner. */
86 for (tokennr = 0; tokennr < maxtoken;) {
88 /* Skip leading white space. */
89 while (iswhite(*cptr))
93 if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#'))
97 token[tokennr] = cptr; /* Point to it. */
98 tokennr++; /* One more. */
100 /* Run off the end? */
101 if (tokennr == maxtoken)
105 if ((delim == '\'') || (delim == '"')) {
109 /* Found the partner. */
110 if ((*cptr == delim) && (cptr[-1] != '\\')) {
113 /* Space after closing quote needed. */
121 } else if ((*cptr == '\0') || (*cptr == '\n'))
127 while ((*cptr != '\0') &&
132 /* Not end-of-line; delimit and move to the next. */
138 /* Can't get here. */
144 * Take a number with an optional scale factor and convert it to a number of
147 * The scale factors are:
149 * s sectors (of 512 bytes)
150 * b blocks (of 512 bytes). This unit is deprecated, because it's
151 * confusing, but maintained to avoid confusing Veritas users.
152 * k kilobytes (1024 bytes)
153 * m megabytes (of 1024 * 1024 bytes)
154 * g gigabytes (of 1024 * 1024 * 1024 bytes)
156 * XXX: need a way to signal error
159 gv_sizespec(char *spec)
167 if (spec != NULL) { /* we have a parameter */
169 if (*s == '-') { /* negative, */
175 if ((*s >= '0') && (*s <= '9')) {
178 while ((*s >= '0') && (*s <= '9'))
180 size = size * 10 + *s++ - '0';
190 return size * sign * 512;
194 return size * sign * 1024;
198 return size * sign * 1024 * 1024;
202 return size * sign * 1024 * 1024 * 1024;
211 gv_drivestate(int state)
224 gv_drivestatei(char *buf)
226 if (!strcmp(buf, "up"))
227 return (GV_DRIVE_UP);
229 return (GV_DRIVE_DOWN);
232 /* Translate from a string to a subdisk state. */
234 gv_sdstatei(char *buf)
236 if (!strcmp(buf, "up"))
238 else if (!strcmp(buf, "reviving"))
239 return (GV_SD_REVIVING);
240 else if (!strcmp(buf, "stale"))
241 return (GV_SD_STALE);
246 /* Translate from a subdisk state to a string. */
248 gv_sdstate(int state)
251 case GV_SD_INITIALIZING:
252 return "initializing";
266 /* Translate from a string to a plex state. */
268 gv_plexstatei(char *buf)
270 if (!strcmp(buf, "up"))
272 else if (!strcmp(buf, "initializing"))
273 return (GV_PLEX_INITIALIZING);
274 else if (!strcmp(buf, "degraded"))
275 return (GV_PLEX_DEGRADED);
277 return (GV_PLEX_DOWN);
280 /* Translate from a plex state to a string. */
282 gv_plexstate(int state)
287 case GV_PLEX_INITIALIZING:
288 return "initializing";
289 case GV_PLEX_DEGRADED:
298 /* Translate from a string to a plex organization. */
300 gv_plexorgi(char *buf)
302 if (!strcmp(buf, "concat"))
303 return (GV_PLEX_CONCAT);
304 else if (!strcmp(buf, "striped"))
305 return (GV_PLEX_STRIPED);
306 else if (!strcmp(buf, "raid5"))
307 return (GV_PLEX_RAID5);
309 return (GV_PLEX_DISORG);
313 gv_volstatei(char *buf)
315 if (!strcmp(buf, "up"))
318 return (GV_VOL_DOWN);
322 gv_volstate(int state)
334 /* Translate from a plex organization to a string. */
343 case GV_PLEX_STRIPED:
353 gv_plexorg_short(int org)
360 case GV_PLEX_STRIPED:
369 /* Get a new drive object. */
371 gv_new_drive(int max, char *token[])
377 if (token[1] == NULL || *token[1] == '\0')
381 d = g_malloc(sizeof(struct gv_drive), M_WAITOK | M_ZERO);
384 d = malloc(sizeof(struct gv_drive));
387 bzero(d, sizeof(struct gv_drive));
391 for (j = 1; j < max; j++) {
392 if (!strcmp(token[j], "state")) {
398 d->state = gv_drivestatei(token[j]);
399 } else if (!strcmp(token[j], "device")) {
407 if (strncmp(ptr, "/dev/", 5) == 0)
409 strncpy(d->device, ptr, GV_MAXDRIVENAME);
411 /* We assume this is the drive name. */
412 strncpy(d->name, token[j], GV_MAXDRIVENAME);
416 if (strlen(d->name) == 0 || strlen(d->device) == 0)
427 /* Get a new volume object. */
429 gv_new_volume(int max, char *token[])
434 if (token[1] == NULL || *token[1] == '\0')
438 v = g_malloc(sizeof(struct gv_volume), M_WAITOK | M_ZERO);
441 v = malloc(sizeof(struct gv_volume));
444 bzero(v, sizeof(struct gv_volume));
448 for (j = 1; j < max; j++) {
449 if (!strcmp(token[j], "state")) {
455 v->state = gv_volstatei(token[j]);
457 /* We assume this is the volume name. */
458 strncpy(v->name, token[j], GV_MAXVOLNAME);
462 if (strlen(v->name) == 0)
473 /* Get a new plex object. */
475 gv_new_plex(int max, char *token[])
480 if (token[1] == NULL || *token[1] == '\0')
484 p = g_malloc(sizeof(struct gv_plex), M_WAITOK | M_ZERO);
486 p = malloc(sizeof(struct gv_plex));
489 bzero(p, sizeof(struct gv_plex));
493 for (j = 1; j < max; j++) {
494 if (!strcmp(token[j], "name")) {
500 strncpy(p->name, token[j], GV_MAXPLEXNAME);
501 } else if (!strcmp(token[j], "org")) {
507 p->org = gv_plexorgi(token[j]);
508 if ((p->org == GV_PLEX_RAID5) ||
509 (p->org == GV_PLEX_STRIPED)) {
515 p->stripesize = gv_sizespec(token[j]);
516 if (p->stripesize == 0) {
521 } else if (!strcmp(token[j], "state")) {
527 p->state = gv_plexstatei(token[j]);
528 } else if (!strcmp(token[j], "vol") ||
529 !strcmp(token[j], "volume")) {
535 strncpy(p->volume, token[j], GV_MAXVOLNAME);
550 /* Get a new subdisk object. */
552 gv_new_sd(int max, char *token[])
557 if (token[1] == NULL || *token[1] == '\0')
561 s = g_malloc(sizeof(struct gv_sd), M_WAITOK | M_ZERO);
563 s = malloc(sizeof(struct gv_sd));
566 bzero(s, sizeof(struct gv_sd));
571 s->drive_offset = -1;
573 for (j = 1; j < max; j++) {
574 if (!strcmp(token[j], "name")) {
580 strncpy(s->name, token[j], GV_MAXSDNAME);
581 } else if (!strcmp(token[j], "drive")) {
587 strncpy(s->drive, token[j], GV_MAXDRIVENAME);
588 } else if (!strcmp(token[j], "plex")) {
594 strncpy(s->plex, token[j], GV_MAXPLEXNAME);
595 } else if (!strcmp(token[j], "state")) {
601 s->state = gv_sdstatei(token[j]);
602 } else if (!strcmp(token[j], "len") ||
603 !strcmp(token[j], "length")) {
609 s->size = gv_sizespec(token[j]);
612 } else if (!strcmp(token[j], "driveoffset")) {
618 s->drive_offset = gv_sizespec(token[j]);
619 if (s->drive_offset != 0 &&
620 s->drive_offset < GV_DATA_START) {
624 } else if (!strcmp(token[j], "plexoffset")) {
630 s->plex_offset = gv_sizespec(token[j]);
631 if (s->plex_offset < 0) {
641 if (strlen(s->drive) == 0)
653 * Take a size in bytes and return a pointer to a string which represents the
654 * size best. If lj is != 0, return left justified, otherwise in a fixed 10
655 * character field suitable for columnar printing.
657 * Note this uses a static string: it's only intended to be used immediately
661 gv_roughlength(off_t bytes, int lj)
663 static char desc[16];
666 if (bytes > (off_t)MEGABYTE * 10000)
667 snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB",
671 else if (bytes > KILOBYTE * 10000)
672 snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB",
676 else if (bytes > 10000)
677 snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB",
682 snprintf(desc, sizeof(desc), lj ? "%jd B" : "%10jd B", bytes);