VirtualBox

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

Last change on this file since 86336 was 86336, checked in by vboxsync, 4 years ago

bugref:9781. Fixed the comment.

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

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