VirtualBox

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

Last change on this file since 107437 was 107190, checked in by vboxsync, 7 weeks ago

src/VBox/Main/src-server/UnattendedInstaller.cpp: Fixed odd conditions (_arm64 variant implies the _x64 one), found by Parfait.

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

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