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 }