ConsoleImpl.cpp revision 1a2cb5a8ab8335c91eb9abaca231365fc5a98a9f
LogRel ((
"VRDPAUTH: User: [%s]. Domain: [%s]. Authentication type: [%s]\n",
/* Multiconnection check. */ /* Note: the variable is incremented in ClientConnect callback, which is called when the client * is successfully connected, that is after the ClientLogon callback. Therefore the mcVRDPClients * value is 0 for first client. LogRel((
"VRDPAUTH: Multiple connections are not enabled. Access denied.\n"));
/* Call the external library. */ LogRel((
"VRDPAUTH: Delegated to guest.\n"));
LogFlowFunc ((
"External auth asked for guest judgement\n"));
/* Issue the request to guest. Assume that the call does not require EMT. It should not. */ /* Ask the guest to judge these credentials. */ LogFlowFunc ((
"Wait for credentials judgement rc = %Vrc!!!\n",
rc));
LogRel((
"VRDPAUTH: Access granted.\n"));
LogRel((
"VRDPAUTH: Access denied.\n"));
* Loads various console data stored in the saved state file. * This method does validation of the state file and returns an error info * The method does nothing if the machine is not in the Saved file or if * console data from it has already been loaded. * @note The caller must lock this object for writing. tr (
"The saved state file '%ls' is invalid (%Vrc). " "Discard the saved state and try again"),
* Callback handler to save various console data to the state file, * called when the user saves the VM state. * @param pvUser pointer to Console * @note Locks the Console object for reading. // don't lock the folder because methods we access are const * Callback handler to load various console data from the state file. * When \a u32Version is 0, this method is called from #loadDataFromSavedState, * otherwise it is called when the VM is being restored from the saved state. * @param pvUser pointer to Console * @param u32Version Console unit version. * When not 0, should match sSSMConsoleVer. * @note Locks the Console object for writing. /* currently, nothing to do when we've been called from VMR3Load */ ///////////////////////////////////////////////////////////////////////////// /* mMachine is constant during life time, no need to lock */ /* we return our local state (since it's always the same as on the server) */ /* mGuest is constant during life time, no need to lock */ /* mKeyboard is constant during life time, no need to lock */ /* mMouse is constant during life time, no need to lock */ /* mDisplay is constant during life time, no need to lock */ /* we need a write lock because of the lazy mDebugger initialization*/ /* check if we have to create the debugger object */ /* mDisplay is constant during life time, no need to lock */ /* loadDataFromSavedState() needs a write lock */ /* Read console data stored in the saved state file (if not yet done) */ ///////////////////////////////////////////////////////////////////////////// "already running (machine state: %d)"),
* First check whether all disks are accessible. This is not a 100% * bulletproof approach (race condition, it might become inaccessible * right after the check) but it's convenient as it will cover 99.9% * of the cases and here, we're able to provide meaningful error tr (
"VM cannot start because the hard disk '%ls' is not accessible " /* now perform the same check if a ISO is mounted */ /// @todo (r=dmik) grab the last access error once // IDVDImage::lastAccessError is there tr (
"The virtual machine could not be started because the DVD image '%ls' which is attached to it could not be found or could not be opened. Please detach the image and try again"),
/* now perform the same check if a floppy is mounted */ /// @todo (r=dmik) grab the last access error once // IDVDImage::lastAccessError is there tr (
"The virtual machine could not be started because the floppy image '%ls' which is attached to it could not be found or could not be opened. Please detach the image and try again"),
/* now the network cards will undergo a quick consistency check */ /* a valid host interface must have been set */ tr (
"VM cannot start because host interface networking " "requires a host interface name to be set"));
tr (
"VM cannot start because the host interface '%ls' " #
endif /* RT_OS_WINDOWS */ /* Read console data stored in the saved state file (if not yet done) */ /* Check all types of shared folders and compose a single list */ /* first, insert global folders */ /* second, insert machine folders */ /* third, insert console folders */ * Saved VMs will have to prove that their saved states are kosher. tr (
"VM cannot start because the saved state file '%ls' is invalid (%Vrc). " "Discard the saved state prior to starting the VM"),
/* create an IProgress object to track progress of this operation */ /* pass reference to caller if requested */ /* setup task object and thread to carry out the operation asynchronously */ /* task is now owned by powerUpThread(), so release it */ /* extra nice error message for a common case */ "not running or paused (machine state: %d)"),
"not running (machine state: %d)"),
/* leave the lock before a VMR3* call (EMT will call us back)! */ "not running (machine state: %d)"),
/* leave the lock before a VMR3* call (EMT will call us back)! */ tr (
"Could not suspend the machine execution (%Vrc)"),
vrc);
"not paused (machine state: %d)"),
/* leave the lock before a VMR3* call (EMT will call us back)! */ tr (
"Could not resume the machine execution (%Vrc)"),
vrc);
"not running (machine state: %d)"),
tr (
"Controlled power off failed (%Vrc)"),
vrc);
tr (
"Checking if the ACPI Power Button event was handled by the " "guest OS failed (%Vrc)"),
vrc);
"not running (machine state: %d)"),
tr (
"Sending sleep button event failed (%Vrc)"),
vrc);
tr (
"Cannot save the execution state as the machine " /* memorize the current machine state */ /* create a progress object to track operation completion */ Bstr (
tr (
"Saving the execution state of the virtual machine")),
FALSE /* aCancelable */);
/* create a task object early to ensure mpVM protection is successful */ * If we fail here it means a PowerDown() call happened on another * thread while we were doing Pause() (which leaves the Console lock). * We assign PowerDown() a higher precendence than SaveState(), * therefore just return the error to the caller. * request a saved state file path from the server * (this will set the machine state to Saving on the server to block * others from accessing this machine) /* sync the state with the server */ /* ensure the directory for the saved state file exists */ tr (
"Could not create a directory '%s' to save the state to (%Vrc)"),
/* setup task object and thread to carry out the operation asynchronously */ /* set the state the operation thread will restore when it is finished */ /* create a thread to wait until the VM state is saved */ /* task is now owned by saveStateThread(), so release it */ /* return the progress to the caller */ /* preserve existing error info */ * cancel the requested save state procedure. * This will reset the machine state to the state it had right * before calling mControl->BeginSavingState(). /* restore the paused state if appropriate */ /* restore the running state if appropriate */ tr (
"Cannot adopt the saved machine state as the machine is " "not in Powered Off or Aborted state (machine state: %d)"),
tr (
"Cannot discard the machine state as the machine is " "not in the saved state (machine state: %d)"),
* Saved -> PoweredOff transition will be detected in the SessionMachine /** read the value of a LEd. */ * Note: we don't lock the console object here because * readAndClearLed() should be thread safe. /* Get LED array to read */ /// @todo (r=dmik) is it legal to attach USB devices when the machine is // Paused, Starting, Saving, Stopping, etc? if not, we should make a // stricter check (mMachineState != MachineState_Running). // I'm changing it to the semi-strict check for the time being. We'll // consider the below later. /* bird: It is not permitted to attach or detach while the VM is saving, * is restoring or has stopped - definintly not. * Attaching while starting, well, if you don't create any deadlock it * should work... Paused should work I guess, but we shouldn't push our * luck if we're pausing because an runtime error condition was raised * (which is one of the reasons there better be a separate state for that tr (
"Cannot attach a USB device to the machine which is not running" /* Don't proceed unless we've found the usb controller. */ tr (
"The virtual machine does not have a USB controller"));
/* leave the lock because the USB Proxy service may call us back * (via onUSBDeviceAttach()) */ /* Request the device capture */ #
else /* !VBOX_WITH_USB */ tr (
"The virtual machine does not have a USB controller"));
#
endif /* !VBOX_WITH_USB */ tr (
"USB device with UUID {%Vuuid} is not attached to this machine"),
* Inform the USB device and USB proxy about what's cooking. /* Request the PDM to detach the USB device. */ /* leave the lock since we don't need it any more (note though that * the USB Proxy service must not call us back here) */ /* Request the device release. Even if it fails, the device will * remain as held by proxy, which is OK for us (the VM process). */ #
else /* !VBOX_WITH_USB */ tr (
"USB device with UUID {%Vuuid} is not attached to this machine"),
#
endif /* !VBOX_WITH_USB */ /// @todo see @todo in AttachUSBDevice() about the Paused state tr (
"Cannot create a transient shared folder on the " "machine in the saved state"));
tr (
"Cannot create a transient shared folder on the " "machine while it is changing the state (machine state: %d)"),
tr (
"Shared folder named '%ls' already exists"),
aName);
tr (
"Shared folder host path '%ls' is not accessible"),
aHostPath);
/* protect mpVM (if not NULL) */ /* If the VM is online and supports shared folders, share this folder * under the specified name. */ /* first, remove the machine or the global folder if there is any */ /* second, create the given folder */ /* notify console callbacks after the folder is added to the list */ /// @todo see @todo in AttachUSBDevice() about the Paused state tr (
"Cannot remove a transient shared folder from the " "machine in the saved state"));
tr (
"Cannot remove a transient shared folder from the " "machine while it is changing the state (machine state: %d)"),
/* protect mpVM (if not NULL) */ /* if the VM is online and supports shared folders, UNshare this /* first, remove the given folder */ /* first, remove the machine or the global folder if there is any */ /* don't check rc here because we need to remove the console * folder from the collection even on failure */ /* notify console callbacks after the folder is removed to the list */ tr (
"Cannot take a snapshot of the machine " "while it is changing the state (machine state: %d)"),
/* memorize the current machine state */ * create a descriptionless VM-side progress object * (only when creating a snapshot online) /* create a task object early to ensure mpVM protection is successful */ * If we fail here it means a PowerDown() call happened on another * thread while we were doing Pause() (which leaves the Console lock). * We assign PowerDown() a higher precendence than TakeSnapshot(), * therefore just return the error to the caller. * request taking a new snapshot object on the server * (this will set the machine state to Saving on the server to block * others from accessing this machine) * state file is non-null only when the VM is paused * (i.e. createing a snapshot online) /* sync the state with the server */ * create a combined VM-side progress object and start the save task * (only when creating a snapshot online) Bstr (
tr (
"Taking snapshot of virtual machine")),
/* setup task object and thread to carry out the operation asynchronously */ /* set the state the operation thread will restore when it is finished */ /* create a thread to wait until the VM state is saved */ /* task is now owned by saveStateThread(), so release it */ /* return the correct progress to the caller */ /* preserve existing error info */ * cancel the requested snapshot (only when creating a snapshot * online, otherwise the server will cancel the snapshot itself). * This will reset the machine state to the state it had right * before calling mControl->BeginTakingSnapshot(). /* restore the paused state if appropriate */ /* restore the running state if appropriate */ tr (
"Cannot discard a snapshot of the running machine " tr (
"Cannot discard the current state of the running machine " tr (
"Cannot discard the current snapshot and state of the " "running machine (machine state: %d)"),
/* Inform the callback about the current status (for example, the new * callback must know the current mouse capabilities and the pointer * shape in order to properly integrate the mouse pointer). */ /* Note: we don't call OnStateChange for new callbacks because the * machine state is a) not actually changed on callback registration * and b) can be always queried from Console. */ tr (
"The given callback handler is not registered"));
// Non-interface public methods ///////////////////////////////////////////////////////////////////////////// * Called by IInternalSessionControl::OnDVDDriveChange(). * @note Locks this object for writing. /* doDriveChange() needs a write lock */ /* Ignore callbacks when there's no VM around */ /* Get the current DVD state */ /* Get the path string and other relevant properties */ /* notify console callbacks on success */ * Called by IInternalSessionControl::OnFloppyDriveChange(). * @note Locks this object for writing. /* doDriveChange() needs a write lock */ /* Ignore callbacks when there's no VM around */ /* Get the current floppy state */ /* If the floppy drive is disabled, we're not interested */ /* Get the path string and other relevant properties */ /* notify console callbacks on success */ * Process a floppy or dvd change. * @returns COM status code. * @param pszDevice The PDM device name. * @param uInstance The PDM device instance. * @param uLun The PDM LUN number of the drive. * @param eState The new state. * @param peState Pointer to the variable keeping the actual state of the drive. * This will be both read and updated to eState or other appropriate state. * @param pszPath The path to the media / drive which is now being mounted / captured. * If NULL no media or drive is attached and the lun will be configured with * the default block driver with no media. This will also be the state if * mounting / capturing the specified media / drive fails. * @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable. * @note Locks this object for writing. "peState=%p:{%d} pszPath=%p:{%s} fPassthrough=%d\n",
/* We will need to release the write lock before calling EMT */ * Call worker in EMT, that's faster and safer than doing everything * using VM3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait * here to make requests from under the lock in order to serialize them. /// @todo (r=dmik) bird, it would be nice to have a special VMR3Req method // for that purpose, that doesn't return useless VERR_TIMEOUT /* leave the lock before waiting for a result (EMT will call us back!) */ * @returns VBox status code. * @param pThis Pointer to the Console object. * @param pszDevice The PDM device name. * @param uInstance The PDM device instance. * @param uLun The PDM LUN number of the drive. * @param eState The new state. * @param peState Pointer to the variable keeping the actual state of the drive. * This will be both read and updated to eState or other appropriate state. * @param pszPath The path to the media / drive which is now being mounted / captured. * If NULL no media or drive is attached and the lun will be configured with * the default block driver with no media. This will also be the state if * mounting / capturing the specified media / drive fails. * @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable. * @note Locks the Console object for writing. LogFlowFunc ((
"pThis=%p pszDevice=%p:{%s} uInstance=%u uLun=%u eState=%d " "peState=%p:{%d} pszPath=%p:{%s} fPassthrough=%d\n",
* Locking the object before doing VMR3* calls is quite safe here, since * we're on EMT. Write lock is necessary because we indirectly modify the * The VM must not be running since it might have pending I/O to * the drive which is being changed. /* disable the callback to prevent Console-level state change */ * Unmount existing media / detach host drive. * Nothing is currently mounted. * Process the HostDriveCaptured state first, as the fallback path * means mounting the normal block driver without media. * Detach existing driver chain (block). * Construct a new driver configuration. /* nuke anything which might have been left behind. */ /* create a new block driver config */ * Attempt to attach the driver. * Process the ImageMounted, NotMounted and failed HostDriveCapture cases. /* fallback: umounted block driver. */ * Resolve the drive interface / create the driver. * We have to create it, so we'll do the full config setup and everything. /* nuke anything which might have been left behind. */ /* create a new block driver config */ * If we've got an image, let's mount it. * Resume the VM if necessary. /* disable the callback to prevent Console-level state change */ /* too bad, we failed. try to sync the console state with the VMM state */ /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume // error (if any) will be hidden from the caller. For proper reporting // of such multiple errors to the caller we need to enhance the // IVurtualBoxError interface. For now, give the first error the higher * Called by IInternalSessionControl::OnNetworkAdapterChange(). * @note Locks this object for writing. /* Don't do anything if the VM isn't running */ /* Get the properties we need from the adapter */ * Find the pcnet instance, get the config interface and update * Perharps it would be much wiser to wrap both 'pcnet' and 'e1000' * into generic 'net' device. Log ((
"Console::onNetworkAdapterChange: setting link state to %d\n",
/* notify console callbacks on success */ * Called by IInternalSessionControl::OnSerialPortChange(). * @note Locks this object for writing. /* Don't do anything if the VM isn't running */ /* nothing to do so far */ /* notify console callbacks on success */ * Called by IInternalSessionControl::OnParallelPortChange(). * @note Locks this object for writing. /* Don't do anything if the VM isn't running */ /* nothing to do so far */ /* notify console callbacks on success */ * Called by IInternalSessionControl::OnVRDPServerChange(). * @note Locks this object for writing. // If there was no VRDP server started the 'stop' will do nothing. // However if a server was started and this notification was called, // we have to restart the server. /* notify console callbacks on success */ * Called by IInternalSessionControl::OnUSBControllerChange(). * @note Locks this object for writing. /* Ignore if no VM is running yet. */ // check for the Enabled state and disable virtual USB controller?? // Anyway, if we want to query the machine's USB Controller we need to cache // it to to mUSBController in #init() (as it is done with mDVDDrive). // bird: While the VM supports hot-plugging, I doubt any guest can handle it at this time... :-) // AutoVMCaller autoVMCaller (this); // CheckComRCReturnRC (autoVMCaller.rc()); /* notify console callbacks on success */ * Called by IInternalSessionControl::OnSharedFolderChange(). * @note Locks this object for writing. /* notify console callbacks on success */ * Called by IInternalSessionControl::OnUSBDeviceAttach() or locally by * processRemoteUSBDevices() after IInternalMachineControl::RunUSBDeviceFilters() * returns TRUE for a given remote USB device. * @return S_OK if the device was attached to the VM. * @return failure if not attached. * The device in question. * The interfaces to hide from the guest. * @note Locks this object for writing. /* protect mpVM (we don't need error info, since it's a callback) */ /* The VM may be no more operational when this message arrives * (e.g. it may be Saving or Stopping or just PoweredOff) -- * autoVMCaller.rc() will return a failure in this case. */ /* notify callbacks about the error */ /* Don't proceed unless there's at least one USB hub. */ /* take the current error info */ /* the error must be a VirtualBoxErrorInfo instance */ /* notify callbacks about the error */ #
else /* !VBOX_WITH_USB */#
endif /* !VBOX_WITH_USB */ * Called by IInternalSessionControl::OnUSBDeviceDetach() and locally by * processRemoteUSBDevices(). * @note Locks this object for writing. /* The VM may be no more operational when this message arrives * (e.g. it may be Saving or Stopping or just PoweredOff). Use * AutoVMCaller to detect it -- AutoVMCaller::rc() will return a * failure in this case. */ /* the device must be in the list otherwise */ /* notify callback about an error */ /* take the current error info */ /* the error must be a VirtualBoxErrorInfo instance */ /* notify callbacks about the error */ #
else /* !VBOX_WITH_USB */#
endif /* !VBOX_WITH_USB */ /* protect mpVM (if not NULL) */ /* To save doing a const cast, we use the mutableRaw() member. */ /* The + 1 is the null terminator */ /* The returned string should never be able to be greater than our buffer */ /* protect mpVM (if not NULL) */ /* To save doing a const cast, we use the mutableRaw() member. */ /* The + 1 is the null terminator */ /* To save doing a const cast, we use the mutableRaw() member. */ /* The + 1 is the null terminator */ * Gets called by Session::UpdateMachineState() * (IInternalSessionControl::updateMachineState()). * Must be called only in certain cases (see the implementation). * @note Locks this object for writing. * @note Locks this object for writing. LogFlowThisFunc ((
"fVisible=%d, fAlpha=%d, xHot = %d, yHot = %d, width=%d, " /* We need a write lock because we alter the cached callback data */ /* Save the callback arguments */ /* start with not valid */ cb = ((
cb +
3) & ~
3) +
width *
4 *
height;
/* + gap + size of the XOR mask */ /* try to reuse the old shape buffer if the size is the same */ * @note Locks this object for writing. /* We need a write lock because we alter the cached callback data */ /* save the callback arguments */ Log2((
"Console::onMouseCapabilityChange: calling %p\n", (
void*)*
it));
* @note Locks this object for reading. * @note Locks this object for reading. * @note Locks this object for reading. /** @todo Use the On-Screen Display feature to report the fact. * The user should be told to install additions that are * provided with the current VBox build: * VBOX_VERSION_MAJOR.VBOX_VERSION_MINOR.VBOX_VERSION_BUILD * @note Locks this object for writing. /* We need a write lock because we alter the cached callback data */ /* save the callback arguments */ * @note Locks this object for reading. * @note Locks this object for reading. * @note Locks this object for reading. /* only one callback may return non-null winId */ //////////////////////////////////////////////////////////////////////////////// * Increases the usage counter of the mpVM pointer. Guarantees that * VMR3Destroy() will not be called on it at least until releaseVMCaller() * If this method returns a failure, the caller is not allowed to use mpVM * and may return the failed result code to the upper level. This method sets * the extended error info on failure if \a aQuiet is false. * Setting \a aQuiet to true is useful for methods that don't want to return * the failed result code to the caller when this method fails (e.g. need to * silently check for the mpVM avaliability). * When mpVM is NULL but \a aAllowNullVM is true, a corresponding error will be * returned instead of asserting. Having it false is intended as a sanity check * for methods that have checked mMachineState and expect mpVM *NOT* to be NULL. * @param aQuiet true to suppress setting error info * @param aAllowNullVM true to accept mpVM being NULL and return a failure * (otherwise this method will assert if mpVM is NULL) * @note Locks this object for writing. /* powerDown() is waiting for all callers to finish */ tr (
"Virtual machine is being powered down"));
/* The machine is not powered up */ tr (
"Virtual machine is not powered up"));
* Decreases the usage counter of the mpVM pointer. Must always complete * the addVMCaller() call after the mpVM pointer is no more necessary. * @note Locks this object for writing. /* inform powerDown() there are no more callers */ * Initialize the release logging facility. In case something * goes wrong, there will be no release logging. Maybe in the future * we can add some logic to use different file names in this case. * Note that the logic must be in sync with Machine::DeleteSettings(). /* make sure the Logs folder exists */ * Rename .(n-1) to .(n), .(n-2) to .(n-1), ..., and the last log file to .1 * Overwrite target files in case they exist. /* If the old file doesn't exist, delete the new file (if it * exists) to provide correct rotation even if the sequence is /* some introductory information */ "VirtualBox %s r%d %s (%s %s) release log\n" /* register this logger as the release logger */ tr (
"Failed to open release log (%s, %Rrc)"),
szError,
vrc);
* Internal power off worker routine. * This method may be called only at certain places with the folliwing meaning * - if the machine state is either Running or Paused, a normal * Console-initiated powerdown takes place (e.g. PowerDown()); * - if the machine state is Saving, saveStateThread() has successfully * - if the machine state is Starting or Restoring, powerUpThread() has * - if the machine state is Stopping, the VM has powered itself off * (i.e. not as a result of the powerDown() call). * Calling it in situations other than the above will cause unexpected * Note that this method should be the only one that destroys mpVM and sets * @note Locks this object for writing. * @note Never call this method from a thread that called addVMCaller() or * instantiated an AutoVMCaller object; first call releaseVMCaller() or * release(). Otherwise it will deadlock. LogRel ((
"Console::powerDown(): a request to power off the VM has been issued " "(mMachineState=%d, InUninit=%d)\n",
* Stop the VRDP server to prevent new clients connection while VM is being powered off. /* Leave the lock since EMT will call us back as addVMCaller in updateDisplayData(). */ * Shutdown HGCM services before stopping the guest, because they might need a cleanup. /* Save all guest/host property store entries to the machine XML #
endif /* VBOX_WITH_INFO_SVC defined */ /* First, wait for all mpVM callers to finish their work if necessary */ /* go to the destroying state to prevent from adding new callers */ * Power off the VM if not already done that. In case of Stopping, the VM * has powered itself off and notified Console in vmstateChangeCallback(). * In case of Starting or Restoring, powerUpThread() is calling us on * failure, so the VM is already off at that point. * don't go from Saving to Stopping, vmstateChangeCallback needs it * to set the state to Saved on VMSTATE_TERMINATED. /* Leave the lock since EMT will call us back on VMR3PowerOff() */ * Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the * VM-(guest-)initiated power off happened in parallel a ms before * this call. So far, we let this error pop up on the user's side. * If we are called from Console::uninit(), then try to destroy the VM * even on failure (this will most likely fail too, but what to do?..) /* If the machine has an USB comtroller, release all USB devices * (symmetric to the code in captureUSBDevices()) */ * Now we've got to destroy the VM as well. (mpVM is not valid * beyond this point). We leave the lock before calling VMR3Destroy() * because it will result into calling destructors of drivers * associated with Console children which may in turn try to lock * Console (e.g. by instantiating SafeVMPtr to access mpVM). It's safe * here because mVMDestroying is set which should prevent any activity. * Set mpVM to NULL early just in case if some old code is not using * addVMCaller()/releaseVMCaller(). /* take the lock again */ * Note: the Console-level machine state change happens on the * VMSTATE_TERMINATE state change in vmstateChangeCallback(). If * powerDown() is called from EMT (i.e. from vmstateChangeCallback() * on receiving VM-initiated VMSTATE_OFF), VMSTATE_TERMINATE hasn't * occured yet. This is okay, because mMachineState is already * Stopping in this case, so any other attempt to call PowerDown() /* bad bad bad, but what to do? */ tr (
"Could not destroy the machine. (Error: %Vrc)"),
vrc);
* Complete the detaching of the USB devices. tr (
"Could not power off the machine. (Error: %Vrc)"),
vrc);
* Finished with destruction. Note that if something impossible happened * and we've failed to destroy the VM, mVMDestroying will remain false and * mMachineState will be something like Stopping, so most Console methods * will return an error to the caller. /* uninit dynamically allocated members of mCallbackData */ * @note Locks this object for writing. // possibly, we need to redo onStateChange() using the dedicated // Event thread, like it is done in VirtualBox. This will make it // much safer (no deadlocks possible if someone tries to use the // console from the callback), however, listeners will lose the // ability to synchronously react to state changes (is it really * Server notification MUST be done from under the lock; otherwise * the machine state here and on the server might go out of sync, that * can lead to various unexpected results (like the machine state being * >= MachineState_Running on the server, while the session state is * already SessionState_Closed at the same time there). * Cross-lock conditions should be carefully watched out: calling * UpdateState we will require Machine and SessionMachine locks * (remember that here we're holding the Console lock here, and * also all locks that have been entered by the thread before calling * 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 E_INVALIDARG when not found * @note The caller must lock this object for writing. tr (
"Could not find a shared folder named '%ls'."),
aName);
* Fetches the list of global or machine shared folders from the server. * @param aGlobal true to fetch global folders. * @note The caller must lock this object for writing. /* protect mpVM (if not NULL) */ /// @todo grab & process global folders when they are done /* send changes to HGCM if the VM is running */ /// @todo report errors as runtime warnings through VMSetError /* a new machine folder is added or * the existing machine folder is changed */ ;
/* the console folder exists, nothing to do */ /* remove the old machhine folder (when changed) * or the global folder if any (when new) */ /* create the new machine folder */ /* forget the processed (or identical) folder */ /* process outdated (removed) folders */ /// @todo report errors as runtime warnings through VMSetError ;
/* the console folder exists, nothing to do */ /* remove the outdated machine folder */ /* create the global folder if there is any */ * Searches for a shared folder with the given name in the list of machine * shared folders and then in the list of the global shared folders. * @param aName Name of the folder to search for. * @param aIt Where to store the pointer to the found folder. * @return @c true if the folder was found and @c false otherwise. * @note The caller must lock this object for reading. /* first, search machine folders */ /* second, search machine folders */ * Calls the HGCM service to add a shared folder definition. * @param aName Shared folder name. * @param aHostPath Shared folder path. * @note Must be called from under AutoVMCaller and when mpVM != NULL! * @note Doesn't lock anything. tr (
"Could not create a shared folder '%ls' " "mapped to '%ls' (%Vrc)"),
* Calls the HGCM service to remove the shared folder definition. * @param aName Shared folder name. * @note Must be called from under AutoVMCaller and when mpVM != NULL! * @note Doesn't lock anything. Log ((
"Removing shared folder '%ls'\n",
aName));
tr (
"Could not remove the shared folder '%ls' (%Vrc)"),
* VM state callback function. Called by the VMM * using its state machine states. * Primarily used to handle VM initiated power off, suspend and state saving, * but also for doing termination completed work (VMSTATE_TERMINATE). * In general this function is called in the context of the EMT. * @param aVM The VM handle. * @param aState The new state. * @param aOldState The old state. * @param aUser The user argument (pointer to the Console object). * @note Locks the Console object for writing. LogFlowFunc ((
"Changing state from %d to %d (aVM=%p)\n",
* Note that we must let this method proceed even if Console::uninit() has * been already called. In such case this VMSTATE change is a result of: * 1) powerDown() called from uninit() itself, or * 2) VM-(guest-)initiated power off. * Do we still think that it is running? It may happen if this is LogFlowFunc ((
"VM has powered itself off but Console still " "thinks it is running. Notifying.\n"));
/* prevent powerDown() from calling VMR3PowerOff() again */ * Setup task object and thread to carry out the operation * asynchronously (if we call powerDown() right here but there * is one or more mpVM callers (added with addVMCaller()) we'll * If creating a task is falied, this can currently mean one * of two: either Console::uninit() has been called just a ms * before (so a powerDown() call is already on the way), or * powerDown() itself is being already executed. Just do LogFlowFunc ((
"Console is already being uninitialized.\n"));
/* task is now owned by powerDownThread(), so release it */ * The VM has been completely destroyed. * Note: This state change can happen at two points: * 1) At the end of VMR3Destroy() if it was not called from EMT. * 2) At the end of vmR3EmulationThread if VMR3Destroy() was * Terminate host interface networking. If aVM is NULL, we've been * manually called from powerUpThread() either before calling * VMR3Create() or after VMR3Create() failed, so no need to touch * From now on the machine is officially powered down or * remains in the Saved state. /* successfully powered down */ * successfully saved (note that the machine is already * in the Saved state on the server due to EndSavingState() * called from saveStateThread(), so only change the local * failed to start, but be patient: set back to PoweredOff * (for similarity with the below) * failed to load the saved state file, but be patient: * set back to Saved (to preserve the saved state file) /* Change the machine state from Running to Paused */ * Change the machine state from Starting, Restoring or Paused /* Guru respects only running VMs */ default:
/* shut up gcc */ * Sends a request to VMM to attach the given host device. * After this method succeeds, the attached device will appear in the * mUSBDevices collection. * @param aHostDevice device to attach * @note Synchronously calls EMT. * @note Must be called from under this object's lock. /* still want a lock object because we need to leave it */ * Get the address and the Uuid, and call the pfnCreateProxyDevice roothub * method in EMT (using usbAttachCallback()). /* leave the lock before a VMR3* call (EMT will call us back)! */ /** @todo just do everything here and only wrap the PDMR3Usb call. That'll offload some notification stuff from the EMT thread. */ tr (
"Failed to attach the USB device. (No available ports on the USB controller)."));
tr (
"Not permitted to open the USB device, check usbfs options"));
tr (
"Failed to create a proxy device for the USB device. (Error: %Vrc)"),
vrc);
* USB device attach callback used by AttachUSBDevice(). * Note that AttachUSBDevice() doesn't return until this callback is executed, * so we don't use AutoCaller and don't care about reference counters of * interface pointers passed in. * @note Locks the console object for writing. /* Create a OUSBDevice and add it to the device list */ * Sends a request to VMM to detach the given host device. After this method * succeeds, the detached device will disappear from the mUSBDevices * @param aIt Iterator pointing to the device to detach. * @note Synchronously calls EMT. * @note Must be called from under this object's lock. /* still want a lock object because we need to leave it */ /* if the device is attached, then there must at least one USB hub. */ /* leave the lock before a VMR3* call (EMT will call us back)! */ /** @todo just do everything here and only wrap the PDMR3Usb call. That'll offload some notification stuff from the EMT thread. */ * USB device detach callback used by DetachUSBDevice(). * Note that DetachUSBDevice() doesn't return until this callback is executed, * so we don't use AutoCaller and don't care about reference counters of * interface pointers passed in. * @note Locks the console object for writing. * If that was a remote device, release the backend pointer. * The pointer was requested in usbAttachCallback. /* Remove the device from the collection */ #
endif /* VBOX_WITH_USB */ * Call the initialisation script for a dynamic TAP interface. * The initialisation script should create a TAP interface, set it up and write its name to * standard output followed by a carriage return. Anything further written to standard * output will be ignored. If it returns a non-zero exit code, or does not write an * intelligable interface name to standard output, it will be treated as having failed. * For now, this method only works on Linux. * @returns COM status code * @param tapDevice string to store the name of the tap device created to * @param tapSetupApplication the name of the setup script /* Command line to start the script with. */ /* Get the script name. */ * Create the process and read its output. Log2((
"About to start the TAP setup script with the following command line: %s\n",
LogRel((
"Failed to start the TAP interface setup script %s, error text: %s\n",
return setError(
E_FAIL,
tr (
"Failed to run the host networking set up command %s: %s"),
/* If we are using a dynamic TAP interface, we need to get the interface name. */ /* Buffer to read the application output to. It doesn't have to be long, as we are only interested in the first few (normally 5 or 6) bytes. */ /* The length of the string returned by the application. We only accept strings of 63 /* Read the name of the device from the application. */ /* The script must return the name of the interface followed by a carriage return as the first line of its output. We need a null-terminated string. */ LogRel((
"The TAP interface setup script did not return the name of a TAP device.\n"));
return setError(
E_FAIL,
tr (
"The host networking set up command did not supply an interface name"));
/* Overwrite the terminating newline character. */ LogRel((
"The TAP interface setup script terminated abnormally.\n"));
return setError(
E_FAIL,
tr (
"The host networking set up command did not run correctly"));
LogRel((
"The TAP interface setup script returned a non-zero exit code.\n"));
return setError(
E_FAIL,
tr (
"The host networking set up command returned a non-zero exit code"));
#
else /* RT_OS_LINUX not defined */ * Helper function to handle host interface device creation and attachment. * @param networkAdapter the network adapter which attachment should be reset * @return COM status code * @note The caller must lock this object for writing. * Are we supposed to use an existing TAP interface? #
endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */ * Allocate a host interface device /* The name of the TAP interface we are using and the TAP setup script resp. */ /* If we are using a static TAP device then try to open it. */ LogRel((
"No setup application was supplied for the TAP interface.\n"));
rc =
setError(
E_FAIL,
tr (
"No setup application was supplied for the host networking interface"));
* Here is the right place to communicate the TAP file descriptor and * the host interface name to the server if/when it becomes really rc =
setError(
E_FAIL,
tr (
"could not set up the host networking device for non blocking access: %s"),
/* will be handled by our caller */ /** @todo Implement tap networking for Darwin. */ /** @todo Implement tap networking for FreeBSD. */ /** @todo Implement tap networking for OS/2. */ #
error "Unknown host OS" /* in case of failure, cleanup. */ LogRel((
"General failure attaching to host interface\n"));
* Helper function to handle detachment from a host interface * @param networkAdapter the network adapter which attachment should be reset * @return COM status code * @note The caller must lock this object for writing. /* is there an open TAP device? */ /* If the name is empty, this is a dynamic TAP device, so close it now, so that the termination script can remove the interface. Otherwise we still need the FD to pass to the termination script. */ * Execute the termination command. /* Get the program name. */ /* Build the command line. */ * Create the process and wait for it to complete. LogRel((
"Failed to execute the clean up script for the TAP interface"));
rc =
setError(
E_FAIL,
tr (
"Failed to execute the clean up script for the TAP interface"));
LogRel((
"The TAP interface clean up script terminated abnormally.\n"));
LogRel((
"The TAP interface clean up script returned a non-zero exit code.\n"));
rc =
setError(
E_FAIL,
tr (
"The TAP interface clean up script returned a non-zero exit code"));
/* If we are using a static TAP device, we close it now, after having called the /* the TAP device name and handle are no longer valid */ * Called at power down to terminate host interface networking. * @note The caller must lock this object for writing. * host interface termination handling * Process callback handler for VMR3Load and VMR3Save. * @param pVM The VM handle. * @param uPercent Completetion precentage (0-100). * @param pvUser Pointer to the VMProgressTask structure. /* update the progress object */ * VM error callback function. Called by the various VM components. * @param pVM VM handle. Can be NULL if an error occurred before * successfully creating a VM. * @param pvUser Pointer to the VMProgressTask structure. * @param rc VBox status code. * @param pszFormat Printf-like error message. * @param args Various number of argumens for the error message. * @thread EMT, VMPowerUp... * @note The VMProgressTask structure modified by this callback is not thread /* we ignore RT_SRC_POS_DECL arguments to avoid confusion of end-users */ "VBox status code: %d (%Vrc)"),
/* For now, this may be called only once. Ignore subsequent calls. */ (
"Cannot set error to '%s': it is already set to '%s'",
* VM runtime error callback function. * See VMSetRuntimeError for the detailed description of parameters. * @param pVM The VM handle. * @param pvUser The user argument. * @param fFatal Whether it is a fatal error or not. * @param pszErrorID Error ID string. * @param pszFormat Error message format string. * @param args Error message arguments. LogRel ((
"Console: VM runtime error: fatal=%RTbool, " "errorID=%s message=\"%s\"\n",
* Captures USB devices that match filters of the VM. * @param pVM The VM handle. * @note The caller must lock this object for writing. /* If the machine has an USB controller, ask the USB proxy service to /* leave the lock before calling Host in VBoxSVC since Host may call * us back from under its lock (e.g. onUSBDeviceAttach()) which would * produce an inter-process dead-lock otherwise. */ * Detach all USB device which are attached to the VM for the * purpose of clean up and such like. * @note The caller must lock this object for writing. /* leave the lock before calling Host in VBoxSVC since Host may call * us back from under its lock (e.g. onUSBDeviceAttach()) which would * produce an inter-process dead-lock otherwise. */ * @note Locks this object for writing. /* Console has been already uninitialized, deny request */ "please report to dmik\n"));
* Mark all existing remote USB devices as dirty. * Process the pDevList and add devices those are not already in the mRemoteUSBDevices list. /** @todo (sunlover) REMOTE_USB Strict validation of the pDevList. */ /* The cbDevList condition must be checked first, because the function can * receive pDevList = NULL and cbDevList = 0 on client disconnect. /* The device is already in the list. */ LogRel((
"Remote USB: ++++ Vendor %04X. Product %04X. Name = [%s].\n",
/* Create the device object and add the new device to list. */ /* Check if the device is ok for current USB filters. */ /// @todo (r=dmik) warning reporting subsystem * Remove dirty devices, that is those which are not reported by the server anymore. LogRel((
"Remote USB: ---- Vendor %04X. Product %04X. Name = [%ls].\n",
/* Detach the device from VM. */ /* And remove it from the list. */ * Thread function which starts the VM (also from saved state) and * @param Thread The thread id. * @param pvUser Pointer to a VMPowerUpTask structure. * @return VINF_SUCCESS (ignored). * @note Locks the Console object for writing. /* Set up a build identifier so that it can be seen from core dumps what * exact build was used to produce the core. */ /* Note: no need to use addCaller() because VMPowerUpTask does that */ /* Create the VRDP server. In case of headless operation, this will * also create the framebuffer, required at VM creation. // does VRDP server call Console from the other thread? // Not sure, so leave the lock just in case LogRel ((
"Failed to launch VRDP server (%Vrc), error message: '%s'\n",
* leave the lock since EMT will call Console. It's safe because * mMachineState is either Starting or Restoring state here. /* Enable client connections to the server. */ * Register our load/save state file handlers * Synchronize debugger settings // does the code below call Console from the other thread? // Not sure, so leave the lock just in case /* enter the lock again */ /* leave the lock before a lengthy operation */ /* Power off in case we failed loading or resuming the VM */ /* Power on the VM (i.e. start executing) */ /* enter the lock again */ /* On failure, destroy the VM */ /* preserve existing error info */ /* powerDown() will call VMR3Destroy() and do all necessary * cleanup (VRDP, USB devices) */ * If VMR3Create() failed it has released the VM memory. /* If VMR3Create() or one of the other calls in this function fail, * an appropriate error message has been set in task->mErrorMsg. * However since that happens via a callback, the hrc status code in * this function is not updated. /* If the error message is not set but we've got a failure, * convert the VBox status code into a meaningfulerror message. * This becomes unused once all the sources of errors set the * appropriate error message themselves. "status code %Vrc\n",
vrc));
tr (
"Failed to start VM execution (%Vrc)"),
vrc);
/* Set the error message as the COM error. * Progress::notifyComplete() will pick it up later. */ * 1) we failed before VMR3Create() was called; * 2) VMR3Create() failed. * In both cases, there is no need to call powerDown(), but we still * vmstateChangeCallback() for that purpose. /* preserve existing error info */ * Evaluate the final result. Note that the appropriate mMachineState value * is already set by vmstateChangeCallback() in all cases. /* leave the lock, don't need it any more */ /* Notify the progress object of the success */ /* The progress object will fetch the current error info */ LogRel ((
"Power up failed (vrc=%Vrc, hrc=%Rhrc (%#08X))\n",
vrc,
hrc,
hrc));
* @param pVM The VM handle. * @param hda The harddisk attachment. * @param phrc Where to store com error - only valid if we return VERR_GENERAL_FAILURE. * @return VBox status code. * Figure out which IDE device this is. * Is there an existing LUN? If not create it. * We ASSUME that this will NEVER collide with the DVD. * Check if things has changed. /// @todo (dmik) we temporarily use the location property to // determine the image file name. This is subject to change // when iSCSI disks are here (we should either query a // storage-specific interface from IHardDisk, or "standardize" // the location property) /// @todo (dmik) we temporarily use the location property to // determine the image file name. This is subject to change // when iSCSI disks are here (we should either query a // storage-specific interface from IHardDisk, or "standardize" // the location property) * Detach the driver and replace the config node. * Create the driver configuration. /// @todo (dmik) we temporarily use the location property to // determine the image file name. This is subject to change // when iSCSI disks are here (we should either query a // storage-specific interface from IHardDisk, or "standardize" // the location property) /* Create an inversed tree of parents. */ /// @todo (dmik) we temporarily use the location property to // determine the image file name. This is subject to change // when iSCSI disks are here (we should either query a // storage-specific interface from IHardDisk, or "standardize" // the location property) * Thread for executing the saved state operation. * @param Thread The thread handle. * @param pvUser Pointer to a VMSaveTask structure. * @return VINF_SUCCESS (ignored). * @note Locks the Console object for writing. * Note: no need to use addCaller() to protect Console or addVMCaller() to * protect mpVM because VMSaveTask does that LogFlowFunc ((
"Waiting until the server creates differencing VDIs...\n"));
Console::
tr (
"Failed to save the machine state to '%s' (%Vrc)"),
/* lock the console sonce we're going to access it */ LogFlowFunc ((
"Reattaching new differencing VDIs...\n"));
* don't leave the lock since reconfigureVDI isn't going to /* finalize the procedure regardless of the result */ * finalize the requested snapshot object. * This will reset the machine state to the state it had right * before calling mControl->BeginTakingSnapshot(). * finalize the requested save state procedure. * In case of success, the server will set the machine state to Saved; * in case of failure it will reset the it to the state it had right * before calling mControl->BeginSavingState(). /* synchronize the state with the server */ /* restore the paused state if appropriate */ /* restore the running state if appropriate */ * The machine has been successfully saved, so power it down * (vmstateChangeCallback() will set state to Saved on success). * Note: we release the task's VM caller, otherwise it will /* notify the progress object about operation completion */ * Thread for powering down the Console. * @param Thread The thread handle. * @param pvUser Pointer to the VMTask structure. * @return VINF_SUCCESS (ignored). * @note Locks the Console object for writing. * Note: no need to use addCaller() to protect Console * because VMTask does that /* release VM caller to let powerDown() proceed */ * The Main status driver instance data. /** The LED connectors. */ /** Pointer to the LED ports interface above us. */ /** Pointer to the array of LED pointers. */ /** The unit number corresponding to the first entry in the LED array. */ /** The unit number corresponding to the last entry in the LED array. * (The size of the LED array is iLastLUN - iFirstLUN + 1.) */ * Notification about a unit which have been changed. * The driver must discard any pointers to data owned by * the unit and requery it. * @param pInterface Pointer to the interface structure containing the called function pointer. * @param iLUN The unit number. Log((
"drvStatus_UnitChanged: iLUN=%d pLed=%p\n",
iLUN,
pLed));
* Queries an interface to the driver. * @returns Pointer to interface. * @returns NULL if the interface was not supported by the driver. * @param pInterface Pointer to this interface structure. * @param enmInterface The requested interface identification. * Destruct a status driver instance. * @param pDrvIns The driver instance data. * Construct a status driver instance. * @param pDrvIns The driver instance data. * If the registration structure is needed, pDrvIns->pDrvReg points to it. * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like * iInstance it's expected to be used a bit in this function. * Validate configuration. AssertMsgFailed((
"Configuration error: Not possible to attach anything to this driver!\n"));
AssertMsgFailed((
"Configuration error: Failed to query the \"papLeds\" value! rc=%Vrc\n",
rc));
AssertMsgFailed((
"Configuration error: Failed to query the \"First\" value! rc=%Vrc\n",
rc));
AssertMsgFailed((
"Configuration error: Failed to query the \"Last\" value! rc=%Vrc\n",
rc));
* Get the ILedPorts interface of the above driver/device and * query the LEDs we want. * Keyboard driver registration record. "Main status driver (Main as in the API).",