1 /*- 2 * Copyright (c) 2005 Chris Jones 3 * All rights reserved. 4 * 5 * This software was developed for the FreeBSD Project by Chris Jones 6 * thanks to the support of Google's Summer of Code program and 7 * mentoring by Lukas Ertl. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/libkern.h> 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 40 #include <geom/geom.h> 41 #include <geom/vinum/geom_vinum_var.h> 42 #include <geom/vinum/geom_vinum.h> 43 #include <geom/vinum/geom_vinum_share.h> 44 45 static int gv_rename_drive(struct gv_softc *, struct gctl_req *, 46 struct gv_drive *, char *, int); 47 static int gv_rename_plex(struct gv_softc *, struct gctl_req *, 48 struct gv_plex *, char *, int); 49 static int gv_rename_sd(struct gv_softc *, struct gctl_req *, 50 struct gv_sd *, char *, int); 51 static int gv_rename_vol(struct gv_softc *, struct gctl_req *, 52 struct gv_volume *, char *, int); 53 54 void 55 gv_rename(struct g_geom *gp, struct gctl_req *req) 56 { 57 struct gv_softc *sc; 58 struct gv_volume *v; 59 struct gv_plex *p; 60 struct gv_sd *s; 61 struct gv_drive *d; 62 char *newname, *object; 63 int err, *flags, type; 64 65 sc = gp->softc; 66 67 flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 68 69 newname = gctl_get_param(req, "newname", NULL); 70 if (newname == NULL) { 71 gctl_error(req, "no new name given"); 72 return; 73 } 74 75 object = gctl_get_param(req, "object", NULL); 76 if (object == NULL) { 77 gctl_error(req, "no object given"); 78 return; 79 } 80 81 type = gv_object_type(sc, object); 82 switch (type) { 83 case GV_TYPE_VOL: 84 v = gv_find_vol(sc, object); 85 if (v == NULL) { 86 gctl_error(req, "unknown volume '%s'", object); 87 return; 88 } 89 err = gv_rename_vol(sc, req, v, newname, *flags); 90 if (err) 91 return; 92 break; 93 case GV_TYPE_PLEX: 94 p = gv_find_plex(sc, object); 95 if (p == NULL) { 96 gctl_error(req, "unknown plex '%s'", object); 97 return; 98 } 99 err = gv_rename_plex(sc, req, p, newname, *flags); 100 if (err) 101 return; 102 break; 103 case GV_TYPE_SD: 104 s = gv_find_sd(sc, object); 105 if (s == NULL) { 106 gctl_error(req, "unknown subdisk '%s'", object); 107 return; 108 } 109 err = gv_rename_sd(sc, req, s, newname, *flags); 110 if (err) 111 return; 112 break; 113 case GV_TYPE_DRIVE: 114 d = gv_find_drive(sc, object); 115 if (d == NULL) { 116 gctl_error(req, "unknown drive '%s'", object); 117 return; 118 } 119 err = gv_rename_drive(sc, req, d, newname, *flags); 120 if (err) 121 return; 122 break; 123 default: 124 gctl_error(req, "unknown object '%s'", object); 125 return; 126 } 127 128 gv_save_config_all(sc); 129 } 130 131 static int 132 gv_rename_drive(struct gv_softc *sc, struct gctl_req *req, struct gv_drive *d, char *newname, int flags) 133 { 134 struct gv_sd *s; 135 136 g_topology_assert(); 137 KASSERT(d != NULL, ("gv_rename_drive: NULL d")); 138 139 if (gv_object_type(sc, newname) != -1) { 140 gctl_error(req, "drive name '%s' already in use", newname); 141 return (-1); 142 } 143 144 strncpy(d->name, newname, GV_MAXDRIVENAME); 145 146 /* XXX can we rename providers here? */ 147 148 LIST_FOREACH(s, &d->subdisks, from_drive) 149 strncpy(s->drive, d->name, GV_MAXDRIVENAME); 150 151 return (0); 152 } 153 154 static int 155 gv_rename_plex(struct gv_softc *sc, struct gctl_req *req, struct gv_plex *p, char *newname, int flags) 156 { 157 struct gv_sd *s; 158 char *plexnum, *plexnump, *oldplex, *oldplexp; 159 char *newsd, *oldsd, *oldsdp; 160 int err; 161 162 g_topology_assert(); 163 KASSERT(p != NULL, ("gv_rename_plex: NULL p")); 164 165 err = 0; 166 167 if (gv_object_type(sc, newname) != -1) { 168 gctl_error(req, "plex name '%s' already in use", newname); 169 return (-1); 170 } 171 172 /* Needed for sanity checking. */ 173 plexnum = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 174 strncpy(plexnum, newname, GV_MAXPLEXNAME); 175 plexnump = plexnum; 176 177 oldplex = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 178 strncpy(oldplex, p->name, GV_MAXPLEXNAME); 179 oldplexp = oldplex; 180 181 /* 182 * Locate the plex number part of the plex names. 183 * 184 * XXX: can we be sure that the current plex name has the format 185 * 'foo.pX'? 186 */ 187 strsep(&oldplexp, "."); 188 strsep(&plexnump, "."); 189 if (plexnump == NULL || *plexnump == '\0') { 190 gctl_error(req, "proposed plex name '%s' is not a valid plex " 191 "name", newname); 192 err = -1; 193 goto failure; 194 } 195 if (strcmp(oldplexp, plexnump)) { 196 gctl_error(req, "current and proposed plex numbers (%s, %s) " 197 "do not match", plexnump, oldplexp); 198 err = -1; 199 goto failure; 200 } 201 202 strncpy(p->name, newname, GV_MAXPLEXNAME); 203 204 /* XXX can we rename providers here? */ 205 206 /* Fix up references and potentially rename subdisks. */ 207 LIST_FOREACH(s, &p->subdisks, in_plex) { 208 strncpy(s->plex, p->name, GV_MAXPLEXNAME); 209 if (flags && GV_FLAG_R) { 210 newsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 211 oldsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 212 oldsdp = oldsd; 213 strncpy(oldsd, s->name, GV_MAXSDNAME); 214 /* 215 * XXX: can we be sure that the current sd name has the 216 * format 'foo.pX.sY'? 217 */ 218 strsep(&oldsdp, "."); 219 strsep(&oldsdp, "."); 220 snprintf(newsd, GV_MAXSDNAME, "%s.%s", p->name, oldsdp); 221 err = gv_rename_sd(sc, req, s, newsd, flags); 222 g_free(newsd); 223 g_free(oldsd); 224 if (err) 225 goto failure; 226 } 227 } 228 229 failure: 230 g_free(plexnum); 231 g_free(oldplex); 232 233 return (err); 234 } 235 236 /* 237 * gv_rename_sd: renames a subdisk. Note that the 'flags' argument is ignored, 238 * since there are no structures below a subdisk. Similarly, we don't have to 239 * clean up any references elsewhere to the subdisk's name. 240 */ 241 static int 242 gv_rename_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *s, char * newname, int flags) 243 { 244 char *new, *newp, *old, *oldp; 245 int err; 246 247 g_topology_assert(); 248 KASSERT(s != NULL, ("gv_rename_sd: NULL s")); 249 250 err = 0; 251 252 if (gv_object_type(sc, newname) != -1) { 253 gctl_error(req, "subdisk name %s already in use", newname); 254 return (-1); 255 } 256 257 /* Needed for sanity checking. */ 258 new = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 259 strncpy(new, newname, GV_MAXSDNAME); 260 newp = new; 261 262 old = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 263 strncpy(old, s->name, GV_MAXSDNAME); 264 oldp = old; 265 266 /* 267 * Locate the sd number part of the sd names. 268 * 269 * XXX: can we be sure that the current sd name has the format 270 * 'foo.pX.sY'? 271 */ 272 strsep(&oldp, "."); 273 strsep(&oldp, "."); 274 strsep(&newp, "."); 275 if (newp == NULL || *newp == '\0') { 276 gctl_error(req, "proposed sd name '%s' is not a valid sd name", 277 newname); 278 err = -1; 279 goto fail; 280 } 281 strsep(&newp, "."); 282 if (newp == NULL || *newp == '\0') { 283 gctl_error(req, "proposed sd name '%s' is not a valid sd name", 284 newname); 285 err = -1; 286 goto fail; 287 } 288 if (strcmp(newp, oldp)) { 289 gctl_error(req, "current and proposed sd numbers (%s, %s) do " 290 "not match", oldp, newp); 291 err = -1; 292 goto fail; 293 } 294 295 strncpy(s->name, newname, GV_MAXSDNAME); 296 297 /* XXX: can we rename providers here? */ 298 299 fail: 300 g_free(new); 301 g_free(old); 302 303 return (err); 304 } 305 306 static int 307 gv_rename_vol(struct gv_softc *sc, struct gctl_req *req, struct gv_volume *v, char *newname, int flags) 308 { 309 struct gv_plex *p; 310 char *new, *old, *oldp; 311 int err; 312 313 g_topology_assert(); 314 KASSERT(v != NULL, ("gv_rename_vol: NULL v")); 315 316 if (gv_object_type(sc, newname) != -1) { 317 gctl_error(req, "volume name %s already in use", newname); 318 return (-1); 319 } 320 321 /* Rename the volume. */ 322 strncpy(v->name, newname, GV_MAXVOLNAME); 323 324 /* Fix up references and potentially rename plexes. */ 325 LIST_FOREACH(p, &v->plexes, in_volume) { 326 strncpy(p->volume, v->name, GV_MAXVOLNAME); 327 if (flags && GV_FLAG_R) { 328 new = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 329 old = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 330 oldp = old; 331 strncpy(old, p->name, GV_MAXPLEXNAME); 332 /* 333 * XXX: can we be sure that the current plex name has 334 * the format 'foo.pX'? 335 */ 336 strsep(&oldp, "."); 337 snprintf(new, GV_MAXPLEXNAME, "%s.%s", v->name, oldp); 338 err = gv_rename_plex(sc, req, p, new, flags); 339 g_free(new); 340 g_free(old); 341 if (err) 342 return (err); 343 } 344 } 345 346 return (0); 347 } 348