MachineImpl.cpp revision bd5c7d04b57ea9dfea041aad6a07cd8823b4e7c0
#
include <
iprt/
cpp/
xml.h>
/* xml::XmlFileWriter::s_psz*Suff. */#
else /* !RT_OS_WINDOWS */#
endif /* !RT_OS_WINDOWS *////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Machine::Data structure ///////////////////////////////////////////////////////////////////////////// /* mUuid is initialized in Machine::init() */ ///////////////////////////////////////////////////////////////////////////// // Machine::HWData structure ///////////////////////////////////////////////////////////////////////////// /* default values for a newly created machine */ mHWVersion =
"2";
/** @todo get the default from the schema if that is possible. */ /* Not supported on 32 bits hosts. */ /* default boot order: floppy - DVD - HDD */ /* Maximum CPU execution cap by default. */ ///////////////////////////////////////////////////////////////////////////// // Machine::HDData structure ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // constructor / destructor ///////////////////////////////////////////////////////////////////////////// * Initializes a new machine instance; this init() variant creates a new, empty machine. * This gets called from VirtualBox::CreateMachine(). * @param aParent Associated parent object * @param strConfigFile Local file system path to the VM settings file (can * be relative to the VirtualBox config directory). * @param strName name for the machine * @param aId UUID for the new machine. * @param aOsType OS Type of this machine or NULL. * @param fForceOverwrite Whether to overwrite an existing machine settings file. * @return Success indicator. if not S_OK, the machine object is invalid /* Enclose the state transition NotReady->InInit->Ready */ // create an empty machine config // set to true now to cause uninit() to call uninitDataAndChildObjects() on failure // the "name sync" flag determines whether the machine directory gets renamed along // with the machine file; say so if the settings file name is the same as the // settings file parent directory (machine directory) // initialize the default snapshots folder /* Apply BIOS defaults */ /* Apply network adapters defaults */ /* Apply serial port defaults */ /* commit all changes made during the initialization */ /* Confirm a successful initialization when it's the case */ LogFlowThisFunc((
"mName='%s', mRegistered=%RTbool, mAccessible=%RTbool, rc=%08X\n",
* Initializes a new instance with data from machine XML (formerly Init_Registered). * Gets called in two modes: * -- from VirtualBox::initMachines() during VirtualBox startup; in that case, the * UUID is specified and we mark the machine as "registered"; * -- from the public VirtualBox::OpenMachine() API, in which case the UUID is NULL * and the machine remains unregistered until RegisterMachine() is called. * @param aParent Associated parent object * @param aConfigFile Local file system path to the VM settings file (can * be relative to the VirtualBox config directory). * @param aId UUID of the machine or NULL (see above). * @return Success indicator. if not S_OK, the machine object is invalid /* Enclose the state transition NotReady->InInit->Ready */ // loading a registered VM: // now load the settings from XML: // this calls initDataAndChildObjects() and loadSettings() // opening an unregistered VM (VirtualBox::OpenMachine()): // set to true now to cause uninit() to call uninitDataAndChildObjects() on failure // load and parse machine XML; this will throw on XML or logic errors // reject VM UUID duplicates, they can happen if someone // tries to register an already known VM config again true /* fPermitInaccessible */,
tr(
"Trying to open a VM config '%s' which has the same UUID as an existing virtual machine"),
// use UUID from machine config NULL /* puuidRegistry */);
/* we assume that error info is set by the thrower */ /* Confirm a successful initialization when it's the case */ // uninit media from this machine's media registry, or else // reloading the settings will fail * Initializes a new instance from a machine config that is already in memory * (import OVF case). Since we are importing, the UUID in the machine * config is ignored and we always generate a fresh one. * @param strName Name for the new machine; this overrides what is specified in config and is used * for the settings file as well. * @param config Machine configuration loaded and parsed from XML. * @return Success indicator. if not S_OK, the machine object is invalid /* Enclose the state transition NotReady->InInit->Ready */ // set to true now to cause uninit() to call uninitDataAndChildObjects() on failure // create empty machine config for instance data // generate fresh UUID, ignore machine config &
mData->
mUuid);
// puuidRegistry: initialize media with this registry ID // override VM name as well, it may be different /* commit all changes made during the initialization */ /* Confirm a successful initialization when it's the case */ // uninit media from this machine's media registry, or else // reloading the settings will fail * Shared code between the various init() implementations. /* share the parent weakly */ /* allocate the essential machine data structure (the rest will be * allocated later by initDataAndChildObjects() */ /* memorize the config file name (as provided) */ /* get the full file name */ tr(
"Invalid machine settings file name '%s' (%Rrc)"),
* Tries to create a machine settings file in the path stored in the machine * instance data. Used when a new machine is created to fail gracefully if * the settings file could not be written (e.g. because machine dir is read-only). // when we create a new machine, we must be able to create the settings file tr(
"Machine settings file '%s' already exists"),
/* try to delete the config file, as otherwise the creation * of a new settings file will fail. */ tr(
"Could not delete the existing settings file '%s' (%Rrc)"),
tr(
"Invalid machine settings file name '%s' (%Rrc)"),
* Initializes the registered machine by loading the settings file. * This method is separated from #init() in order to make it possible to * retry the operation after VirtualBox startup instead of refusing to * startup the whole VirtualBox server in case if the settings file of some * registered VM is invalid or inaccessible. * @note Must be always called from this object's write lock * (unless called from #init() that doesn't need any locking). * @note Locks the mUSBController method for writing. * @note Subclasses must not call this method. /* Temporarily reset the registered flag in order to let setters * potentially called from loadSettings() succeed (isMutable() used in * all setters will return FALSE for a Machine instance if mRegistered // load and parse machine XML; this will throw on XML or logic errors tr(
"Machine UUID {%RTuuid} in '%s' doesn't match its UUID {%s} in the registry file '%s'"),
NULL /* const Guid *puuidRegistry */);
/* we assume that error info is set by the thrower */ /* Restore the registered flag (even on failure) */ /* Set mAccessible to TRUE only if we successfully locked and loaded /* commit all changes made during loading the settings file */ commit();
// @todo r=dj why do we need a commit during init?!? this is very expensive /* If the machine is registered, then, instead of returning a * failure, we mark it as inaccessible and set the result to * success to give it a try later */ /* fetch the current error info */ LogWarning((
"Machine {%RTuuid} is inaccessible! [%ls]\n",
/* rollback all changes */ // uninit media from this machine's media registry, or else // reloading the settings will fail /* uninitialize the common part to make sure all data is reset to * default (null) values */ * Uninitializes the instance. * Called either from FinalRelease() or by the parent when it gets destroyed. * @note The caller of this method must make sure that this object * a) doesn't have active callers on the current thread and b) is not locked * by the current thread; otherwise uninit() will hang either a) due to * AutoUninitSpan waiting for a number of calls to drop to zero or b) due to * a dead-lock caused by this thread waiting for all callers on the other * threads are done but preventing them from doing so by holding a lock. /* Enclose the state transition Ready->InUninit->NotReady */ /* Theoretically, this can only happen if the VirtualBox server has been * terminated while there were clients running that owned open direct * sessions. Since in this case we are definitely called by * VirtualBox::uninit(), we may be sure that SessionMachine::uninit() * won't happen on the client watcher thread (because it does * VirtualBox::addCaller() for the duration of the * SessionMachine::checkForDeath() call, so that VirtualBox::uninit() * cannot happen until the VirtualBox caller is released). This is * important, because SessionMachine::uninit() cannot correctly operate * after we return from this method (it expects the Machine instance is * still valid). We'll call it ourselves below. LogWarningThisFunc((
"Session machine is not NULL (%p), the direct session is still open!\n",
/* set machine state using SessionMachine reimplementation */ * Uninitialize SessionMachine using public uninit() to indicate * an unexpected uninitialization. /* SessionMachine::uninit() must set mSession.mMachine to null */ // uninit media from this machine's media registry, if they're still there /* XXX This will fail with * "cannot be closed because it is still attached to 1 virtual machines" * because at this point we did not call uninitDataAndChildObjects() yet * and therefore also removeBackReference() for all these mediums was not called! */ if (!
uuidMachine.
isEmpty())
// can be empty if we're called from a failure of Machine::init /* the lock is no more necessary (SessionMachine is uninitialized) */ // has machine been modified? /* free the essential data structure last */ ///////////////////////////////////////////////////////////////////////////// /* mParent is constant during life time, no need to lock */ /* try to initialize the VM once more if not accessible */ // reset the XML file to force loadSettings() (called from registeredInit()) // to parse it again; the file might have changed /* make sure interesting parties will notice the accessibility // prohibit setting a UUID only as the machine name, or else it can // never be found by findMachine() /* look up the object by Id to check it is valid */ /* when setting, always use the "etalon" value for consistency -- lookup * by ID is case-insensitive and the input value may have different case */ /* check known version */ tr(
"Invalid RAM size: %lu MB (must be in range [%lu, %lu] MB)"),
tr(
"Invalid virtual CPU count: %lu (must be in range [%lu, %lu])"),
/* We cant go below the current number of CPUs attached if hotplug is enabled*/ tr(
"There is still a CPU attached to socket %lu." "Detach the CPU before removing the socket"),
/* check throttle limits */ tr(
"Invalid CPU execution cap value: %lu (must be in range [%lu, %lu])"),
/* Save settings if online - todo why is this required?? */ /* Add the amount of CPUs currently attached */ * We can disable hotplug only if the amount of maximum CPUs is equal * to the amount of attached CPUs tr(
"CPU hotplugging can't be disabled because the maximum number of CPUs is not equal to the amount of CPUs attached\n"));
tr(
"Invalid VRAM size: %lu MB (must be in range [%lu, %lu] MB)"),
/** @todo this method should not be public */ * Set the memory balloon size. * This method is also called from IGuest::COMSETTER(MemoryBalloonSize) so * we have to make sure that we never call IGuest from here. /* This must match GMMR0Init; currently we only support memory ballooning on all 64-bit hosts except Mac OS X */ tr(
"Invalid memory balloon size: %lu MB (must be in range [%lu, %lu] MB)"),
/** @todo must support changes for running vms and keep this in sync with IGuest. */ /** @todo check validity! */ /** @todo check validity! */ /* make sure monitor count is a sensible number */ tr(
"Invalid monitor count: %lu (must be in range [%lu, %lu])"),
/* mBIOSSettings is constant during life time, no need to lock */ /* Invalidate all standard leafs. */ /* Invalidate all extended leafs. */ * 1. Allow to change the name of the snapshot folder containing snapshots * 2. Rename the folder on disk instead of just changing the property * value (to be smart and not to leave garbage). Note that it cannot be * done here because the change may be rolled back. Thus, the right * place is #saveSettings(). tr(
"The snapshot folder of a machine with snapshots cannot be changed (please delete all snapshots first)"));
tr(
"Invalid snapshot folder '%ls' (%Rrc)"),
/* Note: The GUI depends on this method returning E_NOTIMPL with no * extended error info to indicate that USB is simply not available * (w/o treating it as a failure), for example, as in OSE */ #
endif /* VBOX_WITH_VUSB */ // this is a new machine, and no config file exists yet: /* Note: for machines with no snapshots, we always return FALSE * (mData->mCurrentStateModified will be TRUE in this case, for historical /* Only allow it to be set to true when PoweredOff or Aborted. (Clearing it is always permitted.) */ tr(
"The machine is not powered off (state is %s)"),
/* @todo deal with running state change. */ /* @todo deal with running state change. */ /* @todo deal with running state change. */ /* @todo deal with running state change. */ /* @todo deal with running state change. */ /* Only allow it to be set to true when PoweredOff or Aborted. (Clearing it is always permitted.) */ tr(
"The machine is not powered off (state is %s)"),
/* check the session state */ tr(
"The given session is busy"));
// get the client's IInternalSessionControl interface tr(
"The machine '%s' is not registered"),
/* Hack: in case the session is closing and there is a progress object * which allows waiting for the session to be closed, take the opportunity * and do a limited wait (max. 1 second). This helps a lot when the system * is busy and thus session closing can take a little while. */ // OK, share the session... we are now dealing with three processes: // 1) VBoxSVC (where this code runs); // 2) process C: the caller's client process (who wants a shared session); // 3) process W: the process which already holds the write lock on the machine (write-locking session) // copy pointers to W (the write-locking session) before leaving lock (these must not be NULL) * Leave the lock before calling the client process. It's safe here * since the only thing to do after we get the lock again is to add * the remote control to the list (which doesn't directly influence // get the console of the session holding the write lock (this is a remote call) // the failure may occur w/o any error info (from RPC), so provide one tr(
"Failed to get a console object from the direct session (%Rrc)"),
rc);
// share the session machine and W's console with the caller's session // the failure may occur w/o any error info (from RPC), so provide one tr(
"Failed to assign the machine to the session (%Rrc)"),
rc);
// need to revalidate the state after entering the lock again tr(
"The machine '%s' was unlocked unexpectedly while attempting to share its session"),
// add the caller's session to the list // sharing not permitted, or machine still unlocking: tr(
"The machine '%s' is already locked for a session (or being unlocked)"),
// machine is not locked: then write-lock the machine (create the session machine) // get the caller's session PID // this machine is awaiting for a spawning session to be opened: // then the calling process must be the one that got started by tr(
"An unexpected process (PID=0x%08X) has tried to lock the " "machine '%s', while only the process started by LaunchVMProcess (PID=0x%08X) is allowed"),
// create the mutable SessionMachine from the current machine /* NOTE: doing return from this function after this point but * before the end is forbidden since it may call SessionMachine::uninit() * (through the ComObjPtr's destructor) which requests the VirtualBox write * lock while still holding the Machine lock in alock so that a deadlock * is possible due to the wrong lock order. */ * Set the session state to Spawning to protect against subsequent * attempts to open a session and to unregister the machine after * Leave the lock before calling the client process -- it will call * because the state is Spawning, so that LaunchVMProcess() and * LockMachine() calls will fail. This method, called before we * enter the lock again, will fail because of the wrong PID. * Note that mData->mSession.mRemoteControls accessed outside * the lock may not be modified when state is Spawning, so it's safe. /* The failure may occur w/o any error info (from RPC), so provide one */ tr(
"Failed to assign the machine to the session (%Rrc)"),
rc);
/* complete the remote session initialization */ /* get the console from the direct session */ /* assign machine & console to the remote session */ * after LaunchVMProcess(), the first and the only * entry in remoteControls is that remote session /* The failure may occur w/o any error info (from RPC), so provide one */ tr(
"Failed to assign the machine to the remote session (%Rrc)"),
rc);
/* enter the lock again */ /* Restore the session state */ // finalize spawning anyway (this is why we don't return on errors above) /* Note that the progress object is finalized later */ /** @todo Consider checking mData->mSession.mProgress for cancellation /* We don't reset mSession.mPid here because it is necessary for * SessionMachine::uninit() to reap the child process later. */ /* Close the remote session, remove the remote control from the list * and reset session state to Closed (@note keep the code in sync * with the relevant part in openSession()). */ /* memorize PID of the directly opened session */ /* memorize the direct session control and cache IUnknown for it */ /* associate the SessionMachine with this Machine */ /* request an IUnknown pointer early from the remote party for later * identity checks (it will be internally cached within mDirectControl /* Leave the lock since SessionMachine::uninit() locks VirtualBox which * would break the lock order */ /* uninitialize the created session machine on failure */ * tell the client watcher thread to update the set of * machines that have open sessions * retrieval. This code doesn't quite fit in here, but introducing a * special API method would be even more effort, and would require explicit * support by every API client. It's better to hide the feature a bit. */ /* check the session state */ tr(
"The given session is busy"));
/* get the IInternalSessionControl interface */ (
"No IInternalSessionControl interface"),
/* get the teleporter enable state for the progress object init. */ /* create a progress object */ 2 /* uFirstOperationWeight */,
/* signal the client watcher thread */ /* no progress object - either instant success or failure */ tr(
"The machine '%s' is not locked by a session"),
/* must have a VM process associated - do not kill normal API clients * with an open session */ tr(
"The machine '%s' does not have a VM process"),
/* forcibly terminate the VM process */ /* signal the client watcher thread, as most likely the client has tr(
"Invalid boot position: %lu (must be in range [1, %lu])"),
tr(
"Booting from USB device is currently not supported"));
tr(
"Invalid boot position: %lu (must be in range [1, %lu])"),
LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aType=%d aMedium=%p\n",
// request the host lock first, since might be calling Host methods for getting host drives; // next, protect the media tree all the while we're in here, as well as our member variables /// @todo NEWMEDIA implicit machine registration tr(
"Cannot attach storage devices to an unregistered machine"));
/* Check for an existing controller. */ tr(
"Could not get type of controller '%ls'"),
/* Check that the controller can do hotplugging if we detach the device while the VM is running. */ tr(
"Controller '%ls' does not support hotplugging"),
tr(
"Attaching a DVD drive while the VM is running is not supported"));
// check that the port and device are not out of range /* check if the device slot is already busy */ tr(
"Medium '%s' is already attached to port %d, device %d of controller '%ls' of this virtual machine"),
tr(
"Device is already attached to port %d, device %d of controller '%ls' of this virtual machine"),
tr(
"Medium '%s' is already attached to this virtual machine"),
// MediumType_Readonly is also new, but only applies to DVDs and floppies. // For DVDs it's not written to the config file, so needs no global config // version bump. For floppies it's a new attribute "type", which is ignored // by older VirtualBox version, so needs no global config version bump either. // For hard disks this type is not accepted. // This type is new with VirtualBox 4.0 and therefore requires settings // version 1.11 in the settings backend. Unfortunately it is not enough to do // the usual routine in MachineConfigFile::bumpSettingsVersionIfNeeded() for // two reasons: The medium type is a property of the media registry tree, which // can reside in the global config file (for pre-4.0 media); we would therefore // possibly need to bump the global config version. We don't want to do that though // because that might make downgrading to pre-4.0 impossible. // As a result, we can only use these two new types if the medium is NOT in the tr(
"Cannot attach medium '%s': the media type 'MultiAttach' can only be attached " "to machines that were created with VirtualBox 4.0 or later"),
/* check if the medium was attached to the VM before we started * changing attachments in which case the attachment just needs to /* the simplest case: restore the whole attachment * and return, nothing else to do */ * but don't try to associate it again */ /* go further only if the attachment is to be indirect */ /* perform the so called smart attachment logic for indirect * attachments. Note that smart attachment is only applicable to base /* first, investigate the backup copy of the current hard disk * attachments to make it possible to re-attach existing diffs to * another device slot w/o losing their contents */ /* skip the hard disk if its currently attached (we * cannot attach the same hard disk twice) */ /* matched device, channel and bus (i.e. attached to the * same place) will win and immediately stop the search; * otherwise the attachment that has the youngest * descendant of medium will be used /* the simplest case: restore the whole attachment * and return, nothing else to do */ /* use the previously attached hard disk */ /* not implicit, doesn't require association with this VM */ /* go right to the MediumAttachment creation */ /* must give up the medium lock and medium tree lock as below we * go over snapshots, which needs a lock with higher lock order. */ /* then, search through snapshots for the best diff in the given * hard disk's chain to base the new diff on */ /* matched device, channel and bus (i.e. attached to the * same place) will win and immediately stop the search; * otherwise the attachment that has the youngest * descendant of medium will be used /* re-lock medium tree and the medium, as we need it below */ /* found a suitable diff, use it as a base */ // store this diff in the same registry as the parent // parent image has no registry: this can happen if we're attaching a new immutable // image that has not yet been attached (medium then points to the base and we're // creating the diff image for the immutable, and the parent is not yet registered); // put the parent in the machine registry then /* Apply the normal locking logic to the entire chain. */ true /* fMediumLockWrite */,
tr(
"Could not lock medium when creating diff '%s'"),
/* will leave the lock before the potentially lengthy operation, so * protect with the special state */ /* Unlock the media and free the associated memory. */ /* use the created diff for the actual attachment */ false /* fPassthrough */,
false /* fNonRotational */,
// as the last step, associate the medium to the VM // here we can fail because of Deleting, or being in process of creating a Diff /* success: finally remember the attachment */ LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d\n",
/* Check for an existing controller. */ tr(
"Could not get type of controller '%ls'"),
/* Check that the controller can do hotplugging if we detach the device while the VM is running. */ tr(
"Controller '%ls' does not support hotplugging"),
tr(
"No storage device attached to device slot %d on port %d of controller '%ls'"),
tr(
"Detaching a DVD drive while the VM is running is not supported"));
* The VM has to detach the device before we delete any implicit diffs. * If this fails we can roll back without loosing data. /* If we are here everything went well and we can delete the implicit now. */ LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aPassthrough=%d\n",
tr(
"Invalid machine state: %s"),
tr(
"No storage device attached to device slot %d on port %d of controller '%ls'"),
tr(
"Setting passthrough rejected as the device attached to device slot %d on port %d of controller '%ls' is not a DVD"),
LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aTemporaryEject=%d\n",
tr(
"No storage device attached to device slot %d on port %d of controller '%ls'"),
tr(
"Setting temporary eject flag rejected as the device attached to device slot %d on port %d of controller '%ls' is not a DVD"),
LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aNonRotational=%d\n",
tr(
"Invalid machine state: %s"),
tr(
"No storage device attached to device slot %d on port %d of controller '%ls'"),
tr(
"Setting the non-rotational medium flag rejected as the device attached to device slot %d on port %d of controller '%ls' is not a hard disk"),
LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d\n",
tr(
"Invalid machine state: %s"),
tr(
"No storage device attached to device slot %d on port %d of controller '%ls'"),
/* Get the bandwidth group object and release it - this must not fail. */ LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d aForce=%d\n",
// request the host lock first, since might be calling Host methods for getting host drives; // next, protect the media tree all the while we're in here, as well as our member variables tr(
"No drive attached to device slot %d on port %d of controller '%ls'"),
/* Remember previously mounted medium. The medium before taking the * backup is not necessarily the same thing. */ tr(
"The device at port %d, device %d of controller '%ls' of this virtual machine is not removeable"),
// The backup operation makes the pAttach reference point to the // old settings. Re-get the correct reference. /* On error roll back this change only. */ /* If the attachment is gone in the meantime, bail out. */ LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d\n",
tr(
"No storage device attached to device slot %d on port %d of controller '%ls'"),
* @note Locks this object for reading. /* start with nothing found */ /* return the result to caller (may be empty) */ * @note Locks mParent for writing + this object for writing. // locking note: we only hold the read lock briefly to look up the old value, // then release it and call the onExtraCanChange callbacks. There is a small // chance of a race insofar as the callback might be called twice if two callers // change the same key at the same time, but that's a much better solution // than the deadlock we had here before. The actual changing of the extradata // is then performed under the write lock and race-free. // look up the old value first; if nothing has changed then we need not do anything // ask for permission from all listeners outside the locks; // onExtraDataCanChange() only briefly requests the VirtualBox // lock to copy the list of callbacks to invoke tr(
"Could not set extra data because someone refused the requested change of '%ls' to '%ls'%s%ls"),
// data is changing and change not vetoed: then write it out under the lock // creates a new key if needed // save the global settings; for that we should hold only the VirtualBox lock // fire notification outside the lock /* when there was auto-conversion, we want to save the file even if /* the settings file path may never be null */ /* save all VM data excluding snapshots */ // save the global settings; for that we should hold only the VirtualBox lock * during this rollback, the session will be notified if data has /** @note Locks objects! */ // use AutoLimitedCaller because this call is valid on inaccessible machines as well tr(
"Cannot unregister the machine '%s' while it is locked"),
// wait for state dependents to drop to zero // inaccessible maschines can only be unregistered; uninitialize ourselves // here because currently there may be no unregistered that are inaccessible // (this state combination is not supported). Note releasing the caller and // leaving the lock before calling uninit() // calls VirtualBox::saveSettings() // add the saved state file to the list of files the caller should delete // unconditionally set the machine state to powered off, we now // know no session has locked the machine // fail now before we start detaching media tr(
"Cannot unregister the machine '%s' because it has %d snapshots"),
// This list collects the medium objects from all medium attachments // which we will detach from the machine and its snapshots, in a specific // order which allows for closing all media without getting "media in use" // errors, simply by going through the list from the front to the back: // 1) first media from machine attachments (these have the "leaf" attachments with snapshots // and must be closed before the parent media from the snapshots, or closing the parents // will fail because they still have children); // 2) media from the youngest snapshots followed by those from the parent snapshots until // the root ("first") snapshot of the machine. // we have media attachments: detach them all and add the Medium objects to our list tr(
"Cannot unregister the machine '%s' because it has %d media attachments"),
// autoCleanup must be true here, or we would have failed above // add the media from the medium attachments of the snapshots to llMedia // as well, after the "main" machine media; Snapshot::uninitRecursively() // calls Machine::detachAllMedia() for the snapshot machine, recursing // into the children first // Snapshot::beginDeletingSnapshot() asserts if the machine state is not this // make a copy of the first snapshot so the refcount does not drop to 0 // in beginDeletingSnapshot, which sets pFirstSnapshot to 0 (that hangs // because of the AutoCaller voodoo) // commit all the media changes made above // machine lock no longer needed // return media to caller // calls VirtualBox::saveSettings() tr(
"Cannot delete settings of a registered machine"));
// collect files to delete /* At this point the medium should not have any back references * anymore. If it has it is attached to another VM and *must* not static_cast<
IMachine*>(
this)
/* aInitiator */,
* Static task wrapper passed to RTThreadCreate() in Machine::Delete() which then * calls Machine::deleteTaskWorker() on the actual machine object. * Task thread implementation for Machine::Delete(), called from Machine::deleteThread(). /* Check the result of the asynchrony process. */ /* If the thread of the progress object has an error, then * retrieve the error info from there, or it'll be lost. */ // delete the files pushed on the task list by Machine::Delete() // (this includes saved states of the machine and snapshots and // medium storage files from the IMedium list passed in, and the /* delete the settings only when the file actually exists */ /* Delete any backup or uncommitted XML files. Ignore failures. See the fSafe parameter of xml::XmlFileWriter::write for details. */ /** @todo Find a way to avoid referring directly to iprt/xml.h here. */ /* delete the Logs folder, nothing important should be left * there (we don't check for errors because the user might have * some private files there that we don't want to delete) */ /* Delete all VBox.log[.N] files from the Logs folder * (this must be in sync with the rotation logic in * Console::powerUpThread()). Also, delete the VBox.png[.N] * files that may have been created by the GUI. */ /* delete the Snapshots folder, nothing important should be left * there (we don't check for errors because the user might have * some private files there that we don't want to delete) */ // delete the directory that contains the settings file, but only // if it matches the VM name // null case (caller wants root snapshot): findSnapshotById() handles this tr(
"Shared folder named '%s' already exists"),
true /* fFailOnError */);
/* inform the direct session if any */ /* inform the direct session if any */ tr(
"Machine is not locked for session (session state: %s)"),
/* ignore calls made after #OnSessionEnd() is called */ tr(
"Machine is not locked for session (session state: %s)"),
/* ignore calls made after #OnSessionEnd() is called */ * Look up a guest property in VBoxSVC's internal structures. * Query the VM that a guest property belongs to for the property. * @returns E_ACCESSDENIED if the VM process is not available or not * currently handling queries and the lookup should then be done in /* fail if we were called after #OnSessionEnd() is called. This is a * silly race condition. */ #
endif // VBOX_WITH_GUEST_PROPS#
else // VBOX_WITH_GUEST_PROPS /* The VM is not running or the service is not (yet) accessible */ #
endif // VBOX_WITH_GUEST_PROPS * Set a guest property in VBoxSVC's internal structures. tr(
"Invalid flag values: '%ls'"),
/** @todo r=bird: see efficiency rant in PushGuestProperty. (Yeah, I * know, this is simple and do an OK job atm.) */ tr(
"The property '%ls' cannot be changed by the host"),
/* The backup() operation invalidates our iterator, so /** @todo r=bird: Why aren't we leaving the lock here? The * same code in PushGuestProperty does... */ * Set a property on the VM that that property belongs to. * @returns E_ACCESSDENIED if the VM process is not available or not * currently handling queries and the setting should then be done in /** @todo Fix when adding DeleteGuestProperty(), #
endif // VBOX_WITH_GUEST_PROPS#
else // VBOX_WITH_GUEST_PROPS /* The VM is not running or the service is not (yet) accessible */ #
endif // VBOX_WITH_GUEST_PROPS * Enumerate the guest properties in VBoxSVC's internal structures. * Look for matching patterns and build up a list. * And build up the arrays for returning the property information. * Enumerate the properties managed by a VM. * @returns E_ACCESSDENIED if the VM process is not available or not * currently handling queries and the setting should then be done in #
endif // VBOX_WITH_GUEST_PROPS#
else // VBOX_WITH_GUEST_PROPS /* The VM is not running or the service is not (yet) accessible */ #
endif // VBOX_WITH_GUEST_PROPS LogFlowThisFunc((
"aControllerName=\"%ls\" aControllerPort=%d aDevice=%d\n",
tr(
"No storage device attached to device slot %d on port %d of controller '%ls'"),
tr(
"Invalid connection type: %d"),
/* try to find one with the name first. */ tr(
"Storage controller named '%ls' already exists"),
/* get a new instance number for the storage controller */ /* Only one controller of each type can be marked as bootable. */ /* inform the direct session if any */ tr(
"Could not find a storage controller with instance number '%lu'"),
/* Ensure that only one controller of each type is marked as bootable. */ /* inform the direct session if any */ /* We can remove the controller only if there is no device attached. */ /* check if the device slot is already busy */ tr(
"Storage controller named '%ls' has still devices attached"),
/* We can remove it now. */ /* inform the direct session if any */ tr(
"Saved guest size is not available (%Rrc)"),
tr(
"Saved screenshot data is not available (%Rrc)"),
tr(
"Saved screenshot data is not available (%Rrc)"),
/* Convert pixels to format expected by the API caller. */ /* [0] B, [1] G, [2] R, [3] A. */ for (
unsigned i = 0; i <
cbData; i +=
4)
/* [0] R, [1] G, [2] B, [3] A. */ for (
unsigned i = 0; i <
cbData; i +=
4)
tr(
"Saved screenshot data is not available (%Rrc)"),
tr(
"Saved screenshot data is not available (%Rrc)"),
tr(
"Saved screenshot thumbnail data is not available (%Rrc)"),
/* Save settings if online */ tr(
"CPU index exceeds maximum CPU count (must be in range [0:%lu])"),
/* CPU 0 can't be detached */ /* Save settings if online */ /* If hotplug is enabled the CPU is always enabled. */ /* do not unnecessarily hold the lock while doing something which does * not need the lock and potentially takes a long time. */ /* Limit the chunk size to 32K for now, as that gives better performance * over (XP)COM, and keeps the SOAP reply size under 1M for the webservice. * One byte expands to approx. 25 bytes of breathtaking XML. */ tr(
"Could not read log file '%s' (%Rrc)"),
tr(
"Could not open log file '%s' (%Rrc)"),
* Currently this method doesn't attach device to the running VM, * just makes sure it's plugged on next VM start. tr(
"Host PCI attachment only supported with ICH9 chipset"));
// check if device with this host PCI address already attached tr(
"Device with host PCI address already attached to this VM"));
* Currently this method doesn't detach device from the running VM, * just makes sure it's not plugged on next VM start. /* Fire event outside of the lock */ tr(
"No host PCI device %08x attached"),
/* Convert the options. */ // public methods for internal purposes ///////////////////////////////////////////////////////////////////////////// * Adds the given IsModified_* flag to the dirty flags of the machine. * This must be called either during loadSettings or under the machine write lock. * Adds the given IsModified_* flag to the dirty flags of the machine, taking * care of the write locking. * @param fModifications The flag to add. * Saves the registry entry of this machine to the given configuration node. * @param aEntryNode Node to save the registry entry to. * @note locks this object for reading. * Calculates the absolute path of the given path taking the directory of the * machine settings file as the current directory. * @param aPath Path to calculate the absolute path for. * @param aResult Where to put the result (used only on success, can be the * same Utf8Str instance as passed in @a aPath). * @note Locks this object for reading. * Copies strSource to strTarget, making it relative to the machine folder * if it is a subdirectory thereof, or simply copying it otherwise. * @param strSource Path to evaluate and copy. * @param strTarget Buffer to receive target path. * @note Locks this object for reading. // use strTarget as a temporary buffer to hold the machine settings dir // is relative: then append what's left // for empty paths (only possible for subdirs) use "." to avoid // triggering default settings for not present config attributes. // is not relative: then overwrite * Returns the full path to the machine's log folder in the * \a aLogFolder argument. * Returns the full path to the machine's log file for an given index. * Composes a unique saved state filename based on the current system time. The filename is * granular to the second so this will work so long as no more than one snapshot is taken on * Before version 4.1, we used this formula for saved state files: * which no longer works because saved state files can now be shared between the saved state of the * "saved" machine and an online snapshot, and the following would cause problems: * 2) create online snapshot from that machine state --> reusing saved state file * 3) save machine again --> filename would be reused, breaking the online snapshot * So instead we now use a timestamp. * @note Locks this object for writing, calls the client process tr(
"The machine '%s' is not registered"),
tr(
"The machine '%s' is already locked by a session (or being locked or unlocked)"),
/* get the path to the executable */ /* clone the current environment */ /* put new variables to the environment * (ignore empty variable names here since RTEnv API * intentionally doesn't do that) */ if (*p ==
'\n' && (p ==
newEnvStr || *(p -
1) !=
'\\'))
#
ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */#
else /* !VBOX_WITH_QTGUI */#
endif /* VBOX_WITH_QTGUI */#
else /* !VBOX_WITH_VBOXSDL */#
endif /* !VBOX_WITH_VBOXSDL */ ||
strType ==
"vrdp" /* Deprecated. Same as headless. */ /* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE, * which did not contain VRDP server. In VBox 4.0 the remote desktop server (VRDE) is optional, * and a VM works even if the server has not been installed. * So in 4.0 the "headless" behavior remains the same for default VBox installations. * Only if a VRDE has been installed and the VM enables it, the "headless" will work * differently in 4.0 and 3.x. /* Leave space for "--capture" arg. */ 0,
/* For "--capture". */#
else /* !VBOX_WITH_HEADLESS */#
endif /* !VBOX_WITH_HEADLESS */ tr(
"Invalid session type: '%s'"),
tr(
"Could not launch a process for the machine '%s' (%Rrc)"),
* Note that we don't leave the lock here before calling the client, * because it doesn't need to call us back if called with a NULL argument. * Leaving the lock here is dangerous because we didn't prepare the * launch data yet, but the client we've just started may happen to be * too fast and call openSession() that will fail (because of PID, etc.), * so that the Machine will never get out of the Spawning session state. /* inform the session that it will be a remote one */ /* restore the session state */ /* The failure may occur w/o any error info (from RPC), so provide one */ tr(
"Failed to assign the machine to the session (%Rrc)"),
rc);
/* attach launch data to the machine */ * Returns @c true if the given machine has an open direct session and returns * the session machine instance and additional session data (on some platforms) * Note that when the method returns @c false, the arguments remain unchanged. * @param aMachine Session machine object. * @param aControl Direct session control object (optional). * @param aIPCSem Mutex IPC semaphore handle for this machine (optional). * @note locks this object for reading. /* just return false for inaccessible machines */ /* Additional session data */ * Returns @c true if the given machine has an spawning direct session and * returns and additional session data (on some platforms) if so. * Note that when the method returns @c false, the arguments remain unchanged. * @param aPID PID of the spawned direct session process. * @note locks this object for reading. /* just return false for inaccessible machines */ /* Additional session data */ * Called from the client watcher thread to check for unexpected client process * death during Session_Spawning state (e.g. before it successfully opened a * On Win32 and on OS/2, this method is called only when we've got the * direct client's process termination notification, so it always returns @c * On other platforms, this method returns @c true if the client process is * terminated and @c false if it's still alive. * @note Locks this object for writing. /* VirtualBox::addProcessToReap() needs a write lock */ /* the process was already unexpectedly terminated, we just need to set an * error and finalize session spawning */ tr(
"The virtual machine '%s' has terminated unexpectedly during startup"),
/* PID not yet initialized, skip check. */ tr(
"The virtual machine '%s' has terminated unexpectedly during startup with exit code %d"),
tr(
"The virtual machine '%s' has terminated unexpectedly during startup because of signal %d"),
tr(
"The virtual machine '%s' has terminated abnormally"),
tr(
"The virtual machine '%s' has terminated unexpectedly during startup (%Rrc)"),
/* Close the remote session, remove the remote control from the list * and reset session state to Closed (@note keep the code in sync with * the relevant part in checkForSpawnFailure()). */ /* finalize the progress after setting the state */ * Checks whether the machine can be registered. If so, commits and saves * @note Must be called from mParent's write lock. Locks this object and /* wait for state dependents to drop to zero */ tr(
"The machine '%s' with UUID {%s} is inaccessible and cannot be registered"),
tr(
"The machine '%s' with UUID {%s} is already registered"),
// Ensure the settings are saved. If we are going to be registered and // no config file exists yet, create it by calling saveSettings() too. // we can't have a machine XML file rename pending /* more config checking goes here */ /* we may have had implicit modifications we want to fix on success */ /* we may have had implicit modifications we want to cancel on failure*/ * Increases the number of objects dependent on the machine state or on the * registered state. Guarantees that these two states will not change at least * until #releaseStateDependency() is called. * Depending on the @a aDepType value, additional state checks may be made. * These checks will set extended error info on failure. See * #checkStateDependency() for more info. * If this method returns a failure, the dependency is not added and the caller * is not allowed to rely on any particular machine state or registration state * value and may return the failed result code to the upper level. * @param aDepType Dependency type to add. * @param aState Current machine state (NULL if not interested). * @param aRegistered Current registered state (NULL if not interested). * @note Locks this object for writing. /* ensureNoStateDependencies() is waiting for state dependencies to * drop to zero so don't add more. It may make sense to wait a bit * and retry before reporting an error (since the pending state * transition should be really quick) but let's just assert for * now to see if it ever happens on practice. */ tr(
"Machine state change is in progress. Please retry the operation later."));
* Decreases the number of objects dependent on the machine state. * Must always complete the #addStateDependency() call after the state * dependency is no more necessary. /* releaseStateDependency() w/o addStateDependency()? */ /* inform ensureNoStateDependencies() that there are no more deps */ ///////////////////////////////////////////////////////////////////////////// * Performs machine state checks based on the @a aDepType value. If a check * fails, this method will set extended error info, otherwise it will return * S_OK. It is supposed, that on failure, the caller will immediately return * the return value of this method to the upper level. * When @a aDepType is AnyStateDep, this method always returns S_OK. * When @a aDepType is MutableStateDep, this method returns S_OK only if the * current state of this machine object allows to change settings of the * machine (i.e. the machine is not registered, or registered but not running * and not saved). It is useful to call this method from Machine setters * before performing any change. * When @a aDepType is MutableOrSavedStateDep, this method behaves the same * as for MutableStateDep except that if the machine is saved, S_OK is also * returned. This is useful in setters which allow changing machine * properties when it is in the saved state. * @param aDepType Dependency type to check. * @note Non Machine based classes should use #addStateDependency() and * #releaseStateDependency() methods or the smart AutoStateDependency * @note This method must be called from under this object's read or write && ( !
isSessionMachine()
/** @todo This was just converted raw; Check if Running and Paused should actually be included here... (Live Migration) */ tr(
"The machine is not mutable (state is %s)"),
&& ( !
isSessionMachine()
/** @todo This was just converted raw; Check if Running and Paused should actually be included here... (Live Migration) */ tr(
"The machine is not mutable (state is %s)"),
* Helper to initialize all associated child objects and allocate data * This method must be called as a part of the object's initialization procedure * (usually done in the #init() method). * @note Must be called only from #init() or from #registeredInit(). /* allocate data structures */ /* initialize mOSTypeId */ /* create associated BIOS settings object */ /* create an associated VRDE object (default is disabled) */ /* create associated serial port objects */ /* create associated parallel port objects */ /* create the audio adapter object (always present, default is disabled) */ /* create the USB controller object (always present, default is disabled) */ /* create associated network adapter objects */ /* create the bandwidth control */ * Helper to uninitialize all associated child objects and to free all data * This method must be called as a part of the object's uninitialization * procedure (usually done in the #uninit() method). * @note Must be called only from #uninit() or from #registeredInit(). /* tell all our other child objects we've been uninitialized */ /* Deassociate hard disks (only when a real Machine or a SnapshotMachine * instance is uninitialized; SessionMachine instances refer to real * Machine hard disks). This is necessary for a clean re-initialization of * the VM after successfully re-checking the accessibility state. Note * that in case of normal Machine or SnapshotMachine uninitialization (as * a result of unregistering or deleting the snapshot), outdated hard * disk attachments will already be uninitialized and deleted, so this * code will not affect them. */ // clean up the snapshots list (Snapshot::uninit() will handle the snapshot's children recursively) // snapshots tree is protected by media write lock; strictly // this isn't necessary here since we're deleting the entire // machine, but otherwise we assert in Snapshot::uninit() /* free data structures (the essential mData structure is not freed here * since it may be still in use) */ * Returns a pointer to the Machine object for this machine that acts like a * parent for complex machine data objects such as shared folders, etc. * For primary Machine objects and for SnapshotMachine objects, returns this * object's pointer itself. For SessionMachine objects, returns the peer * (primary) machine pointer. * Makes sure that there are no machine state dependents. If necessary, waits * for the number of dependents to drop to zero. * Make sure this method is called from under this object's write lock to * guarantee that no new dependents may be added when this method returns * @note Locks this object for writing. The lock will be released while waiting * @warning To be used only in methods that change the machine state! /* Wait for all state dependents if necessary */ /* lazy semaphore creation */ /* reset the semaphore before waiting, the last dependent will signal * Changes the machine state and informs callbacks. * This method is not intended to fail so it either returns S_OK or asserts (and * @note Locks this object for writing. /* wait for state dependents to drop to zero */ * Searches for a shared folder with the given logical name * in the collection of shared folders. * @param aName logical name of the shared folder * @param aSharedFolder where to return the found object * @param aSetError whether to set the error info if the folder is * S_OK when found or VBOX_E_OBJECT_NOT_FOUND when not found * must be called from under the object's lock! * Initializes all machine instance data from the given settings structures * from XML. The exception is the machine UUID which needs special handling * depending on the caller's use case, so the caller needs to set that herself. * This gets called in several contexts during machine initialization: * -- When machine XML exists on disk already and needs to be loaded into memory, * for example, from registeredInit() to load all registered machines on * VirtualBox startup. In this case, puuidRegistry is NULL because the media * attached to the machine should be part of some media registry already. * -- During OVF import, when a machine config has been constructed from an * OVF file. In this case, puuidRegistry is set to the machine UUID to * ensure that the media listed as attachments in the config (which have * been imported from the OVF) receive the correct registry ID. * @param config Machine settings from XML. * @param puuidRegistry If != NULL, Medium::setRegistryIdIfFirst() gets called with this registry ID for each attached medium in the config. // copy name, description, OS type, teleporter, UTC etc. // look up the object by Id to check it is valid tr(
"Invalid saved state file path '%s' (%Rrc)"),
// snapshot folder needs special processing so set it again /* currentStateModified (optional, default is true) */ * note: all mUserData members must be assigned prior this point because * we need to commit changes in order to let mUserData be shared by all * snapshot machine instances. // machine registry, if present (must be loaded before snapshots) // determine machine folder /* Snapshot node (optional) */ // there must be only one root snapshot NULL);
// no parent == first snapshot // load storage controllers NULL /* puuidSnapshot */);
* NOTE: the assignment below must be the last thing to do, * otherwise it will be not possible to change the settings * somewhere in the code above because all setters will be * blocked by checkStateDependency(MutableStateDep). /* set the machine state to Aborted or Saved when appropriate */ /* no need to use setMachineState() during init() */ /* no need to use setMachineState() during init() */ // after loading settings, we are no longer different from the XML on disk * Recursively loads all snapshots starting from the given. * @param aNode <Snapshot> node. * @param aCurSnapshotId Current snapshot ID from the settings file. * @param aParentSnapshot Parent snapshot. tr(
"Invalid saved state file path '%s' (%Rrc)"),
/* create a snapshot machine object */ /* create a snapshot object */ /* initialize the snapshot */ /* memorize the first snapshot if necessary */ /* memorize the current snapshot when appropriate */ // now create the children pSnapshot);
// parent = the one we created above * @param aNode <Hardware> node. /* The hardware version attribute (optional). */ // Bandwidth control (must come before network adapters) /* slot unicity is guaranteed by XML Schema */ // parallel ports (optional) /* Guest properties (optional) */ #
endif /* VBOX_WITH_GUEST_PROPS defined */ * Called from loadMachineDataFromSettings() for the storage controller data, including media. * @param puuidRegistry media registry ID to set media to or NULL; see Machine::loadMachineDataFromSettings() /* Try to find one with the name first. */ tr(
"Storage controller named '%s' already exists"),
/* Set IDE emulation settings (only for AHCI controller). */ /* Load the attached devices now. */ * Called from loadStorageControllers for a controller's devices. * @param aStorageController * @param puuidRegistry media registry ID to set media to or NULL; see Machine::loadMachineDataFromSettings() * @param aSnapshotId pointer to the snapshot ID if this is a snapshot machine /* paranoia: detect duplicate attachments */ tr(
"Duplicate attachments for storage controller '%s', port %d, device %d of the virtual machine '%s'"),
// This is not an error. The host drive or UUID might have vanished, so just go ahead without this removeable medium attachment /* find a hard disk by UUID */ // wrap another error message around the "cannot find hard disk" set by findHardDisk // so the user knows that the bad disk is in a snapshot somewhere tr(
"A differencing image of snapshot {%RTuuid} could not be found. %ls"),
tr(
"Immutable hard disk '%s' with UUID {%RTuuid} cannot be directly attached to snapshot with UUID {%RTuuid} " "of the virtual machine '%s' ('%s')"),
tr(
"Immutable hard disk '%s' with UUID {%RTuuid} cannot be directly attached to the virtual machine '%s' ('%s')"),
tr(
"Multi-attach hard disk '%s' with UUID {%RTuuid} cannot be directly attached to snapshot with UUID {%RTuuid} " "of the virtual machine '%s' ('%s')"),
tr(
"Multi-attach hard disk '%s' with UUID {%RTuuid} cannot be directly attached to the virtual machine '%s' ('%s')"),
tr(
"Hard disk '%s' with UUID {%RTuuid} cannot be directly attached to the virtual machine '%s' ('%s') " "because it has %d differencing child hard disks"),
tr(
"Hard disk '%s' with UUID {%RTuuid} is already attached to the virtual machine '%s' ('%s')"),
tr(
"Device '%s' with unknown type is attached to the virtual machine '%s' ('%s')"),
/* Bandwidth groups are loaded at this point. */ tr(
"Device '%s' with unknown bandwidth group '%s' is attached to the virtual machine '%s' ('%s')"),
/* associate the medium with this machine and snapshot */ /* If the medium->addBackReference fails it sets an appropriate * error message, so no need to do any guesswork here. */ // caller wants registry ID to be set on all attached media (OVF import case) /* back up mMediaData to let registeredInit() properly rollback on failure * (= limited accessibility) */ * Returns the snapshot with the given UUID or fails of no such snapshot exists. * @param aId snapshot UUID to find (empty UUID refers the first snapshot) * @param aSnapshot where to return the found snapshot * @param aSetError true to set extended error info on failure tr(
"Could not find a snapshot with UUID {%s}"),
* Returns the snapshot with the given name or fails of no such snapshot. * @param aName snapshot name to find * @param aSnapshot where to return the found snapshot * @param aSetError true to set extended error info on failure tr(
"This machine does not have any snapshots"));
* Returns a storage controller object with the given name. * @param aName storage controller name to find * @param aStorageController where to return the found storage controller * @param aSetError true to set extended error info on failure tr(
"Could not find a storage controller named '%s'"),
// should never happen, but deal with NULL pointers in the list. // getControllerName() needs caller+read lock * Helper for #saveSettings. Cares about renaming the settings directory and * file if the machine name was changed and about creating a new settings file * if this is a new machine. * @note Must be never called directly but only from #saveSettings(). /* attempt to rename the settings file if machine name is changed */ /* first, rename the directory if it matches the machine name */ /* new dir and old dir cannot be equal here because of 'if' * above and because name != newName */ /* perform real rename only if the machine is not new */ tr(
"Could not rename the directory '%s' to '%s' to save the settings file (%Rrc)"),
/* then try to rename the settings file itself */ /* get the path to old settings file in renamed directory */ /* perform real rename only if the machine is not new */ tr(
"Could not rename the settings file '%s' to '%s' (%Rrc)"),
// update m_strConfigFileFull amd mConfigFile // compute the relative path too // store the old and new so that VirtualBox::saveSettings() can update // in the saved state file path, replace the old directory with the new directory // and do the same thing for the saved state file paths of all the online snapshots /* silently try to rename everything back */ /* create a virgin config file */ /* ensure the settings directory exists */ tr(
"Could not create a directory '%s' to save the settings file (%Rrc)"),
/* Note: open flags must correlate with RTFileOpen() in lockConfig() */ tr(
"Could not create the settings file '%s' (%Rrc)"),
* Saves and commits machine data, user data and hardware data. * Note that on failure, the data remains uncommitted. * @a aFlags may combine the following flags: * - SaveS_ResetCurStateModified: Resets mData->mCurrentStateModified to FALSE. * Used when saving settings after an operation that makes them 100% * correspond to the settings from the current snapshot. * - SaveS_InformCallbacksAnyway: Callbacks will be informed even if * #isReallyModified() returns false. This is necessary for cases when we * change machine data directly, not through the backup()/commit() mechanism. * - SaveS_Force: settings will be saved without doing a deep compare of the * settings structures. This is used when this is called because snapshots * have changed to avoid the overhead of the deep compare. * @note Must be called from under this object's write lock. Locks children for * @param pfNeedsGlobalSaveSettings Optional pointer to a bool that must have been * initialized to false and that will be set to true by this function if * the caller must invoke VirtualBox::saveSettings() because the global * settings have changed. This will happen if a machine rename has been * saved and the global machine and media registries will therefore need /* make sure child objects are unable to modify the settings while we are /* First, prepare to save settings. It will care about renaming the * settings directory and file if the machine name was changed and about * creating a new settings file if this is a new machine. */ // keep a pointer to the current settings structures // make a fresh one to have everyone write stuff into // now go and copy all the settings data from COM to the settings structures // (this calles saveSettings() on all the COM objects in the machine) // this gets set by takeSnapshot() (if offline snapshot) and restoreSnapshot() // do a deep compare of the settings that we just saved with the settings // previously stored in the config file; this invokes MachineConfigFile::operator== // which does a deep compare of all the settings, which is expensive but less expensive // than writing out XML in vain // could still be modified if any settings changed // after saving settings, we are no longer different from the XML on disk // we assume that error info is set by the thrower /* Fire the data change event, even on failure (since we've already * committed all data). This is done only for SessionMachines because * mutable Machine instances are always not registered (i.e. private * to the client process that creates them) and thus don't need to * Implementation for saving the machine settings into the given * settings::MachineConfigFile instance. This copies machine extradata * from the previous machine config file in the instance data, if any. * This gets called from two locations: * -- Machine::saveSettings(), during the regular XML writing; * -- Appliance::buildXMLForOneVirtualSystem(), when a machine gets * exported to OVF and we write the VirtualBox proprietary XML * into a <vbox:Machine> tag. * This routine fills all the fields in there, including snapshots, *except* * -- fCurrentStateModified. There is some special logic associated with that. * The caller can then call MachineConfigFile::write() or do something else * Caller must hold the machine lock! * This throws XML errors and HRESULT, so the caller must have a catch block! // copy name, description, OS type, teleport, UTC etc. // when deleting a snapshot we may or may not have a saved state in the current state, // so let's not assert here please /* try to make the file name relative to the settings file dir */ /// @todo Live Migration: config.fTeleported = (mData->mMachineState == MachineState_Teleported); // save machine's media registry if this is VirtualBox 4.0 or later // determine machine folder getId(),
// only media with registry ID == machine UUID * Saves all snapshots of the machine into the given machine config file. Called * from Machine::buildMachineXML() and SessionMachine::deleteSnapshotHandler(). // get reference to the fresh copy of the snapshot on the list and // work on that copy directly to avoid excessive copying later // if (mType == IsSessionMachine) // mParent->onMachineDataChange(mData->mUuid); @todo is this necessary? /* we assume that error info is set by the thrower */ * Saves the VM hardware configuration. It is assumed that the * @param aNode <Hardware> node to save the VM hardware configuration to. /* The hardware version attribute (optional). Automatically upgrade from 1 to 2 when there is no saved state. (ugly!) */ mHWData->
mHWVersion =
"2";
/** @todo Is this safe, to update mHWVersion here? If not some other point needs to be found where this can be done. */ /* Standard and Extended CPUID leafs. */ /* VRDEServer settings (optional) */ /* USB Controller (required) */ /* Network adapters (required) */ /* BandwidthControl (required) */ /* Remove transient guest properties at shutdown unless we /* I presume this doesn't require a backup(). */ #
endif /* VBOX_WITH_GUEST_PROPS defined */ * Saves the storage controller configuration. * @param aNode <StorageControllers> node to save the VM hardware configuration to. /* Save the port count. */ /* Save fUseHostIOCache */ /* Save IDE emulation settings. */ /* save the devices now. */ * Saves the hard disk configuration. * Saves machine state settings as defined by aFlags * @param aFlags Combination of SaveSTS_* flags. * @note Locks objects for writing. /* This object's write lock is also necessary to serialize file access * (prevent concurrent reads and writes) */ /* try to make the file name relative to the settings file dir */ //@todo live migration mData->pMachineConfigFile->fTeleported = (mData->mMachineState == MachineState_Teleported); * Ensures that the given medium is added to a media registry. If this machine * was created with 4.0 or later, then the machine registry is used. Otherwise * the global VirtualBox media registry is used. If the medium was actually * added to a registry (because it wasn't in the registry yet), the UUID of * that registry is added to the given list so that the caller can save the * Caller must hold machine read lock! * @param llRegistriesThatNeedSaving * @param puuid Optional buffer that receives the registry UUID that was used. // decide which medium registry to use now that the medium is attached: // machine XML is VirtualBox 4.0 or higher: // registry actually changed: * Creates differencing hard disks for all normal hard disks attached to this * machine and a new set of attachments to refer to created disks. * Used when taking a snapshot or when deleting the current state. Gets called * from SessionMachine::BeginTakingSnapshot() and SessionMachine::restoreSnapshotHandler(). * This method assumes that mMediaData contains the original hard disk attachments * it needs to create diffs for. On success, these attachments will be replaced * with the created diffs. On failure, #deleteImplicitDiffs() is implicitly * called to delete created diffs which will also rollback mMediaData and restore * whatever was backed up before calling this method. * Attachments with non-normal hard disks are left as is. * If @a aOnline is @c false then the original hard disks that require implicit * diffs will be locked for reading. Otherwise it is assumed that they are * already locked for writing (when the VM was started). Note that in the latter * case it is responsibility of the caller to lock the newly created diffs for * writing if this method succeeds. * @param aProgress Progress object to run (must contain at least as * many operations left as the number of hard disks * @param aOnline Whether the VM was online prior to this operation. * @param pllRegistriesThatNeedSaving Optional pointer to a list of UUIDs to receive the registry IDs that need saving * @note The progress object is not marked as completed, neither on success nor * on failure. This is a responsibility of the caller. * @note Locks this object for writing. /* must be in a protective state because we leave the lock below */ /* lock all attached hard disks early to detect "in use" * situations before creating actual diffs */ false /* fMediumLockWrite */,
tr(
"Collecting locking information for all attached media failed"));
/* Now lock all media. If this fails, nothing is locked. */ tr(
"Locking of attached media failed"));
/* remember the current list (note that we don't use backup() since * mMediaData may be already backed up) */ /* go through remembered attachments and create diffs for normal hard * disks and attach them */ /* copy the attachment as is */ /** @todo the progress object created in Console::TakeSnaphot * only expects operations for hard disks. Later other * device types need to show up in the progress as well. */ // store the diff in the same registry as the parent // (this cannot fail here because we can't create implicit diffs for /** @todo r=bird: How is the locking and diff image cleaned up if we fail before * the push_back? Looks like we're going to leave medium with the * wrong kind of lock (general issue with if we fail anywhere at all) * and an orphaned VDI in the snapshots folder. */ /* update the appropriate lock list */ /* leave the lock before the potentially lengthy operation */ /* add a new attachment */ false /* aPassthrough */,
false /* aNonRotational */,
/* unlock all hard disks we locked */ * Deletes implicit differencing hard disks created either by * #createImplicitDiffs() or by #AttachDevice() and rolls back mMediaData. * Note that to delete hard disks created by #AttachDevice() this method is * called from #fixupMedia() when the changes are rolled back. * @param pllRegistriesThatNeedSaving Optional pointer to a list of UUIDs to receive the registry IDs that need saving * @note Locks this object for writing. /* enumerate new attachments */ /* deassociate and mark for deletion */ /* was this hard disk attached before? */ /* rollback hard disk changes */ /* delete unused implicit diffs */ /* will leave the lock before the potentially lengthy * operation, so protect with the special state (unless already * Looks through the given list of media attachments for one with the given parameters * and returns it, or NULL if not found. The list is a parameter so that backup lists * can be searched as well if needed. * Looks through the given list of media attachments for one with the given parameters * and returns it, or NULL if not found. The list is a parameter so that backup lists * can be searched as well if needed. * Looks through the given list of media attachments for one with the given parameters * and returns it, or NULL if not found. The list is a parameter so that backup lists * can be searched as well if needed. * Main implementation for Machine::DetachDevice. This also gets called * from Machine::prepareUnregister() so it has been taken out for simplicity. * @param pAttach Medium attachment to detach. * @param writeLock Machine write lock which the caller must have locked once. This may be released temporarily in here. * @param pSnapshot If NULL, then the detachment is for the current machine. Otherwise this is for a SnapshotMachine, and this must be its snapshot. * @param pllRegistriesThatNeedSaving Optional pointer to a list of UUIDs to receive the registry IDs that need saving /* attempt to implicitly delete the implicitly created diff */ /// @todo move the implicit flag from MediumAttachment to Medium /// and forbid any hard disk operation when it is implicit. Or maybe /// a special media state for it to make it even more simple. /* will leave the lock before the potentially lengthy operation, so * protect with the special state */ // we cannot use erase (it) below because backup() above will create // a copy of the list and make this copy active, but the iterator // still refers to the original and is not valid for the copy // if this is from a snapshot, do not defer detachment to commitMedia() // else if non-hard disk media, do not defer detachment to commitMedia() either * Goes thru all media of the given list and * 1) calls detachDevice() on each of them for this machine and * 2) adds all Medium objects found in the process to the given list, * depending on cleanupMode. * If cleanupMode is CleanupMode_DetachAllReturnHardDisksOnly, this only * adds hard disks to the list. If it is CleanupMode_Full, this adds all * This gets called from Machine::Unregister, both for the actual Machine and * the SnapshotMachine objects that might be found in the snapshots. * Requires caller and locking. The machine lock must be passed in because it * will be passed on to detachDevice which needs it for temporary unlocking. * @param writeLock Machine lock from top-level caller; this gets passed to detachDevice. * @param pSnapshot Must be NULL when called for a "real" Machine or a snapshot object if called for a SnapshotMachine. * @param cleanupMode If DetachAllReturnHardDisksOnly, only hard disk media get added to llMedia; if Full, then all media get added; * otherwise no media get added. * @param llMedia Caller's list to receive Medium objects which got detached so caller can close() them, depending on cleanupMode. // make a temporary list because detachDevice invalidates iterators into // mMediaData->mAttachments * Search for medias which are not attached to any machine, but * in the chain to an attached disk. Mediums are only consided * - no references to any machines * - are of normal medium type // real machine: then we need to use the proper method NULL /* pfNeedsSaveSettings */);
* Perform deferred hard disk detachments. * Does nothing if the hard disk attachment data (mMediaData) is not changed (not * If @a aOnline is @c true then this method will also unlock the old hard disks * for which the new implicit diffs were created and will lock these new diffs for * @param aOnline Whether the VM was online prior to this operation. * @note Locks this object for writing! /* enumerate new attachments */ /** @todo convert all this Machine-based voodoo to MediumAttachment /* convert implicit attachment to normal */ /* update the appropriate lock list */ /* unlock if there's a need to change the locking */ /* was this medium attached before? */ /* yes: remove from old to avoid de-association */ /* enumerate remaining old attachments and de-associate from the * current machine state */ /* Detach only hard disks, since DVD/floppy media is detached * instantly in MountMedium. */ /* now de-associate from the current machine state */ /* unlock since medium is not used anymore */ /* take media locks again so that the locking state is consistent */ /* commit the hard disk changes */ * Update the parent machine to point to the new owner. * This is necessary because the stored parent will point to the * session machine otherwise and cause crashes or errors later * when the session machine gets invalid. /** @todo Change the MediumAttachment class to behave like any other * class in this regard by creating peer MediumAttachment * objects for session machines and share the data with the peer /* attach new data to the primary machine and reshare it */ * Perform deferred deletion of implicitly created diffs. * Does nothing if the hard disk attachment data (mMediaData) is not changed (not * @param pfNeedsSaveSettings Optional pointer to a bool that must have been initialized to false and that will be set to true * by this function if the caller should invoke VirtualBox::saveSettings() because the global settings have changed. * @note Locks this object for writing! * @todo r=dj this needs a pllRegistriesThatNeedSaving as well /* enumerate new attachments */ /* Fix up the backrefs for DVD/floppy media. */ /* Fix up the backrefs for DVD/floppy media. */ /** @todo convert all this Machine-based voodoo to MediumAttachment * based rollback logic. */ // @todo r=dj the below totally fails if this gets called from Machine::rollback(), // which gets called if Machine::registeredInit() fails... * Returns true if the settings file is located in the directory named exactly * as the machine; this means, among other things, that the machine directory * should be auto-renamed. * @param aSettingsDir if not NULL, the full machine settings file directory * name will be assigned there. * @note Doesn't lock anything. * @note Not thread safe (must be called from this object's lock). * Discards all changes to machine settings. * @param aNotify Whether to notify the direct session about changes or not. * @note Locks objects for writing! /* unitialize all new devices (absent in the backed up list). */ /* rollback any changes to devices after restoring the list */ /* inform the direct session about changes */ * Commits all the changes to machine settings. * Note that this operation is supposed to never fail. * @note Locks this object and children for writing. * use safe commit to ensure Snapshot machines (that share mUserData) * will still refer to a valid memory location /* Commit all changes to new controllers (this will reshare data with * peers for those who have peers) */ /* look if this controller has a peer device */ /* no peer means the device is a newly created one; * create a peer owning data this device share it with */ /* remove peer from the old list */ /* and add it to the new list */ /* uninit old peer's controllers that are left */ /* attach new list of controllers to our peer */ /* we have no peer (our parent is the newly created machine); * just commit changes to devices */ /* the list of controllers itself is not changed, * just commit changes to controllers themselves */ /* attach new data to the primary machine and reshare it */ /* mMediaData is reshared by fixupMedia */ // mPeer->mMediaData.attach(mMediaData); * Copies all the hardware data from the given machine. * Currently, only called when the VM is being restored from a snapshot. In * particular, this implies that the VM is not running during this method's * @note This method must be called from under this object's lock. * @note This method doesn't call #commit(), so all data remains backed up and // create copies of all shared folders (mHWData after attaching a copy // contains just references to original objects) /* create private copies of all controllers */ * Returns whether the given storage controller is hotplug capable. * @returns true if the controller supports hotplugging * @param enmCtrlType The controller type to check for. "Percentage of processor time spent in user mode by the VM process.");
"Percentage of processor time spent in kernel mode by the VM process.");
"Size of resident portion of VM process in memory.");
/* Create and register base metrics */ /* Guest metrics collector */ "Percentage of processor time spent in user mode as seen by the guest.");
"Percentage of processor time spent in kernel mode as seen by the guest.");
"Percentage of processor time spent idling as seen by the guest.");
/* The total amount of physical ram is fixed now, but we'll support dynamic guest ram configurations in the future. */ /* Create and register base metrics */ #
endif /* VBOX_WITH_RESOURCE_USAGE_API *///////////////////////////////////////////////////////////////////////////////// * @note Must be called only by Machine::openSession() from its own write lock. /* Enclose the state transition NotReady->InInit->Ready */ /* create the interprocess semaphore */ (
"Cannot create IPC mutex '%ls', err=%d",
(
"Cannot create IPC mutex '%s', arc=%ld",
/** @todo Check that this still works correctly. */ #
else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */#
endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ tr(
"Cannot create IPC semaphore. Most likely your host kernel lacks " "support for SysV IPC. Check the host kernel configuration for " /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing tr(
"Cannot create IPC semaphore because the system limit for the " "maximum number of semaphore sets (SEMMNI), or the system wide " "maximum number of semaphores (SEMMNS) would be exceeded. The " "current set of SysV IPC semaphores can be determined from " tr(
"Cannot create IPC semaphore because the system-imposed limit " "on the maximum number of allowed semaphores or semaphore " "identifiers system-wide would be exceeded"));
/* set the initial value to 1 */ /* memorize the peer Machine */ /* share the parent pointer */ /* take the pointers to data to share */ /* create another VRDEServer object that will be mutable */ /* create another audio adapter object that will be mutable */ /* create a list of serial ports that will be mutable */ /* create a list of parallel ports that will be mutable */ /* create another USB controller object that will be mutable */ /* create a list of network adapters that will be mutable */ /* create another bandwidth control object that will be mutable */ /* default is to delete saved state on Saved -> PoweredOff transition */ /* Confirm a successful initialization when it's the case */ * Uninitializes this session object. If the reason is other than * Uninit::Unexpected, then this method MUST be called from #checkForDeath(). * @param aReason uninitialization reason * @note Locks mParent + this object for writing. * Strongly reference ourselves to prevent this object deletion after * reference and call the destructor). Important: this must be done before * accessing any members (and before AutoUninitSpan that does it as well). * This self reference will be released as the very last step on return. /* Enclose the state transition Ready->InUninit->NotReady */ /* We've been called by init() because it's failed. It's not really * necessary (nor it's safe) to perform the regular uninit sequence * below, the following is enough. #
endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */ // release all captured USB devices, but do this before requesting the locks below /* Console::captureUSBDevices() is called in the VM process only after * setting the machine state to Starting or Restoring. * Console::detachAllUSBDevices() will be called upon successful * termination. So, we need to release USB devices only if there was * an abnormal termination of a running VM. * This is identical to SessionMachine::DetachAllUSBDevices except * for the aAbnormal argument. */ #
endif /* VBOX_WITH_USB */ // we need to lock this object in uninit() because the lock is shared // with mPeer (as well as data we modify below). mParent->addProcessToReap() // and others need mParent lock, and USB needs host lock. // delete mCollectorGuest; => CollectorGuestManager::destroyUnregistered() // Trigger async cleanup tasks, avoid doing things here which are not // vital to be done immediately and maybe need more locks. This calls // Machine::unregisterMetrics(). * It is safe to call Machine::unregisterMetrics() here because * PerformanceCollector::samplerCallback no longer accesses guest methods /* reset the state to Aborted */ // any machine settings modified? /* delete all differencing hard disks created (this will also attach * their parents back by rolling back mMediaData) */ // delete the saved state file (it might have been already created) // AFTER killing the snapshot so that releaseSavedStateFile() won't // think it's still in use /* mType is not null when this machine's process has been started by * Machine::LaunchVMProcess(), therefore it is our child. We * need to queue the PID to reap the process (and avoid zombies on /* Uninitialization didn't come from #checkForDeath(), so tell the * client watcher thread to update the set of machines that have open /* uninitialize all remote controls */ * An expected uninitialization can come only from #checkForDeath(). * Otherwise it means that something's gone really wrong (for example, * the Session implementation has released the VirtualBox reference * before it triggered #OnSessionEnd(), or before releasing IPC semaphore, * etc). However, it's also possible, that the client releases the IPC * semaphore correctly (i.e. before it releases the VirtualBox reference), * but the VirtualBox release event comes first to the server process. * This case is practically possible, so we should not assert on an * unexpected uninit, just log a warning. /* this must be null here (see #OnSessionEnd()) */ tr(
"The VM session was aborted"));
/* remove the association between the peer machine and this session machine */ /* reset the rest of session data */ /* close the interprocess semaphore before leaving the exclusive lock */ #
endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */ /* free the essential data structure last */ #
if 1 /** @todo Please review this change! (bird) */ /* drop the exclusive lock before setting the below two to NULL */ /* leave the exclusive lock before setting the below two to NULL */ // util::Lockable interface //////////////////////////////////////////////////////////////////////////////// * Overrides VirtualBoxBase::lockHandle() in order to share the lock handle * with the primary Machine instance (mPeer). // IInternalMachineControl methods //////////////////////////////////////////////////////////////////////////////// * @note Locks this object for writing. * @note Locks the same as #setMachineState() does. * @note Locks this object for reading. #
else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */#
endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */ * @note Locks this object for writing. * @note Locks this object for writing. /* Finalize the LaunchVMProcess progress object. */ /* The VM has been powered up successfully, so it makes sense * now to offer the performance metrics for a running machine * object. Doing it earlier wouldn't be safe. */ #
endif /* VBOX_WITH_RESOURCE_USAGE_API */ * @note Locks this object for writing. /* create a progress object to track operation completion */ static_cast<
IMachine *>(
this)
/* aInitiator */,
Bstr(
tr(
"Stopping the virtual machine")).
raw(),
FALSE /* aCancelable */);
/* fill in the console task data */ /* set the state to Stopping (this is expected by Console::PowerDown()) */ * @note Locks this object for writing. * On failure, set the state to the state we had when BeginPoweringDown() * was called (this is expected by Console::PowerDown() and the associated * task). On success the VM process already changed the state to * MachineState_PoweredOff, so no need to do anything. /* notify the progress object about operation completion */ /* clear out the temporary saved state data */ * Goes through the USB filters of the given machine to see if the given * device matches any filter or not. * @note Locks the same as USBController::hasMatchingFilter() does. * @note Locks the same as Host::captureUSBDevice() does. /* if captureDeviceForVM() fails, it must have set extended error info */ * @note Locks the same as Host::detachUSBDevice() does. * Inserts all machine filters to the USB proxy service and then calls * Host::autoCaptureUSBDevices(). * Called by Console from the VM process upon VM startup. * @note Locks what called methods lock. * Removes all machine filters from the USB proxy service and then calls * Host::detachAllUSBDevices(). * Called by Console from the VM process upon normal VM termination or by * SessionMachine::uninit() upon abnormal VM termination (from under the * @note Locks what called methods lock. * @note Locks this object for writing. * We don't assert below because it might happen that a non-direct session * informs us it is closed right after we've been uninitialized -- it's ok. /* get IInternalSessionControl interface */ /* Creating a Progress object requires the VirtualBox lock, and * thus locking it here is required by the lock order rules. */ /* The direct session is being normally closed by the client process * ----------------------------------------------------------------- */ /* go to the closing state (essential for all open*Session() calls and * for #checkForDeath()) */ /* set direct control to NULL to release the remote instance */ /* finalize the progress, someone might wait if a frontend * closes the session before powering on the VM. */ tr(
"The VM session was closed before any attempt to power it on"));
/* Create the progress object the client will use to wait until * #checkForDeath() is called to uninitialize this session object after * it releases the IPC semaphore. * Note! Because we're "reusing" mProgress here, this must be a proxy * object just like for LaunchVMProcess. */ FALSE /* aCancelable */);
/* the remote session is being normally closed */ * @note Locks this object for writing. /* create a progress object to track operation completion */ static_cast<
IMachine *>(
this)
/* aInitiator */,
Bstr(
tr(
"Saving the execution state of the virtual machine")).
raw(),
FALSE /* aCancelable */);
/* stateFilePath is null when the machine is not running */ /* fill in the console task data */ /* set the state to Saving (this is expected by Console::SaveState()) */ * @note Locks mParent + this object for writing. /* endSavingState() need mParent lock */ * On failure, set the state to the state we had when BeginSavingState() * was called (this is expected by Console::SaveState() and the associated * task). On success the VM process already changed the state to * MachineState_Saved, so no need to do anything. * @note Locks this object for writing. ,
E_FAIL);
/** @todo setError. */ tr(
"Invalid saved state file path '%ls' (%Rrc)"),
/* The below setMachineState() will detect the state transition and will * update the settings file */ /* If it is NULL, keep it NULL. */ * Convert input up front. * Now grab the object lock, validate the state and do the update. /** @todo r=bird: The careful memory handling doesn't work out here because * the catch block won't undo any damage we've done. So, if push_back throws * bad_alloc then you've lost the value. * Another thing. Doing a linear search here isn't extremely efficient, esp. * since values that changes actually bubbles to the end of the list. Using * something that has an efficient lookup and can tolerate a bit of updates * would be nice. RTStrSpace is one suggestion (it's not perfect). Some * combination of RTStrCache (for sharing names and getting uniqueness into * the bargain) and hash/tree is another. */ * Send a callback notification if appropriate // request the host lock first, since might be calling Host methods for getting host drives; // next, protect the media tree all the while we're in here, as well as our member variables /* Need to query the details first, as the IMediumAttachment reference * might be to the original settings, which we are going to change. */ /* Remember previously mounted medium. The medium before taking the * backup is not necessarily the same thing. */ // The backup operation makes the pAttach reference point to the // old settings. Re-get the correct reference. // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// * Called from the client watcher thread to check for expected or unexpected * death of the client process that has a direct session to this machine. * On Win32 and on OS/2, this method is called only when we've got the * mutex (i.e. the client has either died or terminated normally) so it always * returns @c true (the client is terminated, the session machine is * On other platforms, the method returns @c true if the client process has * terminated normally or abnormally and the session machine was uninitialized, * and @c false if the client process is still alive. * @note Locks this object for writing. /* Enclose autoCaller with a block because calling uninit() from under it /* return true if not ready, to cause the client watcher to exclude * the corresponding session from watching */ /* Determine the reason of death: if the session state is Closing here, * everything is fine. Otherwise it means that the client did not call * OnSessionEnd() before it released the IPC semaphore. This may happen * either because the client process has abnormally terminated, or * because it simply forgot to call ISession::Close() before exiting. We * threat the latter also as an abnormal termination (see * Session::uninit() for details). */ /* release the IPC mutex */ /* release the IPC mutex */ /* the semaphore is signaled, meaning the session is terminated */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * instead acting like callback we ask IVirtualBox deliver corresponding event * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * @note Locks this object for reading. /* ignore notifications sent after #OnSessionEnd() is called */ * Returns @c true if this machine's USB controller reports it has a matching * filter for the given USB device and @c false otherwise. * @note Caller must have requested machine read lock. /* silently return if not ready -- this method may be called after the * direct machine session has been called */ /** @todo Live Migration: snapshoting & teleporting. Need to fend things of * @note The calls shall hold no locks. Will temporarily lock this object for reading. /* This notification may happen after the machine object has been * uninitialized (the session was closed), so don't assert. */ /* fail on notifications sent after #OnSessionEnd() is called, it is * expected by the caller */ /* No locks should be held at this point. */ * @note The calls shall hold no locks. Will temporarily lock this object for reading. /* This notification may happen after the machine object has been * uninitialized (the session was closed), so don't assert. */ /* fail on notifications sent after #OnSessionEnd() is called, it is * expected by the caller */ /* No locks should be held at this point. */ ///////////////////////////////////////////////////////////////////////////// * Helper method to finalize saving the state. * @note Must be called from under this object's lock. * @param aRc S_OK if the snapshot has been taken successfully * @param aErrMsg human readable error message for failure * @note Locks mParent + this objects for writing. /* save all VM settings */ // we can't have a name change pending at this point // delete the saved state file (it might have been already created); // we need not check whether this is shared with a snapshot here because // we certainly created this saved state file here anew /* notify the progress object about operation completion */ /* clear out the temporary saved state data */ * Deletes the given file if it is no longer in use by either the current machine state * (if the machine is "saved") or any of the machine's snapshots. * Note: This checks mSSData->strStateFilePath, which is shared by the Machine and SessionMachine * but is different for each SnapshotMachine. When calling this, the order of calling this * function on the one hand and changing that variable OR the snapshots tree on the other hand * is therefore critical. I know, it's all rather messy. * @param pSnapshotToIgnore Passed to Snapshot::sharesSavedStateFile(); this snapshot is ignored in the test for whether the saved state file is in use. // it is safe to delete this saved state file if it is not currently in use by the machine ... // ... and it must also not be shared with other snapshots // this checks the SnapshotMachine's state file paths * Locks the attached media. * All attached hard disks are locked for writing and DVD/floppy are locked for * reading. Parents of attached hard disks (if any) are locked for reading. * This method also performs accessibility check of all media it locks: if some * media is inaccessible, the method will return a failure and a bunch of * extended error info objects per each inaccessible medium. * Note that this method is atomic: if it returns a success, all media are * locked as described above; on failure no media is locked at all (all * succeeded individual locks will be undone). * This method is intended to be called when the machine is in Starting or * Restoring state and asserts otherwise. * The locks made by this method must be undone by calling #unlockMedia() when /* bail out if trying to lock things with already set up locking */ /* Collect locking information for all medium objects attached to the VM. */ // There can be attachments without a medium (floppy/dvd), and thus // it's impossible to create a medium lock list. It still makes sense // to have the empty medium lock list in the map in case a medium is tr(
"Collecting locking information for all attached media failed"));
/* Now lock all media. If this fails, nothing is locked. */ tr(
"Locking of attached media failed"));
* Undoes the locks made by by #lockMedia(). /* we may be holding important error info on the current thread; * Helper to change the machine state (reimplementation). * @note Locks this object for writing. (
"oldMachineState=%s, aMachineState=%s\n",
/* detect some state transitions */ /* The EMT thread is about to start */ /* Nothing to do here for now... */ /// @todo NEWMEDIA don't let mDVDDrive and other children /* ignore PoweredOff->Saving->PoweredOff transition when taking a /* The EMT thread has just stopped, unlock attached media. Note that as * opposed to locking that is done from Console, we do unlocking here * because the VM process may have aborted before having a chance to * properly unlock all media it locked. */ * delete the saved state file once the machine has finished * restoring from it (note that Console sets the state from * Restoring to Saved if the VM couldn't restore successfully, * to give the user an ability to fix an error and retry -- * we keep the saved state file in this case) * delete the saved state after Console::ForgetSavedState() is called * or if the VM process (owning a direct VM session) crashed while the // Not sure that deleting the saved state file just because of the // client death before it attempted to restore the VM is a good // thing. But when it crashes we need to go to the Aborted state // which cannot have the saved state file associated... The only // way to fix this is to make the Aborted condition not a VM state // but a bool flag: i.e., when a crash occurs, set it to true and // change the state to PoweredOff or Saved depending on the /* set the current state modified flag to indicate that the current * state is no more identical to the state in the // it is safe to delete the saved state file if ... // ... none of the snapshots share the saved state file /* redirect to the underlying peer machine */ /* the machine has stopped execution * (or the saved state file was adopted) */ /* the saved state file was adopted */ /* Make sure any transient guest properties get removed from the * property store on shutdown. */ SaveSettings();
// @todo r=dj why the public method? why first SaveSettings and then saveStateSettings? /* we've been shut down for any reason */ /* no special action so far */ * Sends the current machine state value to the VM process. * @note Locks this object for reading, then calls a client process. /* directControl may be already set to NULL here in #OnSessionEnd() * called too early by the direct session process while there is still * some operation (like deleting the snapshot) in progress. The client * process in this case is waiting inside Session::close() for the * "end session" process object to complete, while #uninit() called by * #checkForDeath() on the Watcher thread is waiting for the pending * operation to complete. For now, we accept this inconsistent behavior * and simply do nothing here. */