xref: /titanic_41/usr/src/cmd/lvm/util/metareplace.c (revision 70025d765b044c6d8594bb965a2247a61e991a99)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * replace mirror component
31  */
32 
33 #include <meta.h>
34 
35 #include <sdssc.h>
36 
37 /*
38  * print usage message
39  */
40 static void
41 usage(
42 	mdsetname_t	*sp,
43 	int		eval
44 )
45 {
46 	(void) fprintf(stderr, gettext("\
47 usage:	%s [-s setname] mirror component-old component-new\n\
48 	%s [-s setname] -e mirror component\n\
49 	%s [-s setname] [-f] RAID component-old component-new\n\
50 	%s [-s setname] [-f] -e RAID component\n\
51 	%s [-s setname] -c metadevice component-old component-new\n"),
52 	    myname, myname, myname, myname, myname);
53 	md_exit(sp, eval);
54 }
55 
56 /*
57  * online replace a physical disk in a metamirror
58  */
59 int
60 main(
61 	int		argc,
62 	char		*argv[]
63 )
64 {
65 	char		*sname = NULL;
66 	mdsetname_t	*sp = NULL;
67 	mdcmdopts_t	options = (MDCMD_PRINT|MDCMD_DOIT);
68 	mdname_t	*namep;
69 	int		eflag = 0;
70 	int		cflag = 0;
71 	int		c;
72 	md_error_t	status = mdnullerror;
73 	md_error_t	*ep = &status;
74 	int		error;
75 	char		*uname = NULL;
76 	bool_t		called_thru_rpc = FALSE;
77 	char		*cp;
78 	int		origargc = argc;
79 	char		**origargv = argv;
80 
81 	/*
82 	 * Get the locale set up before calling any other routines
83 	 * with messages to ouput.  Just in case we're not in a build
84 	 * environment, make sure that TEXT_DOMAIN gets set to
85 	 * something.
86 	 */
87 #if !defined(TEXT_DOMAIN)
88 #define	TEXT_DOMAIN "SYS_TEST"
89 #endif
90 	(void) setlocale(LC_ALL, "");
91 	(void) textdomain(TEXT_DOMAIN);
92 
93 
94 	if ((cp = strstr(argv[0], ".rpc_call")) == NULL) {
95 		if (sdssc_bind_library() == SDSSC_OKAY)
96 			if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
97 						&error) == SDSSC_PROXY_DONE)
98 				exit(error);
99 	} else {
100 		*cp = '\0'; /* cut off ".rpc_call" */
101 		called_thru_rpc = TRUE;
102 	}
103 
104 	/* initialize */
105 	if (md_init(argc, argv, 0, 1, ep) != 0 ||
106 			meta_check_root(ep) != 0) {
107 		mde_perror(ep, "");
108 		md_exit(sp, 1);
109 	}
110 
111 	/* parse arguments */
112 	optind = 1;
113 	opterr = 1;
114 	while ((c = getopt(argc, argv, "hs:cefn?")) != -1) {
115 		switch (c) {
116 		case 'h':
117 			usage(sp, 0);
118 			break;
119 
120 		case 's':
121 			sname = optarg;
122 			break;
123 
124 		case 'e':
125 			++eflag;
126 			break;
127 
128 		case 'f':
129 			options |= MDCMD_FORCE;
130 			break;
131 
132 		case 'n':
133 			if (called_thru_rpc == TRUE) {
134 				options &= ~MDCMD_DOIT;
135 			} else {
136 				usage(sp, 1);
137 			}
138 			break;
139 
140 		case 'c':
141 			options |= MDCMD_CLUSTER_REPLACE;
142 			++cflag;
143 			break;
144 
145 		case '?':
146 			if (optopt == '?')
147 				usage(sp, 0);
148 			/*FALLTHROUGH*/
149 		default:
150 			usage(sp, 1);
151 			break;
152 		}
153 	}
154 	argc -= optind;
155 	argv += optind;
156 
157 	if (sname != NULL) {
158 		if ((sp = metasetname(sname, ep)) == NULL) {
159 			mde_perror(ep, "");
160 			md_exit(sp, 1);
161 		}
162 	}
163 
164 	/* get device */
165 	if (argc < 1)
166 		usage(sp, 1);
167 
168 	uname = argv[0];
169 
170 	if (((namep = metaname(&sp, argv[0], ep)) == NULL)) {
171 		mde_perror(ep, "");
172 		md_exit(sp, 1);
173 	}
174 
175 	/*
176 	 * This 'if' statement might look a little strange so I'll 'splain
177 	 * a few things.
178 	 *
179 	 * If 'cflag' is not set then always do the metachkmeta.
180 	 *    This is the normal behavior and you're not allowed to run
181 	 *    metarplace on a hotspare. metachkmeta will barf.
182 	 *
183 	 * If 'cflag' and uname is not a hotspare do metachkmeta
184 	 *    Still need to check out the metadevice as long as it's not
185 	 *    a hotspare.
186 	 *
187 	 * Else we've got a hotspare so we can't call metachkmeta
188 	 */
189 	if ((!cflag) || (cflag && (!is_hspname(uname)))) {
190 		if (metachkmeta(namep, ep) != 0) {
191 			mde_perror(ep, "");
192 			md_exit(sp, 1);
193 		}
194 	}
195 
196 	assert(sp != NULL);
197 	if ((called_thru_rpc == FALSE) &&
198 	    meta_is_mn_name(&sp, argv[0], ep)) {
199 		/*
200 		 * If we are dealing with a MN set and we were not
201 		 * called thru an rpc call, we are just to send this
202 		 * command string to the master of the set and let it
203 		 * deal with it.
204 		 * Note that if sp is NULL, meta_is_mn_name() derives sp
205 		 * from argv[0] which is the metadevice arg
206 		 */
207 		int  i;
208 		int  newargc;
209 		int  result;
210 		char *miscname;
211 		char **newargv;
212 
213 		if ((miscname = metagetmiscname(namep, ep)) == NULL) {
214 			mde_perror(ep, "");
215 			md_exit(sp, 1);
216 		}
217 
218 		newargv = calloc(origargc+1, sizeof (char *));
219 		newargv[0] = "metareplace";
220 		newargv[1] = "-n"; /* always do "-n" first */
221 		newargc = 2;
222 		for (i = 1; i < origargc; i++, newargc++) {
223 			newargv[newargc] = origargv[i];
224 		}
225 
226 		result = meta_mn_send_command(sp, newargc, newargv,
227 		    MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep);
228 
229 		/* If we've found a problem don't do it for real */
230 		if (result != 0) {
231 			md_exit(sp, result);
232 		}
233 		/*
234 		 * Do it for real now. Remove "-n" from the arguments and
235 		 * MD_DRYRUN from the flags. If this fails, the master must
236 		 * panic as the mddbs may be inconsistent.
237 		 */
238 		newargv[1] = ""; /* this was "-n" before */
239 		result = meta_mn_send_command(sp, newargc, newargv,
240 		    MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
241 		    NO_CONTEXT_STRING, ep);
242 
243 		free(newargv);
244 
245 		/*
246 		 * if the metareplace command succeeds for a mirror, send a
247 		 * resync starting message for the metadevice
248 		 */
249 		if ((result == 0) && (strcmp(miscname, MD_MIRROR) == 0)) {
250 			if ((result = meta_mn_send_resync_starting(namep, ep))
251 			    != 0)
252 				mde_perror(ep, "Unable to start resync");
253 		}
254 		md_exit(sp, result);
255 	}
256 
257 	--argc, ++argv;
258 
259 	/* grab set lock */
260 	if (meta_lock(sp, TRUE, ep)) {
261 		mde_perror(ep, "");
262 		md_exit(sp, 1);
263 	}
264 
265 	/* check for ownership */
266 	if (meta_check_ownership(sp, ep) != 0) {
267 		mde_perror(ep, "");
268 		md_exit(sp, 1);
269 	}
270 
271 	if (eflag) {				/* enable component */
272 		mdname_t	*compnp;
273 
274 		if (argc != 1)
275 			usage(sp, 1);
276 
277 		if ((compnp = metaname(&sp, argv[0], ep)) == NULL) {
278 			mde_perror(ep, "");
279 			md_exit(sp, 1);
280 		}
281 		if (meta_enable_byname(sp, namep, compnp, options, ep)
282 		    != 0) {
283 			mde_perror(ep, "");
284 			md_exit(sp, 1);
285 		}
286 	} else {				/* replace component */
287 		mdname_t	*oldnp;
288 		mdname_t	*newnp;
289 
290 		if (argc != 2)
291 			usage(sp, 1);
292 
293 		if ((oldnp = metaname(&sp, argv[0], ep)) == NULL) {
294 			mde_perror(ep, "");
295 			md_exit(sp, 1);
296 		}
297 		if ((newnp = metaname(&sp, argv[1], ep)) == NULL) {
298 			mde_perror(ep, "");
299 			md_exit(sp, 1);
300 		}
301 		if (cflag) {			/* new replace stuff */
302 			if (meta_replace(sp, namep, oldnp, newnp, uname,
303 			    options, ep) != 0) {
304 				mde_perror(ep, "");
305 				md_exit(sp, 1);
306 			}
307 		} else {
308 			if (meta_replace_byname(sp, namep, oldnp, newnp,
309 			    options, ep) != 0) {
310 				mde_perror(ep, "");
311 				md_exit(sp, 1);
312 			}
313 		}
314 	}
315 
316 	/* update md.cf */
317 	if (meta_update_md_cf(sp, ep) != 0) {
318 		mde_perror(ep, "");
319 		md_exit(sp, 1);
320 	}
321 
322 	md_exit(sp, 0);
323 	/*NOTREACHED*/
324 	return (0);
325 }
326