xref: /freebsd/sys/geom/vinum/geom_vinum_rename.c (revision 39beb93c)
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