static void cmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) { int ffd; u_char buf[16]; struct gctl_req *r; const char *errstr; r = gctl_get_handle(); gctl_ro_param(r, "verb", -1, "create geom"); gctl_ro_param(r, "class", -1, "BDE"); gctl_ro_param(r, "provider", -1, dest); gctl_ro_param(r, "pass", SHA512_DIGEST_LENGTH, sc->sha2); if (lfile != NULL) { ffd = open(lfile, O_RDONLY, 0); if (ffd < 0) err(1, "%s", lfile); read(ffd, buf, 16); gctl_ro_param(r, "key", 16, buf); close(ffd); } /* gctl_dump(r, stdout); */ errstr = gctl_issue(r); if (errstr != NULL) errx(1, "Attach to %s failed: %s", dest, errstr); exit (0); }
void gvinum_resetconfig(void) { struct gctl_req *req; const char *errstr; char reply[32]; if (!isatty(STDIN_FILENO)) { warn("Please enter this command from a tty device\n"); return; } printf(" WARNING! This command will completely wipe out your gvinum" "configuration.\n" " All data will be lost. If you really want to do this," " enter the text\n\n" " NO FUTURE\n" " Enter text -> "); fgets(reply, sizeof(reply), stdin); if (strcmp(reply, "NO FUTURE\n")) { printf("\n No change\n"); return; } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "resetconfig"); errstr = gctl_issue(req); if (errstr != NULL) { warnx("can't reset config: %s", errstr); gctl_free(req); return; } gctl_free(req); printf("gvinum configuration obliterated\n"); }
static int dumpout(int unit) { static int v; struct gctl_req *grq; int ncp; char *cp; char const *errstr; grq = gctl_get_handle(); ncp = 65536; cp = malloc(ncp); gctl_ro_param(grq, "verb", -1, "list"); gctl_ro_param(grq, "class", -1, "CCD"); gctl_ro_param(grq, "unit", sizeof(unit), &unit); gctl_rw_param(grq, "output", ncp, cp); errstr = gctl_issue(grq); if (errstr != NULL) errx(1, "%s\nor possibly kernel and ccdconfig out of sync", errstr); if (strlen(cp) == 0) errx(1, "ccd%d not configured", unit); if (verbose && !v) { printf("# ccd\t\tileave\tflags\tcomponent devices\n"); v = 1; } printf("%s", cp); free(cp); return (0); }
/* * The guts of printconfig. This is called from gvinum_printconfig and from * gvinum_create when called without an argument, in order to give the user * something to edit. */ void printconfig(FILE *of, char *comment) { struct gctl_req *req; struct utsname uname_s; const char *errstr; time_t now; char buf[GV_CFG_LEN + 1]; uname(&uname_s); time(&now); req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "getconfig"); gctl_ro_param(req, "comment", -1, comment); gctl_rw_param(req, "config", sizeof(buf), buf); errstr = gctl_issue(req); if (errstr != NULL) { warnx("can't get configuration: %s", errstr); return; } gctl_free(req); fprintf(of, "# Vinum configuration of %s, saved at %s", uname_s.nodename, ctime(&now)); if (*comment != '\0') fprintf(of, "# Current configuration:\n"); fprintf(of, "%s", buf); }
int main(int argc, char *argv[]) { struct retval *rv; struct gctl_req *req; char *param, *value; const char *s; int c, len; req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "GPT"); while ((c = getopt(argc, argv, "v")) != -1) { switch (c) { case 'v': verbose = 1; break; case '?': default: usage(); /* NOTREACHED */ break; } } while (optind < argc) { if (!parse(argv[optind++], ¶m, &value, &len)) { if (len > 0) { rv = malloc(sizeof(struct retval)); rv->param = param; rv->value = value; rv->retval = retval; retval = rv; gctl_rw_param(req, param, len, value); } else gctl_ro_param(req, param, -1, value); } } if (verbose) gctl_dump(req, stdout); s = gctl_issue(req); if (s == NULL) { printf("PASS"); while (retval != NULL) { rv = retval->retval; printf(" %s=%s", retval->param, retval->value); free(retval->value); free(retval); retval = rv; } printf("\n"); } else printf("FAIL %s\n", s); gctl_free(req); return (0); }
void gvinum_setstate(int argc, char **argv) { struct gctl_req *req; int flags, i; const char *errstr; flags = 0; optreset = 1; optind = 1; while ((i = getopt(argc, argv, "f")) != -1) { switch (i) { case 'f': flags |= GV_FLAG_F; break; case '?': default: warn("invalid flag: %c", i); return; } } argc -= optind; argv += optind; if (argc != 2) { warnx("usage: setstate [-f] <state> <obj>"); return; } /* * XXX: This hack is needed to avoid tripping over (now) invalid * 'classic' vinum states and will go away later. */ if (strcmp(argv[0], "up") && strcmp(argv[0], "down") && strcmp(argv[0], "stale")) { warnx("invalid state '%s'", argv[0]); return; } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "setstate"); gctl_ro_param(req, "state", -1, argv[0]); gctl_ro_param(req, "object", -1, argv[1]); gctl_ro_param(req, "flags", sizeof(int), &flags); errstr = gctl_issue(req); if (errstr != NULL) warnx("%s", errstr); gctl_free(req); }
void gvinum_parityop(int argc, char **argv, int rebuild) { struct gctl_req *req; int flags, i; const char *errstr; char *op, *msg; if (rebuild) { op = "rebuildparity"; msg = "Rebuilding"; } else { op = "checkparity"; msg = "Checking"; } optreset = 1; optind = 1; flags = 0; while ((i = getopt(argc, argv, "fv")) != -1) { switch (i) { case 'f': flags |= GV_FLAG_F; break; case 'v': flags |= GV_FLAG_V; break; case '?': default: warnx("invalid flag '%c'", i); return; } } argc -= optind; argv += optind; if (argc != 1) { warn("usage: %s [-f] [-v] <plex>", op); return; } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, op); gctl_ro_param(req, "rebuild", sizeof(int), &rebuild); gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_ro_param(req, "plex", -1, argv[0]); errstr = gctl_issue(req); if (errstr) warnx("%s\n", errstr); gctl_free(req); }
void gvinum_rename(int argc, char **argv) { struct gctl_req *req; const char *errstr; int flags, j; flags = 0; if (argc) { optreset = 1; optind = 1; while ((j = getopt(argc, argv, "r")) != -1) { switch (j) { case 'r': flags |= GV_FLAG_R; break; case '?': default: return; } } argc -= optind; argv += optind; } switch (argc) { case 0: warnx("no object to rename specified"); return; case 1: warnx("no new name specified"); return; case 2: break; default: warnx("more than one new name specified"); return; } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "rename"); gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_ro_param(req, "object", -1, argv[0]); gctl_ro_param(req, "newname", -1, argv[1]); errstr = gctl_issue(req); if (errstr != NULL) warnx("can't rename object: %s", errstr); gctl_free(req); return; }
void gvinum_start(int argc, char **argv) { struct gctl_req *req; int i, initsize, j; const char *errstr; char buf[20]; /* 'start' with no arguments is a no-op. */ if (argc == 1) return; initsize = 0; optreset = 1; optind = 1; while ((j = getopt(argc, argv, "S")) != -1) { switch (j) { case 'S': initsize = atoi(optarg); break; case '?': default: return; } } argc -= optind; argv += optind; if (!initsize) initsize = 512; req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "start"); gctl_ro_param(req, "argc", sizeof(int), &argc); gctl_ro_param(req, "initsize", sizeof(int), &initsize); if (argc) { for (i = 0; i < argc; i++) { snprintf(buf, sizeof(buf), "argv%d", i); gctl_ro_param(req, buf, -1, argv[i]); } } errstr = gctl_issue(req); if (errstr != NULL) { warnx("can't start: %s", errstr); gctl_free(req); return; } gctl_free(req); }
void gvinum_saveconfig(void) { struct gctl_req *req; const char *errstr; req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "saveconfig"); errstr = gctl_issue(req); if (errstr != NULL) warnx("can't save configuration: %s", errstr); gctl_free(req); }
/* 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); }
static int write_boot(const char *disk, u_char *boot) { int fd, n, i; char buf[MAXPATHLEN]; const char *q; struct gctl_req *grq; fd = open(disk, O_WRONLY, 0666); if (fd != -1) { if ((n = write(fd, boot, BOOTSIZE)) < 0) err(1, "%s", disk); if (n != BOOTSIZE) errx(1, "%s: short write", disk); close(fd); return 0; } grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write PC98"); gctl_ro_param(grq, "class", -1, "PC98"); q = strrchr(disk, '/'); if (q == NULL) q = disk; else q++; gctl_ro_param(grq, "geom", -1, q); gctl_ro_param(grq, "data", BOOTSIZE, boot); q = gctl_issue(grq); if (q == NULL) return 0; warnx("%s: %s", disk, q); gctl_free(grq); for (i = 0; i < PC98_NPARTS; i++) { snprintf(buf, sizeof(buf), "%ss%d", disk, i + 1); fd = open(buf, O_RDONLY); if (fd < 0) continue; n = ioctl(fd, DIOCSPC98, boot); if (n != 0) err(1, "%s: ioctl DIOCSPC98", disk); close(fd); return 0; } err(1, "%s", disk); }
static void gvinum_resetconfig(int argc, char * const *argv) { struct gctl_req *req; const char *errstr; char reply[32]; int flags, i; flags = 0; while ((i = getopt(argc, argv, "f")) != -1) { switch (i) { case 'f': flags |= GV_FLAG_F; break; default: warn("invalid flag: %c", i); return; } } if ((flags & GV_FLAG_F) == 0) { if (!isatty(STDIN_FILENO)) { warn("Please enter this command from a tty device\n"); return; } printf(" WARNING! This command will completely wipe out" " your gvinum configuration.\n" " All data will be lost. If you really want to do this," " enter the text\n\n" " NO FUTURE\n" " Enter text -> "); fgets(reply, sizeof(reply), stdin); if (strcmp(reply, "NO FUTURE\n")) { printf("\n No change\n"); return; } } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "resetconfig"); errstr = gctl_issue(req); if (errstr != NULL) { warnx("can't reset config: %s", errstr); gctl_free(req); return; } gctl_free(req); printf("gvinum configuration obliterated\n"); }
void gvinum_rm(int argc, char **argv) { struct gctl_req *req; int flags, i, j; const char *errstr; char buf[20], *cmd; cmd = argv[0]; flags = 0; optreset = 1; optind = 1; while ((j = getopt(argc, argv, "rf")) != -1) { switch (j) { case 'f': flags |= GV_FLAG_F; break; case 'r': flags |= GV_FLAG_R; break; case '?': default: return; } } argc -= optind; argv += optind; req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "remove"); gctl_ro_param(req, "argc", sizeof(int), &argc); gctl_ro_param(req, "flags", sizeof(int), &flags); if (argc) { for (i = 0; i < argc; i++) { snprintf(buf, sizeof(buf), "argv%d", i); gctl_ro_param(req, buf, -1, argv[i]); } } errstr = gctl_issue(req); if (errstr != NULL) { warnx("can't remove: %s", errstr); gctl_free(req); return; } gctl_free(req); }
/* * General routine for creating a volume. Mainly for use by concat, mirror, * raid5 and stripe commands. */ void create_volume(int argc, char **argv, char *verb) { struct gctl_req *req; const char *errstr; char buf[BUFSIZ], *drivename, *volname; int drives, flags, i; off_t stripesize; flags = 0; drives = 0; volname = NULL; stripesize = 262144; /* XXX: Should we check for argument length? */ req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-f")) { flags |= GV_FLAG_F; } else if (!strcmp(argv[i], "-n")) { volname = argv[++i]; } else if (!strcmp(argv[i], "-v")) { flags |= GV_FLAG_V; } else if (!strcmp(argv[i], "-s")) { flags |= GV_FLAG_S; if (!strcmp(verb, "raid5")) stripesize = gv_sizespec(argv[++i]); } else { /* Assume it's a drive. */ snprintf(buf, sizeof(buf), "drive%d", drives++); /* First we create the drive. */ drivename = create_drive(argv[i]); if (drivename == NULL) goto bad; /* Then we add it to the request. */ gctl_ro_param(req, buf, -1, drivename); } } gctl_ro_param(req, "stripesize", sizeof(off_t), &stripesize); /* Find a free volume name. */ if (volname == NULL) volname = find_name("gvinumvolume", GV_TYPE_VOL, GV_MAXVOLNAME); /* Then we send a request to actually create the volumes. */ gctl_ro_param(req, "verb", -1, verb); gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_ro_param(req, "drives", sizeof(int), &drives); gctl_ro_param(req, "name", -1, volname); errstr = gctl_issue(req); if (errstr != NULL) warnx("creating %s volume failed: %s", verb, errstr); bad: gctl_free(req); }
static void cmd_detach(const char *dest) { struct gctl_req *r; const char *errstr; char buf[BUFSIZ]; r = gctl_get_handle(); gctl_ro_param(r, "verb", -1, "destroy geom"); gctl_ro_param(r, "class", -1, "BDE"); sprintf(buf, "%s.bde", dest); gctl_ro_param(r, "geom", -1, buf); /* gctl_dump(r, stdout); */ errstr = gctl_issue(r); if (errstr != NULL) errx(1, "Detach of %s failed: %s", dest, errstr); exit (0); }
/* Detach a plex or subdisk from its parent. */ void gvinum_detach(int argc, char **argv) { const char *errstr; struct gctl_req *req; int flags, i; flags = 0; optreset = 1; optind = 1; while ((i = getopt(argc, argv, "f")) != -1) { switch(i) { case 'f': flags |= GV_FLAG_F; break; default: warn("invalid flag: %c", i); return; } } argc -= optind; argv += optind; if (argc != 1) { warnx("usage: detach [-f] <subdisk> | <plex>"); return; } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "detach"); gctl_ro_param(req, "object", -1, argv[0]); gctl_ro_param(req, "flags", sizeof(int), &flags); errstr = gctl_issue(req); if (errstr != NULL) warnx("detach failed: %s", errstr); gctl_free(req); }
/* Note that move is currently of form '[-r] target object [...]' */ void gvinum_move(int argc, char **argv) { struct gctl_req *req; const char *errstr; char buf[20]; int flags, i, j; flags = 0; if (argc) { optreset = 1; optind = 1; while ((j = getopt(argc, argv, "f")) != -1) { switch (j) { case 'f': flags |= GV_FLAG_F; break; case '?': default: return; } } argc -= optind; argv += optind; } switch (argc) { case 0: warnx("no destination or object(s) to move specified"); return; case 1: warnx("no object(s) to move specified"); return; default: break; } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "move"); gctl_ro_param(req, "argc", sizeof(int), &argc); gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_ro_param(req, "destination", -1, argv[0]); for (i = 1; i < argc; i++) { snprintf(buf, sizeof(buf), "argv%d", i); gctl_ro_param(req, buf, -1, argv[i]); } errstr = gctl_issue(req); if (errstr != NULL) warnx("can't move object(s): %s", errstr); gctl_free(req); return; }
/* Attach a plex to a volume or a subdisk to a plex. */ void gvinum_attach(int argc, char **argv) { struct gctl_req *req; const char *errstr; int rename; off_t offset; rename = 0; offset = -1; if (argc < 3) { warnx("usage:\tattach <subdisk> <plex> [rename] " "[<plexoffset>]\n" "\tattach <plex> <volume> [rename]"); return; } if (argc > 3) { if (!strcmp(argv[3], "rename")) { rename = 1; if (argc == 5) offset = strtol(argv[4], NULL, 0); } else offset = strtol(argv[3], NULL, 0); } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "attach"); gctl_ro_param(req, "child", -1, argv[1]); gctl_ro_param(req, "parent", -1, argv[2]); gctl_ro_param(req, "offset", sizeof(off_t), &offset); gctl_ro_param(req, "rename", sizeof(int), &rename); errstr = gctl_issue(req); if (errstr != NULL) warnx("attach failed: %s", errstr); gctl_free(req); }
static int writelabel(void) { int i, fd, serrno; struct gctl_req *grq; char const *errstr; struct disklabel *lp = &lab; if (disable_write) { warnx("write to disk label suppressed - label was as follows:"); display(stdout, NULL); return (0); } lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC; lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); if (installboot) readboot(); for (i = 0; i < lab.d_npartitions; i++) if (lab.d_partitions[i].p_size) lab.d_partitions[i].p_offset += lba_offset; bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * lab.d_secsize, lp); fd = open(specname, O_RDWR); if (fd < 0) { if (is_file) { warn("cannot open file %s for writing label", specname); return(1); } else serrno = errno; if (geom_class_available("PART") != 0) { /* * Since we weren't able open provider for * writing, then recommend user to use gpart(8). */ warnc(serrno, "cannot open provider %s for writing label", specname); warnx("Try to use gpart(8)."); return (1); } /* Give up if GEOM_BSD is not available. */ if (geom_class_available("BSD") == 0) { warnc(serrno, "%s", specname); return (1); } grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write label"); gctl_ro_param(grq, "class", -1, "BSD"); gctl_ro_param(grq, "geom", -1, pname); gctl_ro_param(grq, "label", 148+16*8, bootarea + labeloffset + labelsoffset * lab.d_secsize); errstr = gctl_issue(grq); if (errstr != NULL) { warnx("%s", errstr); gctl_free(grq); return(1); } gctl_free(grq); if (installboot) { grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write bootcode"); gctl_ro_param(grq, "class", -1, "BSD"); gctl_ro_param(grq, "geom", -1, pname); gctl_ro_param(grq, "bootcode", BBSIZE, bootarea); errstr = gctl_issue(grq); if (errstr != NULL) { warnx("%s", errstr); gctl_free(grq); return (1); } gctl_free(grq); } } else { if (write(fd, bootarea, bbsize) != bbsize) { warn("write %s", specname); close (fd); return (1); } close (fd); } return (0); }
static int do_single(int argc, char **argv, int action) { char *cp, *cp2; int ccd, noflags = 0, i, ileave, flags = 0; struct gctl_req *grq; char const *errstr; char buf1[BUFSIZ]; int ex; /* * If unconfiguring, all arguments are treated as ccds. */ if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) { ex = 0; for (; argc != 0;) { cp = *argv++; --argc; if ((ccd = resolve_ccdname(cp)) < 0) { warnx("invalid ccd name: %s", cp); continue; } grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "destroy geom"); gctl_ro_param(grq, "class", -1, "CCD"); sprintf(buf1, "ccd%d", ccd); gctl_ro_param(grq, "geom", -1, buf1); errstr = gctl_issue(grq); if (errstr == NULL) { if (verbose) printf("%s unconfigured\n", cp); gctl_free(grq); continue; } warnx( "%s\nor possibly kernel and ccdconfig out of sync", errstr); ex = 1; } return (ex); } /* Make sure there are enough arguments. */ if (argc < 4) { if (argc == 3) { /* Assume that no flags are specified. */ noflags = 1; } else { if (action == CCD_CONFIGALL) { warnx("%s: bad line: %d", ccdconf, lineno); return (1); } else usage(); } } /* First argument is the ccd to configure. */ cp = *argv++; --argc; if ((ccd = resolve_ccdname(cp)) < 0) { warnx("invalid ccd name: %s", cp); return (1); } /* Next argument is the interleave factor. */ cp = *argv++; --argc; errno = 0; /* to check for ERANGE */ ileave = (int)strtol(cp, &cp2, 10); if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) { warnx("invalid interleave factor: %s", cp); return (1); } if (noflags == 0) { /* Next argument is the ccd configuration flags. */ cp = *argv++; --argc; if ((flags = flags_to_val(cp)) < 0) { warnx("invalid flags argument: %s", cp); return (1); } } grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "create geom"); gctl_ro_param(grq, "class", -1, "CCD"); gctl_ro_param(grq, "unit", sizeof(ccd), &ccd); gctl_ro_param(grq, "ileave", sizeof(ileave), &ileave); if (flags & CCDF_UNIFORM) gctl_ro_param(grq, "uniform", -1, ""); if (flags & CCDF_MIRROR) gctl_ro_param(grq, "mirror", -1, ""); if (flags & CCDF_NO_OFFSET) gctl_ro_param(grq, "no_offset", -1, ""); if (flags & CCDF_LINUX) gctl_ro_param(grq, "linux", -1, ""); gctl_ro_param(grq, "nprovider", sizeof(argc), &argc); for (i = 0; i < argc; i++) { sprintf(buf1, "provider%d", i); cp = argv[i]; if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV))) cp += strlen(_PATH_DEV); gctl_ro_param(grq, buf1, -1, cp); } gctl_rw_param(grq, "output", sizeof(buf1), buf1); errstr = gctl_issue(grq); if (errstr == NULL) { if (verbose) { printf("%s", buf1); } gctl_free(grq); return (0); } warnx( "%s\nor possibly kernel and ccdconfig out of sync", errstr); return (1); }
/* * Write out the mbr to the specified file. */ static void write_mbr(const char *fname, int flags, u_int8_t *mbr, int mbr_size) { struct gctl_req *grq; const char *errmsg; char *pname; ssize_t n; int fd; fd = open(fname, O_WRONLY | flags, 0666); if (fd != -1) { n = write(fd, mbr, mbr_size); close(fd); if (n != mbr_size) errx(1, "%s: short write", fname); return; } /* * If we're called to write to a backup file, don't try to * write through GEOM. */ if (flags != 0) err(1, "can't open file %s to write backup", fname); /* Try open it read only. */ fd = open(fname, O_RDONLY); if (fd == -1) { warn("error opening %s", fname); return; } pname = g_providername(fd); if (pname == NULL) { warn("error getting providername for %s", fname); return; } /* First check that GEOM_PART is available */ if (geom_class_available("PART") != 0) { grq = gctl_get_handle(); gctl_ro_param(grq, "class", -1, "PART"); gctl_ro_param(grq, "arg0", -1, pname); gctl_ro_param(grq, "verb", -1, "bootcode"); gctl_ro_param(grq, "bootcode", mbr_size, mbr); gctl_ro_param(grq, "flags", -1, "C"); errmsg = gctl_issue(grq); if (errmsg != NULL && errmsg[0] != '\0') errx(1, "GEOM_PART: write bootcode to %s failed: %s", fname, errmsg); gctl_free(grq); } else if (geom_class_available("MBR") != 0) { grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write MBR"); gctl_ro_param(grq, "class", -1, "MBR"); gctl_ro_param(grq, "geom", -1, pname); gctl_ro_param(grq, "data", mbr_size, mbr); errmsg = gctl_issue(grq); if (errmsg != NULL) err(1, "GEOM_MBR: write MBR to %s failed", fname); gctl_free(grq); } else errx(1, "can't write MBR to %s", fname); free(pname); }
/* 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); }
void gvinum_list(int argc, char **argv) { struct gctl_req *req; int flags, i, j; const char *errstr; char buf[20], *cmd, config[GV_CFG_LEN + 1]; flags = 0; cmd = "list"; if (argc) { optreset = 1; optind = 1; cmd = argv[0]; while ((j = getopt(argc, argv, "rsvV")) != -1) { switch (j) { case 'r': flags |= GV_FLAG_R; break; case 's': flags |= GV_FLAG_S; break; case 'v': flags |= GV_FLAG_V; break; case 'V': flags |= GV_FLAG_V; flags |= GV_FLAG_VV; break; case '?': default: return; } } argc -= optind; argv += optind; } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "list"); gctl_ro_param(req, "cmd", -1, cmd); gctl_ro_param(req, "argc", sizeof(int), &argc); gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_rw_param(req, "config", sizeof(config), config); if (argc) { for (i = 0; i < argc; i++) { snprintf(buf, sizeof(buf), "argv%d", i); gctl_ro_param(req, buf, -1, argv[i]); } } errstr = gctl_issue(req); if (errstr != NULL) { warnx("can't get configuration: %s", errstr); gctl_free(req); return; } printf("%s", config); gctl_free(req); return; }
/* Find a free name for an object given a a prefix. */ char * find_name(const char *prefix, int type, int namelen) { struct gctl_req *req; char comment[1], buf[GV_CFG_LEN - 1], *name, *sname, *ptr; const char *errstr; int i, n, begin, len, conflict; char line[1024]; comment[0] = '\0'; /* Find a name. Fetch out configuration first. */ req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); gctl_ro_param(req, "verb", -1, "getconfig"); gctl_ro_param(req, "comment", -1, comment); gctl_rw_param(req, "config", sizeof(buf), buf); errstr = gctl_issue(req); if (errstr != NULL) { warnx("can't get configuration: %s", errstr); return (NULL); } gctl_free(req); begin = 0; len = strlen(buf); i = 0; sname = malloc(namelen + 1); /* XXX: Max object setting? */ for (n = 0; n < 10000; n++) { snprintf(sname, namelen, "%s%d", prefix, n); conflict = 0; begin = 0; /* Loop through the configuration line by line. */ for (i = 0; i < len; i++) { if (buf[i] == '\n' || buf[i] == '\0') { ptr = buf + begin; strlcpy(line, ptr, (i - begin) + 1); begin = i + 1; switch (type) { case GV_TYPE_DRIVE: name = find_pattern(line, "drive"); break; case GV_TYPE_VOL: name = find_pattern(line, "volume"); break; case GV_TYPE_PLEX: case GV_TYPE_SD: name = find_pattern(line, "name"); break; default: printf("Invalid type given\n"); continue; } if (name == NULL) continue; if (!strcmp(sname, name)) { conflict = 1; /* XXX: Could quit the loop earlier. */ } } } if (!conflict) return (sname); } free(sname); return (NULL); }
static void write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) { char path[MAXPATHLEN]; char boot[SUN_BOOTSIZE]; char buf[SUN_SIZE]; const char *errstr; off_t off; int bfd; int fd; int i; struct gctl_req *grq; sl->sl_magic = SUN_DKMAGIC; if (check_label(sl) != 0) errx(1, "invalid label"); bzero(buf, sizeof(buf)); sunlabel_enc(buf, sl); if (nflag) { print_label(sl, disk, stdout); return; } if (Bflag) { if ((bfd = open(bootpath, O_RDONLY)) < 0) err(1, "open %s", bootpath); i = read(bfd, boot, sizeof(boot)); if (i < 0) err(1, "read"); else if (i != sizeof (boot)) errx(1, "read wrong size boot code (%d)", i); close(bfd); } snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); fd = open(path, O_RDWR); if (fd < 0) { grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write label"); gctl_ro_param(grq, "class", -1, "SUN"); gctl_ro_param(grq, "geom", -1, disk); gctl_ro_param(grq, "label", sizeof buf, buf); errstr = gctl_issue(grq); if (errstr != NULL) errx(1, "%s", errstr); gctl_free(grq); if (Bflag) { grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write bootcode"); gctl_ro_param(grq, "class", -1, "SUN"); gctl_ro_param(grq, "geom", -1, disk); gctl_ro_param(grq, "bootcode", sizeof boot, boot); errstr = gctl_issue(grq); if (errstr != NULL) errx(1, "%s", errstr); gctl_free(grq); } } else { if (lseek(fd, 0, SEEK_SET) < 0) err(1, "lseek"); if (write(fd, buf, sizeof(buf)) != sizeof(buf)) err (1, "write"); if (Bflag) { for (i = 0; i < SUN_NPART; i++) { if (sl->sl_part[i].sdkp_nsectors == 0) continue; off = sl->sl_part[i].sdkp_cyloffset * sl->sl_ntracks * sl->sl_nsectors * 512; /* * Ignore first SUN_SIZE bytes of boot code to * avoid overwriting the label. */ if (lseek(fd, off + SUN_SIZE, SEEK_SET) < 0) err(1, "lseek"); if (write(fd, boot + SUN_SIZE, sizeof(boot) - SUN_SIZE) != sizeof(boot) - SUN_SIZE) err(1, "write"); } } close(fd); } exit(0); }
void gvinum_create(int argc, char **argv) { struct gctl_req *req; struct gv_drive *d; struct gv_plex *p; struct gv_sd *s; struct gv_volume *v; FILE *tmp; int drives, errors, fd, flags, i, line, plexes, plex_in_volume; int sd_in_plex, status, subdisks, tokens, undeffd, volumes; const char *errstr; char buf[BUFSIZ], buf1[BUFSIZ], commandline[BUFSIZ], *ed, *sdname; char original[BUFSIZ], tmpfile[20], *token[GV_MAXARGS]; char plex[GV_MAXPLEXNAME], volume[GV_MAXVOLNAME]; tmp = NULL; flags = 0; for (i = 1; i < argc; i++) { /* Force flag used to ignore already created drives. */ if (!strcmp(argv[i], "-f")) { flags |= GV_FLAG_F; /* Else it must be a file. */ } else { if ((tmp = fopen(argv[1], "r")) == NULL) { warn("can't open '%s' for reading", argv[1]); return; } } } /* We didn't get a file. */ if (tmp == NULL) { snprintf(tmpfile, sizeof(tmpfile), "/tmp/gvinum.XXXXXX"); if ((fd = mkstemp(tmpfile)) == -1) { warn("temporary file not accessible"); return; } if ((tmp = fdopen(fd, "w")) == NULL) { warn("can't open '%s' for writing", tmpfile); return; } printconfig(tmp, "# "); fclose(tmp); ed = getenv("EDITOR"); if (ed == NULL) ed = _PATH_VI; snprintf(commandline, sizeof(commandline), "%s %s", ed, tmpfile); status = system(commandline); if (status != 0) { warn("couldn't exec %s; status: %d", ed, status); return; } if ((tmp = fopen(tmpfile, "r")) == NULL) { warn("can't open '%s' for reading", tmpfile); return; } } 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); drives = volumes = plexes = subdisks = 0; plex_in_volume = sd_in_plex = undeffd = 0; plex[0] = '\0'; errors = 0; line = 1; while ((fgets(buf, BUFSIZ, tmp)) != NULL) { /* Skip empty lines and comments. */ if (*buf == '\0' || *buf == '#') { line++; continue; } /* Kill off the newline. */ buf[strlen(buf) - 1] = '\0'; /* * Copy the original input line in case we need it for error * output. */ strlcpy(original, buf, sizeof(original)); tokens = gv_tokenize(buf, token, GV_MAXARGS); if (tokens <= 0) { line++; continue; } /* Volume definition. */ if (!strcmp(token[0], "volume")) { v = gv_new_volume(tokens, token); if (v == NULL) { warnx("line %d: invalid volume definition", line); warnx("line %d: '%s'", line, original); errors++; line++; continue; } /* Reset plex count for this volume. */ plex_in_volume = 0; /* * Set default volume name for following plex * definitions. */ strlcpy(volume, v->name, sizeof(volume)); snprintf(buf1, sizeof(buf1), "volume%d", volumes); gctl_ro_param(req, buf1, sizeof(*v), v); volumes++; /* Plex definition. */ } else if (!strcmp(token[0], "plex")) { p = gv_new_plex(tokens, token); if (p == NULL) { warnx("line %d: invalid plex definition", line); warnx("line %d: '%s'", line, original); errors++; line++; continue; } /* Reset subdisk count for this plex. */ sd_in_plex = 0; /* Default name. */ if (strlen(p->name) == 0) { snprintf(p->name, sizeof(p->name), "%s.p%d", volume, plex_in_volume++); } /* Default volume. */ if (strlen(p->volume) == 0) { snprintf(p->volume, sizeof(p->volume), "%s", volume); } /* * Set default plex name for following subdisk * definitions. */ strlcpy(plex, p->name, sizeof(plex)); snprintf(buf1, sizeof(buf1), "plex%d", plexes); gctl_ro_param(req, buf1, sizeof(*p), p); plexes++; /* Subdisk definition. */ } else if (!strcmp(token[0], "sd")) { s = gv_new_sd(tokens, token); if (s == NULL) { warnx("line %d: invalid subdisk " "definition:", line); warnx("line %d: '%s'", line, original); errors++; line++; continue; } /* Default name. */ if (strlen(s->name) == 0) { if (strlen(plex) == 0) { sdname = find_name("gvinumsubdisk.p", GV_TYPE_SD, GV_MAXSDNAME); snprintf(s->name, sizeof(s->name), "%s.s%d", sdname, undeffd++); free(sdname); } else { snprintf(s->name, sizeof(s->name), "%s.s%d",plex, sd_in_plex++); } } /* Default plex. */ if (strlen(s->plex) == 0) snprintf(s->plex, sizeof(s->plex), "%s", plex); snprintf(buf1, sizeof(buf1), "sd%d", subdisks); gctl_ro_param(req, buf1, sizeof(*s), s); subdisks++; /* Subdisk definition. */ } else if (!strcmp(token[0], "drive")) { d = gv_new_drive(tokens, token); if (d == NULL) { warnx("line %d: invalid drive definition:", line); warnx("line %d: '%s'", line, original); errors++; line++; continue; } snprintf(buf1, sizeof(buf1), "drive%d", drives); gctl_ro_param(req, buf1, sizeof(*d), d); drives++; /* Everything else is bogus. */ } else { warnx("line %d: invalid definition:", line); warnx("line %d: '%s'", line, original); errors++; } line++; } fclose(tmp); unlink(tmpfile); if (!errors && (volumes || plexes || subdisks || 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); gctl_ro_param(req, "drives", sizeof(int), &drives); errstr = gctl_issue(req); if (errstr != NULL) warnx("create failed: %s", errstr); } gctl_free(req); }