VirtualBoxImpl.cpp revision 82ae84c8df758538c13cc48d2e569bd8903105d2
* Implementation of IVirtualBox in VBoxSVC. * Copyright (C) 2006-2014 Oracle Corporation * This file is part of VirtualBox Open Source Edition (OSE), as * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. #
include <
memory>
// for auto_ptr#
endif /* VBOX_WITH_RESOURCE_USAGE_API *///////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // static leaked (todo: find better place to free it.) //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// * Abstract callback event class to asynchronously call VirtualBox callbacks * on a dedicated event thread. Subclasses reimplement #handleCallback() * to call appropriate IVirtualBoxCallback methods depending on the event * @note The VirtualBox instance passed to the constructor is strongly * referenced, so that the VirtualBox singleton won't be released until the * event gets handled by the event thread. * Note that this is a weak ref -- the CallbackEvent handler thread * is bound to the lifetime of the VirtualBox instance, so it's safe. //////////////////////////////////////////////////////////////////////////////// // VirtualBox private member data definition //////////////////////////////////////////////////////////////////////////////// * Main VirtualBox data structure. * @note |const| members are persistent during lifetime so can be accessed // const data members not requiring locking // VirtualBox main settings file // constant pseudo-machine ID for global media registry // counter if global media registry needs saving, updated using atomic // operations, without requiring any locks // const objects not requiring locking #
endif /* VBOX_WITH_RESOURCE_USAGE_API */ // Each of the following lists use a particular lock handle that protects the // list as a whole. As opposed to version 3.1 and earlier, these lists no // longer need the main VirtualBox object lock, but only the respective list // lock. In each case, the locking order is defined that the list must be // requested before object locks of members of the lists (see the order definitions // in AutoLock.h; e.g. LOCKCLASS_LISTOFMACHINES before LOCKCLASS_MACHINEOBJECT). // All the media lists are protected by the following locking handle: // the hard disks map is an additional map sorted by UUID for quick lookup // and contains ALL hard disks (base and differencing); it is protected by // the same lock as the other media lists above // list of pending machine renames (also protected by media tree lock; // see VirtualBox::rememberMachineNameChangeForMedia()) // the following are data for the async event thread /** The extension pack manager object lives here. */ /** The global autostart database for the user. */ // constructor / destructor ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// * Initializes the VirtualBox object. * @return COM result code /* Enclose the state transition NotReady->InInit->Ready */ /* Locking this object for writing during init sounds a bit paradoxical, * but in the current locking mess this avoids that some code gets a * read lock and later calls code which wants the same write lock. */ // allocate our instance data LogFlow((
"===========================================================\n"));
/* Get the VirtualBox home directory. */ tr(
"Could not create the VirtualBox home directory '%s' (%Rrc)"),
// load and parse VirtualBox.xml; this will throw on XML or logic errors // this is thrown by the XML backend if the RTOpen() call fails; // only if the main settings file does not exist, create it, // if there's something more serious, then do fail! /* create the performance collector object BEFORE host */ #
endif /* VBOX_WITH_RESOURCE_USAGE_API */ /* create the host object early, machines will need it */ * Create autostart database object early, because the system properties * Initialize extension pack manager before system properties because * it is required for the VD plugins. /* create the system properties object, someone may need it too */ /* guest OS type objects, needed by machines */ /* all registered media, needed by machines */ /* net services - dhcp services */ /* net services - nat networks */ /* we assume that error info is set by the thrower */ /* set up client monitoring */ /* start the async event handler thread */ /* wait until the thread sets m->pAsyncEventQ */ /* Confirm a successful initialization when it's the case */ /* Let the extension packs have a go at things. */ LogFlow((
"===========================================================\n"));
/* Check if machine record has valid parameters. */ LogRel((
"Skipped invalid machine record.\n"));
* Loads a media registry from XML and adds the media contained therein to * the global lists of known media. * This now (4.0) gets called from two locations: * -- VirtualBox::init(), to load the global media registry from VirtualBox.xml; * -- Machine::loadMachineDataFromSettings(), to load the per-machine registry * from machine XML, for machines created with VirtualBox 4.0 or later. * In both cases, the media found are added to the global lists so the * global arrays of media (including the GUI's virtual media manager) * continue to work as before. * @param uuidMachineRegistry The UUID of the media registry. This is either the * transient UUID created at VirtualBox startup for the global registry or * @param mediaRegistry The XML settings structure to load, either from VirtualBox.xml LogFlow((
"VirtualBox::initMedia ENTERING, uuidRegistry=%s, strMachineFolder=%s\n",
xmlHD,
// XML data; this recurses to processes the children LogFlow((
"VirtualBox::initMedia LEAVING\n"));
/* Enclose the state transition Ready->InUninit->NotReady */ LogFlow((
"===========================================================\n"));
/* tell all our child objects we've been uninitialized */ /* It is necessary to hold the VirtualBox and Host locks here because we may have to uninitialize SessionMachines. */ /* Note that we release singleton children after we've all other children. * In some cases this is important because these other children may use * some resources of the singletons which would prevent them from * uninitializing (as for example, mSystemProperties which owns * MediumFormat objects which Medium objects refer to) */ #
endif /* VBOX_WITH_RESOURCE_USAGE_API */ /* signal to exit the event loop */ * Wait for thread termination (only after we've successfully * interrupted the event queue processing!) // Must uninit the event source here, because it makes no sense that // it survives longer than the base object. If someone gets an event // with such an event source then that's life and it has to be dealt // with appropriately on the API client side. // clean up our instance data /* Unload hard disk plugin backends. */ LogFlow((
"===========================================================\n"));
// Wrapped IVirtualBox properties ///////////////////////////////////////////////////////////////////////////// /* mHomeDir is const and doesn't need a lock */ /* mCfgFile.mName is const and doesn't need a lock */ /* mHost is const, no need to lock */ /* mSystemProperties is const, no need to lock */ /* get copy of all machine references, to avoid holding the list lock */ /* throw out any duplicates */ /* protect mProgressOperations */ #
endif /* RT_OS_WINDOWS */ /* mPerformanceCollector is const, no need to lock */ #
else /* !VBOX_WITH_RESOURCE_USAGE_API */#
endif /* !VBOX_WITH_RESOURCE_USAGE_API */ /* event source is const, no need to lock */ /* The extension pack manager is const, no need to lock. */ /* get copy of all machine references, to avoid holding the list lock */ /* throw out any duplicates */ /* get copy of all machine references, to avoid holding the list lock */ /* throw out any duplicates */ /* compiled-in firmware */ /* compiled-in firmware */ /** @todo: account for version in the URL */ /* Assume single record per firmware type */ // Wrapped IVirtualBox methods ///////////////////////////////////////////////////////////////////////////// /* Helper for VirtualBox::ComposeMachineFilename */ /* skip over everything which doesn't contain '=' */ else if (
strKey ==
"directoryIncludesUUID")
tr(
"'%s' is not a valid Guid"),
/* Compose the settings file name using the following scheme: * <base_folder><group>/<machine_name>/<machine_name>.xml * If a non-null and non-empty base folder is specified, the default * machine folder will be used as a base folder. * We sanitise the machine name to a safe white list of characters before /* we use the non-full folder value below to keep the path relative */ /* eliminate toplevel group to avoid // in the result */ * Remove characters from a machine file name which can be problematic on * @param strName The file name to sanitise. /** Set of characters which should be safe for use in filenames: some basic * ASCII, Unicode from Latin-1 alphabetic to the end of Hangul. We try to * skip anything that could count as a control character in Windows or * *nix, or be otherwise difficult for shells to handle (I would have * preferred to remove the space and brackets too). We also remove all * characters which need UTF-16 surrogate pairs for Windows's benefit. */ {
' ',
' ',
'(',
')',
'-',
'.',
'0',
'9',
'A',
'Z',
'a',
'z',
'_',
'_',
/* No leading dot or dash. */ /* Mangle leading and trailing spaces. */ /** Simple unit test/operation examples for sanitiseMachineFilename(). */ /** Expected results of sanitising given file names. */ /** The test file name to be sanitised (Utf-8). */ /** The expected sanitised output (Utf-8). */ {
"OS/2 2.1",
"OS_2 2.1" },
{
"-!My VM!-",
"__My VM_-" },
{
"\xF0\x90\x8C\xB0",
"____" },
{
" My VM ",
"__My VM__" },
{
".My VM.",
"_My VM_" },
pfnPrintf(
"%s: line %d, expected %s, actual %s\n",
/** @todo Proper testcase. */ /** @todo Do we have a better method of doing init functions? */ /** @note Locks mSystemProperties object for reading. */ LogFlowThisFunc((
"aSettingsFile=\"%s\", aName=\"%s\", aOsTypeId =\"%s\", aCreateFlags=\"%s\"\n",
/** @todo tighten checks on aId? */ /* skip over everything which doesn't contain '=' */ else if (
strKey ==
"forceOverwrite")
else if (
strKey ==
"directoryIncludesUUID")
/* Create UUID if none was specified. */ tr(
"'%s' is not a valid Guid"),
/* NULL settings file means compose automatically */ /* create a new object */ /* initialize the machine object */ /* set the return value */ /* call the extension pack hooks */ /* create a new object */ /* initialize the machine object */ NULL);
/* const Guid *aId */ /* set the return value */ /** @note Locks objects! */ /* We can safely cast child to Machine * here because only Machine * implementations of IMachine can be among our children. */ /** @note Locks this object for reading, then some machine objects for reading. */ /* start with not found */ true /* fPermitInaccessible */,
// returns VBOX_E_OBJECT_NOT_FOUND if not found and sets error // returns VBOX_E_OBJECT_NOT_FOUND if not found and sets error /* this will set (*machine) to NULL if machineObj is null */ /* we want to rely on sorted groups during compare, to save time */ /* get copy of all machine references, to avoid holding the list lock */ /* avoid duplicates and save time */ /* we don't access non-const data members so no need to lock */ // have to get write lock as the whole find/update sequence must be done // in one critical section, otherwise there are races which can lead to // multiple Medium objects with the same content // check if the device type is correct, and see if a medium for the // given path has already initialized; if so, return that // enforce read-only for DVDs even if caller specified ReadWrite /* Note that it's important to call uninit() on failure to register * because the differencing hard disk would have been already associated * with the parent and this association needs to be broken. */ /** @note Locks this object for reading. */ tr(
"'%s' is not a valid Guest OS type"),
* @note Locks this object for reading. * @note Locks this object for reading. /* return the result to caller (may be empty) */ * @note Locks 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 '%s' to '%s'%s%ls"),
// data is changing and change not vetoed: then write it out under the lock // creates a new key if needed /* save settings on success */ // fire notification outside the lock * Decrypt all encrypted settings. * So far we only have encrypted iSCSI initiator secrets so we just go through * all hard disk mediums and determine the plain 'InitiatorSecret' from * 'InitiatorSecretEncrypted. The latter is stored as Base64 because medium * properties need to be null-terminated strings. * @param aPlaintext plaintext to be encrypted * @param aCiphertext resulting ciphertext (base64-encoded) * @param aPlaintext resulting plaintext * @param aCiphertext ciphertext (base64-encoded) to decrypt /* sanity check: null-terminated string? */ /* sanity check: valid UTF8 string? */ * Encrypt secret bytes. Use the m->SettingsCipherKey as key. * @param aPlaintext clear text to be encrypted * @param aCiphertext resulting encrypted text * @param aPlaintextSize size of the plaintext * @param aCiphertextSize size of the ciphertext /* store the first 8 bytes of the cipherkey for verification */ for (i = 0, j = 0; i <
8; i++, j++)
/* fill with random data to have a minimal length (salt) */ * Decrypt secret bytes. Use the m->SettingsCipherKey as key. * @param aPlaintext resulting plaintext * @param aCiphertext ciphertext to be decrypted * @param aCiphertextSize size of the ciphertext == size of the plaintext for (i = 0, j = 0; i <
8; i++, j++)
* @param aKey the key to store // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// * Posts an event to the event queue that is processed asynchronously * Posting events to the dedicated event queue is useful to perform secondary * actions outside any object locks -- for example, to iterate over a list * of callbacks and inform them about some change caused by some object's * @param event event to post; must have been allocated using |new|, will * be deleted automatically by the event thread after processing * @note Doesn't lock any object. LogWarningFunc((
"VirtualBox has been uninitialized (state=%d), the event is discarded!\n",
// in any event of failure, we must clean up here, or we'll leak; // the caller has allocated the object using new() * Adds a progress to the global collection of pending operations. * Usually gets called upon progress object initialization. * @param aProgress Operation to add to the collection. * @note Doesn't lock objects. /* protect mProgressOperations */ * Removes the progress from the global collection of pending operations. * Usually gets called upon progress completion. * @param aId UUID of the progress operation to remove * @note Doesn't lock objects. /* protect mProgressOperations */ * Helper method that starts a worker thread that: * - creates a pipe communication channel using SVCHlpClient; * - starts an SVC Helper process that will inherit this channel; * - executes the supplied function by passing it the created SVCHlpClient * and opened instance to communicate to the Helper process and the given * The user function is supposed to communicate to the helper process * using the \a aClient argument to do the requested job and optionally expose * the progress through the \a aProgress object. The user function should never * call notifyComplete() on it: this will be done automatically using the * result code returned by the function. * Before the user function is started, the communication channel passed to * the \a aClient argument is fully set up, the function should start using * its write() and read() methods directly. * The \a aVrc parameter of the user function may be used to return an error * code if it is related to communication errors (for example, returned by * the SVCHlpClient members when they fail). In this case, the correct error * message using this value will be reported to the caller. Note that the * value of \a aVrc is inspected only if the user function itself returns * If a failure happens anywhere before the user function would be normally * called, it will be called anyway in special "cleanup only" mode indicated * by \a aClient, \a aProgress and \aVrc arguments set to NULL. In this mode, * all the function is supposed to do is to cleanup its aUser argument if * necessary (it's assumed that the ownership of this argument is passed to * the user function once #startSVCHelperClient() returns a success, thus * making it responsible for the cleanup). * After the user function returns, the thread will send the SVCHlpMsg::Null * message to indicate a process termination. * @param aPrivileged |true| to start the SVC Helper process as a privileged * user that can perform administrative tasks * @param aFunc user function to run * @param aUser argument to the user function * @param aProgress progress object that will track operation completion * @note aPrivileged is currently ignored (due to some unsolved problems in * Vista) and the process will be started as a normal (unprivileged) * @note Doesn't lock anything. /* create the SVCHelperClientThread() argument */ static_cast <
void *>(d.
get()),
/* d is now owned by SVCHelperClientThread(), so release it */ * Worker thread for startSVCHelperClient(). /* protect VirtualBox from uninitialization */ tr(
"Could not create the communication channel (%Rrc)"),
vrc);
/* get the path to the executable */ /* Attempt to start a privileged process using the Run As dialog */ /* hide excessive details in case of a frequent error * (pressing the Cancel button to close the Run As dialog) */ tr(
"Operation canceled by the user"));
tr(
"Could not launch a privileged process '%s' (%Rrc)"),
tr(
"Could not launch a process '%s' (%Rrc)"),
exePath,
vrc);
/* wait for the client to connect */ /* start the user supplied function */ /* send the termination signal to the process anyway */ tr(
"Could not operate the communication channel (%Rrc)"),
vrc);
/* call the user function in the "cleanup only" mode * to let it free resources passed to in aUser */ #
endif /* RT_OS_WINDOWS */ * Sends a signal to the client watcher to rescan the set of machines * that have open sessions. * @note Doesn't lock anything. * Adds the given child process ID to the list of processes to be reaped. * This call should be followed by #updateClientWatcher() to take the effect. * @note Doesn't lock anything. /** Event for onMachineStateChange(), onMachineDataChange(), onMachineRegistered() */ * @note Doesn't lock any object. * @note Doesn't lock any object. * @note Locks this object for reading. /** Event for onExtraDataChange() */ * @note Doesn't lock any object. * @note Doesn't lock any object. /** Event for onSessionStateChange() */ * @note Doesn't lock any object. /** Event for onSnapshotTaken(), onSnapshotDeleted() and onSnapshotChange() */ * @note Doesn't lock any object. * @note Doesn't lock any object. * @note Doesn't lock any object. /** Event for onGuestPropertyChange() */ * @note Doesn't lock any object. * @note Doesn't lock any object. * @note Locks the list of other objects for reading. /* unknown type must always be the first */ * Returns the list of opened machines (machines having direct sessions opened * by client processes) and optionally the list of direct session controls. * @param aMachines Where to put opened machines (will be empty if none). * @param aControls Where to put direct session controls (optional). * @note The returned lists contain smart pointers. So, clear it as soon as * it becomes no more necessary to release instances. * @note It can be possible that a session machine from the list has been * when accessing unprotected data directly. * @note Locks objects for reading. * Gets a reference to the machine list. This is the real thing, not a copy, * so bad things will happen if the caller doesn't hold the necessary lock. * @returns reference to machine list * @note Caller must hold the VirtualBox object lock at least for reading. * Searches for a machine object with the given ID in the collection * of registered machines. * @param aId Machine UUID to look for. * @param aPermitInaccessible If true, inaccessible machines will be found; * if false, this will fail if the given machine is inaccessible. * @param aSetError If true, set errorinfo if the machine is not found. * @param aMachine Returned machine, if found. // skip inaccessible machines tr(
"Could not find a registered machine with UUID {%RTuuid}"),
* Searches for a machine object with the given name or location in the * collection of registered machines. * @param aName Machine name or location to look for. * @param aSetError If true, set errorinfo if the machine is not found. * @param aMachine Returned machine, if found. continue;
// we can't ask inaccessible machines for their names tr(
"Could not find a registered machine named '%s'"),
aName.
c_str());
/* empty strings are invalid */ /* the toplevel group is valid */ /* any other strings of length 1 are invalid */ /* must start with a slash */ /* must not end with a slash */ /* check the group components */ /* no empty components (or // sequences in other words) */ /* check if the machine name rules are violated, because that means * the group components are too close to the limits. */ /* check if the machine name rules are violated, because that means * the group components is too close to the limits. */ * Validates a machine group. * @param aMachineGroup Machine group. * @param fPrimary Set if this is the primary group. * @return S_OK or E_INVALIDARG tr(
"Machine group '%s' conflicts with a virtual machine name"),
tr(
"Invalid machine group '%s'"),
* @param aMachineGroups Safearray with the machine groups. * @param pllMachineGroups Pointer to list of strings for the result. * @return S_OK or E_INVALIDARG /* no duplicates please */ * Searches for a Medium object with the given ID in the list of registered * @param aId ID of the hard disk. Must not be empty. * @param aSetError If @c true , the appropriate error info is set in case * when the hard disk is not found. * @param aHardDisk Where to store the found hard disk object (can be NULL). * @return S_OK, E_INVALIDARG or VBOX_E_OBJECT_NOT_FOUND when not found. * @note Locks the media tree for reading. // we use the hard disks map, but it is protected by the // hard disk _list_ lock handle tr(
"Could not find an open hard disk with UUID {%RTuuid}"),
* Searches for a Medium object with the given ID or location in the list of * registered hard disks. If both ID and location are specified, the first * object that matches either of them (not necessarily both) is returned. * @param aLocation Full location specification. Must not be empty. * @param aSetError If @c true , the appropriate error info is set in case * when the hard disk is not found. * @param aHardDisk Where to store the found hard disk object (can be NULL). * @return S_OK, E_INVALIDARG or VBOX_E_OBJECT_NOT_FOUND when not found. * @note Locks the media tree for reading. // we use the hard disks map, but it is protected by the // hard disk _list_ lock handle tr(
"Could not find an open hard disk with location '%s'"),
* Searches for a Medium object with the given ID or location in the list of * registered DVD or floppy images, depending on the @a mediumType argument. * If both ID and file path are specified, the first object that matches either * of them (not necessarily both) is returned. * @param mediumType Must be either DeviceType_DVD or DeviceType_Floppy. * @param aId ID of the image file (unused when NULL). * @param aLocation Full path to the image file (unused when NULL). * @param aSetError If @c true, the appropriate error info is set in case when * the image is not found. * @param aImage Where to store the found image object (can be NULL). * @return S_OK when found or E_INVALIDARG or VBOX_E_OBJECT_NOT_FOUND when not found. * @note Locks the media tree for reading. tr(
"Invalid image file location '%s' (%Rrc)"),
// no AutoCaller, registered image life time is bound to this tr(
"Could not find an image file with UUID {%RTuuid} in the media registry ('%s')"),
tr(
"Could not find an image file with location '%s' in the media registry ('%s')"),
* Searches for an IMedium object that represents the given UUID. * If the UUID is empty (indicating an empty drive), this sets pMedium * to NULL and returns S_OK. * If the UUID refers to a host drive of the given device type, this * sets pMedium to the object from the list in IHost and returns S_OK. * If the UUID is an image file, this sets pMedium to the object that * findDVDOrFloppyImage() returned. * If none of the above apply, this returns VBOX_E_OBJECT_NOT_FOUND. * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy. * @param uuid UUID to search for; must refer to a host drive or an image file or be null. * @param fRefresh Whether to refresh the list of host drives in IHost (see Host::getDrives()) * @param pMedium out: IMedium object found. /* handling of case invalid GUID */ tr(
"Guid '%s' is invalid"),
// first search for host drive with that UUID // then search for an image with that UUID /* Look for a GuestOSType object */ (
"Guest OS types array must be filled"));
tr(
"Guest OS type '%ls' is invalid"),
* Returns the constant pseudo-machine UUID that is used to identify the * Starting with VirtualBox 4.0 each medium remembers in its instance data * in which media registry it is saved (if any): this can either be a machine * UUID, if it's in a per-machine media registry, or this global ID. * This UUID is only used to identify the VirtualBox object while VirtualBox * is running. It is a compile-time constant and not saved anywhere. * Getter that SystemProperties and others can use to talk to the extension * Getter that machines can talk to the autostart database. #
endif /* VBOX_WITH_RESOURCE_USAGE_API */ * Returns the default machine folder from the system properties * Returns the default hard disk format from the system properties * Calculates the absolute path of the given path taking the VirtualBox home * directory 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 Doesn't lock any object. /* no need to lock since mHomeDir is const */ * Copies strSource to strTarget, making it relative to the VirtualBox config folder * if it is a subdirectory thereof, or simply copying it otherwise. * @param strSource Path to evalue and copy. * @param strTarget Buffer to receive target path. // no need to lock since mHomeDir is const // use strTarget as a temporary buffer to hold the machine settings dir // is relative: then append what's left // is not relative: then overwrite ///////////////////////////////////////////////////////////////////////////// * Checks if there is a hard disk, DVD or floppy image with the given ID or * location already registered. * On return, sets @a aConflict to the string describing the conflicting medium, * or sets it to @c Null if no conflicting media is found. Returns S_OK in * either case. A failure is unexpected. * @param aId UUID to check. * @param aLocation Location to check. * @param aConflict Where to return parameters of the conflicting medium. * @param ppMedium Medium reference in case this is simply a duplicate. * @note Locks the media tree and media objects for reading. /* Note: no AutoCaller since bound to this */ * Checks whether the given UUID is already in use by one medium for the * @returns true if the UUID is already in use * @param aId The UUID to check. * @param deviceType The device type the UUID is going to be checked for /* A zero UUID is invalid here, always claim that it is already used. */ * Called from Machine::prepareSaveSettings() when it has detected * that a machine has been renamed. Such renames will require * updating the global media registry during the * VirtualBox::saveSettings() that follows later. * When a machine is renamed, there may well be media (in particular, * diff images for snapshots) in the global registry that will need * to have their paths updated. Before 3.2, Machine::saveSettings * used to call VirtualBox::saveSettings implicitly, which was both * unintuitive and caused locking order problems. Now, we remember * such pending name changes with this method so that * VirtualBox::saveSettings() can process them properly. LogRelFunc((
"Thread for saving media registries lacks parameters\n"));
* Goes through all known media (hard disks, floppies and DVDs) and saves * those into the given settings::MediaRegistry structures whose registry * ID match the given UUID. * Before actually writing to the structures, all media paths (not just the * ones for the given registry) are updated if machines have been renamed * This gets called from two contexts: * -- VirtualBox::saveSettings() with the UUID of the global registry * (VirtualBox::Data.uuidRegistry); this will save those media * which had been loaded from the global registry or have been * attached to a "legacy" machine which can't save its own registry; * -- Machine::saveSettings() with the UUID of a machine, if a medium * has been attached to a machine created with VirtualBox 4.0 or later. * Media which have only been temporarily opened without having been * attached to a machine have a NULL registry UUID and therefore don't * This locks the media tree. Throws HRESULT on errors! * @param mediaRegistry Settings structure to fill. * @param uuidRegistry The UUID of the media registry; either a machine UUID * (if machine registry) or the UUID of the global registry. * @param strMachineFolder The machine folder for relative paths, if machine registry, or an empty string otherwise. // lock all media for the following; use a write lock because we're // modifying the PendingMachineRenamesList, which is protected by this // if a machine was renamed, then we'll need to refresh media paths // make a single list from the three media lists so we don't need three loops // with hard disks, we must use the map, not the list, because the list only has base images // Remember which medium objects has been changed, // to trigger saving their registries later. // done, don't do it again until we have more machine renames // Handle the media registry saving in a separate thread, to // avoid giant locking problems and passing up the list many // levels up to whoever triggered saveSettings, as there are // lots of places which would need to handle saving more settings. // failure means that settings aren't saved, but there isn't // much we can do besides avoiding memory leaks LogRelFunc((
"Failed to create thread for saving media registries (%Rrc)\n",
vrc));
* Helper function which actually writes out VirtualBox.xml, the main configuration file. * Gets called from the public VirtualBox::SaveSettings() as well as from various other * places internally when settings need saving. * @note Caller must have locked the VirtualBox object for writing and must not hold any * other locks since this locks all kinds of member objects and trees temporarily, * which could cause conflicts. // save actual machine registry entry /* Saving NAT Network configuration */ // leave extra data alone, it's still in the config file // host data (USB filters) // and write out the XML, still under the lock /* we assume that error info is set by the thrower */ * Helper to register the machine. * When called during VirtualBox startup, adds the given machine to the * collection of registered machines. Otherwise tries to mark the machine * as registered, and, if succeeded, adds it to the collection and * @note The caller must have added itself as a caller of the @a aMachine * object if calls this method not on VirtualBox startup. * @param aMachine machine to register true /* fPermitInaccessible */,
tr(
"Registered machine with UUID {%RTuuid} ('%s') already exists"),
/* add to the collection of registered machines */ * Remembers the given medium object by storing it in either the global * medium registry or a machine one. * @note Caller must hold the media tree lock for writing; in addition, this * locks @a pMedium for reading * @param pMedium Medium object to remember. * @param ppMedium Actually stored medium object. Can be different if due * to an unavoidable race there was a duplicate Medium object * @param argType Either DeviceType_HardDisk, DeviceType_DVD or DeviceType_Floppy. * @param mediaTreeLock Reference to the AutoWriteLock holding the media tree * lock, necessary to release it in the right spot. // caller must hold the media tree write lock tr(
"Cannot register the %s '%s' {%RTuuid} because a %s already exists"),
// add to the collection if it is a base medium // store all hard disks (even differencing images) in the map // pMedium may be the last reference to the Medium object, and the // caller may have specified the same ComObjPtr as the output parameter. // In this case the assignment will uninit the object, and we must not // have a caller pending. // release media tree lock, must not be held at uninit time. // must not hold the media tree write lock any more * Removes the given medium from the respective registry. * @param pMedium Hard disk object to remove. * @note Caller must hold the media tree lock for writing; in addition, this locks @a pMedium for reading // caller must hold the media tree write lock // remove from the collection if it is a base medium // remove all hard disks (even differencing images) from map * Little helper called from unregisterMachineMedia() to recursively add media to the given list, * with children appearing before their parents. // recurse first, then add ourselves; this way children end up on the // list before their parents * Unregisters all Medium objects which belong to the given machine registry. * Gets called from Machine::uninit() just before the machine object dies * and must only be called with a machine UUID as the registry ID. * @param uuidMachine Medium registry ID (always a machine UUID) // recursively with children first * Removes the given machine object from the internal list of registered machines. * Called from Machine::Unregister(). * @param id UUID of the machine. Must be passed by caller because machine may be dead by this time. // remove from the collection of registered machines // save the global registry * Now go over all known media and checks if they were registered in the * media registry of the given machine. Each such medium is then moved to * a different media registry to make sure it doesn't get lost since its * media registry is about to go away. * This fixes the following use case: Image A.vdi of machine A is also used * by machine B, but registered in the media registry of machine A. If machine * A is deleted, A.vdi must be moved to the registry of B, or else B will // iterate over the list of *base* images // machine ID was found in base medium's registry list: // move this base image and all its children to another registry then // 1) first, find a better registry to add things to // 2) better registry found: then use that // 3) and make sure the registry is saved below * Marks the registry for @a uuid as modified, so that it's saved in a later * call to saveModifiedRegistries(). false /* fPermitInaccessible */,
* Saves all settings files according to the modified flags in the Machine * objects and in the VirtualBox object. * This locks machines and the VirtualBox object as necessary, so better not * hold any locks before calling this. /* object is already dead, no point in saving settings */ * Checks if the path to the specified file exists, according to the path * information present in the file name. Optionally the path is created. * Note that the given file name must contain the full path otherwise the * extracted relative path will be created based on the current working * directory which is normally unknown. * @param aCreate Flag if the path should be created if it doesn't exist. * @return Extended error information on failure to check/create the path. Utf8StrFmt(
tr(
"Could not create the directory '%s' (%Rrc)"),
* Returns the lock handle which protects the machines list. As opposed * to version 3.1 and earlier, these lists are no longer protected by the * VirtualBox lock, but by this more specialized lock. Mind the locking * order: always request this lock after the VirtualBox object lock but * before the locks of any machine object. See AutoLock.h. * Returns the lock handle which protects the media trees (hard disks, * DVDs, floppies). As opposed to version 3.1 and earlier, these lists * are no longer protected by the VirtualBox lock, but by this more * specialized lock. Mind the locking order: always request this lock * after the VirtualBox object lock but before the locks of the media * objects contained in these lists. See AutoLock.h. * Thread function that handles custom events posted using #postEvent(). /* Create an event queue for the current thread. */ /* Return the queue to the one who created this thread. */ /* signal that we're ready. */ * In case of spurious wakeups causing VERR_TIMEOUTs and/or other return codes * we must not stop processing events and delete the pEventQueue object. This must * be done ONLY when we stop this loop via interruptEventQueueProcessing(). LogFlow((
"Event queue processing ended with rc=%Rrc\n",
rc));
//////////////////////////////////////////////////////////////////////////////// * Takes the current list of registered callbacks of the managed VirtualBox * instance, and calls #handleCallback() for every callback item from the * list, passing the item as an argument. * @note Locks the managed VirtualBox object for reading but leaves the lock * before iterating over callbacks and calling their methods. LogWarningFunc((
"VirtualBox has been uninitialized (state=%d), the callback event is discarded!\n",
/* We don't need mVirtualBox any more, so release it */ mVirtualBox =
NULL;
/* Not needed any longer. Still make sense to do this? */ //STDMETHODIMP VirtualBox::CreateDHCPServerForInterface(/*IHostNetworkInterface * aIinterface,*/ IDHCPServer ** aServer) * Remembers the given DHCP server in the settings. * @param aDHCPServer DHCP server object to remember. * @param aSaveSettings @c true to save settings to disk (default). * When @a aSaveSettings is @c true, this operation may fail because of the * failed #saveSettings() method it calls. In this case, the dhcp server object * will not be remembered. It is therefore the responsibility of the caller to * call this method as the last step of some action that requires registration * in order to make sure that only fully functional dhcp server objects get * @note Locks this object for writing and @a aDHCPServer for reading. // need it below, in findDHCPServerByNetworkName (reading) and in // m->allDHCPServers.addChild, so need to get it here to avoid lock // order trouble with dhcpServerCaller * Removes the given DHCP server from the settings. * @param aDHCPServer DHCP server object to remove. * @param aSaveSettings @c true to save settings to disk (default). * When @a aSaveSettings is @c true, this operation may fail because of the * failed #saveSettings() method it calls. In this case, the DHCP server * will NOT be removed from the settingsi when this method returns. * @note Locks this object for writing. * Remembers the given NAT network in the settings. * @param aNATNetwork NAT Network object to remember. * @param aSaveSettings @c true to save settings to disk (default). * @note Locks this object for writing and @a aNATNetwork for reading. /* returned value isn't 0 and aSaveSettings is true * means that we create duplicate, otherwise we just load settings. /* No panic please (silently ignore) */ * Removes the given NAT network from the settings. * @param aNATNetwork NAT network object to remove. * @param aSaveSettings @c true to save settings to disk (default). * When @a aSaveSettings is @c true, this operation may fail because of the * failed #saveSettings() method it calls. In this case, the DHCP server * will NOT be removed from the settingsi when this method returns. * @note Locks this object for writing. /* Hm, there're still running clients. */ /* vi: set tabstop=4 shiftwidth=4 expandtab: */