- Timestamp:
- Jan 11, 2022 11:22:13 PM (3 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/MachineImpl.h
r93115 r93190 46 46 # include "Performance.h" 47 47 # include "PerformanceImpl.h" 48 # include "ThreadTask.h"49 48 #endif 49 #include "ThreadTask.h" 50 50 51 51 // generated header -
trunk/src/VBox/Main/include/UnattendedScript.h
r93115 r93190 23 23 24 24 #include "TextScript.h" 25 #include "iprt/expreval.h" 25 26 26 27 using namespace xml; … … 52 53 53 54 protected: 55 typedef enum 56 { 57 kValueEscaping_None, 58 kValueEscaping_Bourne, 59 kValueEscaping_XML_Element, 60 kValueEscaping_XML_Attribute_Double_Quotes 61 } kEvalEscaping_T; 62 54 63 /** 55 64 * Gets the replacement value for the given placeholder. … … 65 74 66 75 /** 67 * Overridable worker for getReplacement. 76 * Gets the replacement value for the given expression placeholder 77 * (@@VBOX_INSERT[expr]@@ and friends). 68 78 * 69 79 * @returns COM status code. 70 * @param pachPlaceholder The placholder string. Not zero terminated. 71 * @param cchPlaceholder The length of the placeholder. 72 * @param cchFullPlaceholder The full placeholder length, including suffixes 73 * indicating how it should be escaped (for error 74 * messages). 75 * @param fOutputting Indicates whether we actually need the correct 76 * value or is just syntax checking excluded 77 * template parts. Intended for voiding triggering 78 * sanity checks regarding which replacements 79 * should be used and not (e.g. no Guest Additions 80 * path when installing GAs aren't enabled). 81 * @param rValue Where to return the value. 80 * @param hEvaluator The evaluator to use for the expression. 81 * @param pachPlaceholder The placholder string. Not zero terminated. 82 * @param cchPlaceholder The length of the placeholder. 83 * @param fOutputting Indicates whether we actually need the correct value 84 * or is just syntax checking excluded template parts. 85 * @param ppszValue Where to return the value. Free by calling 86 * RTStrFree. Set to NULL for empty string. 87 */ 88 HRESULT getReplacementForExpr(RTEXPREVAL hEvaluator, const char *pachPlaceholder, size_t cchPlaceholder, 89 bool fOutputting, char **ppszValue) RT_NOEXCEPT; 90 91 /** 92 * Resolves a conditional expression. 93 * 94 * @returns COM status code. 95 * @param hEvaluator The evaluator to use for the expression. 96 * @param pachPlaceholder The placholder string. Not zero terminated. 97 * @param cchPlaceholder The length of the placeholder. 98 * @param pfOutputting Where to return the result of the conditional. This 99 * holds the current outputting state on input in case 100 * someone want to sanity check anything. 101 */ 102 HRESULT resolveConditionalExpr(RTEXPREVAL hEvaluator, const char *pachPlaceholder, size_t cchPlaceholder, 103 bool *pfOutputting) RT_NOEXCEPT; 104 105 /** @impl_callback_method{FNRTEXPREVALQUERYVARIABLE} */ 106 static DECLCALLBACK(int) queryVariableForExpr(const char *pchName, size_t cchName, void *pvUser, 107 char **ppszValue) RT_NOEXCEPT; 108 109 /** 110 * Gets a variable. 111 * 112 * This is used both for getting replacements (@@VBOX_INSERT_XXX@@) and in 113 * expressions (@@VBOX_INSERT[expr]@@, @@VBOX_COND[expr]@@). 114 * 115 * @returns VBox status code. 116 * @retval VERR_NOT_FOUND if variable does not exist. 117 * 118 * @param pchName The variable name. Not zero terminated. 119 * @param cchName The length of the name. 120 * @param rstrTmp String object that can be used for keeping the 121 * value returned via @a *ppszValue. 122 * @param ppszValue If a value is desired, this is where to return 123 * it. This points to a string that should be 124 * accessible for a little while after the function 125 * returns. Use @a rstrTmp for storage if 126 * necessary. 127 * 128 * This will be NULL when called from the 'defined' 129 * operator. In which case no errors should be 130 * set. 82 131 * @throws std::bad_alloc 132 * @see FNRTEXPREVALQUERYVARIABLE 83 133 */ 84 virtual HRESULT getUnescapedReplacement(const char *pachPlaceholder, size_t cchPlaceholder, 85 size_t cchFullPlaceholder, bool fOutputting, RTCString &rValue); 86 134 virtual int queryVariable(const char *pchName, size_t cchName, Utf8Str &rstrTmp, const char **ppszValue); 87 135 88 136 /** … … 97 145 */ 98 146 virtual HRESULT getConditional(const char *pachPlaceholder, size_t cchPlaceholder, bool *pfOutputting); 99 100 147 }; 101 148 -
trunk/src/VBox/Main/src-server/UnattendedScript.cpp
r93121 r93190 29 29 #include "UnattendedImpl.h" 30 30 31 #include <iprt/err core.h>31 #include <iprt/err.h> 32 32 33 33 #include <iprt/ctype.h> … … 43 43 44 44 /********************************************************************************************************************************* 45 * Defined Constants And Macros * 46 *********************************************************************************************************************************/ 47 static const char g_szPrefix[] = "@@VBOX_"; 48 static const char g_szPrefixInsert[] = "@@VBOX_INSERT"; 49 static const char g_szPrefixInsertXxx[] = "@@VBOX_INSERT_"; 50 static const char g_szPrefixInsertExpr[] = "@@VBOX_INSERT["; 51 static const char g_szPrefixCond[] = "@@VBOX_COND"; 52 static const char g_szPrefixCondXxx[] = "@@VBOX_COND_"; 53 static const char g_szPrefixCondExpr[] = "@@VBOX_COND["; 54 static const char g_szPrefixCondElse[] = "@@VBOX_COND_ELSE@@"; 55 static const char g_szPrefixCondEnd[] = "@@VBOX_COND_END@@"; 56 static const char g_szPrefixSplitter[] = "@@VBOX_SPLITTER"; 57 58 59 /********************************************************************************************************************************* 45 60 * UnattendedScriptTemplate Implementation * 46 61 *********************************************************************************************************************************/ … … 52 67 } 53 68 54 55 69 HRESULT UnattendedScriptTemplate::saveToString(Utf8Str &rStrDst) 56 70 { 57 static const char s_szPrefix[] = "@@VBOX_"; 58 static const char s_szPrefixInsert[] = "@@VBOX_INSERT_"; 59 static const char s_szPrefixCond[] = "@@VBOX_COND_"; 60 static const char s_szPrefixCondElse[] = "@@VBOX_COND_ELSE@@"; 61 static const char s_szPrefixCondEnd[] = "@@VBOX_COND_END@@"; 62 static const char s_szPrefixSplitter[] = "@@VBOX_SPLITTER"; 71 RTEXPREVAL hEvaluator = NIL_RTEXPREVAL; 72 int vrc = RTExprEvalCreate(&hEvaluator, 0, "unattended", this, UnattendedScriptTemplate::queryVariableForExpr); 73 AssertRCReturn(vrc, mpSetError->setErrorVrc(vrc)); 63 74 64 75 struct … … 77 88 * Find the next placeholder and add any text before it to the output. 78 89 */ 79 size_t offPlaceholder = mStrScriptFullContent.find( s_szPrefix, offTemplate);90 size_t offPlaceholder = mStrScriptFullContent.find(g_szPrefix, offTemplate); 80 91 size_t cchToCopy = offPlaceholder != RTCString::npos ? offPlaceholder - offTemplate : cchTemplate - offTemplate; 81 92 if (cchToCopy > 0) … … 104 115 * First we must find the end of the placeholder string. 105 116 */ 106 const char *pszPlaceholder = mStrScriptFullContent.c_str() + offPlaceholder; 107 size_t cchPlaceholder = sizeof(s_szPrefix) - 1; 108 char ch; 117 size_t const cchMaxPlaceholder = RT_MIN(cchTemplate - offPlaceholder, _1K); 118 const char *pszPlaceholder = mStrScriptFullContent.c_str() + offPlaceholder; 119 size_t cchPlaceholder = sizeof(g_szPrefix) - 1; 120 char ch; 109 121 while ( offPlaceholder + cchPlaceholder < cchTemplate 110 122 && (ch = pszPlaceholder[cchPlaceholder]) != '\0' 111 && ( ch == '_' 112 || ch == '[' 113 || ch == ']' 114 || ch == '.' 115 || ch == '>' 116 || ch == '<' 117 || RT_C_IS_UPPER(ch) 118 || RT_C_IS_DIGIT(ch)) ) 123 && (RT_C_IS_PRINT(ch) || RT_C_IS_SPACE(ch)) 124 && ch != '@') 119 125 cchPlaceholder++; 120 126 … … 130 136 if ( pszPlaceholder[cchPlaceholder - 1] != '@' 131 137 || pszPlaceholder[cchPlaceholder - 2] != '@' 132 || ( strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1)!= 0133 && strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1)!= 0134 && strncmp(pszPlaceholder, s_szPrefixSplitter, sizeof(s_szPrefixSplitter) - 1) != 0 ) )135 { 136 hrc = mpSetError->setError(E_FAIL, tr("Malformed template placeholder '%.*s'"),138 || ( strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixInsert)) != 0 139 && strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixCond)) != 0 140 && strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixSplitter)) != 0 ) ) 141 { 142 hrc = mpSetError->setError(E_FAIL, tr("Malformed or too long template placeholder '%.*s'"), 137 143 cchPlaceholder, pszPlaceholder); 138 144 break; … … 144 150 * @@VBOX_INSERT_XXX@@: 145 151 */ 146 if ( strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) == 0)152 if (strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixInsertXxx)) == 0) 147 153 { 148 154 /* … … 170 176 } 171 177 /* 178 * @@VBOX_INSERT[expr]@@: 179 * @@VBOX_INSERT[expr]SH@@: 180 * @@VBOX_INSERT[expr]ELEMENT@@: 181 * @@VBOX_INSERT[expr]ATTRIB_DQ@@: 182 */ 183 else if (strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixInsertExpr)) == 0) 184 { 185 /* 186 * Get the placeholder value and add it to the output. 187 */ 188 char *pszValue = NULL; 189 hrc = getReplacementForExpr(hEvaluator, pszPlaceholder, cchPlaceholder, fOutputting, &pszValue); 190 if (SUCCEEDED(hrc)) 191 { 192 if (fOutputting && pszValue) 193 { 194 try 195 { 196 rStrDst.append(pszValue); 197 } 198 catch (std::bad_alloc &) 199 { 200 hrc = E_OUTOFMEMORY; 201 break; 202 } 203 } 204 RTStrFree(pszValue); 205 } 206 else 207 break; 208 } 209 /* 172 210 * @@VBOX_COND_END@@: Pop one item of the conditional stack. 173 211 */ 174 else if ( strncmp(pszPlaceholder, s_szPrefixCondEnd, sizeof(s_szPrefixCondEnd) - 1U) == 0)212 else if (strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixCondEnd)) == 0) 175 213 { 176 214 if (cConds > 0) … … 183 221 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, 184 222 tr("%s without @@VBOX_COND_XXX@@ at offset %zu (%#zx)"), 185 s_szPrefixCondEnd, offPlaceholder, offPlaceholder);223 g_szPrefixCondEnd, offPlaceholder, offPlaceholder); 186 224 break; 187 225 } … … 190 228 * @@VBOX_COND_ELSE@@: Flip the output setting of the current condition. 191 229 */ 192 else if ( strncmp(pszPlaceholder, s_szPrefixCondElse, sizeof(s_szPrefixCondElse) - 1U) == 0)230 else if (strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixCondElse)) == 0) 193 231 { 194 232 if (cConds > 0) … … 198 236 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, 199 237 tr("%s without @@VBOX_COND_XXX@@ at offset %zu (%#zx)"), 200 s_szPrefixCondElse, offPlaceholder, offPlaceholder);238 g_szPrefixCondElse, offPlaceholder, offPlaceholder); 201 239 break; 202 240 } … … 206 244 * one from the condition. 207 245 */ 208 else if (strncmp(pszPlaceholder, s_szPrefixSplitter, sizeof(s_szPrefixSplitter) - 1) != 0) 209 { 210 Assert(strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) == 0); 246 else if (strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixCondXxx)) == 0) 247 { 211 248 if (cConds + 1 < RT_ELEMENTS(aConds)) 212 249 { … … 229 266 } 230 267 /* 268 * @@VBOX_COND[expr]@@: Push the previous outputting state and combine it with the 269 * one from the condition. 270 */ 271 else if (strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixCondExpr)) == 0) 272 { 273 if (cConds + 1 < RT_ELEMENTS(aConds)) 274 { 275 aConds[cConds].fSavedOutputting = fOutputting; 276 bool fNewOutputting = fOutputting; 277 hrc = resolveConditionalExpr(hEvaluator, pszPlaceholder, cchPlaceholder, &fNewOutputting); 278 if (SUCCEEDED(hrc)) 279 fOutputting = fOutputting && fNewOutputting; 280 else 281 break; 282 cConds++; 283 } 284 else 285 { 286 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, 287 tr("Too deep conditional nesting at offset %zu (%#zx)"), 288 offPlaceholder, offPlaceholder); 289 break; 290 } 291 } 292 /* 231 293 * @@VBOX_SPLITTER_START/END[filename]@@: Ignored in this pass. 232 294 */ 233 295 else 234 296 { 297 Assert(strncmp(pszPlaceholder, RT_STR_TUPLE(g_szPrefixSplitter)) == 0); 235 298 if (fOutputting) 236 299 { … … 265 328 /* failed */ 266 329 rStrDst.setNull(); 330 RTExprEvalRelease(hEvaluator); 267 331 return hrc; 268 332 } … … 274 338 * Check for an escaping suffix. Drop the '@@'. 275 339 */ 276 size_t const cchFullPlaceholder = cchPlaceholder; 277 enum 278 { 279 kValueEscaping_None, 280 kValueEscaping_Bourne, 281 kValueEscaping_XML_Element, 282 kValueEscaping_XML_Attribute_Double_Quotes 283 } enmEscaping; 284 340 size_t const cchFullPlaceholder = cchPlaceholder; 341 kEvalEscaping_T enmEscaping; 285 342 #define PLACEHOLDER_ENDS_WITH(a_szSuffix) \ 286 343 ( cchPlaceholder > sizeof(a_szSuffix) - 1U \ … … 307 364 enmEscaping = kValueEscaping_None; 308 365 } 366 #undef PLACEHOLDER_ENDS_WITH 309 367 310 368 /* … … 314 372 try 315 373 { 316 switch (enmEscaping) 317 { 318 case kValueEscaping_None: 319 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, rValue); 320 if (SUCCEEDED(hrc)) 321 return hrc; 322 break; 323 324 case kValueEscaping_Bourne: 325 case kValueEscaping_XML_Element: 326 case kValueEscaping_XML_Attribute_Double_Quotes: 327 { 328 RTCString strUnescaped; 329 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, strUnescaped); 330 if (SUCCEEDED(hrc)) 331 { 332 switch (enmEscaping) 374 Utf8Str strTmp; 375 const char *pszReadOnlyValue = NULL; 376 int vrc = queryVariable(pachPlaceholder + sizeof(g_szPrefixInsertXxx) - 1, 377 cchPlaceholder - sizeof(g_szPrefixInsertXxx) + 1, 378 strTmp, fOutputting ? &pszReadOnlyValue : NULL); 379 if (RT_SUCCESS(vrc)) 380 { 381 if (fOutputting) 382 { 383 Assert(pszReadOnlyValue != NULL); 384 switch (enmEscaping) 385 { 386 case kValueEscaping_None: 387 rValue = pszReadOnlyValue; 388 return S_OK; 389 390 case kValueEscaping_Bourne: 391 case kValueEscaping_XML_Element: 392 case kValueEscaping_XML_Attribute_Double_Quotes: 333 393 { 334 case kValueEscaping_Bourne:394 switch (enmEscaping) 335 395 { 336 const char * const papszArgs[2] = { strUnescaped.c_str(), NULL }; 337 char *pszEscaped = NULL; 338 int vrc = RTGetOptArgvToString(&pszEscaped, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); 339 if (RT_SUCCESS(vrc)) 396 case kValueEscaping_Bourne: 340 397 { 341 try 398 const char * const papszArgs[2] = { pszReadOnlyValue, NULL }; 399 char *pszEscaped = NULL; 400 vrc = RTGetOptArgvToString(&pszEscaped, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); 401 if (RT_SUCCESS(vrc)) 342 402 { 343 rValue = pszEscaped; 403 try 404 { 405 rValue = pszEscaped; 406 RTStrFree(pszEscaped); 407 return S_OK; 408 } 409 catch (std::bad_alloc &) 410 { 411 hrc = E_OUTOFMEMORY; 412 } 344 413 RTStrFree(pszEscaped); 345 return S_OK;346 414 } 347 catch (std::bad_alloc &) 348 { 349 hrc = E_OUTOFMEMORY; 350 } 351 RTStrFree(pszEscaped); 415 else 416 hrc = mpSetError->setErrorVrc(vrc); 417 break; 352 418 } 353 break; 419 420 case kValueEscaping_XML_Element: 421 rValue.printf("%RMes", pszReadOnlyValue); 422 return S_OK; 423 424 case kValueEscaping_XML_Attribute_Double_Quotes: 425 { 426 RTCString strTmp2; 427 strTmp2.printf("%RMas", pszReadOnlyValue); 428 rValue = RTCString(strTmp2, 1, strTmp2.length() - 2); 429 return S_OK; 430 } 431 432 default: 433 hrc = E_FAIL; 434 break; 354 435 } 355 356 case kValueEscaping_XML_Element: 357 rValue.printf("%RMes", strUnescaped.c_str()); 358 return S_OK; 359 360 case kValueEscaping_XML_Attribute_Double_Quotes: 361 { 362 RTCString strTmp; 363 strTmp.printf("%RMas", strUnescaped.c_str()); 364 rValue = RTCString(strTmp, 1, strTmp.length() - 2); 365 return S_OK; 366 } 367 368 default: 369 hrc = E_FAIL; 370 break; 436 break; 371 437 } 372 } 373 break; 374 } 375 376 default: 377 AssertFailedStmt(hrc = E_FAIL); 378 break; 379 } 438 439 default: 440 AssertFailedStmt(hrc = E_FAIL); 441 break; 442 } 443 } 444 else 445 hrc = S_OK; 446 } 447 else 448 hrc = E_FAIL; 380 449 } 381 450 catch (std::bad_alloc &) … … 387 456 } 388 457 389 HRESULT UnattendedScriptTemplate::getUnescapedReplacement(const char *pachPlaceholder, size_t cchPlaceholder, 390 size_t cchFullPlaceholder, bool fOutputting, RTCString &rValue) 391 { 392 RT_NOREF(fOutputting); 393 #define IS_PLACEHOLDER_MATCH(a_szMatch) \ 394 ( cchPlaceholder == sizeof("@@VBOX_INSERT_" a_szMatch) - 1U \ 395 && memcmp(pachPlaceholder, "@@VBOX_INSERT_" a_szMatch, sizeof("@@VBOX_INSERT_" a_szMatch) - 1U) == 0) 396 397 if (IS_PLACEHOLDER_MATCH("USER_LOGIN")) 398 rValue = mpUnattended->i_getUser(); 399 else if (IS_PLACEHOLDER_MATCH("USER_PASSWORD")) 400 rValue = mpUnattended->i_getPassword(); 401 else if (IS_PLACEHOLDER_MATCH("ROOT_PASSWORD")) 402 rValue = mpUnattended->i_getPassword(); 403 else if (IS_PLACEHOLDER_MATCH("USER_FULL_NAME")) 404 rValue = mpUnattended->i_getFullUserName(); 405 else if (IS_PLACEHOLDER_MATCH("PRODUCT_KEY")) 406 rValue = mpUnattended->i_getProductKey(); 407 else if (IS_PLACEHOLDER_MATCH("POST_INSTALL_COMMAND")) 408 rValue = mpUnattended->i_getPostInstallCommand(); 409 else if (IS_PLACEHOLDER_MATCH("AUXILIARY_INSTALL_DIR")) 410 rValue = mpUnattended->i_getAuxiliaryInstallDir(); 411 else if (IS_PLACEHOLDER_MATCH("IMAGE_INDEX")) 412 rValue.printf("%u", mpUnattended->i_getImageIndex()); 413 else if (IS_PLACEHOLDER_MATCH("OS_ARCH")) 414 rValue = mpUnattended->i_isGuestOs64Bit() ? "amd64" : "x86"; 415 else if (IS_PLACEHOLDER_MATCH("OS_ARCH2")) 416 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "x86"; 417 else if (IS_PLACEHOLDER_MATCH("OS_ARCH3")) 418 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i386"; 419 else if (IS_PLACEHOLDER_MATCH("OS_ARCH4")) 420 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i486"; 421 else if (IS_PLACEHOLDER_MATCH("OS_ARCH6")) 422 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i686"; 423 else if (IS_PLACEHOLDER_MATCH("GUEST_OS_VERSION")) 424 rValue = mpUnattended->i_getDetectedOSVersion(); 425 else if (IS_PLACEHOLDER_MATCH("GUEST_OS_MAJOR_VERSION")) 426 { 427 Utf8Str strOsVer(mpUnattended->i_getDetectedOSVersion()); 428 RTCList<RTCString> partList = strOsVer.split("."); 429 if (partList.size() < 1) 430 { 431 rValue.setNull(); 432 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("Unknown guest OS major version '%s'"), 433 partList.at(0).c_str()); 434 } 435 rValue = partList.at(0); 436 } 437 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_UX")) 438 rValue = mpUnattended->i_getTimeZoneInfo() 439 ? mpUnattended->i_getTimeZoneInfo()->pszUnixName : mpUnattended->i_getTimeZone(); 440 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_NAME")) 458 HRESULT UnattendedScriptTemplate::getReplacementForExpr(RTEXPREVAL hEvaluator, const char *pachPlaceholder, size_t cchPlaceholder, 459 bool fOutputting, char **ppszValue) RT_NOEXCEPT 460 { 461 /* 462 * Process the tail of the placeholder to figure out the escaping rules. 463 * 464 * @@VBOX_INSERT[expr]@@: 465 * @@VBOX_INSERT[expr]SH@@: 466 * @@VBOX_INSERT[expr]ELEMENT@@: 467 * @@VBOX_INSERT[expr]ATTRIB_DQ@@: 468 */ 469 size_t const cchFullPlaceholder = cchPlaceholder; 470 kEvalEscaping_T enmEscaping; 471 #define PLACEHOLDER_ENDS_WITH(a_szSuffix) \ 472 ( cchPlaceholder > sizeof(a_szSuffix) - 1U \ 473 && memcmp(&pachPlaceholder[cchPlaceholder - sizeof(a_szSuffix) + 1U], a_szSuffix, sizeof(a_szSuffix) - 1U) == 0) 474 if (PLACEHOLDER_ENDS_WITH("]SH@@")) 475 { 476 cchPlaceholder -= sizeof("]SH@@") - 1; 477 enmEscaping = kValueEscaping_Bourne; 478 } 479 else if (PLACEHOLDER_ENDS_WITH("]ELEMENT@@")) 480 { 481 cchPlaceholder -= sizeof("]ELEMENT@@") - 1; 482 enmEscaping = kValueEscaping_XML_Element; 483 } 484 else if (PLACEHOLDER_ENDS_WITH("]ATTRIB_DQ@@")) 485 { 486 cchPlaceholder -= sizeof("]ATTRIB_DQ@@") - 1; 487 enmEscaping = kValueEscaping_XML_Attribute_Double_Quotes; 488 } 489 else if (PLACEHOLDER_ENDS_WITH("]@@")) 490 { 491 cchPlaceholder -= sizeof("]@@") - 1; 492 enmEscaping = kValueEscaping_None; 493 } 494 else 495 return mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, tr("Malformed @@VBOX_INSERT[expr]@@: Missing ']' (%.*s)"), 496 cchPlaceholder, pachPlaceholder); 497 #undef PLACEHOLDER_ENDS_WITH 498 499 /* The placeholder prefix length. The expression is from cchPrefix to cchPlaceholder. */ 500 size_t const cchPrefix = sizeof(g_szPrefixInsertExpr) - 1; 501 Assert(pachPlaceholder[cchPrefix - 1] == '['); 502 503 /* 504 * Evaluate the expression. We do this regardless of fOutput for now. 505 */ 506 RTERRINFOSTATIC ErrInfo; 507 char *pszValue = NULL; 508 int vrc = RTExprEvalToString(hEvaluator, &pachPlaceholder[cchPrefix], cchPlaceholder - cchPrefix, &pszValue, 509 RTErrInfoInitStatic(&ErrInfo)); 510 LogFlowFunc(("RTExprEvalToString(%.*s) -> %Rrc pszValue=%s\n", 511 cchPlaceholder - cchPrefix, &pachPlaceholder[cchPrefix], vrc, pszValue)); 512 if (RT_SUCCESS(vrc)) 513 { 514 if (fOutputting) 515 { 516 switch (enmEscaping) 517 { 518 case kValueEscaping_None: 519 *ppszValue = pszValue; 520 pszValue = NULL; 521 break; 522 523 case kValueEscaping_Bourne: 524 { 525 const char * const papszArgs[2] = { pszValue, NULL }; 526 vrc = RTGetOptArgvToString(ppszValue, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH); 527 break; 528 } 529 530 case kValueEscaping_XML_Element: 531 vrc = RTStrAPrintf(ppszValue, "%RMes", pszValue); 532 break; 533 534 case kValueEscaping_XML_Attribute_Double_Quotes: 535 vrc = RTStrAPrintf(ppszValue, "%RMas", pszValue); 536 if (RT_SUCCESS(vrc)) 537 { 538 /* drop the quotes */ 539 char *pszRet = *ppszValue; 540 size_t const cchRet = strlen(pszRet) - 2; 541 memmove(pszRet, &pszRet[1], cchRet); 542 pszRet[cchRet] = '\0'; 543 } 544 break; 545 546 default: 547 AssertFailedStmt(vrc = VERR_IPE_NOT_REACHED_DEFAULT_CASE); 548 break; 549 } 550 RTStrFree(pszValue); 551 if (RT_FAILURE(vrc)) 552 return mpSetError->setErrorVrc(vrc); 553 } 554 else 555 { 556 *ppszValue = NULL; 557 RTStrFree(pszValue); 558 } 559 } 560 else 561 return mpSetError->setErrorBoth(E_FAIL, vrc, tr("Expression evaluation error for '%.*s': %#RTeic"), 562 cchPlaceholder, pachPlaceholder, &ErrInfo.Core); 563 return S_OK; 564 } 565 566 HRESULT UnattendedScriptTemplate::resolveConditionalExpr(RTEXPREVAL hEvaluator, const char *pachPlaceholder, 567 size_t cchPlaceholder, bool *pfOutputting) RT_NOEXCEPT 568 { 569 /* 570 * Check the placeholder tail: @@VBOX_COND[expr]@@ 571 */ 572 static const char s_szTail[] = "]@@"; 573 if (memcmp(&pachPlaceholder[cchPlaceholder - sizeof(s_szTail) + 1], RT_STR_TUPLE(s_szTail)) != 0) 574 return mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, tr("Malformed @@VBOX_COND[expr]@@: Missing ']' (%.*s)"), 575 cchPlaceholder, pachPlaceholder); 576 Assert(pachPlaceholder[sizeof(g_szPrefixCondExpr) - 2 ] == '['); 577 578 /* 579 * Evaluate the expression. 580 */ 581 RTERRINFOSTATIC ErrInfo; 582 const char * const pchExpr = &pachPlaceholder[sizeof(g_szPrefixCondExpr) - 1]; 583 size_t const cchExpr = cchPlaceholder - sizeof(g_szPrefixCondExpr) + 1 - sizeof(s_szTail) + 1; 584 int vrc = RTExprEvalToBool(hEvaluator, pchExpr, cchExpr, pfOutputting, RTErrInfoInitStatic(&ErrInfo)); 585 LogFlowFunc(("RTExprEvalToBool(%.*s) -> %Rrc *pfOutputting=%s\n", cchExpr, pchExpr, vrc, *pfOutputting)); 586 if (RT_SUCCESS(vrc)) 587 return S_OK; 588 return mpSetError->setErrorBoth(E_FAIL, vrc, tr("Expression evaluation error for '%.*s': %#RTeic"), 589 cchPlaceholder, pachPlaceholder, &ErrInfo.Core); 590 } 591 592 /*static */ DECLCALLBACK(int) 593 UnattendedScriptTemplate::queryVariableForExpr(const char *pchName, size_t cchName, void *pvUser, char **ppszValue) 594 { 595 UnattendedScriptTemplate *pThis = (UnattendedScriptTemplate *)pvUser; 596 int vrc; 597 try 598 { 599 const char *pszReadOnlyValue = NULL; 600 Utf8Str strTmp; 601 vrc = pThis->queryVariable(pchName, cchName, strTmp, ppszValue ? &pszReadOnlyValue : NULL); 602 if (ppszValue) 603 { 604 if (RT_SUCCESS(vrc)) 605 vrc = RTStrDupEx(ppszValue, pszReadOnlyValue); 606 else 607 *ppszValue = NULL; 608 } 609 } 610 catch (std::bad_alloc &) 611 { 612 vrc = VERR_NO_MEMORY; 613 *ppszValue = NULL; 614 } 615 return vrc; 616 } 617 618 int UnattendedScriptTemplate::queryVariable(const char *pchName, size_t cchName, Utf8Str &rstrTmp, const char **ppszValue) 619 { 620 #define IS_MATCH(a_szMatch) \ 621 (cchName == sizeof(a_szMatch) - 1U && memcmp(pchName, a_szMatch, sizeof(a_szMatch) - 1U) == 0) 622 623 const char *pszValue; 624 625 /* 626 * Variables 627 */ 628 if (IS_MATCH("USER_LOGIN")) 629 pszValue = mpUnattended->i_getUser().c_str(); 630 else if (IS_MATCH("USER_PASSWORD")) 631 pszValue = mpUnattended->i_getPassword().c_str(); 632 else if (IS_MATCH("ROOT_PASSWORD")) 633 pszValue = mpUnattended->i_getPassword().c_str(); 634 else if (IS_MATCH("USER_FULL_NAME")) 635 pszValue = mpUnattended->i_getFullUserName().c_str(); 636 else if (IS_MATCH("PRODUCT_KEY")) 637 pszValue = mpUnattended->i_getProductKey().c_str(); 638 else if (IS_MATCH("POST_INSTALL_COMMAND")) 639 pszValue = mpUnattended->i_getPostInstallCommand().c_str(); 640 else if (IS_MATCH("AUXILIARY_INSTALL_DIR")) 641 pszValue = mpUnattended->i_getAuxiliaryInstallDir().c_str(); 642 else if (IS_MATCH("IMAGE_INDEX")) 643 pszValue = rstrTmp.printf("%u", mpUnattended->i_getImageIndex()).c_str(); 644 else if (IS_MATCH("OS_ARCH")) 645 pszValue = mpUnattended->i_isGuestOs64Bit() ? "amd64" : "x86"; 646 else if (IS_MATCH("OS_ARCH2")) 647 pszValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "x86"; 648 else if (IS_MATCH("OS_ARCH3")) 649 pszValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i386"; 650 else if (IS_MATCH("OS_ARCH4")) 651 pszValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i486"; 652 else if (IS_MATCH("OS_ARCH6")) 653 pszValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i686"; 654 else if (IS_MATCH("GUEST_OS_VERSION")) 655 pszValue = mpUnattended->i_getDetectedOSVersion().c_str(); 656 else if (IS_MATCH("GUEST_OS_MAJOR_VERSION")) 657 { 658 Utf8Str const &rstrOsVer = mpUnattended->i_getDetectedOSVersion(); 659 size_t offDot = rstrOsVer.find('.'); 660 if (offDot > 0 && offDot != Utf8Str::npos) 661 pszValue = rstrTmp.assign(rstrOsVer, 0, offDot).c_str(); /* caller catches std::bad_alloc */ 662 else if (!ppszValue) 663 return VERR_NOT_FOUND; 664 else 665 { 666 mpSetError->setErrorBoth(E_FAIL, VERR_NO_DATA, tr("Unknown guest OS major version '%s'"), rstrOsVer.c_str()); 667 return VERR_NO_DATA; 668 } 669 } 670 else if (IS_MATCH("TIME_ZONE_UX")) 671 pszValue = mpUnattended->i_getTimeZoneInfo() 672 ? mpUnattended->i_getTimeZoneInfo()->pszUnixName : mpUnattended->i_getTimeZone().c_str(); 673 else if (IS_MATCH("TIME_ZONE_WIN_NAME")) 441 674 { 442 675 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo(); 443 676 if (pInfo) 444 rValue = pInfo->pszWindowsName ? pInfo->pszWindowsName : "GMT";677 pszValue = pInfo->pszWindowsName ? pInfo->pszWindowsName : "GMT"; 445 678 else 446 rValue = mpUnattended->i_getTimeZone();447 } 448 else if (IS_ PLACEHOLDER_MATCH("TIME_ZONE_WIN_INDEX"))679 pszValue = mpUnattended->i_getTimeZone().c_str(); 680 } 681 else if (IS_MATCH("TIME_ZONE_WIN_INDEX")) 449 682 { 450 683 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo(); 451 684 if (pInfo) 452 rValue.printf("%u", pInfo->idxWindows ? pInfo->idxWindows : 85 /*GMT*/);685 pszValue = rstrTmp.printf("%u", pInfo->idxWindows ? pInfo->idxWindows : 85 /*GMT*/).c_str(); 453 686 else 454 rValue = mpUnattended->i_getTimeZone(); 455 } 456 else if (IS_PLACEHOLDER_MATCH("LOCALE")) 457 rValue = mpUnattended->i_getLocale(); 458 else if (IS_PLACEHOLDER_MATCH("DASH_LOCALE")) 459 { 460 rValue = mpUnattended->i_getLocale(); 461 Assert(rValue[2] == '_'); 462 rValue.replace(2, 1, "-"); 463 } 464 else if (IS_PLACEHOLDER_MATCH("LANGUAGE")) 465 rValue = mpUnattended->i_getLanguage(); 466 else if (IS_PLACEHOLDER_MATCH("COUNTRY")) 467 rValue = mpUnattended->i_getCountry(); 468 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_FQDN")) 469 rValue = mpUnattended->i_getHostname(); 470 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_WITHOUT_DOMAIN")) 471 rValue.assign(mpUnattended->i_getHostname(), 0, mpUnattended->i_getHostname().find(".")); 472 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_WITHOUT_DOMAIN_MAX_15")) 473 rValue.assign(mpUnattended->i_getHostname(), 0, RT_MIN(mpUnattended->i_getHostname().find("."), 15)); 474 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_DOMAIN")) 475 rValue.assign(mpUnattended->i_getHostname(), mpUnattended->i_getHostname().find(".") + 1); 476 else if (IS_PLACEHOLDER_MATCH("PROXY")) 477 rValue = mpUnattended->i_getProxy(); 687 pszValue = mpUnattended->i_getTimeZone().c_str(); 688 } 689 else if (IS_MATCH("LOCALE")) 690 pszValue = mpUnattended->i_getLocale().c_str(); 691 else if (IS_MATCH("DASH_LOCALE")) 692 { 693 Assert(mpUnattended->i_getLocale()[2] == '_'); 694 pszValue = rstrTmp.assign(mpUnattended->i_getLocale()).replace(2, 1, "-").c_str(); 695 } 696 else if (IS_MATCH("LANGUAGE")) 697 pszValue = mpUnattended->i_getLanguage().c_str(); 698 else if (IS_MATCH("COUNTRY")) 699 pszValue = mpUnattended->i_getCountry().c_str(); 700 else if (IS_MATCH("HOSTNAME_FQDN")) 701 pszValue = mpUnattended->i_getHostname().c_str(); 702 else if (IS_MATCH("HOSTNAME_WITHOUT_DOMAIN")) 703 pszValue = rstrTmp.assign(mpUnattended->i_getHostname(), 0, mpUnattended->i_getHostname().find(".")).c_str(); 704 else if (IS_MATCH("HOSTNAME_WITHOUT_DOMAIN_MAX_15")) 705 pszValue = rstrTmp.assign(mpUnattended->i_getHostname(), 0, RT_MIN(mpUnattended->i_getHostname().find("."), 15)).c_str(); 706 else if (IS_MATCH("HOSTNAME_DOMAIN")) 707 pszValue = rstrTmp.assign(mpUnattended->i_getHostname(), mpUnattended->i_getHostname().find(".") + 1).c_str(); 708 else if (IS_MATCH("PROXY")) 709 pszValue = mpUnattended->i_getProxy().c_str(); 710 /* 711 * Indicator variables. 712 */ 713 else if (IS_MATCH("IS_INSTALLING_ADDITIONS")) 714 pszValue = mpUnattended->i_getInstallGuestAdditions() ? "1" : "0"; 715 else if (IS_MATCH("IS_USER_LOGIN_ADMINISTRATOR")) 716 pszValue = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) == 0 ? "1" : "0"; 717 else if (IS_MATCH("IS_INSTALLING_TEST_EXEC_SERVICE")) 718 pszValue = mpUnattended->i_getInstallTestExecService() ? "1" : "0"; 719 else if (IS_MATCH("HAS_POST_INSTALL_COMMAND")) 720 pszValue = mpUnattended->i_getPostInstallCommand().isNotEmpty() ? "1" : "0"; 721 else if (IS_MATCH("HAS_PRODUCT_KEY")) 722 pszValue = mpUnattended->i_getProductKey().isNotEmpty() ? "1" : "0"; 723 else if (IS_MATCH("IS_MINIMAL_INSTALLATION")) 724 pszValue = mpUnattended->i_isMinimalInstallation() ? "1" : "0"; 725 else if (IS_MATCH("IS_FIRMWARE_UEFI")) 726 pszValue = mpUnattended->i_isFirmwareEFI() ? "1" : "0"; 727 else if (IS_MATCH("IS_RTC_USING_UTC")) 728 pszValue = mpUnattended->i_isRtcUsingUtc() ? "1" : "0"; 729 else if (IS_MATCH("HAS_PROXY")) 730 pszValue = mpUnattended->i_getProxy().isNotEmpty() ? "1" : "0"; 731 /* 732 * Unknown variable. 733 */ 734 else if (!ppszValue) 735 return VERR_NOT_FOUND; 478 736 else 479 737 { 480 rValue.setNull();481 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("Unknown template placeholder '%.*s'"),482 cchFullPlaceholder, pachPlaceholder);483 }484 return S_OK;485 #undef IS_PLACEHOLDER_MATCH 738 mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("Unknown variable '%.*s'"), cchName, pchName); 739 return VERR_NO_DATA; 740 } 741 if (ppszValue) 742 *ppszValue = pszValue; 743 return VINF_SUCCESS; 486 744 } 487 745 -
trunk/src/VBox/Main/testcase/Makefile.kmk
r93115 r93190 37 37 tstMediumLock \ 38 38 tstBstr \ 39 tstGuid 39 tstGuid \ 40 tstUnattendedScript 40 41 PROGRAMS.linux += \ 41 42 $(if $(VBOX_WITH_USB),tstUSBProxyLinux,) … … 268 269 269 270 271 # 272 # tstUnattendedScript 273 # 274 tstUnattendedScript_TEMPLATE = VBOXMAINCLIENTTSTEXE 275 tstUnattendedScript_DEFS = VBOX_WITH_UNATTENDED IN_VBOXSVC IN_TST_UNATTENDED_SCRIPT 276 tstUnattendedScript_INTERMEDIATES = \ 277 $(VBOX_MAIN_APIWRAPPER_GEN_HDRS) \ 278 $(VBOX_XML_SCHEMADEFS_H) 279 tstUnattendedScript_INCS = \ 280 ../include \ 281 $(VBOX_MAIN_APIWRAPPER_INCS) \ 282 $(dir $(VBOX_XML_SCHEMADEFS_H)) 283 tstUnattendedScript_SOURCES = \ 284 tstUnattendedScript.cpp \ 285 ../src-server/UnattendedScript.cpp \ 286 ../src-all/TextScript.cpp \ 287 ../src-all/VirtualBoxBase.cpp \ 288 ../src-all/VirtualBoxErrorInfoImpl.cpp \ 289 ../src-all/AutoCaller.cpp \ 290 ../src-all/GlobalStatusConversion.cpp 291 tstUnattendedScript_LIBS = \ 292 $(PATH_STAGE_LIB)/VBoxAPIWrap$(VBOX_SUFF_LIB) 293 294 INSTALLS += tstUnattendedScriptFiles 295 tstUnattendedScriptFiles_TEMPLATE = VBOXMAINCLIENTTSTEXE 296 tstUnattendedScriptFiles_SOURCES = \ 297 tstUnattendedScript-1.template \ 298 tstUnattendedScript-1.expected 299 300 301 270 302 # generate rules. 271 303 include $(FILE_KBUILD_SUB_FOOTER)
Note:
See TracChangeset
for help on using the changeset viewer.