diff options
Diffstat (limited to 'usr/src/lib/librdc/common')
| -rw-r--r-- | usr/src/lib/librdc/common/librdc.h | 113 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/llib-lrdc | 46 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/mapfile-vers | 78 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/netaddrs.c | 670 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/rdcconfig.c | 1321 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/rdcerr.c | 98 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/rdcerr.h | 74 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/rdcpersist.c | 716 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/rdcrules.c | 545 | ||||
| -rw-r--r-- | usr/src/lib/librdc/common/rdcrules.h | 46 |
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 */ |
