VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/UnattendedScript.cpp@ 93108

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

Main/UnattendedScript: Added @@VBOX_COND_ELSE@@.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 KB
Line 
1/* $Id: UnattendedScript.cpp 93108 2021-12-31 02:25:56Z vboxsync $ */
2/** @file
3 * Classes for reading/parsing/saving scripts for unattended installation.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
23#include "LoggingNew.h"
24#include "VirtualBoxBase.h"
25#include "AutoCaller.h"
26#include <VBox/com/ErrorInfo.h>
27
28#include "UnattendedScript.h"
29#include "UnattendedImpl.h"
30
31#include <iprt/errcore.h>
32
33#include <iprt/ctype.h>
34#include <iprt/file.h>
35#include <iprt/vfs.h>
36#include <iprt/getopt.h>
37#include <iprt/path.h>
38
39using namespace std;
40
41#ifdef VBOX_WITH_UNATTENDED
42
43
44/*********************************************************************************************************************************
45* UnattendedScriptTemplate Implementation *
46*********************************************************************************************************************************/
47
48UnattendedScriptTemplate::UnattendedScriptTemplate(Unattended *pUnattended, const char *pszDefaultTemplateFilename,
49 const char *pszDefaultFilename)
50 : BaseTextScript(pUnattended, pszDefaultTemplateFilename, pszDefaultFilename), mpUnattended(pUnattended)
51{
52}
53
54
55HRESULT UnattendedScriptTemplate::saveToString(Utf8Str &rStrDst)
56{
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";
63
64 struct
65 {
66 bool fSavedOutputting;
67 } aConds[8];
68 unsigned cConds = 0;
69 bool fOutputting = true;
70 HRESULT hrc = E_FAIL;
71 size_t offTemplate = 0;
72 size_t cchTemplate = mStrScriptFullContent.length();
73 rStrDst.setNull();
74 for (;;)
75 {
76 /*
77 * Find the next placeholder and add any text before it to the output.
78 */
79 size_t offPlaceholder = mStrScriptFullContent.find(s_szPrefix, offTemplate);
80 size_t cchToCopy = offPlaceholder != RTCString::npos ? offPlaceholder - offTemplate : cchTemplate - offTemplate;
81 if (cchToCopy > 0)
82 {
83 if (fOutputting)
84 {
85 try
86 {
87 rStrDst.append(mStrScriptFullContent, offTemplate , cchToCopy);
88 }
89 catch (std::bad_alloc &)
90 {
91 hrc = E_OUTOFMEMORY;
92 break;
93 }
94 }
95 offTemplate += cchToCopy;
96 }
97
98 /*
99 * Process placeholder.
100 */
101 if (offPlaceholder != RTCString::npos)
102 {
103 /*
104 * First we must find the end of the placeholder string.
105 */
106 const char *pszPlaceholder = mStrScriptFullContent.c_str() + offPlaceholder;
107 size_t cchPlaceholder = sizeof(s_szPrefix) - 1;
108 char ch;
109 while ( offPlaceholder + cchPlaceholder < cchTemplate
110 && (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)) )
119 cchPlaceholder++;
120
121 if ( offPlaceholder + cchPlaceholder < cchTemplate
122 && pszPlaceholder[cchPlaceholder] == '@')
123 {
124 cchPlaceholder++;
125 if ( offPlaceholder + cchPlaceholder < cchTemplate
126 && pszPlaceholder[cchPlaceholder] == '@')
127 cchPlaceholder++;
128 }
129
130 if ( pszPlaceholder[cchPlaceholder - 1] != '@'
131 || pszPlaceholder[cchPlaceholder - 2] != '@'
132 || ( strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) != 0
133 && strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) != 0
134 && strncmp(pszPlaceholder, s_szPrefixSplitter, sizeof(s_szPrefixSplitter) - 1) != 0 ) )
135 {
136 hrc = mpSetError->setError(E_FAIL, tr("Malformed template placeholder '%.*s'"),
137 cchPlaceholder, pszPlaceholder);
138 break;
139 }
140
141 offTemplate += cchPlaceholder;
142
143 /*
144 * @@VBOX_INSERT_XXX@@:
145 */
146 if ( strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) == 0 )
147 {
148 /*
149 * Get the placeholder value and add it to the output.
150 */
151 RTCString strValue;
152 hrc = getReplacement(pszPlaceholder, cchPlaceholder, fOutputting, strValue);
153 if (SUCCEEDED(hrc))
154 {
155 if (fOutputting)
156 {
157 try
158 {
159 rStrDst.append(strValue);
160 }
161 catch (std::bad_alloc &)
162 {
163 hrc = E_OUTOFMEMORY;
164 break;
165 }
166 }
167 }
168 else
169 break;
170 }
171 /*
172 * @@VBOX_COND_END@@: Pop one item of the conditional stack.
173 */
174 else if ( strncmp(pszPlaceholder, s_szPrefixCondEnd, sizeof(s_szPrefixCondEnd) - 1U) == 0 )
175 {
176 if (cConds > 0)
177 {
178 cConds--;
179 fOutputting = aConds[cConds].fSavedOutputting;
180 }
181 else
182 {
183 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
184 tr("%s without @@VBOX_COND_XXX@@ at offset %zu (%#zx)"),
185 s_szPrefixCondEnd, offPlaceholder, offPlaceholder);
186 break;
187 }
188 }
189 /*
190 * @@VBOX_COND_ELSE@@: Flip the output setting of the current condition.
191 */
192 else if ( strncmp(pszPlaceholder, s_szPrefixCondElse, sizeof(s_szPrefixCondElse) - 1U) == 0 )
193 {
194 if (cConds > 0)
195 fOutputting = !fOutputting;
196 else
197 {
198 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
199 tr("%s without @@VBOX_COND_XXX@@ at offset %zu (%#zx)"),
200 s_szPrefixCondElse, offPlaceholder, offPlaceholder);
201 break;
202 }
203 }
204 /*
205 * @@VBOX_COND_XXX@@: Push the previous outputting state and combine it with the
206 * one from the condition.
207 */
208 else if (strncmp(pszPlaceholder, s_szPrefixSplitter, sizeof(s_szPrefixSplitter) - 1) != 0)
209 {
210 Assert(strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) == 0);
211 if (cConds + 1 < RT_ELEMENTS(aConds))
212 {
213 aConds[cConds].fSavedOutputting = fOutputting;
214 bool fNewOutputting = fOutputting;
215 hrc = getConditional(pszPlaceholder, cchPlaceholder, &fNewOutputting);
216 if (SUCCEEDED(hrc))
217 fOutputting = fOutputting && fNewOutputting;
218 else
219 break;
220 cConds++;
221 }
222 else
223 {
224 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
225 tr("Too deep conditional nesting at offset %zu (%#zx)"),
226 offPlaceholder, offPlaceholder);
227 break;
228 }
229 }
230 /*
231 * @@VBOX_SPLITTER_START/END[filename]@@: Ignored in this pass.
232 */
233 else
234 {
235 if (fOutputting)
236 {
237 try
238 {
239 rStrDst.append(pszPlaceholder, cchPlaceholder);
240 }
241 catch (std::bad_alloc &)
242 {
243 hrc = E_OUTOFMEMORY;
244 break;
245 }
246 }
247 }
248 }
249
250 /*
251 * Done?
252 */
253 if (offTemplate >= cchTemplate)
254 {
255 if (cConds == 0)
256 return S_OK;
257 if (cConds == 1)
258 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, tr("Missing @@VBOX_COND_END@@"));
259 else
260 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, tr("Missing %u @@VBOX_COND_END@@"), cConds);
261 break;
262 }
263 }
264
265 /* failed */
266 rStrDst.setNull();
267 return hrc;
268}
269
270HRESULT UnattendedScriptTemplate::getReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
271 bool fOutputting, RTCString &rValue)
272{
273 /*
274 * Check for an escaping suffix. Drop the '@@'.
275 */
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
285#define PLACEHOLDER_ENDS_WITH(a_szSuffix) \
286 ( cchPlaceholder > sizeof(a_szSuffix) - 1U \
287 && memcmp(&pachPlaceholder[cchPlaceholder - sizeof(a_szSuffix) + 1U], a_szSuffix, sizeof(a_szSuffix) - 1U) == 0)
288 if (PLACEHOLDER_ENDS_WITH("_SH@@"))
289 {
290 cchPlaceholder -= 3 + 2;
291 enmEscaping = kValueEscaping_Bourne;
292 }
293 else if (PLACEHOLDER_ENDS_WITH("_ELEMENT@@"))
294 {
295 cchPlaceholder -= 8 + 2;
296 enmEscaping = kValueEscaping_XML_Element;
297 }
298 else if (PLACEHOLDER_ENDS_WITH("_ATTRIB_DQ@@"))
299 {
300 cchPlaceholder -= 10 + 2;
301 enmEscaping = kValueEscaping_XML_Attribute_Double_Quotes;
302 }
303 else
304 {
305 Assert(PLACEHOLDER_ENDS_WITH("@@"));
306 cchPlaceholder -= 2;
307 enmEscaping = kValueEscaping_None;
308 }
309
310 /*
311 * Resolve and escape the value.
312 */
313 HRESULT hrc;
314 try
315 {
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)
333 {
334 case kValueEscaping_Bourne:
335 {
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))
340 {
341 try
342 {
343 rValue = pszEscaped;
344 RTStrFree(pszEscaped);
345 return S_OK;
346 }
347 catch (std::bad_alloc &)
348 {
349 hrc = E_OUTOFMEMORY;
350 }
351 RTStrFree(pszEscaped);
352 }
353 break;
354 }
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;
371 }
372 }
373 break;
374 }
375
376 default:
377 AssertFailedStmt(hrc = E_FAIL);
378 break;
379 }
380 }
381 catch (std::bad_alloc &)
382 {
383 hrc = E_OUTOFMEMORY;
384 }
385 rValue.setNull();
386 return hrc;
387}
388
389HRESULT 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"))
441 {
442 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
443 if (pInfo)
444 rValue = pInfo->pszWindowsName ? pInfo->pszWindowsName : "GMT";
445 else
446 rValue = mpUnattended->i_getTimeZone();
447 }
448 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_INDEX"))
449 {
450 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
451 if (pInfo)
452 rValue.printf("%u", pInfo->idxWindows ? pInfo->idxWindows : 85 /*GMT*/);
453 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();
478 else
479 {
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
486}
487
488HRESULT UnattendedScriptTemplate::getConditional(const char *pachPlaceholder, size_t cchPlaceholder, bool *pfOutputting)
489{
490#define IS_PLACEHOLDER_MATCH(a_szMatch) \
491 ( cchPlaceholder == sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U \
492 && memcmp(pachPlaceholder, "@@VBOX_COND_" a_szMatch "@@", sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U) == 0)
493#define IS_PLACEHOLDER_PARTIALLY_MATCH(a_szMatch) \
494 (memcmp(pachPlaceholder, "@@VBOX_COND_" a_szMatch, sizeof("@@VBOX_COND_" a_szMatch) - 1U) == 0)
495
496 /* Install Guest Additions: */
497 if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_ADDITIONS"))
498 *pfOutputting = mpUnattended->i_getInstallGuestAdditions();
499 else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_ADDITIONS"))
500 *pfOutputting = !mpUnattended->i_getInstallGuestAdditions();
501 /* User == Administrator: */
502 else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_ADMINISTRATOR"))
503 *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) == 0;
504 else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_NOT_ADMINISTRATOR"))
505 *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) != 0;
506 /* Install TXS: */
507 else if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_TEST_EXEC_SERVICE"))
508 *pfOutputting = mpUnattended->i_getInstallTestExecService();
509 else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_TEST_EXEC_SERVICE"))
510 *pfOutputting = !mpUnattended->i_getInstallTestExecService();
511 /* Post install command: */
512 else if (IS_PLACEHOLDER_MATCH("HAS_POST_INSTALL_COMMAND"))
513 *pfOutputting = mpUnattended->i_getPostInstallCommand().isNotEmpty();
514 else if (IS_PLACEHOLDER_MATCH("HAS_NO_POST_INSTALL_COMMAND"))
515 *pfOutputting = mpUnattended->i_getPostInstallCommand().isEmpty();
516 /* Product key: */
517 else if (IS_PLACEHOLDER_MATCH("HAS_PRODUCT_KEY"))
518 *pfOutputting = mpUnattended->i_getProductKey().isNotEmpty();
519 else if (IS_PLACEHOLDER_MATCH("HAS_NO_PRODUCT_KEY"))
520 *pfOutputting = mpUnattended->i_getProductKey().isEmpty();
521 /* Minimal installation: */
522 else if (IS_PLACEHOLDER_MATCH("IS_MINIMAL_INSTALLATION"))
523 *pfOutputting = mpUnattended->i_isMinimalInstallation();
524 else if (IS_PLACEHOLDER_MATCH("IS_NOT_MINIMAL_INSTALLATION"))
525 *pfOutputting = !mpUnattended->i_isMinimalInstallation();
526 /* Is firmware UEFI: */
527 else if (IS_PLACEHOLDER_MATCH("IS_FIRMWARE_UEFI"))
528 *pfOutputting = mpUnattended->i_isFirmwareEFI();
529 else if (IS_PLACEHOLDER_MATCH("IS_NOT_FIRMWARE_UEFI"))
530 *pfOutputting = !mpUnattended->i_isFirmwareEFI();
531 /* Is RTC using UTC (i.e. set to UTC time on startup): */
532 else if (IS_PLACEHOLDER_MATCH("IS_RTC_USING_UTC"))
533 *pfOutputting = mpUnattended->i_isRtcUsingUtc();
534 else if (IS_PLACEHOLDER_MATCH("IS_NOT_RTC_USING_UTC"))
535 *pfOutputting = !mpUnattended->i_isRtcUsingUtc();
536 else if (IS_PLACEHOLDER_MATCH("HAS_PROXY"))
537 *pfOutputting = mpUnattended->i_getProxy().isNotEmpty();
538 else if (IS_PLACEHOLDER_PARTIALLY_MATCH("GUEST_VERSION"))
539 {
540 //parse the placeholder and extract the OS version from there
541 RTCString strPlaceHolder(pachPlaceholder);
542 size_t startPos = sizeof("@@VBOX_COND_GUEST_VERSION") - 1;//-1 is for '\n'
543 size_t endPos = strPlaceHolder.find("@@", startPos + 2);
544 //next part should look like [>8.0.0] for example where:
545 // - "[,]" is just the brackets to wrap up the condition;
546 // - ">" is "greater". Also possible comparison is "<";
547 // - 8.0.0 is required guest OS version.
548 //The end of placeholder is "@@" like for others.
549
550 if ( strPlaceHolder[endPos] == '@'
551 && strPlaceHolder[endPos+1] == '@' )
552 {
553 if ( strPlaceHolder[startPos++] == '[' && strPlaceHolder[--endPos] == ']' )
554 {
555 char chComp = strPlaceHolder[startPos++];
556 RTCString strRequiredOSVersion = strPlaceHolder.substr(startPos, endPos - startPos);
557 RTCString strDetectedOSVersion = mpUnattended->i_getDetectedOSVersion();
558 int res = RTStrVersionCompare(strDetectedOSVersion.c_str(), strRequiredOSVersion.c_str());
559 if ( res >= 0 && chComp == '>' )
560 *pfOutputting = true;
561 else if ( res < 0 && chComp == '<' )
562 *pfOutputting = true;
563 else
564 *pfOutputting = false;
565 }
566 }
567 else
568 *pfOutputting = false;//initially is set to "false"
569 }
570 else
571 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("Unknown conditional placeholder '%.*s'"),
572 cchPlaceholder, pachPlaceholder);
573 return S_OK;
574#undef IS_PLACEHOLDER_MATCH
575}
576
577#endif /* VBOX_WITH_UNATTENDED */
578#if 0 /* Keeping this a reference */
579
580
581/*********************************************************************************************************************************
582* UnattendedSUSEXMLScript Implementation *
583*********************************************************************************************************************************/
584
585HRESULT UnattendedSUSEXMLScript::parse()
586{
587 HRESULT hrc = UnattendedXMLScript::parse();
588 if (SUCCEEDED(hrc))
589 {
590 /*
591 * Check that we've got the right root element type.
592 */
593 const xml::ElementNode *pelmRoot = mDoc.getRootElement();
594 if ( pelmRoot
595 && strcmp(pelmRoot->getName(), "profile") == 0)
596 {
597 /*
598 * Work thought the sections.
599 */
600 try
601 {
602 LoopThruSections(pelmRoot);
603 hrc = S_OK;
604 }
605 catch (std::bad_alloc &)
606 {
607 hrc = E_OUTOFMEMORY;
608 }
609 }
610 else if (pelmRoot)
611 hrc = mpSetError->setError(E_FAIL, tr("XML document root element is '%s' instead of 'profile'"),
612 pelmRoot->getName());
613 else
614 hrc = mpSetError->setError(E_FAIL, tr("Missing XML root element"));
615 }
616 return hrc;
617}
618
619HRESULT UnattendedSUSEXMLScript::setFieldInElement(xml::ElementNode *pElement, const DataId enmDataId, const Utf8Str &rStrValue)
620{
621 /*
622 * Don't set empty values.
623 */
624 if (rStrValue.isEmpty())
625 {
626 Utf8Str strProbableValue;
627 try
628 {
629 strProbableValue = createProbableValue(enmDataId, pElement);
630 }
631 catch (std::bad_alloc &)
632 {
633 return E_OUTOFMEMORY;
634 }
635 return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, strProbableValue);
636 }
637 return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, rStrValue);
638}
639
640HRESULT UnattendedSUSEXMLScript::LoopThruSections(const xml::ElementNode *pelmRoot)
641{
642 xml::NodesLoop loopChildren(*pelmRoot);
643 const xml::ElementNode *pelmOuterLoop;
644 while ((pelmOuterLoop = loopChildren.forAllNodes()) != NULL)
645 {
646 const char *pcszElemName = pelmOuterLoop->getName();
647 if (!strcmp(pcszElemName, "users"))
648 {
649 xml::NodesLoop loopUsers(*pelmOuterLoop);
650 const xml::ElementNode *pelmUser;
651 while ((pelmUser = loopUsers.forAllNodes()) != NULL)
652 {
653 HRESULT hrc = HandleUserAccountsSection(pelmUser);
654 if (FAILED(hrc))
655 return hrc;
656 }
657 }
658 }
659 return S_OK;
660}
661
662HRESULT UnattendedSUSEXMLScript::HandleUserAccountsSection(const xml::ElementNode *pelmSection)
663{
664 xml::NodesLoop loopUser(*pelmSection);
665
666 const xml::ElementNode *pelmCur;
667 while ((pelmCur = loopUser.forAllNodes()) != NULL)
668 {
669 const char *pszValue = pelmCur->getValue();
670#ifdef LOG_ENABLED
671 if (!RTStrCmp(pelmCur->getName(), "uid"))
672 LogRelFunc(("UnattendedSUSEXMLScript::HandleUserAccountsSection profile/users/%s/%s = %s\n",
673 pelmSection->getName(), pelmCur->getName(), pszValue));
674#endif
675
676 if (!RTStrCmp(pszValue, "$homedir"))
677 mNodesForCorrectionMap.insert(make_pair(USERHOMEDIR_ID, pelmCur));
678
679 if (!RTStrCmp(pszValue, "$user"))
680 mNodesForCorrectionMap.insert(make_pair(USERNAME_ID, pelmCur));
681
682 if (!RTStrCmp(pszValue, "$password"))
683 mNodesForCorrectionMap.insert(make_pair(USERPASSWORD_ID, pelmCur));
684 }
685 return S_OK;
686}
687
688Utf8Str UnattendedSUSEXMLScript::createProbableValue(const DataId enmDataId, const xml::ElementNode *pCurElem)
689{
690 const xml::ElementNode *pElem = pCurElem;
691
692 switch (enmDataId)
693 {
694 case USERHOMEDIR_ID:
695// if ((pElem = pElem->findChildElement("home")))
696// {
697 return createProbableUserHomeDir(pElem);
698// }
699 break;
700 default:
701 break;
702 }
703
704 return Utf8Str::Empty;
705}
706
707Utf8Str UnattendedSUSEXMLScript::createProbableUserHomeDir(const xml::ElementNode *pCurElem)
708{
709 Utf8Str strCalcValue;
710 const xml::ElementNode *pElem = pCurElem->findNextSibilingElement("username");
711 if (pElem)
712 {
713 const char *pszValue = pElem->getValue();
714 strCalcValue = "/home/";
715 strCalcValue.append(pszValue);
716 }
717
718 return strCalcValue;
719}
720#endif /* just for reference */
721
Note: See TracBrowser for help on using the repository browser.

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