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 <sys/time.h>
  29 #include <errno.h>
  30 #include <signal.h>
  31 #include <stdio.h>
  32 #include <string.h>
  33 #include <fcntl.h>
  34 #include <stdlib.h>
  35 #include <unistd.h>
  36 #include <values.h>
  37 #include <locale.h>
  38 #include <sys/stat.h>
  39 #include <strings.h>
  40 #include <stdarg.h>
  41 #include <sys/param.h>
  42 #include <nsctl.h>
  43 
  44 #include <sys/nsctl/cfg.h>
  45 #include <sys/unistat/spcs_s.h>
  46 #include <sys/unistat/spcs_s_u.h>
  47 #include <sys/unistat/spcs_errors.h>
  48 #include <sys/nsctl/dsw.h>
  49 #include <sys/nsctl/dsw_dev.h>            /* for bitmap format */
  50 
  51 #define DSW_TEXT_DOMAIN "II"
  52 #define BITMAP_TOKEN    "ii.set%d.bitmap"
  53 #define SHADOW_TOKEN    "ii.set%d.shadow"
  54 #define SV_TOKEN        "sv.set%d.vol"
  55 #define DSVOL_TOKEN     "dsvol.set%d.path"
  56 
  57 void iicpshd_usage();
  58 void copyshd(char *, char *);
  59 int find_cfg_info(char *, char *);
  60 int copy_shadow_vol(char *, char *);
  61 void convert_to_blockdevice();
  62 int update_dscfg(char *);
  63 
  64 extern int optind;
  65 
  66 extern  char *optarg;
  67 extern  int optind, opterr, optopt;
  68 int     copy_shadow = 1;
  69 CFGFILE *cfg;
  70 char    real_bitmap[DSW_NAMELEN];
  71 char    buf[CFG_MAX_BUF];
  72 char    key[CFG_MAX_KEY];
  73 int     set_number;
  74 int     sv_number;
  75 int     dsvol_number;
  76 
  77 #ifdef lint
  78 int
  79 iicpshd_lintmain(int argc, char *argv[])
  80 #else
  81 int
  82 main(int argc, char *argv[])
  83 #endif
  84 {
  85         if (argc > 1) {
  86                 if (strcmp(argv[1], "-s") == 0) {
  87                         /* don't copy shadow, only update dscfg and ii header */
  88                         copy_shadow = 0;
  89                         argc--;
  90                         argv++;
  91                 }
  92         }
  93 
  94         if (argc == 1 || (argc%2) == 0) /* must have pairs of filenames */
  95                 iicpshd_usage();
  96 
  97         /* open dscfg anyway */
  98         if ((cfg = cfg_open(NULL)) == NULL) {
  99                 (void) fprintf(stderr, gettext("Error opening config\n"));
 100                 exit(1);
 101         }
 102 
 103         for (argv++; *argv != NULL; argv += 2)
 104                 copyshd(argv[0], argv[1]);
 105 
 106         /* close dscfg */
 107         cfg_close(cfg);
 108         exit(0);
 109         return (0);
 110 }
 111 
 112 void
 113 iicpshd_usage()
 114 {
 115         (void) fprintf(stderr, gettext("Usage:\n"));
 116         (void) fprintf(stderr,
 117             gettext("\tiicpshd [-s] old_shadow new_shadow\n"));
 118         exit(1);
 119 }
 120 
 121 void
 122 copyshd(char *old_vol, char *new_vol)
 123 {
 124         int dsw_fd;
 125         FILE *ifp;
 126         char header[FBA_SIZE(1) * DSW_CBLK_FBA];
 127         ii_header_t *hp;
 128         dsw_stat_t args;
 129 
 130         /*LINTED pointer alignment*/
 131         hp = (ii_header_t *)&header;
 132 
 133         dsw_fd = open(DSWDEV, O_RDONLY);
 134         if (dsw_fd < 0) {
 135                 perror(DSWDEV);
 136                 exit(1);
 137         }
 138         if (*old_vol != '/' || *new_vol != '/') {
 139                 (void) fprintf(stderr, gettext("Both old and new shadow "
 140                     "file names must begin with a /.\n"));
 141                 exit(1);
 142         }
 143 
 144         if (strlen(new_vol) > DSW_NAMELEN) {
 145                 (void) fprintf(stderr,
 146                     gettext("New shadow name is to long.\n"));
 147                 exit(1);
 148         }
 149 
 150         /* check old shadow is in dscfg */
 151         if (find_cfg_info(old_vol, SHADOW_TOKEN) == 0) {
 152                 (void) fprintf(stderr,
 153                     gettext("Old shadow not in existing cfg\n"));
 154                 exit(1);
 155         }
 156 
 157         /* check ii set status, suspend if need */
 158         (void) strncpy(args.shadow_vol, old_vol, DSW_NAMELEN);
 159         args.shadow_vol[DSW_NAMELEN-1] = '\0';
 160         args.status = spcs_s_ucreate();
 161         if (ioctl(dsw_fd, DSWIOC_STAT, &args) != -1) {
 162                 (void) fprintf(stderr, gettext("Suspend the Point-in-Time Copy "
 163                     "set first\n"));
 164                 (void) close(dsw_fd);
 165                 exit(1);
 166         }
 167 
 168         if (copy_shadow) {
 169                 if (copy_shadow_vol(old_vol, new_vol) == 0) {
 170                         perror(gettext("Write new shadow failed"));
 171                         (void) close(dsw_fd);
 172                         exit(1);
 173                 }
 174         }
 175         if (find_cfg_info(old_vol, SV_TOKEN) == 0) {
 176                 (void) fprintf(stderr,
 177                     gettext("Old shadow not in existing cfg\n"));
 178                 exit(1);
 179         }
 180         if (find_cfg_info(old_vol, DSVOL_TOKEN) == 0) {
 181                 (void) fprintf(stderr,
 182                     gettext("Old shadow not in existing cfg\n"));
 183                 exit(1);
 184         }
 185         if (strstr(real_bitmap, "/rdsk/") == NULL) {
 186                 (void) fprintf(stderr,
 187                     gettext("%s is not a character device\n"), real_bitmap);
 188                 exit(1);
 189         }
 190 
 191         /* use block device /dsk/ to update bitmap header */
 192         convert_to_blockdevice();
 193 
 194         /* open bitmap by using update mode */
 195         if ((ifp = fopen(real_bitmap, "r+")) == NULL) {
 196                 (void) fprintf(stderr, gettext("Can't open bitmap file\n"));
 197                 exit(1);
 198         }
 199 
 200         /* Check old header looks like an II bitmap header */
 201         if (fread(&header, DSW_CBLK_FBA, FBA_SIZE(1), ifp) != FBA_SIZE(1)) {
 202                 (void) fprintf(stderr, gettext("Can't read bitmap file\n"));
 203                 exit(1);
 204         }
 205 
 206         if (hp->ii_magic != DSW_CLEAN && hp->ii_magic != DSW_DIRTY) {
 207                 (void) fprintf(stderr,
 208                     gettext("%s is not a Point-in-Time Copy "
 209                     "shadow.\n"), old_vol);
 210                 exit(1);
 211         }
 212 
 213         if (strncmp(hp->shadow_vol, old_vol, DSW_NAMELEN) != 0) {
 214                 (void) fprintf(stderr, gettext("%s has Point-in-Time Copy "
 215                     "shadow magic number,\n"
 216                     "but does not contain correct data.\n"), old_vol);
 217                 exit(1);
 218         }
 219 
 220         (void) memset(hp->shadow_vol, 0, DSW_NAMELEN);
 221         (void) strncpy(hp->shadow_vol, new_vol, DSW_NAMELEN);
 222 
 223         /* reset the pointer position */
 224         rewind(ifp);
 225         if (fwrite(&header, DSW_CBLK_FBA, FBA_SIZE(1), ifp) != FBA_SIZE(1)) {
 226                 perror(new_vol);
 227                 (void) fprintf(stderr,
 228                     gettext("Can't write new bitmap header\n"));
 229                 exit(1);
 230         }
 231         (void) fclose(ifp);
 232         (void) close(dsw_fd);
 233         if (update_dscfg(new_vol) == 0) {
 234                 (void) fprintf(stderr, gettext("Failed to update dscfg.\n"));
 235                 exit(1);
 236         } else {
 237                 spcs_log("ii", NULL,
 238                     "iicpshd copy shadow from %s to %s",
 239                     old_vol, new_vol);
 240         }
 241 }
 242 
 243 /*
 244  * find_cfg_info()
 245  *
 246  */
 247 
 248 int
 249 find_cfg_info(char *volume, char *token)
 250 {
 251         int i;
 252         /* get read lock */
 253         if (!cfg_lock(cfg, CFG_RDLOCK)) {
 254                 spcs_log("ii", NULL,
 255                     "iicpbmp CFG_RDLOCK failed, errno %d", errno);
 256                 (void) fprintf(stderr, gettext("Error locking config\n"));
 257                 exit(1);
 258         }
 259         for (i = 1; ; i++) {
 260                 bzero(buf, CFG_MAX_BUF);
 261                 (void) snprintf(key, sizeof (key), token, i);
 262                 if (cfg_get_cstring(cfg, key, buf, DSW_NAMELEN) < 0) {
 263                         cfg_unlock(cfg);
 264                         return (0);
 265                 }
 266                 if (strcmp(buf, volume) == 0) {
 267                         if (strcmp(token, SHADOW_TOKEN) == 0) {
 268                                 (void) snprintf(key, sizeof (key),
 269                                     BITMAP_TOKEN, i);
 270                                 (void) cfg_get_cstring(cfg, key,
 271                                     real_bitmap, DSW_NAMELEN);
 272                                 set_number = i;
 273                         } else if (strcmp(token, SV_TOKEN) == 0) {
 274                                 sv_number = i;
 275                         } else if (strcmp(token, DSVOL_TOKEN) == 0) {
 276                                 dsvol_number = i;
 277                         }
 278                         /* release read lock */
 279                         cfg_unlock(cfg);
 280                         return (1);
 281                 }
 282         }
 283 }
 284 
 285 int
 286 copy_shadow_vol(char *old_shadow, char *new_shadow) {
 287         int i;
 288         char cp_buffer[256];
 289         FILE *ishdfp, *oshdfp;
 290         if ((ishdfp = fopen(old_shadow, "r")) == NULL) {
 291                 (void) fprintf(stderr, gettext("Can't open old shadow file\n"));
 292                 return (0);
 293         }
 294         if ((oshdfp = fopen(new_shadow, "w")) == NULL) {
 295                 (void) fprintf(stderr, gettext("Can't open new shadow file\n"));
 296                 return (0);
 297         }
 298 
 299         /* Copy the shadow vol */
 300         while ((i = fread(cp_buffer, sizeof (char), sizeof (cp_buffer), ishdfp))
 301                 > 0) {
 302                 if (fwrite(cp_buffer, sizeof (char), i, oshdfp) != i) {
 303                         (void) fclose(ishdfp);
 304                         (void) fclose(oshdfp);
 305                         return (0);
 306                 }
 307         }
 308         (void) fclose(ishdfp);
 309         (void) fclose(oshdfp);
 310         return (1);
 311 }
 312 
 313 int
 314 update_dscfg(char *new_shadow) {
 315 
 316         int len = strlen(new_shadow);
 317         /* get write lock */
 318         if (!cfg_lock(cfg, CFG_WRLOCK)) {
 319                 spcs_log("ii", NULL,
 320                     "iicpbmp CFG_WRLOCK failed, errno %d", errno);
 321                 (void) fprintf(stderr, gettext("Error locking config\n"));
 322                 return (0);
 323         }
 324         (void) sprintf(key, SHADOW_TOKEN, set_number);
 325         if (cfg_put_cstring(cfg, key, new_shadow, len) < 0) {
 326                 perror("cfg_put_cstring");
 327                 return (0);
 328         }
 329         (void) sprintf(key, SV_TOKEN, sv_number);
 330         if (cfg_put_cstring(cfg, key, new_shadow, len) < 0) {
 331                 perror("cfg_put_cstring");
 332                 return (0);
 333         }
 334         (void) sprintf(key, DSVOL_TOKEN, dsvol_number);
 335         if (cfg_put_cstring(cfg, key, new_shadow, len) < 0) {
 336                 perror("cfg_put_cstring");
 337                 return (0);
 338         }
 339         (void) cfg_commit(cfg);
 340         cfg_unlock(cfg);
 341         return (1);
 342 }
 343 
 344 void
 345 convert_to_blockdevice() {
 346         int len = strlen(real_bitmap);
 347         int i = 0, j = 0;
 348         char *temp_string = malloc(len-1);
 349         while (i < len + 1) {
 350                 if (real_bitmap[i] != 'r') {
 351                         temp_string[j] = real_bitmap[i];
 352                         j++;
 353                 }
 354                 i++;
 355         }
 356         (void) strcpy(real_bitmap, temp_string);
 357         free(temp_string);
 358 }