VirtualBox

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

最後變更 在這個檔案從68162是 68162,由 vboxsync 提交於 8 年 前

Main: export Unattended* source files.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 32.7 KB
 
1/* $Id: UnattendedScript.cpp 68162 2017-07-28 15:28:33Z vboxsync $ */
2/** @file
3 * Implementeation of algorithms which read/parse/save scripts for unattended installation.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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* Header Files *
20*********************************************************************************************************************************/
21#define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
22#include "LoggingNew.h"
23#include "VirtualBoxBase.h"
24#include "AutoCaller.h"
25#include <VBox/com/ErrorInfo.h>
26
27#include "MachineImpl.h"
28#include "UnattendedScript.h"
29#include "UnattendedImpl.h"
30
31#include <VBox/err.h>
32
33#include <iprt/ctype.h>
34#include <iprt/file.h>
35#include <iprt/getopt.h>
36#include <iprt/path.h>
37
38using namespace std;
39
40
41//////////////////////////////////////////////////////////////////////////////////////////////////////
42/*
43*
44*
45* Implementation BaseTextScript functions
46*
47*/
48//////////////////////////////////////////////////////////////////////////////////////////////////////
49HRESULT BaseTextScript::read(const Utf8Str &rStrFilename)
50{
51 /*
52 * Open the file for reading and figure it's size. Capping the size
53 * at 16MB so we don't exaust the heap on bad input.
54 */
55 HRESULT hrc;
56 RTVFSFILE hVfsFile;
57 int vrc = RTVfsFileOpenNormal(rStrFilename.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsFile);
58 if (RT_SUCCESS(vrc))
59 {
60 hrc = readFromHandle(hVfsFile, rStrFilename.c_str());
61 RTVfsFileRelease(hVfsFile);
62 }
63 else
64 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc);
65 return hrc;
66}
67
68HRESULT BaseTextScript::readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename)
69{
70 /*
71 * Open the file for reading and figure it's size. Capping the size
72 * at 16MB so we don't exaust the heap on bad input.
73 */
74 HRESULT hrc;
75 uint64_t cbFile = 0;
76 int vrc = RTVfsFileGetSize(hVfsFile, &cbFile);
77 if ( RT_SUCCESS(vrc)
78 && cbFile < _16M)
79 {
80 /*
81 * Exploint the jolt() feature of RTCString and read the content directly into
82 * its storage buffer.
83 */
84 vrc = mStrScriptFullContent.reserveNoThrow((size_t)cbFile + 1);
85 if (RT_SUCCESS(vrc))
86 {
87 char *pszDst = mStrScriptFullContent.mutableRaw();
88 vrc = RTVfsFileReadAt(hVfsFile, 0 /*off*/, pszDst, (size_t)cbFile, NULL);
89 pszDst[(size_t)cbFile] = '\0';
90 if (RT_SUCCESS(vrc))
91 {
92 /*
93 * We must validate the encoding or we'll be subject to potential security trouble.
94 * If this turns out to be problematic, we will need to implement codeset
95 * conversion coping mechanisms.
96 */
97 vrc = RTStrValidateEncodingEx(pszDst, (size_t)cbFile + 1,
98 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
99 if (RT_SUCCESS(vrc))
100 {
101 mStrScriptFullContent.jolt();
102 return S_OK;
103 }
104
105 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc);
106 }
107 else
108 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error reading '%s': %Rrc"), pszFilename, vrc);
109 mStrScriptFullContent.setNull();
110 }
111 else
112 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to allocate memory (%'RU64 bytes) for '%s'"),
113 cbFile, pszFilename);
114 }
115 else if (RT_SUCCESS(vrc))
116 hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG,
117 mpSetError->tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile);
118 else
119 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("RTVfsFileGetSize failed (%Rrc)"), vrc);
120 return hrc;
121}
122
123HRESULT BaseTextScript::save(const Utf8Str &rStrFilename, bool fOverwrite)
124{
125 /*
126 * We may have to append the default filename to the
127 */
128 const char *pszFilename = rStrFilename.c_str();
129 Utf8Str strWithDefaultFilename;
130 if ( getDefaultFilename() != NULL
131 && *getDefaultFilename() != '\0'
132 && RTDirExists(rStrFilename.c_str()) )
133 {
134 try
135 {
136 strWithDefaultFilename = rStrFilename;
137 strWithDefaultFilename.append(RTPATH_SLASH);
138 strWithDefaultFilename.append(getDefaultFilename());
139 }
140 catch (std::bad_alloc)
141 {
142 return E_OUTOFMEMORY;
143 }
144 pszFilename = strWithDefaultFilename.c_str();
145 }
146
147 /*
148 * Save the filename for later use.
149 */
150 try
151 {
152 mStrSavedPath = pszFilename;
153 }
154 catch (std::bad_alloc)
155 {
156 return E_OUTOFMEMORY;
157 }
158
159 /*
160 * Use the saveToString method to produce the content.
161 */
162 Utf8Str strDst;
163 HRESULT hrc = saveToString(strDst);
164 if (SUCCEEDED(hrc))
165 {
166 /*
167 * Write the content.
168 */
169 RTFILE hFile;
170 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
171 if (fOverwrite)
172 fOpen |= RTFILE_O_CREATE_REPLACE;
173 else
174 fOpen |= RTFILE_O_CREATE;
175 int vrc = RTFileOpen(&hFile, pszFilename, fOpen);
176 if (RT_SUCCESS(vrc))
177 {
178 vrc = RTFileWrite(hFile, strDst.c_str(), strDst.length(), NULL);
179 if (RT_SUCCESS(vrc))
180 {
181 vrc = RTFileClose(hFile);
182 if (RT_SUCCESS(vrc))
183 {
184 LogRelFlow(("GeneralTextScript::save(): saved %zu bytes to '%s'\n", strDst.length(), pszFilename));
185 return S_OK;
186 }
187 }
188 RTFileClose(hFile);
189 RTFileDelete(pszFilename);
190 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc);
191 }
192 else
193 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);
194 }
195 return hrc;
196}
197
198//////////////////////////////////////////////////////////////////////////////////////////////////////
199/*
200*
201*
202* Implementation UnattendedScriptTemplate methods
203*
204*/
205//////////////////////////////////////////////////////////////////////////////////////////////////////
206
207UnattendedScriptTemplate::UnattendedScriptTemplate(Unattended *pUnattended, const char *pszDefaultTemplateFilename,
208 const char *pszDefaultFilename)
209 : BaseTextScript(pUnattended, pszDefaultTemplateFilename, pszDefaultFilename), mpUnattended(pUnattended)
210{
211}
212
213
214HRESULT UnattendedScriptTemplate::saveToString(Utf8Str &rStrDst)
215{
216 static const char s_szPrefix[] = "@@VBOX_";
217 static const char s_szPrefixInsert[] = "@@VBOX_INSERT_";
218 static const char s_szPrefixCond[] = "@@VBOX_COND_";
219 static const char s_szPrefixCondEnd[] = "@@VBOX_COND_END@@";
220
221 struct
222 {
223 bool fSavedOutputting;
224 } aConds[8];
225 unsigned cConds = 0;
226 bool fOutputting = true;
227 HRESULT hrc = E_FAIL;
228 size_t offTemplate = 0;
229 size_t cchTemplate = mStrScriptFullContent.length();
230 rStrDst.setNull();
231 for (;;)
232 {
233 /*
234 * Find the next placeholder and add any text before it to the output.
235 */
236 size_t offPlaceholder = mStrScriptFullContent.find(s_szPrefix, offTemplate);
237 size_t cchToCopy = offPlaceholder != RTCString::npos ? offPlaceholder - offTemplate : cchTemplate - offTemplate;
238 if (cchToCopy > 0)
239 {
240 if (fOutputting)
241 {
242 try
243 {
244 rStrDst.append(mStrScriptFullContent, offTemplate, cchToCopy);
245 }
246 catch (std::bad_alloc)
247 {
248 hrc = E_OUTOFMEMORY;
249 break;
250 }
251 }
252 offTemplate += cchToCopy;
253 }
254
255 /*
256 * Process placeholder.
257 */
258 if (offPlaceholder != RTCString::npos)
259 {
260 /*
261 * First we must find the end of the placeholder string.
262 */
263 const char *pszPlaceholder = mStrScriptFullContent.c_str() + offPlaceholder;
264 size_t cchPlaceholder = sizeof(s_szPrefix) - 1;
265 char ch;
266 while ( offPlaceholder + cchPlaceholder < cchTemplate
267 && (ch = pszPlaceholder[cchPlaceholder]) != '\0'
268 && ( ch == '_'
269 || RT_C_IS_UPPER(ch)
270 || RT_C_IS_DIGIT(ch)) )
271 cchPlaceholder++;
272
273 if ( offPlaceholder + cchPlaceholder < cchTemplate
274 && pszPlaceholder[cchPlaceholder] == '@')
275 {
276 cchPlaceholder++;
277 if ( offPlaceholder + cchPlaceholder < cchTemplate
278 && pszPlaceholder[cchPlaceholder] == '@')
279 cchPlaceholder++;
280 }
281
282 if ( pszPlaceholder[cchPlaceholder - 1] != '@'
283 || pszPlaceholder[cchPlaceholder - 2] != '@'
284 || ( strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) != 0
285 && strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) != 0) )
286 {
287 hrc = mpSetError->setError(E_FAIL, mpSetError->tr("Malformed template placeholder '%.*s'"),
288 cchPlaceholder, pszPlaceholder);
289 break;
290 }
291
292 offTemplate += cchPlaceholder;
293
294 /*
295 * @@VBOX_INSERT_XXX@@:
296 */
297 if (strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) == 0)
298 {
299 /*
300 * Get the placeholder value and add it to the output.
301 */
302 RTCString strValue;
303 hrc = getReplacement(pszPlaceholder, cchPlaceholder, fOutputting, strValue);
304 if (SUCCEEDED(hrc))
305 {
306 if (fOutputting)
307 {
308 try
309 {
310 rStrDst.append(strValue);
311 }
312 catch (std::bad_alloc)
313 {
314 hrc = E_OUTOFMEMORY;
315 break;
316 }
317 }
318 }
319 else
320 break;
321 }
322 /*
323 * @@VBOX_COND_END@@: Pop one item of the conditional stack.
324 */
325 else if ( cchPlaceholder == sizeof(s_szPrefixCondEnd) - 1U
326 && strncmp(pszPlaceholder, s_szPrefixCondEnd, sizeof(s_szPrefixCondEnd) - 1U) == 0)
327 {
328 if (cConds > 0)
329 {
330 cConds--;
331 fOutputting = aConds[cConds].fSavedOutputting;
332 }
333 else
334 {
335 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
336 mpSetError->tr("%s without @@VBOX_COND_XXX@@ at offset %zu (%#zx)"),
337 s_szPrefixCondEnd, offPlaceholder, offPlaceholder);
338 break;
339 }
340 }
341 /*
342 * @@VBOX_COND_XXX@@: Push the previous outputting state and combine it with the
343 * one from the condition.
344 */
345 else
346 {
347 Assert(strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) == 0);
348 if (cConds + 1 < RT_ELEMENTS(aConds))
349 {
350 aConds[cConds].fSavedOutputting = fOutputting;
351 bool fNewOutputting = fOutputting;
352 hrc = getConditional(pszPlaceholder, cchPlaceholder, &fNewOutputting);
353 if (SUCCEEDED(hrc))
354 fOutputting = fOutputting && fNewOutputting;
355 else
356 break;
357 cConds++;
358 }
359 else
360 {
361 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
362 mpSetError->tr("Too deep conditional nesting at offset %zu (%#zx)"),
363 offPlaceholder, offPlaceholder);
364 break;
365 }
366 }
367 }
368
369 /*
370 * Done?
371 */
372 if (offTemplate >= cchTemplate)
373 {
374 if (cConds == 0)
375 return S_OK;
376 if (cConds == 1)
377 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, mpSetError->tr("Missing @@VBOX_COND_END@@"));
378 else
379 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, mpSetError->tr("Missing %u @@VBOX_COND_END@@"), cConds);
380 break;
381 }
382 }
383
384 /* failed */
385 rStrDst.setNull();
386 return hrc;
387}
388
389HRESULT UnattendedScriptTemplate::getReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
390 bool fOutputting, RTCString &rValue)
391{
392 /*
393 * Check for an escaping suffix. Drop the '@@'.
394 */
395 size_t const cchFullPlaceholder = cchPlaceholder;
396 enum
397 {
398 kValueEscaping_None,
399 kValueEscaping_Bourne,
400 kValueEscaping_XML_Element,
401 kValueEscaping_XML_Attribute_Double_Quotes
402 } enmEscaping;
403
404#define PLACEHOLDER_ENDS_WITH(a_szSuffix) \
405 ( cchPlaceholder > sizeof(a_szSuffix) - 1U \
406 && memcmp(&pachPlaceholder[cchPlaceholder - sizeof(a_szSuffix) + 1U], a_szSuffix, sizeof(a_szSuffix) - 1U) == 0)
407 if (PLACEHOLDER_ENDS_WITH("_SH@@"))
408 {
409 cchPlaceholder -= 3 + 2;
410 enmEscaping = kValueEscaping_Bourne;
411 }
412 else if (PLACEHOLDER_ENDS_WITH("_ELEMENT@@"))
413 {
414 cchPlaceholder -= 8 + 2;
415 enmEscaping = kValueEscaping_XML_Element;
416 }
417 else if (PLACEHOLDER_ENDS_WITH("_ATTRIB_DQ@@"))
418 {
419 cchPlaceholder -= 10 + 2;
420 enmEscaping = kValueEscaping_XML_Attribute_Double_Quotes;
421 }
422 else
423 {
424 Assert(PLACEHOLDER_ENDS_WITH("@@"));
425 cchPlaceholder -= 2;
426 enmEscaping = kValueEscaping_None;
427 }
428
429 /*
430 * Resolve and escape the value.
431 */
432 HRESULT hrc;
433 try
434 {
435 switch (enmEscaping)
436 {
437 case kValueEscaping_None:
438 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, rValue);
439 if (SUCCEEDED(hrc))
440 return hrc;
441 break;
442
443 case kValueEscaping_Bourne:
444 case kValueEscaping_XML_Element:
445 case kValueEscaping_XML_Attribute_Double_Quotes:
446 {
447 RTCString strUnescaped;
448 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, strUnescaped);
449 if (SUCCEEDED(hrc))
450 {
451 switch (enmEscaping)
452 {
453 case kValueEscaping_Bourne:
454 {
455 const char * const papszArgs[2] = { strUnescaped.c_str(), NULL };
456 char *pszEscaped = NULL;
457 int vrc = RTGetOptArgvToString(&pszEscaped, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
458 if (RT_SUCCESS(vrc))
459 {
460 try
461 {
462 rValue = pszEscaped;
463 RTStrFree(pszEscaped);
464 return S_OK;
465 }
466 catch (std::bad_alloc)
467 {
468 hrc = E_OUTOFMEMORY;
469 }
470 RTStrFree(pszEscaped);
471 }
472 break;
473 }
474
475 case kValueEscaping_XML_Element:
476 rValue.printf("%RMes", strUnescaped.c_str());
477 return S_OK;
478
479 case kValueEscaping_XML_Attribute_Double_Quotes:
480 {
481 RTCString strTmp;
482 strTmp.printf("%RMas", strUnescaped.c_str());
483 rValue = RTCString(strTmp, 1, strTmp.length() - 2);
484 return S_OK;
485 }
486
487 default:
488 hrc = E_FAIL;
489 break;
490 }
491 }
492 break;
493 }
494
495 default:
496 AssertFailedStmt(hrc = E_FAIL);
497 break;
498 }
499 }
500 catch (std::bad_alloc)
501 {
502 hrc = E_OUTOFMEMORY;
503 }
504 rValue.setNull();
505 return hrc;
506}
507
508HRESULT UnattendedScriptTemplate::getUnescapedReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
509 size_t cchFullPlaceholder, bool fOutputting, RTCString &rValue)
510{
511 RT_NOREF(fOutputting);
512#define IS_PLACEHOLDER_MATCH(a_szMatch) \
513 ( cchPlaceholder == sizeof("@@VBOX_INSERT_" a_szMatch) - 1U \
514 && memcmp(pachPlaceholder, "@@VBOX_INSERT_" a_szMatch, sizeof("@@VBOX_INSERT_" a_szMatch) - 1U) == 0)
515
516 if (IS_PLACEHOLDER_MATCH("USER_LOGIN"))
517 rValue = mpUnattended->i_getUser();
518 else if (IS_PLACEHOLDER_MATCH("USER_PASSWORD"))
519 rValue = mpUnattended->i_getPassword();
520 else if (IS_PLACEHOLDER_MATCH("ROOT_PASSWORD"))
521 rValue = mpUnattended->i_getPassword();
522 else if (IS_PLACEHOLDER_MATCH("USER_FULL_NAME"))
523 rValue = mpUnattended->i_getFullUserName();
524 else if (IS_PLACEHOLDER_MATCH("PRODUCT_KEY"))
525 rValue = mpUnattended->i_getProductKey();
526 else if (IS_PLACEHOLDER_MATCH("POST_INSTALL_COMMAND"))
527 rValue = mpUnattended->i_getPostInstallCommand();
528 else if (IS_PLACEHOLDER_MATCH("IMAGE_INDEX"))
529 rValue.printf("%u", mpUnattended->i_getImageIndex());
530 else if (IS_PLACEHOLDER_MATCH("OS_ARCH"))
531 rValue = mpUnattended->i_isGuestOs64Bit() ? "amd64" : "x86";
532 else if (IS_PLACEHOLDER_MATCH("OS_ARCH2"))
533 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "x86";
534 else if (IS_PLACEHOLDER_MATCH("OS_ARCH3"))
535 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i386";
536 else if (IS_PLACEHOLDER_MATCH("OS_ARCH4"))
537 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i486";
538 else if (IS_PLACEHOLDER_MATCH("OS_ARCH6"))
539 rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i686";
540 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_UX"))
541 rValue = mpUnattended->i_getTimeZoneInfo()
542 ? mpUnattended->i_getTimeZoneInfo()->pszUnixName : mpUnattended->i_getTimeZone();
543 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_NAME"))
544 {
545 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
546 if (pInfo)
547 rValue = pInfo->pszWindowsName ? pInfo->pszWindowsName : "GMT";
548 else
549 rValue = mpUnattended->i_getTimeZone();
550 }
551 else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_INDEX"))
552 {
553 PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
554 if (pInfo)
555 rValue.printf("%u", pInfo->idxWindows ? pInfo->idxWindows : 85 /*GMT*/);
556 else
557 rValue = mpUnattended->i_getTimeZone();
558 }
559 else if (IS_PLACEHOLDER_MATCH("LOCALE"))
560 rValue = mpUnattended->i_getLocale();
561 else if (IS_PLACEHOLDER_MATCH("COUNTRY"))
562 rValue = mpUnattended->i_getCountry();
563 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_FQDN"))
564 rValue = mpUnattended->i_getHostname();
565 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_WITHOUT_DOMAIN"))
566 rValue.assign(mpUnattended->i_getHostname(), 0, mpUnattended->i_getHostname().find("."));
567 else if (IS_PLACEHOLDER_MATCH("HOSTNAME_DOMAIN"))
568 rValue.assign(mpUnattended->i_getHostname(), mpUnattended->i_getHostname().find(".") + 1);
569 else
570 {
571 rValue.setNull();
572 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, mpSetError->tr("Unknown template placeholder '%.*s'"),
573 cchFullPlaceholder, pachPlaceholder);
574 }
575 return S_OK;
576#undef IS_PLACEHOLDER_MATCH
577}
578
579HRESULT UnattendedScriptTemplate::getConditional(const char *pachPlaceholder, size_t cchPlaceholder, bool *pfOutputting)
580{
581#define IS_PLACEHOLDER_MATCH(a_szMatch) \
582 ( cchPlaceholder == sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U \
583 && memcmp(pachPlaceholder, "@@VBOX_COND_" a_szMatch "@@", sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U) == 0)
584
585 /* Install guest additions: */
586 if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_ADDITIONS"))
587 *pfOutputting = mpUnattended->i_getInstallGuestAdditions();
588 else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_ADDITIONS"))
589 *pfOutputting = !mpUnattended->i_getInstallGuestAdditions();
590 /* User == Administrator: */
591 else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_ADMINISTRATOR"))
592 *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) == 0;
593 else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_NOT_ADMINISTRATOR"))
594 *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) != 0;
595 /* Install TXS: */
596 else if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_TEST_EXEC_SERVICE"))
597 *pfOutputting = mpUnattended->i_getInstallTestExecService();
598 else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_TEST_EXEC_SERVICE"))
599 *pfOutputting = !mpUnattended->i_getInstallTestExecService();
600 /* Post install command: */
601 else if (IS_PLACEHOLDER_MATCH("HAS_POST_INSTALL_COMMAND"))
602 *pfOutputting = mpUnattended->i_getPostInstallCommand().isNotEmpty();
603 else if (IS_PLACEHOLDER_MATCH("HAS_NO_POST_INSTALL_COMMAND"))
604 *pfOutputting = !mpUnattended->i_getPostInstallCommand().isNotEmpty();
605 /* Minimal installation: */
606 else if (IS_PLACEHOLDER_MATCH("IS_MINIMAL_INSTALLATION"))
607 *pfOutputting = mpUnattended->i_isMinimalInstallation();
608 else if (IS_PLACEHOLDER_MATCH("IS_NOT_MINIMAL_INSTALLATION"))
609 *pfOutputting = !mpUnattended->i_isMinimalInstallation();
610 else
611 return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, mpSetError->tr("Unknown conditional placeholder '%.*s'"),
612 cchPlaceholder, pachPlaceholder);
613 return S_OK;
614#undef IS_PLACEHOLDER_MATCH
615}
616
617
618//////////////////////////////////////////////////////////////////////////////////////////////////////
619/*
620*
621*
622* Implementation GeneralTextScript functions
623*
624*/
625//////////////////////////////////////////////////////////////////////////////////////////////////////
626HRESULT GeneralTextScript::parse()
627{
628 AssertReturn(!mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "parse called more than once"));
629
630 /*
631 * Split the raw context into an array of lines.
632 */
633 try
634 {
635 mScriptContentByLines = mStrScriptFullContent.split("\n");
636 }
637 catch (std::bad_alloc)
638 {
639 mScriptContentByLines.clear();
640 return E_OUTOFMEMORY;
641 }
642
643 mfDataParsed = true;
644 return S_OK;
645}
646
647HRESULT GeneralTextScript::saveToString(Utf8Str &rStrDst)
648{
649 AssertReturn(mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "saveToString() called before parse()"));
650
651 /*
652 * Calc the required size first.
653 */
654 size_t const cLines = mScriptContentByLines.size();
655 size_t cbTotal = 1;
656 for (size_t iLine = 0; iLine < cLines; iLine++)
657 cbTotal = mScriptContentByLines[iLine].length() + 1;
658
659 /*
660 * Clear the output and try reserve sufficient space.
661 */
662 rStrDst.setNull();
663
664 int vrc = rStrDst.reserveNoThrow(cbTotal);
665 if (RT_FAILURE(vrc))
666 return E_OUTOFMEMORY;
667
668 /*
669 * Assemble the output.
670 */
671 for (size_t iLine = 0; iLine < cLines; iLine++)
672 {
673 try
674 {
675 rStrDst.append(mScriptContentByLines[iLine]);
676 rStrDst.append('\n');
677 }
678 catch (std::bad_alloc)
679 {
680 return E_OUTOFMEMORY;
681 }
682 }
683
684 return S_OK;
685}
686
687const RTCString &GeneralTextScript::getContentOfLine(size_t idxLine)
688{
689 if (idxLine < mScriptContentByLines.size())
690 return mScriptContentByLines[idxLine];
691 return Utf8Str::Empty;
692}
693
694
695HRESULT GeneralTextScript::setContentOfLine(size_t idxLine, const Utf8Str &rStrNewLine)
696{
697 AssertReturn(idxLine < mScriptContentByLines.size(),
698 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "attempting to set line %zu when there are only %zu lines",
699 idxLine, mScriptContentByLines.size()));
700 try
701 {
702 mScriptContentByLines[idxLine] = rStrNewLine;
703 }
704 catch (std::bad_alloc)
705 {
706 return E_OUTOFMEMORY;
707 }
708 return S_OK;
709}
710
711vector<size_t> GeneralTextScript::findTemplate(const Utf8Str &rStrNeedle,
712 RTCString::CaseSensitivity enmCase /*= RTCString::CaseSensitive*/)
713{
714 vector<size_t> vecHitLineNumbers;
715 size_t const cLines = mScriptContentByLines.size();
716 for (size_t iLine = 0; iLine < cLines; iLine++)
717 if (mScriptContentByLines[iLine].contains(rStrNeedle, enmCase))
718 vecHitLineNumbers.push_back(iLine);
719
720 return vecHitLineNumbers;
721}
722
723HRESULT GeneralTextScript::findAndReplace(size_t idxLine, const Utf8Str &rStrNeedle, const Utf8Str &rStrReplacement)
724{
725 AssertReturn(idxLine < mScriptContentByLines.size(),
726 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE,
727 "attempting search&replace in line %zu when there are only %zu lines",
728 idxLine, mScriptContentByLines.size()));
729
730 RTCString &rDstString = mScriptContentByLines[idxLine];
731 size_t const offNeedle = rDstString.find(&rStrNeedle);
732 if (offNeedle != RTCString::npos)
733 {
734 try
735 {
736 RTCString strBefore(rDstString, 0, offNeedle);
737 RTCString strAfter(rDstString, offNeedle + rStrNeedle.length());
738 rDstString = strBefore;
739 strBefore.setNull();
740 rDstString.append(rStrReplacement);
741 rDstString.append(strAfter);
742 }
743 catch (std::bad_alloc)
744 {
745 return E_OUTOFMEMORY;
746 }
747 }
748 return S_OK;
749}
750
751HRESULT GeneralTextScript::appendToLine(size_t idxLine, const Utf8Str &rStrToAppend)
752{
753 AssertReturn(idxLine < mScriptContentByLines.size(),
754 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "appending to line %zu when there are only %zu lines",
755 idxLine, mScriptContentByLines.size()));
756
757 try
758 {
759 mScriptContentByLines[idxLine].append(rStrToAppend);
760 }
761 catch (std::bad_alloc)
762 {
763 return E_OUTOFMEMORY;
764 }
765 return S_OK;
766}
767
768HRESULT GeneralTextScript::prependToLine(size_t idxLine, const Utf8Str &rStrToPrepend)
769{
770 AssertReturn(idxLine < mScriptContentByLines.size(),
771 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "prepending to line %zu when there are only %zu lines",
772 idxLine, mScriptContentByLines.size()));
773
774 RTCString &rDstString = mScriptContentByLines[idxLine];
775 try
776 {
777 RTCString strCopy;
778 rDstString.swap(strCopy);
779 rDstString.reserve(strCopy.length() + rStrToPrepend.length() + 1);
780 rDstString = rStrToPrepend;
781 rDstString.append(strCopy);
782 }
783 catch (std::bad_alloc)
784 {
785 return E_OUTOFMEMORY;
786 }
787 return S_OK;
788}
789
790#if 0 /* Keeping this a reference */
791//////////////////////////////////////////////////////////////////////////////////////////////////////
792/*
793*
794*
795* Implementation UnattendedSUSEXMLScript functions
796*
797*/
798/////////////////////////////////////////////////////////////////////////////////////////////////////
799HRESULT UnattendedSUSEXMLScript::parse()
800{
801 HRESULT hrc = UnattendedXMLScript::parse();
802 if (SUCCEEDED(hrc))
803 {
804 /*
805 * Check that we've got the right root element type.
806 */
807 const xml::ElementNode *pelmRoot = mDoc.getRootElement();
808 if ( pelmRoot
809 && strcmp(pelmRoot->getName(), "profile") == 0)
810 {
811 /*
812 * Work thought the sections.
813 */
814 try
815 {
816 LoopThruSections(pelmRoot);
817 hrc = S_OK;
818 }
819 catch (std::bad_alloc)
820 {
821 hrc = E_OUTOFMEMORY;
822 }
823 }
824 else if (pelmRoot)
825 hrc = mpSetError->setError(E_FAIL, mpSetError->tr("XML document root element is '%s' instead of 'profile'"),
826 pelmRoot->getName());
827 else
828 hrc = mpSetError->setError(E_FAIL, mpSetError->tr("Missing XML root element"));
829 }
830 return hrc;
831}
832
833HRESULT UnattendedSUSEXMLScript::setFieldInElement(xml::ElementNode *pElement, const DataId enmDataId, const Utf8Str &rStrValue)
834{
835 /*
836 * Don't set empty values.
837 */
838 if (rStrValue.isEmpty())
839 {
840 Utf8Str strProbableValue;
841 try
842 {
843 strProbableValue = createProbableValue(enmDataId, pElement);
844 }
845 catch (std::bad_alloc)
846 {
847 return E_OUTOFMEMORY;
848 }
849 return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, strProbableValue);
850 }
851 return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, rStrValue);
852}
853
854HRESULT UnattendedSUSEXMLScript::LoopThruSections(const xml::ElementNode *pelmRoot)
855{
856 xml::NodesLoop loopChildren(*pelmRoot);
857 const xml::ElementNode *pelmOuterLoop;
858 while ((pelmOuterLoop = loopChildren.forAllNodes()) != NULL)
859 {
860 const char *pcszElemName = pelmOuterLoop->getName();
861 if (!strcmp(pcszElemName, "users"))
862 {
863 xml::NodesLoop loopUsers(*pelmOuterLoop);
864 const xml::ElementNode *pelmUser;
865 while ((pelmUser = loopUsers.forAllNodes()) != NULL)
866 {
867 HRESULT hrc = HandleUserAccountsSection(pelmUser);
868 if (FAILED(hrc))
869 return hrc;
870 }
871 }
872 }
873 return S_OK;
874}
875
876HRESULT UnattendedSUSEXMLScript::HandleUserAccountsSection(const xml::ElementNode *pelmSection)
877{
878 xml::NodesLoop loopUser(*pelmSection);
879
880 const xml::ElementNode *pelmCur;
881 while ((pelmCur = loopUser.forAllNodes()) != NULL)
882 {
883 const char *pszValue = pelmCur->getValue();
884#ifdef LOG_ENABLED
885 if (!RTStrCmp(pelmCur->getName(), "uid"))
886 LogRelFunc(("UnattendedSUSEXMLScript::HandleUserAccountsSection profile/users/%s/%s = %s\n",
887 pelmSection->getName(), pelmCur->getName(), pszValue));
888#endif
889
890 if (!RTStrCmp(pszValue, "$homedir"))
891 mNodesForCorrectionMap.insert(make_pair(USERHOMEDIR_ID, pelmCur));
892
893 if (!RTStrCmp(pszValue, "$user"))
894 mNodesForCorrectionMap.insert(make_pair(USERNAME_ID, pelmCur));
895
896 if (!RTStrCmp(pszValue, "$password"))
897 mNodesForCorrectionMap.insert(make_pair(USERPASSWORD_ID, pelmCur));
898 }
899 return S_OK;
900}
901
902Utf8Str UnattendedSUSEXMLScript::createProbableValue(const DataId enmDataId, const xml::ElementNode *pCurElem)
903{
904 const xml::ElementNode *pElem = pCurElem;
905
906 switch (enmDataId)
907 {
908 case USERHOMEDIR_ID:
909// if ((pElem = pElem->findChildElement("home")))
910// {
911 return createProbableUserHomeDir(pElem);
912// }
913 break;
914 default:
915 break;
916 }
917
918 return Utf8Str::Empty;
919}
920
921Utf8Str UnattendedSUSEXMLScript::createProbableUserHomeDir(const xml::ElementNode *pCurElem)
922{
923 Utf8Str strCalcValue;
924 const xml::ElementNode *pElem = pCurElem->findNextSibilingElement("username");
925 if (pElem)
926 {
927 const char *pszValue = pElem->getValue();
928 strCalcValue = "/home/";
929 strCalcValue.append(pszValue);
930 }
931
932 return strCalcValue;
933}
934#endif /* just for reference */
935
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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