//
// FilesystemCategory.c++
//
// Category for filesystems in clusters.
//
//
// Copyright (c) 1998, 2000 Silicon Graphics, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2.1 of the GNU Lesser General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it would be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// Further, this software is distributed without any warranty that it is
// free of the rightful claim of any third person regarding infringement
// or the like. Any license provided herein, whether implied or
// otherwise, applies only to this software file. Patent licenses, if
// any, provided herein do not apply to combinations of this program
// with other software, or any other product whatsoever.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
// USA.
//
// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
// Mountain View, CA 94043, or http://www.sgi.com/
//
// For further information regarding this notice, see:
// http://oss.sgi.com/projects/GenInfo/NoticeExplan/
//
#ident "$Revision: 1.11 $"
#include <sys/types.h>
#include <stdio.h>
#include <ci_clikeys.h>
#include <ci_camvalues.h>
#include <ci_cdbvalues.h>
#include <sysadm/Command.h>
#include <sysadm/AppContext.h>
#include <sysadm/Log.h>
#include <fsmgr/FilesystemCategory.h>
namespace fsmgr {
SaCATEGORY_REF_DEF(FilesystemCategory);
const char* FilesystemCategory::NAME = "FilesystemCategory";
const char* FilesystemCategory::FS_DISABLED = "disabled";
class FsClusterListener : public CategoryListener {
private:
FilesystemCategory* _fscat;
public:
FsClusterListener(FilesystemCategory* fscat)
{
_fscat = fscat;
}
void itemAdded(const Item& item)
{
Log::trace(_fscat->NAME,
"itemAdded: %s", (const char*) item.toString());
_fscat->buildItemListFromCluster(item);
}
void itemChanged(const Item&, const Item& newItem)
{
Log::trace(_fscat->NAME,
"itemChanged: %s", (const char*) newItem.toString());
_fscat->buildItemListFromCluster(newItem);
}
void itemRemoved(const Item&)
{
ItemList fsList;
_fscat->replaceItemList(fsList); // clear the list
}
};
//
// constructor
FilesystemCategory::FilesystemCategory()
: CamCategory("FilesystemCategory", cam_category_none)
{
// Specifying cam_category_none above relies on a feature of
// cam_register() which returns an error if the category is
// cam_category_none. We're specifying cam_category_none as the
// CamCategory::_categories[0]. Since cam_register() fails for
// cam_category_none, we know we won't get events for that
// category, and thus we can spoof CamCategory by sticking the
// items we receive from the FsClusterListener in
// CamCategory::_itemCache[0]. Unfortunately we had to make
// _itemCache[] protected instead of private.
addCategory(cam_category_filesystem_status);
_numFs = 0;
_filesystems = new String[_numFs];
}
//
// destructor
FilesystemCategory::~FilesystemCategory()
{
delete [] _filesystems;
_clusterCategory->orphanCategoryListener(_handle);
}
// buildItemListFromCluster rips apart a CLUSTER item and converts it
// into a number of filesystems. Note: required filesystem attributes
// are not checked for Attribute::NUL
//
void FilesystemCategory::buildItemListFromCluster(const Item& cluster)
{
beginBlockChanges();
Attribute aNumFs = cluster.getAttr(CICLI_CLUSTER_NUM_FILESYSTEMS);
long long numFs(0L);
if (aNumFs != Attribute::NUL)
numFs = aNumFs.longValue();
String* newFilesystems = new String[numFs];
Log::debug(NAME, "cluster: %s", (const char*) cluster.toString());
for (long long li = 0; li < numFs; ++li) {
String idNum;
idNum.fromNum((long) li);
String attrId = String(CICLI_CLUSTER_FS_DEVNAME_) + idNum;
Attribute aDevname = cluster.getAttr(attrId); // required
// create item, use device name as selector
//
const String selector = aDevname.stringValue();
Item* item = new Item(getSelector(), selector);
// copy attributes
//
Attribute aCluster = cluster.getAttr(CICLI_CLUSTER); // required
item->setAttr(aCluster);
attrId = String(CICLI_CLUSTER_FS_STATUS_) + idNum;
Attribute aMount = cluster.getAttr(attrId);
item->setAttr(Attribute(CICLI_CLUSTER_FS_STATUS_,
aMount.stringValue()));
// mount cam_status status
// enabled active mounted
// disabled active unmounted
// enabled inactive mount-ready
// enabled error ERROR
if (aMount.stringValue() == FS_DISABLED) {
item->setAttr(Attribute(STATUS_KEY, STATUS_INACTIVE));
} else {
Attribute aStatus = cluster.getAttr(STATUS_KEY);
if (aStatus == Attribute::NUL ||
aStatus.stringValue() == STATUS_INACTIVE ||
aStatus.stringValue() == STATUS_UNKNOWN) {
item->setAttr(Attribute(STATUS_KEY, STATUS_MOUNT_READY));
} else { // if cluster is ERROR, cluster is ACTIVE
item->setAttr(Attribute(STATUS_KEY, STATUS_MOUNTED));
}
}
item->setAttr(Attribute(CICLI_CLUSTER_FS_DEVNAME_,
aDevname.stringValue()));
attrId = String(CICLI_CLUSTER_FS_MOUNTPOINT_) + idNum;
Attribute aMountPt = cluster.getAttr(attrId);
item->setAttr(Attribute(CICLI_CLUSTER_FS_MOUNTPOINT_,
aMountPt.stringValue()));
// mount options are optional
attrId = String(CICLI_CLUSTER_FS_MOUNTOPTIONS_) + idNum;
Attribute aMountOpt = cluster.getAttr(attrId);
if (aMountOpt != Attribute::NUL) {
item->setAttr(Attribute(CICLI_CLUSTER_FS_MOUNTOPTIONS_,
aMountOpt.stringValue()));
}
// force unmount
attrId = String(CICLI_CLUSTER_FS_FORCE_) + idNum;
Attribute aForce = cluster.getAttr(attrId);
bool force = false;
if (aForce != Attribute::NUL) {
force = aForce.booleanValue();
}
item->setAttr(Attribute(CICLI_CLUSTER_FS_FORCE_, force));
// get server list
//
attrId = String(CICLI_CLUSTER_FS_NUM_SERVERS_) + idNum;
Attribute aNumServers = cluster.getAttr(attrId);
long long numServers(0L);
if (aNumServers != Attribute::NUL)
numServers = aNumServers.longValue();
item->setAttr(Attribute(CICLI_CLUSTER_FS_NUM_SERVERS_,
numServers));
Log::debug(NAME, "item %s", (const char*) item->toString());
for (long long lj = 0; lj < numServers; ++lj) {
String serverId;
serverId.fromNum((long) lj);
attrId = String(CICLI_CLUSTER_FS_SERVER_NODE_) +
idNum + "_" + serverId;
Attribute aNode = cluster.getAttr(attrId);
String newId = String(CICLI_CLUSTER_FS_SERVER_NODE_) + serverId;
item->setAttr(Attribute(newId, aNode.stringValue()));
attrId = String(CICLI_CLUSTER_FS_SERVER_RANK_) +
idNum + "_" + serverId;
Attribute aRank = cluster.getAttr(attrId);
newId = String(CICLI_CLUSTER_FS_SERVER_RANK_) + serverId;
item->setAttr(Attribute(newId, aRank.stringValue()));
}
bool alreadyExisted = _itemCache[0].lookupByKey(selector);
Item* cacheItem = new Item(*item);
// this code copied from CamCategory::createItemFromObject()
//
for (int ii = 0; ii < _numCategories; ii++) {
if (_categories[ii] == cam_category_none) { // spoof CamCategory
delete _itemCache[ii].remove(selector);
// Note that at this point _itemCache owns cacheItem, so
// that we should not delete it here.
_itemCache[ii].add(cacheItem, new String(selector));
} else {
copyAttrs(_itemCache[ii].lookupByKey(selector), *item);
}
}
if (alreadyExisted) {
CamCategory::changeItem(*item);
} else if (_itemCache[0].lookupByKey(selector)) {
CamCategory::addItem(*item);
}
delete item;
newFilesystems[(int)li] = String(selector);
}
for (int oldFs = 0; oldFs < _numFs; ++oldFs) {
bool found = false;
for (int newFs = 0; newFs < numFs; ++newFs) {
if (newFilesystems[newFs] == _filesystems[oldFs]) {
found = true;
break;
}
}
if (! found) {
delete _itemCache[0].remove(_filesystems[oldFs]);
removeItem(_filesystems[oldFs]);
}
}
delete [] _filesystems;
_numFs = numFs;
_filesystems = newFilesystems;
endBlockChanges();
}
//
// void FilesystemCategory::modifyItemOnCamEvent(Item* item)
//
// Description:
// Create CAM_STATUS attribute.
//
// Parameters:
// item Item for which to derive any additional attributes
//
void FilesystemCategory::modifyItemOnCamEvent(Item* item)
{
CamCategory::modifyItemOnCamEvent(item);
Attribute status(item->getAttr(CICLI_CLUSTER_FS_STATUS_STRING));
if (status != Attribute::NUL) {
const char* val = STATUS_UNKNOWN;
String statusStr = status.stringValue();
if (statusStr == STATUS_DOWN) {
Attribute aStat = item->getAttr(STATUS_KEY);
if (aStat != Attribute::NUL) {
statusStr = aStat.stringValue();
if (statusStr == STATUS_MOUNT_READY)
val = STATUS_MOUNT_READY;
else if (statusStr == STATUS_INACTIVE) {
Attribute aServer =
item->getAttr(CICLI_CLUSTER_FS_SERVER_NODE_);
if (aServer != Attribute::NUL &&
aServer.stringValue() != "")
val = STATUS_ERROR;
else
val = STATUS_INACTIVE;
} else
val = STATUS_ERROR;
}
} else if (statusStr == STATUS_INACTIVE) {
Attribute aMountStat = item->getAttr(CICLI_CLUSTER_FS_STATUS_);
if (aMountStat != Attribute::NUL) {
statusStr = aMountStat.stringValue();
if (statusStr == CDB_ENABLED)
val = STATUS_ERROR;
else
val = STATUS_INACTIVE;
}
} else if (statusStr == STATUS_UP) {
val = STATUS_MOUNTED;
}
assert(val != NULL);
item->setAttr(Attribute(STATUS_KEY, val));
}
}
void FilesystemCategory::startMonitor()
{
Log::trace(NAME, "startMonitor");
CamCategory::startMonitor();
String errorString;
_clusterCategory =
CategoryFactory::getCategory("ClusterCategory",
errorString);
_listener = new FsClusterListener(this);
_filter.monitorAllItems();
_handle = _clusterCategory->adoptCategoryListener(_listener, _filter);
endExists();
}
} // namespace fsmgr