1 /*-
2 * Copyright (c) 2004, 2007 Lukas Ertl
3 * Copyright (c) 1997, 1998, 1999
4 * Nan Yang Computer Services Limited. All rights reserved.
5 *
6 * Parts written by Greg Lehey
7 *
8 * This software is distributed under the so-called ``Berkeley
9 * License'':
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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
22 * Services Limited.
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.
26 *
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.
38 *
39 */
40
41 /* This file is shared between kernel and userland. */
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD: releng/10.0/sys/geom/vinum/geom_vinum_share.c 190881 2009-04-10 08:50:14Z lulf $");
45
46 #include <sys/param.h>
47 #ifdef _KERNEL
48 #include <sys/malloc.h>
49 #include <sys/systm.h>
50
51 #include <geom/geom.h>
52 #define iswhite(c) (((c) == ' ') || ((c) == '\t'))
53 #else
54 #include <ctype.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #define iswhite isspace
59 #define g_free free
60 #endif /* _KERNEL */
61
62 #include <sys/mutex.h>
63 #include <sys/queue.h>
64
65 #include <geom/vinum/geom_vinum_var.h>
66 #include <geom/vinum/geom_vinum_share.h>
67
68 /*
69 * Take a blank separated list of tokens and turn it into a list of
70 * individual nul-delimited strings. Build a list of pointers at
71 * token, which must have enough space for the tokens. Return the
72 * number of tokens, or -1 on error (typically a missing string
73 * delimiter).
74 */
75 int
76 gv_tokenize(char *cptr, char *token[], int maxtoken)
77 {
78 int tokennr; /* Index of this token. */
79 char delim; /* Delimiter for searching for the partner. */
80
81 for (tokennr = 0; tokennr < maxtoken;) {
82
83 /* Skip leading white space. */
84 while (iswhite(*cptr))
85 cptr++;
86
87 /* End of line. */
88 if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#'))
89 return tokennr;
90
91 delim = *cptr;
92 token[tokennr] = cptr; /* Point to it. */
93 tokennr++; /* One more. */
94
95 /* Run off the end? */
96 if (tokennr == maxtoken)
97 return tokennr;
98
99 /* Quoted? */
100 if ((delim == '\'') || (delim == '"')) {
101 for (;;) {
102 cptr++;
103
104 /* Found the partner. */
105 if ((*cptr == delim) && (cptr[-1] != '\\')) {
106 cptr++;
107
108 /* Space after closing quote needed. */
109 if (!iswhite(*cptr))
110 return -1;
111
112 /* Delimit. */
113 *cptr++ = '\0';
114
115 /* End-of-line? */
116 } else if ((*cptr == '\0') || (*cptr == '\n'))
117 return -1;
118 }
119
120 /* Not quoted. */
121 } else {
122 while ((*cptr != '\0') &&
123 (!iswhite(*cptr)) &&
124 (*cptr != '\n'))
125 cptr++;
126
127 /* Not end-of-line; delimit and move to the next. */
128 if (*cptr != '\0')
129 *cptr++ = '\0';
130 }
131 }
132
133 /* Can't get here. */
134 return maxtoken;
135 }
136
137
138 /*
139 * Take a number with an optional scale factor and convert it to a number of
140 * bytes.
141 *
142 * The scale factors are:
143 *
144 * s sectors (of 512 bytes)
145 * b blocks (of 512 bytes). This unit is deprecated, because it's
146 * confusing, but maintained to avoid confusing Veritas users.
147 * k kilobytes (1024 bytes)
148 * m megabytes (of 1024 * 1024 bytes)
149 * g gigabytes (of 1024 * 1024 * 1024 bytes)
150 *
151 * XXX: need a way to signal error
152 */
153 off_t
154 gv_sizespec(char *spec)
155 {
156 uint64_t size;
157 char *s;
158 int sign;
159
160 size = 0;
161 sign = 1;
162 if (spec != NULL) { /* we have a parameter */
163 s = spec;
164 if (*s == '-') { /* negative, */
165 sign = -1;
166 s++; /* skip */
167 }
168
169 /* It's numeric. */
170 if ((*s >= '') && (*s <= '9')) {
171
172 /* It's numeric. */
173 while ((*s >= '') && (*s <= '9'))
174 /* Convert it. */
175 size = size * 10 + *s++ - '';
176
177 switch (*s) {
178 case '\0':
179 return size * sign;
180
181 case 'B':
182 case 'b':
183 case 'S':
184 case 's':
185 return size * sign * 512;
186
187 case 'K':
188 case 'k':
189 return size * sign * 1024;
190
191 case 'M':
192 case 'm':
193 return size * sign * 1024 * 1024;
194
195 case 'G':
196 case 'g':
197 return size * sign * 1024 * 1024 * 1024;
198 }
199 }
200 }
201
202 return (0);
203 }
204
205 const char *
206 gv_drivestate(int state)
207 {
208 switch (state) {
209 case GV_DRIVE_DOWN:
210 return "down";
211 case GV_DRIVE_UP:
212 return "up";
213 default:
214 return "??";
215 }
216 }
217
218 int
219 gv_drivestatei(char *buf)
220 {
221 if (!strcmp(buf, "up"))
222 return (GV_DRIVE_UP);
223 else
224 return (GV_DRIVE_DOWN);
225 }
226
227 /* Translate from a string to a subdisk state. */
228 int
229 gv_sdstatei(char *buf)
230 {
231 if (!strcmp(buf, "up"))
232 return (GV_SD_UP);
233 else if (!strcmp(buf, "reviving"))
234 return (GV_SD_REVIVING);
235 else if (!strcmp(buf, "initializing"))
236 return (GV_SD_INITIALIZING);
237 else if (!strcmp(buf, "stale"))
238 return (GV_SD_STALE);
239 else
240 return (GV_SD_DOWN);
241 }
242
243 /* Translate from a subdisk state to a string. */
244 const char *
245 gv_sdstate(int state)
246 {
247 switch (state) {
248 case GV_SD_INITIALIZING:
249 return "initializing";
250 case GV_SD_STALE:
251 return "stale";
252 case GV_SD_DOWN:
253 return "down";
254 case GV_SD_REVIVING:
255 return "reviving";
256 case GV_SD_UP:
257 return "up";
258 default:
259 return "??";
260 }
261 }
262
263 /* Translate from a string to a plex state. */
264 int
265 gv_plexstatei(char *buf)
266 {
267 if (!strcmp(buf, "up"))
268 return (GV_PLEX_UP);
269 else if (!strcmp(buf, "initializing"))
270 return (GV_PLEX_INITIALIZING);
271 else if (!strcmp(buf, "degraded"))
272 return (GV_PLEX_DEGRADED);
273 else if (!strcmp(buf, "growable"))
274 return (GV_PLEX_GROWABLE);
275 else
276 return (GV_PLEX_DOWN);
277 }
278
279 /* Translate from a plex state to a string. */
280 const char *
281 gv_plexstate(int state)
282 {
283 switch (state) {
284 case GV_PLEX_DOWN:
285 return "down";
286 case GV_PLEX_INITIALIZING:
287 return "initializing";
288 case GV_PLEX_DEGRADED:
289 return "degraded";
290 case GV_PLEX_GROWABLE:
291 return "growable";
292 case GV_PLEX_UP:
293 return "up";
294 default:
295 return "??";
296 }
297 }
298
299 /* Translate from a string to a plex organization. */
300 int
301 gv_plexorgi(char *buf)
302 {
303 if (!strcmp(buf, "concat"))
304 return (GV_PLEX_CONCAT);
305 else if (!strcmp(buf, "striped"))
306 return (GV_PLEX_STRIPED);
307 else if (!strcmp(buf, "raid5"))
308 return (GV_PLEX_RAID5);
309 else
310 return (GV_PLEX_DISORG);
311 }
312
313 int
314 gv_volstatei(char *buf)
315 {
316 if (!strcmp(buf, "up"))
317 return (GV_VOL_UP);
318 else
319 return (GV_VOL_DOWN);
320 }
321
322 const char *
323 gv_volstate(int state)
324 {
325 switch (state) {
326 case GV_VOL_UP:
327 return "up";
328 case GV_VOL_DOWN:
329 return "down";
330 default:
331 return "??";
332 }
333 }
334
335 /* Translate from a plex organization to a string. */
336 const char *
337 gv_plexorg(int org)
338 {
339 switch (org) {
340 case GV_PLEX_DISORG:
341 return "??";
342 case GV_PLEX_CONCAT:
343 return "concat";
344 case GV_PLEX_STRIPED:
345 return "striped";
346 case GV_PLEX_RAID5:
347 return "raid5";
348 default:
349 return "??";
350 }
351 }
352
353 const char *
354 gv_plexorg_short(int org)
355 {
356 switch (org) {
357 case GV_PLEX_DISORG:
358 return "??";
359 case GV_PLEX_CONCAT:
360 return "C";
361 case GV_PLEX_STRIPED:
362 return "S";
363 case GV_PLEX_RAID5:
364 return "R5";
365 default:
366 return "??";
367 }
368 }
369
370 struct gv_sd *
371 gv_alloc_sd(void)
372 {
373 struct gv_sd *s;
374
375 #ifdef _KERNEL
376 s = g_malloc(sizeof(struct gv_sd), M_NOWAIT);
377 #else
378 s = malloc(sizeof(struct gv_sd));
379 #endif
380 if (s == NULL)
381 return (NULL);
382 bzero(s, sizeof(struct gv_sd));
383 s->plex_offset = -1;
384 s->size = -1;
385 s->drive_offset = -1;
386 return (s);
387 }
388
389 struct gv_drive *
390 gv_alloc_drive(void)
391 {
392 struct gv_drive *d;
393
394 #ifdef _KERNEL
395 d = g_malloc(sizeof(struct gv_drive), M_NOWAIT);
396 #else
397 d = malloc(sizeof(struct gv_drive));
398 #endif
399 if (d == NULL)
400 return (NULL);
401 bzero(d, sizeof(struct gv_drive));
402 return (d);
403 }
404
405 struct gv_volume *
406 gv_alloc_volume(void)
407 {
408 struct gv_volume *v;
409
410 #ifdef _KERNEL
411 v = g_malloc(sizeof(struct gv_volume), M_NOWAIT);
412 #else
413 v = malloc(sizeof(struct gv_volume));
414 #endif
415 if (v == NULL)
416 return (NULL);
417 bzero(v, sizeof(struct gv_volume));
418 return (v);
419 }
420
421 struct gv_plex *
422 gv_alloc_plex(void)
423 {
424 struct gv_plex *p;
425
426 #ifdef _KERNEL
427 p = g_malloc(sizeof(struct gv_plex), M_NOWAIT);
428 #else
429 p = malloc(sizeof(struct gv_plex));
430 #endif
431 if (p == NULL)
432 return (NULL);
433 bzero(p, sizeof(struct gv_plex));
434 return (p);
435 }
436
437 /* Get a new drive object. */
438 struct gv_drive *
439 gv_new_drive(int max, char *token[])
440 {
441 struct gv_drive *d;
442 int j, errors;
443 char *ptr;
444
445 if (token[1] == NULL || *token[1] == '\0')
446 return (NULL);
447 d = gv_alloc_drive();
448 if (d == NULL)
449 return (NULL);
450 errors = 0;
451 for (j = 1; j < max; j++) {
452 if (!strcmp(token[j], "state")) {
453 j++;
454 if (j >= max) {
455 errors++;
456 break;
457 }
458 d->state = gv_drivestatei(token[j]);
459 } else if (!strcmp(token[j], "device")) {
460 j++;
461 if (j >= max) {
462 errors++;
463 break;
464 }
465 ptr = token[j];
466
467 if (strncmp(ptr, "/dev/", 5) == 0)
468 ptr += 5;
469 strlcpy(d->device, ptr, sizeof(d->device));
470 } else {
471 /* We assume this is the drive name. */
472 strlcpy(d->name, token[j], sizeof(d->name));
473 }
474 }
475
476 if (strlen(d->name) == 0 || strlen(d->device) == 0)
477 errors++;
478
479 if (errors) {
480 g_free(d);
481 return (NULL);
482 }
483
484 return (d);
485 }
486
487 /* Get a new volume object. */
488 struct gv_volume *
489 gv_new_volume(int max, char *token[])
490 {
491 struct gv_volume *v;
492 int j, errors;
493
494 if (token[1] == NULL || *token[1] == '\0')
495 return (NULL);
496
497 v = gv_alloc_volume();
498 if (v == NULL)
499 return (NULL);
500
501 errors = 0;
502 for (j = 1; j < max; j++) {
503 if (!strcmp(token[j], "state")) {
504 j++;
505 if (j >= max) {
506 errors++;
507 break;
508 }
509 v->state = gv_volstatei(token[j]);
510 } else {
511 /* We assume this is the volume name. */
512 strlcpy(v->name, token[j], sizeof(v->name));
513 }
514 }
515
516 if (strlen(v->name) == 0)
517 errors++;
518
519 if (errors) {
520 g_free(v);
521 return (NULL);
522 }
523
524 return (v);
525 }
526
527 /* Get a new plex object. */
528 struct gv_plex *
529 gv_new_plex(int max, char *token[])
530 {
531 struct gv_plex *p;
532 int j, errors;
533
534 if (token[1] == NULL || *token[1] == '\0')
535 return (NULL);
536
537 p = gv_alloc_plex();
538 if (p == NULL)
539 return (NULL);
540
541 errors = 0;
542 for (j = 1; j < max; j++) {
543 if (!strcmp(token[j], "name")) {
544 j++;
545 if (j >= max) {
546 errors++;
547 break;
548 }
549 strlcpy(p->name, token[j], sizeof(p->name));
550 } else if (!strcmp(token[j], "org")) {
551 j++;
552 if (j >= max) {
553 errors++;
554 break;
555 }
556 p->org = gv_plexorgi(token[j]);
557 if ((p->org == GV_PLEX_RAID5) ||
558 (p->org == GV_PLEX_STRIPED)) {
559 j++;
560 if (j >= max) {
561 errors++;
562 break;
563 }
564 p->stripesize = gv_sizespec(token[j]);
565 if (p->stripesize == 0) {
566 errors++;
567 break;
568 }
569 }
570 } else if (!strcmp(token[j], "state")) {
571 j++;
572 if (j >= max) {
573 errors++;
574 break;
575 }
576 p->state = gv_plexstatei(token[j]);
577 } else if (!strcmp(token[j], "vol") ||
578 !strcmp(token[j], "volume")) {
579 j++;
580 if (j >= max) {
581 errors++;
582 break;
583 }
584 strlcpy(p->volume, token[j], sizeof(p->volume));
585 } else {
586 errors++;
587 break;
588 }
589 }
590
591 if (errors) {
592 g_free(p);
593 return (NULL);
594 }
595
596 return (p);
597 }
598
599
600
601 /* Get a new subdisk object. */
602 struct gv_sd *
603 gv_new_sd(int max, char *token[])
604 {
605 struct gv_sd *s;
606 int j, errors;
607
608 if (token[1] == NULL || *token[1] == '\0')
609 return (NULL);
610
611 s = gv_alloc_sd();
612 if (s == NULL)
613 return (NULL);
614
615 errors = 0;
616 for (j = 1; j < max; j++) {
617 if (!strcmp(token[j], "name")) {
618 j++;
619 if (j >= max) {
620 errors++;
621 break;
622 }
623 strlcpy(s->name, token[j], sizeof(s->name));
624 } else if (!strcmp(token[j], "drive")) {
625 j++;
626 if (j >= max) {
627 errors++;
628 break;
629 }
630 strlcpy(s->drive, token[j], sizeof(s->drive));
631 } else if (!strcmp(token[j], "plex")) {
632 j++;
633 if (j >= max) {
634 errors++;
635 break;
636 }
637 strlcpy(s->plex, token[j], sizeof(s->plex));
638 } else if (!strcmp(token[j], "state")) {
639 j++;
640 if (j >= max) {
641 errors++;
642 break;
643 }
644 s->state = gv_sdstatei(token[j]);
645 } else if (!strcmp(token[j], "len") ||
646 !strcmp(token[j], "length")) {
647 j++;
648 if (j >= max) {
649 errors++;
650 break;
651 }
652 s->size = gv_sizespec(token[j]);
653 if (s->size <= 0)
654 s->size = -1;
655 } else if (!strcmp(token[j], "driveoffset")) {
656 j++;
657 if (j >= max) {
658 errors++;
659 break;
660 }
661 s->drive_offset = gv_sizespec(token[j]);
662 if (s->drive_offset != 0 &&
663 s->drive_offset < GV_DATA_START) {
664 errors++;
665 break;
666 }
667 } else if (!strcmp(token[j], "plexoffset")) {
668 j++;
669 if (j >= max) {
670 errors++;
671 break;
672 }
673 s->plex_offset = gv_sizespec(token[j]);
674 if (s->plex_offset < 0) {
675 errors++;
676 break;
677 }
678 } else {
679 errors++;
680 break;
681 }
682 }
683
684 if (strlen(s->drive) == 0)
685 errors++;
686
687 if (errors) {
688 g_free(s);
689 return (NULL);
690 }
691
692 return (s);
693 }
694
695 /*
696 * Take a size in bytes and return a pointer to a string which represents the
697 * size best. If lj is != 0, return left justified, otherwise in a fixed 10
698 * character field suitable for columnar printing.
699 *
700 * Note this uses a static string: it's only intended to be used immediately
701 * for printing.
702 */
703 const char *
704 gv_roughlength(off_t bytes, int lj)
705 {
706 static char desc[16];
707
708 /* Gigabytes. */
709 if (bytes > (off_t)MEGABYTE * 10000)
710 snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB",
711 bytes / GIGABYTE);
712
713 /* Megabytes. */
714 else if (bytes > KILOBYTE * 10000)
715 snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB",
716 bytes / MEGABYTE);
717
718 /* Kilobytes. */
719 else if (bytes > 10000)
720 snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB",
721 bytes / KILOBYTE);
722
723 /* Bytes. */
724 else
725 snprintf(desc, sizeof(desc), lj ? "%jd B" : "%10jd B", bytes);
726
727 return (desc);
728 }
Cache object: 88720835495a92152428f8a1fa22dc4c
|