b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync/* $Id$ */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync/** @file
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * VBoxAutostart - VirtualBox Autostart service, start machines during system boot.
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync/*
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * Copyright (C) 2012 Oracle Corporation
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync *
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * available from http://www.virtualbox.org. This file is free software;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * General Public License (GPL) as published by the Free Software
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <VBox/com/com.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <VBox/com/string.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <VBox/com/Guid.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <VBox/com/array.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <VBox/com/ErrorInfo.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <VBox/com/errorprint.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync#include <iprt/message.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <iprt/thread.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <iprt/stream.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <iprt/log.h>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <algorithm>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <list>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include <string>
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync#include "VBoxAutostart.h"
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsyncusing namespace com;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync/**
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * VM list entry.
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsynctypedef struct AUTOSTARTVM
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync{
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync /** ID of the VM to start. */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync Bstr strId;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync /** Startup delay of the VM. */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync ULONG uStartupDelay;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync} AUTOSTARTVM;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsyncstatic DECLCALLBACK(bool) autostartVMCmp(const AUTOSTARTVM &vm1, const AUTOSTARTVM &vm2)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync{
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync return vm1.uStartupDelay <= vm2.uStartupDelay;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync}
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
91b827c98a305956e75cb1618af6ae17e450fb88vboxsyncDECLHIDDEN(RTEXITCODE) autostartStartMain(PCFGAST pCfgAst)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync{
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync int vrc = VINF_SUCCESS;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync std::list<AUTOSTARTVM> listVM;
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync uint32_t uStartupDelay = 0;
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync pCfgAst = autostartConfigAstGetByName(pCfgAst, "startup_delay");
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync if (pCfgAst)
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync {
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync if (pCfgAst->enmType == CFGASTNODETYPE_KEYVALUE)
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync {
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync vrc = RTStrToUInt32Full(pCfgAst->u.KeyValue.aszValue, 10, &uStartupDelay);
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync if (RT_FAILURE(vrc))
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "'startup_delay' must be an unsigned number");
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync }
91b827c98a305956e75cb1618af6ae17e450fb88vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (uStartupDelay)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b6013430932520fe58eba109db1dfce66a7cad88vboxsync autostartSvcLogVerbose("Delay starting for %d seconds ...\n", uStartupDelay);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync vrc = RTThreadSleep(uStartupDelay * 1000);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (vrc == VERR_INTERRUPTED)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync return RTEXITCODE_SUCCESS;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync /*
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * Build a list of all VMs we need to autostart first, apply the overrides
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * from the configuration and start the VMs afterwards.
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync com::SafeIfaceArray<IMachine> machines;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync HRESULT rc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (SUCCEEDED(rc))
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync /*
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync * Iterate through the collection
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync for (size_t i = 0; i < machines.size(); ++i)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (machines[i])
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync BOOL fAccessible;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (!fAccessible)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync continue;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync BOOL fAutostart;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartEnabled)(&fAutostart));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (fAutostart)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync AUTOSTARTVM autostartVM;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostartVM.strId.asOutParam()));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartDelay)(&autostartVM.uStartupDelay));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync listVM.push_back(autostartVM);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if ( SUCCEEDED(rc)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync && listVM.size())
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync ULONG uDelayCurr = 0;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync /* Sort by startup delay and apply base override. */
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync listVM.sort(autostartVMCmp);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync std::list<AUTOSTARTVM>::iterator it;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync for (it = listVM.begin(); it != listVM.end(); it++)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync ComPtr<IMachine> machine;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync ComPtr<IProgress> progress;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if ((*it).uStartupDelay > uDelayCurr)
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b6013430932520fe58eba109db1dfce66a7cad88vboxsync autostartSvcLogVerbose("Delay starting of the next VMs for %d seconds ...\n",
b6013430932520fe58eba109db1dfce66a7cad88vboxsync (*it).uStartupDelay - uDelayCurr);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync RTThreadSleep(((*it).uStartupDelay - uDelayCurr) * 1000);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync uDelayCurr = (*it).uStartupDelay;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(),
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync machine.asOutParam()));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR_BREAK(machine, LaunchVMProcess(g_pSession, Bstr("headless").raw(),
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync Bstr("").raw(), progress.asOutParam()));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (SUCCEEDED(rc) && !progress.isNull())
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b6013430932520fe58eba109db1dfce66a7cad88vboxsync autostartSvcLogVerbose("Waiting for VM \"%ls\" to power on...\n", (*it).strId.raw());
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR(progress, WaitForCompletion(-1));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (SUCCEEDED(rc))
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync BOOL completed = true;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR(progress, COMGETTER(Completed)(&completed));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (SUCCEEDED(rc))
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync ASSERT(completed);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync LONG iRc;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync CHECK_ERROR(progress, COMGETTER(ResultCode)(&iRc));
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (SUCCEEDED(rc))
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync if (FAILED(iRc))
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync {
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync ProgressErrorInfo info(progress);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync com::GluePrintErrorInfo(info);
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync else
b6013430932520fe58eba109db1dfce66a7cad88vboxsync autostartSvcLogVerbose("VM \"%ls\" has been successfully started.\n", (*it).strId.raw());
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync g_pSession->UnlockMachine();
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync }
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync return rcExit;
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync}
b56ca3f25c9c141f3c0855b656f8f64bbfa19496vboxsync