xref: /freebsd/sys/geom/vinum/geom_vinum_rename.c (revision d93a896ef95946b0bf1219866fcb324b78543444)
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/malloc.h>
38 
39 #include <geom/geom.h>
40 #include <geom/vinum/geom_vinum_var.h>
41 #include <geom/vinum/geom_vinum.h>
42 
43 void
44 gv_rename(struct g_geom *gp, struct gctl_req *req)
45 {
46 	struct gv_softc *sc;
47 	struct gv_volume *v;
48 	struct gv_plex *p;
49 	struct gv_sd *s;
50 	struct gv_drive *d;
51 	char *newname, *object, *name;
52 	int *flags, type;
53 
54 	sc = gp->softc;
55 
56 	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
57 	if (flags == NULL) {
58 		gctl_error(req, "no flags given");
59 		return;
60 	}
61 
62 	newname = gctl_get_param(req, "newname", NULL);
63 	if (newname == NULL) {
64 		gctl_error(req, "no new name given");
65 		return;
66 	}
67 
68 	object = gctl_get_param(req, "object", NULL);
69 	if (object == NULL) {
70 		gctl_error(req, "no object given");
71 		return;
72 	}
73 
74 	type = gv_object_type(sc, object);
75 	switch (type) {
76 	case GV_TYPE_VOL:
77 		v = gv_find_vol(sc, object);
78 		if (v == NULL) 	{
79 			gctl_error(req, "unknown volume '%s'", object);
80 			return;
81 		}
82 		name = g_malloc(GV_MAXVOLNAME, M_WAITOK | M_ZERO);
83 		strlcpy(name, newname, GV_MAXVOLNAME);
84 		gv_post_event(sc, GV_EVENT_RENAME_VOL, v, name, *flags, 0);
85 		break;
86 	case GV_TYPE_PLEX:
87 		p = gv_find_plex(sc, object);
88 		if (p == NULL) {
89 			gctl_error(req, "unknown plex '%s'", object);
90 			return;
91 		}
92 		name = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
93 		strlcpy(name, newname, GV_MAXPLEXNAME);
94 		gv_post_event(sc, GV_EVENT_RENAME_PLEX, p, name, *flags, 0);
95 		break;
96 	case GV_TYPE_SD:
97 		s = gv_find_sd(sc, object);
98 		if (s == NULL) {
99 			gctl_error(req, "unknown subdisk '%s'", object);
100 			return;
101 		}
102 		name = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
103 		strlcpy(name, newname, GV_MAXSDNAME);
104 		gv_post_event(sc, GV_EVENT_RENAME_SD, s, name, *flags, 0);
105 		break;
106 	case GV_TYPE_DRIVE:
107 		d = gv_find_drive(sc, object);
108 		if (d == NULL) {
109 			gctl_error(req, "unknown drive '%s'", object);
110 			return;
111 		}
112 		name = g_malloc(GV_MAXDRIVENAME, M_WAITOK | M_ZERO);
113 		strlcpy(name, newname, GV_MAXDRIVENAME);
114 		gv_post_event(sc, GV_EVENT_RENAME_DRIVE, d, name, *flags, 0);
115 		break;
116 	default:
117 		gctl_error(req, "unknown object '%s'", object);
118 		return;
119 	}
120 }
121 
122 int
123 gv_rename_drive(struct gv_softc *sc, struct gv_drive *d, char *newname,
124     int flags)
125 {
126 	struct gv_sd *s;
127 
128 	KASSERT(d != NULL, ("gv_rename_drive: NULL d"));
129 
130 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
131 		G_VINUM_DEBUG(1, "drive name '%s' already in use", newname);
132 		return (GV_ERR_NAMETAKEN);
133 	}
134 
135 	strlcpy(d->name, newname, sizeof(d->name));
136 	if (d->hdr != NULL)
137 		strlcpy(d->hdr->label.name, newname, sizeof(d->hdr->label.name));
138 
139 	LIST_FOREACH(s, &d->subdisks, from_drive)
140 		strlcpy(s->drive, d->name, sizeof(s->drive));
141 
142 	return (0);
143 }
144 
145 int
146 gv_rename_plex(struct gv_softc *sc, struct gv_plex *p, char *newname, int flags)
147 {
148 	char newsd[GV_MAXSDNAME];
149 	struct gv_sd *s;
150 	char *ptr;
151 	int err;
152 
153 	KASSERT(p != NULL, ("gv_rename_plex: NULL p"));
154 
155 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
156 		G_VINUM_DEBUG(1, "plex name '%s' already in use", newname);
157 		return (GV_ERR_NAMETAKEN);
158 	}
159 
160 	/*
161 	 * Locate the plex number part of the plex names.
162 	 * XXX: might be a good idea to sanitize input a bit more
163 	 */
164 	ptr = strrchr(newname, '.');
165 	if (ptr == NULL) {
166 		G_VINUM_DEBUG(0, "proposed plex name '%s' is not a valid plex "
167 		    "name", newname);
168 		return (GV_ERR_INVNAME);
169 	}
170 
171 	strlcpy(p->name, newname, sizeof(p->name));
172 
173 	/* Fix up references and potentially rename subdisks. */
174 	LIST_FOREACH(s, &p->subdisks, in_plex) {
175 		strlcpy(s->plex, p->name, sizeof(s->plex));
176 		if (flags & GV_FLAG_R) {
177 			/*
178 			 * Look for the two last dots in the string, and assume
179 			 * that the old value was ok.
180 			 */
181 			ptr = strrchr(s->name, '.');
182 			if (ptr == NULL)
183 				return (GV_ERR_INVNAME);
184 			ptr++;
185 			snprintf(newsd, sizeof(newsd), "%s.%s", p->name, ptr);
186 			err = gv_rename_sd(sc, s, newsd, flags);
187 			if (err)
188 				return (err);
189 		}
190 	}
191 	return (0);
192 }
193 
194 /*
195  * gv_rename_sd: renames a subdisk.  Note that the 'flags' argument is ignored,
196  * since there are no structures below a subdisk.  Similarly, we don't have to
197  * clean up any references elsewhere to the subdisk's name.
198  */
199 int
200 gv_rename_sd(struct gv_softc *sc, struct gv_sd *s, char *newname, int flags)
201 {
202 	char *dot1, *dot2;
203 
204 	KASSERT(s != NULL, ("gv_rename_sd: NULL s"));
205 
206 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
207 		G_VINUM_DEBUG(1, "subdisk name %s already in use", newname);
208 		return (GV_ERR_NAMETAKEN);
209 	}
210 
211 	/* Locate the sd number part of the sd names. */
212 	dot1 = strchr(newname, '.');
213 	if (dot1 == NULL || (dot2 = strchr(dot1 +  1, '.')) == NULL) {
214 		G_VINUM_DEBUG(0, "proposed sd name '%s' is not a valid sd name",
215 		    newname);
216 		return (GV_ERR_INVNAME);
217 	}
218 	strlcpy(s->name, newname, sizeof(s->name));
219 	return (0);
220 }
221 
222 int
223 gv_rename_vol(struct gv_softc *sc, struct gv_volume *v, char *newname,
224     int flags)
225 {
226 	struct g_provider *pp;
227 	struct gv_plex *p;
228 	char newplex[GV_MAXPLEXNAME], *ptr;
229 	int err;
230 
231 	KASSERT(v != NULL, ("gv_rename_vol: NULL v"));
232 	pp = v->provider;
233 	KASSERT(pp != NULL, ("gv_rename_vol: NULL pp"));
234 
235 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
236 		G_VINUM_DEBUG(1, "volume name %s already in use", newname);
237 		return (GV_ERR_NAMETAKEN);
238 	}
239 
240 	/* Rename the volume. */
241 	strlcpy(v->name, newname, sizeof(v->name));
242 
243 	/* Fix up references and potentially rename plexes. */
244 	LIST_FOREACH(p, &v->plexes, in_volume) {
245 		strlcpy(p->volume, v->name, sizeof(p->volume));
246 		if (flags & GV_FLAG_R) {
247 			/*
248 			 * Look for the last dot in the string, and assume that
249 			 * the old value was ok.
250 			 */
251 			ptr = strrchr(p->name, '.');
252 			ptr++;
253 			snprintf(newplex, sizeof(newplex), "%s.%s", v->name, ptr);
254 			err = gv_rename_plex(sc, p, newplex, flags);
255 			if (err)
256 				return (err);
257 		}
258 	}
259 
260 	return (0);
261 }
262