/*
* 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 <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <stdio.h>
#include <locale.h>
#include <unistd.h>
#include <search.h>
#include <libgen.h>
#include <nsctl.h>
static int sv_max_devices;
/*
* support for the special cluster tag "local" to be used with -C in a
* cluster for local volumes.
*/
static int sv_islocal;
/*
* libcfg access.
*/
/*
* Print width for print_sv() output.
*/
/*
* Pathnames.
*/
/*
* Functions.
*/
static int enable_dev(sv_name_t *);
static int disable_dev(const caddr_t);
static void create_cfg_hash();
static int find_in_hash(char *path);
static void destroy_hashtable();
static void
{
return;
/* NOTREACHED */
}
if (cfg_cluster_tag && *cfg_cluster_tag) {
} else {
}
/* NOTREACHED */
}
}
static void
sv_cfg_close(void)
{
return;
if (cfg_changed) {
(void) cfg_commit(cfg);
cfg_changed = 0;
}
}
static void
usage(void)
{
"\t%s -h help\n"), program);
"\t%s [-C tag] display status\n"),
program);
"\t%s [-C tag] -i display "
"extended status\n"), program);
"\t%s [-C tag] -v display "
"version number\n"), program);
"\t%s [-C tag] -e { -f file | volume } enable\n"), program);
"\t%s [-C tag] -d { -f file | volume } disable\n"), program);
"\t%s [-C tag] -r { -f file | volume } reconfigure\n"), program);
sv_cfg_close();
}
static void
{
if (status) {
}
}
static void
{
sv_cfg_close();
exit(1);
}
static void
{
}
static void
sv_get_maxdevs(void)
{
int fd;
if (sv_max_devices > 0)
return;
if (fd < 0)
}
}
static sv_name_t *
sv_alloc_svnames(void)
{
sv_max_devices * sizeof (*svn));
}
return (svn);
}
static void
{
char *othernode;
int rc;
/*
* check where this disk service is mastered
*/
if (rc < 0) {
}
if (rc == 0) {
"active on node \"%s\"\nPlease re-issue "
}
}
/*
* Carry out cluster based checks for a specified volume, or just
* global options.
*/
static void
{
/*
* Find out if we are running in a cluster
*/
if (sv_iscluster == -1) {
if ((sv_iscluster = cfg_iscluster()) < 0) {
}
}
}
return;
}
/*
* Cluster-only checks on pathname
*/
"disk group name for %s"), path);
return;
}
if (cfg_cluster_tag != NULL) {
/*
* Do dgislocal check now in case path did not contain
* a dgname.
*
*/
}
return; /* NULL dgname is valid */
if (cfg_cluster_tag == NULL) {
/*
* Implicitly set the cluster tag to dgname
*/
if (implicit_tag) {
implicit_tag = NULL;
}
if (implicit_tag == NULL) {
gettext("unable to allocate memory "
"for cluster tag"));
}
} else {
/*
* Check dgname and cluster tag from -C are the same.
*/
gettext("-C (%s) does not match disk group "
"name (%s) for %s"), cfg_cluster_tag,
}
/*
* sv_check_dgislocal(cfg_cluster_tag) was called above.
*/
}
}
static void
print_version(void)
{
int fd;
if (fd < 0) {
return;
}
gettext("unable to read the version number"));
/* NOTREACHED */
}
#ifdef DEBUG
#else
if (svv.svv_micro_rev) {
} else {
}
#endif
}
int
{
extern int optind;
extern char *optarg;
int rc;
(void) textdomain("svadm");
print = 1;
switch (opt) {
case 'C':
if (Cflag) {
gettext("-C specified multiple times"));
usage();
exit(2);
/* NOTREACHED */
}
Cflag++;
break;
case 'e':
print = 0;
enable++;
break;
case 'd':
print = 0;
disable++;
break;
case 'f':
fflag++;
break;
case 'i':
iflag++;
break;
case 'r':
/* Compare running system with sv.cf */
print = 0;
compare++;
break;
case 'v':
print = 0;
version++;
break;
case 'h':
usage();
exit(0);
default:
usage();
exit(2);
/* NOTREACHED */
}
}
/*
* Usage checks
*/
usage();
exit(2);
}
usage();
exit(2);
}
usage();
exit(2);
}
/* check for no more args */
usage();
exit(2);
}
} else {
/* check for inline args */
usage();
exit(2);
}
}
usage();
exit(2);
}
/*
* Check for the special cluster tag and convert into the
* internal representation.
*/
if (cfg_cluster_tag != NULL &&
cfg_cluster_tag = "-";
sv_islocal = 1;
}
/*
* Process commands
*/
/* deal with inline volume argument */
rc = 0;
if (enable)
else if (disable)
else /* if (compare) */
if (rc != 0)
return (1);
return (0);
}
rc = 0;
if (enable)
else if (disable)
else if (compare)
else if (print)
else /* if (version) */
if (rc != 0)
return (1);
return (0);
}
/* LINT - not static as fwcadm uses it */
static int
{
int index;
int cnt;
svn = sv_alloc_svnames();
/*
* Check for more data.
*/
/*
* This was set when reading sv.conf. After the last
* line svn_path was set to \0, so we are finished.
* We shouldn't get here, but put this in just in
* case.
*/
break;
}
}
sv_cfg_close();
return (ret);
}
/* LINT - not static as fwcadm uses it */
static int
{
int rc;
/* force NULL termination */
sv_cfg_close();
return (rc);
}
static int
{
int fd;
int sev;
int rc;
char *lcltag;
char *altname;
return (1);
}
return (1);
}
if (fd < 0) {
return (1);
}
/* first, check for duplicates */
if (rc < 0) {
return (1);
}
if (rc) {
"'%s'. Re-enter command with the latter name."),
}
/* secondly, try to insert it into the dsvol config */
if (implicit_tag && *implicit_tag) {
} else if (cfg_cluster_tag && *cfg_cluster_tag) {
} else {
lcltag = "-";
}
if (CFG_USER_ERR == rc) {
gettext("%s: unable to put %s into dsvol cfg"),
return (1);
}
cfg_changed = 1;
if (CFG_USER_OK == rc) {
/* success */
return (0);
}
/* it's ok -- we were just double-checking */
return (0);
}
gettext("%s: unable to enable %s"),
/* remove it from dsvol, if we're the ones who put it in */
if (CFG_USER_FIRST == rc) {
}
return (1);
}
if (implicit_tag != NULL) {
#ifdef DEBUG
if (cfg_cluster_tag != NULL) {
gettext("enable_dev: -C %s AND implicit_tag %s!"),
}
#endif
} else {
}
rc = 0;
gettext("unable to add %s to configuration storage: %s"),
rc = 1;
}
cfg_changed = 1;
return (rc);
}
/*
* This routine parses the config file passed in via conf_file and
* stores the data in the svn array. The return value is the number
* of entries read from conf_file. If an error occurs the error()
* routine is called (which exits the program).
*/
static int
{
int lineno;
int cnt, i;
}
}
lineno = 0;
lineno++;
if (i < 1)
continue;
else if (i == (sizeof (line) - 1)) {
"line %d: line too long -- should be less than %d characters"),
}
/*
* check for comment line.
*/
if (line[0] == '#')
continue;
if (cnt > 0) {
lineno);
}
continue;
}
"line %d: raw device name (%s) longer than %d characters"),
continue;
}
index++;
}
/* Set the last path to NULL */
return (index);
}
/*
* Disable the device from the kernel configuration.
*
* RETURN:
* 0 on success
* non-zero on failure.
*
* Failures are reported to the user.
*/
static int
{
int fd;
} else {
}
return (-1);
}
/*
* Issue the ioctl to attempt to disable this device. Note that all
* the libdscfg details are handled elsewhere.
*/
if (errno != SV_EDISABLED) {
gettext("%s: unable to disable %s"),
return (-1);
}
}
return (0);
}
static void
{
if (*buf != '\0') {
} else {
}
}
}
/* LINT - not static as fwcadm uses it */
static void
{
int fd, i;
int setnumber;
return;
}
/* Grab the system list from the driver */
}
/*
* We build a hashmap out of the entries from the config file to make
* searching faster. We end up taking a performance hit when the # of
* volumes is small, but for larger configurations it's a
* HUGE improvement.
*/
/* build the hashtable */
/*
* For each volume found from the kernel, print out
* info about it from the kernel.
*/
for (i = 0; i < svl_system.svl_count; i++) {
break;
}
svn = &svn_system[i];
#ifdef DEBUG
#endif
continue;
}
/* get sv entry from the hashtable */
if (verbose) {
}
(void) printf("\n");
} else {
/*
* We didn't find the entry in the hashtable. Let
* the user know that the persistent storage is
* inconsistent with the kernel configuration.
*/
if (cfg_cluster_tag == NULL)
"%s is configured, but not in the "
}
}
/* free up the hashtable */
sv_cfg_close();
}
/* LINT - not static as fwcadm uses it */
static int
{
return (1);
}
/* Grab the system list from the driver */
gettext("unable to get list"));
}
} else {
}
for (i = 0; i < svl_system.svl_count; i++) {
break;
svn = &svn_system[i];
rc = 0;
}
} else {
/* warn the user that we didn't find it in cfg file */
"%s was not found in the config storage"),
/* try to disable anyway */
rc = 1;
}
sv_cfg_close();
}
return (ret);
}
/* LINT - not static as fwcadm uses it */
static int
{
int setnumber;
int rc;
/* remove from kernel */
/* remove the cfgline */
}
} else {
/* warn the user that we didn't find it in cfg file */
/* still attempt to remove */
(void) disable_dev(path);
rc = 1;
}
sv_cfg_close();
return (rc);
}
static void
{
char *tag;
#ifdef DEBUG
}
#endif
if (cfg_cluster_tag != NULL)
else if (implicit_tag != NULL)
tag = implicit_tag;
else
tag = "-";
found = 0;
for (i = 0; i < sv_max_devices; i++) {
setnumber = i + 1;
break;
}
continue;
}
found = 1;
break;
}
}
if (!found) {
path);
return;
}
/* have name match, compare cnode to new tag */
/* cluster tags match */
return;
}
/* need to change the cluster tag */
return;
}
cfg_changed = 1;
/* change "-" tags to "" for display purposes */
tag = "";
(void) printf(
gettext("%s: changed cluster tag for %s from \"%s\" to \"%s\"\n"),
gettext("%s: changed cluster tag for %s from \"%s\" to \"%s\""),
}
/* LINT - not static as fwcadm uses it */
static void
{
int config_cnt;
int sys_cnt = 0;
int setnumber, i, j;
int found;
int fd0;
enable = sv_alloc_svnames();
/*
* Read the configuration file
* The return value is the number of entries
*/
/* Grab the system list from the driver */
}
/*
* Count the number of devices in the system.
* The last entry in the array has '\0' for a path name.
*/
for (j = 0; j < sv_max_devices; j++) {
sys_cnt++;
} else {
break;
}
}
/*
* Compare the configuration array with the system array.
* Mark any differences and disable conflicting devices.
*/
for (i = 0; i < config_cnt; i++) {
found = 0;
for (j = 0; j < sys_cnt; j++) {
svn_system[j].svn_mode == 0)
continue;
/* Check to see if path matches */
svn_config[i].svn_path) == 0) {
/* Found a match */
found++;
break;
}
}
if (!found) {
/* Minor number not in system = > enable device */
svn_config[i].svn_path);
index++;
}
}
/* Disable any devices that weren't in the config file */
for (j = 0; j < sys_cnt; j++) {
svn_system[j].svn_mode != 0) {
if (setnumber != -1) {
/* the volume was found in cfg store */
}
}
}
sv_cfg_close();
}
while (index) {
/*
* Config file doesn't match system => enable the devices
* in enable[]
*/
index--;
}
/*
* Search for entries where the cluster tag has changed.
*/
for (i = 0; i < sv_max_devices; i++) {
break;
}
sv_cfg_close();
}
/*
* We assume that the volume is already enabled and we can only
* be changing the cluster tag. Anything else is an error.
*/
/* LINT - not static as fwcadm uses it */
static void
{
sv_cfg_close();
}
/*
* Read all sets from the libdscfg configuration file, and store everything in
* the hashfile.
*
* We assume that the config file has been opened & rewound for us. We store
* the volume name as the key, and the setnumber where we found it as the data.
*
* The caller can pass in a pointer to the maximum number of volumes, or
* a pointer to NULL, specifying we want 'all' the volumes. The table is
* searched using find_in_hash.
*/
static void
{
int setnumber;
break;
continue;
}
gettext("unable to add entry to hash table"));
}
}
}
/*
* Function to search the hash for a specific volume. If it is found,
* we return the set number. If it isn't found, we return -1
*/
static int
{
}
return (retval);
}
/*
* Just a wrapper to destory the hashtable. At some point in the future we
* might want to do something more.... For instance, verify that the cfg
* database and the kernel configuration match (?) Just an idea.
*/
static void
{
hdestroy();
}
/*
* This function will remove a particular set from the config file.
*
* We make a whole host of assumptions:
* o the hashfile is up to date;
* o The config file has been opened with a WRLOCK for us.
*/
static void
{
int sev;
char *lcltag;
/* attempt to remove the volume from config storage */
} else {
if (implicit_tag && *implicit_tag) {
} else if (cfg_cluster_tag && *cfg_cluster_tag) {
} else {
lcltag = "-";
}
path);
}
cfg_changed = 1;
}
}