Changeset 93094 in vbox for trunk/src/VBox/Main/src-server
- Timestamp:
- Dec 29, 2021 3:06:13 AM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 149108
- 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 44 44 #endif 45 45 #include <iprt/formats/iso9660.h> 46 #include <iprt/formats/fat.h>47 46 #include <iprt/cpp/path.h> 48 47 … … 851 850 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open '%s' on the ISO '%s' (%Rrc)"), 852 851 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 else884 AssertMsgFailed(("Unknown hint: %s\n", rStr.c_str()));885 }886 }887 888 889 HRESULT UnattendedOs2Installer::replaceAuxFloppyImageBootSector(RTVFSFILE hVfsFile) RT_NOEXCEPT890 {891 /*892 * Find the bootsector. Because the ArcaOS ISOs doesn't contain any floppy893 * images, we cannot just lift it off one of those. Instead we'll locate it894 * in the SYSINSTX.COM utility, i.e. the tool which installs it onto floppies895 * and harddisks. The SYSINSTX.COM utility is a NE executable and we don't896 * 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 signature914 * 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 do921 {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_SIGNATURE950 && ( memcmp(pBpb->achType, "FAT ", sizeof(pBpb->achType)) == 0951 || 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 EBPB972 * 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 else989 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to write bootsector: %Rrc"), vrc);990 }991 else992 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 else997 hrc = mpParent->setErrorBoth(E_FAIL, VERR_NOT_FOUND,998 tr("Unable to locate bootsector template in SYSINSTX.COM"));999 RTVfsFileRelease(hVfsSysInstX);1000 }1001 else1002 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open SYSINSTX.COM: %Rrc"), vrc);1003 }1004 else1005 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 else1023 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 else1045 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to format floppy image '%s': %Rrc"), pszFilename, vrc);1046 RTVfsFileRelease(hVfsFile);1047 RTFileDelete(pszFilename);1048 }1049 else1050 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_NOEXCEPT1056 {1057 if (mVecSplitFiles.size() == 0)1058 {1059 #if 01060 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 #else1068 return splitFile(&mMainScript, mVecSplitFiles);1069 #endif1070 }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 struct1087 {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_NONE1163 | (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 else1177 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 try1206 {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 loaded1219 * 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_NONE1226 | (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 else1234 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 try1254 {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 else1307 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_NOEXCEPT1319 {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 else1332 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 ( !pszTail1340 || pszTail - pszMarker > 641341 || 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 try1355 {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 else1378 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) != 01387 || 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 else1415 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 else1421 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 else1426 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_NOEXCEPT1435 {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 to1449 * thing about calling RTFileReadAllFree in error paths.1450 */1451 hrc = splitFileInner(pszFileToSplit, rVecSplitFiles, (const char *)pvSrc, cbSrc);1452 RTFileReadAllFree(pvSrc, cbSrc);1453 }1454 else1455 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_NOEXCEPT1461 {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 }1474 852 return hrc; 1475 853 } -
trunk/src/VBox/Main/src-server/UnattendedOs2Installer.cpp
r93089 r93094 1 1 /* $Id$ */ 2 2 /** @file 3 * Unattended Installer class and it's descendants implementation3 * UnattendedOs2Installer implementation. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-202 0Oracle Corporation7 * Copyright (C) 2006-2021 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 35 35 #include <iprt/fsisomaker.h> 36 36 #include <iprt/fsvfs.h> 37 #include <iprt/getopt.h>38 37 #include <iprt/file.h> 39 38 #include <iprt/path.h> … … 43 42 # undef ES /* Workaround for someone dragging the namespace pollutor sys/regset.h. Sigh. */ 44 43 #endif 45 #include <iprt/formats/iso9660.h>46 44 #include <iprt/formats/fat.h> 47 45 #include <iprt/cpp/path.h> … … 51 49 52 50 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 else67 pUinstaller = new UnattendedWindowsSifInstaller(pParent);68 }69 else if (enmOsType >= VBOXOSTYPE_OS2 && enmOsType < VBOXOSTYPE_Linux)70 pUinstaller = new UnattendedOs2Installer(pParent, strDetectedOSHints);71 else72 {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 else92 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 else105 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 #endif111 }112 RT_NOREF_PV(strDetectedOSFlavor);113 RT_NOREF_PV(strDetectedOSHints);114 return pUinstaller;115 }116 117 118 //////////////////////////////////////////////////////////////////////////////////////////////////////119 /*120 *121 *122 * Implementation Unattended functions123 *124 */125 //////////////////////////////////////////////////////////////////////////////////////////////////////126 127 /*128 *129 * UnattendedInstaller public methods130 *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 else162 {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 else180 {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 else206 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() const225 {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() const231 {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 #endif236 237 bool UnattendedInstaller::isAuxiliaryIsoNeeded() const238 {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 to252 * 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 else273 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: error reading post install script template file (%Rhrc)\n", hrc));274 }275 else276 LogFlow(("UnattendedInstaller::prepareUnattendedScripts: parse failed (%Rhrc)\n", hrc));277 }278 else279 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 methods311 *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 can340 * 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 else349 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 else369 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 else389 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_ALL410 | (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 else428 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 else437 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 else471 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 else477 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 else483 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 else513 {514 RTCList<RTCString> vecFiles(0);515 RTCList<RTCString> vecArgs(0);516 try517 {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 try599 {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 else631 hrc = mpParent->setErrorBoth(E_FAIL, vrc,632 tr("RTFsIsoMakerAddFileWithVfsFile failed on the script '%s' (%Rrc)"),633 pszDstFilename, vrc);634 }635 else636 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 else659 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_RTVFSIOSTREAM682 && hVfsDstIso != NIL_RTVFSIOSTREAM)683 {684 vrc = RTVfsUtilPumpIoStreams(hVfsSrcIso, hVfsDstIso, 0 /*cbBufHint*/);685 if (RT_SUCCESS(vrc))686 hrc = S_OK;687 else688 hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Error writing auxiliary ISO image '%s' (%Rrc)"),689 pszFilename, vrc);690 }691 else692 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 else698 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 try720 {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 try757 {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 try776 {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 else816 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 else825 RTFileClose(hFile);826 if (RT_SUCCESS(vrc))827 hrc = S_OK;828 else829 hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing '%s' (%Rrc)"), pszFilename, vrc);830 }831 else832 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 else851 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 *********************************************************************************************************************************/861 51 862 52 UnattendedOs2Installer::UnattendedOs2Installer(Unattended *pParent, Utf8Str const &rStrHints) 863 53 : UnattendedInstaller(pParent, 864 "os2_response_files.rsp", "os2_ postinstall.cmd",865 "OS2.RSP", "VBOX POST.CMD",54 "os2_response_files.rsp", "os2_cid_install.cmd", 55 "OS2.RSP", "VBOXCID.CMD", 866 56 DeviceType_Floppy) 867 57 { … … 1072 262 } 1073 263 264 /** 265 * OS/2 code pattern. 266 */ 267 typedef 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. */ 288 typedef 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 */ 296 static 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*/ 343 int 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 1074 527 HRESULT UnattendedOs2Installer::copyFilesToAuxFloppyImage(RTVFS hVfs) 1075 528 { … … 1087 540 { 1088 541 bool fMandatory; 1089 const char *apszNames[2]; 542 const char *apszNames[2]; /**< Will always copy it over using the first name. */ 1090 543 const char *apszDisks[3]; 1091 544 const char *pszMinVer; 1092 545 const char *pszMaxVer; 546 int (*pfnPatcher)(uint8_t *pbFile, size_t cbFile, const char *pszFilename, UnattendedOs2Installer *pThis); 1093 547 } const s_aFiles[] = 1094 548 { 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 }, 1136 592 }; 1137 593 … … 1164 620 if (RT_SUCCESS(vrc)) 1165 621 { 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 } 1170 684 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 685 } 1176 686 else … … 1475 985 } 1476 986 1477 1478 1479 //////////////////////////////////////////////////////////////////////////////////////////////////////1480 /*1481 *1482 *1483 * Implementation UnattendedLinuxInstaller functions1484 *1485 */1486 //////////////////////////////////////////////////////////////////////////////////////////////////////1487 HRESULT UnattendedLinuxInstaller::editIsoLinuxCfg(GeneralTextScript *pEditor)1488 {1489 try1490 {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 functions1592 *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.101612 * and possible others).1613 */1614 /** @todo Ubuntu 4.10 does not work, as we generate too long command lines1615 * 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 try1627 {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 try1670 {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 try1698 {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 try1721 {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 the1724 * inteligence of the code isn't helpful. */1725 //find all lines with "label" inside1726 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 intelligently1737 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 functions1761 *1762 */1763 //////////////////////////////////////////////////////////////////////////////////////////////////////1764 HRESULT UnattendedRhel6Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,1765 RTVFS hVfsOrgIso, bool fOverwrite)1766 {1767 Utf8Str strIsoLinuxCfg;1768 try1769 {1770 #if 11771 /* 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 #else1788 /** @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 #endif1816 }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 try1836 {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 functions1862 *1863 */1864 //////////////////////////////////////////////////////////////////////////////////////////////////////1865 #if 0 /* doesn't work, so convert later */1866 /*1867 *1868 * UnattendedSuseInstaller protected methods1869 *1870 */1871 HRESULT UnattendedSuseInstaller::setUserData()1872 {1873 HRESULT rc = S_OK;1874 //here base class function must be called first1875 //because user home directory is set after user name1876 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 methods1888 *1889 */1890 1891 HRESULT UnattendedSuseInstaller::iv_initialPhase()1892 {1893 Assert(isAuxiliaryIsoNeeded());1894 if (mParent->i_isGuestOs64Bit())1895 mFilesAndDirsToExtractFromIso.append("boot/x86_64/loader/ ");1896 else1897 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 script1910 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" inside1919 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 intelligently1931 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 #endif1947
Note:
See TracChangeset
for help on using the changeset viewer.