host/common/sun/portablehelpersminor.cpp (1,811 lines of code) (raw):

#include <unistd.h> #include <fcntl.h> #include <procfs.h> #include <cstdio> #include <cstdlib> #include <cctype> #include <vector> #include <algorithm> #include <utility> #include <fstream> #include <iostream> #include <string> #include <sstream> #include <limits> #include <sys/sockio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <net/if.h> #include <sys/types.h> #include <sys/stat.h> #include <limits.h> #include <dirent.h> #include "portablehelpers.h" #include "portablehelperscommonheaders.h" #include "portablehelpersmajor.h" #include "portablehelpersminor.h" #include "inmdefines.h" #include "configwrapper.h" #include <sys/vfstab.h> #include <sys/dkio.h> #include <sys/vtoc.h> #include <sys/param.h> #include <sys/types.h> #include <dirent.h> #include <errno.h> #include <sys/mnttab.h> #include "volumemanagerfunctionsminor.h" #include "executecommand.h" #include "inmsafeint.h" #include "inmageex.h" #include "boost/algorithm/string/replace.hpp" #include <ace/Guard_T.h> #include "ace/Thread_Mutex.h" #include "ace/Recursive_Thread_Mutex.h" #include <sys/systeminfo.h> #include <sys/utsname.h> #define SIZE_LIMIT_TOP 0x100000000000LL #define NUM_SECTORS_PER_TB (1LL << 31) #define PSNAMELEN 100 /** * * This header file is not present in solaris 8. Need to * check if it is available in all versions of solaris 9. * The solaris 9 build machine has this. * Need to separate this out based on the solaris version we are * using. * */ #ifndef SV_SUN_5DOT8 #include "sys/efi_partition.h" bool GetBasicVolInfoFromEFI(int fd, const std::string &dskdevice, SV_BASIC_VOLINFO *pbasicvolinfo); bool IsFullEFIRawDisk(const char *disk); #endif /* SV_SUN_5DOT8 */ ACE_Recursive_Thread_Mutex g_lockforgetbasicvolinfo; #define THRSHOLD_NUM_FIELDSINFSTAB 7 #define FLAG_FIELD_IN_FSTAB 6 bool ShouldCollectNicInfo(const int &sockfd, struct lifreq *plifr, const char *ipaddr); bool FillNicInfos(const int &sockfd, struct lifconf *plic, struct lifnum *pnum, NicInfos_t & nicInfos); void GetNetIfParameters(const std::string &ifrName, std::string& hardwareAddress, std::string &netmask, E_INM_TRISTATE &isdhcpenabled); void InsertNicInfo(NicInfos_t &nicInfos, const std::string &name, const std::string &hardwareaddress, const std::string &ipaddress, const std::string &netmask, const E_INM_TRISTATE &isdhcpenabled); void UpdateNicInfoAttr(const std::string &attr, const std::string &value, NicInfos_t &nicinfos); static ACE_Mutex getmntent_lock; /* SUN */ SVERROR GetFsVolSize(const char *volName, unsigned long long *pfsSize) { SVERROR sv = SVE_FAIL; if (!(volName && pfsSize)) { /* We need to log a message but if caller has not initialized log then * crash may occur */ DebugPrintf(SV_LOG_ERROR,"@ LINE %d in FILE %s, invalid arguements supplied\n", LINE_NO, FILE_NAME); } else { *pfsSize = GetRawVolSize(volName); if (*pfsSize) { sv = SVS_OK; } else { /* We need to log a message but if caller has not initialized log then * crash may occur */ DebugPrintf(SV_LOG_ERROR,"@ LINE %d in FILE %s, GetRawVolSize failed for volume %s\n", LINE_NO, FILE_NAME, volName); } } return sv; } /* SUN Adding a function get raw volume size */ /* Returns 0 on success */ SV_ULONGLONG GetRawVolSize(const std::string &sVolume) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s with sVolume = %s\n",FUNCTION_NAME, sVolume.c_str()); SV_BASIC_VOLINFO basicvolinfo; SV_ULONGLONG rawsize = 0; if (!GetBasicVolInfo(sVolume, &basicvolinfo)) { DebugPrintf(SV_LOG_ERROR, "@LINE %d in FILE %s, GetBasicVolInfo failed for volume %s\n", LINE_NO, FILE_NAME, sVolume.c_str()); } else { rawsize = basicvolinfo.m_ullrawsize; } DebugPrintf(SV_LOG_DEBUG,"EXITED %s with rawsize = " ULLSPEC "\n",FUNCTION_NAME, rawsize); return rawsize; } SVERROR GetFsSectorSize(const char *volName, unsigned int *psectorSize) { SVERROR sv; sv = GetRawVolumeSectorSize(volName, psectorSize); return sv; } /* SUN */ SVERROR GetRawVolumeSectorSize(const char *volName, unsigned int *psectorSize) { SVERROR sv = SVE_FAIL; if (!(volName && psectorSize)) { /* We need to log a message but if caller has not initialized log then * crash may occur */ DebugPrintf(SV_LOG_ERROR,"@ LINE %d in FILE %s, invalid arguements supplied\n", LINE_NO, FILE_NAME); } else { SV_BASIC_VOLINFO basicvolinfo; if (!GetBasicVolInfo(volName, &basicvolinfo)) { DebugPrintf(SV_LOG_ERROR, "@LINE %d in FILE %s, GetBasicVolInfo failed for volume %s\n", LINE_NO, FILE_NAME, volName); } else { *psectorSize = basicvolinfo.m_uhsectorsz; sv = SVS_OK; } /* sector size may be 0 * This is case with sun volume manager * volumes */ } return sv; } /* SUN */ bool addRWFSEntry(const std::string& device, const std::string& label, const std::string& mountpoint, const std::string& type, std::vector<std::string>& fsents) { bool rv=true; do { if(!removeFSEntry(device, label, fsents)) { rv =false; break; } //device device mount FS fsck mount mount //to mount to fsck point type pass at boot options std::string realDevice = device; if (!GetDeviceNameFromSymLink(realDevice)) { rv = false; break; } std::vector<std::string>::iterator fsent_iter = fsents.begin(); std::vector<std::string>::iterator fsent_end = fsents.end(); std::vector<std::string> tempFSEnts; bool addNewEntry = true; for(; fsent_iter != fsent_end; ++fsent_iter) { std::string fsent = *fsent_iter; if ('#' == fsent[0]) { svector_t fields; Tokenize(fsent, fields, " \t\n"); if(fields.size() != THRSHOLD_NUM_FIELDSINFSTAB) { tempFSEnts.push_back(fsent); continue; } /* fstab_devtomnt may be device or real device */ std::string fstab_devtomnt(fields[0].begin()+1, fields[0].end()); std::string fstab_devtofsck = fields[1]; std::string fstab_mntpnt = fields[2]; std::string fstab_fstype = fields[3]; std::string fstab_fsckpass = fields[4]; std::string fstab_mntatboot = fields[5]; std::string fstab_mntopts = fields[6]; std::string fstab_realdev = fstab_devtomnt; if (!GetDeviceNameFromSymLink(fstab_realdev)) { tempFSEnts.push_back(fsent); } else { /* We have in hand, device and realdevice. The fstab_devtomnt can be equal to any of them or both */ if (realDevice == fstab_realdev) { if (fstab_fstype == type) { if ((mountpoint == "") || (fstab_mntpnt == mountpoint)) { /* mountpoint is empty or fstab_mntpnt and mountpoint match then * uncomment * (can mountpoint be empty?) */ //mounting rw with no mountpoint specified or mounting at previous location; uncomment //If entry has real device, it is left as it is std::string uncommentedfsent(fsent.begin()+1, fsent.end()); tempFSEnts.push_back(uncommentedfsent); } else { std::string uncommentedfsent; //device device mount FS fsck mount mount //to mount to fsck point type pass at boot options uncommentedfsent = device + "\t" + fstab_devtofsck + "\t" + mountpoint + "\t" + type + "\t" + fstab_fsckpass + "\t" + fstab_mntatboot + "\t" + fstab_mntopts + "\n"; tempFSEnts.push_back(uncommentedfsent); } addNewEntry = false; } /* end if of if (fstab_fstype == type)) */ else { /* fstyp does not match. delete this entry */ ; } } /* end of if (realDevice == fstab_devtomnt) */ else { /* device does not match. push the entry as it is */ tempFSEnts.push_back(fsent); } } /* end of else */ } /* end of if ('#' == fsent[0]) */ else // case: uncommented entries { //write all uncommented entries as they are. tempFSEnts.push_back(fsent); } } /* End of for */ if(fsent_iter != fsent_end) { rv = false; break; } if(!rv) break; // if there were no matching commented entries for this in the fstab, create new one if(addNewEntry) { std::string newFSEntry; newFSEntry = device + "\t" + "-" + "\t" + mountpoint + "\t" + type + "\t" + "-" + "\t" + "yes" + "\t" + "rw" + "\n"; tempFSEnts.push_back(newFSEntry); } fsents.assign(tempFSEnts.begin(),tempFSEnts.end()); }while(false); return rv; } /* SUN */ bool addROFSEntry(const std::string& device, const std::string& label, const std::string& mountpoint, const std::string& type, std::vector<std::string>& fsents) { bool rv=true; do { if(!removeFSEntry(device, label, fsents)) { rv =false; break; } //device device mount FS fsck mount mount //to mount to fsck point type pass at boot options std::string newFSEntry; newFSEntry = device + "\t" + "-" + "\t" + mountpoint + "\t" + type + "\t" + "-" + "\t" + "yes" + "\t" + "ro" + "\n"; fsents.push_back(newFSEntry); }while(false); return rv; } /* SUN */ bool MountVolume(const std::string& device,const std::string& mountPoint,const std::string& fsType,bool bSetReadOnly) { int exitCode = 0; std::string errorMsg = ""; bool bmounted = MountDevice(device, mountPoint, fsType, bSetReadOnly, exitCode, errorMsg); std::string flags; if(bSetReadOnly) flags="ro "; else flags="rw "; std::string sparsefile; bool new_sparsefile_format = false; bool is_volpack = IsVolPackDevice(device.c_str(),sparsefile,new_sparsefile_format); if (bmounted && (!is_volpack)) { if(!AddFSEntry(device.c_str(),mountPoint.c_str(),fsType.c_str(),flags.c_str(),false)) { DebugPrintf(SV_LOG_INFO, "Note: /etc/vfstab was not updated. please update it manually.\n"); } } return bmounted; } int posix_fadvise_wrapper(ACE_HANDLE fd, SV_ULONGLONG offset, SV_ULONGLONG len, int advice) { return 0; //SUCCESS } /* SUN */ void setdirectmode(unsigned long int &access) { return; } void setdirectmode(int &access) { return; } /* * FUNTION NAME : removeFSEntry * * DESCRIPTION : * * This is a lowlevel function of DeleteFSEnt() which takes the fstab entries and * the device name on which the operation is performed, deletes the matching * readonly or default entries for this device, comments the maching entries which * contain other flags like noexec,nosuid. It leaves the other entries as they are * * ALGORITHM : * * for each entry fsent in fsents * if the device name or label matches * if the flags contain 'ro' OR only 'defaults' OR only 'rw' * skip this entry * else * comment this entry * else write the entry as it is * * INPUT PARAMETERS : * * device : name of the device on which action is performed * label : lable of the device on which action is performed * fsents : contains all the entries in the fstab file * * OUTPUT PARAMETERS : * * fsents : contains the modified entries after the operation is performed * * RETURN VALUE : true if succeeds false otherwise. */ bool removeFSEntry(const std::string& device, const std::string& label, std::vector<std::string>& fsents) { bool rv=true; std::string realDevice = device; GetDeviceNameFromSymLink(realDevice); std::vector<std::string>::iterator fsent_iter = fsents.begin(); std::vector<std::string>::iterator fsent_end = fsents.end(); std::vector<std::string> tempFSEnts; for(; fsent_iter != fsent_end; ++fsent_iter) { std::string fsent = *fsent_iter; svector_t fields; Tokenize(fsent, fields, " \t\n"); if(fields.size() < THRSHOLD_NUM_FIELDSINFSTAB) { tempFSEnts.push_back(fsent); continue; } std::string fstab_dev = fields[0]; if ('#' == fstab_dev[0]) { tempFSEnts.push_back(fsent); continue; } std::string fstab_flags = fields[FLAG_FIELD_IN_FSTAB]; svector_t flags = split(fstab_flags, "," ); std::string fstab_realdev = fstab_dev; if(GetDeviceNameFromSymLink(fstab_realdev) && (fstab_realdev == realDevice)) {//if the device matches this fstab entry do nothing if( (find(flags.begin(), flags.end(), "ro") != flags.end()) || ((find(flags.begin(), flags.end(), "rw") != flags.end()) && (flags.size() == 1))) ;//do not include this entry. equivalent to deleting. else { std::string tempFSEnt = "#" + *fsent_iter; tempFSEnts.push_back(tempFSEnt); } } else {//if the entry does not match the device or lable we are looking write it as it is. tempFSEnts.push_back(fsent); } } // for loop fsents.assign(tempFSEnts.begin(),tempFSEnts.end()); return rv; } bool GetMountPoints(const char * dev, std::vector<std::string> &mountPoints) { bool rv = false; FILE * fp = NULL; std::string proc_fsname = ""; struct mnttab *entry = NULL; char buffer[MAXPATHLEN*4]; if (!dev) { DebugPrintf(SV_LOG_ERROR, "Function %s @LINE %d in FILE %s : invalid arguement dev is NULL\n", FUNCTION_NAME, LINE_NO, FILE_NAME); return rv; } do { fp = fopen(SV_PROC_MNTS, "r"); if (fp == NULL) { DebugPrintf(SV_LOG_ERROR, "Function %s @LINE %d in FILE %s :failed to open %s \n", FUNCTION_NAME, LINE_NO, FILE_NAME, SV_PROC_MNTS); rv = false; break; } std::string sMountPoint=""; resetmnttab(fp); entry = (struct mnttab *) malloc(sizeof (struct mnttab)); while( SVgetmntent(fp, entry,buffer,sizeof(buffer)) != -1 ) { if (!IsValidDevfile(entry->mnt_special)) continue; proc_fsname = entry->mnt_special; std::string proc_realfsname = proc_fsname; GetDeviceNameFromSymLink(proc_realfsname); std::string realdev = dev; std::string device = dev; if (!GetDeviceNameFromSymLink(realdev)) { DebugPrintf(SV_LOG_ERROR, "Function %s @LINE %d in FILE %s :GetDeviceNameFromSymLink failed.\n", FUNCTION_NAME, LINE_NO, FILE_NAME); rv = false; break; } if (proc_realfsname == realdev) { mountPoints.push_back(entry->mnt_mountp); } } rv = true; }while(0); if ( NULL != fp ) { free (entry); resetmnttab(fp); fclose(fp); } return rv; } SVERROR MakeReadOnly(const char *drive, void *VolumeGUID, etBitOperation ReadOnlyBitFlag) { DebugPrintf("MakeReadOnly (sun) on %s: not implemented\n", drive); return SVE_FAIL; } SVERROR isReadOnly(const char * drive, bool & rvalue) { SVERROR sve = SVS_OK; DebugPrintf(SV_LOG_DEBUG, "@ LINE %d in FILE %s, drive = %s\n", LINE_NO, FILE_NAME, drive); if( NULL == drive ) { sve = EINVAL; DebugPrintf( SV_LOG_ERROR, "@ LINE %d in FILE %s \n", __LINE__, __FILE__ ); DebugPrintf( SV_LOG_ERROR, "FAILED UnhideDrive_RW()... err = EINVAL\n"); return sve; } std::string sMount = ""; std::string mode; if (!IsVolumeMounted(drive,sMount,mode)) { DebugPrintf(SV_LOG_DEBUG,"Device %s is not mounted. It means it is hidden .\n",drive); rvalue=false; return SVS_FALSE ; } SV_BASIC_VOLINFO basicvolinfo; if (!GetBasicVolInfo(drive, &basicvolinfo)) { DebugPrintf(SV_LOG_ERROR, "@LINE %d in FILE %s, GetBasicVolInfo failed for volume %s\n", LINE_NO, FILE_NAME, drive); sve = SVE_FAIL; } else { rvalue = basicvolinfo.m_breadonly; } return sve; } VOLUME_STATE GetVolumeState(const char * drive) { DebugPrintf( SV_LOG_DEBUG, "Entered GetVolumeState\n"); // Algorithm: // Get actual device name. // Get all current mount points associated with the device. // If mount points empty, return HIDDEN // For each mount point... // Is it mounted read write, return UNHIDDEN_RW // // Return UNHIDDEN_RO // bool rv = false; FILE *fp = NULL; struct mnttab *entry = NULL; bool mounted = false; bool rw = false; VOLUME_STATE vs = VOLUME_UNKNOWN; std::string realdevname = drive; std::string devname = drive; char buffer[MAXPATHLEN*4]; do { if(!IsVolpackDriverAvailable()) { std::string sparsefile; bool new_sparsefile_format = false; bool is_volpack = IsVolPackDevice(devname.c_str(),sparsefile,new_sparsefile_format); if(is_volpack) { vs = VOLUME_HIDDEN; break; } } rv = GetDeviceNameFromSymLink(realdevname); if(!rv) { DebugPrintf(SV_LOG_ERROR, "Function %s @LINE %d in FILE %s :invalid device name %s\n", FUNCTION_NAME, LINE_NO, FILE_NAME,realdevname.c_str()); vs = VOLUME_UNKNOWN; break; } rv = IsValidDevfile(realdevname); if(!rv) { DebugPrintf(SV_LOG_ERROR, "Function %s @LINE %d in FILE %s :invalid device name %s\n", FUNCTION_NAME, LINE_NO, FILE_NAME,realdevname.c_str()); vs = VOLUME_UNKNOWN; break; } fp = fopen(SV_PROC_MNTS, "r"); if (fp == NULL) { DebugPrintf(SV_LOG_ERROR, "Function %s @LINE %d in FILE %s :unable to open %s\n", FUNCTION_NAME, LINE_NO, FILE_NAME,SV_PROC_MNTS); vs = VOLUME_UNKNOWN; break; } resetmnttab(fp); entry = (struct mnttab *) malloc(sizeof (struct mnttab)); while(SVgetmntent(fp, entry,buffer,sizeof(buffer)) != -1 ) { std::string procdevName = entry -> mnt_special; std::string realprocdevName = procdevName; if(!GetDeviceNameFromSymLink(realprocdevName)) continue; if (!IsValidDevfile(realprocdevName)) continue; if (realprocdevName == realdevname) { mounted = true; if( 0 != strstr(entry->mnt_mntopts, "rw") ) { rw = true; break; } } } if ( fp ) { free (entry); resetmnttab(fp); fclose(fp); } if(mounted) { if(rw) vs = VOLUME_VISIBLE_RW; else vs = VOLUME_VISIBLE_RO; } else { vs = VOLUME_HIDDEN; } } while (0); DebugPrintf( SV_LOG_DEBUG, "Exited GetVolumeState\n"); return vs; } bool IsVolumeMounted(const std::string volume,std::string& sMountPoint, std::string &mode) { bool bMounted = false; char buffer[MAXPATHLEN*4]; sMountPoint = ""; if(volume.empty()) { DebugPrintf(SV_LOG_ERROR,"Null volume name passed.\n"); return false; } std::string devName = volume; std::string realdevName = volume; std::string proc_fsname = ""; GetDeviceNameFromSymLink(realdevName); FILE *fp; struct mnttab *entry = NULL; fp = fopen(SV_PROC_MNTS, "r"); if (fp == NULL) { DebugPrintf(SV_LOG_ERROR, "Function %s @LINE %d in FILE %s :unable to open %s\n", FUNCTION_NAME, LINE_NO, FILE_NAME,SV_PROC_MNTS); return false; } resetmnttab(fp); entry = (struct mnttab *) malloc(sizeof (struct mnttab)); while(SVgetmntent(fp, entry,buffer,sizeof(buffer)) != -1 ) { if (!IsValidDevfile(entry->mnt_special)) continue; proc_fsname = entry->mnt_special; std::string realproc_fsname = proc_fsname; GetDeviceNameFromSymLink(realproc_fsname); if (realproc_fsname == realdevName) { bMounted = true; sMountPoint = entry->mnt_mountp; } } if ( fp ) { free (entry); resetmnttab(fp); fclose(fp); } return bMounted; } SVERROR FlushFileSystemBuffers(const char *Volume) { std::string volName; ACE_HANDLE hVolume = ACE_INVALID_HANDLE; SVERROR sve = SVS_OK; do { SV_UINT flags = 0; volName = Volume; flags = O_RDWR | O_SYNC | O_RSYNC ; // PR#10815: Long Path support hVolume = ACE_OS::open(getLongPathName(volName.c_str()).c_str(), flags, ACE_DEFAULT_OPEN_PERMS); if(ACE_INVALID_HANDLE == hVolume) { sve = ACE_OS::last_error(); DebugPrintf( SV_LOG_ERROR, "@ LINE %d in FILE %s \n", __LINE__, __FILE__ ); DebugPrintf( SV_LOG_ERROR, "ACE_OS::open failed in FlushFileSystemBuffers.We still proceed %s, err = %s\n", volName.c_str(), sve.toString()); break; } if (ACE_OS::fsync(hVolume) == -1) { sve = ACE_OS::last_error(); DebugPrintf(SV_LOG_WARNING, "FlushFileBuffers for Volume %s did not succeed, err = %s\n", volName.c_str(), sve.toString()); } else DebugPrintf(SV_LOG_DEBUG, "FlushFileBuffers for Volume %s Succeeded\n", volName.c_str()); ACE_OS::close(hVolume); } while (FALSE); return sve; } bool GetVolumeRootPath(const std::string & path, std::string & root) { // char rootPath[SV_INTERNET_MAX_PATH_LENGTH]; struct mnttab *mntptr; size_t lenthOfmntdir = 0; bool found = false; char buffer[MAXPATHLEN*4]; root.clear(); FILE *fp = fopen(SV_PROC_MNTS,"r"); if(fp == NULL) return false; resetmnttab(fp); mntptr = (struct mnttab *) malloc(sizeof (struct mnttab)); while(SVgetmntent(fp, mntptr,buffer,sizeof(buffer)) != -1 ) { lenthOfmntdir = strlen(mntptr->mnt_mountp); if(!strncmp(mntptr->mnt_mountp, path.c_str(), lenthOfmntdir)) { if ( lenthOfmntdir > root.size()) { root = mntptr->mnt_mountp; found = true; } } } if (fp) { free(mntptr); resetmnttab(fp); fclose(fp); } return found; } // // Function: GetDeviceNameForMountPt // given a mount point, convert it to corresponding device name // bool GetDeviceNameForMountPt(const std::string & mtpt, std::string & devName) { bool rv = false; char buffer[MAXPATHLEN*4]; FILE *fp; struct mnttab *entry = NULL; fp = fopen(SV_PROC_MNTS, "r"); if (fp == NULL) { DebugPrintf(SV_LOG_ERROR, "Could not able to open %s\n", SV_PROC_MNTS); return false; } resetmnttab(fp); entry = (struct mnttab *) malloc(sizeof (struct mnttab)); while(SVgetmntent(fp, entry,buffer,sizeof(buffer)) != -1 ) { if ( 0 == strcmp(entry->mnt_mountp, mtpt.c_str())) { devName = entry->mnt_special; if(IsValidDevfile(entry->mnt_special)) { /** NEEDTOASK : Whether to return device name or * real device name? This is very important * as We need to determine which areas get * affected because of real name and device name * are different. Mostly retention and other areas * Currently returning what ever is there in * mnttab. This strongly assumes that mnttab * must have "/dev/dsk/c0t1d0s7", otherwise * This function may cause erroneous results * Need to check if cdpcli needs a real name * or name reported to CX */ std::string realdevName = devName; if(!GetDeviceNameFromSymLink(realdevName)) continue; } rv = true; break; } } if ( fp ) { free(entry); resetmnttab(fp); fclose(fp); } return rv; } bool IsValidMntEnt(struct mnttab *entry) { bool valid = true; if (entry == NULL) valid = false; if (strcmp(entry->mnt_special, "none") == 0) valid = false; if (strncmp(entry->mnt_mountp, "/dev", strlen("/dev")) == 0) valid = false; if (strcmp(entry->mnt_fstype, "nfs") == 0) valid = false; if (strcmp(entry->mnt_fstype, "auto") == 0) valid = false; // all removable media if (strncmp(entry->mnt_mountp, "/proc", strlen("/proc")) == 0) valid = false; return valid; } /* * FUNCTION NAME : mountedVolume * * DESCRIPTION : Given a pathname, return the nested volumes beneath it * * * INPUT PARAMETERS : pathname under which nested volumes need to be checked * * OUTPUT PARAMETERS : nested volumes * * NOTES : doesn't count the provided mountpoint/devicename as a mounted volume * * return value : true if nested volumes are found, otherwise false * */ bool mountedvolume( const std::string& pathname, std::string& mountpoints ) { std::string mntpath = pathname + "/"; char buffer[MAXPATHLEN*4]; FILE* fp = fopen(SV_PROC_MNTS, "r"); if( !pathname.empty() ) { struct mnttab* line = NULL; resetmnttab(fp); line = (struct mnttab *) malloc(sizeof (struct mnttab)); while(SVgetmntent(fp, line,buffer,sizeof(buffer))!= -1 ) { if( !strncmp( line->mnt_special, "/dev/", 5 ) && strcmp( line->mnt_mountp, pathname.c_str())) { if( !strncmp( line->mnt_mountp, mntpath.c_str(), mntpath.size())) { mountpoints += line->mnt_mountp; mountpoints += "\n"; } } } if ( NULL != fp ) { free(line); resetmnttab(fp); fclose(fp); } } return mountpoints.empty() ? false : true; } bool FormVolumeLabel(const std::string device, std::string &label) { bool bretval = true; label = ""; return bretval; } std::string GetCommandPath(const std::string &cmd) { /* APART FROM COMMON PATHS, WE SHOULD FIND AN EQUIVALENT OF "which" COMMAND */ return "/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin"; } bool GetVolSizeWithOpenflag(const std::string vol, const int oflag, SV_ULONGLONG &refvolsize) { bool bretval = true; std::string dev_name = vol + "s2"; ACE_stat s; if(0 == sv_stat(getLongPathName(vol.c_str()).c_str(), &s )) refvolsize = GetRawVolSize(vol); else if(0 == sv_stat(getLongPathName(dev_name.c_str()).c_str(), &s )) { char symlnk[PATH_MAX + 1] = {0}; ssize_t len; len = readlink(dev_name.c_str(), symlnk, sizeof(symlnk) - 1); std::string linkname = symlnk; linkname.erase(len - 2); linkname += ",raw"; refvolsize = GetRawVolSize(linkname); } if (!refvolsize) { DebugPrintf(SV_LOG_ERROR,"@ LINE %d in FILE %s, GetRawVolSize failed for volume %s\n", LINE_NO, FILE_NAME, vol.c_str()); bretval = false; } return bretval; } void FormatVolumeNameForCxReporting(std::string& volumeName) { // we need to strip off any leading \, ., ? if they exists std::string::size_type idx = volumeName.find_first_not_of("\\.?"); if (std::string::npos != idx) { volumeName.erase(0, idx); } // strip off trailing :\ or : if they exist std::string::size_type len = volumeName.length(); idx = len; if ('\\' == volumeName[len - 1] || ':' == volumeName[len - 1]) { --idx; } if (idx < len) { volumeName.erase(idx); } } bool GetSectorSizeWithFd(int fd, const std::string vol, SV_ULONG &SectorSize) { bool bretval = false; if (-1 == fd) { DebugPrintf(SV_LOG_ERROR, "@ LINE %d in FILE %s, invalid fd = %d\n", LINE_NO, FILE_NAME, fd); } else { SVERROR sv; unsigned int volsectorsize = 0; sv = GetRawVolumeSectorSize(vol.c_str(), &volsectorsize); if (sv.failed()) { DebugPrintf(SV_LOG_ERROR, "@ LINE %d in FILE %s, failed to get sector size for volume = %s\n", LINE_NO, FILE_NAME, vol.c_str()); } else { SectorSize = volsectorsize; bretval = true; } } return bretval; } bool GetNumBlocksWithFd(int fd, const std::string vol, SV_ULONGLONG &NumBlks) { bool bretval = false; if (-1 == fd) { DebugPrintf(SV_LOG_ERROR, "@ LINE %d in FILE %s, invalid fd = %d\n", LINE_NO, FILE_NAME, fd); } else { SV_BASIC_VOLINFO basicvolinfo; if (!GetBasicVolInfo(vol, &basicvolinfo)) { DebugPrintf(SV_LOG_ERROR, "@LINE %d in FILE %s, GetBasicVolInfo failed for volume %s\n", LINE_NO, FILE_NAME, vol.c_str()); } else { NumBlks = basicvolinfo.m_lnumblocks; bretval = true; } } return bretval; } /* SUN SPECIFIC */ /* The reason is that in linux, the device name * is although a link to the real name, read link * on device name gives absolute path of the real name * but in solaris, readlink on device name gives the * relative path. This function can be made common * to unix once the solaris version(which should work * for both solaris and linux) is tested on linux) */ // // Gets the root device name from a symbolic link // bool GetDeviceNameFromSymLink(std::string &deviceName) { bool bretval = false; const std::string saveDeviceName = deviceName; struct stat64 st_buf; if (NULL == deviceName.c_str()) { DebugPrintf(SV_LOG_ERROR, "@ LINE %d in FILE %s, no device name supplied\n", LINE_NO, FILE_NAME); } else if(stat64(deviceName.c_str(), &st_buf)) { DebugPrintf(SV_LOG_WARNING, "@ LINE %d in FILE %s, stat failed on %s with errno = %d\n", LINE_NO, FILE_NAME, deviceName.c_str(), errno); } else { /** * * Commenting below debug printf since it fills in the log file. * Can be uncommented when needed. * */ /* DebugPrintf(SV_LOG_DEBUG, "ENTERED %s with deviceName = %s\n",FUNCTION_NAME, deviceName.c_str()); */ const char UNIXROOTDIR = '/'; const char UNIXDIRSEPARATOR = '/'; // make sure device is valid struct stat64 volStat; // make sure device file exists if (0 == lstat64(deviceName.c_str(), &volStat)) { if (S_ISLNK(volStat.st_mode)) { ssize_t len; /* Not initialized since terminating finally with \0 */ char symlnk[PATH_MAX + 1]; do { len = readlink(deviceName.c_str(), symlnk, sizeof(symlnk) - 1); if (-1 == len) { /* This is the final device. so return true */ if (0 == lstat64(deviceName.c_str(), &volStat)) { bretval = true; } break; } symlnk[len] = '\0'; if (UNIXROOTDIR != symlnk[0]) { /* This is a relative path */ char dirnameofdevice[PATH_MAX + 1] = {'\0'}; SVERROR sv = DirName(deviceName.c_str(), dirnameofdevice); if (sv.failed()) { DebugPrintf(SV_LOG_ERROR,"DirName failed @ LINE %d in FILE %s.\n", LINE_NO, FILE_NAME); break; } std::string catenatedlinkname = dirnameofdevice; catenatedlinkname += UNIXDIRSEPARATOR; catenatedlinkname += symlnk; char absolutename[PATH_MAX + 1] = {'\0'}; if (NULL == realpath(catenatedlinkname.c_str(), absolutename)) { DebugPrintf(SV_LOG_ERROR,"realpath failed @ LINE %d in FILE %s for file %s with errno = %d.\n", LINE_NO, FILE_NAME, deviceName.c_str(), errno); break; } deviceName = absolutename; } else { /* symlink is in absolute form */ deviceName = symlnk; } } while (true); } else { /* This is not a link file */ bretval = true; } } } /* else */ if (!bretval) { DebugPrintf(SV_LOG_WARNING, "Unable to determine attributes of file %s @LINE %d in FILE %s\n",saveDeviceName.c_str(), LINE_NO, FILE_NAME); } /** * * Commenting below debug printf since it fills in the log file. * Can be uncommented when needed. * */ /* DebugPrintf(SV_LOG_DEBUG,"EXITING %s with deviceName = %s and bretval = %s\n",FUNCTION_NAME, deviceName.c_str(), bretval?"true":"false"); */ return bretval; } /* This function assumes name coming is of form "/dev/dsk/c0t1d0s7" or "/dev/md/dsk/d20" */ bool GetBasicVolInfo(const std::string &sDevName, SV_BASIC_VOLINFO *pbasicvolinfo) { bool bretval = false; if (!pbasicvolinfo) { DebugPrintf(SV_LOG_ERROR, "@ LINE %d in FILE %s, invalid arguement pbasicvolinfo = %p\n", LINE_NO, FILE_NAME, pbasicvolinfo); return bretval; } ACE_Guard<ACE_Recursive_Thread_Mutex> guard(g_lockforgetbasicvolinfo); if (!guard.locked()) { DebugPrintf(SV_LOG_WARNING, "@LINE %d in FILE %s unable to apply lock\n", __LINE__, __FILE__); return bretval; } DebugPrintf(SV_LOG_DEBUG, "ENTERED %s with deviceName = %s\n",FUNCTION_NAME, sDevName.c_str()); std::string sRawVolName = GetRawVolumeName(sDevName); int fd; int read_vtoc_retval = 0; struct vtoc vt; fd = open(sRawVolName.c_str(), O_NDELAY | O_RDONLY); if (-1 == fd) { DebugPrintf(SV_LOG_ERROR, "open() failed for raw volume %s at line %d in file %s with errno = %d\n", sRawVolName.c_str(), __LINE__, __FILE__, errno); } else { read_vtoc_retval = read_vtoc(fd, &vt); if (read_vtoc_retval < 0) { #ifndef SV_SUN_5DOT8 if (VT_ENOTSUP == read_vtoc_retval) { if (GetBasicVolInfoFromEFI(fd, sDevName, pbasicvolinfo)) { DebugPrintf(SV_LOG_DEBUG, "reading efi label succeeded for raw volume %s at line %d in file %s\n", sRawVolName.c_str(), __LINE__, __FILE__); bretval = true; } else { DebugPrintf(SV_LOG_ERROR, "reading efi label failed for raw volume %s at line %d in file %s with errno = %d\n", sRawVolName.c_str(), __LINE__, __FILE__, errno); } } else { #endif /* SV_SUN_5DOT8 */ DebugPrintf(SV_LOG_ERROR, "read_vtoc() failed for raw volume %s at line %d in file %s with errno = %d\n", sRawVolName.c_str(), __LINE__, __FILE__, errno); #ifndef SV_SUN_5DOT8 } #endif /* SV_SUN_5DOT8 */ } else if (READVTOCRVALFORP0 == read_vtoc_retval) { DebugPrintf(SV_LOG_DEBUG, "For %s, read vtoc returned %d." "This is a fdisk partition p0\n", sDevName.c_str(), read_vtoc_retval); bretval = GetBasicVolInfoForP0(fd, sDevName, pbasicvolinfo); } else if (read_vtoc_retval < vt.v_nparts) { DebugPrintf(SV_LOG_DEBUG, "read_vtoc returned %d for raw volume %s at line %d in file %s\n", read_vtoc_retval, sRawVolName.c_str(), __LINE__, __FILE__); pbasicvolinfo->m_breadonly = (vt.v_part[read_vtoc_retval].p_flag & V_RONLY); pbasicvolinfo->m_lnumblocks = vt.v_part[read_vtoc_retval].p_size; pbasicvolinfo->m_uhsectorsz = vt.v_sectorsz ? vt.v_sectorsz : DEV_BSIZE; /* pbasicvolinfo->m_ullrawsize = GiveValidSize(sDevName, pbasicvolinfo->m_lnumblocks, pbasicvolinfo->m_uhsectorsz, E_ATMORETHANSIZE); */ pbasicvolinfo->m_ullrawsize = ((unsigned long long)pbasicvolinfo->m_lnumblocks) * ((unsigned long long)pbasicvolinfo->m_uhsectorsz); bretval = true; } else { DebugPrintf(SV_LOG_ERROR, "read_vtoc returned %d for raw volume %s which " "is greater than the number of partition structures\n", read_vtoc_retval, sDevName.c_str()); } close(fd); } DebugPrintf(SV_LOG_DEBUG,"EXITING %s with bretval = %s\n",FUNCTION_NAME, bretval?"true":"false"); return bretval; } bool IsReportingRealNameToCx(void) { return false; } /** * * Finds out and gets the link name from actual device name * for only physical disks since does cfgadm * The actual device name for * solaris volume manager are not documented * and so we should use solaris volume manager name d[0-9]+ * for the cdpcli input. * Also ls -l on a solaris volume * manager volume gives: * root@IMITSF1 # ls -l /dev/md/dsk/d50 * lrwxrwxrwx 1 root root 37 Mar 3 17:54 /dev/md/dsk/d50 -> ../../../devices/pseudo/md@0:0,50,blk * root@IMITSF1 # * */ bool GetLinkNameIfRealDeviceName(const std::string sVolName, std::string &sLinkName) { bool bretval; /** * This will contain the actual device name when * GetDeviceNameFromSymLink is called on sVolName * So that we always have realname for comparision * We compare with real name */ std::string realname; /** * Assign the volume name as the first step */ realname = sLinkName = sVolName; bretval = true; if (!GetDeviceNameFromSymLink(realname)) { return !(bretval); } if (realname == sVolName) { /** * * realname and the sVolName are same * This means sVolName is a real name. * Always support to get the link name * of the physical disk slice since * solaris volume manager volume has * a link or not is not documented. * and VxVM volumes under "/dev/vx/dsk" * do not have any links. * */ /** * * The algorithm: * ============= * 1. Do * */ DIR *dirp; struct dirent *dentp, *dentresult; size_t direntsize = sizeof(struct dirent) + PATH_MAX + 1; const std::string DskDir = "/dev/dsk"; dentresult = NULL; dirp = opendir(DskDir.c_str()); if (dirp) { dentp = (struct dirent *)calloc(direntsize, 1); if (dentp) { while ((0 == readdir_r(dirp, dentp, &dentresult)) && dentresult) { if (strcmp(dentp->d_name, ".") && strcmp(dentp->d_name, "..")) //skip . and .. { std::string dskdevice = DskDir + "/" + dentp->d_name; std::string dskdevicerealname = dskdevice; if (GetDeviceNameFromSymLink(dskdevicerealname) && (dskdevicerealname == sVolName)) { sLinkName = dskdevice; break; } } /* end of skipping . and .. */ memset(dentp, 0, direntsize); } /* end of while readdir_r */ free(dentp); } /* endif of if (dentp) */ else { bretval = false; } closedir(dirp); } /* end of if (dirp) */ } /* end of if (realname == sVolName) */ return bretval; } #ifndef SV_SUN_5DOT8 bool GetBasicVolInfoFromEFI(int fd, const std::string &dskdevice, SV_BASIC_VOLINFO *pbasicvolinfo) { bool bretval = false; std::string sRawVolName = GetRawVolumeName(dskdevice); if (!pbasicvolinfo) { return bretval; } int efi_alloc_and_read_rval = -1; dk_gpt_t *vt = NULL; void *libefihandle = NULL; int (*ptr_efi_alloc_and_read)(int fd, dk_gpt_t **vtoc) = NULL; void (*ptr_efi_free)(dk_gpt_t *vtoc) = NULL; void *pv_efi_alloc_and_read = NULL, *pv_efi_free = NULL; std::string libefiso; libefiso = LIBEFI_DIRPATH; libefiso += UNIX_PATH_SEPARATOR; libefiso += LIBEFINAME; DebugPrintf(SV_LOG_DEBUG, "@LINE %d in FILE %s libefiso path is %s\n", __LINE__, __FILE__, libefiso.c_str()); libefihandle = dlopen(libefiso.c_str(), RTLD_LAZY); if (libefihandle) { const std::string EFI_ALLOC_AND_READ_FUNCTIONNAME = "efi_alloc_and_read"; const std::string EFI_FREE_FUNCTIONNAME = "efi_free"; pv_efi_alloc_and_read = dlsym(libefihandle, EFI_ALLOC_AND_READ_FUNCTIONNAME.c_str()); pv_efi_free = dlsym(libefihandle, EFI_FREE_FUNCTIONNAME.c_str()); if (pv_efi_alloc_and_read && pv_efi_free) { ptr_efi_alloc_and_read = (int (*)(int fd, dk_gpt_t **vtoc))pv_efi_alloc_and_read; ptr_efi_free = (void (*)(dk_gpt_t *vtoc))pv_efi_free; efi_alloc_and_read_rval = ptr_efi_alloc_and_read(fd, &vt); if ((efi_alloc_and_read_rval >= 0) && vt) { /** * * * When a disk is under disk set of solaris volume manager, * efi_version is coming as 0, but the structure is filled * in properly. * * NOTE: Keep the commented check of EFI_VERSION_CURRENT * as it is. */ //if (EFI_VERSION_CURRENT == vt->efi_version) //{ if (FULLEFIIDX == efi_alloc_and_read_rval) { DebugPrintf(SV_LOG_DEBUG,"@ LINE %d in FILE %s, %s is a full efi label disk\n", LINE_NO, FILE_NAME, sRawVolName.c_str()); /** * * For EFI entire disk, should not use the efi_alloc_and_read_rval since * has no significance. But still efi_alloc_and_read_rval is positive * and the dk_gpt_t structure is properly filled in. * currently putting read only as false for EFI labelled full disk since * need to find out a way of finding it out. * */ pbasicvolinfo->m_breadonly = false; pbasicvolinfo->m_lnumblocks = vt->efi_last_lba + 1; pbasicvolinfo->m_uhsectorsz = vt->efi_lbasize; pbasicvolinfo->m_ullrawsize = GiveValidSize(sRawVolName, pbasicvolinfo->m_lnumblocks, pbasicvolinfo->m_uhsectorsz, E_ATLESSTHANSIZE); } else { DebugPrintf(SV_LOG_DEBUG,"@ LINE %d in FILE %s, %s is a partition on efi label disk\n", LINE_NO, FILE_NAME, sRawVolName.c_str()); pbasicvolinfo->m_breadonly = (vt->efi_parts[efi_alloc_and_read_rval].p_flag & V_RONLY); pbasicvolinfo->m_lnumblocks = vt->efi_parts[efi_alloc_and_read_rval].p_size; pbasicvolinfo->m_ullrawsize = ((unsigned long long)vt->efi_parts[efi_alloc_and_read_rval].p_size) * ((unsigned long long)vt->efi_lbasize); pbasicvolinfo->m_uhsectorsz = vt->efi_lbasize; } bretval = true; //} //else //{ // DebugPrintf(SV_LOG_ERROR,"@ LINE %d in FILE %s, vt->efi_version is not EFI_VERSION_CURRENT\n", LINE_NO, FILE_NAME); //} ptr_efi_free(vt); } /* end of if ((efi_alloc_and_read_rval >= 0) && vt) */ else { DebugPrintf(SV_LOG_WARNING, "@LINE %d in FILE %s efi_alloc_and_read on %s failed\n", __LINE__, __FILE__, sRawVolName.c_str()); } } /* end if of if (pv_efi_alloc_and_read && pv_efi_free) */ else { DebugPrintf(SV_LOG_WARNING, "@LINE %d in FILE %s efi_free or efi_alloc_and_read are not present in libefi.so\n", __LINE__, __FILE__); } dlclose(libefihandle); } /* end of if (libefihandle) */ else { DebugPrintf(SV_LOG_WARNING, "@LINE %d in FILE %s libefi.so is not present on system\n", __LINE__, __FILE__); } return bretval; } bool IsFullEFIRawDisk(const char *disk) { bool bretval = false; if (disk) { const std::string RDSKPREFIX = "/dev/rdsk/"; if (!strncmp(disk, RDSKPREFIX.c_str(), strlen(RDSKPREFIX.c_str()))) { size_t len = strlen(disk); const char *p = disk + (len - 1); while (p >= disk) { if (isdigit(*p)) { p--; } else { bretval = ('d' == *p)?true:false; break; } } } } return bretval; } #endif /* SV_SUN_5DOT8 */ std::string GetRawVolumeName(const std::string &dskname) { std::string rdskname = dskname; boost::algorithm::replace_first(rdskname, DSKDIR, RDSKDIR); boost::algorithm::replace_first(rdskname, DMPDIR, RDMPDIR); return rdskname; } std::string GetBlockVolumeName(const std::string &rdskname) { std::string dskname = rdskname; boost::algorithm::replace_first(dskname, RDSKDIR, DSKDIR); boost::algorithm::replace_first(dskname, RDMPDIR, DMPDIR); return dskname; } /* SUN */ bool IsProcessRunning(const std::string &sProcessName) { const char *procdir = "/proc"; /* standard /proc directory */ bool rv = false; psinfo_t info; /* process information structure from /proc */ DIR *dirp; size_t pdlen; char psname[PSNAMELEN]; struct dirent *dentp; int cnt = 0; do { if ((dirp = opendir(procdir)) == NULL) { printf("Failed Opening proc directory \n"); rv = false; break; } (void) inm_strcpy_s(psname, ARRAYSIZE(psname), procdir); pdlen = strlen(psname); psname[pdlen++] = '/'; /* for each active process --- */ while (dentp = readdir(dirp)) { int psfd; /* file descriptor for /proc/nnnnn/stat */ if (dentp->d_name[0] == '.') /* skip . and .. */ continue; (void) inm_strcpy_s(psname + pdlen, ARRAYSIZE(psname) - pdlen, dentp->d_name); (void) inm_strcat_s(psname, ARRAYSIZE(psname), "/psinfo"); if ((psfd = open(psname, O_RDONLY)) == -1) continue; memset(&info, 0, sizeof info); ssize_t bytesread = read(psfd, &info, sizeof (info)); (void) close(psfd); if (bytesread == sizeof (info)) { if (0 == strcmp(sProcessName.c_str(), info.pr_fname)) { cnt++; if (cnt > 1) { rv = true; break; } } } } closedir(dirp); }while(0); return rv; } unsigned long long GetSizeThroughRead(int fd, const std::string &device) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s with fd = %d and device = %s\n", FUNCTION_NAME, fd, device.c_str()); char buf[DEV_BSIZE]; diskaddr_t read_failed_from_top = 0; diskaddr_t read_succeeded_from_bottom = 0; diskaddr_t current_file_position; unsigned long long sizefromread = 0; off_t lseekrval = 0; int fd_dsk = -1; if (((lseek(fd, (offset_t)0, SEEK_SET)) == -1) || ((read(fd, buf, DEV_BSIZE)) == -1)) { DebugPrintf(SV_LOG_ERROR,"@ LINE %d in FILE %s, lseek failed for device %s with errno = %d\n", LINE_NO, FILE_NAME, device.c_str(), errno); return 0; } for (current_file_position = NUM_SECTORS_PER_TB * 4; read_failed_from_top == 0 && current_file_position < SIZE_LIMIT_TOP; current_file_position += 4 * NUM_SECTORS_PER_TB) { if (((lseek(fd, (offset_t)(current_file_position * DEV_BSIZE), SEEK_SET)) == -1) || ((read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)) { read_failed_from_top = current_file_position; } else { read_succeeded_from_bottom = current_file_position; } } if (read_failed_from_top == 0) { DebugPrintf(SV_LOG_ERROR,"@ LINE %d in FILE %s, read failed for device %s with errno = %d\n", LINE_NO, FILE_NAME, device.c_str(), errno); return 0; } while (read_failed_from_top - read_succeeded_from_bottom > 1) { current_file_position = read_succeeded_from_bottom + (read_failed_from_top - read_succeeded_from_bottom)/2; if (((lseek(fd, (offset_t)(current_file_position * DEV_BSIZE), SEEK_SET)) == -1) || ((read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)) { read_failed_from_top = current_file_position; } else { read_succeeded_from_bottom = current_file_position; } } sizefromread = (((unsigned long long)(read_succeeded_from_bottom + 1)) * ((unsigned long long)DEV_BSIZE)); /* DebugPrintf(SV_LOG_DEBUG,"@ LINE %d in FILE %s, size of device %s from read = %llu\n", LINE_NO, FILE_NAME, device.c_str(), sizefromread); */ DebugPrintf(SV_LOG_DEBUG,"EXITED %s with size = %llu for device %s\n",FUNCTION_NAME, sizefromread, device.c_str()); return sizefromread; } /* SUN */ bool MountDevice(const std::string& device,const std::string& mountPoint,const std::string& fsType,bool bSetReadOnly, int &exitCode, std::string &errorMsg) { if ( mountPoint.empty()) { std::stringstream strerr; strerr << "Empty mountpoint specified."; strerr << "Cannot mount device " << device << '\n'; DebugPrintf(SV_LOG_ERROR,"%s", strerr.str().c_str()); errorMsg = strerr.str(); return false; } std::string errmsg; if(!IsValidMountPoint(mountPoint,errmsg)) { std::stringstream strerr; strerr << "Cannot mount device " << device << " on mount point " << mountPoint << ". " << errmsg << "\n"; DebugPrintf(SV_LOG_ERROR,"%s", strerr.str().c_str()); errorMsg = strerr.str(); return false; } if(SVMakeSureDirectoryPathExists(mountPoint.c_str()).failed()) { std::stringstream strerr; strerr << "Failed to create mount point directory " << mountPoint << '\n'; DebugPrintf(SV_LOG_ERROR,"%s", strerr.str().c_str()); errorMsg = strerr.str(); return false; } bool bCanMount = false; bool remount = false; std::string flag; if(bSetReadOnly) flag="ro "; else flag="rw "; std::string sFileSystem = fsType; if(sFileSystem == "") { /* NEEDTOASK: * Linux handles this situation by specifying * auto as the filesystem. There is not equivalent * of auto in solaris. No manual page mentions about autofs * being similar to auto filesystem type in linux. * (linux manual page recommends against use of auto) * and even if we mount using autofs, it gets mounted * but ls on mountpoint hangs * sFileSystem = "autofs"; */ std::stringstream strerr; strerr << "The filesystem supplied to mount is empty."; strerr << "Hence cannot mount device " << device << '\n'; DebugPrintf(SV_LOG_ERROR,"%s", strerr.str().c_str()); errorMsg = strerr.str(); return false; } std::string flags = flag; //This is used only in case of Uncomment FSTAB. flag gets updated with -o remount where as flags doesn't. std::string sMount = ""; std::string mode; if ( IsVolumeMounted(device,sMount,mode)) { if ( sMount == mountPoint) //need to check if mode is same or not. If the mode is same, we will say already mounted, else we will do ewmount { if ("ufs" == sFileSystem) { bCanMount = true; flag+="-o remount "; } else { std::stringstream strerr; strerr << "the device " << device << " is already mounted on " << sMount << '\n'; DebugPrintf(SV_LOG_ERROR,"%s", strerr.str().c_str()); errorMsg = strerr.str(); return false; } } else { bCanMount = false; std::stringstream strerr; strerr << "Failed to unhide volume " << "since already visible on mount point " << sMount << " and requested mount point is " << mountPoint << '\n'; DebugPrintf(SV_LOG_ERROR,"%s", strerr.str().c_str()); errorMsg = strerr.str(); return false; } } else /* volume is not mounted */ { bCanMount = true; } if ( bCanMount) { sFileSystem = ToLower(sFileSystem); if(!strcmp(sFileSystem.c_str(),"fat32") || !strcmp(sFileSystem.c_str(),"fat") || !strcmp(sFileSystem.c_str(), "vfat")) { sFileSystem = "pcfs"; } std::string fsmount; /* mount -F pcfs -o rw special mntpoint */ fsmount += MOUNT_COMMAND; fsmount += " "; fsmount += OPTION_TO_SPECIFY_FILESYSTEM; fsmount += " "; fsmount += sFileSystem.c_str(); fsmount += " -o "; fsmount += flag ; fsmount += " "; fsmount += device.c_str() ; fsmount += " "; fsmount += "\""; fsmount += mountPoint.c_str() ; fsmount += "\""; DebugPrintf(SV_LOG_DEBUG, "@ LINE %d in FILE %s THE MOUNT COMMAND FORMED is %s\n", LINE_NO, FILE_NAME, fsmount.c_str()); std::string fsck_replay; std::string fsck_full; // For vxfs filesystems, we need to run fsck // with log replay when trying to perform mount // on a non frozen source image (ie without issuing a tag) // log replay: fsck -F vxfs -y special fsck_replay += FSCK_COMMAND; fsck_replay += " "; fsck_replay += FSCK_FS_OPTION ; fsck_replay += " "; fsck_replay += sFileSystem.c_str(); fsck_replay += " -y "; fsck_replay += device.c_str() ; // full fsck: fsck -F vxfs -y -o full,nolog special fsck_full += FSCK_COMMAND; fsck_full += " "; fsck_full += FSCK_FS_OPTION ; fsck_full += " "; fsck_full += sFileSystem.c_str(); fsck_full += " -y "; fsck_full += FSCK_FULL_OPTION ; fsck_full += " "; fsck_full += device.c_str() ; if(flag!=flags) remount=true; int retriesformount = 0; bool mounted = false; bool fsck_replay_done = false; bool fsck_full_done = false; // fsck needs to be done only for vxfs when performing // read write mount. in other cases, we will set // fsck done as true so it does not get executed if(bSetReadOnly || strcmp(sFileSystem.c_str(),"vxfs")) { fsck_replay_done = true; fsck_full_done = true; } do { DebugPrintf(SV_LOG_INFO, "executing %s...\n", fsmount.c_str()); mounted = ExecuteInmCommand(fsmount, errorMsg, exitCode); if (mounted) { return true; } else { DebugPrintf(SV_LOG_DEBUG, "mount %s with filesystem %s failed on %s with error message = %s. Retrying again\n", device.c_str(),sFileSystem.c_str(),mountPoint.c_str(), errorMsg.c_str()); } retriesformount++; if(!fsck_replay_done) { DebugPrintf(SV_LOG_INFO, "executing %s...\n", fsck_replay.c_str()); if(!ExecuteInmCommand(fsck_replay, errorMsg, exitCode)) { DebugPrintf(SV_LOG_INFO, "%s failed with exit code (%d) error message = %s.\n", fsck_replay.c_str(), exitCode, errorMsg.c_str()); } fsck_replay_done = true; continue; } if(!fsck_full_done) { DebugPrintf(SV_LOG_INFO, "executing %s...\n", fsck_full.c_str()); if(!ExecuteInmCommand(fsck_full, errorMsg, exitCode)) { DebugPrintf(SV_LOG_INFO, "%s failed with exit code (%d) error message = %s.\n", fsck_full.c_str(), exitCode, errorMsg.c_str()); } fsck_full_done = true; continue; } } while (retriesformount < RETRIES_FOR_MOUNT); DebugPrintf(SV_LOG_ERROR, "mount %s with filesystem %s failed on %s with error message = %s\n", device.c_str(),sFileSystem.c_str(),mountPoint.c_str(), errorMsg.c_str()); return false; } return true; } std::string GetExecdName(void) { std::string ExecdName; psinfo_t info; memset(&info, 0, sizeof info); pid_t pid = getpid(); std::stringstream proccessfile; proccessfile << "/proc/" << pid << "/psinfo"; int psfd; do { if ((psfd = open(proccessfile.str().c_str(), O_RDONLY)) == -1) break; if (read(psfd, &info, sizeof (info)) == sizeof (info)) { ExecdName = info.pr_fname; } (void) close(psfd); }while(false); return ExecdName; } bool IsNonGlobalZone(Pats &pats, std::string &hypervisorname, std::string &hypervisorvers) { bool bisnonglobal = false; DIR *dirp; dirp = opendir(GLOBALZONEDIR); if (dirp) { closedir(dirp); } else { hypervisorname = ZONEHYPERVISOR; bisnonglobal = true; } return bisnonglobal; } bool IsOpenVzVM(Pats &pats, std::string &hypervisorname, std::string &hypervisorvers) { bool bisvm = false; return bisvm; } bool IsVMFromCpuInfo(Pats &pats, std::string &hypervisorname, std::string &hypervisorvers) { bool bisvm = false; return bisvm; } bool IsXenVm(Pats &pats, std::string &hypervisorname, std::string &hypervisorvers) { bool bisvm = false; return bisvm; } bool IsNativeVm(Pats &pats, std::string &hypervisorname, std::string &hypervisorvers) { return IsNonGlobalZone(pats, hypervisorname, hypervisorvers); } void GetNicInfos(NicInfos_t & nicInfos) { bool bgotnicinfos = false; int sockfd = -1; DebugPrintf( SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME); sockfd = socket(PF_INET, SOCK_DGRAM, 0); if (-1 != sockfd) { struct lifnum num; int ioctlrval = -1; num.lifn_family = AF_INET; num.lifn_flags = 0; ioctlrval = ioctl(sockfd, SIOCGLIFNUM, &num); if (!ioctlrval) { DebugPrintf(SV_LOG_DEBUG, "number of network interfaces = %d\n", num.lifn_count); struct lifconf lic; lic.lifc_family = AF_INET; lic.lifc_flags = 0; INM_SAFE_ARITHMETIC(lic.lifc_len = (num.lifn_count * InmSafeInt<size_t>::Type(sizeof (struct lifreq))), INMAGE_EX(num.lifn_count)(sizeof (struct lifreq))) lic.lifc_req = (struct lifreq *)calloc(lic.lifc_len, 1); if (lic.lifc_req) { ioctlrval = ioctl(sockfd, SIOCGLIFCONF, &lic); if (!ioctlrval) { bgotnicinfos = FillNicInfos(sockfd, &lic, &num, nicInfos); } else { DebugPrintf(SV_LOG_ERROR, "ioctl SIOCGLIFCONF failed with errno = %d\n", errno); } free(lic.lifc_req); } else { DebugPrintf(SV_LOG_ERROR, "calloc to allocate memory for network interfaces failed with errno = %d\n", errno); } } else { DebugPrintf(SV_LOG_ERROR, "ioctl SIOCGLIFNUM failed with errno = %d\n", errno); } close(sockfd); } else { DebugPrintf(SV_LOG_ERROR, "socket call failed with errno = %d\n", errno); } if (bgotnicinfos) { std::string gws = GetDefaultGateways(NSNicInfo::DELIM); DebugPrintf(SV_LOG_DEBUG, "gateways = %s\n", gws.c_str()); if (!gws.empty()) { UpdateNicInfoAttr(NSNicInfo::DEFAULT_IP_GATEWAYS, gws, nicInfos); } std::string nameservers = GetNameServerAddresses(NSNicInfo::DELIM); DebugPrintf(SV_LOG_DEBUG, "nameserver ip addresses = %s\n", nameservers.c_str()); if (!nameservers.empty()) { UpdateNicInfoAttr(NSNicInfo::DNS_SERVER_ADDRESSES, nameservers, nicInfos); } } else { DebugPrintf(SV_LOG_ERROR, "cannot collect the network interfaces information\n"); } DebugPrintf( SV_LOG_DEBUG, "EXITING %s\n", FUNCTION_NAME); } bool FillNicInfos(const int &sockfd, struct lifconf *plic, struct lifnum *pnum, NicInfos_t & nicInfos) { bool bfillnicinfos = true; char ipaddr[INET_ADDRSTRLEN] = "\0"; const char *prval = NULL; struct sockaddr_in *sa = NULL; bool bcollect; DebugPrintf( SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME); for (int i = 0; i < pnum->lifn_count; i++) { sa = (struct sockaddr_in *)&(plic->lifc_req[i].lifr_addr); prval = inet_ntop(AF_INET, &(sa->sin_addr.s_addr), ipaddr, sizeof ipaddr); if (prval) { bcollect = ShouldCollectNicInfo(sockfd, plic->lifc_req + i, ipaddr); if (bcollect) { std::string hardwareaddress; std::string netmask; E_INM_TRISTATE isdhcpenabled = E_INM_TRISTATE_FLOATING; GetNetIfParameters(plic->lifc_req[i].lifr_name, hardwareaddress, netmask, isdhcpenabled); if (hardwareaddress.empty()) { continue; } InsertNicInfo(nicInfos, plic->lifc_req[i].lifr_name, hardwareaddress, ipaddr, netmask, isdhcpenabled); } else { DebugPrintf(SV_LOG_DEBUG, "Not collecting information for nic %s\n", plic->lifc_req[i].lifr_name); } } else { DebugPrintf(SV_LOG_ERROR, "converting network ip address for interface %s to" " readble string failed with errno = %d." " processing next interface if available\n", plic->lifc_req[i].lifr_name, errno); } } /* for */ DebugPrintf( SV_LOG_DEBUG, "EXITING %s\n", FUNCTION_NAME); return bfillnicinfos; } void GetNetIfParameters(const std::string &ifrName, std::string& hardwareAddress, std::string &netmask, E_INM_TRISTATE &isdhcpenabled) { /* Place holder function */ throw std::string("GetNetIfParameters is an obsolete now."); } bool ShouldCollectNicInfo(const int &sockfd, struct lifreq *plifr, const char *ipaddr) { bool bshouldcollect = false; int ioctlrval = -1; DebugPrintf( SV_LOG_DEBUG, "ENTERED %s\n", FUNCTION_NAME); ioctlrval = ioctl(sockfd, SIOCGLIFFLAGS, plifr); if (!ioctlrval) { if (plifr->lifr_flags & IFF_UP) { bshouldcollect = !(plifr->lifr_flags & IFF_LOOPBACK); } } else { DebugPrintf(SV_LOG_ERROR, "ioctl SIOCGLIFFLAGS failed on interface %s." " However trying to report IP and Interface name\n", plifr->lifr_name); bshouldcollect = true; } if (bshouldcollect) { bshouldcollect = IsValidIP(ipaddr); } DebugPrintf( SV_LOG_DEBUG, "EXITING %s\n", FUNCTION_NAME); return bshouldcollect; } SV_ULONGLONG GetTotalFileSystemSpace(const struct statvfs64 &vfs) { SV_ULONGLONG space = ((SV_ULONGLONG)vfs.f_blocks) * ((SV_ULONGLONG)vfs.f_frsize); return space; } SV_ULONGLONG GetFreeFileSystemSpace(const struct statvfs64 &vfs) { SV_ULONGLONG space = ((SV_ULONGLONG)vfs.f_bavail) * ((SV_ULONGLONG)vfs.f_frsize); return space; } bool GetBasicVolInfoForP0(const int &fd, const std::string &sDevName, SV_BASIC_VOLINFO *pbasicvolinfo) { DebugPrintf(SV_LOG_DEBUG, "ENTERED %s with disk name %s\n", FUNCTION_NAME, sDevName.c_str()); bool bgotbasicvolinfo = false; struct dk_minfo mi; struct part_info pi; memset(&pi, 0, sizeof pi); memset(&mi, 0, sizeof mi); unsigned long long secsize = NBPSCTR; int mirval = ioctl(fd, DKIOCGMEDIAINFO, &mi); if (0 == mirval) { secsize = mi.dki_lbsize; } else { DebugPrintf(SV_LOG_ERROR, "For %s, ioctl DKIOCGMEDIAINFO failed with errno = %d, " "while getting size for fdisk p0\n", sDevName.c_str(), errno); } unsigned long long size = 0; unsigned long long nsecs = 0; int pirval = ioctl(fd, DKIOCPARTINFO, &pi); if (0 == pirval) { nsecs = pi.p_length; size = nsecs * secsize; if (size) { pbasicvolinfo->m_ullrawsize = size; pbasicvolinfo->m_uhsectorsz = secsize; pbasicvolinfo->m_lnumblocks = nsecs; pbasicvolinfo->m_breadonly = false; bgotbasicvolinfo = true; DebugPrintf(SV_LOG_DEBUG, "For %s, size got is " ULLSPEC " for fdisk p0\n", sDevName.c_str(), size); } else { DebugPrintf(SV_LOG_ERROR, "For %s, size got is zero for fdisk p0\n", sDevName.c_str()); } } else { DebugPrintf(SV_LOG_ERROR, "For %s, ioctl DKIOCPARTINFO failed with errno = %d for fdisk p0\n", sDevName.c_str(), errno); } DebugPrintf(SV_LOG_DEBUG, "EXITED %s with disk name %s\n", FUNCTION_NAME, sDevName.c_str()); return bgotbasicvolinfo; } unsigned long long GiveValidSize(const std::string &device, const unsigned long long nsecs, const unsigned long long secsz, const E_VERIFYSIZEAT everifysizeat) { unsigned long long size = 0; int fd = open(device.c_str(), O_RDONLY); if (-1 != fd) { bool bisreadable = IsDeviceReadable(fd, device, nsecs, secsz, everifysizeat); bool bshouldbrute = bisreadable ? (E_ATMORETHANSIZE == everifysizeat) : (E_ATLESSTHANSIZE == everifysizeat); if (bshouldbrute) { DebugPrintf(SV_LOG_WARNING, "For device: %s, size: " ULLSPEC " is invalid. Getting size by reading\n", device.c_str(), nsecs * secsz); size = GetSizeThroughRead(fd, device); DebugPrintf(SV_LOG_DEBUG, "For device: %s, size is " ULLSPEC " is got by reading\n", device.c_str(), size); } else { size = nsecs * secsz; } close(fd); } return size; } int SVgetmntent(FILE *fp, struct mnttab *mp,char* buffer,int buflength) { /* place holder function */ throw std::string("SVgetmntent is an obsolete now."); return 0; } bool RemoveVgWithAllLvsForVsnap(const std::string & device,std::string& output, std::string& error,bool needvgcleanup) { return true; } bool GetZpoolsWithStorageDevices(ZpoolsWithStorageDevices_t &zpoolswithstoragedevices) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); std::string cmd("/usr/sbin/zpool status 2> /dev/null | /usr/bin/grep -v \'^$\'"); std::stringstream results; if (!executePipe(cmd, results)) { DebugPrintf(SV_LOG_ERROR,"Unable to run zpool status. vsnaps will not be deleted. please try again\n"); return false; } if (results.str().empty()) { DebugPrintf(SV_LOG_DEBUG,"EXITING %s with retval true. since zpool status has given empty output\n",FUNCTION_NAME); return true; } const std::string POOLNAMETOKEN = "pool:"; std::string::size_type prevPoolIdx, nextPoolIdx; //find first pool prevPoolIdx = results.str().find(POOLNAMETOKEN, 0); if (std::string::npos == prevPoolIdx) { DebugPrintf(SV_LOG_DEBUG,"EXITING %s with retval true. since zpool status has given no pools\n",FUNCTION_NAME); return true; } do { //exit condition: no more output to search for pools if (prevPoolIdx == results.str().length()) break; //find next pool nextPoolIdx = results.str().find(POOLNAMETOKEN, prevPoolIdx+1); //handle last pool if (std::string::npos == nextPoolIdx) nextPoolIdx = results.str().length(); std::stringstream zpoolstream(std::string(results.str().substr(prevPoolIdx, nextPoolIdx - prevPoolIdx))); prevPoolIdx = nextPoolIdx; GetZpoolStorageDevices(zpoolstream, zpoolswithstoragedevices); } while (!results.eof()); DebugPrintf(SV_LOG_DEBUG,"EXITING %s with retval as true\n",FUNCTION_NAME); return true; } void GetZpoolStorageDevices(std::stringstream &zpoolstream, ZpoolsWithStorageDevices_t &zpoolswithstoragedevices) { DebugPrintf(SV_LOG_DEBUG,"ENTERED %s\n",FUNCTION_NAME); DebugPrintf(SV_LOG_DEBUG, "============= ZPOOL START =============\n"); DebugPrintf(SV_LOG_DEBUG, "%s", zpoolstream.str().c_str()); DebugPrintf(SV_LOG_DEBUG, "============= ZPOOL END =============\n"); const std::string DskDir = "/dev/dsk/"; /* sample output: * ============= *(03-03-2014 12:55:02): DEBUG 17539 1 ============= ZPOOL START ============= *(03-03-2014 12:55:02): DEBUG 17539 1 pool: BUILDS * state: UNAVAIL *status: One or more devices are unavailable in response to persistent errors. * There are insufficient replicas for the pool to continue functioning. *action: Destroy and re-create the pool from a backup source. Manually marking * the device repaired using 'zpool clear' or 'fmadm repaired' may * allow some data to be * recovered. * Run 'zpool status -v' to see device specific details. * scan: none requested *config: * NAME STATE READ WRITE CKSUM * BUILDS UNAVAIL 0 0 0 * c8t1d0 UNAVAIL 0 0 0 * (03-03-2014 12:55:02): DEBUG 17539 1 ============= ZPOOL END ============= *(03-03-2014 12:55:02): DEBUG 17539 1 ============= ZPOOL START ============= *(03-03-2014 12:55:02): DEBUG 17539 1 pool: rpool * state: ONLINE * scan: none requested *config: * NAME STATE READ WRITE CKSUM * rpool ONLINE 0 0 0 * c8t0d0 ONLINE 0 0 0 *errors: No known data errors *(03-03-2014 12:55:02): DEBUG 17539 1 ============= ZPOOL END ============= */ //poolname std::string poollabel, poolname; zpoolstream >> poollabel; std::getline(zpoolstream, poolname); Trim(poolname, " "); //reach state: std::string tmpstr; while (!zpoolstream.eof()) { std::getline(zpoolstream, tmpstr); if (tmpstr.empty()) break; Trim(tmpstr, " "); if (0 == tmpstr.find("state:")) break; tmpstr.clear(); } std::stringstream ssstate(tmpstr); std::string state; ssstate >> tmpstr >> state; DebugPrintf(SV_LOG_DEBUG, "poollabel %s, poolname %s, state %s\n", poollabel.c_str(), poolname.c_str(), state.c_str()); /* collect only online pools */ if (("pool:" == poollabel) && !poolname.empty() && ("ONLINE" == state)) { std::pair<ZpoolsWithStorageDevicesIter_t, bool> p = zpoolswithstoragedevices.insert(std::make_pair(poolname, svector_t())); ZpoolsWithStorageDevicesIter_t it = p.first; svector_t &storagedevices = it->second; //reach config: tmpstr.clear(); while (!zpoolstream.eof()) { std::getline(zpoolstream, tmpstr); if (tmpstr.empty()) break; Trim(tmpstr, " "); if (0 == tmpstr.find("config:")) break; tmpstr.clear(); } //reach NAME STATE READ WRITE CKSUM tmpstr.clear(); while (!zpoolstream.eof()) { std::getline(zpoolstream, tmpstr); if (tmpstr.empty()) break; Trim(tmpstr, " \t"); if ((0 == tmpstr.find("NAME")) && (std::string::npos != tmpstr.find("STATE"))) break; tmpstr.clear(); } //skip "rpool ONLINE 0 0 0" line zpoolstream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //pick the first devices until end is reached or errors: is reached. tmpstr.clear(); while (!zpoolstream.eof()) { std::getline(zpoolstream, tmpstr); if (tmpstr.empty()) break; Trim(tmpstr, " \t"); if (0 == tmpstr.find("errors:")) break; std::stringstream ssdeviceline(tmpstr); std::string storagedevice; ssdeviceline >> storagedevice; if (0 != storagedevice.find('/')) storagedevice = DskDir + storagedevice; storagedevices.push_back(storagedevice); tmpstr.clear(); } } else DebugPrintf(SV_LOG_DEBUG, "No pool name or offline pool found\n"); DebugPrintf(SV_LOG_DEBUG,"EXITED %s\n",FUNCTION_NAME); } void PrintZpoolsWithStorageDevices(const ZpoolsWithStorageDevices_t &zpoolswithstoragedevices) { for (ConstZpoolsWithStorageDevicesIter_t cit = zpoolswithstoragedevices.begin(); cit != zpoolswithstoragedevices.end(); cit++) { const std::string &poolname = cit->first; const svector_t &storagedevices = cit->second; DebugPrintf(SV_LOG_DEBUG, "poolname %s has below devices:\n", poolname.c_str()); for_each(storagedevices.begin(), storagedevices.end(), PrintString); DebugPrintf(SV_LOG_DEBUG, "==============\n"); } }