[68162] | 1 | /* $Id: UnattendedImpl.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * Unattended class implementation
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[68162] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[68162] | 26 | */
|
---|
| 27 |
|
---|
[69238] | 28 |
|
---|
[68162] | 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
| 32 | #define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
|
---|
| 33 | #include "LoggingNew.h"
|
---|
| 34 | #include "VirtualBoxBase.h"
|
---|
| 35 | #include "UnattendedImpl.h"
|
---|
| 36 | #include "UnattendedInstaller.h"
|
---|
| 37 | #include "UnattendedScript.h"
|
---|
| 38 | #include "VirtualBoxImpl.h"
|
---|
| 39 | #include "SystemPropertiesImpl.h"
|
---|
| 40 | #include "MachineImpl.h"
|
---|
| 41 | #include "Global.h"
|
---|
[93410] | 42 | #include "StringifyEnums.h"
|
---|
[68162] | 43 |
|
---|
| 44 | #include <VBox/err.h>
|
---|
[93521] | 45 | #include <iprt/cpp/xml.h>
|
---|
[68162] | 46 | #include <iprt/ctype.h>
|
---|
| 47 | #include <iprt/file.h>
|
---|
[96861] | 48 | #ifndef RT_OS_WINDOWS
|
---|
| 49 | # include <iprt/formats/mz.h>
|
---|
| 50 | # include <iprt/formats/pecoff.h>
|
---|
| 51 | #endif
|
---|
[93521] | 52 | #include <iprt/formats/wim.h>
|
---|
[68318] | 53 | #include <iprt/fsvfs.h>
|
---|
| 54 | #include <iprt/inifile.h>
|
---|
[68162] | 55 | #include <iprt/locale.h>
|
---|
| 56 | #include <iprt/path.h>
|
---|
[93189] | 57 | #include <iprt/vfs.h>
|
---|
[68162] | 58 |
|
---|
| 59 | using namespace std;
|
---|
| 60 |
|
---|
| 61 |
|
---|
| 62 | /*********************************************************************************************************************************
|
---|
| 63 | * Structures and Typedefs *
|
---|
| 64 | *********************************************************************************************************************************/
|
---|
| 65 | /**
|
---|
| 66 | * Controller slot for a DVD drive.
|
---|
| 67 | *
|
---|
| 68 | * The slot can be free and needing a drive to be attached along with the ISO
|
---|
| 69 | * image, or it may already be there and only need mounting the ISO. The
|
---|
| 70 | * ControllerSlot::fFree member indicates which it is.
|
---|
| 71 | */
|
---|
| 72 | struct ControllerSlot
|
---|
| 73 | {
|
---|
| 74 | StorageBus_T enmBus;
|
---|
| 75 | Utf8Str strControllerName;
|
---|
[85277] | 76 | LONG iPort;
|
---|
| 77 | LONG iDevice;
|
---|
[68162] | 78 | bool fFree;
|
---|
| 79 |
|
---|
[85277] | 80 | ControllerSlot(StorageBus_T a_enmBus, const Utf8Str &a_rName, LONG a_iPort, LONG a_iDevice, bool a_fFree)
|
---|
| 81 | : enmBus(a_enmBus), strControllerName(a_rName), iPort(a_iPort), iDevice(a_iDevice), fFree(a_fFree)
|
---|
[68162] | 82 | {}
|
---|
| 83 |
|
---|
| 84 | bool operator<(const ControllerSlot &rThat) const
|
---|
| 85 | {
|
---|
| 86 | if (enmBus == rThat.enmBus)
|
---|
| 87 | {
|
---|
| 88 | if (strControllerName == rThat.strControllerName)
|
---|
| 89 | {
|
---|
[85277] | 90 | if (iPort == rThat.iPort)
|
---|
| 91 | return iDevice < rThat.iDevice;
|
---|
| 92 | return iPort < rThat.iPort;
|
---|
[68162] | 93 | }
|
---|
| 94 | return strControllerName < rThat.strControllerName;
|
---|
| 95 | }
|
---|
| 96 |
|
---|
| 97 | /*
|
---|
| 98 | * Bus comparsion in boot priority order.
|
---|
| 99 | */
|
---|
| 100 | /* IDE first. */
|
---|
| 101 | if (enmBus == StorageBus_IDE)
|
---|
| 102 | return true;
|
---|
| 103 | if (rThat.enmBus == StorageBus_IDE)
|
---|
| 104 | return false;
|
---|
| 105 | /* SATA next */
|
---|
| 106 | if (enmBus == StorageBus_SATA)
|
---|
| 107 | return true;
|
---|
| 108 | if (rThat.enmBus == StorageBus_SATA)
|
---|
| 109 | return false;
|
---|
| 110 | /* SCSI next */
|
---|
| 111 | if (enmBus == StorageBus_SCSI)
|
---|
| 112 | return true;
|
---|
| 113 | if (rThat.enmBus == StorageBus_SCSI)
|
---|
| 114 | return false;
|
---|
| 115 | /* numerical */
|
---|
| 116 | return (int)enmBus < (int)rThat.enmBus;
|
---|
| 117 | }
|
---|
| 118 |
|
---|
| 119 | bool operator==(const ControllerSlot &rThat) const
|
---|
| 120 | {
|
---|
| 121 | return enmBus == rThat.enmBus
|
---|
| 122 | && strControllerName == rThat.strControllerName
|
---|
[85277] | 123 | && iPort == rThat.iPort
|
---|
| 124 | && iDevice == rThat.iDevice;
|
---|
[68162] | 125 | }
|
---|
| 126 | };
|
---|
| 127 |
|
---|
| 128 | /**
|
---|
| 129 | * Installation disk.
|
---|
| 130 | *
|
---|
| 131 | * Used when reconfiguring the VM.
|
---|
| 132 | */
|
---|
| 133 | typedef struct UnattendedInstallationDisk
|
---|
| 134 | {
|
---|
| 135 | StorageBus_T enmBusType; /**< @todo nobody is using this... */
|
---|
| 136 | Utf8Str strControllerName;
|
---|
| 137 | DeviceType_T enmDeviceType;
|
---|
| 138 | AccessMode_T enmAccessType;
|
---|
[85277] | 139 | LONG iPort;
|
---|
| 140 | LONG iDevice;
|
---|
[68162] | 141 | bool fMountOnly;
|
---|
| 142 | Utf8Str strImagePath;
|
---|
[98035] | 143 | bool fAuxiliary;
|
---|
[68162] | 144 |
|
---|
| 145 | UnattendedInstallationDisk(StorageBus_T a_enmBusType, Utf8Str const &a_rBusName, DeviceType_T a_enmDeviceType,
|
---|
[85277] | 146 | AccessMode_T a_enmAccessType, LONG a_iPort, LONG a_iDevice, bool a_fMountOnly,
|
---|
[98035] | 147 | Utf8Str const &a_rImagePath, bool a_fAuxiliary)
|
---|
[68162] | 148 | : enmBusType(a_enmBusType), strControllerName(a_rBusName), enmDeviceType(a_enmDeviceType), enmAccessType(a_enmAccessType)
|
---|
[98035] | 149 | , iPort(a_iPort), iDevice(a_iDevice), fMountOnly(a_fMountOnly), strImagePath(a_rImagePath), fAuxiliary(a_fAuxiliary)
|
---|
[68162] | 150 | {
|
---|
| 151 | Assert(strControllerName.length() > 0);
|
---|
| 152 | }
|
---|
| 153 |
|
---|
[98035] | 154 | UnattendedInstallationDisk(std::list<ControllerSlot>::const_iterator const &itDvdSlot, Utf8Str const &a_rImagePath,
|
---|
| 155 | bool a_fAuxiliary)
|
---|
[68162] | 156 | : enmBusType(itDvdSlot->enmBus), strControllerName(itDvdSlot->strControllerName), enmDeviceType(DeviceType_DVD)
|
---|
[85277] | 157 | , enmAccessType(AccessMode_ReadOnly), iPort(itDvdSlot->iPort), iDevice(itDvdSlot->iDevice)
|
---|
[98035] | 158 | , fMountOnly(!itDvdSlot->fFree), strImagePath(a_rImagePath), fAuxiliary(a_fAuxiliary)
|
---|
[68162] | 159 | {
|
---|
| 160 | Assert(strControllerName.length() > 0);
|
---|
| 161 | }
|
---|
| 162 | } UnattendedInstallationDisk;
|
---|
| 163 |
|
---|
| 164 |
|
---|
[93082] | 165 | /**
|
---|
| 166 | * OS/2 syslevel file header.
|
---|
| 167 | */
|
---|
| 168 | #pragma pack(1)
|
---|
| 169 | typedef struct OS2SYSLEVELHDR
|
---|
| 170 | {
|
---|
| 171 | uint16_t uMinusOne; /**< 0x00: UINT16_MAX */
|
---|
| 172 | char achSignature[8]; /**< 0x02: "SYSLEVEL" */
|
---|
| 173 | uint8_t abReserved1[5]; /**< 0x0a: Usually zero. Ignore. */
|
---|
| 174 | uint16_t uSyslevelFileVer; /**< 0x0f: The syslevel file version: 1. */
|
---|
| 175 | uint8_t abReserved2[16]; /**< 0x11: Zero. Ignore. */
|
---|
| 176 | uint32_t offTable; /**< 0x21: Offset of the syslevel table. */
|
---|
| 177 | } OS2SYSLEVELHDR;
|
---|
| 178 | #pragma pack()
|
---|
| 179 | AssertCompileSize(OS2SYSLEVELHDR, 0x25);
|
---|
| 180 |
|
---|
| 181 | /**
|
---|
| 182 | * OS/2 syslevel table entry.
|
---|
| 183 | */
|
---|
| 184 | #pragma pack(1)
|
---|
| 185 | typedef struct OS2SYSLEVELENTRY
|
---|
| 186 | {
|
---|
| 187 | uint16_t id; /**< 0x00: ? */
|
---|
| 188 | uint8_t bEdition; /**< 0x02: The OS/2 edition: 0=standard, 1=extended, x=component defined */
|
---|
| 189 | uint8_t bVersion; /**< 0x03: 0x45 = 4.5 */
|
---|
| 190 | uint8_t bModify; /**< 0x04: Lower nibble is added to bVersion, so 0x45 0x02 => 4.52 */
|
---|
| 191 | uint8_t abReserved1[2]; /**< 0x05: Zero. Ignore. */
|
---|
| 192 | char achCsdLevel[8]; /**< 0x07: The current CSD level. */
|
---|
| 193 | char achCsdPrior[8]; /**< 0x0f: The prior CSD level. */
|
---|
| 194 | char szName[80]; /**< 0x5f: System/component name. */
|
---|
| 195 | char achId[9]; /**< 0x67: System/component ID. */
|
---|
| 196 | uint8_t bRefresh; /**< 0x70: Single digit refresh version, ignored if zero. */
|
---|
| 197 | char szType[9]; /**< 0x71: Some kind of type string. Optional */
|
---|
| 198 | uint8_t abReserved2[6]; /**< 0x7a: Zero. Ignore. */
|
---|
| 199 | } OS2SYSLEVELENTRY;
|
---|
| 200 | #pragma pack()
|
---|
| 201 | AssertCompileSize(OS2SYSLEVELENTRY, 0x80);
|
---|
| 202 |
|
---|
[93579] | 203 |
|
---|
| 204 |
|
---|
[93525] | 205 | /**
|
---|
| 206 | * Concatenate image name and version strings and return.
|
---|
| 207 | *
|
---|
[93579] | 208 | * A possible output would be "Windows 10 Home (10.0.19041.330 / x64)".
|
---|
| 209 | *
|
---|
| 210 | * @returns Name string to use.
|
---|
| 211 | * @param r_strName String object that can be formatted into and returned.
|
---|
[93525] | 212 | */
|
---|
[93579] | 213 | const Utf8Str &WIMImage::formatName(Utf8Str &r_strName) const
|
---|
[93525] | 214 | {
|
---|
[93587] | 215 | /* We skip the mFlavor as it's typically part of the description already. */
|
---|
| 216 |
|
---|
[93581] | 217 | if (mVersion.isEmpty() && mArch.isEmpty() && mDefaultLanguage.isEmpty() && mLanguages.size() == 0)
|
---|
[93578] | 218 | return mName;
|
---|
[93579] | 219 |
|
---|
| 220 | r_strName = mName;
|
---|
| 221 | bool fFirst = true;
|
---|
| 222 | if (mVersion.isNotEmpty())
|
---|
| 223 | {
|
---|
| 224 | r_strName.appendPrintf(fFirst ? " (%s" : " / %s", mVersion.c_str());
|
---|
| 225 | fFirst = false;
|
---|
| 226 | }
|
---|
| 227 | if (mArch.isNotEmpty())
|
---|
| 228 | {
|
---|
| 229 | r_strName.appendPrintf(fFirst ? " (%s" : " / %s", mArch.c_str());
|
---|
| 230 | fFirst = false;
|
---|
| 231 | }
|
---|
[93581] | 232 | if (mDefaultLanguage.isNotEmpty())
|
---|
| 233 | {
|
---|
| 234 | r_strName.appendPrintf(fFirst ? " (%s" : " / %s", mDefaultLanguage.c_str());
|
---|
| 235 | fFirst = false;
|
---|
| 236 | }
|
---|
| 237 | else
|
---|
| 238 | for (size_t i = 0; i < mLanguages.size(); i++)
|
---|
| 239 | {
|
---|
| 240 | r_strName.appendPrintf(fFirst ? " (%s" : " / %s", mLanguages[i].c_str());
|
---|
| 241 | fFirst = false;
|
---|
| 242 | }
|
---|
[93579] | 243 | r_strName.append(")");
|
---|
| 244 | return r_strName;
|
---|
[93525] | 245 | }
|
---|
[93082] | 246 |
|
---|
[93575] | 247 |
|
---|
[68162] | 248 | //////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
| 249 | /*
|
---|
| 250 | *
|
---|
| 251 | *
|
---|
| 252 | * Implementation Unattended functions
|
---|
| 253 | *
|
---|
| 254 | */
|
---|
| 255 | //////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
| 256 |
|
---|
| 257 | Unattended::Unattended()
|
---|
[68170] | 258 | : mhThreadReconfigureVM(NIL_RTNATIVETHREAD), mfRtcUseUtc(false), mfGuestOs64Bit(false)
|
---|
[68239] | 259 | , mpInstaller(NULL), mpTimeZoneInfo(NULL), mfIsDefaultAuxiliaryBasePath(true), mfDoneDetectIsoOS(false)
|
---|
[94533] | 260 | , mfAvoidUpdatesOverNetwork(false)
|
---|
[68162] | 261 | { }
|
---|
| 262 |
|
---|
| 263 | Unattended::~Unattended()
|
---|
| 264 | {
|
---|
| 265 | if (mpInstaller)
|
---|
| 266 | {
|
---|
| 267 | delete mpInstaller;
|
---|
| 268 | mpInstaller = NULL;
|
---|
| 269 | }
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | HRESULT Unattended::FinalConstruct()
|
---|
| 273 | {
|
---|
| 274 | return BaseFinalConstruct();
|
---|
| 275 | }
|
---|
| 276 |
|
---|
| 277 | void Unattended::FinalRelease()
|
---|
| 278 | {
|
---|
| 279 | uninit();
|
---|
| 280 |
|
---|
| 281 | BaseFinalRelease();
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 | void Unattended::uninit()
|
---|
| 285 | {
|
---|
| 286 | /* Enclose the state transition Ready->InUninit->NotReady */
|
---|
| 287 | AutoUninitSpan autoUninitSpan(this);
|
---|
| 288 | if (autoUninitSpan.uninitDone())
|
---|
| 289 | return;
|
---|
| 290 |
|
---|
| 291 | unconst(mParent) = NULL;
|
---|
| 292 | mMachine.setNull();
|
---|
| 293 | }
|
---|
| 294 |
|
---|
| 295 | /**
|
---|
| 296 | * Initializes the unattended object.
|
---|
| 297 | *
|
---|
| 298 | * @param aParent Pointer to the parent object.
|
---|
| 299 | */
|
---|
| 300 | HRESULT Unattended::initUnattended(VirtualBox *aParent)
|
---|
| 301 | {
|
---|
| 302 | LogFlowThisFunc(("aParent=%p\n", aParent));
|
---|
| 303 | ComAssertRet(aParent, E_INVALIDARG);
|
---|
| 304 |
|
---|
| 305 | /* Enclose the state transition NotReady->InInit->Ready */
|
---|
| 306 | AutoInitSpan autoInitSpan(this);
|
---|
| 307 | AssertReturn(autoInitSpan.isOk(), E_FAIL);
|
---|
| 308 |
|
---|
| 309 | unconst(mParent) = aParent;
|
---|
| 310 |
|
---|
| 311 | /*
|
---|
| 312 | * Fill public attributes (IUnattended) with useful defaults.
|
---|
| 313 | */
|
---|
| 314 | try
|
---|
| 315 | {
|
---|
| 316 | mStrUser = "vboxuser";
|
---|
| 317 | mStrPassword = "changeme";
|
---|
| 318 | mfInstallGuestAdditions = false;
|
---|
| 319 | mfInstallTestExecService = false;
|
---|
| 320 | midxImage = 1;
|
---|
| 321 |
|
---|
| 322 | HRESULT hrc = mParent->i_getSystemProperties()->i_getDefaultAdditionsISO(mStrAdditionsIsoPath);
|
---|
| 323 | ComAssertComRCRet(hrc, hrc);
|
---|
| 324 | }
|
---|
[73505] | 325 | catch (std::bad_alloc &)
|
---|
[68162] | 326 | {
|
---|
| 327 | return E_OUTOFMEMORY;
|
---|
| 328 | }
|
---|
| 329 |
|
---|
| 330 | /*
|
---|
| 331 | * Confirm a successful initialization
|
---|
| 332 | */
|
---|
| 333 | autoInitSpan.setSucceeded();
|
---|
| 334 |
|
---|
| 335 | return S_OK;
|
---|
| 336 | }
|
---|
| 337 |
|
---|
| 338 | HRESULT Unattended::detectIsoOS()
|
---|
| 339 | {
|
---|
[68318] | 340 | HRESULT hrc;
|
---|
[68239] | 341 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 342 |
|
---|
[68318] | 343 | /** @todo once UDF is implemented properly and we've tested this code a lot
|
---|
| 344 | * more, replace E_NOTIMPL with E_FAIL. */
|
---|
| 345 |
|
---|
[93575] | 346 | /*
|
---|
| 347 | * Reset output state before we start
|
---|
| 348 | */
|
---|
| 349 | mStrDetectedOSTypeId.setNull();
|
---|
| 350 | mStrDetectedOSVersion.setNull();
|
---|
| 351 | mStrDetectedOSFlavor.setNull();
|
---|
| 352 | mDetectedOSLanguages.clear();
|
---|
| 353 | mStrDetectedOSHints.setNull();
|
---|
| 354 | mDetectedImages.clear();
|
---|
[68318] | 355 |
|
---|
[68239] | 356 | /*
|
---|
[68318] | 357 | * Open the ISO.
|
---|
| 358 | */
|
---|
| 359 | RTVFSFILE hVfsFileIso;
|
---|
| 360 | int vrc = RTVfsFileOpenNormal(mStrIsoPath.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsFileIso);
|
---|
| 361 | if (RT_FAILURE(vrc))
|
---|
| 362 | return setErrorBoth(E_NOTIMPL, vrc, tr("Failed to open '%s' (%Rrc)"), mStrIsoPath.c_str(), vrc);
|
---|
| 363 |
|
---|
| 364 | RTERRINFOSTATIC ErrInfo;
|
---|
| 365 | RTVFS hVfsIso;
|
---|
| 366 | vrc = RTFsIso9660VolOpen(hVfsFileIso, 0 /*fFlags*/, &hVfsIso, RTErrInfoInitStatic(&ErrInfo));
|
---|
| 367 | if (RT_SUCCESS(vrc))
|
---|
| 368 | {
|
---|
| 369 | /*
|
---|
| 370 | * Try do the detection. Repeat for different file system variations (nojoliet, noudf).
|
---|
| 371 | */
|
---|
| 372 | hrc = i_innerDetectIsoOS(hVfsIso);
|
---|
| 373 |
|
---|
| 374 | RTVfsRelease(hVfsIso);
|
---|
[93585] | 375 | if (hrc == S_FALSE) /** @todo Finish the linux and windows detection code. Only OS/2 returns S_OK right now. */
|
---|
[93157] | 376 | hrc = E_NOTIMPL;
|
---|
[68318] | 377 | }
|
---|
| 378 | else if (RTErrInfoIsSet(&ErrInfo.Core))
|
---|
| 379 | hrc = setErrorBoth(E_NOTIMPL, vrc, tr("Failed to open '%s' as ISO FS (%Rrc) - %s"),
|
---|
| 380 | mStrIsoPath.c_str(), vrc, ErrInfo.Core.pszMsg);
|
---|
| 381 | else
|
---|
| 382 | hrc = setErrorBoth(E_NOTIMPL, vrc, tr("Failed to open '%s' as ISO FS (%Rrc)"), mStrIsoPath.c_str(), vrc);
|
---|
| 383 | RTVfsFileRelease(hVfsFileIso);
|
---|
| 384 |
|
---|
| 385 | /*
|
---|
[68239] | 386 | * Just fake up some windows installation media locale (for <UILanguage>).
|
---|
| 387 | * Note! The translation here isn't perfect. Feel free to send us a patch.
|
---|
| 388 | */
|
---|
[69063] | 389 | if (mDetectedOSLanguages.size() == 0)
|
---|
[68239] | 390 | {
|
---|
[69063] | 391 | char szTmp[16];
|
---|
| 392 | const char *pszFilename = RTPathFilename(mStrIsoPath.c_str());
|
---|
| 393 | if ( pszFilename
|
---|
| 394 | && RT_C_IS_ALPHA(pszFilename[0])
|
---|
| 395 | && RT_C_IS_ALPHA(pszFilename[1])
|
---|
| 396 | && (pszFilename[2] == '-' || pszFilename[2] == '_') )
|
---|
| 397 | {
|
---|
| 398 | szTmp[0] = (char)RT_C_TO_LOWER(pszFilename[0]);
|
---|
| 399 | szTmp[1] = (char)RT_C_TO_LOWER(pszFilename[1]);
|
---|
| 400 | szTmp[2] = '-';
|
---|
| 401 | if (szTmp[0] == 'e' && szTmp[1] == 'n')
|
---|
| 402 | strcpy(&szTmp[3], "US");
|
---|
| 403 | else if (szTmp[0] == 'a' && szTmp[1] == 'r')
|
---|
| 404 | strcpy(&szTmp[3], "SA");
|
---|
| 405 | else if (szTmp[0] == 'd' && szTmp[1] == 'a')
|
---|
| 406 | strcpy(&szTmp[3], "DK");
|
---|
| 407 | else if (szTmp[0] == 'e' && szTmp[1] == 't')
|
---|
| 408 | strcpy(&szTmp[3], "EE");
|
---|
| 409 | else if (szTmp[0] == 'e' && szTmp[1] == 'l')
|
---|
| 410 | strcpy(&szTmp[3], "GR");
|
---|
| 411 | else if (szTmp[0] == 'h' && szTmp[1] == 'e')
|
---|
| 412 | strcpy(&szTmp[3], "IL");
|
---|
| 413 | else if (szTmp[0] == 'j' && szTmp[1] == 'a')
|
---|
| 414 | strcpy(&szTmp[3], "JP");
|
---|
| 415 | else if (szTmp[0] == 's' && szTmp[1] == 'v')
|
---|
| 416 | strcpy(&szTmp[3], "SE");
|
---|
| 417 | else if (szTmp[0] == 'u' && szTmp[1] == 'k')
|
---|
| 418 | strcpy(&szTmp[3], "UA");
|
---|
| 419 | else if (szTmp[0] == 'c' && szTmp[1] == 's')
|
---|
| 420 | strcpy(szTmp, "cs-CZ");
|
---|
| 421 | else if (szTmp[0] == 'n' && szTmp[1] == 'o')
|
---|
| 422 | strcpy(szTmp, "nb-NO");
|
---|
| 423 | else if (szTmp[0] == 'p' && szTmp[1] == 'p')
|
---|
| 424 | strcpy(szTmp, "pt-PT");
|
---|
| 425 | else if (szTmp[0] == 'p' && szTmp[1] == 't')
|
---|
| 426 | strcpy(szTmp, "pt-BR");
|
---|
| 427 | else if (szTmp[0] == 'c' && szTmp[1] == 'n')
|
---|
| 428 | strcpy(szTmp, "zh-CN");
|
---|
| 429 | else if (szTmp[0] == 'h' && szTmp[1] == 'k')
|
---|
| 430 | strcpy(szTmp, "zh-HK");
|
---|
| 431 | else if (szTmp[0] == 't' && szTmp[1] == 'w')
|
---|
| 432 | strcpy(szTmp, "zh-TW");
|
---|
| 433 | else if (szTmp[0] == 's' && szTmp[1] == 'r')
|
---|
| 434 | strcpy(szTmp, "sr-Latn-CS"); /* hmm */
|
---|
| 435 | else
|
---|
| 436 | {
|
---|
| 437 | szTmp[3] = (char)RT_C_TO_UPPER(pszFilename[0]);
|
---|
| 438 | szTmp[4] = (char)RT_C_TO_UPPER(pszFilename[1]);
|
---|
| 439 | szTmp[5] = '\0';
|
---|
| 440 | }
|
---|
| 441 | }
|
---|
[68239] | 442 | else
|
---|
[69063] | 443 | strcpy(szTmp, "en-US");
|
---|
| 444 | try
|
---|
[68239] | 445 | {
|
---|
[69063] | 446 | mDetectedOSLanguages.append(szTmp);
|
---|
[68239] | 447 | }
|
---|
[73505] | 448 | catch (std::bad_alloc &)
|
---|
[69063] | 449 | {
|
---|
| 450 | return E_OUTOFMEMORY;
|
---|
| 451 | }
|
---|
[68239] | 452 | }
|
---|
| 453 |
|
---|
| 454 | /** @todo implement actual detection logic. */
|
---|
[68318] | 455 | return hrc;
|
---|
[68162] | 456 | }
|
---|
| 457 |
|
---|
[68318] | 458 | HRESULT Unattended::i_innerDetectIsoOS(RTVFS hVfsIso)
|
---|
| 459 | {
|
---|
[70999] | 460 | DETECTBUFFER uBuf;
|
---|
[94079] | 461 | mEnmOsType = VBOXOSTYPE_Unknown;
|
---|
| 462 | HRESULT hrc = i_innerDetectIsoOSWindows(hVfsIso, &uBuf);
|
---|
| 463 | if (hrc == S_FALSE && mEnmOsType == VBOXOSTYPE_Unknown)
|
---|
| 464 | hrc = i_innerDetectIsoOSLinux(hVfsIso, &uBuf);
|
---|
| 465 | if (hrc == S_FALSE && mEnmOsType == VBOXOSTYPE_Unknown)
|
---|
| 466 | hrc = i_innerDetectIsoOSOs2(hVfsIso, &uBuf);
|
---|
[95436] | 467 | if (hrc == S_FALSE && mEnmOsType == VBOXOSTYPE_Unknown)
|
---|
| 468 | hrc = i_innerDetectIsoOSFreeBsd(hVfsIso, &uBuf);
|
---|
[94079] | 469 | if (mEnmOsType != VBOXOSTYPE_Unknown)
|
---|
[93458] | 470 | {
|
---|
[94079] | 471 | try { mStrDetectedOSTypeId = Global::OSTypeId(mEnmOsType); }
|
---|
[93458] | 472 | catch (std::bad_alloc &) { hrc = E_OUTOFMEMORY; }
|
---|
| 473 | }
|
---|
[70999] | 474 | return hrc;
|
---|
| 475 | }
|
---|
[68318] | 476 |
|
---|
[70999] | 477 | /**
|
---|
[93581] | 478 | * Tries to parse a LANGUAGES element, with the following structure.
|
---|
| 479 | * @verbatim
|
---|
| 480 | * <LANGUAGES>
|
---|
| 481 | * <LANGUAGE>
|
---|
| 482 | * en-US
|
---|
| 483 | * </LANGUAGE>
|
---|
| 484 | * <DEFAULT>
|
---|
| 485 | * en-US
|
---|
| 486 | * </DEFAULT>
|
---|
| 487 | * </LANGUAGES>
|
---|
| 488 | * @endverbatim
|
---|
| 489 | *
|
---|
| 490 | * Will set mLanguages and mDefaultLanguage success.
|
---|
| 491 | *
|
---|
| 492 | * @param pElmLanguages Points to the LANGUAGES XML node.
|
---|
| 493 | * @param rImage Out reference to an WIMImage instance.
|
---|
| 494 | */
|
---|
| 495 | static void parseLangaguesElement(const xml::ElementNode *pElmLanguages, WIMImage &rImage)
|
---|
| 496 | {
|
---|
| 497 | /*
|
---|
| 498 | * The languages.
|
---|
| 499 | */
|
---|
| 500 | ElementNodesList children;
|
---|
| 501 | int cChildren = pElmLanguages->getChildElements(children, "LANGUAGE");
|
---|
| 502 | if (cChildren == 0)
|
---|
| 503 | cChildren = pElmLanguages->getChildElements(children, "language");
|
---|
| 504 | if (cChildren == 0)
|
---|
| 505 | cChildren = pElmLanguages->getChildElements(children, "Language");
|
---|
| 506 | for (ElementNodesList::iterator iterator = children.begin(); iterator != children.end(); ++iterator)
|
---|
| 507 | {
|
---|
| 508 | const ElementNode * const pElmLanguage = *(iterator);
|
---|
| 509 | if (pElmLanguage)
|
---|
| 510 | {
|
---|
| 511 | const char *pszValue = pElmLanguage->getValue();
|
---|
| 512 | if (pszValue && *pszValue != '\0')
|
---|
| 513 | rImage.mLanguages.append(pszValue);
|
---|
| 514 | }
|
---|
| 515 | }
|
---|
| 516 |
|
---|
| 517 | /*
|
---|
| 518 | * Default language.
|
---|
| 519 | */
|
---|
| 520 | const xml::ElementNode *pElmDefault;
|
---|
| 521 | if ( (pElmDefault = pElmLanguages->findChildElement("DEFAULT")) != NULL
|
---|
| 522 | || (pElmDefault = pElmLanguages->findChildElement("default")) != NULL
|
---|
| 523 | || (pElmDefault = pElmLanguages->findChildElement("Default")) != NULL)
|
---|
| 524 | rImage.mDefaultLanguage = pElmDefault->getValue();
|
---|
| 525 | }
|
---|
| 526 |
|
---|
| 527 |
|
---|
| 528 | /**
|
---|
[93580] | 529 | * Tries to set the image architecture.
|
---|
| 530 | *
|
---|
| 531 | * Input examples (x86 and amd64 respectively):
|
---|
| 532 | * @verbatim
|
---|
| 533 | * <ARCH>0</ARCH>
|
---|
| 534 | * <ARCH>9</ARCH>
|
---|
| 535 | * @endverbatim
|
---|
| 536 | *
|
---|
| 537 | * Will set mArch and update mOSType on success.
|
---|
| 538 | *
|
---|
[93581] | 539 | * @param pElmArch Points to the ARCH XML node.
|
---|
[93580] | 540 | * @param rImage Out reference to an WIMImage instance.
|
---|
| 541 | */
|
---|
| 542 | static void parseArchElement(const xml::ElementNode *pElmArch, WIMImage &rImage)
|
---|
| 543 | {
|
---|
| 544 | /* These are from winnt.h */
|
---|
| 545 | static struct { const char *pszArch; VBOXOSTYPE enmArch; } s_aArches[] =
|
---|
| 546 | {
|
---|
| 547 | /* PROCESSOR_ARCHITECTURE_INTEL / [0] = */ { "x86", VBOXOSTYPE_x86 },
|
---|
| 548 | /* PROCESSOR_ARCHITECTURE_MIPS / [1] = */ { "mips", VBOXOSTYPE_UnknownArch },
|
---|
| 549 | /* PROCESSOR_ARCHITECTURE_ALPHA / [2] = */ { "alpha", VBOXOSTYPE_UnknownArch },
|
---|
| 550 | /* PROCESSOR_ARCHITECTURE_PPC / [3] = */ { "ppc", VBOXOSTYPE_UnknownArch },
|
---|
| 551 | /* PROCESSOR_ARCHITECTURE_SHX / [4] = */ { "shx", VBOXOSTYPE_UnknownArch },
|
---|
| 552 | /* PROCESSOR_ARCHITECTURE_ARM / [5] = */ { "arm32", VBOXOSTYPE_arm32 },
|
---|
| 553 | /* PROCESSOR_ARCHITECTURE_IA64 / [6] = */ { "ia64", VBOXOSTYPE_UnknownArch },
|
---|
| 554 | /* PROCESSOR_ARCHITECTURE_ALPHA64 / [7] = */ { "alpha64", VBOXOSTYPE_UnknownArch },
|
---|
| 555 | /* PROCESSOR_ARCHITECTURE_MSIL / [8] = */ { "msil", VBOXOSTYPE_UnknownArch },
|
---|
| 556 | /* PROCESSOR_ARCHITECTURE_AMD64 / [9] = */ { "x64", VBOXOSTYPE_x64 },
|
---|
| 557 | /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 / [10] = */ { "x86-on-x64", VBOXOSTYPE_UnknownArch },
|
---|
| 558 | /* PROCESSOR_ARCHITECTURE_NEUTRAL / [11] = */ { "noarch", VBOXOSTYPE_UnknownArch },
|
---|
| 559 | /* PROCESSOR_ARCHITECTURE_ARM64 / [12] = */ { "arm64", VBOXOSTYPE_arm64 },
|
---|
| 560 | /* PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64/ [13] = */ { "arm32-on-arm64", VBOXOSTYPE_UnknownArch },
|
---|
| 561 | /* PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 / [14] = */ { "x86-on-arm32", VBOXOSTYPE_UnknownArch },
|
---|
| 562 | };
|
---|
| 563 | const char *pszArch = pElmArch->getValue();
|
---|
| 564 | if (pszArch && *pszArch)
|
---|
| 565 | {
|
---|
| 566 | uint32_t uArch;
|
---|
| 567 | int vrc = RTStrToUInt32Ex(pszArch, NULL, 10 /*uBase*/, &uArch);
|
---|
| 568 | if ( RT_SUCCESS(vrc)
|
---|
| 569 | && vrc != VWRN_NUMBER_TOO_BIG
|
---|
| 570 | && vrc != VWRN_NEGATIVE_UNSIGNED
|
---|
| 571 | && uArch < RT_ELEMENTS(s_aArches))
|
---|
| 572 | {
|
---|
| 573 | rImage.mArch = s_aArches[uArch].pszArch;
|
---|
[93584] | 574 | rImage.mOSType = (VBOXOSTYPE)(s_aArches[uArch].enmArch | (rImage.mOSType & VBOXOSTYPE_OsTypeMask));
|
---|
[93580] | 575 | }
|
---|
| 576 | else
|
---|
| 577 | LogRel(("Unattended: bogus ARCH element value: '%s'\n", pszArch));
|
---|
| 578 | }
|
---|
| 579 | }
|
---|
| 580 |
|
---|
| 581 | /**
|
---|
[93521] | 582 | * Parses XML Node assuming a structure as follows
|
---|
[93526] | 583 | * @verbatim
|
---|
[93521] | 584 | * <VERSION>
|
---|
| 585 | * <MAJOR>10</MAJOR>
|
---|
| 586 | * <MINOR>0</MINOR>
|
---|
| 587 | * <BUILD>19041</BUILD>
|
---|
[93575] | 588 | * <SPBUILD>1</SPBUILD>
|
---|
[93521] | 589 | * </VERSION>
|
---|
[93526] | 590 | * @endverbatim
|
---|
[93580] | 591 | *
|
---|
[94079] | 592 | * Will update mOSType, mEnmOsType as well as setting mVersion on success.
|
---|
[93580] | 593 | *
|
---|
[93521] | 594 | * @param pNode Points to the vesion XML node,
|
---|
| 595 | * @param image Out reference to an WIMImage instance.
|
---|
| 596 | */
|
---|
| 597 | static void parseVersionElement(const xml::ElementNode *pNode, WIMImage &image)
|
---|
| 598 | {
|
---|
[93575] | 599 | /* Major part: */
|
---|
[93580] | 600 | const xml::ElementNode *pElmMajor;
|
---|
| 601 | if ( (pElmMajor = pNode->findChildElement("MAJOR")) != NULL
|
---|
| 602 | || (pElmMajor = pNode->findChildElement("major")) != NULL
|
---|
| 603 | || (pElmMajor = pNode->findChildElement("Major")) != NULL)
|
---|
| 604 | if (pElmMajor)
|
---|
[93575] | 605 | {
|
---|
[93580] | 606 | const char * const pszMajor = pElmMajor->getValue();
|
---|
[93575] | 607 | if (pszMajor && *pszMajor)
|
---|
| 608 | {
|
---|
| 609 | /* Minor part: */
|
---|
[93580] | 610 | const ElementNode *pElmMinor;
|
---|
| 611 | if ( (pElmMinor = pNode->findChildElement("MINOR")) != NULL
|
---|
| 612 | || (pElmMinor = pNode->findChildElement("minor")) != NULL
|
---|
| 613 | || (pElmMinor = pNode->findChildElement("Minor")) != NULL)
|
---|
[93575] | 614 | {
|
---|
[93580] | 615 | const char * const pszMinor = pElmMinor->getValue();
|
---|
[93575] | 616 | if (pszMinor && *pszMinor)
|
---|
| 617 | {
|
---|
| 618 | /* Build: */
|
---|
[93580] | 619 | const ElementNode *pElmBuild;
|
---|
| 620 | if ( (pElmBuild = pNode->findChildElement("BUILD")) != NULL
|
---|
| 621 | || (pElmBuild = pNode->findChildElement("build")) != NULL
|
---|
| 622 | || (pElmBuild = pNode->findChildElement("Build")) != NULL)
|
---|
[93575] | 623 | {
|
---|
[93580] | 624 | const char * const pszBuild = pElmBuild->getValue();
|
---|
[93575] | 625 | if (pszBuild && *pszBuild)
|
---|
| 626 | {
|
---|
| 627 | /* SPBuild: */
|
---|
[93580] | 628 | const ElementNode *pElmSpBuild;
|
---|
| 629 | if ( ( (pElmSpBuild = pNode->findChildElement("SPBUILD")) != NULL
|
---|
| 630 | || (pElmSpBuild = pNode->findChildElement("spbuild")) != NULL
|
---|
| 631 | || (pElmSpBuild = pNode->findChildElement("Spbuild")) != NULL
|
---|
| 632 | || (pElmSpBuild = pNode->findChildElement("SpBuild")) != NULL)
|
---|
| 633 | && pElmSpBuild->getValue()
|
---|
| 634 | && *pElmSpBuild->getValue() != '\0')
|
---|
| 635 | image.mVersion.printf("%s.%s.%s.%s", pszMajor, pszMinor, pszBuild, pElmSpBuild->getValue());
|
---|
[93575] | 636 | else
|
---|
| 637 | image.mVersion.printf("%s.%s.%s", pszMajor, pszMinor, pszBuild);
|
---|
[93580] | 638 |
|
---|
| 639 | /*
|
---|
| 640 | * Convert that to a version windows OS ID (newest first!).
|
---|
| 641 | */
|
---|
[94079] | 642 | image.mEnmOsType = VBOXOSTYPE_Unknown;
|
---|
[93580] | 643 | if (RTStrVersionCompare(image.mVersion.c_str(), "10.0.22000.0") >= 0)
|
---|
[94079] | 644 | image.mEnmOsType = VBOXOSTYPE_Win11_x64;
|
---|
[93580] | 645 | else if (RTStrVersionCompare(image.mVersion.c_str(), "10.0") >= 0)
|
---|
[94079] | 646 | image.mEnmOsType = VBOXOSTYPE_Win10;
|
---|
[93580] | 647 | else if (RTStrVersionCompare(image.mVersion.c_str(), "6.3") >= 0)
|
---|
[94079] | 648 | image.mEnmOsType = VBOXOSTYPE_Win81;
|
---|
[93580] | 649 | else if (RTStrVersionCompare(image.mVersion.c_str(), "6.2") >= 0)
|
---|
[94079] | 650 | image.mEnmOsType = VBOXOSTYPE_Win8;
|
---|
[93580] | 651 | else if (RTStrVersionCompare(image.mVersion.c_str(), "6.1") >= 0)
|
---|
[94079] | 652 | image.mEnmOsType = VBOXOSTYPE_Win7;
|
---|
[93580] | 653 | else if (RTStrVersionCompare(image.mVersion.c_str(), "6.0") >= 0)
|
---|
[94079] | 654 | image.mEnmOsType = VBOXOSTYPE_WinVista;
|
---|
[93589] | 655 | if (image.mFlavor.contains("server", Utf8Str::CaseInsensitive))
|
---|
| 656 | {
|
---|
| 657 | if (RTStrVersionCompare(image.mVersion.c_str(), "10.0.20348") >= 0)
|
---|
[94079] | 658 | image.mEnmOsType = VBOXOSTYPE_Win2k22_x64;
|
---|
[93589] | 659 | else if (RTStrVersionCompare(image.mVersion.c_str(), "10.0.17763") >= 0)
|
---|
[94079] | 660 | image.mEnmOsType = VBOXOSTYPE_Win2k19_x64;
|
---|
[93589] | 661 | else if (RTStrVersionCompare(image.mVersion.c_str(), "10.0") >= 0)
|
---|
[94079] | 662 | image.mEnmOsType = VBOXOSTYPE_Win2k16_x64;
|
---|
[93589] | 663 | else if (RTStrVersionCompare(image.mVersion.c_str(), "6.2") >= 0)
|
---|
[94079] | 664 | image.mEnmOsType = VBOXOSTYPE_Win2k12_x64;
|
---|
[93589] | 665 | else if (RTStrVersionCompare(image.mVersion.c_str(), "6.0") >= 0)
|
---|
[94079] | 666 | image.mEnmOsType = VBOXOSTYPE_Win2k8;
|
---|
[93589] | 667 | }
|
---|
[94079] | 668 | if (image.mEnmOsType != VBOXOSTYPE_Unknown)
|
---|
[93580] | 669 | image.mOSType = (VBOXOSTYPE)( (image.mOSType & VBOXOSTYPE_ArchitectureMask)
|
---|
[94079] | 670 | | (image.mEnmOsType & VBOXOSTYPE_OsTypeMask));
|
---|
[93580] | 671 | return;
|
---|
[93575] | 672 | }
|
---|
| 673 | }
|
---|
| 674 | }
|
---|
| 675 | }
|
---|
| 676 | }
|
---|
| 677 | }
|
---|
[93580] | 678 | Log(("Unattended: Warning! Bogus/missing version info for image #%u / %s\n", image.mImageIndex, image.mName.c_str()));
|
---|
[93521] | 679 | }
|
---|
| 680 |
|
---|
| 681 | /**
|
---|
| 682 | * Parses XML tree assuming th following structure
|
---|
[93526] | 683 | * @verbatim
|
---|
[93521] | 684 | * <WIM>
|
---|
[93575] | 685 | * ...
|
---|
[93521] | 686 | * <IMAGE INDEX="1">
|
---|
[93575] | 687 | * ...
|
---|
| 688 | * <DISPLAYNAME>Windows 10 Home</DISPLAYNAME>
|
---|
| 689 | * <WINDOWS>
|
---|
[93577] | 690 | * <ARCH>NN</ARCH>
|
---|
[93575] | 691 | * <VERSION>
|
---|
| 692 | * ...
|
---|
| 693 | * </VERSION>
|
---|
[93580] | 694 | * <LANGUAGES>
|
---|
| 695 | * <LANGUAGE>
|
---|
| 696 | * en-US
|
---|
| 697 | * </LANGUAGE>
|
---|
| 698 | * <DEFAULT>
|
---|
| 699 | * en-US
|
---|
| 700 | * </DEFAULT>
|
---|
| 701 | * </LANGUAGES>
|
---|
[93575] | 702 | * </WINDOWS>
|
---|
[93521] | 703 | * </IMAGE>
|
---|
| 704 | * </WIM>
|
---|
[93526] | 705 | * @endverbatim
|
---|
[93521] | 706 | *
|
---|
| 707 | * @param pElmRoot Pointer to the root node of the tree,
|
---|
| 708 | * @param imageList Detected images are appended to this list.
|
---|
| 709 | */
|
---|
| 710 | static void parseWimXMLData(const xml::ElementNode *pElmRoot, RTCList<WIMImage> &imageList)
|
---|
| 711 | {
|
---|
| 712 | if (!pElmRoot)
|
---|
| 713 | return;
|
---|
| 714 |
|
---|
| 715 | ElementNodesList children;
|
---|
| 716 | int cChildren = pElmRoot->getChildElements(children, "IMAGE");
|
---|
| 717 | if (cChildren == 0)
|
---|
| 718 | cChildren = pElmRoot->getChildElements(children, "image");
|
---|
[93579] | 719 | if (cChildren == 0)
|
---|
| 720 | cChildren = pElmRoot->getChildElements(children, "Image");
|
---|
[93521] | 721 |
|
---|
| 722 | for (ElementNodesList::iterator iterator = children.begin(); iterator != children.end(); ++iterator)
|
---|
| 723 | {
|
---|
| 724 | const ElementNode *pChild = *(iterator);
|
---|
| 725 | if (!pChild)
|
---|
| 726 | continue;
|
---|
[93533] | 727 |
|
---|
[93575] | 728 | WIMImage newImage;
|
---|
[93533] | 729 |
|
---|
[93575] | 730 | if ( !pChild->getAttributeValue("INDEX", &newImage.mImageIndex)
|
---|
| 731 | && !pChild->getAttributeValue("index", &newImage.mImageIndex)
|
---|
| 732 | && !pChild->getAttributeValue("Index", &newImage.mImageIndex))
|
---|
[93533] | 733 | continue;
|
---|
| 734 |
|
---|
[93580] | 735 | const ElementNode *pElmName;
|
---|
| 736 | if ( (pElmName = pChild->findChildElement("DISPLAYNAME")) == NULL
|
---|
| 737 | && (pElmName = pChild->findChildElement("displayname")) == NULL
|
---|
| 738 | && (pElmName = pChild->findChildElement("Displayname")) == NULL
|
---|
| 739 | && (pElmName = pChild->findChildElement("DisplayName")) == NULL
|
---|
| 740 | /* Early vista images didn't have DISPLAYNAME. */
|
---|
| 741 | && (pElmName = pChild->findChildElement("NAME")) == NULL
|
---|
| 742 | && (pElmName = pChild->findChildElement("name")) == NULL
|
---|
| 743 | && (pElmName = pChild->findChildElement("Name")) == NULL)
|
---|
[93521] | 744 | continue;
|
---|
[93580] | 745 | newImage.mName = pElmName->getValue();
|
---|
[93525] | 746 | if (newImage.mName.isEmpty())
|
---|
| 747 | continue;
|
---|
[93534] | 748 |
|
---|
[93580] | 749 | const ElementNode *pElmWindows;
|
---|
| 750 | if ( (pElmWindows = pChild->findChildElement("WINDOWS")) != NULL
|
---|
| 751 | || (pElmWindows = pChild->findChildElement("windows")) != NULL
|
---|
| 752 | || (pElmWindows = pChild->findChildElement("Windows")) != NULL)
|
---|
[93575] | 753 | {
|
---|
[93587] | 754 | /* Do edition/flags before the version so it can better determin
|
---|
| 755 | the OS version enum value. Old windows version (vista) typically
|
---|
| 756 | doesn't have an EDITIONID element, so fall back on the FLAGS element
|
---|
| 757 | under IMAGE as it is pretty similar (case differences). */
|
---|
| 758 | const ElementNode *pElmEditionId;
|
---|
| 759 | if ( (pElmEditionId = pElmWindows->findChildElement("EDITIONID")) != NULL
|
---|
| 760 | || (pElmEditionId = pElmWindows->findChildElement("editionid")) != NULL
|
---|
| 761 | || (pElmEditionId = pElmWindows->findChildElement("Editionid")) != NULL
|
---|
| 762 | || (pElmEditionId = pElmWindows->findChildElement("EditionId")) != NULL
|
---|
| 763 | || (pElmEditionId = pChild->findChildElement("FLAGS")) != NULL
|
---|
| 764 | || (pElmEditionId = pChild->findChildElement("flags")) != NULL
|
---|
| 765 | || (pElmEditionId = pChild->findChildElement("Flags")) != NULL)
|
---|
| 766 | if ( pElmEditionId->getValue()
|
---|
| 767 | && *pElmEditionId->getValue() != '\0')
|
---|
| 768 | newImage.mFlavor = pElmEditionId->getValue();
|
---|
| 769 |
|
---|
[93580] | 770 | const ElementNode *pElmVersion;
|
---|
| 771 | if ( (pElmVersion = pElmWindows->findChildElement("VERSION")) != NULL
|
---|
| 772 | || (pElmVersion = pElmWindows->findChildElement("version")) != NULL
|
---|
| 773 | || (pElmVersion = pElmWindows->findChildElement("Version")) != NULL)
|
---|
| 774 | parseVersionElement(pElmVersion, newImage);
|
---|
[93577] | 775 |
|
---|
| 776 | /* The ARCH element contains a number from the
|
---|
| 777 | PROCESSOR_ARCHITECTURE_XXX set of defines in winnt.h: */
|
---|
[93580] | 778 | const ElementNode *pElmArch;
|
---|
| 779 | if ( (pElmArch = pElmWindows->findChildElement("ARCH")) != NULL
|
---|
| 780 | || (pElmArch = pElmWindows->findChildElement("arch")) != NULL
|
---|
| 781 | || (pElmArch = pElmWindows->findChildElement("Arch")) != NULL)
|
---|
| 782 | parseArchElement(pElmArch, newImage);
|
---|
[93581] | 783 |
|
---|
| 784 | /* Extract languages and default language: */
|
---|
| 785 | const ElementNode *pElmLang;
|
---|
| 786 | if ( (pElmLang = pElmWindows->findChildElement("LANGUAGES")) != NULL
|
---|
| 787 | || (pElmLang = pElmWindows->findChildElement("languages")) != NULL
|
---|
| 788 | || (pElmLang = pElmWindows->findChildElement("Languages")) != NULL)
|
---|
| 789 | parseLangaguesElement(pElmLang, newImage);
|
---|
[93575] | 790 | }
|
---|
| 791 |
|
---|
[93587] | 792 |
|
---|
[93521] | 793 | imageList.append(newImage);
|
---|
| 794 | }
|
---|
| 795 | }
|
---|
| 796 |
|
---|
| 797 | /**
|
---|
[70999] | 798 | * Detect Windows ISOs.
|
---|
| 799 | *
|
---|
| 800 | * @returns COM status code.
|
---|
| 801 | * @retval S_OK if detected
|
---|
| 802 | * @retval S_FALSE if not fully detected.
|
---|
| 803 | *
|
---|
| 804 | * @param hVfsIso The ISO file system.
|
---|
| 805 | * @param pBuf Read buffer.
|
---|
| 806 | */
|
---|
[94079] | 807 | HRESULT Unattended::i_innerDetectIsoOSWindows(RTVFS hVfsIso, DETECTBUFFER *pBuf)
|
---|
[70999] | 808 | {
|
---|
[69063] | 809 | /** @todo The 'sources/' path can differ. */
|
---|
| 810 |
|
---|
[68318] | 811 | // globalinstallorder.xml - vista beta2
|
---|
| 812 | // sources/idwbinfo.txt - ditto.
|
---|
| 813 | // sources/lang.ini - ditto.
|
---|
| 814 |
|
---|
[93584] | 815 | /*
|
---|
| 816 | * The install.wim file contains an XML document describing the install
|
---|
| 817 | * images it contains. This includes all the info we need for a successful
|
---|
| 818 | * detection.
|
---|
| 819 | */
|
---|
[93521] | 820 | RTVFSFILE hVfsFile;
|
---|
| 821 | int vrc = RTVfsFileOpen(hVfsIso, "sources/install.wim", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 822 | if (RT_SUCCESS(vrc))
|
---|
| 823 | {
|
---|
| 824 | WIMHEADERV1 header;
|
---|
| 825 | size_t cbRead = 0;
|
---|
| 826 | vrc = RTVfsFileRead(hVfsFile, &header, sizeof(header), &cbRead);
|
---|
| 827 | if (RT_SUCCESS(vrc) && cbRead == sizeof(header))
|
---|
| 828 | {
|
---|
| 829 | /* If the xml data is not compressed, xml data is not empty, and not too big. */
|
---|
| 830 | if ( (header.XmlData.bFlags & RESHDR_FLAGS_METADATA)
|
---|
| 831 | && !(header.XmlData.bFlags & RESHDR_FLAGS_COMPRESSED)
|
---|
[93575] | 832 | && header.XmlData.cbOriginal >= 32
|
---|
| 833 | && header.XmlData.cbOriginal < _32M
|
---|
| 834 | && header.XmlData.cbOriginal == header.XmlData.cb)
|
---|
[93521] | 835 | {
|
---|
[93575] | 836 | size_t const cbXmlData = (size_t)header.XmlData.cbOriginal;
|
---|
| 837 | char *pachXmlBuf = (char *)RTMemTmpAlloc(cbXmlData);
|
---|
| 838 | if (pachXmlBuf)
|
---|
[93521] | 839 | {
|
---|
[93575] | 840 | vrc = RTVfsFileReadAt(hVfsFile, (RTFOFF)header.XmlData.off, pachXmlBuf, cbXmlData, NULL);
|
---|
[93521] | 841 | if (RT_SUCCESS(vrc))
|
---|
| 842 | {
|
---|
[93575] | 843 | LogRel2(("XML Data (%#zx bytes):\n%32.*Rhxd\n", cbXmlData, cbXmlData, pachXmlBuf));
|
---|
| 844 |
|
---|
| 845 | /* Parse the XML: */
|
---|
[93521] | 846 | xml::Document doc;
|
---|
| 847 | xml::XmlMemParser parser;
|
---|
| 848 | try
|
---|
| 849 | {
|
---|
[93575] | 850 | RTCString strFileName = "source/install.wim";
|
---|
| 851 | parser.read(pachXmlBuf, cbXmlData, strFileName, doc);
|
---|
[93521] | 852 | }
|
---|
| 853 | catch (xml::XmlError &rErr)
|
---|
| 854 | {
|
---|
| 855 | LogRel(("Unattended: An error has occured during XML parsing: %s\n", rErr.what()));
|
---|
| 856 | vrc = VERR_XAR_TOC_XML_PARSE_ERROR;
|
---|
| 857 | }
|
---|
[93575] | 858 | catch (std::bad_alloc &)
|
---|
| 859 | {
|
---|
| 860 | LogRel(("Unattended: std::bad_alloc\n"));
|
---|
| 861 | vrc = VERR_NO_MEMORY;
|
---|
| 862 | }
|
---|
[93521] | 863 | catch (...)
|
---|
| 864 | {
|
---|
| 865 | LogRel(("Unattended: An unknown error has occured during XML parsing.\n"));
|
---|
| 866 | vrc = VERR_UNEXPECTED_EXCEPTION;
|
---|
| 867 | }
|
---|
| 868 | if (RT_SUCCESS(vrc))
|
---|
| 869 | {
|
---|
[93575] | 870 | /* Extract the information we need from the XML document: */
|
---|
[93521] | 871 | xml::ElementNode *pElmRoot = doc.getRootElement();
|
---|
| 872 | if (pElmRoot)
|
---|
| 873 | {
|
---|
[93575] | 874 | Assert(mDetectedImages.size() == 0);
|
---|
| 875 | try
|
---|
| 876 | {
|
---|
[93584] | 877 | mDetectedImages.clear(); /* debugging convenience */
|
---|
[93575] | 878 | parseWimXMLData(pElmRoot, mDetectedImages);
|
---|
| 879 | }
|
---|
| 880 | catch (std::bad_alloc &)
|
---|
| 881 | {
|
---|
| 882 | vrc = VERR_NO_MEMORY;
|
---|
| 883 | }
|
---|
[93584] | 884 |
|
---|
| 885 | /*
|
---|
| 886 | * If we found images, update the detected info attributes.
|
---|
| 887 | */
|
---|
| 888 | if (RT_SUCCESS(vrc) && mDetectedImages.size() > 0)
|
---|
| 889 | {
|
---|
| 890 | size_t i;
|
---|
| 891 | for (i = 0; i < mDetectedImages.size(); i++)
|
---|
| 892 | if (mDetectedImages[i].mImageIndex == midxImage)
|
---|
| 893 | break;
|
---|
| 894 | if (i >= mDetectedImages.size())
|
---|
| 895 | i = 0; /* use the first one if midxImage wasn't found */
|
---|
| 896 | if (i_updateDetectedAttributeForImage(mDetectedImages[i]))
|
---|
| 897 | {
|
---|
| 898 | LogRel2(("Unattended: happy with mDetectedImages[%u]\n", i));
|
---|
[94079] | 899 | mEnmOsType = mDetectedImages[i].mOSType;
|
---|
[93584] | 900 | return S_OK;
|
---|
| 901 | }
|
---|
| 902 | }
|
---|
[93521] | 903 | }
|
---|
| 904 | else
|
---|
| 905 | LogRel(("Unattended: No root element found in XML Metadata of install.wim\n"));
|
---|
| 906 | }
|
---|
| 907 | }
|
---|
| 908 | else
|
---|
| 909 | LogRel(("Unattended: Failed during reading XML Metadata out of install.wim\n"));
|
---|
[93575] | 910 | RTMemTmpFree(pachXmlBuf);
|
---|
[93521] | 911 | }
|
---|
[93575] | 912 | else
|
---|
| 913 | {
|
---|
| 914 | LogRel(("Unattended: Failed to allocate %#zx bytes for XML Metadata\n", cbXmlData));
|
---|
| 915 | vrc = VERR_NO_TMP_MEMORY;
|
---|
| 916 | }
|
---|
[93521] | 917 | }
|
---|
| 918 | else
|
---|
[93575] | 919 | LogRel(("Unattended: XML Metadata of install.wim is either compressed, empty, or too big (bFlags=%#x cbOriginal=%#RX64 cb=%#RX64)\n",
|
---|
| 920 | header.XmlData.bFlags, header.XmlData.cbOriginal, header.XmlData.cb));
|
---|
[93521] | 921 | }
|
---|
| 922 | RTVfsFileRelease(hVfsFile);
|
---|
[93575] | 923 |
|
---|
| 924 | /* Bail out if we ran out of memory here. */
|
---|
| 925 | if (vrc == VERR_NO_MEMORY || vrc == VERR_NO_TMP_MEMORY)
|
---|
| 926 | return setErrorBoth(E_OUTOFMEMORY, vrc, tr("Out of memory"));
|
---|
[93521] | 927 | }
|
---|
| 928 |
|
---|
| 929 | const char *pszVersion = NULL;
|
---|
| 930 | const char *pszProduct = NULL;
|
---|
[68318] | 931 | /*
|
---|
| 932 | * Try look for the 'sources/idwbinfo.txt' file containing windows build info.
|
---|
| 933 | * This file appeared with Vista beta 2 from what we can tell. Before windows 10
|
---|
| 934 | * it contains easily decodable branch names, after that things goes weird.
|
---|
| 935 | */
|
---|
[93521] | 936 | vrc = RTVfsFileOpen(hVfsIso, "sources/idwbinfo.txt", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
[68318] | 937 | if (RT_SUCCESS(vrc))
|
---|
| 938 | {
|
---|
[94079] | 939 | mEnmOsType = VBOXOSTYPE_WinNT_x64;
|
---|
[68318] | 940 |
|
---|
| 941 | RTINIFILE hIniFile;
|
---|
| 942 | vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
|
---|
| 943 | RTVfsFileRelease(hVfsFile);
|
---|
| 944 | if (RT_SUCCESS(vrc))
|
---|
| 945 | {
|
---|
[70999] | 946 | vrc = RTIniFileQueryValue(hIniFile, "BUILDINFO", "BuildArch", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
[68318] | 947 | if (RT_SUCCESS(vrc))
|
---|
| 948 | {
|
---|
[70999] | 949 | LogRelFlow(("Unattended: sources/idwbinfo.txt: BuildArch=%s\n", pBuf->sz));
|
---|
| 950 | if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("amd64")) == 0
|
---|
| 951 | || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("x64")) == 0 /* just in case */ )
|
---|
[94079] | 952 | mEnmOsType = VBOXOSTYPE_WinNT_x64;
|
---|
[70999] | 953 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("x86")) == 0)
|
---|
[94079] | 954 | mEnmOsType = VBOXOSTYPE_WinNT;
|
---|
[68318] | 955 | else
|
---|
| 956 | {
|
---|
[70999] | 957 | LogRel(("Unattended: sources/idwbinfo.txt: Unknown: BuildArch=%s\n", pBuf->sz));
|
---|
[94079] | 958 | mEnmOsType = VBOXOSTYPE_WinNT_x64;
|
---|
[68318] | 959 | }
|
---|
| 960 | }
|
---|
| 961 |
|
---|
[70999] | 962 | vrc = RTIniFileQueryValue(hIniFile, "BUILDINFO", "BuildBranch", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
[68318] | 963 | if (RT_SUCCESS(vrc))
|
---|
| 964 | {
|
---|
[70999] | 965 | LogRelFlow(("Unattended: sources/idwbinfo.txt: BuildBranch=%s\n", pBuf->sz));
|
---|
| 966 | if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("vista")) == 0
|
---|
| 967 | || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winmain_beta")) == 0)
|
---|
[96861] | 968 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_WinVista);
|
---|
[79931] | 969 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("lh_sp2rtm")) == 0)
|
---|
| 970 | {
|
---|
[96861] | 971 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_WinVista);
|
---|
[79931] | 972 | pszVersion = "sp2";
|
---|
| 973 | }
|
---|
| 974 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("longhorn_rtm")) == 0)
|
---|
| 975 | {
|
---|
[96861] | 976 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_WinVista);
|
---|
[79931] | 977 | pszVersion = "sp1";
|
---|
| 978 | }
|
---|
[70999] | 979 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("win7")) == 0)
|
---|
[96861] | 980 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win7);
|
---|
[70999] | 981 | else if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winblue")) == 0
|
---|
| 982 | || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winmain_blue")) == 0
|
---|
| 983 | || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("win81")) == 0 /* not seen, but just in case its out there */ )
|
---|
[96861] | 984 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win81);
|
---|
[70999] | 985 | else if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("win8")) == 0
|
---|
| 986 | || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winmain_win8")) == 0 )
|
---|
[96861] | 987 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win8);
|
---|
[79920] | 988 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("th1")) == 0)
|
---|
| 989 | {
|
---|
| 990 | pszVersion = "1507"; // aka. GA, retroactively 1507
|
---|
[96861] | 991 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 992 | }
|
---|
| 993 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("th2")) == 0)
|
---|
| 994 | {
|
---|
| 995 | pszVersion = "1511"; // aka. threshold 2
|
---|
[96861] | 996 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 997 | }
|
---|
| 998 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("rs1_release")) == 0)
|
---|
| 999 | {
|
---|
| 1000 | pszVersion = "1607"; // aka. anniversay update; rs=redstone
|
---|
[96861] | 1001 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1002 | }
|
---|
| 1003 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("rs2_release")) == 0)
|
---|
| 1004 | {
|
---|
| 1005 | pszVersion = "1703"; // aka. creators update
|
---|
[96861] | 1006 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1007 | }
|
---|
| 1008 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("rs3_release")) == 0)
|
---|
| 1009 | {
|
---|
| 1010 | pszVersion = "1709"; // aka. fall creators update
|
---|
[96861] | 1011 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1012 | }
|
---|
| 1013 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("rs4_release")) == 0)
|
---|
| 1014 | {
|
---|
| 1015 | pszVersion = "1803";
|
---|
[96861] | 1016 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1017 | }
|
---|
| 1018 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("rs5_release")) == 0)
|
---|
| 1019 | {
|
---|
| 1020 | pszVersion = "1809";
|
---|
[96861] | 1021 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1022 | }
|
---|
| 1023 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("19h1_release")) == 0)
|
---|
| 1024 | {
|
---|
| 1025 | pszVersion = "1903";
|
---|
[96861] | 1026 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1027 | }
|
---|
| 1028 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("19h2_release")) == 0)
|
---|
| 1029 | {
|
---|
| 1030 | pszVersion = "1909"; // ??
|
---|
[96861] | 1031 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1032 | }
|
---|
| 1033 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("20h1_release")) == 0)
|
---|
| 1034 | {
|
---|
| 1035 | pszVersion = "2003"; // ??
|
---|
[96861] | 1036 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1037 | }
|
---|
[84993] | 1038 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("vb_release")) == 0)
|
---|
| 1039 | {
|
---|
| 1040 | pszVersion = "2004"; // ?? vb=Vibranium
|
---|
[96861] | 1041 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[84993] | 1042 | }
|
---|
[79920] | 1043 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("20h2_release")) == 0)
|
---|
| 1044 | {
|
---|
| 1045 | pszVersion = "2009"; // ??
|
---|
[96861] | 1046 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1047 | }
|
---|
| 1048 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("21h1_release")) == 0)
|
---|
| 1049 | {
|
---|
| 1050 | pszVersion = "2103"; // ??
|
---|
[96861] | 1051 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1052 | }
|
---|
| 1053 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("21h2_release")) == 0)
|
---|
| 1054 | {
|
---|
| 1055 | pszVersion = "2109"; // ??
|
---|
[96861] | 1056 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win10);
|
---|
[79920] | 1057 | }
|
---|
[91502] | 1058 | else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("co_release")) == 0)
|
---|
| 1059 | {
|
---|
| 1060 | pszVersion = "21H2"; // ??
|
---|
[94079] | 1061 | mEnmOsType = VBOXOSTYPE_Win11_x64;
|
---|
[91502] | 1062 | }
|
---|
[68318] | 1063 | else
|
---|
[70999] | 1064 | LogRel(("Unattended: sources/idwbinfo.txt: Unknown: BuildBranch=%s\n", pBuf->sz));
|
---|
[68318] | 1065 | }
|
---|
| 1066 | RTIniFileRelease(hIniFile);
|
---|
| 1067 | }
|
---|
| 1068 | }
|
---|
[79926] | 1069 | bool fClarifyProd = false;
|
---|
| 1070 | if (RT_FAILURE(vrc))
|
---|
| 1071 | {
|
---|
| 1072 | /*
|
---|
| 1073 | * Check a INF file with a DriverVer that is updated with each service pack.
|
---|
| 1074 | * DriverVer=10/01/2002,5.2.3790.3959
|
---|
| 1075 | */
|
---|
| 1076 | vrc = RTVfsFileOpen(hVfsIso, "AMD64/HIVESYS.INF", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1077 | if (RT_SUCCESS(vrc))
|
---|
[94079] | 1078 | mEnmOsType = VBOXOSTYPE_WinNT_x64;
|
---|
[79926] | 1079 | else
|
---|
| 1080 | {
|
---|
| 1081 | vrc = RTVfsFileOpen(hVfsIso, "I386/HIVESYS.INF", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1082 | if (RT_SUCCESS(vrc))
|
---|
[94079] | 1083 | mEnmOsType = VBOXOSTYPE_WinNT;
|
---|
[79926] | 1084 | }
|
---|
| 1085 | if (RT_SUCCESS(vrc))
|
---|
| 1086 | {
|
---|
| 1087 | RTINIFILE hIniFile;
|
---|
| 1088 | vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
|
---|
| 1089 | RTVfsFileRelease(hVfsFile);
|
---|
| 1090 | if (RT_SUCCESS(vrc))
|
---|
| 1091 | {
|
---|
| 1092 | vrc = RTIniFileQueryValue(hIniFile, "Version", "DriverVer", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1093 | if (RT_SUCCESS(vrc))
|
---|
| 1094 | {
|
---|
| 1095 | LogRelFlow(("Unattended: HIVESYS.INF: DriverVer=%s\n", pBuf->sz));
|
---|
| 1096 | const char *psz = strchr(pBuf->sz, ',');
|
---|
| 1097 | psz = psz ? psz + 1 : pBuf->sz;
|
---|
| 1098 | if (RTStrVersionCompare(psz, "6.0.0") >= 0)
|
---|
| 1099 | LogRel(("Unattended: HIVESYS.INF: unknown: DriverVer=%s\n", psz));
|
---|
| 1100 | else if (RTStrVersionCompare(psz, "5.2.0") >= 0) /* W2K3, XP64 */
|
---|
| 1101 | {
|
---|
| 1102 | fClarifyProd = true;
|
---|
[96861] | 1103 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win2k3);
|
---|
[79926] | 1104 | if (RTStrVersionCompare(psz, "5.2.3790.3959") >= 0)
|
---|
| 1105 | pszVersion = "sp2";
|
---|
| 1106 | else if (RTStrVersionCompare(psz, "5.2.3790.1830") >= 0)
|
---|
| 1107 | pszVersion = "sp1";
|
---|
| 1108 | }
|
---|
| 1109 | else if (RTStrVersionCompare(psz, "5.1.0") >= 0) /* XP */
|
---|
| 1110 | {
|
---|
[96861] | 1111 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_WinXP);
|
---|
[79926] | 1112 | if (RTStrVersionCompare(psz, "5.1.2600.5512") >= 0)
|
---|
| 1113 | pszVersion = "sp3";
|
---|
| 1114 | else if (RTStrVersionCompare(psz, "5.1.2600.2180") >= 0)
|
---|
| 1115 | pszVersion = "sp2";
|
---|
| 1116 | else if (RTStrVersionCompare(psz, "5.1.2600.1105") >= 0)
|
---|
| 1117 | pszVersion = "sp1";
|
---|
| 1118 | }
|
---|
| 1119 | else if (RTStrVersionCompare(psz, "5.0.0") >= 0)
|
---|
| 1120 | {
|
---|
[96861] | 1121 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win2k);
|
---|
[79926] | 1122 | if (RTStrVersionCompare(psz, "5.0.2195.6717") >= 0)
|
---|
| 1123 | pszVersion = "sp4";
|
---|
| 1124 | else if (RTStrVersionCompare(psz, "5.0.2195.5438") >= 0)
|
---|
| 1125 | pszVersion = "sp3";
|
---|
| 1126 | else if (RTStrVersionCompare(psz, "5.0.2195.1620") >= 0)
|
---|
| 1127 | pszVersion = "sp1";
|
---|
| 1128 | }
|
---|
| 1129 | else
|
---|
| 1130 | LogRel(("Unattended: HIVESYS.INF: unknown: DriverVer=%s\n", psz));
|
---|
| 1131 | }
|
---|
| 1132 | RTIniFileRelease(hIniFile);
|
---|
| 1133 | }
|
---|
| 1134 | }
|
---|
| 1135 | }
|
---|
| 1136 | if (RT_FAILURE(vrc) || fClarifyProd)
|
---|
| 1137 | {
|
---|
| 1138 | /*
|
---|
| 1139 | * NT 4 and older does not have DriverVer entries, we consult the PRODSPEC.INI, which
|
---|
| 1140 | * works for NT4 & W2K. It does usually not reflect the service pack.
|
---|
| 1141 | */
|
---|
| 1142 | vrc = RTVfsFileOpen(hVfsIso, "AMD64/PRODSPEC.INI", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1143 | if (RT_SUCCESS(vrc))
|
---|
[94079] | 1144 | mEnmOsType = VBOXOSTYPE_WinNT_x64;
|
---|
[79926] | 1145 | else
|
---|
| 1146 | {
|
---|
| 1147 | vrc = RTVfsFileOpen(hVfsIso, "I386/PRODSPEC.INI", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1148 | if (RT_SUCCESS(vrc))
|
---|
[94079] | 1149 | mEnmOsType = VBOXOSTYPE_WinNT;
|
---|
[79926] | 1150 | }
|
---|
| 1151 | if (RT_SUCCESS(vrc))
|
---|
| 1152 | {
|
---|
| 1153 |
|
---|
| 1154 | RTINIFILE hIniFile;
|
---|
| 1155 | vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
|
---|
| 1156 | RTVfsFileRelease(hVfsFile);
|
---|
| 1157 | if (RT_SUCCESS(vrc))
|
---|
| 1158 | {
|
---|
| 1159 | vrc = RTIniFileQueryValue(hIniFile, "Product Specification", "Version", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1160 | if (RT_SUCCESS(vrc))
|
---|
| 1161 | {
|
---|
| 1162 | LogRelFlow(("Unattended: PRODSPEC.INI: Version=%s\n", pBuf->sz));
|
---|
| 1163 | if (RTStrVersionCompare(pBuf->sz, "5.1") >= 0) /* Shipped with XP + W2K3, but version stuck at 5.0. */
|
---|
| 1164 | LogRel(("Unattended: PRODSPEC.INI: unknown: DriverVer=%s\n", pBuf->sz));
|
---|
| 1165 | else if (RTStrVersionCompare(pBuf->sz, "5.0") >= 0) /* 2000 */
|
---|
| 1166 | {
|
---|
| 1167 | vrc = RTIniFileQueryValue(hIniFile, "Product Specification", "Product", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1168 | if (RT_SUCCESS(vrc) && RTStrNICmp(pBuf->sz, RT_STR_TUPLE("Windows XP")) == 0)
|
---|
[96861] | 1169 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_WinXP);
|
---|
[79926] | 1170 | else if (RT_SUCCESS(vrc) && RTStrNICmp(pBuf->sz, RT_STR_TUPLE("Windows Server 2003")) == 0)
|
---|
[96861] | 1171 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win2k3);
|
---|
[79926] | 1172 | else
|
---|
[96861] | 1173 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Win2k);
|
---|
[79926] | 1174 |
|
---|
| 1175 | if (RT_SUCCESS(vrc) && (strstr(pBuf->sz, "Server") || strstr(pBuf->sz, "server")))
|
---|
| 1176 | pszProduct = "Server";
|
---|
| 1177 | }
|
---|
| 1178 | else if (RTStrVersionCompare(pBuf->sz, "4.0") >= 0) /* NT4 */
|
---|
[94079] | 1179 | mEnmOsType = VBOXOSTYPE_WinNT4;
|
---|
[79926] | 1180 | else
|
---|
| 1181 | LogRel(("Unattended: PRODSPEC.INI: unknown: DriverVer=%s\n", pBuf->sz));
|
---|
| 1182 |
|
---|
| 1183 | vrc = RTIniFileQueryValue(hIniFile, "Product Specification", "ProductType", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1184 | if (RT_SUCCESS(vrc))
|
---|
| 1185 | pszProduct = strcmp(pBuf->sz, "0") == 0 ? "Workstation" : /* simplification: */ "Server";
|
---|
| 1186 | }
|
---|
| 1187 | RTIniFileRelease(hIniFile);
|
---|
| 1188 | }
|
---|
| 1189 | }
|
---|
| 1190 | if (fClarifyProd)
|
---|
| 1191 | vrc = VINF_SUCCESS;
|
---|
| 1192 | }
|
---|
| 1193 | if (RT_FAILURE(vrc))
|
---|
| 1194 | {
|
---|
| 1195 | /*
|
---|
| 1196 | * NT 3.x we look at the LoadIdentifier (boot manager) string in TXTSETUP.SIF/TXT.
|
---|
| 1197 | */
|
---|
| 1198 | vrc = RTVfsFileOpen(hVfsIso, "I386/TXTSETUP.SIF", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1199 | if (RT_FAILURE(vrc))
|
---|
| 1200 | vrc = RTVfsFileOpen(hVfsIso, "I386/TXTSETUP.INF", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1201 | if (RT_SUCCESS(vrc))
|
---|
| 1202 | {
|
---|
[94079] | 1203 | mEnmOsType = VBOXOSTYPE_WinNT;
|
---|
[79926] | 1204 |
|
---|
| 1205 | RTINIFILE hIniFile;
|
---|
| 1206 | vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
|
---|
| 1207 | RTVfsFileRelease(hVfsFile);
|
---|
| 1208 | if (RT_SUCCESS(vrc))
|
---|
| 1209 | {
|
---|
| 1210 | vrc = RTIniFileQueryValue(hIniFile, "SetupData", "ProductType", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1211 | if (RT_SUCCESS(vrc))
|
---|
| 1212 | pszProduct = strcmp(pBuf->sz, "0") == 0 ? "Workstation" : /* simplification: */ "Server";
|
---|
| 1213 |
|
---|
| 1214 | vrc = RTIniFileQueryValue(hIniFile, "SetupData", "LoadIdentifier", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1215 | if (RT_SUCCESS(vrc))
|
---|
| 1216 | {
|
---|
| 1217 | LogRelFlow(("Unattended: TXTSETUP.SIF: LoadIdentifier=%s\n", pBuf->sz));
|
---|
| 1218 | char *psz = pBuf->sz;
|
---|
| 1219 | while (!RT_C_IS_DIGIT(*psz) && *psz)
|
---|
| 1220 | psz++;
|
---|
| 1221 | char *psz2 = psz;
|
---|
| 1222 | while (RT_C_IS_DIGIT(*psz2) || *psz2 == '.')
|
---|
| 1223 | psz2++;
|
---|
| 1224 | *psz2 = '\0';
|
---|
| 1225 | if (RTStrVersionCompare(psz, "6.0") >= 0)
|
---|
| 1226 | LogRel(("Unattended: TXTSETUP.SIF: unknown: LoadIdentifier=%s\n", pBuf->sz));
|
---|
| 1227 | else if (RTStrVersionCompare(psz, "4.0") >= 0)
|
---|
[94079] | 1228 | mEnmOsType = VBOXOSTYPE_WinNT4;
|
---|
[79926] | 1229 | else if (RTStrVersionCompare(psz, "3.1") >= 0)
|
---|
| 1230 | {
|
---|
[94079] | 1231 | mEnmOsType = VBOXOSTYPE_WinNT3x;
|
---|
[79926] | 1232 | pszVersion = psz;
|
---|
| 1233 | }
|
---|
| 1234 | else
|
---|
| 1235 | LogRel(("Unattended: TXTSETUP.SIF: unknown: LoadIdentifier=%s\n", pBuf->sz));
|
---|
| 1236 | }
|
---|
| 1237 | RTIniFileRelease(hIniFile);
|
---|
| 1238 | }
|
---|
| 1239 | }
|
---|
| 1240 | }
|
---|
| 1241 |
|
---|
[79920] | 1242 | if (pszVersion)
|
---|
| 1243 | try { mStrDetectedOSVersion = pszVersion; }
|
---|
| 1244 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
[79926] | 1245 | if (pszProduct)
|
---|
| 1246 | try { mStrDetectedOSFlavor = pszProduct; }
|
---|
| 1247 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
[68318] | 1248 |
|
---|
[69063] | 1249 | /*
|
---|
| 1250 | * Look for sources/lang.ini and try parse it to get the languages out of it.
|
---|
| 1251 | */
|
---|
| 1252 | /** @todo We could also check sources/??-* and boot/??-* if lang.ini is not
|
---|
| 1253 | * found or unhelpful. */
|
---|
| 1254 | vrc = RTVfsFileOpen(hVfsIso, "sources/lang.ini", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1255 | if (RT_SUCCESS(vrc))
|
---|
| 1256 | {
|
---|
| 1257 | RTINIFILE hIniFile;
|
---|
| 1258 | vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
|
---|
| 1259 | RTVfsFileRelease(hVfsFile);
|
---|
| 1260 | if (RT_SUCCESS(vrc))
|
---|
| 1261 | {
|
---|
| 1262 | mDetectedOSLanguages.clear();
|
---|
| 1263 |
|
---|
| 1264 | uint32_t idxPair;
|
---|
| 1265 | for (idxPair = 0; idxPair < 256; idxPair++)
|
---|
| 1266 | {
|
---|
[70999] | 1267 | size_t cbHalf = sizeof(*pBuf) / 2;
|
---|
| 1268 | char *pszKey = pBuf->sz;
|
---|
| 1269 | char *pszValue = &pBuf->sz[cbHalf];
|
---|
[69063] | 1270 | vrc = RTIniFileQueryPair(hIniFile, "Available UI Languages", idxPair,
|
---|
| 1271 | pszKey, cbHalf, NULL, pszValue, cbHalf, NULL);
|
---|
| 1272 | if (RT_SUCCESS(vrc))
|
---|
| 1273 | {
|
---|
| 1274 | try
|
---|
| 1275 | {
|
---|
| 1276 | mDetectedOSLanguages.append(pszKey);
|
---|
| 1277 | }
|
---|
[73505] | 1278 | catch (std::bad_alloc &)
|
---|
[69063] | 1279 | {
|
---|
| 1280 | RTIniFileRelease(hIniFile);
|
---|
| 1281 | return E_OUTOFMEMORY;
|
---|
| 1282 | }
|
---|
| 1283 | }
|
---|
| 1284 | else if (vrc == VERR_NOT_FOUND)
|
---|
| 1285 | break;
|
---|
| 1286 | else
|
---|
| 1287 | Assert(vrc == VERR_BUFFER_OVERFLOW);
|
---|
| 1288 | }
|
---|
| 1289 | if (idxPair == 0)
|
---|
| 1290 | LogRel(("Unattended: Warning! Empty 'Available UI Languages' section in sources/lang.ini\n"));
|
---|
| 1291 | RTIniFileRelease(hIniFile);
|
---|
| 1292 | }
|
---|
| 1293 | }
|
---|
| 1294 |
|
---|
[68318] | 1295 | return S_FALSE;
|
---|
| 1296 | }
|
---|
| 1297 |
|
---|
[71003] | 1298 | /**
|
---|
[96861] | 1299 | * Architecture strings for Linux and the like.
|
---|
| 1300 | */
|
---|
| 1301 | static struct { const char *pszArch; uint32_t cchArch; VBOXOSTYPE fArch; } const g_aLinuxArches[] =
|
---|
| 1302 | {
|
---|
| 1303 | { RT_STR_TUPLE("amd64"), VBOXOSTYPE_x64 },
|
---|
| 1304 | { RT_STR_TUPLE("x86_64"), VBOXOSTYPE_x64 },
|
---|
| 1305 | { RT_STR_TUPLE("x86-64"), VBOXOSTYPE_x64 }, /* just in case */
|
---|
| 1306 | { RT_STR_TUPLE("x64"), VBOXOSTYPE_x64 }, /* ditto */
|
---|
| 1307 |
|
---|
| 1308 | { RT_STR_TUPLE("x86"), VBOXOSTYPE_x86 },
|
---|
| 1309 | { RT_STR_TUPLE("i386"), VBOXOSTYPE_x86 },
|
---|
| 1310 | { RT_STR_TUPLE("i486"), VBOXOSTYPE_x86 },
|
---|
| 1311 | { RT_STR_TUPLE("i586"), VBOXOSTYPE_x86 },
|
---|
| 1312 | { RT_STR_TUPLE("i686"), VBOXOSTYPE_x86 },
|
---|
| 1313 | { RT_STR_TUPLE("i786"), VBOXOSTYPE_x86 },
|
---|
| 1314 | { RT_STR_TUPLE("i886"), VBOXOSTYPE_x86 },
|
---|
| 1315 | { RT_STR_TUPLE("i986"), VBOXOSTYPE_x86 },
|
---|
| 1316 | };
|
---|
| 1317 |
|
---|
| 1318 | /**
|
---|
[71003] | 1319 | * Detects linux architecture.
|
---|
| 1320 | *
|
---|
| 1321 | * @returns true if detected, false if not.
|
---|
| 1322 | * @param pszArch The architecture string.
|
---|
| 1323 | * @param penmOsType Where to return the arch and type on success.
|
---|
| 1324 | * @param enmBaseOsType The base (x86) OS type to return.
|
---|
| 1325 | */
|
---|
| 1326 | static bool detectLinuxArch(const char *pszArch, VBOXOSTYPE *penmOsType, VBOXOSTYPE enmBaseOsType)
|
---|
[70999] | 1327 | {
|
---|
[96861] | 1328 | for (size_t i = 0; i < RT_ELEMENTS(g_aLinuxArches); i++)
|
---|
| 1329 | if (RTStrNICmp(pszArch, g_aLinuxArches[i].pszArch, g_aLinuxArches[i].cchArch) == 0)
|
---|
| 1330 | {
|
---|
| 1331 | *penmOsType = (VBOXOSTYPE)(enmBaseOsType | g_aLinuxArches[i].fArch);
|
---|
| 1332 | return true;
|
---|
| 1333 | }
|
---|
[71003] | 1334 | /** @todo check for 'noarch' since source CDs have been seen to use that. */
|
---|
[70999] | 1335 | return false;
|
---|
| 1336 | }
|
---|
| 1337 |
|
---|
[93311] | 1338 | /**
|
---|
| 1339 | * Detects linux architecture by searching for the architecture substring in @p pszArch.
|
---|
| 1340 | *
|
---|
| 1341 | * @returns true if detected, false if not.
|
---|
| 1342 | * @param pszArch The architecture string.
|
---|
| 1343 | * @param penmOsType Where to return the arch and type on success.
|
---|
| 1344 | * @param enmBaseOsType The base (x86) OS type to return.
|
---|
[96861] | 1345 | * @param ppszHit Where to return the pointer to the architecture
|
---|
| 1346 | * specifier. Optional.
|
---|
| 1347 | * @param ppszNext Where to return the pointer to the char
|
---|
| 1348 | * following the architecuture specifier. Optional.
|
---|
[93311] | 1349 | */
|
---|
[96861] | 1350 | static bool detectLinuxArchII(const char *pszArch, VBOXOSTYPE *penmOsType, VBOXOSTYPE enmBaseOsType,
|
---|
| 1351 | char **ppszHit = NULL, char **ppszNext = NULL)
|
---|
[93311] | 1352 | {
|
---|
[96861] | 1353 | for (size_t i = 0; i < RT_ELEMENTS(g_aLinuxArches); i++)
|
---|
[93311] | 1354 | {
|
---|
[96861] | 1355 | const char *pszHit = RTStrIStr(pszArch, g_aLinuxArches[i].pszArch);
|
---|
| 1356 | if (pszHit != NULL)
|
---|
| 1357 | {
|
---|
| 1358 | if (ppszHit)
|
---|
| 1359 | *ppszHit = (char *)pszHit;
|
---|
| 1360 | if (ppszNext)
|
---|
| 1361 | *ppszNext = (char *)pszHit + g_aLinuxArches[i].cchArch;
|
---|
| 1362 | *penmOsType = (VBOXOSTYPE)(enmBaseOsType | g_aLinuxArches[i].fArch);
|
---|
| 1363 | return true;
|
---|
| 1364 | }
|
---|
[93311] | 1365 | }
|
---|
| 1366 | return false;
|
---|
| 1367 | }
|
---|
| 1368 |
|
---|
[71003] | 1369 | static bool detectLinuxDistroName(const char *pszOsAndVersion, VBOXOSTYPE *penmOsType, const char **ppszNext)
|
---|
| 1370 | {
|
---|
| 1371 | bool fRet = true;
|
---|
| 1372 |
|
---|
| 1373 | if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Red")) == 0
|
---|
| 1374 | && !RT_C_IS_ALNUM(pszOsAndVersion[3]))
|
---|
| 1375 |
|
---|
| 1376 | {
|
---|
| 1377 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 3);
|
---|
| 1378 | if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Hat")) == 0
|
---|
| 1379 | && !RT_C_IS_ALNUM(pszOsAndVersion[3]))
|
---|
| 1380 | {
|
---|
[96861] | 1381 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_RedHat);
|
---|
[71003] | 1382 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 3);
|
---|
| 1383 | }
|
---|
| 1384 | else
|
---|
| 1385 | fRet = false;
|
---|
| 1386 | }
|
---|
[95154] | 1387 | else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("OpenSUSE")) == 0
|
---|
| 1388 | && !RT_C_IS_ALNUM(pszOsAndVersion[8]))
|
---|
| 1389 | {
|
---|
[96861] | 1390 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_OpenSUSE);
|
---|
[95154] | 1391 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 8);
|
---|
| 1392 | }
|
---|
[71003] | 1393 | else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Oracle")) == 0
|
---|
| 1394 | && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
|
---|
| 1395 | {
|
---|
[96861] | 1396 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Oracle);
|
---|
[71003] | 1397 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
|
---|
| 1398 | }
|
---|
| 1399 | else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("CentOS")) == 0
|
---|
| 1400 | && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
|
---|
| 1401 | {
|
---|
[96861] | 1402 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_RedHat);
|
---|
[71003] | 1403 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
|
---|
| 1404 | }
|
---|
| 1405 | else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Fedora")) == 0
|
---|
| 1406 | && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
|
---|
| 1407 | {
|
---|
[96861] | 1408 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_FedoraCore);
|
---|
[71003] | 1409 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
|
---|
| 1410 | }
|
---|
[79417] | 1411 | else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Ubuntu")) == 0
|
---|
| 1412 | && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
|
---|
| 1413 | {
|
---|
[96861] | 1414 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Ubuntu);
|
---|
[79417] | 1415 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
|
---|
| 1416 | }
|
---|
[96706] | 1417 | else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Linux Mint")) == 0
|
---|
| 1418 | && !RT_C_IS_ALNUM(pszOsAndVersion[10]))
|
---|
| 1419 | {
|
---|
[96861] | 1420 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Ubuntu);
|
---|
[96706] | 1421 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 10);
|
---|
| 1422 | }
|
---|
[79417] | 1423 | else if ( ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Xubuntu")) == 0
|
---|
[94296] | 1424 | || RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Kubuntu")) == 0
|
---|
| 1425 | || RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Lubuntu")) == 0)
|
---|
[79417] | 1426 | && !RT_C_IS_ALNUM(pszOsAndVersion[7]))
|
---|
| 1427 | {
|
---|
[96861] | 1428 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Ubuntu);
|
---|
[79417] | 1429 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 7);
|
---|
| 1430 | }
|
---|
[93311] | 1431 | else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Debian")) == 0
|
---|
| 1432 | && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
|
---|
| 1433 | {
|
---|
[96861] | 1434 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Debian);
|
---|
[93311] | 1435 | pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
|
---|
| 1436 | }
|
---|
[71003] | 1437 | else
|
---|
| 1438 | fRet = false;
|
---|
| 1439 |
|
---|
| 1440 | /*
|
---|
| 1441 | * Skip forward till we get a number.
|
---|
| 1442 | */
|
---|
| 1443 | if (ppszNext)
|
---|
| 1444 | {
|
---|
| 1445 | *ppszNext = pszOsAndVersion;
|
---|
| 1446 | char ch;
|
---|
| 1447 | for (const char *pszVersion = pszOsAndVersion; (ch = *pszVersion) != '\0'; pszVersion++)
|
---|
| 1448 | if (RT_C_IS_DIGIT(ch))
|
---|
| 1449 | {
|
---|
| 1450 | *ppszNext = pszVersion;
|
---|
| 1451 | break;
|
---|
| 1452 | }
|
---|
| 1453 | }
|
---|
| 1454 | return fRet;
|
---|
| 1455 | }
|
---|
| 1456 |
|
---|
[94296] | 1457 | static bool detectLinuxDistroNameII(const char *pszOsAndVersion, VBOXOSTYPE *penmOsType, const char **ppszNext)
|
---|
| 1458 | {
|
---|
| 1459 | bool fRet = true;
|
---|
| 1460 | if ( RTStrIStr(pszOsAndVersion, "RedHat") != NULL
|
---|
| 1461 | || RTStrIStr(pszOsAndVersion, "Red Hat") != NULL)
|
---|
[96861] | 1462 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_RedHat);
|
---|
[94296] | 1463 | else if (RTStrIStr(pszOsAndVersion, "Oracle") != NULL)
|
---|
[96861] | 1464 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Oracle);
|
---|
[94296] | 1465 | else if (RTStrIStr(pszOsAndVersion, "CentOS") != NULL)
|
---|
[96861] | 1466 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_RedHat);
|
---|
[94296] | 1467 | else if (RTStrIStr(pszOsAndVersion, "Fedora") != NULL)
|
---|
[96861] | 1468 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_FedoraCore);
|
---|
[94296] | 1469 | else if (RTStrIStr(pszOsAndVersion, "Ubuntu") != NULL)
|
---|
[96861] | 1470 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Ubuntu);
|
---|
[96706] | 1471 | else if (RTStrIStr(pszOsAndVersion, "Mint") != NULL)
|
---|
[96861] | 1472 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Ubuntu);
|
---|
[94296] | 1473 | else if (RTStrIStr(pszOsAndVersion, "Debian"))
|
---|
[96861] | 1474 | *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_Debian);
|
---|
[94296] | 1475 | else
|
---|
| 1476 | fRet = false;
|
---|
[71003] | 1477 |
|
---|
[94296] | 1478 | /*
|
---|
| 1479 | * Skip forward till we get a number.
|
---|
| 1480 | */
|
---|
| 1481 | if (ppszNext)
|
---|
| 1482 | {
|
---|
| 1483 | *ppszNext = pszOsAndVersion;
|
---|
| 1484 | char ch;
|
---|
| 1485 | for (const char *pszVersion = pszOsAndVersion; (ch = *pszVersion) != '\0'; pszVersion++)
|
---|
| 1486 | if (RT_C_IS_DIGIT(ch))
|
---|
| 1487 | {
|
---|
| 1488 | *ppszNext = pszVersion;
|
---|
| 1489 | break;
|
---|
| 1490 | }
|
---|
| 1491 | }
|
---|
| 1492 | return fRet;
|
---|
| 1493 | }
|
---|
| 1494 |
|
---|
[96721] | 1495 |
|
---|
[70999] | 1496 | /**
|
---|
[96721] | 1497 | * Helps detecting linux distro flavor by finding substring position of non numerical
|
---|
| 1498 | * part of the disk name.
|
---|
| 1499 | *
|
---|
| 1500 | * @returns true if detected, false if not.
|
---|
[96861] | 1501 | * @param pszDiskName Name of the disk as it is read from .disk/info or
|
---|
| 1502 | * README.diskdefines file.
|
---|
| 1503 | * @param poffVersion String position where first numerical character is
|
---|
| 1504 | * found. We use substring upto this position as OS flavor
|
---|
[96721] | 1505 | */
|
---|
[96861] | 1506 | static bool detectLinuxDistroFlavor(const char *pszDiskName, size_t *poffVersion)
|
---|
[96721] | 1507 | {
|
---|
[96861] | 1508 | Assert(poffVersion);
|
---|
| 1509 | if (!pszDiskName)
|
---|
[96721] | 1510 | return false;
|
---|
[96861] | 1511 | char ch;
|
---|
| 1512 | while ((ch = *pszDiskName) != '\0' && !RT_C_IS_DIGIT(ch))
|
---|
[96721] | 1513 | {
|
---|
| 1514 | ++pszDiskName;
|
---|
[96861] | 1515 | *poffVersion += 1;
|
---|
[96721] | 1516 | }
|
---|
| 1517 | return true;
|
---|
| 1518 | }
|
---|
| 1519 |
|
---|
| 1520 | /**
|
---|
[70999] | 1521 | * Detect Linux distro ISOs.
|
---|
| 1522 | *
|
---|
| 1523 | * @returns COM status code.
|
---|
| 1524 | * @retval S_OK if detected
|
---|
| 1525 | * @retval S_FALSE if not fully detected.
|
---|
| 1526 | *
|
---|
| 1527 | * @param hVfsIso The ISO file system.
|
---|
| 1528 | * @param pBuf Read buffer.
|
---|
| 1529 | */
|
---|
[94079] | 1530 | HRESULT Unattended::i_innerDetectIsoOSLinux(RTVFS hVfsIso, DETECTBUFFER *pBuf)
|
---|
[70999] | 1531 | {
|
---|
| 1532 | /*
|
---|
| 1533 | * Redhat and derivatives may have a .treeinfo (ini-file style) with useful info
|
---|
| 1534 | * or at least a barebone .discinfo file.
|
---|
| 1535 | */
|
---|
| 1536 |
|
---|
| 1537 | /*
|
---|
| 1538 | * Start with .treeinfo: https://release-engineering.github.io/productmd/treeinfo-1.0.html
|
---|
| 1539 | */
|
---|
| 1540 | RTVFSFILE hVfsFile;
|
---|
| 1541 | int vrc = RTVfsFileOpen(hVfsIso, ".treeinfo", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1542 | if (RT_SUCCESS(vrc))
|
---|
| 1543 | {
|
---|
| 1544 | RTINIFILE hIniFile;
|
---|
| 1545 | vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
|
---|
| 1546 | RTVfsFileRelease(hVfsFile);
|
---|
| 1547 | if (RT_SUCCESS(vrc))
|
---|
| 1548 | {
|
---|
| 1549 | /* Try figure the architecture first (like with windows). */
|
---|
| 1550 | vrc = RTIniFileQueryValue(hIniFile, "tree", "arch", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1551 | if (RT_FAILURE(vrc) || !pBuf->sz[0])
|
---|
| 1552 | vrc = RTIniFileQueryValue(hIniFile, "general", "arch", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
[93365] | 1553 | if (RT_FAILURE(vrc))
|
---|
| 1554 | LogRel(("Unattended: .treeinfo: No 'arch' property.\n"));
|
---|
| 1555 | else
|
---|
[70999] | 1556 | {
|
---|
| 1557 | LogRelFlow(("Unattended: .treeinfo: arch=%s\n", pBuf->sz));
|
---|
[94079] | 1558 | if (detectLinuxArch(pBuf->sz, &mEnmOsType, VBOXOSTYPE_RedHat))
|
---|
[93365] | 1559 | {
|
---|
| 1560 | /* Try figure the release name, it doesn't have to be redhat. */
|
---|
| 1561 | vrc = RTIniFileQueryValue(hIniFile, "release", "name", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1562 | if (RT_FAILURE(vrc) || !pBuf->sz[0])
|
---|
| 1563 | vrc = RTIniFileQueryValue(hIniFile, "product", "name", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1564 | if (RT_FAILURE(vrc) || !pBuf->sz[0])
|
---|
| 1565 | vrc = RTIniFileQueryValue(hIniFile, "general", "family", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1566 | if (RT_SUCCESS(vrc))
|
---|
| 1567 | {
|
---|
| 1568 | LogRelFlow(("Unattended: .treeinfo: name/family=%s\n", pBuf->sz));
|
---|
[94079] | 1569 | if (!detectLinuxDistroName(pBuf->sz, &mEnmOsType, NULL))
|
---|
[93365] | 1570 | {
|
---|
| 1571 | LogRel(("Unattended: .treeinfo: Unknown: name/family='%s', assuming Red Hat\n", pBuf->sz));
|
---|
[96861] | 1572 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_RedHat);
|
---|
[93365] | 1573 | }
|
---|
| 1574 | }
|
---|
[70999] | 1575 |
|
---|
[93365] | 1576 | /* Try figure the version. */
|
---|
| 1577 | vrc = RTIniFileQueryValue(hIniFile, "release", "version", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1578 | if (RT_FAILURE(vrc) || !pBuf->sz[0])
|
---|
| 1579 | vrc = RTIniFileQueryValue(hIniFile, "product", "version", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1580 | if (RT_FAILURE(vrc) || !pBuf->sz[0])
|
---|
| 1581 | vrc = RTIniFileQueryValue(hIniFile, "general", "version", pBuf->sz, sizeof(*pBuf), NULL);
|
---|
| 1582 | if (RT_SUCCESS(vrc))
|
---|
| 1583 | {
|
---|
| 1584 | LogRelFlow(("Unattended: .treeinfo: version=%s\n", pBuf->sz));
|
---|
| 1585 | try { mStrDetectedOSVersion = RTStrStrip(pBuf->sz); }
|
---|
| 1586 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
[96721] | 1587 |
|
---|
| 1588 | size_t cchVersionPosition = 0;
|
---|
| 1589 | if (detectLinuxDistroFlavor(pBuf->sz, &cchVersionPosition))
|
---|
| 1590 | {
|
---|
| 1591 | try { mStrDetectedOSFlavor = Utf8Str(pBuf->sz, cchVersionPosition); }
|
---|
| 1592 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 1593 | }
|
---|
[93365] | 1594 | }
|
---|
[70999] | 1595 | }
|
---|
[93365] | 1596 | else
|
---|
| 1597 | LogRel(("Unattended: .treeinfo: Unknown: arch='%s'\n", pBuf->sz));
|
---|
[70999] | 1598 | }
|
---|
| 1599 |
|
---|
| 1600 | RTIniFileRelease(hIniFile);
|
---|
| 1601 | }
|
---|
| 1602 |
|
---|
[94079] | 1603 | if (mEnmOsType != VBOXOSTYPE_Unknown)
|
---|
[70999] | 1604 | return S_FALSE;
|
---|
| 1605 | }
|
---|
| 1606 |
|
---|
| 1607 | /*
|
---|
| 1608 | * Try .discinfo next: https://release-engineering.github.io/productmd/discinfo-1.0.html
|
---|
| 1609 | * We will probably need additional info here...
|
---|
| 1610 | */
|
---|
| 1611 | vrc = RTVfsFileOpen(hVfsIso, ".discinfo", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1612 | if (RT_SUCCESS(vrc))
|
---|
| 1613 | {
|
---|
| 1614 | size_t cchIgn;
|
---|
[93311] | 1615 | vrc = RTVfsFileRead(hVfsFile, pBuf->sz, sizeof(*pBuf) - 1, &cchIgn);
|
---|
| 1616 | pBuf->sz[RT_SUCCESS(vrc) ? cchIgn : 0] = '\0';
|
---|
[70999] | 1617 | RTVfsFileRelease(hVfsFile);
|
---|
| 1618 |
|
---|
| 1619 | /* Parse and strip the first 5 lines. */
|
---|
| 1620 | const char *apszLines[5];
|
---|
| 1621 | char *psz = pBuf->sz;
|
---|
| 1622 | for (unsigned i = 0; i < RT_ELEMENTS(apszLines); i++)
|
---|
| 1623 | {
|
---|
| 1624 | apszLines[i] = psz;
|
---|
| 1625 | if (*psz)
|
---|
| 1626 | {
|
---|
| 1627 | char *pszEol = (char *)strchr(psz, '\n');
|
---|
| 1628 | if (!pszEol)
|
---|
| 1629 | psz = strchr(psz, '\0');
|
---|
| 1630 | else
|
---|
| 1631 | {
|
---|
| 1632 | *pszEol = '\0';
|
---|
| 1633 | apszLines[i] = RTStrStrip(psz);
|
---|
[71003] | 1634 | psz = pszEol + 1;
|
---|
[70999] | 1635 | }
|
---|
| 1636 | }
|
---|
| 1637 | }
|
---|
| 1638 |
|
---|
| 1639 | /* Do we recognize the architecture? */
|
---|
[71003] | 1640 | LogRelFlow(("Unattended: .discinfo: arch=%s\n", apszLines[2]));
|
---|
[94079] | 1641 | if (detectLinuxArch(apszLines[2], &mEnmOsType, VBOXOSTYPE_RedHat))
|
---|
[70999] | 1642 | {
|
---|
[93365] | 1643 | /* Do we recognize the release string? */
|
---|
| 1644 | LogRelFlow(("Unattended: .discinfo: product+version=%s\n", apszLines[1]));
|
---|
| 1645 | const char *pszVersion = NULL;
|
---|
[94079] | 1646 | if (!detectLinuxDistroName(apszLines[1], &mEnmOsType, &pszVersion))
|
---|
[93365] | 1647 | LogRel(("Unattended: .discinfo: Unknown: release='%s'\n", apszLines[1]));
|
---|
[71011] | 1648 |
|
---|
[93365] | 1649 | if (*pszVersion)
|
---|
[71011] | 1650 | {
|
---|
[93365] | 1651 | LogRelFlow(("Unattended: .discinfo: version=%s\n", pszVersion));
|
---|
| 1652 | try { mStrDetectedOSVersion = RTStrStripL(pszVersion); }
|
---|
| 1653 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 1654 |
|
---|
| 1655 | /* CentOS likes to call their release 'Final' without mentioning the actual version
|
---|
| 1656 | number (e.g. CentOS-4.7-x86_64-binDVD.iso), so we need to go look elsewhere.
|
---|
| 1657 | This is only important for centos 4.x and 3.x releases. */
|
---|
| 1658 | if (RTStrNICmp(pszVersion, RT_STR_TUPLE("Final")) == 0)
|
---|
[71011] | 1659 | {
|
---|
[93365] | 1660 | static const char * const s_apszDirs[] = { "CentOS/RPMS/", "RedHat/RPMS", "Server", "Workstation" };
|
---|
| 1661 | for (unsigned iDir = 0; iDir < RT_ELEMENTS(s_apszDirs); iDir++)
|
---|
[71011] | 1662 | {
|
---|
[93365] | 1663 | RTVFSDIR hVfsDir;
|
---|
| 1664 | vrc = RTVfsDirOpen(hVfsIso, s_apszDirs[iDir], 0, &hVfsDir);
|
---|
[71011] | 1665 | if (RT_FAILURE(vrc))
|
---|
[93365] | 1666 | continue;
|
---|
| 1667 | char szRpmDb[128];
|
---|
| 1668 | char szReleaseRpm[128];
|
---|
| 1669 | szRpmDb[0] = '\0';
|
---|
| 1670 | szReleaseRpm[0] = '\0';
|
---|
| 1671 | for (;;)
|
---|
[71011] | 1672 | {
|
---|
[93365] | 1673 | RTDIRENTRYEX DirEntry;
|
---|
| 1674 | size_t cbDirEntry = sizeof(DirEntry);
|
---|
| 1675 | vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING);
|
---|
| 1676 | if (RT_FAILURE(vrc))
|
---|
| 1677 | break;
|
---|
[71011] | 1678 |
|
---|
[93365] | 1679 | /* redhat-release-4WS-2.4.i386.rpm
|
---|
| 1680 | centos-release-4-7.x86_64.rpm, centos-release-4-4.3.i386.rpm
|
---|
| 1681 | centos-release-5-3.el5.centos.1.x86_64.rpm */
|
---|
| 1682 | if ( (psz = strstr(DirEntry.szName, "-release-")) != NULL
|
---|
| 1683 | || (psz = strstr(DirEntry.szName, "-RELEASE-")) != NULL)
|
---|
[71011] | 1684 | {
|
---|
[93365] | 1685 | psz += 9;
|
---|
| 1686 | if (RT_C_IS_DIGIT(*psz))
|
---|
| 1687 | RTStrCopy(szReleaseRpm, sizeof(szReleaseRpm), psz);
|
---|
[71011] | 1688 | }
|
---|
[93365] | 1689 | /* rpmdb-redhat-4WS-2.4.i386.rpm,
|
---|
| 1690 | rpmdb-CentOS-4.5-0.20070506.i386.rpm,
|
---|
| 1691 | rpmdb-redhat-3.9-0.20070703.i386.rpm. */
|
---|
| 1692 | else if ( ( RTStrStartsWith(DirEntry.szName, "rpmdb-")
|
---|
| 1693 | || RTStrStartsWith(DirEntry.szName, "RPMDB-"))
|
---|
| 1694 | && RT_C_IS_DIGIT(DirEntry.szName[6]) )
|
---|
| 1695 | RTStrCopy(szRpmDb, sizeof(szRpmDb), &DirEntry.szName[6]);
|
---|
| 1696 | }
|
---|
| 1697 | RTVfsDirRelease(hVfsDir);
|
---|
[71011] | 1698 |
|
---|
[93365] | 1699 | /* Did we find anything relvant? */
|
---|
| 1700 | psz = szRpmDb;
|
---|
| 1701 | if (!RT_C_IS_DIGIT(*psz))
|
---|
| 1702 | psz = szReleaseRpm;
|
---|
| 1703 | if (RT_C_IS_DIGIT(*psz))
|
---|
| 1704 | {
|
---|
| 1705 | /* Convert '-' to '.' and strip stuff which doesn't look like a version string. */
|
---|
| 1706 | char *pszCur = psz + 1;
|
---|
| 1707 | for (char ch = *pszCur; ch != '\0'; ch = *++pszCur)
|
---|
| 1708 | if (ch == '-')
|
---|
| 1709 | *pszCur = '.';
|
---|
| 1710 | else if (ch != '.' && !RT_C_IS_DIGIT(ch))
|
---|
| 1711 | {
|
---|
| 1712 | *pszCur = '\0';
|
---|
| 1713 | break;
|
---|
| 1714 | }
|
---|
| 1715 | while (&pszCur[-1] != psz && pszCur[-1] == '.')
|
---|
| 1716 | *--pszCur = '\0';
|
---|
| 1717 |
|
---|
| 1718 | /* Set it and stop looking. */
|
---|
| 1719 | try { mStrDetectedOSVersion = psz; }
|
---|
| 1720 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 1721 | break;
|
---|
| 1722 | }
|
---|
[71011] | 1723 | }
|
---|
| 1724 | }
|
---|
| 1725 | }
|
---|
[96721] | 1726 | size_t cchVersionPosition = 0;
|
---|
| 1727 | if (detectLinuxDistroFlavor(apszLines[1], &cchVersionPosition))
|
---|
| 1728 | {
|
---|
| 1729 | try { mStrDetectedOSFlavor = Utf8Str(apszLines[1], cchVersionPosition); }
|
---|
| 1730 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 1731 | }
|
---|
[70999] | 1732 | }
|
---|
[93365] | 1733 | else
|
---|
| 1734 | LogRel(("Unattended: .discinfo: Unknown: arch='%s'\n", apszLines[2]));
|
---|
[70999] | 1735 |
|
---|
[94079] | 1736 | if (mEnmOsType != VBOXOSTYPE_Unknown)
|
---|
[70999] | 1737 | return S_FALSE;
|
---|
| 1738 | }
|
---|
| 1739 |
|
---|
[79417] | 1740 | /*
|
---|
[96721] | 1741 | * Ubuntu has a README.diskdefines file on their ISO (already on 4.10 / warty warthog).
|
---|
[79417] | 1742 | * Example content:
|
---|
| 1743 | * #define DISKNAME Ubuntu 4.10 "Warty Warthog" - Preview amd64 Binary-1
|
---|
| 1744 | * #define TYPE binary
|
---|
| 1745 | * #define TYPEbinary 1
|
---|
| 1746 | * #define ARCH amd64
|
---|
| 1747 | * #define ARCHamd64 1
|
---|
| 1748 | * #define DISKNUM 1
|
---|
| 1749 | * #define DISKNUM1 1
|
---|
| 1750 | * #define TOTALNUM 1
|
---|
| 1751 | * #define TOTALNUM1 1
|
---|
| 1752 | */
|
---|
| 1753 | vrc = RTVfsFileOpen(hVfsIso, "README.diskdefines", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1754 | if (RT_SUCCESS(vrc))
|
---|
| 1755 | {
|
---|
| 1756 | size_t cchIgn;
|
---|
[93311] | 1757 | vrc = RTVfsFileRead(hVfsFile, pBuf->sz, sizeof(*pBuf) - 1, &cchIgn);
|
---|
| 1758 | pBuf->sz[RT_SUCCESS(vrc) ? cchIgn : 0] = '\0';
|
---|
[79417] | 1759 | RTVfsFileRelease(hVfsFile);
|
---|
| 1760 |
|
---|
| 1761 | /* Find the DISKNAME and ARCH defines. */
|
---|
| 1762 | const char *pszDiskName = NULL;
|
---|
| 1763 | const char *pszArch = NULL;
|
---|
| 1764 | char *psz = pBuf->sz;
|
---|
| 1765 | for (unsigned i = 0; *psz != '\0'; i++)
|
---|
| 1766 | {
|
---|
| 1767 | while (RT_C_IS_BLANK(*psz))
|
---|
| 1768 | psz++;
|
---|
| 1769 |
|
---|
| 1770 | /* Match #define: */
|
---|
| 1771 | static const char s_szDefine[] = "#define";
|
---|
| 1772 | if ( strncmp(psz, s_szDefine, sizeof(s_szDefine) - 1) == 0
|
---|
| 1773 | && RT_C_IS_BLANK(psz[sizeof(s_szDefine) - 1]))
|
---|
| 1774 | {
|
---|
| 1775 | psz = &psz[sizeof(s_szDefine) - 1];
|
---|
| 1776 | while (RT_C_IS_BLANK(*psz))
|
---|
| 1777 | psz++;
|
---|
| 1778 |
|
---|
| 1779 | /* Match the identifier: */
|
---|
| 1780 | char *pszIdentifier = psz;
|
---|
| 1781 | if (RT_C_IS_ALPHA(*psz) || *psz == '_')
|
---|
| 1782 | {
|
---|
| 1783 | do
|
---|
| 1784 | psz++;
|
---|
| 1785 | while (RT_C_IS_ALNUM(*psz) || *psz == '_');
|
---|
[85277] | 1786 | size_t cchIdentifier = (size_t)(psz - pszIdentifier);
|
---|
[79417] | 1787 |
|
---|
| 1788 | /* Skip to the value. */
|
---|
| 1789 | while (RT_C_IS_BLANK(*psz))
|
---|
| 1790 | psz++;
|
---|
| 1791 | char *pszValue = psz;
|
---|
| 1792 |
|
---|
| 1793 | /* Skip to EOL and strip the value. */
|
---|
| 1794 | char *pszEol = psz = strchr(psz, '\n');
|
---|
| 1795 | if (psz)
|
---|
| 1796 | *psz++ = '\0';
|
---|
| 1797 | else
|
---|
| 1798 | pszEol = strchr(pszValue, '\0');
|
---|
| 1799 | while (pszEol > pszValue && RT_C_IS_SPACE(pszEol[-1]))
|
---|
| 1800 | *--pszEol = '\0';
|
---|
| 1801 |
|
---|
| 1802 | LogRelFlow(("Unattended: README.diskdefines: %.*s=%s\n", cchIdentifier, pszIdentifier, pszValue));
|
---|
| 1803 |
|
---|
| 1804 | /* Do identifier matching: */
|
---|
| 1805 | if (cchIdentifier == sizeof("DISKNAME") - 1 && strncmp(pszIdentifier, RT_STR_TUPLE("DISKNAME")) == 0)
|
---|
| 1806 | pszDiskName = pszValue;
|
---|
| 1807 | else if (cchIdentifier == sizeof("ARCH") - 1 && strncmp(pszIdentifier, RT_STR_TUPLE("ARCH")) == 0)
|
---|
| 1808 | pszArch = pszValue;
|
---|
| 1809 | else
|
---|
| 1810 | continue;
|
---|
| 1811 | if (pszDiskName == NULL || pszArch == NULL)
|
---|
| 1812 | continue;
|
---|
| 1813 | break;
|
---|
| 1814 | }
|
---|
| 1815 | }
|
---|
| 1816 |
|
---|
| 1817 | /* Next line: */
|
---|
| 1818 | psz = strchr(psz, '\n');
|
---|
| 1819 | if (!psz)
|
---|
| 1820 | break;
|
---|
| 1821 | psz++;
|
---|
| 1822 | }
|
---|
| 1823 |
|
---|
| 1824 | /* Did we find both of them? */
|
---|
| 1825 | if (pszDiskName && pszArch)
|
---|
| 1826 | {
|
---|
[94079] | 1827 | if (detectLinuxArch(pszArch, &mEnmOsType, VBOXOSTYPE_Ubuntu))
|
---|
[79417] | 1828 | {
|
---|
[93365] | 1829 | const char *pszVersion = NULL;
|
---|
[94079] | 1830 | if (detectLinuxDistroName(pszDiskName, &mEnmOsType, &pszVersion))
|
---|
[93365] | 1831 | {
|
---|
| 1832 | LogRelFlow(("Unattended: README.diskdefines: version=%s\n", pszVersion));
|
---|
| 1833 | try { mStrDetectedOSVersion = RTStrStripL(pszVersion); }
|
---|
| 1834 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
[96721] | 1835 |
|
---|
| 1836 | size_t cchVersionPosition = 0;
|
---|
| 1837 | if (detectLinuxDistroFlavor(pszDiskName, &cchVersionPosition))
|
---|
| 1838 | {
|
---|
| 1839 | try { mStrDetectedOSFlavor = Utf8Str(pszDiskName, cchVersionPosition); }
|
---|
| 1840 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 1841 | }
|
---|
[93365] | 1842 | }
|
---|
| 1843 | else
|
---|
| 1844 | LogRel(("Unattended: README.diskdefines: Unknown: diskname='%s'\n", pszDiskName));
|
---|
[79417] | 1845 | }
|
---|
| 1846 | else
|
---|
[93365] | 1847 | LogRel(("Unattended: README.diskdefines: Unknown: arch='%s'\n", pszArch));
|
---|
[79417] | 1848 | }
|
---|
| 1849 | else
|
---|
| 1850 | LogRel(("Unattended: README.diskdefines: Did not find both DISKNAME and ARCH. :-/\n"));
|
---|
| 1851 |
|
---|
[94079] | 1852 | if (mEnmOsType != VBOXOSTYPE_Unknown)
|
---|
[79417] | 1853 | return S_FALSE;
|
---|
| 1854 | }
|
---|
| 1855 |
|
---|
[93311] | 1856 | /*
|
---|
[96861] | 1857 | * All of the debian based distro versions I checked have a single line ./disk/info
|
---|
| 1858 | * file. Only info I could find related to .disk folder is:
|
---|
| 1859 | * https://lists.debian.org/debian-cd/2004/01/msg00069.html
|
---|
| 1860 | *
|
---|
[93311] | 1861 | * Some example content from several install ISOs is as follows:
|
---|
[96861] | 1862 | * Ubuntu 4.10 "Warty Warthog" - Preview amd64 Binary-1 (20041020)
|
---|
| 1863 | * Linux Mint 20.3 "Una" - Release amd64 20220104
|
---|
| 1864 | * Debian GNU/Linux 11.2.0 "Bullseye" - Official amd64 NETINST 20211218-11:12
|
---|
| 1865 | * Debian GNU/Linux 9.13.0 "Stretch" - Official amd64 DVD Binary-1 20200718-11:07
|
---|
| 1866 | * Xubuntu 20.04.2.0 LTS "Focal Fossa" - Release amd64 (20210209.1)
|
---|
| 1867 | * Ubuntu 17.10 "Artful Aardvark" - Release amd64 (20180105.1)
|
---|
| 1868 | * Ubuntu 16.04.6 LTS "Xenial Xerus" - Release i386 (20190227.1)
|
---|
| 1869 | * Debian GNU/Linux 8.11.1 "Jessie" - Official amd64 CD Binary-1 20190211-02:10
|
---|
| 1870 | * Kali GNU/Linux 2021.3a "Kali-last-snapshot" - Official amd64 BD Binary-1 with firmware 20211015-16:55
|
---|
| 1871 | * Official Debian GNU/Linux Live 10.10.0 cinnamon 2021-06-19T12:13
|
---|
[93311] | 1872 | */
|
---|
| 1873 | vrc = RTVfsFileOpen(hVfsIso, ".disk/info", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 1874 | if (RT_SUCCESS(vrc))
|
---|
| 1875 | {
|
---|
| 1876 | size_t cchIgn;
|
---|
| 1877 | vrc = RTVfsFileRead(hVfsFile, pBuf->sz, sizeof(*pBuf) - 1, &cchIgn);
|
---|
| 1878 | pBuf->sz[RT_SUCCESS(vrc) ? cchIgn : 0] = '\0';
|
---|
| 1879 |
|
---|
| 1880 | pBuf->sz[sizeof(*pBuf) - 1] = '\0';
|
---|
| 1881 | RTVfsFileRelease(hVfsFile);
|
---|
| 1882 |
|
---|
| 1883 | char *psz = pBuf->sz;
|
---|
| 1884 | char *pszDiskName = psz;
|
---|
| 1885 | char *pszArch = NULL;
|
---|
| 1886 |
|
---|
| 1887 | /* Only care about the first line of the file even if it is multi line and assume disk name ended with ' - '.*/
|
---|
| 1888 | psz = RTStrStr(pBuf->sz, " - ");
|
---|
| 1889 | if (psz && memchr(pBuf->sz, '\n', (size_t)(psz - pBuf->sz)) == NULL)
|
---|
| 1890 | {
|
---|
| 1891 | *psz = '\0';
|
---|
| 1892 | psz += 3;
|
---|
| 1893 | if (*psz)
|
---|
| 1894 | pszArch = psz;
|
---|
| 1895 | }
|
---|
| 1896 |
|
---|
[94296] | 1897 | /* Some Debian Live ISO's have info file content as follows:
|
---|
| 1898 | * Official Debian GNU/Linux Live 10.10.0 cinnamon 2021-06-19T12:13
|
---|
| 1899 | * thus pszArch stays empty. Try Volume Id (label) if we get lucky and get architecture from that. */
|
---|
| 1900 | if (!pszArch)
|
---|
[93311] | 1901 | {
|
---|
[94296] | 1902 | char szVolumeId[128];
|
---|
[96861] | 1903 | vrc = RTVfsQueryLabel(hVfsIso, false /*fAlternative*/, szVolumeId, sizeof(szVolumeId), NULL);
|
---|
[94296] | 1904 | if (RT_SUCCESS(vrc))
|
---|
| 1905 | {
|
---|
| 1906 | if (!detectLinuxArchII(szVolumeId, &mEnmOsType, VBOXOSTYPE_Ubuntu))
|
---|
[94297] | 1907 | LogRel(("Unattended: .disk/info: Unknown: arch='%s'\n", szVolumeId));
|
---|
[94296] | 1908 | }
|
---|
| 1909 | else
|
---|
| 1910 | LogRel(("Unattended: .disk/info No Volume Label found\n"));
|
---|
| 1911 | }
|
---|
| 1912 | else
|
---|
| 1913 | {
|
---|
[94079] | 1914 | if (!detectLinuxArchII(pszArch, &mEnmOsType, VBOXOSTYPE_Ubuntu))
|
---|
[94296] | 1915 | LogRel(("Unattended: .disk/info: Unknown: arch='%s'\n", pszArch));
|
---|
| 1916 | }
|
---|
[93311] | 1917 |
|
---|
[94296] | 1918 | if (pszDiskName)
|
---|
| 1919 | {
|
---|
[93311] | 1920 | const char *pszVersion = NULL;
|
---|
[94296] | 1921 | if (detectLinuxDistroNameII(pszDiskName, &mEnmOsType, &pszVersion))
|
---|
[93311] | 1922 | {
|
---|
[94296] | 1923 | LogRelFlow(("Unattended: .disk/info: version=%s\n", pszVersion));
|
---|
[93311] | 1924 | try { mStrDetectedOSVersion = RTStrStripL(pszVersion); }
|
---|
| 1925 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
[96721] | 1926 |
|
---|
| 1927 | size_t cchVersionPosition = 0;
|
---|
| 1928 | if (detectLinuxDistroFlavor(pszDiskName, &cchVersionPosition))
|
---|
| 1929 | {
|
---|
| 1930 | try { mStrDetectedOSFlavor = Utf8Str(pszDiskName, cchVersionPosition); }
|
---|
| 1931 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 1932 | }
|
---|
[93311] | 1933 | }
|
---|
| 1934 | else
|
---|
[94296] | 1935 | LogRel(("Unattended: .disk/info: Unknown: diskname='%s'\n", pszDiskName));
|
---|
[93311] | 1936 | }
|
---|
[94296] | 1937 |
|
---|
| 1938 | if (mEnmOsType == VBOXOSTYPE_Unknown)
|
---|
| 1939 | LogRel(("Unattended: .disk/info: Did not find DISKNAME or/and ARCH. :-/\n"));
|
---|
[93311] | 1940 | else
|
---|
| 1941 | return S_FALSE;
|
---|
| 1942 | }
|
---|
| 1943 |
|
---|
[96861] | 1944 | /*
|
---|
| 1945 | * Fedora live iso should be recognizable from the primary volume ID (the
|
---|
| 1946 | * joliet one is usually truncated). We set fAlternative = true here to
|
---|
| 1947 | * get the primary volume ID.
|
---|
| 1948 | */
|
---|
| 1949 | char szVolumeId[128];
|
---|
| 1950 | vrc = RTVfsQueryLabel(hVfsIso, true /*fAlternative*/, szVolumeId, sizeof(szVolumeId), NULL);
|
---|
| 1951 | if (RT_SUCCESS(vrc) && RTStrStartsWith(szVolumeId, "Fedora-"))
|
---|
| 1952 | return i_innerDetectIsoOSLinuxFedora(hVfsIso, pBuf, &szVolumeId[sizeof("Fedora-") - 1]);
|
---|
[70999] | 1953 | return S_FALSE;
|
---|
| 1954 | }
|
---|
| 1955 |
|
---|
| 1956 |
|
---|
[93082] | 1957 | /**
|
---|
[96861] | 1958 | * Continues working a Fedora ISO image after the caller found a "Fedora-*"
|
---|
| 1959 | * volume ID.
|
---|
| 1960 | *
|
---|
| 1961 | * Sample Volume IDs:
|
---|
| 1962 | * - Fedora-WS-Live-34-1-2 (joliet: Fedora-WS-Live-3)
|
---|
| 1963 | * - Fedora-S-dvd-x86_64-34 (joliet: Fedora-S-dvd-x86)
|
---|
| 1964 | * - Fedora-WS-dvd-i386-25 (joliet: Fedora-WS-dvd-i3)
|
---|
| 1965 | */
|
---|
| 1966 | HRESULT Unattended::i_innerDetectIsoOSLinuxFedora(RTVFS hVfsIso, DETECTBUFFER *pBuf, char *pszVolId)
|
---|
| 1967 | {
|
---|
| 1968 | char * const pszFlavor = pszVolId;
|
---|
| 1969 | char * psz = pszVolId;
|
---|
| 1970 |
|
---|
| 1971 | /* The volume id may or may not include an arch, component.
|
---|
| 1972 | We ASSUME that it includes a numeric part with the version, or at least
|
---|
| 1973 | part of it. */
|
---|
| 1974 | char *pszVersion = NULL;
|
---|
| 1975 | char *pszArch = NULL;
|
---|
| 1976 | if (detectLinuxArchII(psz, &mEnmOsType, VBOXOSTYPE_FedoraCore, &pszArch, &pszVersion))
|
---|
[96862] | 1977 | {
|
---|
| 1978 | while (*pszVersion == '-')
|
---|
| 1979 | pszVersion++;
|
---|
[96861] | 1980 | *pszArch = '\0';
|
---|
[96862] | 1981 | }
|
---|
[96861] | 1982 | else
|
---|
| 1983 | {
|
---|
| 1984 | mEnmOsType = (VBOXOSTYPE)(VBOXOSTYPE_FedoraCore | VBOXOSTYPE_UnknownArch);
|
---|
| 1985 |
|
---|
| 1986 | char ch;
|
---|
| 1987 | while ((ch = *psz) != '\0' && (!RT_C_IS_DIGIT(ch) || !RT_C_IS_PUNCT(psz[-1])))
|
---|
| 1988 | psz++;
|
---|
| 1989 | if (ch != '\0')
|
---|
| 1990 | pszVersion = psz;
|
---|
| 1991 | }
|
---|
| 1992 |
|
---|
| 1993 | /*
|
---|
| 1994 | * Replace '-' with '.' in the version part and use it as the version.
|
---|
| 1995 | */
|
---|
| 1996 | if (pszVersion)
|
---|
| 1997 | {
|
---|
| 1998 | psz = pszVersion;
|
---|
| 1999 | while ((psz = strchr(psz, '-')) != NULL)
|
---|
| 2000 | *psz++ = '.';
|
---|
| 2001 | try { mStrDetectedOSVersion = RTStrStrip(pszVersion); }
|
---|
| 2002 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 2003 |
|
---|
| 2004 | *pszVersion = '\0'; /* don't include in flavor */
|
---|
| 2005 | }
|
---|
| 2006 |
|
---|
| 2007 | /*
|
---|
| 2008 | * Split up the pre-arch/version bits into words and use them as the flavor.
|
---|
| 2009 | */
|
---|
| 2010 | psz = pszFlavor;
|
---|
| 2011 | while ((psz = strchr(psz, '-')) != NULL)
|
---|
| 2012 | *psz++ = ' ';
|
---|
| 2013 | try { mStrDetectedOSFlavor = RTStrStrip(pszFlavor); }
|
---|
| 2014 | catch (std::bad_alloc &) { return E_OUTOFMEMORY; }
|
---|
| 2015 |
|
---|
| 2016 | /*
|
---|
| 2017 | * If we don't have an architecture, we look at the vmlinuz file as the x86
|
---|
| 2018 | * and AMD64 versions starts with a MZ+PE header giving the architecture.
|
---|
| 2019 | */
|
---|
| 2020 | if ((mEnmOsType & VBOXOSTYPE_ArchitectureMask) == VBOXOSTYPE_UnknownArch)
|
---|
| 2021 | {
|
---|
| 2022 | static const char * const s_apszVmLinuz[] = { "images/pxeboot/vmlinuz", "isolinux/vmlinuz" };
|
---|
| 2023 | for (size_t i = 0; i < RT_ELEMENTS(s_apszVmLinuz); i++)
|
---|
| 2024 | {
|
---|
| 2025 | RTVFSFILE hVfsFileLinuz = NIL_RTVFSFILE;
|
---|
| 2026 | int vrc = RTVfsFileOpen(hVfsIso, s_apszVmLinuz[i], RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
|
---|
| 2027 | &hVfsFileLinuz);
|
---|
| 2028 | if (RT_SUCCESS(vrc))
|
---|
| 2029 | {
|
---|
| 2030 | /* DOS signature: */
|
---|
| 2031 | PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)&pBuf->ab[0];
|
---|
| 2032 | AssertCompile(sizeof(*pBuf) > sizeof(*pDosHdr));
|
---|
| 2033 | vrc = RTVfsFileReadAt(hVfsFileLinuz, 0, pDosHdr, sizeof(*pDosHdr), NULL);
|
---|
| 2034 | if (RT_SUCCESS(vrc) && pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
|
---|
| 2035 | {
|
---|
| 2036 | /* NT signature - only need magic + file header, so use the 64 version for better debugging: */
|
---|
| 2037 | PIMAGE_NT_HEADERS64 pNtHdrs = (PIMAGE_NT_HEADERS64)&pBuf->ab[0];
|
---|
| 2038 | vrc = RTVfsFileReadAt(hVfsFileLinuz, pDosHdr->e_lfanew, pNtHdrs, sizeof(*pNtHdrs), NULL);
|
---|
| 2039 | AssertCompile(sizeof(*pBuf) > sizeof(*pNtHdrs));
|
---|
| 2040 | if (RT_SUCCESS(vrc) && pNtHdrs->Signature == IMAGE_NT_SIGNATURE)
|
---|
| 2041 | {
|
---|
| 2042 | if (pNtHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
---|
| 2043 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & ~VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_x86);
|
---|
| 2044 | else if (pNtHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
---|
| 2045 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & ~VBOXOSTYPE_ArchitectureMask) | VBOXOSTYPE_x64);
|
---|
| 2046 | else
|
---|
| 2047 | AssertFailed();
|
---|
| 2048 | }
|
---|
| 2049 | }
|
---|
| 2050 |
|
---|
| 2051 | RTVfsFileRelease(hVfsFileLinuz);
|
---|
| 2052 | if ((mEnmOsType & VBOXOSTYPE_ArchitectureMask) != VBOXOSTYPE_UnknownArch)
|
---|
| 2053 | break;
|
---|
| 2054 | }
|
---|
| 2055 | }
|
---|
| 2056 | }
|
---|
| 2057 |
|
---|
| 2058 | /*
|
---|
| 2059 | * If that failed, look for other files that gives away the arch.
|
---|
| 2060 | */
|
---|
| 2061 | if ((mEnmOsType & VBOXOSTYPE_ArchitectureMask) == VBOXOSTYPE_UnknownArch)
|
---|
| 2062 | {
|
---|
| 2063 | static struct { const char *pszFile; VBOXOSTYPE fArch; } const s_aArchSpecificFiles[] =
|
---|
| 2064 | {
|
---|
| 2065 | { "EFI/BOOT/grubaa64.efi", VBOXOSTYPE_arm64 },
|
---|
| 2066 | { "EFI/BOOT/BOOTAA64.EFI", VBOXOSTYPE_arm64 },
|
---|
| 2067 | };
|
---|
| 2068 | PRTFSOBJINFO pObjInfo = (PRTFSOBJINFO)&pBuf->ab[0];
|
---|
| 2069 | AssertCompile(sizeof(*pBuf) > sizeof(*pObjInfo));
|
---|
| 2070 | for (size_t i = 0; i < RT_ELEMENTS(s_aArchSpecificFiles); i++)
|
---|
| 2071 | {
|
---|
| 2072 | int vrc = RTVfsQueryPathInfo(hVfsIso, s_aArchSpecificFiles[i].pszFile, pObjInfo,
|
---|
| 2073 | RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
| 2074 | if (RT_SUCCESS(vrc) && RTFS_IS_FILE(pObjInfo->Attr.fMode))
|
---|
| 2075 | {
|
---|
| 2076 | mEnmOsType = (VBOXOSTYPE)((mEnmOsType & ~VBOXOSTYPE_ArchitectureMask) | s_aArchSpecificFiles[i].fArch);
|
---|
| 2077 | break;
|
---|
| 2078 | }
|
---|
| 2079 | }
|
---|
| 2080 | }
|
---|
| 2081 |
|
---|
| 2082 | /*
|
---|
| 2083 | * If we like, we could parse grub.conf to look for fullly spelled out
|
---|
| 2084 | * flavor, though the menu items typically only contains the major version
|
---|
| 2085 | * number, so little else to add, really.
|
---|
| 2086 | */
|
---|
| 2087 |
|
---|
| 2088 | return (mEnmOsType & VBOXOSTYPE_ArchitectureMask) != VBOXOSTYPE_UnknownArch ? S_OK : S_FALSE;
|
---|
| 2089 | }
|
---|
| 2090 |
|
---|
| 2091 |
|
---|
| 2092 | /**
|
---|
[93082] | 2093 | * Detect OS/2 installation ISOs.
|
---|
| 2094 | *
|
---|
| 2095 | * Mainly aiming at ACP2/MCP2 as that's what we currently use in our testing.
|
---|
| 2096 | *
|
---|
| 2097 | * @returns COM status code.
|
---|
| 2098 | * @retval S_OK if detected
|
---|
| 2099 | * @retval S_FALSE if not fully detected.
|
---|
| 2100 | *
|
---|
| 2101 | * @param hVfsIso The ISO file system.
|
---|
| 2102 | * @param pBuf Read buffer.
|
---|
| 2103 | */
|
---|
[94079] | 2104 | HRESULT Unattended::i_innerDetectIsoOSOs2(RTVFS hVfsIso, DETECTBUFFER *pBuf)
|
---|
[93082] | 2105 | {
|
---|
| 2106 | /*
|
---|
| 2107 | * The OS2SE20.SRC contains the location of the tree with the diskette
|
---|
| 2108 | * images, typically "\OS2IMAGE".
|
---|
| 2109 | */
|
---|
| 2110 | RTVFSFILE hVfsFile;
|
---|
| 2111 | int vrc = RTVfsFileOpen(hVfsIso, "OS2SE20.SRC", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 2112 | if (RT_SUCCESS(vrc))
|
---|
| 2113 | {
|
---|
| 2114 | size_t cbRead = 0;
|
---|
| 2115 | vrc = RTVfsFileRead(hVfsFile, pBuf->sz, sizeof(pBuf->sz) - 1, &cbRead);
|
---|
| 2116 | RTVfsFileRelease(hVfsFile);
|
---|
| 2117 | if (RT_SUCCESS(vrc))
|
---|
| 2118 | {
|
---|
| 2119 | pBuf->sz[cbRead] = '\0';
|
---|
| 2120 | RTStrStrip(pBuf->sz);
|
---|
| 2121 | vrc = RTStrValidateEncoding(pBuf->sz);
|
---|
| 2122 | if (RT_SUCCESS(vrc))
|
---|
| 2123 | LogRelFlow(("Unattended: OS2SE20.SRC=%s\n", pBuf->sz));
|
---|
| 2124 | else
|
---|
| 2125 | LogRel(("Unattended: OS2SE20.SRC invalid encoding: %Rrc, %.*Rhxs\n", vrc, cbRead, pBuf->sz));
|
---|
| 2126 | }
|
---|
| 2127 | else
|
---|
| 2128 | LogRel(("Unattended: Error reading OS2SE20.SRC: %\n", vrc));
|
---|
| 2129 | }
|
---|
| 2130 | /*
|
---|
| 2131 | * ArcaOS has dropped the file, assume it's \OS2IMAGE and see if it's there.
|
---|
| 2132 | */
|
---|
| 2133 | else if (vrc == VERR_FILE_NOT_FOUND)
|
---|
| 2134 | RTStrCopy(pBuf->sz, sizeof(pBuf->sz), "\\OS2IMAGE");
|
---|
| 2135 | else
|
---|
| 2136 | return S_FALSE;
|
---|
| 2137 |
|
---|
| 2138 | /*
|
---|
| 2139 | * Check that the directory directory exists and has a DISK_0 under it
|
---|
| 2140 | * with an OS2LDR on it.
|
---|
| 2141 | */
|
---|
| 2142 | size_t const cchOs2Image = strlen(pBuf->sz);
|
---|
| 2143 | vrc = RTPathAppend(pBuf->sz, sizeof(pBuf->sz), "DISK_0/OS2LDR");
|
---|
| 2144 | RTFSOBJINFO ObjInfo = {0};
|
---|
| 2145 | vrc = RTVfsQueryPathInfo(hVfsIso, pBuf->sz, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
| 2146 | if (vrc == VERR_FILE_NOT_FOUND)
|
---|
| 2147 | {
|
---|
| 2148 | RTStrCat(pBuf->sz, sizeof(pBuf->sz), "."); /* eCS 2.0 image includes the dot from the 8.3 name. */
|
---|
| 2149 | vrc = RTVfsQueryPathInfo(hVfsIso, pBuf->sz, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
| 2150 | }
|
---|
| 2151 | if ( RT_FAILURE(vrc)
|
---|
| 2152 | || !RTFS_IS_FILE(ObjInfo.Attr.fMode))
|
---|
| 2153 | {
|
---|
| 2154 | LogRel(("Unattended: RTVfsQueryPathInfo(, '%s' (from OS2SE20.SRC),) -> %Rrc, fMode=%#x\n",
|
---|
| 2155 | pBuf->sz, vrc, ObjInfo.Attr.fMode));
|
---|
| 2156 | return S_FALSE;
|
---|
| 2157 | }
|
---|
| 2158 |
|
---|
| 2159 | /*
|
---|
| 2160 | * So, it's some kind of OS/2 2.x or later ISO alright.
|
---|
| 2161 | */
|
---|
[94079] | 2162 | mEnmOsType = VBOXOSTYPE_OS2;
|
---|
[93082] | 2163 | mStrDetectedOSHints.printf("OS2SE20.SRC=%.*s", cchOs2Image, pBuf->sz);
|
---|
| 2164 |
|
---|
| 2165 | /*
|
---|
| 2166 | * ArcaOS ISOs seems to have a AOSBOOT dir on them.
|
---|
| 2167 | * This contains a ARCANOAE.FLG file with content we can use for the version:
|
---|
| 2168 | * ArcaOS 5.0.7 EN
|
---|
| 2169 | * Built 2021-12-07 18:34:34
|
---|
[94079] | 2170 | * We drop the "ArcaOS" bit, as it's covered by mEnmOsType. Then we pull up
|
---|
[93082] | 2171 | * the second line.
|
---|
| 2172 | *
|
---|
| 2173 | * Note! Yet to find a way to do unattended install of ArcaOS, as it comes
|
---|
| 2174 | * with no CD-boot floppy images, only simple .PF archive files for
|
---|
| 2175 | * unpacking onto the ram disk or whatever. Modifying these is
|
---|
| 2176 | * possible (ibsen's aPLib v0.36 compression with some simple custom
|
---|
| 2177 | * headers), but it would probably be a royal pain. Could perhaps
|
---|
| 2178 | * cook something from OS2IMAGE\DISK_0 thru 3...
|
---|
| 2179 | */
|
---|
| 2180 | vrc = RTVfsQueryPathInfo(hVfsIso, "AOSBOOT", &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
| 2181 | if ( RT_SUCCESS(vrc)
|
---|
| 2182 | && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 2183 | {
|
---|
[94079] | 2184 | mEnmOsType = VBOXOSTYPE_ArcaOS;
|
---|
[93082] | 2185 |
|
---|
| 2186 | /* Read the version file: */
|
---|
| 2187 | vrc = RTVfsFileOpen(hVfsIso, "SYS/ARCANOAE.FLG", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 2188 | if (RT_SUCCESS(vrc))
|
---|
| 2189 | {
|
---|
| 2190 | size_t cbRead = 0;
|
---|
| 2191 | vrc = RTVfsFileRead(hVfsFile, pBuf->sz, sizeof(pBuf->sz) - 1, &cbRead);
|
---|
| 2192 | RTVfsFileRelease(hVfsFile);
|
---|
| 2193 | pBuf->sz[cbRead] = '\0';
|
---|
| 2194 | if (RT_SUCCESS(vrc))
|
---|
| 2195 | {
|
---|
| 2196 | /* Strip the OS name: */
|
---|
| 2197 | char *pszVersion = RTStrStrip(pBuf->sz);
|
---|
| 2198 | static char s_szArcaOS[] = "ArcaOS";
|
---|
| 2199 | if (RTStrStartsWith(pszVersion, s_szArcaOS))
|
---|
| 2200 | pszVersion = RTStrStripL(pszVersion + sizeof(s_szArcaOS) - 1);
|
---|
| 2201 |
|
---|
| 2202 | /* Pull up the 2nd line if it, condensing the \r\n into a single space. */
|
---|
| 2203 | char *pszNewLine = strchr(pszVersion, '\n');
|
---|
| 2204 | if (pszNewLine && RTStrStartsWith(pszNewLine + 1, "Built 20"))
|
---|
| 2205 | {
|
---|
| 2206 | size_t offRemove = 0;
|
---|
[93083] | 2207 | while (RT_C_IS_SPACE(pszNewLine[-1 - (ssize_t)offRemove]))
|
---|
[93082] | 2208 | offRemove++;
|
---|
| 2209 | if (offRemove > 0)
|
---|
| 2210 | {
|
---|
| 2211 | pszNewLine -= offRemove;
|
---|
| 2212 | memmove(pszNewLine, pszNewLine + offRemove, strlen(pszNewLine + offRemove) - 1);
|
---|
| 2213 | }
|
---|
| 2214 | *pszNewLine = ' ';
|
---|
| 2215 | }
|
---|
| 2216 |
|
---|
| 2217 | /* Drop any additional lines: */
|
---|
| 2218 | pszNewLine = strchr(pszVersion, '\n');
|
---|
| 2219 | if (pszNewLine)
|
---|
| 2220 | *pszNewLine = '\0';
|
---|
| 2221 | RTStrStripR(pszVersion);
|
---|
| 2222 |
|
---|
| 2223 | /* Done (hope it makes some sense). */
|
---|
| 2224 | mStrDetectedOSVersion = pszVersion;
|
---|
| 2225 | }
|
---|
| 2226 | else
|
---|
| 2227 | LogRel(("Unattended: failed to read AOSBOOT/ARCANOAE.FLG: %Rrc\n", vrc));
|
---|
| 2228 | }
|
---|
| 2229 | else
|
---|
| 2230 | LogRel(("Unattended: failed to open AOSBOOT/ARCANOAE.FLG for reading: %Rrc\n", vrc));
|
---|
| 2231 | }
|
---|
| 2232 | /*
|
---|
| 2233 | * Similarly, eCS has an ECS directory and it typically contains a
|
---|
| 2234 | * ECS_INST.FLG file with the version info. Content differs a little:
|
---|
| 2235 | * eComStation 2.0 EN_US Thu May 13 10:27:54 pm 2010
|
---|
| 2236 | * Built on ECS60441318
|
---|
| 2237 | * Here we drop the "eComStation" bit and leave the 2nd line as it.
|
---|
| 2238 | *
|
---|
| 2239 | * Note! At least 2.0 has a DISKIMGS folder with what looks like boot
|
---|
| 2240 | * disks, so we could probably get something going here without
|
---|
| 2241 | * needing to write an OS2 boot sector...
|
---|
| 2242 | */
|
---|
| 2243 | else
|
---|
| 2244 | {
|
---|
| 2245 | vrc = RTVfsQueryPathInfo(hVfsIso, "ECS", &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
| 2246 | if ( RT_SUCCESS(vrc)
|
---|
| 2247 | && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 2248 | {
|
---|
[94079] | 2249 | mEnmOsType = VBOXOSTYPE_ECS;
|
---|
[93082] | 2250 |
|
---|
| 2251 | /* Read the version file: */
|
---|
| 2252 | vrc = RTVfsFileOpen(hVfsIso, "ECS/ECS_INST.FLG", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 2253 | if (RT_SUCCESS(vrc))
|
---|
| 2254 | {
|
---|
| 2255 | size_t cbRead = 0;
|
---|
| 2256 | vrc = RTVfsFileRead(hVfsFile, pBuf->sz, sizeof(pBuf->sz) - 1, &cbRead);
|
---|
| 2257 | RTVfsFileRelease(hVfsFile);
|
---|
| 2258 | pBuf->sz[cbRead] = '\0';
|
---|
| 2259 | if (RT_SUCCESS(vrc))
|
---|
| 2260 | {
|
---|
| 2261 | /* Strip the OS name: */
|
---|
| 2262 | char *pszVersion = RTStrStrip(pBuf->sz);
|
---|
| 2263 | static char s_szECS[] = "eComStation";
|
---|
| 2264 | if (RTStrStartsWith(pszVersion, s_szECS))
|
---|
| 2265 | pszVersion = RTStrStripL(pszVersion + sizeof(s_szECS) - 1);
|
---|
| 2266 |
|
---|
| 2267 | /* Drop any additional lines: */
|
---|
| 2268 | char *pszNewLine = strchr(pszVersion, '\n');
|
---|
| 2269 | if (pszNewLine)
|
---|
| 2270 | *pszNewLine = '\0';
|
---|
| 2271 | RTStrStripR(pszVersion);
|
---|
| 2272 |
|
---|
| 2273 | /* Done (hope it makes some sense). */
|
---|
| 2274 | mStrDetectedOSVersion = pszVersion;
|
---|
| 2275 | }
|
---|
| 2276 | else
|
---|
| 2277 | LogRel(("Unattended: failed to read ECS/ECS_INST.FLG: %Rrc\n", vrc));
|
---|
| 2278 | }
|
---|
| 2279 | else
|
---|
| 2280 | LogRel(("Unattended: failed to open ECS/ECS_INST.FLG for reading: %Rrc\n", vrc));
|
---|
| 2281 | }
|
---|
| 2282 | else
|
---|
| 2283 | {
|
---|
| 2284 | /*
|
---|
| 2285 | * Official IBM OS/2 builds doesn't have any .FLG file on them,
|
---|
| 2286 | * so need to pry the information out in some other way. Best way
|
---|
| 2287 | * is to read the SYSLEVEL.OS2 file, which is typically on disk #2,
|
---|
| 2288 | * though on earlier versions (warp3) it was disk #1.
|
---|
| 2289 | */
|
---|
| 2290 | vrc = RTPathJoin(pBuf->sz, sizeof(pBuf->sz), strchr(mStrDetectedOSHints.c_str(), '=') + 1,
|
---|
| 2291 | "/DISK_2/SYSLEVEL.OS2");
|
---|
| 2292 | if (RT_SUCCESS(vrc))
|
---|
| 2293 | {
|
---|
| 2294 | vrc = RTVfsFileOpen(hVfsIso, pBuf->sz, RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 2295 | if (vrc == VERR_FILE_NOT_FOUND)
|
---|
| 2296 | {
|
---|
| 2297 | RTPathJoin(pBuf->sz, sizeof(pBuf->sz), strchr(mStrDetectedOSHints.c_str(), '=') + 1, "/DISK_1/SYSLEVEL.OS2");
|
---|
| 2298 | vrc = RTVfsFileOpen(hVfsIso, pBuf->sz, RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 2299 | }
|
---|
| 2300 | if (RT_SUCCESS(vrc))
|
---|
| 2301 | {
|
---|
| 2302 | RT_ZERO(pBuf->ab);
|
---|
| 2303 | size_t cbRead = 0;
|
---|
| 2304 | vrc = RTVfsFileRead(hVfsFile, pBuf->ab, sizeof(pBuf->ab), &cbRead);
|
---|
| 2305 | RTVfsFileRelease(hVfsFile);
|
---|
| 2306 | if (RT_SUCCESS(vrc))
|
---|
| 2307 | {
|
---|
| 2308 | /* Check the header. */
|
---|
| 2309 | OS2SYSLEVELHDR const *pHdr = (OS2SYSLEVELHDR const *)&pBuf->ab[0];
|
---|
| 2310 | if ( pHdr->uMinusOne == UINT16_MAX
|
---|
| 2311 | && pHdr->uSyslevelFileVer == 1
|
---|
| 2312 | && memcmp(pHdr->achSignature, RT_STR_TUPLE("SYSLEVEL")) == 0
|
---|
| 2313 | && pHdr->offTable < cbRead
|
---|
| 2314 | && pHdr->offTable + sizeof(OS2SYSLEVELENTRY) <= cbRead)
|
---|
| 2315 | {
|
---|
| 2316 | OS2SYSLEVELENTRY *pEntry = (OS2SYSLEVELENTRY *)&pBuf->ab[pHdr->offTable];
|
---|
| 2317 | if ( RT_SUCCESS(RTStrValidateEncodingEx(pEntry->szName, sizeof(pEntry->szName),
|
---|
| 2318 | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED))
|
---|
| 2319 | && RT_SUCCESS(RTStrValidateEncodingEx(pEntry->achCsdLevel, sizeof(pEntry->achCsdLevel), 0))
|
---|
| 2320 | && pEntry->bVersion != 0
|
---|
| 2321 | && ((pEntry->bVersion >> 4) & 0xf) < 10
|
---|
| 2322 | && (pEntry->bVersion & 0xf) < 10
|
---|
| 2323 | && pEntry->bModify < 10
|
---|
| 2324 | && pEntry->bRefresh < 10)
|
---|
| 2325 | {
|
---|
| 2326 | /* Flavor: */
|
---|
| 2327 | char *pszName = RTStrStrip(pEntry->szName);
|
---|
| 2328 | if (pszName)
|
---|
| 2329 | mStrDetectedOSFlavor = pszName;
|
---|
| 2330 |
|
---|
| 2331 | /* Version: */
|
---|
| 2332 | if (pEntry->bRefresh != 0)
|
---|
| 2333 | mStrDetectedOSVersion.printf("%d.%d%d.%d", pEntry->bVersion >> 4, pEntry->bVersion & 0xf,
|
---|
| 2334 | pEntry->bModify, pEntry->bRefresh);
|
---|
| 2335 | else
|
---|
| 2336 | mStrDetectedOSVersion.printf("%d.%d%d", pEntry->bVersion >> 4, pEntry->bVersion & 0xf,
|
---|
| 2337 | pEntry->bModify);
|
---|
| 2338 | pEntry->achCsdLevel[sizeof(pEntry->achCsdLevel) - 1] = '\0';
|
---|
| 2339 | char *pszCsd = RTStrStrip(pEntry->achCsdLevel);
|
---|
| 2340 | if (*pszCsd != '\0')
|
---|
| 2341 | {
|
---|
| 2342 | mStrDetectedOSVersion.append(' ');
|
---|
| 2343 | mStrDetectedOSVersion.append(pszCsd);
|
---|
| 2344 | }
|
---|
| 2345 | if (RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "4.50") >= 0)
|
---|
[94079] | 2346 | mEnmOsType = VBOXOSTYPE_OS2Warp45;
|
---|
[93082] | 2347 | else if (RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "4.00") >= 0)
|
---|
[94079] | 2348 | mEnmOsType = VBOXOSTYPE_OS2Warp4;
|
---|
[93082] | 2349 | else if (RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "3.00") >= 0)
|
---|
[94079] | 2350 | mEnmOsType = VBOXOSTYPE_OS2Warp3;
|
---|
[93082] | 2351 | }
|
---|
| 2352 | else
|
---|
| 2353 | LogRel(("Unattended: bogus SYSLEVEL.OS2 file entry: %.128Rhxd\n", pEntry));
|
---|
| 2354 | }
|
---|
| 2355 | else
|
---|
| 2356 | LogRel(("Unattended: bogus SYSLEVEL.OS2 file header: uMinusOne=%#x uSyslevelFileVer=%#x achSignature=%.8Rhxs offTable=%#x vs cbRead=%#zx\n",
|
---|
| 2357 | pHdr->uMinusOne, pHdr->uSyslevelFileVer, pHdr->achSignature, pHdr->offTable, cbRead));
|
---|
| 2358 | }
|
---|
| 2359 | else
|
---|
| 2360 | LogRel(("Unattended: failed to read SYSLEVEL.OS2: %Rrc\n", vrc));
|
---|
| 2361 | }
|
---|
| 2362 | else
|
---|
| 2363 | LogRel(("Unattended: failed to open '%s' for reading: %Rrc\n", pBuf->sz, vrc));
|
---|
| 2364 | }
|
---|
| 2365 | }
|
---|
| 2366 | }
|
---|
| 2367 |
|
---|
| 2368 | /** @todo language detection? */
|
---|
| 2369 |
|
---|
[93157] | 2370 | /*
|
---|
| 2371 | * Only tested ACP2, so only return S_OK for it.
|
---|
| 2372 | */
|
---|
[94079] | 2373 | if ( mEnmOsType == VBOXOSTYPE_OS2Warp45
|
---|
[93157] | 2374 | && RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "4.52") >= 0
|
---|
| 2375 | && mStrDetectedOSFlavor.contains("Server", RTCString::CaseInsensitive))
|
---|
| 2376 | return S_OK;
|
---|
| 2377 |
|
---|
[93082] | 2378 | return S_FALSE;
|
---|
| 2379 | }
|
---|
| 2380 |
|
---|
| 2381 |
|
---|
[95436] | 2382 | /**
|
---|
| 2383 | * Detect FreeBSD distro ISOs.
|
---|
| 2384 | *
|
---|
| 2385 | * @returns COM status code.
|
---|
| 2386 | * @retval S_OK if detected
|
---|
| 2387 | * @retval S_FALSE if not fully detected.
|
---|
| 2388 | *
|
---|
| 2389 | * @param hVfsIso The ISO file system.
|
---|
| 2390 | * @param pBuf Read buffer.
|
---|
| 2391 | */
|
---|
| 2392 | HRESULT Unattended::i_innerDetectIsoOSFreeBsd(RTVFS hVfsIso, DETECTBUFFER *pBuf)
|
---|
| 2393 | {
|
---|
| 2394 | RT_NOREF(pBuf);
|
---|
| 2395 |
|
---|
| 2396 | /*
|
---|
| 2397 | * FreeBSD since 10.0 has a .profile file in the root which can be used to determine that this is FreeBSD
|
---|
| 2398 | * along with the version.
|
---|
| 2399 | */
|
---|
| 2400 |
|
---|
| 2401 | RTVFSFILE hVfsFile;
|
---|
| 2402 | HRESULT hrc = S_FALSE;
|
---|
| 2403 | int vrc = RTVfsFileOpen(hVfsIso, ".profile", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
|
---|
| 2404 | if (RT_SUCCESS(vrc))
|
---|
| 2405 | {
|
---|
| 2406 | static const uint8_t s_abFreeBsdHdr[] = "# $FreeBSD: releng/";
|
---|
| 2407 | char abRead[32];
|
---|
| 2408 |
|
---|
| 2409 | vrc = RTVfsFileRead(hVfsFile, &abRead[0], sizeof(abRead), NULL /*pcbRead*/);
|
---|
| 2410 | if ( RT_SUCCESS(vrc)
|
---|
| 2411 | && !memcmp(&abRead[0], &s_abFreeBsdHdr[0], sizeof(s_abFreeBsdHdr) - 1)) /* Skip terminator */
|
---|
| 2412 | {
|
---|
| 2413 | abRead[sizeof(abRead) - 1] = '\0';
|
---|
| 2414 |
|
---|
| 2415 | /* Detect the architecture using the volume label. */
|
---|
| 2416 | char szVolumeId[128];
|
---|
| 2417 | size_t cchVolumeId;
|
---|
[96861] | 2418 | vrc = RTVfsQueryLabel(hVfsIso, false /*fAlternative*/, szVolumeId, 128, &cchVolumeId);
|
---|
[95436] | 2419 | if (RT_SUCCESS(vrc))
|
---|
| 2420 | {
|
---|
| 2421 | /* Can re-use the Linux code here. */
|
---|
| 2422 | if (!detectLinuxArchII(szVolumeId, &mEnmOsType, VBOXOSTYPE_FreeBSD))
|
---|
| 2423 | LogRel(("Unattended/FBSD: Unknown: arch='%s'\n", szVolumeId));
|
---|
| 2424 |
|
---|
| 2425 | /* Detect the version from the string coming after the needle in .profile. */
|
---|
| 2426 | AssertCompile(sizeof(s_abFreeBsdHdr) - 1 < sizeof(abRead));
|
---|
| 2427 |
|
---|
| 2428 | char *pszVersionStart = &abRead[sizeof(s_abFreeBsdHdr) - 1];
|
---|
| 2429 | char *pszVersionEnd = pszVersionStart;
|
---|
| 2430 |
|
---|
| 2431 | while (RT_C_IS_DIGIT(*pszVersionEnd))
|
---|
| 2432 | pszVersionEnd++;
|
---|
| 2433 | if (*pszVersionEnd == '.')
|
---|
| 2434 | {
|
---|
| 2435 | pszVersionEnd++; /* Skip the . */
|
---|
| 2436 |
|
---|
| 2437 | while (RT_C_IS_DIGIT(*pszVersionEnd))
|
---|
| 2438 | pszVersionEnd++;
|
---|
| 2439 |
|
---|
| 2440 | /* Terminate the version string. */
|
---|
| 2441 | *pszVersionEnd = '\0';
|
---|
| 2442 |
|
---|
| 2443 | try { mStrDetectedOSVersion = pszVersionStart; }
|
---|
| 2444 | catch (std::bad_alloc &) { hrc = E_OUTOFMEMORY; }
|
---|
| 2445 | }
|
---|
| 2446 | else
|
---|
| 2447 | LogRel(("Unattended/FBSD: Unknown: version='%s'\n", &abRead[0]));
|
---|
| 2448 | }
|
---|
| 2449 | else
|
---|
| 2450 | {
|
---|
| 2451 | LogRel(("Unattended/FBSD: No Volume Label found\n"));
|
---|
| 2452 | mEnmOsType = VBOXOSTYPE_FreeBSD;
|
---|
| 2453 | }
|
---|
| 2454 |
|
---|
| 2455 | hrc = S_OK;
|
---|
| 2456 | }
|
---|
| 2457 |
|
---|
| 2458 | RTVfsFileRelease(hVfsFile);
|
---|
| 2459 | }
|
---|
| 2460 |
|
---|
| 2461 | return hrc;
|
---|
| 2462 | }
|
---|
| 2463 |
|
---|
| 2464 |
|
---|
[68162] | 2465 | HRESULT Unattended::prepare()
|
---|
| 2466 | {
|
---|
| 2467 | LogFlow(("Unattended::prepare: enter\n"));
|
---|
| 2468 |
|
---|
| 2469 | /*
|
---|
| 2470 | * Must have a machine.
|
---|
| 2471 | */
|
---|
| 2472 | ComPtr<Machine> ptrMachine;
|
---|
| 2473 | Guid MachineUuid;
|
---|
| 2474 | {
|
---|
| 2475 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 2476 | ptrMachine = mMachine;
|
---|
| 2477 | if (ptrMachine.isNull())
|
---|
| 2478 | return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("No machine associated with this IUnatteded instance"));
|
---|
| 2479 | MachineUuid = mMachineUuid;
|
---|
| 2480 | }
|
---|
| 2481 |
|
---|
| 2482 | /*
|
---|
| 2483 | * Before we write lock ourselves, we must get stuff from Machine and
|
---|
| 2484 | * VirtualBox because their locks have higher priorities than ours.
|
---|
| 2485 | */
|
---|
| 2486 | Utf8Str strGuestOsTypeId;
|
---|
| 2487 | Utf8Str strMachineName;
|
---|
| 2488 | Utf8Str strDefaultAuxBasePath;
|
---|
| 2489 | HRESULT hrc;
|
---|
| 2490 | try
|
---|
| 2491 | {
|
---|
| 2492 | Bstr bstrTmp;
|
---|
| 2493 | hrc = ptrMachine->COMGETTER(OSTypeId)(bstrTmp.asOutParam());
|
---|
| 2494 | if (SUCCEEDED(hrc))
|
---|
| 2495 | {
|
---|
| 2496 | strGuestOsTypeId = bstrTmp;
|
---|
[68164] | 2497 | hrc = ptrMachine->COMGETTER(Name)(bstrTmp.asOutParam());
|
---|
[68162] | 2498 | if (SUCCEEDED(hrc))
|
---|
| 2499 | strMachineName = bstrTmp;
|
---|
| 2500 | }
|
---|
| 2501 | int vrc = ptrMachine->i_calculateFullPath(Utf8StrFmt("Unattended-%RTuuid-", MachineUuid.raw()), strDefaultAuxBasePath);
|
---|
| 2502 | if (RT_FAILURE(vrc))
|
---|
| 2503 | return setErrorBoth(E_FAIL, vrc);
|
---|
| 2504 | }
|
---|
[73505] | 2505 | catch (std::bad_alloc &)
|
---|
[68162] | 2506 | {
|
---|
| 2507 | return E_OUTOFMEMORY;
|
---|
| 2508 | }
|
---|
| 2509 | bool const fIs64Bit = i_isGuestOSArchX64(strGuestOsTypeId);
|
---|
| 2510 |
|
---|
[68164] | 2511 | BOOL fRtcUseUtc = FALSE;
|
---|
| 2512 | hrc = ptrMachine->COMGETTER(RTCUseUTC)(&fRtcUseUtc);
|
---|
| 2513 | if (FAILED(hrc))
|
---|
| 2514 | return hrc;
|
---|
[68162] | 2515 |
|
---|
[91502] | 2516 | FirmwareType_T enmFirmware = FirmwareType_BIOS;
|
---|
| 2517 | hrc = ptrMachine->COMGETTER(FirmwareType)(&enmFirmware);
|
---|
| 2518 | if (FAILED(hrc))
|
---|
| 2519 | return hrc;
|
---|
| 2520 |
|
---|
[68162] | 2521 | /*
|
---|
[68164] | 2522 | * Write lock this object and set attributes we got from IMachine.
|
---|
[68162] | 2523 | */
|
---|
| 2524 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 2525 |
|
---|
[68164] | 2526 | mStrGuestOsTypeId = strGuestOsTypeId;
|
---|
| 2527 | mfGuestOs64Bit = fIs64Bit;
|
---|
| 2528 | mfRtcUseUtc = RT_BOOL(fRtcUseUtc);
|
---|
[92732] | 2529 | menmFirmwareType = enmFirmware;
|
---|
[68164] | 2530 |
|
---|
[68162] | 2531 | /*
|
---|
| 2532 | * Do some state checks.
|
---|
| 2533 | */
|
---|
| 2534 | if (mpInstaller != NULL)
|
---|
| 2535 | return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("The prepare method has been called (must call done to restart)"));
|
---|
| 2536 | if ((Machine *)ptrMachine != (Machine *)mMachine)
|
---|
| 2537 | return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("The 'machine' while we were using it - please don't do that"));
|
---|
| 2538 |
|
---|
| 2539 | /*
|
---|
| 2540 | * Check if the specified ISOs and files exist.
|
---|
| 2541 | */
|
---|
| 2542 | if (!RTFileExists(mStrIsoPath.c_str()))
|
---|
| 2543 | return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate the installation ISO file '%s'"),
|
---|
| 2544 | mStrIsoPath.c_str());
|
---|
| 2545 | if (mfInstallGuestAdditions && !RTFileExists(mStrAdditionsIsoPath.c_str()))
|
---|
[84564] | 2546 | return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate the Guest Additions ISO file '%s'"),
|
---|
[68162] | 2547 | mStrAdditionsIsoPath.c_str());
|
---|
| 2548 | if (mfInstallTestExecService && !RTFileExists(mStrValidationKitIsoPath.c_str()))
|
---|
| 2549 | return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate the validation kit ISO file '%s'"),
|
---|
| 2550 | mStrValidationKitIsoPath.c_str());
|
---|
| 2551 | if (mStrScriptTemplatePath.isNotEmpty() && !RTFileExists(mStrScriptTemplatePath.c_str()))
|
---|
| 2552 | return setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Could not locate unattended installation script template '%s'"),
|
---|
| 2553 | mStrScriptTemplatePath.c_str());
|
---|
| 2554 |
|
---|
| 2555 | /*
|
---|
[68239] | 2556 | * Do media detection if it haven't been done yet.
|
---|
| 2557 | */
|
---|
| 2558 | if (!mfDoneDetectIsoOS)
|
---|
| 2559 | {
|
---|
| 2560 | hrc = detectIsoOS();
|
---|
| 2561 | if (FAILED(hrc) && hrc != E_NOTIMPL)
|
---|
| 2562 | return hrc;
|
---|
| 2563 | }
|
---|
| 2564 |
|
---|
[93571] | 2565 | /*
|
---|
| 2566 | * We can now check midxImage against mDetectedImages, since the latter is
|
---|
| 2567 | * populated during the detectIsoOS call. We ignore midxImage if no images
|
---|
| 2568 | * were detected, assuming that it's not relevant or used for different purposes.
|
---|
| 2569 | */
|
---|
| 2570 | if (mDetectedImages.size() > 0)
|
---|
[93545] | 2571 | {
|
---|
[93571] | 2572 | bool fImageFound = false;
|
---|
| 2573 | for (size_t i = 0; i < mDetectedImages.size(); ++i)
|
---|
| 2574 | if (midxImage == mDetectedImages[i].mImageIndex)
|
---|
| 2575 | {
|
---|
[93584] | 2576 | i_updateDetectedAttributeForImage(mDetectedImages[i]);
|
---|
[93571] | 2577 | fImageFound = true;
|
---|
| 2578 | break;
|
---|
| 2579 | }
|
---|
| 2580 | if (!fImageFound)
|
---|
| 2581 | return setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("imageIndex value %u not found in detectedImageIndices"), midxImage);
|
---|
[93545] | 2582 | }
|
---|
| 2583 |
|
---|
[68239] | 2584 | /*
|
---|
[93405] | 2585 | * Get the ISO's detect guest OS type info and make it's a known one (just
|
---|
| 2586 | * in case the above step doesn't work right).
|
---|
| 2587 | */
|
---|
| 2588 | uint32_t const idxIsoOSType = Global::getOSTypeIndexFromId(mStrDetectedOSTypeId.c_str());
|
---|
| 2589 | VBOXOSTYPE const enmIsoOSType = idxIsoOSType < Global::cOSTypes ? Global::sOSTypes[idxIsoOSType].osType : VBOXOSTYPE_Unknown;
|
---|
| 2590 | if ((enmIsoOSType & VBOXOSTYPE_OsTypeMask) == VBOXOSTYPE_Unknown)
|
---|
| 2591 | return setError(E_FAIL, tr("The supplied ISO file does not contain an OS currently supported for unattended installation"));
|
---|
| 2592 |
|
---|
| 2593 | /*
|
---|
| 2594 | * Get the VM's configured guest OS type info.
|
---|
| 2595 | */
|
---|
| 2596 | uint32_t const idxMachineOSType = Global::getOSTypeIndexFromId(mStrGuestOsTypeId.c_str());
|
---|
| 2597 | VBOXOSTYPE const enmMachineOSType = idxMachineOSType < Global::cOSTypes
|
---|
| 2598 | ? Global::sOSTypes[idxMachineOSType].osType : VBOXOSTYPE_Unknown;
|
---|
| 2599 |
|
---|
| 2600 | /*
|
---|
| 2601 | * Check that the detected guest OS type for the ISO is compatible with
|
---|
| 2602 | * that of the VM, boardly speaking.
|
---|
| 2603 | */
|
---|
| 2604 | if (idxMachineOSType != idxIsoOSType)
|
---|
| 2605 | {
|
---|
| 2606 | /* Check that the architecture is compatible: */
|
---|
| 2607 | if ( (enmIsoOSType & VBOXOSTYPE_ArchitectureMask) != (enmMachineOSType & VBOXOSTYPE_ArchitectureMask)
|
---|
| 2608 | && ( (enmIsoOSType & VBOXOSTYPE_ArchitectureMask) != VBOXOSTYPE_x86
|
---|
| 2609 | || (enmMachineOSType & VBOXOSTYPE_ArchitectureMask) != VBOXOSTYPE_x64))
|
---|
| 2610 | return setError(E_FAIL, tr("The supplied ISO file is incompatible with the guest OS type of the VM: CPU architecture mismatch"));
|
---|
| 2611 |
|
---|
| 2612 | /** @todo check BIOS/EFI requirement */
|
---|
| 2613 | }
|
---|
| 2614 |
|
---|
| 2615 | /*
|
---|
[68162] | 2616 | * Do some default property stuff and check other properties.
|
---|
| 2617 | */
|
---|
| 2618 | try
|
---|
| 2619 | {
|
---|
| 2620 | char szTmp[128];
|
---|
| 2621 |
|
---|
| 2622 | if (mStrLocale.isEmpty())
|
---|
| 2623 | {
|
---|
| 2624 | int vrc = RTLocaleQueryNormalizedBaseLocaleName(szTmp, sizeof(szTmp));
|
---|
| 2625 | if ( RT_SUCCESS(vrc)
|
---|
| 2626 | && RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(szTmp))
|
---|
| 2627 | mStrLocale.assign(szTmp, 5);
|
---|
| 2628 | else
|
---|
| 2629 | mStrLocale = "en_US";
|
---|
| 2630 | Assert(RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(mStrLocale));
|
---|
| 2631 | }
|
---|
| 2632 |
|
---|
[68239] | 2633 | if (mStrLanguage.isEmpty())
|
---|
| 2634 | {
|
---|
| 2635 | if (mDetectedOSLanguages.size() > 0)
|
---|
| 2636 | mStrLanguage = mDetectedOSLanguages[0];
|
---|
| 2637 | else
|
---|
| 2638 | mStrLanguage.assign(mStrLocale).findReplace('_', '-');
|
---|
| 2639 | }
|
---|
| 2640 |
|
---|
[68162] | 2641 | if (mStrCountry.isEmpty())
|
---|
| 2642 | {
|
---|
| 2643 | int vrc = RTLocaleQueryUserCountryCode(szTmp);
|
---|
| 2644 | if (RT_SUCCESS(vrc))
|
---|
| 2645 | mStrCountry = szTmp;
|
---|
| 2646 | else if ( mStrLocale.isNotEmpty()
|
---|
| 2647 | && RTLOCALE_IS_LANGUAGE2_UNDERSCORE_COUNTRY2(mStrLocale))
|
---|
| 2648 | mStrCountry.assign(mStrLocale, 3, 2);
|
---|
| 2649 | else
|
---|
| 2650 | mStrCountry = "US";
|
---|
| 2651 | }
|
---|
| 2652 |
|
---|
| 2653 | if (mStrTimeZone.isEmpty())
|
---|
| 2654 | {
|
---|
| 2655 | int vrc = RTTimeZoneGetCurrent(szTmp, sizeof(szTmp));
|
---|
[79910] | 2656 | if ( RT_SUCCESS(vrc)
|
---|
| 2657 | && strcmp(szTmp, "localtime") != 0 /* Typcial solaris TZ that isn't very helpful. */)
|
---|
[68162] | 2658 | mStrTimeZone = szTmp;
|
---|
| 2659 | else
|
---|
| 2660 | mStrTimeZone = "Etc/UTC";
|
---|
| 2661 | Assert(mStrTimeZone.isNotEmpty());
|
---|
| 2662 | }
|
---|
| 2663 | mpTimeZoneInfo = RTTimeZoneGetInfoByUnixName(mStrTimeZone.c_str());
|
---|
| 2664 | if (!mpTimeZoneInfo)
|
---|
| 2665 | mpTimeZoneInfo = RTTimeZoneGetInfoByWindowsName(mStrTimeZone.c_str());
|
---|
| 2666 | Assert(mpTimeZoneInfo || mStrTimeZone != "Etc/UTC");
|
---|
| 2667 | if (!mpTimeZoneInfo)
|
---|
| 2668 | LogRel(("Unattended::prepare: warning: Unknown time zone '%s'\n", mStrTimeZone.c_str()));
|
---|
| 2669 |
|
---|
| 2670 | if (mStrHostname.isEmpty())
|
---|
| 2671 | {
|
---|
| 2672 | /* Mangle the VM name into a valid hostname. */
|
---|
| 2673 | for (size_t i = 0; i < strMachineName.length(); i++)
|
---|
| 2674 | {
|
---|
| 2675 | char ch = strMachineName[i];
|
---|
| 2676 | if ( (unsigned)ch < 127
|
---|
| 2677 | && RT_C_IS_ALNUM(ch))
|
---|
| 2678 | mStrHostname.append(ch);
|
---|
| 2679 | else if (mStrHostname.isNotEmpty() && RT_C_IS_PUNCT(ch) && !mStrHostname.endsWith("-"))
|
---|
| 2680 | mStrHostname.append('-');
|
---|
| 2681 | }
|
---|
| 2682 | if (mStrHostname.length() == 0)
|
---|
| 2683 | mStrHostname.printf("%RTuuid-vm", MachineUuid.raw());
|
---|
| 2684 | else if (mStrHostname.length() < 3)
|
---|
| 2685 | mStrHostname.append("-vm");
|
---|
| 2686 | mStrHostname.append(".myguest.virtualbox.org");
|
---|
| 2687 | }
|
---|
| 2688 |
|
---|
| 2689 | if (mStrAuxiliaryBasePath.isEmpty())
|
---|
| 2690 | {
|
---|
| 2691 | mStrAuxiliaryBasePath = strDefaultAuxBasePath;
|
---|
| 2692 | mfIsDefaultAuxiliaryBasePath = true;
|
---|
| 2693 | }
|
---|
| 2694 | }
|
---|
[73505] | 2695 | catch (std::bad_alloc &)
|
---|
[68162] | 2696 | {
|
---|
| 2697 | return E_OUTOFMEMORY;
|
---|
| 2698 | }
|
---|
| 2699 |
|
---|
| 2700 | /*
|
---|
[93405] | 2701 | * Instatiate the guest installer matching the ISO.
|
---|
[68162] | 2702 | */
|
---|
[93405] | 2703 | mpInstaller = UnattendedInstaller::createInstance(enmIsoOSType, mStrDetectedOSTypeId, mStrDetectedOSVersion,
|
---|
[71007] | 2704 | mStrDetectedOSFlavor, mStrDetectedOSHints, this);
|
---|
[68162] | 2705 | if (mpInstaller != NULL)
|
---|
| 2706 | {
|
---|
| 2707 | hrc = mpInstaller->initInstaller();
|
---|
| 2708 | if (SUCCEEDED(hrc))
|
---|
| 2709 | {
|
---|
| 2710 | /*
|
---|
| 2711 | * Do the script preps (just reads them).
|
---|
| 2712 | */
|
---|
| 2713 | hrc = mpInstaller->prepareUnattendedScripts();
|
---|
| 2714 | if (SUCCEEDED(hrc))
|
---|
| 2715 | {
|
---|
| 2716 | LogFlow(("Unattended::prepare: returns S_OK\n"));
|
---|
| 2717 | return S_OK;
|
---|
| 2718 | }
|
---|
| 2719 | }
|
---|
| 2720 |
|
---|
| 2721 | /* Destroy the installer instance. */
|
---|
| 2722 | delete mpInstaller;
|
---|
| 2723 | mpInstaller = NULL;
|
---|
| 2724 | }
|
---|
| 2725 | else
|
---|
| 2726 | hrc = setErrorBoth(E_FAIL, VERR_NOT_FOUND,
|
---|
| 2727 | tr("Unattended installation is not supported for guest type '%s'"), mStrGuestOsTypeId.c_str());
|
---|
| 2728 | LogRelFlow(("Unattended::prepare: failed with %Rhrc\n", hrc));
|
---|
| 2729 | return hrc;
|
---|
| 2730 | }
|
---|
| 2731 |
|
---|
| 2732 | HRESULT Unattended::constructMedia()
|
---|
| 2733 | {
|
---|
| 2734 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 2735 |
|
---|
| 2736 | LogFlow(("===========================================================\n"));
|
---|
| 2737 | LogFlow(("Call Unattended::constructMedia()\n"));
|
---|
| 2738 |
|
---|
| 2739 | if (mpInstaller == NULL)
|
---|
| 2740 | return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "prepare() not yet called");
|
---|
| 2741 |
|
---|
| 2742 | return mpInstaller->prepareMedia();
|
---|
| 2743 | }
|
---|
| 2744 |
|
---|
| 2745 | HRESULT Unattended::reconfigureVM()
|
---|
| 2746 | {
|
---|
| 2747 | LogFlow(("===========================================================\n"));
|
---|
| 2748 | LogFlow(("Call Unattended::reconfigureVM()\n"));
|
---|
| 2749 |
|
---|
| 2750 | /*
|
---|
| 2751 | * Interrogate VirtualBox/IGuestOSType before we lock stuff and create ordering issues.
|
---|
| 2752 | */
|
---|
| 2753 | StorageBus_T enmRecommendedStorageBus = StorageBus_IDE;
|
---|
| 2754 | {
|
---|
| 2755 | Bstr bstrGuestOsTypeId;
|
---|
[93405] | 2756 | Bstr bstrDetectedOSTypeId;
|
---|
[68162] | 2757 | {
|
---|
| 2758 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
[93405] | 2759 | if (mpInstaller == NULL)
|
---|
| 2760 | return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("prepare() not yet called"));
|
---|
| 2761 | bstrGuestOsTypeId = mStrGuestOsTypeId;
|
---|
| 2762 | bstrDetectedOSTypeId = mStrDetectedOSTypeId;
|
---|
[68162] | 2763 | }
|
---|
| 2764 | ComPtr<IGuestOSType> ptrGuestOSType;
|
---|
| 2765 | HRESULT hrc = mParent->GetGuestOSType(bstrGuestOsTypeId.raw(), ptrGuestOSType.asOutParam());
|
---|
| 2766 | if (SUCCEEDED(hrc))
|
---|
[72919] | 2767 | {
|
---|
| 2768 | if (!ptrGuestOSType.isNull())
|
---|
| 2769 | hrc = ptrGuestOSType->COMGETTER(RecommendedDVDStorageBus)(&enmRecommendedStorageBus);
|
---|
| 2770 | }
|
---|
[68162] | 2771 | if (FAILED(hrc))
|
---|
| 2772 | return hrc;
|
---|
[93405] | 2773 |
|
---|
| 2774 | /* If the detected guest OS type differs, log a warning if their DVD storage
|
---|
| 2775 | bus recommendations differ. */
|
---|
| 2776 | if (bstrGuestOsTypeId != bstrDetectedOSTypeId)
|
---|
| 2777 | {
|
---|
| 2778 | StorageBus_T enmRecommendedStorageBus2 = StorageBus_IDE;
|
---|
| 2779 | hrc = mParent->GetGuestOSType(bstrDetectedOSTypeId.raw(), ptrGuestOSType.asOutParam());
|
---|
| 2780 | if (SUCCEEDED(hrc) && !ptrGuestOSType.isNull())
|
---|
| 2781 | hrc = ptrGuestOSType->COMGETTER(RecommendedDVDStorageBus)(&enmRecommendedStorageBus2);
|
---|
| 2782 | if (FAILED(hrc))
|
---|
| 2783 | return hrc;
|
---|
| 2784 |
|
---|
| 2785 | if (enmRecommendedStorageBus != enmRecommendedStorageBus2)
|
---|
| 2786 | LogRel(("Unattended::reconfigureVM: DVD storage bus recommendations differs for the VM and the ISO guest OS types: VM: %s (%ls), ISO: %s (%ls)\n",
|
---|
[93410] | 2787 | ::stringifyStorageBus(enmRecommendedStorageBus), bstrGuestOsTypeId.raw(),
|
---|
| 2788 | ::stringifyStorageBus(enmRecommendedStorageBus2), bstrDetectedOSTypeId.raw() ));
|
---|
[93405] | 2789 | }
|
---|
[68162] | 2790 | }
|
---|
| 2791 |
|
---|
| 2792 | /*
|
---|
| 2793 | * Take write lock (for lock order reasons, write lock our parent object too)
|
---|
| 2794 | * then make sure we're the only caller of this method.
|
---|
| 2795 | */
|
---|
| 2796 | AutoMultiWriteLock2 alock(mMachine, this COMMA_LOCKVAL_SRC_POS);
|
---|
| 2797 | HRESULT hrc;
|
---|
| 2798 | if (mhThreadReconfigureVM == NIL_RTNATIVETHREAD)
|
---|
| 2799 | {
|
---|
| 2800 | RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf();
|
---|
| 2801 | mhThreadReconfigureVM = hNativeSelf;
|
---|
| 2802 |
|
---|
| 2803 | /*
|
---|
| 2804 | * Create a new session, lock the machine and get the session machine object.
|
---|
| 2805 | * Do the locking without pinning down the write locks, just to be on the safe side.
|
---|
| 2806 | */
|
---|
| 2807 | ComPtr<ISession> ptrSession;
|
---|
| 2808 | try
|
---|
| 2809 | {
|
---|
| 2810 | hrc = ptrSession.createInprocObject(CLSID_Session);
|
---|
| 2811 | }
|
---|
[73505] | 2812 | catch (std::bad_alloc &)
|
---|
[68162] | 2813 | {
|
---|
| 2814 | hrc = E_OUTOFMEMORY;
|
---|
| 2815 | }
|
---|
| 2816 | if (SUCCEEDED(hrc))
|
---|
| 2817 | {
|
---|
| 2818 | alock.release();
|
---|
| 2819 | hrc = mMachine->LockMachine(ptrSession, LockType_Shared);
|
---|
| 2820 | alock.acquire();
|
---|
| 2821 | if (SUCCEEDED(hrc))
|
---|
| 2822 | {
|
---|
| 2823 | ComPtr<IMachine> ptrSessionMachine;
|
---|
| 2824 | hrc = ptrSession->COMGETTER(Machine)(ptrSessionMachine.asOutParam());
|
---|
| 2825 | if (SUCCEEDED(hrc))
|
---|
| 2826 | {
|
---|
| 2827 | /*
|
---|
| 2828 | * Hand the session to the inner work and let it do it job.
|
---|
| 2829 | */
|
---|
| 2830 | try
|
---|
| 2831 | {
|
---|
| 2832 | hrc = i_innerReconfigureVM(alock, enmRecommendedStorageBus, ptrSessionMachine);
|
---|
| 2833 | }
|
---|
| 2834 | catch (...)
|
---|
| 2835 | {
|
---|
| 2836 | hrc = E_UNEXPECTED;
|
---|
| 2837 | }
|
---|
| 2838 | }
|
---|
| 2839 |
|
---|
| 2840 | /* Paranoia: release early in case we it a bump below. */
|
---|
| 2841 | Assert(mhThreadReconfigureVM == hNativeSelf);
|
---|
| 2842 | mhThreadReconfigureVM = NIL_RTNATIVETHREAD;
|
---|
| 2843 |
|
---|
| 2844 | /*
|
---|
| 2845 | * While unlocking the machine we'll have to drop the locks again.
|
---|
| 2846 | */
|
---|
| 2847 | alock.release();
|
---|
| 2848 |
|
---|
| 2849 | ptrSessionMachine.setNull();
|
---|
| 2850 | HRESULT hrc2 = ptrSession->UnlockMachine();
|
---|
| 2851 | AssertLogRelMsg(SUCCEEDED(hrc2), ("UnlockMachine -> %Rhrc\n", hrc2));
|
---|
| 2852 |
|
---|
| 2853 | ptrSession.setNull();
|
---|
| 2854 |
|
---|
| 2855 | alock.acquire();
|
---|
| 2856 | }
|
---|
| 2857 | else
|
---|
| 2858 | mhThreadReconfigureVM = NIL_RTNATIVETHREAD;
|
---|
| 2859 | }
|
---|
| 2860 | else
|
---|
| 2861 | mhThreadReconfigureVM = NIL_RTNATIVETHREAD;
|
---|
| 2862 | }
|
---|
| 2863 | else
|
---|
| 2864 | hrc = setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("reconfigureVM running on other thread"));
|
---|
| 2865 | return hrc;
|
---|
| 2866 | }
|
---|
| 2867 |
|
---|
| 2868 |
|
---|
| 2869 | HRESULT Unattended::i_innerReconfigureVM(AutoMultiWriteLock2 &rAutoLock, StorageBus_T enmRecommendedStorageBus,
|
---|
| 2870 | ComPtr<IMachine> const &rPtrSessionMachine)
|
---|
| 2871 | {
|
---|
| 2872 | if (mpInstaller == NULL)
|
---|
[91503] | 2873 | return setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("prepare() not yet called"));
|
---|
[68162] | 2874 |
|
---|
| 2875 | // Fetch all available storage controllers
|
---|
| 2876 | com::SafeIfaceArray<IStorageController> arrayOfControllers;
|
---|
| 2877 | HRESULT hrc = rPtrSessionMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(arrayOfControllers));
|
---|
| 2878 | AssertComRCReturn(hrc, hrc);
|
---|
| 2879 |
|
---|
| 2880 | /*
|
---|
| 2881 | * Figure out where the images are to be mounted, adding controllers/ports as needed.
|
---|
| 2882 | */
|
---|
| 2883 | std::vector<UnattendedInstallationDisk> vecInstallationDisks;
|
---|
| 2884 | if (mpInstaller->isAuxiliaryFloppyNeeded())
|
---|
| 2885 | {
|
---|
| 2886 | hrc = i_reconfigureFloppy(arrayOfControllers, vecInstallationDisks, rPtrSessionMachine, rAutoLock);
|
---|
| 2887 | if (FAILED(hrc))
|
---|
| 2888 | return hrc;
|
---|
| 2889 | }
|
---|
| 2890 |
|
---|
| 2891 | hrc = i_reconfigureIsos(arrayOfControllers, vecInstallationDisks, rPtrSessionMachine, rAutoLock, enmRecommendedStorageBus);
|
---|
| 2892 | if (FAILED(hrc))
|
---|
| 2893 | return hrc;
|
---|
| 2894 |
|
---|
| 2895 | /*
|
---|
| 2896 | * Mount the images.
|
---|
| 2897 | */
|
---|
| 2898 | for (size_t idxImage = 0; idxImage < vecInstallationDisks.size(); idxImage++)
|
---|
| 2899 | {
|
---|
| 2900 | UnattendedInstallationDisk const *pImage = &vecInstallationDisks.at(idxImage);
|
---|
| 2901 | Assert(pImage->strImagePath.isNotEmpty());
|
---|
| 2902 | hrc = i_attachImage(pImage, rPtrSessionMachine, rAutoLock);
|
---|
| 2903 | if (FAILED(hrc))
|
---|
| 2904 | return hrc;
|
---|
| 2905 | }
|
---|
| 2906 |
|
---|
| 2907 | /*
|
---|
| 2908 | * Set the boot order.
|
---|
[68164] | 2909 | *
|
---|
| 2910 | * ASSUME that the HD isn't bootable when we start out, but it will be what
|
---|
| 2911 | * we boot from after the first stage of the installation is done. Setting
|
---|
| 2912 | * it first prevents endless reboot cylces.
|
---|
[68162] | 2913 | */
|
---|
[68164] | 2914 | /** @todo consider making 100% sure the disk isn't bootable (edit partition
|
---|
| 2915 | * table active bits and EFI stuff). */
|
---|
[68162] | 2916 | Assert( mpInstaller->getBootableDeviceType() == DeviceType_DVD
|
---|
| 2917 | || mpInstaller->getBootableDeviceType() == DeviceType_Floppy);
|
---|
[68164] | 2918 | hrc = rPtrSessionMachine->SetBootOrder(1, DeviceType_HardDisk);
|
---|
[68162] | 2919 | if (SUCCEEDED(hrc))
|
---|
[68164] | 2920 | hrc = rPtrSessionMachine->SetBootOrder(2, mpInstaller->getBootableDeviceType());
|
---|
[68162] | 2921 | if (SUCCEEDED(hrc))
|
---|
| 2922 | hrc = rPtrSessionMachine->SetBootOrder(3, mpInstaller->getBootableDeviceType() == DeviceType_DVD
|
---|
[72980] | 2923 | ? DeviceType_Floppy : DeviceType_DVD);
|
---|
[68162] | 2924 | if (FAILED(hrc))
|
---|
| 2925 | return hrc;
|
---|
| 2926 |
|
---|
| 2927 | /*
|
---|
| 2928 | * Essential step.
|
---|
| 2929 | *
|
---|
| 2930 | * HACK ALERT! We have to release the lock here or we'll get into trouble with
|
---|
| 2931 | * the VirtualBox lock (via i_saveHardware/NetworkAdaptger::i_hasDefaults/VirtualBox::i_findGuestOSType).
|
---|
| 2932 | */
|
---|
| 2933 | if (SUCCEEDED(hrc))
|
---|
| 2934 | {
|
---|
| 2935 | rAutoLock.release();
|
---|
| 2936 | hrc = rPtrSessionMachine->SaveSettings();
|
---|
| 2937 | rAutoLock.acquire();
|
---|
| 2938 | }
|
---|
| 2939 |
|
---|
| 2940 | return hrc;
|
---|
| 2941 | }
|
---|
| 2942 |
|
---|
| 2943 | /**
|
---|
| 2944 | * Makes sure we've got a floppy drive attached to a floppy controller, adding
|
---|
| 2945 | * the auxiliary floppy image to the installation disk vector.
|
---|
| 2946 | *
|
---|
| 2947 | * @returns COM status code.
|
---|
| 2948 | * @param rControllers The existing controllers.
|
---|
| 2949 | * @param rVecInstallatationDisks The list of image to mount.
|
---|
| 2950 | * @param rPtrSessionMachine The session machine smart pointer.
|
---|
| 2951 | * @param rAutoLock The lock.
|
---|
| 2952 | */
|
---|
| 2953 | HRESULT Unattended::i_reconfigureFloppy(com::SafeIfaceArray<IStorageController> &rControllers,
|
---|
| 2954 | std::vector<UnattendedInstallationDisk> &rVecInstallatationDisks,
|
---|
| 2955 | ComPtr<IMachine> const &rPtrSessionMachine,
|
---|
| 2956 | AutoMultiWriteLock2 &rAutoLock)
|
---|
| 2957 | {
|
---|
| 2958 | Assert(mpInstaller->isAuxiliaryFloppyNeeded());
|
---|
| 2959 |
|
---|
| 2960 | /*
|
---|
| 2961 | * Look for a floppy controller with a primary drive (A:) we can "insert"
|
---|
| 2962 | * the auxiliary floppy image. Add a controller and/or a drive if necessary.
|
---|
| 2963 | */
|
---|
| 2964 | bool fFoundPort0Dev0 = false;
|
---|
| 2965 | Bstr bstrControllerName;
|
---|
| 2966 | Utf8Str strControllerName;
|
---|
| 2967 |
|
---|
| 2968 | for (size_t i = 0; i < rControllers.size(); ++i)
|
---|
| 2969 | {
|
---|
| 2970 | StorageBus_T enmStorageBus;
|
---|
| 2971 | HRESULT hrc = rControllers[i]->COMGETTER(Bus)(&enmStorageBus);
|
---|
| 2972 | AssertComRCReturn(hrc, hrc);
|
---|
| 2973 | if (enmStorageBus == StorageBus_Floppy)
|
---|
| 2974 | {
|
---|
| 2975 |
|
---|
| 2976 | /*
|
---|
| 2977 | * Found a floppy controller.
|
---|
| 2978 | */
|
---|
| 2979 | hrc = rControllers[i]->COMGETTER(Name)(bstrControllerName.asOutParam());
|
---|
| 2980 | AssertComRCReturn(hrc, hrc);
|
---|
| 2981 |
|
---|
| 2982 | /*
|
---|
| 2983 | * Check the attchments to see if we've got a device 0 attached on port 0.
|
---|
| 2984 | *
|
---|
| 2985 | * While we're at it we eject flppies from all floppy drives we encounter,
|
---|
| 2986 | * we don't want any confusion at boot or during installation.
|
---|
| 2987 | */
|
---|
| 2988 | com::SafeIfaceArray<IMediumAttachment> arrayOfMediumAttachments;
|
---|
| 2989 | hrc = rPtrSessionMachine->GetMediumAttachmentsOfController(bstrControllerName.raw(),
|
---|
| 2990 | ComSafeArrayAsOutParam(arrayOfMediumAttachments));
|
---|
| 2991 | AssertComRCReturn(hrc, hrc);
|
---|
| 2992 | strControllerName = bstrControllerName;
|
---|
| 2993 | AssertLogRelReturn(strControllerName.isNotEmpty(), setErrorBoth(E_UNEXPECTED, VERR_INTERNAL_ERROR_2));
|
---|
| 2994 |
|
---|
| 2995 | for (size_t j = 0; j < arrayOfMediumAttachments.size(); j++)
|
---|
| 2996 | {
|
---|
| 2997 | LONG iPort = -1;
|
---|
| 2998 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Port)(&iPort);
|
---|
| 2999 | AssertComRCReturn(hrc, hrc);
|
---|
| 3000 |
|
---|
| 3001 | LONG iDevice = -1;
|
---|
| 3002 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Device)(&iDevice);
|
---|
| 3003 | AssertComRCReturn(hrc, hrc);
|
---|
| 3004 |
|
---|
| 3005 | DeviceType_T enmType;
|
---|
| 3006 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Type)(&enmType);
|
---|
| 3007 | AssertComRCReturn(hrc, hrc);
|
---|
| 3008 |
|
---|
| 3009 | if (enmType == DeviceType_Floppy)
|
---|
| 3010 | {
|
---|
| 3011 | ComPtr<IMedium> ptrMedium;
|
---|
| 3012 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Medium)(ptrMedium.asOutParam());
|
---|
| 3013 | AssertComRCReturn(hrc, hrc);
|
---|
| 3014 |
|
---|
| 3015 | if (ptrMedium.isNotNull())
|
---|
| 3016 | {
|
---|
| 3017 | ptrMedium.setNull();
|
---|
| 3018 | rAutoLock.release();
|
---|
| 3019 | hrc = rPtrSessionMachine->UnmountMedium(bstrControllerName.raw(), iPort, iDevice, TRUE /*fForce*/);
|
---|
| 3020 | rAutoLock.acquire();
|
---|
| 3021 | }
|
---|
| 3022 |
|
---|
| 3023 | if (iPort == 0 && iDevice == 0)
|
---|
| 3024 | fFoundPort0Dev0 = true;
|
---|
| 3025 | }
|
---|
| 3026 | else if (iPort == 0 && iDevice == 0)
|
---|
| 3027 | return setError(E_FAIL,
|
---|
| 3028 | tr("Found non-floppy device attached to port 0 device 0 on the floppy controller '%ls'"),
|
---|
| 3029 | bstrControllerName.raw());
|
---|
| 3030 | }
|
---|
| 3031 | }
|
---|
| 3032 | }
|
---|
| 3033 |
|
---|
| 3034 | /*
|
---|
| 3035 | * Add a floppy controller if we need to.
|
---|
| 3036 | */
|
---|
| 3037 | if (strControllerName.isEmpty())
|
---|
| 3038 | {
|
---|
| 3039 | bstrControllerName = strControllerName = "Floppy";
|
---|
| 3040 | ComPtr<IStorageController> ptrControllerIgnored;
|
---|
| 3041 | HRESULT hrc = rPtrSessionMachine->AddStorageController(bstrControllerName.raw(), StorageBus_Floppy,
|
---|
| 3042 | ptrControllerIgnored.asOutParam());
|
---|
| 3043 | LogRelFunc(("Machine::addStorageController(Floppy) -> %Rhrc \n", hrc));
|
---|
| 3044 | if (FAILED(hrc))
|
---|
| 3045 | return hrc;
|
---|
| 3046 | }
|
---|
| 3047 |
|
---|
| 3048 | /*
|
---|
| 3049 | * Adding a floppy drive (if needed) and mounting the auxiliary image is
|
---|
| 3050 | * done later together with the ISOs.
|
---|
| 3051 | */
|
---|
| 3052 | rVecInstallatationDisks.push_back(UnattendedInstallationDisk(StorageBus_Floppy, strControllerName,
|
---|
| 3053 | DeviceType_Floppy, AccessMode_ReadWrite,
|
---|
| 3054 | 0, 0,
|
---|
| 3055 | fFoundPort0Dev0 /*fMountOnly*/,
|
---|
[98035] | 3056 | mpInstaller->getAuxiliaryFloppyFilePath(), false));
|
---|
[68162] | 3057 | return S_OK;
|
---|
| 3058 | }
|
---|
| 3059 |
|
---|
| 3060 | /**
|
---|
| 3061 | * Reconfigures DVD drives of the VM to mount all the ISOs we need.
|
---|
| 3062 | *
|
---|
| 3063 | * This will umount all DVD media.
|
---|
| 3064 | *
|
---|
| 3065 | * @returns COM status code.
|
---|
| 3066 | * @param rControllers The existing controllers.
|
---|
| 3067 | * @param rVecInstallatationDisks The list of image to mount.
|
---|
| 3068 | * @param rPtrSessionMachine The session machine smart pointer.
|
---|
| 3069 | * @param rAutoLock The lock.
|
---|
| 3070 | * @param enmRecommendedStorageBus The recommended storage bus type for adding
|
---|
| 3071 | * DVD drives on.
|
---|
| 3072 | */
|
---|
| 3073 | HRESULT Unattended::i_reconfigureIsos(com::SafeIfaceArray<IStorageController> &rControllers,
|
---|
| 3074 | std::vector<UnattendedInstallationDisk> &rVecInstallatationDisks,
|
---|
| 3075 | ComPtr<IMachine> const &rPtrSessionMachine,
|
---|
| 3076 | AutoMultiWriteLock2 &rAutoLock, StorageBus_T enmRecommendedStorageBus)
|
---|
| 3077 | {
|
---|
| 3078 | /*
|
---|
| 3079 | * Enumerate the attachements of every controller, looking for DVD drives,
|
---|
| 3080 | * ASSUMEING all drives are bootable.
|
---|
| 3081 | *
|
---|
| 3082 | * Eject the medium from all the drives (don't want any confusion) and look
|
---|
| 3083 | * for the recommended storage bus in case we need to add more drives.
|
---|
| 3084 | */
|
---|
| 3085 | HRESULT hrc;
|
---|
| 3086 | std::list<ControllerSlot> lstControllerDvdSlots;
|
---|
| 3087 | Utf8Str strRecommendedControllerName; /* non-empty if recommended bus found. */
|
---|
| 3088 | Utf8Str strControllerName;
|
---|
| 3089 | Bstr bstrControllerName;
|
---|
| 3090 | for (size_t i = 0; i < rControllers.size(); ++i)
|
---|
| 3091 | {
|
---|
| 3092 | hrc = rControllers[i]->COMGETTER(Name)(bstrControllerName.asOutParam());
|
---|
| 3093 | AssertComRCReturn(hrc, hrc);
|
---|
| 3094 | strControllerName = bstrControllerName;
|
---|
| 3095 |
|
---|
| 3096 | /* Look for recommended storage bus. */
|
---|
| 3097 | StorageBus_T enmStorageBus;
|
---|
| 3098 | hrc = rControllers[i]->COMGETTER(Bus)(&enmStorageBus);
|
---|
| 3099 | AssertComRCReturn(hrc, hrc);
|
---|
| 3100 | if (enmStorageBus == enmRecommendedStorageBus)
|
---|
| 3101 | {
|
---|
| 3102 | strRecommendedControllerName = bstrControllerName;
|
---|
| 3103 | AssertLogRelReturn(strControllerName.isNotEmpty(), setErrorBoth(E_UNEXPECTED, VERR_INTERNAL_ERROR_2));
|
---|
| 3104 | }
|
---|
| 3105 |
|
---|
| 3106 | /* Scan the controller attachments. */
|
---|
| 3107 | com::SafeIfaceArray<IMediumAttachment> arrayOfMediumAttachments;
|
---|
| 3108 | hrc = rPtrSessionMachine->GetMediumAttachmentsOfController(bstrControllerName.raw(),
|
---|
| 3109 | ComSafeArrayAsOutParam(arrayOfMediumAttachments));
|
---|
| 3110 | AssertComRCReturn(hrc, hrc);
|
---|
| 3111 |
|
---|
| 3112 | for (size_t j = 0; j < arrayOfMediumAttachments.size(); j++)
|
---|
| 3113 | {
|
---|
| 3114 | DeviceType_T enmType;
|
---|
| 3115 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Type)(&enmType);
|
---|
| 3116 | AssertComRCReturn(hrc, hrc);
|
---|
| 3117 | if (enmType == DeviceType_DVD)
|
---|
| 3118 | {
|
---|
| 3119 | LONG iPort = -1;
|
---|
| 3120 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Port)(&iPort);
|
---|
| 3121 | AssertComRCReturn(hrc, hrc);
|
---|
| 3122 |
|
---|
| 3123 | LONG iDevice = -1;
|
---|
| 3124 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Device)(&iDevice);
|
---|
| 3125 | AssertComRCReturn(hrc, hrc);
|
---|
| 3126 |
|
---|
| 3127 | /* Remeber it. */
|
---|
| 3128 | lstControllerDvdSlots.push_back(ControllerSlot(enmStorageBus, strControllerName, iPort, iDevice, false /*fFree*/));
|
---|
| 3129 |
|
---|
| 3130 | /* Eject the medium, if any. */
|
---|
| 3131 | ComPtr<IMedium> ptrMedium;
|
---|
| 3132 | hrc = arrayOfMediumAttachments[j]->COMGETTER(Medium)(ptrMedium.asOutParam());
|
---|
| 3133 | AssertComRCReturn(hrc, hrc);
|
---|
| 3134 | if (ptrMedium.isNotNull())
|
---|
| 3135 | {
|
---|
| 3136 | ptrMedium.setNull();
|
---|
| 3137 |
|
---|
| 3138 | rAutoLock.release();
|
---|
| 3139 | hrc = rPtrSessionMachine->UnmountMedium(bstrControllerName.raw(), iPort, iDevice, TRUE /*fForce*/);
|
---|
| 3140 | rAutoLock.acquire();
|
---|
| 3141 | }
|
---|
| 3142 | }
|
---|
| 3143 | }
|
---|
| 3144 | }
|
---|
| 3145 |
|
---|
| 3146 | /*
|
---|
| 3147 | * How many drives do we need? Add more if necessary.
|
---|
| 3148 | */
|
---|
| 3149 | ULONG cDvdDrivesNeeded = 0;
|
---|
| 3150 | if (mpInstaller->isAuxiliaryIsoNeeded())
|
---|
| 3151 | cDvdDrivesNeeded++;
|
---|
| 3152 | if (mpInstaller->isOriginalIsoNeeded())
|
---|
| 3153 | cDvdDrivesNeeded++;
|
---|
[68222] | 3154 | #if 0 /* These are now in the AUX VISO. */
|
---|
[68162] | 3155 | if (mpInstaller->isAdditionsIsoNeeded())
|
---|
| 3156 | cDvdDrivesNeeded++;
|
---|
| 3157 | if (mpInstaller->isValidationKitIsoNeeded())
|
---|
| 3158 | cDvdDrivesNeeded++;
|
---|
[68222] | 3159 | #endif
|
---|
[68162] | 3160 | Assert(cDvdDrivesNeeded > 0);
|
---|
| 3161 | if (cDvdDrivesNeeded > lstControllerDvdSlots.size())
|
---|
| 3162 | {
|
---|
| 3163 | /* Do we need to add the recommended controller? */
|
---|
| 3164 | if (strRecommendedControllerName.isEmpty())
|
---|
| 3165 | {
|
---|
| 3166 | switch (enmRecommendedStorageBus)
|
---|
| 3167 | {
|
---|
| 3168 | case StorageBus_IDE: strRecommendedControllerName = "IDE"; break;
|
---|
| 3169 | case StorageBus_SATA: strRecommendedControllerName = "SATA"; break;
|
---|
| 3170 | case StorageBus_SCSI: strRecommendedControllerName = "SCSI"; break;
|
---|
| 3171 | case StorageBus_SAS: strRecommendedControllerName = "SAS"; break;
|
---|
| 3172 | case StorageBus_USB: strRecommendedControllerName = "USB"; break;
|
---|
| 3173 | case StorageBus_PCIe: strRecommendedControllerName = "PCIe"; break;
|
---|
| 3174 | default:
|
---|
| 3175 | return setError(E_FAIL, tr("Support for recommended storage bus %d not implemented"),
|
---|
| 3176 | (int)enmRecommendedStorageBus);
|
---|
| 3177 | }
|
---|
| 3178 | ComPtr<IStorageController> ptrControllerIgnored;
|
---|
| 3179 | hrc = rPtrSessionMachine->AddStorageController(Bstr(strRecommendedControllerName).raw(), enmRecommendedStorageBus,
|
---|
| 3180 | ptrControllerIgnored.asOutParam());
|
---|
| 3181 | LogRelFunc(("Machine::addStorageController(%s) -> %Rhrc \n", strRecommendedControllerName.c_str(), hrc));
|
---|
| 3182 | if (FAILED(hrc))
|
---|
| 3183 | return hrc;
|
---|
| 3184 | }
|
---|
| 3185 |
|
---|
| 3186 | /* Add free controller slots, maybe raising the port limit on the controller if we can. */
|
---|
| 3187 | hrc = i_findOrCreateNeededFreeSlots(strRecommendedControllerName, enmRecommendedStorageBus, rPtrSessionMachine,
|
---|
| 3188 | cDvdDrivesNeeded, lstControllerDvdSlots);
|
---|
| 3189 | if (FAILED(hrc))
|
---|
| 3190 | return hrc;
|
---|
| 3191 | if (cDvdDrivesNeeded > lstControllerDvdSlots.size())
|
---|
| 3192 | {
|
---|
| 3193 | /* We could in many cases create another controller here, but it's not worth the effort. */
|
---|
[91718] | 3194 | return setError(E_FAIL, tr("Not enough free slots on controller '%s' to add %u DVD drive(s)", "",
|
---|
| 3195 | cDvdDrivesNeeded - lstControllerDvdSlots.size()),
|
---|
[68162] | 3196 | strRecommendedControllerName.c_str(), cDvdDrivesNeeded - lstControllerDvdSlots.size());
|
---|
| 3197 | }
|
---|
| 3198 | Assert(cDvdDrivesNeeded == lstControllerDvdSlots.size());
|
---|
| 3199 | }
|
---|
| 3200 |
|
---|
| 3201 | /*
|
---|
| 3202 | * Sort the DVD slots in boot order.
|
---|
| 3203 | */
|
---|
| 3204 | lstControllerDvdSlots.sort();
|
---|
| 3205 |
|
---|
| 3206 | /*
|
---|
| 3207 | * Prepare ISO mounts.
|
---|
| 3208 | *
|
---|
[68222] | 3209 | * Boot order depends on bootFromAuxiliaryIso() and we must grab DVD slots
|
---|
| 3210 | * according to the boot order.
|
---|
[68162] | 3211 | */
|
---|
| 3212 | std::list<ControllerSlot>::const_iterator itDvdSlot = lstControllerDvdSlots.begin();
|
---|
[68222] | 3213 | if (mpInstaller->isAuxiliaryIsoNeeded() && mpInstaller->bootFromAuxiliaryIso())
|
---|
[68162] | 3214 | {
|
---|
[98035] | 3215 | rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, mpInstaller->getAuxiliaryIsoFilePath(), true));
|
---|
[68162] | 3216 | ++itDvdSlot;
|
---|
| 3217 | }
|
---|
| 3218 |
|
---|
| 3219 | if (mpInstaller->isOriginalIsoNeeded())
|
---|
| 3220 | {
|
---|
[98035] | 3221 | rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, i_getIsoPath(), false));
|
---|
[68162] | 3222 | ++itDvdSlot;
|
---|
| 3223 | }
|
---|
| 3224 |
|
---|
[68222] | 3225 | if (mpInstaller->isAuxiliaryIsoNeeded() && !mpInstaller->bootFromAuxiliaryIso())
|
---|
| 3226 | {
|
---|
[98035] | 3227 | rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, mpInstaller->getAuxiliaryIsoFilePath(), true));
|
---|
[68222] | 3228 | ++itDvdSlot;
|
---|
| 3229 | }
|
---|
| 3230 |
|
---|
| 3231 | #if 0 /* These are now in the AUX VISO. */
|
---|
[68162] | 3232 | if (mpInstaller->isAdditionsIsoNeeded())
|
---|
| 3233 | {
|
---|
[98035] | 3234 | rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, i_getAdditionsIsoPath(), false));
|
---|
[68162] | 3235 | ++itDvdSlot;
|
---|
| 3236 | }
|
---|
| 3237 |
|
---|
| 3238 | if (mpInstaller->isValidationKitIsoNeeded())
|
---|
| 3239 | {
|
---|
[98035] | 3240 | rVecInstallatationDisks.push_back(UnattendedInstallationDisk(itDvdSlot, i_getValidationKitIsoPath(), false));
|
---|
[68162] | 3241 | ++itDvdSlot;
|
---|
| 3242 | }
|
---|
[68222] | 3243 | #endif
|
---|
[68162] | 3244 |
|
---|
| 3245 | return S_OK;
|
---|
| 3246 | }
|
---|
| 3247 |
|
---|
| 3248 | /**
|
---|
| 3249 | * Used to find more free slots for DVD drives during VM reconfiguration.
|
---|
| 3250 | *
|
---|
| 3251 | * This may modify the @a portCount property of the given controller.
|
---|
| 3252 | *
|
---|
| 3253 | * @returns COM status code.
|
---|
| 3254 | * @param rStrControllerName The name of the controller to find/create
|
---|
| 3255 | * free slots on.
|
---|
| 3256 | * @param enmStorageBus The storage bus type.
|
---|
| 3257 | * @param rPtrSessionMachine Reference to the session machine.
|
---|
| 3258 | * @param cSlotsNeeded Total slots needed (including those we've
|
---|
| 3259 | * already found).
|
---|
| 3260 | * @param rDvdSlots The slot collection for DVD drives to add
|
---|
| 3261 | * free slots to as we find/create them.
|
---|
| 3262 | */
|
---|
| 3263 | HRESULT Unattended::i_findOrCreateNeededFreeSlots(const Utf8Str &rStrControllerName, StorageBus_T enmStorageBus,
|
---|
| 3264 | ComPtr<IMachine> const &rPtrSessionMachine, uint32_t cSlotsNeeded,
|
---|
| 3265 | std::list<ControllerSlot> &rDvdSlots)
|
---|
| 3266 | {
|
---|
| 3267 | Assert(cSlotsNeeded > rDvdSlots.size());
|
---|
| 3268 |
|
---|
| 3269 | /*
|
---|
| 3270 | * Get controlleer stats.
|
---|
| 3271 | */
|
---|
| 3272 | ComPtr<IStorageController> pController;
|
---|
| 3273 | HRESULT hrc = rPtrSessionMachine->GetStorageControllerByName(Bstr(rStrControllerName).raw(), pController.asOutParam());
|
---|
| 3274 | AssertComRCReturn(hrc, hrc);
|
---|
| 3275 |
|
---|
| 3276 | ULONG cMaxDevicesPerPort = 1;
|
---|
| 3277 | hrc = pController->COMGETTER(MaxDevicesPerPortCount)(&cMaxDevicesPerPort);
|
---|
| 3278 | AssertComRCReturn(hrc, hrc);
|
---|
| 3279 | AssertLogRelReturn(cMaxDevicesPerPort > 0, E_UNEXPECTED);
|
---|
| 3280 |
|
---|
| 3281 | ULONG cPorts = 0;
|
---|
| 3282 | hrc = pController->COMGETTER(PortCount)(&cPorts);
|
---|
| 3283 | AssertComRCReturn(hrc, hrc);
|
---|
| 3284 |
|
---|
| 3285 | /*
|
---|
| 3286 | * Get the attachment list and turn into an internal list for lookup speed.
|
---|
| 3287 | */
|
---|
| 3288 | com::SafeIfaceArray<IMediumAttachment> arrayOfMediumAttachments;
|
---|
| 3289 | hrc = rPtrSessionMachine->GetMediumAttachmentsOfController(Bstr(rStrControllerName).raw(),
|
---|
| 3290 | ComSafeArrayAsOutParam(arrayOfMediumAttachments));
|
---|
| 3291 | AssertComRCReturn(hrc, hrc);
|
---|
| 3292 |
|
---|
| 3293 | std::vector<ControllerSlot> arrayOfUsedSlots;
|
---|
| 3294 | for (size_t i = 0; i < arrayOfMediumAttachments.size(); i++)
|
---|
| 3295 | {
|
---|
| 3296 | LONG iPort = -1;
|
---|
| 3297 | hrc = arrayOfMediumAttachments[i]->COMGETTER(Port)(&iPort);
|
---|
| 3298 | AssertComRCReturn(hrc, hrc);
|
---|
| 3299 |
|
---|
| 3300 | LONG iDevice = -1;
|
---|
| 3301 | hrc = arrayOfMediumAttachments[i]->COMGETTER(Device)(&iDevice);
|
---|
| 3302 | AssertComRCReturn(hrc, hrc);
|
---|
| 3303 |
|
---|
| 3304 | arrayOfUsedSlots.push_back(ControllerSlot(enmStorageBus, Utf8Str::Empty, iPort, iDevice, false /*fFree*/));
|
---|
| 3305 | }
|
---|
| 3306 |
|
---|
| 3307 | /*
|
---|
| 3308 | * Iterate thru all possible slots, adding those not found in arrayOfUsedSlots.
|
---|
| 3309 | */
|
---|
[85277] | 3310 | for (int32_t iPort = 0; iPort < (int32_t)cPorts; iPort++)
|
---|
| 3311 | for (int32_t iDevice = 0; iDevice < (int32_t)cMaxDevicesPerPort; iDevice++)
|
---|
[68162] | 3312 | {
|
---|
| 3313 | bool fFound = false;
|
---|
| 3314 | for (size_t i = 0; i < arrayOfUsedSlots.size(); i++)
|
---|
[85277] | 3315 | if ( arrayOfUsedSlots[i].iPort == iPort
|
---|
| 3316 | && arrayOfUsedSlots[i].iDevice == iDevice)
|
---|
[68162] | 3317 | {
|
---|
| 3318 | fFound = true;
|
---|
| 3319 | break;
|
---|
| 3320 | }
|
---|
| 3321 | if (!fFound)
|
---|
| 3322 | {
|
---|
| 3323 | rDvdSlots.push_back(ControllerSlot(enmStorageBus, rStrControllerName, iPort, iDevice, true /*fFree*/));
|
---|
| 3324 | if (rDvdSlots.size() >= cSlotsNeeded)
|
---|
| 3325 | return S_OK;
|
---|
| 3326 | }
|
---|
| 3327 | }
|
---|
| 3328 |
|
---|
| 3329 | /*
|
---|
| 3330 | * Okay we still need more ports. See if increasing the number of controller
|
---|
| 3331 | * ports would solve it.
|
---|
| 3332 | */
|
---|
| 3333 | ULONG cMaxPorts = 1;
|
---|
| 3334 | hrc = pController->COMGETTER(MaxPortCount)(&cMaxPorts);
|
---|
| 3335 | AssertComRCReturn(hrc, hrc);
|
---|
| 3336 | if (cMaxPorts <= cPorts)
|
---|
| 3337 | return S_OK;
|
---|
| 3338 | size_t cNewPortsNeeded = (cSlotsNeeded - rDvdSlots.size() + cMaxDevicesPerPort - 1) / cMaxDevicesPerPort;
|
---|
| 3339 | if (cPorts + cNewPortsNeeded > cMaxPorts)
|
---|
| 3340 | return S_OK;
|
---|
| 3341 |
|
---|
| 3342 | /*
|
---|
| 3343 | * Raise the port count and add the free slots we've just created.
|
---|
| 3344 | */
|
---|
| 3345 | hrc = pController->COMSETTER(PortCount)(cPorts + (ULONG)cNewPortsNeeded);
|
---|
| 3346 | AssertComRCReturn(hrc, hrc);
|
---|
[85277] | 3347 | int32_t const cPortsNew = (int32_t)(cPorts + cNewPortsNeeded);
|
---|
| 3348 | for (int32_t iPort = (int32_t)cPorts; iPort < cPortsNew; iPort++)
|
---|
| 3349 | for (int32_t iDevice = 0; iDevice < (int32_t)cMaxDevicesPerPort; iDevice++)
|
---|
[68162] | 3350 | {
|
---|
| 3351 | rDvdSlots.push_back(ControllerSlot(enmStorageBus, rStrControllerName, iPort, iDevice, true /*fFree*/));
|
---|
| 3352 | if (rDvdSlots.size() >= cSlotsNeeded)
|
---|
| 3353 | return S_OK;
|
---|
| 3354 | }
|
---|
| 3355 |
|
---|
| 3356 | /* We should not get here! */
|
---|
| 3357 | AssertLogRelFailedReturn(E_UNEXPECTED);
|
---|
| 3358 | }
|
---|
| 3359 |
|
---|
| 3360 | HRESULT Unattended::done()
|
---|
| 3361 | {
|
---|
| 3362 | LogFlow(("Unattended::done\n"));
|
---|
| 3363 | if (mpInstaller)
|
---|
| 3364 | {
|
---|
| 3365 | LogRelFlow(("Unattended::done: Deleting installer object (%p)\n", mpInstaller));
|
---|
| 3366 | delete mpInstaller;
|
---|
| 3367 | mpInstaller = NULL;
|
---|
| 3368 | }
|
---|
| 3369 | return S_OK;
|
---|
| 3370 | }
|
---|
| 3371 |
|
---|
| 3372 | HRESULT Unattended::getIsoPath(com::Utf8Str &isoPath)
|
---|
| 3373 | {
|
---|
| 3374 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3375 | isoPath = mStrIsoPath;
|
---|
| 3376 | return S_OK;
|
---|
| 3377 | }
|
---|
| 3378 |
|
---|
| 3379 | HRESULT Unattended::setIsoPath(const com::Utf8Str &isoPath)
|
---|
| 3380 | {
|
---|
| 3381 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3382 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
[68239] | 3383 | mStrIsoPath = isoPath;
|
---|
| 3384 | mfDoneDetectIsoOS = false;
|
---|
[68162] | 3385 | return S_OK;
|
---|
| 3386 | }
|
---|
| 3387 |
|
---|
| 3388 | HRESULT Unattended::getUser(com::Utf8Str &user)
|
---|
| 3389 | {
|
---|
| 3390 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3391 | user = mStrUser;
|
---|
| 3392 | return S_OK;
|
---|
| 3393 | }
|
---|
| 3394 |
|
---|
| 3395 |
|
---|
| 3396 | HRESULT Unattended::setUser(const com::Utf8Str &user)
|
---|
| 3397 | {
|
---|
| 3398 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3399 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3400 | mStrUser = user;
|
---|
| 3401 | return S_OK;
|
---|
| 3402 | }
|
---|
| 3403 |
|
---|
| 3404 | HRESULT Unattended::getPassword(com::Utf8Str &password)
|
---|
| 3405 | {
|
---|
| 3406 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3407 | password = mStrPassword;
|
---|
| 3408 | return S_OK;
|
---|
| 3409 | }
|
---|
| 3410 |
|
---|
| 3411 | HRESULT Unattended::setPassword(const com::Utf8Str &password)
|
---|
| 3412 | {
|
---|
| 3413 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3414 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3415 | mStrPassword = password;
|
---|
| 3416 | return S_OK;
|
---|
| 3417 | }
|
---|
| 3418 |
|
---|
| 3419 | HRESULT Unattended::getFullUserName(com::Utf8Str &fullUserName)
|
---|
| 3420 | {
|
---|
| 3421 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3422 | fullUserName = mStrFullUserName;
|
---|
| 3423 | return S_OK;
|
---|
| 3424 | }
|
---|
| 3425 |
|
---|
| 3426 | HRESULT Unattended::setFullUserName(const com::Utf8Str &fullUserName)
|
---|
| 3427 | {
|
---|
| 3428 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3429 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3430 | mStrFullUserName = fullUserName;
|
---|
| 3431 | return S_OK;
|
---|
| 3432 | }
|
---|
| 3433 |
|
---|
| 3434 | HRESULT Unattended::getProductKey(com::Utf8Str &productKey)
|
---|
| 3435 | {
|
---|
| 3436 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3437 | productKey = mStrProductKey;
|
---|
| 3438 | return S_OK;
|
---|
| 3439 | }
|
---|
| 3440 |
|
---|
| 3441 | HRESULT Unattended::setProductKey(const com::Utf8Str &productKey)
|
---|
| 3442 | {
|
---|
| 3443 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3444 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3445 | mStrProductKey = productKey;
|
---|
| 3446 | return S_OK;
|
---|
| 3447 | }
|
---|
| 3448 |
|
---|
| 3449 | HRESULT Unattended::getAdditionsIsoPath(com::Utf8Str &additionsIsoPath)
|
---|
| 3450 | {
|
---|
| 3451 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3452 | additionsIsoPath = mStrAdditionsIsoPath;
|
---|
| 3453 | return S_OK;
|
---|
| 3454 | }
|
---|
| 3455 |
|
---|
| 3456 | HRESULT Unattended::setAdditionsIsoPath(const com::Utf8Str &additionsIsoPath)
|
---|
| 3457 | {
|
---|
| 3458 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3459 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3460 | mStrAdditionsIsoPath = additionsIsoPath;
|
---|
| 3461 | return S_OK;
|
---|
| 3462 | }
|
---|
| 3463 |
|
---|
| 3464 | HRESULT Unattended::getInstallGuestAdditions(BOOL *installGuestAdditions)
|
---|
| 3465 | {
|
---|
| 3466 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3467 | *installGuestAdditions = mfInstallGuestAdditions;
|
---|
| 3468 | return S_OK;
|
---|
| 3469 | }
|
---|
| 3470 |
|
---|
| 3471 | HRESULT Unattended::setInstallGuestAdditions(BOOL installGuestAdditions)
|
---|
| 3472 | {
|
---|
| 3473 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3474 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3475 | mfInstallGuestAdditions = installGuestAdditions != FALSE;
|
---|
| 3476 | return S_OK;
|
---|
| 3477 | }
|
---|
| 3478 |
|
---|
| 3479 | HRESULT Unattended::getValidationKitIsoPath(com::Utf8Str &aValidationKitIsoPath)
|
---|
| 3480 | {
|
---|
| 3481 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3482 | aValidationKitIsoPath = mStrValidationKitIsoPath;
|
---|
| 3483 | return S_OK;
|
---|
| 3484 | }
|
---|
| 3485 |
|
---|
| 3486 | HRESULT Unattended::setValidationKitIsoPath(const com::Utf8Str &aValidationKitIsoPath)
|
---|
| 3487 | {
|
---|
| 3488 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3489 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3490 | mStrValidationKitIsoPath = aValidationKitIsoPath;
|
---|
| 3491 | return S_OK;
|
---|
| 3492 | }
|
---|
| 3493 |
|
---|
| 3494 | HRESULT Unattended::getInstallTestExecService(BOOL *aInstallTestExecService)
|
---|
| 3495 | {
|
---|
| 3496 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3497 | *aInstallTestExecService = mfInstallTestExecService;
|
---|
| 3498 | return S_OK;
|
---|
| 3499 | }
|
---|
| 3500 |
|
---|
| 3501 | HRESULT Unattended::setInstallTestExecService(BOOL aInstallTestExecService)
|
---|
| 3502 | {
|
---|
| 3503 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3504 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3505 | mfInstallTestExecService = aInstallTestExecService != FALSE;
|
---|
| 3506 | return S_OK;
|
---|
| 3507 | }
|
---|
| 3508 |
|
---|
| 3509 | HRESULT Unattended::getTimeZone(com::Utf8Str &aTimeZone)
|
---|
| 3510 | {
|
---|
| 3511 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3512 | aTimeZone = mStrTimeZone;
|
---|
| 3513 | return S_OK;
|
---|
| 3514 | }
|
---|
| 3515 |
|
---|
| 3516 | HRESULT Unattended::setTimeZone(const com::Utf8Str &aTimezone)
|
---|
| 3517 | {
|
---|
| 3518 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3519 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3520 | mStrTimeZone = aTimezone;
|
---|
| 3521 | return S_OK;
|
---|
| 3522 | }
|
---|
| 3523 |
|
---|
| 3524 | HRESULT Unattended::getLocale(com::Utf8Str &aLocale)
|
---|
| 3525 | {
|
---|
| 3526 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3527 | aLocale = mStrLocale;
|
---|
| 3528 | return S_OK;
|
---|
| 3529 | }
|
---|
| 3530 |
|
---|
| 3531 | HRESULT Unattended::setLocale(const com::Utf8Str &aLocale)
|
---|
| 3532 | {
|
---|
| 3533 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3534 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3535 | if ( aLocale.isEmpty() /* use default */
|
---|
| 3536 | || ( aLocale.length() == 5
|
---|
| 3537 | && RT_C_IS_LOWER(aLocale[0])
|
---|
| 3538 | && RT_C_IS_LOWER(aLocale[1])
|
---|
| 3539 | && aLocale[2] == '_'
|
---|
| 3540 | && RT_C_IS_UPPER(aLocale[3])
|
---|
| 3541 | && RT_C_IS_UPPER(aLocale[4])) )
|
---|
| 3542 | {
|
---|
| 3543 | mStrLocale = aLocale;
|
---|
| 3544 | return S_OK;
|
---|
| 3545 | }
|
---|
| 3546 | return setError(E_INVALIDARG, tr("Expected two lower cased letters, an underscore, and two upper cased letters"));
|
---|
| 3547 | }
|
---|
| 3548 |
|
---|
[68239] | 3549 | HRESULT Unattended::getLanguage(com::Utf8Str &aLanguage)
|
---|
| 3550 | {
|
---|
| 3551 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3552 | aLanguage = mStrLanguage;
|
---|
| 3553 | return S_OK;
|
---|
| 3554 | }
|
---|
| 3555 |
|
---|
| 3556 | HRESULT Unattended::setLanguage(const com::Utf8Str &aLanguage)
|
---|
| 3557 | {
|
---|
| 3558 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3559 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3560 | mStrLanguage = aLanguage;
|
---|
| 3561 | return S_OK;
|
---|
| 3562 | }
|
---|
| 3563 |
|
---|
[68162] | 3564 | HRESULT Unattended::getCountry(com::Utf8Str &aCountry)
|
---|
| 3565 | {
|
---|
| 3566 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3567 | aCountry = mStrCountry;
|
---|
| 3568 | return S_OK;
|
---|
| 3569 | }
|
---|
| 3570 |
|
---|
| 3571 | HRESULT Unattended::setCountry(const com::Utf8Str &aCountry)
|
---|
| 3572 | {
|
---|
| 3573 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3574 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3575 | if ( aCountry.isEmpty()
|
---|
| 3576 | || ( aCountry.length() == 2
|
---|
| 3577 | && RT_C_IS_UPPER(aCountry[0])
|
---|
| 3578 | && RT_C_IS_UPPER(aCountry[1])) )
|
---|
| 3579 | {
|
---|
| 3580 | mStrCountry = aCountry;
|
---|
| 3581 | return S_OK;
|
---|
| 3582 | }
|
---|
| 3583 | return setError(E_INVALIDARG, tr("Expected two upper cased letters"));
|
---|
| 3584 | }
|
---|
| 3585 |
|
---|
| 3586 | HRESULT Unattended::getProxy(com::Utf8Str &aProxy)
|
---|
| 3587 | {
|
---|
| 3588 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
[84645] | 3589 | aProxy = mStrProxy; /// @todo turn schema map into string or something.
|
---|
[68162] | 3590 | return S_OK;
|
---|
| 3591 | }
|
---|
| 3592 |
|
---|
| 3593 | HRESULT Unattended::setProxy(const com::Utf8Str &aProxy)
|
---|
| 3594 | {
|
---|
| 3595 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3596 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3597 | if (aProxy.isEmpty())
|
---|
| 3598 | {
|
---|
| 3599 | /* set default proxy */
|
---|
[93189] | 3600 | /** @todo BUGBUG! implement this */
|
---|
[68162] | 3601 | }
|
---|
| 3602 | else if (aProxy.equalsIgnoreCase("none"))
|
---|
| 3603 | {
|
---|
| 3604 | /* clear proxy config */
|
---|
[93189] | 3605 | mStrProxy.setNull();
|
---|
[68162] | 3606 | }
|
---|
| 3607 | else
|
---|
| 3608 | {
|
---|
[84645] | 3609 | /** @todo Parse and set proxy config into a schema map or something along those lines. */
|
---|
[93189] | 3610 | /** @todo BUGBUG! implement this */
|
---|
[84645] | 3611 | // return E_NOTIMPL;
|
---|
| 3612 | mStrProxy = aProxy;
|
---|
[68162] | 3613 | }
|
---|
| 3614 | return S_OK;
|
---|
| 3615 | }
|
---|
| 3616 |
|
---|
| 3617 | HRESULT Unattended::getPackageSelectionAdjustments(com::Utf8Str &aPackageSelectionAdjustments)
|
---|
| 3618 | {
|
---|
| 3619 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3620 | aPackageSelectionAdjustments = RTCString::join(mPackageSelectionAdjustments, ";");
|
---|
| 3621 | return S_OK;
|
---|
| 3622 | }
|
---|
| 3623 |
|
---|
| 3624 | HRESULT Unattended::setPackageSelectionAdjustments(const com::Utf8Str &aPackageSelectionAdjustments)
|
---|
| 3625 | {
|
---|
| 3626 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3627 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3628 | if (aPackageSelectionAdjustments.isEmpty())
|
---|
| 3629 | mPackageSelectionAdjustments.clear();
|
---|
| 3630 | else
|
---|
| 3631 | {
|
---|
| 3632 | RTCList<RTCString, RTCString *> arrayStrSplit = aPackageSelectionAdjustments.split(";");
|
---|
| 3633 | for (size_t i = 0; i < arrayStrSplit.size(); i++)
|
---|
| 3634 | {
|
---|
| 3635 | if (arrayStrSplit[i].equals("minimal"))
|
---|
| 3636 | { /* okay */ }
|
---|
| 3637 | else
|
---|
| 3638 | return setError(E_INVALIDARG, tr("Unknown keyword: %s"), arrayStrSplit[i].c_str());
|
---|
| 3639 | }
|
---|
| 3640 | mPackageSelectionAdjustments = arrayStrSplit;
|
---|
| 3641 | }
|
---|
| 3642 | return S_OK;
|
---|
| 3643 | }
|
---|
| 3644 |
|
---|
| 3645 | HRESULT Unattended::getHostname(com::Utf8Str &aHostname)
|
---|
| 3646 | {
|
---|
| 3647 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3648 | aHostname = mStrHostname;
|
---|
| 3649 | return S_OK;
|
---|
| 3650 | }
|
---|
| 3651 |
|
---|
| 3652 | HRESULT Unattended::setHostname(const com::Utf8Str &aHostname)
|
---|
| 3653 | {
|
---|
| 3654 | /*
|
---|
| 3655 | * Validate input.
|
---|
| 3656 | */
|
---|
| 3657 | if (aHostname.length() > (aHostname.endsWith(".") ? 254U : 253U))
|
---|
| 3658 | return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
|
---|
[91718] | 3659 | tr("Hostname '%s' is %zu bytes long, max is 253 (excluding trailing dot)", "", aHostname.length()),
|
---|
[68162] | 3660 | aHostname.c_str(), aHostname.length());
|
---|
| 3661 | size_t cLabels = 0;
|
---|
| 3662 | const char *pszSrc = aHostname.c_str();
|
---|
| 3663 | for (;;)
|
---|
| 3664 | {
|
---|
| 3665 | size_t cchLabel = 1;
|
---|
| 3666 | char ch = *pszSrc++;
|
---|
| 3667 | if (RT_C_IS_ALNUM(ch))
|
---|
| 3668 | {
|
---|
| 3669 | cLabels++;
|
---|
| 3670 | while ((ch = *pszSrc++) != '.' && ch != '\0')
|
---|
| 3671 | {
|
---|
| 3672 | if (RT_C_IS_ALNUM(ch) || ch == '-')
|
---|
| 3673 | {
|
---|
| 3674 | if (cchLabel < 63)
|
---|
| 3675 | cchLabel++;
|
---|
| 3676 | else
|
---|
| 3677 | return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
|
---|
| 3678 | tr("Invalid hostname '%s' - label %u is too long, max is 63."),
|
---|
| 3679 | aHostname.c_str(), cLabels);
|
---|
| 3680 | }
|
---|
| 3681 | else
|
---|
| 3682 | return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
|
---|
| 3683 | tr("Invalid hostname '%s' - illegal char '%c' at position %zu"),
|
---|
| 3684 | aHostname.c_str(), ch, pszSrc - aHostname.c_str() - 1);
|
---|
| 3685 | }
|
---|
| 3686 | if (cLabels == 1 && cchLabel < 2)
|
---|
| 3687 | return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
|
---|
| 3688 | tr("Invalid hostname '%s' - the name part must be at least two characters long"),
|
---|
| 3689 | aHostname.c_str());
|
---|
| 3690 | if (ch == '\0')
|
---|
| 3691 | break;
|
---|
| 3692 | }
|
---|
| 3693 | else if (ch != '\0')
|
---|
| 3694 | return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
|
---|
| 3695 | tr("Invalid hostname '%s' - illegal lead char '%c' at position %zu"),
|
---|
| 3696 | aHostname.c_str(), ch, pszSrc - aHostname.c_str() - 1);
|
---|
| 3697 | else
|
---|
| 3698 | return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
|
---|
| 3699 | tr("Invalid hostname '%s' - trailing dot not permitted"), aHostname.c_str());
|
---|
| 3700 | }
|
---|
| 3701 | if (cLabels < 2)
|
---|
| 3702 | return setErrorBoth(E_INVALIDARG, VERR_INVALID_NAME,
|
---|
| 3703 | tr("Incomplete hostname '%s' - must include both a name and a domain"), aHostname.c_str());
|
---|
| 3704 |
|
---|
| 3705 | /*
|
---|
| 3706 | * Make the change.
|
---|
| 3707 | */
|
---|
| 3708 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3709 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3710 | mStrHostname = aHostname;
|
---|
| 3711 | return S_OK;
|
---|
| 3712 | }
|
---|
| 3713 |
|
---|
| 3714 | HRESULT Unattended::getAuxiliaryBasePath(com::Utf8Str &aAuxiliaryBasePath)
|
---|
| 3715 | {
|
---|
| 3716 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3717 | aAuxiliaryBasePath = mStrAuxiliaryBasePath;
|
---|
| 3718 | return S_OK;
|
---|
| 3719 | }
|
---|
| 3720 |
|
---|
| 3721 | HRESULT Unattended::setAuxiliaryBasePath(const com::Utf8Str &aAuxiliaryBasePath)
|
---|
| 3722 | {
|
---|
| 3723 | if (aAuxiliaryBasePath.isEmpty())
|
---|
[91503] | 3724 | return setError(E_INVALIDARG, tr("Empty base path is not allowed"));
|
---|
[68162] | 3725 | if (!RTPathStartsWithRoot(aAuxiliaryBasePath.c_str()))
|
---|
[91503] | 3726 | return setError(E_INVALIDARG, tr("Base path must be absolute"));
|
---|
[68162] | 3727 |
|
---|
| 3728 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3729 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3730 | mStrAuxiliaryBasePath = aAuxiliaryBasePath;
|
---|
| 3731 | mfIsDefaultAuxiliaryBasePath = mStrAuxiliaryBasePath.isEmpty();
|
---|
| 3732 | return S_OK;
|
---|
| 3733 | }
|
---|
| 3734 |
|
---|
| 3735 | HRESULT Unattended::getImageIndex(ULONG *index)
|
---|
| 3736 | {
|
---|
| 3737 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3738 | *index = midxImage;
|
---|
| 3739 | return S_OK;
|
---|
| 3740 | }
|
---|
| 3741 |
|
---|
| 3742 | HRESULT Unattended::setImageIndex(ULONG index)
|
---|
| 3743 | {
|
---|
| 3744 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3745 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
[93584] | 3746 |
|
---|
| 3747 | /* Validate the selection if detection was done already: */
|
---|
| 3748 | if (mDetectedImages.size() > 0)
|
---|
| 3749 | {
|
---|
| 3750 | for (size_t i = 0; i < mDetectedImages.size(); i++)
|
---|
| 3751 | if (mDetectedImages[i].mImageIndex == index)
|
---|
| 3752 | {
|
---|
| 3753 | midxImage = index;
|
---|
| 3754 | i_updateDetectedAttributeForImage(mDetectedImages[i]);
|
---|
| 3755 | return S_OK;
|
---|
| 3756 | }
|
---|
| 3757 | LogRel(("Unattended: Setting invalid index=%u\n", index)); /** @todo fail? */
|
---|
| 3758 | }
|
---|
| 3759 |
|
---|
[93545] | 3760 | midxImage = index;
|
---|
| 3761 | return S_OK;
|
---|
[68162] | 3762 | }
|
---|
| 3763 |
|
---|
| 3764 | HRESULT Unattended::getMachine(ComPtr<IMachine> &aMachine)
|
---|
| 3765 | {
|
---|
| 3766 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3767 | return mMachine.queryInterfaceTo(aMachine.asOutParam());
|
---|
| 3768 | }
|
---|
| 3769 |
|
---|
| 3770 | HRESULT Unattended::setMachine(const ComPtr<IMachine> &aMachine)
|
---|
| 3771 | {
|
---|
| 3772 | /*
|
---|
| 3773 | * Lookup the VM so we can safely get the Machine instance.
|
---|
| 3774 | * (Don't want to test how reliable XPCOM and COM are with finding
|
---|
| 3775 | * the local object instance when a client passes a stub back.)
|
---|
| 3776 | */
|
---|
| 3777 | Bstr bstrUuidMachine;
|
---|
| 3778 | HRESULT hrc = aMachine->COMGETTER(Id)(bstrUuidMachine.asOutParam());
|
---|
| 3779 | if (SUCCEEDED(hrc))
|
---|
| 3780 | {
|
---|
| 3781 | Guid UuidMachine(bstrUuidMachine);
|
---|
| 3782 | ComObjPtr<Machine> ptrMachine;
|
---|
| 3783 | hrc = mParent->i_findMachine(UuidMachine, false /*fPermitInaccessible*/, true /*aSetError*/, &ptrMachine);
|
---|
| 3784 | if (SUCCEEDED(hrc))
|
---|
| 3785 | {
|
---|
| 3786 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3787 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER,
|
---|
| 3788 | tr("Cannot change after prepare() has been called")));
|
---|
| 3789 | mMachine = ptrMachine;
|
---|
| 3790 | mMachineUuid = UuidMachine;
|
---|
| 3791 | if (mfIsDefaultAuxiliaryBasePath)
|
---|
| 3792 | mStrAuxiliaryBasePath.setNull();
|
---|
| 3793 | hrc = S_OK;
|
---|
| 3794 | }
|
---|
| 3795 | }
|
---|
| 3796 | return hrc;
|
---|
| 3797 | }
|
---|
| 3798 |
|
---|
| 3799 | HRESULT Unattended::getScriptTemplatePath(com::Utf8Str &aScriptTemplatePath)
|
---|
| 3800 | {
|
---|
| 3801 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3802 | if ( mStrScriptTemplatePath.isNotEmpty()
|
---|
| 3803 | || mpInstaller == NULL)
|
---|
| 3804 | aScriptTemplatePath = mStrScriptTemplatePath;
|
---|
| 3805 | else
|
---|
| 3806 | aScriptTemplatePath = mpInstaller->getTemplateFilePath();
|
---|
| 3807 | return S_OK;
|
---|
| 3808 | }
|
---|
| 3809 |
|
---|
| 3810 | HRESULT Unattended::setScriptTemplatePath(const com::Utf8Str &aScriptTemplatePath)
|
---|
| 3811 | {
|
---|
| 3812 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3813 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3814 | mStrScriptTemplatePath = aScriptTemplatePath;
|
---|
| 3815 | return S_OK;
|
---|
| 3816 | }
|
---|
| 3817 |
|
---|
| 3818 | HRESULT Unattended::getPostInstallScriptTemplatePath(com::Utf8Str &aPostInstallScriptTemplatePath)
|
---|
| 3819 | {
|
---|
| 3820 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3821 | if ( mStrPostInstallScriptTemplatePath.isNotEmpty()
|
---|
| 3822 | || mpInstaller == NULL)
|
---|
| 3823 | aPostInstallScriptTemplatePath = mStrPostInstallScriptTemplatePath;
|
---|
| 3824 | else
|
---|
| 3825 | aPostInstallScriptTemplatePath = mpInstaller->getPostTemplateFilePath();
|
---|
| 3826 | return S_OK;
|
---|
| 3827 | }
|
---|
| 3828 |
|
---|
| 3829 | HRESULT Unattended::setPostInstallScriptTemplatePath(const com::Utf8Str &aPostInstallScriptTemplatePath)
|
---|
| 3830 | {
|
---|
| 3831 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3832 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3833 | mStrPostInstallScriptTemplatePath = aPostInstallScriptTemplatePath;
|
---|
| 3834 | return S_OK;
|
---|
| 3835 | }
|
---|
| 3836 |
|
---|
| 3837 | HRESULT Unattended::getPostInstallCommand(com::Utf8Str &aPostInstallCommand)
|
---|
| 3838 | {
|
---|
| 3839 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3840 | aPostInstallCommand = mStrPostInstallCommand;
|
---|
| 3841 | return S_OK;
|
---|
| 3842 | }
|
---|
| 3843 |
|
---|
| 3844 | HRESULT Unattended::setPostInstallCommand(const com::Utf8Str &aPostInstallCommand)
|
---|
| 3845 | {
|
---|
| 3846 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3847 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3848 | mStrPostInstallCommand = aPostInstallCommand;
|
---|
| 3849 | return S_OK;
|
---|
| 3850 | }
|
---|
| 3851 |
|
---|
| 3852 | HRESULT Unattended::getExtraInstallKernelParameters(com::Utf8Str &aExtraInstallKernelParameters)
|
---|
| 3853 | {
|
---|
| 3854 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3855 | if ( mStrExtraInstallKernelParameters.isNotEmpty()
|
---|
| 3856 | || mpInstaller == NULL)
|
---|
| 3857 | aExtraInstallKernelParameters = mStrExtraInstallKernelParameters;
|
---|
| 3858 | else
|
---|
| 3859 | aExtraInstallKernelParameters = mpInstaller->getDefaultExtraInstallKernelParameters();
|
---|
| 3860 | return S_OK;
|
---|
| 3861 | }
|
---|
| 3862 |
|
---|
| 3863 | HRESULT Unattended::setExtraInstallKernelParameters(const com::Utf8Str &aExtraInstallKernelParameters)
|
---|
| 3864 | {
|
---|
| 3865 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3866 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
| 3867 | mStrExtraInstallKernelParameters = aExtraInstallKernelParameters;
|
---|
| 3868 | return S_OK;
|
---|
| 3869 | }
|
---|
| 3870 |
|
---|
| 3871 | HRESULT Unattended::getDetectedOSTypeId(com::Utf8Str &aDetectedOSTypeId)
|
---|
| 3872 | {
|
---|
| 3873 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3874 | aDetectedOSTypeId = mStrDetectedOSTypeId;
|
---|
| 3875 | return S_OK;
|
---|
| 3876 | }
|
---|
| 3877 |
|
---|
| 3878 | HRESULT Unattended::getDetectedOSVersion(com::Utf8Str &aDetectedOSVersion)
|
---|
| 3879 | {
|
---|
| 3880 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3881 | aDetectedOSVersion = mStrDetectedOSVersion;
|
---|
| 3882 | return S_OK;
|
---|
| 3883 | }
|
---|
| 3884 |
|
---|
| 3885 | HRESULT Unattended::getDetectedOSFlavor(com::Utf8Str &aDetectedOSFlavor)
|
---|
| 3886 | {
|
---|
| 3887 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3888 | aDetectedOSFlavor = mStrDetectedOSFlavor;
|
---|
| 3889 | return S_OK;
|
---|
| 3890 | }
|
---|
| 3891 |
|
---|
[68239] | 3892 | HRESULT Unattended::getDetectedOSLanguages(com::Utf8Str &aDetectedOSLanguages)
|
---|
| 3893 | {
|
---|
| 3894 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3895 | aDetectedOSLanguages = RTCString::join(mDetectedOSLanguages, " ");
|
---|
| 3896 | return S_OK;
|
---|
| 3897 | }
|
---|
| 3898 |
|
---|
[68162] | 3899 | HRESULT Unattended::getDetectedOSHints(com::Utf8Str &aDetectedOSHints)
|
---|
| 3900 | {
|
---|
| 3901 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3902 | aDetectedOSHints = mStrDetectedOSHints;
|
---|
| 3903 | return S_OK;
|
---|
| 3904 | }
|
---|
| 3905 |
|
---|
[93529] | 3906 | HRESULT Unattended::getDetectedImageNames(std::vector<com::Utf8Str> &aDetectedImageNames)
|
---|
| 3907 | {
|
---|
| 3908 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3909 | aDetectedImageNames.clear();
|
---|
| 3910 | for (size_t i = 0; i < mDetectedImages.size(); ++i)
|
---|
[93579] | 3911 | {
|
---|
| 3912 | Utf8Str strTmp;
|
---|
| 3913 | aDetectedImageNames.push_back(mDetectedImages[i].formatName(strTmp));
|
---|
| 3914 | }
|
---|
[93529] | 3915 | return S_OK;
|
---|
| 3916 | }
|
---|
| 3917 |
|
---|
[93535] | 3918 | HRESULT Unattended::getDetectedImageIndices(std::vector<ULONG> &aDetectedImageIndices)
|
---|
[93534] | 3919 | {
|
---|
| 3920 | AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 3921 | aDetectedImageIndices.clear();
|
---|
| 3922 | for (size_t i = 0; i < mDetectedImages.size(); ++i)
|
---|
| 3923 | aDetectedImageIndices.push_back(mDetectedImages[i].mImageIndex);
|
---|
| 3924 | return S_OK;
|
---|
| 3925 | }
|
---|
| 3926 |
|
---|
[94075] | 3927 | HRESULT Unattended::getIsUnattendedInstallSupported(BOOL *aIsUnattendedInstallSupported)
|
---|
| 3928 | {
|
---|
[96619] | 3929 | /*
|
---|
| 3930 | * Take the initial position that it's not supported, so we can return
|
---|
| 3931 | * right away when we decide it's not possible.
|
---|
| 3932 | */
|
---|
| 3933 | *aIsUnattendedInstallSupported = false;
|
---|
| 3934 |
|
---|
[94078] | 3935 | /* Unattended is disabled by default if we could not detect OS type. */
|
---|
[96619] | 3936 | if (mStrDetectedOSTypeId.isEmpty())
|
---|
[94078] | 3937 | return S_OK;
|
---|
[96619] | 3938 |
|
---|
| 3939 | const VBOXOSTYPE enmOsTypeMasked = (VBOXOSTYPE)(mEnmOsType & VBOXOSTYPE_OsTypeMask);
|
---|
| 3940 |
|
---|
| 3941 | /* We require a version to have been detected, except for windows where the
|
---|
| 3942 | field is generally only used for the service pack number at present and
|
---|
| 3943 | will be empty for RTMs isos. */
|
---|
| 3944 | if ( ( enmOsTypeMasked <= VBOXOSTYPE_WinNT
|
---|
| 3945 | || enmOsTypeMasked >= VBOXOSTYPE_OS2)
|
---|
| 3946 | && mStrDetectedOSVersion.isEmpty())
|
---|
| 3947 | return S_OK;
|
---|
| 3948 |
|
---|
| 3949 | /*
|
---|
| 3950 | * Sort out things that we know doesn't work. Order by VBOXOSTYPE value.
|
---|
| 3951 | */
|
---|
| 3952 |
|
---|
| 3953 | /* We do not support any of the DOS based windows version, nor DOS, in case
|
---|
| 3954 | any of that gets detected (it shouldn't): */
|
---|
| 3955 | if (enmOsTypeMasked >= VBOXOSTYPE_DOS && enmOsTypeMasked < VBOXOSTYPE_WinNT)
|
---|
| 3956 | return S_OK;
|
---|
| 3957 |
|
---|
| 3958 | /* Windows NT 3.x doesn't work, also skip unknown windows NT version: */
|
---|
| 3959 | if (enmOsTypeMasked >= VBOXOSTYPE_WinNT && enmOsTypeMasked < VBOXOSTYPE_WinNT4)
|
---|
| 3960 | return S_OK;
|
---|
| 3961 |
|
---|
| 3962 | /* For OS/2 we only support OS2 4.5 (actually only 4.52 server has been
|
---|
| 3963 | tested, but we'll get to the others eventually): */
|
---|
| 3964 | if ( enmOsTypeMasked >= VBOXOSTYPE_OS2
|
---|
| 3965 | && enmOsTypeMasked < VBOXOSTYPE_Linux
|
---|
| 3966 | && enmOsTypeMasked != VBOXOSTYPE_OS2Warp45 /* probably works */ )
|
---|
| 3967 | return S_OK;
|
---|
| 3968 |
|
---|
[95064] | 3969 | /* Old Debians fail since package repos have been move to some other mirror location. */
|
---|
[96619] | 3970 | if ( enmOsTypeMasked == VBOXOSTYPE_Debian
|
---|
| 3971 | && RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "9.0") < 0)
|
---|
| 3972 | return S_OK;
|
---|
| 3973 |
|
---|
[95154] | 3974 | /* Skip all OpenSUSE variants for now. */
|
---|
[96619] | 3975 | if (enmOsTypeMasked == VBOXOSTYPE_OpenSUSE)
|
---|
[95154] | 3976 | return S_OK;
|
---|
[96619] | 3977 |
|
---|
[96721] | 3978 | if (enmOsTypeMasked == VBOXOSTYPE_Ubuntu)
|
---|
| 3979 | {
|
---|
| 3980 | /* We cannot install Ubuntus older than 11.04. */
|
---|
| 3981 | if (RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "11.04") < 0)
|
---|
| 3982 | return S_OK;
|
---|
| 3983 | /* Lubuntu, starting with 20.04, has switched to calamares, which cannot be automated. */
|
---|
| 3984 | if ( RTStrIStr(mStrDetectedOSFlavor.c_str(), "lubuntu")
|
---|
| 3985 | && RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "20.04") > 0)
|
---|
| 3986 | return S_OK;
|
---|
| 3987 | }
|
---|
[96619] | 3988 |
|
---|
| 3989 | /* Earlier than OL 6.4 cannot be installed. OL 6.x fails with unsupported hardware error (CPU family). */
|
---|
| 3990 | if ( enmOsTypeMasked == VBOXOSTYPE_Oracle
|
---|
| 3991 | && RTStrVersionCompare(mStrDetectedOSVersion.c_str(), "6.4") < 0)
|
---|
| 3992 | return S_OK;
|
---|
| 3993 |
|
---|
[96861] | 3994 | /* Fredora ISOs cannot be installed at present. */
|
---|
| 3995 | if (enmOsTypeMasked == VBOXOSTYPE_FedoraCore)
|
---|
| 3996 | return S_OK;
|
---|
| 3997 |
|
---|
[96619] | 3998 | /*
|
---|
| 3999 | * Assume the rest works.
|
---|
| 4000 | */
|
---|
[94079] | 4001 | *aIsUnattendedInstallSupported = true;
|
---|
[94075] | 4002 | return S_OK;
|
---|
| 4003 | }
|
---|
| 4004 |
|
---|
[94533] | 4005 | HRESULT Unattended::getAvoidUpdatesOverNetwork(BOOL *aAvoidUpdatesOverNetwork)
|
---|
[94532] | 4006 | {
|
---|
[94533] | 4007 | *aAvoidUpdatesOverNetwork = mfAvoidUpdatesOverNetwork;
|
---|
[94532] | 4008 | return S_OK;
|
---|
| 4009 | }
|
---|
| 4010 |
|
---|
[94533] | 4011 | HRESULT Unattended::setAvoidUpdatesOverNetwork(BOOL aAvoidUpdatesOverNetwork)
|
---|
[94532] | 4012 | {
|
---|
| 4013 | AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
|
---|
| 4014 | AssertReturn(mpInstaller == NULL, setErrorBoth(E_FAIL, VERR_WRONG_ORDER, tr("Cannot change after prepare() has been called")));
|
---|
[94533] | 4015 | mfAvoidUpdatesOverNetwork = RT_BOOL(aAvoidUpdatesOverNetwork);
|
---|
[94532] | 4016 | return S_OK;
|
---|
| 4017 | }
|
---|
| 4018 |
|
---|
[68162] | 4019 | /*
|
---|
| 4020 | * Getters that the installer and script classes can use.
|
---|
| 4021 | */
|
---|
| 4022 | Utf8Str const &Unattended::i_getIsoPath() const
|
---|
| 4023 | {
|
---|
| 4024 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4025 | return mStrIsoPath;
|
---|
| 4026 | }
|
---|
| 4027 |
|
---|
| 4028 | Utf8Str const &Unattended::i_getUser() const
|
---|
| 4029 | {
|
---|
| 4030 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4031 | return mStrUser;
|
---|
| 4032 | }
|
---|
| 4033 |
|
---|
| 4034 | Utf8Str const &Unattended::i_getPassword() const
|
---|
| 4035 | {
|
---|
| 4036 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4037 | return mStrPassword;
|
---|
| 4038 | }
|
---|
| 4039 |
|
---|
| 4040 | Utf8Str const &Unattended::i_getFullUserName() const
|
---|
| 4041 | {
|
---|
| 4042 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4043 | return mStrFullUserName.isNotEmpty() ? mStrFullUserName : mStrUser;
|
---|
| 4044 | }
|
---|
| 4045 |
|
---|
| 4046 | Utf8Str const &Unattended::i_getProductKey() const
|
---|
| 4047 | {
|
---|
| 4048 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4049 | return mStrProductKey;
|
---|
| 4050 | }
|
---|
| 4051 |
|
---|
[84645] | 4052 | Utf8Str const &Unattended::i_getProxy() const
|
---|
| 4053 | {
|
---|
| 4054 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4055 | return mStrProxy;
|
---|
| 4056 | }
|
---|
| 4057 |
|
---|
[68162] | 4058 | Utf8Str const &Unattended::i_getAdditionsIsoPath() const
|
---|
| 4059 | {
|
---|
| 4060 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4061 | return mStrAdditionsIsoPath;
|
---|
| 4062 | }
|
---|
| 4063 |
|
---|
| 4064 | bool Unattended::i_getInstallGuestAdditions() const
|
---|
| 4065 | {
|
---|
| 4066 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4067 | return mfInstallGuestAdditions;
|
---|
| 4068 | }
|
---|
| 4069 |
|
---|
| 4070 | Utf8Str const &Unattended::i_getValidationKitIsoPath() const
|
---|
| 4071 | {
|
---|
| 4072 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4073 | return mStrValidationKitIsoPath;
|
---|
| 4074 | }
|
---|
| 4075 |
|
---|
| 4076 | bool Unattended::i_getInstallTestExecService() const
|
---|
| 4077 | {
|
---|
| 4078 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4079 | return mfInstallTestExecService;
|
---|
| 4080 | }
|
---|
| 4081 |
|
---|
| 4082 | Utf8Str const &Unattended::i_getTimeZone() const
|
---|
| 4083 | {
|
---|
| 4084 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4085 | return mStrTimeZone;
|
---|
| 4086 | }
|
---|
| 4087 |
|
---|
| 4088 | PCRTTIMEZONEINFO Unattended::i_getTimeZoneInfo() const
|
---|
| 4089 | {
|
---|
| 4090 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4091 | return mpTimeZoneInfo;
|
---|
| 4092 | }
|
---|
| 4093 |
|
---|
| 4094 | Utf8Str const &Unattended::i_getLocale() const
|
---|
| 4095 | {
|
---|
| 4096 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4097 | return mStrLocale;
|
---|
| 4098 | }
|
---|
| 4099 |
|
---|
[68239] | 4100 | Utf8Str const &Unattended::i_getLanguage() const
|
---|
| 4101 | {
|
---|
| 4102 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4103 | return mStrLanguage;
|
---|
| 4104 | }
|
---|
| 4105 |
|
---|
[68162] | 4106 | Utf8Str const &Unattended::i_getCountry() const
|
---|
| 4107 | {
|
---|
| 4108 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4109 | return mStrCountry;
|
---|
| 4110 | }
|
---|
| 4111 |
|
---|
| 4112 | bool Unattended::i_isMinimalInstallation() const
|
---|
| 4113 | {
|
---|
| 4114 | size_t i = mPackageSelectionAdjustments.size();
|
---|
| 4115 | while (i-- > 0)
|
---|
| 4116 | if (mPackageSelectionAdjustments[i].equals("minimal"))
|
---|
| 4117 | return true;
|
---|
| 4118 | return false;
|
---|
| 4119 | }
|
---|
| 4120 |
|
---|
| 4121 | Utf8Str const &Unattended::i_getHostname() const
|
---|
| 4122 | {
|
---|
| 4123 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4124 | return mStrHostname;
|
---|
| 4125 | }
|
---|
| 4126 |
|
---|
| 4127 | Utf8Str const &Unattended::i_getAuxiliaryBasePath() const
|
---|
| 4128 | {
|
---|
| 4129 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4130 | return mStrAuxiliaryBasePath;
|
---|
| 4131 | }
|
---|
| 4132 |
|
---|
| 4133 | ULONG Unattended::i_getImageIndex() const
|
---|
| 4134 | {
|
---|
| 4135 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4136 | return midxImage;
|
---|
| 4137 | }
|
---|
| 4138 |
|
---|
| 4139 | Utf8Str const &Unattended::i_getScriptTemplatePath() const
|
---|
| 4140 | {
|
---|
| 4141 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4142 | return mStrScriptTemplatePath;
|
---|
| 4143 | }
|
---|
| 4144 |
|
---|
| 4145 | Utf8Str const &Unattended::i_getPostInstallScriptTemplatePath() const
|
---|
| 4146 | {
|
---|
| 4147 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4148 | return mStrPostInstallScriptTemplatePath;
|
---|
| 4149 | }
|
---|
| 4150 |
|
---|
| 4151 | Utf8Str const &Unattended::i_getPostInstallCommand() const
|
---|
| 4152 | {
|
---|
| 4153 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4154 | return mStrPostInstallCommand;
|
---|
| 4155 | }
|
---|
| 4156 |
|
---|
[91502] | 4157 | Utf8Str const &Unattended::i_getAuxiliaryInstallDir() const
|
---|
| 4158 | {
|
---|
| 4159 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4160 | /* Only the installer knows, forward the call. */
|
---|
| 4161 | AssertReturn(mpInstaller != NULL, Utf8Str::Empty);
|
---|
| 4162 | return mpInstaller->getAuxiliaryInstallDir();
|
---|
| 4163 | }
|
---|
| 4164 |
|
---|
[68162] | 4165 | Utf8Str const &Unattended::i_getExtraInstallKernelParameters() const
|
---|
| 4166 | {
|
---|
| 4167 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4168 | return mStrExtraInstallKernelParameters;
|
---|
| 4169 | }
|
---|
| 4170 |
|
---|
[68164] | 4171 | bool Unattended::i_isRtcUsingUtc() const
|
---|
| 4172 | {
|
---|
| 4173 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4174 | return mfRtcUseUtc;
|
---|
| 4175 | }
|
---|
| 4176 |
|
---|
[68162] | 4177 | bool Unattended::i_isGuestOs64Bit() const
|
---|
| 4178 | {
|
---|
| 4179 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4180 | return mfGuestOs64Bit;
|
---|
| 4181 | }
|
---|
| 4182 |
|
---|
[91502] | 4183 | bool Unattended::i_isFirmwareEFI() const
|
---|
| 4184 | {
|
---|
| 4185 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4186 | return menmFirmwareType != FirmwareType_BIOS;
|
---|
| 4187 | }
|
---|
| 4188 |
|
---|
[93189] | 4189 | Utf8Str const &Unattended::i_getDetectedOSVersion()
|
---|
[86274] | 4190 | {
|
---|
| 4191 | Assert(isReadLockedOnCurrentThread());
|
---|
| 4192 | return mStrDetectedOSVersion;
|
---|
| 4193 | }
|
---|
| 4194 |
|
---|
[94533] | 4195 | bool Unattended::i_getAvoidUpdatesOverNetwork() const
|
---|
[94532] | 4196 | {
|
---|
| 4197 | Assert(isReadLockedOnCurrentThread());
|
---|
[94533] | 4198 | return mfAvoidUpdatesOverNetwork;
|
---|
[94532] | 4199 | }
|
---|
| 4200 |
|
---|
[68162] | 4201 | HRESULT Unattended::i_attachImage(UnattendedInstallationDisk const *pImage, ComPtr<IMachine> const &rPtrSessionMachine,
|
---|
| 4202 | AutoMultiWriteLock2 &rLock)
|
---|
| 4203 | {
|
---|
| 4204 | /*
|
---|
| 4205 | * Attach the disk image
|
---|
| 4206 | * HACK ALERT! Temporarily release the Unattended lock.
|
---|
| 4207 | */
|
---|
| 4208 | rLock.release();
|
---|
| 4209 |
|
---|
| 4210 | ComPtr<IMedium> ptrMedium;
|
---|
[98035] | 4211 | HRESULT hrc = mParent->OpenMedium(Bstr(pImage->strImagePath).raw(),
|
---|
[97367] | 4212 | pImage->enmDeviceType,
|
---|
| 4213 | pImage->enmAccessType,
|
---|
| 4214 | true,
|
---|
| 4215 | ptrMedium.asOutParam());
|
---|
[98035] | 4216 | LogRelFlowFunc(("VirtualBox::openMedium -> %Rhrc\n", hrc));
|
---|
| 4217 | if (SUCCEEDED(hrc))
|
---|
[68162] | 4218 | {
|
---|
[98035] | 4219 | if (pImage->fAuxiliary && pImage->strImagePath.endsWith(".viso"))
|
---|
| 4220 | {
|
---|
| 4221 | hrc = ptrMedium->SetProperty(Bstr("UnattendedInstall").raw(), Bstr("1").raw());
|
---|
| 4222 | LogRelFlowFunc(("Medium::SetProperty -> %Rhrc\n", hrc));
|
---|
| 4223 | }
|
---|
[68162] | 4224 | if (pImage->fMountOnly)
|
---|
| 4225 | {
|
---|
| 4226 | // mount the opened disk image
|
---|
[98035] | 4227 | hrc = rPtrSessionMachine->MountMedium(Bstr(pImage->strControllerName).raw(), pImage->iPort,
|
---|
| 4228 | pImage->iDevice, ptrMedium, TRUE /*fForce*/);
|
---|
| 4229 | LogRelFlowFunc(("Machine::MountMedium -> %Rhrc\n", hrc));
|
---|
[68162] | 4230 | }
|
---|
| 4231 | else
|
---|
| 4232 | {
|
---|
| 4233 | //attach the opened disk image to the controller
|
---|
[98035] | 4234 | hrc = rPtrSessionMachine->AttachDevice(Bstr(pImage->strControllerName).raw(), pImage->iPort,
|
---|
| 4235 | pImage->iDevice, pImage->enmDeviceType, ptrMedium);
|
---|
| 4236 | LogRelFlowFunc(("Machine::AttachDevice -> %Rhrc\n", hrc));
|
---|
[68162] | 4237 | }
|
---|
| 4238 | }
|
---|
| 4239 |
|
---|
| 4240 | rLock.acquire();
|
---|
[98035] | 4241 | return hrc;
|
---|
[68162] | 4242 | }
|
---|
| 4243 |
|
---|
| 4244 | bool Unattended::i_isGuestOSArchX64(Utf8Str const &rStrGuestOsTypeId)
|
---|
| 4245 | {
|
---|
| 4246 | ComPtr<IGuestOSType> pGuestOSType;
|
---|
| 4247 | HRESULT hrc = mParent->GetGuestOSType(Bstr(rStrGuestOsTypeId).raw(), pGuestOSType.asOutParam());
|
---|
| 4248 | if (SUCCEEDED(hrc))
|
---|
| 4249 | {
|
---|
| 4250 | BOOL fIs64Bit = FALSE;
|
---|
[72919] | 4251 | if (!pGuestOSType.isNull())
|
---|
| 4252 | hrc = pGuestOSType->COMGETTER(Is64Bit)(&fIs64Bit);
|
---|
[68162] | 4253 | if (SUCCEEDED(hrc))
|
---|
| 4254 | return fIs64Bit != FALSE;
|
---|
| 4255 | }
|
---|
| 4256 | return false;
|
---|
| 4257 | }
|
---|
[93584] | 4258 |
|
---|
| 4259 |
|
---|
| 4260 | bool Unattended::i_updateDetectedAttributeForImage(WIMImage const &rImage)
|
---|
| 4261 | {
|
---|
| 4262 | bool fRet = true;
|
---|
| 4263 |
|
---|
| 4264 | /*
|
---|
| 4265 | * If the image doesn't have a valid value, we don't change it.
|
---|
| 4266 | * This is obviously a little bit bogus, but what can we do...
|
---|
| 4267 | */
|
---|
| 4268 | const char *pszOSTypeId = Global::OSTypeId(rImage.mOSType);
|
---|
| 4269 | if (pszOSTypeId && strcmp(pszOSTypeId, "Other") != 0)
|
---|
| 4270 | mStrDetectedOSTypeId = pszOSTypeId;
|
---|
| 4271 | else
|
---|
| 4272 | fRet = false;
|
---|
| 4273 |
|
---|
| 4274 | if (rImage.mVersion.isNotEmpty())
|
---|
| 4275 | mStrDetectedOSVersion = rImage.mVersion;
|
---|
| 4276 | else
|
---|
| 4277 | fRet = false;
|
---|
| 4278 |
|
---|
[93587] | 4279 | if (rImage.mFlavor.isNotEmpty())
|
---|
| 4280 | mStrDetectedOSFlavor = rImage.mFlavor;
|
---|
| 4281 | else
|
---|
| 4282 | fRet = false;
|
---|
| 4283 |
|
---|
[93584] | 4284 | if (rImage.mLanguages.size() > 0)
|
---|
| 4285 | mDetectedOSLanguages = rImage.mLanguages;
|
---|
| 4286 | else
|
---|
| 4287 | fRet = false;
|
---|
| 4288 |
|
---|
[94079] | 4289 | mEnmOsType = rImage.mEnmOsType;
|
---|
| 4290 |
|
---|
[93584] | 4291 | return fRet;
|
---|
| 4292 | }
|
---|