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 * detach submirrors 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] [-f] mirror submirror\n\ 47 %s [-s setname] [-f] trans\n"), 48 myname, myname); 49 md_exit(sp, eval); 50 } 51 52 /* 53 * detach submirror from mirror 54 */ 55 static int 56 mirror_detach( 57 mdsetname_t **spp, 58 mdname_t *mirnp, 59 int argc, 60 char *argv[], 61 mdcmdopts_t options, 62 md_error_t *ep 63 ) 64 { 65 mdname_t *submirnp; 66 int c; 67 68 /* reset and parse args */ 69 optind = 1; 70 opterr = 1; 71 while ((c = getopt(argc, argv, "s:f")) != -1) { 72 switch (c) { 73 case 's': 74 break; 75 76 case 'f': 77 options |= MDCMD_FORCE; 78 break; 79 80 default: 81 usage(*spp, 1); 82 /*NOTREACHED*/ 83 break; 84 } 85 } 86 argc -= optind; 87 argv += optind; 88 if (argc != 2) 89 usage(*spp, 1); 90 91 /* get submirror */ 92 if ((submirnp = metaname(spp, argv[1], META_DEVICE, ep)) == NULL) 93 return (-1); 94 95 /* detach submirror */ 96 if (meta_mirror_detach(*spp, mirnp, submirnp, options, ep) != 0) 97 return (-1); 98 99 /* update md.cf */ 100 if (meta_update_md_cf(*spp, ep) != 0) 101 return (-1); 102 103 /* return success */ 104 return (0); 105 } 106 107 /* 108 * detach log from trans 109 */ 110 static int 111 trans_detach( 112 mdsetname_t *sp, 113 mdname_t *transnp, 114 int argc, 115 char *argv[], 116 mdcmdopts_t options, 117 md_error_t *ep 118 ) 119 { 120 int delayed; 121 int c; 122 123 /* reset and parse args */ 124 optind = 1; 125 opterr = 1; 126 while ((c = getopt(argc, argv, "s:f")) != -1) { 127 switch (c) { 128 case 's': 129 break; 130 131 case 'f': 132 options |= MDCMD_FORCE; 133 break; 134 135 default: 136 usage(sp, 1); 137 /*NOTREACHED*/ 138 break; 139 } 140 } 141 argc -= optind; 142 argv += optind; 143 if (argc != 1) 144 usage(sp, 1); 145 146 /* detach log */ 147 if (meta_trans_detach(sp, transnp, options, &delayed, ep) != 0) 148 return (-1); 149 150 /* update md.cf */ 151 if (meta_update_md_cf(sp, ep) != 0) 152 return (-1); 153 154 /* return success */ 155 return (0); 156 } 157 158 /* 159 * parse args and doit 160 */ 161 int 162 main( 163 int argc, 164 char *argv[] 165 ) 166 { 167 char *sname = NULL; 168 mdsetname_t *sp = NULL; 169 mdcmdopts_t options = (MDCMD_PRINT); 170 mdname_t *np; 171 char *miscname; 172 int c; 173 md_error_t status = mdnullerror; 174 md_error_t *ep = &status; 175 int error; 176 bool_t called_thru_rpc = FALSE; 177 char *cp; 178 179 180 /* 181 * Get the locale set up before calling any other routines 182 * with messages to ouput. Just in case we're not in a build 183 * environment, make sure that TEXT_DOMAIN gets set to 184 * something. 185 */ 186 #if !defined(TEXT_DOMAIN) 187 #define TEXT_DOMAIN "SYS_TEST" 188 #endif 189 (void) setlocale(LC_ALL, ""); 190 (void) textdomain(TEXT_DOMAIN); 191 192 if ((cp = strstr(argv[0], ".rpc_call")) == NULL) { 193 if (sdssc_bind_library() == SDSSC_OKAY) 194 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 195 &error) == SDSSC_PROXY_DONE) 196 exit(error); 197 } else { 198 *cp = '\0'; /* cut off ".rpc_call" */ 199 called_thru_rpc = TRUE; 200 } 201 202 203 /* initialize */ 204 if (md_init(argc, argv, 0, 1, ep) != 0 || 205 meta_check_root(ep) != 0) { 206 mde_perror(ep, ""); 207 md_exit(sp, 1); 208 } 209 210 /* find set and metadevice first */ 211 optind = 1; 212 opterr = 1; 213 while ((c = getopt(argc, argv, "hs:f?")) != -1) { 214 switch (c) { 215 case 'h': 216 usage(sp, 0); 217 break; 218 219 case 's': 220 sname = optarg; 221 break; 222 223 case '?': 224 if (optopt == '?') 225 usage(sp, 0); 226 break; 227 } 228 } 229 if ((argc - optind) <= 0) 230 usage(sp, 1); 231 232 if (sname != NULL) { 233 if ((sp = metasetname(sname, ep)) == NULL) { 234 mde_perror(ep, ""); 235 md_exit(sp, 1); 236 } 237 } 238 239 /* Get metadevice name */ 240 if (((np = metaname(&sp, argv[optind], META_DEVICE, ep)) == NULL) || 241 (metachkmeta(np, ep) != 0)) { 242 mde_perror(ep, ""); 243 md_exit(sp, 1); 244 } 245 assert(sp != NULL); 246 247 if ((called_thru_rpc == FALSE) && 248 meta_is_mn_name(&sp, argv[optind], ep)) { 249 /* 250 * If we are dealing with a MN set and we were not 251 * called thru an rpc call, we are just to send this 252 * command string to the master of the set and let it 253 * deal with it. 254 * Note that if sp is NULL, meta_is_mn_name() derives sp 255 * from argv[optind] which is the metadevice arg 256 * If this fails, the master must panic as the mddb may be 257 * inconsistent 258 */ 259 int result; 260 result = meta_mn_send_command(sp, argc, argv, MD_DISP_STDERR | 261 MD_PANIC_WHEN_INCONSISTENT, NO_CONTEXT_STRING, ep); 262 /* 263 * The error message has been already been displayed 264 * just exit 265 */ 266 md_exit(sp, result); 267 } 268 269 /* grab set lock */ 270 if (meta_lock(sp, TRUE, ep)) { 271 mde_perror(ep, ""); 272 md_exit(sp, 1); 273 } 274 275 /* check ownership */ 276 if (meta_check_ownership(sp, ep) != 0) { 277 mde_perror(ep, ""); 278 md_exit(sp, 1); 279 } 280 if ((miscname = metagetmiscname(np, ep)) == NULL) { 281 mde_perror(ep, ""); 282 md_exit(sp, 1); 283 } 284 285 /* dispatch based on device type */ 286 if (strcmp(miscname, MD_MIRROR) == 0) { 287 if (mirror_detach(&sp, np, argc, argv, options, ep) != 0) { 288 mde_perror(ep, ""); 289 md_exit(sp, 1); 290 } 291 } else if (strcmp(miscname, MD_TRANS) == 0) { 292 if (trans_detach(sp, np, argc, argv, options, ep) != 0) { 293 mde_perror(ep, ""); 294 md_exit(sp, 1); 295 } 296 } else { 297 md_eprintf(gettext( 298 "%s: invalid metadevice type %s\n"), 299 np->cname, miscname); 300 md_exit(sp, 1); 301 } 302 303 /* return success */ 304 md_exit(sp, 0); 305 /*NOTREACHED*/ 306 return (0); 307 } 308