VirtualBox

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

Last change on this file since 93920 was 93405, checked in by vboxsync, 3 years ago

Main/Unattended: Use the detected guest OS type instead of the configured VM guest OS type for picking the installer. bugref:10186 bugref:9515

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.0 KB
Line 
1/* $Id: UnattendedInstaller.cpp 93405 2022-01-24 09:56:23Z vboxsync $ */
2/** @file
3 * UnattendedInstaller class and it's descendants implementation
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
23#include "LoggingNew.h"
24#include "VirtualBoxBase.h"
25#include "VirtualBoxErrorInfoImpl.h"
26#include "AutoCaller.h"
27#include <VBox/com/ErrorInfo.h>
28
29#include "UnattendedImpl.h"
30#include "UnattendedInstaller.h"
31#include "UnattendedScript.h"
32
33#include <VBox/err.h>
34#include <iprt/ctype.h>
35#include <iprt/fsisomaker.h>
36#include <iprt/fsvfs.h>
37#include <iprt/getopt.h>
38#include <iprt/file.h>
39#include <iprt/path.h>
40#include <iprt/stream.h>
41#include <iprt/vfs.h>
42#ifdef RT_OS_SOLARIS
43# undef ES /* Workaround for someone dragging the namespace pollutor sys/regset.h. Sigh. */
44#endif
45#include <iprt/formats/iso9660.h>
46#include <iprt/cpp/path.h>
47
48
49using namespace std;
50
51
52/* static */ UnattendedInstaller *
53UnattendedInstaller::createInstance(VBOXOSTYPE enmDetectedOSType, const Utf8Str &strDetectedOSType,
54 const Utf8Str &strDetectedOSVersion, const Utf8Str &strDetectedOSFlavor,
55 const Utf8Str &strDetectedOSHints, Unattended *pParent)
56{
57 UnattendedInstaller *pUinstaller = NULL;
58
59 if (strDetectedOSType.find("Windows") != RTCString::npos)
60 {
61 if (enmDetectedOSType >= VBOXOSTYPE_WinVista)
62 pUinstaller = new UnattendedWindowsXmlInstaller(pParent);
63 else
64 pUinstaller = new UnattendedWindowsSifInstaller(pParent);
65 }
66 else if (enmDetectedOSType >= VBOXOSTYPE_OS2 && enmDetectedOSType < VBOXOSTYPE_Linux)
67 pUinstaller = new UnattendedOs2Installer(pParent, strDetectedOSHints);
68 else
69 {
70 if (enmDetectedOSType == VBOXOSTYPE_Debian || enmDetectedOSType == VBOXOSTYPE_Debian_x64)
71 pUinstaller = new UnattendedDebianInstaller(pParent);
72 else if (enmDetectedOSType >= VBOXOSTYPE_Ubuntu && enmDetectedOSType <= VBOXOSTYPE_Ubuntu_x64)
73 pUinstaller = new UnattendedUbuntuInstaller(pParent);
74 else if (enmDetectedOSType >= VBOXOSTYPE_RedHat && enmDetectedOSType <= VBOXOSTYPE_RedHat_x64)
75 {
76 if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "8") >= 0)
77 pUinstaller = new UnattendedRhel8Installer(pParent);
78 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "7") >= 0)
79 pUinstaller = new UnattendedRhel7Installer(pParent);
80 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "6") >= 0)
81 pUinstaller = new UnattendedRhel6Installer(pParent);
82 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "5") >= 0)
83 pUinstaller = new UnattendedRhel5Installer(pParent);
84 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "4") >= 0)
85 pUinstaller = new UnattendedRhel4Installer(pParent);
86 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "3") >= 0)
87 pUinstaller = new UnattendedRhel3Installer(pParent);
88 else
89 pUinstaller = new UnattendedRhel6Installer(pParent);
90 }
91 else if (enmDetectedOSType >= VBOXOSTYPE_FedoraCore && enmDetectedOSType <= VBOXOSTYPE_FedoraCore_x64)
92 pUinstaller = new UnattendedFedoraInstaller(pParent);
93 else if (enmDetectedOSType >= VBOXOSTYPE_Oracle && enmDetectedOSType <= VBOXOSTYPE_Oracle_x64)
94 {
95 if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "8") >= 0)
96 pUinstaller = new UnattendedOracleLinux8Installer(pParent);
97 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "7") >= 0)
98 pUinstaller = new UnattendedOracleLinux7Installer(pParent);
99 else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "6") >= 0)
100 pUinstaller = new UnattendedOracleLinux6Installer(pParent);
101 else
102 pUinstaller = new UnattendedOracleLinux6Installer(pParent);
103 }
104#if 0 /* doesn't work, so convert later. */
105 else if (enmDetectedOSType == VBOXOSTYPE_OpenSUSE || enmDetectedOSType == VBOXOSTYPE_OpenSUSE_x64)
106 pUinstaller = new UnattendedSuseInstaller(new UnattendedSUSEXMLScript(pParent), pParent);
107#endif
108 }
109 RT_NOREF_PV(strDetectedOSFlavor);
110 RT_NOREF_PV(strDetectedOSHints);
111 return pUinstaller;
112}
113
114
115//////////////////////////////////////////////////////////////////////////////////////////////////////
116/*
117*
118*
119* Implementation Unattended functions
120*
121*/
122//////////////////////////////////////////////////////////////////////////////////////////////////////
123
124/*
125 *
126 * UnattendedInstaller public methods
127 *
128 */
129UnattendedInstaller::UnattendedInstaller(Unattended *pParent,
130 const char *pszMainScriptTemplateName, const char *pszPostScriptTemplateName,
131 const char *pszMainScriptFilename, const char *pszPostScriptFilename,
132 DeviceType_T enmBootDevice /*= DeviceType_DVD */)
133 : mMainScript(pParent, pszMainScriptTemplateName, pszMainScriptFilename)
134 , mPostScript(pParent, pszPostScriptTemplateName, pszPostScriptFilename)
135 , mpParent(pParent)
136 , meBootDevice(enmBootDevice)
137{
138 AssertPtr(pParent);
139 Assert(*pszMainScriptTemplateName);
140 Assert(*pszMainScriptFilename);
141 Assert(*pszPostScriptTemplateName);
142 Assert(*pszPostScriptFilename);
143 Assert(enmBootDevice == DeviceType_DVD || enmBootDevice == DeviceType_Floppy);
144}
145
146UnattendedInstaller::~UnattendedInstaller()
147{
148 mpParent = NULL;
149}
150
151HRESULT UnattendedInstaller::initInstaller()
152{
153 /*
154 * Calculate the full main script template location.
155 */
156 if (mpParent->i_getScriptTemplatePath().isNotEmpty())
157 mStrMainScriptTemplate = mpParent->i_getScriptTemplatePath();
158 else
159 {
160 int vrc = RTPathAppPrivateNoArchCxx(mStrMainScriptTemplate);
161 if (RT_SUCCESS(vrc))
162 vrc = RTPathAppendCxx(mStrMainScriptTemplate, "UnattendedTemplates");
163 if (RT_SUCCESS(vrc))
164 vrc = RTPathAppendCxx(mStrMainScriptTemplate, mMainScript.getDefaultTemplateFilename());
165 if (RT_FAILURE(vrc))
166 return mpParent->setErrorBoth(E_FAIL, vrc,
167 tr("Failed to construct path to the unattended installer script templates (%Rrc)"),
168 vrc);
169 }
170
171 /*
172 * Calculate the full post script template location.
173 */
174 if (mpParent->i_getPostInstallScriptTemplatePath().isNotEmpty())
175 mStrPostScriptTemplate = mpParent->i_getPostInstallScriptTemplatePath();
176 else
177 {
178 int vrc = RTPathAppPrivateNoArchCxx(mStrPostScriptTemplate);
179 if (RT_SUCCESS(vrc))
180 vrc = RTPathAppendCxx(mStrPostScriptTemplate, "UnattendedTemplates");
181 if (RT_SUCCESS(vrc))
182 vrc = RTPathAppendCxx(mStrPostScriptTemplate, mPostScript.getDefaultTemplateFilename());
183 if (RT_FAILURE(vrc))
184 return mpParent->setErrorBoth(E_FAIL, vrc,
185 tr("Failed to construct path to the unattended installer script templates (%Rrc)"),
186 vrc);
187 }
188
189 /*
190 * Construct paths we need.
191 */
192 if (isAuxiliaryFloppyNeeded())
193 {
194 mStrAuxiliaryFloppyFilePath = mpParent->i_getAuxiliaryBasePath();
195 mStrAuxiliaryFloppyFilePath.append("aux-floppy.img");
196 }
197 if (isAuxiliaryIsoNeeded())
198 {
199 mStrAuxiliaryIsoFilePath = mpParent->i_getAuxiliaryBasePath();
200 if (!isAuxiliaryIsoIsVISO())
201 mStrAuxiliaryIsoFilePath.append("aux-iso.iso");
202 else
203 mStrAuxiliaryIsoFilePath.append("aux-iso.viso");
204 }
205
206 /*
207 * Check that we've got the minimum of data available.
208 */
209 if (mpParent->i_getIsoPath().isEmpty())
210 return mpParent->setError(E_INVALIDARG, tr("Cannot proceed with an empty installation ISO path"));
211 if (mpParent->i_getUser().isEmpty())
212 return mpParent->setError(E_INVALIDARG, tr("Empty user name is not allowed"));
213 if (mpParent->i_getPassword().isEmpty())
214 return mpParent->setError(E_INVALIDARG, tr("Empty password is not allowed"));
215
216 LogRelFunc(("UnattendedInstaller::savePassedData(): \n"));
217 return S_OK;
218}
219
220#if 0 /* Always in AUX ISO */
221bool UnattendedInstaller::isAdditionsIsoNeeded() const
222{
223 /* In the VISO case, we'll add the additions to the VISO in a subdir. */
224 return !isAuxiliaryIsoIsVISO() && mpParent->i_getInstallGuestAdditions();
225}
226
227bool UnattendedInstaller::isValidationKitIsoNeeded() const
228{
229 /* In the VISO case, we'll add the validation kit to the VISO in a subdir. */
230 return !isAuxiliaryIsoIsVISO() && mpParent->i_getInstallTestExecService();
231}
232#endif
233
234bool UnattendedInstaller::isAuxiliaryIsoNeeded() const
235{
236 /* In the VISO case we use the AUX ISO for GAs and TXS. */
237 return isAuxiliaryIsoIsVISO()
238 && ( mpParent->i_getInstallGuestAdditions()
239 || mpParent->i_getInstallTestExecService());
240}
241
242
243HRESULT UnattendedInstaller::prepareUnattendedScripts()
244{
245 LogFlow(("UnattendedInstaller::prepareUnattendedScripts()\n"));
246
247 /*
248 * The script template editor calls setError, so status codes just needs to
249 * be passed on to the caller. Do the same for both scripts.
250 */
251 HRESULT hrc = mMainScript.read(getTemplateFilePath());
252 if (SUCCEEDED(hrc))
253 {
254 hrc = mMainScript.parse();
255 if (SUCCEEDED(hrc))
256 {
257 /* Ditto for the post script. */
258 hrc = mPostScript.read(getPostTemplateFilePath());
259 if (SUCCEEDED(hrc))
260 {
261 hrc = mPostScript.parse();
262 if (SUCCEEDED(hrc))
263 {
264 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: returns S_OK\n"));
265 return S_OK;
266 }
267 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: parse failed on post script (%Rhrc)\n", hrc));
268 }
269 else
270 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: error reading post install script template file (%Rhrc)\n", hrc));
271 }
272 else
273 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: parse failed (%Rhrc)\n", hrc));
274 }
275 else
276 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: error reading installation script template file (%Rhrc)\n", hrc));
277 return hrc;
278}
279
280HRESULT UnattendedInstaller::prepareMedia(bool fOverwrite /*=true*/)
281{
282 LogRelFlow(("UnattendedInstaller::prepareMedia:\n"));
283 HRESULT hrc = S_OK;
284 if (isAuxiliaryFloppyNeeded())
285 hrc = prepareAuxFloppyImage(fOverwrite);
286 if (SUCCEEDED(hrc))
287 {
288 if (isAuxiliaryIsoNeeded())
289 {
290 hrc = prepareAuxIsoImage(fOverwrite);
291 if (FAILED(hrc))
292 {
293 LogRelFlow(("UnattendedInstaller::prepareMedia: prepareAuxIsoImage failed\n"));
294
295 /* Delete the floppy image if we created one. */
296 if (isAuxiliaryFloppyNeeded())
297 RTFileDelete(getAuxiliaryFloppyFilePath().c_str());
298 }
299 }
300 }
301 LogRelFlow(("UnattendedInstaller::prepareMedia: returns %Rrc\n", hrc));
302 return hrc;
303}
304
305/*
306 *
307 * UnattendedInstaller protected methods
308 *
309 */
310HRESULT UnattendedInstaller::prepareAuxFloppyImage(bool fOverwrite)
311{
312 Assert(isAuxiliaryFloppyNeeded());
313
314 /*
315 * Create the image.
316 */
317 RTVFSFILE hVfsFile;
318 HRESULT hrc = newAuxFloppyImage(getAuxiliaryFloppyFilePath().c_str(), fOverwrite, &hVfsFile);
319 if (SUCCEEDED(hrc))
320 {
321 /*
322 * Open the FAT file system so we can copy files onto the floppy.
323 */
324 RTERRINFOSTATIC ErrInfo;
325 RTVFS hVfs;
326 int vrc = RTFsFatVolOpen(hVfsFile, false /*fReadOnly*/, 0 /*offBootSector*/, &hVfs, RTErrInfoInitStatic(&ErrInfo));
327 RTVfsFileRelease(hVfsFile);
328 if (RT_SUCCESS(vrc))
329 {
330 /*
331 * Call overridable method to copies the files onto it.
332 */
333 hrc = copyFilesToAuxFloppyImage(hVfs);
334
335 /*
336 * Release the VFS. On failure, delete the floppy image so the operation can
337 * be repeated in non-overwrite mode and so that we don't leave any mess behind.
338 */
339 RTVfsRelease(hVfs);
340 }
341 else if (RTErrInfoIsSet(&ErrInfo.Core))
342 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
343 tr("Failed to open FAT file system on newly created floppy image '%s': %Rrc: %s"),
344 getAuxiliaryFloppyFilePath().c_str(), vrc, ErrInfo.Core.pszMsg);
345 else
346 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
347 tr("Failed to open FAT file system onnewly created floppy image '%s': %Rrc"),
348 getAuxiliaryFloppyFilePath().c_str(), vrc);
349 if (FAILED(hrc))
350 RTFileDelete(getAuxiliaryFloppyFilePath().c_str());
351 }
352 return hrc;
353}
354
355HRESULT UnattendedInstaller::newAuxFloppyImage(const char *pszFilename, bool fOverwrite, PRTVFSFILE phVfsFile)
356{
357 /*
358 * Open the image file.
359 */
360 HRESULT hrc;
361 RTVFSFILE hVfsFile;
362 uint64_t fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT);
363 if (fOverwrite)
364 fOpen |= RTFILE_O_CREATE_REPLACE;
365 else
366 fOpen |= RTFILE_O_OPEN;
367 int vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
368 if (RT_SUCCESS(vrc))
369 {
370 /*
371 * Format it.
372 */
373 vrc = RTFsFatVolFormat144(hVfsFile, false /*fQuick*/);
374 if (RT_SUCCESS(vrc))
375 {
376 *phVfsFile = hVfsFile;
377 LogRelFlow(("UnattendedInstaller::newAuxFloppyImage: created and formatted '%s'\n", pszFilename));
378 return S_OK;
379 }
380
381 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to format floppy image '%s': %Rrc"), pszFilename, vrc);
382 RTVfsFileRelease(hVfsFile);
383 RTFileDelete(pszFilename);
384 }
385 else
386 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to create floppy image '%s': %Rrc"), pszFilename, vrc);
387 return hrc;
388}
389
390HRESULT UnattendedInstaller::copyFilesToAuxFloppyImage(RTVFS hVfs)
391{
392 HRESULT hrc = addScriptToFloppyImage(&mMainScript, hVfs);
393 if (SUCCEEDED(hrc))
394 hrc = addScriptToFloppyImage(&mPostScript, hVfs);
395 return hrc;
396}
397
398HRESULT UnattendedInstaller::addScriptToFloppyImage(BaseTextScript *pEditor, RTVFS hVfs)
399{
400 /*
401 * Open the destination file.
402 */
403 HRESULT hrc;
404 RTVFSFILE hVfsFileDst;
405 int vrc = RTVfsFileOpen(hVfs, pEditor->getDefaultFilename(),
406 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_ALL
407 | (0660 << RTFILE_O_CREATE_MODE_SHIFT),
408 &hVfsFileDst);
409 if (RT_SUCCESS(vrc))
410 {
411 /*
412 * Save the content to a string.
413 */
414 Utf8Str strScript;
415 hrc = pEditor->saveToString(strScript);
416 if (SUCCEEDED(hrc))
417 {
418 /*
419 * Write the string.
420 */
421 vrc = RTVfsFileWrite(hVfsFileDst, strScript.c_str(), strScript.length(), NULL);
422 if (RT_SUCCESS(vrc))
423 hrc = S_OK; /* done */
424 else
425 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
426 tr("Error writing %zu bytes to '%s' in floppy image '%s': %Rrc",
427 "", strScript.length()),
428 strScript.length(), pEditor->getDefaultFilename(),
429 getAuxiliaryFloppyFilePath().c_str());
430 }
431 RTVfsFileRelease(hVfsFileDst);
432 }
433 else
434 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
435 tr("Error creating '%s' in floppy image '%s': %Rrc"),
436 pEditor->getDefaultFilename(), getAuxiliaryFloppyFilePath().c_str());
437 return hrc;
438}
439
440HRESULT UnattendedInstaller::addFileToFloppyImage(RTVFS hVfs, const char *pszSrc, const char *pszDst)
441{
442 HRESULT hrc;
443
444 /*
445 * Open the source file.
446 */
447 RTVFSIOSTREAM hVfsIosSrc;
448 int vrc = RTVfsIoStrmOpenNormal(pszSrc, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsIosSrc);
449 if (RT_SUCCESS(vrc))
450 {
451 /*
452 * Open the destination file.
453 */
454 RTVFSFILE hVfsFileDst;
455 vrc = RTVfsFileOpen(hVfs, pszDst,
456 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT),
457 &hVfsFileDst);
458 if (RT_SUCCESS(vrc))
459 {
460 /*
461 * Do the copying.
462 */
463 RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFileDst);
464 vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0);
465 if (RT_SUCCESS(vrc))
466 hrc = S_OK;
467 else
468 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing copying '%s' to floppy image '%s': %Rrc"),
469 pszSrc, getAuxiliaryFloppyFilePath().c_str(), vrc);
470 RTVfsIoStrmRelease(hVfsIosDst);
471 RTVfsFileRelease(hVfsFileDst);
472 }
473 else
474 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error opening '%s' on floppy image '%s' for writing: %Rrc"),
475 pszDst, getAuxiliaryFloppyFilePath().c_str(), vrc);
476
477 RTVfsIoStrmRelease(hVfsIosSrc);
478 }
479 else
480 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error opening '%s' for copying onto floppy image '%s': %Rrc"),
481 pszSrc, getAuxiliaryFloppyFilePath().c_str(), vrc);
482 return hrc;
483}
484
485HRESULT UnattendedInstaller::prepareAuxIsoImage(bool fOverwrite)
486{
487 /*
488 * Open the original installation ISO.
489 */
490 RTVFS hVfsOrgIso;
491 HRESULT hrc = openInstallIsoImage(&hVfsOrgIso);
492 if (SUCCEEDED(hrc))
493 {
494 /*
495 * The next steps depends on the kind of image we're making.
496 */
497 if (!isAuxiliaryIsoIsVISO())
498 {
499 RTFSISOMAKER hIsoMaker;
500 hrc = newAuxIsoImageMaker(&hIsoMaker);
501 if (SUCCEEDED(hrc))
502 {
503 hrc = addFilesToAuxIsoImageMaker(hIsoMaker, hVfsOrgIso);
504 if (SUCCEEDED(hrc))
505 hrc = finalizeAuxIsoImage(hIsoMaker, getAuxiliaryIsoFilePath().c_str(), fOverwrite);
506 RTFsIsoMakerRelease(hIsoMaker);
507 }
508 }
509 else
510 {
511 RTCList<RTCString> vecFiles(0);
512 RTCList<RTCString> vecArgs(0);
513 try
514 {
515 vecArgs.append() = "--iprt-iso-maker-file-marker-bourne-sh";
516 RTUUID Uuid;
517 int vrc = RTUuidCreate(&Uuid); AssertRC(vrc);
518 char szTmp[RTUUID_STR_LENGTH + 1];
519 vrc = RTUuidToStr(&Uuid, szTmp, sizeof(szTmp)); AssertRC(vrc);
520 vecArgs.append() = szTmp;
521 vecArgs.append() = "--file-mode=0444";
522 vecArgs.append() = "--dir-mode=0555";
523 }
524 catch (std::bad_alloc &)
525 {
526 hrc = E_OUTOFMEMORY;
527 }
528 if (SUCCEEDED(hrc))
529 {
530 hrc = addFilesToAuxVisoVectors(vecArgs, vecFiles, hVfsOrgIso, fOverwrite);
531 if (SUCCEEDED(hrc))
532 hrc = finalizeAuxVisoFile(vecArgs, getAuxiliaryIsoFilePath().c_str(), fOverwrite);
533
534 if (FAILED(hrc))
535 for (size_t i = 0; i < vecFiles.size(); i++)
536 RTFileDelete(vecFiles[i].c_str());
537 }
538 }
539 RTVfsRelease(hVfsOrgIso);
540 }
541 return hrc;
542}
543
544HRESULT UnattendedInstaller::openInstallIsoImage(PRTVFS phVfsIso, uint32_t fFlags /*= 0*/)
545{
546 /* Open the file. */
547 const char *pszIsoPath = mpParent->i_getIsoPath().c_str();
548 RTVFSFILE hOrgIsoFile;
549 int vrc = RTVfsFileOpenNormal(pszIsoPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hOrgIsoFile);
550 if (RT_FAILURE(vrc))
551 return mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to open ISO image '%s' (%Rrc)"), pszIsoPath, vrc);
552
553 /* Pass the file to the ISO file system interpreter. */
554 RTERRINFOSTATIC ErrInfo;
555 vrc = RTFsIso9660VolOpen(hOrgIsoFile, fFlags, phVfsIso, RTErrInfoInitStatic(&ErrInfo));
556 RTVfsFileRelease(hOrgIsoFile);
557 if (RT_SUCCESS(vrc))
558 return S_OK;
559 if (RTErrInfoIsSet(&ErrInfo.Core))
560 return mpParent->setErrorBoth(E_FAIL, vrc, tr("ISO reader fail to open '%s' (%Rrc): %s"),
561 pszIsoPath, vrc, ErrInfo.Core.pszMsg);
562 return mpParent->setErrorBoth(E_FAIL, vrc, tr("ISO reader fail to open '%s' (%Rrc)"), pszIsoPath, vrc);
563}
564
565HRESULT UnattendedInstaller::newAuxIsoImageMaker(PRTFSISOMAKER phIsoMaker)
566{
567 int vrc = RTFsIsoMakerCreate(phIsoMaker);
568 if (RT_SUCCESS(vrc))
569 return S_OK;
570 return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerCreate failed (%Rrc)"), vrc);
571}
572
573HRESULT UnattendedInstaller::addFilesToAuxIsoImageMaker(RTFSISOMAKER hIsoMaker, RTVFS hVfsOrgIso)
574{
575 RT_NOREF(hVfsOrgIso);
576
577 /*
578 * Add the two scripts to the image with default names.
579 */
580 HRESULT hrc = addScriptToIsoMaker(&mMainScript, hIsoMaker);
581 if (SUCCEEDED(hrc))
582 hrc = addScriptToIsoMaker(&mPostScript, hIsoMaker);
583 return hrc;
584}
585
586HRESULT UnattendedInstaller::addScriptToIsoMaker(BaseTextScript *pEditor, RTFSISOMAKER hIsoMaker,
587 const char *pszDstFilename /*= NULL*/)
588{
589 /*
590 * Calc default destination filename if desired.
591 */
592 RTCString strDstNameBuf;
593 if (!pszDstFilename)
594 {
595 try
596 {
597 strDstNameBuf = RTPATH_SLASH_STR;
598 strDstNameBuf.append(pEditor->getDefaultTemplateFilename());
599 pszDstFilename = strDstNameBuf.c_str();
600 }
601 catch (std::bad_alloc &)
602 {
603 return E_OUTOFMEMORY;
604 }
605 }
606
607 /*
608 * Create a memory file for the script.
609 */
610 Utf8Str strScript;
611 HRESULT hrc = pEditor->saveToString(strScript);
612 if (SUCCEEDED(hrc))
613 {
614 RTVFSFILE hVfsScriptFile;
615 size_t cchScript = strScript.length();
616 int vrc = RTVfsFileFromBuffer(RTFILE_O_READ, strScript.c_str(), strScript.length(), &hVfsScriptFile);
617 strScript.setNull();
618 if (RT_SUCCESS(vrc))
619 {
620 /*
621 * Add it to the ISO.
622 */
623 vrc = RTFsIsoMakerAddFileWithVfsFile(hIsoMaker, pszDstFilename, hVfsScriptFile, NULL);
624 RTVfsFileRelease(hVfsScriptFile);
625 if (RT_SUCCESS(vrc))
626 hrc = S_OK;
627 else
628 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
629 tr("RTFsIsoMakerAddFileWithVfsFile failed on the script '%s' (%Rrc)"),
630 pszDstFilename, vrc);
631 }
632 else
633 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
634 tr("RTVfsFileFromBuffer failed on the %zu byte script '%s' (%Rrc)", "", cchScript),
635 cchScript, pszDstFilename, vrc);
636 }
637 return hrc;
638}
639
640HRESULT UnattendedInstaller::finalizeAuxIsoImage(RTFSISOMAKER hIsoMaker, const char *pszFilename, bool fOverwrite)
641{
642 /*
643 * Finalize the image.
644 */
645 int vrc = RTFsIsoMakerFinalize(hIsoMaker);
646 if (RT_FAILURE(vrc))
647 return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerFinalize failed (%Rrc)"), vrc);
648
649 /*
650 * Open the destination file.
651 */
652 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
653 if (fOverwrite)
654 fOpen |= RTFILE_O_CREATE_REPLACE;
655 else
656 fOpen |= RTFILE_O_CREATE;
657 RTVFSFILE hVfsDstFile;
658 vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsDstFile);
659 if (RT_FAILURE(vrc))
660 {
661 if (vrc == VERR_ALREADY_EXISTS)
662 return mpParent->setErrorBoth(E_FAIL, vrc, tr("The auxiliary ISO image file '%s' already exists"),
663 pszFilename);
664 return mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to open the auxiliary ISO image file '%s' for writing (%Rrc)"),
665 pszFilename, vrc);
666 }
667
668 /*
669 * Get the source file from the image maker.
670 */
671 HRESULT hrc;
672 RTVFSFILE hVfsSrcFile;
673 vrc = RTFsIsoMakerCreateVfsOutputFile(hIsoMaker, &hVfsSrcFile);
674 if (RT_SUCCESS(vrc))
675 {
676 RTVFSIOSTREAM hVfsSrcIso = RTVfsFileToIoStream(hVfsSrcFile);
677 RTVFSIOSTREAM hVfsDstIso = RTVfsFileToIoStream(hVfsDstFile);
678 if ( hVfsSrcIso != NIL_RTVFSIOSTREAM
679 && hVfsDstIso != NIL_RTVFSIOSTREAM)
680 {
681 vrc = RTVfsUtilPumpIoStreams(hVfsSrcIso, hVfsDstIso, 0 /*cbBufHint*/);
682 if (RT_SUCCESS(vrc))
683 hrc = S_OK;
684 else
685 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Error writing auxiliary ISO image '%s' (%Rrc)"),
686 pszFilename, vrc);
687 }
688 else
689 hrc = mpParent->setErrorBoth(E_FAIL, VERR_INTERNAL_ERROR_2,
690 tr("Internal Error: Failed to case VFS file to VFS I/O stream"));
691 RTVfsIoStrmRelease(hVfsSrcIso);
692 RTVfsIoStrmRelease(hVfsDstIso);
693 }
694 else
695 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerCreateVfsOutputFile failed (%Rrc)"), vrc);
696 RTVfsFileRelease(hVfsSrcFile);
697 RTVfsFileRelease(hVfsDstFile);
698 if (FAILED(hrc))
699 RTFileDelete(pszFilename);
700 return hrc;
701}
702
703HRESULT UnattendedInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
704 RTVFS hVfsOrgIso, bool fOverwrite)
705{
706 RT_NOREF(hVfsOrgIso);
707
708 /*
709 * Save and add the scripts.
710 */
711 HRESULT hrc = addScriptToVisoVectors(&mMainScript, rVecArgs, rVecFiles, fOverwrite);
712 if (SUCCEEDED(hrc))
713 hrc = addScriptToVisoVectors(&mPostScript, rVecArgs, rVecFiles, fOverwrite);
714 if (SUCCEEDED(hrc))
715 {
716 try
717 {
718 /*
719 * If we've got a Guest Additions ISO, add its content to a /vboxadditions dir.
720 */
721 if (mpParent->i_getInstallGuestAdditions())
722 {
723 rVecArgs.append().append("--push-iso=").append(mpParent->i_getAdditionsIsoPath());
724 rVecArgs.append() = "/vboxadditions=/";
725 rVecArgs.append() = "--pop";
726 }
727
728 /*
729 * If we've got a Validation Kit ISO, add its content to a /vboxvalidationkit dir.
730 */
731 if (mpParent->i_getInstallTestExecService())
732 {
733 rVecArgs.append().append("--push-iso=").append(mpParent->i_getValidationKitIsoPath());
734 rVecArgs.append() = "/vboxvalidationkit=/";
735 rVecArgs.append() = "--pop";
736 }
737 }
738 catch (std::bad_alloc &)
739 {
740 hrc = E_OUTOFMEMORY;
741 }
742 }
743 return hrc;
744}
745
746HRESULT UnattendedInstaller::addScriptToVisoVectors(BaseTextScript *pEditor, RTCList<RTCString> &rVecArgs,
747 RTCList<RTCString> &rVecFiles, bool fOverwrite)
748{
749 /*
750 * Calc the aux script file name.
751 */
752 RTCString strScriptName;
753 try
754 {
755 strScriptName = mpParent->i_getAuxiliaryBasePath();
756 strScriptName.append(pEditor->getDefaultFilename());
757 }
758 catch (std::bad_alloc &)
759 {
760 return E_OUTOFMEMORY;
761 }
762
763 /*
764 * Save it.
765 */
766 HRESULT hrc = pEditor->save(strScriptName.c_str(), fOverwrite);
767 if (SUCCEEDED(hrc))
768 {
769 /*
770 * Add it to the vectors.
771 */
772 try
773 {
774 rVecArgs.append().append('/').append(pEditor->getDefaultFilename()).append('=').append(strScriptName);
775 rVecFiles.append(strScriptName);
776 }
777 catch (std::bad_alloc &)
778 {
779 RTFileDelete(strScriptName.c_str());
780 hrc = E_OUTOFMEMORY;
781 }
782 }
783 return hrc;
784}
785
786HRESULT UnattendedInstaller::finalizeAuxVisoFile(RTCList<RTCString> const &rVecArgs, const char *pszFilename, bool fOverwrite)
787{
788 /*
789 * Create a C-style argument vector and turn that into a command line string.
790 */
791 size_t const cArgs = rVecArgs.size();
792 const char **papszArgs = (const char **)RTMemTmpAlloc((cArgs + 1) * sizeof(const char *));
793 if (!papszArgs)
794 return E_OUTOFMEMORY;
795 for (size_t i = 0; i < cArgs; i++)
796 papszArgs[i] = rVecArgs[i].c_str();
797 papszArgs[cArgs] = NULL;
798
799 char *pszCmdLine;
800 int vrc = RTGetOptArgvToString(&pszCmdLine, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
801 RTMemTmpFree(papszArgs);
802 if (RT_FAILURE(vrc))
803 return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTGetOptArgvToString failed (%Rrc)"), vrc);
804
805 /*
806 * Open the file.
807 */
808 HRESULT hrc;
809 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ;
810 if (fOverwrite)
811 fOpen |= RTFILE_O_CREATE_REPLACE;
812 else
813 fOpen |= RTFILE_O_CREATE;
814 RTFILE hFile;
815 vrc = RTFileOpen(&hFile, pszFilename, fOpen);
816 if (RT_SUCCESS(vrc))
817 {
818 vrc = RTFileWrite(hFile, pszCmdLine, strlen(pszCmdLine), NULL);
819 if (RT_SUCCESS(vrc))
820 vrc = RTFileClose(hFile);
821 else
822 RTFileClose(hFile);
823 if (RT_SUCCESS(vrc))
824 hrc = S_OK;
825 else
826 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing '%s' (%Rrc)"), pszFilename, vrc);
827 }
828 else
829 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to create '%s' (%Rrc)"), pszFilename, vrc);
830
831 RTStrFree(pszCmdLine);
832 return hrc;
833}
834
835HRESULT UnattendedInstaller::loadAndParseFileFromIso(RTVFS hVfsOrgIso, const char *pszFilename, AbstractScript *pEditor)
836{
837 HRESULT hrc;
838 RTVFSFILE hVfsFile;
839 int vrc = RTVfsFileOpen(hVfsOrgIso, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsFile);
840 if (RT_SUCCESS(vrc))
841 {
842 hrc = pEditor->readFromHandle(hVfsFile, pszFilename);
843 RTVfsFileRelease(hVfsFile);
844 if (SUCCEEDED(hrc))
845 hrc = pEditor->parse();
846 }
847 else
848 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open '%s' on the ISO '%s' (%Rrc)"),
849 pszFilename, mpParent->i_getIsoPath().c_str(), vrc);
850 return hrc;
851}
852
853
854
855//////////////////////////////////////////////////////////////////////////////////////////////////////
856/*
857*
858*
859* Implementation UnattendedLinuxInstaller functions
860*
861*/
862//////////////////////////////////////////////////////////////////////////////////////////////////////
863HRESULT UnattendedLinuxInstaller::editIsoLinuxCfg(GeneralTextScript *pEditor)
864{
865 try
866 {
867 /* Set timeouts to 10 seconds. */
868 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("timeout", RTCString::CaseInsensitive);
869 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
870 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("timeout", RTCString::CaseInsensitive))
871 {
872 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), "timeout 10");
873 if (FAILED(hrc))
874 return hrc;
875 }
876
877 /* Comment out 'display <filename>' directives that's used for displaying files at boot time. */
878 vecLineNumbers = pEditor->findTemplate("display", RTCString::CaseInsensitive);
879 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
880 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("display", RTCString::CaseInsensitive))
881 {
882 HRESULT hrc = pEditor->prependToLine(vecLineNumbers.at(i), "#");
883 if (FAILED(hrc))
884 return hrc;
885 }
886
887 /* Modify kernel parameters. */
888 vecLineNumbers = pEditor->findTemplate("append", RTCString::CaseInsensitive);
889 if (vecLineNumbers.size() > 0)
890 {
891 Utf8Str const &rStrAppend = mpParent->i_getExtraInstallKernelParameters().isNotEmpty()
892 ? mpParent->i_getExtraInstallKernelParameters()
893 : mStrDefaultExtraInstallKernelParameters;
894
895 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
896 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("append", RTCString::CaseInsensitive))
897 {
898 Utf8Str strLine = pEditor->getContentOfLine(vecLineNumbers[i]);
899
900 /* Do removals. */
901 if (mArrStrRemoveInstallKernelParameters.size() > 0)
902 {
903 size_t offStart = strLine.find("append") + 5;
904 while (offStart < strLine.length() && !RT_C_IS_SPACE(strLine[offStart]))
905 offStart++;
906 while (offStart < strLine.length() && RT_C_IS_SPACE(strLine[offStart]))
907 offStart++;
908 if (offStart < strLine.length())
909 {
910 for (size_t iRemove = 0; iRemove < mArrStrRemoveInstallKernelParameters.size(); iRemove++)
911 {
912 RTCString const &rStrRemove = mArrStrRemoveInstallKernelParameters[iRemove];
913 for (size_t off = offStart; off < strLine.length(); )
914 {
915 Assert(!RT_C_IS_SPACE(strLine[off]));
916
917 /* Find the end of word. */
918 size_t offEnd = off + 1;
919 while (offEnd < strLine.length() && !RT_C_IS_SPACE(strLine[offEnd]))
920 offEnd++;
921
922 /* Check if it matches. */
923 if (RTStrSimplePatternNMatch(rStrRemove.c_str(), rStrRemove.length(),
924 strLine.c_str() + off, offEnd - off))
925 {
926 while (off > 0 && RT_C_IS_SPACE(strLine[off - 1]))
927 off--;
928 strLine.erase(off, offEnd - off);
929 }
930
931 /* Advance to the next word. */
932 off = offEnd;
933 while (off < strLine.length() && RT_C_IS_SPACE(strLine[off]))
934 off++;
935 }
936 }
937 }
938 }
939
940 /* Do the appending. */
941 if (rStrAppend.isNotEmpty())
942 {
943 if (!rStrAppend.startsWith(" ") && !strLine.endsWith(" "))
944 strLine.append(' ');
945 strLine.append(rStrAppend);
946 }
947
948 /* Update line. */
949 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), strLine);
950 if (FAILED(hrc))
951 return hrc;
952 }
953 }
954 }
955 catch (std::bad_alloc &)
956 {
957 return E_OUTOFMEMORY;
958 }
959 return S_OK;
960}
961
962
963//////////////////////////////////////////////////////////////////////////////////////////////////////
964/*
965*
966*
967* Implementation UnattendedDebianInstaller functions
968*
969*/
970//////////////////////////////////////////////////////////////////////////////////////////////////////
971
972/**
973 * Helper for checking if a file exists.
974 * @todo promote to IPRT?
975 */
976static bool hlpVfsFileExists(RTVFS hVfs, const char *pszPath)
977{
978 RTFSOBJINFO ObjInfo;
979 int vrc = RTVfsQueryPathInfo(hVfs, pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
980 return RT_SUCCESS(vrc) && RTFS_IS_FILE(ObjInfo.Attr.fMode);
981}
982
983HRESULT UnattendedDebianInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
984 RTVFS hVfsOrgIso, bool fOverwrite)
985{
986 /*
987 * The txt.cfg file used to be called isolinux.txt (ubuntu 4.10
988 * and possible others).
989 */
990 /** @todo Ubuntu 4.10 does not work, as we generate too long command lines
991 * and the kernel crashes immediately. */
992 const char *pszIsoLinuxTxtCfg = "/isolinux/txt.cfg";
993 if ( !hlpVfsFileExists(hVfsOrgIso, pszIsoLinuxTxtCfg)
994 && hlpVfsFileExists(hVfsOrgIso, "/isolinux/isolinux.txt"))
995 pszIsoLinuxTxtCfg = "/isolinux/isolinux.txt";
996
997 /*
998 * VISO bits and filenames.
999 */
1000 RTCString strIsoLinuxCfg;
1001 RTCString strTxtCfg;
1002 try
1003 {
1004 /* Remaster ISO. */
1005 rVecArgs.append() = "--no-file-mode";
1006 rVecArgs.append() = "--no-dir-mode";
1007
1008 rVecArgs.append() = "--import-iso";
1009 rVecArgs.append(mpParent->i_getIsoPath());
1010
1011 rVecArgs.append() = "--file-mode=0444";
1012 rVecArgs.append() = "--dir-mode=0555";
1013
1014 /* Remove the two isolinux configure files we'll be replacing. */
1015 rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
1016 rVecArgs.append().assign(&pszIsoLinuxTxtCfg[1]).append("=:must-remove:");
1017
1018 /* Add the replacement files. */
1019 strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
1020 strIsoLinuxCfg.append("isolinux-isolinux.cfg");
1021 rVecArgs.append().append("isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
1022
1023 strTxtCfg = mpParent->i_getAuxiliaryBasePath();
1024 strTxtCfg.append("isolinux-txt.cfg");
1025 rVecArgs.append().assign(&pszIsoLinuxTxtCfg[1]).append("=").append(strTxtCfg);
1026 }
1027 catch (std::bad_alloc &)
1028 {
1029 return E_OUTOFMEMORY;
1030 }
1031
1032 /*
1033 * Edit the isolinux.cfg file.
1034 */
1035 {
1036 GeneralTextScript Editor(mpParent);
1037 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, "/isolinux/isolinux.cfg", &Editor);
1038 if (SUCCEEDED(hrc))
1039 hrc = editIsoLinuxCfg(&Editor);
1040 if (SUCCEEDED(hrc))
1041 {
1042 hrc = Editor.save(strIsoLinuxCfg, fOverwrite);
1043 if (SUCCEEDED(hrc))
1044 {
1045 try
1046 {
1047 rVecFiles.append(strIsoLinuxCfg);
1048 }
1049 catch (std::bad_alloc &)
1050 {
1051 RTFileDelete(strIsoLinuxCfg.c_str());
1052 hrc = E_OUTOFMEMORY;
1053 }
1054 }
1055 }
1056 if (FAILED(hrc))
1057 return hrc;
1058 }
1059
1060 /*
1061 * Edit the txt.cfg file.
1062 */
1063 {
1064 GeneralTextScript Editor(mpParent);
1065 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, pszIsoLinuxTxtCfg, &Editor);
1066 if (SUCCEEDED(hrc))
1067 hrc = editDebianTxtCfg(&Editor);
1068 if (SUCCEEDED(hrc))
1069 {
1070 hrc = Editor.save(strTxtCfg, fOverwrite);
1071 if (SUCCEEDED(hrc))
1072 {
1073 try
1074 {
1075 rVecFiles.append(strTxtCfg);
1076 }
1077 catch (std::bad_alloc &)
1078 {
1079 RTFileDelete(strTxtCfg.c_str());
1080 hrc = E_OUTOFMEMORY;
1081 }
1082 }
1083 }
1084 if (FAILED(hrc))
1085 return hrc;
1086 }
1087
1088 /*
1089 * Call parent to add the preseed file from mAlg.
1090 */
1091 return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1092}
1093
1094HRESULT UnattendedDebianInstaller::editDebianTxtCfg(GeneralTextScript *pEditor)
1095{
1096 try
1097 {
1098 /** @todo r=bird: Add some comments saying wtf you're actually up to here.
1099 * Repeating what's clear from function calls and boasting the
1100 * inteligence of the code isn't helpful. */
1101 //find all lines with "label" inside
1102 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("label", RTCString::CaseInsensitive);
1103 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1104 {
1105 RTCString const &rContent = pEditor->getContentOfLine(vecLineNumbers[i]);
1106
1107 // ASSUME: suppose general string looks like "label install", two words separated by " ".
1108 RTCList<RTCString> vecPartsOfcontent = rContent.split(" ");
1109 if (vecPartsOfcontent.size() > 1 && vecPartsOfcontent[1].contains("install")) /** @todo r=bird: case insensitive? */
1110 {
1111 std::vector<size_t> vecDefaultLineNumbers = pEditor->findTemplate("default", RTCString::CaseInsensitive);
1112 //handle the lines more intelligently
1113 for (size_t j = 0; j < vecDefaultLineNumbers.size(); ++j)
1114 {
1115 Utf8Str strNewContent("default ");
1116 strNewContent.append(vecPartsOfcontent[1]);
1117 HRESULT hrc = pEditor->setContentOfLine(vecDefaultLineNumbers[j], strNewContent);
1118 if (FAILED(hrc))
1119 return hrc;
1120 }
1121 }
1122 }
1123 }
1124 catch (std::bad_alloc &)
1125 {
1126 return E_OUTOFMEMORY;
1127 }
1128 return UnattendedLinuxInstaller::editIsoLinuxCfg(pEditor);
1129}
1130
1131
1132//////////////////////////////////////////////////////////////////////////////////////////////////////
1133/*
1134*
1135*
1136* Implementation UnattendedRhel6Installer functions
1137*
1138*/
1139//////////////////////////////////////////////////////////////////////////////////////////////////////
1140HRESULT UnattendedRhel6Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
1141 RTVFS hVfsOrgIso, bool fOverwrite)
1142{
1143 Utf8Str strIsoLinuxCfg;
1144 try
1145 {
1146#if 1
1147 /* Remaster ISO. */
1148 rVecArgs.append() = "--no-file-mode";
1149 rVecArgs.append() = "--no-dir-mode";
1150
1151 rVecArgs.append() = "--import-iso";
1152 rVecArgs.append(mpParent->i_getIsoPath());
1153
1154 rVecArgs.append() = "--file-mode=0444";
1155 rVecArgs.append() = "--dir-mode=0555";
1156
1157 /* We replace isolinux.cfg with our edited version (see further down). */
1158 rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
1159 strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
1160 strIsoLinuxCfg.append("isolinux-isolinux.cfg");
1161 rVecArgs.append().append("isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
1162
1163#else
1164 /** @todo Maybe we should just remaster the ISO for redhat derivatives too?
1165 * One less CDROM to mount. */
1166 /* Name the ISO. */
1167 rVecArgs.append() = "--volume-id=VBox Unattended Boot";
1168
1169 /* Copy the isolinux directory from the original install ISO. */
1170 rVecArgs.append().append("--push-iso=").append(mpParent->i_getIsoPath());
1171 rVecArgs.append() = "/isolinux=/isolinux";
1172 rVecArgs.append() = "--pop";
1173
1174 /* We replace isolinux.cfg with our edited version (see further down). */
1175 rVecArgs.append() = "/isolinux/isolinux.cfg=:must-remove:";
1176
1177 strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
1178 strIsoLinuxCfg.append("isolinux-isolinux.cfg");
1179 rVecArgs.append().append("/isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
1180
1181 /* Configure booting /isolinux/isolinux.bin. */
1182 rVecArgs.append() = "--eltorito-boot";
1183 rVecArgs.append() = "/isolinux/isolinux.bin";
1184 rVecArgs.append() = "--no-emulation-boot";
1185 rVecArgs.append() = "--boot-info-table";
1186 rVecArgs.append() = "--boot-load-seg=0x07c0";
1187 rVecArgs.append() = "--boot-load-size=4";
1188
1189 /* Make the boot catalog visible in the file system. */
1190 rVecArgs.append() = "--boot-catalog=/isolinux/vboxboot.cat";
1191#endif
1192 }
1193 catch (std::bad_alloc &)
1194 {
1195 return E_OUTOFMEMORY;
1196 }
1197
1198 /*
1199 * Edit isolinux.cfg and save it.
1200 */
1201 {
1202 GeneralTextScript Editor(mpParent);
1203 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, "/isolinux/isolinux.cfg", &Editor);
1204 if (SUCCEEDED(hrc))
1205 hrc = editIsoLinuxCfg(&Editor);
1206 if (SUCCEEDED(hrc))
1207 {
1208 hrc = Editor.save(strIsoLinuxCfg, fOverwrite);
1209 if (SUCCEEDED(hrc))
1210 {
1211 try
1212 {
1213 rVecFiles.append(strIsoLinuxCfg);
1214 }
1215 catch (std::bad_alloc &)
1216 {
1217 RTFileDelete(strIsoLinuxCfg.c_str());
1218 hrc = E_OUTOFMEMORY;
1219 }
1220 }
1221 }
1222 if (FAILED(hrc))
1223 return hrc;
1224 }
1225
1226 /*
1227 * Call parent to add the ks.cfg file from mAlg.
1228 */
1229 return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1230}
1231
1232
1233//////////////////////////////////////////////////////////////////////////////////////////////////////
1234/*
1235*
1236*
1237* Implementation UnattendedSuseInstaller functions
1238*
1239*/
1240//////////////////////////////////////////////////////////////////////////////////////////////////////
1241#if 0 /* doesn't work, so convert later */
1242/*
1243 *
1244 * UnattendedSuseInstaller protected methods
1245 *
1246*/
1247HRESULT UnattendedSuseInstaller::setUserData()
1248{
1249 HRESULT rc = S_OK;
1250 //here base class function must be called first
1251 //because user home directory is set after user name
1252 rc = UnattendedInstaller::setUserData();
1253
1254 rc = mAlg->setField(USERHOMEDIR_ID, "");
1255 if (FAILED(rc))
1256 return rc;
1257
1258 return rc;
1259}
1260
1261/*
1262 *
1263 * UnattendedSuseInstaller private methods
1264 *
1265*/
1266
1267HRESULT UnattendedSuseInstaller::iv_initialPhase()
1268{
1269 Assert(isAuxiliaryIsoNeeded());
1270 if (mParent->i_isGuestOs64Bit())
1271 mFilesAndDirsToExtractFromIso.append("boot/x86_64/loader/ ");
1272 else
1273 mFilesAndDirsToExtractFromIso.append("boot/i386/loader/ ");
1274 return extractOriginalIso(mFilesAndDirsToExtractFromIso);
1275}
1276
1277
1278HRESULT UnattendedSuseInstaller::setupScriptOnAuxiliaryCD(const Utf8Str &path)
1279{
1280 HRESULT rc = S_OK;
1281
1282 GeneralTextScript isoSuseCfgScript(mpParent);
1283 rc = isoSuseCfgScript.read(path);
1284 rc = isoSuseCfgScript.parse();
1285 //fix linux core bootable parameters: add path to the preseed script
1286
1287 std::vector<size_t> listOfLines = isoSuseCfgScript.findTemplate("append");
1288 for(unsigned int i=0; i<listOfLines.size(); ++i)
1289 {
1290 isoSuseCfgScript.appendToLine(listOfLines.at(i),
1291 " auto=true priority=critical autoyast=default instmode=cd quiet splash noprompt noshell --");
1292 }
1293
1294 //find all lines with "label" inside
1295 listOfLines = isoSuseCfgScript.findTemplate("label");
1296 for(unsigned int i=0; i<listOfLines.size(); ++i)
1297 {
1298 Utf8Str content = isoSuseCfgScript.getContentOfLine(listOfLines.at(i));
1299
1300 //suppose general string looks like "label linux", two words separated by " ".
1301 RTCList<RTCString> partsOfcontent = content.split(" ");
1302
1303 if (partsOfcontent.at(1).contains("linux"))
1304 {
1305 std::vector<size_t> listOfDefault = isoSuseCfgScript.findTemplate("default");
1306 //handle the lines more intelligently
1307 for(unsigned int j=0; j<listOfDefault.size(); ++j)
1308 {
1309 Utf8Str newContent("default ");
1310 newContent.append(partsOfcontent.at(1));
1311 isoSuseCfgScript.setContentOfLine(listOfDefault.at(j), newContent);
1312 }
1313 }
1314 }
1315
1316 rc = isoSuseCfgScript.save(path, true);
1317
1318 LogRelFunc(("UnattendedSuseInstaller::setupScriptsOnAuxiliaryCD(): The file %s has been changed\n", path.c_str()));
1319
1320 return rc;
1321}
1322#endif
1323
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