The function fails with PRL_ERR_FAILURE.
Here's what I found in parallels.log:
And this is the code that shows the problem. It looks for a running backupable machine and tries to back it up:
Here's what I found in parallels.log:
11-01 08:05:13.597 F /prldirs:2592:b76e/ ParallelsDirs::Init( ) was called. Current app mode = 1 ( DESKTOP ) build version: 19.1.0 (54729) Sat, 14 Oct 2023 10:05:20
11-01 08:05:13.691 W /[QT]:2592:b774/ WARNING: QApplication was not created in the main() thread.
11-01 08:05:13.737 F /disp:755:b777/ Client [Client] state changed [Connected] uuid [{5d198400-fc27-4a43-a96b-09c8a7de39b6}] pid [2592] uid [501]
11-01 08:05:13.743 F /disp:755:b777/ Processing command 'DspCmdUserLoginLocal' 2040 (PJOC_SRV_LOGIN_LOCAL) from client [{5d198400-fc27-4a43-a96b-09c8a7de39b6}]
11-01 08:05:13.751 F /disp:755:b777/ Processing command 'DspCmdUserLoginLocalStage2' 2041 (PJOC_SRV_LOGIN_LOCAL) from client [{5d198400-fc27-4a43-a96b-09c8a7de39b6}]
11-01 08:05:13.751 F /disp:755:b777/ Parallels user [tester@.] successfully logged on( LOCAL ). [sessionId = {5d198400-fc27-4a43-a96b-09c8a7de39b6}, Interactive]
11-01 08:05:13.756 F /disp:755:b777/ Session with uuid[ {5d198400-fc27-4a43-a96b-09c8a7de39b6} ] was started.
11-01 08:05:13.763 F /disp:755:b777/ Processing command 'DspCmdGetBackupVmList' 2188 (PJOC_UNKNOWN) from client [{5d198400-fc27-4a43-a96b-09c8a7de39b6}]
11-01 08:05:13.772 F /disp:755:b777/ Processing command 'DspCmdBackupBegin' 2185 (PJOC_UNKNOWN) from client [{5d198400-fc27-4a43-a96b-09c8a7de39b6}]
11-01 08:05:13.772 W /[QT]:755:b777/ QObject::connect: No such slot Dsp::Backup::CBackupBeginCommand::cancel()
11-01 08:05:13.780 F /DispBackup:755:18c0/ [DspBackup] Can't prepare VM for backup: event source is not accessible
11-01 08:05:13.780 F /DispBackup:755:18c0/ [DspBackup] Unable to begin the backup session '{b9d7093f-e24d-44cd-96c3-c4711e649ef3}': 0x80000009 (PRL_ERR_FAILURE)
11-01 08:05:13.780 F /DispBackup:755:18c0/ Failed to begin the backup: 0x80000009 (PRL_ERR_FAILURE)
11-01 08:05:13.780 F /DispBackup:755:18c0/ Failed to begin the backup: 0x80000009 (PRL_ERR_FAILURE)
11-01 08:05:13.784 F /disp:755:b777/ Client [Client] state changed [Disconnected] uuid [{5d198400-fc27-4a43-a96b-09c8a7de39b6}] pid [2592] uid [501]
And this is the code that shows the problem. It looks for a running backupable machine and tries to back it up:
Code:
#import <ParallelsVirtualizationSDK/Parallels.h>
#import <ParallelsVirtualizationSDK/PrlApiMacro.h>
#import <ParallelsVirtualizationSDK/PrlApiCore.h>
#import <assert.h>
#import <iostream>
#import <libgen.h>
namespace
{
void CheckPrlResult(PRL_RESULT result)
{
if (result == PRL_ERR_SUCCESS)
return;
std::cout << "Error: " << prl_result_to_string(result) << std::endl;
assert(false);
}
PRL_RESULT WaitJobResult(PRL_HANDLE job, PRL_HANDLE_PTR jobResult)
{
CheckPrlResult(PrlJob_Wait(job, 60000));
CheckPrlResult(PrlJob_GetResult(job, jobResult));
PRL_RESULT jobResultCode;
CheckPrlResult(PrlJob_GetRetCode(job, &jobResultCode));
return jobResultCode;
}
std::string MachineStateToString(VIRTUAL_MACHINE_STATE state)
{
switch (state)
{
case VMS_UNKNOWN: return "Unknown";
case VMS_STOPPED: return "Stopped";
case VMS_STARTING: return "Starting";
case VMS_RESTORING: return "Restoring";
case VMS_RUNNING: return "Running";
case VMS_PAUSED: return "Paused";
case VMS_SUSPENDING: return "Suspending";
case VMS_STOPPING: return "Stopping";
case VMS_COMPACTING: return "Compacting";
case VMS_SUSPENDED: return "Suspended";
case VMS_SNAPSHOTING: return "Snapshoting";
case VMS_RESETTING: return "Resetting";
case VMS_PAUSING: return "Pausing";
case VMS_CONTINUING: return "Continuing";
case VMS_MIGRATING_OBSOLETE: return "Migrating";
case VMS_DELETING_STATE: return "Deleting";
case VMS_RESUMING: return "Resuming";
case VMS_SUSPENDING_SYNC: return "Suspending sync";
case VMS_RECONNECTING_OBSOLETE: return "Reconnecting";
case VMS_MOUNTED_OBSOLETE: return "Mounted";
}
}
}
int main(int argc, const char * argv[])
{
CheckPrlResult(PrlApi_InitEx(PARALLELS_API_VER_5, PAM_DESKTOP, 0, 0));
PRL_HANDLE server;
CheckPrlResult(PrlSrv_Create(&server));
auto loginJob = PrlSrv_LoginLocal(server, nullptr, 0, PSL_NORMAL_SECURITY);
PRL_HANDLE loginResult;
CheckPrlResult(WaitJobResult(loginJob, &loginResult));
PRL_HANDLE loginResultParam;
CheckPrlResult(PrlResult_GetParam(loginResult, &loginResultParam));
PRL_UINT32 bufSize = 0;
CheckPrlResult(PrlLoginResponse_GetProductVersion(loginResultParam, nullptr, &bufSize));
char version[bufSize];
CheckPrlResult(PrlLoginResponse_GetProductVersion(loginResultParam, version, &bufSize));
std::cout << "Version: " << version << std::endl;
PrlHandle_Free(loginResultParam);
PrlHandle_Free(loginResult);
PrlHandle_Free(loginJob);
PRL_HANDLE listJob = PrlSrv_GetBackupVmList(server, 0);
PRL_HANDLE listResult;
CheckPrlResult(WaitJobResult(listJob, &listResult));
PRL_UINT32 machineCount;
CheckPrlResult(PrlResult_GetParamsCount(listResult, &machineCount));
std::cout << "Machines: " << machineCount << std::endl;
for (PRL_UINT32 i = 0; i < machineCount; i++)
{
std::cout << "Getting machine..." << std::endl;
PRL_HANDLE machineHandle;
CheckPrlResult(PrlResult_GetParamByIndex(listResult, i, &machineHandle));
std::cout << "Getting backup info..." << std::endl;
PRL_HANDLE backupInfo;
CheckPrlResult(PrlBackup_GetInfo(machineHandle, &backupInfo));
std::cout << "Getting machine state..." << std::endl;
VIRTUAL_MACHINE_STATE machineState;
CheckPrlResult(PrlBackupInfo_GetState(backupInfo, &machineState));
std::cout << "Machine state: " << MachineStateToString(machineState) << std::endl;
if (machineState == VMS_RUNNING)
{
std::cout << "Setting up backup..." << std::endl;
PRL_HANDLE params;
CheckPrlResult(PrlBackup_GetParams(machineHandle, ¶ms));
CheckPrlResult(PrlBackupParam_SetChangeMonitoring(params, PRL_TRUE));
CheckPrlResult(PrlBackupParam_SetLevel(params, PBL_FULL));
PRL_UINT32 options = PBOPT_DISABLE_GUEST_FS_SUSPEND;
CheckPrlResult(PrlBackupParam_SetOptions(params, options));
CheckPrlResult(PrlBackup_SetParams(machineHandle, params));
std::cout << "Starting backup..." << std::endl;
PRL_HANDLE backupJob = PrlBackup_Begin(machineHandle, 0);
PRL_HANDLE backupJobResult;
CheckPrlResult(WaitJobResult(backupJob, &backupJobResult));
PrlHandle_Free(backupJobResult);
PrlHandle_Free(backupJob);
PRL_HANDLE fileList;
CheckPrlResult(PrlBackup_GetFilesList(machineHandle, &fileList));
PRL_UINT32 fileCount;
CheckPrlResult(PrlHndlList_GetItemsCount(fileList, &fileCount));
std::cout << "Files in backup: " << fileCount << std::endl;
for (PRL_UINT32 j = 0; j < fileCount; j++)
{
PRL_HANDLE file;
CheckPrlResult(PrlHndlList_GetItem(fileList, j, &file));
PRL_UINT32 filePathSize = 0;
CheckPrlResult(PrlBackupFile_GetPath(file, nullptr, &filePathSize));
char filePath[filePathSize];
CheckPrlResult(PrlBackupFile_GetPath(file, filePath, &filePathSize));
std::cout << filePath << std::endl;
PrlHandle_Free(file);
}
std::cout << "Rolling back..." << std::endl;
PRL_HANDLE rollbackJob = PrlBackup_Rollback(machineHandle, 0);
PRL_HANDLE rollbackJobResult;
CheckPrlResult(WaitJobResult(rollbackJob, &rollbackJobResult));
PrlHandle_Free(rollbackJobResult);
PrlHandle_Free(rollbackJob);
}
else
{
std::cout << "Skipping..." << std::endl;
}
PrlHandle_Free(backupInfo);
PrlHandle_Free(machineHandle);
}
PrlHandle_Free(listResult);
PrlHandle_Free(listJob);
PrlHandle_Free(server);
return 0;
}