1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2005 Chris Jones 3219820Sjeff * All rights reserved. 4219820Sjeff * 5219820Sjeff * This software was developed for the FreeBSD Project by Chris Jones 6219820Sjeff * thanks to the support of Google's Summer of Code program and 7219820Sjeff * mentoring by Lukas Ertl. 8219820Sjeff * 9219820Sjeff * Redistribution and use in source and binary forms, with or without 10219820Sjeff * modification, are permitted provided that the following conditions 11219820Sjeff * are met: 12219820Sjeff * 1. Redistributions of source code must retain the above copyright 13219820Sjeff * notice, this list of conditions and the following disclaimer. 14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 15219820Sjeff * notice, this list of conditions and the following disclaimer in the 16219820Sjeff * documentation and/or other materials provided with the distribution. 17219820Sjeff * 18219820Sjeff * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28219820Sjeff * SUCH DAMAGE. 29219820Sjeff * 30219820Sjeff */ 31219820Sjeff 32219820Sjeff#include <sys/cdefs.h> 33219820Sjeff__FBSDID("$FreeBSD$"); 34219820Sjeff 35219820Sjeff#include <sys/param.h> 36219820Sjeff#include <sys/libkern.h> 37219820Sjeff#include <sys/malloc.h> 38219820Sjeff 39219820Sjeff#include <geom/geom.h> 40219820Sjeff#include <geom/vinum/geom_vinum_var.h> 41219820Sjeff#include <geom/vinum/geom_vinum.h> 42219820Sjeff 43219820Sjeffvoid 44219820Sjeffgv_rename(struct g_geom *gp, struct gctl_req *req) 45219820Sjeff{ 46219820Sjeff struct gv_softc *sc; 47219820Sjeff struct gv_volume *v; 48219820Sjeff struct gv_plex *p; 49219820Sjeff struct gv_sd *s; 50219820Sjeff struct gv_drive *d; 51219820Sjeff char *newname, *object, *name; 52219820Sjeff int *flags, type; 53219820Sjeff 54219820Sjeff sc = gp->softc; 55219820Sjeff 56219820Sjeff flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 57219820Sjeff if (flags == NULL) { 58219820Sjeff gctl_error(req, "no flags given"); 59219820Sjeff return; 60219820Sjeff } 61219820Sjeff 62219820Sjeff newname = gctl_get_param(req, "newname", NULL); 63219820Sjeff if (newname == NULL) { 64219820Sjeff gctl_error(req, "no new name given"); 65219820Sjeff return; 66219820Sjeff } 67219820Sjeff 68219820Sjeff object = gctl_get_param(req, "object", NULL); 69219820Sjeff if (object == NULL) { 70219820Sjeff gctl_error(req, "no object given"); 71219820Sjeff return; 72219820Sjeff } 73219820Sjeff 74219820Sjeff type = gv_object_type(sc, object); 75219820Sjeff switch (type) { 76219820Sjeff case GV_TYPE_VOL: 77219820Sjeff v = gv_find_vol(sc, object); 78219820Sjeff if (v == NULL) { 79219820Sjeff gctl_error(req, "unknown volume '%s'", object); 80219820Sjeff return; 81219820Sjeff } 82219820Sjeff name = g_malloc(GV_MAXVOLNAME, M_WAITOK | M_ZERO); 83219820Sjeff strlcpy(name, newname, GV_MAXVOLNAME); 84219820Sjeff gv_post_event(sc, GV_EVENT_RENAME_VOL, v, name, *flags, 0); 85219820Sjeff break; 86219820Sjeff case GV_TYPE_PLEX: 87219820Sjeff p = gv_find_plex(sc, object); 88219820Sjeff if (p == NULL) { 89219820Sjeff gctl_error(req, "unknown plex '%s'", object); 90219820Sjeff return; 91219820Sjeff } 92219820Sjeff name = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 93219820Sjeff strlcpy(name, newname, GV_MAXPLEXNAME); 94219820Sjeff gv_post_event(sc, GV_EVENT_RENAME_PLEX, p, name, *flags, 0); 95219820Sjeff break; 96219820Sjeff case GV_TYPE_SD: 97219820Sjeff s = gv_find_sd(sc, object); 98219820Sjeff if (s == NULL) { 99219820Sjeff gctl_error(req, "unknown subdisk '%s'", object); 100219820Sjeff return; 101219820Sjeff } 102219820Sjeff name = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 103219820Sjeff strlcpy(name, newname, GV_MAXSDNAME); 104219820Sjeff gv_post_event(sc, GV_EVENT_RENAME_SD, s, name, *flags, 0); 105219820Sjeff break; 106219820Sjeff case GV_TYPE_DRIVE: 107219820Sjeff d = gv_find_drive(sc, object); 108219820Sjeff if (d == NULL) { 109219820Sjeff gctl_error(req, "unknown drive '%s'", object); 110219820Sjeff return; 111219820Sjeff } 112219820Sjeff name = g_malloc(GV_MAXDRIVENAME, M_WAITOK | M_ZERO); 113219820Sjeff strlcpy(name, newname, GV_MAXDRIVENAME); 114219820Sjeff gv_post_event(sc, GV_EVENT_RENAME_DRIVE, d, name, *flags, 0); 115219820Sjeff break; 116219820Sjeff default: 117219820Sjeff gctl_error(req, "unknown object '%s'", object); 118219820Sjeff return; 119219820Sjeff } 120219820Sjeff} 121219820Sjeff 122219820Sjeffint 123219820Sjeffgv_rename_drive(struct gv_softc *sc, struct gv_drive *d, char *newname, 124219820Sjeff int flags) 125219820Sjeff{ 126219820Sjeff struct gv_sd *s; 127219820Sjeff 128219820Sjeff KASSERT(d != NULL, ("gv_rename_drive: NULL d")); 129219820Sjeff 130219820Sjeff if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { 131219820Sjeff G_VINUM_DEBUG(1, "drive name '%s' already in use", newname); 132219820Sjeff return (GV_ERR_NAMETAKEN); 133219820Sjeff } 134219820Sjeff 135219820Sjeff strlcpy(d->name, newname, sizeof(d->name)); 136219820Sjeff if (d->hdr != NULL) 137219820Sjeff strlcpy(d->hdr->label.name, newname, sizeof(d->hdr->label.name)); 138219820Sjeff 139219820Sjeff LIST_FOREACH(s, &d->subdisks, from_drive) 140219820Sjeff strlcpy(s->drive, d->name, sizeof(s->drive)); 141219820Sjeff 142219820Sjeff return (0); 143219820Sjeff} 144219820Sjeff 145219820Sjeffint 146219820Sjeffgv_rename_plex(struct gv_softc *sc, struct gv_plex *p, char *newname, int flags) 147219820Sjeff{ 148219820Sjeff char newsd[GV_MAXSDNAME]; 149219820Sjeff struct gv_sd *s; 150219820Sjeff char *ptr; 151219820Sjeff int err; 152219820Sjeff 153219820Sjeff KASSERT(p != NULL, ("gv_rename_plex: NULL p")); 154219820Sjeff 155219820Sjeff if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { 156219820Sjeff G_VINUM_DEBUG(1, "plex name '%s' already in use", newname); 157219820Sjeff return (GV_ERR_NAMETAKEN); 158219820Sjeff } 159219820Sjeff 160219820Sjeff /* 161219820Sjeff * Locate the plex number part of the plex names. 162219820Sjeff * XXX: might be a good idea to sanitize input a bit more 163219820Sjeff */ 164219820Sjeff ptr = strrchr(newname, '.'); 165219820Sjeff if (ptr == NULL) { 166219820Sjeff G_VINUM_DEBUG(0, "proposed plex name '%s' is not a valid plex " 167219820Sjeff "name", newname); 168219820Sjeff return (GV_ERR_INVNAME); 169219820Sjeff } 170219820Sjeff 171219820Sjeff strlcpy(p->name, newname, sizeof(p->name)); 172219820Sjeff 173219820Sjeff /* Fix up references and potentially rename subdisks. */ 174219820Sjeff LIST_FOREACH(s, &p->subdisks, in_plex) { 175219820Sjeff strlcpy(s->plex, p->name, sizeof(s->plex)); 176219820Sjeff if (flags & GV_FLAG_R) { 177219820Sjeff /* 178219820Sjeff * Look for the two last dots in the string, and assume 179219820Sjeff * that the old value was ok. 180219820Sjeff */ 181219820Sjeff ptr = strrchr(s->name, '.'); 182219820Sjeff if (ptr == NULL) 183219820Sjeff return (GV_ERR_INVNAME); 184219820Sjeff ptr++; 185219820Sjeff snprintf(newsd, sizeof(newsd), "%s.%s", p->name, ptr); 186219820Sjeff err = gv_rename_sd(sc, s, newsd, flags); 187219820Sjeff if (err) 188219820Sjeff return (err); 189219820Sjeff } 190219820Sjeff } 191219820Sjeff return (0); 192219820Sjeff} 193219820Sjeff 194219820Sjeff/* 195219820Sjeff * gv_rename_sd: renames a subdisk. Note that the 'flags' argument is ignored, 196219820Sjeff * since there are no structures below a subdisk. Similarly, we don't have to 197219820Sjeff * clean up any references elsewhere to the subdisk's name. 198219820Sjeff */ 199219820Sjeffint 200219820Sjeffgv_rename_sd(struct gv_softc *sc, struct gv_sd *s, char *newname, int flags) 201219820Sjeff{ 202219820Sjeff char *dot1, *dot2; 203219820Sjeff 204219820Sjeff KASSERT(s != NULL, ("gv_rename_sd: NULL s")); 205219820Sjeff 206219820Sjeff if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { 207219820Sjeff G_VINUM_DEBUG(1, "subdisk name %s already in use", newname); 208219820Sjeff return (GV_ERR_NAMETAKEN); 209219820Sjeff } 210219820Sjeff 211219820Sjeff /* Locate the sd number part of the sd names. */ 212219820Sjeff dot1 = strchr(newname, '.'); 213219820Sjeff if (dot1 == NULL || (dot2 = strchr(dot1 + 1, '.')) == NULL) { 214219820Sjeff G_VINUM_DEBUG(0, "proposed sd name '%s' is not a valid sd name", 215219820Sjeff newname); 216219820Sjeff return (GV_ERR_INVNAME); 217219820Sjeff } 218219820Sjeff strlcpy(s->name, newname, sizeof(s->name)); 219219820Sjeff return (0); 220219820Sjeff} 221219820Sjeff 222219820Sjeffint 223219820Sjeffgv_rename_vol(struct gv_softc *sc, struct gv_volume *v, char *newname, 224219820Sjeff int flags) 225219820Sjeff{ 226219820Sjeff struct g_provider *pp; 227219820Sjeff struct gv_plex *p; 228219820Sjeff char newplex[GV_MAXPLEXNAME], *ptr; 229219820Sjeff int err; 230219820Sjeff 231219820Sjeff KASSERT(v != NULL, ("gv_rename_vol: NULL v")); 232219820Sjeff pp = v->provider; 233219820Sjeff KASSERT(pp != NULL, ("gv_rename_vol: NULL pp")); 234219820Sjeff 235219820Sjeff if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { 236219820Sjeff G_VINUM_DEBUG(1, "volume name %s already in use", newname); 237219820Sjeff return (GV_ERR_NAMETAKEN); 238219820Sjeff } 239219820Sjeff 240219820Sjeff /* Rename the volume. */ 241219820Sjeff strlcpy(v->name, newname, sizeof(v->name)); 242219820Sjeff 243219820Sjeff /* Fix up references and potentially rename plexes. */ 244219820Sjeff LIST_FOREACH(p, &v->plexes, in_volume) { 245219820Sjeff strlcpy(p->volume, v->name, sizeof(p->volume)); 246219820Sjeff if (flags & GV_FLAG_R) { 247219820Sjeff /* 248219820Sjeff * Look for the last dot in the string, and assume that 249219820Sjeff * the old value was ok. 250219820Sjeff */ 251219820Sjeff ptr = strrchr(p->name, '.'); 252219820Sjeff ptr++; 253219820Sjeff snprintf(newplex, sizeof(newplex), "%s.%s", v->name, ptr); 254219820Sjeff err = gv_rename_plex(sc, p, newplex, flags); 255219820Sjeff if (err) 256219820Sjeff return (err); 257219820Sjeff } 258219820Sjeff } 259219820Sjeff 260219820Sjeff return (0); 261219820Sjeff} 262219820Sjeff