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