/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #include #endif #define DEFAULT_PARSER_LOC "/etc/dscfg_format" int Cflg; int Dflg; int Lflg; int aflg; int iflg; int lflg; int nflg; int pflg; int rflg; int sflg; int uflg; int verbose; int noflags; int errflg; int mustcommit; char *locname; /* config location from cfg_location */ char *cmdname; #define MAX_FILENAME 80 char output_file[MAX_FILENAME]; /* specified output file */ char altroot[MAX_FILENAME]; /* specifed root location */ char config_file[MAX_FILENAME]; /* specified configuration file */ char input_file[MAX_FILENAME]; /* specified input file */ char logical_host[MAX_FILENAME]; /* specified cluster node */ char device_group[MAX_FILENAME]; /* specified device group name */ #define IS_NOT_CLUSTER 1 #define IS_CLUSTER 2 void cfg_invalidate_hsizes(int, const char *); static int check_cluster(); void usage(char *errmsg) { if (errmsg) (void) fprintf(stderr, "%s: %s\n", cmdname, errmsg); (void) fprintf(stderr, gettext("dscfg \t\t\t\tDisplay location of " "local configuration database\n")); (void) fprintf(stderr, gettext("dscfg -l -s path\t\t" "List contents of configuration database\n")); (void) fprintf(stderr, gettext( "\t\t\t\tlocated at path specified\n")); (void) fprintf(stderr, gettext("dscfg -i\t\t\t" "Initialize configuration database\n")); (void) fprintf(stderr, gettext("dscfg -i -p " #ifdef DEBUG "[-n] " #endif "/etc/dscfg_format\tFormat configuration database\n")); (void) fprintf(stderr, gettext("dscfg -a file\t\t\tRestore configuration " "database from file\n")); (void) fprintf(stderr, gettext("\t\t\t\tspecified\n")); (void) fprintf(stderr, gettext("dscfg -l\t\t\tList contents of configuration database" "\n")); (void) fprintf(stderr, gettext("dscfg -L\t\t\tDisplay configuration database's\n")); (void) fprintf(stderr, gettext("\t\t\t\tlock status\n")); (void) fprintf(stderr, gettext("dscfg -h\t\t\tUsage message\n")); if (check_cluster() != IS_NOT_CLUSTER) { (void) fprintf(stderr, gettext("\nSun Cluster Usage\n")); (void) fprintf(stderr, gettext("******************\n")); (void) fprintf(stderr, gettext("dscfg -s path\t\t\tSet cluster " "configuration database at DID\n")); (void) fprintf(stderr, gettext("\t\t\t\tpath specified\n")); (void) fprintf(stderr, gettext("dscfg -D device_group\t\t" "Check status of cluster device group\n")); (void) fprintf(stderr, gettext("dscfg -C -\t\t\t" "Display location of cluster configuration\n")); (void) fprintf(stderr, gettext("\t\t\t\tdatabase\n")); (void) fprintf(stderr, gettext("dscfg -l -s DID_device\t\tList " "the contents of cluster configuration\n")); (void) fprintf(stderr, gettext("\t\t\t\tdatabase\n")); (void) fprintf(stderr, gettext("dscfg -C - -i\t\t\tInitialize " "cluster configuration database\n")); (void) fprintf(stderr, gettext("dscfg -C - -i -p " "/etc/dscfg_format Format cluster configuration database\n")); (void) fprintf(stderr, gettext("dscfg -C - -a file\t\t" "Restore cluster configuration database from\n")); (void) fprintf(stderr, gettext("\t\t\t\tfile specified\n")); (void) fprintf(stderr, gettext("dscfg -C - -l\t\t\t" "List contents of local configuration database\n")); (void) fprintf(stderr, gettext("dscfg -C device_group -l\t" "List configuration database by device group\n")); (void) fprintf(stderr, gettext("dscfg -C \"-\" -l\t\t\t" "List configuration database excluding\n")); (void) fprintf(stderr, gettext("\t\t\t\tdevice groups\n")); } } int parse_parse_config(CFGFILE *cfg) { FILE *fp; char inbuf[CFG_MAX_BUF]; char *buff; int rc; /* * Open parser config file, use default if none specified */ buff = (input_file[0]) ? input_file : DEFAULT_PARSER_LOC; if ((fp = fopen(buff, "r")) == NULL) { (void) fprintf(stderr, gettext("parser config file (%s) not found\n"), buff); return (-1); } /* * start at begining of configration database */ cfg_rewind(cfg, CFG_SEC_ALL); while (((buff = fgets(inbuf, (sizeof (inbuf) - 1), fp)) != NULL)) { if (*buff == '#' || *buff == '%') continue; /* overwrite newline */ buff[strlen(buff) - 1] = '\0'; rc = cfg_update_parser_config(cfg, buff, CFG_PARSE_CONF); if (rc < 0) { (void) fprintf(stderr, gettext("update parser config rc %d key %s\n"), rc, buff); (void) fclose(fp); return (-1); } } (void) fclose(fp); return (1); } void parse_text_config(CFGFILE *cfg) { FILE *fp; char inbuf[CFG_MAX_BUF]; char *buff; char *key; char *p; int rc; if ((fp = fopen(input_file, "r")) == NULL) { (void) fprintf(stderr, gettext("Unable to open text config %s\n"), input_file); exit(2); } bzero(inbuf, sizeof (inbuf)); cfg_rewind(cfg, CFG_SEC_CONF); while (((buff = fgets(inbuf, (sizeof (inbuf) - 1), fp)) != NULL)) { if (*buff == '#') continue; /* overwrite newline */ buff[strlen(buff) - 1] = '\0'; key = strtok(buff, ":"); if (!key) { continue; } p = &buff[strlen(key)+2]; while (*p && isspace(*p)) { ++p; } if (!*p) { continue; } rc = cfg_put_cstring(cfg, key, p, strlen(p)); if (rc < 0) { (void) fprintf(stderr, gettext("update text config failed rc %d key %s"), rc, buff); return; } bzero(inbuf, sizeof (inbuf)); } (void) fclose(fp); } void dump_status(CFGFILE *cfg) { cfp_t *cfp = FP_SUN_CLUSTER(cfg); /* * WARNING will robinson * The following is using a non-exported internal interface * to libcfg * You may not use any of the following fields in MS software */ if (!locname) exit(2); if (!verbose) (void) printf("%s\n", locname); else { #ifdef DEBUG (void) printf(gettext("Configuration location: %s\n"), locname); (void) printf( gettext("Header info:\n\t\t\tmagic: %x\tstate: %x\n"), cfp->cf_head->h_magic, cfp->cf_head->h_state); (void) printf( gettext("Parser section:\t\t" "Start: %x\tsize: %d offset: %d\n"), cfp->cf_mapped, cfp->cf_head->h_parsesize, cfp->cf_head->h_parseoff); (void) printf( gettext("Config section:\t\t" "Start: %x\tsize:%d\tacsize: %d\n"), cfp->cf_head->h_cparse, cfp->cf_head->h_csize, cfp->cf_head->h_acsize); (void) printf("\t\t\tccopy1: %s\tccopy2: %s\n", cfp->cf_head->h_ccopy1, cfp->cf_head->h_ccopy2); (void) printf( gettext("Sequence:\t\tseq1: %d\t\tseq2: %d\n"), cfp->cf_head->h_seq1, cfp->cf_head->h_seq2); #endif } } void dump_lockstat(CFGFILE *cfg) { pid_t pid; CFGLOCK lock; char ps_str[1024]; if (cfg_get_lock(cfg, &lock, &pid) == TRUE) { (void) printf("%s %ld\n", lock == CFG_RDLOCK ? gettext("Read locked by process id") : gettext("Write locked by process id"), pid); (void) sprintf(ps_str, "ps -p %ld", pid); system(ps_str); } else (void) printf("%s\n", gettext("Not locked.")); } /* * dump current configuration section to stdout */ void print_config(CFGFILE *cfg) { time_t tloc = 0; int set = 0; char pconfig[CFG_MAX_BUF]; char key[CFG_MAX_KEY]; char buf[CFG_MAX_BUF]; char *cp, pbuf[CFG_MAX_BUF]; FILE *fp; int rc; int end; (void) snprintf(pconfig, sizeof (pconfig), "%s%s", altroot, DEFAULT_PARSER_LOC); if ((fp = fopen(pconfig, "r")) == NULL) { (void) fprintf(stderr, gettext("dscfg: unable to open " "parser configuration (%s): %s\n"), pconfig, strerror(errno)); exit(1); } (void) time(&tloc); (void) printf(gettext("# Consolidated Dataservice Configuration\n")); (void) printf(gettext("# Do not edit out whitespace or dashes\n")); (void) printf(gettext("# File created on: %s"), ctime(&tloc)); while (fgets(pbuf, (sizeof (pbuf) - 1), fp) != NULL) { if (pbuf[0] == '#') { /* comment */ continue; } /* force a NULL terminator */ pbuf[sizeof (pbuf) - 1] = '\0'; if (pbuf[0] == '%') { /* * descriptive text * - print it (with comment leader) and move on */ (void) printf("#%s", &pbuf[1]); continue; } /* * truncate the parser config in pbuf[] to just the tag */ cp = strchr(pbuf, '.'); if (cp != NULL) { *cp = '\0'; } set = 1; /*CONSTCOND*/ while (1) { bzero(buf, CFG_MAX_BUF); (void) snprintf(key, sizeof (key), "%s.set%d", pbuf, set); rc = cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF); if (rc < 0) { break; } /* trim trailing space if necessary */ end = strlen(buf) - 1; if (buf[end] == ' ') buf[end] = '\0'; (void) printf("%s:%s\n", pbuf, buf); set++; } } (void) fclose(fp); } int make_new_config(const char *fileloc) { int fd; int rc; int skip; char buf[CFG_MAX_BUF]; /*CONSTCOND*/ assert((sizeof (buf) % 512) == 0); bzero(buf, CFG_MAX_BUF); if ((fd = open(fileloc, O_RDWR | O_CREAT, 0640)) == -1) { return (-1); } /* if this is a device, we may have to skip the vtoc */ if ((skip = cfg_shldskip_vtoc(fd, fileloc)) == -1) { (void) fprintf(stderr, gettext("dscfg: unable to read vtoc on (%s)\n"), fileloc); return (-1); } else if (skip) { do { rc = lseek(fd, CFG_VTOC_SKIP, SEEK_SET); } while (rc == -1 && errno == EINTR); if (rc == -1) { (void) fprintf(stderr, gettext("dscfg: seek error")); return (-1); } } do { rc = write(fd, buf, sizeof (buf)); } while (rc == -1 && errno == EINTR); close(fd); return ((rc < 0) ? 0 : 1); } /* * dscfg * configure or return dataservice persistent configuration * * options * -i initialize file for first time * -l dump current configuration to stdout in ascii * -a add * -C node Set resource filter * -p parser config specified input file * -s set partition location or filename in default location * -L print configuration lock status * -u upgrade * -r prepend bootdir to beginning of path for cfg_open * no options status * * */ #ifdef lint int dscfg_lintmain(int argc, char *argv[]) #else int main(int argc, char *argv[]) #endif { CFGFILE *cfg; extern char *optarg; char *loc; int offset = 0; int rc; char c; int local; int action_counts = 0; bzero(input_file, sizeof (input_file)); (void) setlocale(LC_ALL, ""); (void) textdomain("dscfg"); logical_host[0] = '\0'; cmdname = argv[0]; #ifdef DEBUG while ((c = getopt(argc, argv, "a:C:dD:ilLp:r:s:hvn")) != EOF) { #else while ((c = getopt(argc, argv, "a:C:dD:ilLp:r:s:h")) != EOF) { #endif switch (c) { case 'a': aflg++; strcpy(input_file, optarg); mustcommit++; action_counts++; break; case 'C': Cflg++; strcpy(logical_host, optarg); if (logical_host && *logical_host == '-') if (argc == 3) action_counts++; break; case 'D': Dflg++; strcpy(device_group, optarg); action_counts++; break; case 'i': iflg++; mustcommit++; action_counts++; break; case 'l': lflg++; action_counts++; break; case 'L': Lflg++; action_counts++; break; case 'p': pflg++; strcpy(input_file, optarg); mustcommit++; break; case 's': sflg++; strcpy(config_file, optarg); action_counts++; break; case 'h': usage(NULL); exit(0); /*NOTREACHED*/ #ifdef DEBUG case 'v': verbose++; action_counts++; break; #endif #ifdef UPGRADE case 'u': uflg++; action_counts++; break; #endif case 'r': rflg++; strcpy(altroot, optarg); break; case 'n': nflg++; break; default: usage(NULL); exit(1); break; }; } switch (action_counts) { case 0: if (argc > 1) { if (pflg) usage(gettext( "-p option must be used in conjunction with -i")); else usage(gettext("must specify an action flag")); exit(1); } break; case 1: break; case 2: if (lflg && sflg) break; else { usage(gettext("too many action flags")); exit(1); break; } default: usage(gettext("too many action flags")); exit(1); break; } if (argc == 1 || (argc == 2 && verbose) || (argc == 3 && (rflg|Cflg))) noflags++; if (Dflg) { /* * Determine if the value specified is a device group * that is active on this node */ char *other_node; if ((cfg_issuncluster() > 0) && (strlen(device_group) > 0)) { local = cfg_dgname_islocal(device_group, &other_node); if (local == 0) (void) fprintf(stderr, gettext( "Device group %s active on %s\n"), device_group, other_node); else if (local == 1) (void) fprintf(stderr, gettext( "Device group %s active on this node\n"), device_group); else (void) fprintf(stderr, gettext( "Device group %s not found\n"), device_group); return (local); } else { (void) fprintf(stderr, gettext( "dscfg -D is only allowed in " "Sun Cluster OE\n")); return (0); } } if (sflg && !lflg) { /* * Only allow setting location on a non-sun cluster system * if the cluster reference file is already present. */ struct stat dscfg_stat = {0}; if (cfg_issuncluster() <= 0) { if (stat(CFG_CLUSTER_LOCATION, &dscfg_stat) != 0) { if (dscfg_stat.st_blocks == 0) { (void) fprintf(stderr, gettext( "dscfg -s is only allowed in " "Sun Cluster OE\n")); exit(1); } } } spcs_log("dscfg", NULL, gettext("dscfg -s %s"), config_file); locname = cfg_location(config_file, CFG_LOC_SET_CLUSTER, rflg ? altroot : NULL); if (locname == NULL) { (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(NULL)); exit(1); } else exit(0); } else if (sflg && lflg) { /* s used with l for temporarily peeking at a dscfg database */ loc = config_file; } else { locname = cfg_location(NULL, Cflg ? CFG_LOC_GET_CLUSTER : CFG_LOC_GET_LOCAL, rflg ? altroot : NULL); if (Cflg && (locname == NULL)) { (void) fprintf(stderr, gettext( "dscfg: cluster config not set: %s\n"), cfg_error(NULL)); return (1); } loc = rflg ? locname : NULL; } /* * the following hack forces the configuration file to initialize */ if (iflg && !pflg) { int fild; int c; char buf[CFG_MAX_BUF] = {0}; cfp_t *cfp; if (!nflg) { (void) printf( gettext("WARNING: This option will erase your " "Availability Suite configuration\n")); (void) printf( gettext("Do you want to continue? (Y/N) [N] ")); c = getchar(); switch (c) { case 'y': case 'Y': break; case 'n': case 'N': case '\n': (void) fprintf(stderr, gettext( "dscfg: configuration not initialized\n")); exit(1); default: (void) fprintf(stderr, gettext( "dscfg: %d is not a valid response\n"), c); exit(1); } } spcs_log("dscfg", NULL, gettext("dscfg -i")); if ((cfg = cfg_open(loc)) == NULL) { /* this is not a good config, or non-existent so.. */ if (!make_new_config(locname)) { (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(NULL)); exit(1); } if ((cfg = cfg_open(loc)) == NULL) { (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(NULL)); exit(1); } } /* * Set cluster node if specified */ if (Cflg) cfg_resource(cfg, logical_host); if (cfg_is_cfg(cfg) != 1) { if (!make_new_config(locname)) { (void) fprintf(stderr, gettext("dscfg: unable " " to create new config \n")); exit(1); } } if (!cfg_lock(cfg, CFG_WRLOCK)) { (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(NULL)); exit(1); } cfp = FP_SUN_CLUSTER(cfg); if ((fild = cfp->cf_fd) == 0) { (void) fprintf(stderr, gettext("dscfg: failure to access %s " "configuration database: %s\n"), (Cflg) ? gettext("cluster") : gettext("local"), cfg_error(NULL)); exit(1); } if (cfg_shldskip_vtoc(fild, locname) > 0) offset += CFG_VTOC_SKIP; lseek(fild, offset, SEEK_SET); write(fild, buf, sizeof (buf)); cfg_invalidate_hsizes(fild, locname); cfg_close(cfg); exit(0); } if (pflg && !iflg) { usage(gettext("-p option must be used in conjunction with -i")); exit(1); } if (uflg) { char cmd[CFG_MAX_BUF]; if (rflg) (void) snprintf(cmd, sizeof (cmd), "%s/usr/sbin/dscfg -r %s -l >" " %s/var/tmp/.dscfg.bak", altroot, altroot, altroot); else (void) snprintf(cmd, sizeof (cmd), "/usr/sbin/dscfg -l >" " /var/tmp/.dscfg.bak"); if (system(cmd) != 0) { (void) fprintf(stderr, "dscfg: unable to create backup\n"); exit(1); } if ((cfg = cfg_open(loc)) == NULL) { (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(NULL)); exit(2); } if (!cfg_lock(cfg, CFG_UPGRADE)) { (void) fprintf(stderr, gettext("dscfg: upgrade failed\n")); cfg_close(cfg); exit(1); } cfg_close(cfg); exit(0); } if ((cfg = cfg_open(loc)) == NULL) { (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(NULL)); exit(2); } /* * Set cluster node if specified */ if (Cflg) cfg_resource(cfg, logical_host); if ((!pflg) && (!noflags)) { if (cfg_is_cfg(cfg) != 1) { (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(NULL)); cfg_close(cfg); exit(1); } } if (Lflg) { dump_lockstat(cfg); cfg_close(cfg); exit(0); } if (noflags) { dump_status(cfg); cfg_close(cfg); exit(0); } if (!cfg_lock(cfg, mustcommit? CFG_WRLOCK : CFG_RDLOCK)) { (void) fprintf(stderr, gettext("cfg_lock: lock failed\n")); cfg_close(cfg); exit(1); } if (lflg) { print_config(cfg); cfg_close(cfg); exit(0); } /* * initialize configuration */ if (iflg) { spcs_log("dscfg", NULL, gettext("dscfg -i -p %s"), input_file); if (!pflg) { (void) fprintf(stderr, gettext("dscfg: cannot init without " "parser configuration file\n")); cfg_close(cfg); exit(1); } else if (parse_parse_config(cfg) < 0) { (void) fprintf(stderr, gettext("dscfg: cannot load " "parser configuration file\n")); cfg_close(cfg); exit(1); } } /* * read asci config file and write */ if (aflg) { spcs_log("dscfg", NULL, gettext("dscfg -a %s"), input_file); parse_text_config(cfg); } if (mustcommit) { rc = cfg_commit(cfg); if (rc < 0) { int sev = 0; (void) fprintf(stderr, gettext("dscfg: %s\n"), cfg_error(&sev)); if (sev == CFG_EFATAL) { cfg_close(cfg); exit(2); } } } cfg_close(cfg); return (0); } static int check_cluster() { static int is_cluster = -1; int rc; if (is_cluster != -1) return (is_cluster); rc = cfg_iscluster(); if (rc > 0) { is_cluster = IS_CLUSTER; return (is_cluster); } else if (rc == 0) { is_cluster = IS_NOT_CLUSTER; return (is_cluster); } else { (void) fprintf(stderr, gettext("dscfg: unable to determin environment\n")); /*NOTREACHED*/ } /* gcc */ return (is_cluster); }