VirtualBox

Changeset 93094 in vbox for trunk/src/VBox/Main/src-server


Ignore:
Timestamp:
Dec 29, 2021 3:06:13 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
149108
Message:

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

Location:
trunk/src/VBox/Main/src-server
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/UnattendedInstaller.cpp

    r93089 r93094  
    4444#endif
    4545#include <iprt/formats/iso9660.h>
    46 #include <iprt/formats/fat.h>
    4746#include <iprt/cpp/path.h>
    4847
     
    851850        hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open '%s' on the ISO '%s' (%Rrc)"),
    852851                                     pszFilename, mpParent->i_getIsoPath().c_str(), vrc);
    853     return hrc;
    854 }
    855 
    856 
    857 
    858 /*********************************************************************************************************************************
    859 *   Implementation of UnattendedOs2Installer                                                                                     *
    860 *********************************************************************************************************************************/
    861 
    862 UnattendedOs2Installer::UnattendedOs2Installer(Unattended *pParent, Utf8Str const &rStrHints)
    863     : UnattendedInstaller(pParent,
    864                           "os2_response_files.rsp", "os2_postinstall.cmd",
    865                           "OS2.RSP",                "VBOXPOST.CMD",
    866                           DeviceType_Floppy)
    867 {
    868     Assert(!isOriginalIsoNeeded());
    869     Assert(isAuxiliaryFloppyNeeded());
    870     Assert(isAuxiliaryIsoIsVISO());
    871     Assert(bootFromAuxiliaryIso());
    872     mStrAuxiliaryInstallDir = "S:\\";
    873 
    874     /* Extract the info from the hints variable: */
    875     RTCList<RTCString, RTCString *> Pairs = rStrHints.split(" ");
    876     size_t i = Pairs.size();
    877     Assert(i > 0);
    878     while (i -- > 0)
    879     {
    880         RTCString const rStr = Pairs[i];
    881         if (rStr.startsWith("OS2SE20.SRC="))
    882             mStrOs2Images = rStr.substr(sizeof("OS2SE20.SRC=") - 1);
    883         else
    884             AssertMsgFailed(("Unknown hint: %s\n", rStr.c_str()));
    885     }
    886 }
    887 
    888 
    889 HRESULT UnattendedOs2Installer::replaceAuxFloppyImageBootSector(RTVFSFILE hVfsFile) RT_NOEXCEPT
    890 {
    891     /*
    892      * Find the bootsector.  Because the ArcaOS ISOs doesn't contain any floppy
    893      * images, we cannot just lift it off one of those.  Instead we'll locate it
    894      * in the SYSINSTX.COM utility, i.e. the tool which installs it onto floppies
    895      * and harddisks.  The SYSINSTX.COM utility is a NE executable and we don't
    896      * have issues with compressed pages like with LX images.
    897      *
    898      * The utility seems always to be located on disk 0.
    899      */
    900     RTVFS   hVfsOrgIso;
    901     HRESULT hrc = openInstallIsoImage(&hVfsOrgIso);
    902     if (SUCCEEDED(hrc))
    903     {
    904         char szPath[256];
    905         int vrc = RTPathJoin(szPath, sizeof(szPath), mStrOs2Images.c_str(), "DISK_0/SYSINSTX.COM");
    906         if (RT_SUCCESS(vrc))
    907         {
    908             RTVFSFILE hVfsSysInstX;
    909             vrc = RTVfsFileOpen(hVfsOrgIso, szPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsSysInstX);
    910             if (RT_SUCCESS(vrc))
    911             {
    912                 /*
    913                  * Scan the image looking for a 512 block ending with a DOS signature
    914                  * and starting with a three byte jump followed by an OEM name string.
    915                  */
    916                 uint8_t *pbBootSector = NULL;
    917                 RTFOFF   off          = 0;
    918                 bool     fEof         = false;
    919                 uint8_t  abBuf[_8K]   = {0};
    920                 do
    921                 {
    922                     /* Read the next chunk. */
    923                     memmove(abBuf, &abBuf[sizeof(abBuf) - 512], 512); /* Move up the last 512 (all zero the first time around). */
    924                     size_t cbRead = 0;
    925                     vrc = RTVfsFileReadAt(hVfsSysInstX, off, &abBuf[512], sizeof(abBuf) - 512, &cbRead);
    926                     if (RT_FAILURE(vrc))
    927                         break;
    928                     fEof = cbRead != sizeof(abBuf) - 512;
    929                     off += cbRead;
    930 
    931                     /* Scan it. */
    932                     size_t   cbLeft = sizeof(abBuf);
    933                     uint8_t *pbCur  = abBuf;
    934                     while (cbLeft >= 512)
    935                     {
    936                         /* Look for the DOS signature (0x55 0xaa) at the end of the sector: */
    937                         uint8_t *pbHit = (uint8_t *)memchr(pbCur + 510, 0x55, cbLeft - 510 - 1);
    938                         if (!pbHit)
    939                             break;
    940                         if (pbHit[1] == 0xaa)
    941                         {
    942                             uint8_t *pbStart = pbHit - 510;
    943                             if (   pbStart[0] == 0xeb        /* JMP imm8 */
    944                                 && pbStart[1] >= 3 + 8 + sizeof(FATEBPB) - 2 /* must jump after the FATEBPB */
    945                                 && RT_C_IS_ALNUM(pbStart[3]) /* ASSUME OEM string starts with two letters (typically 'IBM x.y')*/
    946                                 && RT_C_IS_ALNUM(pbStart[4]))
    947                             {
    948                                 FATEBPB *pBpb = (FATEBPB *)&pbStart[3 + 8];
    949                                 if (   pBpb->bExtSignature == FATEBPB_SIGNATURE
    950                                     && (   memcmp(pBpb->achType, "FAT     ", sizeof(pBpb->achType)) == 0
    951                                         || memcmp(pBpb->achType, FATEBPB_TYPE_FAT12, sizeof(pBpb->achType)) == 0))
    952                                 {
    953                                     pbBootSector = pbStart;
    954                                     break;
    955                                 }
    956                             }
    957                         }
    958 
    959                         /* skip */
    960                         pbCur  = pbHit - 510 + 1;
    961                         cbLeft = (uintptr_t)&abBuf[sizeof(abBuf)] - (uintptr_t)pbCur;
    962                     }
    963                 } while (!fEof);
    964 
    965                 if (pbBootSector)
    966                 {
    967                     if (pbBootSector != abBuf)
    968                         pbBootSector = (uint8_t *)memmove(abBuf, pbBootSector, 512);
    969 
    970                     /*
    971                      * We've now got a bootsector.  So, we need to copy the EBPB
    972                      * from the destination image before replacing it.
    973                      */
    974                     vrc = RTVfsFileReadAt(hVfsFile, 0, &abBuf[512], 512, NULL);
    975                     if (RT_SUCCESS(vrc))
    976                     {
    977                         memcpy(&pbBootSector[3 + 8], &abBuf[512 + 3 + 8], sizeof(FATEBPB));
    978 
    979                         /*
    980                          * Write it.
    981                          */
    982                         vrc = RTVfsFileWriteAt(hVfsFile, 0, pbBootSector, 512, NULL);
    983                         if (RT_SUCCESS(vrc))
    984                         {
    985                             LogFlowFunc(("Successfully installed new bootsector\n"));
    986                             hrc = S_OK;
    987                         }
    988                         else
    989                             hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to write bootsector: %Rrc"), vrc);
    990                     }
    991                     else
    992                         hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to read bootsector: %Rrc"), vrc);
    993                 }
    994                 else if (RT_FAILURE(vrc))
    995                     hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error reading SYSINSTX.COM: %Rrc"), vrc);
    996                 else
    997                     hrc = mpParent->setErrorBoth(E_FAIL, VERR_NOT_FOUND,
    998                                                  tr("Unable to locate bootsector template in SYSINSTX.COM"));
    999                 RTVfsFileRelease(hVfsSysInstX);
    1000             }
    1001             else
    1002                 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open SYSINSTX.COM: %Rrc"), vrc);
    1003         }
    1004         else
    1005             hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to construct SYSINSTX.COM path"));
    1006         RTVfsRelease(hVfsOrgIso);
    1007     }
    1008     return hrc;
    1009 
    1010 }
    1011 
    1012 HRESULT UnattendedOs2Installer::newAuxFloppyImage(const char *pszFilename, bool fOverwrite, PRTVFSFILE phVfsFile)
    1013 {
    1014     /*
    1015      * Open the image file.
    1016      */
    1017     HRESULT     hrc;
    1018     RTVFSFILE   hVfsFile;
    1019     uint64_t    fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT);
    1020     if (fOverwrite)
    1021         fOpen |= RTFILE_O_CREATE_REPLACE;
    1022     else
    1023         fOpen |= RTFILE_O_OPEN;
    1024     int vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
    1025     if (RT_SUCCESS(vrc))
    1026     {
    1027         /*
    1028          * Format it.
    1029          */
    1030         vrc = RTFsFatVolFormat288(hVfsFile, false /*fQuick*/);
    1031         if (RT_SUCCESS(vrc))
    1032         {
    1033             /*
    1034              * Now we install the OS/2 boot sector on it.
    1035              */
    1036             hrc = replaceAuxFloppyImageBootSector(hVfsFile);
    1037             if (SUCCEEDED(hrc))
    1038             {
    1039                 *phVfsFile = hVfsFile;
    1040                 LogRelFlow(("UnattendedInstaller::newAuxFloppyImage: created and formatted  '%s'\n", pszFilename));
    1041                 return S_OK;
    1042             }
    1043         }
    1044         else
    1045             hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to format floppy image '%s': %Rrc"), pszFilename, vrc);
    1046         RTVfsFileRelease(hVfsFile);
    1047         RTFileDelete(pszFilename);
    1048     }
    1049     else
    1050         hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to create floppy image '%s': %Rrc"), pszFilename, vrc);
    1051     return hrc;
    1052 }
    1053 
    1054 
    1055 HRESULT UnattendedOs2Installer::splitResponseFile() RT_NOEXCEPT
    1056 {
    1057     if (mVecSplitFiles.size() == 0)
    1058     {
    1059 #if 0
    1060         Utf8Str strResponseFile;
    1061         int vrc = strResponseFile.assignNoThrow(mpParent->i_getAuxiliaryBasePath());
    1062         if (RT_SUCCESS(vrc))
    1063             vrc = strResponseFile.appendNoThrow(mMainScript.getDefaultFilename());
    1064         if (RT_SUCCESS(vrc))
    1065             return splitFile(strResponseFile.c_str(), mVecSplitFiles);
    1066         return mpParent->setErrorVrc(vrc);
    1067 #else
    1068         return splitFile(&mMainScript, mVecSplitFiles);
    1069 #endif
    1070     }
    1071     return S_OK;
    1072 }
    1073 
    1074 HRESULT UnattendedOs2Installer::copyFilesToAuxFloppyImage(RTVFS hVfs)
    1075 {
    1076     /*
    1077      * Make sure we've split the files already.
    1078      */
    1079     HRESULT hrc = splitResponseFile();
    1080     if (FAILED(hrc))
    1081         return hrc;
    1082 
    1083     /*
    1084      * We need to copy over the files needed to boot OS/2.
    1085      */
    1086     static struct
    1087     {
    1088         bool        fMandatory;
    1089         const char *apszNames[2];
    1090         const char *apszDisks[3];
    1091         const char *pszMinVer;
    1092         const char *pszMaxVer;
    1093     } const s_aFiles[] =
    1094     {
    1095         { true, { "OS2BOOT",      NULL          }, { "DISK_0", NULL,     NULL }, "2.1",  NULL }, /* 2.0 did not have OS2BOOT */
    1096         { true, { "OS2LDR",       NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1097         { true, { "OS2LDR.MSG",   NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1098         { true, { "OS2KRNL",      "OS2KRNLI"    }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1099         { true, { "OS2DUMP",      NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1100         //
    1101         { true, { "ANSICALL.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1102         { true, { "BKSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1103         { true, { "BMSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1104         { true, { "BVHINIT.DLL",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1105         { true, { "BVSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1106         { true, { "CDFS.IFS",     NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1107         { true, { "CLOCK01.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1108         { true, { "COUNT437.SYS", "COUNTRY.SYS" }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1109         { true, { "DOS.SYS",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1110         { true, { "DOSCALL1.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1111         { true, { "IBM1FLPY.ADD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1112         { true, { "IBM1S506.ADD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1113         { true, { "IBMIDECD.FLT", NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL }, /* not in 2.1 & Warp3  */
    1114         { true, { "IBMKBD.SYS", "KBD01.SYS"/*?*/}, { "DISK_1", "DISK_2", NULL }, NULL,   NULL},
    1115         { true, { "ISAPNP.SNP",   NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL }, /* not in 2.1 */
    1116         { true, { "KBDBASE.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, "3.0",  NULL }, /* not in 2.1 */
    1117         { true, { "KBDCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1118         { true, { "KEYBOARD.DCP", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1119         { true, { "MOUCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1120         { true, { "MSG.DLL",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1121         { true, { "NAMPIPES.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1122         { true, { "NLS.DLL",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1123         { true, { "OS2CDROM.DMD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1124         { true, { "OS2CHAR.DLL",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1125         { true, { "OS2DASD.DMD",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1126         { true, { "OS2LVM.DMD",   NULL          }, { "DISK_1", "DISK_2", NULL }, "4.5",  NULL },
    1127         { true, { "OS2VER",       NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1128         { true, { "PNP.SYS",      NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL },
    1129         { true, { "QUECALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1130         { true, { "RESOURCE.SYS", NULL          }, { "DISK_1", "DISK_2", NULL }, "3.0",  NULL }, /* not in 2.1*/
    1131         { true, { "SCREEN01.SYS", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1132         { true, { "SESMGR.DLL",   NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1133         { true, { "TESTCFG.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1134         { true, { "VIO437.DCP",   "VTBL850.DCP" }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1135         { true, { "VIOCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1136     };
    1137 
    1138 
    1139     RTVFS hVfsOrgIso;
    1140     hrc = openInstallIsoImage(&hVfsOrgIso);
    1141     if (SUCCEEDED(hrc))
    1142     {
    1143         for (size_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
    1144         {
    1145             bool fCopied = false;
    1146             for (size_t iDisk = 0; iDisk < RT_ELEMENTS(s_aFiles[i].apszDisks) && s_aFiles[i].apszDisks[iDisk] && !fCopied; iDisk++)
    1147             {
    1148                 for (size_t iName = 0; iName < RT_ELEMENTS(s_aFiles[i].apszNames) && s_aFiles[i].apszNames[iName]; iName++)
    1149                 {
    1150                     char szPath[256];
    1151                     int vrc = RTPathJoin(szPath, sizeof(szPath), mStrOs2Images.c_str(), s_aFiles[i].apszDisks[iDisk]);
    1152                     if (RT_SUCCESS(vrc))
    1153                         vrc = RTPathAppend(szPath, sizeof(szPath), s_aFiles[i].apszNames[iName]);
    1154                     AssertRCBreakStmt(vrc, hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("RTPathJoin/Append failed for %s: %Rrc"),
    1155                                                                         s_aFiles[i].apszNames[iName], vrc));
    1156                     RTVFSFILE hVfsSrc;
    1157                     vrc = RTVfsFileOpen(hVfsOrgIso, szPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsSrc);
    1158                     if (RT_SUCCESS(vrc))
    1159                     {
    1160                         RTVFSFILE hVfsDst;
    1161                         vrc = RTVfsFileOpen(hVfs, s_aFiles[i].apszNames[0],
    1162                                             RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
    1163                                             | (0755 << RTFILE_O_CREATE_MODE_SHIFT), &hVfsDst);
    1164                         if (RT_SUCCESS(vrc))
    1165                         {
    1166                             RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(hVfsSrc);
    1167                             RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsDst);
    1168                             vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0);
    1169                             RTVfsIoStrmRelease(hVfsIosDst);
    1170                             RTVfsFileRelease(hVfsDst);
    1171                             RTVfsIoStrmRelease(hVfsIosSrc);
    1172                             if (RT_FAILURE(vrc))
    1173                                 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to write %s to the floppy: %Rrc"),
    1174                                                              s_aFiles[i].apszNames, vrc);
    1175                         }
    1176                         else
    1177                             hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open %s on floppy: %Rrc"),
    1178                                                          s_aFiles[i].apszNames, vrc);
    1179 
    1180                         RTVfsFileRelease(hVfsSrc);
    1181                         fCopied = true;
    1182                         break;
    1183                     }
    1184                 }
    1185             }
    1186             if (FAILED(hrc))
    1187                 break;
    1188             if (!fCopied)
    1189             {
    1190                 /** @todo do version filtering.   */
    1191                 hrc = mpParent->setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND,
    1192                                              tr("Failed to locate '%s' needed for the install floppy"), s_aFiles[i].apszNames[0]);
    1193                 break;
    1194             }
    1195         }
    1196         RTVfsRelease(hVfsOrgIso);
    1197     }
    1198 
    1199     /*
    1200      * In addition, we need to add a CONFIG.SYS and the startup script.
    1201      */
    1202     if (SUCCEEDED(hrc))
    1203     {
    1204         Utf8Str strSrc;
    1205         try
    1206         {
    1207             strSrc = mpParent->i_getAuxiliaryBasePath();
    1208             strSrc.append("CONFIG.SYS");
    1209         }
    1210         catch (std::bad_alloc &)
    1211         {
    1212             return E_OUTOFMEMORY;
    1213         }
    1214         hrc = addFileToFloppyImage(hVfs, strSrc.c_str(), "CONFIG.SYS");
    1215     }
    1216 
    1217     /*
    1218      * We also want a ALTF2ON.$$$ file so we can see which drivers are loaded
    1219      * and where it might get stuck.
    1220      */
    1221     if (SUCCEEDED(hrc))
    1222     {
    1223         RTVFSFILE hVfsFile;
    1224         int vrc = RTVfsFileOpen(hVfs, "ALTF2ON.$$$",
    1225                                 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
    1226                                 | (0755 << RTFILE_O_CREATE_MODE_SHIFT), &hVfsFile);
    1227         if (RT_SUCCESS(vrc))
    1228         {
    1229             /** @todo buggy fat vfs: cannot write empty files */
    1230             RTVfsFileWrite(hVfsFile, RT_STR_TUPLE("\r\n"), NULL);
    1231             RTVfsFileRelease(hVfsFile);
    1232         }
    1233         else
    1234             hrc = mpParent->setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Failed to create 'ALTF2ON.$$$' on the install floppy"));
    1235     }
    1236 
    1237     return hrc;
    1238 }
    1239 
    1240 HRESULT UnattendedOs2Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
    1241                                                          RTVFS hVfsOrgIso, bool fOverwrite)
    1242 {
    1243     /*
    1244      * Make sure we've split the files already.
    1245      */
    1246     HRESULT hrc = splitResponseFile();
    1247     if (FAILED(hrc))
    1248         return hrc;
    1249 
    1250     /*
    1251      * Add our stuff to the vectors.
    1252      */
    1253     try
    1254     {
    1255         /* Remaster ISO. */
    1256         rVecArgs.append() = "--no-file-mode";
    1257         rVecArgs.append() = "--no-dir-mode";
    1258 
    1259         rVecArgs.append() = "--import-iso";
    1260         rVecArgs.append(mpParent->i_getIsoPath());
    1261 
    1262         rVecArgs.append() = "--file-mode=0444";
    1263         rVecArgs.append() = "--dir-mode=0555";
    1264 
    1265         /* Add the boot floppy to the ISO: */
    1266         rVecArgs.append() = "--eltorito-new-entry";
    1267         rVecArgs.append() = "--eltorito-add-image";
    1268         rVecArgs.append(mStrAuxiliaryFloppyFilePath);
    1269         rVecArgs.append() = "--eltorito-floppy-288";
    1270 
    1271 
    1272         /* Add the response files and postinstall files to the ISO: */
    1273         Utf8Str const &rStrAuxPrefix = mpParent->i_getAuxiliaryBasePath();
    1274         size_t i = mVecSplitFiles.size();
    1275         while (i-- > 0)
    1276         {
    1277             RTCString const &rStrFile = mVecSplitFiles[i];
    1278             rVecArgs.append().assign("VBoxCID/").append(rStrFile).append('=').append(rStrAuxPrefix).append(rStrFile);
    1279         }
    1280     }
    1281     catch (std::bad_alloc &)
    1282     {
    1283         return E_OUTOFMEMORY;
    1284     }
    1285 
    1286     /*
    1287      * Call parent.
    1288      */
    1289     return UnattendedInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
    1290 }
    1291 
    1292 /**
    1293  * Helper for splitFile.
    1294  */
    1295 const char *splitFileLocateSubstring(const char *pszSrc, size_t cchSrc, const char *pszSubstring, size_t cchSubstring)
    1296 {
    1297     char const ch0 = *pszSubstring;
    1298     while (cchSrc >= cchSubstring)
    1299     {
    1300         const char *pszHit0 = (const char *)memchr(pszSrc, ch0, cchSrc - cchSubstring + 1);
    1301         if (pszHit0)
    1302         {
    1303             if (memcmp(pszHit0, pszSubstring, cchSubstring) == 0)
    1304                 return pszHit0;
    1305         }
    1306         else
    1307             break;
    1308         cchSrc -= (size_t)(pszHit0 - pszSrc) + 1;
    1309         pszSrc  = pszHit0 + 1;
    1310     }
    1311     return NULL;
    1312 }
    1313 
    1314 /**
    1315  * Worker for splitFile().
    1316  */
    1317 HRESULT UnattendedOs2Installer::splitFileInner(const char *pszFileToSplit, RTCList<RTCString> &rVecSplitFiles,
    1318                                                const char *pszSrc, size_t cbLeft) RT_NOEXCEPT
    1319 {
    1320     static const char  s_szPrefix[] = "@@VBOX_SPLITTER_";
    1321     const char * const pszStart     = pszSrc;
    1322     const char * const pszEnd       = &pszSrc[cbLeft];
    1323     while (cbLeft > 0)
    1324     {
    1325         /*
    1326          * Locate the next split start marker (everything before it is ignored).
    1327          */
    1328         const char *pszMarker = splitFileLocateSubstring(pszSrc, cbLeft, s_szPrefix, sizeof(s_szPrefix) - 1);
    1329         if (pszMarker)
    1330             pszMarker += sizeof(s_szPrefix) - 1;
    1331         else
    1332             break;
    1333         if (strncmp(pszMarker, RT_STR_TUPLE("START[")) != 0)
    1334             return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
    1335                                           tr("Unexpected splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_%.64s"),
    1336                                           pszFileToSplit, pszMarker - pszStart, pszMarker);
    1337         pszMarker += sizeof("START[") - 1;
    1338         const char *pszTail = splitFileLocateSubstring(pszMarker, (size_t)(pszEnd - pszMarker), RT_STR_TUPLE("]@@"));
    1339         if (   !pszTail
    1340             || pszTail - pszMarker > 64
    1341             || memchr(pszMarker, '\\', pszTail - pszMarker)
    1342             || memchr(pszMarker, '/', pszTail - pszMarker)
    1343             || memchr(pszMarker, ':', pszTail - pszMarker)
    1344            )
    1345             return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
    1346                                           tr("Malformed splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_START[%.64s"),
    1347                                           pszFileToSplit, (size_t)(pszEnd - pszMarker), pszMarker);
    1348         int vrc = RTStrValidateEncodingEx(pszMarker, pszTail - pszMarker, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
    1349         if (RT_FAILURE(vrc))
    1350             return mpParent->setErrorBoth(E_FAIL, vrc,
    1351                                           tr("Malformed splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_START[%.*Rhxs"),
    1352                                           pszFileToSplit, (size_t)(pszEnd - pszMarker), pszTail - pszMarker, pszMarker);
    1353         const char *pszFilename;
    1354         try
    1355         {
    1356             pszFilename = rVecSplitFiles.append().assign(pszMarker, pszTail - pszMarker).c_str();
    1357         }
    1358         catch (std::bad_alloc &)
    1359         {
    1360             return E_OUTOFMEMORY;
    1361         }
    1362         const char *pszDocStart = pszTail + sizeof("]@@") - 1;
    1363         while (RT_C_IS_SPACE(*pszDocStart))
    1364             if (*pszDocStart++ == '\n')
    1365                 break;
    1366 
    1367         /* Advance. */
    1368         pszSrc = pszDocStart;
    1369         cbLeft = pszEnd - pszDocStart;
    1370 
    1371         /*
    1372          * Locate the matching end marker (there cannot be any other markers inbetween).
    1373          */
    1374         const char * const pszDocEnd = pszMarker = splitFileLocateSubstring(pszSrc, cbLeft, s_szPrefix, sizeof(s_szPrefix) - 1);
    1375         if (pszMarker)
    1376             pszMarker += sizeof(s_szPrefix) - 1;
    1377         else
    1378             return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
    1379                                           tr("No END splitter tag for '%s' in '%s'"), pszFilename, pszFileToSplit);
    1380         if (strncmp(pszMarker, RT_STR_TUPLE("END[")) != 0)
    1381             return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
    1382                                           tr("Unexpected splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_%.64s"),
    1383                                           pszFileToSplit, (size_t)(pszEnd - pszMarker), pszMarker);
    1384         pszMarker += sizeof("END[") - 1;
    1385         size_t const cchFilename = strlen(pszFilename);
    1386         if (   strncmp(pszMarker, pszFilename, cchFilename) != 0
    1387             || pszMarker[cchFilename] != ']'
    1388             || pszMarker[cchFilename + 1] != '@'
    1389             || pszMarker[cchFilename + 2] != '@')
    1390             return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
    1391                                           tr("Mismatching splitter tag for '%s' in '%s' at offset %p: @@VBOX_SPLITTER_END[%.64Rhxs"),
    1392                                           pszFilename, pszFileToSplit, (size_t)(pszEnd - pszMarker), pszMarker);
    1393 
    1394         /* Advance. */
    1395         pszSrc = pszMarker + cchFilename + sizeof("]@@") - 1;
    1396         cbLeft = (size_t)(pszEnd - pszSrc);
    1397 
    1398         /*
    1399          * Write out the file.
    1400          */
    1401         Utf8Str strDstFilename;
    1402         vrc = strDstFilename.assignNoThrow(mpParent->i_getAuxiliaryBasePath());
    1403         if (RT_SUCCESS(vrc))
    1404             vrc = strDstFilename.appendNoThrow(pszFilename);
    1405         if (RT_SUCCESS(vrc))
    1406         {
    1407             RTFILE hFile;
    1408             vrc = RTFileOpen(&hFile, strDstFilename.c_str(), RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
    1409             if (RT_SUCCESS(vrc))
    1410             {
    1411                 vrc = RTFileWrite(hFile, pszDocStart, (size_t)(pszDocEnd - pszDocStart), NULL);
    1412                 if (RT_SUCCESS(vrc))
    1413                     vrc = RTFileClose(hFile);
    1414                 else
    1415                     RTFileClose(hFile);
    1416                 if (RT_FAILURE(vrc))
    1417                     return mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing '%s' (split out from '%s'): %Rrc"),
    1418                                                   strDstFilename.c_str(), pszFileToSplit, vrc);
    1419             }
    1420             else
    1421                 return mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
    1422                                               tr("File splitter failed to open output file '%s' in '%s': %Rrc (%s)"),
    1423                                               pszFilename, pszFileToSplit, vrc, strDstFilename.c_str());
    1424         }
    1425         else
    1426             return mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
    1427                                           tr("File splitter failed to construct path for '%s' in '%s': %Rrc"),
    1428                                           pszFilename, pszFileToSplit, vrc);
    1429     }
    1430 
    1431     return S_OK;
    1432 }
    1433 
    1434 HRESULT UnattendedOs2Installer::splitFile(const char *pszFileToSplit, RTCList<RTCString> &rVecSplitFiles) RT_NOEXCEPT
    1435 {
    1436     /*
    1437      * Read the whole source file into memory, making sure it's zero terminated.
    1438      */
    1439     HRESULT hrc;
    1440     void   *pvSrc;
    1441     size_t  cbSrc;
    1442     int vrc = RTFileReadAllEx(pszFileToSplit, 0 /*off*/, _16M /*cbMax*/,
    1443                               RTFILE_RDALL_F_TRAILING_ZERO_BYTE | RTFILE_RDALL_F_FAIL_ON_MAX_SIZE | RTFILE_RDALL_O_DENY_WRITE,
    1444                               &pvSrc, &cbSrc);
    1445     if (RT_SUCCESS(vrc))
    1446     {
    1447         /*
    1448          * Do the actual splitting in a worker function to avoid needing to
    1449          * thing about calling RTFileReadAllFree in error paths.
    1450          */
    1451         hrc = splitFileInner(pszFileToSplit, rVecSplitFiles, (const char *)pvSrc, cbSrc);
    1452         RTFileReadAllFree(pvSrc, cbSrc);
    1453     }
    1454     else
    1455         hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to read '%s' for splitting up: %Rrc"),
    1456                                      pszFileToSplit, vrc);
    1457     return hrc;
    1458 }
    1459 
    1460 HRESULT UnattendedOs2Installer::splitFile(BaseTextScript *pEditor, RTCList<RTCString> &rVecSplitFiles) RT_NOEXCEPT
    1461 {
    1462     /*
    1463      * Get the output from the editor.
    1464      */
    1465     Utf8Str strSrc;
    1466     HRESULT hrc = pEditor->saveToString(strSrc);
    1467     if (SUCCEEDED(hrc))
    1468     {
    1469         /*
    1470          * Do the actual splitting.
    1471          */
    1472         hrc = splitFileInner(pEditor->getDefaultFilename(), rVecSplitFiles, strSrc.c_str(), strSrc.length());
    1473     }
    1474852    return hrc;
    1475853}
  • trunk/src/VBox/Main/src-server/UnattendedOs2Installer.cpp

    r93089 r93094  
    11/* $Id$ */
    22/** @file
    3  * UnattendedInstaller class and it's descendants implementation
     3 * UnattendedOs2Installer implementation.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2020 Oracle Corporation
     7 * Copyright (C) 2006-2021 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3535#include <iprt/fsisomaker.h>
    3636#include <iprt/fsvfs.h>
    37 #include <iprt/getopt.h>
    3837#include <iprt/file.h>
    3938#include <iprt/path.h>
     
    4342# undef ES /* Workaround for someone dragging the namespace pollutor sys/regset.h. Sigh. */
    4443#endif
    45 #include <iprt/formats/iso9660.h>
    4644#include <iprt/formats/fat.h>
    4745#include <iprt/cpp/path.h>
     
    5149
    5250
    53 /* static */ UnattendedInstaller *UnattendedInstaller::createInstance(VBOXOSTYPE enmOsType,
    54                                                                       const Utf8Str &strGuestOsType,
    55                                                                       const Utf8Str &strDetectedOSVersion,
    56                                                                       const Utf8Str &strDetectedOSFlavor,
    57                                                                       const Utf8Str &strDetectedOSHints,
    58                                                                       Unattended *pParent)
    59 {
    60     UnattendedInstaller *pUinstaller = NULL;
    61 
    62     if (strGuestOsType.find("Windows") != RTCString::npos)
    63     {
    64         if (enmOsType >= VBOXOSTYPE_WinVista)
    65             pUinstaller = new UnattendedWindowsXmlInstaller(pParent);
    66         else
    67             pUinstaller = new UnattendedWindowsSifInstaller(pParent);
    68     }
    69     else if (enmOsType >= VBOXOSTYPE_OS2 && enmOsType < VBOXOSTYPE_Linux)
    70         pUinstaller = new UnattendedOs2Installer(pParent, strDetectedOSHints);
    71     else
    72     {
    73         if (enmOsType == VBOXOSTYPE_Debian || enmOsType == VBOXOSTYPE_Debian_x64)
    74             pUinstaller = new UnattendedDebianInstaller(pParent);
    75         else if (enmOsType >= VBOXOSTYPE_Ubuntu && enmOsType <= VBOXOSTYPE_Ubuntu_x64)
    76             pUinstaller = new UnattendedUbuntuInstaller(pParent);
    77         else if (enmOsType >= VBOXOSTYPE_RedHat && enmOsType <= VBOXOSTYPE_RedHat_x64)
    78         {
    79             if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "8") >= 0)
    80                 pUinstaller = new UnattendedRhel8Installer(pParent);
    81             else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "7") >= 0)
    82                 pUinstaller = new UnattendedRhel7Installer(pParent);
    83             else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "6") >= 0)
    84                 pUinstaller = new UnattendedRhel6Installer(pParent);
    85             else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "5") >= 0)
    86                 pUinstaller = new UnattendedRhel5Installer(pParent);
    87             else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "4") >= 0)
    88                 pUinstaller = new UnattendedRhel4Installer(pParent);
    89             else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "3") >= 0)
    90                 pUinstaller = new UnattendedRhel3Installer(pParent);
    91             else
    92                 pUinstaller = new UnattendedRhel6Installer(pParent);
    93         }
    94         else if (enmOsType >= VBOXOSTYPE_FedoraCore && enmOsType <= VBOXOSTYPE_FedoraCore_x64)
    95             pUinstaller = new UnattendedFedoraInstaller(pParent);
    96         else if (enmOsType >= VBOXOSTYPE_Oracle && enmOsType <= VBOXOSTYPE_Oracle_x64)
    97         {
    98             if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "8") >= 0)
    99                 pUinstaller = new UnattendedOracleLinux8Installer(pParent);
    100             else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "7") >= 0)
    101                 pUinstaller = new UnattendedOracleLinux7Installer(pParent);
    102             else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "6") >= 0)
    103                 pUinstaller = new UnattendedOracleLinux6Installer(pParent);
    104             else
    105                 pUinstaller = new UnattendedOracleLinux6Installer(pParent);
    106         }
    107 #if 0 /* doesn't work, so convert later. */
    108         else if (enmOsType == VBOXOSTYPE_OpenSUSE || enmOsType == VBOXOSTYPE_OpenSUSE_x64)
    109             pUinstaller = new UnattendedSuseInstaller(new UnattendedSUSEXMLScript(pParent), pParent);
    110 #endif
    111     }
    112     RT_NOREF_PV(strDetectedOSFlavor);
    113     RT_NOREF_PV(strDetectedOSHints);
    114     return pUinstaller;
    115 }
    116 
    117 
    118 //////////////////////////////////////////////////////////////////////////////////////////////////////
    119 /*
    120 *
    121 *
    122 *  Implementation Unattended functions
    123 *
    124 */
    125 //////////////////////////////////////////////////////////////////////////////////////////////////////
    126 
    127 /*
    128  *
    129  * UnattendedInstaller public methods
    130  *
    131  */
    132 UnattendedInstaller::UnattendedInstaller(Unattended *pParent,
    133                                          const char *pszMainScriptTemplateName, const char *pszPostScriptTemplateName,
    134                                          const char *pszMainScriptFilename,     const char *pszPostScriptFilename,
    135                                          DeviceType_T enmBootDevice  /*= DeviceType_DVD */)
    136     : mMainScript(pParent, pszMainScriptTemplateName, pszMainScriptFilename)
    137     , mPostScript(pParent, pszPostScriptTemplateName, pszPostScriptFilename)
    138     , mpParent(pParent)
    139     , meBootDevice(enmBootDevice)
    140 {
    141     AssertPtr(pParent);
    142     Assert(*pszMainScriptTemplateName);
    143     Assert(*pszMainScriptFilename);
    144     Assert(*pszPostScriptTemplateName);
    145     Assert(*pszPostScriptFilename);
    146     Assert(enmBootDevice == DeviceType_DVD || enmBootDevice == DeviceType_Floppy);
    147 }
    148 
    149 UnattendedInstaller::~UnattendedInstaller()
    150 {
    151     mpParent = NULL;
    152 }
    153 
    154 HRESULT UnattendedInstaller::initInstaller()
    155 {
    156     /*
    157      * Calculate the full main script template location.
    158      */
    159     if (mpParent->i_getScriptTemplatePath().isNotEmpty())
    160         mStrMainScriptTemplate = mpParent->i_getScriptTemplatePath();
    161     else
    162     {
    163         int vrc = RTPathAppPrivateNoArchCxx(mStrMainScriptTemplate);
    164         if (RT_SUCCESS(vrc))
    165             vrc = RTPathAppendCxx(mStrMainScriptTemplate, "UnattendedTemplates");
    166         if (RT_SUCCESS(vrc))
    167             vrc = RTPathAppendCxx(mStrMainScriptTemplate, mMainScript.getDefaultTemplateFilename());
    168         if (RT_FAILURE(vrc))
    169             return mpParent->setErrorBoth(E_FAIL, vrc,
    170                                           tr("Failed to construct path to the unattended installer script templates (%Rrc)"),
    171                                           vrc);
    172     }
    173 
    174     /*
    175      * Calculate the full post script template location.
    176      */
    177     if (mpParent->i_getPostInstallScriptTemplatePath().isNotEmpty())
    178         mStrPostScriptTemplate = mpParent->i_getPostInstallScriptTemplatePath();
    179     else
    180     {
    181         int vrc = RTPathAppPrivateNoArchCxx(mStrPostScriptTemplate);
    182         if (RT_SUCCESS(vrc))
    183             vrc = RTPathAppendCxx(mStrPostScriptTemplate, "UnattendedTemplates");
    184         if (RT_SUCCESS(vrc))
    185             vrc = RTPathAppendCxx(mStrPostScriptTemplate, mPostScript.getDefaultTemplateFilename());
    186         if (RT_FAILURE(vrc))
    187             return mpParent->setErrorBoth(E_FAIL, vrc,
    188                                           tr("Failed to construct path to the unattended installer script templates (%Rrc)"),
    189                                           vrc);
    190     }
    191 
    192     /*
    193      * Construct paths we need.
    194      */
    195     if (isAuxiliaryFloppyNeeded())
    196     {
    197         mStrAuxiliaryFloppyFilePath = mpParent->i_getAuxiliaryBasePath();
    198         mStrAuxiliaryFloppyFilePath.append("aux-floppy.img");
    199     }
    200     if (isAuxiliaryIsoNeeded())
    201     {
    202         mStrAuxiliaryIsoFilePath = mpParent->i_getAuxiliaryBasePath();
    203         if (!isAuxiliaryIsoIsVISO())
    204             mStrAuxiliaryIsoFilePath.append("aux-iso.iso");
    205         else
    206             mStrAuxiliaryIsoFilePath.append("aux-iso.viso");
    207     }
    208 
    209     /*
    210      * Check that we've got the minimum of data available.
    211      */
    212     if (mpParent->i_getIsoPath().isEmpty())
    213         return mpParent->setError(E_INVALIDARG, tr("Cannot proceed with an empty installation ISO path"));
    214     if (mpParent->i_getUser().isEmpty())
    215         return mpParent->setError(E_INVALIDARG, tr("Empty user name is not allowed"));
    216     if (mpParent->i_getPassword().isEmpty())
    217         return mpParent->setError(E_INVALIDARG, tr("Empty password is not allowed"));
    218 
    219     LogRelFunc(("UnattendedInstaller::savePassedData(): \n"));
    220     return S_OK;
    221 }
    222 
    223 #if 0  /* Always in AUX ISO */
    224 bool UnattendedInstaller::isAdditionsIsoNeeded() const
    225 {
    226     /* In the VISO case, we'll add the additions to the VISO in a subdir. */
    227     return !isAuxiliaryIsoIsVISO() && mpParent->i_getInstallGuestAdditions();
    228 }
    229 
    230 bool UnattendedInstaller::isValidationKitIsoNeeded() const
    231 {
    232     /* In the VISO case, we'll add the validation kit to the VISO in a subdir. */
    233     return !isAuxiliaryIsoIsVISO() && mpParent->i_getInstallTestExecService();
    234 }
    235 #endif
    236 
    237 bool UnattendedInstaller::isAuxiliaryIsoNeeded() const
    238 {
    239     /* In the VISO case we use the AUX ISO for GAs and TXS. */
    240     return isAuxiliaryIsoIsVISO()
    241         && (   mpParent->i_getInstallGuestAdditions()
    242             || mpParent->i_getInstallTestExecService());
    243 }
    244 
    245 
    246 HRESULT UnattendedInstaller::prepareUnattendedScripts()
    247 {
    248     LogFlow(("UnattendedInstaller::prepareUnattendedScripts()\n"));
    249 
    250     /*
    251      * The script template editor calls setError, so status codes just needs to
    252      * be passed on to the caller.  Do the same for both scripts.
    253      */
    254     HRESULT hrc = mMainScript.read(getTemplateFilePath());
    255     if (SUCCEEDED(hrc))
    256     {
    257         hrc = mMainScript.parse();
    258         if (SUCCEEDED(hrc))
    259         {
    260             /* Ditto for the post script. */
    261             hrc = mPostScript.read(getPostTemplateFilePath());
    262             if (SUCCEEDED(hrc))
    263             {
    264                 hrc = mPostScript.parse();
    265                 if (SUCCEEDED(hrc))
    266                 {
    267                     LogFlow(("UnattendedInstaller::prepareUnattendedScripts: returns S_OK\n"));
    268                     return S_OK;
    269                 }
    270                 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: parse failed on post script (%Rhrc)\n", hrc));
    271             }
    272             else
    273                 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: error reading post install script template file (%Rhrc)\n", hrc));
    274         }
    275         else
    276             LogFlow(("UnattendedInstaller::prepareUnattendedScripts: parse failed (%Rhrc)\n", hrc));
    277     }
    278     else
    279         LogFlow(("UnattendedInstaller::prepareUnattendedScripts: error reading installation script template file (%Rhrc)\n", hrc));
    280     return hrc;
    281 }
    282 
    283 HRESULT UnattendedInstaller::prepareMedia(bool fOverwrite /*=true*/)
    284 {
    285     LogRelFlow(("UnattendedInstaller::prepareMedia:\n"));
    286     HRESULT hrc = S_OK;
    287     if (isAuxiliaryFloppyNeeded())
    288         hrc = prepareAuxFloppyImage(fOverwrite);
    289     if (SUCCEEDED(hrc))
    290     {
    291         if (isAuxiliaryIsoNeeded())
    292         {
    293             hrc = prepareAuxIsoImage(fOverwrite);
    294             if (FAILED(hrc))
    295             {
    296                 LogRelFlow(("UnattendedInstaller::prepareMedia: prepareAuxIsoImage failed\n"));
    297 
    298                 /* Delete the floppy image if we created one.  */
    299                 if (isAuxiliaryFloppyNeeded())
    300                     RTFileDelete(getAuxiliaryFloppyFilePath().c_str());
    301             }
    302         }
    303     }
    304     LogRelFlow(("UnattendedInstaller::prepareMedia: returns %Rrc\n", hrc));
    305     return hrc;
    306 }
    307 
    308 /*
    309  *
    310  * UnattendedInstaller protected methods
    311  *
    312  */
    313 HRESULT UnattendedInstaller::prepareAuxFloppyImage(bool fOverwrite)
    314 {
    315     Assert(isAuxiliaryFloppyNeeded());
    316 
    317     /*
    318      * Create the image.
    319      */
    320     RTVFSFILE hVfsFile;
    321     HRESULT hrc = newAuxFloppyImage(getAuxiliaryFloppyFilePath().c_str(), fOverwrite, &hVfsFile);
    322     if (SUCCEEDED(hrc))
    323     {
    324         /*
    325          * Open the FAT file system so we can copy files onto the floppy.
    326          */
    327         RTERRINFOSTATIC ErrInfo;
    328         RTVFS           hVfs;
    329         int vrc = RTFsFatVolOpen(hVfsFile, false /*fReadOnly*/,  0 /*offBootSector*/, &hVfs, RTErrInfoInitStatic(&ErrInfo));
    330         RTVfsFileRelease(hVfsFile);
    331         if (RT_SUCCESS(vrc))
    332         {
    333             /*
    334              * Call overridable method to copies the files onto it.
    335              */
    336             hrc = copyFilesToAuxFloppyImage(hVfs);
    337 
    338             /*
    339              * Release the VFS.  On failure, delete the floppy image so the operation can
    340              * be repeated in non-overwrite mode and so that we don't leave any mess behind.
    341              */
    342             RTVfsRelease(hVfs);
    343         }
    344         else if (RTErrInfoIsSet(&ErrInfo.Core))
    345             hrc = mpParent->setErrorBoth(E_FAIL, vrc,
    346                                          tr("Failed to open FAT file system on newly created floppy image '%s': %Rrc: %s"),
    347                                          getAuxiliaryFloppyFilePath().c_str(), vrc, ErrInfo.Core.pszMsg);
    348         else
    349             hrc = mpParent->setErrorBoth(E_FAIL, vrc,
    350                                          tr("Failed to open FAT file system onnewly created floppy image '%s': %Rrc"),
    351                                          getAuxiliaryFloppyFilePath().c_str(), vrc);
    352         if (FAILED(hrc))
    353             RTFileDelete(getAuxiliaryFloppyFilePath().c_str());
    354     }
    355     return hrc;
    356 }
    357 
    358 HRESULT UnattendedInstaller::newAuxFloppyImage(const char *pszFilename, bool fOverwrite, PRTVFSFILE phVfsFile)
    359 {
    360     /*
    361      * Open the image file.
    362      */
    363     HRESULT     hrc;
    364     RTVFSFILE   hVfsFile;
    365     uint64_t    fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT);
    366     if (fOverwrite)
    367         fOpen |= RTFILE_O_CREATE_REPLACE;
    368     else
    369         fOpen |= RTFILE_O_OPEN;
    370     int vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
    371     if (RT_SUCCESS(vrc))
    372     {
    373         /*
    374          * Format it.
    375          */
    376         vrc = RTFsFatVolFormat144(hVfsFile, false /*fQuick*/);
    377         if (RT_SUCCESS(vrc))
    378         {
    379             *phVfsFile = hVfsFile;
    380             LogRelFlow(("UnattendedInstaller::newAuxFloppyImage: created and formatted  '%s'\n", pszFilename));
    381             return S_OK;
    382         }
    383 
    384         hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to format floppy image '%s': %Rrc"), pszFilename, vrc);
    385         RTVfsFileRelease(hVfsFile);
    386         RTFileDelete(pszFilename);
    387     }
    388     else
    389         hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to create floppy image '%s': %Rrc"), pszFilename, vrc);
    390     return hrc;
    391 }
    392 
    393 HRESULT UnattendedInstaller::copyFilesToAuxFloppyImage(RTVFS hVfs)
    394 {
    395     HRESULT hrc = addScriptToFloppyImage(&mMainScript, hVfs);
    396     if (SUCCEEDED(hrc))
    397         hrc = addScriptToFloppyImage(&mPostScript, hVfs);
    398     return hrc;
    399 }
    400 
    401 HRESULT UnattendedInstaller::addScriptToFloppyImage(BaseTextScript *pEditor, RTVFS hVfs)
    402 {
    403     /*
    404      * Open the destination file.
    405      */
    406     HRESULT   hrc;
    407     RTVFSFILE hVfsFileDst;
    408     int vrc = RTVfsFileOpen(hVfs, pEditor->getDefaultFilename(),
    409                             RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_ALL
    410                             | (0660 << RTFILE_O_CREATE_MODE_SHIFT),
    411                             &hVfsFileDst);
    412     if (RT_SUCCESS(vrc))
    413     {
    414         /*
    415          * Save the content to a string.
    416          */
    417         Utf8Str strScript;
    418         hrc = pEditor->saveToString(strScript);
    419         if (SUCCEEDED(hrc))
    420         {
    421             /*
    422              * Write the string.
    423              */
    424             vrc = RTVfsFileWrite(hVfsFileDst, strScript.c_str(), strScript.length(), NULL);
    425             if (RT_SUCCESS(vrc))
    426                 hrc = S_OK; /* done */
    427             else
    428                 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
    429                                              tr("Error writing %zu bytes to '%s' in floppy image '%s': %Rrc",
    430                                                 "", strScript.length()),
    431                                              strScript.length(), pEditor->getDefaultFilename(),
    432                                              getAuxiliaryFloppyFilePath().c_str());
    433         }
    434         RTVfsFileRelease(hVfsFileDst);
    435     }
    436     else
    437         hrc = mpParent->setErrorBoth(E_FAIL, vrc,
    438                                      tr("Error creating '%s' in floppy image '%s': %Rrc"),
    439                                      pEditor->getDefaultFilename(), getAuxiliaryFloppyFilePath().c_str());
    440     return hrc;
    441 }
    442 
    443 HRESULT UnattendedInstaller::addFileToFloppyImage(RTVFS hVfs, const char *pszSrc, const char *pszDst)
    444 {
    445     HRESULT hrc;
    446 
    447     /*
    448      * Open the source file.
    449      */
    450     RTVFSIOSTREAM hVfsIosSrc;
    451     int vrc = RTVfsIoStrmOpenNormal(pszSrc, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hVfsIosSrc);
    452     if (RT_SUCCESS(vrc))
    453     {
    454         /*
    455          * Open the destination file.
    456          */
    457         RTVFSFILE hVfsFileDst;
    458         vrc = RTVfsFileOpen(hVfs, pszDst,
    459                             RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT),
    460                             &hVfsFileDst);
    461         if (RT_SUCCESS(vrc))
    462         {
    463             /*
    464              * Do the copying.
    465              */
    466             RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsFileDst);
    467             vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0);
    468             if (RT_SUCCESS(vrc))
    469                 hrc = S_OK;
    470             else
    471                 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing copying '%s' to floppy image '%s': %Rrc"),
    472                                              pszSrc, getAuxiliaryFloppyFilePath().c_str(), vrc);
    473             RTVfsIoStrmRelease(hVfsIosDst);
    474             RTVfsFileRelease(hVfsFileDst);
    475         }
    476         else
    477             hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error opening '%s' on floppy image '%s' for writing: %Rrc"),
    478                                          pszDst, getAuxiliaryFloppyFilePath().c_str(), vrc);
    479 
    480         RTVfsIoStrmRelease(hVfsIosSrc);
    481     }
    482     else
    483         hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error opening '%s' for copying onto floppy image '%s': %Rrc"),
    484                                      pszSrc, getAuxiliaryFloppyFilePath().c_str(), vrc);
    485     return hrc;
    486 }
    487 
    488 HRESULT UnattendedInstaller::prepareAuxIsoImage(bool fOverwrite)
    489 {
    490     /*
    491      * Open the original installation ISO.
    492      */
    493     RTVFS   hVfsOrgIso;
    494     HRESULT hrc = openInstallIsoImage(&hVfsOrgIso);
    495     if (SUCCEEDED(hrc))
    496     {
    497         /*
    498          * The next steps depends on the kind of image we're making.
    499          */
    500         if (!isAuxiliaryIsoIsVISO())
    501         {
    502             RTFSISOMAKER hIsoMaker;
    503             hrc = newAuxIsoImageMaker(&hIsoMaker);
    504             if (SUCCEEDED(hrc))
    505             {
    506                 hrc = addFilesToAuxIsoImageMaker(hIsoMaker, hVfsOrgIso);
    507                 if (SUCCEEDED(hrc))
    508                     hrc = finalizeAuxIsoImage(hIsoMaker, getAuxiliaryIsoFilePath().c_str(), fOverwrite);
    509                 RTFsIsoMakerRelease(hIsoMaker);
    510             }
    511         }
    512         else
    513         {
    514             RTCList<RTCString> vecFiles(0);
    515             RTCList<RTCString> vecArgs(0);
    516             try
    517             {
    518                 vecArgs.append() = "--iprt-iso-maker-file-marker-bourne-sh";
    519                 RTUUID Uuid;
    520                 int vrc = RTUuidCreate(&Uuid); AssertRC(vrc);
    521                 char szTmp[RTUUID_STR_LENGTH + 1];
    522                 vrc = RTUuidToStr(&Uuid, szTmp, sizeof(szTmp)); AssertRC(vrc);
    523                 vecArgs.append() = szTmp;
    524                 vecArgs.append() = "--file-mode=0444";
    525                 vecArgs.append() = "--dir-mode=0555";
    526             }
    527             catch (std::bad_alloc &)
    528             {
    529                 hrc = E_OUTOFMEMORY;
    530             }
    531             if (SUCCEEDED(hrc))
    532             {
    533                 hrc = addFilesToAuxVisoVectors(vecArgs, vecFiles, hVfsOrgIso, fOverwrite);
    534                 if (SUCCEEDED(hrc))
    535                     hrc = finalizeAuxVisoFile(vecArgs, getAuxiliaryIsoFilePath().c_str(), fOverwrite);
    536 
    537                 if (FAILED(hrc))
    538                     for (size_t i = 0; i < vecFiles.size(); i++)
    539                         RTFileDelete(vecFiles[i].c_str());
    540             }
    541         }
    542         RTVfsRelease(hVfsOrgIso);
    543     }
    544     return hrc;
    545 }
    546 
    547 HRESULT UnattendedInstaller::openInstallIsoImage(PRTVFS phVfsIso, uint32_t fFlags /*= 0*/)
    548 {
    549     /* Open the file. */
    550     const char *pszIsoPath = mpParent->i_getIsoPath().c_str();
    551     RTVFSFILE hOrgIsoFile;
    552     int vrc = RTVfsFileOpenNormal(pszIsoPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, &hOrgIsoFile);
    553     if (RT_FAILURE(vrc))
    554         return mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to open ISO image '%s' (%Rrc)"), pszIsoPath, vrc);
    555 
    556     /* Pass the file to the ISO file system interpreter. */
    557     RTERRINFOSTATIC ErrInfo;
    558     vrc = RTFsIso9660VolOpen(hOrgIsoFile, fFlags, phVfsIso, RTErrInfoInitStatic(&ErrInfo));
    559     RTVfsFileRelease(hOrgIsoFile);
    560     if (RT_SUCCESS(vrc))
    561         return S_OK;
    562     if (RTErrInfoIsSet(&ErrInfo.Core))
    563         return mpParent->setErrorBoth(E_FAIL, vrc, tr("ISO reader fail to open '%s' (%Rrc): %s"),
    564                                       pszIsoPath, vrc, ErrInfo.Core.pszMsg);
    565     return mpParent->setErrorBoth(E_FAIL, vrc, tr("ISO reader fail to open '%s' (%Rrc)"), pszIsoPath, vrc);
    566 }
    567 
    568 HRESULT UnattendedInstaller::newAuxIsoImageMaker(PRTFSISOMAKER phIsoMaker)
    569 {
    570     int vrc = RTFsIsoMakerCreate(phIsoMaker);
    571     if (RT_SUCCESS(vrc))
    572         return S_OK;
    573     return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerCreate failed (%Rrc)"), vrc);
    574 }
    575 
    576 HRESULT UnattendedInstaller::addFilesToAuxIsoImageMaker(RTFSISOMAKER hIsoMaker, RTVFS hVfsOrgIso)
    577 {
    578     RT_NOREF(hVfsOrgIso);
    579 
    580     /*
    581      * Add the two scripts to the image with default names.
    582      */
    583     HRESULT hrc = addScriptToIsoMaker(&mMainScript, hIsoMaker);
    584     if (SUCCEEDED(hrc))
    585         hrc = addScriptToIsoMaker(&mPostScript, hIsoMaker);
    586     return hrc;
    587 }
    588 
    589 HRESULT UnattendedInstaller::addScriptToIsoMaker(BaseTextScript *pEditor, RTFSISOMAKER hIsoMaker,
    590                                                  const char *pszDstFilename /*= NULL*/)
    591 {
    592     /*
    593      * Calc default destination filename if desired.
    594      */
    595     RTCString strDstNameBuf;
    596     if (!pszDstFilename)
    597     {
    598         try
    599         {
    600             strDstNameBuf = RTPATH_SLASH_STR;
    601             strDstNameBuf.append(pEditor->getDefaultTemplateFilename());
    602             pszDstFilename = strDstNameBuf.c_str();
    603         }
    604         catch (std::bad_alloc &)
    605         {
    606             return E_OUTOFMEMORY;
    607         }
    608     }
    609 
    610     /*
    611      * Create a memory file for the script.
    612      */
    613     Utf8Str strScript;
    614     HRESULT hrc = pEditor->saveToString(strScript);
    615     if (SUCCEEDED(hrc))
    616     {
    617         RTVFSFILE hVfsScriptFile;
    618         size_t    cchScript = strScript.length();
    619         int vrc = RTVfsFileFromBuffer(RTFILE_O_READ, strScript.c_str(), strScript.length(), &hVfsScriptFile);
    620         strScript.setNull();
    621         if (RT_SUCCESS(vrc))
    622         {
    623             /*
    624              * Add it to the ISO.
    625              */
    626             vrc = RTFsIsoMakerAddFileWithVfsFile(hIsoMaker, pszDstFilename, hVfsScriptFile, NULL);
    627             RTVfsFileRelease(hVfsScriptFile);
    628             if (RT_SUCCESS(vrc))
    629                 hrc = S_OK;
    630             else
    631                 hrc = mpParent->setErrorBoth(E_FAIL, vrc,
    632                                              tr("RTFsIsoMakerAddFileWithVfsFile failed on the script '%s' (%Rrc)"),
    633                                              pszDstFilename, vrc);
    634         }
    635         else
    636             hrc = mpParent->setErrorBoth(E_FAIL, vrc,
    637                                          tr("RTVfsFileFromBuffer failed on the %zu byte script '%s' (%Rrc)", "", cchScript),
    638                                          cchScript, pszDstFilename, vrc);
    639     }
    640     return hrc;
    641 }
    642 
    643 HRESULT UnattendedInstaller::finalizeAuxIsoImage(RTFSISOMAKER hIsoMaker, const char *pszFilename, bool fOverwrite)
    644 {
    645     /*
    646      * Finalize the image.
    647      */
    648     int vrc = RTFsIsoMakerFinalize(hIsoMaker);
    649     if (RT_FAILURE(vrc))
    650         return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerFinalize failed (%Rrc)"), vrc);
    651 
    652     /*
    653      * Open the destination file.
    654      */
    655     uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
    656     if (fOverwrite)
    657         fOpen |= RTFILE_O_CREATE_REPLACE;
    658     else
    659         fOpen |= RTFILE_O_CREATE;
    660     RTVFSFILE hVfsDstFile;
    661     vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsDstFile);
    662     if (RT_FAILURE(vrc))
    663     {
    664         if (vrc == VERR_ALREADY_EXISTS)
    665             return mpParent->setErrorBoth(E_FAIL, vrc, tr("The auxiliary ISO image file '%s' already exists"),
    666                                           pszFilename);
    667         return mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to open the auxiliary ISO image file '%s' for writing (%Rrc)"),
    668                                       pszFilename, vrc);
    669     }
    670 
    671     /*
    672      * Get the source file from the image maker.
    673      */
    674     HRESULT   hrc;
    675     RTVFSFILE hVfsSrcFile;
    676     vrc = RTFsIsoMakerCreateVfsOutputFile(hIsoMaker, &hVfsSrcFile);
    677     if (RT_SUCCESS(vrc))
    678     {
    679         RTVFSIOSTREAM hVfsSrcIso = RTVfsFileToIoStream(hVfsSrcFile);
    680         RTVFSIOSTREAM hVfsDstIso = RTVfsFileToIoStream(hVfsDstFile);
    681         if (   hVfsSrcIso != NIL_RTVFSIOSTREAM
    682             && hVfsDstIso != NIL_RTVFSIOSTREAM)
    683         {
    684             vrc = RTVfsUtilPumpIoStreams(hVfsSrcIso, hVfsDstIso, 0 /*cbBufHint*/);
    685             if (RT_SUCCESS(vrc))
    686                 hrc = S_OK;
    687             else
    688                 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Error writing auxiliary ISO image '%s' (%Rrc)"),
    689                                              pszFilename, vrc);
    690         }
    691         else
    692             hrc = mpParent->setErrorBoth(E_FAIL, VERR_INTERNAL_ERROR_2,
    693                                          tr("Internal Error: Failed to case VFS file to VFS I/O stream"));
    694         RTVfsIoStrmRelease(hVfsSrcIso);
    695         RTVfsIoStrmRelease(hVfsDstIso);
    696     }
    697     else
    698         hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("RTFsIsoMakerCreateVfsOutputFile failed (%Rrc)"), vrc);
    699     RTVfsFileRelease(hVfsSrcFile);
    700     RTVfsFileRelease(hVfsDstFile);
    701     if (FAILED(hrc))
    702         RTFileDelete(pszFilename);
    703     return hrc;
    704 }
    705 
    706 HRESULT UnattendedInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
    707                                                       RTVFS hVfsOrgIso, bool fOverwrite)
    708 {
    709     RT_NOREF(hVfsOrgIso);
    710 
    711     /*
    712      * Save and add the scripts.
    713      */
    714     HRESULT hrc = addScriptToVisoVectors(&mMainScript, rVecArgs, rVecFiles, fOverwrite);
    715     if (SUCCEEDED(hrc))
    716         hrc = addScriptToVisoVectors(&mPostScript, rVecArgs, rVecFiles, fOverwrite);
    717     if (SUCCEEDED(hrc))
    718     {
    719         try
    720         {
    721             /*
    722              * If we've got a Guest Additions ISO, add its content to a /vboxadditions dir.
    723              */
    724             if (mpParent->i_getInstallGuestAdditions())
    725             {
    726                 rVecArgs.append().append("--push-iso=").append(mpParent->i_getAdditionsIsoPath());
    727                 rVecArgs.append() = "/vboxadditions=/";
    728                 rVecArgs.append() = "--pop";
    729             }
    730 
    731             /*
    732              * If we've got a Validation Kit ISO, add its content to a /vboxvalidationkit dir.
    733              */
    734             if (mpParent->i_getInstallTestExecService())
    735             {
    736                 rVecArgs.append().append("--push-iso=").append(mpParent->i_getValidationKitIsoPath());
    737                 rVecArgs.append() = "/vboxvalidationkit=/";
    738                 rVecArgs.append() = "--pop";
    739             }
    740         }
    741         catch (std::bad_alloc &)
    742         {
    743             hrc = E_OUTOFMEMORY;
    744         }
    745     }
    746     return hrc;
    747 }
    748 
    749 HRESULT UnattendedInstaller::addScriptToVisoVectors(BaseTextScript *pEditor, RTCList<RTCString> &rVecArgs,
    750                                                     RTCList<RTCString> &rVecFiles, bool fOverwrite)
    751 {
    752     /*
    753      * Calc the aux script file name.
    754      */
    755     RTCString strScriptName;
    756     try
    757     {
    758         strScriptName = mpParent->i_getAuxiliaryBasePath();
    759         strScriptName.append(pEditor->getDefaultFilename());
    760     }
    761     catch (std::bad_alloc &)
    762     {
    763         return E_OUTOFMEMORY;
    764     }
    765 
    766     /*
    767      * Save it.
    768      */
    769     HRESULT hrc = pEditor->save(strScriptName.c_str(), fOverwrite);
    770     if (SUCCEEDED(hrc))
    771     {
    772         /*
    773          * Add it to the vectors.
    774          */
    775         try
    776         {
    777             rVecArgs.append().append('/').append(pEditor->getDefaultFilename()).append('=').append(strScriptName);
    778             rVecFiles.append(strScriptName);
    779         }
    780         catch (std::bad_alloc &)
    781         {
    782             RTFileDelete(strScriptName.c_str());
    783             hrc = E_OUTOFMEMORY;
    784         }
    785     }
    786     return hrc;
    787 }
    788 
    789 HRESULT UnattendedInstaller::finalizeAuxVisoFile(RTCList<RTCString> const &rVecArgs, const char *pszFilename, bool fOverwrite)
    790 {
    791     /*
    792      * Create a C-style argument vector and turn that into a command line string.
    793      */
    794     size_t const cArgs     = rVecArgs.size();
    795     const char **papszArgs = (const char **)RTMemTmpAlloc((cArgs + 1) * sizeof(const char *));
    796     if (!papszArgs)
    797         return E_OUTOFMEMORY;
    798     for (size_t i = 0; i < cArgs; i++)
    799         papszArgs[i] = rVecArgs[i].c_str();
    800     papszArgs[cArgs] = NULL;
    801 
    802     char *pszCmdLine;
    803     int vrc = RTGetOptArgvToString(&pszCmdLine, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
    804     RTMemTmpFree(papszArgs);
    805     if (RT_FAILURE(vrc))
    806         return mpParent->setErrorBoth(E_FAIL, vrc, tr("RTGetOptArgvToString failed (%Rrc)"), vrc);
    807 
    808     /*
    809      * Open the file.
    810      */
    811     HRESULT  hrc;
    812     uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ;
    813     if (fOverwrite)
    814         fOpen |= RTFILE_O_CREATE_REPLACE;
    815     else
    816         fOpen |= RTFILE_O_CREATE;
    817     RTFILE hFile;
    818     vrc = RTFileOpen(&hFile, pszFilename, fOpen);
    819     if (RT_SUCCESS(vrc))
    820     {
    821         vrc = RTFileWrite(hFile, pszCmdLine, strlen(pszCmdLine), NULL);
    822         if (RT_SUCCESS(vrc))
    823             vrc = RTFileClose(hFile);
    824         else
    825             RTFileClose(hFile);
    826         if (RT_SUCCESS(vrc))
    827             hrc = S_OK;
    828         else
    829             hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing '%s' (%Rrc)"), pszFilename, vrc);
    830     }
    831     else
    832         hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to create '%s' (%Rrc)"), pszFilename, vrc);
    833 
    834     RTStrFree(pszCmdLine);
    835     return hrc;
    836 }
    837 
    838 HRESULT UnattendedInstaller::loadAndParseFileFromIso(RTVFS hVfsOrgIso, const char *pszFilename, AbstractScript *pEditor)
    839 {
    840     HRESULT   hrc;
    841     RTVFSFILE hVfsFile;
    842     int vrc = RTVfsFileOpen(hVfsOrgIso, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsFile);
    843     if (RT_SUCCESS(vrc))
    844     {
    845         hrc = pEditor->readFromHandle(hVfsFile, pszFilename);
    846         RTVfsFileRelease(hVfsFile);
    847         if (SUCCEEDED(hrc))
    848             hrc = pEditor->parse();
    849     }
    850     else
    851         hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open '%s' on the ISO '%s' (%Rrc)"),
    852                                      pszFilename, mpParent->i_getIsoPath().c_str(), vrc);
    853     return hrc;
    854 }
    855 
    856 
    857 
    858 /*********************************************************************************************************************************
    859 *   Implementation of UnattendedOs2Installer                                                                                     *
    860 *********************************************************************************************************************************/
    86151
    86252UnattendedOs2Installer::UnattendedOs2Installer(Unattended *pParent, Utf8Str const &rStrHints)
    86353    : UnattendedInstaller(pParent,
    864                           "os2_response_files.rsp", "os2_postinstall.cmd",
    865                           "OS2.RSP",                "VBOXPOST.CMD",
     54                          "os2_response_files.rsp", "os2_cid_install.cmd",
     55                          "OS2.RSP",                "VBOXCID.CMD",
    86656                          DeviceType_Floppy)
    86757{
     
    1072262}
    1073263
     264/**
     265 * OS/2 code pattern.
     266 */
     267typedef struct OS2CODEPATTERN
     268{
     269    /** The code pattern. */
     270    uint8_t const *pbPattern;
     271    /** The mask to apply when using the pattern (ignore 0x00 bytes, compare 0xff
     272     *  bytes). */
     273    uint8_t const *pbMask;
     274    /** The pattern size.  */
     275    size_t         cb;
     276    /** User info \#1. */
     277    uintptr_t      uUser1;
     278    /** User info \#2. */
     279    uint32_t       uUser2;
     280    /** User info \#3. */
     281    uint32_t       uUser3;
     282    /** User info \#4. */
     283    uint32_t       uUser4;
     284    /** User info \#5. */
     285    uint32_t       uUser5;
     286} OS2CODEPATTERN;
     287/** Pointer to an OS/2 code pattern.   */
     288typedef OS2CODEPATTERN const *PCOS2CODEPATTERN;
     289
     290
     291/**
     292 * Search @a pbCode for the code patterns in @a paPatterns.
     293 *
     294 * @returns pointer within @a pbCode to matching code, NULL if no match.
     295 */
     296static uint8_t *findCodePattern(PCOS2CODEPATTERN paPatterns, size_t cPatterns, uint8_t *pbCode, size_t cbCode,
     297                                PCOS2CODEPATTERN *ppMatch)
     298{
     299    for (size_t i = 0; i < cPatterns; i++)
     300    {
     301        size_t const   cbPattern = paPatterns[i].cb;
     302        uint8_t const *pbPattern = paPatterns[i].pbPattern;
     303        uint8_t const *pbMask    = paPatterns[i].pbMask;
     304        Assert(pbMask[0] == 0xff); /* ASSUME the we can use the first byte with memchr. */
     305        uint8_t const  bFirst    = *pbPattern;
     306        size_t         off       = 0;
     307        while (off + cbPattern <= cbCode)
     308        {
     309            uint8_t *pbHit = (uint8_t *)memchr(&pbCode[off], bFirst, cbCode - off - cbPattern + 1);
     310            if (!pbHit)
     311                break;
     312
     313            size_t offPattern = 1;
     314            while (   offPattern < cbPattern
     315                   && (pbPattern[offPattern] & pbMask[offPattern]) == (pbHit[offPattern] & pbMask[offPattern]))
     316                offPattern++;
     317            if (offPattern == cbPattern)
     318            {
     319                *ppMatch = &paPatterns[i];
     320                return pbHit;
     321            }
     322
     323            /* next */
     324            off++;
     325        }
     326    }
     327    return NULL;
     328}
     329
     330
     331/**
     332 * Patcher callback for OS2LDR.
     333 *
     334 * There are one or two delay calibration loops here that doesn't work well on
     335 * fast CPUs. Typically ends up with division by chainsaw, which in a BIOS
     336 * context means an unending loop as the BIOS \#DE handler doesn't do much.
     337 *
     338 * The patching is simplictic, in that it just returns a constant value.  We
     339 * could rewrite this to use RDTSC and some secret MSR/whatever for converting
     340 * that to a decent loop count.
     341 */
     342/*static*/
     343int UnattendedOs2Installer::patchOs2Ldr(uint8_t *pbFile, size_t cbFile, const char *pszFilename, UnattendedOs2Installer *pThis)
     344{
     345    RT_NOREF(pThis, pszFilename);
     346
     347    /*
     348     * This first variant is from ACP2:
     349     *
     350     * VBoxDbg> r
     351     * eax=00001000 ebx=00010000 ecx=56d8ffd5 edx=178b0000 esi=00000000 edi=0000b750
     352     * eip=0000847a esp=0000cfe8 ebp=00000000 iopl=0 nv up ei pl zr na po nc
     353     * cs=2000 ds=2000 es=2000 fs=0000 gs=0000 ss=2000               eflags=00000246
     354     * 2000:0000847a f7 fb                   idiv bx
     355     * VBoxDbg> ucfg 2000:840a
     356     *
     357     * This is a little annoying because it stores the result in a global variable,
     358     * so we cannot just do an early return, instead we have to have to jump to the
     359     * end of the function so it can be stored correctly.
     360     */
     361    static uint8_t const s_abVariant1[] =
     362    {
     363        /*2000:840a*/ 0x60,                 /* pushaw             */
     364        /*2000:840b*/ 0x1e,                 /* push DS            */
     365        /*2000:840c*/ 0x0e,                 /* push CS            */
     366        /*2000:840d*/ 0x1f,                 /* pop DS             */
     367        /*2000:840e*/ 0x9c,                 /* pushfw             */
     368        /*2000:840f*/ 0xfa,                 /* cli                */
     369        /*2000:8410*/ 0xb0, 0x34,           /* mov AL, 034h       */
     370        /*2000:8412*/ 0xe6, 0x43,           /* out 043h, AL       */
     371        /*2000:8414*/ 0xe8, 0x75, 0xfc,     /* call 0808ch        */
     372        /*2000:8417*/ 0x32, 0xc0,           /* xor al, al         */
     373        /*2000:8419*/ 0xe6, 0x40,           /* out 040h, AL       */
     374        /*2000:841b*/ 0xe8, 0x6e, 0xfc,     /* call 0808ch        */
     375        /*2000:841e*/ 0xe6, 0x40,           /* out 040h, AL       */
     376        /*2000:8420*/ 0xe8, 0x69, 0xfc,     /* call 0808ch        */
     377        /*2000:8423*/ 0xb0, 0x00,           /* mov AL, 000h       */
     378        /*2000:8425*/ 0xe6, 0x43,           /* out 043h, AL       */
     379        /*2000:8427*/ 0xe8, 0x62, 0xfc,     /* call 0808ch        */
     380        /*2000:842a*/ 0xe4, 0x40,           /* in AL, 040h        */
     381        /*2000:842c*/ 0xe8, 0x5d, 0xfc,     /* call 0808ch        */
     382        /*2000:842f*/ 0x8a, 0xd8,           /* mov bl, al         */
     383        /*2000:8431*/ 0xe4, 0x40,           /* in AL, 040h        */
     384        /*2000:8433*/ 0x8a, 0xf8,           /* mov bh, al         */
     385        /*2000:8435*/ 0xb0, 0x00,           /* mov AL, 000h       */
     386        /*2000:8437*/ 0xe6, 0x43,           /* out 043h, AL       */
     387        /*2000:8439*/ 0xe8, 0x50, 0xfc,     /* call 0808ch        */
     388        /*2000:843c*/ 0xe4, 0x40,           /* in AL, 040h        */
     389        /*2000:843e*/ 0xe8, 0x4b, 0xfc,     /* call 0808ch        */
     390        /*2000:8441*/ 0x8a, 0xc8,           /* mov cl, al         */
     391        /*2000:8443*/ 0xe4, 0x40,           /* in AL, 040h        */
     392        /*2000:8445*/ 0x8a, 0xe8,           /* mov ch, al         */
     393        /*2000:8447*/ 0xbe, 0x00, 0x10,     /* mov si, 01000h     */
     394        /*2000:844a*/ 0x87, 0xdb,           /* xchg bx, bx        */
     395        /*2000:844c*/ 0x4e,                 /* dec si             */
     396        /*2000:844d*/ 0x75, 0xfd,           /* jne -003h (0844ch) */
     397        /*2000:844f*/ 0xb0, 0x00,           /* mov AL, 000h       */
     398        /*2000:8451*/ 0xe6, 0x43,           /* out 043h, AL       */
     399        /*2000:8453*/ 0xe8, 0x36, 0xfc,     /* call 0808ch        */
     400        /*2000:8456*/ 0xe4, 0x40,           /* in AL, 040h        */
     401        /*2000:8458*/ 0xe8, 0x31, 0xfc,     /* call 0808ch        */
     402        /*2000:845b*/ 0x8a, 0xd0,           /* mov dl, al         */
     403        /*2000:845d*/ 0xe4, 0x40,           /* in AL, 040h        */
     404        /*2000:845f*/ 0x8a, 0xf0,           /* mov dh, al         */
     405        /*2000:8461*/ 0x9d,                 /* popfw              */
     406        /*2000:8462*/ 0x2b, 0xd9,           /* sub bx, cx         */
     407        /*2000:8464*/ 0x2b, 0xca,           /* sub cx, dx         */
     408        /*2000:8466*/ 0x2b, 0xcb,           /* sub cx, bx         */
     409        /*2000:8468*/ 0x87, 0xca,           /* xchg dx, cx        */
     410        /*2000:846a*/ 0xb8, 0x28, 0x00,     /* mov ax, 00028h     */
     411        /*2000:846d*/ 0xf7, 0xea,           /* imul dx            */
     412        /*2000:846f*/ 0xbb, 0x18, 0x00,     /* mov bx, 00018h     */
     413        /*2000:8472*/ 0xf7, 0xfb,           /* idiv bx            */
     414        /*2000:8474*/ 0x33, 0xd2,           /* xor dx, dx         */
     415        /*2000:8476*/ 0xbb, 0x00, 0x10,     /* mov bx, 01000h     */
     416        /*2000:8479*/ 0x93,                 /* xchg bx, ax        */
     417        /*2000:847a*/ 0xf7, 0xfb,           /* idiv bx            */
     418        /*2000:847c*/ 0x0b, 0xd2,           /* or dx, dx          */
     419        /*2000:847e*/ 0x74, 0x01,           /* je +001h (08481h)  */
     420        /*2000:8480*/ 0x40,                 /* inc ax             */
     421        /*2000:8481*/ 0x40,                 /* inc ax             */
     422        /*2000:8482*/ 0xa3, 0x4d, 0xac,     /* mov word [0ac4dh], ax */
     423        /*2000:8485*/ 0x1f,                 /* pop DS             */
     424        /*2000:8486*/ 0x61,                 /* popaw              */
     425        /*2000:8487*/ 0xc3,                 /* retn               */
     426    };
     427    static uint8_t const s_abVariant1Mask[] =
     428    {
     429        /*2000:840a*/ 0xff,                 /* pushaw             */
     430        /*2000:840b*/ 0xff,                 /* push DS            */
     431        /*2000:840c*/ 0xff,                 /* push CS            */
     432        /*2000:840d*/ 0xff,                 /* pop DS             */
     433        /*2000:840e*/ 0xff,                 /* pushfw             */
     434        /*2000:840f*/ 0xff,                 /* cli                */
     435        /*2000:8410*/ 0xff, 0xff,           /* mov AL, 034h       */
     436        /*2000:8412*/ 0xff, 0xff,           /* out 043h, AL       */
     437        /*2000:8414*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     438        /*2000:8417*/ 0xff, 0xff,           /* xor al, al         */
     439        /*2000:8419*/ 0xff, 0xff,           /* out 040h, AL       */
     440        /*2000:841b*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     441        /*2000:841e*/ 0xff, 0xff,           /* out 040h, AL       */
     442        /*2000:8420*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     443        /*2000:8423*/ 0xff, 0xff,           /* mov AL, 000h       */
     444        /*2000:8425*/ 0xff, 0xff,           /* out 043h, AL       */
     445        /*2000:8427*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     446        /*2000:842a*/ 0xff, 0xff,           /* in AL, 040h        */
     447        /*2000:842c*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     448        /*2000:842f*/ 0xff, 0xff,           /* mov bl, al         */
     449        /*2000:8431*/ 0xff, 0xff,           /* in AL, 040h        */
     450        /*2000:8433*/ 0xff, 0xff,           /* mov bh, al         */
     451        /*2000:8435*/ 0xff, 0xff,           /* mov AL, 000h       */
     452        /*2000:8437*/ 0xff, 0xff,           /* out 043h, AL       */
     453        /*2000:8439*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     454        /*2000:843c*/ 0xff, 0x40,           /* in AL, 040h        */
     455        /*2000:843e*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     456        /*2000:8441*/ 0xff, 0xff,           /* mov cl, al         */
     457        /*2000:8443*/ 0xff, 0xff,           /* in AL, 040h        */
     458        /*2000:8445*/ 0xff, 0xff,           /* mov ch, al         */
     459        /*2000:8447*/ 0xff, 0x00, 0x00,     /* mov si, 01000h     - ignore loop count */
     460        /*2000:844a*/ 0xff, 0xff,           /* xchg bx, bx        */
     461        /*2000:844c*/ 0xff,                 /* dec si             */
     462        /*2000:844d*/ 0xff, 0xfd,           /* jne -003h (0844ch) */
     463        /*2000:844f*/ 0xff, 0xff,           /* mov AL, 000h       */
     464        /*2000:8451*/ 0xff, 0xff,           /* out 043h, AL       */
     465        /*2000:8453*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     466        /*2000:8456*/ 0xff, 0xff,           /* in AL, 040h        */
     467        /*2000:8458*/ 0xff, 0x00, 0x00,     /* call 0808ch        - ignore offset */
     468        /*2000:845b*/ 0xff, 0xff,           /* mov dl, al         */
     469        /*2000:845d*/ 0xff, 0xff,           /* in AL, 040h        */
     470        /*2000:845f*/ 0xff, 0xff,           /* mov dh, al         */
     471        /*2000:8461*/ 0xff,                 /* popfw              */
     472        /*2000:8462*/ 0xff, 0xff,           /* sub bx, cx         */
     473        /*2000:8464*/ 0xff, 0xff,           /* sub cx, dx         */
     474        /*2000:8466*/ 0xff, 0xff,           /* sub cx, bx         */
     475        /*2000:8468*/ 0xff, 0xff,           /* xchg dx, cx        */
     476        /*2000:846a*/ 0xff, 0xff, 0xff,     /* mov ax, 00028h     */
     477        /*2000:846d*/ 0xff, 0xff,           /* imul dx            */
     478        /*2000:846f*/ 0xff, 0xff, 0xff,     /* mov bx, 00018h     */
     479        /*2000:8472*/ 0xff, 0xff,           /* idiv bx            */
     480        /*2000:8474*/ 0xff, 0xff,           /* xor dx, dx         */
     481        /*2000:8476*/ 0xff, 0x00, 0x00,     /* mov bx, 01000h     - ignore loop count */
     482        /*2000:8479*/ 0xff,                 /* xchg bx, ax        */
     483        /*2000:847a*/ 0xff, 0xff,           /* idiv bx            */
     484        /*2000:847c*/ 0xff, 0xff,           /* or dx, dx          */
     485        /*2000:847e*/ 0xff, 0xff,           /* je +001h (08481h)  */
     486        /*2000:8480*/ 0xff,                 /* inc ax             */
     487        /*2000:8481*/ 0xff,                 /* inc ax             */
     488        /*2000:8482*/ 0xff, 0x00, 0x00,     /* mov word [0ac4dh], ax */
     489        /*2000:8485*/ 0xff,                 /* pop DS             */
     490        /*2000:8486*/ 0xff,                 /* popaw              */
     491        /*2000:8487*/ 0xff,                 /* retn               */
     492    };
     493    AssertCompile(sizeof(s_abVariant1Mask) == sizeof(s_abVariant1));
     494
     495    /* uUser1 = off to start injecting code; uUser2 = jump target offset from start of pattern */
     496    static const OS2CODEPATTERN s_aPatterns[] =
     497    {
     498        {  s_abVariant1, s_abVariant1Mask, sizeof(s_abVariant1Mask), 0x840e - 0x840a, 0x8482 - 0x840a, 0, 0, 0 },
     499    };
     500
     501    PCOS2CODEPATTERN pPattern;
     502    uint8_t *pbHit = findCodePattern(&s_aPatterns[0], RT_ELEMENTS(s_aPatterns), pbFile, cbFile, &pPattern);
     503    if (pPattern)
     504    {
     505        uint8_t *pbJmpTarget = &pbHit[pPattern->uUser2];
     506        uint8_t *pbPatch = &pbHit[pPattern->uUser1];
     507        *pbPatch++ = 0xb8;  /* mov ax, 01000h */
     508        *pbPatch++ = 0x00;
     509        *pbPatch++ = 0x10;
     510#if 0
     511        *pbPatch++ = 0xfa; /* cli */
     512        *pbPatch++ = 0xf4; /* hlt */
     513#endif
     514        uint16_t offRel16 = (uint16_t)(pbJmpTarget - &pbPatch[3]);
     515        *pbPatch++ = 0xe9;  /* jmp rel16 */
     516        *pbPatch++ = (uint8_t)offRel16;
     517        *pbPatch++ = (uint8_t)(offRel16 >> 8);
     518        *pbPatch++ = 0xcc;
     519        *pbPatch++ = 0xcc;
     520    }
     521    else
     522        LogRelFunc(("No patch pattern match!\n"));
     523
     524    return VINF_SUCCESS;
     525}
     526
    1074527HRESULT UnattendedOs2Installer::copyFilesToAuxFloppyImage(RTVFS hVfs)
    1075528{
     
    1087540    {
    1088541        bool        fMandatory;
    1089         const char *apszNames[2];
     542        const char *apszNames[2]; /**< Will always copy it over using the first name. */
    1090543        const char *apszDisks[3];
    1091544        const char *pszMinVer;
    1092545        const char *pszMaxVer;
     546        int       (*pfnPatcher)(uint8_t *pbFile, size_t cbFile, const char *pszFilename, UnattendedOs2Installer *pThis);
    1093547    } const s_aFiles[] =
    1094548    {
    1095         { true, { "OS2BOOT",      NULL          }, { "DISK_0", NULL,     NULL }, "2.1",  NULL }, /* 2.0 did not have OS2BOOT */
    1096         { true, { "OS2LDR",       NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1097         { true, { "OS2LDR.MSG",   NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1098         { true, { "OS2KRNL",      "OS2KRNLI"    }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1099         { true, { "OS2DUMP",      NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1100         //
    1101         { true, { "ANSICALL.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1102         { true, { "BKSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1103         { true, { "BMSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1104         { true, { "BVHINIT.DLL",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1105         { true, { "BVSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1106         { true, { "CDFS.IFS",     NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1107         { true, { "CLOCK01.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1108         { true, { "COUNT437.SYS", "COUNTRY.SYS" }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1109         { true, { "DOS.SYS",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1110         { true, { "DOSCALL1.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1111         { true, { "IBM1FLPY.ADD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1112         { true, { "IBM1S506.ADD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1113         { true, { "IBMIDECD.FLT", NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL }, /* not in 2.1 & Warp3  */
    1114         { true, { "IBMKBD.SYS", "KBD01.SYS"/*?*/}, { "DISK_1", "DISK_2", NULL }, NULL,   NULL},
    1115         { true, { "ISAPNP.SNP",   NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL }, /* not in 2.1 */
    1116         { true, { "KBDBASE.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, "3.0",  NULL }, /* not in 2.1 */
    1117         { true, { "KBDCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1118         { true, { "KEYBOARD.DCP", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1119         { true, { "MOUCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1120         { true, { "MSG.DLL",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1121         { true, { "NAMPIPES.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1122         { true, { "NLS.DLL",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1123         { true, { "OS2CDROM.DMD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1124         { true, { "OS2CHAR.DLL",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1125         { true, { "OS2DASD.DMD",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1126         { true, { "OS2LVM.DMD",   NULL          }, { "DISK_1", "DISK_2", NULL }, "4.5",  NULL },
    1127         { true, { "OS2VER",       NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL },
    1128         { true, { "PNP.SYS",      NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL },
    1129         { true, { "QUECALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1130         { true, { "RESOURCE.SYS", NULL          }, { "DISK_1", "DISK_2", NULL }, "3.0",  NULL }, /* not in 2.1*/
    1131         { true, { "SCREEN01.SYS", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1132         { true, { "SESMGR.DLL",   NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1133         { true, { "TESTCFG.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1134         { true, { "VIO437.DCP",   "VTBL850.DCP" }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
    1135         { true, { "VIOCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL },
     549        { true, { "OS2BOOT",      NULL          }, { "DISK_0", NULL,     NULL }, "2.1",  NULL, NULL }, /* 2.0 did not have OS2BOOT */
     550        { true, { "OS2LDR",       NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL, patchOs2Ldr },
     551        { true, { "OS2LDR.MSG",   NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL, NULL },
     552        { true, { "OS2KRNL",      "OS2KRNLI"    }, { "DISK_0", NULL,     NULL }, NULL,   NULL, NULL }, /* OS2KRNLI seems to trigger question for 2nd floppy */
     553        { true, { "OS2DUMP",      NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL, NULL },
     554
     555        { true, { "ANSICALL.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     556        { true, { "BKSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     557        { true, { "BMSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     558        { true, { "BVHINIT.DLL",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     559        { true, { "BVSCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     560        { true, { "CDFS.IFS",     NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     561        { true, { "CLOCK01.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     562        { true, { "COUNT437.SYS", "COUNTRY.SYS" }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     563        { true, { "DOS.SYS",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     564        { true, { "DOSCALL1.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     565        { true, { "IBM1FLPY.ADD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     566        { true, { "IBM1S506.ADD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     567        { true, { "IBMIDECD.FLT", NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL, NULL }, /* not in 2.1 & Warp3  */
     568        { true, { "IBMKBD.SYS", "KBD01.SYS"/*?*/}, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     569#if 1 /* Sometimes takes forever. (Bad IODelay count? Fixed by OS2LDR patching?) Removing seems to cause testcfg.sys to crash. */
     570        { true, { "ISAPNP.SNP",   NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL, NULL }, /* not in 2.1 */
     571#endif
     572        { true, { "KBDBASE.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, "3.0",  NULL, NULL }, /* not in 2.1 */
     573        { true, { "KBDCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     574        { true, { "KEYBOARD.DCP", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     575        { true, { "MOUCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     576        { true, { "MSG.DLL",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     577        { true, { "NAMPIPES.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     578        { true, { "NLS.DLL",      NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     579        { true, { "OS2CDROM.DMD", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     580        { true, { "OS2CHAR.DLL",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     581        { true, { "OS2DASD.DMD",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     582        { true, { "OS2LVM.DMD",   NULL          }, { "DISK_1", "DISK_2", NULL }, "4.5",  NULL, NULL },
     583        { true, { "OS2VER",       NULL          }, { "DISK_0", NULL,     NULL }, NULL,   NULL, NULL },
     584        { true, { "PNP.SYS",      NULL          }, { "DISK_1", "DISK_2", NULL }, "4.0",  NULL, NULL },
     585        { true, { "QUECALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     586        { true, { "RESOURCE.SYS", NULL          }, { "DISK_1", "DISK_2", NULL }, "3.0",  NULL, NULL }, /* not in 2.1*/
     587        { true, { "SCREEN01.SYS", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     588        { true, { "SESMGR.DLL",   NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     589        { true, { "TESTCFG.SYS",  NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     590        { true, { "VIO437.DCP",   "VTBL850.DCP" }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
     591        { true, { "VIOCALLS.DLL", NULL          }, { "DISK_1", "DISK_2", NULL }, NULL,   NULL, NULL },
    1136592    };
    1137593
     
    1164620                        if (RT_SUCCESS(vrc))
    1165621                        {
    1166                             RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(hVfsSrc);
    1167                             RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsDst);
    1168                             vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0);
    1169                             RTVfsIoStrmRelease(hVfsIosDst);
     622                            if (!s_aFiles[i].pfnPatcher)
     623                            {
     624                                /*
     625                                 * Not patching this file, so just pump it thru and close it.
     626                                 */
     627                                RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(hVfsSrc);
     628                                RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsDst);
     629                                vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0);
     630                                RTVfsIoStrmRelease(hVfsIosDst);
     631                                RTVfsIoStrmRelease(hVfsIosSrc);
     632                                if (RT_FAILURE(vrc))
     633                                    hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
     634                                                                 tr("Failed to write %s to the floppy: %Rrc"),
     635                                                                 s_aFiles[i].apszNames, vrc);
     636                            }
     637                            else
     638                            {
     639                                /*
     640                                 * Read the file into memory, do the patching and writed
     641                                 * the patched content to the floppy.
     642                                 */
     643                                uint64_t cbFile = 0;
     644                                vrc = RTVfsFileQuerySize(hVfsSrc, &cbFile);
     645                                if (RT_SUCCESS(vrc) && cbFile < _32M)
     646                                {
     647                                    uint8_t *pbFile = (uint8_t *)RTMemTmpAllocZ((size_t)cbFile);
     648                                    if (pbFile)
     649                                    {
     650                                        vrc = RTVfsFileRead(hVfsSrc, pbFile, (size_t)cbFile, NULL);
     651                                        if (RT_SUCCESS(vrc))
     652                                        {
     653                                            vrc = s_aFiles[i].pfnPatcher(pbFile, (size_t)cbFile, s_aFiles[i].apszNames[0], this);
     654                                            if (RT_SUCCESS(vrc))
     655                                            {
     656                                                vrc = RTVfsFileWrite(hVfsDst, pbFile, (size_t)cbFile, NULL);
     657                                                if (RT_FAILURE(vrc))
     658                                                    hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
     659                                                                                 tr("Failed to write %s to the floppy: %Rrc"),
     660                                                                                 s_aFiles[i].apszNames, vrc);
     661                                            }
     662                                            else
     663                                                hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Patcher failed for '%s': %Rrc"),
     664                                                                             s_aFiles[i].apszNames, vrc);
     665                                        }
     666                                        else
     667                                            hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
     668                                                                         tr("Error reading '%s' into memory for patching: %Rrc"),
     669                                                                         s_aFiles[i].apszNames, vrc);
     670                                        RTMemTmpFree(pbFile);
     671                                    }
     672                                    else
     673                                        hrc = mpParent->setError(E_OUTOFMEMORY, tr("Failed to allocate %zu bytes for '%s'"),
     674                                                                 (size_t)cbFile, s_aFiles[i].apszNames);
     675                                }
     676                                else if (RT_FAILURE(vrc))
     677                                    hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
     678                                                                 tr("Failed to query the size of '%s': %Rrc"),
     679                                                                 s_aFiles[i].apszNames, vrc);
     680                                else
     681                                    hrc = mpParent->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, tr("File too big to patch: '%s'"),
     682                                                                 s_aFiles[i].apszNames);
     683                            }
    1170684                            RTVfsFileRelease(hVfsDst);
    1171                             RTVfsIoStrmRelease(hVfsIosSrc);
    1172                             if (RT_FAILURE(vrc))
    1173                                 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to write %s to the floppy: %Rrc"),
    1174                                                              s_aFiles[i].apszNames, vrc);
    1175685                        }
    1176686                        else
     
    1475985}
    1476986
    1477 
    1478 
    1479 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1480 /*
    1481 *
    1482 *
    1483 *  Implementation UnattendedLinuxInstaller functions
    1484 *
    1485 */
    1486 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1487 HRESULT UnattendedLinuxInstaller::editIsoLinuxCfg(GeneralTextScript *pEditor)
    1488 {
    1489     try
    1490     {
    1491         /* Set timeouts to 10 seconds. */
    1492         std::vector<size_t> vecLineNumbers = pEditor->findTemplate("timeout", RTCString::CaseInsensitive);
    1493         for (size_t i = 0; i < vecLineNumbers.size(); ++i)
    1494             if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("timeout", RTCString::CaseInsensitive))
    1495             {
    1496                 HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), "timeout 10");
    1497                 if (FAILED(hrc))
    1498                     return hrc;
    1499             }
    1500 
    1501         /* Comment out 'display <filename>' directives that's used for displaying files at boot time. */
    1502         vecLineNumbers = pEditor->findTemplate("display", RTCString::CaseInsensitive);
    1503         for (size_t i = 0; i < vecLineNumbers.size(); ++i)
    1504             if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("display", RTCString::CaseInsensitive))
    1505             {
    1506                 HRESULT hrc = pEditor->prependToLine(vecLineNumbers.at(i), "#");
    1507                 if (FAILED(hrc))
    1508                     return hrc;
    1509             }
    1510 
    1511         /* Modify kernel parameters. */
    1512         vecLineNumbers = pEditor->findTemplate("append", RTCString::CaseInsensitive);
    1513         if (vecLineNumbers.size() > 0)
    1514         {
    1515             Utf8Str const &rStrAppend = mpParent->i_getExtraInstallKernelParameters().isNotEmpty()
    1516                                       ? mpParent->i_getExtraInstallKernelParameters()
    1517                                       : mStrDefaultExtraInstallKernelParameters;
    1518 
    1519             for (size_t i = 0; i < vecLineNumbers.size(); ++i)
    1520                 if (pEditor->getContentOfLine(vecLineNumbers[i]).startsWithWord("append", RTCString::CaseInsensitive))
    1521                 {
    1522                     Utf8Str strLine = pEditor->getContentOfLine(vecLineNumbers[i]);
    1523 
    1524                     /* Do removals. */
    1525                     if (mArrStrRemoveInstallKernelParameters.size() > 0)
    1526                     {
    1527                         size_t offStart = strLine.find("append") + 5;
    1528                         while (offStart < strLine.length() && !RT_C_IS_SPACE(strLine[offStart]))
    1529                             offStart++;
    1530                         while (offStart < strLine.length() && RT_C_IS_SPACE(strLine[offStart]))
    1531                             offStart++;
    1532                         if (offStart < strLine.length())
    1533                         {
    1534                             for (size_t iRemove = 0; iRemove < mArrStrRemoveInstallKernelParameters.size(); iRemove++)
    1535                             {
    1536                                 RTCString const &rStrRemove = mArrStrRemoveInstallKernelParameters[iRemove];
    1537                                 for (size_t off = offStart; off < strLine.length(); )
    1538                                 {
    1539                                     Assert(!RT_C_IS_SPACE(strLine[off]));
    1540 
    1541                                     /* Find the end of word. */
    1542                                     size_t offEnd = off + 1;
    1543                                     while (offEnd < strLine.length() && !RT_C_IS_SPACE(strLine[offEnd]))
    1544                                         offEnd++;
    1545 
    1546                                     /* Check if it matches. */
    1547                                     if (RTStrSimplePatternNMatch(rStrRemove.c_str(), rStrRemove.length(),
    1548                                                                  strLine.c_str() + off, offEnd - off))
    1549                                     {
    1550                                         while (off > 0 && RT_C_IS_SPACE(strLine[off - 1]))
    1551                                             off--;
    1552                                         strLine.erase(off, offEnd - off);
    1553                                     }
    1554 
    1555                                     /* Advance to the next word. */
    1556                                     off = offEnd;
    1557                                     while (off < strLine.length() && RT_C_IS_SPACE(strLine[off]))
    1558                                         off++;
    1559                                 }
    1560                             }
    1561                         }
    1562                     }
    1563 
    1564                     /* Do the appending. */
    1565                     if (rStrAppend.isNotEmpty())
    1566                     {
    1567                         if (!rStrAppend.startsWith(" ") && !strLine.endsWith(" "))
    1568                             strLine.append(' ');
    1569                         strLine.append(rStrAppend);
    1570                     }
    1571 
    1572                     /* Update line. */
    1573                     HRESULT hrc = pEditor->setContentOfLine(vecLineNumbers.at(i), strLine);
    1574                     if (FAILED(hrc))
    1575                         return hrc;
    1576                 }
    1577         }
    1578     }
    1579     catch (std::bad_alloc &)
    1580     {
    1581         return E_OUTOFMEMORY;
    1582     }
    1583     return S_OK;
    1584 }
    1585 
    1586 
    1587 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1588 /*
    1589 *
    1590 *
    1591 *  Implementation UnattendedDebianInstaller functions
    1592 *
    1593 */
    1594 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1595 
    1596 /**
    1597  * Helper for checking if a file exists.
    1598  * @todo promote to IPRT?
    1599  */
    1600 static bool hlpVfsFileExists(RTVFS hVfs, const char *pszPath)
    1601 {
    1602     RTFSOBJINFO ObjInfo;
    1603     int vrc = RTVfsQueryPathInfo(hVfs, pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
    1604     return RT_SUCCESS(vrc) && RTFS_IS_FILE(ObjInfo.Attr.fMode);
    1605 }
    1606 
    1607 HRESULT UnattendedDebianInstaller::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
    1608                                                             RTVFS hVfsOrgIso, bool fOverwrite)
    1609 {
    1610     /*
    1611      * The txt.cfg file used to be called isolinux.txt (ubuntu 4.10
    1612      * and possible others).
    1613      */
    1614     /** @todo Ubuntu 4.10 does not work, as we generate too long command lines
    1615      *        and the kernel crashes immediately. */
    1616     const char *pszIsoLinuxTxtCfg = "/isolinux/txt.cfg";
    1617     if (   !hlpVfsFileExists(hVfsOrgIso, pszIsoLinuxTxtCfg)
    1618         && hlpVfsFileExists(hVfsOrgIso, "/isolinux/isolinux.txt"))
    1619         pszIsoLinuxTxtCfg             = "/isolinux/isolinux.txt";
    1620 
    1621     /*
    1622      * VISO bits and filenames.
    1623      */
    1624     RTCString strIsoLinuxCfg;
    1625     RTCString strTxtCfg;
    1626     try
    1627     {
    1628         /* Remaster ISO. */
    1629         rVecArgs.append() = "--no-file-mode";
    1630         rVecArgs.append() = "--no-dir-mode";
    1631 
    1632         rVecArgs.append() = "--import-iso";
    1633         rVecArgs.append(mpParent->i_getIsoPath());
    1634 
    1635         rVecArgs.append() = "--file-mode=0444";
    1636         rVecArgs.append() = "--dir-mode=0555";
    1637 
    1638         /* Remove the two isolinux configure files we'll be replacing. */
    1639         rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
    1640         rVecArgs.append().assign(&pszIsoLinuxTxtCfg[1]).append("=:must-remove:");
    1641 
    1642         /* Add the replacement files. */
    1643         strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
    1644         strIsoLinuxCfg.append("isolinux-isolinux.cfg");
    1645         rVecArgs.append().append("isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
    1646 
    1647         strTxtCfg = mpParent->i_getAuxiliaryBasePath();
    1648         strTxtCfg.append("isolinux-txt.cfg");
    1649         rVecArgs.append().assign(&pszIsoLinuxTxtCfg[1]).append("=").append(strTxtCfg);
    1650     }
    1651     catch (std::bad_alloc &)
    1652     {
    1653         return E_OUTOFMEMORY;
    1654     }
    1655 
    1656     /*
    1657      * Edit the isolinux.cfg file.
    1658      */
    1659     {
    1660         GeneralTextScript Editor(mpParent);
    1661         HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, "/isolinux/isolinux.cfg", &Editor);
    1662         if (SUCCEEDED(hrc))
    1663             hrc = editIsoLinuxCfg(&Editor);
    1664         if (SUCCEEDED(hrc))
    1665         {
    1666             hrc = Editor.save(strIsoLinuxCfg, fOverwrite);
    1667             if (SUCCEEDED(hrc))
    1668             {
    1669                 try
    1670                 {
    1671                     rVecFiles.append(strIsoLinuxCfg);
    1672                 }
    1673                 catch (std::bad_alloc &)
    1674                 {
    1675                     RTFileDelete(strIsoLinuxCfg.c_str());
    1676                     hrc = E_OUTOFMEMORY;
    1677                 }
    1678             }
    1679         }
    1680         if (FAILED(hrc))
    1681             return hrc;
    1682     }
    1683 
    1684     /*
    1685      * Edit the txt.cfg file.
    1686      */
    1687     {
    1688         GeneralTextScript Editor(mpParent);
    1689         HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, pszIsoLinuxTxtCfg, &Editor);
    1690         if (SUCCEEDED(hrc))
    1691             hrc = editDebianTxtCfg(&Editor);
    1692         if (SUCCEEDED(hrc))
    1693         {
    1694             hrc = Editor.save(strTxtCfg, fOverwrite);
    1695             if (SUCCEEDED(hrc))
    1696             {
    1697                 try
    1698                 {
    1699                     rVecFiles.append(strTxtCfg);
    1700                 }
    1701                 catch (std::bad_alloc &)
    1702                 {
    1703                     RTFileDelete(strTxtCfg.c_str());
    1704                     hrc = E_OUTOFMEMORY;
    1705                 }
    1706             }
    1707         }
    1708         if (FAILED(hrc))
    1709             return hrc;
    1710     }
    1711 
    1712     /*
    1713      * Call parent to add the preseed file from mAlg.
    1714      */
    1715     return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
    1716 }
    1717 
    1718 HRESULT UnattendedDebianInstaller::editDebianTxtCfg(GeneralTextScript *pEditor)
    1719 {
    1720     try
    1721     {
    1722         /** @todo r=bird: Add some comments saying wtf you're actually up to here.
    1723          *        Repeating what's clear from function calls and boasting the
    1724          *        inteligence of the code isn't helpful. */
    1725         //find all lines with "label" inside
    1726         std::vector<size_t> vecLineNumbers = pEditor->findTemplate("label", RTCString::CaseInsensitive);
    1727         for (size_t i = 0; i < vecLineNumbers.size(); ++i)
    1728         {
    1729             RTCString const &rContent = pEditor->getContentOfLine(vecLineNumbers[i]);
    1730 
    1731             // ASSUME: suppose general string looks like "label install", two words separated by " ".
    1732             RTCList<RTCString> vecPartsOfcontent = rContent.split(" ");
    1733             if (vecPartsOfcontent.size() > 1 && vecPartsOfcontent[1].contains("install")) /** @todo r=bird: case insensitive? */
    1734             {
    1735                 std::vector<size_t> vecDefaultLineNumbers = pEditor->findTemplate("default", RTCString::CaseInsensitive);
    1736                 //handle the lines more intelligently
    1737                 for (size_t j = 0; j < vecDefaultLineNumbers.size(); ++j)
    1738                 {
    1739                     Utf8Str strNewContent("default ");
    1740                     strNewContent.append(vecPartsOfcontent[1]);
    1741                     HRESULT hrc = pEditor->setContentOfLine(vecDefaultLineNumbers[j], strNewContent);
    1742                     if (FAILED(hrc))
    1743                         return hrc;
    1744                 }
    1745             }
    1746         }
    1747     }
    1748     catch (std::bad_alloc &)
    1749     {
    1750         return E_OUTOFMEMORY;
    1751     }
    1752     return UnattendedLinuxInstaller::editIsoLinuxCfg(pEditor);
    1753 }
    1754 
    1755 
    1756 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1757 /*
    1758 *
    1759 *
    1760 *  Implementation UnattendedRhel6Installer functions
    1761 *
    1762 */
    1763 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1764 HRESULT UnattendedRhel6Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
    1765                                                                RTVFS hVfsOrgIso, bool fOverwrite)
    1766 {
    1767     Utf8Str strIsoLinuxCfg;
    1768     try
    1769     {
    1770 #if 1
    1771         /* Remaster ISO. */
    1772         rVecArgs.append() = "--no-file-mode";
    1773         rVecArgs.append() = "--no-dir-mode";
    1774 
    1775         rVecArgs.append() = "--import-iso";
    1776         rVecArgs.append(mpParent->i_getIsoPath());
    1777 
    1778         rVecArgs.append() = "--file-mode=0444";
    1779         rVecArgs.append() = "--dir-mode=0555";
    1780 
    1781         /* We replace isolinux.cfg with our edited version (see further down). */
    1782         rVecArgs.append() = "isolinux/isolinux.cfg=:must-remove:";
    1783         strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
    1784         strIsoLinuxCfg.append("isolinux-isolinux.cfg");
    1785         rVecArgs.append().append("isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
    1786 
    1787 #else
    1788         /** @todo Maybe we should just remaster the ISO for redhat derivatives too?
    1789          *        One less CDROM to mount. */
    1790         /* Name the ISO. */
    1791         rVecArgs.append() = "--volume-id=VBox Unattended Boot";
    1792 
    1793         /* Copy the isolinux directory from the original install ISO. */
    1794         rVecArgs.append().append("--push-iso=").append(mpParent->i_getIsoPath());
    1795         rVecArgs.append() = "/isolinux=/isolinux";
    1796         rVecArgs.append() = "--pop";
    1797 
    1798         /* We replace isolinux.cfg with our edited version (see further down). */
    1799         rVecArgs.append() = "/isolinux/isolinux.cfg=:must-remove:";
    1800 
    1801         strIsoLinuxCfg = mpParent->i_getAuxiliaryBasePath();
    1802         strIsoLinuxCfg.append("isolinux-isolinux.cfg");
    1803         rVecArgs.append().append("/isolinux/isolinux.cfg=").append(strIsoLinuxCfg);
    1804 
    1805         /* Configure booting /isolinux/isolinux.bin. */
    1806         rVecArgs.append() = "--eltorito-boot";
    1807         rVecArgs.append() = "/isolinux/isolinux.bin";
    1808         rVecArgs.append() = "--no-emulation-boot";
    1809         rVecArgs.append() = "--boot-info-table";
    1810         rVecArgs.append() = "--boot-load-seg=0x07c0";
    1811         rVecArgs.append() = "--boot-load-size=4";
    1812 
    1813         /* Make the boot catalog visible in the file system. */
    1814         rVecArgs.append() = "--boot-catalog=/isolinux/vboxboot.cat";
    1815 #endif
    1816     }
    1817     catch (std::bad_alloc &)
    1818     {
    1819         return E_OUTOFMEMORY;
    1820     }
    1821 
    1822     /*
    1823      * Edit isolinux.cfg and save it.
    1824      */
    1825     {
    1826         GeneralTextScript Editor(mpParent);
    1827         HRESULT hrc = loadAndParseFileFromIso(hVfsOrgIso, "/isolinux/isolinux.cfg", &Editor);
    1828         if (SUCCEEDED(hrc))
    1829             hrc = editIsoLinuxCfg(&Editor);
    1830         if (SUCCEEDED(hrc))
    1831         {
    1832             hrc = Editor.save(strIsoLinuxCfg, fOverwrite);
    1833             if (SUCCEEDED(hrc))
    1834             {
    1835                 try
    1836                 {
    1837                     rVecFiles.append(strIsoLinuxCfg);
    1838                 }
    1839                 catch (std::bad_alloc &)
    1840                 {
    1841                     RTFileDelete(strIsoLinuxCfg.c_str());
    1842                     hrc = E_OUTOFMEMORY;
    1843                 }
    1844             }
    1845         }
    1846         if (FAILED(hrc))
    1847             return hrc;
    1848     }
    1849 
    1850     /*
    1851      * Call parent to add the ks.cfg file from mAlg.
    1852      */
    1853     return UnattendedLinuxInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
    1854 }
    1855 
    1856 
    1857 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1858 /*
    1859 *
    1860 *
    1861 *  Implementation UnattendedSuseInstaller functions
    1862 *
    1863 */
    1864 //////////////////////////////////////////////////////////////////////////////////////////////////////
    1865 #if 0 /* doesn't work, so convert later */
    1866 /*
    1867  *
    1868  * UnattendedSuseInstaller protected methods
    1869  *
    1870 */
    1871 HRESULT UnattendedSuseInstaller::setUserData()
    1872 {
    1873     HRESULT rc = S_OK;
    1874     //here base class function must be called first
    1875     //because user home directory is set after user name
    1876     rc = UnattendedInstaller::setUserData();
    1877 
    1878     rc = mAlg->setField(USERHOMEDIR_ID, "");
    1879     if (FAILED(rc))
    1880         return rc;
    1881 
    1882     return rc;
    1883 }
    1884 
    1885 /*
    1886  *
    1887  * UnattendedSuseInstaller private methods
    1888  *
    1889 */
    1890 
    1891 HRESULT UnattendedSuseInstaller::iv_initialPhase()
    1892 {
    1893     Assert(isAuxiliaryIsoNeeded());
    1894     if (mParent->i_isGuestOs64Bit())
    1895         mFilesAndDirsToExtractFromIso.append("boot/x86_64/loader/ ");
    1896     else
    1897         mFilesAndDirsToExtractFromIso.append("boot/i386/loader/ ");
    1898     return extractOriginalIso(mFilesAndDirsToExtractFromIso);
    1899 }
    1900 
    1901 
    1902 HRESULT UnattendedSuseInstaller::setupScriptOnAuxiliaryCD(const Utf8Str &path)
    1903 {
    1904     HRESULT rc = S_OK;
    1905 
    1906     GeneralTextScript isoSuseCfgScript(mpParent);
    1907     rc = isoSuseCfgScript.read(path);
    1908     rc = isoSuseCfgScript.parse();
    1909     //fix linux core bootable parameters: add path to the preseed script
    1910 
    1911     std::vector<size_t> listOfLines = isoSuseCfgScript.findTemplate("append");
    1912     for(unsigned int i=0; i<listOfLines.size(); ++i)
    1913     {
    1914         isoSuseCfgScript.appendToLine(listOfLines.at(i),
    1915                                       " auto=true priority=critical autoyast=default instmode=cd quiet splash noprompt noshell --");
    1916     }
    1917 
    1918     //find all lines with "label" inside
    1919     listOfLines = isoSuseCfgScript.findTemplate("label");
    1920     for(unsigned int i=0; i<listOfLines.size(); ++i)
    1921     {
    1922         Utf8Str content = isoSuseCfgScript.getContentOfLine(listOfLines.at(i));
    1923 
    1924         //suppose general string looks like "label linux", two words separated by " ".
    1925         RTCList<RTCString> partsOfcontent = content.split(" ");
    1926 
    1927         if (partsOfcontent.at(1).contains("linux"))
    1928         {
    1929             std::vector<size_t> listOfDefault = isoSuseCfgScript.findTemplate("default");
    1930             //handle the lines more intelligently
    1931             for(unsigned int j=0; j<listOfDefault.size(); ++j)
    1932             {
    1933                 Utf8Str newContent("default ");
    1934                 newContent.append(partsOfcontent.at(1));
    1935                 isoSuseCfgScript.setContentOfLine(listOfDefault.at(j), newContent);
    1936             }
    1937         }
    1938     }
    1939 
    1940     rc = isoSuseCfgScript.save(path, true);
    1941 
    1942     LogRelFunc(("UnattendedSuseInstaller::setupScriptsOnAuxiliaryCD(): The file %s has been changed\n", path.c_str()));
    1943 
    1944     return rc;
    1945 }
    1946 #endif
    1947 
Note: See TracChangeset for help on using the changeset viewer.

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