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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * change metadevice parameters
30 */
31
32 #include <meta.h>
33
34 #include <sdssc.h>
35
36 /*
37 * print usage message
38 */
39 static void
usage(mdsetname_t * sp,int eval)40 usage(
41 mdsetname_t *sp,
42 int eval
43 )
44 {
45 (void) fprintf(stderr, gettext("\
46 usage: %s [-s setname] [options] concat/stripe | RAID\n\
47 %s [-s setname] [options] mirror\n\
48 \n\
49 Concat/Stripe or RAID options:\n\
50 -h hotspare_pool | \"none\"\n\
51 \n\
52 Mirror options:\n\
53 -r roundrobin | geometric | first\n\
54 -w parallel | serial\n\
55 -p 0-%d\n"), myname, myname, MD_PASS_MAX);
56
57 md_exit(sp, eval);
58 }
59
60 /*
61 * do mirror parameters
62 */
63 static int
mirror_params(mdsetname_t * sp,mdname_t * mirnp,int argc,char * argv[],md_error_t * ep)64 mirror_params(
65 mdsetname_t *sp,
66 mdname_t *mirnp,
67 int argc,
68 char *argv[],
69 md_error_t *ep
70 )
71 {
72 mm_params_t mmp;
73 int modified = 0;
74 int c;
75
76 /* we must have a set */
77 assert(sp != NULL);
78 assert(sp->setno == MD_MIN2SET(meta_getminor(mirnp->dev)));
79
80 /* initialize */
81 (void) memset(&mmp, '\0', sizeof (mmp));
82
83 /* reset and parse args */
84 optind = 1;
85 opterr = 1;
86 while ((c = getopt(argc, argv, "s:r:w:p:")) != -1) {
87 switch (c) {
88 case 's':
89 break;
90
91 case 'r':
92 if (name_to_rd_opt(mirnp->cname, optarg,
93 &mmp.read_option, ep) != 0) {
94 return (-1);
95 }
96 mmp.change_read_option = 1;
97 modified = 1;
98 break;
99
100 case 'w':
101 if (name_to_wr_opt(mirnp->cname, optarg,
102 &mmp.write_option, ep) != 0) {
103 return (-1);
104 }
105 mmp.change_write_option = 1;
106 modified = 1;
107 break;
108
109 case 'p':
110 if (name_to_pass_num(mirnp->cname, optarg,
111 &mmp.pass_num, ep) != 0) {
112 return (-1);
113 }
114 mmp.change_pass_num = 1;
115 modified = 1;
116 break;
117
118 default:
119 usage(sp, 1);
120 /*NOTREACHED*/
121 break;
122 }
123 }
124
125 argc -= optind;
126 argv += optind;
127 if (argc != 1)
128 usage(sp, 1);
129
130 /* if just printing */
131 if (! modified) {
132 if (meta_mirror_get_params(sp, mirnp, &mmp, ep) != 0)
133 return (-1);
134 (void) printf(
135 gettext(
136 "%s: Mirror current parameters are:\n"),
137 mirnp->cname);
138 if (meta_print_mirror_options(mmp.read_option,
139 mmp.write_option, mmp.pass_num, 0, NULL,
140 sp, stdout, ep) != 0) {
141 return (-1);
142 }
143 }
144
145 /* otherwise, change parameters */
146 else {
147 if (meta_mirror_set_params(sp, mirnp, &mmp, ep) != 0)
148 return (-1);
149
150 /* update md.cf */
151 if (meta_update_md_cf(sp, ep) != 0)
152 return (-1);
153 }
154
155 /* return success */
156 return (0);
157 }
158
159 /*
160 * do stripe parameters
161 */
162 static int
stripe_params(mdsetname_t * sp,mdname_t * stripenp,int argc,char * argv[],md_error_t * ep)163 stripe_params(
164 mdsetname_t *sp,
165 mdname_t *stripenp,
166 int argc,
167 char *argv[],
168 md_error_t *ep
169 )
170 {
171 ms_params_t msp;
172 int modified = 0;
173 mdhspname_t *hspnp;
174 int c;
175
176 /* we must have a set */
177 assert(sp != NULL);
178 assert(sp->setno == MD_MIN2SET(meta_getminor(stripenp->dev)));
179
180 /* initialize */
181 (void) memset(&msp, '\0', sizeof (msp));
182
183 /* reset and parse args */
184 optind = 1;
185 opterr = 1;
186 while ((c = getopt(argc, argv, "s:h:")) != -1) {
187 switch (c) {
188 case 's':
189 break;
190
191 case 'h':
192 if (meta_is_none(optarg)) {
193 msp.hsp_id = MD_HSP_NONE;
194 } else if ((hspnp = metahspname(&sp, optarg,
195 ep)) == NULL) {
196 return (-1);
197 } else if (metachkhsp(sp, hspnp, ep) != 0) {
198 return (-1);
199 } else {
200 msp.hsp_id = hspnp->hsp;
201 }
202 msp.change_hsp_id = 1;
203 modified = 1;
204 break;
205
206 default:
207 usage(sp, 1);
208 /*NOTREACHED*/
209 break;
210 }
211 }
212 argc -= optind;
213 argv += optind;
214 if (argc != 1)
215 usage(sp, 1);
216
217 /* if just printing */
218 if (! modified) {
219 if (meta_stripe_get_params(sp, stripenp, &msp, ep) != 0)
220 return (-1);
221 if (msp.hsp_id == MD_HSP_NONE)
222 hspnp = NULL;
223 else if ((hspnp = metahsphspname(&sp, msp.hsp_id, ep)) == NULL)
224 return (-1);
225 (void) printf(gettext(
226 "%s: Concat/Stripe current parameters are:\n"),
227 stripenp->cname);
228 if (meta_print_stripe_options(hspnp, NULL, stdout, ep) != 0)
229 return (-1);
230 }
231
232 /* otherwise, change parameters */
233 else {
234 if (meta_stripe_set_params(sp, stripenp, &msp, ep) != 0)
235 return (-1);
236
237 /* update md.cf */
238 if (meta_update_md_cf(sp, ep) != 0)
239 return (-1);
240 }
241
242 /* return success */
243 return (0);
244 }
245
246 /*
247 * do raid parameters
248 */
249 static int
raid_params(mdsetname_t * sp,mdname_t * raidnp,int argc,char * argv[],md_error_t * ep)250 raid_params(
251 mdsetname_t *sp,
252 mdname_t *raidnp,
253 int argc,
254 char *argv[],
255 md_error_t *ep
256 )
257 {
258 mr_params_t msp;
259 int modified = 0;
260 mdhspname_t *hspnp;
261 int c;
262
263 /* we must have a set */
264 assert(sp != NULL);
265 assert(sp->setno == MD_MIN2SET(meta_getminor(raidnp->dev)));
266
267 /* initialize */
268 (void) memset(&msp, '\0', sizeof (msp));
269
270 /* reset and parse args */
271 optind = 1;
272 opterr = 1;
273 while ((c = getopt(argc, argv, "s:h:")) != -1) {
274 switch (c) {
275 case 's':
276 break;
277
278 case 'h':
279 if (meta_is_none(optarg)) {
280 msp.hsp_id = MD_HSP_NONE;
281 } else if ((hspnp = metahspname(&sp, optarg,
282 ep)) == NULL) {
283 return (-1);
284 } else if (metachkhsp(sp, hspnp, ep) != 0) {
285 return (-1);
286 } else {
287 msp.hsp_id = hspnp->hsp;
288 }
289 msp.change_hsp_id = 1;
290 modified = 1;
291 break;
292
293 default:
294 usage(sp, 1);
295 /*NOTREACHED*/
296 break;
297 }
298 }
299 argc -= optind;
300 argv += optind;
301 if (argc != 1)
302 usage(sp, 1);
303
304 /* if just printing */
305 if (! modified) {
306 if (meta_raid_get_params(sp, raidnp, &msp, ep) != 0)
307 return (-1);
308 if (msp.hsp_id == MD_HSP_NONE)
309 hspnp = NULL;
310 else if ((hspnp = metahsphspname(&sp, msp.hsp_id, ep)) == NULL)
311 return (-1);
312 (void) printf(gettext(
313 "%s: RAID current parameters are:\n"),
314 raidnp->cname);
315 if (meta_print_raid_options(hspnp, NULL, stdout, ep) != 0)
316 return (-1);
317 }
318
319 /* otherwise, change parameters */
320 else {
321 if (meta_raid_set_params(sp, raidnp, &msp, ep) != 0)
322 return (-1);
323
324 /* update md.cf */
325 if (meta_update_md_cf(sp, ep) != 0)
326 return (-1);
327 }
328
329 /* return success */
330 return (0);
331 }
332
333 /*
334 * parse args and doit
335 */
336 int
main(int argc,char ** argv)337 main(
338 int argc,
339 char **argv
340 )
341 {
342 char *sname = NULL;
343 mdsetname_t *sp = NULL;
344 mdname_t *np;
345 char *miscname;
346 int c;
347 md_error_t status = mdnullerror;
348 md_error_t *ep = &status;
349 int error;
350 bool_t called_thru_rpc = FALSE;
351 char *cp;
352 char *firstarg = NULL;
353
354
355 /*
356 * Get the locale set up before calling any other routines
357 * with messages to ouput. Just in case we're not in a build
358 * environment, make sure that TEXT_DOMAIN gets set to
359 * something.
360 */
361 #if !defined(TEXT_DOMAIN)
362 #define TEXT_DOMAIN "SYS_TEST"
363 #endif
364 (void) setlocale(LC_ALL, "");
365 (void) textdomain(TEXT_DOMAIN);
366
367 if ((cp = strstr(argv[0], ".rpc_call")) == NULL) {
368 if (sdssc_bind_library() == SDSSC_OKAY)
369 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
370 &error) == SDSSC_PROXY_DONE)
371 exit(error);
372 } else {
373 *cp = '\0'; /* cut off ".rpc_call" */
374 called_thru_rpc = TRUE;
375 }
376
377
378 /* initialize */
379 if (md_init(argc, argv, 0, 1, ep) != 0 ||
380 meta_check_root(ep) != 0) {
381 mde_perror(ep, "");
382 md_exit(sp, 1);
383 }
384
385 /* find set and metadevice first */
386 optind = 1;
387 opterr = 1;
388 while ((c = getopt(argc, argv, "s:h:p:r:w:o:?")) != -1) {
389 switch (c) {
390 case 's':
391 sname = optarg;
392 break;
393 case 'h':
394 firstarg = optarg;
395 break;
396 case '?':
397 if (optopt == '?')
398 usage(sp, 0);
399 break;
400 }
401 }
402 if ((argc - optind) <= 0)
403 usage(sp, 1);
404
405 if (sname != NULL) {
406 if ((sp = metasetname(sname, ep)) == NULL) {
407 mde_perror(ep, "");
408 md_exit(sp, 1);
409 }
410 }
411 if (firstarg == NULL)
412 firstarg = argv[optind];
413 if ((called_thru_rpc == FALSE) &&
414 meta_is_mn_name(&sp, firstarg, ep)) {
415 /*
416 * If we are dealing with a MN set and we were not
417 * called thru an rpc call, we are just to send this
418 * command string to the master of the set and let it
419 * deal with it.
420 * Note that if sp is NULL, meta_is_mn_name() derives sp
421 * from firstarg which is the metadevice arg
422 * If this fails, the master must panic as the mddb may be
423 * inconsistent
424 */
425 int result;
426 result = meta_mn_send_command(sp, argc, argv, MD_DISP_STDERR |
427 MD_PANIC_WHEN_INCONSISTENT, NO_CONTEXT_STRING, ep);
428 /* No further action required */
429 md_exit(sp, result);
430 }
431
432 if ((np = metaname(&sp, argv[optind], META_DEVICE, ep)) == NULL) {
433 mde_perror(ep, "");
434 md_exit(sp, 1);
435 }
436 assert(sp != NULL);
437 /* grab set lock */
438 if (meta_lock(sp, TRUE, ep)) {
439 mde_perror(ep, "");
440 md_exit(sp, 1);
441 }
442
443 if (meta_check_ownership(sp, ep) != 0) {
444 mde_perror(ep, "");
445 md_exit(sp, 1);
446 }
447 if ((miscname = metagetmiscname(np, ep)) == NULL) {
448 mde_perror(ep, "");
449 md_exit(sp, 1);
450 }
451
452 /* dispatch based on device type */
453 if (strcmp(miscname, MD_STRIPE) == 0) {
454 if (stripe_params(sp, np, argc, argv, ep) != 0) {
455 mde_perror(ep, "");
456 md_exit(sp, 1);
457 }
458 } else if (strcmp(miscname, MD_MIRROR) == 0) {
459 if (mirror_params(sp, np, argc, argv, ep) != 0) {
460 mde_perror(ep, "");
461 md_exit(sp, 1);
462 }
463 } else if (strcmp(miscname, MD_RAID) == 0) {
464 if (raid_params(sp, np, argc, argv, ep) != 0) {
465 mde_perror(ep, "");
466 md_exit(sp, 1);
467 }
468 } else {
469 md_eprintf(gettext(
470 "%s: invalid metadevice type %s\n"),
471 np->cname, miscname);
472 md_exit(sp, 1);
473 }
474
475 /* return success */
476 md_exit(sp, 0);
477 /*NOTREACHED*/
478 return (0);
479 }
480