mgmt_lib.c revision cee0fb94c0d4227de0a00efc162fb2739844b641
/*
* 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 <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/nvpair.h>
#include "mms_mgmt.h"
#include "mgmt_acsls.h"
#include "mmp_defs.h"
#include "mgmt_library.h"
#include "mgmt_sym.h"
#include "mgmt_util.h"
static char *_SrcFile = __FILE__;
#define HERE _SrcFile, __LINE__
/*
* Cannot set to online during create
* {O_ONLINE, "LibraryOnline", "true", B_FALSE, val_truefalse},
*/
static mms_mgmt_setopt_t libopts[] = {
{O_NAME, "LibraryName", NULL, B_TRUE, NULL},
{O_TYPE, "LibraryType", NULL, B_TRUE, NULL},
{O_ACSHOST, "LibraryIP", NULL, B_TRUE, NULL},
{O_ACSPORT, "LibraryACSLSPort", "50004", B_TRUE, val_numonly},
{O_ACSNUM, "LibraryACS", NULL, B_TRUE, val_numonly},
{O_LSMNUM, "LibraryLSM", NULL, B_TRUE, val_numonly},
{O_LIBCONN, "LibraryConnection", "network", B_TRUE, NULL},
{O_SERIALNO, "LibrarySerialNum", NULL, B_TRUE, NULL},
{O_ACSPORT, NULL, NULL, B_FALSE, val_numonly},
{NULL, NULL, NULL, B_FALSE, NULL}
};
#define LIBOPT_COUNT sizeof (libopts) / sizeof (mms_mgmt_setopt_t)
static mms_mgmt_setopt_t lmopts[] = {
{O_LMNAME, "LMName", NULL, B_TRUE, NULL},
{O_NAME, "LibraryName", NULL, B_TRUE, NULL},
{O_DEVCONN, "LMTargetHost", NULL, B_TRUE, NULL},
{O_MSGLEVEL, "LMMessageLevel", "error", B_FALSE, val_level},
{O_TRACELEVEL, "TraceLevel", "debug", B_FALSE, val_level},
{O_TRACESZ, "TraceFileSize", "10M", B_FALSE, val_mms_size},
{O_OBJSTATE, "LMDisabled", "false", B_FALSE, val_truefalse},
{NULL, NULL, NULL, B_FALSE, NULL}
};
#define LMOPT_COUNT sizeof (lmopts) / sizeof (mms_mgmt_setopt_t)
/*
* Cannot set to online during create
* {O_ONLINE, "DriveOnline", "true", B_FALSE, val_truefalse},
*/
static mms_mgmt_setopt_t driveopts[] = {
{O_NAME, "DriveName", NULL, B_TRUE, NULL},
{O_TYPE, "DriveType", NULL, B_TRUE, NULL},
{O_SERIALNO, "DriveSerialNum", NULL, B_TRUE, NULL},
{O_MMSLIB, "LibraryName", NULL, B_TRUE, NULL},
{O_DGNAME, "DriveGroupName", NULL, B_TRUE, NULL},
{O_RESERVE, "ReserveDrive", "yes", B_FALSE, val_yesno},
{NULL, NULL, NULL, B_FALSE, NULL}
};
#define DRVOPT_COUNT sizeof (driveopts) / sizeof (mms_mgmt_setopt_t)
/*
* Note that O_DEVCONN (string array) is required for DM. Add a DM
* for each host specified in the array.
*/
static mms_mgmt_setopt_t dmopts[] = {
{O_DMNAME, "DMName", NULL, B_TRUE, NULL},
{O_NAME, "DriveName", NULL, B_TRUE, NULL},
{O_DEVCONN, "DMTargetHost", NULL, B_TRUE, NULL},
{O_MSGLEVEL, "DMMessageLevel", "error", B_FALSE, val_level},
{O_TRACELEVEL, "TraceLevel", "debug", B_FALSE, val_level},
{O_TRACESZ, "TraceFileSize", "10M", B_FALSE, val_mms_size},
{O_DISABLED, "DMDisabled", "false", B_FALSE, val_truefalse},
{NULL, NULL, NULL, B_FALSE, NULL}
};
#define DMOPT_COUNT sizeof (dmopts) / sizeof (mms_mgmt_setopt_t)
static mms_mgmt_setopt_t drvgrpopts[] = {
{O_DGNAME, "DriveGroupName", NULL, B_TRUE, NULL},
{O_UNLOADTM, "DriveGroupUnloadTime", "60", B_FALSE, NULL},
{NULL, NULL, NULL, B_FALSE, NULL}
};
#define DGOPT_COUNT sizeof (drvgrpopts) / sizeof (mms_mgmt_setopt_t)
/*
* Note that O_APPS (string array) is required for DriveGroupApplication.
* Add a DGA for each application specified in the array.
* {O_APPS, "ApplicationName", NULL, B_FALSE, NULL},
*/
static mms_mgmt_setopt_t drvgrpappopts[] = {
{O_DGNAME, "DriveGroupName", NULL, B_TRUE, NULL},
{O_APPS, "ApplicationName", NULL, B_TRUE, NULL},
{NULL, NULL, NULL, B_FALSE, NULL}
};
#define DGAOPT_COUNT sizeof (drvgrpappopts) / sizeof (mms_mgmt_setopt_t)
static int
mms_remove_lm(void *session, char *libname);
static int
mms_remove_dm(void *session, nvlist_t *nvl, nvlist_t *errs);
static int
mms_remove_dg(void *session, char *dgname);
static int
update_DMs(void *session, char *drive, nvlist_t **olddms, int count,
nvlist_t *nvl, nvlist_t *errs);
static int
update_DGAs(void *session, char *dgname, nvlist_t **old, int count,
nvlist_t *nvl, nvlist_t *errs);
/*
* mms_mgmt_discover_libraries()
*
* Finds ACSLS libraries, and optionally associated drives.
*/
int
mms_mgmt_discover_libraries(
char *acshost, boolean_t getdrives, mms_list_t *liblist)
{
int st;
mms_acslib_t *lsm = NULL;
mms_acslib_t *mlsm = NULL;
mms_drive_t *drv = NULL;
mms_drive_t *mdrv = NULL;
mms_list_t mlist;
void *session = NULL;
if (!acshost || !liblist) {
return (MMS_MGMT_NOARG);
}
(void) memset(&mlist, 0, sizeof (mms_list_t));
mms_list_create(liblist, sizeof (mms_acslib_t),
offsetof(mms_acslib_t, lib_link));
st = get_acs_library_cfg(acshost, getdrives, liblist);
if (st != 0) {
return (st);
}
st = create_mm_clnt(NULL, NULL, NULL, NULL, &session);
if (st == 0) {
st = mms_get_library(session, getdrives, &mlist);
(void) mms_goodbye(session, 0);
}
if (st != 0) {
free_acslib_list(liblist);
liblist->list_size = 0;
return (st);
}
mms_list_foreach(liblist, lsm) {
if (mlist.list_size == 0) {
continue;
}
mms_list_foreach(&mlist, mlsm) {
if ((strcmp(lsm->serialnum, mlsm->serialnum) != 0) ||
(strcmp(lsm->type, mlsm->type) != 0)) {
continue;
}
(void) strlcpy(lsm->name, mlsm->name,
sizeof (lsm->name));
if (getdrives) {
if (lsm->drive_list.list_size == 0) {
break;
}
mms_list_foreach(&lsm->drive_list, drv) {
if (mlsm->drive_list.list_size == 0) {
break;
}
mms_list_foreach(&mlsm->drive_list,
mdrv) {
if ((strcmp(drv->serialnum,
mdrv->serialnum) != 0) ||
(strcmp(drv->type,
mdrv->type) != 0)) {
continue;
}
(void) strlcpy(drv->name,
mdrv->name,
sizeof (drv->name));
break;
}
}
}
break;
}
}
free_acslib_list(&mlist);
return (0);
}
/*
* The mms_get_library() function lists all the libraries that are controlled
* by MM. The LM(s) and the drives in each library alongwith the the respective
* DM(s) information for each drive are also obtained.
*
* The session argument should be provided if an existing connection to the
* MM server is to be reused. If this argument is NULL, a new connection to
* MM will be created and destroyed before returning.
*
* PARAM
* session - IN - MM session information
* get_drives - IN - whether the drives should also be returned
* acslib_list - OUT - list of mms_acslib_t
*
* RETURN
* Upon successful completion, a value of 0 is returned. If errors are
* encountered, an appropriate error number is returned
*
*/
int
mms_get_library(
void *session,
boolean_t get_drives,
mms_list_t *acslib_list)
{
void *response;
mms_acslib_t *acslib;
int st;
char cmd[1024];
char tid[64];
void *sess = NULL;
void** sessp = session;
mms_trace(MMS_DEBUG, "mms_get_library() start");
if (session == NULL) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
(void) mms_gen_taskid(tid);
/*
* generate command to query the MM for all the libraries and their
* associated LM(s)
*/
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] report[LIBRARY] reportmode[namevalue];", tid);
mms_trace(MMS_DEBUG, "mms_get_library() request command: %s", cmd);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_get_library()", &response);
if (st != 0) {
goto done;
}
(void) mmp_parse_library_rsp(response, acslib_list);
mms_free_rsp(response);
for (acslib = mms_list_head(acslib_list); acslib;
acslib = mms_list_next(acslib_list, acslib)) {
/* Get the LMs for each library */
st = mms_get_lm(sessp, acslib->name, &(acslib->lm_list));
if (st != 0) {
break;
}
/* Get the drives in the each library */
if (get_drives) {
st = mms_get_drives_for_lib(
sessp, acslib->name, &acslib->drive_list);
if (st != 0) {
break;
}
}
}
mms_trace(MMS_DEBUG, "mms_get_library() completed, return[%d]", st);
done:
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
/*
* The mms_get_lm() function gets information about all the LM(s) for a
* particular library. The LM name and hostname are filled in the structure
* mms_lm_t
*/
int
mms_get_lm(void *session, char *libname, mms_list_t *lm_list)
{
void *response;
int st;
char tid[64];
char cmd[8192];
if ((session == NULL) || (libname == NULL) || (lm_list == NULL)) {
return (MMS_MGMT_NOARG);
}
mms_trace(MMS_DEBUG, "mms_get_lm() for library[%s]", libname);
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] match[ streq(LM.'LibraryName' '%s')]"
" report[LM] reportmode[namevalue];", tid, libname);
mms_trace(MMS_DEBUG, "Send command[%s]", cmd);
st = mms_mgmt_send_cmd(session, tid, cmd, "mms_get_lm()", &response);
if (st == 0) {
st = mmp_parse_lm_rsp(response, lm_list);
}
mms_trace(MMS_DEBUG, "mms_get_lm() completed, return[%d]", st);
mms_free_rsp(response);
return (st);
}
/*
* The mms_get_dm() function gets information about all the dms for a
* particular drive. The DM name, drive path, hostname and status are
* filled in the structure mms_dm_t
*
*/
int
mms_get_dm(void *session, char *drivename, mms_list_t *dm_list)
{
void *response;
int st;
char tid[64];
char cmd[8192];
if ((session == NULL) || (drivename == NULL) || (dm_list == NULL)) {
return (MMS_MGMT_NOARG);
}
mms_trace(MMS_DEBUG, "mms_get_dm() for drive[%s]", drivename);
(void) mms_gen_taskid(tid);
/* why not just a standard report? */
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] match[ streq(DM.'DriveName' '%s')] "
"report[DM] reportmode[namevalue];",
tid, drivename);
mms_trace(MMS_DEBUG, "mms_get_dm() request command[%s]", cmd);
st = mms_mgmt_send_cmd(session, tid, cmd, "mms_get_dm()", &response);
if (st == 0) {
st = mmp_parse_dm_rsp(response, dm_list);
}
mms_trace(MMS_DEBUG, "mms_get_dm() completed, return[%d]", st);
mms_free_rsp(response);
return (st);
}
/*
* The mms_get_drives_for_lib() function returns information about the
* drives hosted by a particular library (in the MM configuration)
*
* PARAM
* session - IN - connection to MM
* libname - IN - name of library
* drive_list - OUT - A list of drives in the given library
*
* RETURN
* upon successful completion, a value of 0 is returned to indicate success and
* drives is updated with a list of drives
* If the request cannot be completed, an appropriate error number is returned
* to signify the error
*
* MMS_ERR
* MMS Connection errors
*/
int
mms_get_drives_for_lib(void *session, char *libname, mms_list_t *drive_list)
{
void *response;
int st;
char tid[64];
char cmd[8192];
if ((session == NULL) || (libname == NULL) || (drive_list == NULL)) {
return (MMS_MGMT_NOARG);
}
mms_trace(MMS_DEBUG, "mms_get_drives_for_lib(%s)", libname);
(void) mms_gen_taskid(tid);
/* this command is suspect too, if there's a drive but no DM */
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] match[ streq(DRIVE.'LibraryName' '%s')]"
" report[DRIVE DM] reportmode[namevalue];",
tid, libname);
mms_trace(MMS_DEBUG, "mms_get_drives_for_lib() request command %s",
cmd);
st = mms_mgmt_send_cmd(session, tid, cmd, "mms_get_drives_for_lib()",
&response);
if (st == 0) {
st = mmp_parse_drive_rsp(response, drive_list);
}
mms_free_rsp(response);
mms_trace(MMS_DEBUG,
"mms_get_drives_for_lib() completed, return[%d]", st);
return (st);
}
int
mms_get_drive(void *session, char *drivename, mms_drive_t **drive)
{
void *response;
int st;
void *sess = NULL;
void *sessp = session;
char tid[64];
char cmd[8192];
mms_list_t drive_list;
if (!drivename || !drive) {
return (MMS_MGMT_NOARG);
}
*drive = NULL;
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
mms_trace(MMS_DEBUG, "mms_get_drives(%s)", drivename);
(void) mms_gen_taskid(tid);
/* this command is suspect too, if there's a drive but no DM */
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] match[ streq(DRIVE.'DriveName' '%s')]"
" report[DRIVE DM] reportmode[namevalue];",
tid, drivename);
mms_trace(MMS_DEBUG, "mms_get_drive() request command %s", cmd);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_get_drive()",
&response);
if (st == 0) {
st = mmp_parse_drive_rsp(response, &drive_list);
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
if (st == 0) {
*drive = mms_list_head(&drive_list);
}
mms_free_rsp(response);
mms_list_destroy(&drive_list);
mms_trace(MMS_DEBUG, "mms_get_drive() completed, return[%d]", st);
return (st);
}
/*
* The mms_add_library() function is used to add a library to the MM
* configuration. The following steps are taken:
*
* 1. A Library object is created and associated with its network IP (ACSLS)
* 2. the Library object is associated with a Library Manager
* 3. Library is brought online
*
* ARGUMENTS:
* session MM session information. If this argument is
* NULL, a new session is created.
* lib library attributes
*
* RETURN VALUES:
* 0 Success
* >0 Failure
*
* ERRORS
* MMS_MGMT_NOARG One or more required arguments is missing
* ENOENT One or more required options is missing
* ENOMEM Out of memory
* TBD Could not communicate with MM
* TBD Other MMP errors
*
* Notes:
* MMS defines a Library Manager(LM) to manage each Library object.
* While the MMS spec supports a library to be managed by multiple
* LMs (without any upper limit), multiple LMs are only required for
* switchover or failover purposes. As such, for the first release of
* the MMS api, the hostname of the LM is defaulted to the MM host.
*
* If not specified, the library name is derived from library type and
* serial number.
*/
int
mms_add_library(void *session, nvlist_t *lib, nvlist_t *errs)
{
void *response;
int st;
char tid[64];
char cmd[8192];
char buf[1024];
char libname[1024];
char *namep = NULL;
char *val;
size_t len = sizeof (cmd);
char *cmdp;
void *sess;
void *sessp = session;
char *ltype = NULL;
if (!lib) {
return (MMS_MGMT_NOARG);
}
if (!mgmt_chk_auth("solaris.mms.create")) {
return (EACCES);
}
mms_trace(MMS_DEBUG, "mms_add_library");
/* type is required */
st = nvlist_lookup_string(lib, O_TYPE, &ltype);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_TYPE, st);
return (st);
}
st = nvlist_lookup_string(lib, O_NAME, &namep);
if (st != 0) {
if (st != ENOENT) {
MGMT_ADD_ERR(errs, O_NAME, st);
return (st);
}
}
/*
* special case for additional disk libraries - just pass it
* off to the disk archiving functions.
*/
if (strcasecmp(ltype, "DISK") == 0) {
st = mms_mgmt_add_dklib(session, namep, errs);
return (st);
}
if (namep == NULL) {
/* Create library name */
st = nvlist_lookup_string(lib, O_SERIALNO, &val);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_SERIALNO, st);
return (st);
}
(void) snprintf(libname, sizeof (libname), "LIB_%s_%s",
ltype, val);
(void) nvlist_add_string(lib, O_NAME, libname);
namep = libname;
}
/* Create LM name */
(void) snprintf(buf, sizeof (buf), "LM_%s", namep);
(void) nvlist_add_string(lib, O_LMNAME, buf);
/*
* MMS defines a Library Manager(LM) to manage each Library object.
* While the MMS spec supports a library to be managed by multiple LMs
* (without any upper limit), multiple LMs are only required for
* switchover or failover purposes. As such, for the first release of
* the MMS api, the hostname of the LM for ACSLS libraries defaults to
* the hostname running MM.
*/
#ifdef MGMT_VAR_CFG
st = nvlist_lookup_string(lib, O_DEVCONN, &val);
if (st != 0) {
if (st != ENOENT) {
MGMT_ADD_ERR(errs, O_DEVCONN, st);
return (st);
}
st = mms_cfg_getvar(MMS_CFG_MGR_HOST, buf);
if (st != 0) {
return (MMS_MGMT_NO_MMHOST);
}
(void) nvlist_add_string(lib, O_DEVCONN, buf);
}
#else
/* always set to this host */
st = gethostname(buf, sizeof (buf));
if (st != 0) {
MGMT_ADD_ERR(errs, "cannot determine hostname", st);
return (st);
}
(void) nvlist_add_string(lib, O_DEVCONN, buf);
#endif /* MGMT_VAR_CFG */
/* create LIBRARY object */
st = create_mmp_clause("LIBRARY", libopts, lib, errs, cmd, len);
if (st != 0) {
return (st);
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_add_library()", &response);
if (st != 0) {
MGMT_ADD_ERR(errs, namep, st);
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
/* move ahead in the cmdbuf */
cmdp = cmd + strlen(cmd);
len -= strlen(cmd);
/* Build the LM object */
st = create_mmp_clause("LM", lmopts, lib, errs, cmdp, len);
if (st == 0) {
st = mms_mgmt_send_cmd(sessp, tid, cmdp, "mms_add_library()",
&response);
}
/* online the library */
if (st == 0) {
if (!nvlist_exists(lib, O_OBJSTATE)) {
(void) nvlist_add_string(lib, O_OBJSTATE, "online");
}
st = mms_mgmt_set_state(sessp, lib, errs);
}
if (st != 0) {
MGMT_ADD_ERR(errs, namep, st);
(void) mms_remove_library(sessp, lib, errs);
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
int
mms_add_drive(void *session, nvlist_t *nvl, nvlist_t *errs)
{
int st;
char buf[2048];
void *sess = NULL;
void *sessp = session;
char *val;
char drvnm[1024];
char *namep;
char **saved = NULL;
int count = 0;
char hostbuf[1024];
int i;
if (!nvl) {
return (MMS_MGMT_NOARG);
}
if (!mgmt_chk_auth("solaris.mms.create")) {
return (EACCES);
}
st = gethostname(hostbuf, sizeof (hostbuf));
if (st != 0) {
st = errno;
MGMT_ADD_ERR(errs, "could not determine hostname", st);
return (st);
}
/* Library asssociation and connection are required */
if (!nvlist_exists(nvl, O_MMSLIB)) {
st = ENOENT;
MGMT_ADD_OPTERR(errs, O_MMSLIB, st);
return (st);
}
#ifdef MMS_VAR_CFG
if (!nvlist_exists(nvl, O_DEVCONN)) {
st = ENOENT;
MGMT_ADD_OPTERR(errs, O_DEVCONN, st);
return (st);
}
#else
/* must always be the same as MM server */
st = nvlist_lookup_string(nvl, O_DEVCONN, &val);
if (st == 0) {
st = mgmt_compare_hosts(val, hostbuf);
if (st != 0) {
st = MMS_MGMT_REMOTE_NOT_SUPP;
MGMT_ADD_OPTERR(errs, val, st);
return (st);
}
} else {
(void) nvlist_add_string(nvl, O_DEVCONN, hostbuf);
}
#endif /* MMS_VAR_CFG */
st = nvlist_lookup_string(nvl, O_NAME, &val);
if (st == 0) {
/* name provided */
namep = val;
} else {
if (st != ENOENT) {
MGMT_ADD_ERR(errs, O_NAME, st);
return (st);
}
st = nvlist_lookup_string(nvl, O_SERIALNO, &val);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_SERIALNO, st);
return (st);
}
(void) snprintf(drvnm, sizeof (drvnm), "DRV_%s", val);
(void) nvlist_add_string(nvl, O_NAME, drvnm);
namep = drvnm;
}
/* create the Drive Group Name */
(void) snprintf(buf, sizeof (buf), "DG_%s", namep);
(void) nvlist_add_string(nvl, O_DGNAME, buf);
if (session == NULL) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
/*
* Ready to create the objects. On failure, unwind the list and
* remove what was added. Order is DRIVEGROUP, DRIVE,
* foreach host add DM, foreach app add DRIVEGROUPAPPLICATION.
*/
/* create DRIVEGROUP */
st = mms_add_object(sessp, "DRIVEGROUP", drvgrpopts, nvl, errs);
if (st != 0) {
goto done;
}
/* Create DRIVE */
st = mms_add_object(sessp, "DRIVE", driveopts, nvl, errs);
if (st != 0) {
goto done;
}
/* For each host specified in O_DEVCONN, create a DM */
saved = var_to_array(nvl, O_DEVCONN, &count);
if (saved == NULL) {
/* should never happen since we checked earlier */
goto done;
}
for (i = 0; i < count; i++) {
/* create DM Name */
(void) snprintf(buf, sizeof (buf), "DM_%s_%d", namep, i + 1);
(void) nvlist_add_string(nvl, O_DMNAME, buf);
(void) nvlist_add_string(nvl, O_DEVCONN, saved[i]);
st = mms_add_object(sessp, "DM", dmopts, nvl, errs);
if (st != 0) {
(void) snprintf(buf, sizeof (buf),
"%s = %s", O_DEVCONN, saved[i]);
MGMT_ADD_ERR(errs, buf, st);
break;
}
}
/* put back the original array */
(void) nvlist_add_string_array(nvl, O_DEVCONN, saved, count);
mgmt_free_str_arr(saved, count);
if (st != 0) {
goto done;
}
/* For each application in O_APPS, create a DRIVEGROUPAPPLICATION */
saved = var_to_array(nvl, O_APPS, &count);
if (saved == NULL) {
/* nothing to do */
goto done;
}
for (i = 0; i < count; i++) {
if (!saved[i]) {
continue;
}
/*
* special case 'all' and 'none'.
* 'all' is meant to mean all currently defined apps
* + all future ones, but no way to specify in MMS today.
* 'none' just means set no apps, so do nothing.
*/
if ((strcasecmp(saved[i], "none") == 0) ||
(strcasecmp(saved[i], "all") == 0)) {
continue;
}
(void) nvlist_add_string(nvl, O_APPS, saved[i]);
st = mms_add_object(sessp, "DRIVEGROUPAPPLICATION",
drvgrpappopts, nvl, errs);
if (st != 0) {
/*
* Failure on this particular bit is ok, just note
* the failure as a warning
*/
(void) snprintf(buf, sizeof (buf),
"%s = %s", O_APPS, saved[i]);
MGMT_ADD_ERR(errs, buf, st);
st = 0;
}
}
/* put back the original list */
(void) nvlist_add_string_array(nvl, O_APPS, saved, count);
mgmt_free_str_arr(saved, count);
/* online the drive */
if (st == 0) {
if (!nvlist_exists(nvl, O_OBJSTATE)) {
(void) nvlist_add_string(nvl, O_OBJSTATE, "online");
}
st = mms_mgmt_set_state(sessp, nvl, errs);
}
done:
if (st != 0) {
(void) mms_remove_drive(sessp, nvl, errs);
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
mms_trace(MMS_DEBUG, "mms_add_drive() completed, return[%d]", st);
return (st);
}
void
free_acslib_list(void *arg)
{
mms_list_t *lst = arg;
mms_acslib_t *lsm;
if (!lst || (lst->list_size == 0)) {
return;
}
mms_list_foreach(lst, lsm) {
free_drive_list(&lsm->drive_list);
mms_list_free_and_destroy(&lsm->lm_list, free);
}
mms_list_free_and_destroy(lst, free);
}
void
free_drive_list(void *arg)
{
mms_list_t *lst = arg;
mms_drive_t *drv;
if (!lst || (lst->list_size == 0)) {
return;
}
mms_list_foreach(lst, drv) {
mms_list_free_and_destroy(&drv->dm_list, free);
mms_list_free_and_destroy(&drv->app_list, free);
}
mms_list_free_and_destroy(lst, free);
}
int
mms_remove_library(void *session, nvlist_t *lib, nvlist_t *errs)
{
int st;
char *val;
void *sessp = session;
void *sess = NULL;
void *response;
char cmd[8192];
char tid[64];
if (!lib) {
return (MMS_MGMT_NOARG);
}
if (!mgmt_chk_auth("solaris.mms.delete")) {
return (EACCES);
}
st = nvlist_lookup_string(lib, O_NAME, &val);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_NAME, st);
return (st);
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
/* TODO: Add checks for library dependencies in cartridgegroups */
/* TODO: Add checks for drives in this library */
(void) mms_gen_taskid(tid);
st = mms_remove_lm(sessp, val);
if (st == 0) {
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] type[LIBRARY] "
"match[streq (LIBRARY.'%s' '%s')];",
tid, "LibraryName", val);
mms_trace(MMS_DEBUG, "mms_remove_library() request command: %s",
cmd);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_remove_library()",
&response);
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
if (st != 0) {
MGMT_ADD_ERR(errs, val, st);
}
return (st);
}
static int
mms_remove_lm(void *session, char *libname)
{
int st;
void *sess = NULL;
void *sessp = session;
char cmd[2048];
char tid[64];
void *response;
if (!libname) {
return (MMS_MGMT_NOARG);
}
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] type[LM] match[streq (LM.'%s' '%s')];",
tid, "LibraryName", libname);
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_remove_lm()", &response);
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
static int
mms_remove_dg(void *session, char *dgname)
{
int st;
void *sess = NULL;
void *sessp = session;
void *response = NULL;
char tid[64];
char cmd[1024];
if (!dgname) {
return (MMS_MGMT_NOARG);
}
/*
* remove DRIVEGROUPAPPLICATIONs associated with this
* DRIVEGROUP too.
*/
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] type[DRIVEGROUPAPPLICATION]"
" match[streq (DRIVEGROUP.'DriveGroupName' '%s')];",
tid, dgname);
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_remove_dga", &response);
if (st == 0) {
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] type[DRIVEGROUP] "
"match[streq(DRIVEGROUP.'DriveGroupName' '%s')];",
tid, dgname);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_remove_dg",
&response);
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
static int
mms_remove_dm(void *session, nvlist_t *nvl, nvlist_t *errs)
{
int st;
void *sess = NULL;
void *sessp = session;
void *response = NULL;
mms_list_t dmlist;
char *drive;
mms_dm_t *dm;
char tid[64];
char cmd[1024];
if (!nvl) {
return (MMS_MGMT_NOARG);
}
st = nvlist_lookup_string(nvl, O_NAME, &drive);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_NAME, st);
return (st);
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
/* Find the list of DMs to be removed */
st = mms_get_dm(sessp, drive, &dmlist);
if (st != 0) {
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
mms_list_foreach(&dmlist, dm) {
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] type[DM] "
"match[streq (DM.'%s' '%s')];",
tid, "DMName", dm->name);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_remove_dm()",
&response);
if (st != 0) {
MGMT_ADD_ERR(errs, dm->name, st);
mms_trace(MMS_ERR, "Error removing DM %s, status = %d",
dm->name, st);
break;
}
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
mms_list_free_and_destroy(&dmlist, free);
return (st);
}
int
mms_remove_drive(void *session, nvlist_t *nvl, nvlist_t *errs)
{
int st;
void *sess = NULL;
void *sessp = session;
void *response = NULL;
char *drivename;
char tid[64];
char cmd[1024];
if (!nvl) {
return (MMS_MGMT_NOARG);
}
if (!mgmt_chk_auth("solaris.mms.delete")) {
return (EACCES);
}
st = nvlist_lookup_string(nvl, O_NAME, &drivename);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_NAME, st);
return (st);
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
st = mms_remove_dm(sessp, nvl, errs);
if (st == 0) {
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] "
"type[DRIVE] match[streq (DRIVE.'%s' '%s')];",
tid, "DriveName", drivename);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_remove_dm()",
&response);
}
if (st == 0) {
(void) snprintf(cmd, sizeof (cmd), "DG_%s", drivename);
st = mms_remove_dg(sessp, cmd);
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
/* MODIFY functions */
int
mms_modify_library(void *session, nvlist_t *nvl, nvlist_t *errs)
{
int st;
char *fnam = "mms_modify_library()";
char *libname;
void *sess = NULL;
void *sessp = session;
char tid[64];
char cmd[8192];
char lmcmd[8192];
nvlist_t *libattrs = NULL;
void *response = NULL;
int count = 0;
int lmcount = 0;
char *carray[LIBOPT_COUNT];
char *lmarray[LMOPT_COUNT];
nvpair_t *nvp;
nvlist_t *nva;
if (!mgmt_chk_auth("solaris.mms.modify")) {
return (EACCES);
}
(void) memset(&carray, 0, sizeof (carray));
(void) memset(&lmarray, 0, sizeof (lmarray));
/* get existing attrs for LIBRARY, LM */
/* see what changed, if anything */
/* update the objects */
if (!nvl) {
return (MMS_MGMT_NOARG);
}
st = nvlist_lookup_string(nvl, O_NAME, &libname);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_NAME, st);
return (st);
}
/* see if there are LIBRARY attrs to be changed. Skip over O_NAME. */
st = mgmt_find_changed_attrs("LIBRARY", libopts, nvl, carray, &count,
errs);
if (st != 0) {
return (st);
}
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] match[streq (LIBRARY.'%s' '%s')] "
"reportmode[namevalue] report[LIBRARY];", tid,
"LibraryName", libname);
/*
* see if there are LM attrs to be changed.
* Skip over O_NAME and O_LMNAME.
*/
st = mgmt_find_changed_attrs("LM", lmopts, nvl, lmarray, &lmcount,
errs);
if (st != 0) {
return (st);
}
(void) mms_gen_taskid(tid);
(void) snprintf(lmcmd, sizeof (lmcmd),
"show task['%s'] match[streq (LM.'%s' '%s')] "
"reportmode[namevalue] report[LM];", tid, "LibraryName", libname);
if ((count == 0) && (lmcount == 0)) {
/* nothing to do */
return (MMS_MGMT_NOARG);
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
if (count > 0) {
st = mms_mgmt_send_cmd(sessp, tid, cmd, fnam, &response);
if (st == 0) {
st = mmp_get_nvattrs("LibraryName", B_FALSE, response,
&libattrs);
mms_free_rsp(response);
}
if (st == 0) {
st = nvlist_lookup_nvlist(libattrs, libname, &nva);
if (st == 0) {
cmp_mmp_opts(libopts, carray, nva, &count);
}
nvlist_free(libattrs);
libattrs = NULL;
} else {
goto done;
}
}
if (lmcount > 0) {
st = mms_mgmt_send_cmd(sessp, tid, lmcmd, fnam, &response);
if (st == 0) {
st = mmp_get_nvattrs("LMName", B_FALSE, response,
&libattrs);
mms_free_rsp(response);
}
if (st != 0) {
goto done;
}
nvp = nvlist_next_nvpair(libattrs, NULL);
if (nvp) {
cmp_mmp_opts(lmopts, lmarray, nva, &lmcount);
nvlist_free(libattrs);
} else {
/* something is very wrong. no LM returned */
lmcount = 0;
}
}
/* if we have any attrs left to set, do it */
if (count > 0) {
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"attribute task['%s'] "
"match[streq (LIBRARY.'LibraryName' '%s')] ",
tid, libname);
mk_set_clause("LIBRARY", libopts, carray, cmd, sizeof (cmd));
(void) strlcat(cmd, ";", sizeof (cmd));
st = mms_mgmt_send_cmd(sessp, tid, cmd, fnam, &response);
if (st != 0) {
goto done;
}
}
if (lmcount > 0) {
(void) mms_gen_taskid(tid);
(void) snprintf(lmcmd, sizeof (lmcmd),
"attribute task['%s'] "
"match[streq (LM.'LibraryName' '%s')] ",
tid, libname);
mk_set_clause("LM", lmopts, lmarray, lmcmd, sizeof (lmcmd));
(void) strlcat(lmcmd, ";", sizeof (lmcmd));
st = mms_mgmt_send_cmd(sessp, tid, lmcmd, fnam, &response);
}
done:
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
int
mms_modify_drive(void *session, nvlist_t *nvl, nvlist_t *errs)
{
int st;
char *fnam = "mms_modify_drive()";
char *drvname;
void *sess = NULL;
void *sessp = session;
char tid[64];
char cmd[8192];
char dmcmd[8192];
char dgcmd[8192];
char dgacmd[8192];
nvlist_t *drvattrs = NULL;
nvlist_t *dgattrs = NULL;
nvlist_t *dgaattrs = NULL;
nvlist_t *dmattrs = NULL;
void *response = NULL;
int count = 0;
int dgcount = 0;
int dmcount = 0;
char *carray[DRVOPT_COUNT];
char *dgarray[DGOPT_COUNT];
char *dmarray[DMOPT_COUNT];
nvpair_t *nvp;
nvlist_t *nva;
boolean_t dodg = B_FALSE;
boolean_t dodga = B_FALSE;
char *dgname = NULL;
int numdms = 0;
nvlist_t *olddm[10]; /* should never need more than 2 */
int numdga = 0;
nvlist_t *olddga[10];
if (!mgmt_chk_auth("solaris.mms.modify")) {
return (EACCES);
}
(void) memset(&carray, 0, sizeof (carray));
if (!nvl) {
return (MMS_MGMT_NOARG);
}
st = nvlist_lookup_string(nvl, O_NAME, &drvname);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_NAME, st);
}
/* only get the DRIVEGROUP if we need it */
if (nvlist_exists(nvl, O_APPS)) {
dodg = B_TRUE;
dodga = B_TRUE;
} else if (nvlist_exists(nvl, O_UNLOADTM)) {
dodg = B_TRUE;
}
/* see if there are DRIVE attrs to be changed. */
(void) mms_gen_taskid(tid);
/* figure out what things are changing */
st = mgmt_find_changed_attrs("DRIVE", driveopts, nvl, carray, &count,
errs);
if (st != 0) {
return (st);
}
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] match[streq (DRIVE.'%s' '%s')] "
"reportmode[namevalue] report[DRIVE];", tid, "DriveName", drvname);
/* DM */
st = mgmt_find_changed_attrs("DM", dmopts, nvl, dmarray, &dmcount,
errs);
if (st != 0) {
return (st);
}
(void) mms_gen_taskid(tid);
if (nvlist_exists(nvl, O_DEVCONN)) {
/* need to make sure we've got info about all the DMs */
(void) snprintf(dmcmd, sizeof (dmcmd),
"show task['%s'] "
"match[streq(DM.'DriveName' '%s')] "
"reportmode[namevalue] report[DM];", tid, drvname);
dmcount++;
}
if (st != 0) {
return (st);
}
/* connect to MM */
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
/* fetch the drive attributes */
st = mms_mgmt_send_cmd(sessp, tid, cmd, fnam, &response);
if (st == 0) {
st = mmp_get_nvattrs("DriveName", B_FALSE, response,
&drvattrs);
mms_free_rsp(response);
}
if (st != 0) {
goto done;
}
/* DRIVEGROUP */
if (dodg) {
st = nvlist_lookup_nvlist(drvattrs, drvname, &nva);
if (nva == NULL) {
/* uh oh */
st = ENOENT;
} else {
if (st == 0) {
st = nvlist_lookup_string(nva, "DriveGroupName",
&dgname);
}
}
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_NAME, st);
goto done;
}
(void) mms_gen_taskid(tid);
(void) snprintf(dgcmd, sizeof (dgcmd),
"show task['%s'] "
"match[streq(DRIVEGROUP.'DriveGroupName' '%s')] "
"reportmode[namevalue] report[DRIVEGROUP];", tid, dgname);
}
if (dodga) {
/*
* get all of them. We need to make sure all apps
* in O_APPS are represented.
*/
(void) mms_gen_taskid(tid);
(void) snprintf(dgacmd, sizeof (dgacmd),
"show task['%s'] report[DRIVEGROUPAPPLICATION] "
"match[streq(DRIVEGROUPAPPLICATION.'DriveGroupName' '%s')]"
" reportmode[namevalue];", tid, dgname);
}
if ((count == 0) && (dmcount == 0) && !dodg && !dodga) {
/* nothing to do */
goto done;
}
if (dodg) {
st = mms_mgmt_send_cmd(sessp, tid, dgcmd, fnam, &response);
if (st == 0) {
st = mmp_get_nvattrs("DriveGroupName", B_FALSE,
response, &dgattrs);
mms_free_rsp(response);
}
if (st != 0) {
goto done;
}
}
if (dmcount > 0) {
st = mms_mgmt_send_cmd(sessp, tid, dmcmd, fnam, &response);
if (st == 0) {
st = mmp_get_nvattrs("DMName", B_FALSE, response,
&dmattrs);
mms_free_rsp(response);
}
if (st != 0) {
goto done;
}
}
if (dodga) {
st = mms_mgmt_send_cmd(sessp, tid, dgacmd, fnam, &response);
if (st == 0) {
st = mmp_get_nvattrs("ApplicationName", B_FALSE,
response, &dgaattrs);
}
if (st != 0) {
goto done;
}
}
st = nvlist_lookup_nvlist(drvattrs, drvname, &nva);
if (st == 0) {
cmp_mmp_opts(driveopts, carray, nva, &count);
if (count > 0) {
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"attribute task['%s'] "
"match[streq (DRIVE.'DriveName' '%s')] ",
tid, drvname);
mk_set_clause("DRIVE", driveopts, carray, cmd,
sizeof (cmd));
(void) strlcat(cmd, ";", sizeof (cmd));
st = mms_mgmt_send_cmd(sessp, tid, cmd, fnam,
&response);
if (st != 0) {
goto done;
}
}
}
st = nvlist_lookup_nvlist(dgattrs, dgname, &nva);
if (st == 0) {
cmp_mmp_opts(drvgrpopts, dgarray, nva, &dgcount);
if (dgcount > 0) {
(void) mms_gen_taskid(tid);
(void) snprintf(dgcmd, sizeof (dgcmd),
"attribute task['%s'] "
"match[streq (DRIVEGROUP.'DriveGroupName' '%s')] ",
tid, dgname);
mk_set_clause("DRIVEGROUP", drvgrpopts, dgarray, dgcmd,
sizeof (dgcmd));
(void) strlcat(dgcmd, ";", sizeof (dgcmd));
st = mms_mgmt_send_cmd(sessp, tid, dgcmd, fnam,
&response);
if (st != 0) {
goto done;
}
}
}
nvp = NULL;
while ((nvp = nvlist_next_nvpair(dmattrs, nvp)) != NULL) {
st = nvpair_value_nvlist(nvp, &nva);
if (!nva) {
continue;
}
/* be more robust here. If it > 2, that's surprising */
if (numdms < 10) {
olddm[numdms++] = nva;
}
}
/* Update the DMs */
st = update_DMs(sessp, drvname, olddm, numdms, nvl, errs);
if (st != 0) {
goto done;
}
nvp = NULL;
while ((nvp = nvlist_next_nvpair(dgaattrs, nvp)) != NULL) {
if ((nvpair_value_nvlist(nvp, &nva)) != 0) {
continue;
}
/*
* For DRIVEGROUPAPPLICATION, need to check
* current DGAs. Remove any not reflected in
* app list, add new
*/
if (numdga < 10) {
olddga[numdga++] = nva;
}
}
/* Update the DriveGroupApplications */
st = update_DGAs(sessp, dgname, olddga, numdga, nvl, errs);
done:
if (sess) {
(void) mms_goodbye(sess, 0);
}
if (drvattrs) {
nvlist_free(drvattrs);
}
if (dmattrs) {
nvlist_free(dmattrs);
}
if (dgattrs) {
nvlist_free(dgattrs);
}
if (dgaattrs) {
nvlist_free(dgaattrs);
}
return (st);
}
static int
update_DGAs(void *session, char *dgname, nvlist_t **old, int count,
nvlist_t *nvl, nvlist_t *errs)
{
int st;
int vcount;
char **varray = NULL;
int i;
int j;
char *val;
char cmd[8192];
char tid[64];
void *response;
int rst = 0;
if (!session || !dgname || !old || !nvl) {
return (MMS_MGMT_NOARG);
}
vcount = 0;
varray = var_to_array(nvl, O_APPS, &vcount);
for (i = 0; i < count; i++) {
val = NULL;
(void) nvlist_lookup_string(old[i], "ApplicationName", &val);
if (!val) {
continue;
}
for (j = 0; j < vcount; j++) {
if (!varray[j]) {
continue;
}
if (strcmp(val, varray[j]) == 0) {
/* match, keep this one */
free(varray[j]);
varray[j] = NULL;
break;
}
}
if (j == vcount) {
/* Remove this DGA */
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] type[DRIVEGROUPAPPLICATION] "
"match[ and ("
"streq(DRIVEGROUPAPPLICATION.'DriveGroupName' "
"'%s') "
"streq(DRIVEGROUPAPPLICATION.'ApplicationName' "
"'%s')"
") ];", tid, dgname, val);
st = mms_mgmt_send_cmd(session, tid, cmd, "removeDGA",
&response);
if (st != 0) {
if (rst == 0) {
rst = st;
}
MGMT_ADD_ERR(errs, val, st);
}
}
}
/* add any remaining */
for (i = 0; i < vcount; i++) {
if (!varray[i] || (strlen(varray[i]) == 0) ||
(strcasecmp(varray[i], "none") == 0) ||
(strcasecmp(varray[i], "all") == 0)) {
continue;
}
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"create task['%s'] type[DRIVEGROUPAPPLICATION] "
"set[DRIVEGROUPAPPLICATION.'DriveGroupName' '%s'] "
"set[DRIVEGROUPAPPLICATION.'ApplicationName' '%s'];",
tid, dgname, varray[i]);
st = mms_mgmt_send_cmd(session, tid, cmd, "add DGA",
&response);
if (st != 0) {
if (rst == 0) {
rst = st;
}
MGMT_ADD_ERR(errs, val, st);
}
}
mgmt_free_str_arr(varray, vcount);
return (rst);
}
static int
update_DMs(void *session, char *drive, nvlist_t **olddms, int count,
nvlist_t *nvl, nvlist_t *errs)
{
int st;
int rst = 0;
int i;
int j;
int vcount;
char **varray = NULL;
char *val = NULL;
char *val2 = NULL;
char *msglevel = NULL;
char *trclevel = NULL;
char *trcsz = NULL;
boolean_t updated = B_FALSE;
void *sess = NULL;
void *sessp = session;
char cmd[8192];
char tid[64];
void *response = NULL;
int highid = 0;
char buf[1024];
char *bufp;
if (!drive || !olddms || !nvl) {
return (MMS_MGMT_NOARG);
}
(void) nvlist_lookup_string(nvl, O_MSGLEVEL, &msglevel);
(void) nvlist_lookup_string(nvl, O_TRACELEVEL, &trclevel);
(void) nvlist_lookup_string(nvl, O_TRACESZ, &trcsz);
(void) snprintf(buf, sizeof (buf), "DM_%s_", drive);
vcount = 0;
varray = var_to_array(nvl, O_DEVCONN, &vcount);
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
for (i = 0; i < count; i++) {
/* save away existing values in case we need to add a DM */
if (!msglevel) {
(void) nvlist_lookup_string(olddms[i], "DMMessagelevel",
&msglevel);
}
if (!trclevel) {
(void) nvlist_lookup_string(olddms[i], "TraceLevel",
&trclevel);
}
if (!trcsz) {
(void) nvlist_lookup_string(olddms[i], "TraceFileSize",
&trcsz);
}
(void) nvlist_lookup_string(olddms[i], "DMTargetHost", &val);
(void) nvlist_lookup_string(olddms[i], "DMName", &val2);
for (j = 0; j < vcount; j++) {
if (!varray[j]) {
continue;
}
bufp = val2;
if (mgmt_compare_hosts(varray[i], val) != 0) {
continue;
}
/* this DM can stay. */
if (strncmp(buf, val2, strlen(buf)) == 0) {
bufp += strlen(buf);
st = atoi(bufp);
if (st > highid) {
highid = st;
}
st = 0;
}
free(varray[j]);
varray[j] = NULL;
break;
}
if ((vcount > 1) && (j == vcount)) {
/* This DM needs to be removed */
if (st != 0) {
if (rst == 0) {
rst = st;
}
(void) snprintf(cmd, sizeof (cmd),
"%s = %s", O_DEVCONN, val);
MGMT_ADD_ERR(errs, cmd, EINVAL);
continue;
}
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"delete task['%s'] type[DM] "
"match[ streq(DM.'DMName' '%s')];",
tid, val2);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "removeDM",
&response);
if (st != 0) {
if (rst == 0) {
rst = st;
}
MGMT_ADD_ERR(errs, val2, st);
continue;
}
}
}
/*
* unused DMs are gone. Add any new ones, and update all with
* new values if any
*/
for (i = 0; i < vcount; i++) {
if (!varray[i]) {
continue;
}
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"create task['%s'] type[DM] "
"set[DM.'DMName' 'DM_%s_%d'] "
"set[DM.'DriveName' '%s'] "
"set[DM.'DMTargetHost' '%s'] ",
tid, drive, ++highid, drive, varray[i]);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "addDM",
&response);
if (st != 0) {
if (rst == 0) {
rst = st;
}
MGMT_ADD_ERR(errs, varray[i], st);
}
free(varray[i]);
}
/* done with the new DMs */
free(varray);
/* update any existing DMs with the new values, if any */
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"attribute task['%s'] "
"match[ streq(DM.'DriveName' '%s')]", tid, drive);
if (msglevel) {
(void) snprintf(buf, sizeof (buf),
" set[DM.'DMMessageLevel' '%s']", msglevel);
(void) strlcat(cmd, buf, sizeof (cmd));
updated = B_TRUE;
}
if (trclevel) {
(void) snprintf(buf, sizeof (buf),
" set[DM.'TraceLevel' '%s']", trclevel);
(void) strlcat(cmd, buf, sizeof (cmd));
updated = B_TRUE;
}
if (trcsz) {
(void) snprintf(buf, sizeof (buf),
" set[DM.'TraceFileSize' '%s']", trcsz);
(void) strlcat(cmd, buf, sizeof (cmd));
updated = B_TRUE;
}
(void) strlcat(cmd, ";", sizeof (cmd));
if (updated) {
st = mms_mgmt_send_cmd(sessp, tid, cmd, "updateDM",
&response);
if (st != 0) {
if (rst == 0) {
rst = st;
}
}
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (rst);
}
/* Online/Offline functions */
int
mms_mgmt_set_state(void *session, nvlist_t *nvl, nvlist_t *errs)
{
int st;
char *fnam = "mms_mgmt_set_state()";
char *otype;
char *name;
char cmd[8192];
char tid[64];
void *sess = NULL;
void *sessp = session;
void *response = NULL;
char *state = NULL;
char *val;
char buf[1024];
nvlist_t *attrs = NULL;
nvpair_t *nvp;
nvlist_t *nva;
char *key = NULL;
if (!nvl) {
return (MMS_MGMT_NOARG);
}
if (!mgmt_chk_auth("solaris.mms.device.state")) {
return (EACCES);
}
st = nvlist_lookup_string(nvl, O_OBJTYPE, &otype);
if (st == 0) {
if (strcmp(otype, "dkdrive") == 0) {
otype = "drive";
} else if ((strcmp(otype, "drive") != 0) &&
(strcmp(otype, "library") != 0)) {
st = EINVAL;
}
}
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_OBJTYPE, st);
return (st);
}
st = nvlist_lookup_string(nvl, O_OBJSTATE, &state);
if (st == 0) {
if ((strcmp(state, "online") != 0) &&
(strcmp(state, "offline") != 0)) {
st = EINVAL;
}
}
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_OBJSTATE, st);
return (st);
}
st = nvlist_lookup_string(nvl, O_NAME, &name);
if (st != 0) {
MGMT_ADD_OPTERR(errs, O_NAME, st);
return (st);
}
/* get LM or DM names */
(void) mms_gen_taskid(tid);
if (*otype == 'l') {
key = "LMName";
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] reportmode[namevalue] "
"match[streq(LM.'LibraryName' '%s')] "
"report[LM.'LMName'];",
tid, name);
} else {
key = "DMName";
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] reportmode[namevalue] "
"match[streq(DM.'DriveName' '%s')] "
"report[DM.'DMName' DM.'DMTargetHost'];",
tid, name);
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
st = mms_mgmt_send_cmd(sessp, tid, cmd, fnam, &response);
if (st == 0) {
st = mmp_get_nvattrs(key, B_FALSE, response, &attrs);
mms_free_rsp(response);
}
if (st != 0) {
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"%s task['%s'] %s['%s'", otype, tid, state, name);
nvp = NULL;
/* LM required for lib online, but must not be sent for offline */
if ((strcmp(otype, "library") == 0) &&
(strcmp(state, "online") == 0)) {
while ((nvp = nvlist_next_nvpair(attrs, nvp)) != NULL) {
st = nvpair_value_nvlist(nvp, &nva);
if (st != 0) {
continue;
}
st = nvlist_lookup_string(nva, "LMName", &val);
if (st == 0) {
(void) snprintf(buf, sizeof (buf),
" '%s'", val);
(void) strlcat(cmd, buf, sizeof (cmd));
}
}
st = 0;
}
(void) strlcat(cmd, "];", sizeof (cmd));
st = mms_mgmt_send_cmd(sessp, tid, cmd, fnam, &response);
/* not a failure if already in requested state */
if ((st == MMS_ELIBALREADYONLINE) ||
(st == MMS_EDRIVEALREADYONLINE) ||
(st == MMS_ELIBALREADYOFFLINE) ||
(st == MMS_EDRIVEALREADYOFFLINE)) {
st = 0;
}
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
int
mms_mgmt_list_drives(void *session, nvlist_t *nvl, nvlist_t *errs,
nvlist_t **drvs)
{
int st;
void *sessp = session;
void *sess = NULL;
void *response = NULL;
char tid[64];
char cmd[8192];
nvlist_t *drvattrs = NULL;
nvpair_t *nvp = NULL;
nvlist_t *drv;
char *val;
char *conn[10]; /* should never be more than 2 */
char *apps[10]; /* fix this to be dynamic */
nvlist_t *oattrs = NULL;
nvpair_t *dvp;
nvlist_t *dva;
char *dval;
int i;
boolean_t first;
int count = 0;
char **varray = NULL;
char buf[2048];
if (!drvs) {
return (MMS_MGMT_NOARG);
}
if (*drvs == NULL) {
st = nvlist_alloc(drvs, 0, 0);
if (st != 0) {
MGMT_ADD_ERR(errs, "internal error", st);
return (st);
}
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
/* primary filter on name */
varray = var_to_array(nvl, O_NAME, &count);
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] report[DRIVE] reportmode[namevalue]", tid);
if (count == 1) {
(void) snprintf(buf, sizeof (buf),
" match[streq(DRIVE.'DriveName' '%s')]",
varray[0]);
(void) strlcat(cmd, buf, sizeof (cmd));
} else if (count > 1) {
(void) strlcat(cmd, " match[or (", sizeof (cmd));
for (i = 0; i < count; i++) {
if (!varray[i]) {
continue;
}
(void) snprintf(buf, sizeof (buf),
"streq(DRIVE.'DriveName' '%s') ",
varray[i]);
(void) strlcat(cmd, buf, sizeof (cmd));
}
(void) strlcat(cmd, ")]", sizeof (cmd));
}
(void) strlcat(cmd, ";", sizeof (cmd));
mgmt_free_str_arr(varray, count);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "list_drives()", &response);
if (st == 0) {
st = mmp_get_nvattrs(O_NAME, B_TRUE, response, &drvattrs);
mms_free_rsp(response);
}
if (st != 0) {
goto done;
}
while ((nvp = nvlist_next_nvpair(drvattrs, nvp)) != NULL) {
st = nvpair_value_nvlist(nvp, &drv);
if (st != 0) {
/* should never happen */
continue;
}
st = nvlist_lookup_string(drv, O_NAME, &val);
if (st != 0) {
/* bad response from MM */
continue;
}
(void) memset(&conn, 0, sizeof (conn));
(void) memset(&apps, 0, sizeof (apps));
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] report[DM] reportmode[namevalue] "
"match[streq(DM.'DriveName' '%s')];", tid, val);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "list_dm()",
&response);
if (st != 0) {
continue;
}
oattrs = NULL;
i = 0;
st = mmp_get_nvattrs("DMName", B_FALSE, response, &oattrs);
mms_free_rsp(response);
dvp = NULL;
while ((dvp = nvlist_next_nvpair(oattrs, dvp)) != NULL) {
st = nvpair_value_nvlist(dvp, &dva);
if (st != 0) {
continue;
}
st = nvlist_lookup_string(dva, "DMTargetHost", &dval);
if (st == 0) {
conn[i++] = dval;
}
if (!nvlist_exists(dva, O_TRACESZ)) {
st = nvlist_lookup_string(dva, "TraceFileSize",
&dval);
if (st == 0) {
(void) nvlist_add_string(drv, O_TRACESZ,
dval);
}
}
if (!nvlist_exists(dva, O_TRACELEVEL)) {
st = nvlist_lookup_string(dva, "TraceLevel",
&dval);
if (st == 0) {
(void) nvlist_add_string(drv,
O_TRACELEVEL, dval);
}
}
}
cmd[0] = '\0';
first = B_TRUE;
while (i > 0) {
if (!first) {
(void) strlcat(cmd, ",", sizeof (cmd));
} else {
first = B_FALSE;
}
(void) strlcat(cmd, conn[--i], sizeof (cmd));
}
(void) nvlist_add_string(drv, O_DEVCONN, cmd);
nvlist_free(oattrs);
oattrs = NULL;
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] reportmode[namevalue] "
"report[DRIVEGROUPAPPLICATION.'ApplicationName'] "
"match[streq(DRIVE.'DriveName' '%s')];", tid, val);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "list drive apps()",
&response);
if (st == 0) {
st = mmp_get_nvattrs("ApplicationName", B_FALSE,
response, &oattrs);
mms_free_rsp(response);
}
if (st != 0) {
continue;
}
i = 0;
while ((dvp = nvlist_next_nvpair(oattrs, dvp)) != NULL) {
dval = nvpair_name(dvp);
if (dval == NULL) {
continue;
}
apps[i++] = dval;
}
cmd[0] = '\0';
first = B_TRUE;
while (i > 0) {
if (!first) {
(void) strlcat(cmd, ",", sizeof (cmd));
} else {
first = B_FALSE;
}
(void) strlcat(cmd, apps[--i], sizeof (cmd));
}
(void) nvlist_add_string(drv, O_APPS, cmd);
nvlist_free(oattrs);
(void) nvlist_add_nvlist(*drvs, val, drv);
}
/* filter before returning */
mgmt_filter_results(nvl, *drvs);
/* reset status */
st = 0;
done:
nvlist_free(drvattrs);
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}
int
mms_mgmt_list_libraries(void *session, nvlist_t *nvl, nvlist_t *errs,
nvlist_t **libs)
{
int st;
void *sessp = session;
void *sess = NULL;
void *response = NULL;
char tid[64];
char cmd[8192];
nvlist_t *libattrs = NULL;
nvpair_t *nvp = NULL;
nvlist_t *lib;
char *val;
nvlist_t *oattrs = NULL;
nvpair_t *lvp;
nvlist_t *lva;
char *lval;
int count = 0;
int i;
char **varray = NULL;
char buf[2048];
if (!libs) {
return (MMS_MGMT_NOARG);
}
if (*libs == NULL) {
st = nvlist_alloc(libs, 0, 0);
if (st != 0) {
MGMT_ADD_ERR(errs, "internal error", st);
return (st);
}
}
if (!session) {
st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
if (st != 0) {
return (st);
}
sessp = sess;
}
/* primary filter on name */
varray = var_to_array(nvl, O_NAME, &count);
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] report[LIBRARY] reportmode[namevalue]", tid);
if (count == 1) {
(void) snprintf(buf, sizeof (buf),
" match[streq(LIBRARY.'LibraryName' '%s')]",
varray[0]);
(void) strlcat(cmd, buf, sizeof (cmd));
} else if (count > 1) {
(void) strlcat(cmd, " match[or (", sizeof (cmd));
for (i = 0; i < count; i++) {
if (!varray[i]) {
continue;
}
(void) snprintf(buf, sizeof (buf),
"streq(LIBRARY.'LibraryName' '%s') ",
varray[i]);
(void) strlcat(cmd, buf, sizeof (cmd));
}
(void) strlcat(cmd, ")]", sizeof (cmd));
}
(void) strlcat(cmd, ";", sizeof (cmd));
mgmt_free_str_arr(varray, count);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "list_libraries()", &response);
if (st == 0) {
st = mmp_get_nvattrs(O_MMSLIB, B_TRUE, response, &libattrs);
mms_free_rsp(response);
}
if (st != 0) {
goto done;
}
while ((nvp = nvlist_next_nvpair(libattrs, nvp)) != NULL) {
st = nvpair_value_nvlist(nvp, &lib);
if (st != 0) {
/* should never happen */
continue;
}
st = nvlist_lookup_string(lib, O_MMSLIB, &val);
if (st != 0) {
/* bad response from MM */
continue;
}
(void) mms_gen_taskid(tid);
(void) snprintf(cmd, sizeof (cmd),
"show task['%s'] report[LM] reportmode[namevalue] "
"match[streq(LM.'LibraryName' '%s')];", tid, val);
st = mms_mgmt_send_cmd(sessp, tid, cmd, "list_dm()",
&response);
if (st != 0) {
continue;
}
oattrs = NULL;
st = mmp_get_nvattrs("LMName", B_FALSE, response, &oattrs);
mms_free_rsp(response);
lvp = NULL;
while ((lvp = nvlist_next_nvpair(oattrs, lvp)) != NULL) {
st = nvpair_value_nvlist(lvp, &lva);
if (st != 0) {
continue;
}
if (!nvlist_exists(lva, O_TRACESZ)) {
st = nvlist_lookup_string(lva, "TraceFileSize",
&lval);
if (st == 0) {
(void) nvlist_add_string(lib, O_TRACESZ,
lval);
}
}
if (!nvlist_exists(lva, O_TRACELEVEL)) {
st = nvlist_lookup_string(lva, "TraceLevel",
&lval);
if (st == 0) {
(void) nvlist_add_string(lib,
O_TRACELEVEL, lval);
}
}
if (!nvlist_exists(lva, O_MSGLEVEL)) {
st = nvlist_lookup_string(lva, "MessageLevel",
&lval);
if (st == 0) {
(void) nvlist_add_string(lib,
O_MSGLEVEL, lval);
}
}
}
nvlist_free(oattrs);
(void) nvlist_add_nvlist(*libs, val, lib);
}
/* filter before returning */
mgmt_filter_results(nvl, *libs);
/* reset status */
st = 0;
done:
nvlist_free(libattrs);
if (sess) {
(void) mms_goodbye(sess, 0);
}
return (st);
}