1152615Sle/*-
2152615Sle *  Copyright (c) 2005 Chris Jones
3152615Sle *  All rights reserved.
4152615Sle *
5152615Sle * This software was developed for the FreeBSD Project by Chris Jones
6152615Sle * thanks to the support of Google's Summer of Code program and
7152615Sle * mentoring by Lukas Ertl.
8152634Sle *
9152615Sle * Redistribution and use in source and binary forms, with or without
10152615Sle * modification, are permitted provided that the following conditions
11152615Sle * are met:
12152615Sle * 1. Redistributions of source code must retain the above copyright
13152615Sle *    notice, this list of conditions and the following disclaimer.
14152615Sle * 2. Redistributions in binary form must reproduce the above copyright
15152615Sle *    notice, this list of conditions and the following disclaimer in the
16152615Sle *    documentation and/or other materials provided with the distribution.
17152634Sle *
18152615Sle * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19152615Sle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20152615Sle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21152615Sle * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22152615Sle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23152615Sle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24152615Sle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25152615Sle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26152615Sle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27152615Sle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28152615Sle * SUCH DAMAGE.
29152615Sle *
30152615Sle */
31152615Sle
32152615Sle#include <sys/cdefs.h>
33152615Sle__FBSDID("$FreeBSD$");
34152615Sle
35152615Sle#include <sys/param.h>
36152615Sle#include <sys/libkern.h>
37152615Sle#include <sys/malloc.h>
38152615Sle
39152615Sle#include <geom/geom.h>
40152615Sle#include <geom/vinum/geom_vinum_var.h>
41152615Sle#include <geom/vinum/geom_vinum.h>
42152615Sle
43152615Slevoid
44152615Slegv_rename(struct g_geom *gp, struct gctl_req *req)
45152615Sle{
46152615Sle	struct gv_softc *sc;
47152615Sle	struct gv_volume *v;
48152615Sle	struct gv_plex *p;
49152615Sle	struct gv_sd *s;
50152615Sle	struct gv_drive *d;
51190507Slulf	char *newname, *object, *name;
52190507Slulf	int *flags, type;
53152615Sle
54152615Sle	sc = gp->softc;
55152615Sle
56152615Sle	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
57185309Slulf	if (flags == NULL) {
58185309Slulf		gctl_error(req, "no flags given");
59185309Slulf		return;
60185309Slulf	}
61152615Sle
62152615Sle	newname = gctl_get_param(req, "newname", NULL);
63152615Sle	if (newname == NULL) {
64152615Sle		gctl_error(req, "no new name given");
65152615Sle		return;
66152615Sle	}
67152615Sle
68152615Sle	object = gctl_get_param(req, "object", NULL);
69152615Sle	if (object == NULL) {
70152615Sle		gctl_error(req, "no object given");
71152615Sle		return;
72152615Sle	}
73152615Sle
74152615Sle	type = gv_object_type(sc, object);
75152615Sle	switch (type) {
76152615Sle	case GV_TYPE_VOL:
77152615Sle		v = gv_find_vol(sc, object);
78152615Sle		if (v == NULL) 	{
79152615Sle			gctl_error(req, "unknown volume '%s'", object);
80152615Sle			return;
81152615Sle		}
82190507Slulf		name = g_malloc(GV_MAXVOLNAME, M_WAITOK | M_ZERO);
83190507Slulf		strlcpy(name, newname, GV_MAXVOLNAME);
84190507Slulf		gv_post_event(sc, GV_EVENT_RENAME_VOL, v, name, *flags, 0);
85152615Sle		break;
86152615Sle	case GV_TYPE_PLEX:
87152615Sle		p = gv_find_plex(sc, object);
88152615Sle		if (p == NULL) {
89152615Sle			gctl_error(req, "unknown plex '%s'", object);
90152615Sle			return;
91152615Sle		}
92190507Slulf		name = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
93190507Slulf		strlcpy(name, newname, GV_MAXPLEXNAME);
94190507Slulf		gv_post_event(sc, GV_EVENT_RENAME_PLEX, p, name, *flags, 0);
95152615Sle		break;
96152615Sle	case GV_TYPE_SD:
97152615Sle		s = gv_find_sd(sc, object);
98152615Sle		if (s == NULL) {
99152615Sle			gctl_error(req, "unknown subdisk '%s'", object);
100152615Sle			return;
101152615Sle		}
102190507Slulf		name = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
103190507Slulf		strlcpy(name, newname, GV_MAXSDNAME);
104190507Slulf		gv_post_event(sc, GV_EVENT_RENAME_SD, s, name, *flags, 0);
105152615Sle		break;
106152615Sle	case GV_TYPE_DRIVE:
107152615Sle		d = gv_find_drive(sc, object);
108152615Sle		if (d == NULL) {
109152615Sle			gctl_error(req, "unknown drive '%s'", object);
110152615Sle			return;
111152615Sle		}
112190507Slulf		name = g_malloc(GV_MAXDRIVENAME, M_WAITOK | M_ZERO);
113190507Slulf		strlcpy(name, newname, GV_MAXDRIVENAME);
114190507Slulf		gv_post_event(sc, GV_EVENT_RENAME_DRIVE, d, name, *flags, 0);
115152615Sle		break;
116152615Sle	default:
117152615Sle		gctl_error(req, "unknown object '%s'", object);
118152615Sle		return;
119152615Sle	}
120152615Sle}
121152615Sle
122190507Slulfint
123190507Slulfgv_rename_drive(struct gv_softc *sc, struct gv_drive *d, char *newname,
124190507Slulf    int flags)
125152615Sle{
126152615Sle	struct gv_sd *s;
127152615Sle
128152615Sle	KASSERT(d != NULL, ("gv_rename_drive: NULL d"));
129152615Sle
130190507Slulf	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
131190507Slulf		G_VINUM_DEBUG(1, "drive name '%s' already in use", newname);
132190507Slulf		return (GV_ERR_NAMETAKEN);
133152615Sle	}
134152615Sle
135190507Slulf	strlcpy(d->name, newname, sizeof(d->name));
136190507Slulf	if (d->hdr != NULL)
137190507Slulf		strlcpy(d->hdr->label.name, newname, sizeof(d->hdr->label.name));
138152615Sle
139152615Sle	LIST_FOREACH(s, &d->subdisks, from_drive)
140190507Slulf		strlcpy(s->drive, d->name, sizeof(s->drive));
141152615Sle
142152615Sle	return (0);
143152615Sle}
144152615Sle
145190507Slulfint
146190507Slulfgv_rename_plex(struct gv_softc *sc, struct gv_plex *p, char *newname, int flags)
147152615Sle{
148190507Slulf	char newsd[GV_MAXSDNAME];
149152615Sle	struct gv_sd *s;
150190507Slulf	char *ptr;
151152615Sle	int err;
152152615Sle
153152615Sle	KASSERT(p != NULL, ("gv_rename_plex: NULL p"));
154152615Sle
155190507Slulf	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
156190507Slulf		G_VINUM_DEBUG(1, "plex name '%s' already in use", newname);
157190507Slulf		return (GV_ERR_NAMETAKEN);
158152615Sle	}
159152615Sle
160152633Sle	/*
161152633Sle	 * Locate the plex number part of the plex names.
162190507Slulf	 * XXX: might be a good idea to sanitize input a bit more
163152633Sle	 */
164190507Slulf	ptr = strrchr(newname, '.');
165190507Slulf	if (ptr == NULL) {
166190507Slulf		G_VINUM_DEBUG(0, "proposed plex name '%s' is not a valid plex "
167152633Sle		    "name", newname);
168190507Slulf		return (GV_ERR_INVNAME);
169152633Sle	}
170152615Sle
171190507Slulf	strlcpy(p->name, newname, sizeof(p->name));
172152615Sle
173152615Sle	/* Fix up references and potentially rename subdisks. */
174152615Sle	LIST_FOREACH(s, &p->subdisks, in_plex) {
175190507Slulf		strlcpy(s->plex, p->name, sizeof(s->plex));
176213318Slulf		if (flags & GV_FLAG_R) {
177152633Sle			/*
178190507Slulf			 * Look for the two last dots in the string, and assume
179190507Slulf			 * that the old value was ok.
180152633Sle			 */
181190507Slulf			ptr = strrchr(s->name, '.');
182190507Slulf			if (ptr == NULL)
183190507Slulf				return (GV_ERR_INVNAME);
184190507Slulf			ptr++;
185190507Slulf			snprintf(newsd, sizeof(newsd), "%s.%s", p->name, ptr);
186190507Slulf			err = gv_rename_sd(sc, s, newsd, flags);
187152615Sle			if (err)
188190507Slulf				return (err);
189152615Sle		}
190152615Sle	}
191190507Slulf	return (0);
192152615Sle}
193152615Sle
194152615Sle/*
195152615Sle * gv_rename_sd: renames a subdisk.  Note that the 'flags' argument is ignored,
196152615Sle * since there are no structures below a subdisk.  Similarly, we don't have to
197152615Sle * clean up any references elsewhere to the subdisk's name.
198152615Sle */
199190507Slulfint
200190507Slulfgv_rename_sd(struct gv_softc *sc, struct gv_sd *s, char *newname, int flags)
201152615Sle{
202190507Slulf	char *dot1, *dot2;
203152615Sle
204152615Sle	KASSERT(s != NULL, ("gv_rename_sd: NULL s"));
205152615Sle
206190507Slulf	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
207190507Slulf		G_VINUM_DEBUG(1, "subdisk name %s already in use", newname);
208190507Slulf		return (GV_ERR_NAMETAKEN);
209152615Sle	}
210152615Sle
211190507Slulf	/* Locate the sd number part of the sd names. */
212190507Slulf	dot1 = strchr(newname, '.');
213190507Slulf	if (dot1 == NULL || (dot2 = strchr(dot1 +  1, '.')) == NULL) {
214190507Slulf		G_VINUM_DEBUG(0, "proposed sd name '%s' is not a valid sd name",
215152633Sle		    newname);
216190507Slulf		return (GV_ERR_INVNAME);
217152633Sle	}
218190507Slulf	strlcpy(s->name, newname, sizeof(s->name));
219190507Slulf	return (0);
220152615Sle}
221152615Sle
222190507Slulfint
223190507Slulfgv_rename_vol(struct gv_softc *sc, struct gv_volume *v, char *newname,
224190507Slulf    int flags)
225152615Sle{
226190507Slulf	struct g_provider *pp;
227152615Sle	struct gv_plex *p;
228190507Slulf	char newplex[GV_MAXPLEXNAME], *ptr;
229152615Sle	int err;
230152615Sle
231152615Sle	KASSERT(v != NULL, ("gv_rename_vol: NULL v"));
232190507Slulf	pp = v->provider;
233190507Slulf	KASSERT(pp != NULL, ("gv_rename_vol: NULL pp"));
234152615Sle
235190507Slulf	if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) {
236190507Slulf		G_VINUM_DEBUG(1, "volume name %s already in use", newname);
237190507Slulf		return (GV_ERR_NAMETAKEN);
238152615Sle	}
239152615Sle
240152615Sle	/* Rename the volume. */
241190507Slulf	strlcpy(v->name, newname, sizeof(v->name));
242152615Sle
243152615Sle	/* Fix up references and potentially rename plexes. */
244152615Sle	LIST_FOREACH(p, &v->plexes, in_volume) {
245190507Slulf		strlcpy(p->volume, v->name, sizeof(p->volume));
246213318Slulf		if (flags & GV_FLAG_R) {
247152633Sle			/*
248190507Slulf			 * Look for the last dot in the string, and assume that
249190507Slulf			 * the old value was ok.
250152633Sle			 */
251190507Slulf			ptr = strrchr(p->name, '.');
252190507Slulf			ptr++;
253190507Slulf			snprintf(newplex, sizeof(newplex), "%s.%s", v->name, ptr);
254190507Slulf			err = gv_rename_plex(sc, p, newplex, flags);
255152615Sle			if (err)
256152633Sle				return (err);
257152615Sle		}
258152615Sle	}
259152634Sle
260152615Sle	return (0);
261152615Sle}
262