2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (c) 2004, 2007 Lukas Ertl
5 * Copyright (c) 1997, 1998, 1999
6 * Nan Yang Computer Services Limited. All rights reserved.
8 * Parts written by Greg Lehey
10 * This software is distributed under the so-called ``Berkeley
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by Nan Yang Computer
25 * 4. Neither the name of the Company nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * This software is provided ``as is'', and any express or implied
30 * warranties, including, but not limited to, the implied warranties of
31 * merchantability and fitness for a particular purpose are disclaimed.
32 * In no event shall the company or contributors be liable for any
33 * direct, indirect, incidental, special, exemplary, or consequential
34 * damages (including, but not limited to, procurement of substitute
35 * goods or services; loss of use, data, or profits; or business
36 * interruption) however caused and on any theory of liability, whether
37 * in contract, strict liability, or tort (including negligence or
38 * otherwise) arising in any way out of the use of this software, even if
39 * advised of the possibility of such damage.
43 /* This file is shared between kernel and userland. */
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
48 #include <sys/param.h>
50 #include <sys/malloc.h>
51 #include <sys/systm.h>
53 #include <geom/geom.h>
54 #define iswhite(c) (((c) == ' ') || ((c) == '\t'))
60 #define iswhite isspace
64 #include <sys/mutex.h>
65 #include <sys/queue.h>
67 #include <geom/vinum/geom_vinum_var.h>
68 #include <geom/vinum/geom_vinum_share.h>
71 * Take a blank separated list of tokens and turn it into a list of
72 * individual nul-delimited strings. Build a list of pointers at
73 * token, which must have enough space for the tokens. Return the
74 * number of tokens, or -1 on error (typically a missing string
78 gv_tokenize(char *cptr, char *token[], int maxtoken)
80 int tokennr; /* Index of this token. */
81 char delim; /* Delimiter for searching for the partner. */
83 for (tokennr = 0; tokennr < maxtoken;) {
85 /* Skip leading white space. */
86 while (iswhite(*cptr))
90 if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#'))
94 token[tokennr] = cptr; /* Point to it. */
95 tokennr++; /* One more. */
97 /* Run off the end? */
98 if (tokennr == maxtoken)
102 if ((delim == '\'') || (delim == '"')) {
106 /* Found the partner. */
107 if ((*cptr == delim) && (cptr[-1] != '\\')) {
110 /* Space after closing quote needed. */
118 } else if ((*cptr == '\0') || (*cptr == '\n'))
124 while ((*cptr != '\0') &&
129 /* Not end-of-line; delimit and move to the next. */
135 /* Can't get here. */
141 * Take a number with an optional scale factor and convert it to a number of
144 * The scale factors are:
146 * s sectors (of 512 bytes)
147 * b blocks (of 512 bytes). This unit is deprecated, because it's
148 * confusing, but maintained to avoid confusing Veritas users.
149 * k kilobytes (1024 bytes)
150 * m megabytes (of 1024 * 1024 bytes)
151 * g gigabytes (of 1024 * 1024 * 1024 bytes)
153 * XXX: need a way to signal error
156 gv_sizespec(char *spec)
164 if (spec != NULL) { /* we have a parameter */
166 if (*s == '-') { /* negative, */
172 if ((*s >= '0') && (*s <= '9')) {
175 while ((*s >= '0') && (*s <= '9'))
177 size = size * 10 + *s++ - '0';
187 return size * sign * 512;
191 return size * sign * 1024;
195 return size * sign * 1024 * 1024;
199 return size * sign * 1024 * 1024 * 1024;
208 gv_drivestate(int state)
221 gv_drivestatei(char *buf)
223 if (!strcmp(buf, "up"))
224 return (GV_DRIVE_UP);
226 return (GV_DRIVE_DOWN);
229 /* Translate from a string to a subdisk state. */
231 gv_sdstatei(char *buf)
233 if (!strcmp(buf, "up"))
235 else if (!strcmp(buf, "reviving"))
236 return (GV_SD_REVIVING);
237 else if (!strcmp(buf, "initializing"))
238 return (GV_SD_INITIALIZING);
239 else if (!strcmp(buf, "stale"))
240 return (GV_SD_STALE);
245 /* Translate from a subdisk state to a string. */
247 gv_sdstate(int state)
250 case GV_SD_INITIALIZING:
251 return "initializing";
265 /* Translate from a string to a plex state. */
267 gv_plexstatei(char *buf)
269 if (!strcmp(buf, "up"))
271 else if (!strcmp(buf, "initializing"))
272 return (GV_PLEX_INITIALIZING);
273 else if (!strcmp(buf, "degraded"))
274 return (GV_PLEX_DEGRADED);
275 else if (!strcmp(buf, "growable"))
276 return (GV_PLEX_GROWABLE);
278 return (GV_PLEX_DOWN);
281 /* Translate from a plex state to a string. */
283 gv_plexstate(int state)
288 case GV_PLEX_INITIALIZING:
289 return "initializing";
290 case GV_PLEX_DEGRADED:
292 case GV_PLEX_GROWABLE:
301 /* Translate from a string to a plex organization. */
303 gv_plexorgi(char *buf)
305 if (!strcmp(buf, "concat"))
306 return (GV_PLEX_CONCAT);
307 else if (!strcmp(buf, "striped"))
308 return (GV_PLEX_STRIPED);
309 else if (!strcmp(buf, "raid5"))
310 return (GV_PLEX_RAID5);
312 return (GV_PLEX_DISORG);
316 gv_volstatei(char *buf)
318 if (!strcmp(buf, "up"))
321 return (GV_VOL_DOWN);
325 gv_volstate(int state)
337 /* Translate from a plex organization to a string. */
346 case GV_PLEX_STRIPED:
356 gv_plexorg_short(int org)
363 case GV_PLEX_STRIPED:
378 s = g_malloc(sizeof(struct gv_sd), M_NOWAIT);
380 s = malloc(sizeof(struct gv_sd));
384 bzero(s, sizeof(struct gv_sd));
387 s->drive_offset = -1;
397 d = g_malloc(sizeof(struct gv_drive), M_NOWAIT);
399 d = malloc(sizeof(struct gv_drive));
403 bzero(d, sizeof(struct gv_drive));
408 gv_alloc_volume(void)
413 v = g_malloc(sizeof(struct gv_volume), M_NOWAIT);
415 v = malloc(sizeof(struct gv_volume));
419 bzero(v, sizeof(struct gv_volume));
429 p = g_malloc(sizeof(struct gv_plex), M_NOWAIT);
431 p = malloc(sizeof(struct gv_plex));
435 bzero(p, sizeof(struct gv_plex));
439 /* Get a new drive object. */
441 gv_new_drive(int max, char *token[])
447 if (token[1] == NULL || *token[1] == '\0')
449 d = gv_alloc_drive();
453 for (j = 1; j < max; j++) {
454 if (!strcmp(token[j], "state")) {
460 d->state = gv_drivestatei(token[j]);
461 } else if (!strcmp(token[j], "device")) {
469 if (strncmp(ptr, "/dev/", 5) == 0)
471 strlcpy(d->device, ptr, sizeof(d->device));
473 /* We assume this is the drive name. */
474 strlcpy(d->name, token[j], sizeof(d->name));
478 if (strlen(d->name) == 0 || strlen(d->device) == 0)
489 /* Get a new volume object. */
491 gv_new_volume(int max, char *token[])
496 if (token[1] == NULL || *token[1] == '\0')
499 v = gv_alloc_volume();
504 for (j = 1; j < max; j++) {
505 if (!strcmp(token[j], "state")) {
511 v->state = gv_volstatei(token[j]);
513 /* We assume this is the volume name. */
514 strlcpy(v->name, token[j], sizeof(v->name));
518 if (strlen(v->name) == 0)
529 /* Get a new plex object. */
531 gv_new_plex(int max, char *token[])
536 if (token[1] == NULL || *token[1] == '\0')
544 for (j = 1; j < max; j++) {
545 if (!strcmp(token[j], "name")) {
551 strlcpy(p->name, token[j], sizeof(p->name));
552 } else if (!strcmp(token[j], "org")) {
558 p->org = gv_plexorgi(token[j]);
559 if ((p->org == GV_PLEX_RAID5) ||
560 (p->org == GV_PLEX_STRIPED)) {
566 p->stripesize = gv_sizespec(token[j]);
567 if (p->stripesize == 0) {
572 } else if (!strcmp(token[j], "state")) {
578 p->state = gv_plexstatei(token[j]);
579 } else if (!strcmp(token[j], "vol") ||
580 !strcmp(token[j], "volume")) {
586 strlcpy(p->volume, token[j], sizeof(p->volume));
603 /* Get a new subdisk object. */
605 gv_new_sd(int max, char *token[])
610 if (token[1] == NULL || *token[1] == '\0')
618 for (j = 1; j < max; j++) {
619 if (!strcmp(token[j], "name")) {
625 strlcpy(s->name, token[j], sizeof(s->name));
626 } else if (!strcmp(token[j], "drive")) {
632 strlcpy(s->drive, token[j], sizeof(s->drive));
633 } else if (!strcmp(token[j], "plex")) {
639 strlcpy(s->plex, token[j], sizeof(s->plex));
640 } else if (!strcmp(token[j], "state")) {
646 s->state = gv_sdstatei(token[j]);
647 } else if (!strcmp(token[j], "len") ||
648 !strcmp(token[j], "length")) {
654 s->size = gv_sizespec(token[j]);
657 } else if (!strcmp(token[j], "driveoffset")) {
663 s->drive_offset = gv_sizespec(token[j]);
664 if (s->drive_offset != 0 &&
665 s->drive_offset < GV_DATA_START) {
669 } else if (!strcmp(token[j], "plexoffset")) {
675 s->plex_offset = gv_sizespec(token[j]);
676 if (s->plex_offset < 0) {
686 if (strlen(s->drive) == 0)
698 * Take a size in bytes and return a pointer to a string which represents the
699 * size best. If lj is != 0, return left justified, otherwise in a fixed 10
700 * character field suitable for columnar printing.
702 * Note this uses a static string: it's only intended to be used immediately
706 gv_roughlength(off_t bytes, int lj)
708 static char desc[16];
711 if (bytes > (off_t)MEGABYTE * 10000)
712 snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB",
716 else if (bytes > KILOBYTE * 10000)
717 snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB",
721 else if (bytes > 10000)
722 snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB",
727 snprintf(desc, sizeof(desc), lj ? "%jd B" : "%10jd B", bytes);