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