1130389Sle/*- 2190507Slulf * Copyright (c) 2004, 2007 Lukas Ertl 3130389Sle * Copyright (c) 1997, 1998, 1999 4130389Sle * Nan Yang Computer Services Limited. All rights reserved. 5130389Sle * 6130389Sle * Parts written by Greg Lehey 7130389Sle * 8130389Sle * This software is distributed under the so-called ``Berkeley 9130389Sle * License'': 10130389Sle * 11130389Sle * Redistribution and use in source and binary forms, with or without 12130389Sle * modification, are permitted provided that the following conditions 13130389Sle * are met: 14130389Sle * 1. Redistributions of source code must retain the above copyright 15130389Sle * notice, this list of conditions and the following disclaimer. 16130389Sle * 2. Redistributions in binary form must reproduce the above copyright 17130389Sle * notice, this list of conditions and the following disclaimer in the 18130389Sle * documentation and/or other materials provided with the distribution. 19130389Sle * 3. All advertising materials mentioning features or use of this software 20130389Sle * must display the following acknowledgement: 21130389Sle * This product includes software developed by Nan Yang Computer 22130389Sle * Services Limited. 23130389Sle * 4. Neither the name of the Company nor the names of its contributors 24130389Sle * may be used to endorse or promote products derived from this software 25130389Sle * without specific prior written permission. 26130389Sle * 27130389Sle * This software is provided ``as is'', and any express or implied 28130389Sle * warranties, including, but not limited to, the implied warranties of 29130389Sle * merchantability and fitness for a particular purpose are disclaimed. 30130389Sle * In no event shall the company or contributors be liable for any 31130389Sle * direct, indirect, incidental, special, exemplary, or consequential 32130389Sle * damages (including, but not limited to, procurement of substitute 33130389Sle * goods or services; loss of use, data, or profits; or business 34130389Sle * interruption) however caused and on any theory of liability, whether 35130389Sle * in contract, strict liability, or tort (including negligence or 36130389Sle * otherwise) arising in any way out of the use of this software, even if 37130389Sle * advised of the possibility of such damage. 38130389Sle * 39130389Sle */ 40130389Sle 41130389Sle/* This file is shared between kernel and userland. */ 42130389Sle 43130389Sle#include <sys/cdefs.h> 44130389Sle__FBSDID("$FreeBSD$"); 45130389Sle 46130389Sle#include <sys/param.h> 47130389Sle#ifdef _KERNEL 48130389Sle#include <sys/malloc.h> 49130389Sle#include <sys/systm.h> 50130389Sle 51130389Sle#include <geom/geom.h> 52130389Sle#define iswhite(c) (((c) == ' ') || ((c) == '\t')) 53130389Sle#else 54130389Sle#include <ctype.h> 55130389Sle#include <stdio.h> 56130389Sle#include <stdlib.h> 57130389Sle#include <string.h> 58130389Sle#define iswhite isspace 59130389Sle#define g_free free 60130389Sle#endif /* _KERNEL */ 61130389Sle 62130389Sle#include <sys/mutex.h> 63130389Sle#include <sys/queue.h> 64130389Sle 65130389Sle#include <geom/vinum/geom_vinum_var.h> 66130389Sle#include <geom/vinum/geom_vinum_share.h> 67130389Sle 68130389Sle/* 69130389Sle * Take a blank separated list of tokens and turn it into a list of 70130389Sle * individual nul-delimited strings. Build a list of pointers at 71130389Sle * token, which must have enough space for the tokens. Return the 72130389Sle * number of tokens, or -1 on error (typically a missing string 73130389Sle * delimiter). 74130389Sle */ 75130389Sleint 76130389Slegv_tokenize(char *cptr, char *token[], int maxtoken) 77130389Sle{ 78130389Sle int tokennr; /* Index of this token. */ 79130389Sle char delim; /* Delimiter for searching for the partner. */ 80130389Sle 81130389Sle for (tokennr = 0; tokennr < maxtoken;) { 82130389Sle 83130389Sle /* Skip leading white space. */ 84130389Sle while (iswhite(*cptr)) 85130389Sle cptr++; 86130389Sle 87130389Sle /* End of line. */ 88130389Sle if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#')) 89130389Sle return tokennr; 90130389Sle 91130389Sle delim = *cptr; 92130389Sle token[tokennr] = cptr; /* Point to it. */ 93130389Sle tokennr++; /* One more. */ 94130389Sle 95130389Sle /* Run off the end? */ 96130389Sle if (tokennr == maxtoken) 97130389Sle return tokennr; 98130389Sle 99130389Sle /* Quoted? */ 100130389Sle if ((delim == '\'') || (delim == '"')) { 101130389Sle for (;;) { 102130389Sle cptr++; 103130389Sle 104130389Sle /* Found the partner. */ 105130389Sle if ((*cptr == delim) && (cptr[-1] != '\\')) { 106130389Sle cptr++; 107130389Sle 108130389Sle /* Space after closing quote needed. */ 109130389Sle if (!iswhite(*cptr)) 110130389Sle return -1; 111130389Sle 112130389Sle /* Delimit. */ 113130389Sle *cptr++ = '\0'; 114130389Sle 115130389Sle /* End-of-line? */ 116130389Sle } else if ((*cptr == '\0') || (*cptr == '\n')) 117130389Sle return -1; 118130389Sle } 119130389Sle 120130389Sle /* Not quoted. */ 121130389Sle } else { 122130389Sle while ((*cptr != '\0') && 123130389Sle (!iswhite(*cptr)) && 124130389Sle (*cptr != '\n')) 125130389Sle cptr++; 126130389Sle 127130389Sle /* Not end-of-line; delimit and move to the next. */ 128130389Sle if (*cptr != '\0') 129130389Sle *cptr++ = '\0'; 130130389Sle } 131130389Sle } 132130389Sle 133130389Sle /* Can't get here. */ 134130389Sle return maxtoken; 135130389Sle} 136130389Sle 137130389Sle 138130389Sle/* 139130389Sle * Take a number with an optional scale factor and convert it to a number of 140130389Sle * bytes. 141130389Sle * 142130389Sle * The scale factors are: 143130389Sle * 144130389Sle * s sectors (of 512 bytes) 145130389Sle * b blocks (of 512 bytes). This unit is deprecated, because it's 146130389Sle * confusing, but maintained to avoid confusing Veritas users. 147130389Sle * k kilobytes (1024 bytes) 148130389Sle * m megabytes (of 1024 * 1024 bytes) 149130389Sle * g gigabytes (of 1024 * 1024 * 1024 bytes) 150130389Sle * 151130389Sle * XXX: need a way to signal error 152130389Sle */ 153130389Sleoff_t 154130389Slegv_sizespec(char *spec) 155130389Sle{ 156130389Sle uint64_t size; 157130389Sle char *s; 158130389Sle int sign; 159130389Sle 160130389Sle size = 0; 161130389Sle sign = 1; 162130389Sle if (spec != NULL) { /* we have a parameter */ 163130389Sle s = spec; 164130389Sle if (*s == '-') { /* negative, */ 165130389Sle sign = -1; 166130389Sle s++; /* skip */ 167130389Sle } 168130389Sle 169130389Sle /* It's numeric. */ 170130389Sle if ((*s >= '0') && (*s <= '9')) { 171130389Sle 172130389Sle /* It's numeric. */ 173130389Sle while ((*s >= '0') && (*s <= '9')) 174130389Sle /* Convert it. */ 175130389Sle size = size * 10 + *s++ - '0'; 176130389Sle 177130389Sle switch (*s) { 178130389Sle case '\0': 179130389Sle return size * sign; 180130389Sle 181130389Sle case 'B': 182130389Sle case 'b': 183130389Sle case 'S': 184130389Sle case 's': 185130389Sle return size * sign * 512; 186130389Sle 187130389Sle case 'K': 188130389Sle case 'k': 189130389Sle return size * sign * 1024; 190130389Sle 191130389Sle case 'M': 192130389Sle case 'm': 193130389Sle return size * sign * 1024 * 1024; 194130389Sle 195130389Sle case 'G': 196130389Sle case 'g': 197130389Sle return size * sign * 1024 * 1024 * 1024; 198130389Sle } 199130389Sle } 200130389Sle } 201130389Sle 202130389Sle return (0); 203130389Sle} 204130389Sle 205130389Sleconst char * 206130389Slegv_drivestate(int state) 207130389Sle{ 208130389Sle switch (state) { 209130389Sle case GV_DRIVE_DOWN: 210130389Sle return "down"; 211130389Sle case GV_DRIVE_UP: 212130389Sle return "up"; 213130389Sle default: 214130389Sle return "??"; 215130389Sle } 216130389Sle} 217130389Sle 218130389Sleint 219130389Slegv_drivestatei(char *buf) 220130389Sle{ 221130389Sle if (!strcmp(buf, "up")) 222130389Sle return (GV_DRIVE_UP); 223130389Sle else 224130389Sle return (GV_DRIVE_DOWN); 225130389Sle} 226130389Sle 227130389Sle/* Translate from a string to a subdisk state. */ 228130389Sleint 229130389Slegv_sdstatei(char *buf) 230130389Sle{ 231130389Sle if (!strcmp(buf, "up")) 232130389Sle return (GV_SD_UP); 233130389Sle else if (!strcmp(buf, "reviving")) 234130389Sle return (GV_SD_REVIVING); 235190507Slulf else if (!strcmp(buf, "initializing")) 236190507Slulf return (GV_SD_INITIALIZING); 237130389Sle else if (!strcmp(buf, "stale")) 238130389Sle return (GV_SD_STALE); 239130389Sle else 240130389Sle return (GV_SD_DOWN); 241130389Sle} 242130389Sle 243130389Sle/* Translate from a subdisk state to a string. */ 244130389Sleconst char * 245130389Slegv_sdstate(int state) 246130389Sle{ 247130389Sle switch (state) { 248130389Sle case GV_SD_INITIALIZING: 249130389Sle return "initializing"; 250130389Sle case GV_SD_STALE: 251130389Sle return "stale"; 252130389Sle case GV_SD_DOWN: 253130389Sle return "down"; 254130389Sle case GV_SD_REVIVING: 255130389Sle return "reviving"; 256130389Sle case GV_SD_UP: 257130389Sle return "up"; 258130389Sle default: 259130389Sle return "??"; 260130389Sle } 261130389Sle} 262130389Sle 263130389Sle/* Translate from a string to a plex state. */ 264130389Sleint 265130389Slegv_plexstatei(char *buf) 266130389Sle{ 267130389Sle if (!strcmp(buf, "up")) 268130389Sle return (GV_PLEX_UP); 269130389Sle else if (!strcmp(buf, "initializing")) 270130389Sle return (GV_PLEX_INITIALIZING); 271130389Sle else if (!strcmp(buf, "degraded")) 272130389Sle return (GV_PLEX_DEGRADED); 273190507Slulf else if (!strcmp(buf, "growable")) 274190507Slulf return (GV_PLEX_GROWABLE); 275130389Sle else 276130389Sle return (GV_PLEX_DOWN); 277130389Sle} 278130389Sle 279130389Sle/* Translate from a plex state to a string. */ 280130389Sleconst char * 281130389Slegv_plexstate(int state) 282130389Sle{ 283130389Sle switch (state) { 284130389Sle case GV_PLEX_DOWN: 285130389Sle return "down"; 286130389Sle case GV_PLEX_INITIALIZING: 287130389Sle return "initializing"; 288130389Sle case GV_PLEX_DEGRADED: 289130389Sle return "degraded"; 290190507Slulf case GV_PLEX_GROWABLE: 291190507Slulf return "growable"; 292130389Sle case GV_PLEX_UP: 293130389Sle return "up"; 294130389Sle default: 295130389Sle return "??"; 296130389Sle } 297130389Sle} 298130389Sle 299130389Sle/* Translate from a string to a plex organization. */ 300130389Sleint 301130389Slegv_plexorgi(char *buf) 302130389Sle{ 303130389Sle if (!strcmp(buf, "concat")) 304130389Sle return (GV_PLEX_CONCAT); 305130389Sle else if (!strcmp(buf, "striped")) 306130389Sle return (GV_PLEX_STRIPED); 307130389Sle else if (!strcmp(buf, "raid5")) 308130389Sle return (GV_PLEX_RAID5); 309130389Sle else 310130389Sle return (GV_PLEX_DISORG); 311130389Sle} 312130389Sle 313130389Sleint 314130389Slegv_volstatei(char *buf) 315130389Sle{ 316130389Sle if (!strcmp(buf, "up")) 317130389Sle return (GV_VOL_UP); 318130389Sle else 319130389Sle return (GV_VOL_DOWN); 320130389Sle} 321130389Sle 322130389Sleconst char * 323130389Slegv_volstate(int state) 324130389Sle{ 325130389Sle switch (state) { 326130389Sle case GV_VOL_UP: 327130389Sle return "up"; 328130389Sle case GV_VOL_DOWN: 329130389Sle return "down"; 330130389Sle default: 331130389Sle return "??"; 332130389Sle } 333130389Sle} 334130389Sle 335130389Sle/* Translate from a plex organization to a string. */ 336130389Sleconst char * 337130389Slegv_plexorg(int org) 338130389Sle{ 339130389Sle switch (org) { 340130389Sle case GV_PLEX_DISORG: 341130389Sle return "??"; 342130389Sle case GV_PLEX_CONCAT: 343130389Sle return "concat"; 344130389Sle case GV_PLEX_STRIPED: 345130389Sle return "striped"; 346130389Sle case GV_PLEX_RAID5: 347130389Sle return "raid5"; 348130389Sle default: 349130389Sle return "??"; 350130389Sle } 351130389Sle} 352130389Sle 353130389Sleconst char * 354130389Slegv_plexorg_short(int org) 355130389Sle{ 356130389Sle switch (org) { 357130389Sle case GV_PLEX_DISORG: 358130389Sle return "??"; 359130389Sle case GV_PLEX_CONCAT: 360130389Sle return "C"; 361130389Sle case GV_PLEX_STRIPED: 362130389Sle return "S"; 363130389Sle case GV_PLEX_RAID5: 364130389Sle return "R5"; 365130389Sle default: 366130389Sle return "??"; 367130389Sle } 368130389Sle} 369130389Sle 370190881Slulfstruct gv_sd * 371190881Slulfgv_alloc_sd(void) 372190881Slulf{ 373190881Slulf struct gv_sd *s; 374190881Slulf 375190881Slulf#ifdef _KERNEL 376190881Slulf s = g_malloc(sizeof(struct gv_sd), M_NOWAIT); 377190881Slulf#else 378190881Slulf s = malloc(sizeof(struct gv_sd)); 379190881Slulf#endif 380190881Slulf if (s == NULL) 381190881Slulf return (NULL); 382190881Slulf bzero(s, sizeof(struct gv_sd)); 383190881Slulf s->plex_offset = -1; 384190881Slulf s->size = -1; 385190881Slulf s->drive_offset = -1; 386190881Slulf return (s); 387190881Slulf} 388190881Slulf 389130389Slestruct gv_drive * 390190881Slulfgv_alloc_drive(void) 391130389Sle{ 392130389Sle struct gv_drive *d; 393130389Sle 394130389Sle#ifdef _KERNEL 395190507Slulf d = g_malloc(sizeof(struct gv_drive), M_NOWAIT); 396130389Sle#else 397130389Sle d = malloc(sizeof(struct gv_drive)); 398190507Slulf#endif 399130389Sle if (d == NULL) 400130389Sle return (NULL); 401130389Sle bzero(d, sizeof(struct gv_drive)); 402190881Slulf return (d); 403190881Slulf} 404130389Sle 405190881Slulfstruct gv_volume * 406190881Slulfgv_alloc_volume(void) 407190881Slulf{ 408190881Slulf struct gv_volume *v; 409190881Slulf 410190881Slulf#ifdef _KERNEL 411190881Slulf v = g_malloc(sizeof(struct gv_volume), M_NOWAIT); 412190881Slulf#else 413190881Slulf v = malloc(sizeof(struct gv_volume)); 414190881Slulf#endif 415190881Slulf if (v == NULL) 416190881Slulf return (NULL); 417190881Slulf bzero(v, sizeof(struct gv_volume)); 418190881Slulf return (v); 419190881Slulf} 420190881Slulf 421190881Slulfstruct gv_plex * 422190881Slulfgv_alloc_plex(void) 423190881Slulf{ 424190881Slulf struct gv_plex *p; 425190881Slulf 426190881Slulf#ifdef _KERNEL 427190881Slulf p = g_malloc(sizeof(struct gv_plex), M_NOWAIT); 428190881Slulf#else 429190881Slulf p = malloc(sizeof(struct gv_plex)); 430190881Slulf#endif 431190881Slulf if (p == NULL) 432190881Slulf return (NULL); 433190881Slulf bzero(p, sizeof(struct gv_plex)); 434190881Slulf return (p); 435190881Slulf} 436190881Slulf 437190881Slulf/* Get a new drive object. */ 438190881Slulfstruct gv_drive * 439190881Slulfgv_new_drive(int max, char *token[]) 440190881Slulf{ 441190881Slulf struct gv_drive *d; 442190881Slulf int j, errors; 443190881Slulf char *ptr; 444190881Slulf 445190881Slulf if (token[1] == NULL || *token[1] == '\0') 446190881Slulf return (NULL); 447190881Slulf d = gv_alloc_drive(); 448190881Slulf if (d == NULL) 449190881Slulf return (NULL); 450130389Sle errors = 0; 451130389Sle for (j = 1; j < max; j++) { 452130389Sle if (!strcmp(token[j], "state")) { 453130389Sle j++; 454130389Sle if (j >= max) { 455130389Sle errors++; 456130389Sle break; 457130389Sle } 458130389Sle d->state = gv_drivestatei(token[j]); 459130389Sle } else if (!strcmp(token[j], "device")) { 460130389Sle j++; 461130389Sle if (j >= max) { 462130389Sle errors++; 463130389Sle break; 464130389Sle } 465136064Sle ptr = token[j]; 466168669Sle 467168669Sle if (strncmp(ptr, "/dev/", 5) == 0) 468168669Sle ptr += 5; 469190507Slulf strlcpy(d->device, ptr, sizeof(d->device)); 470130389Sle } else { 471130389Sle /* We assume this is the drive name. */ 472190507Slulf strlcpy(d->name, token[j], sizeof(d->name)); 473130389Sle } 474130389Sle } 475130389Sle 476130389Sle if (strlen(d->name) == 0 || strlen(d->device) == 0) 477130389Sle errors++; 478130389Sle 479130389Sle if (errors) { 480130389Sle g_free(d); 481130389Sle return (NULL); 482130389Sle } 483130389Sle 484130389Sle return (d); 485130389Sle} 486130389Sle 487130389Sle/* Get a new volume object. */ 488130389Slestruct gv_volume * 489130389Slegv_new_volume(int max, char *token[]) 490130389Sle{ 491130389Sle struct gv_volume *v; 492130389Sle int j, errors; 493130389Sle 494130389Sle if (token[1] == NULL || *token[1] == '\0') 495130389Sle return (NULL); 496130389Sle 497190881Slulf v = gv_alloc_volume(); 498130389Sle if (v == NULL) 499130389Sle return (NULL); 500130389Sle 501130389Sle errors = 0; 502130389Sle for (j = 1; j < max; j++) { 503130389Sle if (!strcmp(token[j], "state")) { 504130389Sle j++; 505130389Sle if (j >= max) { 506130389Sle errors++; 507130389Sle break; 508130389Sle } 509130389Sle v->state = gv_volstatei(token[j]); 510130389Sle } else { 511130389Sle /* We assume this is the volume name. */ 512190507Slulf strlcpy(v->name, token[j], sizeof(v->name)); 513130389Sle } 514130389Sle } 515130389Sle 516130389Sle if (strlen(v->name) == 0) 517130389Sle errors++; 518130389Sle 519130389Sle if (errors) { 520130389Sle g_free(v); 521130389Sle return (NULL); 522130389Sle } 523130389Sle 524130389Sle return (v); 525130389Sle} 526130389Sle 527130389Sle/* Get a new plex object. */ 528130389Slestruct gv_plex * 529130389Slegv_new_plex(int max, char *token[]) 530130389Sle{ 531130389Sle struct gv_plex *p; 532130389Sle int j, errors; 533130389Sle 534130389Sle if (token[1] == NULL || *token[1] == '\0') 535130389Sle return (NULL); 536130389Sle 537190881Slulf p = gv_alloc_plex(); 538130389Sle if (p == NULL) 539130389Sle return (NULL); 540130389Sle 541130389Sle errors = 0; 542130389Sle for (j = 1; j < max; j++) { 543130389Sle if (!strcmp(token[j], "name")) { 544130389Sle j++; 545130389Sle if (j >= max) { 546130389Sle errors++; 547130389Sle break; 548130389Sle } 549190507Slulf strlcpy(p->name, token[j], sizeof(p->name)); 550130389Sle } else if (!strcmp(token[j], "org")) { 551130389Sle j++; 552130389Sle if (j >= max) { 553130389Sle errors++; 554130389Sle break; 555130389Sle } 556130389Sle p->org = gv_plexorgi(token[j]); 557130389Sle if ((p->org == GV_PLEX_RAID5) || 558130389Sle (p->org == GV_PLEX_STRIPED)) { 559130389Sle j++; 560130389Sle if (j >= max) { 561130389Sle errors++; 562130389Sle break; 563130389Sle } 564130389Sle p->stripesize = gv_sizespec(token[j]); 565130389Sle if (p->stripesize == 0) { 566130389Sle errors++; 567130389Sle break; 568130389Sle } 569130389Sle } 570130389Sle } else if (!strcmp(token[j], "state")) { 571130389Sle j++; 572130389Sle if (j >= max) { 573130389Sle errors++; 574130389Sle break; 575130389Sle } 576130389Sle p->state = gv_plexstatei(token[j]); 577179206Slulf } else if (!strcmp(token[j], "vol") || 578179206Slulf !strcmp(token[j], "volume")) { 579130389Sle j++; 580130389Sle if (j >= max) { 581130389Sle errors++; 582130389Sle break; 583130389Sle } 584190507Slulf strlcpy(p->volume, token[j], sizeof(p->volume)); 585130389Sle } else { 586130389Sle errors++; 587130389Sle break; 588130389Sle } 589130389Sle } 590130389Sle 591130389Sle if (errors) { 592130389Sle g_free(p); 593130389Sle return (NULL); 594130389Sle } 595130389Sle 596130389Sle return (p); 597130389Sle} 598130389Sle 599190881Slulf 600190881Slulf 601130389Sle/* Get a new subdisk object. */ 602130389Slestruct gv_sd * 603130389Slegv_new_sd(int max, char *token[]) 604130389Sle{ 605130389Sle struct gv_sd *s; 606130389Sle int j, errors; 607130389Sle 608130389Sle if (token[1] == NULL || *token[1] == '\0') 609190507Slulf return (NULL); 610130389Sle 611190881Slulf s = gv_alloc_sd(); 612130389Sle if (s == NULL) 613190507Slulf return (NULL); 614130389Sle 615130389Sle errors = 0; 616130389Sle for (j = 1; j < max; j++) { 617130389Sle if (!strcmp(token[j], "name")) { 618130389Sle j++; 619130389Sle if (j >= max) { 620130389Sle errors++; 621130389Sle break; 622130389Sle } 623190507Slulf strlcpy(s->name, token[j], sizeof(s->name)); 624130389Sle } else if (!strcmp(token[j], "drive")) { 625130389Sle j++; 626130389Sle if (j >= max) { 627130389Sle errors++; 628130389Sle break; 629130389Sle } 630190507Slulf strlcpy(s->drive, token[j], sizeof(s->drive)); 631130389Sle } else if (!strcmp(token[j], "plex")) { 632130389Sle j++; 633130389Sle if (j >= max) { 634130389Sle errors++; 635130389Sle break; 636130389Sle } 637190507Slulf strlcpy(s->plex, token[j], sizeof(s->plex)); 638130389Sle } else if (!strcmp(token[j], "state")) { 639130389Sle j++; 640130389Sle if (j >= max) { 641130389Sle errors++; 642130389Sle break; 643130389Sle } 644130389Sle s->state = gv_sdstatei(token[j]); 645130389Sle } else if (!strcmp(token[j], "len") || 646130389Sle !strcmp(token[j], "length")) { 647130389Sle j++; 648130389Sle if (j >= max) { 649130389Sle errors++; 650130389Sle break; 651130389Sle } 652130389Sle s->size = gv_sizespec(token[j]); 653130990Sle if (s->size <= 0) 654130990Sle s->size = -1; 655130389Sle } else if (!strcmp(token[j], "driveoffset")) { 656130389Sle j++; 657130389Sle if (j >= max) { 658130389Sle errors++; 659130389Sle break; 660130389Sle } 661130389Sle s->drive_offset = gv_sizespec(token[j]); 662130389Sle if (s->drive_offset != 0 && 663130389Sle s->drive_offset < GV_DATA_START) { 664130389Sle errors++; 665130389Sle break; 666130389Sle } 667130389Sle } else if (!strcmp(token[j], "plexoffset")) { 668130389Sle j++; 669130389Sle if (j >= max) { 670130389Sle errors++; 671130389Sle break; 672130389Sle } 673130389Sle s->plex_offset = gv_sizespec(token[j]); 674130389Sle if (s->plex_offset < 0) { 675130389Sle errors++; 676130389Sle break; 677130389Sle } 678130389Sle } else { 679130389Sle errors++; 680130389Sle break; 681130389Sle } 682130389Sle } 683130389Sle 684130389Sle if (strlen(s->drive) == 0) 685130389Sle errors++; 686130389Sle 687130389Sle if (errors) { 688130389Sle g_free(s); 689130389Sle return (NULL); 690130389Sle } 691130389Sle 692130389Sle return (s); 693130389Sle} 694137727Sle 695137727Sle/* 696137727Sle * Take a size in bytes and return a pointer to a string which represents the 697137727Sle * size best. If lj is != 0, return left justified, otherwise in a fixed 10 698137727Sle * character field suitable for columnar printing. 699137727Sle * 700137727Sle * Note this uses a static string: it's only intended to be used immediately 701137727Sle * for printing. 702137727Sle */ 703137727Sleconst char * 704137727Slegv_roughlength(off_t bytes, int lj) 705137727Sle{ 706137727Sle static char desc[16]; 707137727Sle 708137727Sle /* Gigabytes. */ 709137727Sle if (bytes > (off_t)MEGABYTE * 10000) 710137727Sle snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB", 711137727Sle bytes / GIGABYTE); 712137727Sle 713137727Sle /* Megabytes. */ 714137727Sle else if (bytes > KILOBYTE * 10000) 715137727Sle snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB", 716137727Sle bytes / MEGABYTE); 717137727Sle 718137727Sle /* Kilobytes. */ 719137727Sle else if (bytes > 10000) 720137727Sle snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB", 721137727Sle bytes / KILOBYTE); 722137727Sle 723137727Sle /* Bytes. */ 724137727Sle else 725137727Sle snprintf(desc, sizeof(desc), lj ? "%jd B" : "%10jd B", bytes); 726137727Sle 727137727Sle return (desc); 728137727Sle} 729