summaryrefslogtreecommitdiff
path: root/usr/src/lib/librdc/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/librdc/common')
-rw-r--r--usr/src/lib/librdc/common/librdc.h113
-rw-r--r--usr/src/lib/librdc/common/llib-lrdc46
-rw-r--r--usr/src/lib/librdc/common/mapfile-vers78
-rw-r--r--usr/src/lib/librdc/common/netaddrs.c670
-rw-r--r--usr/src/lib/librdc/common/rdcconfig.c1321
-rw-r--r--usr/src/lib/librdc/common/rdcerr.c98
-rw-r--r--usr/src/lib/librdc/common/rdcerr.h74
-rw-r--r--usr/src/lib/librdc/common/rdcpersist.c716
-rw-r--r--usr/src/lib/librdc/common/rdcrules.c545
-rw-r--r--usr/src/lib/librdc/common/rdcrules.h46
10 files changed, 3707 insertions, 0 deletions
diff --git a/usr/src/lib/librdc/common/librdc.h b/usr/src/lib/librdc/common/librdc.h
new file mode 100644
index 0000000000..99ac34afe7
--- /dev/null
+++ b/usr/src/lib/librdc/common/librdc.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBRDC_H
+#define _LIBRDC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int Is_ipv6present(void);
+extern int self_check(char *);
+extern int gethost_netaddrs(char *, char *, char *, char *);
+extern struct hostent *gethost_byname(const char *);
+extern struct netbuf *get_addr(char *, ulong_t, ulong_t, struct netconfig **,
+ char *, char *, struct t_info *, int);
+extern int convert_nconf_to_knconf(struct netconfig *, struct knetconfig *);
+extern int rdc_check_release(char **);
+
+#if !defined(NSC_MAXPATH)
+#define NSC_MAXPATH 64
+#endif
+
+#define RDC_MAX_THREADS 1024
+/* user interface to sndr */
+typedef struct rdcconfig_s {
+ char phost[NSC_MAXPATH];
+ char pfile[NSC_MAXPATH];
+ char pbmp[NSC_MAXPATH];
+ char shost[NSC_MAXPATH];
+ char sfile[NSC_MAXPATH];
+ char sbmp[NSC_MAXPATH];
+ char direct[NSC_MAXPATH];
+ char mode[NSC_MAXPATH];
+ char group[NSC_MAXPATH];
+ char ctag[NSC_MAXPATH];
+ char options[NSC_MAXPATH];
+ int persist; /* 0 no, 1 yes */
+ struct rdcconfig_s *next;
+} rdcconfig_t;
+
+#define RDC_ERR_SIZE 256
+
+typedef struct rdc_rc_s {
+ int rc;
+ char msg[RDC_ERR_SIZE];
+ struct rdc_rc_s *next;
+ rdcconfig_t set;
+} rdc_rc_t;
+
+#define RDC_FREEONE 0 /* free one rdcconfig_t* */
+#define RDC_FREEALL 1 /* free entire chain of rdcconfig_t* */
+
+/* and it's operations */
+extern rdcconfig_t *rdc_alloc_config(const char *phost, const char *pfile,
+ const char *pbmp, const char *shost, const char *sfile, const char *sbmp,
+ const char *mode, const char *group, const char *ctag, const char *options,
+ int persist);
+extern void rdc_free_config(rdcconfig_t *rdc, int all);
+extern void rdc_free_rclist(rdc_rc_t *rc);
+extern rdc_rc_t *new_rc(void);
+extern rdc_rc_t *rdc_enable(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_enable_clrbmp(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_disable(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_log(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_usync(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_fsync(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_rsync(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_ursync(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_wait(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_set_autosync(rdcconfig_t *rdc, int autosync);
+extern rdc_rc_t *rdc_set_maxqfbas(rdcconfig_t *rdc, int maxqfbas);
+extern rdc_rc_t *rdc_set_maxqitems(rdcconfig_t *rdc, int maxqitems);
+extern int rdc_get_maxqfbas(rdcconfig_t *rdc);
+extern int rdc_get_maxqitems(rdcconfig_t *rdc);
+extern int rdc_get_autosync(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_reconfig_pbmp(rdcconfig_t *rdc, char *pbmp);
+extern rdc_rc_t *rdc_reconfig_sbmp(rdcconfig_t *rdc, char *sbmp);
+extern rdc_rc_t *rdc_reconfig_group(rdcconfig_t *rdc, char *group);
+extern rdc_rc_t *rdc_reconfig_ctag(rdcconfig_t *rdc, char *ctag);
+extern rdc_rc_t *rdc_set_sync(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_set_async(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_health(rdcconfig_t *rdc);
+extern rdc_rc_t *rdc_reverse_role(rdcconfig_t *rdc);
+extern char *rdc_error(int *sev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBRDC_H */
diff --git a/usr/src/lib/librdc/common/llib-lrdc b/usr/src/lib/librdc/common/llib-lrdc
new file mode 100644
index 0000000000..03b796f3be
--- /dev/null
+++ b/usr/src/lib/librdc/common/llib-lrdc
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <rpc/rpc.h>
+#include <netconfig.h>
+#include "librdc.h"
+
+int Is_ipv6present(void);
+int self_check(char *hostname);
+int gethost_netaddrs(char *fromhost, char *tohost, char *fromnetaddr,
+ char *tonetaddr);
+struct hostent *gethost_byname(const char *name);
+struct netbuf *get_addr(char *hostname, ulong_t prog, ulong_t vers,
+ struct netconfig **nconfp, char *proto, char *srvport,
+ struct t_info *tinfo, int portmap);
+int convert_nconf_to_knconf(struct netconfig *nconf, struct knetconfig *knconf);
+int rdc_check_release(char **reqd);
diff --git a/usr/src/lib/librdc/common/mapfile-vers b/usr/src/lib/librdc/common/mapfile-vers
new file mode 100644
index 0000000000..48bd348c64
--- /dev/null
+++ b/usr/src/lib/librdc/common/mapfile-vers
@@ -0,0 +1,78 @@
+# 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.
+#
+#
+# Generic interface definition for usr/src/lib/librdc.
+#
+# For information regarding the establishment of versioned definitions see:
+# The Linker and Libraries Manual (version 2.5 or greater)
+# This is part of the Developers Guide in the Answerbook. Specifically refer
+# to Chapter 2 under section "Defining Additional Symbols" through section
+# "Reducing Symbol Scope", and Chapter 5 "Versioning".
+#
+# For specific OSNET rules for the modification (evolution) of these version
+# definitions see:
+# Policy for Shared Library Version Names and Interface Definitions
+
+
+SUNWprivate_1.1 {
+ global:
+ Is_ipv6present;
+ convert_nconf_to_knconf;
+ get_addr;
+ gethost_byname;
+ gethost_netaddrs;
+ rdc_check_release;
+ rdc_set_error;
+ rdc_alloc_config;
+ rdc_free_config;
+ rdc_free_rclist;
+ self_check;
+ rdc_enable;
+ rdc_enable_clrbmp;
+ rdc_disable;
+ rdc_log;
+ rdc_usync;
+ rdc_fsync;
+ rdc_rsync;
+ rdc_ursync;
+ rdc_wait;
+ rdc_set_autosync;
+ rdc_set_maxqfbas;
+ rdc_set_maxqitems;
+ rdc_get_maxqfbas;
+ rdc_get_maxqitems;
+ rdc_get_autosync;
+ rdc_reconfig_pbmp;
+ rdc_reconfig_sbmp;
+ rdc_reconfig_group;
+ rdc_reconfig_ctag;
+ rdc_set_sync;
+ rdc_set_async;
+ rdc_health;
+ rdc_reverse_role;
+ rdc_error;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/librdc/common/netaddrs.c b/usr/src/lib/librdc/common/netaddrs.c
new file mode 100644
index 0000000000..ed90358618
--- /dev/null
+++ b/usr/src/lib/librdc/common/netaddrs.c
@@ -0,0 +1,670 @@
+/*
+ * 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 <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <varargs.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <sys/pathconf.h>
+#include <netdir.h>
+#include <netconfig.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <netinet/in.h>
+#include <nfs/nfs_sec.h>
+#include <strings.h>
+#include <sys/nsctl/rdc_prot.h>
+#include <nsctl.h>
+
+#include "librdc.h"
+
+#define MAXIFS 32
+
+/* number of transports to try */
+#define MNT_PREF_LISTLEN 2
+#define FIRST_TRY 1
+#define SECOND_TRY 2
+
+
+int
+Is_ipv6present(void)
+{
+#ifdef AF_INET6
+ int sock;
+ struct lifnum lifn;
+
+ sock = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return (0);
+
+ lifn.lifn_family = AF_INET6;
+ lifn.lifn_flags = 0;
+ if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
+ close(sock);
+ return (0);
+ }
+ close(sock);
+ if (lifn.lifn_count == 0)
+ return (0);
+ return (1);
+#else
+ return (0);
+#endif
+}
+
+/*
+ * The following is stolen from autod_nfs.c
+ */
+static void
+getmyaddrs(struct ifconf *ifc)
+{
+ int sock;
+ int numifs;
+ char *buf;
+ int family;
+
+ ifc->ifc_buf = NULL;
+ ifc->ifc_len = 0;
+
+#ifdef AF_INET6
+ family = AF_INET6;
+#else
+ family = AF_INET;
+#endif
+ if ((sock = socket(family, SOCK_DGRAM, 0)) < 0) {
+#ifdef DEBUG
+ perror("getmyaddrs(): socket");
+#endif
+ return;
+ }
+
+ if (ioctl(sock, SIOCGIFNUM, (char *)&numifs) < 0) {
+#ifdef DEBUG
+ perror("getmyaddrs(): SIOCGIFNUM");
+#endif
+ numifs = MAXIFS;
+ }
+
+ buf = (char *)malloc(numifs * sizeof (struct ifreq));
+ if (buf == NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "getmyaddrs(): malloc failed\n");
+#endif
+ (void) close(sock);
+ return;
+ }
+
+ ifc->ifc_buf = buf;
+ ifc->ifc_len = numifs * sizeof (struct ifreq);
+
+ if (ioctl(sock, SIOCGIFCONF, (char *)ifc) < 0) {
+#ifdef DEBUG
+ perror("getmyaddrs(): SIOCGIFCONF");
+#else
+ ;
+ /*EMPTY*/
+#endif
+ }
+
+ (void) close(sock);
+}
+
+int
+self_check(char *hostname)
+{
+ int n;
+ struct sockaddr_in *s1, *s2;
+ struct ifreq *ifr;
+ struct nd_hostserv hs;
+ struct nd_addrlist *retaddrs;
+ struct netconfig *nconfp;
+ struct ifconf *ifc;
+ int retval;
+
+ ifc = malloc(sizeof (struct ifconf));
+ if (ifc == NULL)
+ return (0);
+ memset((char *)ifc, 0, sizeof (struct ifconf));
+ getmyaddrs(ifc);
+ /*
+ * Get the IP address for hostname
+ */
+ nconfp = getnetconfigent("udp");
+ if (nconfp == NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "self_check(): getnetconfigent failed\n");
+#endif
+ retval = 0;
+ goto out;
+ }
+ hs.h_host = hostname;
+ hs.h_serv = "rpcbind";
+ if (netdir_getbyname(nconfp, &hs, &retaddrs) != ND_OK) {
+ freenetconfigent(nconfp);
+ retval = 0;
+ goto out;
+ }
+ freenetconfigent(nconfp);
+ /* LINTED pointer alignment */
+ s1 = (struct sockaddr_in *)retaddrs->n_addrs->buf;
+
+ /*
+ * Now compare it against the list of
+ * addresses for the interfaces on this
+ * host.
+ */
+ ifr = ifc->ifc_req;
+ n = ifc->ifc_len / sizeof (struct ifreq);
+ s2 = NULL;
+ for (; n > 0; n--, ifr++) {
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+
+ /* LINTED pointer alignment */
+ s2 = (struct sockaddr_in *)&ifr->ifr_addr;
+
+ if (memcmp((char *)&s2->sin_addr,
+ (char *)&s1->sin_addr, sizeof (s1->sin_addr)) == 0) {
+ netdir_free((void *)retaddrs, ND_ADDRLIST);
+ retval = 1;
+ goto out; /* it's me */
+ }
+ }
+ netdir_free((void *)retaddrs, ND_ADDRLIST);
+ retval = 0;
+
+out:
+ if (ifc->ifc_buf != NULL)
+ free(ifc->ifc_buf);
+ free(ifc);
+ return (retval);
+}
+
+
+int
+convert_nconf_to_knconf(struct netconfig *nconf, struct knetconfig *knconf)
+{
+ struct stat sb;
+
+ if (stat(nconf->nc_device, &sb) < 0) {
+ (void) syslog(LOG_ERR, "can't find device for transport %s\n",
+ nconf->nc_device);
+ return (-1);
+ }
+#ifdef DEBUG_ADDR
+ printf("lib knconf %x %s %s %x\n", nconf->nc_semantics,
+ nconf->nc_protofmly, nconf->nc_proto, sb.st_rdev);
+#endif
+
+ knconf->knc_semantics = nconf->nc_semantics;
+ knconf->knc_protofmly = nconf->nc_protofmly;
+ knconf->knc_proto = nconf->nc_proto;
+ knconf->knc_rdev = sb.st_rdev;
+
+ return (0);
+}
+
+struct hostent *
+gethost_byname(const char *name)
+{
+ int errnum;
+#ifdef AF_INET6
+ return (getipnodebyname(name, AF_INET6, AI_DEFAULT, &errnum));
+#else /* !AF_INET6 */
+ return (gethostbyname(name));
+#endif /* AF_INET6 */
+}
+
+int
+gethost_netaddrs(char *fromhost, char *tohost,
+ char *fromnetaddr, char *tonetaddr)
+{
+ struct hostent *host;
+ int j;
+ int errnum;
+
+#ifdef AF_INET6
+ host = getipnodebyname(fromhost, AF_INET6, AI_DEFAULT, &errnum);
+ if (host == NULL) {
+#ifdef DEBUG
+ (void) fprintf(stderr, dgettext("sndr",
+ "Could not find host %s"), fromhost);
+#endif
+ return (-1);
+ }
+ for (j = 0; j < host->h_length; j++)
+ fromnetaddr[j] = host->h_addr[j];
+ freehostent(host);
+#else /* !AF_INET6 */
+ host = gethostbyname(fromhost);
+ if (host == NULL) {
+#ifdef DEBUG
+ (void) fprintf(stderr, dgettext("sndr",
+ "Could not find host %s"), fromhost);
+#endif
+ return (-1);
+ }
+
+ if (host->h_length < 4) {
+#ifdef DEBUG
+ fprintf(stderr, "host->h_length(%d) < 4!\n", host->h_length);
+#endif
+ return (-1);
+ }
+
+ for (j = 0; j < host->h_length; j++)
+ fromnetaddr[j] = host->h_addr[j];
+#endif /* AF_INET6 */
+
+#ifdef AF_INET6
+ host = getipnodebyname(tohost, AF_INET6, AI_DEFAULT, &errnum);
+ if (host == NULL) {
+#ifdef DEBUG
+ (void) fprintf(stderr, dgettext("sndr",
+ "Could not find host %s"), tohost);
+#endif
+ return (-1);
+ }
+ for (j = 0; j < host->h_length; j++)
+ tonetaddr[j] = host->h_addr[j];
+ freehostent(host);
+#else /* !AF_INET6 */
+ host = gethostbyname(tohost);
+ if (host == NULL) {
+#ifdef DEBUG
+ (void) fprintf(stderr, dgettext("sndr",
+ "Could not find host %s"), tohost);
+#endif
+ return (-1);
+ }
+
+ if (host->h_length < 4) {
+#ifdef DEBUG
+ fprintf(stderr, "host->h_length(%d) < 4!\n", host->h_length);
+#endif
+ return (-1);
+ }
+
+ for (j = 0; j < host->h_length; j++)
+ tonetaddr[j] = host->h_addr[j];
+#endif /* AF_INET6 */
+ return (0);
+}
+
+/*
+ * Get the network address on "hostname" for program "prog"
+ * with version "vers" by using the nconf configuration data
+ * passed in.
+ *
+ * If the address of a netconfig pointer is null then
+ * information is not sufficient and no netbuf will be returned.
+ *
+ * Finally, ping the null procedure of that service.
+ *
+ */
+static struct netbuf *
+get_the_addr(char *hostname, ulong_t prog, ulong_t vers,
+ struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
+ int portmap)
+{
+ struct netbuf *nb = NULL;
+ struct t_bind *tbind = NULL;
+ CLIENT *cl = NULL;
+ struct timeval tv;
+ int fd = -1;
+ AUTH *ah = NULL;
+
+ if (nconf == NULL)
+ return (NULL);
+
+ if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1)
+ goto done;
+
+ /* LINTED pointer alignment */
+ if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) == NULL)
+ goto done;
+
+ if (portmap) { /* contact rpcbind */
+ if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
+ hostname) == FALSE) {
+ goto done;
+ }
+
+ if (port) {
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in *)tbind->addr.buf)->sin_port
+ = port;
+#ifdef NC_INET6
+ else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
+ = port;
+#endif
+ }
+
+ /* Simon -- we never use the client we create?! */
+ cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
+ if (cl == NULL)
+ goto done;
+
+ ah = authsys_create_default();
+ if (ah != NULL)
+ cl->cl_auth = ah;
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+ (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
+ } else { /* create our own address and skip rpcbind */
+ struct netbuf *nb;
+ struct hostent *hp;
+ int j;
+ int errnum;
+ unsigned short family;
+ nb = &(tbind->addr);
+
+#ifdef AF_INET6
+ if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
+ hp = getipnodebyname(hostname, AF_INET6, 0, &errnum);
+ family = AF_INET6;
+ nb->len = nb->maxlen = sizeof (struct sockaddr_in6);
+ } else {
+ hp = getipnodebyname(hostname, AF_INET, 0, &errnum);
+ family = AF_INET;
+ nb->len = nb->maxlen = sizeof (struct sockaddr_in);
+ }
+ if (hp == NULL) {
+#ifdef DEBUG_ADDR
+ (void) fprintf(stderr, dgettext("sndr",
+ "Could not find host %s\n"), hostname);
+#endif
+ goto done;
+ }
+ nb->buf = (char *)calloc(1, nb->maxlen);
+ if (nb->buf == NULL) {
+ (void) printf(dgettext("sndr", "no memory\n"));
+ goto done;
+ }
+
+ if (family == AF_INET) {
+ for (j = 0; j < hp->h_length; j++)
+ nb->buf[j+4] = hp->h_addr[j];
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in *)(nb->buf))->sin_port = port;
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in *)(nb->buf))->sin_family = AF_INET;
+ } else {
+ for (j = 0; j < hp->h_length; j++)
+ nb->buf[j+8] = hp->h_addr[j];
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in6 *)(nb->buf))->sin6_port = port;
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in6 *)(nb->buf))->sin6_family =
+ AF_INET6;
+ }
+ freehostent(hp);
+#else
+ hp = gethostbyname(hostname);
+ if (hp == NULL) {
+#ifdef DEBUG
+ (void) fprintf(stderr, dgettext("sndr",
+ "Could not find host %s"), hostname);
+#endif
+ goto done;
+ }
+
+ nb->len = nb->maxlen = sizeof (struct sockaddr_in);
+ nb->buf = (char *)calloc(1, nb->maxlen);
+ if (nb->buf == NULL) {
+ (void) printf(dgettext("sndr", "no memory\n"));
+ free(nb);
+ nb = NULL;
+ goto done;
+ }
+
+ for (j = 0; j < hp->h_length; j++)
+ nb->buf[j+4] = hp->h_addr[j];
+
+ if (hp->h_addrtype == AF_INET) {
+ ((struct sockaddr_in *)(nb->buf))->sin_port = port;
+ ((struct sockaddr_in *)(nb->buf))->sin_family = AF_INET;
+ }
+#endif
+ }
+
+ /*
+ * Make a copy of the netbuf to return
+ */
+ nb = (struct netbuf *)calloc(1, sizeof (*nb));
+ if (nb == NULL) {
+ (void) printf(dgettext("sndr", "no memory\n"));
+ goto done;
+ }
+
+ *nb = tbind->addr; /* structure copy */
+
+ nb->buf = (char *)calloc(1, nb->maxlen);
+ if (nb->buf == NULL) {
+ (void) printf(dgettext("sndr", "no memory\n"));
+ free(nb);
+ nb = NULL;
+ goto done;
+ }
+
+ (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
+
+done:
+ if (cl) {
+ if (ah != NULL) {
+ AUTH_DESTROY(cl->cl_auth);
+ cl->cl_auth = NULL;
+ }
+
+ clnt_destroy(cl);
+ cl = NULL;
+ }
+
+ if (tbind) {
+ t_free((char *)tbind, T_BIND);
+ tbind = NULL;
+ }
+
+ if (fd >= 0)
+ (void) t_close(fd);
+ return (nb);
+}
+
+/*
+ * Get a network address on "hostname" for program "prog"
+ * with version "vers". If the port number is specified (non zero)
+ * then try for a TCP/UDP transport and set the port number of the
+ * resulting IP address.
+ *
+ * If the address of a netconfig pointer was passed and
+ * if it's not null, use it as the netconfig otherwise
+ * assign the address of the netconfig that was used to
+ * establish contact with the service.
+ * If portmap is false, we return a similiar address and we do not
+ * contact rpcbind
+ *
+ */
+struct netbuf *
+get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp,
+ char *proto, char *srvport, struct t_info *tinfo, int portmap)
+{
+ struct netbuf *nb = NULL;
+ struct netconfig *nconf = NULL;
+ NCONF_HANDLE *nc = NULL;
+ int nthtry = FIRST_TRY;
+ struct servent *svp;
+ ushort_t port;
+
+ /*
+ * First lets get the requested port
+ */
+
+ if ((svp = getservbyname(srvport, proto)) == NULL)
+ goto done;
+ port = svp->s_port;
+ /*
+ * No nconf passed in.
+ *
+ * Try to get a nconf from /etc/netconfig filtered by
+ * the NETPATH environment variable.
+ * First search for COTS, second for CLTS unless proto
+ * is specified. When we retry, we reset the
+ * netconfig list so that we would search the whole list
+ * all over again.
+ */
+ if ((nc = setnetpath()) == NULL)
+ goto done;
+
+ /*
+ * If proto is specified, then only search for the match,
+ * otherwise try COTS first, if failed, try CLTS.
+ */
+ if (proto) {
+ while (nconf = getnetpath(nc)) {
+ if (strcmp(nconf->nc_netid, proto) == 0) {
+ /*
+ * If the port number is specified then TCP/UDP
+ * is needed. Otherwise any cots/clts will do.
+ */
+ if (port == 0)
+ break;
+
+ if ((strcmp(nconf->nc_protofmly, NC_INET) == 0
+#ifdef NC_INET6
+ /* CSTYLED */
+ || strcmp(nconf->nc_protofmly, NC_INET6) == 0
+#endif
+ /* CSTYLED */
+ ) &&
+ (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
+ strcmp(nconf->nc_proto, NC_UDP) == 0))
+ break;
+ else {
+ nconf = NULL;
+ break;
+ }
+ }
+ }
+ if (nconf == NULL)
+ goto done;
+ if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
+ tinfo, portmap)) == NULL) {
+ goto done;
+ }
+ } else {
+retry:
+ while (nconf = getnetpath(nc)) {
+ if (nconf->nc_flag & NC_VISIBLE) {
+ if (nthtry == FIRST_TRY) {
+ if ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
+ (nconf->nc_semantics == NC_TPI_COTS)) {
+ if (port == 0)
+ break;
+ if ((strcmp(nconf->nc_protofmly,
+ NC_INET) == 0
+#ifdef NC_INET6
+ /* CSTYLED */
+ || strcmp(nconf->nc_protofmly,
+ NC_INET6) == 0
+#endif
+ /* CSTYLED */
+ ) &&
+ (strcmp(nconf->nc_proto, NC_TCP) == 0))
+ break;
+ }
+ }
+ }
+ } /* while */
+ if (nconf == NULL) {
+ if (++nthtry <= MNT_PREF_LISTLEN) {
+ endnetpath(nc);
+ if ((nc = setnetpath()) == NULL)
+ goto done;
+ goto retry;
+ } else
+ goto done;
+ } else {
+ if ((nb = get_the_addr(hostname, prog, vers, nconf,
+ port, tinfo, portmap)) == NULL) {
+ /*
+ * Continue the same search path in the
+ * netconfig db until no more matched
+ * nconf (nconf == NULL).
+ */
+ goto retry;
+ }
+#ifdef AF_INET6
+ if ((nb->len == 8) &&
+ (strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
+ /*
+ * We have a mismatch in the netconfig retry
+ */
+ free(nb);
+ goto retry;
+ }
+#endif
+ }
+ }
+
+ /*
+ * Got nconf and nb. Now dup the netconfig structure (nconf)
+ * and return it thru nconfp.
+ */
+ *nconfp = getnetconfigent(nconf->nc_netid);
+ if (*nconfp == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ free(nb);
+ nb = NULL;
+ }
+done:
+ if (nc)
+ endnetpath(nc);
+ return (nb);
+}
+
+
+/* return values as for nsc_check_release() */
+int
+rdc_check_release(char **reqd)
+{
+ /* librdc.so must be built on the runtime OS release */
+ return (nsc_check_release(BUILD_REV_STR, NULL, reqd));
+}
diff --git a/usr/src/lib/librdc/common/rdcconfig.c b/usr/src/lib/librdc/common/rdcconfig.c
new file mode 100644
index 0000000000..92e735d66e
--- /dev/null
+++ b/usr/src/lib/librdc/common/rdcconfig.c
@@ -0,0 +1,1321 @@
+/*
+ * 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 <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/stream.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <thread.h>
+#include <pthread.h>
+
+#include <sys/unistat/spcs_s.h>
+#include <sys/unistat/spcs_s_u.h>
+#include <sys/unistat/spcs_s_impl.h>
+#include <sys/unistat/spcs_errors.h>
+
+#include <sys/nsctl/rdc_io.h>
+#include <sys/nsctl/rdc_ioctl.h>
+#include <sys/nsctl/rdc_prot.h>
+#include <sys/nsctl/librdc.h>
+#include <sys/nsctl/rdcrules.h>
+#include <sys/nsctl/rdcerr.h>
+#include <sys/nsctl/cfg.h>
+
+#include <sys/unistat/spcs_dtrinkets.h>
+#include <sys/unistat/spcs_etrinkets.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <rpc/rpc_com.h>
+#include <rpc/rpc.h>
+
+struct netbuf svaddr, *svp;
+struct netconfig nconf, *conf;
+struct knetconfig knconf;
+
+/*
+ * libdscfg type stuff here
+ */
+extern int sv_enable(CFGFILE *cfg, rdcconfig_t *rdc);
+extern int add_to_rdc_cfg(rdcconfig_t *rdcs);
+extern int remove_from_rdc_cfg(rdcconfig_t *rdcs);
+extern int replace_cfgfield(rdcconfig_t *rdcs, char *field, char *value);
+extern int reverse_in_cfg(rdcconfig_t *rdcs);
+
+rdcconfig_t *
+rdc_dup_config(rdcconfig_t *orig)
+{
+ rdcconfig_t *rc;
+
+ rc = (rdcconfig_t *)calloc(1, sizeof (*rc));
+ if (!rc) {
+ rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
+ return (NULL);
+ }
+
+ *rc = *orig;
+ rc->next = NULL; /* don't want to hook into wrong chaing */
+ return (rc);
+}
+
+/*
+ * takes in a chain of rdcconfig_t's and a chain
+ * of rdc_rc_t's, checks for success in the rdc_rc_t,
+ * then adds the corresponding rdcconfig_t to the return
+ * chain.
+ */
+rdcconfig_t *
+chain_successful(rdcconfig_t *rdcs, rdc_rc_t *rcs)
+{
+ rdc_rc_t *rcp;
+ rdcconfig_t *rdcp;
+ rdcconfig_t *ret = NULL;
+ rdcconfig_t *retp = NULL;
+
+ rcp = rcs;
+ rdcp = rdcs;
+
+ while (rcp) {
+ if (rcp->rc == 0) {
+ if ((ret == NULL) && (rdcp->persist)) {
+ retp = ret = rdc_dup_config(rdcp);
+
+ } else if ((ret) && (rdcp->persist)) {
+ retp->next = rdc_dup_config(rdcp);
+ retp = retp->next;
+ }
+ }
+ rcp = rcp->next;
+ rdcp = rdcp->next;
+ }
+ return (ret);
+
+}
+
+rdc_set_t
+config2set(rdcconfig_t *rdc)
+{
+ rdc_set_t urdc;
+
+ bzero(&urdc, sizeof (rdc_set_t));
+ strncpy(urdc.primary.intf, rdc->phost, MAX_RDC_HOST_SIZE);
+ strncpy(urdc.primary.file, rdc->pfile, NSC_MAXPATH);
+ strncpy(urdc.primary.bitmap, rdc->pbmp, NSC_MAXPATH);
+ strncpy(urdc.secondary.intf, rdc->shost, MAX_RDC_HOST_SIZE);
+ strncpy(urdc.secondary.file, rdc->sfile, NSC_MAXPATH);
+ strncpy(urdc.secondary.bitmap, rdc->sbmp, NSC_MAXPATH);
+ strncpy(urdc.group_name, rdc->group, NSC_MAXPATH);
+
+ return (urdc);
+}
+
+rdc_rc_t *
+new_rc()
+{
+ rdc_rc_t *rc;
+
+ rc = (rdc_rc_t *)calloc(1, sizeof (*rc));
+ if (rc == NULL) {
+ rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
+ return (NULL);
+ }
+ return (rc);
+}
+
+rdc_rc_t
+rdc_config(rdc_config_t *rdccfg)
+{
+ rdc_rc_t rc;
+ rdc_set_t *set;
+ spcs_s_info_t ustatus;
+
+ bzero(&rc, sizeof (rc));
+ ustatus = spcs_s_ucreate();
+
+ if (self_check(rdccfg->rdc_set->primary.intf)) {
+ rdccfg->options |= RDC_OPT_PRIMARY;
+ /* this needs changin if we do campus */
+ rdccfg->rdc_set->direct_file[0] = 0;
+ } else {
+ rdccfg->options |= RDC_OPT_SECONDARY;
+ }
+
+ /* set up return stuff.. */
+ set = &rdccfg->rdc_set[0];
+ strncpy(rc.set.phost, set->primary.intf, MAX_RDC_HOST_SIZE);
+ strncpy(rc.set.pfile, set->primary.file, NSC_MAXPATH);
+ strncpy(rc.set.shost, set->secondary.intf, MAX_RDC_HOST_SIZE);
+ strncpy(rc.set.sfile, set->secondary.file, NSC_MAXPATH);
+
+ rc.rc = RDC_IOCTL(RDC_CONFIG, rdccfg, NULL, 0, 0, 0, ustatus);
+
+ if (rc.rc < 0) {
+ rdc_set_error(&ustatus, RDC_SPCS, 0, 0);
+ strncpy(rc.msg, rdc_error(NULL), RDC_ERR_SIZE);
+ }
+
+ return (rc);
+}
+
+void *
+rdc_mtconfig(void *rdc)
+{
+ rdc_rc_t *rc[1];
+ rdc_set_t *set;
+ spcs_s_info_t ustatus;
+ rdc_config_t *rdccfg = (rdc_config_t *)rdc;
+
+ ustatus = spcs_s_ucreate();
+
+ if (self_check(rdccfg->rdc_set->primary.intf)) {
+ rdccfg->options |= RDC_OPT_PRIMARY;
+ /* this needs changin if we do campus */
+ rdccfg->rdc_set->direct_file[0] = 0;
+ } else {
+ rdccfg->options |= RDC_OPT_SECONDARY;
+ }
+
+ set = &rdccfg->rdc_set[0];
+ *rc = new_rc();
+
+ strncpy(rc[0]->set.phost, set->primary.intf, MAX_RDC_HOST_SIZE);
+ strncpy(rc[0]->set.pfile, set->primary.file, NSC_MAXPATH);
+ strncpy(rc[0]->set.pbmp, set->primary.bitmap, NSC_MAXPATH);
+ strncpy(rc[0]->set.shost, set->secondary.intf, MAX_RDC_HOST_SIZE);
+ strncpy(rc[0]->set.sfile, set->secondary.file, NSC_MAXPATH);
+ strncpy(rc[0]->set.sbmp, set->secondary.bitmap, NSC_MAXPATH);
+
+ rc[0]->rc = RDC_IOCTL(RDC_CONFIG, rdccfg, NULL, 0, 0, 0, ustatus);
+
+ if (rc[0]->rc < 0) {
+ rdc_set_error(&ustatus, RDC_SPCS, 0, 0);
+ strncpy(rc[0]->msg, rdc_error(NULL), RDC_ERR_SIZE);
+ }
+
+ sleep(1); /* give thr_join a chance to be called */
+ free(rdccfg);
+ thr_exit((void **) *rc);
+ return (NULL);
+}
+int
+populate_addrs(rdc_set_t *urdc, int isenable)
+{
+ struct t_info tinfo;
+ struct hostent *hp;
+ char toname[MAX_RDC_HOST_SIZE];
+ char fromname[MAX_RDC_HOST_SIZE];
+
+ strncpy(fromname, urdc->primary.intf, MAX_RDC_HOST_SIZE);
+ strncpy(toname, urdc->secondary.intf, MAX_RDC_HOST_SIZE);
+
+ if ((fromname[0] == '\0') || (fromname[0] == '\0')) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_FATAL,
+ "NULL hostname recieved");
+ return (-1);
+ }
+
+ hp = gethost_byname(fromname);
+ strncpy(fromname, hp->h_name, MAX_RDC_HOST_SIZE);
+ hp = gethost_byname(toname);
+ strncpy(toname, hp->h_name, MAX_RDC_HOST_SIZE);
+
+ if (self_check(fromname) && self_check(toname)) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_FATAL, "");
+ }
+
+ if (isenable) {
+ svp = get_addr(toname, RDC_PROGRAM, RDC_VERS_MIN,
+ &conf, NULL, "rdc", &tinfo, 0);
+ if (svp == NULL)
+ return (-1);
+ svaddr = *svp;
+ } else {
+ bzero(&svaddr, sizeof (svaddr));
+ }
+
+ urdc->secondary.addr.len = svaddr.len;
+ urdc->secondary.addr.maxlen = svaddr.maxlen;
+ urdc->secondary.addr.buf = (void*)svaddr.buf;
+
+ if (isenable) {
+ svp = get_addr(fromname, RDC_PROGRAM, RDC_VERS_MIN,
+ &conf, NULL, "rdc", &tinfo, 0);
+ if (svp == NULL)
+ return (-1);
+ svaddr = *svp;
+ } else {
+ bzero(&svaddr, sizeof (svaddr));
+ }
+
+ urdc->primary.addr.len = svaddr.len;
+ urdc->primary.addr.maxlen = svaddr.maxlen;
+ urdc->primary.addr.buf = (void*)svaddr.buf;
+
+ if (isenable) {
+ convert_nconf_to_knconf(conf, &knconf);
+ urdc->netconfig = &knconf;
+ } else {
+ urdc->netconfig = NULL;
+ }
+ urdc->syshostid = (int32_t)gethostid();
+
+ return (1);
+
+}
+void
+rdc_free_config(rdcconfig_t *rdc, int all)
+{
+ rdcconfig_t *rdcp;
+ rdcconfig_t *rdcq;
+
+ rdcp = rdc;
+ if (all == RDC_FREEONE) {
+ free(rdcp);
+ } else while (rdcp) {
+ rdcq = rdcp->next;
+ free(rdcp);
+ rdcp = rdcq;
+ }
+ rdc = NULL;
+}
+
+void
+rdc_free_rclist(rdc_rc_t *rc) {
+ rdc_rc_t *rcp, *rcq;
+
+ rcp = rc;
+ while (rcp) {
+ rcq = rcp->next;
+ free(rcp);
+ rcp = rcq;
+ }
+
+}
+/*ARGSUSED*/
+rdcconfig_t *
+rdc_alloc_config(const char *phost, const char *pfile,
+ const char *pbmp, const char *shost, const char *sfile, const char *sbmp,
+ const char *mode, const char *group, const char *ctag, const char *options,
+ int persist)
+{
+ rdcconfig_t *rc;
+
+ rc = (rdcconfig_t *)calloc(1, sizeof (*rc));
+ if (!rc) {
+ rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
+ return (NULL);
+ }
+ if (phost)
+ strncpy(rc->phost, phost, NSC_MAXPATH);
+ if (pfile)
+ strncpy(rc->pfile, pfile, NSC_MAXPATH);
+ if (pbmp)
+ strncpy(rc->pbmp, pbmp, NSC_MAXPATH);
+ if (shost)
+ strncpy(rc->shost, shost, NSC_MAXPATH);
+ if (sfile)
+ strncpy(rc->sfile, sfile, NSC_MAXPATH);
+ if (sbmp)
+ strncpy(rc->sbmp, sbmp, NSC_MAXPATH);
+
+ strncpy(rc->direct, "ip", 2);
+
+ if (mode)
+ strncpy(rc->mode, mode, NSC_MAXPATH);
+ if (ctag)
+ strncpy(rc->ctag, ctag, NSC_MAXPATH);
+ if (options)
+ strncpy(rc->options, options, NSC_MAXPATH);
+
+ rc->persist = persist;
+ rc->next = NULL;
+
+ return (rc);
+
+}
+
+void
+populate_rc(rdc_rc_t *rcp, rdcconfig_t *rdcp)
+{
+ rcp->rc = -1;
+ strncpy(rcp->msg, rdc_error(NULL), RDC_ERR_SIZE);
+ strncpy(rcp->set.phost, rdcp->phost, NSC_MAXPATH);
+ strncpy(rcp->set.pfile, rdcp->pfile, NSC_MAXPATH);
+ strncpy(rcp->set.shost, rdcp->shost, NSC_MAXPATH);
+ strncpy(rcp->set.sfile, rdcp->sfile, NSC_MAXPATH);
+}
+
+/*
+ * rdc_enable
+ * return values
+ * NULL on error
+ * pointer to rdc_rc_t list of return values
+ */
+rdc_rc_t *
+rdc_enable(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdcconfig_t *cfg_rdcs = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) { /* error already set */
+ return (NULL);
+ }
+ rcp = rc;
+ while (rdcp) {
+ if (!rdcp->mode) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ RDC_EINVAL);
+ return (NULL);
+ }
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_ENABLE;
+ rdccfg.options = RDC_OPT_SETBMP;
+ if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
+ rdccfg.options |= RDC_OPT_SYNC;
+ } else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
+ rdccfg.options |= RDC_OPT_ASYNC;
+ } else {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ RDC_EINVAL);
+ return (NULL);
+ }
+
+ populate_addrs(&rdccfg.rdc_set[0], 1);
+
+ if (can_enable(rdcp)) {
+ /* do the operation */
+ *rcp = rdc_config(&rdccfg);
+
+ } else { /* set up what rdc_config would've set up */
+
+ populate_rc(rcp, rdcp);
+
+ }
+ if ((rcp->rc == 0) && (!rdcp->persist)) {
+ /*
+ * if we are not persisting, do this now,
+ * otherwise we will do it when
+ * we have a lock on the cfg in add_to_rdc_cfg
+ */
+ sv_enable(NULL, rdcp);
+ }
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp) {
+ /* dont free here, return what you have */
+ break;
+ }
+ }
+
+ /*
+ * travel the rc chain and rdc chain checking results,
+ * building a new chain, and updating dscfg
+ */
+ rcp = rc;
+ rdcp = rdc;
+
+ cfg_rdcs = chain_successful(rdcp, rcp);
+
+ if (add_to_rdc_cfg(cfg_rdcs) < 0) {
+ /* XXX should disable or something here */
+ return (rc);
+ }
+ rdc_free_config(cfg_rdcs, RDC_FREEALL);
+ return (rc);
+
+}
+
+rdc_rc_t *
+rdc_enable_clrbmp(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdcconfig_t *cfg_rdcs = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
+ if (!rc) {
+ rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
+ return (NULL);
+ }
+ rcp = rc;
+ while (rdcp) {
+ if (!rdcp->mode) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ RDC_EINVAL);
+ return (NULL);
+ }
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_ENABLE;
+ rdccfg.options = RDC_OPT_CLRBMP;
+ if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
+ rdccfg.options |= RDC_OPT_SYNC;
+ } else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
+ rdccfg.options |= RDC_OPT_ASYNC;
+ } else {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ RDC_EINVAL);
+ return (NULL);
+ }
+
+ populate_addrs(&rdccfg.rdc_set[0], 1);
+
+ if (can_enable(rdcp)) {
+ /* do the operation */
+ *rcp = rdc_config(&rdccfg);
+
+ } else { /* set up what rdc_config would've set up */
+
+ populate_rc(rcp, rdcp);
+
+ }
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+
+ /*
+ * travel the rc chain and rdc chain checking results,
+ * building a new chain, and updating dscfg
+ */
+ rcp = rc;
+ rdcp = rdc;
+
+ cfg_rdcs = chain_successful(rdcp, rcp);
+
+ if (add_to_rdc_cfg(cfg_rdcs) < 0) {
+ /* XXX should disable or something here */
+ return (rc);
+ }
+ rdc_free_config(cfg_rdcs, RDC_FREEALL);
+
+ return (rc);
+
+}
+
+rdc_rc_t *
+rdc_disable(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdcconfig_t *cfg_rdcs = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_DISABLE;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ return (rc);
+
+ }
+ rcp = rc;
+ rdcp = rdc;
+
+ cfg_rdcs = chain_successful(rdcp, rcp);
+
+ remove_from_rdc_cfg(cfg_rdcs);
+
+ rdc_free_config(cfg_rdcs, RDC_FREEALL);
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_log(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_LOG;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_usync(rdcconfig_t *rdc)
+{
+ rdc_config_t *rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+ rdc_rc_t *tmprc;
+ int trc;
+
+ rdcp = rdc;
+
+ while (rdcp) {
+ /* freed in rdc_mtconfig */
+ rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
+ rdccfg->rdc_set[0] = config2set(rdcp);
+ rdccfg->command = RDC_CMD_COPY;
+ rdccfg->options = RDC_OPT_UPDATE|RDC_OPT_FORWARD;
+ populate_addrs(&rdccfg->rdc_set[0], 0);
+ trc = thr_create(NULL, 0, rdc_mtconfig,
+ (void **) rdccfg, THR_BOUND, NULL);
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ }
+
+ /*
+ * collect status here from thr_join-status,
+ * and add to rdc_rc_t chain ?
+ * this will block, but caller could always thread too
+ */
+ while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
+ if (rc == NULL) {
+ rcp = rc = (rdc_rc_t *)tmprc;
+ } else {
+ rcp->next = (rdc_rc_t *)tmprc;
+ rcp = rcp->next;
+ }
+ }
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_fsync(rdcconfig_t *rdc)
+{
+ rdc_config_t *rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+ rdc_rc_t *tmprc = NULL;
+ int trc;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ /* freed in rdc_mtconfig */
+ rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
+ rdccfg->rdc_set[0] = config2set(rdcp);
+ rdccfg->command = RDC_CMD_COPY;
+ rdccfg->options = RDC_OPT_FULL|RDC_OPT_FORWARD;
+ populate_addrs(&rdccfg->rdc_set[0], 0);
+ trc = thr_create(NULL, 0, rdc_mtconfig,
+ (void **) rdccfg, THR_BOUND, NULL);
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ }
+
+ /*
+ * collect status here from thr_join-status,
+ * and add to rdc_rc_t chain ?
+ * this will block, but caller could always thread too
+ */
+ while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
+ if (rc == NULL) {
+ rcp = rc = (rdc_rc_t *)tmprc;
+ } else {
+ rcp->next = (rdc_rc_t *)tmprc;
+ rcp = rcp->next;
+ }
+ }
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_rsync(rdcconfig_t *rdc)
+{
+ rdc_config_t *rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+ rdc_rc_t *tmprc = NULL;
+ int trc;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ tmprc = cant_rsync(rdcp);
+ if (tmprc != NULL) {
+ if (rc == NULL) {
+ rcp = rc = tmprc;
+ } else {
+ rcp->next = tmprc;
+ rcp = rcp->next;
+ }
+ goto next;
+ }
+
+ /* freed in rdc_mtconfig */
+ rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
+ rdccfg->rdc_set[0] = config2set(rdcp);
+ rdccfg->command = RDC_CMD_COPY;
+ rdccfg->options = RDC_OPT_REVERSE|RDC_OPT_FULL;
+ populate_addrs(&rdccfg->rdc_set[0], 0);
+ trc = thr_create(NULL, 0, rdc_mtconfig,
+ (void **) rdccfg, THR_BOUND, NULL);
+next:
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+ }
+
+ /*
+ * collect status here from thr_join-status,
+ * and add to rdc_rc_t chain ?
+ * this will block, but caller could always thread too
+ */
+ while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
+ if (rc == NULL) {
+ rcp = rc = (rdc_rc_t *)tmprc;
+ } else {
+ rcp->next = (rdc_rc_t *)tmprc;
+ rcp = rcp->next;
+ }
+ }
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_ursync(rdcconfig_t *rdc)
+{
+ rdc_config_t *rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+ rdc_rc_t *tmprc = NULL;
+ int trc;
+
+ rdcp = rdc;
+
+ while (rdcp) {
+ tmprc = cant_rsync(rdcp);
+ if (tmprc != NULL) {
+ if (rc == NULL) {
+ rcp = rc = tmprc;
+ } else {
+ rcp->next = tmprc;
+ rcp = rcp->next;
+ }
+ goto next;
+ }
+
+ /* freed in rdc_mtconfig */
+ rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
+ rdccfg->rdc_set[0] = config2set(rdcp);
+ rdccfg->command = RDC_CMD_COPY;
+ rdccfg->options = RDC_OPT_REVERSE | RDC_OPT_UPDATE;
+ populate_addrs(&rdccfg->rdc_set[0], 0);
+ trc = thr_create(NULL, 0, rdc_mtconfig,
+ (void **) rdccfg, THR_BOUND, NULL);
+next:
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ }
+
+ /*
+ * collect status here from thr_join-status,
+ * and add to rdc_rc_t chain ?
+ * this will block, but caller could always thread too
+ */
+ while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
+ if (rc == NULL) {
+ rcp = rc = (rdc_rc_t *)tmprc;
+ } else {
+ rcp->next = (rdc_rc_t *)tmprc;
+ rcp = rcp->next;
+ }
+ }
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_wait(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_WAIT;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_set_autosync(rdcconfig_t *rdc, int autosync)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_TUNABLE;
+ rdccfg.rdc_set[0].autosync = autosync;
+ rdccfg.rdc_set[0].maxqitems = -1;
+ rdccfg.rdc_set[0].maxqfbas = -1;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_set_maxqfbas(rdcconfig_t *rdc, int maxqfbas)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_TUNABLE;
+ rdccfg.rdc_set[0].autosync = -1;
+ rdccfg.rdc_set[0].maxqitems = -1;
+ rdccfg.rdc_set[0].maxqfbas = maxqfbas;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_set_maxqitems(rdcconfig_t *rdc, int maxqitems)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdc);
+ rdccfg.command = RDC_CMD_TUNABLE;
+ rdccfg.rdc_set[0].autosync = -1;
+ rdccfg.rdc_set[0].maxqitems = maxqitems;
+ rdccfg.rdc_set[0].maxqfbas = -1;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ return (rc);
+}
+
+rdc_set_t
+rdc_status(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdc);
+ rdccfg.command = RDC_CMD_STATUS;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+ rdc_config(&rdccfg);
+
+ return (rdccfg.rdc_set[0]);
+}
+
+int
+rdc_get_autosync(rdcconfig_t *rdc)
+{
+ rdc_set_t rdcset;
+
+ rdcset = rdc_status(rdc);
+ return (rdcset.autosync);
+}
+
+int
+rdc_get_maxqfbas(rdcconfig_t *rdc)
+{
+ rdc_set_t rdcset;
+
+ rdcset = rdc_status(rdc);
+ return (rdcset.maxqfbas);
+
+}
+
+int
+rdc_get_maxqitems(rdcconfig_t *rdc)
+{
+ rdc_set_t rdcset;
+
+ rdcset = rdc_status(rdc);
+ return (rdcset.maxqitems);
+
+}
+
+int
+set_mode(rdcconfig_t *rdc)
+{
+ if (strcmp(rdc->mode, "async") == 0)
+ return (RDC_OPT_ASYNC);
+ else
+ return (RDC_OPT_SYNC);
+}
+
+/*
+ * reconfig bitmaps are single set only ops
+ * for obvious reasons
+ */
+rdc_rc_t *
+rdc_reconfig_pbmp(rdcconfig_t *rdc, char *pbmp)
+{
+ rdc_config_t rdccfg;
+ rdc_rc_t *rc;
+
+ rc = new_rc();
+ if ((!rc) || (!pbmp))
+ return (NULL);
+
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdc);
+ strncpy(rdccfg.rdc_set[0].primary.bitmap, pbmp, NSC_MAXPATH);
+ rdccfg.command = RDC_CMD_RECONFIG;
+ rdccfg.options |= set_mode(rdc);
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ if (can_reconfig_pbmp(rdc, pbmp))
+ *rc = rdc_config(&rdccfg);
+ else
+ populate_rc(rc, rdc);
+
+ if ((rc->rc == 0) && (rdc->persist))
+ if (replace_cfgfield(rdc, "pbitmap", pbmp) < 0) {
+ rc->rc = -1;
+ strncpy(rc->msg, rdc_error(NULL), RDC_ERR_SIZE);
+ }
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_reconfig_sbmp(rdcconfig_t *rdc, char *sbmp)
+{
+ rdc_config_t rdccfg;
+ rdc_rc_t *rc;
+
+ rc = new_rc();
+ if (!rc)
+ return (NULL);
+
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdc);
+ strncpy(rdccfg.rdc_set[0].secondary.bitmap, sbmp, NSC_MAXPATH);
+ rdccfg.command = RDC_CMD_RECONFIG;
+ rdccfg.options |= set_mode(rdc);
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ if (can_reconfig_sbmp(rdc, sbmp))
+ *rc = rdc_config(&rdccfg);
+ else
+ populate_rc(rc, rdc);
+
+ if ((rc->rc == 0) && (rdc->persist))
+ replace_cfgfield(rdc, "sbitmap", sbmp);
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_reconfig_group(rdcconfig_t *rdc, char *group)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdcconfig_t *cfg_rdcs = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ /* just in case */
+ strncpy(rdcp->group, group, NSC_MAXPATH);
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_RECONFIG;
+ rdccfg.options |= set_mode(rdcp);
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ /* reconfig group rules enforced in kernel */
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ rcp = rc;
+ rdcp = rdc;
+ cfg_rdcs = chain_successful(rdcp, rcp);
+ replace_cfgfield(cfg_rdcs, "group", group);
+ rdc_free_config(cfg_rdcs, RDC_FREEALL);
+
+ return (rc);
+}
+/*ARGSUSED*/
+rdc_rc_t *
+rdc_reconfig_ctag(rdcconfig_t *rdc, char *ctag)
+{
+ return (NULL);
+}
+
+rdc_rc_t *
+rdc_set_sync(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdcconfig_t *cfg_rdcs = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdc);
+ rdccfg.command = RDC_CMD_RECONFIG;
+ rdccfg.options |= RDC_OPT_SYNC;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+
+ rcp = rc;
+ rdcp = rdc;
+ cfg_rdcs = chain_successful(rdcp, rcp);
+ replace_cfgfield(cfg_rdcs, "mode", "sync");
+ rdc_free_config(cfg_rdcs, RDC_FREEALL);
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_set_async(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdcconfig_t *cfg_rdcs = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_RECONFIG;
+ rdccfg.options |= RDC_OPT_ASYNC;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ rcp = rc;
+ rdcp = rdc;
+ cfg_rdcs = chain_successful(rdcp, rcp);
+ replace_cfgfield(cfg_rdcs, "mode", "async");
+ rdc_free_config(cfg_rdcs, RDC_FREEALL);
+
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_health(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_HEALTH;
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+
+ if (!rcp)
+ break;
+
+ }
+ return (rc);
+}
+
+rdc_rc_t *
+rdc_reverse_role(rdcconfig_t *rdc)
+{
+ rdc_config_t rdccfg;
+ rdcconfig_t *rdcp = NULL;
+ rdcconfig_t *cfg_rdcs = NULL;
+ rdc_rc_t *rc = NULL;
+ rdc_rc_t *rcp = NULL;
+
+ rdcp = rdc;
+ rc = new_rc();
+ if (!rc) {
+ return (NULL);
+ }
+ rcp = rc;
+
+ while (rdcp) {
+ bzero(&rdccfg, sizeof (rdc_config_t));
+ rdccfg.rdc_set[0] = config2set(rdcp);
+ rdccfg.command = RDC_CMD_RECONFIG;
+ rdccfg.options |= RDC_OPT_REVERSE_ROLE;
+ rdccfg.options |= set_mode(rdcp);
+ populate_addrs(&rdccfg.rdc_set[0], 0);
+
+ *rcp = rdc_config(&rdccfg);
+
+ rdcp = rdcp->next;
+ if (!rdcp)
+ break;
+
+ rcp->next = new_rc();
+ rcp = rcp->next;
+ if (!rcp)
+ break;
+ }
+ rcp = rc;
+ rdcp = rdc;
+ cfg_rdcs = chain_successful(rdcp, rcp);
+ reverse_in_cfg(cfg_rdcs);
+ rdc_free_config(cfg_rdcs, RDC_FREEALL);
+
+ return (rc);
+}
diff --git a/usr/src/lib/librdc/common/rdcerr.c b/usr/src/lib/librdc/common/rdcerr.c
new file mode 100644
index 0000000000..6328371ecd
--- /dev/null
+++ b/usr/src/lib/librdc/common/rdcerr.c
@@ -0,0 +1,98 @@
+/*
+ * 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 <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libintl.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <sys/nsctl/rdcerr.h>
+#include <sys/nsctl/cfg.h>
+
+#include <sys/unistat/spcs_dtrinkets.h>
+#include <sys/unistat/spcs_etrinkets.h>
+#include <sys/unistat/spcs_s.h>
+#include <sys/unistat/spcs_s_u.h>
+#include <sys/unistat/spcs_s_impl.h>
+#include <sys/unistat/spcs_errors.h>
+
+
+int rdc_severity;
+char *rdc_error_str;
+char err[RDC_ERR_SIZE];
+
+void
+rdc_set_error(spcs_s_info_t *ustatus, int context, int severity,
+ char *errorstr, ...)
+{
+ char msg[1024];
+ va_list ap;
+
+ bzero(err, RDC_ERR_SIZE);
+ switch (context) {
+ case RDC_INTERNAL:
+ rdc_severity = severity;
+ if (errorstr) {
+ va_start(ap, errorstr);
+ vsprintf(err, errorstr, ap);
+ va_end(ap);
+ }
+ rdc_error_str = dgettext("librdc", err ? err : "");
+ break;
+
+ case RDC_OS:
+ rdc_severity = severity ? severity : RDC_FATAL;
+ rdc_error_str = strerror(errno);
+ break;
+
+ case RDC_SPCS:
+ rdc_severity = severity ? severity : RDC_FATAL;
+ rdc_error_str = spcs_s_string(*ustatus, msg);
+ break;
+
+ case RDC_DSCFG:
+ rdc_error_str = cfg_error(&rdc_severity);
+ break;
+
+ default:
+ break;
+ }
+
+ spcs_log("librdc", NULL, dgettext("librdc", "%s"),
+ rdc_error_str ? rdc_error_str : "");
+
+}
+
+char *
+rdc_error(int *severity)
+{
+ if (severity != NULL)
+ *severity = rdc_severity;
+ return (rdc_error_str ? rdc_error_str : "");
+}
diff --git a/usr/src/lib/librdc/common/rdcerr.h b/usr/src/lib/librdc/common/rdcerr.h
new file mode 100644
index 0000000000..f8c8b83423
--- /dev/null
+++ b/usr/src/lib/librdc/common/rdcerr.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef _RDCERR_H
+#define _RDCERR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#include <sys/unistat/spcs_s.h>
+#include <sys/unistat/spcs_s_u.h>
+#include <sys/unistat/spcs_s_impl.h>
+#include <sys/unistat/spcs_errors.h>
+
+/* serious error? */
+#define RDC_FATAL 0x02
+#define RDC_NONFATAL 0x03
+
+/* types of errors */
+#define RDC_INTERNAL 0x01
+#define RDC_OS 0X02
+#define RDC_SPCS 0x04
+#define RDC_DSCFG 0x08
+
+/* errors */
+#define RDC_EINVAL "Invalid argument"
+
+#define RDC_NAME_DU_JOUR "Remote Mirror"
+
+#ifndef RDC_ERR_SIZE
+#define RDC_ERR_SIZE 256
+#endif
+
+
+void
+rdc_set_error(spcs_s_info_t *ustatus, int context, int severity,
+char *errorstr, ...);
+
+char *
+rdc_err(int *severity);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RDCERR_H */
diff --git a/usr/src/lib/librdc/common/rdcpersist.c b/usr/src/lib/librdc/common/rdcpersist.c
new file mode 100644
index 0000000000..703c8eef11
--- /dev/null
+++ b/usr/src/lib/librdc/common/rdcpersist.c
@@ -0,0 +1,716 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mkdev.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libintl.h>
+#include <locale.h>
+#include <stdlib.h>
+
+#include <sys/nsctl/rdcerr.h>
+#include <sys/nsctl/rdc_ioctl.h>
+#include <sys/nsctl/librdc.h>
+#include <sys/nsctl/cfg.h>
+#include <sys/nsctl/nsc_hash.h>
+#include <sys/nsctl/sv.h>
+
+#include <sys/unistat/spcs_dtrinkets.h>
+#include <sys/unistat/spcs_etrinkets.h>
+#include <sys/unistat/spcs_s.h>
+#include <sys/unistat/spcs_s_u.h>
+#include <sys/unistat/spcs_s_impl.h>
+#include <sys/unistat/spcs_errors.h>
+
+typedef struct volcount_s {
+ int count;
+} volcount_t;
+
+hash_node_t **volhash = NULL;
+
+char *
+config2buf(char *buf, rdcconfig_t *rdc)
+{
+ snprintf(buf, CFG_MAX_BUF, "%s %s %s %s %s %s %s %s %s %s %s",
+ rdc->phost, rdc->pfile, rdc->pbmp, rdc->shost, rdc->sfile,
+ rdc->sbmp, rdc->direct, rdc->mode, rdc->group ? rdc->group : "",
+ rdc->ctag ? rdc->ctag : "", rdc->options ? rdc->options : "");
+ return (buf);
+
+}
+
+/*
+ * SV type functions.
+ */
+
+static void
+load_rdc_vols(CFGFILE *cfg)
+{
+ int set;
+ char key[ CFG_MAX_KEY ];
+ char buf[ CFG_MAX_BUF ];
+ char *vol, *bmp, *host1, *host2;
+ volcount_t *volcount;
+
+ if (volhash) {
+ return;
+ }
+
+ cfg_rewind(cfg, CFG_SEC_CONF);
+ volhash = nsc_create_hash();
+ for (set = 1; /*CSTYLED*/; set++) {
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d", set);
+ if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)) {
+ break;
+ }
+
+ host1 = strtok(buf, " ");
+ vol = strtok(NULL, " ");
+ bmp = strtok(NULL, " ");
+
+ if (!self_check(host1)) {
+ /* next one had better be ours */
+ host2 = strtok(NULL, " ");
+ vol = strtok(NULL, " ");
+ bmp = strtok(NULL, " ");
+
+ if (!self_check(host2)) {
+ continue;
+ }
+ }
+
+ /* primary vol may be used more than once */
+ volcount = (volcount_t *)nsc_lookup(volhash, vol);
+ if (volcount) {
+ volcount->count++;
+ } else {
+ volcount = (volcount_t *)malloc(sizeof (volcount_t));
+ volcount->count = 1;
+ nsc_insert_node(volhash, volcount, vol);
+ }
+
+ /* bitmap ought to be only used once */
+ volcount = (volcount_t *)nsc_lookup(volhash, bmp);
+ if (volcount) {
+ /* argh */
+ volcount->count++;
+ } else {
+ volcount = (volcount_t *)malloc(sizeof (volcount_t));
+ volcount->count = 1;
+ nsc_insert_node(volhash, volcount, bmp);
+ }
+ }
+}
+
+int
+sv_enable_one_nocfg(char *vol)
+{
+ struct stat sb;
+ sv_conf_t svc;
+ int fd;
+
+ bzero(&svc, sizeof (svc));
+ if (stat(vol, &sb) != 0) {
+ rdc_set_error(NULL, RDC_OS, 0, "unable to stat %s", vol);
+ return (-1);
+ }
+ if (!S_ISCHR(sb.st_mode)) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, "%s is not"
+ " a character device", vol);
+ return (-1);
+ }
+
+ svc.svc_major = major(sb.st_rdev);
+ svc.svc_minor = minor(sb.st_rdev);
+ strncpy(svc.svc_path, vol, sizeof (svc.svc_path));
+
+ fd = open(SV_DEVICE, O_RDONLY);
+ if (fd < 0) {
+ rdc_set_error(NULL, RDC_OS, 0, 0);
+ return (-1);
+ }
+
+ svc.svc_flag = (NSC_DEVICE | NSC_CACHE);
+ svc.svc_error = spcs_s_ucreate();
+
+ if (ioctl(fd, SVIOC_ENABLE, &svc) < 0) {
+ if (errno != SV_EENABLED) {
+ rdc_set_error(&svc.svc_error, RDC_INTERNAL,
+ RDC_NONFATAL, 0);
+ return (-1);
+ }
+ }
+
+ spcs_log("sv", NULL, gettext("enabled %s"), svc.svc_path);
+
+ close(fd);
+ return (1);
+}
+
+int
+sv_enable_nocfg(rdcconfig_t *rdc)
+{
+ struct stat stbv;
+ struct stat stbb;
+ sv_conf_t svcv;
+ sv_conf_t svcb;
+ char vol[NSC_MAXPATH];
+ char bmp[NSC_MAXPATH];
+ int fd = -1;
+
+
+ if (self_check(rdc->phost)) {
+ strncpy(vol, rdc->pfile, NSC_MAXPATH);
+ strncpy(bmp, rdc->pbmp, NSC_MAXPATH);
+ } else {
+ strncpy(vol, rdc->sfile, NSC_MAXPATH);
+ strncpy(bmp, rdc->sbmp, NSC_MAXPATH);
+ }
+
+ bzero(&svcv, sizeof (svcv));
+ bzero(&svcb, sizeof (svcb));
+
+ if ((stat(vol, &stbv) != 0) || (stat(bmp, &stbb) != 0))
+ return (-1);
+
+ if ((!S_ISCHR(stbv.st_mode)) || (!S_ISCHR(stbb.st_mode)))
+ return (-1);
+
+ svcv.svc_major = major(stbv.st_rdev);
+ svcb.svc_minor = minor(stbb.st_rdev);
+
+ strncpy(svcv.svc_path, vol, sizeof (svcv.svc_path));
+ strncpy(svcb.svc_path, bmp, sizeof (svcb.svc_path));
+
+ fd = open(SV_DEVICE, O_RDONLY);
+ if (fd < 0)
+ return (-1);
+
+ /* SV enable the volume */
+ svcv.svc_flag = (NSC_DEVICE | NSC_CACHE);
+ svcv.svc_error = spcs_s_ucreate();
+
+ if (ioctl(fd, SVIOC_ENABLE, &svcv) < 0) {
+ if (errno != SV_EENABLED) {
+ spcs_log("sv", &svcv.svc_error,
+ gettext("unable to enable %s"),
+ svcv.svc_path);
+ spcs_s_ufree(&svcv.svc_error);
+ return (-1);
+ }
+ }
+
+ /* SV enable the bitmap disable the vol on error */
+ svcb.svc_flag = (NSC_DEVICE | NSC_CACHE);
+ svcb.svc_error = spcs_s_ucreate();
+
+ if (ioctl(fd, SVIOC_ENABLE, &svcb) < 0) {
+ if (errno != SV_EENABLED) {
+ spcs_log("sv", &svcb.svc_error,
+ gettext("unable to enable %s"),
+ svcb.svc_path);
+ if (ioctl(fd, SVIOC_DISABLE, &svcv) < 0)
+ spcs_log("sv", &svcv.svc_error,
+ gettext("unable to disable %s"),
+ svcv.svc_path);
+
+ spcs_s_ufree(&svcv.svc_error);
+ spcs_s_ufree(&svcb.svc_error);
+ return (-1);
+ }
+ }
+
+
+ spcs_log("sv", NULL, gettext("enabled %s"), svcv.svc_path);
+ spcs_log("sv", NULL, gettext("enabled %s"), svcb.svc_path);
+ spcs_s_ufree(&svcv.svc_error);
+ spcs_s_ufree(&svcb.svc_error);
+
+
+ if (fd >= 0)
+ (void) close(fd);
+
+ return (1);
+}
+
+int
+do_autosv_enable(CFGFILE *cfg, rdcconfig_t *rdc)
+{
+ char vol[NSC_MAXPATH];
+ char bmp[NSC_MAXPATH];
+
+ cfg_load_svols(cfg);
+ cfg_load_dsvols(cfg);
+ cfg_load_shadows(cfg);
+ load_rdc_vols(cfg);
+
+ if (self_check(rdc->phost)) {
+ strncpy(vol, rdc->pfile, NSC_MAXPATH);
+ strncpy(bmp, rdc->pbmp, NSC_MAXPATH);
+ } else {
+ strncpy(vol, rdc->sfile, NSC_MAXPATH);
+ strncpy(bmp, rdc->sbmp, NSC_MAXPATH);
+ }
+ if (nsc_lookup(volhash, vol) == NULL) {
+ if (cfg_vol_enable(cfg, vol, rdc->ctag, "sndr") < 0) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "auto sv enable failed for %s", vol);
+ return (-1);
+ }
+ }
+ if (nsc_lookup(volhash, bmp) == NULL) {
+ if (cfg_vol_enable(cfg, bmp, rdc->ctag, "sndr") < 0) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "auto sv enable failed for %s", vol);
+ return (-1);
+ }
+ }
+
+ nsc_remove_all(volhash, free);
+ volhash = NULL;
+
+ cfg_unload_shadows();
+ cfg_unload_dsvols();
+ cfg_unload_svols();
+
+ return (1);
+}
+
+int
+do_autosv_disable(CFGFILE *cfg, rdcconfig_t *rdc)
+{
+ char vol[NSC_MAXPATH];
+ char bmp[NSC_MAXPATH];
+ volcount_t *vc;
+
+ cfg_load_svols(cfg);
+ cfg_load_dsvols(cfg);
+ cfg_load_shadows(cfg);
+ load_rdc_vols(cfg);
+
+ if (self_check(rdc->phost)) {
+ strncpy(vol, rdc->pfile, NSC_MAXPATH);
+ strncpy(bmp, rdc->pbmp, NSC_MAXPATH);
+ } else {
+ strncpy(vol, rdc->sfile, NSC_MAXPATH);
+ strncpy(bmp, rdc->sbmp, NSC_MAXPATH);
+ }
+
+ vc = nsc_lookup(volhash, vol);
+ if (vc && (vc->count == 1)) {
+ if (cfg_vol_disable(cfg, vol, rdc->ctag, "sndr") < 0)
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "auto sv disable failed for %s", vol);
+ } else if (!vc) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "Unable to find %s in config", vol);
+ }
+ vc = nsc_lookup(volhash, bmp);
+ if (vc && (vc->count == 1)) {
+ if (cfg_vol_disable(cfg, bmp, rdc->ctag, "sndr") < 0)
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "auto sv disable failed for %s", bmp);
+
+ } else if (!vc) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "Unable to find %s in config", bmp);
+ }
+
+ return (1);
+
+}
+
+/*
+ * do sv enables for the appropriate vol
+ * and bitmap. If called without persistance
+ * it will follow a chain and sv enable all
+ * otherwise, it will enable only the one
+ * set.
+ */
+int
+sv_enable(CFGFILE *cfg, rdcconfig_t *rdcs)
+{
+ rdcconfig_t *rdcp = NULL;
+
+ rdcp = rdcs;
+ if (!rdcp->persist) {
+
+ return (sv_enable_nocfg(rdcp));
+
+ } else if (cfg == NULL) {
+
+ return (-1);
+
+ }
+
+ do_autosv_enable(cfg, rdcp);
+
+ return (1);
+}
+
+int
+sv_disable(CFGFILE *cfg, rdcconfig_t *rdcs)
+{
+ rdcconfig_t *rdcp;
+
+ rdcp = rdcs;
+ if (!rdcp->persist) { /* don't disable */
+
+ return (1);
+
+ } else if (cfg == NULL) {
+
+ return (-1);
+
+ }
+
+ do_autosv_disable(cfg, rdcp);
+
+ return (1);
+
+}
+
+/*
+ * disable the appropriate bitmap in rdc
+ * and replace it with bitmap
+ */
+int
+sv_reconfig(CFGFILE *cfg, rdcconfig_t *rdc, char *oldbmp, char *newbmp)
+{
+ rdcconfig_t *rdcp;
+ int fail = 0;
+
+ rdcp = rdc;
+ if (!rdcp->persist) { /* just enable, don't disable */
+
+ sv_enable_one_nocfg(newbmp);
+
+ } else if (rdcp->persist) { /* do sv disable and enable */
+ volcount_t *vc;
+
+ cfg_load_svols(cfg);
+ cfg_load_dsvols(cfg);
+ cfg_load_shadows(cfg);
+ load_rdc_vols(cfg);
+
+ vc = (volcount_t *)nsc_lookup(volhash, oldbmp);
+ if (vc && (vc->count == 1)) {
+ if (cfg_vol_disable(cfg, oldbmp, rdc->ctag, "sndr") < 0)
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "auto sv disable failed for %s", oldbmp);
+
+ }
+ if (nsc_lookup(volhash, newbmp) == NULL) {
+ if (cfg_vol_enable(cfg,
+ newbmp, rdc->ctag, "sndr") < 0) {
+
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "auto sv enable failed for %s", newbmp);
+ fail++;
+ }
+ }
+ nsc_remove_all(volhash, free);
+ volhash = NULL;
+
+ cfg_unload_shadows();
+ cfg_unload_dsvols();
+ cfg_unload_svols();
+ if (fail)
+ return (-1);
+
+ }
+ return (1);
+
+}
+
+/*
+ * SNDR functions
+ */
+
+/*
+ * add_to_rdc_cfg
+ * this adds the successfully created rdc sets to libdscfg,
+ * also, as auto_sv stuff is part of libdscfg, it does the
+ * auto_sv stuff and enables the correct volumes
+ */
+int
+add_to_rdc_cfg(rdcconfig_t *rdcs)
+{
+ CFGFILE *cfg;
+ rdcconfig_t *rdcp;
+ char *buf;
+
+
+ buf = calloc(CFG_MAX_BUF, sizeof (char));
+ if (!buf) {
+ rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
+ return (NULL);
+ }
+
+ if ((cfg = cfg_open(NULL)) == NULL) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+ if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+
+ rdcp = rdcs;
+ while (rdcp) {
+ buf = config2buf(buf, rdcp);
+ if ((sv_enable(cfg, rdcp) < 0) ||
+ (cfg_put_cstring(cfg, "sndr", buf, CFG_MAX_BUF) < 0)) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ free(buf);
+ return (-1);
+ }
+ rdcp = rdcp->next;
+ }
+ if (!cfg_commit(cfg)) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, NULL);
+ return (-1);
+ }
+
+ cfg_close(cfg);
+
+ return (0);
+}
+
+int
+cfg_lookup(CFGFILE *cfg, char *shost, char *sfile)
+{
+ char buf[CFG_MAX_BUF];
+ char key[CFG_MAX_KEY];
+ int setnum;
+ int numsets = 0;
+
+ numsets = cfg_get_num_entries(cfg, "sndr");
+ for (setnum = 1; setnum <= numsets; setnum++) {
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.shost", setnum);
+ if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+ if (strncmp(buf, shost, strlen(shost)))
+ continue;
+
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.secondary", setnum);
+ if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+ if (strncmp(buf, sfile, strlen(sfile)))
+ continue;
+ break;
+ }
+ return (setnum);
+}
+
+void
+remove_from_rdc_cfg(rdcconfig_t *rdcs)
+{
+ CFGFILE *cfg;
+ rdcconfig_t *rdcp;
+ char key[CFG_MAX_KEY];
+
+ rdcp = rdcs;
+ cfg = cfg_open(NULL);
+ cfg_lock(cfg, CFG_WRLOCK);
+
+ while (rdcp) {
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d",
+ cfg_lookup(cfg, rdcp->shost, rdcp->sfile));
+ if ((sv_disable(cfg, rdcp) < 0) ||
+ (cfg_put_cstring(cfg, key, NULL, 0)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ }
+
+ rdcp = rdcp->next;
+ }
+ cfg_commit(cfg);
+ cfg_close(cfg);
+}
+/*ARGSUSED*/
+int
+replace_entry(int offset, char *entry)
+{
+ return (1);
+}
+
+/*
+ * this will set the value at "field" in dscfg to the
+ * value contained in entry.
+ * for things like bitmap reconfigs, only pass one rdc
+ * not a chain
+ */
+int
+replace_cfgfield(rdcconfig_t *rdc, char *field, char *entry)
+{
+ CFGFILE *cfg;
+ rdcconfig_t *rdcp;
+ char key[CFG_MAX_KEY];
+ char newentry[CFG_MAX_BUF];
+ char oldbmp[CFG_MAX_BUF];
+ int setnum;
+ int ispbmp = 0;
+ int issbmp = 0;
+
+ if (strncmp(field, "pbitmap", NSC_MAXPATH) == 0)
+ ispbmp++;
+ if (strncmp(field, "sbitmap", NSC_MAXPATH) == 0)
+ issbmp++;
+
+ bzero(newentry, sizeof (newentry));
+ if (!entry || strlen(entry) == 0)
+ *newentry = '-';
+ else
+ strncpy(newentry, entry, CFG_MAX_BUF);
+
+
+ if ((cfg = cfg_open(NULL)) == NULL) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+ if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+
+ rdcp = rdc;
+ while (rdcp) {
+ if ((setnum = cfg_lookup(cfg, rdcp->shost, rdcp->sfile)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.%s", setnum, field);
+ if (!((ispbmp || issbmp) &&
+ (cfg_get_cstring(cfg, key, oldbmp, CFG_MAX_BUF)) == 0)) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, "unable to get %s",
+ key);
+ }
+ if (((ispbmp && self_check(rdcp->phost)) ||
+ (issbmp && self_check(rdcp->shost))) &&
+ (sv_reconfig(cfg, rdcp, oldbmp, newentry) < 0)) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "unable to sv reconfig %s to %s", oldbmp, newentry);
+ return (-1);
+ }
+
+ if ((cfg_put_cstring(cfg, key, newentry, CFG_MAX_BUF)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+ rdcp = rdcp->next;
+ }
+ cfg_commit(cfg);
+ cfg_close(cfg);
+ return (1);
+}
+
+/*
+ * reverse_in_cfg
+ * used by RDC_OPT_REVERSE_ROLE
+ * swaps primary info and secondary info
+ */
+int
+reverse_in_cfg(rdcconfig_t *rdc)
+{
+ CFGFILE *cfg;
+ rdcconfig_t *rdcp = NULL;
+ char key[CFG_MAX_KEY];
+ int setnum;
+
+ if ((cfg = cfg_open(NULL)) == NULL) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+ if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ return (-1);
+ }
+
+ rdcp = rdc;
+ while (rdcp) {
+ if ((setnum = cfg_lookup(cfg, rdcp->shost, rdcp->sfile)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ goto badconfig;
+ }
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.phost", setnum);
+ if ((cfg_put_cstring(cfg, key, rdcp->shost, CFG_MAX_BUF)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ goto badconfig;
+ }
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.primary", setnum);
+ if ((cfg_put_cstring(cfg, key, rdcp->sfile, CFG_MAX_BUF)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ goto badconfig;
+ }
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.pbitmap", setnum);
+ if ((cfg_put_cstring(cfg, key, rdcp->sbmp, CFG_MAX_BUF)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ goto badconfig;
+ }
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.shost", setnum);
+ if ((cfg_put_cstring(cfg, key, rdcp->phost, CFG_MAX_BUF)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ goto badconfig;
+ }
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.secondary", setnum);
+ if ((cfg_put_cstring(cfg, key, rdcp->pfile, CFG_MAX_BUF)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ goto badconfig;
+ }
+ bzero(key, CFG_MAX_KEY);
+ snprintf(key, CFG_MAX_KEY, "sndr.set%d.sbitmap", setnum);
+ if ((cfg_put_cstring(cfg, key, rdcp->pbmp, CFG_MAX_BUF)) < 0) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, 0);
+ goto badconfig;
+ }
+ rdcp = rdcp->next;
+ }
+ if (!cfg_commit(cfg)) {
+ cfg_close(cfg);
+ return (-1);
+ }
+ cfg_close(cfg);
+ return (0);
+
+badconfig:
+ cfg_close(cfg);
+ return (-1);
+}
diff --git a/usr/src/lib/librdc/common/rdcrules.c b/usr/src/lib/librdc/common/rdcrules.c
new file mode 100644
index 0000000000..76fe39d48d
--- /dev/null
+++ b/usr/src/lib/librdc/common/rdcrules.c
@@ -0,0 +1,545 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/mdb_modapi.h>
+#include <stdio.h>
+#include <errno.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <sys/stream.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <thread.h>
+#include <pthread.h>
+
+#include <sys/unistat/spcs_s.h>
+#include <sys/unistat/spcs_s_u.h>
+#include <sys/unistat/spcs_s_impl.h>
+#include <sys/unistat/spcs_errors.h>
+
+#include <sys/nsctl/rdc_io.h>
+#include <sys/nsctl/rdc_ioctl.h>
+#include <sys/nsctl/rdc_prot.h>
+#include <sys/nsctl/librdc.h>
+#include <sys/nsctl/rdcerr.h>
+#include <sys/nsctl/cfg.h>
+
+#include <sys/unistat/spcs_dtrinkets.h>
+#include <sys/unistat/spcs_etrinkets.h>
+
+#include <sys/socket.h>
+#include <sys/mnttab.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <rpc/rpc_com.h>
+#include <rpc/rpc.h>
+
+#define RDC_LOCAL_TAG "local"
+
+/*
+ * bitmap_in_use
+ * return 1 if in use
+ * return 0 if not in use
+ * return -1 on error
+ */
+
+int
+bitmap_in_use(int cmd, char *hostp, char *bmp)
+{
+ int i, setnumber;
+ CFGFILE *cfg;
+ char host[CFG_MAX_BUF];
+ char shost[CFG_MAX_BUF];
+ char pri[CFG_MAX_BUF]; /* rdc primary vol */
+ char sec[CFG_MAX_BUF]; /* rdc secondary vol */
+ char sbm[CFG_MAX_BUF]; /* rdc secondary bitmap */
+ char bit[CFG_MAX_BUF]; /* a bitmap */
+ char mas[CFG_MAX_BUF]; /* II master */
+ char sha[CFG_MAX_BUF]; /* II shadow */
+ char mod[CFG_MAX_BUF]; /* II mode */
+ char ovr[CFG_MAX_BUF]; /* II overflow */
+ char buf[CFG_MAX_BUF];
+ char key[CFG_MAX_KEY];
+ int rc;
+ int ret = 0;
+
+
+ if ((cfg = cfg_open(NULL)) == NULL) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, NULL);
+ return (-1);
+ }
+ if (!cfg_lock(cfg, CFG_RDLOCK)) {
+ rdc_set_error(NULL, RDC_DSCFG, 0, NULL);
+ cfg_close(cfg);
+ return (-1);
+ }
+
+ /*
+ * look into II config to see if this is being used elsewhere
+ */
+ /*CSTYLED*/
+ for (i = 0; ; i++) {
+ setnumber = i + 1;
+ snprintf(key, sizeof (key), "ii.set%d", setnumber);
+ if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
+ break;
+
+ rc = sscanf(buf, "%s %s %s %s %s", mas, sha, bit, mod, ovr);
+ if (rc != 5) {
+ rdc_set_error(NULL, RDC_OS, 0, NULL);
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * got master shadow bitmap, now compare
+ */
+ if ((strcmp(bmp, mas) == 0) ||
+ (strcmp(bmp, sha) == 0) ||
+ (strcmp(bmp, bit) == 0) ||
+ (strcmp(bmp, ovr) == 0)) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ "bitmap %s is in use by"
+ "Point-in-Time Copy", bmp);
+ ret = 1;
+ goto done;
+ }
+ }
+ /*
+ * and last but not least, make sure sndr is not using vol for anything
+ */
+ /*CSTYLED*/
+ for (i = 0; ; i++) {
+ setnumber = i + 1;
+ snprintf(key, sizeof (key), "sndr.set%d", setnumber);
+ if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
+ break;
+ /*
+ * I think this is quicker than
+ * having to double dip into the config
+ */
+ (void) sscanf(buf, "%s %s %s %s %s %s", host, pri, bit,
+ shost, sec, sbm);
+ if (cmd == RDC_CMD_ENABLE) {
+ if (self_check(host)) {
+ if ((strcmp(bmp, pri) == 0) ||
+ (strcmp(bmp, bit) == 0)) {
+ rdc_set_error(NULL, RDC_INTERNAL,
+ RDC_NONFATAL, dgettext("librdc",
+ "bitmap %s is in use by %s"),
+ bmp, RDC_NAME_DU_JOUR);
+
+
+ ret = 1;
+ goto done;
+ }
+ } else {
+ if ((strcmp(bmp, sec) == 0) ||
+ (strcmp(bmp, sbm) == 0)) {
+ rdc_set_error(NULL, RDC_INTERNAL,
+ RDC_NONFATAL, dgettext("librdc",
+ "bitmap %s is in use by %s"),
+ bmp, RDC_NAME_DU_JOUR);
+ ret = 1;
+ goto done;
+ }
+ }
+ } else if (cmd == RDC_CMD_RECONFIG) {
+
+ /*
+ * read this logic 1000 times and consider
+ * multi homed, one to many, many to one (marketing)
+ * etc, etc, before changing
+ */
+ if (self_check(hostp)) {
+ if (self_check(host)) {
+ if ((strcmp(bmp, pri) == 0) ||
+ (strcmp(bmp, bit) == 0)) {
+ rdc_set_error(NULL,
+ RDC_INTERNAL, RDC_NONFATAL,
+ dgettext("librdc", "bitmap"
+ " %s is in use by %s"),
+ bmp, RDC_NAME_DU_JOUR);
+ ret = 1;
+ goto done;
+ }
+ } else {
+ if ((strcmp(hostp, shost) == 0) &&
+ (strcmp(bmp, sec) == 0) ||
+ (strcmp(bmp, sbm) == 0)) {
+ rdc_set_error(NULL,
+ RDC_INTERNAL, RDC_NONFATAL,
+ dgettext("librdc", "bitmap"
+ " %s is in use by %s"),
+ bmp, RDC_NAME_DU_JOUR);
+ ret = 1;
+ goto done;
+ }
+ }
+ } else { /* self_check(hostp) failed */
+ if (self_check(host)) {
+ if ((strcmp(shost, hostp) == 0) &&
+ (strcmp(bmp, sec) == 0) ||
+ (strcmp(bmp, sbm) == 0)) {
+ rdc_set_error(NULL,
+ RDC_INTERNAL, RDC_NONFATAL,
+ dgettext("librdc", "bitmap"
+ " %s is in use by %s"),
+ bmp, RDC_NAME_DU_JOUR);
+ ret = 1;
+ goto done;
+ }
+ } else {
+ if ((strcmp(host, hostp) == 0) &&
+ (strcmp(bmp, pri) == 0) ||
+ (strcmp(bmp, bit) == 0)) {
+ rdc_set_error(NULL,
+ RDC_INTERNAL, RDC_NONFATAL,
+ dgettext("librdc", "bitmap"
+ " %s is in use by %s"),
+ bmp, RDC_NAME_DU_JOUR);
+ ret = 1;
+ goto done;
+ }
+ }
+ }
+
+ }
+
+ }
+done:
+ cfg_close(cfg);
+ return (ret);
+
+}
+
+int
+check_dgislocal(char *dgname)
+{
+ char *othernode;
+ int rc;
+
+ /*
+ * check where this disk service is mastered
+ */
+
+ rc = cfg_dgname_islocal(dgname, &othernode);
+ if (rc < 0) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ gettext("unable to find "
+ "disk service, %s: %s"), dgname, strerror(errno));
+ return (-1);
+ }
+
+ if (rc == 0) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ gettext("disk service, %s, is "
+ "active on node \"%s\"\nPlease re-issue "
+ "the command on that node"), dgname, othernode);
+ return (-1);
+ }
+ return (DCMD_OK);
+}
+
+int
+ctag_check(rdcconfig_t *rdc)
+{
+ char *file_dgname;
+ char *bmp_dgname;
+ char *fromhost, *tohost;
+ char *fromfile, *tofile;
+ char *frombitmap, *tobitmap;
+ char *localfile;
+ char *ctag;
+ char file_buf[MAX_RDC_HOST_SIZE];
+ char bmp_buf[MAX_RDC_HOST_SIZE];
+ int is_primary;
+ int islocal = 0;
+ struct hostent *hp;
+ char fromname[MAXHOSTNAMELEN], toname[MAXHOSTNAMELEN];
+
+ fromhost = rdc->phost;
+ fromfile = rdc->pfile;
+ frombitmap = rdc->pbmp;
+ tohost = rdc->shost;
+ tofile = rdc->sfile;
+ tobitmap = rdc->sbmp;
+ ctag = rdc->ctag;
+
+ /*
+ * Check for the special (local) cluster tag
+ */
+ if (!cfg_iscluster())
+ return (0);
+
+ if (ctag != NULL && strcmp(rdc->ctag, RDC_LOCAL_TAG) == 0) {
+ strcpy(rdc->ctag, "-");
+ islocal = TRUE;
+ } else {
+ islocal = FALSE;
+ }
+
+ hp = gethost_byname(fromhost);
+ strncpy(fromname, hp->h_name, MAXHOSTNAMELEN);
+ hp = gethost_byname(tohost);
+ strncpy(toname, hp->h_name, MAXHOSTNAMELEN);
+ if (!self_check(fromname) && !self_check(toname)) {
+ /*
+ * If we could get a list of logical hosts on this cluster
+ * then we could print something intelligent about where
+ * the volume is mastered. For now, just print some babble
+ * about the fact that we have no idea.
+ */
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ gettext("either %s:%s or %s:%s is not local"),
+ fromhost, fromfile, tohost, tofile);
+ return (-1);
+ }
+
+ is_primary = self_check(fromname);
+
+ /*
+ * If implicit disk group name and no ctag specified by user,
+ * we set the ctag to it.
+ * If implicit disk group name, it must match any supplied ctag.
+ */
+ if (is_primary)
+ localfile = fromfile;
+ else
+ localfile = tofile;
+ file_dgname = cfg_dgname(localfile, file_buf, sizeof (file_buf));
+ if (file_dgname != NULL && file_dgname[0] != '\0')
+ if (check_dgislocal(file_dgname) < 0) {
+ /* errors already set */
+ return (-1);
+ }
+
+ if (strlen(ctag) == 0 && file_dgname && strlen(file_dgname))
+ strncpy(ctag, file_dgname, MAX_RDC_HOST_SIZE);
+
+ /*
+ * making an exception here for users giving the "local"tag
+ * this overrides this error message. (rdc_islocal ! = 1)
+ */
+ if (strlen(ctag) != 0 && file_dgname && islocal != 1 &&
+ strlen(file_dgname) != 0 &&
+ strncmp(ctag, file_dgname, MAX_RDC_HOST_SIZE) != 0) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ gettext("ctag \"%s\" does not "
+ "match disk group name \"%s\" of volume %s"), ctag,
+ file_dgname, localfile);
+ return (-1);
+ }
+ if ((file_dgname == NULL) || ((strlen(ctag) == 0) &&
+ (strlen(file_dgname) == 0))) {
+ /*
+ * we must have a non-volume managed disk here
+ * so ask for a tag and get out
+ */
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ gettext("volume \"%s\" is not part"
+ " of a disk group,\nplease specify resource ctag\n"),
+ localfile);
+
+ }
+
+ /*
+ * Local bitmap must also have same ctag.
+ */
+ if (is_primary)
+ localfile = frombitmap;
+ else
+ localfile = tobitmap;
+ bmp_dgname = cfg_dgname(localfile, bmp_buf, sizeof (bmp_buf));
+ if (bmp_dgname != NULL && bmp_dgname[0] != '\0')
+ if (check_dgislocal(bmp_dgname) < 0) {
+ /* error already set */
+ return (-1);
+ }
+
+ if (file_dgname && strlen(file_dgname) != 0) {
+ /* File is in a real disk group */
+ if ((bmp_dgname == NULL) || (strlen(bmp_dgname) == 0)) {
+ /* Bitmap is not in a real disk group */
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ gettext("bitmap %s is not in disk group \"%s\""),
+ localfile, islocal < 1?file_dgname:ctag);
+ return (-1);
+ }
+ }
+ if (strlen(ctag) != 0 && bmp_dgname && islocal != 1 &&
+ strlen(bmp_dgname) != 0 &&
+ strncmp(ctag, bmp_dgname, MAX_RDC_HOST_SIZE) != 0) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ gettext("ctag \"%s\" does not "
+ "match disk group name \"%s\" of bitmap %s"),
+ ctag, bmp_dgname, localfile);
+ return (-1);
+ }
+
+ return (0);
+}
+int
+mounted(char *device)
+{
+ char target[NSC_MAXPATH];
+ struct mnttab mntref;
+ struct mnttab mntent;
+ FILE *mntfp;
+ int rdsk;
+ char *s;
+ int rc;
+ int i;
+
+ rdsk = i = 0;
+ for (s = target; i < NSC_MAXPATH && (*s = *device++); i++) {
+ if (*s == 'r' && rdsk == 0 && strncmp(device, "dsk/", 4) == 0)
+ rdsk = 1;
+ else
+ s++;
+ }
+ *s = '\0';
+
+ mntref.mnt_special = target;
+ mntref.mnt_mountp = NULL;
+ mntref.mnt_fstype = NULL;
+ mntref.mnt_mntopts = NULL;
+ mntref.mnt_time = NULL;
+
+ mntfp = fopen(MNTTAB, "r");
+
+ if (mntfp == NULL) {
+ /* Assume the worst, that it is mounted */
+ return (1);
+ }
+
+ if ((rc = getmntany(mntfp, &mntent, &mntref)) != -1) {
+ /* found something before EOF */
+ fclose(mntfp);
+ return (1);
+ }
+
+ fclose(mntfp);
+ return (0);
+}
+
+int
+can_enable(rdcconfig_t *rdc)
+{
+ struct stat stb;
+
+ if ((strcmp(rdc->pfile, rdc->pbmp) == 0) ||
+ (strcmp(rdc->sfile, rdc->sbmp) == 0)) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ dgettext("librdc", "volumes and bitmaps must not match"));
+ return (0);
+ }
+ if (ctag_check(rdc) < 0) {
+ /* rdc_error should already be set */
+ return (0);
+ }
+
+ if (self_check(rdc->phost)) {
+ if (stat(rdc->pfile, &stb) != 0) {
+ rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
+ return (0);
+ }
+ if (!S_ISCHR(stb.st_mode)) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ dgettext("librdc", "%s is not a character device"),
+ rdc->pfile);
+ return (0);
+ }
+ return (rdc->persist ?
+ !bitmap_in_use(RDC_CMD_ENABLE, rdc->phost, rdc->pbmp) : 1);
+ } else { /* on the secondary */
+ if (stat(rdc->sfile, &stb) != 0) {
+ rdc_set_error(NULL, RDC_OS, 0,
+ dgettext("librdc", "unable to access %s: %s"),
+ rdc->sfile, strerror(errno));
+ }
+ if (!S_ISCHR(stb.st_mode)) {
+ rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
+ dgettext("librdc",
+ "%s is not a character device"), rdc->sfile);
+ }
+ return (rdc->persist ?
+ !bitmap_in_use(RDC_CMD_ENABLE, rdc->shost, rdc->sbmp) : 1);
+ }
+}
+
+int
+can_reconfig_pbmp(rdcconfig_t *rdc, char *bmp)
+{
+ if (!rdc->persist)
+ return (0);
+
+ return (!bitmap_in_use(RDC_CMD_RECONFIG, rdc->phost, bmp));
+}
+
+int
+can_reconfig_sbmp(rdcconfig_t *rdc, char *bmp)
+{
+ if (!rdc->persist)
+ return (0);
+
+ return (!bitmap_in_use(RDC_CMD_RECONFIG, rdc->shost, bmp));
+}
+
+rdc_rc_t *
+cant_rsync(rdcconfig_t *rdc)
+{
+ rdc_rc_t *rc;
+
+ if (mounted(rdc->pfile)) {
+ rc = new_rc();
+ if (rc == NULL)
+ return (NULL);
+ strncpy(rc->set.phost, rdc->phost, MAX_RDC_HOST_SIZE);
+ strncpy(rc->set.pfile, rdc->pfile, NSC_MAXPATH);
+ strncpy(rc->set.pbmp, rdc->pbmp, NSC_MAXPATH);
+ strncpy(rc->set.shost, rdc->shost, MAX_RDC_HOST_SIZE);
+ strncpy(rc->set.sfile, rdc->sfile, NSC_MAXPATH);
+ strncpy(rc->set.sbmp, rdc->sbmp, NSC_MAXPATH);
+
+ rc->rc = -1;
+
+ rdc_set_error(NULL, RDC_INTERNAL, 0, "unable to sync %s volume"
+ " is currently mounted", rdc->pfile);
+ strncpy(rc->msg, rdc_error(NULL), RDC_ERR_SIZE);
+
+ return (rc);
+ }
+ return (NULL);
+}
diff --git a/usr/src/lib/librdc/common/rdcrules.h b/usr/src/lib/librdc/common/rdcrules.h
new file mode 100644
index 0000000000..ab111fbdce
--- /dev/null
+++ b/usr/src/lib/librdc/common/rdcrules.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#ifndef _RDCRULES_H
+#define _RDCRULES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* insert handy rule enforcing functions here */
+
+extern int bitmap_in_use(int cmd, char *hostp, char *bmp);
+extern int mounted(char *);
+extern int can_enable(rdcconfig_t *rdc);
+extern int can_reconfig_pbmp(rdcconfig_t *rdc, char *bmp);
+extern int can_reconfig_sbmp(rdcconfig_t *rdc, char *bmp);
+extern rdc_rc_t *cant_rsync(rdcconfig_t *rdc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RDCRULES_H */