在查看虚拟磁盘文件系统的时候,需要将虚拟磁盘挂载到主机上,VMware提供了相应的接口——Virtual Disk Mount API
这部分遇到了几个坑,记录一下,也算是对做相同或相似工作的人提个醒,遇到了这些问题能够绕过去。
首先安装VDDK,参照如下链接:
https://code.vmware.com/doc/preview?id=1497#/doc/vddkInstall.4.3.html
其次,VDDK安装完成后就可以开始编码了,如果在后续的编译或执行过程中遇到了问题,请参照下面这位小哥的博客:
https://blog.csdn.net/zhouxukun123/article/category/7140664
使用Virtual Disk Mount API可以将一个本地的虚拟磁盘文件挂载到本地,也可以将一个ESXi上虚拟机的虚拟磁盘文件挂载到本地。挂载的过程大致分为如下几个步骤(以本地vmdk文件的挂载为例):
1.初始化
vixError = VixDiskLib_InitEx(VERSION_MAJOR, VERSION_MINOR, &LogFunc, &WarnFunc, &PanicFunc, libdir, NULL);
VERSION_MAJOR、VERSION_MINOR分别对应你下载的VDDK的主次版本号
vixError = VixMntapi_Init(VIXMNTAPI_MAJOR_VERSION, VIXMNTAPI_MINOR_VERSION, &LogFunc, &WarnFunc, &PanicFunc, libdir, NULL);
这个函数中前两个参数的宏定义在vixMntapi.h中,分别为1和0
2.建立连接,获取VixDiskLibConnection
如果是本地vmdk文件:
vixError = VixDiskLib_Connect(NULL, &connection);
如果是远程虚拟机:
vixError = VixDiskLib_Connect(&cnxParam, &connection);
3.打开磁盘,获取VixDiskSetHandle
vixError = VixMntapi_OpenDisks(connection,diskNames, diskHandlesCount, openFlag, &diskSetHandle);
其中diskNames的类型为const char *diskNames[],是需要打开的各个vmdk文件的绝对路径的数组。diskHandlesCount在Linux下为1。成功之后可以用VixMntapi_GetDiskSetInfo查看虚拟磁盘的挂载路径
4.获取虚拟磁盘分区的句柄
vixError = VixMntapi_GetVolumeHandles(diskSetHandle, &numVolumes, &volumeHandles);
执行成功则返回分区个数numVolumes和分区句柄的数组volumeHandles
5.挂载分区
vixError = VixMntapi_MountVolume(volumeHandles[i], FALSE);
6.获取分区挂载位置
vixError = VixMntapi_GetVolumeInfo(volumeHandles[i], &newVolume.volInfo);
7.卸载分区
VixMntapi_DismountVolume(volumeHandles[i],TRUE);
8.关闭虚拟磁盘
vixError=VixMntapi_CloseDiskSet(diskSetHandle);
9.清理工作
vixError = VixDiskLib_Disconnect(connection);
VixMntapi_Exit();
大致就是这样的步骤,遇到的几个问题在下面罗列一下:
圈1.初始化
注意初始化时候的版本号,vix Mnt api的版本号一定为1和0。
圈2.打开虚拟磁盘
函数
VixMntapi_OpenDisks(VixDiskLibConnection connection,
const char *diskNames[],
size_t numberOfDisks,
uint32 openFlags,
VixDiskSetHandle *handle);
其参数说明如下:
/**
* Opens the set of disks for mounting.
* @param connection [in] VixDiskLibConnection to use for opening the disks.
* VixDiskLib_Open with the specified flags will be called on each
* disk to open.
* @param diskNames [in] Array of names of disks to open.
* @param numberOfDisks [in] Number of disk handles in the array.
* Must be 1 for Linux.
* @param flags [in] Flags to open the disk.
* @param handle [out] Disk set handle filled in.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
一是要注意numberOfDisks在Linux下为1;
二是建议flags置0、置0、置0!!!这个地方坑我很惨,如果以只读模式打开会造成分区无法挂载的问题。实际上挂载后会修改xxx.vmdk(虚拟磁盘的配置文件)的CID字段和ddb.longContentID字段,对应的xxx-flat.vmdk(虚拟磁盘的二进制数据)文件也会被修改,如果开启了块修改追踪,对应的xxx-ctk.vmdk也会被修改。
圈3.挂载分区
函数
VixMntapi_MountVolume(VixVolumeHandle volumeHandle,
Bool readOnly);
在Linux下不支持只读模式的分区挂载,第二个参数置为FALSE。
最后贴上完整的代码:
//#pragma comment(lib, "vixDiskLib.lib")
//#pragma comment(lib, "vixMntapi.lib")
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#include <process.h>
#else
#include <dlfcn.h>
#include <sys/time.h>
#endif
//#include "ChangedBlock.h"
#include "util.h"
#include <time.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <stdexcept>
#include <cstring>
#include <unistd.h>
#include "vixDiskLib.h"
#include "vixMntapi.h"
using namespace std;
#define VERSION_MAJOR 6
#define VERSION_MINOR 0
#define ERROR_MNTAPI_VOLUME_ALREADY_MOUNTED 24305
static void LogFunc(const char *fmt, va_list args);
static void WarnFunc(const char *fmt, va_list args);
static void PanicFunc(const char *fmt, va_list args);
typedef struct {
VixVolumeHandle volumeHandle;
VixVolumeInfo* volInfo;
} MountedVolume;
int main() {
VixError vixError;
char libdir[] = {"/xxx/vmware-vix-disklib-distrib"};
char host[] = {"xxx.vm.com"};
char userName[] = {"xxx"};
char password[] = {"xxx"};
char vmPath[] = {"vmPath=datacenter/vm/xxx"};
char thumbPrint[] = {"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"};
VixDiskLibConnectParams cnxParam = {0};
cnxParam.credType = VIXDISKLIB_CRED_UID;
cnxParam.serverName = host;
cnxParam.creds.uid.userName = userName;
cnxParam.creds.uid.password = password;
cnxParam.port = 443;
cnxParam.vmxSpec = vmPath;
cnxParam.thumbPrint = thumbPrint;
//////TEST MNT API//////
VixDiskLibConnection connection = NULL;
const int diskHandlesCount=1;
uint32 openFlags = VIXDISKLIB_FLAG_OPEN_READ_ONLY;
VixDiskSetHandle diskSetHandle = NULL;
const char *diskNames[diskHandlesCount];
diskNames[0]="/mnt/home/zcy/xxx/xxx.vmdk";
VixDiskSetInfo *diskSetInfo = NULL;
VixVolumeHandle *volumeHandles = NULL;
size_t numVolumes = 0;
//VixDiskLib_InitEx
vixError = VixDiskLib_InitEx(VERSION_MAJOR, VERSION_MINOR, &LogFunc, &WarnFunc, &PanicFunc, libdir, NULL);
printf("VixDiskLib_InitEx %d\n", vixError);
if (vixError != VIX_OK) {
printf("VixDiskLib_InitEx failed\n");
exit(0);
}
printf("VixDiskLib_InitEx success\n");
//VixMntapi_Init
vixError = VixMntapi_Init(VIXMNTAPI_MAJOR_VERSION, VIXMNTAPI_MINOR_VERSION, &LogFunc, &WarnFunc, &PanicFunc, libdir, NULL);
printf("VixMntapi_Init %d\n", vixError);
if (vixError != VIX_OK) {
printf("VixMntapi_Init failed\n");
exit(0);
}
printf("VixMntapi_Init success\n");
///////////////////////连接选项////////////////////////
//if remote connection
// vixError = VixDiskLib_Connect(&cnxParam, &connection);
//if local connection
vixError = VixDiskLib_Connect(NULL, &connection);
////////////////////////////////////////////////////////
if(vixError!=VIX_OK){
printf("VixDiskLib_Connect failed\n");
goto SAFE_EXIT;
}
printf("VixDiskLib_Connect success\n");
//open vmdks, obtain diskSetHandle
//openFlag must be zero
vixError = VixMntapi_OpenDisks(connection,diskNames, diskHandlesCount, 0, &diskSetHandle);
if(vixError!=VIX_OK){
printf("VixMntapi_OpenDisks failed\n");
goto SAFE_EXIT;
}
printf("\n####WATCH ME####\n");
printf("diskSetHandle is %p\n",diskSetHandle);
printf("\n################\n");
printf("VixMntapi_OpenDisks success\n");
//get diskset info
vixError = VixMntapi_GetDiskSetInfo(diskSetHandle, &diskSetInfo);
if(vixError!=VIX_OK){
printf("VixMntapi_GetDiskSetInfo failed\n");
goto SAFE_EXIT;
}
printf("VixMntapi_GetDiskSetInfo success\n");
printf("DiskSet Info - flags %u (passed - %u), mountPoint %s.\n",
diskSetInfo->openFlags, openFlags,
diskSetInfo->mountPath);
//get volume handle
vixError = VixMntapi_GetVolumeHandles(diskSetHandle, &numVolumes, &volumeHandles);
printf("\n####WATCH ME####\n");
printf("numVolumes is %d\n",numVolumes);
printf("\n################\n");
if(vixError!=VIX_OK){
printf("VixMntapi_GetVolumeHandles failed\n");
goto SAFE_EXIT;
}
printf("VixMntapi_GetVolumeHandles success\n");
for (int i = 0; i < numVolumes; ++i) {
printf("\n####WATCH ME####\n");
printf("volumeHandles[%d] is %p\n",i,volumeHandles[i]);
printf("\n################\n");
}
//mount volume
for (int i = 0; i < numVolumes; i++) {
printf("\n\nMounting volume using VixMntapi_MountVolume...\n");
vixError = VixMntapi_MountVolume(volumeHandles[i], FALSE);
if(vixError==VIX_OK){
printf("mount volume %d success\n",i);
continue;
}
else{
if (vixError == ERROR_MNTAPI_VOLUME_ALREADY_MOUNTED)
printf("volume %d already mounted\n",i);
else
goto SAFE_EXIT;
}
}
//get volume info
for(int i=0;i<numVolumes;i++){
printf("\n\nGetting volume info using VixMntapi_GetVolumeInfo...\n");
MountedVolume newVolume = {0, 0};
vixError = VixMntapi_GetVolumeInfo(volumeHandles[i], &newVolume.volInfo);
if(vixError!=VIX_OK){
printf("VixMntapi_GetVolumeInfo failed\n");
goto SAFE_EXIT;
}
printf("VixMntapi_GetVolumeInfo success\n");
printf("\nMounted Volume %d, Type %d, isMounted %d, symLink %s, numGuestMountPoints %d (%s)\n\n",
i, newVolume.volInfo->type, newVolume.volInfo->isMounted,
newVolume.volInfo->symbolicLink == NULL ? "<null>" : newVolume.volInfo->symbolicLink,
newVolume.volInfo->numGuestMountPoints,
(newVolume.volInfo->numGuestMountPoints == 1) ? (newVolume.volInfo->inGuestMountPoints[0]) : "<null>" );
}
///////////////
SAFE_EXIT:
printf("Cleanup Stuff:\n");
if(diskSetInfo!=NULL){
VixMntapi_FreeDiskSetInfo(diskSetInfo);
printf("VixMntapi_FreeDiskSetInfo\n");
}
printf("dismount volumes?(y/n)");
char dismountOption='y';
scanf("%c",&dismountOption);
if(dismountOption=='y'||dismountOption=='Y'){
if (numVolumes!=0){
for (int (i) = 0; (i) < numVolumes; ++(i)) {
printf("dismount volume %d\n",i);
VixMntapi_DismountVolume(volumeHandles[i],TRUE);
}
}
if(diskSetHandle){
vixError=VixMntapi_CloseDiskSet(diskSetHandle);
printf("VixMntapi_CloseDiskSet\n");
}
}
if (connection != NULL) {
vixError = VixDiskLib_Disconnect(connection);
printf("VixDiskLib_Disconnect\n");
}
VixMntapi_Exit();
printf("VixMntapi_Exit\n");
return 0;
}
/*
*--------------------------------------------------------------------------
*
* LogFunc --
*
* Callback for VixDiskLib Log messages.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------------------
*/
static void
LogFunc(const char *fmt, va_list args) {
printf("Log: ");
vprintf(fmt, args);
}
/*
*--------------------------------------------------------------------------
*
* WarnFunc --
*
* Callback for VixDiskLib Warning messages.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------------------
*/
static void
WarnFunc(const char *fmt, va_list args) {
printf("Warning: ");
vprintf(fmt, args);
}
/*
*--------------------------------------------------------------------------
*
* PanicFunc --
*
* Callback for VixDiskLib Panic messages.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------------------
*/
static void
PanicFunc(const char *fmt, va_list args) {
printf("Panic: ");
vprintf(fmt, args);
exit(10);
}