/* Create a drive quick and dirty. */ char * create_drive(char *device) { struct gv_drive *d; struct gctl_req *req; const char *errstr; char *drivename, *dname; int drives, i, flags, volumes, subdisks, plexes; flags = plexes = subdisks = volumes = 0; drives = 1; dname = NULL; drivename = find_drive(); if (drivename == NULL) return (NULL); req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "create"); d = gv_alloc_drive(); if (d == NULL) err(1, "unable to allocate for gv_drive object"); strlcpy(d->name, drivename, sizeof(d->name)); copy_device(d, device); gctl_ro_param(req, "drive0", sizeof(*d), d); gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_ro_param(req, "drives", sizeof(int), &drives); gctl_ro_param(req, "volumes", sizeof(int), &volumes); gctl_ro_param(req, "plexes", sizeof(int), &plexes); gctl_ro_param(req, "subdisks", sizeof(int), &subdisks); errstr = gctl_issue(req); if (errstr != NULL) { warnx("error creating drive: %s", errstr); gctl_free(req); return (NULL); } else { gctl_free(req); /* XXX: This is needed because we have to make sure the drives * are created before we return. */ /* Loop until it's in the config. */ for (i = 0; i < 100000; i++) { dname = find_name("gvinumdrive", GV_TYPE_DRIVE, GV_MAXDRIVENAME); /* If we got a different name, quit. */ if (dname == NULL) continue; if (strcmp(dname, drivename)) { free(dname); return (drivename); } free(dname); dname = NULL; usleep(100000); /* Sleep for 0.1s */ } } gctl_free(req); return (drivename); }
/* Get a new drive object. */ struct gv_drive * gv_new_drive(int max, char *token[]) { struct gv_drive *d; int j, errors; char *ptr; if (token[1] == NULL || *token[1] == '\0') return (NULL); d = gv_alloc_drive(); if (d == NULL) return (NULL); errors = 0; for (j = 1; j < max; j++) { if (!strcmp(token[j], "state")) { j++; if (j >= max) { errors++; break; } d->state = gv_drivestatei(token[j]); } else if (!strcmp(token[j], "device")) { j++; if (j >= max) { errors++; break; } ptr = token[j]; if (strncmp(ptr, "/dev/", 5) == 0) ptr += 5; strlcpy(d->device, ptr, sizeof(d->device)); } else { /* We assume this is the drive name. */ strlcpy(d->name, token[j], sizeof(d->name)); } } if (strlen(d->name) == 0 || strlen(d->device) == 0) errors++; if (errors) { g_free(d); return (NULL); } return (d); }
/* 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); }