VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/UnattendedImpl.cpp@ 68240

Last change on this file since 68240 was 68240, checked in by vboxsync, 8 years ago

Unattended: Added detectedOSLanguages and language attributes to deal with the windows installer's stupid UILanguage requirement. The specified language must be supported by the installation media, probably by way of lang.ini, which means we need to implement UDF support to really get this right. For now, looking for language specifier in the ISO name (ASSUMES filename unchanged since MSDN download). [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.7 KB
Line 
1/* $Id: UnattendedImpl.cpp 68240 2017-08-02 12:42:18Z vboxsync $ */
2/** @file
3 * Unattended class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*********************************************************************************************************************************
19* Header Files *
20*********************************************************************************************************************************/
21#define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
22#include "LoggingNew.h"
23#include "VirtualBoxBase.h"
24#include "UnattendedImpl.h"
25#include "UnattendedInstaller.h"
26#include "UnattendedScript.h"
27#include "VirtualBoxImpl.h"
28#include "SystemPropertiesImpl.h"
29#include "MachineImpl.h"
30#include "Global.h"
31
32#include <VBox/err.h>
33#include <iprt/ctype.h>
34#include <iprt/file.h>
35#include <iprt/locale.h>
36#include <iprt/path.h>
37
38using namespace std;
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Controller slot for a DVD drive.
46 *
47 * The slot can be free and needing a drive to be attached along with the ISO
48 * image, or it may already be there and only need mounting the ISO. The
49 * ControllerSlot::fFree member indicates which it is.
50 */
51struct ControllerSlot
52{
53 StorageBus_T enmBus;
54 Utf8Str strControllerName;
55 ULONG uPort;
56 ULONG uDevice;
57 bool fFree;
58
59 ControllerSlot(StorageBus_T a_enmBus, const Utf8Str &a_rName, ULONG a_uPort, ULONG a_uDevice, bool a_fFree)
60 : enmBus(a_enmBus), strControllerName(a_rName), uPort(a_uPort), uDevice(a_uDevice), fFree(a_fFree)
61 {}
62
63 bool operator<(const ControllerSlot &rThat) const
64 {
65 if (enmBus == rThat.enmBus)
66 {
67 if (strControllerName == rThat.strControllerName)
68 {
69 if (uPort == rThat.uPort)
70 return uDevice < rThat.uDevice;
71 return uPort < rThat.uPort;
72 }
73 return strControllerName < rThat.strControllerName;
74 }
75
76 /*
77 * Bus comparsion in boot priority order.
78 */
79 /* IDE first. */
80 if (enmBus == StorageBus_IDE)
81 return true;
82 if (rThat.enmBus == StorageBus_IDE)
83 return false;
84 /* SATA next */
85 if (enmBus == StorageBus_SATA)
86 return true;
87 if (rThat.enmBus == StorageBus_SATA)
88 return false;
89 /* SCSI next */
90 if (enmBus == StorageBus_SCSI)
91 return true;
92 if (rThat.enmBus == StorageBus_SCSI)
93 return false;
94 /* numerical */
95 return (int)enmBus < (int)rThat.enmBus;
96 }
97
98 bool operator==(const ControllerSlot &rThat) const
99 {
100 return enmBus == rThat.enmBus
101 && strControllerName == rThat.strControllerName
102 && uPort == rThat.uPort
103 && uDevice == rThat.uDevice;
104 }
105};
106
107/**
108 * Installation disk.
109 *
110 * Used when reconfiguring the VM.
111 */
112typedef struct UnattendedInstallationDisk
113{
114 StorageBus_T enmBusType; /**< @todo nobody is using this... */
115 Utf8Str strControllerName;
116 DeviceType_T enmDeviceType;
117 AccessMode_T enmAccessType;
118 ULONG uPort;
119 ULONG uDevice;
120 bool fMountOnly;
121 Utf8Str strImagePath;
122
123 UnattendedInstallationDisk(StorageBus_T a_enmBusType, Utf8Str const &a_rBusName, DeviceType_T a_enmDeviceType,
124 AccessMode_T a_enmAccessType, ULONG a_uPort, ULONG a_uDevice, bool a_fMountOnly,
125 Utf8Str const &a_rImagePath)
126 : enmBusType(a_enmBusType), strControllerName(a_rBusName), enmDeviceType(a_enmDeviceType), enmAccessType(a_enmAccessType)
127 , uPort(a_uPort), uDevice(a_uDevice), fMountOnly(a_fMountOnly), strImagePath(a_rImagePath)
128 {
129 Assert(strControllerName.length() > 0);
130 }
131
132 UnattendedInstallationDisk(std::list<ControllerSlot>::const_iterator const &itDvdSlot, Utf8Str const &a_rImagePath)
133 : enmBusType(itDvdSlot->enmBus), strControllerName(itDvdSlot->strControllerName), enmDeviceType(DeviceType_DVD)
134 , enmAccessType(AccessMode_ReadOnly), uPort(itDvdSlot->uPort), uDevice(itDvdSlot->uDevice)
135 , fMountOnly(!itDvdSlot->fFree), strImagePath(a_rImagePath)
136 {
137 Assert(strControllerName.length() > 0);
138 }
139} UnattendedInstallationDisk;
140
141
142//////////////////////////////////////////////////////////////////////////////////////////////////////
143/*
144*
145*
146* Implementation Unattended functions
147*
148*/
149//////////////////////////////////////////////////////////////////////////////////////////////////////
150
151Unattended::Unattended()
152 : mhThreadReconfigureVM(NIL_RTNATIVETHREAD), mfRtcUseUtc(false), mfGuestOs64Bit(false)
153 , mpInstaller(NULL), mpTimeZoneInfo(NULL), mfIsDefaultAuxiliaryBasePath(true), mfDoneDetectIsoOS(false)
154{ }
155
156Unattended::~Unattended()
157{
158 if (mpInstaller)
159 {
160 delete mpInstaller;
161 mpInstaller = NULL;
162 }
163}
164
165HRESULT Unattended::FinalConstruct()
166{
167 return BaseFinalConstruct();
168}
169
170void Unattended::FinalRelease()
171{
172 uninit();
173
174 BaseFinalRelease();
175}
176
177void Unattended::uninit()
178{
179 /* Enclose the state transition Ready->InUninit->NotReady */
180 AutoUninitSpan autoUninitSpan(this);
181 if (autoUninitSpan.uninitDone())
182 return;
183
184 unconst(mParent) = NULL;
185 mMachine.setNull();
186}
187
188/**
189 * Initializes the unattended object.
190 *
191 * @param aParent Pointer to the parent object.
192 */
193HRESULT Unattended::initUnattended(VirtualBox *aParent)
194{
195 LogFlowThisFunc(("aParent=%p\n", aParent));
196 ComAssertRet(aParent, E_INVALIDARG);
197
198 /* Enclose the state transition NotReady->InInit->Ready */
199 AutoInitSpan autoInitSpan(this);
200 AssertReturn(autoInitSpan.isOk(), E_FAIL);
201
202 unconst(mParent) = aParent;
203
204 /*
205 * Fill public attributes (IUnattended) with useful defaults.
206 */
207 try
208 {
209 mStrUser = "vboxuser";
210 mStrPassword = "changeme";
211 mfInstallGuestAdditions = false;
212 mfInstallTestExecService = false;
213 midxImage = 1;
214
215 HRESULT hrc = mParent->i_getSystemProperties()->i_getDefaultAdditionsISO(mStrAdditionsIsoPath);
216 ComAssertComRCRet(hrc, hrc);
217 }
218 catch (std::bad_alloc)
219 {
220 return E_OUTOFMEMORY;
221 }
222
223 /*
224 * Confirm a successful initialization
225 */
226 autoInitSpan.setSucceeded();
227
228 return S_OK;
229}
230
231HRESULT Unattended::detectIsoOS()
232{
233 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
234
235 /*
236 * Just fake up some windows installation media locale (for <UILanguage>).
237 * Note! The translation here isn't perfect. Feel free to send us a patch.
238 */
239 /** @todo Looks like we can get this from sources/lang.ini as well as
240 * sources/??-* and boot/??-*. Will require UDF reader. */
241 char szTmp[16];
242 const char *pszFilename = RTPathFilename(mStrIsoPath.c_str());
243 if ( pszFilename
244 && RT_C_IS_ALPHA(pszFilename[0])
245 && RT_C_IS_ALPHA(pszFilename[1])
246 && (pszFilename[2] == '-' || pszFilename[2] == '_') )
247 {
248 szTmp[0] = (char)RT_C_TO_LOWER(pszFilename[0]);
249 szTmp[1] = (char)RT_C_TO_LOWER(pszFilename[1]);
250 szTmp[2] = '-';
251 if (szTmp[0] == 'e' && szTmp[1] == 'n')
252 strcpy(&szTmp[3], "US");
253 else if (szTmp[0] == 'a' && szTmp[1] == 'r')
254 strcpy(&szTmp[3], "SA");
255 else if (szTmp[0] == 'd' && szTmp[1] == 'a')
256 strcpy(&szTmp[3], "DK");
257 else if (szTmp[0] == 'e' && szTmp[1] == 't')
258 strcpy(&szTmp[3], "EE");
259 else if (szTmp[0] == 'e' && szTmp[1] == 'l')
260 strcpy(&szTmp[3], "GR");
261 else if (szTmp[0] == 'h' && szTmp[1] == 'e')
262 strcpy(&szTmp[3], "IL");
263 else if (szTmp[0] == 'j' && szTmp[1] == 'a')
264 strcpy(&szTmp[3], "JP");
265 else if (szTmp[0] == 's' && szTmp[1] == 'v')
266 strcpy(&szTmp[3], "SE");
267 else if (szTmp[0] == 'u' && szTmp[1] == 'k')
268 strcpy(&szTmp[3], "UA");
269 else if (szTmp[0] == 'c' && szTmp[1] == 's')
270 strcpy(szTmp, "cs-CZ");
271 else if (szTmp[0] == 'n' && szTmp[1] == 'o')
272 strcpy(szTmp, "nb-NO");
273 else if (szTmp[0] == 'p' && szTmp[1] == 'p')
274 strcpy(szTmp, "pt-PT");
275 else if (szTmp[0] == 'p' && szTmp[1] == 't')
276 strcpy(szTmp, "pt-BR");
277 else if (szTmp[0] == 'c' && szTmp[1] == 'n')
278 strcpy(szTmp, "zh-CN");
279 else if (szTmp[0] == 'h' && szTmp[1] == 'k')
280 strcpy(szTmp, "zh-HK");
281 else if (szTmp[0] == 't' && szTmp[1] == 'w')
282 strcpy(szTmp, "zh-TW");
283 else if (szTmp[0] == 's' && szTmp[1] == 'r')
284 strcpy(szTmp, "sr-Latn-CS"); /* hmm */
285 else
286 {
287 szTmp[3] = (char)RT_C_TO_UPPER(pszFilename[0]);
288 szTmp[4] = (char)RT_C_TO_UPPER(pszFilename[1]);
289 szTmp[5] = '\0';
290 }
291 }
292 else
293 strcpy(szTmp, "en-US");
294 try
295 {
296 mDetectedOSLanguages.clear();
297 mDetectedOSLanguages.append(szTmp);
298 }
299 catch (std::bad_alloc)
300 {
301 return E_OUTOFMEMORY;
302 }
303
304 /** @todo implement actual detection logic. */
305 return E_NOTIMPL;
306}
307
308HRESULT Unattended::prepare()
309{
310 LogFlow(("Unattended::prepare: enter\n"));
311
312 /*
313 * Must have a machine.
314 */
315 ComPtr<Machine> ptrMachine;
316 Guid MachineUuid;
317 {
318 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
319 ptrMachine = mMachine;
320 if (ptrMachine.isNull())
321 return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("No machine associated with this IUnatteded instance"));
322 MachineUuid = mMachineUuid;
323 }
324
325 /*
326 * Before we write lock ourselves, we must get stuff from Machine and
327 * VirtualBox because their locks have higher priorities than ours.
328 */
329 Utf8Str strGuestOsTypeId;
330 Utf8Str strMachineName;
331 Utf8Str strDefaultAuxBasePath;
332 HRESULT hrc;
333 try
334 {
335 Bstr bstrTmp;
336 hrc = ptrMachine->COMGETTER(OSTypeId)(bstrTmp.asOutParam());
337 if (SUCCEEDED(hrc))
338 {
339 strGuestOsTypeId = bstrTmp;
340 hrc = ptrMachine->COMGETTER(Name)(bstrTmp.asOutParam());
341 if (SUCCEEDED(hrc))
342 strMachineName = bstrTmp;
343 }
344 int vrc = ptrMachine->i_calculateFullPath(Utf8StrFmt("Unattended-%RTuuid-", MachineUuid.raw()), strDefaultAuxBasePath);
345 if (RT_FAILURE(vrc))
346 return setErrorBoth(E_FAIL, vrc);
347 }
348 catch (std::bad_alloc)
349 {
350 return E_OUTOFMEMORY;
351 }
352 bool const fIs64Bit = i_isGuestOSArchX64(strGuestOsTypeId);
353
354 BOOL fRtcUseUtc = FALSE;
355 hrc = ptrMachine->COMGETTER(RTCUseUTC)(&fRtcUseUtc);
356 if (FAILED(hrc))
357 return hrc;
358
359 /*
360 * Write lock this object and set attributes we got from IMachine.
361 */
362 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
363
364 mStrGuestOsTypeId = strGuestOsTypeId;
365 mfGuestOs64Bit = fIs64Bit;
366 mfRtcUseUtc = RT_BOOL(fRtcUseUtc);
367
368 /*
369 * Do some state checks.
370 */
371 if (mpInstaller != NULL)
372 return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("The prepare method has been called (must call done to restart)"));
373 if ((Machine *)ptrMachine != (Machine *)mMachine)
374 return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("The 'machine' while we were using it - please don't do that"));
375
376 /*
377 * Check if the specified ISOs and files exist.
378 */
379 if (!RTFileExists(mStrIsoPath.c_str()))
380 return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate the installation ISO file '%s'"),
381 mStrIsoPath.c_str());
382 if (mfInstallGuestAdditions && !RTFileExists(mStrAdditionsIsoPath.c_str()))
383 return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate the guest additions ISO file '%s'"),
384 mStrAdditionsIsoPath.c_str());
385 if (mfInstallTestExecService && !RTFileExists(mStrValidationKitIsoPath.c_str()))
386 return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate the validation kit ISO file '%s'"),
387 mStrValidationKitIsoPath.c_str());
388 if (mStrScriptTemplatePath.isNotEmpty() && !RTFileExists(mStrScriptTemplatePath.c_str()))
389 return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate unattended installation script template '%s'"),
390 mStrScriptTemplatePath.c_str());
391
392 /*
393 * Do media detection if it haven't been done yet.
394 */
395 if (!mfDoneDetectIsoOS)
396 {
397 hrc = detectIsoOS();
398 if (FAILED(hrc) && hrc != E_NOTIMPL)
399 return hrc;
400 }
401
402 /*
403 * Do some default property stuff and check other properties.
404 */
405 try
406 {
407 char szTmp[128];
408
409 if (mStrLocale.isEmpty())
410 {
411 int vrc = RTLocaleQueryNormalizedBaseLocaleName(szTmp, sizeof(szTmp));
412 if ( RT_SUCCESS(vrc)
413 && RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(szTmp))
414 mStrLocale.assign(szTmp, 5);
415 else
416 mStrLocale = "en_US";
417 Assert(RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(mStrLocale));
418 }
419
420 if (mStrLanguage.isEmpty())
421 {
422 if (mDetectedOSLanguages.size() > 0)
423 mStrLanguage = mDetectedOSLanguages[0];
424 else
425 mStrLanguage.assign(mStrLocale).findReplace('_', '-');
426 }
427
428 if (mStrCountry.isEmpty())
429 {
430 int vrc = RTLocaleQueryUserCountryCode(szTmp);
431 if (RT_SUCCESS(vrc))
432 mStrCountry = szTmp;
433 else if ( mStrLocale.isNotEmpty()
434 && RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(mStrLocale))
435 mStrCountry.assign(mStrLocale, 3, 2);
436 else
437 mStrCountry = "US";
438 }
439
440 if (mStrTimeZone.isEmpty())
441 {
442 int vrc = RTTimeZoneGetCurrent(szTmp, sizeof(szTmp));
443 if (RT_SUCCESS(vrc))
444 mStrTimeZone = szTmp;
445 else
446 mStrTimeZone = "Etc/UTC";
447 Assert(mStrTimeZone.isNotEmpty());
448 }
449 mpTimeZoneInfo = RTTimeZoneGetInfoByUnixName(mStrTimeZone.c_str());
450 if (!mpTimeZoneInfo)
451 mpTimeZoneInfo = RTTimeZoneGetInfoByWindowsName(mStrTimeZone.c_str());
452 Assert(mpTimeZoneInfo || mStrTimeZone != "Etc/UTC");
453 if (!mpTimeZoneInfo)
454 LogRel(("Unattended::prepare: warning: Unknown time zone '%s'\n", mStrTimeZone.c_str()));
455
456 if (mStrHostname.isEmpty())
457 {
458 /* Mangle the VM name into a valid hostname. */
459 for (size_t i = 0; i < strMachineName.length(); i++)
460 {
461 char ch = strMachineName[i];
462 if ( (unsigned)ch < 127
463 && RT_C_IS_ALNUM(ch))
464 mStrHostname.append(ch);
465 else if (mStrHostname.isNotEmpty() && RT_C_IS_PUNCT(ch) && !mStrHostname.endsWith("-"))
466 mStrHostname.append('-');
467 }
468 if (mStrHostname.length() == 0)
469 mStrHostname.printf("%RTuuid-vm", MachineUuid.raw());
470 else if (mStrHostname.length() < 3)
471 mStrHostname.append("-vm");
472 mStrHostname.append(".myguest.virtualbox.org");
473 }
474
475 if (mStrAuxiliaryBasePath.isEmpty())
476 {
477 mStrAuxiliaryBasePath = strDefaultAuxBasePath;
478 mfIsDefaultAuxiliaryBasePath = true;
479 }
480 }
481 catch (std::bad_alloc)
482 {
483 return E_OUTOFMEMORY;
484 }
485
486 /*
487 * Get the guest OS type info and instantiate the appropriate installer.
488 */
489 uint32_t const idxOSType = Global::getOSTypeIndexFromId(mStrGuestOsTypeId.c_str());
490 meGuestOsType = idxOSType < Global::cOSTypes ? Global::sOSTypes[idxOSType].osType : VBOXOSTYPE_Unknown;
491
492 mpInstaller = UnattendedInstaller::createInstance(meGuestOsType, mStrGuestOsTypeId, this);
493 if (mpInstaller != NULL)
494 {
495 hrc = mpInstaller->initInstaller();
496 if (SUCCEEDED(hrc))
497 {
498 /*
499 * Do the script preps (just reads them).
500 */
501 hrc = mpInstaller->prepareUnattendedScripts();
502 if (SUCCEEDED(hrc))
503 {
504 LogFlow(("Unattended::prepare: returns S_OK\n"));
505 return S_OK;
506 }
507 }
508
509 /* Destroy the installer instance. */
510 delete mpInstaller;
511 mpInstaller = NULL;
512 }
513 else
514 hrc = setErrorBoth(E_FAIL, VERR_NOT_FOUND,
515 tr("Unattended installation is not supported for guest type '%s'"), mStrGuestOsTypeId.c_str());
516 LogRelFlow(("Unattended::prepare: failed with %Rhrc\n", hrc));
517 return hrc;
518}
519
520HRESULT Unattended::constructMedia()
521{
522 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
523
524 LogFlow(("===========================================================\n"));
525 LogFlow(("Call Unattended::constructMedia()\n"));
526
527 if (mpInstaller == NULL)
528 return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "prepare() not yet called");
529
530 return mpInstaller->prepareMedia();
531}
532
533HRESULT Unattended::reconfigureVM()
534{
535 LogFlow(("===========================================================\n"));
536 LogFlow(("Call Unattended::reconfigureVM()\n"));
537
538 /*
539 * Interrogate VirtualBox/IGuestOSType before we lock stuff and create ordering issues.
540 */
541 StorageBus_T enmRecommendedStorageBus = StorageBus_IDE;
542 {
543 Bstr bstrGuestOsTypeId;
544 {
545 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
546 bstrGuestOsTypeId = mStrGuestOsTypeId;
547 }
548 ComPtr<IGuestOSType> ptrGuestOSType;
549 HRESULT hrc = mParent->GetGuestOSType(bstrGuestOsTypeId.raw(), ptrGuestOSType.asOutParam());
550 if (SUCCEEDED(hrc))
551 hrc = ptrGuestOSType->COMGETTER(RecommendedDVDStorageBus)(&enmRecommendedStorageBus);
552 if (FAILED(hrc))
553 return hrc;
554 }
555
556 /*
557 * Take write lock (for lock order reasons, write lock our parent object too)
558 * then make sure we're the only caller of this method.
559 */
560 AutoMultiWriteLock2 alock(mMachine, this COMMA_LOCKVAL_SRC_POS);
561 HRESULT hrc;
562 if (mhThreadReconfigureVM == NIL_RTNATIVETHREAD)
563 {
564 RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf();
565 mhThreadReconfigureVM = hNativeSelf;
566
567 /*
568 * Create a new session, lock the machine and get the session machine object.
569 * Do the locking without pinning down the write locks, just to be on the safe side.
570 */
571 ComPtr<ISession> ptrSession;
572 try
573 {
574 hrc = ptrSession.createInprocObject(CLSID_Session);
575 }
576 catch (std::bad_alloc)
577 {
578 hrc = E_OUTOFMEMORY;
579 }
580 if (SUCCEEDED(hrc))
581 {
582 alock.release();
583 hrc = mMachine->LockMachine(ptrSession, LockType_Shared);
584 alock.acquire();
585 if (SUCCEEDED(hrc))
586 {
587 ComPtr<IMachine> ptrSessionMachine;
588 hrc = ptrSession->COMGETTER(Machine)(ptrSessionMachine.asOutParam());
589 if (SUCCEEDED(hrc))
590 {
591 /*
592 * Hand the session to the inner work and let it do it job.
593 */
594 try
595 {
596 hrc = i_innerReconfigureVM(alock, enmRecommendedStorageBus, ptrSessionMachine);
597 }
598 catch (...)
599 {
600 hrc = E_UNEXPECTED;
601 }
602 }
603
604 /* Paranoia: release early in case we it a bump below. */
605 Assert(mhThreadReconfigureVM == hNativeSelf);
606 mhThreadReconfigureVM = NIL_RTNATIVETHREAD;
607
608 /*
609 * While unlocking the machine we'll have to drop the locks again.
610 */
611 alock.release();
612
613 ptrSessionMachine.setNull();
614 HRESULT hrc2 = ptrSession->UnlockMachine();
615 AssertLogRelMsg(SUCCEEDED(hrc2), ("UnlockMachine -> %Rhrc\n", hrc2));
616
617 ptrSession.setNull();
618
619 alock.acquire();
620 }
621 else
622 mhThreadReconfigureVM = NIL_RTNATIVETHREAD;
623 }
624 else
625 mhThreadReconfigureVM = NIL_RTNATIVETHREAD;
626 }
627 else
628 hrc = setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("reconfigureVM running on other thread"));
629 return hrc;
630}
631
632
633HRESULT Unattended::i_innerReconfigureVM(AutoMultiWriteLock2 &rAutoLock, StorageBus_T enmRecommendedStorageBus,
634 ComPtr<IMachine> const &rPtrSessionMachine)
635{
636 if (mpInstaller == NULL)
637 return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "prepare() not yet called");
638
639 // Fetch all available storage controllers
640 com::SafeIfaceArray<IStorageController> arrayOfControllers;
641 HRESULT hrc = rPtrSessionMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(arrayOfControllers));
642 AssertComRCReturn(hrc, hrc);
643
644 /*
645 * Figure out where the images are to be mounted, adding controllers/ports as needed.
646 */
647 std::vector<UnattendedInstallationDisk> vecInstallationDisks;
648 if (mpInstaller->isAuxiliaryFloppyNeeded())
649 {
650 hrc = i_reconfigureFloppy(arrayOfControllers, vecInstallationDisks, rPtrSessionMachine, rAutoLock);
651 if (FAILED(hrc))
652 return hrc;
653 }
654
655 hrc = i_reconfigureIsos(arrayOfControllers, vecInstallationDisks, rPtrSessionMachine, rAutoLock, enmRecommendedStorageBus);
656 if (FAILED(hrc))
657 return hrc;
658
659 /*
660 * Mount the images.
661 */
662 for (size_t idxImage = 0; idxImage < vecInstallationDisks.size(); idxImage++)
663 {
664 UnattendedInstallationDisk const *pImage = &vecInstallationDisks.at(idxImage);
665 Assert(pImage->strImagePath.isNotEmpty());
666 hrc = i_attachImage(pImage, rPtrSessionMachine, rAutoLock);
667 if (FAILED(hrc))
668 return hrc;
669 }
670
671 /*
672 * Set the boot order.
673 *
674 * ASSUME that the HD isn't bootable when we start out, but it will be what
675 * we boot from after the first stage of the installation is done. Setting
676 * it first prevents endless reboot cylces.
677 */
678 /** @todo consider making 100% sure the disk isn't bootable (edit partition
679 * table active bits and EFI stuff). */
680 Assert( mpInstaller->getBootableDeviceType() == DeviceType_DVD
681 || mpInstaller->getBootableDeviceType() == DeviceType_Floppy);
682 hrc = rPtrSessionMachine->SetBootOrder(1, DeviceType_HardDisk);
683 if (SUCCEEDED(hrc))
684 hrc = rPtrSessionMachine->SetBootOrder(2, mpInstaller->getBootableDeviceType());
685 if (SUCCEEDED(hrc))
686 hrc = rPtrSessionMachine->SetBootOrder(3, mpInstaller->getBootableDeviceType() == DeviceType_DVD
687 ? (DeviceType_T)DeviceType_Floppy : (DeviceType_T)DeviceType_DVD);
688 if (FAILED(hrc))
689 return hrc;
690
691 /*
692 * Essential step.
693 *
694 * HACK ALERT! We have to release the lock here or we'll get into trouble with
695 * the VirtualBox lock (via i_saveHardware/NetworkAdaptger::i_hasDefaults/VirtualBox::i_findGuestOSType).
696 */
697 if (SUCCEEDED(hrc))
698 {
699 rAutoLock.release();
700 hrc = rPtrSessionMachine->SaveSettings();
701 rAutoLock.acquire();
702 }
703
704 return hrc;
705}
706
707/**
708 * Makes sure we've got a floppy drive attached to a floppy controller, adding
709 * the auxiliary floppy image to the installation disk vector.
710 *
711 * @returns COM status code.
712 * @param rControllers The existing controllers.
713 * @param rVecInstallatationDisks The list of image to mount.
714 * @param rPtrSessionMachine The session machine smart pointer.
715 * @param rAutoLock The lock.
716 */
717HRESULT Unattended::i_reconfigureFloppy(com::SafeIfaceArray<IStorageController> &rControllers,
718 std::vector<UnattendedInstallationDisk> &rVecInstallatationDisks,
719 ComPtr<IMachine> const &rPtrSessionMachine,
720 AutoMultiWriteLock2 &rAutoLock)
721{
722 Assert(mpInstaller->isAuxiliaryFloppyNeeded());
723
724 /*
725 * Look for a floppy controller with a primary drive (A:) we can "insert"
726 * the auxiliary floppy image. Add a controller and/or a drive if necessary.
727 */
728 bool fFoundPort0Dev0 = false;
729 Bstr bstrControllerName;
730 Utf8Str strControllerName;
731
732 for (size_t i = 0; i < rControllers.size(); ++i)
733 {
734 StorageBus_T enmStorageBus;
735 HRESULT hrc = rControllers[i]->COMGETTER(Bus)(&enmStorageBus);
736 AssertComRCReturn(hrc, hrc);
737 if (enmStorageBus == StorageBus_Floppy)
738 {
739
740 /*
741 * Found a floppy controller.
742 */
743 hrc = rControllers[i]->COMGETTER(Name)(bstrControllerName.asOutParam());
744 AssertComRCReturn(hrc, hrc);
745
746 /*
747 * Check the attchments to see if we've got a device 0 attached on port 0.
748 *
749 * While we're at it we eject flppies from all floppy drives we encounter,
750 * we don't want any confusion at boot or during installation.
751 */
752 com::SafeIfaceArray<IMediumAttachment> arrayOfMediumAttachments;
753 hrc = rPtrSessionMachine->GetMediumAttachmentsOfController(bstrControllerName.raw(),
754 ComSafeArrayAsOutParam(arrayOfMediumAttachments));
755 AssertComRCReturn(hrc, hrc);
756 strControllerName = bstrControllerName;
757 AssertLogRelReturn(strControllerName.isNotEmpty(), setErrorBoth(E_UNEXPECTED, VERR_INTERNAL_ERROR_2));
758
759 for (size_t j = 0; j < arrayOfMediumAttachments.size(); j++)
760 {
761 LONG iPort = -1;
762 hrc = arrayOfMediumAttachments[j]->COMGETTER(Port)(&iPort);
763 AssertComRCReturn(hrc, hrc);
764
765 LONG iDevice = -1;
766 hrc = arrayOfMediumAttachments[j]->COMGETTER(Device)(&iDevice);
767 AssertComRCReturn(hrc, hrc);
768
769 DeviceType_T enmType;
770 hrc = arrayOfMediumAttachments[j]->COMGETTER(Type)(&enmType);
771 AssertComRCReturn(hrc, hrc);
772
773 if (enmType == DeviceType_Floppy)
774 {
775 ComPtr<IMedium> ptrMedium;
776 hrc = arrayOfMediumAttachments[j]->COMGETTER(Medium)(ptrMedium.asOutParam());
777 AssertComRCReturn(hrc, hrc);
778
779 if (ptrMedium.isNotNull())
780 {
781 ptrMedium.setNull();
782 rAutoLock.release();
783 hrc = rPtrSessionMachine->UnmountMedium(bstrControllerName.raw(), iPort, iDevice, TRUE /*fForce*/);
784 rAutoLock.acquire();
785 }
786
787 if (iPort == 0 && iDevice == 0)
788 fFoundPort0Dev0 = true;
789 }
790 else if (iPort == 0 && iDevice == 0)
791 return setError(E_FAIL,
792 tr("Found non-floppy device attached to port 0 device 0 on the floppy controller '%ls'"),
793 bstrControllerName.raw());
794 }
795 }
796 }
797
798 /*
799 * Add a floppy controller if we need to.
800 */
801 if (strControllerName.isEmpty())
802 {
803 bstrControllerName = strControllerName = "Floppy";
804 ComPtr<IStorageController> ptrControllerIgnored;
805 HRESULT hrc = rPtrSessionMachine->AddStorageController(bstrControllerName.raw(), StorageBus_Floppy,
806 ptrControllerIgnored.asOutParam());
807 LogRelFunc(("Machine::addStorageController(Floppy) -> %Rhrc \n", hrc));
808 if (FAILED(hrc))
809 return hrc;
810 }
811
812 /*
813 * Adding a floppy drive (if needed) and mounting the auxiliary image is
814 * done later together with the ISOs.
815 */
816 rVecInstallatationDisks.push_back(UnattendedInstallationDisk(StorageBus_Floppy, strControllerName,
817 DeviceType_Floppy, AccessMode_ReadWrite,
818 0, 0,
819 fFoundPort0Dev0 /*fMountOnly*/,
820 mpInstaller->getAuxiliaryFloppyFilePath()));
821 return S_OK;
822}
823
824/**
825 * Reconfigures DVD drives of the VM to mount all the ISOs we need.
826 *
827 * This will umount all DVD media.
828 *
829 * @returns COM status code.
830 * @param rControllers The existing controllers.
831 * @param rVecInstallatationDisks The list of image to mount.
832 * @param rPtrSessionMachine The session machine smart pointer.
833 * @param rAutoLock The lock.
834 * @param enmRecommendedStorageBus The recommended storage bus type for adding
835 * DVD drives on.
836 */
837HRESULT Unattended::i_reconfigureIsos(com::SafeIfaceArray<IStorageController> &rControllers,
838 std::vector<UnattendedInstallationDisk> &rVecInstallatationDisks,
839 ComPtr<IMachine> const &rPtrSessionMachine,
840 AutoMultiWriteLock2 &rAutoLock, StorageBus_T enmRecommendedStorageBus)
841{
842 /*
843 * Enumerate the attachements of every controller, looking for DVD drives,
844 * ASSUMEING all drives are bootable.
845 *
846 * Eject the medium from all the drives (don't want any confusion) and look
847 * for the recommended storage bus in case we need to add more drives.
848 */
849 HRESULT hrc;
850 std::list<ControllerSlot> lstControllerDvdSlots;
851 Utf8Str strRecommendedControllerName; /* non-empty if recommended bus found. */
852 Utf8Str strControllerName;
853 Bstr bstrControllerName;
854 for (size_t i = 0; i < rControllers.size(); ++i)
855 {
856 hrc = rControllers[i]->COMGETTER(Name)(bstrControllerName.asOutParam());
857 AssertComRCReturn(hrc, hrc);
858 strControllerName = bstrControllerName;
859
860 /* Look for recommended storage bus. */
861 StorageBus_T enmStorageBus;
862 hrc = rControllers[i]->COMGETTER(Bus)(&enmStorageBus);
863 AssertComRCReturn(hrc, hrc);
864 if (enmStorageBus == enmRecommendedStorageBus)
865 {
866 strRecommendedControllerName = bstrControllerName;
867 AssertLogRelReturn(strControllerName.isNotEmpty(), setErrorBoth(E_UNEXPECTED, VERR_INTERNAL_ERROR_2));
868 }
869
870 /* Scan the controller attachments. */
871 com::SafeIfaceArray<IMediumAttachment> arrayOfMediumAttachments;
872 hrc = rPtrSessionMachine->GetMediumAttachmentsOfController(bstrControllerName.raw(),
873 ComSafeArrayAsOutParam(arrayOfMediumAttachments));
874 AssertComRCReturn(hrc, hrc);
875
876 for (size_t j = 0; j < arrayOfMediumAttachments.size(); j++)
877 {
878 DeviceType_T enmType;
879 hrc = arrayOfMediumAttachments[j]->COMGETTER(Type)(&enmType);
880 AssertComRCReturn(hrc, hrc);
881 if (enmType == DeviceType_DVD)
882 {
883 LONG iPort = -1;
884 hrc = arrayOfMediumAttachments[j]->COMGETTER(Port)(&iPort);
885 AssertComRCReturn(hrc, hrc);
886
887 LONG iDevice = -1;
888 hrc = arrayOfMediumAttachments[j]->COMGETTER(Device)(&iDevice);
889 AssertComRCReturn(hrc, hrc);
890
891 /* Remeber it. */
892 lstControllerDvdSlots.push_back(ControllerSlot(enmStorageBus, strControllerName, iPort, iDevice, false /*fFree*/));
893
894 /* Eject the medium, if any. */
895 ComPtr<IMedium> ptrMedium;
896 hrc = arrayOfMediumAttachments[j]->COMGETTER(Medium)(ptrMedium.asOutParam());
897 AssertComRCReturn(hrc, hrc);
898 if (ptrMedium.isNotNull())
899 {
900 ptrMedium.setNull();
901
902 rAutoLock.release();
903 hrc = rPtrSessionMachine->UnmountMedium(bstrControllerName.raw(), iPort, iDevice, TRUE /*fForce*/);
904 rAutoLock.acquire();
905 }
906 }
907 }
908 }
909
910 /*
911 * How many drives do we need? Add more if necessary.
912 */
913 ULONG cDvdDrivesNeeded = 0;
914 if (mpInstaller->isAuxiliaryIsoNeeded())
915 cDvdDrivesNeeded++;
916 if (mpInstaller->isOriginalIsoNeeded())
917 cDvdDrivesNeeded++;
918#if 0 /* These are now in the AUX VISO. */
919 if (mpInstaller->isAdditionsIsoNeeded())
920 cDvdDrivesNeeded++;
921 if (mpInstaller->isValidationKitIsoNeeded())
922 cDvdDrivesNeeded++;
923#endif
924 Assert(cDvdDrivesNeeded > 0);
925 if (cDvdDrivesNeeded > lstControllerDvdSlots.size())
926 {
927 /* Do we need to add the recommended controller? */
928 if (strRecommendedControllerName.isEmpty())
929 {
930 switch (enmRecommendedStorageBus)
931 {
932 case StorageBus_IDE: strRecommendedControllerName = "IDE"; break;
933 case StorageBus_SATA: strRecommendedControllerName = "SATA"; break;
934 case StorageBus_SCSI: strRecommendedControllerName = "SCSI"; break;
935 case StorageBus_SAS: strRecommendedControllerName = "SAS"; break;
936 case StorageBus_USB: strRecommendedControllerName = "USB"; break;
937 case StorageBus_PCIe: strRecommendedControllerName = "PCIe"; break;
938 default:
939 return setError(E_FAIL, tr("Support for recommended storage bus %d not implemented"),
940 (int)enmRecommendedStorageBus);
941 }
942 ComPtr<IStorageController> ptrControllerIgnored;
943 hrc = rPtrSessionMachine->AddStorageController(Bstr(strRecommendedControllerName).raw(), enmRecommendedStorageBus,
944 ptrControllerIgnored.asOutParam());
945 LogRelFunc(("Machine::addStorageController(%s) -> %Rhrc \n", strRecommendedControllerName.c_str(), hrc));
946 if (FAILED(hrc))
947 return hrc;
948 }
949
950 /* Add free controller slots, maybe raising the port limit on the controller if we can. */
951 hrc = i_findOrCreateNeededFreeSlots(strRecommendedControllerName, enmRecommendedStorageBus, rPtrSessionMachine,
952 cDvdDrivesNeeded, lstControllerDvdSlots);
953 if (FAILED(hrc))
954 return hrc;
955 if (cDvdDrivesNeeded > lstControllerDvdSlots.size())
956 {
957 /* We could in many cases create another controller here, but it's not worth the effort. */
958 return setError(E_FAIL, tr("Not enough free slots on controller '%s' to add %u DVD drive(s)"),
959 strRecommendedControllerName.c_str(), cDvdDrivesNeeded - lstControllerDvdSlots.size());
960 }
961 Assert(cDvdDrivesNeeded == lstControllerDvdSlots.size());
962 }
963
964 /*
965 * Sort the DVD slots in boot order.
966 */
967 lstControllerDvdSlots.sort();
968
969 /*
970 * Prepare ISO mounts.
971 *
972 * Boot order depends on bootFromAuxiliaryIso() and we must grab DVD slots
973 * according to the boot order.
974 */
975 std::list<ControllerSlot>::const_iterator itDvdSlot = lstControllerDvdSlots.begin();
976 if (mpInstaller->isAuxiliaryIsoNeeded() && mpInstaller->bootFromAuxiliaryIso())
977 {
978 rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, mpInstaller->getAuxiliaryIsoFilePath()));
979 ++itDvdSlot;
980 }
981
982 if (mpInstaller->isOriginalIsoNeeded())
983 {
984 rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, i_getIsoPath()));
985 ++itDvdSlot;
986 }
987
988 if (mpInstaller->isAuxiliaryIsoNeeded() && !mpInstaller->bootFromAuxiliaryIso())
989 {
990 rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, mpInstaller->getAuxiliaryIsoFilePath()));
991 ++itDvdSlot;
992 }
993
994#if 0 /* These are now in the AUX VISO. */
995 if (mpInstaller->isAdditionsIsoNeeded())
996 {
997 rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, i_getAdditionsIsoPath()));
998 ++itDvdSlot;
999 }
1000
1001 if (mpInstaller->isValidationKitIsoNeeded())
1002 {
1003 rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, i_getValidationKitIsoPath()));
1004 ++itDvdSlot;
1005 }
1006#endif
1007
1008 return S_OK;
1009}
1010
1011/**
1012 * Used to find more free slots for DVD drives during VM reconfiguration.
1013 *
1014 * This may modify the @a portCount property of the given controller.
1015 *
1016 * @returns COM status code.
1017 * @param rStrControllerName The name of the controller to find/create
1018 * free slots on.
1019 * @param enmStorageBus The storage bus type.
1020 * @param rPtrSessionMachine Reference to the session machine.
1021 * @param cSlotsNeeded Total slots needed (including those we've
1022 * already found).
1023 * @param rDvdSlots The slot collection for DVD drives to add
1024 * free slots to as we find/create them.
1025 */
1026HRESULT Unattended::i_findOrCreateNeededFreeSlots(const Utf8Str &rStrControllerName, StorageBus_T enmStorageBus,
1027 ComPtr<IMachine> const &rPtrSessionMachine, uint32_t cSlotsNeeded,
1028 std::list<ControllerSlot> &rDvdSlots)
1029{
1030 Assert(cSlotsNeeded > rDvdSlots.size());
1031
1032 /*
1033 * Get controlleer stats.
1034 */
1035 ComPtr<IStorageController> pController;
1036 HRESULT hrc = rPtrSessionMachine->GetStorageControllerByName(Bstr(rStrControllerName).raw(), pController.asOutParam());
1037 AssertComRCReturn(hrc, hrc);
1038
1039 ULONG cMaxDevicesPerPort = 1;
1040 hrc = pController->COMGETTER(MaxDevicesPerPortCount)(&cMaxDevicesPerPort);
1041 AssertComRCReturn(hrc, hrc);
1042 AssertLogRelReturn(cMaxDevicesPerPort > 0, E_UNEXPECTED);
1043
1044 ULONG cPorts = 0;
1045 hrc = pController->COMGETTER(PortCount)(&cPorts);
1046 AssertComRCReturn(hrc, hrc);
1047
1048 /*
1049 * Get the attachment list and turn into an internal list for lookup speed.
1050 */
1051 com::SafeIfaceArray<IMediumAttachment> arrayOfMediumAttachments;
1052 hrc = rPtrSessionMachine->GetMediumAttachmentsOfController(Bstr(rStrControllerName).raw(),
1053 ComSafeArrayAsOutParam(arrayOfMediumAttachments));
1054 AssertComRCReturn(hrc, hrc);
1055
1056 std::vector<ControllerSlot> arrayOfUsedSlots;
1057 for (size_t i = 0; i < arrayOfMediumAttachments.size(); i++)
1058 {
1059 LONG iPort = -1;
1060 hrc = arrayOfMediumAttachments[i]->COMGETTER(Port)(&iPort);
1061 AssertComRCReturn(hrc, hrc);
1062
1063 LONG iDevice = -1;
1064 hrc = arrayOfMediumAttachments[i]->COMGETTER(Device)(&iDevice);
1065 AssertComRCReturn(hrc, hrc);
1066
1067 arrayOfUsedSlots.push_back(ControllerSlot(enmStorageBus, Utf8Str::Empty, iPort, iDevice, false /*fFree*/));
1068 }
1069
1070 /*
1071 * Iterate thru all possible slots, adding those not found in arrayOfUsedSlots.
1072 */
1073 for (uint32_t iPort = 0; iPort < cPorts; iPort++)
1074 for (uint32_t iDevice = 0; iDevice < cMaxDevicesPerPort; iDevice++)
1075 {
1076 bool fFound = false;
1077 for (size_t i = 0; i < arrayOfUsedSlots.size(); i++)
1078 if ( arrayOfUsedSlots[i].uPort == iPort
1079 && arrayOfUsedSlots[i].uDevice == iDevice)
1080 {
1081 fFound = true;
1082 break;
1083 }
1084 if (!fFound)
1085 {
1086 rDvdSlots.push_back(ControllerSlot(enmStorageBus, rStrControllerName, iPort, iDevice, true /*fFree*/));
1087 if (rDvdSlots.size() >= cSlotsNeeded)
1088 return S_OK;
1089 }
1090 }
1091
1092 /*
1093 * Okay we still need more ports. See if increasing the number of controller
1094 * ports would solve it.
1095 */
1096 ULONG cMaxPorts = 1;
1097 hrc = pController->COMGETTER(MaxPortCount)(&cMaxPorts);
1098 AssertComRCReturn(hrc, hrc);
1099 if (cMaxPorts <= cPorts)
1100 return S_OK;
1101 size_t cNewPortsNeeded = (cSlotsNeeded - rDvdSlots.size() + cMaxDevicesPerPort - 1) / cMaxDevicesPerPort;
1102 if (cPorts + cNewPortsNeeded > cMaxPorts)
1103 return S_OK;
1104
1105 /*
1106 * Raise the port count and add the free slots we've just created.
1107 */
1108 hrc = pController->COMSETTER(PortCount)(cPorts + (ULONG)cNewPortsNeeded);
1109 AssertComRCReturn(hrc, hrc);
1110 for (uint32_t iPort = cPorts; iPort < cPorts + cNewPortsNeeded; iPort++)
1111 for (uint32_t iDevice = 0; iDevice < cMaxDevicesPerPort; iDevice++)
1112 {
1113 rDvdSlots.push_back(ControllerSlot(enmStorageBus, rStrControllerName, iPort, iDevice, true /*fFree*/));
1114 if (rDvdSlots.size() >= cSlotsNeeded)
1115 return S_OK;
1116 }
1117
1118 /* We should not get here! */
1119 AssertLogRelFailedReturn(E_UNEXPECTED);
1120}
1121
1122HRESULT Unattended::done()
1123{
1124 LogFlow(("Unattended::done\n"));
1125 if (mpInstaller)
1126 {
1127 LogRelFlow(("Unattended::done: Deleting installer object (%p)\n", mpInstaller));
1128 delete mpInstaller;
1129 mpInstaller = NULL;
1130 }
1131 return S_OK;
1132}
1133
1134HRESULT Unattended::getIsoPath(com::Utf8Str &isoPath)
1135{
1136 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1137 isoPath = mStrIsoPath;
1138 return S_OK;
1139}
1140
1141HRESULT Unattended::setIsoPath(const com::Utf8Str &isoPath)
1142{
1143 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1144 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1145 mStrIsoPath = isoPath;
1146 mfDoneDetectIsoOS = false;
1147 return S_OK;
1148}
1149
1150HRESULT Unattended::getUser(com::Utf8Str &user)
1151{
1152 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1153 user = mStrUser;
1154 return S_OK;
1155}
1156
1157
1158HRESULT Unattended::setUser(const com::Utf8Str &user)
1159{
1160 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1161 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1162 mStrUser = user;
1163 return S_OK;
1164}
1165
1166HRESULT Unattended::getPassword(com::Utf8Str &password)
1167{
1168 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1169 password = mStrPassword;
1170 return S_OK;
1171}
1172
1173HRESULT Unattended::setPassword(const com::Utf8Str &password)
1174{
1175 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1176 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1177 mStrPassword = password;
1178 return S_OK;
1179}
1180
1181HRESULT Unattended::getFullUserName(com::Utf8Str &fullUserName)
1182{
1183 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1184 fullUserName = mStrFullUserName;
1185 return S_OK;
1186}
1187
1188HRESULT Unattended::setFullUserName(const com::Utf8Str &fullUserName)
1189{
1190 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1191 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1192 mStrFullUserName = fullUserName;
1193 return S_OK;
1194}
1195
1196HRESULT Unattended::getProductKey(com::Utf8Str &productKey)
1197{
1198 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1199 productKey = mStrProductKey;
1200 return S_OK;
1201}
1202
1203HRESULT Unattended::setProductKey(const com::Utf8Str &productKey)
1204{
1205 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1206 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1207 mStrProductKey = productKey;
1208 return S_OK;
1209}
1210
1211HRESULT Unattended::getAdditionsIsoPath(com::Utf8Str &additionsIsoPath)
1212{
1213 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1214 additionsIsoPath = mStrAdditionsIsoPath;
1215 return S_OK;
1216}
1217
1218HRESULT Unattended::setAdditionsIsoPath(const com::Utf8Str &additionsIsoPath)
1219{
1220 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1221 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1222 mStrAdditionsIsoPath = additionsIsoPath;
1223 return S_OK;
1224}
1225
1226HRESULT Unattended::getInstallGuestAdditions(BOOL *installGuestAdditions)
1227{
1228 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1229 *installGuestAdditions = mfInstallGuestAdditions;
1230 return S_OK;
1231}
1232
1233HRESULT Unattended::setInstallGuestAdditions(BOOL installGuestAdditions)
1234{
1235 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1236 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1237 mfInstallGuestAdditions = installGuestAdditions != FALSE;
1238 return S_OK;
1239}
1240
1241HRESULT Unattended::getValidationKitIsoPath(com::Utf8Str &aValidationKitIsoPath)
1242{
1243 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1244 aValidationKitIsoPath = mStrValidationKitIsoPath;
1245 return S_OK;
1246}
1247
1248HRESULT Unattended::setValidationKitIsoPath(const com::Utf8Str &aValidationKitIsoPath)
1249{
1250 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1251 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1252 mStrValidationKitIsoPath = aValidationKitIsoPath;
1253 return S_OK;
1254}
1255
1256HRESULT Unattended::getInstallTestExecService(BOOL *aInstallTestExecService)
1257{
1258 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1259 *aInstallTestExecService = mfInstallTestExecService;
1260 return S_OK;
1261}
1262
1263HRESULT Unattended::setInstallTestExecService(BOOL aInstallTestExecService)
1264{
1265 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1266 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1267 mfInstallTestExecService = aInstallTestExecService != FALSE;
1268 return S_OK;
1269}
1270
1271HRESULT Unattended::getTimeZone(com::Utf8Str &aTimeZone)
1272{
1273 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1274 aTimeZone = mStrTimeZone;
1275 return S_OK;
1276}
1277
1278HRESULT Unattended::setTimeZone(const com::Utf8Str &aTimezone)
1279{
1280 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1281 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1282 mStrTimeZone = aTimezone;
1283 return S_OK;
1284}
1285
1286HRESULT Unattended::getLocale(com::Utf8Str &aLocale)
1287{
1288 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1289 aLocale = mStrLocale;
1290 return S_OK;
1291}
1292
1293HRESULT Unattended::setLocale(const com::Utf8Str &aLocale)
1294{
1295 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1296 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1297 if ( aLocale.isEmpty() /* use default */
1298 || ( aLocale.length() == 5
1299 && RT_C_IS_LOWER(aLocale[0])
1300 && RT_C_IS_LOWER(aLocale[1])
1301 && aLocale[2] == '_'
1302 && RT_C_IS_UPPER(aLocale[3])
1303 && RT_C_IS_UPPER(aLocale[4])) )
1304 {
1305 mStrLocale = aLocale;
1306 return S_OK;
1307 }
1308 return setError(E_INVALIDARG, tr("Expected two lower cased letters, an underscore, and two upper cased letters"));
1309}
1310
1311HRESULT Unattended::getLanguage(com::Utf8Str &aLanguage)
1312{
1313 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1314 aLanguage = mStrLanguage;
1315 return S_OK;
1316}
1317
1318HRESULT Unattended::setLanguage(const com::Utf8Str &aLanguage)
1319{
1320 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1321 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1322 mStrLanguage = aLanguage;
1323 return S_OK;
1324}
1325
1326HRESULT Unattended::getCountry(com::Utf8Str &aCountry)
1327{
1328 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1329 aCountry = mStrCountry;
1330 return S_OK;
1331}
1332
1333HRESULT Unattended::setCountry(const com::Utf8Str &aCountry)
1334{
1335 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1336 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1337 if ( aCountry.isEmpty()
1338 || ( aCountry.length() == 2
1339 && RT_C_IS_UPPER(aCountry[0])
1340 && RT_C_IS_UPPER(aCountry[1])) )
1341 {
1342 mStrCountry = aCountry;
1343 return S_OK;
1344 }
1345 return setError(E_INVALIDARG, tr("Expected two upper cased letters"));
1346}
1347
1348HRESULT Unattended::getProxy(com::Utf8Str &aProxy)
1349{
1350 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1351 aProxy = ""; /// @todo turn schema map into string or something.
1352 return S_OK;
1353}
1354
1355HRESULT Unattended::setProxy(const com::Utf8Str &aProxy)
1356{
1357 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1358 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1359 if (aProxy.isEmpty())
1360 {
1361 /* set default proxy */
1362 }
1363 else if (aProxy.equalsIgnoreCase("none"))
1364 {
1365 /* clear proxy config */
1366 }
1367 else
1368 {
1369 /* Parse and set proxy config into a schema map or something along those lines. */
1370 return E_NOTIMPL;
1371 }
1372 return S_OK;
1373}
1374
1375HRESULT Unattended::getPackageSelectionAdjustments(com::Utf8Str &aPackageSelectionAdjustments)
1376{
1377 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1378 aPackageSelectionAdjustments = RTCString::join(mPackageSelectionAdjustments, ";");
1379 return S_OK;
1380}
1381
1382HRESULT Unattended::setPackageSelectionAdjustments(const com::Utf8Str &aPackageSelectionAdjustments)
1383{
1384 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1385 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1386 if (aPackageSelectionAdjustments.isEmpty())
1387 mPackageSelectionAdjustments.clear();
1388 else
1389 {
1390 RTCList<RTCString, RTCString *> arrayStrSplit = aPackageSelectionAdjustments.split(";");
1391 for (size_t i = 0; i < arrayStrSplit.size(); i++)
1392 {
1393 if (arrayStrSplit[i].equals("minimal"))
1394 { /* okay */ }
1395 else
1396 return setError(E_INVALIDARG, tr("Unknown keyword: %s"), arrayStrSplit[i].c_str());
1397 }
1398 mPackageSelectionAdjustments = arrayStrSplit;
1399 }
1400 return S_OK;
1401}
1402
1403HRESULT Unattended::getHostname(com::Utf8Str &aHostname)
1404{
1405 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1406 aHostname = mStrHostname;
1407 return S_OK;
1408}
1409
1410HRESULT Unattended::setHostname(const com::Utf8Str &aHostname)
1411{
1412 /*
1413 * Validate input.
1414 */
1415 if (aHostname.length() > (aHostname.endsWith(".") ? 254U : 253U))
1416 return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
1417 tr("Hostname '%s' is %zu bytes long, max is 253 (excluing trailing dot)"),
1418 aHostname.c_str(), aHostname.length());
1419 size_t cLabels = 0;
1420 const char *pszSrc = aHostname.c_str();
1421 for (;;)
1422 {
1423 size_t cchLabel = 1;
1424 char ch = *pszSrc++;
1425 if (RT_C_IS_ALNUM(ch))
1426 {
1427 cLabels++;
1428 while ((ch = *pszSrc++) != '.' && ch != '\0')
1429 {
1430 if (RT_C_IS_ALNUM(ch) || ch == '-')
1431 {
1432 if (cchLabel < 63)
1433 cchLabel++;
1434 else
1435 return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
1436 tr("Invalid hostname '%s' - label %u is too long, max is 63."),
1437 aHostname.c_str(), cLabels);
1438 }
1439 else
1440 return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
1441 tr("Invalid hostname '%s' - illegal char '%c' at position %zu"),
1442 aHostname.c_str(), ch, pszSrc - aHostname.c_str() - 1);
1443 }
1444 if (cLabels == 1 && cchLabel < 2)
1445 return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
1446 tr("Invalid hostname '%s' - the name part must be at least two characters long"),
1447 aHostname.c_str());
1448 if (ch == '\0')
1449 break;
1450 }
1451 else if (ch != '\0')
1452 return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
1453 tr("Invalid hostname '%s' - illegal lead char '%c' at position %zu"),
1454 aHostname.c_str(), ch, pszSrc - aHostname.c_str() - 1);
1455 else
1456 return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
1457 tr("Invalid hostname '%s' - trailing dot not permitted"), aHostname.c_str());
1458 }
1459 if (cLabels < 2)
1460 return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
1461 tr("Incomplete hostname '%s' - must include both a name and a domain"), aHostname.c_str());
1462
1463 /*
1464 * Make the change.
1465 */
1466 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1467 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1468 mStrHostname = aHostname;
1469 return S_OK;
1470}
1471
1472HRESULT Unattended::getAuxiliaryBasePath(com::Utf8Str &aAuxiliaryBasePath)
1473{
1474 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1475 aAuxiliaryBasePath = mStrAuxiliaryBasePath;
1476 return S_OK;
1477}
1478
1479HRESULT Unattended::setAuxiliaryBasePath(const com::Utf8Str &aAuxiliaryBasePath)
1480{
1481 if (aAuxiliaryBasePath.isEmpty())
1482 return setError(E_INVALIDARG, "Empty base path is not allowed");
1483 if (!RTPathStartsWithRoot(aAuxiliaryBasePath.c_str()))
1484 return setError(E_INVALIDARG, "Base path must be absolute");
1485
1486 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1487 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1488 mStrAuxiliaryBasePath = aAuxiliaryBasePath;
1489 mfIsDefaultAuxiliaryBasePath = mStrAuxiliaryBasePath.isEmpty();
1490 return S_OK;
1491}
1492
1493HRESULT Unattended::getImageIndex(ULONG *index)
1494{
1495 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1496 *index = midxImage;
1497 return S_OK;
1498}
1499
1500HRESULT Unattended::setImageIndex(ULONG index)
1501{
1502 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1503 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1504 midxImage = index;
1505 return S_OK;
1506}
1507
1508HRESULT Unattended::getMachine(ComPtr<IMachine> &aMachine)
1509{
1510 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1511 return mMachine.queryInterfaceTo(aMachine.asOutParam());
1512}
1513
1514HRESULT Unattended::setMachine(const ComPtr<IMachine> &aMachine)
1515{
1516 /*
1517 * Lookup the VM so we can safely get the Machine instance.
1518 * (Don't want to test how reliable XPCOM and COM are with finding
1519 * the local object instance when a client passes a stub back.)
1520 */
1521 Bstr bstrUuidMachine;
1522 HRESULT hrc = aMachine->COMGETTER(Id)(bstrUuidMachine.asOutParam());
1523 if (SUCCEEDED(hrc))
1524 {
1525 Guid UuidMachine(bstrUuidMachine);
1526 ComObjPtr<Machine> ptrMachine;
1527 hrc = mParent->i_findMachine(UuidMachine, false /*fPermitInaccessible*/, true /*aSetError*/, &ptrMachine);
1528 if (SUCCEEDED(hrc))
1529 {
1530 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1531 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER,
1532 tr("Cannot change after prepare() has been called")));
1533 mMachine = ptrMachine;
1534 mMachineUuid = UuidMachine;
1535 if (mfIsDefaultAuxiliaryBasePath)
1536 mStrAuxiliaryBasePath.setNull();
1537 hrc = S_OK;
1538 }
1539 }
1540 return hrc;
1541}
1542
1543HRESULT Unattended::getScriptTemplatePath(com::Utf8Str &aScriptTemplatePath)
1544{
1545 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1546 if ( mStrScriptTemplatePath.isNotEmpty()
1547 || mpInstaller == NULL)
1548 aScriptTemplatePath = mStrScriptTemplatePath;
1549 else
1550 aScriptTemplatePath = mpInstaller->getTemplateFilePath();
1551 return S_OK;
1552}
1553
1554HRESULT Unattended::setScriptTemplatePath(const com::Utf8Str &aScriptTemplatePath)
1555{
1556 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1557 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1558 mStrScriptTemplatePath = aScriptTemplatePath;
1559 return S_OK;
1560}
1561
1562HRESULT Unattended::getPostInstallScriptTemplatePath(com::Utf8Str &aPostInstallScriptTemplatePath)
1563{
1564 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1565 if ( mStrPostInstallScriptTemplatePath.isNotEmpty()
1566 || mpInstaller == NULL)
1567 aPostInstallScriptTemplatePath = mStrPostInstallScriptTemplatePath;
1568 else
1569 aPostInstallScriptTemplatePath = mpInstaller->getPostTemplateFilePath();
1570 return S_OK;
1571}
1572
1573HRESULT Unattended::setPostInstallScriptTemplatePath(const com::Utf8Str &aPostInstallScriptTemplatePath)
1574{
1575 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1576 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1577 mStrPostInstallScriptTemplatePath = aPostInstallScriptTemplatePath;
1578 return S_OK;
1579}
1580
1581HRESULT Unattended::getPostInstallCommand(com::Utf8Str &aPostInstallCommand)
1582{
1583 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1584 aPostInstallCommand = mStrPostInstallCommand;
1585 return S_OK;
1586}
1587
1588HRESULT Unattended::setPostInstallCommand(const com::Utf8Str &aPostInstallCommand)
1589{
1590 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1591 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1592 mStrPostInstallCommand = aPostInstallCommand;
1593 return S_OK;
1594}
1595
1596HRESULT Unattended::getExtraInstallKernelParameters(com::Utf8Str &aExtraInstallKernelParameters)
1597{
1598 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1599 if ( mStrExtraInstallKernelParameters.isNotEmpty()
1600 || mpInstaller == NULL)
1601 aExtraInstallKernelParameters = mStrExtraInstallKernelParameters;
1602 else
1603 aExtraInstallKernelParameters = mpInstaller->getDefaultExtraInstallKernelParameters();
1604 return S_OK;
1605}
1606
1607HRESULT Unattended::setExtraInstallKernelParameters(const com::Utf8Str &aExtraInstallKernelParameters)
1608{
1609 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1610 AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
1611 mStrExtraInstallKernelParameters = aExtraInstallKernelParameters;
1612 return S_OK;
1613}
1614
1615HRESULT Unattended::getDetectedOSTypeId(com::Utf8Str &aDetectedOSTypeId)
1616{
1617 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1618 aDetectedOSTypeId = mStrDetectedOSTypeId;
1619 return S_OK;
1620}
1621
1622HRESULT Unattended::getDetectedOSVersion(com::Utf8Str &aDetectedOSVersion)
1623{
1624 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1625 aDetectedOSVersion = mStrDetectedOSVersion;
1626 return S_OK;
1627}
1628
1629HRESULT Unattended::getDetectedOSFlavor(com::Utf8Str &aDetectedOSFlavor)
1630{
1631 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1632 aDetectedOSFlavor = mStrDetectedOSFlavor;
1633 return S_OK;
1634}
1635
1636HRESULT Unattended::getDetectedOSLanguages(com::Utf8Str &aDetectedOSLanguages)
1637{
1638 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1639 aDetectedOSLanguages = RTCString::join(mDetectedOSLanguages, " ");
1640 return S_OK;
1641}
1642
1643HRESULT Unattended::getDetectedOSHints(com::Utf8Str &aDetectedOSHints)
1644{
1645 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1646 aDetectedOSHints = mStrDetectedOSHints;
1647 return S_OK;
1648}
1649
1650/*
1651 * Getters that the installer and script classes can use.
1652 */
1653Utf8Str const &Unattended::i_getIsoPath() const
1654{
1655 Assert(isReadLockedOnCurrentThread());
1656 return mStrIsoPath;
1657}
1658
1659Utf8Str const &Unattended::i_getUser() const
1660{
1661 Assert(isReadLockedOnCurrentThread());
1662 return mStrUser;
1663}
1664
1665Utf8Str const &Unattended::i_getPassword() const
1666{
1667 Assert(isReadLockedOnCurrentThread());
1668 return mStrPassword;
1669}
1670
1671Utf8Str const &Unattended::i_getFullUserName() const
1672{
1673 Assert(isReadLockedOnCurrentThread());
1674 return mStrFullUserName.isNotEmpty() ? mStrFullUserName : mStrUser;
1675}
1676
1677Utf8Str const &Unattended::i_getProductKey() const
1678{
1679 Assert(isReadLockedOnCurrentThread());
1680 return mStrProductKey;
1681}
1682
1683Utf8Str const &Unattended::i_getAdditionsIsoPath() const
1684{
1685 Assert(isReadLockedOnCurrentThread());
1686 return mStrAdditionsIsoPath;
1687}
1688
1689bool Unattended::i_getInstallGuestAdditions() const
1690{
1691 Assert(isReadLockedOnCurrentThread());
1692 return mfInstallGuestAdditions;
1693}
1694
1695Utf8Str const &Unattended::i_getValidationKitIsoPath() const
1696{
1697 Assert(isReadLockedOnCurrentThread());
1698 return mStrValidationKitIsoPath;
1699}
1700
1701bool Unattended::i_getInstallTestExecService() const
1702{
1703 Assert(isReadLockedOnCurrentThread());
1704 return mfInstallTestExecService;
1705}
1706
1707Utf8Str const &Unattended::i_getTimeZone() const
1708{
1709 Assert(isReadLockedOnCurrentThread());
1710 return mStrTimeZone;
1711}
1712
1713PCRTTIMEZONEINFO Unattended::i_getTimeZoneInfo() const
1714{
1715 Assert(isReadLockedOnCurrentThread());
1716 return mpTimeZoneInfo;
1717}
1718
1719Utf8Str const &Unattended::i_getLocale() const
1720{
1721 Assert(isReadLockedOnCurrentThread());
1722 return mStrLocale;
1723}
1724
1725Utf8Str const &Unattended::i_getLanguage() const
1726{
1727 Assert(isReadLockedOnCurrentThread());
1728 return mStrLanguage;
1729}
1730
1731Utf8Str const &Unattended::i_getCountry() const
1732{
1733 Assert(isReadLockedOnCurrentThread());
1734 return mStrCountry;
1735}
1736
1737bool Unattended::i_isMinimalInstallation() const
1738{
1739 size_t i = mPackageSelectionAdjustments.size();
1740 while (i-- > 0)
1741 if (mPackageSelectionAdjustments[i].equals("minimal"))
1742 return true;
1743 return false;
1744}
1745
1746Utf8Str const &Unattended::i_getHostname() const
1747{
1748 Assert(isReadLockedOnCurrentThread());
1749 return mStrHostname;
1750}
1751
1752Utf8Str const &Unattended::i_getAuxiliaryBasePath() const
1753{
1754 Assert(isReadLockedOnCurrentThread());
1755 return mStrAuxiliaryBasePath;
1756}
1757
1758ULONG Unattended::i_getImageIndex() const
1759{
1760 Assert(isReadLockedOnCurrentThread());
1761 return midxImage;
1762}
1763
1764Utf8Str const &Unattended::i_getScriptTemplatePath() const
1765{
1766 Assert(isReadLockedOnCurrentThread());
1767 return mStrScriptTemplatePath;
1768}
1769
1770Utf8Str const &Unattended::i_getPostInstallScriptTemplatePath() const
1771{
1772 Assert(isReadLockedOnCurrentThread());
1773 return mStrPostInstallScriptTemplatePath;
1774}
1775
1776Utf8Str const &Unattended::i_getPostInstallCommand() const
1777{
1778 Assert(isReadLockedOnCurrentThread());
1779 return mStrPostInstallCommand;
1780}
1781
1782Utf8Str const &Unattended::i_getExtraInstallKernelParameters() const
1783{
1784 Assert(isReadLockedOnCurrentThread());
1785 return mStrExtraInstallKernelParameters;
1786}
1787
1788bool Unattended::i_isRtcUsingUtc() const
1789{
1790 Assert(isReadLockedOnCurrentThread());
1791 return mfRtcUseUtc;
1792}
1793
1794bool Unattended::i_isGuestOs64Bit() const
1795{
1796 Assert(isReadLockedOnCurrentThread());
1797 return mfGuestOs64Bit;
1798}
1799
1800VBOXOSTYPE Unattended::i_getGuestOsType() const
1801{
1802 Assert(isReadLockedOnCurrentThread());
1803 return meGuestOsType;
1804}
1805
1806HRESULT Unattended::i_attachImage(UnattendedInstallationDisk const *pImage, ComPtr<IMachine> const &rPtrSessionMachine,
1807 AutoMultiWriteLock2 &rLock)
1808{
1809 /*
1810 * Attach the disk image
1811 * HACK ALERT! Temporarily release the Unattended lock.
1812 */
1813 rLock.release();
1814
1815 ComPtr<IMedium> ptrMedium;
1816 HRESULT rc = mParent->OpenMedium(Bstr(pImage->strImagePath).raw(),
1817 pImage->enmDeviceType,
1818 pImage->enmAccessType,
1819 true,
1820 ptrMedium.asOutParam());
1821 LogRelFlowFunc(("VirtualBox::openMedium -> %Rhrc\n", rc));
1822 if (SUCCEEDED(rc))
1823 {
1824 if (pImage->fMountOnly)
1825 {
1826 // mount the opened disk image
1827 rc = rPtrSessionMachine->MountMedium(Bstr(pImage->strControllerName).raw(), pImage->uPort,
1828 pImage->uDevice, ptrMedium, TRUE /*fForce*/);
1829 LogRelFlowFunc(("Machine::MountMedium -> %Rhrc\n", rc));
1830 }
1831 else
1832 {
1833 //attach the opened disk image to the controller
1834 rc = rPtrSessionMachine->AttachDevice(Bstr(pImage->strControllerName).raw(), pImage->uPort,
1835 pImage->uDevice, pImage->enmDeviceType, ptrMedium);
1836 LogRelFlowFunc(("Machine::AttachDevice -> %Rhrc\n", rc));
1837 }
1838 }
1839
1840 rLock.acquire();
1841 return rc;
1842}
1843
1844bool Unattended::i_isGuestOSArchX64(Utf8Str const &rStrGuestOsTypeId)
1845{
1846 ComPtr<IGuestOSType> pGuestOSType;
1847 HRESULT hrc = mParent->GetGuestOSType(Bstr(rStrGuestOsTypeId).raw(), pGuestOSType.asOutParam());
1848 if (SUCCEEDED(hrc))
1849 {
1850 BOOL fIs64Bit = FALSE;
1851 hrc = pGuestOSType->COMGETTER(Is64Bit)(&fIs64Bit);
1852 if (SUCCEEDED(hrc))
1853 return fIs64Bit != FALSE;
1854 }
1855 return false;
1856}
1857
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette