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