iiadm.c revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
/*
* 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
* 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 <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <values.h>
#include <locale.h>
#include <langinfo.h>
#include <strings.h>
#include <stdarg.h>
#include <ctype.h>
#include <math.h>
#include <nsctl.h>
#include <netdb.h>
#include <search.h>
typedef struct mstcount_s {
int count;
} mstcount_t;
typedef struct shdvol_s {
char master[ DSW_NAMELEN ];
} shdvol_t;
typedef struct grptag_s {
char ctag[ DSW_NAMELEN ];
} grptag_t;
#define DSW_TEXT_DOMAIN "II"
#include <dlfcn.h>
#define RDC_LIB "/usr/lib/librdc.so.1"
static int (*self_check)(char *);
/*
* Support for the special cluster tag "local" to be used with -C in a
* cluster for local volumes.
*/
#define II_LOCAL_TAG "local"
#define II_NOT_CLUSTER 1
#define II_CLUSTER 2
#define II_CLUSTER_LCL 3
static char *cfg_cluster_tag = NULL;
unsigned long bm_size; /* size in bytes of bitmap */
unsigned long bm_actual; /* original number of bits in bitmap */
int debug = 0;
int dsw_fd;
#define LD_II 0x00000001
#define LD_DSVOLS 0x00000002
#define LD_SVOLS 0x00000004
#define LD_SHADOWS 0x00000008
static int reload_vols = 0;
static int config_locked = 0;
static int last_lock;
/*
* names for do_copy() flags.
*/
char *cmdnam;
unsigned char *allocate_bitmap(char *);
void usage(char *);
void enable(char *, char *, char *, char *);
int disable(char *);
void bitmap_op(char *, int, int, int, int);
void print_status(dsw_config_t *, int);
int abort_copy(char *);
int reset(char *);
int overflow(char *);
void iiversion(void);
int wait_for_copy(char *);
int export(char *);
void list_volumes(void);
void dsw_error(char *, spcs_s_info_t *);
void InitEnv();
static void check_dg_is_local(char *dgname);
static int check_resource_group(char *volume);
static int check_cluster();
static void unload_ii_vols();
static void load_ii_vols(CFGFILE *);
static int perform_autosv();
static int is_exported(char *);
static void conform_name(char **);
static void do_attach(dsw_config_t *);
void dsw_list_clusters(char *);
void dsw_enable(int, char **);
void dsw_disable(int, char **);
void dsw_copy_to_shadow(int, char **);
void dsw_update_shadow(int, char **);
void dsw_copy_to_master(int, char **);
void dsw_update_master(int, char **);
void dsw_abort_copy(int, char **);
void dsw_display_status(int, char **);
void dsw_display_bitmap(int, char **);
void dsw_reset(int, char **);
void dsw_overflow(int, char **);
void dsw_version(int, char **);
void dsw_wait(int, char **);
void dsw_list_volumes(int, char **);
void dsw_list_group_volumes();
void dsw_export(int, char **);
void dsw_import(int, char **);
void dsw_join(int, char **);
void dsw_attach(int, char **);
void dsw_detach(int, char **);
void dsw_params(int, char **);
void dsw_olist(int, char **);
void dsw_ostat(int, char **);
void dsw_move_2_group(int, char **);
void dsw_list_groups();
void check_iishadow(char *);
extern char *optarg;
int Aflg;
int Cflg;
int CLflg;
int Dflg;
int Eflg;
int Iflg;
int Jflg;
int Lflg;
int Oflg;
int Pflg;
int Qflg;
int Rflg;
int aflg;
int bflg;
int cflg;
int dflg;
int eflg;
int fflg;
int gflg;
int gLflg;
int hflg;
int iflg;
int lflg;
int mflg;
int nflg;
int pflg;
int uflg;
int vflg;
int wflg;
int errflg;
#ifdef DEBUG
const char single_opts[] =
"a:b:c:d:e:f:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
#else
/* no b or f flags */
const char single_opts[] = "a:c:d:e:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
#endif
const char group_opts[] = "ac:de:ilmnpu:wA:C:DELPR";
const char *opt_list = single_opts;
char buf[CFG_MAX_BUF];
char key[CFG_MAX_KEY];
char last_overflow[DSW_NAMELEN];
int setnumber;
char *group_name;
char **group_volumes;
enum copy_direction direction;
char *param_delay, *param_unit;
char *overflow_file;
#ifdef lint
int
#else
int
#endif
{
int c;
int actions = 0;
int ac;
char *av[1024];
InitEnv();
switch (c) {
case 'c':
cflg++;
actions++;
av[0] = "copy_to_master";
av[0] = "copy_to_shadow";
} else {
errflg ++;
"must specify m or s with -c"));
}
ac = 2;
break;
case 'd':
dflg++;
actions++;
av[0] = "disable";
ac = 2;
break;
case 'e':
eflg++;
actions++;
av[0] = "enable";
else {
errflg ++;
"must specify ind or dep with -e"));
}
ac = 1;
break;
case 'g':
gflg++;
group_name = optarg;
if (gLflg)
actions++;
}
break;
case 'h':
hflg++;
actions++;
break;
case 'u':
uflg++;
actions++;
av[0] = "update_master";
av[0] = "update_shadow";
} else {
errflg ++;
"must specify m or s with -u"));
}
ac = 2;
break;
case 'i':
iflg++;
actions++;
av[0] = "display_status";
break;
case 'l':
lflg++;
actions++;
av[0] = "list_config";
ac = 1;
break;
case 'm':
mflg++;
actions++;
av[0] = "move_to_group";
ac = 1;
break;
case 'n':
nflg++;
break;
case 'p':
pflg++;
break;
case 'b':
bflg++;
actions++;
av[0] = "display_bitmap";
ac = 2;
break;
case 'a':
aflg++;
actions++;
av[0] = "abort_copy";
ac = 2;
break;
case 'v':
vflg++;
actions++;
ac = 1;
break;
case 'w':
wflg++;
actions++;
av[0] = "wait";
ac = 2;
break;
case 'A':
Aflg++;
actions++;
av[0] = "attach";
ac = 2;
break;
case 'C':
Cflg++;
if (CLflg)
actions++;
}
break;
case 'D':
Dflg++;
actions++;
av[0] = "detach";
ac = 2;
break;
case 'O':
Oflg++;
actions++;
av[0] = "overflow";
ac = 2;
break;
case 'R':
Rflg++;
actions++;
av[0] = "reset";
ac = 2;
break;
case 'E':
Eflg++;
actions++;
av[0] = "export";
ac = 2;
break;
case 'I':
Iflg++;
actions++;
av[0] = "import";
ac = 2;
break;
case 'J':
Jflg++;
actions++;
av[0] = "join";
ac = 2;
break;
case 'P':
Pflg++;
actions++;
av[0] = "parameter";
ac = 1;
break;
case 'L':
Lflg++;
actions++;
/* If -g group -L, force error */
if (group_name) actions++;
av[0] = "LIST";
ac = 1;
break;
case 'Q':
Qflg++;
actions++;
av[0] = "query";
ac = 2;
break;
case '?':
errflg++;
break;
}
if (hflg) {
exit(0);
}
if (errflg)
switch (actions) {
case 0:
if (argc > 1)
/* default behavior is to list configuration */
break;
case 1:
break;
default:
break;
}
/*
* Open configuration file.
*/
perror("unable to access configuration");
exit(2);
}
/*
* Set write locking (CFG_WRLOCK) for:
* iiadm -e (enable)
* iiadm -d (disable)
* iiadm -A (attach overflow)
* iiadm -D (detach overflow)
* iiadm -g grp -m volume (move volume into group)
* iiadm -E (export shadow [needs to update dsvol section])
* iiadm -I (import shadow [ditto])
* iiadm -J (join shadow [ditto])
* read locking (CFG_RDLOCK) for all other commands
*/
perror("unable to lock configuration");
exit(2);
}
config_locked = 1;
/*
* If we are in a cluster, set or derive a valid disk group
*/
switch (check_cluster()) {
case II_CLUSTER:
/*
* If in a Sun Cluster, can't Import an II shadow
* Must be done as -C local
*/
if (Iflg)
"-I (import) only allowed as -C local"), NULL);
/*FALLTHRU*/
case II_CLUSTER_LCL:
/*
* If a cluster tag was specified or derived, set it
*/
if (CLflg) {
exit(0);
} else {
}
break;
case II_NOT_CLUSTER:
if (cfg_cluster_tag != NULL)
"-C is valid only in a Sun Cluster"), NULL);
break;
default:
"Unexpected return from check_cluster()"), NULL);
}
/* preload the ii config */
reload_vols |= LD_II;
if (eflg) {
ac = 5;
} else if (dflg) {
} else if (uflg) {
else
} else if (iflg) {
ac = 2;
} else
ac = 1;
} else if (bflg) {
} else if (cflg) {
else
} else if (aflg) {
} else if (Eflg) {
} else if (Iflg) {
ac = 3;
} else if (Aflg) {
if (group_name) {
"when using groups with -A"));
ac = 2;
} else {
ac = 3;
}
} else if (Dflg) {
} else if (Jflg) {
ac = 3;
} else if (Pflg) {
} else
"must specify delay, unit and shadow with -P"));
} else if (Oflg) {
} else if (Rflg) {
} else if (vflg) {
} else if (wflg) {
} else if (lflg) {
if ((gflg) && (!group_name))
else
} else if (Lflg) {
} else if (gLflg) {
} else if (Qflg) {
} else if (mflg) {
}
if (cfg)
exit(0);
return (0);
}
static int
{
}
static int
{
int unlocked = 0;
int rc;
int save_errno;
if (config_locked) {
switch (cmd) {
case DSWIOC_ENABLE:
case DSWIOC_RESUME:
case DSWIOC_SUSPEND:
case DSWIOC_COPY:
case DSWIOC_BITMAP:
case DSWIOC_DISABLE:
case DSWIOC_SHUTDOWN:
case DSWIOC_ABORT:
case DSWIOC_RESET:
case DSWIOC_OFFLINE:
case DSWIOC_WAIT:
case DSWIOC_ACOPY:
case DSWIOC_EXPORT:
case DSWIOC_IMPORT:
case DSWIOC_JOIN:
case DSWIOC_COPYP:
case DSWIOC_OATTACH:
case DSWIOC_ODETACH:
case DSWIOC_SBITSSET:
case DSWIOC_CBITSSET:
case DSWIOC_SEGMENT:
case DSWIOC_MOVEGRP:
case DSWIOC_CHANGETAG:
unlocked = 1;
break;
case DSWIOC_STAT:
case DSWIOC_VERSION:
case DSWIOC_LIST:
case DSWIOC_OCREAT:
case DSWIOC_OLIST:
case DSWIOC_OSTAT:
case DSWIOC_OSTAT2:
case DSWIOC_LISTLEN:
case DSWIOC_OLISTLEN:
case DSWIOC_CLIST:
case DSWIOC_GLIST:
break;
default:
"cfg locking needs to be set for %08x\n", cmd);
exit(1);
break;
}
}
if (unlocked) {
/* unload vol hashes */
if (reload_vols & LD_II)
if (reload_vols & LD_SHADOWS)
if (reload_vols & LD_DSVOLS)
if (reload_vols & LD_SVOLS)
}
save_errno = errno;
if (config_locked && unlocked) {
}
if (unlocked) {
/* reload vol hashes */
if (reload_vols & LD_SVOLS)
if (reload_vols & LD_DSVOLS)
if (reload_vols & LD_SHADOWS)
if (reload_vols & LD_II)
}
errno = save_errno;
return (rc);
}
static int
{
char buf[CFG_MAX_BUF];
char key[CFG_MAX_KEY];
return (-1);
return (0);
}
static int
{
setnumber++) {
return (1);
}
return (0);
}
int
find_any_cf_line(char *volume)
{
}
static int
{
setnumber++) {
return (1);
}
return (0);
}
int
find_shadow_line(char *volume)
{
}
/*
* this function is designed to be called once, subsequent calls won't
* free memory allocated by earlier invocations.
*/
char *
{
if (num < 0)
if (acopy_args == NULL)
acopy_args->flags = 0;
if (rc == -1)
&acopy_args->status);
else
return (acopy_args->shadow_vol);
}
/*
* this function is designed to be called once, subsequent calls won't
* free memory allocated by earlier invocations.
*/
int
find_group_members(char *group)
{
int nmembers = 0;
int vector_len = 0;
sizeof (buf)) < 0)
break;
continue;
sizeof (buf)) < 0)
break;
if (nmembers >= vector_len) {
vector_len += 10;
sizeof (char *));
}
nmembers++;
}
if (group_volumes)
return (nmembers);
}
static int
{
return (0);
}
if (io) {
}
return (1);
}
int
{
}
int
{
dsw_config_t *c, cf;
if (io) {
}
setnumber = 1;
/* perform action for each line of the stored config file */
++setnumber)) {
(void) get_dsw_config(setnumber, c);
if (check_resource_group(c->bitmap_vol)) {
setnumber = 0;
continue;
}
switch (check_cluster()) {
case II_CLUSTER:
if ((cfg_cluster_tag) &&
continue;
break;
case II_CLUSTER_LCL:
if (strlen(c->cluster_tag))
continue;
break;
}
if (io) {
}
return (1);
}
}
return (0);
}
void
{
/* insert the well-known fields first */
/* if we have a group name, add it */
if (group_name) {
perror("cfg_put_cstring");
}
else
perror("cfg_location");
}
/* commit the record */
(void) cfg_commit(cfg);
}
else
perror("cfg_put_string");
}
void
{
char sn[CFG_MAX_BUF];
if (perform_autosv()) {
if (volhash) {
}
}
if (sdata) {
/*
* Handle the normal cases of disabling a set that is
* not an imported shadow volume
*/
/*
* Handle multiple-shadows of single master
*/
mdata = (mstcount_t *)
cfg_cluster_tag, "ii") < 0)
"SV disable of master failed"),
NULL);
}
}
/*
* Handle disk group name of different shadow
*/
if (shd_exp) {
/*
* If shadow is exported, then do nothing
*/
/*EMPTY*/;
} else if (cfg_cluster_tag &&
/* reload disk group volumes */
(void) cfg_load_dsvols(cfg);
(void) cfg_load_svols(cfg);
"ii") < 0)
"SV disable of shadow failed"),
NULL);
} else {
cfg_cluster_tag, "ii") < 0)
"SV disable of shadow failed"),
NULL);
}
}
}
perror("cfg_put_cstring");
}
(void) cfg_commit(cfg);
}
/*
* determine if we are running in a Sun Cluster Environment
*/
int
{
static int is_cluster = -1;
int rc;
#ifdef DEBUG
#endif
/*
* If this routine was previously called, just return results
*/
if (is_cluster != -1)
return (is_cluster);
/*
* See if Sun Cluster was installed on this node
*/
#ifdef DEBUG
else
#endif
rc = cfg_iscluster();
if (rc > 0) {
/*
* Determine if user specified -C local
*/
if ((cfg_cluster_tag == NULL) ||
/*
* We're in a Sun Cluster, and no "-C local"
*/
} else {
/*
* We're in a Sun Cluster, but "-C local" was specified
*/
cfg_cluster_tag = "";
}
return (is_cluster);
} else if (rc == 0) {
/*
* Not in a Sun Cluster
*/
return (is_cluster);
} else {
/*NOTREACHED*/
}
/* gcc */
return (is_cluster);
}
/*
* Determine if we need to set a cfg_resource based on this volume
*/
static int
check_resource_group(char *volume)
{
char diskgroup[CFG_MAX_BUF];
/*
* If we are in a cluster, attempt to derive a new resource group
*/
#ifdef DEBUG
#else
if (check_cluster() == II_CLUSTER) {
#endif
if (cfg_cluster_tag == NULL) {
if (cfg_cluster_tag == NULL)
"Memory allocation failure"), NULL);
return (1);
} else {
/*
* Check dgname and cluster tag from -C are the same.
*/
char error_buffer[128];
"-C (%s) does not match disk group "
"name (%s) for %s"), cfg_cluster_tag,
}
}
} else if (cfg_cluster_tag == NULL)
"Point-in-Time Copy volumes, that are not "
"in a device group which has been "
"registered with SunCluster, "
"require usage of \"-C\""), NULL);
}
return (0);
}
static void
check_dg_is_local(char *dgname)
{
char error_buffer[128];
char *othernode;
int rc;
/*
* check where this disk service is mastered
*/
if (rc < 0) {
} else if (rc == 0) {
gettext("disk service, %s, is active on node \"%s\"\n"
"Please re-issue the command on that node"), dgname,
}
}
/*
* Carry out cluster based checks for a specified volume, or just
* global options.
*/
static int
{
char dgname[CFG_MAX_BUF];
char error_buffer[128];
#ifdef DEBUG
if (override) {
return (1);
}
#endif
/*
* Check on path name, a returned NULL dgname is valid
*/
"unable to determine disk group name for %s"), path);
}
return (0);
/*
* See if disk group is local to this node
*/
/*
* Copy dgname into result
*/
return (1);
}
/*
* sigterm (): traps specified signal , usually termination one
*/
void
{
exit(1);
}
/*
* sigchild; reap child and collect status.
*/
volatile pid_t dead_child;
int dead_stat;
/*ARGSUSED*/
void
{
}
/*
* InitEnv(): initializes environment
*/
void
InitEnv()
{
(void) textdomain(DSW_TEXT_DOMAIN);
#ifndef DEBUG
#endif
if (dsw_fd < 0) {
exit(1);
}
setsid();
}
/*
* print an error message, followed by decoded errno then exit.
*/
void
{
char *sp;
/* deflect ESRCH */
} else {
}
} else {
}
if (cfg)
exit(2);
}
void
free_bitmap(unsigned char *bitmap)
{
}
int
char *master_volume;
unsigned char *shd_bitmap;
unsigned char *copy_bitmap;
unsigned long size;
{
}
unsigned char *
allocate_bitmap(char *shadow_volume)
{
unsigned char *shd_bitmap;
unsigned char *copy_bitmap;
unsigned char *p;
unsigned char *q;
int i;
int stat_flags;
if (stat_flags & DSW_BMPOFFLINE)
return (NULL);
if (!shd_bitmap) {
return (NULL);
}
if (!copy_bitmap) {
return (NULL);
}
return (NULL);
}
/*
* "or" the copy and shadow bitmaps together to return a composite
* bitmap that contains the total set of differences between the
* volumes.
*/
for (i = bm_size; i-- > 0; /*CSTYLED*/)
*p++ |= *q++;
return (shd_bitmap);
}
/*
* print usage message and exit.
*/
void
{
if (why) {
gettext("\nBrief summary:"));
gettext("\t-e {ind|dep} master_vol shadow_vol "
"bitmap_vol"));
gettext("\t-[cu {s|m}] volume_set"));
gettext("\t-i all"));
gettext("\t-[adDEilPRw] volume_set"));
gettext("\t-g group_name [options]"));
gettext("\t-C cluster_tag [options]"));
gettext("\t-[hilLv]"));
gettext("\t-[IJ] volume_set bitmap"));
gettext("\t-A overflow_vol volume_set"));
gettext("\t-[OQ] overflow_vol"));
gettext("\t-P {delay} {units} volume_set"));
/* assume we came here due to a user mistake */
exit(1);
/* NOTREACHED */
} else {
gettext("Point-in-Time Copy Administrator CLI options"));
gettext("Usage summary:"));
gettext("\t-e ind m s b\tenable independent master shadow "
"bitmap"));
gettext("\t-e dep m s b\tenable dependent master shadow "
"bitmap"));
if (check_cluster() == II_CLUSTER)
gettext("\t-ne ind m s b\tenable exportable master "
"shadow bitmap"));
gettext("\t-d v\t\tdisable volume"));
gettext("\t-u s v\t\tupdate shadow volume"));
gettext("\t-u m v\t\tupdate master volume"));
gettext("\t-c s v\t\tcopy to shadow volume"));
gettext("\t-c m v\t\tcopy to master volume"));
gettext("\t-a v\t\tabort copy volume"));
gettext("\t-w v\t\twait volume"));
gettext("\t-i v\t\tdisplay volume status"));
gettext("\t-i all\t\tdisplay all volume status"));
gettext("\t-l\t\tlist all volumes"));
gettext("\t-R v\t\treset volume"));
gettext("\t-A o v\t\tattach overflow to volume"));
gettext("\t-D v\t\tdetach overflow from volume"));
gettext("\t-L\t\tlist all overflow volumes"));
gettext("\t-O o\t\tinitialize overflow"));
gettext("\t-Q o\t\tquery status of overflow"));
gettext("\t-E v\t\texport shadow volume"));
gettext("\t-I v b\t\timport volume bitmap"));
gettext("\t-J v b\t\tjoin volume bitmap"));
gettext("\t-C tag\t\tcluster resource tag"));
#ifdef DEBUG
gettext("\t-b v\t\tdisplay bitmap volume"));
gettext("\t-f f\t\tuse private configuration file"));
#endif
gettext("\t-v\t\tprint software versions"));
gettext("\t-n\t\tperform action without question"));
gettext("\t-p [-c|-u] {m|s}"
"enable PID locking on copy or update"));
gettext("\t-p -w v\t\tdisable PID locking"));
gettext("\t-h\t\tiiadm usage summary"));
gettext("\nUsage summary for options that support "
"grouping (-g g):"));
gettext("\t-g g -e ind m s b group enable independent "
"master shadow bitmap"));
gettext("\t-g g -e dep m s b group enable dependent "
"master shadow bitmap"));
gettext("\t-g g -d\t\tdisable group"));
gettext("\t-g g -u s\tupdate shadow for all volumes in "
"group"));
gettext("\t-g g -u m\tupdate master for all volumes in "
"group"));
gettext("\t-g g -c s\tcopy to shadow for all volumes in "
"group"));
gettext("\t-g g -c m\tcopy to master for all volumes in "
"group"));
gettext("\t-g g -a\t\tabort copy for all volumes in "
"group"));
gettext("\t-g g -w\t\twait for all volumes in group"));
gettext("\t-g g -i\t\tdisplay status of all volumes in "
"group"));
gettext("\t-g g -l\t\tlist all volumes in group"));
gettext("\t-g -L\t\tlist all groups"));
gettext("\t-g g -m v v\tmove one or more volumes into "
"group"));
gettext("\t-g \"\" -m v\tremove volume from group"));
gettext("\t-g g -R\t\treset all volumes in group"));
gettext("\t-g g -A o\tattach overflow to all volumes in "
"group"));
gettext("\t-g g -D\t\tdetach overflow from all volumes in "
"group"));
gettext("\t-g g -E\t\texport shadow volume for all "
"volumes in group"));
"volumes in group"));
"volumes in group"));
gettext("\nLegend summary:"));
gettext("\tind\t\tindependent volume set"));
gettext("\tdep\t\tdependent volume set"));
gettext("\tall\t\tall configured volumes"));
gettext("\tm\t\tmaster volume"));
gettext("\ts\t\tshadow volume"));
gettext("\tv\t\tshadow volume (reference name)"));
gettext("\to\t\toverflow volume"));
gettext("\tb\t\tbitmap volume"));
#ifdef DEBUG
gettext("\tf\t\tconfiguration file name"));
#endif
gettext("\td\t\tdelay tick interval"));
gettext("\tu\t\tunit size"));
gettext("\tg\t\tgroup name"));
/* assume we came here because user request help text */
exit(0);
/* NOTREACHED */
}
}
static int
yes(void)
{
int i, b;
for (i = 0; /*CSTYLED*/; i++) {
b = getchar();
if (i < MAX_LINE_SIZE)
ans[i] = 0;
break;
}
if (i < MAX_LINE_SIZE)
ans[i] = b;
}
if (i >= MAX_LINE_SIZE) {
i = MAX_LINE_SIZE;
ans[MAX_LINE_SIZE] = 0;
}
return (0);
return (1);
else {
gettext("You have to respond with"),
return (2);
}
}
return (1);
}
static int
convert_int(char *str)
{
char *buf;
if (rc != 1) {
/* dsw_error calls exit which frees 'buf' */
}
return (result);
}
void
check_action(char *will_happen)
{
int answer;
return;
/*CONSTCOND*/
while (1) {
break;
}
if (answer == 1)
return;
exit(1);
}
/*
* Wait for child process to get to some state, where some state may be:
*
* Status Set up the shadow enough so that it responds
* to status requests.
*/
int
{
int rc;
/* poll shadow group with a status ioctl() */
errno = 0;
/* keep polling while we fail with DSW_ENOTFOUND */
return (0);
} else {
/* event == CopyStart */
if (rc == -1) {
return (1); /* something wrong */
}
return (0); /* copying underway */
}
}
/* child died */
return (WEXITSTATUS(dead_stat));
else
return (1);
}
int
mounted(char *t)
{
int rdsk;
int i;
char target[DSW_NAMELEN];
char *s;
rdsk = i = 0;
for (s = target; i < DSW_NAMELEN && (*s = *t++); i++) {
if (*s == 'r' && rdsk == 0)
rdsk = 1;
else
s++;
}
*s = '\0';
NULL);
}
/* found something before EOF */
return (1);
}
return (0);
}
void
char *bitmap_volume, char *copy_type)
{
char *p;
int rc;
char mst_dg[DSW_NAMELEN] = {0};
char shd_dg[DSW_NAMELEN] = {0};
char bmp_dg[DSW_NAMELEN] = {0};
int mvol_enabled;
char *altname;
else
/* validate volume names */
if (perform_autosv()) {
cfg_load_shadows(cfg) < 0) {
}
/* see if it's been used before under a different name */
if (rc < 0) {
}
if (rc) {
}
}
/*
* If not local, determine disk group names for volumes in II set
*/
switch (check_cluster()) {
case II_CLUSTER:
/*
* Check if none or all volumes are in a disk group
*/
rc = 0;
"Not all Point-in-Time Copy volumes are "
"in a disk group"), NULL);
/*
* If volumes are not in a disk group, but are in a
* cluster, then "-C <tag>", must be set
*/
"Point-in-Time Copy volumes, that are not "
"in a device group which has been "
"registered with SunCluster, "
"require usage of \"-C\""), NULL);
/*
* the same disk group
* If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster
*/
"Volumes are not in same disk group"), NULL);
/*
* Can never enable the same shadow twice, regardless of
* exportable shadow device group movement
*/
"Shadow volume is already configured"), NULL);
/*
* Groups cannot span multiple clusters
*/
if (group_name && perform_autosv()) {
if (gdata &&
"in the same cluster resource"), NULL);
}
}
/*
* Check cluster tag and bitmap disk group
* set latter if different
*/
if (check_resource_group(bitmap_volume)) {
/*
* Unload and reload in the event cluster tag has
* changed
*/
if (perform_autosv()) {
if (cfg_load_svols(cfg) < 0 ||
cfg_load_dsvols(cfg) < 0 ||
cfg_load_shadows(cfg) < 0) {
"Unable to parse config "
"file"), NULL);
}
}
}
/*
* Copy cluster name into config
*/
break;
case II_CLUSTER_LCL:
/* ensure that the -C local won't interfere with the set */
if (group_name && perform_autosv()) {
if (gdata) {
"into -C local and specified "
"group"), NULL);
}
}
}
break;
}
/*
* If we've got a group name, add it into the config
*/
if (group_name) {
}
/*
* Determine accessability of volumes
*/
"Unable to access master volume"), NULL);
"Master volume is not a character device"), NULL);
/* check the shadow_vol hasn't be used as SNDR secondary vol */
"Unable to access shadow volume"), NULL);
"Shadow volume is not a character device"), NULL);
if (mounted(shadow_volume)) {
"Shadow volume is mounted, unmount it first"), NULL);
}
"Master and shadow are the same device"), NULL);
}
}
"Bitmap volume is not a character device"), NULL);
"Master and bitmap are the same device"), NULL);
"Shadow and bitmap are the same device"), NULL);
}
}
errno = 0;
/*
* Check that none of the member volumes forms part of another
* InstantImage group.
*
* -- this check has been removed; it is done in the kernel instead
* -- PJW
*/
/*
* Check against overflow volumes
*/
"Master volume is already an overflow volume"),
NULL);
"Shadow volume is already an overflow volume"),
NULL);
"Bitmap volume is already an overflow volume"),
NULL);
}
/*
* Make sure that the shadow volume is not already configured
*/
"Shadow volume is already configured"), NULL);
if (perform_autosv()) {
/*
* parse the dsvol entries to see if we need to place
* the master or shadow under SV control
*/
"ii") < 0) {
gettext("Cannot enable master volume"),
NULL);
}
mvol_enabled = 1;
} else {
mvol_enabled = 0;
}
if (nflg) {
shd_dg, "ii");
} else {
cfg_cluster_tag, "ii");
}
if (rc < 0) {
if (mvol_enabled) {
if (cfg_vol_disable(cfg,
"ii") < 0)
"SV disable of master failed"),
NULL);
}
gettext("Cannot enable shadow volume"),
NULL);
}
}
reload_vols = 0;
}
config_locked = 0;
case (pid_t)-1:
break;
case 0:
/*
* Failed to enable shadow group, log problem and remove
* the shadow group from the config file.
*/
gettext("Enable failed %s %s %s (%s)"),
"independent" : "dependent");
"Enable failed, can't tidy up cfg"),
}
config_locked = 1;
}
if (rc == -1)
else
break;
default:
break;
}
}
int
{
int rc;
int wait_loc;
enum copy_wait wait_action;
int stat_flags;
static int unlocked = 0;
int do_enable = 0;
char key[CFG_MAX_KEY];
char optval[CFG_MAX_BUF];
unsigned int flags;
NULL);
}
config_locked = 1;
"group"), NULL);
config_locked = 0;
unlocked = 1;
/* set is suspended, so we do the enable processing instead */
do_enable = 1;
/* first check to see whether the set was offline */
"configuration"), NULL);
}
config_locked = 1;
unlocked = 0;
}
config_locked = 0;
unlocked = 1;
if ((flags & DSW_OFFLINE) == 0) {
/* set wasn't offline - don't reset */
NULL);
}
} else {
}
if (wait_action == WaitForStart)
case (pid_t)-1:
break;
case 0:
if (do_enable) {
} else {
}
}
/* last_overflow is set during find_shadow_config */
if (strlen(last_overflow) > 0 &&
/* reattach it */
}
exit(0);
break;
default:
if (wait_action == WaitForStart) {
} else { /* wait_action == WaitForEnd */
wait_loc = 0;
rc = 0;
else
rc = -1;
}
break;
}
/* if successful, remove flags entry from options field */
if (rc >= 0) {
"configuration"), NULL);
}
config_locked = 1;
"Copy group"), NULL);
}
< 0) {
}
config_locked = 0;
}
return (rc);
}
int
{
int rc;
"group"), NULL);
if (rc == -1) {
}
if (rc == -1)
else
return (0);
}
void
int is_compact)
{
unsigned char *bitmap;
char *name;
int i, x, y;
unsigned j;
unsigned long n;
unsigned long percent;
return;
if (bitmap_percent) {
/* count the number of bits set in bitmap */
for (i = n = 0; i < bm_size; i++)
for (j = (unsigned)bitmap[i]; j; j &= j -1)
n++;
if (is_compact)
used, n);
if (bm_actual < 100) {
percent = 0;
} else {
}
/* distinguish between 0.0000% and 0.n% of bitmap set */
if (percent < 1)
(void) printf("\t(%s)\n", n > 0 ?
}
if (print_bitmap) {
i = bm_size * 8;
x += (8 - (x % 8)); /* round up to nearest multiple of 8 */
y = i / x;
if (y * x < i)
y++;
(void) printf("#define bm%s_width %d\n#define bm%s_height %d\n",
(void) printf("#define bm%s_x_hot 0\n#define bm%s_y_hot 0\n",
for (i = 0; i < bm_size; i++) {
if (i % 12 == 0)
(void) printf("\n");
}
y = x * y;
for (; i < y; i++) {
if (i % 12 == 0)
(void) printf("\n");
(void) printf("0x00, ");
}
(void) printf("\n};\n");
}
}
static int
{
char *ptr;
/* no group set, just count volume list */
;
return (i);
}
if (group_list == NULL)
group_list->flags = 0;
if (rc < 0)
&group_list->status);
/* create hash and enter all volumes into it */
i = 0;
while (i < count) {
++i;
ptr += DSW_NAMELEN;
}
/* now compare the volume list with the hash */
for (i = 0; vol_list[ i ]; i++) {
if (!found)
NULL);
}
if (i != count)
/* everything checks out */
hdestroy();
return (count);
}
int
enum copy_direction direction)
{
int i;
int rc;
int n_vols;
char *t;
char buf[1024];
char *sp;
char *ppid;
if (acopy_args == NULL)
acopy_args->flags = 0;
if (update_mode == Update)
if (pflg) {
#ifdef DEBUG
if (ppid) {
} else {
}
#else
#endif
}
for (i = 0; i < n_vols; i++) {
"group"), NULL);
t = parms.master_vol;
} else {
t = parms.shadow_vol;
}
if (mounted(t)) {
"unmount it first"), NULL);
}
if (rc == -1) {
gettext("Shadow group %s is suspended"),
vol_list[i]);
}
gettext("Copy already in progress"));
exit(1);
}
}
for (i = 0; i < n_vols; i++) {
update_mode == Update ?
vol_list[i],
gettext("to shadow"));
}
} else {
}
if (rc == -1) {
i = acopy_args->count;
if (i < 0 || i >= n_vols) {
} else {
gettext("Atomic update of %s failed"),
}
}
return (rc);
}
int
{
int rc;
int wait_loc;
char *t;
char *volume;
char *ppid;
"group"), NULL);
config_locked = 0;
if (update_mode == Update)
t = parms.master_vol;
} else {
t = parms.shadow_vol;
}
if (pflg) {
#ifdef DEBUG
if (ppid) {
} else {
}
#else
#endif
}
if (mounted(t)) {
"unmount it first"), NULL);
}
if (rc == -1)
gettext("Copy already in progress"));
exit(1);
}
update_mode == Update ?
gettext("to shadow"));
if (wait_action == WaitForStart)
case (pid_t)-1:
NULL);
break;
case 0:
if (rc == -1) {
gettext("Fail %s %s %s"),
update_mode == Update ?
: gettext("to shadow"));
}
update_mode == Update ?
gettext("to shadow"));
exit(0);
break;
default:
if (wait_action == WaitForStart) {
} else { /* wait_action == WaitForEnd */
wait_loc = 0;
rc = 0;
else
rc = 1;
}
break;
}
return (rc);
}
void
{
int stat_flags;
static int need_sep = 0;
if (need_sep++ > 0)
(void) printf("--------------------------------------"
"----------------------------------------\n");
if (in_config) {
(void) printf("%s: %s\n",
(void) printf("%s: %s\n",
(void) printf("%s: %s\n",
}
/*
* Do special checking on the status of this volume in a Sun Cluster
*/
if (check_cluster() == II_CLUSTER) {
if (rc < 0) {
"Suspended on this node, not active elsewhere\n"));
return;
} else if (rc == 0) {
"Suspended on this node, active on %s\n"),
return;
}
}
}
}
/* Handle Not found or not in config */
/* Just suspend */
return;
}
gettext("(overflow volume)"));
conf->group_name);
conf->cluster_tag);
if (stat_flags & DSW_GOLDEN)
else
if (stat_flags & DSW_TREEMAP)
if (stat_flags & DSW_COPYINGP)
else if (stat_flags & DSW_COPYING)
if (stat_flags & DSW_COPYINGM)
if (stat_flags & DSW_COPYINGS)
if (stat_flags & DSW_COPYINGX)
if (stat_flags & DSW_MSTOFFLINE)
if (stat_flags & DSW_SHDOFFLINE)
if (stat_flags & DSW_BMPOFFLINE)
if (stat_flags & DSW_OVROFFLINE)
if (stat_flags & DSW_SHDEXPORT)
if (stat_flags & DSW_SHDIMPORT)
if (stat_flags & DSW_OVERFLOW)
if (stat_flags & DSW_VOVERFLOW)
(void) printf("\n");
if (tmp_time != 0)
else
(void) printf("%s %lld %s %lld\n",
}
}
int
abort_copy(char *volume)
{
"group"), NULL);
return (0);
}
void
{
#ifdef DEBUG
#else
} else {
}
#endif
}
void
{
/* make a hashtable */
/*NOTREACHED*/
}
}
/* populate the hashtable */
/*NOTREACHED*/
}
}
/* perform action for each line of the stored config file */
/* Are there any II sets configured on this node? */
/* Is this volume configured on this node? */
/* Handle Imported Shadows */
/* LINTED alignment of cast ok */
else
}
else
}
else
if ((cfg_cluster_tag) &&
continue;
continue;
(void) printf("%s %.*s %.*s %.*s%s\n",
}
hdestroy();
}
int
wait_for_copy(char *volume)
{
int rc;
static int unlocked = 0;
char *ppid;
NULL);
}
config_locked = 1;
"group"), NULL);
config_locked = 0;
unlocked = 1;
if (pflg) {
#ifdef DEBUG
if (ppid) {
} else {
}
#else
#endif
}
if (rc == -1)
return (0);
}
int
{
int rc;
"group"), NULL);
/* If this is an exportable shadow in the cluster, change ctag */
}
if (rc == -1)
if (perform_autosv()) {
}
}
/* restore old cluster tag, if changed */
return (0);
}
int
{
int rc;
"group"), NULL);
if (rc == 0) {
/* remove overflow from cfg line */
perror("cfg_put_cstring");
}
(void) cfg_commit(cfg);
} else {
}
return (rc);
}
static void
can_disable(char *vol)
{
"and dependent on the master volume"), NULL);
}
}
}
static void
{
char **p;
for (p = group_volumes; *p; p++) {
/* set was successfully disabled */
remove_iiset(setnumber, *p, 0);
}
}
}
int
{
int rc = 0;
char **p;
int flags = 0;
int shd_exported = 0;
if (argc != 2)
if (group_name) {
"has no members"), NULL);
for (p = group_volumes; *p; p++) {
can_disable(*p);
}
if (*group_name)
flags = CV_IS_GROUP;
} else {
"Copy group"), NULL);
}
flags = 0;
}
if (group_name && !*group_name) {
/* user typed iiadm -g "" -d */
for (p = group_volumes; *p; p++) {
remove_iiset(setnumber, *p, 0);
}
} else {
shd_exported = 1;
}
"Imported shadow not disabled"), NULL);
}
if (errno == DSW_EDISABLE) {
/*
* one or more sets within the group
* couldn't disable
*/
} else {
}
}
}
if (group_name && *group_name) {
for (p = group_volumes; *p; p++) {
/* argh! */
"in a Point-in-Time Copy group"), *p);
} else {
remove_iiset(setnumber, *p, 0);
}
}
} else if (!group_name) {
/* argh! */
"Copy group"), NULL);
}
}
return (0);
}
int
{
int rc = 0;
if (argc != 2)
if (group_name) {
"has no members"),
NULL);
for (; *group_volumes; group_volumes++)
} else {
}
return (rc);
}
void
dsw_list_clusters(char *cluster)
{
char *ptr;
if (acopy_args == NULL)
acopy_args->flags = 0;
if (cluster)
if (rc == -1)
&acopy_args->status);
if (cluster) {
cluster);
} else {
}
}
}
void
{
if (argc != 5)
exit(0);
}
void
{
exit(0);
}
void
{
char **volume_list;
if (argc != 2)
if (group_name == NULL)
volume_list = ++argv;
else {
"has no members"),
NULL);
}
}
void
{
char **volume_list;
if (argc != 2)
if (group_name == NULL)
volume_list = ++argv;
else {
"has no members"),
NULL);
}
}
void
{
char **volume_list;
if (argc != 2)
if (group_name == NULL) {
volume_list = ++argv;
} else {
" master in this group with its shadow volume?"));
"has no members"),
NULL);
}
}
void
{
char **volume_list;
if (argc != 2)
if (group_name == NULL) {
volume_list = ++argv;
} else {
" master in this group with its shadow volume?"));
"has no members"),
NULL);
}
}
void
{
}
void
{
int in_config;
/* "iiadm -i" and "iiadm -i all" are equivalent */
if (!in_config) {
"Volume is not in configuration file\n"), NULL);
}
} else if (group_name) {
"has no members"),
NULL);
for (; *group_volumes; group_volumes++) {
if (in_config)
}
} else {
/* perform action for each line of the stored config file */
for (setnumber = 1;
switch (check_cluster()) {
case II_CLUSTER:
if ((cfg_cluster_tag) &&
continue;
break;
case II_CLUSTER_LCL:
continue;
break;
}
}
}
exit(0);
}
void
{
int in_config;
if (argc != 2)
if (!in_config) {
"Volume is not in configuration file\n"), NULL);
}
exit(0);
}
/*ARGSUSED*/
void
{
iiversion();
exit(0);
}
void
{
}
void
{
if (argc != 2)
}
void
{
}
/*ARGSUSED*/
void
{
if (argc != 1)
list_volumes();
exit(0);
}
void
{
if (argc != 2)
}
void
{
exit(0);
}
void
{
dsw_config_t parms = {0};
int rc = 0;
char shd_dg[DSW_NAMELEN];
char bmp_dg[DSW_NAMELEN];
/*
* If importing a shadow volume and the shadow volume is already
* configured, we only support this if we are in a Sun Cluster
* and the current user specified a cluster tag of -C local
*/
}
switch (check_cluster()) {
case II_CLUSTER:
case II_CLUSTER_LCL:
(void) check_resource_group(shadow_volume);
if (cfg_cluster_tag) { /* check all volumes are in same dg */
== NULL)
" disk group"), NULL);
== NULL)
" disk group"), NULL);
" same disk group as shadow set members"),
NULL);
}
break;
case II_NOT_CLUSTER:
/* do nothing */
break;
default:
"Unexpected return from check_cluster()"), NULL);
}
/* Local configuration volumes */
}
if (rc == -1) {
}
if (perform_autosv()) {
< 0) {
}
/* cfg_commit is called by add_cfg_entry below */
}
}
void
{
if (argc != 3)
exit(0);
}
void
{
int rc = 0;
int size;
uchar_t *shd_bitmap = 0;
char dgname[DSW_NAMELEN];
"group"), NULL);
/* If this is an exportable shadow in the cluster, change ctag */
}
gettext("Can't open imported bitmap volume\n"));
exit(1);
}
gettext("Can't read imported bitmap volume\n"));
exit(1);
}
/* See if this is a bitmap header */
case DSW_DIRTY: /* A copy of a enable bitmap volume */
case DSW_CLEAN:
break;
case DSW_INVALID: /* A valid diskable secondary bitmap */
break;
default:
gettext("Secondary bitmap is not a valid bitmap volume\n"));
exit(1);
}
perror("malloc");
exit(1);
}
perror("fseek");
exit(1);
}
gettext("Can't read imported bitmap volume\n"));
exit(1);
}
if (rc == -1) {
}
if (perform_autosv()) {
if (rc < 0) {
}
}
}
int
params(char *shadow_volume)
{
char *delay = param_delay;
char *unit = param_unit;
int rc = 0;
int get = 0;
int new_delay;
int new_unit;
get = 1;
} else {
}
if (rc == -1) {
gettext("Parameter ranges are delay(%d - %d), "
}
if (!get)
else
return (0);
}
static void
{
int rc;
int check = 0;
if (rc == -1) {
check = 1;
/* if overflow() fails, it calls dsw_error to exit */
}
if (check == 1) {
gettext("Volume is not in a Point-in-Time Copy "
"group"), NULL);
}
}
}
int
attach(char *shadow_volume)
{
char shd_dg[DSW_NAMELEN];
char ovr_dg[DSW_NAMELEN];
switch (check_cluster()) {
case II_CLUSTER:
case II_CLUSTER_LCL:
(void) check_resource_group(shadow_volume);
if (cfg_cluster_tag) { /* check all volumes are in same dg */
== NULL)
" disk group"), NULL);
== NULL)
" disk group"), NULL);
" same disk group as shadow set members"),
NULL);
}
break;
case II_NOT_CLUSTER:
/* do nothing */
break;
default:
"Unexpected return from check_cluster()"), NULL);
}
/* assure that the overflow_file is not an II volume */
"Overflow volume is already in a Point-in-Time Copy "
"group"), NULL);
/* use find_shadow_config() to find setnumber */
"group"), NULL);
/* can only attach an overflow volume to dependent, compact shadow */
/* bitmap_vol is overloaded */
/* add overflow to cfg line */
strlen(overflow_file)) < 0) {
perror("cfg_put_cstring");
}
(void) cfg_commit(cfg);
return (0);
}
void
{
if (argc != 3)
exit(0);
}
void
{
if (argc == 4) {
}
}
}
/*ARGSUSED*/
void
{
exit(0);
}
/*ARGSUSED*/
void
{
int count, i;
/* count entries */
count = 0;
++count;
}
/* create hash (adding room for suspended overflow volumes) */
/*NOTREACHED*/
}
if (count > 0) {
/* create memory to store copy of list */
if (!vol) {
gettext("Out of memory creating lookup table"),
NULL);
/*NOTREACHED*/
}
/* fill hash */
/* make copy of string */
}
}
/* loop through config file entries */
i = 0;
/*CONSTCOND*/
while (1) {
++i;
break;
}
/* has this set got an overflow volume? */
if (!*buf) {
continue;
}
/* look up overflow in hash */
}
} else {
/* must be part of a suspended set */
}
}
exit(0);
}
void
{
int stat_flags;
if (argc != 2)
if (stat_flags & IIO_CNTR_INVLD)
"sets associated with overflow volume "
"did not occur.\n"
"Overflow counters will be inconsistent "
"until new point-in-time(s) are taken.\n"));
}
exit(0);
}
/*ARGSUSED*/
void
{
int waserr = 0;
/* handle move to NULL group, or group of all spaces or tabs */
group_name = "-";
} else {
/* get the ctag for this group (if any) */
}
"Copy group"), NULL);
/* ensure the ctag matches the group */
DSW_NAMELEN) != 0) {
gettext("into new group - cluster "
"resource mismatch"));
waserr = 1;
continue;
}
}
/* move the set in the kernel */
NULL);
/* now update the config */
strlen(group_name)) < 0) {
perror("cfg_put_cstring");
}
(void) cfg_commit(cfg);
}
}
void
{
}
break;
/* skip if shadow set is not in any group */
continue;
}
}
void
{
NULL);
}
for (; *group_volumes; group_volumes++)
}
static void
{
static int whinged = 0;
if (volhash) {
return;
}
volhash = nsc_create_hash();
/* grab master volume name */
if (!mst) {
break;
}
/* grab shadow, group & cnode fields */
/* Fix optional tags */
if (ctag)
if (group)
/* If cluster tags don't match, skip record */
continue;
}
/* master volume, may be duplicates */
if (mdata) {
} else {
}
/* grab shadow volume name */
/* No need to continue if no groups or ctags */
continue;
}
if (gdata) {
/* group already exists - check ctag */
if (*ctag &&
if (!whinged) {
"cluster resource groups "
"defined within a single "
"I/O group\n"));
whinged = 1;
}
}
} else {
}
}
/* free up any leftovers */
if (entries)
}
static void
{
volhash = 0;
}
static int
{
static int result;
static int calculated = 0;
int rc;
#ifdef DEBUG
if (getenv("II_SET_CLUSTER"))
return (1);
#endif
if (calculated) {
return (result);
}
/*
* we only perform auto-sv if we're in a sun cluster or if
* we're on a standalone system. I.e. we don't do auto-sv on Harry
*/
rc = check_cluster();
if (II_NOT_CLUSTER == rc) {
result = 1;
} else {
result = cfg_issuncluster();
}
calculated = 1;
return (result);
}
/*
* Returns true if set has had the shadow volume exported.
* Returns false if shadow volume is not exported, or set is suspended.
*/
static int
is_exported(char *set)
{
int rc;
if (-1 == rc) {
/* set must be suspended, or being disabled */
return (0);
}
}
static void
conform_name(char **path)
{
char *cfgname;
if (rc < 0) {
}
if (rc) {
" name?"));
/*
* NOTE: *path ought to be deallocated ('free(*path)') after
* we're done with it, but since this routine is called just
* before we exit, it doesn't really matter
*/
}
}
/*
* verify_groupname(char *, int);
*
* Check the group name for the following rules:
* 1. The name does not start with a '-'
* 2. The name does not contain any space characters as defined by
* isspace(3C).
* If either of these rules are broken, error immediately. The check for a
* leading dash can be skipped if the 'testDash' argument is false. This is to
* allow for the '-g -L' functionality.
*
*/
static void
{
int i;
}
for (i = 0; grp[i] != '\0'; i++) {
NULL);
}
}
}
void
check_iishadow(char *shadow_vol) {
int i;
int entries;
char **entry;
char *shost;
char *svol;
char *buf;
void *librdc;
/*
* See if librdc is around
* If not, we can just return
*/
else {
return;
}
for (i = 0; i < entries; i++) {
if (entries)
"shadow volume is in use as SNDR secondary volume"),
NULL);
}
}
if (entries)
}