in host/common/unix/portablehelpersmajor.cpp [1180:1431]
SVERROR HideDrive(const char * drive, char const* mountPoint, std::string& output, std::string& error, bool checkformultipaths )
{
SVERROR sve = SVS_OK;
if( NULL == drive )
{
sve = EINVAL;
DebugPrintf( SV_LOG_ERROR, "@ LINE %d in FILE %s \n", __LINE__, __FILE__ );
DebugPrintf( SV_LOG_ERROR, "FAILED HideDrive()... err = EINVAL\n");
error = "HideDrive(): The drive name is empty";
return sve;
}
/**************************************************
* This function has been made common to linux and *
* and solaris, by means of following: *
* 1. The command names have been defined as macros*
* in implementation specific header files of *
* sun and linux. *
* 2. Added a function "GetCommandPath" that *
* actually returns the specific path where *
* the commands like fuser, umount are there *
**************************************************/
/**
*
* TODO: For solaris, since lazy unmount of
* device is not supported, but since there
* is support for forcible umount with -f option,
* use of fuser can be eliminated.
*
*/
std::vector<std::string> mountPoints;
std::string devicename=drive;
if(!GetDeviceNameFromSymLink(devicename))
{
DebugPrintf(SV_LOG_ERROR,
"Function %s @LINE %d in FILE %s :failed GetDeviceNameFromSymLink for %s \n",
FUNCTION_NAME, LINE_NO, FILE_NAME, drive);
error = "HideDrive(): Unable to obtain DeviceName from SymLink ";
error += devicename;
return SVE_FAIL;
}
const char * dev = devicename.c_str();
/* This handles the GetDeviceNameFromSymLink function call by itself
* since it compares device with actual name as well as link name */
if(!GetMountPoints(dev,mountPoints))
{
DebugPrintf(SV_LOG_ERROR,
"Function %s @LINE %d in FILE %s :failed GetMountPoints for %s \n",
FUNCTION_NAME, LINE_NO, FILE_NAME, drive);
error = "HideDrive(): Unable to retrieve mountpoints associated with ";
error += dev;
return SVE_FAIL;
}
/*
* In case of vsnaps,we should not call CanUnmountMountPointsIncludingMultipath'
*/
if(checkformultipaths)
{
if(!CanUnmountMountPointsIncludingMultipath(drive,mountPoints,error))
{
DebugPrintf(SV_LOG_DEBUG,
"Function %s @LINE %d in FILE %s :failed CanUnmountMountPointsIncludingMultipath for %s \n",
FUNCTION_NAME, LINE_NO, FILE_NAME, drive);
return SVE_FAIL;
}
}
if(mountPoints.empty())
{
DebugPrintf(SV_LOG_INFO, "Mountpoints corresponding to %s are already removed.\n", drive);
DeleteFSEntry(drive);
return SVS_OK;
}
LocalConfigurator localConfigurator;
SV_UINT max_unmount_reties = localConfigurator.getMaxUnmountRetries();
std::vector<std::string>::iterator mnt_iter = mountPoints.begin();
std::vector<std::string>::iterator mnt_end = mountPoints.end();
for ( ; mnt_iter != mnt_end ; ++mnt_iter)
{
std::string errmsg;
if(!IsValidMountPoint((*mnt_iter),errmsg))
{
sve = SVE_FAIL;
std::ostringstream ostr;
ostr << "Cannot Hide " << drive << ". " << errmsg <<std::endl;
error = ostr.str().c_str();
return sve;
}
//Bug #7348 - mountpoint with spaces
std::string mountpoint = "\"";
mountpoint += (*mnt_iter);
mountpoint += "\"";
const char * mntpt = mountpoint.c_str();
//changes for Bug 4147
//checking for PWD is same as hide drive mount point directory or not
//CHK_DIR: is added in the error string to identify the below condition failed
//this is added to identify not a failed case in the vsnap unmount
char cwd_path[MAXPATHLEN];
if (ACE_OS::getcwd (cwd_path, sizeof (cwd_path)) == 0)
{
if(ENOENT != ACE_OS::last_error())
{
std::stringstream errmsgcwd;
errmsgcwd << "Failed to get the current directory.\n";
errmsgcwd <<"errno = " << ACE_OS::last_error() << "\nerror = " << ACE_OS::strerror(ACE_OS::last_error());
errmsgcwd <<" .\n";
error = "CHK_DIR: " + errmsgcwd.str();
DebugPrintf(SV_LOG_INFO, "%s\n",errmsgcwd.str().c_str());
return SVE_FAIL;
}
}
else
{
std::string curdir = cwd_path;
std::string mountdir = (*mnt_iter);
if(0 == curdir.find(mountdir, 0))
{
std::string errmsg;
errmsg = "The mount directory is ";
errmsg += mountdir;
errmsg += ".\nThe present working directory is ";
errmsg += curdir;
errmsg += ".\nThe present working directory is inside the mount directory.\n";
error = "CHK_DIR: " + errmsg;
DebugPrintf(SV_LOG_INFO, "%s\n",errmsg.c_str());
return SVE_FAIL;
}
}
DebugPrintf(SV_LOG_INFO, "\n\nUnMounting %s ...\n", mntpt);
SV_UINT retrycount = 0;
int retval = 0;
do
{
retval = TerminateUsersAndUnmountMountPoint(mntpt,error);
if(retval == -1 || (retval == 1 && retrycount == max_unmount_reties))
{
return SVE_FAIL;
}
else if(retval == 1)
{
DebugPrintf(SV_LOG_INFO, "Attempting to retry unmount operation on %s.\n", mntpt);
retrycount++;
}
}while(retval);
// VsnapDeleteMntPoint(mntpt) ;
} // finished removing the mount points
if(mnt_iter != mnt_end)
{
DebugPrintf(SV_LOG_ERROR, "Removal of Mountpoints corresponding to %s failed.\n", drive);
error = "HideDrive(): Removal of Mountpoints corresponding to ";
error += drive;
error += " failed";
//if(fd != -1) close(fd);
return SVE_FAIL;
}
// fuser -m returns 1 if nobody accessess the specified block device
// It returns 0 if atleast one process accesses the block device
DebugPrintf(SV_LOG_INFO, "\nTrying to find processes accessing %s ...\n", drive);
std::string command = SV_FUSER_FORDEV;
InmCommand fuserdevice(command + dev);
std::string pathvar = "PATH=";
pathvar += GetCommandPath(command);
fuserdevice.PutEnv(pathvar);
InmCommand::statusType status = fuserdevice.Run();
if (status != InmCommand::completed) {
DebugPrintf(SV_LOG_ERROR,
"Function %s @LINE %d in FILE %s :failed to find processes accessing %s\n",
FUNCTION_NAME, LINE_NO, FILE_NAME,drive);
error = "HideDrive(): Failed to find processes accessing ";
error += drive;
if(!fuserdevice.StdErr().empty())
{
error += fuserdevice.StdErr();
}
//if(fd != -1) close(fd);
return SVE_FAIL;
}
if(!fuserdevice.ExitCode()) //Device is busy, exitcode returned is 0
{
DebugPrintf(SV_LOG_INFO, "\nTrying to shutdown processes accessing %s ...\n", drive);
command = SV_FUSER_DEV_KILL;
InmCommand fuserdevicekill(command + dev);
pathvar = "PATH=";
pathvar += GetCommandPath(command);
fuserdevicekill.PutEnv(pathvar);
status = fuserdevicekill.Run();
if (status != InmCommand::completed) {
DebugPrintf(SV_LOG_ERROR,
"Function %s @LINE %d in FILE %s :failed to shutdown processes accessing %s\n",
FUNCTION_NAME, LINE_NO, FILE_NAME,drive);
error = "HideDrive(): Failed to shutdown processes accessing ";
error += drive;
if(!fuserdevicekill.StdErr().empty())
{
error += fuserdevicekill.StdErr();
}
//if(fd != -1) close(fd);
return SVE_FAIL;
}
if (fuserdevicekill.ExitCode()) {
DebugPrintf(SV_LOG_ERROR,
"Function %s @LINE %d in FILE %s :failed to shutdown processes accessing %s\n",
FUNCTION_NAME, LINE_NO, FILE_NAME,drive);
error = "HideDrive(): Failed to shutdown processes accessing ";
error += drive;
std::ostringstream msg;
msg << "Exit Code = " << fuserdevicekill.ExitCode() << std::endl;
if(!fuserdevicekill.StdOut().empty())
{
msg << "Output = " << fuserdevicekill.StdOut() << std::endl;
}
if(!fuserdevicekill.StdErr().empty())
{
msg << "Error = " << fuserdevicekill.StdErr() << std::endl;
}
error += msg.str();
//if(fd != -1) close(fd);
return SVE_FAIL;
}
}
DebugPrintf(SV_LOG_INFO, "Removing entries for the device %s from %s ...\n", drive, SV_FSTAB);
if(!DeleteFSEntry(drive))
{
DebugPrintf(SV_LOG_INFO, "Note: %s was not updated. please update it manually.\n", SV_FSTAB);
}
DebugPrintf(SV_LOG_INFO, "Removal of Mountpoints corresponding to %s succeeded\n", drive);
return sve;
}