/*
* 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 <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <locale.h>
#include <errno.h>
#define DO_DISABLE 0
/*
*/
typedef struct hash_data_s {
union {
char *users;
char *mode;
} u;
char *path;
char *node;
int setno;
} hash_data_t;
typedef struct {
char *path;
} device_t;
static hash_data_t *make_svol_data(char *, char *, char *, int);
static hash_data_t *make_dsvol_data(char *, char *, char *, int);
static void delete_svol_data(void *);
static void delete_dsvol_data(void *);
static int add_dev_entry(const char *);
static int compare(const void *, const void *);
static char *find_devid(const char *);
static void free_dev_entries();
static void rebuild_devhash();
static int dsvol_loaded = 0;
static int svol_loaded = 0;
static int devcount = 0;
static int devalloc = 0;
/*
* cfg_add_user
*
* Description:
* Adds the calling tool as a user of the volume.
*
* Inputs:
* char *path: The pathname of the volume to be enabled.
* char *cnode: The device group name, or NULL if -C local or not cluster
* CFGFILE *cfg: A pointer to the current config file, or NULL if this
*
* Return values:
* CFG_USER_FIRST: Indicates that this is the first user of this
* particular volume.
* CFG_USER_OK: Indicates that the volume has already been entered into
* the config file.
* CFG_USER_ERR: Indicates that some failure has occurred and no changes
* to the config file have been made.
* CFG_USER_REPEAT: Indicates that this user has already registered for
* the volume.
*/
int
{
self_loaded = 0;
change_made = 0;
if (self_open) {
return (CFG_USER_ERR);
}
/* oops */
return (CFG_USER_ERR);
}
}
/* Check cnode */
if (cnode) {
if (ctag) {
return (CFG_USER_ERR);
} else
} else
if (!dsvol_loaded) {
if (cfg_load_dsvols(cfg) < 0) {
if (self_open) {
}
return (CFG_USER_ERR);
}
self_loaded = 1;
}
/* find the volume */
if (!data) {
/* whoops, not found. Add as new user */
user);
if (rc < 0) {
if (self_loaded) {
}
if (self_open) {
}
return (CFG_USER_ERR);
}
/* reload hash, if we need to */
if (!self_loaded) {
if (cfg_load_dsvols(cfg) < 0) {
if (self_open) {
}
return (CFG_USER_ERR);
}
}
change_made = 1;
} else {
/* Check to ensure we're not already listed */
char *q = strtok(p, ",");
q = strtok(0, ",");
}
free(p); /* not using data; only testing 'q' ptr */
if (!q) {
/* not listed as a user */
if (self_loaded) {
}
if (self_open) {
}
return (CFG_USER_ERR);
}
/*
* Since we deleted an entry from the config
* file, we don't know what all the new
* set numbers are. We need to reload
* everything
*/
if (!self_loaded) {
if (cfg_load_dsvols(cfg) < 0) {
if (self_open) {
}
return (CFG_USER_ERR);
}
}
change_made = 1;
} else {
}
}
if (self_loaded) {
}
if (self_open) {
if (change_made)
(void) cfg_commit(cfg);
}
return (retval);
}
/*
* cfg_rem_user
*
* Description:
* Removes a user from the config file.
*
* Inputs:
* char *path: The pathname of the volume to be enabled.
* char *cnode: The device group name, or NULL if -C local or not cluster
* char *user: The subsystem that is adding this tag (sv, ii, sndr)
* CFGFILE *cfg: A pointer to the current config file, or NULL if this
* Return values:
* CFG_USER_ERR: An error occurred during the processing of this
* directive.
* CFG_USER_OK: User successfully removed; volume in use by other(s).
* CFG_USER_LAST: User successfuly removed; no other users registered
* CFG_USER_GONE: The volume is no longer listed in the dsvol section,
* indicating some sort of application-level error.
*
*/
int
{
int retval;
int force_remove;
self_loaded = 0;
change_made = 0;
if ('-' == *user) {
++user;
}
/* Check cnode */
if (cnode) {
if (ctag) {
return (CFG_USER_ERR);
} else
} else
if (self_open) {
return (CFG_USER_ERR);
}
/* oops */
return (CFG_USER_ERR);
}
}
change_made = 0;
if (!dsvol_loaded) {
if (cfg_load_dsvols(cfg) < 0) {
if (self_open) {
}
return (CFG_USER_ERR);
}
self_loaded = 1;
}
/* find the volume */
if (!data) {
/* yipes */
} else if (force_remove) {
if (self_loaded) {
}
if (self_open) {
}
return (CFG_USER_ERR);
}
if (!self_loaded) {
if (cfg_load_dsvols(cfg) < 0) {
if (self_open) {
}
return (CFG_USER_ERR);
}
}
} else {
char *q = strtok(p, ",");
int appended = 0;
if (appended) {
} else {
appended = 1;
}
q = strtok(0, ",");
}
if (!q) {
/* uh-oh */
} else {
/* old user skipped; add in remaining users */
while (q = strtok(0, ", ")) {
if (appended) {
} else {
appended = 1;
}
}
if (appended) {
if (self_loaded) {
}
if (self_open) {
}
return (CFG_USER_ERR);
}
if (!self_loaded) {
if (cfg_load_dsvols(cfg) < 0) {
if (self_open) {
}
return (CFG_USER_ERR);
}
}
} else {
0) < 0) {
if (self_loaded) {
}
if (self_open) {
}
return (CFG_USER_ERR);
}
/*
* Since we deleted an entry from the config
* file, we don't know what all the new
* set numbers are. We need to reload
* everything
*/
if (!self_loaded) {
if (cfg_load_dsvols(cfg) < 0) {
if (self_open) {
}
return (CFG_USER_ERR);
}
}
}
change_made = 1;
}
}
if (self_loaded) {
}
if (self_open) {
if (change_made)
(void) cfg_commit(cfg);
}
return (retval);
}
/*
* Enable a volume under SV control (or add this char *user to the list
* of users of that volume).
*
* Parameters:
* cfg - The config file to use.
* path - The pathname of the volume
* ctag - The cluster tag for this volume (if any)
* user - The user (sv, ii, sndr) of the volume.
*/
int
{
int rc;
int retval;
ctag = "-";
}
retval = -1;
switch (rc) {
case CFG_USER_ERR:
gettext("unable to set up dsvol section of config for %s"),
path);
break;
case CFG_USER_OK:
retval = 0;
break;
case CFG_USER_FIRST:
/* enable sv! */
if (retval < 0) {
}
break;
default:
break;
}
return (retval);
}
/*
* Disable a volume from SV control (or remove this char *user from the list
* of users of that volume).
*
* Parameters:
* cfg - The config file to use.
* path - The pathname of the volume
* ctag - The cluster tag for this volume (if any)
* user - The user (sv, ii, sndr) of the volume.
*/
int
{
int rc;
int retval;
ctag = "-";
}
retval = -1;
switch (rc) {
case CFG_USER_ERR:
gettext("unable to set up dsvol section of config for %s"),
path);
break;
case CFG_USER_OK:
retval = 0;
break;
case CFG_USER_GONE:
gettext("%s tried to remove non-existent tag for %s"),
break;
case CFG_USER_LAST:
/* diable sv! */
break;
default:
break;
}
return (retval);
}
/*
* cfg_load_dsvols
*
* Description:
* Loads the dsvol section of the config file into a giant hash, to
* make searching faster. The important bit to remember is to not
* release the write lock between calling cfg_load_dsvols() and the
* cfg_*_user() functions.
*
* Assumptions:
* 1/ cfg file is open
* 2/ cfg file has been write-locked
*
* Return value:
* -1 if error, or total number of sets found
*/
int
{
char *buf;
int devs_added = 0;
int offset = 0;
ctag = "-";
}
dsvol = nsc_create_hash();
if (!dsvol) {
return (-1);
}
rc = 0;
/* split up the line */
/* oops, now what? */
break;
}
break;
}
++offset;
continue;
}
break;
}
if (!data) {
break;
}
if (rc < 0) {
break;
}
/* we also need to keep track of node information */
if (rc < 0) {
break;
} else if (rc)
++devs_added;
rc = 0;
}
if (entries)
if (devs_added) {
}
dsvol_loaded = 1;
}
/*
* cfg_unload_dsvols
*
* Description:
* Free all memory allocated with cfg_load_dsvols.
*/
void
{
if (dsvol) {
dsvol = 0;
dsvol_loaded = 0;
}
}
/*
* cfg_load_svols
*
* Description:
* Loads the sv section of the config file into a giant hash, to make
* searching faster. The important bit to remember is to not release
* the write lock between calling cfg_load_svols() and the cfg_*_user()
* functions.
*
* Assumptions:
* 1/ cfg file is open
* 2/ cfg file has been write-locked
*/
int
{
ctag = "-";
}
svol = nsc_create_hash();
if (!svol) {
return (-1);
}
/* split up the line */
break;
}
break;
}
cnode = "";
}
++offset;
continue;
}
if (!data) {
break;
}
break;
}
}
if (entries)
svol_loaded = 1;
return (0);
}
/*
* cfg_unload_svols
*
* Description:
* Frees all memory allocated with cfg_load_dsvols
*/
void
{
if (svol) {
svol = 0;
svol_loaded = 0;
}
}
/*
* cfg_get_canonical_name
*
* Description:
* Find out whether a device is already known by another name in
* the config file.
*
* Parameters:
* cfg - The config file to use
* path - The pathname of the device
* result - (output) The name it is otherwise known as. This parameter
* must be freed by the caller.
*
* Return values:
* -1: error
* 0: name is as expected, or is not known
* 1: Name is known by different name (stored in 'result')
*/
int
{
int self_loaded;
char *alt_path;
int retval;
if (devlist) {
self_loaded = 0;
} else {
if (cfg_load_shadows(cfg) < 0) {
return (-1);
}
self_loaded = 1;
}
/* see if it exists under a different name */
retval = 0;
} else {
/* a-ha */
retval = 1;
}
if (self_loaded) {
}
return (retval);
}
/*
* cfg_load_shadows
*
* Description:
* Load in shadow and bitmap volumes from the II section of the
* config file. SNDR's volumes are handled already by cfg_load_dsvols.
* Not all shadow volumes are listed under dsvol: they can be exported.
*
* Parameters:
* cfg - The config file to use
*
* Return values:
* -1: error
* 0: success
*/
int
{
int devs_added = 0;
if (dsvol_loaded) {
self_loaded = 0;
} else {
if (cfg_load_dsvols(cfg) < 0) {
return (-1);
}
self_loaded = 1;
}
shadowvol = nsc_create_hash();
if (!shadowvol) {
return (-1);
}
rc = 0;
/* skip the master vol */
/* shadow is next */
if (rc < 0) {
break;
} else if (rc)
++devs_added;
/* and next is bitmap */
if (rc < 0) {
break;
} else if (rc)
++devs_added;
rc = 0;
}
if (entries)
if (self_loaded) {
}
if (devs_added) {
/* sort it, in preparation for lookups */
}
return (rc);
}
void
{
/* do nothing */
}
/* ---------------------------------------------------------------------- */
static hash_data_t *
{
if (!data) {
return (0);
}
return (data);
}
static void
{
free(p);
}
static hash_data_t *
{
if (!data) {
return (0);
}
return (data);
}
static void
{
free(p);
}
static int
{
int cfg_changed = 0;
int print_log = 0;
if (caller_cfg == NULL) {
return (-1);
if (ctag)
} else
cfg = caller_cfg;
self_loaded = 0;
gettext("unable to disable %s"));
if (devhash)
if (statinfo) {
goto error;
} else {
goto error;
goto error;
}
if (fd < 0)
goto error;
do {
if (rc < 0) {
if (enable)
goto error;
else
} else
}
/* SV enable succeeded */
goto error;
if (enable) {
/* SV config not updated, so SV disable again */
print_log++;
} else
cfg_changed = 1;
} else {
/* pull it out of the config */
if (!svol_loaded) {
if (cfg_load_svols(cfg) < 0) {
if (NULL == caller_cfg) {
}
return (-1);
}
self_loaded = 1;
}
if (node) {
gettext("failed to remove %s from "
}
/*
* Since we deleted an entry from the config
* file, we don't know what all the new
* set numbers are. We need to reload
* everything
*/
if (!self_loaded) {
if (cfg_load_svols(cfg) < 0) {
if (NULL == caller_cfg) {
}
return (-1);
}
}
cfg_changed = 1;
}
if (self_loaded) {
self_loaded = 0;
}
}
}
#ifdef lint
#endif
if (fd >= 0)
return (-1);
if (cfg_changed)
(void) cfg_commit(cfg);
if (caller_cfg == NULL)
return (1);
if (print_log)
gettext("unable to add to configuration, disabled %s"),
return (-1);
}
/*
* add_dev_entry
*
* Add an entry into the devlist and the devhash for future lookups.
*
* Return values:
* -1 An error occurred.
* 0 Entry added
* 1 Entry already exists.
*/
static int
{
if (!devhash) {
devhash = nsc_create_hash();
if (!devhash) {
return (-1);
}
} else {
if (data) {
return (1);
}
}
/* ignore error, we are most likely deleting entry anyway */
}
/* make some room */
devalloc += DEV_EXPAND;
sizeof (device_t));
if (!newmem) {
return (-1);
} else {
}
}
return (-1);
}
++devcount;
return (0);
}
static void
{
int i;
if (!devhash)
nsc_remove_all(devhash, 0);
devhash = nsc_create_hash();
if (!devhash)
return;
for (i = 0; i < devcount; i++) {
}
}
static int
{
}
static char *
{
return (NULL);
/* See if we already know the device id by this name */
if (result) {
return (NULL);
}
/* try to find it by another name */
return (NULL);
/* it's storted, so we use the binary-chop method to find it */
if (result) {
}
return (NULL);
}
static void
{
int i;
device_t *p;
if (!devlist) {
return;
}
}
devcount = 0;
devalloc = 0;
if (devhash) {
nsc_remove_all(devhash, 0);
}
}