/* Grow a subdisk by adding disk backed by provider. */ void gvinum_grow(int argc, char **argv) { struct gctl_req *req; char *drive, *sdname; char sdprefix[GV_MAXSDNAME]; struct gv_drive *d; struct gv_sd *s; const char *errstr; int drives, volumes, plexes, subdisks, flags; drives = volumes = plexes = subdisks = 0; if (argc < 3) { warnx("usage:\tgrow plex drive\n"); return; } s = gv_alloc_sd(); if (s == NULL) { warn("unable to create subdisk"); return; } d = gv_alloc_drive(); if (d == NULL) { warn("unable to create drive"); free(s); return; } /* Lookup device and set an appropriate drive name. */ drive = find_drive(); if (drive == NULL) { warn("unable to find an appropriate drive name"); free(s); free(d); return; } strlcpy(d->name, drive, sizeof(d->name)); copy_device(d, argv[2]); drives = 1; /* We try to use the plex name as basis for the subdisk name. */ snprintf(sdprefix, sizeof(sdprefix), "%s.s", argv[1]); sdname = find_name(sdprefix, GV_TYPE_SD, GV_MAXSDNAME); if (sdname == NULL) { warn("unable to find an appropriate subdisk name"); free(s); free(d); free(drive); return; } strlcpy(s->name, sdname, sizeof(s->name)); free(sdname); strlcpy(s->plex, argv[1], sizeof(s->plex)); strlcpy(s->drive, d->name, sizeof(s->drive)); subdisks = 1; req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "create"); gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_ro_param(req, "volumes", sizeof(int), &volumes); gctl_ro_param(req, "plexes", sizeof(int), &plexes); gctl_ro_param(req, "subdisks", sizeof(int), &subdisks); gctl_ro_param(req, "drives", sizeof(int), &drives); gctl_ro_param(req, "drive0", sizeof(*d), d); gctl_ro_param(req, "sd0", sizeof(*s), s); errstr = gctl_issue(req); free(drive); if (errstr != NULL) { warnx("unable to grow plex: %s", errstr); free(s); free(d); return; } gctl_free(req); }
/* Get a new subdisk object. */ struct gv_sd * gv_new_sd(int max, char *token[]) { struct gv_sd *s; int j, errors; if (token[1] == NULL || *token[1] == '\0') return (NULL); s = gv_alloc_sd(); if (s == NULL) return (NULL); errors = 0; for (j = 1; j < max; j++) { if (!strcmp(token[j], "name")) { j++; if (j >= max) { errors++; break; } strlcpy(s->name, token[j], sizeof(s->name)); } else if (!strcmp(token[j], "drive")) { j++; if (j >= max) { errors++; break; } strlcpy(s->drive, token[j], sizeof(s->drive)); } else if (!strcmp(token[j], "plex")) { j++; if (j >= max) { errors++; break; } strlcpy(s->plex, token[j], sizeof(s->plex)); } else if (!strcmp(token[j], "state")) { j++; if (j >= max) { errors++; break; } s->state = gv_sdstatei(token[j]); } else if (!strcmp(token[j], "len") || !strcmp(token[j], "length")) { j++; if (j >= max) { errors++; break; } s->size = gv_sizespec(token[j]); if (s->size <= 0) s->size = -1; } else if (!strcmp(token[j], "driveoffset")) { j++; if (j >= max) { errors++; break; } s->drive_offset = gv_sizespec(token[j]); if (s->drive_offset != 0 && s->drive_offset < GV_DATA_START) { errors++; break; } } else if (!strcmp(token[j], "plexoffset")) { j++; if (j >= max) { errors++; break; } s->plex_offset = gv_sizespec(token[j]); if (s->plex_offset < 0) { errors++; break; } } else { errors++; break; } } if (strlen(s->drive) == 0) errors++; if (errors) { g_free(s); return (NULL); } return (s); }