VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/UnattendedInstaller.cpp@ 102395

Last change on this file since 102395 was 102347, checked in by vboxsync, 16 months ago

Main/Unattended: Added support for Ubuntu Server >= 20.04. bugref:10551

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.5 KB
Line 
1/* $Id: UnattendedInstaller.cpp 102347 2023-11-27 18:55:29Z vboxsync $ */
2/** @file
3 * UnattendedInstaller class and it's descendants implementation
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
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
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
33#include "LoggingNew.h"
34#include "VirtualBoxBase.h"
35#include "VirtualBoxErrorInfoImpl.h"
36#include "AutoCaller.h"
37#include <VBox/com/ErrorInfo.h>
38
39#include "UnattendedImpl.h"
40#include "UnattendedInstaller.h"
41#include "UnattendedScript.h"
42
43#include <VBox/err.h>
44#include <iprt/ctype.h>
45#include <iprt/fsisomaker.h>
46#include <iprt/fsvfs.h>
47#include <iprt/getopt.h>
48#include <iprt/file.h>
49#include <iprt/path.h>
50#include <iprt/rand.h>
51#include <iprt/sha.h>
52#include <iprt/stream.h>
53#include <iprt/vfs.h>
54#ifdef RT_OS_SOLARIS
55# undef ES /* Workaround for someone dragging the namespace pollutor sys/regset.h. Sigh. */
56#endif
57#include <iprt/formats/iso9660.h>
58#include <iprt/cpp/path.h>
59
60
61using namespace std;
62
63
64/* static */ UnattendedInstaller *
65UnattendedInstaller::createInstance(VBOXOSTYPE enmDetectedOSType, const Utf8Str &strDetectedOSType,
66 const Utf8Str &strDetectedOSVersion, const Utf8Str &strDetectedOSFlavor,
67 const Utf8Str &strDetectedOSHints, Unattended *pParent)
68{
69 UnattendedInstaller *pUinstaller = NULL;
70
71 if (strDetectedOSType.find("Windows") != RTCString::npos)
72 {
73 if (enmDetectedOSType >= VBOXOSTYPE_WinVista)
74 pUinstaller = new UnattendedWindowsXmlInstaller(pParent);
75 else
76 pUinstaller = new UnattendedWindowsSifInstaller(pParent);
77 }
78 else if (enmDetectedOSType >= VBOXOSTYPE_OS2 && enmDetectedOSType < VBOXOSTYPE_Linux)
79 pUinstaller = new UnattendedOs2Installer(pParent, strDetectedOSHints);
80 else
81 {
82 if ( enmDetectedOSType >= VBOXOSTYPE_Debian
83 && ( enmDetectedOSType <= VBOXOSTYPE_Debian_latest_x64
84 || enmDetectedOSType <= VBOXOSTYPE_Debian_latest_arm64))
85 pUinstaller = new UnattendedDebianInstaller(pParent);
86 else if ( enmDetectedOSType >= VBOXOSTYPE_Ubuntu
87 && ( enmDetectedOSType <= VBOXOSTYPE_Ubuntu_latest_x64
88 || enmDetectedOSType <= VBOXOSTYPE_Ubuntu_latest_arm64))
89 {
90 /*
91 * Here we have to decide, based on the Ubuntu version, which exact installer flavor we have to use:
92 * - The preseed installer for older Ubuntu distros, or
93 * - The autoinstall installer for newer Ubuntu desktop or Ubuntu server versions.
94 */
95 if (/* Ubuntu Desktop >= 22.10 switch to the autoinstall installer. */
96 RTStrVersionCompare(strDetectedOSVersion.c_str(), "22.10") >= 0
97 /* Ubuntu Server >= 20.04 also uses autoinstall installer. Before that no unattended installation was possible. */
98 || ( RTStrVersionCompare(strDetectedOSVersion.c_str(), "20.04") >= 0
99 && strDetectedOSFlavor.contains("Server", RTCString::CaseSensitivity::CaseSensitive))
100 )
101 pUinstaller = new UnattendedUbuntuAutoInstallInstaller(pParent);
102 else
103 pUinstaller = new UnattendedUbuntuPreseedInstaller(pParent);
104 }
105 else if (enmDetectedOSType >= VBOXOSTYPE_RedHat && enmDetectedOSType <= VBOXOSTYPE_RedHat_latest_x64)
106 {
107 if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "8") >= 0)
108 pUinstaller = new UnattendedRhel8Installer(pParent);
109 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "7") >= 0)
110 pUinstaller = new UnattendedRhel7Installer(pParent);
111 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "6") >= 0)
112 pUinstaller = new UnattendedRhel6Installer(pParent);
113 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "5") >= 0)
114 pUinstaller = new UnattendedRhel5Installer(pParent);
115 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "4") >= 0)
116 pUinstaller = new UnattendedRhel4Installer(pParent);
117 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "3") >= 0)
118 pUinstaller = new UnattendedRhel3Installer(pParent);
119 else
120 pUinstaller = new UnattendedRhel6Installer(pParent);
121 }
122 else if (enmDetectedOSType >= VBOXOSTYPE_FedoraCore && enmDetectedOSType <= VBOXOSTYPE_FedoraCore_x64)
123 pUinstaller = new UnattendedFedoraInstaller(pParent);
124 else if ( enmDetectedOSType >= VBOXOSTYPE_Oracle
125 && ( enmDetectedOSType <= VBOXOSTYPE_Oracle_latest_x64
126 || enmDetectedOSType <= VBOXOSTYPE_Oracle_latest_arm64))
127 {
128 if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "9") >= 0)
129 pUinstaller = new UnattendedOracleLinux9Installer(pParent);
130 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "8") >= 0)
131 pUinstaller = new UnattendedOracleLinux8Installer(pParent);
132 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "7") >= 0)
133 pUinstaller = new UnattendedOracleLinux7Installer(pParent);
134 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "6") >= 0)
135 pUinstaller = new UnattendedOracleLinux6Installer(pParent);
136 else
137 pUinstaller = new UnattendedOracleLinux6Installer(pParent);
138 }
139 else if ( enmDetectedOSType >= VBOXOSTYPE_FreeBSD
140 && ( enmDetectedOSType <= VBOXOSTYPE_FreeBSD_x64
141 || enmDetectedOSType <= VBOXOSTYPE_FreeBSD_arm64))
142 pUinstaller = new UnattendedFreeBsdInstaller(pParent);
143#if 0 /* doesn't work, so convert later. */
144 else if (enmDetectedOSType == VBOXOSTYPE_OpenSUSE || enmDetectedOSType == VBOXOSTYPE_OpenSUSE_x64)
145 pUinstaller = new UnattendedSuseInstaller(new UnattendedSUSEXMLScript(pParent), pParent);
146#endif
147 }
148 RT_NOREF_PV(strDetectedOSFlavor);
149 RT_NOREF_PV(strDetectedOSHints);
150 return pUinstaller;
151}
152
153
154//////////////////////////////////////////////////////////////////////////////////////////////////////
155/*
156*
157*
158* Implementation Unattended functions
159*
160*/
161//////////////////////////////////////////////////////////////////////////////////////////////////////
162
163/*
164 *
165 * UnattendedInstaller public methods
166 *
167 */
168UnattendedInstaller::UnattendedInstaller(Unattended *pParent,
169 const char *pszMainScriptTemplateName, const char *pszPostScriptTemplateName,
170 const char *pszMainScriptFilename, const char *pszPostScriptFilename,
171 DeviceType_T enmBootDevice /*= DeviceType_DVD */)
172 : mMainScript(pParent, pszMainScriptTemplateName, pszMainScriptFilename)
173 , mPostScript(pParent, pszPostScriptTemplateName, pszPostScriptFilename)
174 , mpParent(pParent)
175 , meBootDevice(enmBootDevice)
176{
177 AssertPtr(pParent);
178 Assert(*pszMainScriptTemplateName);
179 Assert(*pszMainScriptFilename);
180 Assert(*pszPostScriptTemplateName);
181 Assert(*pszPostScriptFilename);
182 Assert(enmBootDevice == DeviceType_DVD || enmBootDevice == DeviceType_Floppy);
183}
184
185UnattendedInstaller::~UnattendedInstaller()
186{
187 mpParent = NULL;
188}
189
190HRESULT UnattendedInstaller::initInstaller()
191{
192 /*
193 * Calculate the full main script template location.
194 */
195 if (mpParent->i_getScriptTemplatePath().isNotEmpty())
196 mStrMainScriptTemplate = mpParent->i_getScriptTemplatePath();
197 else
198 {
199 int vrc = RTPathAppPrivateNoArchCxx(mStrMainScriptTemplate);
200 if (RT_SUCCESS(vrc))
201 vrc = RTPathAppendCxx(mStrMainScriptTemplate, "UnattendedTemplates");
202 if (RT_SUCCESS(vrc))
203 vrc = RTPathAppendCxx(mStrMainScriptTemplate, mMainScript.getDefaultTemplateFilename());
204 if (RT_FAILURE(vrc))
205 return mpParent->setErrorBoth(E_FAIL, vrc,
206 tr("Failed to construct path to the unattended installer script templates (%Rrc)"),
207 vrc);
208 }
209
210 /*
211 * Calculate the full post script template location.
212 */
213 if (mpParent->i_getPostInstallScriptTemplatePath().isNotEmpty())
214 mStrPostScriptTemplate = mpParent->i_getPostInstallScriptTemplatePath();
215 else
216 {
217 int vrc = RTPathAppPrivateNoArchCxx(mStrPostScriptTemplate);
218 if (RT_SUCCESS(vrc))
219 vrc = RTPathAppendCxx(mStrPostScriptTemplate, "UnattendedTemplates");
220 if (RT_SUCCESS(vrc))
221 vrc = RTPathAppendCxx(mStrPostScriptTemplate, mPostScript.getDefaultTemplateFilename());
222 if (RT_FAILURE(vrc))
223 return mpParent->setErrorBoth(E_FAIL, vrc,
224 tr("Failed to construct path to the unattended installer script templates (%Rrc)"),
225 vrc);
226 }
227
228 /*
229 * Construct paths we need.
230 */
231 if (isAuxiliaryFloppyNeeded())
232 {
233 mStrAuxiliaryFloppyFilePath = mpParent->i_getAuxiliaryBasePath();
234 mStrAuxiliaryFloppyFilePath.append("aux-floppy.img");
235 }
236 if (isAuxiliaryIsoNeeded())
237 {
238 mStrAuxiliaryIsoFilePath = mpParent->i_getAuxiliaryBasePath();
239 if (!isAuxiliaryIsoIsVISO())
240 mStrAuxiliaryIsoFilePath.append("aux-iso.iso");
241 else
242 mStrAuxiliaryIsoFilePath.append("aux-iso.viso");
243 }
244
245 /*
246 * Check that we've got the minimum of data available.
247 */
248 if (mpParent->i_getIsoPath().isEmpty())
249 return mpParent->setError(E_INVALIDARG, tr("Cannot proceed with an empty installation ISO path"));
250 if (mpParent->i_getUser().isEmpty())
251 return mpParent->setError(E_INVALIDARG, tr("Empty user name is not allowed"));
252 if (mpParent->i_getPassword().isEmpty())
253 return mpParent->setError(E_INVALIDARG, tr("Empty password is not allowed"));
254
255 LogRelFunc(("UnattendedInstaller::savePassedData(): \n"));
256 return S_OK;
257}
258
259#if 0 /* Always in AUX ISO */
260bool UnattendedInstaller::isAdditionsIsoNeeded() const
261{
262 /* In the VISO case, we'll add the additions to the VISO in a subdir. */
263 return !isAuxiliaryIsoIsVISO() && mpParent->i_getInstallGuestAdditions();
264}
265
266bool UnattendedInstaller::isValidationKitIsoNeeded() const
267{
268 /* In the VISO case, we'll add the validation kit to the VISO in a subdir. */
269 return !isAuxiliaryIsoIsVISO() && mpParent->i_getInstallTestExecService();
270}
271#endif
272
273bool UnattendedInstaller::isAuxiliaryIsoNeeded() const
274{
275 /* In the VISO case we use the AUX ISO for GAs, TXS, and User Payloads. */
276 return isAuxiliaryIsoIsVISO()
277 && ( mpParent->i_getInstallGuestAdditions()
278 || mpParent->i_getInstallTestExecService()
279 || mpParent->i_getInstallUserPayload());
280}
281
282
283HRESULT UnattendedInstaller::prepareUnattendedScripts()
284{
285 LogFlow(("UnattendedInstaller::prepareUnattendedScripts()\n"));
286
287 /*
288 * The script template editor calls setError, so status codes just needs to
289 * be passed on to the caller. Do the same for both scripts.
290 */
291 HRESULT hrc = mMainScript.read(getTemplateFilePath());
292 if (SUCCEEDED(hrc))
293 {
294 hrc = mMainScript.parse();
295 if (SUCCEEDED(hrc))
296 {
297 /* Ditto for the post script. */
298 hrc = mPostScript.read(getPostTemplateFilePath());
299 if (SUCCEEDED(hrc))
300 {
301 hrc = mPostScript.parse();
302 if (SUCCEEDED(hrc))
303 {
304 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: returns S_OK\n"));
305 return S_OK;
306 }
307 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: parse failed on post script (%Rhrc)\n", hrc));
308 }
309 else
310 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: error reading post install script template file (%Rhrc)\n", hrc));
311 }
312 else
313 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: parse failed (%Rhrc)\n", hrc));
314 }
315 else
316 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: error reading installation script template file (%Rhrc)\n", hrc));
317 return hrc;
318}
319
320HRESULT UnattendedInstaller::prepareMedia(bool fOverwrite /*=true*/)
321{
322 LogRelFlow(("UnattendedInstaller::prepareMedia:\n"));
323 HRESULT hrc = S_OK;
324 if (isAuxiliaryFloppyNeeded())
325 hrc = prepareAuxFloppyImage(fOverwrite);
326 if (SUCCEEDED(hrc))
327 {
328 if (isAuxiliaryIsoNeeded())
329 {
330 hrc = prepareAuxIsoImage(fOverwrite);
331 if (FAILED(hrc))
332 {
333 LogRelFlow(("UnattendedInstaller::prepareMedia: prepareAuxIsoImage failed\n"));
334
335 /* Delete the floppy image if we created one. */
336 if (isAuxiliaryFloppyNeeded())
337 RTFileDelete(getAuxiliaryFloppyFilePath().c_str());
338 }
339 }
340 }
341 LogRelFlow(("UnattendedInstaller::prepareMedia: returns %Rrc\n", hrc));
342 return hrc;
343}
344
345/*
346 *
347 * UnattendedInstaller protected methods
348 *
349 */
350HRESULT UnattendedInstaller::prepareAuxFloppyImage(bool fOverwrite)
351{
352 Assert(isAuxiliaryFloppyNeeded());
353
354 /*
355 * Create the image.
356 */
357 RTVFSFILE hVfsFile;
358 HRESULT hrc = newAuxFloppyImage(getAuxiliaryFloppyFilePath().c_str(), fOverwrite, &hVfsFile);
359 if (SUCCEEDED(hrc))
360 {
361 /*
362 * Open the FAT file system so we can copy files onto the floppy.
363 */
364 RTERRINFOSTATIC ErrInfo;
365 RTVFS hVfs;
366 int vrc = RTFsFatVolOpen(hVfsFile, false /*fReadOnly*/, 0 /*offBootSector*/, &hVfs, RTErrInfoInitStatic(&ErrInfo));
367 RTVfsFileRelease(hVfsFile);
368 if (RT_SUCCESS(vrc))
369 {
370 /*
371 * Call overridable method to copies the files onto it.
372 */
373 hrc = copyFilesToAuxFloppyImage(hVfs);
374
375 /*
376 * Release the VFS. On failure, delete the floppy image so the operation can
377 * be repeated in non-overwrite mode and so that we don't leave any mess behind.
378 */
379 RTVfsRelease(hVfs);
380 }
381 else if (RTErrInfoIsSet(&ErrInfo.Core))
382 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
383 tr("Failed to open FAT file system on newly created floppy image '%s': %Rrc: %s"),
384 getAuxiliaryFloppyFilePath().c_str(), vrc, ErrInfo.Core.pszMsg);
385 else
386 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
387 tr("Failed to open FAT file system onnewly created floppy image '%s': %Rrc"),
388 getAuxiliaryFloppyFilePath().c_str(), vrc);
389 if (FAILED(hrc))
390 RTFileDelete(getAuxiliaryFloppyFilePath().c_str());
391 }
392 return hrc;
393}
394
395HRESULT UnattendedInstaller::newAuxFloppyImage(const char *pszFilename, bool fOverwrite, PRTVFSFILE phVfsFile)
396{
397 /*
398 * Open the image file.
399 */
400 HRESULT hrc;
401 RTVFSFILE hVfsFile;
402 uint64_t fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT);
403 if (fOverwrite)
404 fOpen |= RTFILE_O_CREATE_REPLACE;
405 else
406 fOpen |= RTFILE_O_OPEN;
407 int vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
408 if (RT_SUCCESS(vrc))
409 {
410 /*
411 * Format it.
412 */
413 vrc = RTFsFatVolFormat144(hVfsFile, false /*fQuick*/);
414 if (RT_SUCCESS(vrc))
415 {
416 *phVfsFile = hVfsFile;
417 LogRelFlow(("UnattendedInstaller::newAuxFloppyImage: created and formatted '%s'\n", pszFilename));
418 return S_OK;
419 }
420
421 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to format floppy image '%s': %Rrc"), pszFilename, vrc);
422 RTVfsFileRelease(hVfsFile);
423 RTFileDelete(pszFilename);
424 }
425 else
426 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to create floppy image '%s': %Rrc"), pszFilename, vrc);
427 return hrc;
428}
429
430HRESULT UnattendedInstaller::copyFilesToAuxFloppyImage(RTVFS hVfs)
431{
432 HRESULT hrc = addScriptToFloppyImage(&mMainScript, hVfs);
433 if (SUCCEEDED(hrc))
434 hrc = addScriptToFloppyImage(&mPostScript, hVfs);
435 return hrc;
436}
437
438HRESULT UnattendedInstaller::addScriptToFloppyImage(BaseTextScript *pEditor, RTVFS hVfs)
439{
440 /*
441 * Open the destination file.
442 */
443 HRESULT hrc;
444 RTVFSFILE hVfsFileDst;
445 int vrc = RTVfsFileOpen(hVfs, pEditor->getDefaultFilename(),
446 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_ALL
447 | (0660 << RTFILE_O_CREATE_MODE_SHIFT),
448 &hVfsFileDst);
449 if (RT_SUCCESS(vrc))
450 {
451 /*
452 * Save the content to a string.
453 */
454 Utf8Str strScript;
455 hrc = pEditor->saveToString(strScript);
456 if (SUCCEEDED(hrc))
457 {
458 /*
459 * Write the string.
460 */
461 vrc = RTVfsFileWrite(hVfsFileDst, strScript.c_str(), strScript.length(), NULL);
462 if (RT_SUCCESS(vrc))
463 hrc = S_OK; /* done */
464 else
465 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
466 tr("Error writing %zu bytes to '%s' in floppy image '%s': %Rrc",
467 "", strScript.length()),
468 strScript.length(), pEditor->getDefaultFilename(),
469 getAuxiliaryFloppyFilePath().c_str());
470 }
471 RTVfsFileRelease(hVfsFileDst);
472 }
473 else
474 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
475 tr("Error creating '%s' in floppy image '%s': %Rrc"),
476 pEditor->getDefaultFilename(), getAuxiliaryFloppyFilePath().c_str());
477 return hrc;
478}
479
480HRESULT UnattendedInstaller::addFileToFloppyImage(RTVFS hVfs, const char *pszSrc, const char *pszDst)
481{
482 HRESULT hrc;
483
484 /*
485 * Open the source file.
486 */
487 RTVFSIOSTREAM hVfsIosSrc;
488 int vrc = RTVfsIoStrmOpenNormal(pszSrc, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsIosSrc);
489 if (RT_SUCCESS(vrc))
490 {
491 /*
492 * Open the destination file.
493 */
494 RTVFSFILE hVfsFileDst;
495 vrc = RTVfsFileOpen(hVfs, pszDst,
496 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT),
497 &hVfsFileDst);
498 if (RT_SUCCESS(vrc))
499 {
500 /*
501 * Do the copying.
502 */
503 RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFileDst);
504 vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0);
505 if (RT_SUCCESS(vrc))
506 hrc = S_OK;
507 else
508 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing copying '%s' to floppy image '%s': %Rrc"),
509 pszSrc, getAuxiliaryFloppyFilePath().c_str(), vrc);
510 RTVfsIoStrmRelease(hVfsIosDst);
511 RTVfsFileRelease(hVfsFileDst);
512 }
513 else
514 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error opening '%s' on floppy image '%s' for writing: %Rrc"),
515 pszDst, getAuxiliaryFloppyFilePath().c_str(), vrc);
516
517 RTVfsIoStrmRelease(hVfsIosSrc);
518 }
519 else
520 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error opening '%s' for copying onto floppy image '%s': %Rrc"),
521 pszSrc, getAuxiliaryFloppyFilePath().c_str(), vrc);
522 return hrc;
523}
524
525HRESULT UnattendedInstaller::prepareAuxIsoImage(bool fOverwrite)
526{
527 /*
528 * Open the original installation ISO.
529 */
530 RTVFS hVfsOrgIso;
531 HRESULT hrc = openInstallIsoImage(&hVfsOrgIso);
532 if (SUCCEEDED(hrc))
533 {
534 /*
535 * The next steps depends on the kind of image we're making.
536 */
537 if (!isAuxiliaryIsoIsVISO())
538 {
539 RTFSISOMAKER hIsoMaker;
540 hrc = newAuxIsoImageMaker(&hIsoMaker);
541 if (SUCCEEDED(hrc))
542 {
543 hrc = addFilesToAuxIsoImageMaker(hIsoMaker, hVfsOrgIso);
544 if (SUCCEEDED(hrc))
545 hrc = finalizeAuxIsoImage(hIsoMaker, getAuxiliaryIsoFilePath().c_str(), fOverwrite);
546 RTFsIsoMakerRelease(hIsoMaker);
547 }
548 }
549 else
550 {
551 RTCList<RTCString> vecFiles(0);
552 RTCList<RTCString> vecArgs(0);
553 try
554 {
555 vecArgs.append() = "--iprt-iso-maker-file-marker-bourne-sh";
556 RTUUID Uuid;
557 int vrc = RTUuidCreate(&Uuid); AssertRC(vrc);
558 char szTmp[RTUUID_STR_LENGTH + 1];
559 vrc = RTUuidToStr(&Uuid, szTmp, sizeof(szTmp)); AssertRC(vrc);
560 vecArgs.append() = szTmp;
561 vecArgs.append() = "--file-mode=0444";
562 vecArgs.append() = "--dir-mode=0555";
563 }
564 catch (std::bad_alloc &)
565 {
566 hrc = E_OUTOFMEMORY;
567 }
568 if (SUCCEEDED(hrc))
569 {
570 hrc = addFilesToAuxVisoVectors(vecArgs, vecFiles, hVfsOrgIso, fOverwrite);
571 if (SUCCEEDED(hrc))
572 hrc = finalizeAuxVisoFile(vecArgs, getAuxiliaryIsoFilePath().c_str(), fOverwrite);
573
574 if (FAILED(hrc))
575 for (size_t i = 0; i < vecFiles.size(); i++)
576 RTFileDelete(vecFiles[i].c_str());
577 }
578 }
579 RTVfsRelease(hVfsOrgIso);
580 }
581 return hrc;
582}
583
584HRESULT UnattendedInstaller::openInstallIsoImage(PRTVFS phVfsIso, uint32_t fFlags /*= 0*/)
585{
586 /* Open the file. */
587 const char *pszIsoPath = mpParent->i_getIsoPath().c_str();
588 RTVFSFILE hOrgIsoFile;
589 int vrc = RTVfsFileOpenNormal(pszIsoPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hOrgIsoFile);
590 if (RT_FAILURE(vrc))
591 return mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to open ISO image '%s' (%Rrc)"), pszIsoPath, vrc);
592
593 /* Pass the file to the ISO file system interpreter. */
594 RTERRINFOSTATIC ErrInfo;
595 vrc = RTFsIso9660VolOpen(hOrgIsoFile, fFlags, phVfsIso, RTErrInfoInitStatic(&ErrInfo));
596 RTVfsFileRelease(hOrgIsoFile);
597 if (RT_SUCCESS(vrc))
598 return S_OK;
599 if (RTErrInfoIsSet(&ErrInfo.Core))
600 return mpParent->setErrorBoth(E_FAIL, vrc, tr("ISO reader fail to open '%s' (%Rrc): %s"),
601 pszIsoPath, vrc, ErrInfo.Core.pszMsg);
602 return mpParent->setErrorBoth(E_FAIL, vrc, tr("ISO reader fail to open '%s' (%Rrc)"), pszIsoPath, vrc);
603}
604
605HRESULT UnattendedInstaller::newAuxIsoImageMaker(PRTFSISOMAKER phIsoMaker)
606{
607 int vrc = RTFsIsoMakerCreate(phIsoMaker);
608 if (RT_SUCCESS(vrc))
609 return S_OK;
610 return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerCreate failed (%Rrc)"), vrc);
611}
612
613HRESULT UnattendedInstaller::addFilesToAuxIsoImageMaker(RTFSISOMAKER hIsoMaker, RTVFS hVfsOrgIso)
614{
615 RT_NOREF(hVfsOrgIso);
616
617 /*
618 * Add the two scripts to the image with default names.
619 */
620 HRESULT hrc = addScriptToIsoMaker(&mMainScript, hIsoMaker);
621 if (SUCCEEDED(hrc))
622 hrc = addScriptToIsoMaker(&mPostScript, hIsoMaker);
623 return hrc;
624}
625
626HRESULT UnattendedInstaller::addScriptToIsoMaker(BaseTextScript *pEditor, RTFSISOMAKER hIsoMaker,
627 const char *pszDstFilename /*= NULL*/)
628{
629 /*
630 * Calc default destination filename if desired.
631 */
632 RTCString strDstNameBuf;
633 if (!pszDstFilename)
634 {
635 try
636 {
637 strDstNameBuf = RTPATH_SLASH_STR;
638 strDstNameBuf.append(pEditor->getDefaultTemplateFilename());
639 pszDstFilename = strDstNameBuf.c_str();
640 }
641 catch (std::bad_alloc &)
642 {
643 return E_OUTOFMEMORY;
644 }
645 }
646
647 /*
648 * Create a memory file for the script.
649 */
650 Utf8Str strScript;
651 HRESULT hrc = pEditor->saveToString(strScript);
652 if (SUCCEEDED(hrc))
653 {
654 RTVFSFILE hVfsScriptFile;
655 size_t cchScript = strScript.length();
656 int vrc = RTVfsFileFromBuffer(RTFILE_O_READ, strScript.c_str(), strScript.length(), &hVfsScriptFile);
657 strScript.setNull();
658 if (RT_SUCCESS(vrc))
659 {
660 /*
661 * Add it to the ISO.
662 */
663 vrc = RTFsIsoMakerAddFileWithVfsFile(hIsoMaker, pszDstFilename, hVfsScriptFile, NULL);
664 RTVfsFileRelease(hVfsScriptFile);
665 if (RT_SUCCESS(vrc))
666 hrc = S_OK;
667 else
668 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
669 tr("RTFsIsoMakerAddFileWithVfsFile failed on the script '%s' (%Rrc)"),
670 pszDstFilename, vrc);
671 }
672 else
673 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
674 tr("RTVfsFileFromBuffer failed on the %zu byte script '%s' (%Rrc)", "", cchScript),
675 cchScript, pszDstFilename, vrc);
676 }
677 return hrc;
678}
679
680HRESULT UnattendedInstaller::finalizeAuxIsoImage(RTFSISOMAKER hIsoMaker, const char *pszFilename, bool fOverwrite)
681{
682 /*
683 * Finalize the image.
684 */
685 int vrc = RTFsIsoMakerFinalize(hIsoMaker);
686 if (RT_FAILURE(vrc))
687 return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerFinalize failed (%Rrc)"), vrc);
688
689 /*
690 * Open the destination file.
691 */
692 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
693 if (fOverwrite)
694 fOpen |= RTFILE_O_CREATE_REPLACE;
695 else
696 fOpen |= RTFILE_O_CREATE;
697 RTVFSFILE hVfsDstFile;
698 vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsDstFile);
699 if (RT_FAILURE(vrc))
700 {
701 if (vrc == VERR_ALREADY_EXISTS)
702 return mpParent->setErrorBoth(E_FAIL, vrc, tr("The auxiliary ISO image file '%s' already exists"),
703 pszFilename);
704 return mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to open the auxiliary ISO image file '%s' for writing (%Rrc)"),
705 pszFilename, vrc);
706 }
707
708 /*
709 * Get the source file from the image maker.
710 */
711 HRESULT hrc;
712 RTVFSFILE hVfsSrcFile;
713 vrc = RTFsIsoMakerCreateVfsOutputFile(hIsoMaker, &hVfsSrcFile);
714 if (RT_SUCCESS(vrc))
715 {
716 RTVFSIOSTREAM hVfsSrcIso = RTVfsFileToIoStream(hVfsSrcFile);
717 RTVFSIOSTREAM hVfsDstIso = RTVfsFileToIoStream(hVfsDstFile);
718 if ( hVfsSrcIso != NIL_RTVFSIOSTREAM
719 && hVfsDstIso != NIL_RTVFSIOSTREAM)
720 {
721 vrc = RTVfsUtilPumpIoStreams(hVfsSrcIso, hVfsDstIso, 0 /*cbBufHint*/);
722 if (RT_SUCCESS(vrc))
723 hrc = S_OK;
724 else
725 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Error writing auxiliary ISO image '%s' (%Rrc)"),
726 pszFilename, vrc);
727 }
728 else
729 hrc = mpParent->setErrorBoth(E_FAIL, VERR_INTERNAL_ERROR_2,
730 tr("Internal Error: Failed to case VFS file to VFS I/O stream"));
731 RTVfsIoStrmRelease(hVfsSrcIso);
732 RTVfsIoStrmRelease(hVfsDstIso);
733 }
734 else
735 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerCreateVfsOutputFile failed (%Rrc)"), vrc);
736 RTVfsFileRelease(hVfsSrcFile);
737 RTVfsFileRelease(hVfsDstFile);
738 if (FAILED(hrc))
739 RTFileDelete(pszFilename);
740 return hrc;
741}
742
743HRESULT UnattendedInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
744 RTVFS hVfsOrgIso, bool fOverwrite)
745{
746 RT_NOREF(hVfsOrgIso);
747
748 /*
749 * Save and add the scripts.
750 */
751 HRESULT hrc = addScriptToVisoVectors(&mMainScript, rVecArgs, rVecFiles, fOverwrite);
752 if (SUCCEEDED(hrc))
753 hrc = addScriptToVisoVectors(&mPostScript, rVecArgs, rVecFiles, fOverwrite);
754 if (SUCCEEDED(hrc))
755 {
756 try
757 {
758 /*
759 * If we've got a Guest Additions ISO, add its content to a /vboxadditions dir.
760 */
761 if (mpParent->i_getInstallGuestAdditions())
762 {
763 rVecArgs.append().append("--push-iso=").append(mpParent->i_getAdditionsIsoPath());
764 rVecArgs.append() = "/vboxadditions=/";
765 rVecArgs.append() = "--pop";
766 }
767
768 /*
769 * If we've got a Validation Kit ISO, add its content to a /vboxvalidationkit dir.
770 */
771 if (mpParent->i_getInstallTestExecService())
772 {
773 rVecArgs.append().append("--push-iso=").append(mpParent->i_getValidationKitIsoPath());
774 rVecArgs.append() = "/vboxvalidationkit=/";
775 rVecArgs.append() = "--pop";
776 }
777
778 /*
779 * If we've got a User Payload ISO, add its content to a /vboxuserpayload dir.
780 */
781 if (mpParent->i_getInstallUserPayload())
782 {
783 rVecArgs.append().append("--push-iso=").append(mpParent->i_getUserPayloadIsoPath());
784 rVecArgs.append() = "/vboxuserpayload=/";
785 rVecArgs.append() = "--pop";
786 }
787 }
788 catch (std::bad_alloc &)
789 {
790 hrc = E_OUTOFMEMORY;
791 }
792 }
793 return hrc;
794}
795
796HRESULT UnattendedInstaller::addScriptToVisoVectors(BaseTextScript *pEditor, RTCList<RTCString> &rVecArgs,
797 RTCList<RTCString> &rVecFiles, bool fOverwrite)
798{
799 /*
800 * Calc the aux script file name.
801 */
802 RTCString strScriptName;
803 try
804 {
805 strScriptName = mpParent->i_getAuxiliaryBasePath();
806 strScriptName.append(pEditor->getDefaultFilename());
807 }
808 catch (std::bad_alloc &)
809 {
810 return E_OUTOFMEMORY;
811 }
812
813 /*
814 * Save it.
815 */
816 HRESULT hrc = pEditor->save(strScriptName.c_str(), fOverwrite);
817 if (SUCCEEDED(hrc))
818 {
819 /*
820 * Add it to the vectors.
821 */
822 try
823 {
824 rVecArgs.append().append('/').append(pEditor->getDefaultFilename()).append('=').append(strScriptName);
825 rVecFiles.append(strScriptName);
826 }
827 catch (std::bad_alloc &)
828 {
829 RTFileDelete(strScriptName.c_str());
830 hrc = E_OUTOFMEMORY;
831 }
832 }
833 return hrc;
834}
835
836HRESULT UnattendedInstaller::finalizeAuxVisoFile(RTCList<RTCString> const &rVecArgs, const char *pszFilename, bool fOverwrite)
837{
838 /*
839 * Create a C-style argument vector and turn that into a command line string.
840 */
841 size_t const cArgs = rVecArgs.size();
842 const char **papszArgs = (const char **)RTMemTmpAlloc((cArgs + 1) * sizeof(const char *));
843 if (!papszArgs)
844 return E_OUTOFMEMORY;
845 for (size_t i = 0; i < cArgs; i++)
846 papszArgs[i] = rVecArgs[i].c_str();
847 papszArgs[cArgs] = NULL;
848
849 char *pszCmdLine;
850 int vrc = RTGetOptArgvToString(&pszCmdLine, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
851 RTMemTmpFree(papszArgs);
852 if (RT_FAILURE(vrc))
853 return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTGetOptArgvToString failed (%Rrc)"), vrc);
854
855 /*
856 * Open the file.
857 */
858 HRESULT hrc;
859 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ;
860 if (fOverwrite)
861 fOpen |= RTFILE_O_CREATE_REPLACE;
862 else
863 fOpen |= RTFILE_O_CREATE;
864 RTFILE hFile;
865 vrc = RTFileOpen(&hFile, pszFilename, fOpen);
866 if (RT_SUCCESS(vrc))
867 {
868 vrc = RTFileWrite(hFile, pszCmdLine, strlen(pszCmdLine), NULL);
869 if (RT_SUCCESS(vrc))
870 vrc = RTFileClose(hFile);
871 else
872 RTFileClose(hFile);
873 if (RT_SUCCESS(vrc))
874 hrc = S_OK;
875 else
876 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing '%s' (%Rrc)"), pszFilename, vrc);
877 }
878 else
879 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to create '%s' (%Rrc)"), pszFilename, vrc);
880
881 RTStrFree(pszCmdLine);
882 return hrc;
883}
884
885HRESULT UnattendedInstaller::loadAndParseFileFromIso(RTVFS hVfsOrgIso, const char *pszFilename, AbstractScript *pEditor)
886{
887 HRESULT hrc;
888 RTVFSFILE hVfsFile;
889 int vrc = RTVfsFileOpen(hVfsOrgIso, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsFile);
890 if (RT_SUCCESS(vrc))
891 {
892 hrc = pEditor->readFromHandle(hVfsFile, pszFilename);
893 RTVfsFileRelease(hVfsFile);
894 if (SUCCEEDED(hrc))
895 hrc = pEditor->parse();
896 }
897 else
898 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open '%s' on the ISO '%s' (%Rrc)"),
899 pszFilename, mpParent->i_getIsoPath().c_str(), vrc);
900 return hrc;
901}
902
903
904
905//////////////////////////////////////////////////////////////////////////////////////////////////////
906/*
907*
908*
909* Implementation UnattendedLinuxInstaller functions
910*
911*/
912//////////////////////////////////////////////////////////////////////////////////////////////////////
913HRESULT UnattendedLinuxInstaller::editIsoLinuxCfg(GeneralTextScript *pEditor)
914{
915 try
916 {
917 /* Comment out 'display <filename>' directives that's used for displaying files at boot time. */
918 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("display", RTCString::CaseInsensitive);
919 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
920 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("display", RTCString::CaseInsensitive))
921 {
922 HRESULT hrc = pEditor->prependToLine(vecLineNumbers.at(i), "#");
923 if (FAILED(hrc))
924 return hrc;
925 }
926 }
927 catch (std::bad_alloc &)
928 {
929 return E_OUTOFMEMORY;
930 }
931 return editIsoLinuxCommon(pEditor);
932}
933
934HRESULT UnattendedLinuxInstaller::editIsoLinuxCommon(GeneralTextScript *pEditor)
935{
936 try
937 {
938 /* Set timeouts to 4 seconds. */
939 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("timeout", RTCString::CaseInsensitive);
940 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
941 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("timeout", RTCString::CaseInsensitive))
942 {
943 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), "timeout 4");
944 if (FAILED(hrc))
945 return hrc;
946 }
947
948 /* Modify kernel parameters. */
949 vecLineNumbers = pEditor->findTemplate("append", RTCString::CaseInsensitive);
950 if (vecLineNumbers.size() > 0)
951 {
952 Utf8Str const &rStrAppend = mpParent->i_getExtraInstallKernelParameters().isNotEmpty()
953 ? mpParent->i_getExtraInstallKernelParameters()
954 : mStrDefaultExtraInstallKernelParameters;
955
956 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
957 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("append", RTCString::CaseInsensitive))
958 {
959 Utf8Str strLine = pEditor->getContentOfLine(vecLineNumbers[i]);
960
961 /* Do removals. */
962 if (mArrStrRemoveInstallKernelParameters.size() > 0)
963 {
964 size_t offStart = strLine.find("append") + 5;
965 while (offStart < strLine.length() && !RT_C_IS_SPACE(strLine[offStart]))
966 offStart++;
967 while (offStart < strLine.length() && RT_C_IS_SPACE(strLine[offStart]))
968 offStart++;
969 if (offStart < strLine.length())
970 {
971 for (size_t iRemove = 0; iRemove < mArrStrRemoveInstallKernelParameters.size(); iRemove++)
972 {
973 RTCString const &rStrRemove = mArrStrRemoveInstallKernelParameters[iRemove];
974 for (size_t off = offStart; off < strLine.length(); )
975 {
976 Assert(!RT_C_IS_SPACE(strLine[off]));
977
978 /* Find the end of word. */
979 size_t offEnd = off + 1;
980 while (offEnd < strLine.length() && !RT_C_IS_SPACE(strLine[offEnd]))
981 offEnd++;
982
983 /* Check if it matches. */
984 if (RTStrSimplePatternNMatch(rStrRemove.c_str(), rStrRemove.length(),
985 strLine.c_str() + off, offEnd - off))
986 {
987 while (off > 0 && RT_C_IS_SPACE(strLine[off - 1]))
988 off--;
989 strLine.erase(off, offEnd - off);
990 }
991
992 /* Advance to the next word. */
993 off = offEnd;
994 while (off < strLine.length() && RT_C_IS_SPACE(strLine[off]))
995 off++;
996 }
997 }
998 }
999 }
1000
1001 /* Do the appending. */
1002 if (rStrAppend.isNotEmpty())
1003 {
1004 if (!rStrAppend.startsWith(" ") && !strLine.endsWith(" "))
1005 strLine.append(' ');
1006 strLine.append(rStrAppend);
1007 }
1008
1009 /* Update line. */
1010 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), strLine);
1011 if (FAILED(hrc))
1012 return hrc;
1013 }
1014 }
1015 }
1016 catch (std::bad_alloc &)
1017 {
1018 return E_OUTOFMEMORY;
1019 }
1020 return S_OK;
1021}
1022
1023
1024HRESULT UnattendedLinuxInstaller::editGrubCfg(GeneralTextScript *pEditor)
1025{
1026 /* Default menu entry of grub.cfg is set in /etc/deafult/grub file. */
1027 try
1028 {
1029 /* Set timeouts to 4 seconds. */
1030 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("set timeout", RTCString::CaseInsensitive);
1031 if (vecLineNumbers.size() > 0)
1032 {
1033 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1034 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("set timeout", RTCString::CaseInsensitive))
1035 {
1036 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), "set timeout=4");
1037 if (FAILED(hrc))
1038 return hrc;
1039 }
1040 }
1041 else
1042 {
1043 /* Append timeout if not set (happens with arm64 iso images at least). */
1044 HRESULT hrc = pEditor->appendLine("set timeout=4");
1045 if (FAILED(hrc))
1046 return hrc;
1047 }
1048
1049 /* Modify kernel lines assuming that they starts with 'linux' keyword and 2nd word is the kernel command.*
1050 * we remove whatever comes after command and add our own command line options. */
1051 vecLineNumbers = pEditor->findTemplate("linux", RTCString::CaseInsensitive);
1052 if (vecLineNumbers.size() > 0)
1053 {
1054 Utf8Str const &rStrAppend = mpParent->i_getExtraInstallKernelParameters().isNotEmpty()
1055 ? mpParent->i_getExtraInstallKernelParameters()
1056 : mStrDefaultExtraInstallKernelParameters;
1057
1058 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1059 {
1060 HRESULT hrc = S_OK;
1061 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("linux", RTCString::CaseInsensitive))
1062 {
1063 Utf8Str strLine = pEditor->getContentOfLine(vecLineNumbers[i]);
1064 size_t cbPos = strLine.find("linux") + strlen("linux");
1065 bool fSecondWord = false;
1066 /* Find the end of 2nd word assuming that it is kernel command. */
1067 while (cbPos < strLine.length())
1068 {
1069 if (!fSecondWord)
1070 {
1071 if (strLine[cbPos] != '\t' && strLine[cbPos] != ' ')
1072 fSecondWord = true;
1073 }
1074 else
1075 {
1076 if (strLine[cbPos] == '\t' || strLine[cbPos] == ' ')
1077 break;
1078 }
1079 ++cbPos;
1080 }
1081 if (!fSecondWord)
1082 hrc = E_FAIL;
1083
1084 if (SUCCEEDED(hrc))
1085 {
1086 strLine.erase(cbPos, strLine.length() - cbPos);
1087
1088 /* Do the appending. */
1089 if (rStrAppend.isNotEmpty())
1090 {
1091 if (!rStrAppend.startsWith(" ") && !strLine.endsWith(" "))
1092 strLine.append(' ');
1093 strLine.append(rStrAppend);
1094 }
1095
1096 /* Update line. */
1097 hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), strLine);
1098 }
1099 if (FAILED(hrc))
1100 return hrc;
1101 }
1102 }
1103 }
1104 }
1105 catch (std::bad_alloc &)
1106 {
1107 return E_OUTOFMEMORY;
1108 }
1109 return S_OK;
1110}
1111
1112
1113//////////////////////////////////////////////////////////////////////////////////////////////////////
1114/*
1115*
1116*
1117* Implementation UnattendedDebianInstaller functions
1118*
1119*/
1120//////////////////////////////////////////////////////////////////////////////////////////////////////
1121
1122/**
1123 * Helper for checking if a file exists.
1124 * @todo promote to IPRT?
1125 */
1126static bool hlpVfsFileExists(RTVFS hVfs, const char *pszPath)
1127{
1128 RTFSOBJINFO ObjInfo;
1129 int vrc = RTVfsQueryPathInfo(hVfs, pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
1130 return RT_SUCCESS(vrc) && RTFS_IS_FILE(ObjInfo.Attr.fMode);
1131}
1132
1133HRESULT UnattendedDebianInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
1134 RTVFS hVfsOrgIso, bool fOverwrite)
1135{
1136 /*
1137 * Figure out the name of the menu config file that we have to edit.
1138 */
1139 bool fMenuConfigIsGrub = false;
1140 const char *pszMenuConfigFilename = "/isolinux/txt.cfg";
1141 if (!hlpVfsFileExists(hVfsOrgIso, pszMenuConfigFilename))
1142 {
1143 /* On Debian Live ISOs (at least from 9 to 11) the there is only menu.cfg. */
1144 if (hlpVfsFileExists(hVfsOrgIso, "/isolinux/menu.cfg"))
1145 pszMenuConfigFilename = "/isolinux/menu.cfg";
1146 /* On Linux Mint 20.3, 21, and 19 (at least) there is only isolinux.cfg. */
1147 else if (hlpVfsFileExists(hVfsOrgIso, "/isolinux/isolinux.cfg"))
1148 pszMenuConfigFilename = "/isolinux/isolinux.cfg";
1149 /* Ubuntus 21.10+ are UEFI only. No isolinux directory. We modify grub.cfg. */
1150 else if (hlpVfsFileExists(hVfsOrgIso, "/boot/grub/grub.cfg"))
1151 {
1152 pszMenuConfigFilename = "/boot/grub/grub.cfg";
1153 fMenuConfigIsGrub = true;
1154 }
1155 }
1156
1157 /* Check for existence of isolinux.cfg since UEFI-only ISOs do not have this file. */
1158 bool const fIsoLinuxCfgExists = hlpVfsFileExists(hVfsOrgIso, "isolinux/isolinux.cfg");
1159 Assert(!fIsoLinuxCfgExists || !fMenuConfigIsGrub); /** @todo r=bird: Perhaps prefix the hlpVfsFileExists call with 'fIsoLinuxCfgExists &&' above ? */
1160
1161 /*
1162 * VISO bits and filenames.
1163 */
1164 RTCString strIsoLinuxCfg;
1165 RTCString strTxtCfg;
1166 try
1167 {
1168 /* Remaster ISO. */
1169 rVecArgs.append() = "--no-file-mode";
1170 rVecArgs.append() = "--no-dir-mode";
1171
1172 rVecArgs.append() = "--import-iso";
1173 rVecArgs.append(mpParent->i_getIsoPath());
1174
1175 rVecArgs.append() = "--file-mode=0444";
1176 rVecArgs.append() = "--dir-mode=0555";
1177
1178 /* Replace the isolinux.cfg configuration file. */
1179 if (fIsoLinuxCfgExists)
1180 {
1181 /* First remove. */
1182 rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
1183 /* Then add the modified file. */
1184 strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
1185 strIsoLinuxCfg.append("isolinux-isolinux.cfg");
1186 rVecArgs.append().append("isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
1187 }
1188
1189 /*
1190 * Replace menu configuration file as well.
1191 * Some distros (Linux Mint) has only isolinux.cfg. No menu.cfg or txt.cfg.
1192 */
1193 if (RTStrICmp(pszMenuConfigFilename, "/isolinux/isolinux.cfg") != 0)
1194 {
1195
1196 /* Replace menu configuration file as well. */
1197 rVecArgs.append().assign(pszMenuConfigFilename).append("=:must-remove:");
1198 strTxtCfg = mpParent->i_getAuxiliaryBasePath();
1199 if (fMenuConfigIsGrub)
1200 strTxtCfg.append("grub.cfg");
1201 else
1202 strTxtCfg.append("isolinux-txt.cfg");
1203 rVecArgs.append().assign(pszMenuConfigFilename).append("=").append(strTxtCfg);
1204 }
1205 }
1206 catch (std::bad_alloc &)
1207 {
1208 return E_OUTOFMEMORY;
1209 }
1210
1211 /*
1212 * Edit the isolinux.cfg file if it is there.
1213 */
1214 if (fIsoLinuxCfgExists)
1215 {
1216 GeneralTextScript Editor(mpParent);
1217 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, "/isolinux/isolinux.cfg", &Editor);
1218 if (SUCCEEDED(hrc))
1219 hrc = editIsoLinuxCfg(&Editor, RTPathFilename(pszMenuConfigFilename));
1220 if (SUCCEEDED(hrc))
1221 {
1222 hrc = Editor.save(strIsoLinuxCfg, fOverwrite);
1223 if (SUCCEEDED(hrc))
1224 {
1225 try
1226 {
1227 rVecFiles.append(strIsoLinuxCfg);
1228 }
1229 catch (std::bad_alloc &)
1230 {
1231 RTFileDelete(strIsoLinuxCfg.c_str());
1232 hrc = E_OUTOFMEMORY;
1233 }
1234 }
1235 }
1236 if (FAILED(hrc))
1237 return hrc;
1238 }
1239
1240 /*
1241 * Edit the menu config file.
1242 * Some distros (Linux Mint) has only isolinux.cfg. No menu.cfg or txt.cfg.
1243 */
1244 if (RTStrICmp(pszMenuConfigFilename, "/isolinux/isolinux.cfg") != 0)
1245 {
1246 GeneralTextScript Editor(mpParent);
1247 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, pszMenuConfigFilename, &Editor);
1248 if (SUCCEEDED(hrc))
1249 {
1250 if (fMenuConfigIsGrub)
1251 hrc = editGrubCfg(&Editor);
1252 else
1253 hrc = editDebianMenuCfg(&Editor);
1254 if (SUCCEEDED(hrc))
1255 {
1256 hrc = Editor.save(strTxtCfg, fOverwrite);
1257 if (SUCCEEDED(hrc))
1258 {
1259 try
1260 {
1261 rVecFiles.append(strTxtCfg);
1262 }
1263 catch (std::bad_alloc &)
1264 {
1265 RTFileDelete(strTxtCfg.c_str());
1266 hrc = E_OUTOFMEMORY;
1267 }
1268 }
1269 }
1270 }
1271 if (FAILED(hrc))
1272 return hrc;
1273 }
1274
1275 /*
1276 * Call parent to add the preseed file from mAlg.
1277 */
1278 return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1279}
1280
1281HRESULT UnattendedDebianInstaller::editIsoLinuxCfg(GeneralTextScript *pEditor, const char *pszMenuConfigFileName)
1282{
1283 try
1284 {
1285 /* Include menu config file. Since it can be txt.cfg, menu.cfg or something else we need to parametrize this. */
1286 if (pszMenuConfigFileName && pszMenuConfigFileName[0] != '\0')
1287 {
1288 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("include", RTCString::CaseInsensitive);
1289 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1290 {
1291 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("include", RTCString::CaseInsensitive))
1292 {
1293 Utf8Str strIncludeLine("include ");
1294 strIncludeLine.append(pszMenuConfigFileName);
1295 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), strIncludeLine);
1296 if (FAILED(hrc))
1297 return hrc;
1298 }
1299 }
1300 }
1301
1302 /* Comment out default directives since in Debian case default is handled in menu config file. */
1303 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("default", RTCString::CaseInsensitive);
1304 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1305 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("default", RTCString::CaseInsensitive)
1306 && !pEditor->getContentOfLine(vecLineNumbers[i]).contains("default vesa", RTCString::CaseInsensitive))
1307 {
1308 HRESULT hrc = pEditor->prependToLine(vecLineNumbers.at(i), "#");
1309 if (FAILED(hrc))
1310 return hrc;
1311 }
1312
1313 /* Comment out "ui gfxboot bootlogo" line as it somehow messes things up on Kubuntu 20.04 (possibly others as well). */
1314 vecLineNumbers = pEditor->findTemplate("ui gfxboot", RTCString::CaseInsensitive);
1315 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1316 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("ui gfxboot", RTCString::CaseInsensitive))
1317 {
1318 HRESULT hrc = pEditor->prependToLine(vecLineNumbers.at(i), "#");
1319 if (FAILED(hrc))
1320 return hrc;
1321 }
1322 }
1323 catch (std::bad_alloc &)
1324 {
1325 return E_OUTOFMEMORY;
1326 }
1327 return UnattendedLinuxInstaller::editIsoLinuxCfg(pEditor);
1328}
1329
1330HRESULT UnattendedDebianInstaller::editDebianMenuCfg(GeneralTextScript *pEditor)
1331{
1332 /*
1333 * Unlike Redhats, Debian variants define boot menu not in isolinux.cfg but some other
1334 * menu configuration files. They are mostly called txt.cfg and/or menu.cfg (and possibly some other names)
1335 * In this functions we attempt to set menu's default label (default menu item) to the one containing the word 'install',
1336 * failing to find such a label (on Kubuntu 20.04 for example) we pick the first label with name 'live'.
1337 */
1338 try
1339 {
1340 HRESULT hrc = S_OK;
1341 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("label", RTCString::CaseInsensitive);
1342 const char *pszNewLabelName = "VBoxUnatendedInstall";
1343 bool fLabelFound = modifyLabelLine(pEditor, vecLineNumbers, "install", pszNewLabelName);
1344 if (!fLabelFound)
1345 fLabelFound = modifyLabelLine(pEditor, vecLineNumbers, "live", pszNewLabelName);
1346
1347 if (!fLabelFound)
1348 hrc = E_FAIL;;
1349
1350 if (SUCCEEDED(hrc))
1351 {
1352 /* Modify the content of default lines so that they point to label we have chosen above. */
1353 Utf8Str strNewContent("default ");
1354 strNewContent.append(pszNewLabelName);
1355
1356 std::vector<size_t> vecDefaultLineNumbers = pEditor->findTemplate("default", RTCString::CaseInsensitive);
1357 if (!vecDefaultLineNumbers.empty())
1358 {
1359 for (size_t j = 0; j < vecDefaultLineNumbers.size(); ++j)
1360 {
1361 hrc = pEditor->setContentOfLine(vecDefaultLineNumbers[j], strNewContent);
1362 if (FAILED(hrc))
1363 break;
1364 }
1365 }
1366 /* Add a defaul label line. */
1367 else
1368 hrc = pEditor->appendLine(strNewContent);
1369 }
1370 if (FAILED(hrc))
1371 return hrc;
1372 }
1373 catch (std::bad_alloc &)
1374 {
1375 return E_OUTOFMEMORY;
1376 }
1377 return UnattendedLinuxInstaller::editIsoLinuxCommon(pEditor);
1378}
1379
1380bool UnattendedDebianInstaller::modifyLabelLine(GeneralTextScript *pEditor, const std::vector<size_t> &vecLineNumbers,
1381 const char *pszKeyWord, const char *pszNewLabelName)
1382{
1383 if (!pEditor)
1384 return false;
1385 Utf8Str strNewLabel("label ");
1386 strNewLabel.append(pszNewLabelName);
1387 HRESULT hrc = S_OK;
1388 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1389 {
1390 RTCString const &rContent = pEditor->getContentOfLine(vecLineNumbers[i]);
1391 /* Skip this line if it does not start with the word 'label'. */
1392 if (!RTStrIStartsWith(rContent.c_str(), "label"))
1393 continue;
1394 /* Use the first menu item starting with word label and includes pszKeyWord.*/
1395 if (RTStrIStr(rContent.c_str(), pszKeyWord) != NULL)
1396 {
1397 /* Set the content of the line. It looks like multiple word labels (like label Debian Installer)
1398 * does not work very well in some cases. */
1399 hrc = pEditor->setContentOfLine(vecLineNumbers[i], strNewLabel);
1400 if (SUCCEEDED(hrc))
1401 return true;
1402 }
1403 }
1404 return false;
1405}
1406
1407
1408//////////////////////////////////////////////////////////////////////////////////////////////////////
1409/*
1410*
1411*
1412* Implementation UnattendedUbuntuAutoInstallInstaller functions
1413*
1414*/
1415//////////////////////////////////////////////////////////////////////////////////////////////////////
1416HRESULT UnattendedUbuntuAutoInstallInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
1417 RTVFS hVfsOrgIso, bool fOverwrite)
1418{
1419 try
1420 {
1421 /* Add the (empty) meta-data file to the ISO: */
1422 Utf8Str strUnattendedTemplates;
1423 int vrc = RTPathAppPrivateNoArchCxx(strUnattendedTemplates);
1424 AssertRCReturn(vrc, mpParent->setErrorVrc(vrc));
1425 vrc = RTPathAppendCxx(strUnattendedTemplates, "UnattendedTemplates");
1426 AssertRCReturn(vrc, mpParent->setErrorVrc(vrc));
1427 rVecArgs.append().assign("/meta-data=").append(strUnattendedTemplates).append("/ubuntu_autoinstall_meta_data");
1428 }
1429 catch (std::bad_alloc &)
1430 {
1431 return E_OUTOFMEMORY;
1432 }
1433
1434 /*
1435 * Call parent to add default Debian-based stuff.
1436 */
1437 return UnattendedDebianInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1438}
1439
1440
1441//////////////////////////////////////////////////////////////////////////////////////////////////////
1442/*
1443*
1444*
1445* Implementation UnattendedRhel6Installer functions
1446*
1447*/
1448//////////////////////////////////////////////////////////////////////////////////////////////////////
1449HRESULT UnattendedRhelInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
1450 RTVFS hVfsOrgIso, bool fOverwrite)
1451{
1452 /*
1453 * Figure out the name of the menu config file that we have to edit.
1454 */
1455 bool fMenuConfigIsGrub = false;
1456 const char *pszMenuConfigFilename = "/isolinux/isolinux.cfg";
1457 if (!hlpVfsFileExists(hVfsOrgIso, pszMenuConfigFilename))
1458 {
1459 /* arm64 variants of Oracle Linux 9 have grub. */
1460 if (hlpVfsFileExists(hVfsOrgIso, "/EFI/BOOT/grub.cfg"))
1461 {
1462 pszMenuConfigFilename = "/EFI/BOOT/grub.cfg";
1463 fMenuConfigIsGrub = true;
1464 }
1465 else
1466 AssertFailed();
1467 }
1468
1469 /*
1470 * VISO bits and filenames.
1471 */
1472 RTCString strBootCfg;
1473 try
1474 {
1475#if 1
1476 /* Remaster ISO. */
1477 rVecArgs.append() = "--no-file-mode";
1478 rVecArgs.append() = "--no-dir-mode";
1479
1480 rVecArgs.append() = "--import-iso";
1481 rVecArgs.append(mpParent->i_getIsoPath());
1482
1483 rVecArgs.append() = "--file-mode=0444";
1484 rVecArgs.append() = "--dir-mode=0555";
1485
1486 /* Replace the grub.cfg/isolinux.cfg configuration file. */
1487 if (fMenuConfigIsGrub)
1488 {
1489 /* Replace menu configuration file as well. */
1490 rVecArgs.append().assign(pszMenuConfigFilename).append("=:must-remove:");
1491 strBootCfg = mpParent->i_getAuxiliaryBasePath();
1492 strBootCfg.append("grub.cfg");
1493 rVecArgs.append().assign(pszMenuConfigFilename).append("=").append(strBootCfg);
1494 }
1495 else
1496 {
1497 /* First remove. */
1498 rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
1499 strBootCfg = mpParent->i_getAuxiliaryBasePath();
1500 strBootCfg.append("isolinux-isolinux.cfg");
1501 rVecArgs.append().append("isolinux/isolinux.cfg=").append(strBootCfg);
1502 }
1503#else
1504 /** @todo Maybe we should just remaster the ISO for redhat derivatives too?
1505 * One less CDROM to mount. */
1506 /* Name the ISO. */
1507 rVecArgs.append() = "--volume-id=VBox Unattended Boot";
1508
1509 /* Copy the isolinux directory from the original install ISO. */
1510 rVecArgs.append().append("--push-iso=").append(mpParent->i_getIsoPath());
1511 rVecArgs.append() = "/isolinux=/isolinux";
1512 rVecArgs.append() = "--pop";
1513
1514 /* We replace isolinux.cfg with our edited version (see further down). */
1515 rVecArgs.append() = "/isolinux/isolinux.cfg=:must-remove:";
1516
1517 strBootCfg = mpParent->i_getAuxiliaryBasePath();
1518 strBootCfg.append("isolinux-isolinux.cfg");
1519 rVecArgs.append().append("/isolinux/isolinux.cfg=").append(strBootCfg);
1520
1521 /* Configure booting /isolinux/isolinux.bin. */
1522 rVecArgs.append() = "--eltorito-boot";
1523 rVecArgs.append() = "/isolinux/isolinux.bin";
1524 rVecArgs.append() = "--no-emulation-boot";
1525 rVecArgs.append() = "--boot-info-table";
1526 rVecArgs.append() = "--boot-load-seg=0x07c0";
1527 rVecArgs.append() = "--boot-load-size=4";
1528
1529 /* Make the boot catalog visible in the file system. */
1530 rVecArgs.append() = "--boot-catalog=/isolinux/vboxboot.cat";
1531#endif
1532 }
1533 catch (std::bad_alloc &)
1534 {
1535 return E_OUTOFMEMORY;
1536 }
1537
1538 {
1539 GeneralTextScript Editor(mpParent);
1540 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, pszMenuConfigFilename, &Editor);
1541 if (SUCCEEDED(hrc))
1542 {
1543 if (fMenuConfigIsGrub)
1544 hrc = editGrubCfg(&Editor);
1545 else
1546 hrc = editIsoLinuxCfg(&Editor);
1547 if (SUCCEEDED(hrc))
1548 {
1549 hrc = Editor.save(strBootCfg, fOverwrite);
1550 if (SUCCEEDED(hrc))
1551 {
1552 try
1553 {
1554 rVecFiles.append(strBootCfg);
1555 }
1556 catch (std::bad_alloc &)
1557 {
1558 RTFileDelete(strBootCfg.c_str());
1559 hrc = E_OUTOFMEMORY;
1560 }
1561 }
1562 }
1563 }
1564 if (FAILED(hrc))
1565 return hrc;
1566 }
1567
1568 /*
1569 * Call parent to add the ks.cfg file from mAlg.
1570 */
1571 return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1572}
1573
1574
1575//////////////////////////////////////////////////////////////////////////////////////////////////////
1576/*
1577*
1578*
1579* Implementation UnattendedSuseInstaller functions
1580*
1581*/
1582//////////////////////////////////////////////////////////////////////////////////////////////////////
1583#if 0 /* doesn't work, so convert later */
1584/*
1585 *
1586 * UnattendedSuseInstaller protected methods
1587 *
1588*/
1589HRESULT UnattendedSuseInstaller::setUserData()
1590{
1591 HRESULT hrc = S_OK;
1592 //here base class function must be called first
1593 //because user home directory is set after user name
1594 hrc = UnattendedInstaller::setUserData();
1595
1596 hrc = mAlg->setField(USERHOMEDIR_ID, "");
1597 if (FAILED(hrc))
1598 return hrc;
1599
1600 return hrc;
1601}
1602
1603/*
1604 *
1605 * UnattendedSuseInstaller private methods
1606 *
1607*/
1608
1609HRESULT UnattendedSuseInstaller::iv_initialPhase()
1610{
1611 Assert(isAuxiliaryIsoNeeded());
1612 if (mParent->i_isGuestOs64Bit())
1613 mFilesAndDirsToExtractFromIso.append("boot/x86_64/loader/ ");
1614 else
1615 mFilesAndDirsToExtractFromIso.append("boot/i386/loader/ ");
1616 return extractOriginalIso(mFilesAndDirsToExtractFromIso);
1617}
1618
1619
1620HRESULT UnattendedSuseInstaller::setupScriptOnAuxiliaryCD(const Utf8Str &path)
1621{
1622 HRESULT hrc = S_OK;
1623
1624 GeneralTextScript isoSuseCfgScript(mpParent);
1625 hrc = isoSuseCfgScript.read(path);
1626 hrc = isoSuseCfgScript.parse();
1627 //fix linux core bootable parameters: add path to the preseed script
1628
1629 std::vector<size_t> listOfLines = isoSuseCfgScript.findTemplate("append");
1630 for(unsigned int i=0; i<listOfLines.size(); ++i)
1631 {
1632 isoSuseCfgScript.appendToLine(listOfLines.at(i),
1633 " auto=true priority=critical autoyast=default instmode=cd quiet splash noprompt noshell --");
1634 }
1635
1636 //find all lines with "label" inside
1637 listOfLines = isoSuseCfgScript.findTemplate("label");
1638 for(unsigned int i=0; i<listOfLines.size(); ++i)
1639 {
1640 Utf8Str content = isoSuseCfgScript.getContentOfLine(listOfLines.at(i));
1641
1642 //suppose general string looks like "label linux", two words separated by " ".
1643 RTCList<RTCString> partsOfcontent = content.split(" ");
1644
1645 if (partsOfcontent.at(1).contains("linux"))
1646 {
1647 std::vector<size_t> listOfDefault = isoSuseCfgScript.findTemplate("default");
1648 //handle the lines more intelligently
1649 for(unsigned int j=0; j<listOfDefault.size(); ++j)
1650 {
1651 Utf8Str newContent("default ");
1652 newContent.append(partsOfcontent.at(1));
1653 isoSuseCfgScript.setContentOfLine(listOfDefault.at(j), newContent);
1654 }
1655 }
1656 }
1657
1658 hrc = isoSuseCfgScript.save(path, true);
1659
1660 LogRelFunc(("UnattendedSuseInstaller::setupScriptsOnAuxiliaryCD(): The file %s has been changed\n", path.c_str()));
1661
1662 return hrc;
1663}
1664#endif
1665
1666
1667//////////////////////////////////////////////////////////////////////////////////////////////////////
1668/*
1669*
1670*
1671* Implementation UnattendedFreeBsdInstaller functions
1672*
1673*/
1674//////////////////////////////////////////////////////////////////////////////////////////////////////
1675HRESULT UnattendedFreeBsdInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
1676 RTVFS hVfsOrgIso, bool fOverwrite)
1677{
1678 try
1679 {
1680 RTCString strScriptName;
1681 strScriptName = mpParent->i_getAuxiliaryBasePath();
1682 strScriptName.append(mMainScript.getDefaultFilename());
1683
1684 /* Need to retain the original file permissions for executables. */
1685 rVecArgs.append() = "--no-file-mode";
1686 rVecArgs.append() = "--no-dir-mode";
1687
1688 rVecArgs.append() = "--import-iso";
1689 rVecArgs.append(mpParent->i_getIsoPath());
1690
1691 rVecArgs.append() = "--file-mode=0444";
1692 rVecArgs.append() = "--dir-mode=0555";
1693
1694 /* Remaster ISO, the installer config has to go into /etc. */
1695 rVecArgs.append().append("/etc/installerconfig=").append(strScriptName);
1696 }
1697 catch (std::bad_alloc &)
1698 {
1699 return E_OUTOFMEMORY;
1700 }
1701
1702 /*
1703 * Call parent to add the remaining files
1704 */
1705 return UnattendedInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1706}
Note: See TracBrowser for help on using the repository browser.

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