VirtualBox

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

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

Main/Unattended: ​​bugref:9781. Some commenting.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.8 KB
Line 
1/* $Id: UnattendedInstaller.cpp 94325 2022-03-22 14:19:46Z 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 /* Don't include menu.cfg which may default (as most Debians do) to some vanilla menu item. txt.cfg has command
868 * kernel line options pointing to our preseed file. */
869 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("include", RTCString::CaseInsensitive);
870 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
871 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("include", RTCString::CaseInsensitive))
872 {
873 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), "include txt.cfg");
874 if (FAILED(hrc))
875 return hrc;
876 }
877
878
879 /* Comment out 'display <filename>' directives that's used for displaying files at boot time. */
880 vecLineNumbers = pEditor->findTemplate("display", RTCString::CaseInsensitive);
881 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
882 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("display", RTCString::CaseInsensitive))
883 {
884 HRESULT hrc = pEditor->prependToLine(vecLineNumbers.at(i), "#");
885 if (FAILED(hrc))
886 return hrc;
887 }
888 }
889 catch (std::bad_alloc &)
890 {
891 return E_OUTOFMEMORY;
892 }
893 return editIsoLinuxCommon(pEditor);
894}
895
896HRESULT UnattendedLinuxInstaller::editIsoLinuxCommon(GeneralTextScript *pEditor)
897{
898 try
899 {
900 /* Set timeouts to 10 seconds. */
901 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("timeout", RTCString::CaseInsensitive);
902 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
903 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("timeout", RTCString::CaseInsensitive))
904 {
905 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), "timeout 10");
906 if (FAILED(hrc))
907 return hrc;
908 }
909
910 /* Modify kernel parameters. */
911 vecLineNumbers = pEditor->findTemplate("append", RTCString::CaseInsensitive);
912 if (vecLineNumbers.size() > 0)
913 {
914 Utf8Str const &rStrAppend = mpParent->i_getExtraInstallKernelParameters().isNotEmpty()
915 ? mpParent->i_getExtraInstallKernelParameters()
916 : mStrDefaultExtraInstallKernelParameters;
917
918 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
919 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("append", RTCString::CaseInsensitive))
920 {
921 Utf8Str strLine = pEditor->getContentOfLine(vecLineNumbers[i]);
922
923 /* Do removals. */
924 if (mArrStrRemoveInstallKernelParameters.size() > 0)
925 {
926 size_t offStart = strLine.find("append") + 5;
927 while (offStart < strLine.length() && !RT_C_IS_SPACE(strLine[offStart]))
928 offStart++;
929 while (offStart < strLine.length() && RT_C_IS_SPACE(strLine[offStart]))
930 offStart++;
931 if (offStart < strLine.length())
932 {
933 for (size_t iRemove = 0; iRemove < mArrStrRemoveInstallKernelParameters.size(); iRemove++)
934 {
935 RTCString const &rStrRemove = mArrStrRemoveInstallKernelParameters[iRemove];
936 for (size_t off = offStart; off < strLine.length(); )
937 {
938 Assert(!RT_C_IS_SPACE(strLine[off]));
939
940 /* Find the end of word. */
941 size_t offEnd = off + 1;
942 while (offEnd < strLine.length() && !RT_C_IS_SPACE(strLine[offEnd]))
943 offEnd++;
944
945 /* Check if it matches. */
946 if (RTStrSimplePatternNMatch(rStrRemove.c_str(), rStrRemove.length(),
947 strLine.c_str() + off, offEnd - off))
948 {
949 while (off > 0 && RT_C_IS_SPACE(strLine[off - 1]))
950 off--;
951 strLine.erase(off, offEnd - off);
952 }
953
954 /* Advance to the next word. */
955 off = offEnd;
956 while (off < strLine.length() && RT_C_IS_SPACE(strLine[off]))
957 off++;
958 }
959 }
960 }
961 }
962
963 /* Do the appending. */
964 if (rStrAppend.isNotEmpty())
965 {
966 if (!rStrAppend.startsWith(" ") && !strLine.endsWith(" "))
967 strLine.append(' ');
968 strLine.append(rStrAppend);
969 }
970
971 /* Update line. */
972 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), strLine);
973 if (FAILED(hrc))
974 return hrc;
975 }
976 }
977 }
978 catch (std::bad_alloc &)
979 {
980 return E_OUTOFMEMORY;
981 }
982 return S_OK;
983}
984
985
986//////////////////////////////////////////////////////////////////////////////////////////////////////
987/*
988*
989*
990* Implementation UnattendedDebianInstaller functions
991*
992*/
993//////////////////////////////////////////////////////////////////////////////////////////////////////
994
995/**
996 * Helper for checking if a file exists.
997 * @todo promote to IPRT?
998 */
999static bool hlpVfsFileExists(RTVFS hVfs, const char *pszPath)
1000{
1001 RTFSOBJINFO ObjInfo;
1002 int vrc = RTVfsQueryPathInfo(hVfs, pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
1003 return RT_SUCCESS(vrc) && RTFS_IS_FILE(ObjInfo.Attr.fMode);
1004}
1005
1006HRESULT UnattendedDebianInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
1007 RTVFS hVfsOrgIso, bool fOverwrite)
1008{
1009 /*
1010 * The txt.cfg file used to be called isolinux.txt (ubuntu 4.10
1011 * and possible others).
1012 */
1013 /** @todo Ubuntu 4.10 does not work, as we generate too long command lines
1014 * and the kernel crashes immediately. */
1015 const char *pszIsoLinuxTxtCfg = "/isolinux/txt.cfg";
1016 if ( !hlpVfsFileExists(hVfsOrgIso, pszIsoLinuxTxtCfg)
1017 && hlpVfsFileExists(hVfsOrgIso, "/isolinux/isolinux.txt"))
1018 pszIsoLinuxTxtCfg = "/isolinux/isolinux.txt";
1019
1020 /*
1021 * VISO bits and filenames.
1022 */
1023 RTCString strIsoLinuxCfg;
1024 RTCString strTxtCfg;
1025 try
1026 {
1027 /* Remaster ISO. */
1028 rVecArgs.append() = "--no-file-mode";
1029 rVecArgs.append() = "--no-dir-mode";
1030
1031 rVecArgs.append() = "--import-iso";
1032 rVecArgs.append(mpParent->i_getIsoPath());
1033
1034 rVecArgs.append() = "--file-mode=0444";
1035 rVecArgs.append() = "--dir-mode=0555";
1036
1037 /* Remove the two isolinux configure files we'll be replacing. */
1038 rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
1039 rVecArgs.append().assign(&pszIsoLinuxTxtCfg[1]).append("=:must-remove:");
1040
1041 /* Add the replacement files. */
1042 strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
1043 strIsoLinuxCfg.append("isolinux-isolinux.cfg");
1044 rVecArgs.append().append("isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
1045
1046 strTxtCfg = mpParent->i_getAuxiliaryBasePath();
1047 strTxtCfg.append("isolinux-txt.cfg");
1048 rVecArgs.append().assign(&pszIsoLinuxTxtCfg[1]).append("=").append(strTxtCfg);
1049 }
1050 catch (std::bad_alloc &)
1051 {
1052 return E_OUTOFMEMORY;
1053 }
1054
1055 /*
1056 * Edit the isolinux.cfg file.
1057 */
1058 {
1059 GeneralTextScript Editor(mpParent);
1060 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, "/isolinux/isolinux.cfg", &Editor);
1061 if (SUCCEEDED(hrc))
1062 hrc = editIsoLinuxCfg(&Editor);
1063 if (SUCCEEDED(hrc))
1064 {
1065 hrc = Editor.save(strIsoLinuxCfg, fOverwrite);
1066 if (SUCCEEDED(hrc))
1067 {
1068 try
1069 {
1070 rVecFiles.append(strIsoLinuxCfg);
1071 }
1072 catch (std::bad_alloc &)
1073 {
1074 RTFileDelete(strIsoLinuxCfg.c_str());
1075 hrc = E_OUTOFMEMORY;
1076 }
1077 }
1078 }
1079 if (FAILED(hrc))
1080 return hrc;
1081 }
1082
1083 /*
1084 * Edit the txt.cfg file.
1085 */
1086 {
1087 GeneralTextScript Editor(mpParent);
1088 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, pszIsoLinuxTxtCfg, &Editor);
1089 if (SUCCEEDED(hrc))
1090 hrc = editDebianTxtCfg(&Editor);
1091 if (SUCCEEDED(hrc))
1092 {
1093 hrc = Editor.save(strTxtCfg, fOverwrite);
1094 if (SUCCEEDED(hrc))
1095 {
1096 try
1097 {
1098 rVecFiles.append(strTxtCfg);
1099 }
1100 catch (std::bad_alloc &)
1101 {
1102 RTFileDelete(strTxtCfg.c_str());
1103 hrc = E_OUTOFMEMORY;
1104 }
1105 }
1106 }
1107 if (FAILED(hrc))
1108 return hrc;
1109 }
1110
1111 /*
1112 * Call parent to add the preseed file from mAlg.
1113 */
1114 return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1115}
1116
1117HRESULT UnattendedDebianInstaller::editDebianTxtCfg(GeneralTextScript *pEditor)
1118{
1119 /*
1120 * Unlike Redhats Debian variants define boot menu not in isolinux.cfg but some other
1121 * menu configuration files. They are mostly called txt.cfg and menu.cfg (and possibly some other names)
1122 * In this functions we attempt to set menu's default label to the one containing te word 'install'.
1123 */
1124 try
1125 {
1126 std::vector<size_t> vecLineNumbers = pEditor->findTemplate("label", RTCString::CaseInsensitive);
1127 for (size_t i = 0; i < vecLineNumbers.size(); ++i)
1128 {
1129 RTCString const &rContent = pEditor->getContentOfLine(vecLineNumbers[i]);
1130
1131 // ASSUME: suppose general string looks like "label install", two words separated by " ".
1132 RTCList<RTCString> vecPartsOfcontent = rContent.split(" ");
1133 if (vecPartsOfcontent.size() > 1 && vecPartsOfcontent[1].contains("install")) /** @todo r=bird: case insensitive? */
1134 {
1135 std::vector<size_t> vecDefaultLineNumbers = pEditor->findTemplate("default", RTCString::CaseInsensitive);
1136 for (size_t j = 0; j < vecDefaultLineNumbers.size(); ++j)
1137 {
1138 Utf8Str strNewContent("default ");
1139 strNewContent.append(vecPartsOfcontent[1]);
1140 HRESULT hrc = pEditor->setContentOfLine(vecDefaultLineNumbers[j], strNewContent);
1141 if (FAILED(hrc))
1142 return hrc;
1143 }
1144 }
1145 }
1146 }
1147 catch (std::bad_alloc &)
1148 {
1149 return E_OUTOFMEMORY;
1150 }
1151 return UnattendedLinuxInstaller::editIsoLinuxCommon(pEditor);
1152}
1153
1154
1155//////////////////////////////////////////////////////////////////////////////////////////////////////
1156/*
1157*
1158*
1159* Implementation UnattendedRhel6Installer functions
1160*
1161*/
1162//////////////////////////////////////////////////////////////////////////////////////////////////////
1163HRESULT UnattendedRhel6Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
1164 RTVFS hVfsOrgIso, bool fOverwrite)
1165{
1166 Utf8Str strIsoLinuxCfg;
1167 try
1168 {
1169#if 1
1170 /* Remaster ISO. */
1171 rVecArgs.append() = "--no-file-mode";
1172 rVecArgs.append() = "--no-dir-mode";
1173
1174 rVecArgs.append() = "--import-iso";
1175 rVecArgs.append(mpParent->i_getIsoPath());
1176
1177 rVecArgs.append() = "--file-mode=0444";
1178 rVecArgs.append() = "--dir-mode=0555";
1179
1180 /* We replace isolinux.cfg with our edited version (see further down). */
1181 rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
1182 strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
1183 strIsoLinuxCfg.append("isolinux-isolinux.cfg");
1184 rVecArgs.append().append("isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
1185
1186#else
1187 /** @todo Maybe we should just remaster the ISO for redhat derivatives too?
1188 * One less CDROM to mount. */
1189 /* Name the ISO. */
1190 rVecArgs.append() = "--volume-id=VBox Unattended Boot";
1191
1192 /* Copy the isolinux directory from the original install ISO. */
1193 rVecArgs.append().append("--push-iso=").append(mpParent->i_getIsoPath());
1194 rVecArgs.append() = "/isolinux=/isolinux";
1195 rVecArgs.append() = "--pop";
1196
1197 /* We replace isolinux.cfg with our edited version (see further down). */
1198 rVecArgs.append() = "/isolinux/isolinux.cfg=:must-remove:";
1199
1200 strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
1201 strIsoLinuxCfg.append("isolinux-isolinux.cfg");
1202 rVecArgs.append().append("/isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
1203
1204 /* Configure booting /isolinux/isolinux.bin. */
1205 rVecArgs.append() = "--eltorito-boot";
1206 rVecArgs.append() = "/isolinux/isolinux.bin";
1207 rVecArgs.append() = "--no-emulation-boot";
1208 rVecArgs.append() = "--boot-info-table";
1209 rVecArgs.append() = "--boot-load-seg=0x07c0";
1210 rVecArgs.append() = "--boot-load-size=4";
1211
1212 /* Make the boot catalog visible in the file system. */
1213 rVecArgs.append() = "--boot-catalog=/isolinux/vboxboot.cat";
1214#endif
1215 }
1216 catch (std::bad_alloc &)
1217 {
1218 return E_OUTOFMEMORY;
1219 }
1220
1221 /*
1222 * Edit isolinux.cfg and save it.
1223 */
1224 {
1225 GeneralTextScript Editor(mpParent);
1226 HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, "/isolinux/isolinux.cfg", &Editor);
1227 if (SUCCEEDED(hrc))
1228 hrc = editIsoLinuxCfg(&Editor);
1229 if (SUCCEEDED(hrc))
1230 {
1231 hrc = Editor.save(strIsoLinuxCfg, fOverwrite);
1232 if (SUCCEEDED(hrc))
1233 {
1234 try
1235 {
1236 rVecFiles.append(strIsoLinuxCfg);
1237 }
1238 catch (std::bad_alloc &)
1239 {
1240 RTFileDelete(strIsoLinuxCfg.c_str());
1241 hrc = E_OUTOFMEMORY;
1242 }
1243 }
1244 }
1245 if (FAILED(hrc))
1246 return hrc;
1247 }
1248
1249 /*
1250 * Call parent to add the ks.cfg file from mAlg.
1251 */
1252 return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
1253}
1254
1255
1256//////////////////////////////////////////////////////////////////////////////////////////////////////
1257/*
1258*
1259*
1260* Implementation UnattendedSuseInstaller functions
1261*
1262*/
1263//////////////////////////////////////////////////////////////////////////////////////////////////////
1264#if 0 /* doesn't work, so convert later */
1265/*
1266 *
1267 * UnattendedSuseInstaller protected methods
1268 *
1269*/
1270HRESULT UnattendedSuseInstaller::setUserData()
1271{
1272 HRESULT rc = S_OK;
1273 //here base class function must be called first
1274 //because user home directory is set after user name
1275 rc = UnattendedInstaller::setUserData();
1276
1277 rc = mAlg->setField(USERHOMEDIR_ID, "");
1278 if (FAILED(rc))
1279 return rc;
1280
1281 return rc;
1282}
1283
1284/*
1285 *
1286 * UnattendedSuseInstaller private methods
1287 *
1288*/
1289
1290HRESULT UnattendedSuseInstaller::iv_initialPhase()
1291{
1292 Assert(isAuxiliaryIsoNeeded());
1293 if (mParent->i_isGuestOs64Bit())
1294 mFilesAndDirsToExtractFromIso.append("boot/x86_64/loader/ ");
1295 else
1296 mFilesAndDirsToExtractFromIso.append("boot/i386/loader/ ");
1297 return extractOriginalIso(mFilesAndDirsToExtractFromIso);
1298}
1299
1300
1301HRESULT UnattendedSuseInstaller::setupScriptOnAuxiliaryCD(const Utf8Str &path)
1302{
1303 HRESULT rc = S_OK;
1304
1305 GeneralTextScript isoSuseCfgScript(mpParent);
1306 rc = isoSuseCfgScript.read(path);
1307 rc = isoSuseCfgScript.parse();
1308 //fix linux core bootable parameters: add path to the preseed script
1309
1310 std::vector<size_t> listOfLines = isoSuseCfgScript.findTemplate("append");
1311 for(unsigned int i=0; i<listOfLines.size(); ++i)
1312 {
1313 isoSuseCfgScript.appendToLine(listOfLines.at(i),
1314 " auto=true priority=critical autoyast=default instmode=cd quiet splash noprompt noshell --");
1315 }
1316
1317 //find all lines with "label" inside
1318 listOfLines = isoSuseCfgScript.findTemplate("label");
1319 for(unsigned int i=0; i<listOfLines.size(); ++i)
1320 {
1321 Utf8Str content = isoSuseCfgScript.getContentOfLine(listOfLines.at(i));
1322
1323 //suppose general string looks like "label linux", two words separated by " ".
1324 RTCList<RTCString> partsOfcontent = content.split(" ");
1325
1326 if (partsOfcontent.at(1).contains("linux"))
1327 {
1328 std::vector<size_t> listOfDefault = isoSuseCfgScript.findTemplate("default");
1329 //handle the lines more intelligently
1330 for(unsigned int j=0; j<listOfDefault.size(); ++j)
1331 {
1332 Utf8Str newContent("default ");
1333 newContent.append(partsOfcontent.at(1));
1334 isoSuseCfgScript.setContentOfLine(listOfDefault.at(j), newContent);
1335 }
1336 }
1337 }
1338
1339 rc = isoSuseCfgScript.save(path, true);
1340
1341 LogRelFunc(("UnattendedSuseInstaller::setupScriptsOnAuxiliaryCD(): The file %s has been changed\n", path.c_str()));
1342
1343 return rc;
1344}
1345#endif
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