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 if (flags == NULL) { 69 gctl_error(req, "no flags given"); 70 return; 71 } 72 73 newname = gctl_get_param(req, "newname", NULL); 74 if (newname == NULL) { 75 gctl_error(req, "no new name given"); 76 return; 77 } 78 79 object = gctl_get_param(req, "object", NULL); 80 if (object == NULL) { 81 gctl_error(req, "no object given"); 82 return; 83 } 84 85 type = gv_object_type(sc, object); 86 switch (type) { 87 case GV_TYPE_VOL: 88 v = gv_find_vol(sc, object); 89 if (v == NULL) { 90 gctl_error(req, "unknown volume '%s'", object); 91 return; 92 } 93 err = gv_rename_vol(sc, req, v, newname, *flags); 94 if (err) 95 return; 96 break; 97 case GV_TYPE_PLEX: 98 p = gv_find_plex(sc, object); 99 if (p == NULL) { 100 gctl_error(req, "unknown plex '%s'", object); 101 return; 102 } 103 err = gv_rename_plex(sc, req, p, newname, *flags); 104 if (err) 105 return; 106 break; 107 case GV_TYPE_SD: 108 s = gv_find_sd(sc, object); 109 if (s == NULL) { 110 gctl_error(req, "unknown subdisk '%s'", object); 111 return; 112 } 113 err = gv_rename_sd(sc, req, s, newname, *flags); 114 if (err) 115 return; 116 break; 117 case GV_TYPE_DRIVE: 118 d = gv_find_drive(sc, object); 119 if (d == NULL) { 120 gctl_error(req, "unknown drive '%s'", object); 121 return; 122 } 123 err = gv_rename_drive(sc, req, d, newname, *flags); 124 if (err) 125 return; 126 break; 127 default: 128 gctl_error(req, "unknown object '%s'", object); 129 return; 130 } 131 132 gv_save_config_all(sc); 133 } 134 135 static int 136 gv_rename_drive(struct gv_softc *sc, struct gctl_req *req, struct gv_drive *d, char *newname, int flags) 137 { 138 struct gv_sd *s; 139 140 g_topology_assert(); 141 KASSERT(d != NULL, ("gv_rename_drive: NULL d")); 142 143 if (gv_object_type(sc, newname) != -1) { 144 gctl_error(req, "drive name '%s' already in use", newname); 145 return (-1); 146 } 147 148 strncpy(d->name, newname, GV_MAXDRIVENAME); 149 strncpy(d->hdr->label.name, newname, GV_MAXDRIVENAME); 150 151 /* XXX can we rename providers here? */ 152 153 LIST_FOREACH(s, &d->subdisks, from_drive) 154 strncpy(s->drive, d->name, GV_MAXDRIVENAME); 155 156 return (0); 157 } 158 159 static int 160 gv_rename_plex(struct gv_softc *sc, struct gctl_req *req, struct gv_plex *p, char *newname, int flags) 161 { 162 struct gv_sd *s; 163 char *plexnum, *plexnump, *oldplex, *oldplexp; 164 char *newsd, *oldsd, *oldsdp; 165 int err; 166 167 g_topology_assert(); 168 KASSERT(p != NULL, ("gv_rename_plex: NULL p")); 169 170 err = 0; 171 172 if (gv_object_type(sc, newname) != -1) { 173 gctl_error(req, "plex name '%s' already in use", newname); 174 return (-1); 175 } 176 177 /* Needed for sanity checking. */ 178 plexnum = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 179 strncpy(plexnum, newname, GV_MAXPLEXNAME); 180 plexnump = plexnum; 181 182 oldplex = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 183 strncpy(oldplex, p->name, GV_MAXPLEXNAME); 184 oldplexp = oldplex; 185 186 /* 187 * Locate the plex number part of the plex names. 188 * 189 * XXX: can we be sure that the current plex name has the format 190 * 'foo.pX'? 191 */ 192 strsep(&oldplexp, "."); 193 strsep(&plexnump, "."); 194 if (plexnump == NULL || *plexnump == '\0') { 195 gctl_error(req, "proposed plex name '%s' is not a valid plex " 196 "name", newname); 197 err = -1; 198 goto failure; 199 } 200 if (strcmp(oldplexp, plexnump)) { 201 gctl_error(req, "current and proposed plex numbers (%s, %s) " 202 "do not match", plexnump, oldplexp); 203 err = -1; 204 goto failure; 205 } 206 207 strncpy(p->name, newname, GV_MAXPLEXNAME); 208 209 /* XXX can we rename providers here? */ 210 211 /* Fix up references and potentially rename subdisks. */ 212 LIST_FOREACH(s, &p->subdisks, in_plex) { 213 strncpy(s->plex, p->name, GV_MAXPLEXNAME); 214 if (flags && GV_FLAG_R) { 215 newsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 216 oldsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 217 oldsdp = oldsd; 218 strncpy(oldsd, s->name, GV_MAXSDNAME); 219 /* 220 * XXX: can we be sure that the current sd name has the 221 * format 'foo.pX.sY'? 222 */ 223 strsep(&oldsdp, "."); 224 strsep(&oldsdp, "."); 225 snprintf(newsd, GV_MAXSDNAME, "%s.%s", p->name, oldsdp); 226 err = gv_rename_sd(sc, req, s, newsd, flags); 227 g_free(newsd); 228 g_free(oldsd); 229 if (err) 230 goto failure; 231 } 232 } 233 234 failure: 235 g_free(plexnum); 236 g_free(oldplex); 237 238 return (err); 239 } 240 241 /* 242 * gv_rename_sd: renames a subdisk. Note that the 'flags' argument is ignored, 243 * since there are no structures below a subdisk. Similarly, we don't have to 244 * clean up any references elsewhere to the subdisk's name. 245 */ 246 static int 247 gv_rename_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *s, char * newname, int flags) 248 { 249 char *new, *newp, *old, *oldp; 250 int err; 251 252 g_topology_assert(); 253 KASSERT(s != NULL, ("gv_rename_sd: NULL s")); 254 255 err = 0; 256 257 if (gv_object_type(sc, newname) != -1) { 258 gctl_error(req, "subdisk name %s already in use", newname); 259 return (-1); 260 } 261 262 /* Needed for sanity checking. */ 263 new = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 264 strncpy(new, newname, GV_MAXSDNAME); 265 newp = new; 266 267 old = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); 268 strncpy(old, s->name, GV_MAXSDNAME); 269 oldp = old; 270 271 /* 272 * Locate the sd number part of the sd names. 273 * 274 * XXX: can we be sure that the current sd name has the format 275 * 'foo.pX.sY'? 276 */ 277 strsep(&oldp, "."); 278 strsep(&oldp, "."); 279 strsep(&newp, "."); 280 if (newp == NULL || *newp == '\0') { 281 gctl_error(req, "proposed sd name '%s' is not a valid sd name", 282 newname); 283 err = -1; 284 goto fail; 285 } 286 strsep(&newp, "."); 287 if (newp == NULL || *newp == '\0') { 288 gctl_error(req, "proposed sd name '%s' is not a valid sd name", 289 newname); 290 err = -1; 291 goto fail; 292 } 293 if (strcmp(newp, oldp)) { 294 gctl_error(req, "current and proposed sd numbers (%s, %s) do " 295 "not match", oldp, newp); 296 err = -1; 297 goto fail; 298 } 299 300 strncpy(s->name, newname, GV_MAXSDNAME); 301 302 /* XXX: can we rename providers here? */ 303 304 fail: 305 g_free(new); 306 g_free(old); 307 308 return (err); 309 } 310 311 static int 312 gv_rename_vol(struct gv_softc *sc, struct gctl_req *req, struct gv_volume *v, char *newname, int flags) 313 { 314 struct gv_plex *p; 315 char *new, *old, *oldp; 316 int err; 317 318 g_topology_assert(); 319 KASSERT(v != NULL, ("gv_rename_vol: NULL v")); 320 321 if (gv_object_type(sc, newname) != -1) { 322 gctl_error(req, "volume name %s already in use", newname); 323 return (-1); 324 } 325 326 /* Rename the volume. */ 327 strncpy(v->name, newname, GV_MAXVOLNAME); 328 329 /* Fix up references and potentially rename plexes. */ 330 LIST_FOREACH(p, &v->plexes, in_volume) { 331 strncpy(p->volume, v->name, GV_MAXVOLNAME); 332 if (flags && GV_FLAG_R) { 333 new = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 334 old = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); 335 oldp = old; 336 strncpy(old, p->name, GV_MAXPLEXNAME); 337 /* 338 * XXX: can we be sure that the current plex name has 339 * the format 'foo.pX'? 340 */ 341 strsep(&oldp, "."); 342 snprintf(new, GV_MAXPLEXNAME, "%s.%s", v->name, oldp); 343 err = gv_rename_plex(sc, req, p, new, flags); 344 g_free(new); 345 g_free(old); 346 if (err) 347 return (err); 348 } 349 } 350 351 return (0); 352 } 353