]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/vinum/geom_vinum_share.c
contrib/tzdata: import tzdata 2023a
[FreeBSD/FreeBSD.git] / sys / geom / vinum / geom_vinum_share.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2004, 2007 Lukas Ertl
5  * Copyright (c) 1997, 1998, 1999
6  *      Nan Yang Computer Services Limited.  All rights reserved.
7  *
8  *  Parts written by Greg Lehey
9  *
10  *  This software is distributed under the so-called ``Berkeley
11  *  License'':
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
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
24  *      Services Limited.
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.
28  *
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.
40  *
41  */
42
43 /* This file is shared between kernel and userland. */
44
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47
48 #include <sys/param.h>
49 #ifdef _KERNEL
50 #include <sys/malloc.h>
51 #include <sys/systm.h>
52
53 #include <geom/geom.h>
54 #define iswhite(c) (((c) == ' ') || ((c) == '\t'))
55 #else
56 #include <ctype.h>
57 #include <paths.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #define iswhite isspace
62 #define g_free  free
63 #endif /* _KERNEL */
64
65 #include <sys/mutex.h>
66 #include <sys/queue.h>
67
68 #include <geom/vinum/geom_vinum_var.h>
69 #include <geom/vinum/geom_vinum_share.h>
70
71 /*
72  * Take a blank separated list of tokens and turn it into a list of
73  * individual nul-delimited strings.  Build a list of pointers at
74  * token, which must have enough space for the tokens.  Return the
75  * number of tokens, or -1 on error (typically a missing string
76  * delimiter).
77  */
78 int
79 gv_tokenize(char *cptr, char *token[], int maxtoken)
80 {
81         int tokennr;    /* Index of this token. */
82         char delim;     /* Delimiter for searching for the partner. */
83
84         for (tokennr = 0; tokennr < maxtoken;) {
85                 /* Skip leading white space. */
86                 while (iswhite(*cptr))
87                         cptr++;
88
89                 /* End of line. */
90                 if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#'))
91                         return tokennr;
92
93                 delim = *cptr;
94                 token[tokennr] = cptr;          /* Point to it. */
95                 tokennr++;                      /* One more. */
96
97                 /* Run off the end? */
98                 if (tokennr == maxtoken)
99                         return tokennr;
100
101                 /* Quoted? */
102                 if ((delim == '\'') || (delim == '"')) {
103                         for (;;) {
104                                 cptr++;
105
106                                 /* Found the partner. */
107                                 if ((*cptr == delim) && (cptr[-1] != '\\')) {
108                                         cptr++;
109
110                                         /* Space after closing quote needed. */
111                                         if (!iswhite(*cptr))
112                                                 return -1;
113
114                                         /* Delimit. */
115                                         *cptr++ = '\0';
116
117                                 /* End-of-line? */
118                                 } else if ((*cptr == '\0') || (*cptr == '\n'))
119                                         return -1;
120                         }
121
122                 /* Not quoted. */
123                 } else {
124                         while ((*cptr != '\0') &&
125                             (!iswhite(*cptr)) &&
126                             (*cptr != '\n'))
127                                 cptr++;
128
129                         /* Not end-of-line; delimit and move to the next. */
130                         if (*cptr != '\0')
131                                 *cptr++ = '\0';
132                 }
133         }
134
135         /* Can't get here. */
136         return maxtoken;
137 }
138
139 /*
140  * Take a number with an optional scale factor and convert it to a number of
141  * bytes.
142  *
143  * The scale factors are:
144  *
145  * s    sectors (of 512 bytes)
146  * b    blocks (of 512 bytes).  This unit is deprecated, because it's
147  *      confusing, but maintained to avoid confusing Veritas users.
148  * k    kilobytes (1024 bytes)
149  * m    megabytes (of 1024 * 1024 bytes)
150  * g    gigabytes (of 1024 * 1024 * 1024 bytes)
151  *
152  * XXX: need a way to signal error
153  */
154 off_t
155 gv_sizespec(char *spec)
156 {
157         uint64_t size;
158         char *s;
159         int sign;
160
161         size = 0;
162         sign = 1;
163         if (spec != NULL) {             /* we have a parameter */
164                 s = spec;
165                 if (*s == '-') {        /* negative, */
166                         sign = -1;
167                         s++;            /* skip */
168                 }
169
170                 /* It's numeric. */
171                 if ((*s >= '0') && (*s <= '9')) {
172                         /* It's numeric. */
173                         while ((*s >= '0') && (*s <= '9'))
174                                 /* Convert it. */
175                                 size = size * 10 + *s++ - '0';
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, _PATH_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 /* Get a new subdisk object. */
600 struct gv_sd *
601 gv_new_sd(int max, char *token[])
602 {
603         struct gv_sd *s;
604         int j, errors;
605
606         if (token[1] == NULL || *token[1] == '\0')
607                 return (NULL);
608
609         s = gv_alloc_sd();
610         if (s == NULL)
611                 return (NULL);
612
613         errors = 0;
614         for (j = 1; j < max; j++) {
615                 if (!strcmp(token[j], "name")) {
616                         j++;
617                         if (j >= max) {
618                                 errors++;
619                                 break;
620                         }
621                         strlcpy(s->name, token[j], sizeof(s->name));
622                 } else if (!strcmp(token[j], "drive")) {
623                         j++;
624                         if (j >= max) {
625                                 errors++;
626                                 break;
627                         }
628                         strlcpy(s->drive, token[j], sizeof(s->drive));
629                 } else if (!strcmp(token[j], "plex")) {
630                         j++;
631                         if (j >= max) {
632                                 errors++;
633                                 break;
634                         }
635                         strlcpy(s->plex, token[j], sizeof(s->plex));
636                 } else if (!strcmp(token[j], "state")) {
637                         j++;
638                         if (j >= max) {
639                                 errors++;
640                                 break;
641                         }
642                         s->state = gv_sdstatei(token[j]);
643                 } else if (!strcmp(token[j], "len") ||
644                     !strcmp(token[j], "length")) {
645                         j++;
646                         if (j >= max) {
647                                 errors++;
648                                 break;
649                         }
650                         s->size = gv_sizespec(token[j]);
651                         if (s->size <= 0)
652                                 s->size = -1;
653                 } else if (!strcmp(token[j], "driveoffset")) {
654                         j++;
655                         if (j >= max) {
656                                 errors++;
657                                 break;
658                         }
659                         s->drive_offset = gv_sizespec(token[j]);
660                         if (s->drive_offset != 0 &&
661                             s->drive_offset < GV_DATA_START) {
662                                 errors++;
663                                 break;
664                         }
665                 } else if (!strcmp(token[j], "plexoffset")) {
666                         j++;
667                         if (j >= max) {
668                                 errors++;
669                                 break;
670                         }
671                         s->plex_offset = gv_sizespec(token[j]);
672                         if (s->plex_offset < 0) {
673                                 errors++;
674                                 break;
675                         }
676                 } else {
677                         errors++;
678                         break;
679                 }
680         }
681
682         if (strlen(s->drive) == 0)
683                 errors++;
684
685         if (errors) {
686                 g_free(s);
687                 return (NULL);
688         }
689
690         return (s);
691 }
692
693 /*
694  * Take a size in bytes and return a pointer to a string which represents the
695  * size best.  If lj is != 0, return left justified, otherwise in a fixed 10
696  * character field suitable for columnar printing.
697  *
698  * Note this uses a static string: it's only intended to be used immediately
699  * for printing.
700  */
701 const char *
702 gv_roughlength(off_t bytes, int lj)
703 {
704         static char desc[16];
705
706         /* Gigabytes. */
707         if (bytes > (off_t)MEGABYTE * 10000)
708                 snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB",
709                     bytes / GIGABYTE);
710
711         /* Megabytes. */
712         else if (bytes > KILOBYTE * 10000)
713                 snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB",
714                     bytes / MEGABYTE);
715
716         /* Kilobytes. */
717         else if (bytes > 10000)
718                 snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB",
719                     bytes / KILOBYTE);
720
721         /* Bytes. */
722         else
723                 snprintf(desc, sizeof(desc), lj ? "%jd  B" : "%10jd  B", bytes);
724
725         return (desc);
726 }