VirtualBox

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

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

Main/Unattended: Some more work on the OS/2 unattended installation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.2 KB
Line 
1/* $Id: UnattendedScript.cpp 93085 2021-12-27 04:55:00Z 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_szPrefixCondEnd[] = "@@VBOX_COND_END@@";
61 static const char s_szPrefixSplitter[] = "@@VBOX_SPLITTER";
62
63 struct
64 {
65 bool fSavedOutputting;
66 } aConds[8];
67 unsigned cConds = 0;
68 bool fOutputting = true;
69 HRESULT hrc = E_FAIL;
70 size_t offTemplate = 0;
71 size_t cchTemplate = mStrScriptFullContent.length();
72 rStrDst.setNull();
73 for (;;)
74 {
75 /*
76 * Find the next placeholder and add any text before it to the output.
77 */
78 size_t offPlaceholder = mStrScriptFullContent.find(s_szPrefix, offTemplate);
79 size_t cchToCopy = offPlaceholder != RTCString::npos ? offPlaceholder - offTemplate : cchTemplate - offTemplate;
80 if (cchToCopy > 0)
81 {
82 if (fOutputting)
83 {
84 try
85 {
86 rStrDst.append(mStrScriptFullContent, offTemplate , cchToCopy);
87 }
88 catch (std::bad_alloc &)
89 {
90 hrc = E_OUTOFMEMORY;
91 break;
92 }
93 }
94 offTemplate += cchToCopy;
95 }
96
97 /*
98 * Process placeholder.
99 */
100 if (offPlaceholder != RTCString::npos)
101 {
102 /*
103 * First we must find the end of the placeholder string.
104 */
105 const char *pszPlaceholder = mStrScriptFullContent.c_str() + offPlaceholder;
106 size_t cchPlaceholder = sizeof(s_szPrefix) - 1;
107 char ch;
108 while ( offPlaceholder + cchPlaceholder < cchTemplate
109 && (ch = pszPlaceholder[cchPlaceholder]) != '\0'
110 && ( ch == '_'
111 || ch == '['
112 || ch == ']'
113 || ch == '.'
114 || ch == '>'
115 || ch == '<'
116 || RT_C_IS_UPPER(ch)
117 || RT_C_IS_DIGIT(ch)) )
118 cchPlaceholder++;
119
120 if ( offPlaceholder + cchPlaceholder < cchTemplate
121 && pszPlaceholder[cchPlaceholder] == '@')
122 {
123 cchPlaceholder++;
124 if ( offPlaceholder + cchPlaceholder < cchTemplate
125 && pszPlaceholder[cchPlaceholder] == '@')
126 cchPlaceholder++;
127 }
128
129 if ( pszPlaceholder[cchPlaceholder - 1] != '@'
130 || pszPlaceholder[cchPlaceholder - 2] != '@'
131 || ( strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) != 0
132 && strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) != 0
133 && strncmp(pszPlaceholder, s_szPrefixSplitter, sizeof(s_szPrefixSplitter) - 1) != 0 ) )
134 {
135 hrc = mpSetError->setError(E_FAIL, tr("Malformed template placeholder '%.*s'"),
136 cchPlaceholder, pszPlaceholder);
137 break;
138 }
139
140 offTemplate += cchPlaceholder;
141
142 /*
143 * @@VBOX_INSERT_XXX@@:
144 */
145 if ( strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) == 0 )
146 {
147 /*
148 * Get the placeholder value and add it to the output.
149 */
150 RTCString strValue;
151 hrc = getReplacement(pszPlaceholder, cchPlaceholder, fOutputting, strValue);
152 if (SUCCEEDED(hrc))
153 {
154 if (fOutputting)
155 {
156 try
157 {
158 rStrDst.append(strValue);
159 }
160 catch (std::bad_alloc &)
161 {
162 hrc = E_OUTOFMEMORY;
163 break;
164 }
165 }
166 }
167 else
168 break;
169 }
170 /*
171 * @@VBOX_COND_END@@: Pop one item of the conditional stack.
172 */
173 else if ( strncmp(pszPlaceholder, s_szPrefixCondEnd, sizeof(s_szPrefixCondEnd) - 1U) == 0 )
174 {
175 if (cConds > 0)
176 {
177 cConds--;
178 fOutputting = aConds[cConds].fSavedOutputting;
179 }
180 else
181 {
182 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
183 tr("%s without @@VBOX_COND_XXX@@ at offset %zu (%#zx)"),
184 s_szPrefixCondEnd, offPlaceholder, offPlaceholder);
185 break;
186 }
187 }
188 /*
189 * @@VBOX_COND_XXX@@: Push the previous outputting state and combine it with the
190 * one from the condition.
191 */
192 else if (strncmp(pszPlaceholder, s_szPrefixSplitter, sizeof(s_szPrefixSplitter) - 1) != 0)
193 {
194 Assert(strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) == 0);
195 if (cConds + 1 < RT_ELEMENTS(aConds))
196 {
197 aConds[cConds].fSavedOutputting = fOutputting;
198 bool fNewOutputting = fOutputting;
199 hrc = getConditional(pszPlaceholder, cchPlaceholder, &fNewOutputting);
200 if (SUCCEEDED(hrc))
201 fOutputting = fOutputting && fNewOutputting;
202 else
203 break;
204 cConds++;
205 }
206 else
207 {
208 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
209 tr("Too deep conditional nesting at offset %zu (%#zx)"),
210 offPlaceholder, offPlaceholder);
211 break;
212 }
213 }
214 /*
215 * @@VBOX_SPLITTER_START/END[filename]@@: Ignored in this pass.
216 */
217 else
218 {
219 if (fOutputting)
220 {
221 try
222 {
223 rStrDst.append(pszPlaceholder, cchPlaceholder);
224 }
225 catch (std::bad_alloc &)
226 {
227 hrc = E_OUTOFMEMORY;
228 break;
229 }
230 }
231 }
232 }
233
234 /*
235 * Done?
236 */
237 if (offTemplate >= cchTemplate)
238 {
239 if (cConds == 0)
240 return S_OK;
241 if (cConds == 1)
242 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, tr("Missing @@VBOX_COND_END@@"));
243 else
244 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, tr("Missing %u @@VBOX_COND_END@@"), cConds);
245 break;
246 }
247 }
248
249 /* failed */
250 rStrDst.setNull();
251 return hrc;
252}
253
254HRESULT UnattendedScriptTemplate::getReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
255 bool fOutputting, RTCString &rValue)
256{
257 /*
258 * Check for an escaping suffix. Drop the '@@'.
259 */
260 size_t const cchFullPlaceholder = cchPlaceholder;
261 enum
262 {
263 kValueEscaping_None,
264 kValueEscaping_Bourne,
265 kValueEscaping_XML_Element,
266 kValueEscaping_XML_Attribute_Double_Quotes
267 } enmEscaping;
268
269#define PLACEHOLDER_ENDS_WITH(a_szSuffix) \
270 ( cchPlaceholder > sizeof(a_szSuffix) - 1U \
271 && memcmp(&pachPlaceholder[cchPlaceholder - sizeof(a_szSuffix) + 1U], a_szSuffix, sizeof(a_szSuffix) - 1U) == 0)
272 if (PLACEHOLDER_ENDS_WITH("_SH@@"))
273 {
274 cchPlaceholder -= 3 + 2;
275 enmEscaping = kValueEscaping_Bourne;
276 }
277 else if (PLACEHOLDER_ENDS_WITH("_ELEMENT@@"))
278 {
279 cchPlaceholder -= 8 + 2;
280 enmEscaping = kValueEscaping_XML_Element;
281 }
282 else if (PLACEHOLDER_ENDS_WITH("_ATTRIB_DQ@@"))
283 {
284 cchPlaceholder -= 10 + 2;
285 enmEscaping = kValueEscaping_XML_Attribute_Double_Quotes;
286 }
287 else
288 {
289 Assert(PLACEHOLDER_ENDS_WITH("@@"));
290 cchPlaceholder -= 2;
291 enmEscaping = kValueEscaping_None;
292 }
293
294 /*
295 * Resolve and escape the value.
296 */
297 HRESULT hrc;
298 try
299 {
300 switch (enmEscaping)
301 {
302 case kValueEscaping_None:
303 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, rValue);
304 if (SUCCEEDED(hrc))
305 return hrc;
306 break;
307
308 case kValueEscaping_Bourne:
309 case kValueEscaping_XML_Element:
310 case kValueEscaping_XML_Attribute_Double_Quotes:
311 {
312 RTCString strUnescaped;
313 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, strUnescaped);
314 if (SUCCEEDED(hrc))
315 {
316 switch (enmEscaping)
317 {
318 case kValueEscaping_Bourne:
319 {
320 const char * const papszArgs[2] = { strUnescaped.c_str(), NULL };
321 char *pszEscaped = NULL;
322 int vrc = RTGetOptArgvToString(&pszEscaped, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
323 if (RT_SUCCESS(vrc))
324 {
325 try
326 {
327 rValue = pszEscaped;
328 RTStrFree(pszEscaped);
329 return S_OK;
330 }
331 catch (std::bad_alloc &)
332 {
333 hrc = E_OUTOFMEMORY;
334 }
335 RTStrFree(pszEscaped);
336 }
337 break;
338 }
339
340 case kValueEscaping_XML_Element:
341 rValue.printf("%RMes", strUnescaped.c_str());
342 return S_OK;
343
344 case kValueEscaping_XML_Attribute_Double_Quotes:
345 {
346 RTCString strTmp;
347 strTmp.printf("%RMas", strUnescaped.c_str());
348 rValue = RTCString(strTmp, 1, strTmp.length() - 2);
349 return S_OK;
350 }
351
352 default:
353 hrc = E_FAIL;
354 break;
355 }
356 }
357 break;
358 }
359
360 default:
361 AssertFailedStmt(hrc = E_FAIL);
362 break;
363 }
364 }
365 catch (std::bad_alloc &)
366 {
367 hrc = E_OUTOFMEMORY;
368 }
369 rValue.setNull();
370 return hrc;
371}
372
373HRESULT UnattendedScriptTemplate::getUnescapedReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
374 size_t cchFullPlaceholder, bool fOutputting, RTCString &rValue)
375{
376 RT_NOREF(fOutputting);
377#define IS_PLACEHOLDER_MATCH(a_szMatch) \
378 ( cchPlaceholder == sizeof("@@VBOX_INSERT_" a_szMatch) - 1U \
379 && memcmp(pachPlaceholder, "@@VBOX_INSERT_" a_szMatch, sizeof("@@VBOX_INSERT_" a_szMatch) - 1U) == 0)
380
381 if (IS_PLACEHOLDER_MATCH("USER_LOGIN"))
382 rValue = mpUnattended->i_getUser();
383 else if (IS_PLACEHOLDER_MATCH("USER_PASSWORD"))
384 rValue = mpUnattended->i_getPassword();
385 else if (IS_PLACEHOLDER_MATCH("ROOT_PASSWORD"))
386 rValue = mpUnattended->i_getPassword();
387 else if (IS_PLACEHOLDER_MATCH("USER_FULL_NAME"))
388 rValue = mpUnattended->i_getFullUserName();
389 else if (IS_PLACEHOLDER_MATCH("PRODUCT_KEY"))
390 rValue = mpUnattended->i_getProductKey();
391 else if (IS_PLACEHOLDER_MATCH("POST_INSTALL_COMMAND"))
392 rValue = mpUnattended->i_getPostInstallCommand();
393 else if (IS_PLACEHOLDER_MATCH("AUXILIARY_INSTALL_DIR"))
394 rValue = mpUnattended->i_getAuxiliaryInstallDir();
395 else if (IS_PLACEHOLDER_MATCH("IMAGE_INDEX"))
396 rValue.printf("%u", mpUnattended->i_getImageIndex());
397 else if (IS_PLACEHOLDER_MATCH("OS_ARCH"))
398 rValue = mpUnattended->i_isGuestOs64Bit() ? "amd64" : "x86";
399 else if (IS_PLACEHOLDER_MATCH("OS_ARCH2"))
400 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "x86";
401 else if (IS_PLACEHOLDER_MATCH("OS_ARCH3"))
402 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i386";
403 else if (IS_PLACEHOLDER_MATCH("OS_ARCH4"))
404 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i486";
405 else if (IS_PLACEHOLDER_MATCH("OS_ARCH6"))
406 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i686";
407 else if (IS_PLACEHOLDER_MATCH("GUEST_OS_VERSION"))
408 rValue = mpUnattended->i_getDetectedOSVersion();
409 else if (IS_PLACEHOLDER_MATCH("GUEST_OS_MAJOR_VERSION"))
410 {
411 Utf8Str strOsVer(mpUnattended->i_getDetectedOSVersion());
412 RTCList<RTCString> partList = strOsVer.split(".");
413 if (partList.size() < 1)
414 {
415 rValue.setNull();
416 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("Unknown guest OS major version '%s'"),
417 partList.at(0).c_str());
418 }
419 rValue = partList.at(0);
420 }
421 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_UX"))
422 rValue = mpUnattended->i_getTimeZoneInfo()
423 ? mpUnattended->i_getTimeZoneInfo()->pszUnixName : mpUnattended->i_getTimeZone();
424 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_NAME"))
425 {
426 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
427 if (pInfo)
428 rValue = pInfo->pszWindowsName ? pInfo->pszWindowsName : "GMT";
429 else
430 rValue = mpUnattended->i_getTimeZone();
431 }
432 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_INDEX"))
433 {
434 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
435 if (pInfo)
436 rValue.printf("%u", pInfo->idxWindows ? pInfo->idxWindows : 85 /*GMT*/);
437 else
438 rValue = mpUnattended->i_getTimeZone();
439 }
440 else if (IS_PLACEHOLDER_MATCH("LOCALE"))
441 rValue = mpUnattended->i_getLocale();
442 else if (IS_PLACEHOLDER_MATCH("DASH_LOCALE"))
443 {
444 rValue = mpUnattended->i_getLocale();
445 Assert(rValue[2] == '_');
446 rValue.replace(2, 1, "-");
447 }
448 else if (IS_PLACEHOLDER_MATCH("LANGUAGE"))
449 rValue = mpUnattended->i_getLanguage();
450 else if (IS_PLACEHOLDER_MATCH("COUNTRY"))
451 rValue = mpUnattended->i_getCountry();
452 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_FQDN"))
453 rValue = mpUnattended->i_getHostname();
454 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_WITHOUT_DOMAIN"))
455 rValue.assign(mpUnattended->i_getHostname(), 0, mpUnattended->i_getHostname().find("."));
456 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_WITHOUT_DOMAIN_MAX_15"))
457 rValue.assign(mpUnattended->i_getHostname(), 0, RT_MIN(mpUnattended->i_getHostname().find("."), 15));
458 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_DOMAIN"))
459 rValue.assign(mpUnattended->i_getHostname(), mpUnattended->i_getHostname().find(".") + 1);
460 else if (IS_PLACEHOLDER_MATCH("PROXY"))
461 rValue = mpUnattended->i_getProxy();
462 else
463 {
464 rValue.setNull();
465 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("Unknown template placeholder '%.*s'"),
466 cchFullPlaceholder, pachPlaceholder);
467 }
468 return S_OK;
469#undef IS_PLACEHOLDER_MATCH
470}
471
472HRESULT UnattendedScriptTemplate::getConditional(const char *pachPlaceholder, size_t cchPlaceholder, bool *pfOutputting)
473{
474#define IS_PLACEHOLDER_MATCH(a_szMatch) \
475 ( cchPlaceholder == sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U \
476 && memcmp(pachPlaceholder, "@@VBOX_COND_" a_szMatch "@@", sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U) == 0)
477#define IS_PLACEHOLDER_PARTIALLY_MATCH(a_szMatch) \
478 (memcmp(pachPlaceholder, "@@VBOX_COND_" a_szMatch, sizeof("@@VBOX_COND_" a_szMatch) - 1U) == 0)
479
480 /* Install Guest Additions: */
481 if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_ADDITIONS"))
482 *pfOutputting = mpUnattended->i_getInstallGuestAdditions();
483 else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_ADDITIONS"))
484 *pfOutputting = !mpUnattended->i_getInstallGuestAdditions();
485 /* User == Administrator: */
486 else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_ADMINISTRATOR"))
487 *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) == 0;
488 else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_NOT_ADMINISTRATOR"))
489 *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) != 0;
490 /* Install TXS: */
491 else if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_TEST_EXEC_SERVICE"))
492 *pfOutputting = mpUnattended->i_getInstallTestExecService();
493 else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_TEST_EXEC_SERVICE"))
494 *pfOutputting = !mpUnattended->i_getInstallTestExecService();
495 /* Post install command: */
496 else if (IS_PLACEHOLDER_MATCH("HAS_POST_INSTALL_COMMAND"))
497 *pfOutputting = mpUnattended->i_getPostInstallCommand().isNotEmpty();
498 else if (IS_PLACEHOLDER_MATCH("HAS_NO_POST_INSTALL_COMMAND"))
499 *pfOutputting = mpUnattended->i_getPostInstallCommand().isEmpty();
500 /* Product key: */
501 else if (IS_PLACEHOLDER_MATCH("HAS_PRODUCT_KEY"))
502 *pfOutputting = mpUnattended->i_getProductKey().isNotEmpty();
503 else if (IS_PLACEHOLDER_MATCH("HAS_NO_PRODUCT_KEY"))
504 *pfOutputting = mpUnattended->i_getProductKey().isEmpty();
505 /* Minimal installation: */
506 else if (IS_PLACEHOLDER_MATCH("IS_MINIMAL_INSTALLATION"))
507 *pfOutputting = mpUnattended->i_isMinimalInstallation();
508 else if (IS_PLACEHOLDER_MATCH("IS_NOT_MINIMAL_INSTALLATION"))
509 *pfOutputting = !mpUnattended->i_isMinimalInstallation();
510 /* Is firmware UEFI: */
511 else if (IS_PLACEHOLDER_MATCH("IS_FIRMWARE_UEFI"))
512 *pfOutputting = mpUnattended->i_isFirmwareEFI();
513 else if (IS_PLACEHOLDER_MATCH("IS_NOT_FIRMWARE_UEFI"))
514 *pfOutputting = !mpUnattended->i_isFirmwareEFI();
515 /* Is RTC using UTC (i.e. set to UTC time on startup): */
516 else if (IS_PLACEHOLDER_MATCH("IS_RTC_USING_UTC"))
517 *pfOutputting = mpUnattended->i_isRtcUsingUtc();
518 else if (IS_PLACEHOLDER_MATCH("IS_NOT_RTC_USING_UTC"))
519 *pfOutputting = !mpUnattended->i_isRtcUsingUtc();
520 else if (IS_PLACEHOLDER_MATCH("HAS_PROXY"))
521 *pfOutputting = mpUnattended->i_getProxy().isNotEmpty();
522 else if (IS_PLACEHOLDER_PARTIALLY_MATCH("GUEST_VERSION"))
523 {
524 //parse the placeholder and extract the OS version from there
525 RTCString strPlaceHolder(pachPlaceholder);
526 size_t startPos = sizeof("@@VBOX_COND_GUEST_VERSION") - 1;//-1 is for '\n'
527 size_t endPos = strPlaceHolder.find("@@", startPos + 2);
528 //next part should look like [>8.0.0] for example where:
529 // - "[,]" is just the brackets to wrap up the condition;
530 // - ">" is "greater". Also possible comparison is "<";
531 // - 8.0.0 is required guest OS version.
532 //The end of placeholder is "@@" like for others.
533
534 if ( strPlaceHolder[endPos] == '@'
535 && strPlaceHolder[endPos+1] == '@' )
536 {
537 if ( strPlaceHolder[startPos++] == '[' && strPlaceHolder[--endPos] == ']' )
538 {
539 char chComp = strPlaceHolder[startPos++];
540 RTCString strRequiredOSVersion = strPlaceHolder.substr(startPos, endPos - startPos);
541 RTCString strDetectedOSVersion = mpUnattended->i_getDetectedOSVersion();
542 int res = RTStrVersionCompare(strDetectedOSVersion.c_str(), strRequiredOSVersion.c_str());
543 if ( res >= 0 && chComp == '>' )
544 *pfOutputting = true;
545 else if ( res < 0 && chComp == '<' )
546 *pfOutputting = true;
547 else
548 *pfOutputting = false;
549 }
550 }
551 else
552 *pfOutputting = false;//initially is set to "false"
553 }
554 else
555 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, tr("Unknown conditional placeholder '%.*s'"),
556 cchPlaceholder, pachPlaceholder);
557 return S_OK;
558#undef IS_PLACEHOLDER_MATCH
559}
560
561#endif /* VBOX_WITH_UNATTENDED */
562#if 0 /* Keeping this a reference */
563
564
565/*********************************************************************************************************************************
566* UnattendedSUSEXMLScript Implementation *
567*********************************************************************************************************************************/
568
569HRESULT UnattendedSUSEXMLScript::parse()
570{
571 HRESULT hrc = UnattendedXMLScript::parse();
572 if (SUCCEEDED(hrc))
573 {
574 /*
575 * Check that we've got the right root element type.
576 */
577 const xml::ElementNode *pelmRoot = mDoc.getRootElement();
578 if ( pelmRoot
579 && strcmp(pelmRoot->getName(), "profile") == 0)
580 {
581 /*
582 * Work thought the sections.
583 */
584 try
585 {
586 LoopThruSections(pelmRoot);
587 hrc = S_OK;
588 }
589 catch (std::bad_alloc &)
590 {
591 hrc = E_OUTOFMEMORY;
592 }
593 }
594 else if (pelmRoot)
595 hrc = mpSetError->setError(E_FAIL, tr("XML document root element is '%s' instead of 'profile'"),
596 pelmRoot->getName());
597 else
598 hrc = mpSetError->setError(E_FAIL, tr("Missing XML root element"));
599 }
600 return hrc;
601}
602
603HRESULT UnattendedSUSEXMLScript::setFieldInElement(xml::ElementNode *pElement, const DataId enmDataId, const Utf8Str &rStrValue)
604{
605 /*
606 * Don't set empty values.
607 */
608 if (rStrValue.isEmpty())
609 {
610 Utf8Str strProbableValue;
611 try
612 {
613 strProbableValue = createProbableValue(enmDataId, pElement);
614 }
615 catch (std::bad_alloc &)
616 {
617 return E_OUTOFMEMORY;
618 }
619 return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, strProbableValue);
620 }
621 return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, rStrValue);
622}
623
624HRESULT UnattendedSUSEXMLScript::LoopThruSections(const xml::ElementNode *pelmRoot)
625{
626 xml::NodesLoop loopChildren(*pelmRoot);
627 const xml::ElementNode *pelmOuterLoop;
628 while ((pelmOuterLoop = loopChildren.forAllNodes()) != NULL)
629 {
630 const char *pcszElemName = pelmOuterLoop->getName();
631 if (!strcmp(pcszElemName, "users"))
632 {
633 xml::NodesLoop loopUsers(*pelmOuterLoop);
634 const xml::ElementNode *pelmUser;
635 while ((pelmUser = loopUsers.forAllNodes()) != NULL)
636 {
637 HRESULT hrc = HandleUserAccountsSection(pelmUser);
638 if (FAILED(hrc))
639 return hrc;
640 }
641 }
642 }
643 return S_OK;
644}
645
646HRESULT UnattendedSUSEXMLScript::HandleUserAccountsSection(const xml::ElementNode *pelmSection)
647{
648 xml::NodesLoop loopUser(*pelmSection);
649
650 const xml::ElementNode *pelmCur;
651 while ((pelmCur = loopUser.forAllNodes()) != NULL)
652 {
653 const char *pszValue = pelmCur->getValue();
654#ifdef LOG_ENABLED
655 if (!RTStrCmp(pelmCur->getName(), "uid"))
656 LogRelFunc(("UnattendedSUSEXMLScript::HandleUserAccountsSection profile/users/%s/%s = %s\n",
657 pelmSection->getName(), pelmCur->getName(), pszValue));
658#endif
659
660 if (!RTStrCmp(pszValue, "$homedir"))
661 mNodesForCorrectionMap.insert(make_pair(USERHOMEDIR_ID, pelmCur));
662
663 if (!RTStrCmp(pszValue, "$user"))
664 mNodesForCorrectionMap.insert(make_pair(USERNAME_ID, pelmCur));
665
666 if (!RTStrCmp(pszValue, "$password"))
667 mNodesForCorrectionMap.insert(make_pair(USERPASSWORD_ID, pelmCur));
668 }
669 return S_OK;
670}
671
672Utf8Str UnattendedSUSEXMLScript::createProbableValue(const DataId enmDataId, const xml::ElementNode *pCurElem)
673{
674 const xml::ElementNode *pElem = pCurElem;
675
676 switch (enmDataId)
677 {
678 case USERHOMEDIR_ID:
679// if ((pElem = pElem->findChildElement("home")))
680// {
681 return createProbableUserHomeDir(pElem);
682// }
683 break;
684 default:
685 break;
686 }
687
688 return Utf8Str::Empty;
689}
690
691Utf8Str UnattendedSUSEXMLScript::createProbableUserHomeDir(const xml::ElementNode *pCurElem)
692{
693 Utf8Str strCalcValue;
694 const xml::ElementNode *pElem = pCurElem->findNextSibilingElement("username");
695 if (pElem)
696 {
697 const char *pszValue = pElem->getValue();
698 strCalcValue = "/home/";
699 strCalcValue.append(pszValue);
700 }
701
702 return strCalcValue;
703}
704#endif /* just for reference */
705
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