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 * replace mirror component 30 */ 31 32 #include <meta.h> 33 34 #include <sdssc.h> 35 36 /* 37 * print usage message 38 */ 39 static void 40 usage( 41 mdsetname_t *sp, 42 int eval 43 ) 44 { 45 (void) fprintf(stderr, gettext("\ 46 usage: %s [-s setname] mirror component-old component-new\n\ 47 %s [-s setname] -e mirror component\n\ 48 %s [-s setname] [-f] RAID component-old component-new\n\ 49 %s [-s setname] [-f] -e RAID component\n"), 50 myname, myname, myname, myname); 51 md_exit(sp, eval); 52 } 53 54 /* 55 * online replace a physical disk in a metamirror 56 */ 57 int 58 main( 59 int argc, 60 char *argv[] 61 ) 62 { 63 char *sname = NULL; 64 mdsetname_t *sp = NULL; 65 mdcmdopts_t options = (MDCMD_PRINT|MDCMD_DOIT); 66 mdname_t *namep; 67 int eflag = 0; 68 int c; 69 md_error_t status = mdnullerror; 70 md_error_t *ep = &status; 71 int error; 72 char *uname = NULL; 73 bool_t called_thru_rpc = FALSE; 74 char *cp; 75 int origargc = argc; 76 char **origargv = argv; 77 78 /* 79 * Get the locale set up before calling any other routines 80 * with messages to ouput. Just in case we're not in a build 81 * environment, make sure that TEXT_DOMAIN gets set to 82 * something. 83 */ 84 #if !defined(TEXT_DOMAIN) 85 #define TEXT_DOMAIN "SYS_TEST" 86 #endif 87 (void) setlocale(LC_ALL, ""); 88 (void) textdomain(TEXT_DOMAIN); 89 90 91 if ((cp = strstr(argv[0], ".rpc_call")) == NULL) { 92 if (sdssc_bind_library() == SDSSC_OKAY) 93 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 94 &error) == SDSSC_PROXY_DONE) 95 exit(error); 96 } else { 97 *cp = '\0'; /* cut off ".rpc_call" */ 98 called_thru_rpc = TRUE; 99 } 100 101 /* initialize */ 102 if (md_init(argc, argv, 0, 1, ep) != 0 || 103 meta_check_root(ep) != 0) { 104 mde_perror(ep, ""); 105 md_exit(sp, 1); 106 } 107 108 /* parse arguments */ 109 optind = 1; 110 opterr = 1; 111 while ((c = getopt(argc, argv, "hs:efn?")) != -1) { 112 switch (c) { 113 case 'h': 114 usage(sp, 0); 115 break; 116 117 case 's': 118 sname = optarg; 119 break; 120 121 case 'e': 122 ++eflag; 123 break; 124 125 case 'f': 126 options |= MDCMD_FORCE; 127 break; 128 129 case 'n': 130 if (called_thru_rpc == TRUE) { 131 options &= ~MDCMD_DOIT; 132 } else { 133 usage(sp, 1); 134 } 135 break; 136 137 case '?': 138 if (optopt == '?') 139 usage(sp, 0); 140 /*FALLTHROUGH*/ 141 default: 142 usage(sp, 1); 143 break; 144 } 145 } 146 argc -= optind; 147 argv += optind; 148 149 if (sname != NULL) { 150 if ((sp = metasetname(sname, ep)) == NULL) { 151 mde_perror(ep, ""); 152 md_exit(sp, 1); 153 } 154 } 155 156 /* get device */ 157 if (argc < 1) 158 usage(sp, 1); 159 160 uname = argv[0]; 161 162 if (((namep = metaname(&sp, uname, META_DEVICE, ep)) == NULL)) { 163 mde_perror(ep, ""); 164 md_exit(sp, 1); 165 } 166 167 if (metachkmeta(namep, ep) != 0) { 168 mde_perror(ep, ""); 169 md_exit(sp, 1); 170 } 171 172 assert(sp != NULL); 173 if ((called_thru_rpc == FALSE) && 174 meta_is_mn_name(&sp, argv[0], ep)) { 175 /* 176 * If we are dealing with a MN set and we were not 177 * called thru an rpc call, we are just to send this 178 * command string to the master of the set and let it 179 * deal with it. 180 * Note that if sp is NULL, meta_is_mn_name() derives sp 181 * from argv[0] which is the metadevice arg 182 */ 183 int i; 184 int newargc; 185 int result; 186 char *miscname; 187 char **newargv; 188 189 if ((miscname = metagetmiscname(namep, ep)) == NULL) { 190 mde_perror(ep, ""); 191 md_exit(sp, 1); 192 } 193 194 newargv = calloc(origargc+1, sizeof (char *)); 195 newargv[0] = "metareplace"; 196 newargv[1] = "-n"; /* always do "-n" first */ 197 newargc = 2; 198 for (i = 1; i < origargc; i++, newargc++) { 199 newargv[newargc] = origargv[i]; 200 } 201 202 result = meta_mn_send_command(sp, newargc, newargv, 203 MD_DISP_STDERR | MD_DRYRUN, NO_CONTEXT_STRING, ep); 204 205 /* If we've found a problem don't do it for real */ 206 if (result != 0) { 207 md_exit(sp, result); 208 } 209 /* 210 * Do it for real now. Remove "-n" from the arguments and 211 * MD_DRYRUN from the flags. If this fails, the master must 212 * panic as the mddbs may be inconsistent. 213 */ 214 newargv[1] = ""; /* this was "-n" before */ 215 result = meta_mn_send_command(sp, newargc, newargv, 216 MD_DISP_STDERR | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT, 217 NO_CONTEXT_STRING, ep); 218 219 free(newargv); 220 221 /* 222 * if the metareplace command succeeds for a mirror, send a 223 * resync starting message for the metadevice 224 */ 225 if ((result == 0) && (strcmp(miscname, MD_MIRROR) == 0)) { 226 if ((result = meta_mn_send_resync_starting(namep, ep)) 227 != 0) 228 mde_perror(ep, "Unable to start resync"); 229 } 230 md_exit(sp, result); 231 } 232 233 --argc, ++argv; 234 235 /* grab set lock */ 236 if (meta_lock(sp, TRUE, ep)) { 237 mde_perror(ep, ""); 238 md_exit(sp, 1); 239 } 240 241 /* check for ownership */ 242 if (meta_check_ownership(sp, ep) != 0) { 243 mde_perror(ep, ""); 244 md_exit(sp, 1); 245 } 246 247 if (eflag) { /* enable component */ 248 mdname_t *compnp; 249 250 if (argc != 1) 251 usage(sp, 1); 252 253 if ((compnp = metaname(&sp, argv[0], UNKNOWN, ep)) == NULL) { 254 mde_perror(ep, ""); 255 md_exit(sp, 1); 256 } 257 if (meta_enable_byname(sp, namep, compnp, options, ep) 258 != 0) { 259 mde_perror(ep, ""); 260 md_exit(sp, 1); 261 } 262 } else { /* replace component */ 263 mdname_t *oldnp; 264 mdname_t *newnp; 265 266 if (argc != 2) 267 usage(sp, 1); 268 269 if ((oldnp = metaname(&sp, argv[0], UNKNOWN, ep)) == NULL) { 270 mde_perror(ep, ""); 271 md_exit(sp, 1); 272 } 273 if ((newnp = metaname(&sp, argv[1], UNKNOWN, ep)) == NULL) { 274 mde_perror(ep, ""); 275 md_exit(sp, 1); 276 } 277 if (meta_replace_byname(sp, namep, oldnp, newnp, 278 options, ep) != 0) { 279 mde_perror(ep, ""); 280 md_exit(sp, 1); 281 } 282 } 283 284 /* update md.cf */ 285 if (meta_update_md_cf(sp, ep) != 0) { 286 mde_perror(ep, ""); 287 md_exit(sp, 1); 288 } 289 290 md_exit(sp, 0); 291 /*NOTREACHED*/ 292 return (0); 293 } 294