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