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 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <stdio.h> 29 #include <sys/mnttab.h> 30 #include <errno.h> 31 #include <limits.h> 32 #include <fcntl.h> 33 #include <strings.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <sys/stat.h> 37 #include <signal.h> 38 39 #include <locale.h> 40 #include <langinfo.h> 41 #include <libintl.h> 42 #include <stdarg.h> 43 #include <sys/nsctl/rdc_io.h> 44 #include <sys/nsctl/rdc_ioctl.h> 45 #include <sys/nsctl/rdc_prot.h> 46 47 #include <sys/nsctl/cfg.h> 48 49 #include <sys/unistat/spcs_s.h> 50 #include <sys/unistat/spcs_s_u.h> 51 #include <sys/unistat/spcs_errors.h> 52 53 #include "rdcadm.h" 54 55 56 int maxqfbas = MAXQFBAS; 57 int maxqitems = MAXQITEMS; 58 int autosync = AUTOSYNC; 59 int asyncthr = ASYNCTHR; 60 int qblock = QBLOCK; 61 62 int 63 mounted(char *device) 64 { 65 char target[NSC_MAXPATH]; 66 struct mnttab mntref; 67 struct mnttab mntent; 68 FILE *mntfp; 69 int rdsk; 70 char *s; 71 int i; 72 73 rdsk = i = 0; 74 for (s = target; i < NSC_MAXPATH && (*s = *device++); i++) { 75 if (*s == 'r' && rdsk == 0 && strncmp(device, "dsk/", 4) == 0) 76 rdsk = 1; 77 else 78 s++; 79 } 80 *s = '\0'; 81 82 mntref.mnt_special = target; 83 mntref.mnt_mountp = NULL; 84 mntref.mnt_fstype = NULL; 85 mntref.mnt_mntopts = NULL; 86 mntref.mnt_time = NULL; 87 88 mntfp = fopen(MNTTAB, "r"); 89 90 if (mntfp == NULL) { 91 rdc_warn(NULL, 92 gettext("can not check volume %s against mount table"), 93 mntref.mnt_special); 94 /* Assume the worst, that it is mounted */ 95 return (1); 96 } 97 98 if (getmntany(mntfp, &mntent, &mntref) != -1) { 99 /* found something before EOF */ 100 (void) fclose(mntfp); 101 return (1); 102 } 103 104 (void) fclose(mntfp); 105 return (0); 106 } 107 108 109 /* Needs to match parsing code in rdcboot.c and rdcadm.c */ 110 char * 111 rdc_decode_flag(int flag, int options) 112 { 113 static char str[32]; 114 115 switch (flag) { 116 case (RDC_CMD_COPY): 117 if (options & RDC_OPT_FULL) 118 (void) strcpy(str, "-m"); 119 else 120 (void) strcpy(str, "-u"); 121 if (options & RDC_OPT_REVERSE) 122 (void) strcat(str, " -r"); 123 break; 124 125 case (RDC_CMD_DISABLE): 126 (void) strcpy(str, "-d"); 127 break; 128 129 case (RDC_CMD_ENABLE): 130 if (options & RDC_OPT_SETBMP) 131 (void) strcpy(str, "-e"); 132 else 133 (void) strcpy(str, "-E"); 134 break; 135 136 case (RDC_CMD_LOG): 137 (void) strcpy(str, "-l"); 138 break; 139 140 case (RDC_CMD_HEALTH): 141 (void) strcpy(str, "-H"); 142 break; 143 144 case (RDC_CMD_WAIT): 145 (void) strcpy(str, "-w"); 146 break; 147 148 case (RDC_CMD_RECONFIG): 149 (void) strcpy(str, "-R ..."); 150 break; 151 152 case (RDC_CMD_TUNABLE): 153 (void) strcpy(str, ""); 154 if (maxqfbas != MAXQFBAS) 155 (void) strcat(str, " -F"); 156 if (maxqitems != MAXQITEMS) 157 (void) strcat(str, " -W"); 158 if (autosync != AUTOSYNC) 159 (void) strcat(str, " -a"); 160 if (asyncthr != ASYNCTHR) 161 (void) strcat(str, " -A"); 162 if (qblock != QBLOCK) 163 (void) strcat(str, " -D"); 164 break; 165 166 case (RDC_CMD_SUSPEND): 167 (void) strcpy(str, "-s"); 168 break; 169 170 case (RDC_CMD_RESUME): 171 (void) strcpy(str, "-r"); 172 break; 173 174 case (RDC_CMD_RESET): 175 (void) strcpy(str, "-R"); 176 break; 177 178 case (RDC_CMD_ADDQ): 179 (void) strcpy(str, "-q a"); 180 break; 181 182 case (RDC_CMD_REMQ): 183 (void) strcpy(str, "-q d"); 184 break; 185 186 case (RDC_CMD_REPQ): 187 (void) strcpy(str, "-q r"); 188 break; 189 190 default: 191 (void) strcpy(str, gettext("unknown")); 192 break; 193 } 194 195 return (str); 196 } 197 198 199 static void 200 rdc_msg(char *prefix, spcs_s_info_t *status, char *string, va_list ap) 201 { 202 if (status) { 203 (void) fprintf(stderr, "Remote Mirror: %s\n", prefix); 204 spcs_s_report(*status, stderr); 205 } else { 206 (void) fprintf(stderr, "%s: %s: ", program, prefix); 207 } 208 209 if (string && *string != '\0') { 210 (void) vfprintf(stderr, string, ap); 211 } 212 213 (void) fprintf(stderr, "\n"); 214 } 215 216 void 217 rdc_err(spcs_s_info_t *status, char *string, ...) 218 { 219 va_list ap; 220 va_start(ap, string); 221 222 rdc_msg(gettext("Error"), status, string, ap); 223 224 va_end(ap); 225 exit(1); 226 } 227 228 void 229 rdc_warn(spcs_s_info_t *status, char *string, ...) 230 { 231 va_list ap; 232 va_start(ap, string); 233 234 rdc_msg(gettext("warning"), status, string, ap); 235 236 va_end(ap); 237 } 238 239 int 240 rdc_get_maxsets(void) 241 { 242 rdc_status_t rdc_status; 243 spcs_s_info_t ustatus; 244 int rc; 245 246 rdc_status.nset = 0; 247 ustatus = spcs_s_ucreate(); 248 249 rc = RDC_IOCTL(RDC_STATUS, &rdc_status, 0, 0, 0, 0, ustatus); 250 if (rc == SPCS_S_ERROR) { 251 rdc_err(&ustatus, gettext("statistics error")); 252 } 253 254 spcs_s_ufree(&ustatus); 255 return (rdc_status.maxsets); 256 } 257 258 /* 259 * Look up a set in libcfg to find the setnumber. 260 * 261 * ASSUMPTIONS: 262 * - a valid cfg handle 263 * 264 * INPUTS: 265 * cfg - cfg handle 266 * tohost - secondary hostname 267 * tofile - secondary volume 268 * 269 * OUTPUTS: 270 * set number if found, otherwise -1 for an error 271 */ 272 int 273 find_setnumber_in_libcfg(CFGFILE *cfg, char *ctag, char *tohost, char *tofile) 274 { 275 int setnumber; 276 int entries, rc; 277 char *buf, *secondary, *shost; 278 char **entry; 279 char *cnode; 280 int offset = 0; 281 282 if (cfg == NULL) { 283 #ifdef DEBUG 284 rdc_warn(NULL, "cfg is NULL while looking up set number"); 285 #endif 286 return (-1); 287 } 288 289 entries = cfg_get_section(cfg, &entry, "sndr"); 290 291 rc = -1; 292 for (setnumber = 1; setnumber <= entries; setnumber++) { 293 buf = entry[setnumber - 1]; 294 295 (void) strtok(buf, " "); /* phost */ 296 (void) strtok(NULL, " "); /* primary */ 297 (void) strtok(NULL, " "); /* pbitmap */ 298 shost = strtok(NULL, " "); 299 secondary = strtok(NULL, " "); 300 301 if (ctag && *ctag) { 302 (void) strtok(NULL, " "); /* sbitmap */ 303 (void) strtok(NULL, " "); /* type */ 304 (void) strtok(NULL, " "); /* mode */ 305 (void) strtok(NULL, " "); /* group */ 306 cnode = strtok(NULL, " "); 307 308 if (ctag && strcmp(cnode, ctag) != 0) { 309 /* filter this out */ 310 ++offset; 311 continue; 312 } 313 } 314 315 /* Check secondary volume name first, will get less hits */ 316 if (strcmp(secondary, tofile) != 0) { 317 free(buf); 318 continue; 319 } 320 321 if (strcmp(shost, tohost) == 0) { 322 free(buf); 323 rc = setnumber - offset; 324 break; 325 } 326 327 free(buf); 328 } 329 330 while (setnumber < entries) 331 free(entry[setnumber++]); 332 if (entries) 333 free(entry); 334 335 return (rc); 336 } 337 338 void 339 get_group_diskq(CFGFILE *cfg, char *group, char *diskq) 340 { 341 int i; 342 char key[CFG_MAX_KEY]; 343 char buf[CFG_MAX_BUF]; 344 345 if (*group == '\0') 346 return; 347 for (i = 1; ; i++) { 348 bzero(&key, sizeof (key)); 349 bzero(&buf, sizeof (buf)); 350 (void) sprintf(key, "sndr.set%d.group", i); 351 if (cfg_get_cstring(cfg, key, &buf, sizeof (buf)) < 0) 352 break; 353 if (strncmp(group, buf, sizeof (buf)) == 0) { 354 (void) sprintf(key, "sndr.set%d.diskq", i); 355 if (cfg_get_cstring(cfg, key, diskq, CFG_MAX_BUF) < 0) { 356 rdc_warn(NULL, gettext("unable to retrieve " 357 "group %s's disk queue"), group); 358 } 359 } 360 } 361 } 362 363 int 364 get_cfg_setid(CFGFILE *cfg, char *ctag, char *tohost, char *tofile) 365 { 366 int setnum = 0; 367 int close_cfg = 0; 368 char key[CFG_MAX_KEY]; 369 char setid[64]; 370 371 if (cfg == NULL) { 372 close_cfg = 1; 373 if ((cfg = cfg_open(NULL)) == NULL) { 374 return (-1); /* message printed by caller */ 375 } 376 if (!cfg_lock(cfg, CFG_RDLOCK)) { 377 cfg_close(cfg); 378 return (-1); 379 } 380 } 381 setnum = find_setnumber_in_libcfg(cfg, ctag, tohost, tofile); 382 if (setnum < 0) 383 return (setnum); 384 385 (void) snprintf(key, CFG_MAX_KEY, "sndr.set%d.options", setnum); 386 if (cfg_get_single_option(cfg, CFG_SEC_CONF, key, "setid", 387 setid, sizeof (setid)) < 0) { 388 if (close_cfg) 389 cfg_close(cfg); 390 391 spcs_log("sndr", NULL, 392 gettext("%s unable to get unique setid " 393 "for %s:%s"), program, tohost, tofile); 394 return (-1); 395 396 } 397 if (close_cfg) 398 cfg_close(cfg); 399 400 return (atoi(setid)); 401 402 } 403 404 int 405 get_new_cfg_setid(CFGFILE *cfg) 406 { 407 int setid; 408 char buf[CFG_MAX_BUF]; 409 char *ctag; 410 411 /* If in a Sun Cluster, SetIDs need to have a ctag */ 412 if ((ctag = cfg_get_resource(cfg)) != NULL) { 413 ctag = strdup(ctag); 414 cfg_resource(cfg, "setid-ctag"); 415 } 416 417 if (cfg_get_cstring(cfg, "setid.set1.value", buf, CFG_MAX_BUF) < 0) { 418 setid = 1; 419 if (cfg_put_cstring(cfg, "setid", "1", CFG_MAX_BUF) < 0) { 420 rdc_err(NULL, "Unable to store new setid"); 421 } 422 } else { 423 setid = atoi(buf); 424 setid++; 425 if (setid <= 0) { 426 setid = 1; 427 } 428 } 429 430 bzero(&buf, CFG_MAX_BUF); 431 (void) snprintf(buf, sizeof (buf), "%d", setid); 432 if (cfg_put_cstring(cfg, "setid.set1.value", buf, CFG_MAX_BUF) < 0) { 433 rdc_err(NULL, "Unable to store new setid"); 434 } 435 436 /* Restore old ctag if in a Sun Cluster */ 437 if (ctag) { 438 cfg_resource(cfg, ctag); 439 free(ctag); 440 } 441 442 return (setid); 443 } 444 445 sigset_t origmask; 446 447 void 448 block_sigs(void) 449 { 450 sigset_t allsigs; 451 452 (void) sigfillset(&allsigs); 453 if (sigprocmask(SIG_BLOCK, &allsigs, &origmask) < 0) 454 rdc_warn(NULL, gettext("Unable to block signals")); 455 } 456 457 void 458 unblock_sigs(void) 459 { 460 if (sigprocmask(SIG_SETMASK, &origmask, NULL) < 0) 461 rdc_warn(NULL, gettext("Unable to unblock signals")); 462 463 }