xref: /freebsd/sys/geom/vinum/geom_vinum_rename.c (revision 4928135658a9d0eaee37003df6137ab363fcb0b4)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  *  Copyright (c) 2005 Chris Jones
5  *  All rights reserved.
6  *
7  * This software was developed for the FreeBSD Project by Chris Jones
8  * thanks to the support of Google's Summer of Code program and
9  * mentoring by Lukas Ertl.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/libkern.h>
39 #include <sys/malloc.h>
40 
41 #include <geom/geom.h>
42 #include <geom/vinum/geom_vinum_var.h>
43 #include <geom/vinum/geom_vinum.h>
44 
45 void
46 gv_rename(struct g_geom *gp, struct gctl_req *req)
47 {
48 	struct gv_softc *sc;
49 	struct gv_volume *v;
50 	struct gv_plex *p;
51 	struct gv_sd *s;
52 	struct gv_drive *d;
53 	char *newname, *object, *name;
54 	int *flags, type;
55 
56 	sc = gp->softc;
57 
58 	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
59 	if (flags == NULL) {
60 		gctl_error(req, "no flags given");
61 		return;
62 	}
63 
64 	newname = gctl_get_param(req, "newname", NULL);
65 	if (newname == NULL) {
66 		gctl_error(req, "no new name given");
67 		return;
68 	}
69 
70 	object = gctl_get_param(req, "object", NULL);
71 	if (object == NULL) {
72 		gctl_error(req, "no object given");
73 		return;
74 	}
75 
76 	type = gv_object_type(sc, object);
77 	switch (type) {
78 	case GV_TYPE_VOL:
79 		v = gv_find_vol(sc, object);
80 		if (v == NULL) 	{
81 			gctl_error(req, "unknown volume '%s'", object);
82 			return;
83 		}
84 		name = g_malloc(GV_MAXVOLNAME, M_WAITOK | M_ZERO);
85 		strlcpy(name, newname, GV_MAXVOLNAME);
86 		gv_post_event(sc, GV_EVENT_RENAME_VOL, v, name, *flags, 0);
87 		break;
88 	case GV_TYPE_PLEX:
89 		p = gv_find_plex(sc, object);
90 		if (p == NULL) {
91 			gctl_error(req, "unknown plex '%s'", object);
92 			return;
93 		}
94 		name = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
95 		strlcpy(name, newname, GV_MAXPLEXNAME);
96 		gv_post_event(sc, GV_EVENT_RENAME_PLEX, p, name, *flags, 0);
97 		break;
98 	case GV_TYPE_SD:
99 		s = gv_find_sd(sc, object);
100 		if (s == NULL) {
101 			gctl_error(req, "unknown subdisk '%s'", object);
102 			return;
103 		}
104 		name = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
105 		strlcpy(name, newname, GV_MAXSDNAME);
106 		gv_post_event(sc, GV_EVENT_RENAME_SD, s, name, *flags, 0);
107 		break;
108 	case GV_TYPE_DRIVE:
109 		d = gv_find_drive(sc, object);
110 		if (d == NULL) {
111 			gctl_error(req, "unknown drive '%s'", object);
112 			return;
113 		}
114 		name = g_malloc(GV_MAXDRIVENAME, M_WAITOK | M_ZERO);
115 		strlcpy(name, newname, GV_MAXDRIVENAME);
116 		gv_post_event(sc, GV_EVENT_RENAME_DRIVE, d, name, *flags, 0);
117 		break;
118 	default:
119 		gctl_error(req, "unknown object '%s'", object);
120 		return;
121 	}
122 }
123 
124 int
125 gv_rename_drive(struct gv_softc *sc, struct gv_drive *d, char *newname,
126     int flags)
127 {
128 	struct gv_sd *s;
129 
130 	KASSERT(d != NULL, ("gv_rename_drive: NULL d"));
131 
132 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
133 		G_VINUM_DEBUG(1, "drive name '%s' already in use", newname);
134 		return (GV_ERR_NAMETAKEN);
135 	}
136 
137 	strlcpy(d->name, newname, sizeof(d->name));
138 	if (d->hdr != NULL)
139 		strlcpy(d->hdr->label.name, newname, sizeof(d->hdr->label.name));
140 
141 	LIST_FOREACH(s, &d->subdisks, from_drive)
142 		strlcpy(s->drive, d->name, sizeof(s->drive));
143 
144 	return (0);
145 }
146 
147 int
148 gv_rename_plex(struct gv_softc *sc, struct gv_plex *p, char *newname, int flags)
149 {
150 	char newsd[GV_MAXSDNAME];
151 	struct gv_sd *s;
152 	char *ptr;
153 	int err;
154 
155 	KASSERT(p != NULL, ("gv_rename_plex: NULL p"));
156 
157 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
158 		G_VINUM_DEBUG(1, "plex name '%s' already in use", newname);
159 		return (GV_ERR_NAMETAKEN);
160 	}
161 
162 	/*
163 	 * Locate the plex number part of the plex names.
164 	 * XXX: might be a good idea to sanitize input a bit more
165 	 */
166 	ptr = strrchr(newname, '.');
167 	if (ptr == NULL) {
168 		G_VINUM_DEBUG(0, "proposed plex name '%s' is not a valid plex "
169 		    "name", newname);
170 		return (GV_ERR_INVNAME);
171 	}
172 
173 	strlcpy(p->name, newname, sizeof(p->name));
174 
175 	/* Fix up references and potentially rename subdisks. */
176 	LIST_FOREACH(s, &p->subdisks, in_plex) {
177 		strlcpy(s->plex, p->name, sizeof(s->plex));
178 		if (flags & GV_FLAG_R) {
179 			/*
180 			 * Look for the two last dots in the string, and assume
181 			 * that the old value was ok.
182 			 */
183 			ptr = strrchr(s->name, '.');
184 			if (ptr == NULL)
185 				return (GV_ERR_INVNAME);
186 			ptr++;
187 			snprintf(newsd, sizeof(newsd), "%s.%s", p->name, ptr);
188 			err = gv_rename_sd(sc, s, newsd, flags);
189 			if (err)
190 				return (err);
191 		}
192 	}
193 	return (0);
194 }
195 
196 /*
197  * gv_rename_sd: renames a subdisk.  Note that the 'flags' argument is ignored,
198  * since there are no structures below a subdisk.  Similarly, we don't have to
199  * clean up any references elsewhere to the subdisk's name.
200  */
201 int
202 gv_rename_sd(struct gv_softc *sc, struct gv_sd *s, char *newname, int flags)
203 {
204 	char *dot1, *dot2;
205 
206 	KASSERT(s != NULL, ("gv_rename_sd: NULL s"));
207 
208 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
209 		G_VINUM_DEBUG(1, "subdisk name %s already in use", newname);
210 		return (GV_ERR_NAMETAKEN);
211 	}
212 
213 	/* Locate the sd number part of the sd names. */
214 	dot1 = strchr(newname, '.');
215 	if (dot1 == NULL || (dot2 = strchr(dot1 +  1, '.')) == NULL) {
216 		G_VINUM_DEBUG(0, "proposed sd name '%s' is not a valid sd name",
217 		    newname);
218 		return (GV_ERR_INVNAME);
219 	}
220 	strlcpy(s->name, newname, sizeof(s->name));
221 	return (0);
222 }
223 
224 int
225 gv_rename_vol(struct gv_softc *sc, struct gv_volume *v, char *newname,
226     int flags)
227 {
228 	struct g_provider *pp;
229 	struct gv_plex *p;
230 	char newplex[GV_MAXPLEXNAME], *ptr;
231 	int err;
232 
233 	KASSERT(v != NULL, ("gv_rename_vol: NULL v"));
234 	pp = v->provider;
235 	KASSERT(pp != NULL, ("gv_rename_vol: NULL pp"));
236 
237 	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
238 		G_VINUM_DEBUG(1, "volume name %s already in use", newname);
239 		return (GV_ERR_NAMETAKEN);
240 	}
241 
242 	/* Rename the volume. */
243 	strlcpy(v->name, newname, sizeof(v->name));
244 
245 	/* Fix up references and potentially rename plexes. */
246 	LIST_FOREACH(p, &v->plexes, in_volume) {
247 		strlcpy(p->volume, v->name, sizeof(p->volume));
248 		if (flags & GV_FLAG_R) {
249 			/*
250 			 * Look for the last dot in the string, and assume that
251 			 * the old value was ok.
252 			 */
253 			ptr = strrchr(p->name, '.');
254 			ptr++;
255 			snprintf(newplex, sizeof(newplex), "%s.%s", v->name, ptr);
256 			err = gv_rename_plex(sc, p, newplex, flags);
257 			if (err)
258 				return (err);
259 		}
260 	}
261 
262 	return (0);
263 }
264