VirtualBox

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

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

Main: Split out the unattended OS/2 bits. Added OS2LDR patching and more.

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