VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/CFGM.cpp@ 96860

Last change on this file since 96860 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 100.8 KB
Line 
1/* $Id: CFGM.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * CFGM - Configuration Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/** @page pg_cfgm CFGM - The Configuration Manager
29 *
30 * The configuration manager is a directory containing the VM configuration at
31 * run time. It works in a manner similar to the windows registry - it's like a
32 * file system hierarchy, but the files (values) live in a separate name space
33 * and can include the path separators.
34 *
35 * The configuration is normally created via a callback passed to VMR3Create()
36 * via the pfnCFGMConstructor parameter. To make testcase writing a bit simpler,
37 * we allow the callback to be NULL, in which case a simple default
38 * configuration will be created by CFGMR3ConstructDefaultTree(). The
39 * Console::configConstructor() method in Main/ConsoleImpl2.cpp creates the
40 * configuration from the XML.
41 *
42 * Devices, drivers, services and other PDM stuff are given their own subtree
43 * where they are protected from accessing information of any parents. This is
44 * is implemented via the CFGMR3SetRestrictedRoot() API.
45 *
46 * Data validation beyond the basic primitives is left to the caller. The caller
47 * is in a better position to know the proper validation rules of the individual
48 * properties.
49 *
50 * @see grp_cfgm
51 *
52 *
53 * @section sec_cfgm_primitives Data Primitives
54 *
55 * CFGM supports the following data primitives:
56 * - Integers. Representation is unsigned 64-bit. Boolean, unsigned and
57 * small integers, and pointers are all represented using this primitive.
58 * - Zero terminated character strings. These are of course UTF-8.
59 * - Variable length byte strings. This can be used to get/put binary
60 * objects like for instance RTMAC.
61 *
62 */
63
64
65/*********************************************************************************************************************************
66* Header Files *
67*********************************************************************************************************************************/
68#define LOG_GROUP LOG_GROUP_CFGM
69#include <VBox/vmm/cfgm.h>
70#include <VBox/vmm/dbgf.h>
71#include <VBox/vmm/mm.h>
72#include <VBox/vmm/vmm.h>
73#include "CFGMInternal.h"
74#include <VBox/vmm/vm.h>
75#include <VBox/vmm/uvm.h>
76#include <VBox/err.h>
77
78#include <VBox/log.h>
79#include <iprt/assert.h>
80#include <iprt/mem.h>
81#include <iprt/memsafer.h>
82#include <iprt/param.h>
83#include <iprt/string.h>
84#include <iprt/utf16.h>
85#include <iprt/uuid.h>
86
87
88/*********************************************************************************************************************************
89* Internal Functions *
90*********************************************************************************************************************************/
91static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp);
92static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp);
93static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
94static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild);
95static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
96static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
97static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf);
98static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf);
99
100
101/** @todo replace pVM for pUVM !*/
102
103/**
104 * Allocator wrapper.
105 *
106 * @returns Pointer to the allocated memory, NULL on failure.
107 * @param pVM The cross context VM structure, if the tree
108 * is associated with one.
109 * @param enmTag The allocation tag.
110 * @param cb The size of the allocation.
111 */
112static void *cfgmR3MemAlloc(PVM pVM, MMTAG enmTag, size_t cb)
113{
114 if (pVM)
115 return MMR3HeapAlloc(pVM, enmTag, cb);
116 return RTMemAlloc(cb);
117}
118
119
120/**
121 * Free wrapper.
122 *
123 * @returns Pointer to the allocated memory, NULL on failure.
124 * @param pVM The cross context VM structure, if the tree
125 * is associated with one.
126 * @param pv The memory block to free.
127 */
128static void cfgmR3MemFree(PVM pVM, void *pv)
129{
130 if (pVM)
131 MMR3HeapFree(pv);
132 else
133 RTMemFree(pv);
134}
135
136
137/**
138 * String allocator wrapper.
139 *
140 * @returns Pointer to the allocated memory, NULL on failure.
141 * @param pVM The cross context VM structure, if the tree
142 * is associated with one.
143 * @param enmTag The allocation tag.
144 * @param cbString The size of the allocation, terminator included.
145 */
146static char *cfgmR3StrAlloc(PVM pVM, MMTAG enmTag, size_t cbString)
147{
148 if (pVM)
149 return (char *)MMR3HeapAlloc(pVM, enmTag, cbString);
150 return (char *)RTStrAlloc(cbString);
151}
152
153
154/**
155 * String free wrapper.
156 *
157 * @returns Pointer to the allocated memory, NULL on failure.
158 * @param pVM The cross context VM structure, if the tree
159 * is associated with one.
160 * @param pszString The memory block to free.
161 */
162static void cfgmR3StrFree(PVM pVM, char *pszString)
163{
164 if (pVM)
165 MMR3HeapFree(pszString);
166 else
167 RTStrFree(pszString);
168}
169
170
171/**
172 * Frees one node, leaving any children or leaves to the caller.
173 *
174 * @param pNode The node structure to free.
175 */
176static void cfgmR3FreeNodeOnly(PCFGMNODE pNode)
177{
178 pNode->pFirstLeaf = NULL;
179 pNode->pFirstChild = NULL;
180 pNode->pNext = NULL;
181 pNode->pPrev = NULL;
182 if (!pNode->pVM)
183 RTMemFree(pNode);
184 else
185 {
186 pNode->pVM = NULL;
187 MMR3HeapFree(pNode);
188 }
189}
190
191
192
193
194/**
195 * Constructs the configuration for the VM.
196 *
197 * This should only be called used once.
198 *
199 * @returns VBox status code.
200 * @param pVM The cross context VM structure.
201 * @param pfnCFGMConstructor Pointer to callback function for constructing
202 * the VM configuration tree. This is called on
203 * the EMT.
204 * @param pvUser The user argument passed to pfnCFGMConstructor.
205 * @thread EMT.
206 * @internal
207 */
208VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser)
209{
210 LogFlow(("CFGMR3Init: pfnCFGMConstructor=%p pvUser=%p\n", pfnCFGMConstructor, pvUser));
211
212 /*
213 * Init data members.
214 */
215 pVM->cfgm.s.pRoot = NULL;
216
217 /*
218 * Register DBGF into item.
219 */
220 int rc = DBGFR3InfoRegisterInternal(pVM, "cfgm", "Dumps a part of the CFGM tree. The argument indicates where to start.",
221 cfgmR3Info);
222 AssertRCReturn(rc,rc);
223
224 /*
225 * Root Node.
226 */
227 PCFGMNODE pRoot = (PCFGMNODE)MMR3HeapAllocZ(pVM, MM_TAG_CFGM, sizeof(*pRoot));
228 if (!pRoot)
229 return VERR_NO_MEMORY;
230 pRoot->pVM = pVM;
231 pRoot->cchName = 0;
232 pVM->cfgm.s.pRoot = pRoot;
233
234 /*
235 * Call the constructor if specified, if not use the default one.
236 */
237 if (pfnCFGMConstructor)
238 rc = pfnCFGMConstructor(pVM->pUVM, pVM, VMMR3GetVTable(), pvUser);
239 else
240 rc = CFGMR3ConstructDefaultTree(pVM);
241 if (RT_SUCCESS(rc))
242 {
243 Log(("CFGMR3Init: Successfully constructed the configuration\n"));
244 CFGMR3Dump(CFGMR3GetRoot(pVM));
245 }
246 else
247 LogRel(("Constructor failed with rc=%Rrc pfnCFGMConstructor=%p\n", rc, pfnCFGMConstructor));
248
249 return rc;
250}
251
252
253/**
254 * Terminates the configuration manager.
255 *
256 * @returns VBox status code.
257 * @param pVM The cross context VM structure.
258 * @internal
259 */
260VMMR3DECL(int) CFGMR3Term(PVM pVM)
261{
262 CFGMR3RemoveNode(pVM->cfgm.s.pRoot);
263 pVM->cfgm.s.pRoot = NULL;
264 return 0;
265}
266
267
268/**
269 * Gets the root node for the VM.
270 *
271 * @returns Pointer to root node.
272 * @param pVM The cross context VM structure.
273 */
274VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM)
275{
276 return pVM->cfgm.s.pRoot;
277}
278
279
280/**
281 * Gets the root node for the VM.
282 *
283 * @returns Pointer to root node.
284 * @param pUVM The user mode VM structure.
285 */
286VMMR3DECL(PCFGMNODE) CFGMR3GetRootU(PUVM pUVM)
287{
288 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
289 PVM pVM = pUVM->pVM;
290 AssertReturn(pVM, NULL);
291 return pVM->cfgm.s.pRoot;
292}
293
294
295/**
296 * Gets the parent of a CFGM node.
297 *
298 * @returns Pointer to the parent node.
299 * @returns NULL if pNode is Root or pNode is the start of a
300 * restricted subtree (use CFGMR3GetParentEx() for that).
301 *
302 * @param pNode The node which parent we query.
303 */
304VMMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode)
305{
306 if (pNode && !pNode->fRestrictedRoot)
307 return pNode->pParent;
308 return NULL;
309}
310
311
312/**
313 * Gets the parent of a CFGM node.
314 *
315 * @returns Pointer to the parent node.
316 * @returns NULL if pNode is Root or pVM is not correct.
317 *
318 * @param pVM The cross context VM structure. Used as token that
319 * the caller is trusted.
320 * @param pNode The node which parent we query.
321 */
322VMMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode)
323{
324 if (pNode && pNode->pVM == pVM)
325 return pNode->pParent;
326 return NULL;
327}
328
329
330/**
331 * Query a child node.
332 *
333 * @returns Pointer to the specified node.
334 * @returns NULL if node was not found or pNode is NULL.
335 * @param pNode Node pszPath is relative to.
336 * @param pszPath Path to the child node or pNode.
337 * It's good style to end this with '/'.
338 */
339VMMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath)
340{
341 PCFGMNODE pChild;
342 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
343 if (RT_SUCCESS(rc))
344 return pChild;
345 return NULL;
346}
347
348
349/**
350 * Query a child node by a format string.
351 *
352 * @returns Pointer to the specified node.
353 * @returns NULL if node was not found or pNode is NULL.
354 * @param pNode Node pszPath is relative to.
355 * @param pszPathFormat Path to the child node or pNode.
356 * It's good style to end this with '/'.
357 * @param ... Arguments to pszPathFormat.
358 */
359VMMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...)
360{
361 va_list Args;
362 va_start(Args, pszPathFormat);
363 PCFGMNODE pRet = CFGMR3GetChildFV(pNode, pszPathFormat, Args);
364 va_end(Args);
365 return pRet;
366}
367
368
369/**
370 * Query a child node by a format string.
371 *
372 * @returns Pointer to the specified node.
373 * @returns NULL if node was not found or pNode is NULL.
374 * @param pNode Node pszPath is relative to.
375 * @param pszPathFormat Path to the child node or pNode.
376 * It's good style to end this with '/'.
377 * @param Args Arguments to pszPathFormat.
378 */
379VMMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args)
380{
381 char *pszPath;
382 RTStrAPrintfV(&pszPath, pszPathFormat, Args);
383 if (pszPath)
384 {
385 PCFGMNODE pChild;
386 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
387 RTStrFree(pszPath);
388 if (RT_SUCCESS(rc))
389 return pChild;
390 }
391 return NULL;
392}
393
394
395/**
396 * Gets the first child node.
397 * Use this to start an enumeration of child nodes.
398 *
399 * @returns Pointer to the first child.
400 * @returns NULL if no children.
401 * @param pNode Node to enumerate children for.
402 */
403VMMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode)
404{
405 return pNode ? pNode->pFirstChild : NULL;
406}
407
408
409/**
410 * Gets the next sibling node.
411 * Use this to continue an enumeration.
412 *
413 * @returns Pointer to the first child.
414 * @returns NULL if no children.
415 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
416 * or successive calls to this function.
417 */
418VMMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur)
419{
420 return pCur ? pCur->pNext : NULL;
421}
422
423
424/**
425 * Gets the name of the current node.
426 * (Needed for enumeration.)
427 *
428 * @returns VBox status code.
429 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
430 * or successive calls to CFGMR3GetNextChild().
431 * @param pszName Where to store the node name.
432 * @param cchName Size of the buffer pointed to by pszName (with terminator).
433 */
434VMMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName)
435{
436 int rc;
437 if (pCur)
438 {
439 if (cchName > pCur->cchName)
440 {
441 rc = VINF_SUCCESS;
442 memcpy(pszName, pCur->szName, pCur->cchName + 1);
443 }
444 else
445 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
446 }
447 else
448 rc = VERR_CFGM_NO_NODE;
449 return rc;
450}
451
452
453/**
454 * Gets the length of the current node's name.
455 * (Needed for enumeration.)
456 *
457 * @returns Node name length in bytes including the terminating null char.
458 * @returns 0 if pCur is NULL.
459 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
460 * or successive calls to CFGMR3GetNextChild().
461 */
462VMMR3DECL(size_t) CFGMR3GetNameLen(PCFGMNODE pCur)
463{
464 return pCur ? pCur->cchName + 1 : 0;
465}
466
467
468/**
469 * Validates that the child nodes are within a set of valid names.
470 *
471 * @returns true if all names are found in pszzAllowed.
472 * @returns false if not.
473 * @param pNode The node which children should be examined.
474 * @param pszzValid List of valid names separated by '\\0' and ending with
475 * a double '\\0'.
476 *
477 * @deprecated Use CFGMR3ValidateConfig.
478 */
479VMMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid)
480{
481 if (pNode)
482 {
483 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
484 {
485 /* search pszzValid for the name */
486 const char *psz = pszzValid;
487 while (*psz)
488 {
489 size_t cch = strlen(psz);
490 if ( cch == pChild->cchName
491 && !memcmp(psz, pChild->szName, cch))
492 break;
493
494 /* next */
495 psz += cch + 1;
496 }
497
498 /* if at end of pszzValid we didn't find it => failure */
499 if (!*psz)
500 {
501 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pChild->szName));
502 return false;
503 }
504 }
505 }
506
507 /* all ok. */
508 return true;
509}
510
511
512/**
513 * Gets the first value of a node.
514 * Use this to start an enumeration of values.
515 *
516 * @returns Pointer to the first value.
517 * @param pCur The node (Key) which values to enumerate.
518 */
519VMMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur)
520{
521 return pCur ? pCur->pFirstLeaf : NULL;
522}
523
524/**
525 * Gets the next value in enumeration.
526 *
527 * @returns Pointer to the next value.
528 * @param pCur The current value as returned by this function or CFGMR3GetFirstValue().
529 */
530VMMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur)
531{
532 return pCur ? pCur->pNext : NULL;
533}
534
535/**
536 * Get the value name.
537 * (Needed for enumeration.)
538 *
539 * @returns VBox status code.
540 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
541 * or successive calls to CFGMR3GetNextValue().
542 * @param pszName Where to store the value name.
543 * @param cchName Size of the buffer pointed to by pszName (with terminator).
544 */
545VMMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName)
546{
547 int rc;
548 if (pCur)
549 {
550 if (cchName > pCur->cchName)
551 {
552 rc = VINF_SUCCESS;
553 memcpy(pszName, pCur->szName, pCur->cchName + 1);
554 }
555 else
556 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
557 }
558 else
559 rc = VERR_CFGM_NO_NODE;
560 return rc;
561}
562
563
564/**
565 * Gets the length of the current node's name.
566 * (Needed for enumeration.)
567 *
568 * @returns Value name length in bytes including the terminating null char.
569 * @returns 0 if pCur is NULL.
570 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
571 * or successive calls to CFGMR3GetNextValue().
572 */
573VMMR3DECL(size_t) CFGMR3GetValueNameLen(PCFGMLEAF pCur)
574{
575 return pCur ? pCur->cchName + 1 : 0;
576}
577
578
579/**
580 * Gets the value type.
581 * (For enumeration.)
582 *
583 * @returns VBox status code.
584 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
585 * or successive calls to CFGMR3GetNextValue().
586 */
587VMMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur)
588{
589 Assert(pCur);
590 return pCur->enmType;
591}
592
593
594/**
595 * Validates that the values are within a set of valid names.
596 *
597 * @returns true if all names are found in pszzValid.
598 * @returns false if not.
599 * @param pNode The node which values should be examined.
600 * @param pszzValid List of valid names separated by '\\0' and ending with
601 * a double '\\0'.
602 * @deprecated Use CFGMR3ValidateConfig.
603 */
604VMMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid)
605{
606 if (pNode)
607 {
608 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
609 {
610 /* search pszzValid for the name */
611 const char *psz = pszzValid;
612 while (*psz)
613 {
614 size_t cch = strlen(psz);
615 if ( cch == pLeaf->cchName
616 && !memcmp(psz, pLeaf->szName, cch))
617 break;
618
619 /* next */
620 psz += cch + 1;
621 }
622
623 /* if at end of pszzValid we didn't find it => failure */
624 if (!*psz)
625 {
626 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pLeaf->szName));
627 return false;
628 }
629 }
630 }
631
632 /* all ok. */
633 return true;
634}
635
636
637/**
638 * Checks if the given value exists.
639 *
640 * @returns true if it exists, false if not.
641 * @param pNode Which node to search for pszName in.
642 * @param pszName The name of the value we seek.
643 */
644VMMR3DECL(bool) CFGMR3Exists(PCFGMNODE pNode, const char *pszName)
645{
646 PCFGMLEAF pLeaf;
647 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
648 return RT_SUCCESS_NP(rc);
649}
650
651
652/**
653 * Query value type.
654 *
655 * @returns VBox status code.
656 * @param pNode Which node to search for pszName in.
657 * @param pszName Name of an integer value.
658 * @param penmType Where to store the type.
659 */
660VMMR3DECL(int) CFGMR3QueryType(PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)
661{
662 PCFGMLEAF pLeaf;
663 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
664 if (RT_SUCCESS(rc))
665 {
666 if (penmType)
667 *penmType = pLeaf->enmType;
668 }
669 return rc;
670}
671
672
673/**
674 * Query value size.
675 * This works on all types of values.
676 *
677 * @returns VBox status code.
678 * @param pNode Which node to search for pszName in.
679 * @param pszName Name of an integer value.
680 * @param pcb Where to store the value size.
681 */
682VMMR3DECL(int) CFGMR3QuerySize(PCFGMNODE pNode, const char *pszName, size_t *pcb)
683{
684 PCFGMLEAF pLeaf;
685 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
686 if (RT_SUCCESS(rc))
687 {
688 switch (pLeaf->enmType)
689 {
690 case CFGMVALUETYPE_INTEGER:
691 *pcb = sizeof(pLeaf->Value.Integer.u64);
692 break;
693
694 case CFGMVALUETYPE_STRING:
695 case CFGMVALUETYPE_PASSWORD:
696 *pcb = pLeaf->Value.String.cb;
697 break;
698
699 case CFGMVALUETYPE_BYTES:
700 *pcb = pLeaf->Value.Bytes.cb;
701 break;
702
703 default:
704 rc = VERR_CFGM_IPE_1;
705 AssertMsgFailed(("Invalid value type %d\n", pLeaf->enmType));
706 break;
707 }
708 }
709 return rc;
710}
711
712
713/**
714 * Query integer value.
715 *
716 * @returns VBox status code.
717 * @param pNode Which node to search for pszName in.
718 * @param pszName Name of an integer value.
719 * @param pu64 Where to store the integer value.
720 */
721VMMR3DECL(int) CFGMR3QueryInteger(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
722{
723 PCFGMLEAF pLeaf;
724 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
725 if (RT_SUCCESS(rc))
726 {
727 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
728 *pu64 = pLeaf->Value.Integer.u64;
729 else
730 rc = VERR_CFGM_NOT_INTEGER;
731 }
732 return rc;
733}
734
735
736/**
737 * Query integer value with default.
738 *
739 * @returns VBox status code.
740 * @param pNode Which node to search for pszName in.
741 * @param pszName Name of an integer value.
742 * @param pu64 Where to store the integer value. This is set to the default on failure.
743 * @param u64Def The default value. This is always set.
744 */
745VMMR3DECL(int) CFGMR3QueryIntegerDef(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
746{
747 PCFGMLEAF pLeaf;
748 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
749 if (RT_SUCCESS(rc))
750 {
751 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
752 *pu64 = pLeaf->Value.Integer.u64;
753 else
754 rc = VERR_CFGM_NOT_INTEGER;
755 }
756
757 if (RT_FAILURE(rc))
758 {
759 *pu64 = u64Def;
760 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
761 rc = VINF_SUCCESS;
762 }
763
764 return rc;
765}
766
767
768/**
769 * Query zero terminated character value.
770 *
771 * @returns VBox status code.
772 * @param pNode Which node to search for pszName in.
773 * @param pszName Name of a zero terminate character value.
774 * @param pszString Where to store the string.
775 * @param cchString Size of the string buffer. (Includes terminator.)
776 */
777VMMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
778{
779 PCFGMLEAF pLeaf;
780 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
781 if (RT_SUCCESS(rc))
782 {
783 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
784 {
785 size_t cbSrc = pLeaf->Value.String.cb;
786 if (cchString >= cbSrc)
787 {
788 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
789 memset(pszString + cbSrc, 0, cchString - cbSrc);
790 }
791 else
792 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
793 }
794 else
795 rc = VERR_CFGM_NOT_STRING;
796 }
797 return rc;
798}
799
800
801/**
802 * Query zero terminated character value with default.
803 *
804 * @returns VBox status code.
805 * @param pNode Which node to search for pszName in.
806 * @param pszName Name of a zero terminate character value.
807 * @param pszString Where to store the string. This will not be set on overflow error.
808 * @param cchString Size of the string buffer. (Includes terminator.)
809 * @param pszDef The default value.
810 */
811VMMR3DECL(int) CFGMR3QueryStringDef(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)
812{
813 PCFGMLEAF pLeaf;
814 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
815 if (RT_SUCCESS(rc))
816 {
817 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
818 {
819 size_t cbSrc = pLeaf->Value.String.cb;
820 if (cchString >= cbSrc)
821 {
822 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
823 memset(pszString + cbSrc, 0, cchString - cbSrc);
824 }
825 else
826 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
827 }
828 else
829 rc = VERR_CFGM_NOT_STRING;
830 }
831
832 if (RT_FAILURE(rc) && rc != VERR_CFGM_NOT_ENOUGH_SPACE)
833 {
834 size_t cchDef = strlen(pszDef);
835 if (cchString > cchDef)
836 {
837 memcpy(pszString, pszDef, cchDef);
838 memset(pszString + cchDef, 0, cchString - cchDef);
839 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
840 rc = VINF_SUCCESS;
841 }
842 else if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
843 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
844 }
845
846 return rc;
847}
848
849
850/**
851 * Query byte string value.
852 *
853 * @returns VBox status code.
854 * @param pNode Which node to search for pszName in.
855 * @param pszName Name of a byte string value.
856 * @param pvData Where to store the binary data.
857 * @param cbData Size of buffer pvData points too.
858 */
859VMMR3DECL(int) CFGMR3QueryBytes(PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)
860{
861 PCFGMLEAF pLeaf;
862 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
863 if (RT_SUCCESS(rc))
864 {
865 if (pLeaf->enmType == CFGMVALUETYPE_BYTES)
866 {
867 if (cbData >= pLeaf->Value.Bytes.cb)
868 {
869 memcpy(pvData, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
870 memset((char *)pvData + pLeaf->Value.Bytes.cb, 0, cbData - pLeaf->Value.Bytes.cb);
871 }
872 else
873 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
874 }
875 else
876 rc = VERR_CFGM_NOT_BYTES;
877 }
878 return rc;
879}
880
881
882/**
883 * Query zero terminated character value.
884 *
885 * @returns VBox status code.
886 * @param pNode Which node to search for pszName in.
887 * @param pszName Name of a zero terminate character value.
888 * @param pszString Where to store the string.
889 * @param cchString Size of the string buffer. (Includes terminator.)
890 *
891 * @note Concurrent calls to this function and CFGMR3QueryPasswordDef are not
892 * supported.
893 */
894VMMR3DECL(int) CFGMR3QueryPassword(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
895{
896 PCFGMLEAF pLeaf;
897 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
898 if (RT_SUCCESS(rc))
899 {
900 if (pLeaf->enmType == CFGMVALUETYPE_PASSWORD)
901 {
902 size_t cbSrc = pLeaf->Value.String.cb;
903 if (cchString >= cbSrc)
904 {
905 RTMemSaferUnscramble(pLeaf->Value.String.psz, cbSrc);
906 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
907 memset(pszString + cbSrc, 0, cchString - cbSrc);
908 RTMemSaferScramble(pLeaf->Value.String.psz, cbSrc);
909
910 Assert(pszString[cbSrc - 1] == '\0');
911 }
912 else
913 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
914 }
915 else
916 rc = VERR_CFGM_NOT_PASSWORD;
917 }
918 return rc;
919}
920
921
922/**
923 * Query zero terminated character value with default.
924 *
925 * @returns VBox status code.
926 * @param pNode Which node to search for pszName in.
927 * @param pszName Name of a zero terminate character value.
928 * @param pszString Where to store the string. This will not be set on overflow error.
929 * @param cchString Size of the string buffer. (Includes terminator.)
930 * @param pszDef The default value.
931 *
932 * @note Concurrent calls to this function and CFGMR3QueryPassword are not
933 * supported.
934 */
935VMMR3DECL(int) CFGMR3QueryPasswordDef(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)
936{
937 PCFGMLEAF pLeaf;
938 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
939 if (RT_SUCCESS(rc))
940 {
941 if (pLeaf->enmType == CFGMVALUETYPE_PASSWORD)
942 {
943 size_t cbSrc = pLeaf->Value.String.cb;
944 if (cchString >= cbSrc)
945 {
946 RTMemSaferUnscramble(pLeaf->Value.String.psz, cbSrc);
947 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
948 memset(pszString + cbSrc, 0, cchString - cbSrc);
949 RTMemSaferScramble(pLeaf->Value.String.psz, cbSrc);
950
951 Assert(pszString[cbSrc - 1] == '\0');
952 }
953 else
954 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
955 }
956 else
957 rc = VERR_CFGM_NOT_PASSWORD;
958 }
959
960 if (RT_FAILURE(rc) && rc != VERR_CFGM_NOT_ENOUGH_SPACE)
961 {
962 size_t cchDef = strlen(pszDef);
963 if (cchString > cchDef)
964 {
965 memcpy(pszString, pszDef, cchDef);
966 memset(pszString + cchDef, 0, cchString - cchDef);
967 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
968 rc = VINF_SUCCESS;
969 }
970 else if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
971 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
972 }
973
974 return rc;
975}
976
977
978/**
979 * Validate one level of a configuration node.
980 *
981 * This replaces the CFGMR3AreChildrenValid and CFGMR3AreValuesValid APIs.
982 *
983 * @returns VBox status code.
984 *
985 * When an error is returned, both VMSetError and AssertLogRelMsgFailed
986 * have been called. So, all the caller needs to do is to propagate
987 * the error status up to PDM.
988 *
989 * @param pNode The node to validate.
990 * @param pszNode The node path, always ends with a slash. Use
991 * "/" for the root config node.
992 * @param pszValidValues Patterns describing the valid value names. See
993 * RTStrSimplePatternMultiMatch for details on the
994 * pattern syntax.
995 * @param pszValidNodes Patterns describing the valid node (key) names.
996 * See RTStrSimplePatternMultiMatch for details on
997 * the pattern syntax.
998 * @param pszWho Who is calling.
999 * @param uInstance The instance number of the caller.
1000 */
1001VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode,
1002 const char *pszValidValues, const char *pszValidNodes,
1003 const char *pszWho, uint32_t uInstance)
1004{
1005 /* Input validation. */
1006 AssertPtrNullReturn(pNode, VERR_INVALID_POINTER);
1007 AssertPtrReturn(pszNode, VERR_INVALID_POINTER);
1008 Assert(*pszNode && pszNode[strlen(pszNode) - 1] == '/');
1009 AssertPtrReturn(pszValidValues, VERR_INVALID_POINTER);
1010 AssertPtrReturn(pszValidNodes, VERR_INVALID_POINTER);
1011 AssertPtrReturn(pszWho, VERR_INVALID_POINTER);
1012
1013 if (pNode)
1014 {
1015 /*
1016 * Enumerate the leaves and check them against pszValidValues.
1017 */
1018 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
1019 {
1020 if (!RTStrSimplePatternMultiMatch(pszValidValues, RTSTR_MAX,
1021 pLeaf->szName, pLeaf->cchName,
1022 NULL))
1023 {
1024 AssertLogRelMsgFailed(("%s/%u: Value '%s%s' didn't match '%s'\n",
1025 pszWho, uInstance, pszNode, pLeaf->szName, pszValidValues));
1026 return VMSetError(pNode->pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
1027 N_("Unknown configuration value '%s%s' found in the configuration of %s instance #%u"),
1028 pszNode, pLeaf->szName, pszWho, uInstance);
1029 }
1030
1031 }
1032
1033 /*
1034 * Enumerate the child nodes and check them against pszValidNodes.
1035 */
1036 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
1037 {
1038 if (!RTStrSimplePatternMultiMatch(pszValidNodes, RTSTR_MAX,
1039 pChild->szName, pChild->cchName,
1040 NULL))
1041 {
1042 AssertLogRelMsgFailed(("%s/%u: Node '%s%s' didn't match '%s'\n",
1043 pszWho, uInstance, pszNode, pChild->szName, pszValidNodes));
1044 return VMSetError(pNode->pVM, VERR_CFGM_CONFIG_UNKNOWN_NODE, RT_SRC_POS,
1045 N_("Unknown configuration node '%s%s' found in the configuration of %s instance #%u"),
1046 pszNode, pChild->szName, pszWho, uInstance);
1047 }
1048 }
1049 }
1050
1051 /* All is well. */
1052 return VINF_SUCCESS;
1053}
1054
1055
1056
1057/**
1058 * Populates the CFGM tree with the default configuration.
1059 *
1060 * This assumes an empty tree and is intended for testcases and such that only
1061 * need to do very small adjustments to the config.
1062 *
1063 * @returns VBox status code.
1064 * @param pVM The cross context VM structure.
1065 * @internal
1066 */
1067VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM)
1068{
1069 int rc;
1070 int rcAll = VINF_SUCCESS;
1071#define UPDATERC() do { if (RT_FAILURE(rc) && RT_SUCCESS(rcAll)) rcAll = rc; } while (0)
1072
1073 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
1074 AssertReturn(pRoot, VERR_WRONG_ORDER);
1075
1076 /*
1077 * Create VM default values.
1078 */
1079 rc = CFGMR3InsertString(pRoot, "Name", "Default VM");
1080 UPDATERC();
1081 rc = CFGMR3InsertInteger(pRoot, "RamSize", 128U * _1M);
1082 UPDATERC();
1083 rc = CFGMR3InsertInteger(pRoot, "RamHoleSize", 512U * _1M);
1084 UPDATERC();
1085 rc = CFGMR3InsertInteger(pRoot, "TimerMillies", 10);
1086 UPDATERC();
1087
1088 /*
1089 * PDM.
1090 */
1091 PCFGMNODE pPdm;
1092 rc = CFGMR3InsertNode(pRoot, "PDM", &pPdm);
1093 UPDATERC();
1094 PCFGMNODE pDevices = NULL;
1095 rc = CFGMR3InsertNode(pPdm, "Devices", &pDevices);
1096 UPDATERC();
1097 rc = CFGMR3InsertInteger(pDevices, "LoadBuiltin", 1); /* boolean */
1098 UPDATERC();
1099 PCFGMNODE pDrivers = NULL;
1100 rc = CFGMR3InsertNode(pPdm, "Drivers", &pDrivers);
1101 UPDATERC();
1102 rc = CFGMR3InsertInteger(pDrivers, "LoadBuiltin", 1); /* boolean */
1103 UPDATERC();
1104
1105
1106 /*
1107 * Devices
1108 */
1109 pDevices = NULL;
1110 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);
1111 UPDATERC();
1112 /* device */
1113 PCFGMNODE pDev = NULL;
1114 PCFGMNODE pInst = NULL;
1115 PCFGMNODE pCfg = NULL;
1116#if 0
1117 PCFGMNODE pLunL0 = NULL;
1118 PCFGMNODE pLunL1 = NULL;
1119#endif
1120
1121 /*
1122 * PC Arch.
1123 */
1124 rc = CFGMR3InsertNode(pDevices, "pcarch", &pDev);
1125 UPDATERC();
1126 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1127 UPDATERC();
1128 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1129 UPDATERC();
1130 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1131 UPDATERC();
1132
1133 /*
1134 * PC Bios.
1135 */
1136 rc = CFGMR3InsertNode(pDevices, "pcbios", &pDev);
1137 UPDATERC();
1138 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1139 UPDATERC();
1140 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1141 UPDATERC();
1142 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1143 UPDATERC();
1144 rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
1145 UPDATERC();
1146 rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
1147 UPDATERC();
1148 rc = CFGMR3InsertString(pCfg, "BootDevice2", "NONE");
1149 UPDATERC();
1150 rc = CFGMR3InsertString(pCfg, "BootDevice3", "NONE");
1151 UPDATERC();
1152 rc = CFGMR3InsertString(pCfg, "HardDiskDevice", "piix3ide");
1153 UPDATERC();
1154 rc = CFGMR3InsertString(pCfg, "FloppyDevice", "");
1155 UPDATERC();
1156 RTUUID Uuid;
1157 RTUuidClear(&Uuid);
1158 rc = CFGMR3InsertBytes(pCfg, "UUID", &Uuid, sizeof(Uuid));
1159 UPDATERC();
1160
1161 /*
1162 * PCI bus.
1163 */
1164 rc = CFGMR3InsertNode(pDevices, "pci", &pDev); /* piix3 */
1165 UPDATERC();
1166 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1167 UPDATERC();
1168 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1169 UPDATERC();
1170 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1171 UPDATERC();
1172
1173 /*
1174 * PS/2 keyboard & mouse
1175 */
1176 rc = CFGMR3InsertNode(pDevices, "pckbd", &pDev);
1177 UPDATERC();
1178 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1179 UPDATERC();
1180 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1181 UPDATERC();
1182#if 0
1183 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
1184 UPDATERC();
1185 rc = CFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue");
1186 UPDATERC();
1187 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
1188 UPDATERC();
1189 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 64);
1190 UPDATERC();
1191 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
1192 UPDATERC();
1193 rc = CFGMR3InsertString(pLunL1, "Driver", "MainKeyboard");
1194 UPDATERC();
1195 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
1196 UPDATERC();
1197#endif
1198#if 0
1199 rc = CFGMR3InsertNode(pInst, "LUN#1", &pLunL0);
1200 UPDATERC();
1201 rc = CFGMR3InsertString(pLunL0, "Driver", "MouseQueue");
1202 UPDATERC();
1203 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
1204 UPDATERC();
1205 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 128);
1206 UPDATERC();
1207 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
1208 UPDATERC();
1209 rc = CFGMR3InsertString(pLunL1, "Driver", "MainMouse");
1210 UPDATERC();
1211 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
1212 UPDATERC();
1213#endif
1214
1215 /*
1216 * i8254 Programmable Interval Timer And Dummy Speaker
1217 */
1218 rc = CFGMR3InsertNode(pDevices, "i8254", &pDev);
1219 UPDATERC();
1220 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1221 UPDATERC();
1222#ifdef DEBUG
1223 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1224 UPDATERC();
1225#endif
1226 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1227 UPDATERC();
1228
1229 /*
1230 * i8259 Programmable Interrupt Controller.
1231 */
1232 rc = CFGMR3InsertNode(pDevices, "i8259", &pDev);
1233 UPDATERC();
1234 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1235 UPDATERC();
1236 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1237 UPDATERC();
1238 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1239 UPDATERC();
1240
1241 /*
1242 * RTC MC146818.
1243 */
1244 rc = CFGMR3InsertNode(pDevices, "mc146818", &pDev);
1245 UPDATERC();
1246 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1247 UPDATERC();
1248 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1249 UPDATERC();
1250
1251 /*
1252 * VGA.
1253 */
1254 rc = CFGMR3InsertNode(pDevices, "vga", &pDev);
1255 UPDATERC();
1256 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1257 UPDATERC();
1258 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1259 UPDATERC();
1260 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1261 UPDATERC();
1262 rc = CFGMR3InsertInteger(pCfg, "VRamSize", 4 * _1M);
1263 UPDATERC();
1264
1265 /* Bios logo. */
1266 rc = CFGMR3InsertInteger(pCfg, "FadeIn", 1);
1267 UPDATERC();
1268 rc = CFGMR3InsertInteger(pCfg, "FadeOut", 1);
1269 UPDATERC();
1270 rc = CFGMR3InsertInteger(pCfg, "LogoTime", 0);
1271 UPDATERC();
1272 rc = CFGMR3InsertString(pCfg, "LogoFile", "");
1273 UPDATERC();
1274
1275#if 0
1276 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
1277 UPDATERC();
1278 rc = CFGMR3InsertString(pLunL0, "Driver", "MainDisplay");
1279 UPDATERC();
1280#endif
1281
1282 /*
1283 * IDE controller.
1284 */
1285 rc = CFGMR3InsertNode(pDevices, "piix3ide", &pDev); /* piix3 */
1286 UPDATERC();
1287 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1288 UPDATERC();
1289 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1290 UPDATERC();
1291 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1292 UPDATERC();
1293
1294 /*
1295 * VMMDev.
1296 */
1297 rc = CFGMR3InsertNode(pDevices, "VMMDev", &pDev);
1298 UPDATERC();
1299 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1300 UPDATERC();
1301 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1302 UPDATERC();
1303 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1304 UPDATERC();
1305
1306
1307 /*
1308 * ...
1309 */
1310
1311#undef UPDATERC
1312 return rcAll;
1313}
1314
1315
1316
1317
1318/**
1319 * Resolves a path reference to a child node.
1320 *
1321 * @returns VBox status code.
1322 * @param pNode Which node to search for pszName in.
1323 * @param pszPath Path to the child node.
1324 * @param ppChild Where to store the pointer to the child node.
1325 */
1326static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild)
1327{
1328 *ppChild = NULL;
1329 if (!pNode)
1330 return VERR_CFGM_NO_PARENT;
1331 PCFGMNODE pChild = NULL;
1332 for (;;)
1333 {
1334 /* skip leading slashes. */
1335 while (*pszPath == '/')
1336 pszPath++;
1337
1338 /* End of path? */
1339 if (!*pszPath)
1340 {
1341 if (!pChild)
1342 return VERR_CFGM_INVALID_CHILD_PATH;
1343 *ppChild = pChild;
1344 return VINF_SUCCESS;
1345 }
1346
1347 /* find end of component. */
1348 const char *pszNext = strchr(pszPath, '/');
1349 if (!pszNext)
1350 pszNext = strchr(pszPath, '\0');
1351 RTUINT cchName = pszNext - pszPath;
1352
1353 /* search child list. */
1354 pChild = pNode->pFirstChild;
1355 for ( ; pChild; pChild = pChild->pNext)
1356 if (pChild->cchName == cchName)
1357 {
1358 int iDiff = memcmp(pszPath, pChild->szName, cchName);
1359 if (iDiff <= 0)
1360 {
1361 if (iDiff != 0)
1362 pChild = NULL;
1363 break;
1364 }
1365 }
1366 if (!pChild)
1367 return VERR_CFGM_CHILD_NOT_FOUND;
1368
1369 /* next iteration */
1370 pNode = pChild;
1371 pszPath = pszNext;
1372 }
1373
1374 /* won't get here */
1375}
1376
1377
1378/**
1379 * Resolves a path reference to a child node.
1380 *
1381 * @returns VBox status code.
1382 * @param pNode Which node to search for pszName in.
1383 * @param pszName Name of a byte string value.
1384 * @param ppLeaf Where to store the pointer to the leaf node.
1385 */
1386static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1387{
1388 *ppLeaf = NULL;
1389 if (!pNode)
1390 return VERR_CFGM_NO_PARENT;
1391
1392 size_t cchName = strlen(pszName);
1393 PCFGMLEAF pLeaf = pNode->pFirstLeaf;
1394 while (pLeaf)
1395 {
1396 if (cchName == pLeaf->cchName)
1397 {
1398 int iDiff = memcmp(pszName, pLeaf->szName, cchName);
1399 if (iDiff <= 0)
1400 {
1401 if (iDiff != 0)
1402 break;
1403 *ppLeaf = pLeaf;
1404 return VINF_SUCCESS;
1405 }
1406 }
1407
1408 /* next */
1409 pLeaf = pLeaf->pNext;
1410 }
1411 return VERR_CFGM_VALUE_NOT_FOUND;
1412}
1413
1414
1415
1416/**
1417 * Creates a CFGM tree.
1418 *
1419 * This is intended for creating device/driver configs can be
1420 * passed around and later attached to the main tree in the
1421 * correct location.
1422 *
1423 * @returns Pointer to the root node, NULL on error (out of memory or invalid
1424 * VM handle).
1425 * @param pUVM The user mode VM handle. For testcase (and other
1426 * purposes, NULL can be used. However, the resulting
1427 * tree cannot be inserted into a tree that has a
1428 * non-NULL value. Using NULL can be usedful for
1429 * testcases and similar, non VMM uses.
1430 */
1431VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM)
1432{
1433 if (pUVM)
1434 {
1435 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1436 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1437 }
1438
1439 PCFGMNODE pNew;
1440 if (pUVM)
1441 pNew = (PCFGMNODE)MMR3HeapAllocU(pUVM, MM_TAG_CFGM, sizeof(*pNew));
1442 else
1443 pNew = (PCFGMNODE)RTMemAlloc(sizeof(*pNew));
1444 if (pNew)
1445 {
1446 pNew->pPrev = NULL;
1447 pNew->pNext = NULL;
1448 pNew->pParent = NULL;
1449 pNew->pFirstChild = NULL;
1450 pNew->pFirstLeaf = NULL;
1451 pNew->pVM = pUVM ? pUVM->pVM : NULL;
1452 pNew->fRestrictedRoot = false;
1453 pNew->cchName = 0;
1454 pNew->szName[0] = 0;
1455 }
1456 return pNew;
1457}
1458
1459
1460/**
1461 * Duplicates a CFGM sub-tree or a full tree.
1462 *
1463 * @returns Pointer to the root node. NULL if we run out of memory or the
1464 * input parameter is NULL.
1465 * @param pRoot The root of the tree to duplicate.
1466 * @param ppCopy Where to return the root of the duplicate.
1467 */
1468VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy)
1469{
1470 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1471
1472 /*
1473 * Create a new tree.
1474 */
1475 PCFGMNODE pNewRoot = CFGMR3CreateTree(pRoot->pVM ? pRoot->pVM->pUVM : NULL);
1476 if (!pNewRoot)
1477 return VERR_NO_MEMORY;
1478
1479 /*
1480 * Duplicate the content.
1481 */
1482 int rc = VINF_SUCCESS;
1483 PCFGMNODE pSrcCur = pRoot;
1484 PCFGMNODE pDstCur = pNewRoot;
1485 for (;;)
1486 {
1487 if ( !pDstCur->pFirstChild
1488 && !pDstCur->pFirstLeaf)
1489 {
1490 /*
1491 * Values first.
1492 */
1493 /** @todo this isn't the most efficient way to do it. */
1494 for (PCFGMLEAF pLeaf = pSrcCur->pFirstLeaf; pLeaf && RT_SUCCESS(rc); pLeaf = pLeaf->pNext)
1495 rc = CFGMR3InsertValue(pDstCur, pLeaf);
1496
1497 /*
1498 * Insert immediate child nodes.
1499 */
1500 /** @todo this isn't the most efficient way to do it. */
1501 for (PCFGMNODE pChild = pSrcCur->pFirstChild; pChild && RT_SUCCESS(rc); pChild = pChild->pNext)
1502 rc = CFGMR3InsertNode(pDstCur, pChild->szName, NULL);
1503
1504 AssertLogRelRCBreak(rc);
1505 }
1506
1507 /*
1508 * Deep copy of the children.
1509 */
1510 if (pSrcCur->pFirstChild)
1511 {
1512 Assert(pDstCur->pFirstChild && !strcmp(pDstCur->pFirstChild->szName, pSrcCur->pFirstChild->szName));
1513 pSrcCur = pSrcCur->pFirstChild;
1514 pDstCur = pDstCur->pFirstChild;
1515 }
1516 /*
1517 * If it's the root node, we're done.
1518 */
1519 else if (pSrcCur == pRoot)
1520 break;
1521 else
1522 {
1523 /*
1524 * Upon reaching the end of a sibling list, we must ascend and
1525 * resume the sibiling walk on an previous level.
1526 */
1527 if (!pSrcCur->pNext)
1528 {
1529 do
1530 {
1531 pSrcCur = pSrcCur->pParent;
1532 pDstCur = pDstCur->pParent;
1533 } while (!pSrcCur->pNext && pSrcCur != pRoot);
1534 if (pSrcCur == pRoot)
1535 break;
1536 }
1537
1538 /*
1539 * Next sibling.
1540 */
1541 Assert(pDstCur->pNext && !strcmp(pDstCur->pNext->szName, pSrcCur->pNext->szName));
1542 pSrcCur = pSrcCur->pNext;
1543 pDstCur = pDstCur->pNext;
1544 }
1545 }
1546
1547 if (RT_FAILURE(rc))
1548 {
1549 CFGMR3RemoveNode(pNewRoot);
1550 return rc;
1551 }
1552
1553 *ppCopy = pNewRoot;
1554 return VINF_SUCCESS;
1555}
1556
1557
1558/**
1559 * Insert subtree.
1560 *
1561 * This function inserts (no duplication) a tree created by CFGMR3CreateTree()
1562 * into the main tree.
1563 *
1564 * The root node of the inserted subtree will need to be reallocated, which
1565 * effectually means that the passed in pSubTree handle becomes invalid
1566 * upon successful return. Use the value returned in ppChild instead
1567 * of pSubTree.
1568 *
1569 * @returns VBox status code.
1570 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1571 * @param pNode Parent node.
1572 * @param pszName Name or path of the new child node.
1573 * @param pSubTree The subtree to insert. Must be returned by CFGMR3CreateTree().
1574 * @param ppChild Where to store the address of the new child node. (optional)
1575 */
1576VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild)
1577{
1578 /*
1579 * Validate input.
1580 */
1581 AssertPtrReturn(pNode, VERR_INVALID_POINTER);
1582 AssertPtrReturn(pSubTree, VERR_INVALID_POINTER);
1583 AssertReturn(pNode != pSubTree, VERR_INVALID_PARAMETER);
1584 AssertReturn(!pSubTree->pParent, VERR_INVALID_PARAMETER);
1585 AssertReturn(pNode->pVM == pSubTree->pVM, VERR_INVALID_PARAMETER);
1586 Assert(!pSubTree->pNext);
1587 Assert(!pSubTree->pPrev);
1588
1589 /*
1590 * Use CFGMR3InsertNode to create a new node and then
1591 * re-attach the children and leaves of the subtree to it.
1592 */
1593 PCFGMNODE pNewChild;
1594 int rc = CFGMR3InsertNode(pNode, pszName, &pNewChild);
1595 if (RT_SUCCESS(rc))
1596 {
1597 Assert(!pNewChild->pFirstChild);
1598 Assert(!pNewChild->pFirstLeaf);
1599
1600 pNewChild->pFirstChild = pSubTree->pFirstChild;
1601 pNewChild->pFirstLeaf = pSubTree->pFirstLeaf;
1602 for (PCFGMNODE pChild = pNewChild->pFirstChild; pChild; pChild = pChild->pNext)
1603 pChild->pParent = pNewChild;
1604
1605 if (ppChild)
1606 *ppChild = pNewChild;
1607
1608 /* free the old subtree root */
1609 cfgmR3FreeNodeOnly(pSubTree);
1610 }
1611 return rc;
1612}
1613
1614
1615/**
1616 * Replaces a (sub-)tree with new one.
1617 *
1618 * This function removes the exiting (sub-)tree, completely freeing it in the
1619 * process, and inserts (no duplication) the specified tree. The tree can
1620 * either be created by CFGMR3CreateTree or CFGMR3DuplicateSubTree.
1621 *
1622 * @returns VBox status code.
1623 * @param pRoot The sub-tree to replace. This node will remain valid
1624 * after the call.
1625 * @param pNewRoot The tree to replace @a pRoot with. This not will
1626 * become invalid after a successful call.
1627 */
1628VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot)
1629{
1630 /*
1631 * Validate input.
1632 */
1633 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1634 AssertPtrReturn(pNewRoot, VERR_INVALID_POINTER);
1635 AssertReturn(pRoot != pNewRoot, VERR_INVALID_PARAMETER);
1636 AssertReturn(!pNewRoot->pParent, VERR_INVALID_PARAMETER);
1637 AssertReturn(pNewRoot->pVM == pRoot->pVM, VERR_INVALID_PARAMETER);
1638 AssertReturn(!pNewRoot->pNext, VERR_INVALID_PARAMETER);
1639 AssertReturn(!pNewRoot->pPrev, VERR_INVALID_PARAMETER);
1640
1641 /*
1642 * Free the current properties fo pRoot.
1643 */
1644 while (pRoot->pFirstChild)
1645 CFGMR3RemoveNode(pRoot->pFirstChild);
1646
1647 while (pRoot->pFirstLeaf)
1648 cfgmR3RemoveLeaf(pRoot, pRoot->pFirstLeaf);
1649
1650 /*
1651 * Copy all the properties from the new root to the current one.
1652 */
1653 pRoot->pFirstLeaf = pNewRoot->pFirstLeaf;
1654 pRoot->pFirstChild = pNewRoot->pFirstChild;
1655 for (PCFGMNODE pChild = pRoot->pFirstChild; pChild; pChild = pChild->pNext)
1656 pChild->pParent = pRoot;
1657
1658 cfgmR3FreeNodeOnly(pNewRoot);
1659
1660 return VINF_SUCCESS;
1661}
1662
1663
1664/**
1665 * Copies all values and keys from one tree onto another.
1666 *
1667 * The flags control what happens to keys and values with the same name
1668 * existing in both source and destination.
1669 *
1670 * @returns VBox status code.
1671 * @param pDstTree The destination tree.
1672 * @param pSrcTree The source tree.
1673 * @param fFlags Copy flags, see CFGM_COPY_FLAGS_XXX.
1674 */
1675VMMR3DECL(int) CFGMR3CopyTree(PCFGMNODE pDstTree, PCFGMNODE pSrcTree, uint32_t fFlags)
1676{
1677 /*
1678 * Input validation.
1679 */
1680 AssertPtrReturn(pSrcTree, VERR_INVALID_POINTER);
1681 AssertPtrReturn(pDstTree, VERR_INVALID_POINTER);
1682 AssertReturn(pDstTree != pSrcTree, VERR_INVALID_PARAMETER);
1683 AssertReturn(!(fFlags & ~(CFGM_COPY_FLAGS_VALUE_DISP_MASK | CFGM_COPY_FLAGS_KEY_DISP_MASK)), VERR_INVALID_PARAMETER);
1684 AssertReturn( (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_0
1685 && (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_1,
1686 VERR_INVALID_PARAMETER);
1687 AssertReturn((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_KEY_DISP,
1688 VERR_INVALID_PARAMETER);
1689
1690 /*
1691 * Copy the values.
1692 */
1693 int rc;
1694 for (PCFGMLEAF pValue = CFGMR3GetFirstValue(pSrcTree); pValue; pValue = CFGMR3GetNextValue(pValue))
1695 {
1696 rc = CFGMR3InsertValue(pDstTree, pValue);
1697 if (rc == VERR_CFGM_LEAF_EXISTS)
1698 {
1699 if ((fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_VALUES)
1700 {
1701 rc = CFGMR3RemoveValue(pDstTree, pValue->szName);
1702 if (RT_FAILURE(rc))
1703 break;
1704 rc = CFGMR3InsertValue(pDstTree, pValue);
1705 }
1706 else
1707 rc = VINF_SUCCESS;
1708 }
1709 AssertRCReturn(rc, rc);
1710 }
1711
1712 /*
1713 * Copy/merge the keys - merging results in recursion.
1714 */
1715 for (PCFGMNODE pSrcChild = CFGMR3GetFirstChild(pSrcTree); pSrcChild; pSrcChild = CFGMR3GetNextChild(pSrcChild))
1716 {
1717 PCFGMNODE pDstChild = CFGMR3GetChild(pDstTree, pSrcChild->szName);
1718 if ( pDstChild
1719 && (fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_KEYS)
1720 {
1721 CFGMR3RemoveNode(pDstChild);
1722 pDstChild = NULL;
1723 }
1724 if (!pDstChild)
1725 {
1726 PCFGMNODE pChildCopy;
1727 rc = CFGMR3DuplicateSubTree(pSrcChild, &pChildCopy);
1728 AssertRCReturn(rc, rc);
1729 rc = CFGMR3InsertSubTree(pDstTree, pSrcChild->szName, pChildCopy, NULL);
1730 AssertRCReturnStmt(rc, CFGMR3RemoveNode(pChildCopy), rc);
1731 }
1732 else if ((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_MERGE_KEYS)
1733 {
1734 rc = CFGMR3CopyTree(pDstChild, pSrcChild, fFlags);
1735 AssertRCReturn(rc, rc);
1736 }
1737 }
1738
1739 return VINF_SUCCESS;
1740}
1741
1742
1743
1744/**
1745 * Compares two names.
1746 *
1747 * @returns Similar to memcpy.
1748 * @param pszName1 The first name.
1749 * @param cchName1 The length of the first name.
1750 * @param pszName2 The second name.
1751 * @param cchName2 The length of the second name.
1752 */
1753DECLINLINE(int) cfgmR3CompareNames(const char *pszName1, size_t cchName1, const char *pszName2, size_t cchName2)
1754{
1755 int iDiff;
1756 if (cchName1 <= cchName2)
1757 {
1758 iDiff = memcmp(pszName1, pszName2, cchName1);
1759 if (!iDiff && cchName1 < cchName2)
1760 iDiff = -1;
1761 }
1762 else
1763 {
1764 iDiff = memcmp(pszName1, pszName2, cchName2);
1765 if (!iDiff)
1766 iDiff = 1;
1767 }
1768 return iDiff;
1769}
1770
1771
1772/**
1773 * Insert a node.
1774 *
1775 * @returns VBox status code.
1776 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1777 * @param pNode Parent node.
1778 * @param pszName Name or path of the new child node.
1779 * @param ppChild Where to store the address of the new child node. (optional)
1780 */
1781VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
1782{
1783 int rc;
1784 if (pNode)
1785 {
1786 /*
1787 * If given a path we have to deal with it component by component.
1788 */
1789 while (*pszName == '/')
1790 pszName++;
1791 if (strchr(pszName, '/'))
1792 {
1793 char *pszDup = RTStrDup(pszName);
1794 if (pszDup)
1795 {
1796 char *psz = pszDup;
1797 for (;;)
1798 {
1799 /* Terminate at '/' and find the next component. */
1800 char *pszNext = strchr(psz, '/');
1801 if (pszNext)
1802 {
1803 *pszNext++ = '\0';
1804 while (*pszNext == '/')
1805 pszNext++;
1806 if (*pszNext == '\0')
1807 pszNext = NULL;
1808 }
1809
1810 /* does it exist? */
1811 PCFGMNODE pChild = CFGMR3GetChild(pNode, psz);
1812 if (!pChild)
1813 {
1814 /* no, insert it */
1815 rc = CFGMR3InsertNode(pNode, psz, &pChild);
1816 if (RT_FAILURE(rc))
1817 break;
1818 if (!pszNext)
1819 {
1820 if (ppChild)
1821 *ppChild = pChild;
1822 break;
1823 }
1824
1825 }
1826 /* if last component fail */
1827 else if (!pszNext)
1828 {
1829 rc = VERR_CFGM_NODE_EXISTS;
1830 break;
1831 }
1832
1833 /* next */
1834 pNode = pChild;
1835 psz = pszNext;
1836 }
1837 RTStrFree(pszDup);
1838 }
1839 else
1840 rc = VERR_NO_TMP_MEMORY;
1841 }
1842 /*
1843 * Not multicomponent, just make sure it's a non-zero name.
1844 */
1845 else if (*pszName)
1846 {
1847 /*
1848 * Check if already exists and find last node in chain.
1849 */
1850 size_t cchName = strlen(pszName);
1851 PCFGMNODE pPrev = NULL;
1852 PCFGMNODE pNext = pNode->pFirstChild;
1853 if (pNext)
1854 {
1855 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1856 {
1857 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
1858 if (iDiff <= 0)
1859 {
1860 if (!iDiff)
1861 return VERR_CFGM_NODE_EXISTS;
1862 break;
1863 }
1864 }
1865 }
1866
1867 /*
1868 * Allocate and init node.
1869 */
1870 PCFGMNODE pNew = (PCFGMNODE)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1871 if (pNew)
1872 {
1873 pNew->pParent = pNode;
1874 pNew->pFirstChild = NULL;
1875 pNew->pFirstLeaf = NULL;
1876 pNew->pVM = pNode->pVM;
1877 pNew->fRestrictedRoot = false;
1878 pNew->cchName = cchName;
1879 memcpy(pNew->szName, pszName, cchName + 1);
1880
1881 /*
1882 * Insert into child list.
1883 */
1884 pNew->pPrev = pPrev;
1885 if (pPrev)
1886 pPrev->pNext = pNew;
1887 else
1888 pNode->pFirstChild = pNew;
1889 pNew->pNext = pNext;
1890 if (pNext)
1891 pNext->pPrev = pNew;
1892
1893 if (ppChild)
1894 *ppChild = pNew;
1895 rc = VINF_SUCCESS;
1896 }
1897 else
1898 rc = VERR_NO_MEMORY;
1899 }
1900 else
1901 {
1902 rc = VERR_CFGM_INVALID_NODE_PATH;
1903 AssertMsgFailed(("Invalid path %s\n", pszName));
1904 }
1905 }
1906 else
1907 {
1908 rc = VERR_CFGM_NO_PARENT;
1909 AssertMsgFailed(("No parent! path %s\n", pszName));
1910 }
1911
1912 return rc;
1913}
1914
1915
1916/**
1917 * Insert a node, format string name.
1918 *
1919 * @returns VBox status code.
1920 * @param pNode Parent node.
1921 * @param ppChild Where to store the address of the new child node. (optional)
1922 * @param pszNameFormat Name of or path the new child node.
1923 * @param ... Name format arguments.
1924 */
1925VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
1926{
1927 va_list Args;
1928 va_start(Args, pszNameFormat);
1929 int rc = CFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
1930 va_end(Args);
1931 return rc;
1932}
1933
1934
1935/**
1936 * Insert a node, format string name.
1937 *
1938 * @returns VBox status code.
1939 * @param pNode Parent node.
1940 * @param ppChild Where to store the address of the new child node. (optional)
1941 * @param pszNameFormat Name or path of the new child node.
1942 * @param Args Name format arguments.
1943 */
1944VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args)
1945{
1946 int rc;
1947 char *pszName;
1948 RTStrAPrintfV(&pszName, pszNameFormat, Args);
1949 if (pszName)
1950 {
1951 rc = CFGMR3InsertNode(pNode, pszName, ppChild);
1952 RTStrFree(pszName);
1953 }
1954 else
1955 rc = VERR_NO_MEMORY;
1956 return rc;
1957}
1958
1959
1960/**
1961 * Marks the node as the root of a restricted subtree, i.e. the end of
1962 * a CFGMR3GetParent() journey.
1963 *
1964 * @param pNode The node to mark.
1965 */
1966VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode)
1967{
1968 if (pNode)
1969 pNode->fRestrictedRoot = true;
1970}
1971
1972
1973/**
1974 * Insert a node.
1975 *
1976 * @returns VBox status code.
1977 * @param pNode Parent node.
1978 * @param pszName Name of the new child node.
1979 * @param ppLeaf Where to store the new leaf.
1980 * The caller must fill in the enmType and Value fields!
1981 */
1982static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1983{
1984 int rc;
1985 if (*pszName)
1986 {
1987 if (pNode)
1988 {
1989 /*
1990 * Check if already exists and find last node in chain.
1991 */
1992 size_t cchName = strlen(pszName);
1993 PCFGMLEAF pPrev = NULL;
1994 PCFGMLEAF pNext = pNode->pFirstLeaf;
1995 if (pNext)
1996 {
1997 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1998 {
1999 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
2000 if (iDiff <= 0)
2001 {
2002 if (!iDiff)
2003 return VERR_CFGM_LEAF_EXISTS;
2004 break;
2005 }
2006 }
2007 }
2008
2009 /*
2010 * Allocate and init node.
2011 */
2012 PCFGMLEAF pNew = (PCFGMLEAF)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
2013 if (pNew)
2014 {
2015 pNew->cchName = cchName;
2016 memcpy(pNew->szName, pszName, cchName + 1);
2017
2018 /*
2019 * Insert into child list.
2020 */
2021 pNew->pPrev = pPrev;
2022 if (pPrev)
2023 pPrev->pNext = pNew;
2024 else
2025 pNode->pFirstLeaf = pNew;
2026 pNew->pNext = pNext;
2027 if (pNext)
2028 pNext->pPrev = pNew;
2029
2030 *ppLeaf = pNew;
2031 rc = VINF_SUCCESS;
2032 }
2033 else
2034 rc = VERR_NO_MEMORY;
2035 }
2036 else
2037 rc = VERR_CFGM_NO_PARENT;
2038 }
2039 else
2040 rc = VERR_CFGM_INVALID_CHILD_PATH;
2041 return rc;
2042}
2043
2044
2045/**
2046 * Removes a node.
2047 *
2048 * @param pNode The node to remove.
2049 */
2050VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
2051{
2052 if (pNode)
2053 {
2054 /*
2055 * Free children.
2056 */
2057 while (pNode->pFirstChild)
2058 CFGMR3RemoveNode(pNode->pFirstChild);
2059
2060 /*
2061 * Free leaves.
2062 */
2063 while (pNode->pFirstLeaf)
2064 cfgmR3RemoveLeaf(pNode, pNode->pFirstLeaf);
2065
2066 /*
2067 * Unlink ourselves.
2068 */
2069 if (pNode->pPrev)
2070 pNode->pPrev->pNext = pNode->pNext;
2071 else
2072 {
2073 if (pNode->pParent)
2074 pNode->pParent->pFirstChild = pNode->pNext;
2075 else if ( pNode->pVM /* might be a different tree */
2076 && pNode == pNode->pVM->cfgm.s.pRoot)
2077 pNode->pVM->cfgm.s.pRoot = NULL;
2078 }
2079 if (pNode->pNext)
2080 pNode->pNext->pPrev = pNode->pPrev;
2081
2082 /*
2083 * Free ourselves.
2084 */
2085 cfgmR3FreeNodeOnly(pNode);
2086 }
2087}
2088
2089
2090/**
2091 * Removes a leaf.
2092 *
2093 * @param pNode Parent node.
2094 * @param pLeaf Leaf to remove.
2095 */
2096static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
2097{
2098 if (pNode && pLeaf)
2099 {
2100 /*
2101 * Unlink.
2102 */
2103 if (pLeaf->pPrev)
2104 pLeaf->pPrev->pNext = pLeaf->pNext;
2105 else
2106 pNode->pFirstLeaf = pLeaf->pNext;
2107 if (pLeaf->pNext)
2108 pLeaf->pNext->pPrev = pLeaf->pPrev;
2109
2110 /*
2111 * Free value and node.
2112 */
2113 cfgmR3FreeValue(pNode->pVM, pLeaf);
2114 pLeaf->pNext = NULL;
2115 pLeaf->pPrev = NULL;
2116 cfgmR3MemFree(pNode->pVM, pLeaf);
2117 }
2118}
2119
2120
2121/**
2122 * Frees whatever resources the leaf value is owning.
2123 *
2124 * Use this before assigning a new value to a leaf.
2125 * The caller must either free the leaf or assign a new value to it.
2126 *
2127 * @param pVM The cross context VM structure, if the tree
2128 * is associated with one.
2129 * @param pLeaf Pointer to the leaf which value should be free.
2130 */
2131static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf)
2132{
2133 if (pLeaf)
2134 {
2135 switch (pLeaf->enmType)
2136 {
2137 case CFGMVALUETYPE_BYTES:
2138 cfgmR3MemFree(pVM, pLeaf->Value.Bytes.pau8);
2139 pLeaf->Value.Bytes.pau8 = NULL;
2140 pLeaf->Value.Bytes.cb = 0;
2141 break;
2142
2143 case CFGMVALUETYPE_STRING:
2144 cfgmR3StrFree(pVM, pLeaf->Value.String.psz);
2145 pLeaf->Value.String.psz = NULL;
2146 pLeaf->Value.String.cb = 0;
2147 break;
2148
2149 case CFGMVALUETYPE_PASSWORD:
2150 RTMemSaferFree(pLeaf->Value.String.psz, pLeaf->Value.String.cb);
2151 pLeaf->Value.String.psz = NULL;
2152 pLeaf->Value.String.cb = 0;
2153 break;
2154
2155 case CFGMVALUETYPE_INTEGER:
2156 break;
2157 }
2158 pLeaf->enmType = (CFGMVALUETYPE)0;
2159 }
2160}
2161
2162/**
2163 * Destroys a tree created with CFGMR3CreateTree or CFGMR3DuplicateSubTree.
2164 *
2165 * @returns VBox status code.
2166 * @param pRoot The root node of the tree.
2167 */
2168VMMR3DECL(int) CFGMR3DestroyTree(PCFGMNODE pRoot)
2169{
2170 if (!pRoot)
2171 return VINF_SUCCESS;
2172 AssertReturn(!pRoot->pParent, VERR_INVALID_PARAMETER);
2173 AssertReturn(!pRoot->pVM || pRoot != pRoot->pVM->cfgm.s.pRoot, VERR_ACCESS_DENIED);
2174
2175 CFGMR3RemoveNode(pRoot);
2176 return VINF_SUCCESS;
2177}
2178
2179
2180/**
2181 * Inserts a new integer value.
2182 *
2183 * @returns VBox status code.
2184 * @param pNode Parent node.
2185 * @param pszName Value name.
2186 * @param u64Integer The value.
2187 */
2188VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
2189{
2190 PCFGMLEAF pLeaf;
2191 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2192 if (RT_SUCCESS(rc))
2193 {
2194 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
2195 pLeaf->Value.Integer.u64 = u64Integer;
2196 }
2197 return rc;
2198}
2199
2200
2201/**
2202 * Inserts a new string value.
2203 *
2204 * This variant expects that the caller know the length of the string already so
2205 * we can avoid calling strlen() here.
2206 *
2207 * @returns VBox status code.
2208 * @param pNode Parent node.
2209 * @param pszName Value name.
2210 * @param pszString The value. Must not be NULL.
2211 * @param cchString The length of the string excluding the
2212 * terminator.
2213 */
2214VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString)
2215{
2216 Assert(RTStrNLen(pszString, cchString) == cchString);
2217
2218 int rc;
2219 if (pNode)
2220 {
2221 /*
2222 * Allocate string object first.
2223 */
2224 char *pszStringCopy = (char *)cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cchString + 1);
2225 if (pszStringCopy)
2226 {
2227 memcpy(pszStringCopy, pszString, cchString);
2228 pszStringCopy[cchString] = '\0';
2229
2230 /*
2231 * Create value leaf and set it to string type.
2232 */
2233 PCFGMLEAF pLeaf;
2234 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2235 if (RT_SUCCESS(rc))
2236 {
2237 pLeaf->enmType = CFGMVALUETYPE_STRING;
2238 pLeaf->Value.String.psz = pszStringCopy;
2239 pLeaf->Value.String.cb = cchString + 1;
2240 }
2241 else
2242 cfgmR3StrFree(pNode->pVM, pszStringCopy);
2243 }
2244 else
2245 rc = VERR_NO_MEMORY;
2246 }
2247 else
2248 rc = VERR_CFGM_NO_PARENT;
2249
2250 return rc;
2251}
2252
2253
2254/**
2255 * Inserts a new string value.
2256 *
2257 * Calls strlen(pszString) internally; if you know the length of the string,
2258 * CFGMR3InsertStringLengthKnown() is faster.
2259 *
2260 * @returns VBox status code.
2261 * @param pNode Parent node.
2262 * @param pszName Value name.
2263 * @param pszString The value.
2264 */
2265VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
2266{
2267 return CFGMR3InsertStringN(pNode, pszName, pszString, strlen(pszString));
2268}
2269
2270
2271/**
2272 * Same as CFGMR3InsertString except the string value given in RTStrPrintfV
2273 * fashion.
2274 *
2275 * @returns VBox status code.
2276 * @param pNode Parent node.
2277 * @param pszName Value name.
2278 * @param pszFormat The value given as a format string.
2279 * @param va Argument to pszFormat.
2280 */
2281VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const char *pszFormat, va_list va)
2282{
2283 int rc;
2284 if (pNode)
2285 {
2286 /*
2287 * Allocate string object first.
2288 */
2289 char *pszString;
2290 if (!pNode->pVM)
2291 pszString = RTStrAPrintf2(pszFormat, va);
2292 else
2293 pszString = MMR3HeapAPrintfVU(pNode->pVM->pUVM, MM_TAG_CFGM_STRING, pszFormat, va);
2294 if (pszString)
2295 {
2296 /*
2297 * Create value leaf and set it to string type.
2298 */
2299 PCFGMLEAF pLeaf;
2300 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2301 if (RT_SUCCESS(rc))
2302 {
2303 pLeaf->enmType = CFGMVALUETYPE_STRING;
2304 pLeaf->Value.String.psz = pszString;
2305 pLeaf->Value.String.cb = strlen(pszString) + 1;
2306 }
2307 else
2308 cfgmR3StrFree(pNode->pVM, pszString);
2309 }
2310 else
2311 rc = VERR_NO_MEMORY;
2312 }
2313 else
2314 rc = VERR_CFGM_NO_PARENT;
2315
2316 return rc;
2317}
2318
2319
2320/**
2321 * Same as CFGMR3InsertString except the string value given in RTStrPrintf
2322 * fashion.
2323 *
2324 * @returns VBox status code.
2325 * @param pNode Parent node.
2326 * @param pszName Value name.
2327 * @param pszFormat The value given as a format string.
2328 * @param ... Argument to pszFormat.
2329 */
2330VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, const char *pszFormat, ...)
2331{
2332 va_list va;
2333 va_start(va, pszFormat);
2334 int rc = CFGMR3InsertStringFV(pNode, pszName, pszFormat, va);
2335 va_end(va);
2336 return rc;
2337}
2338
2339
2340/**
2341 * Same as CFGMR3InsertString except the string value given as a UTF-16 string.
2342 *
2343 * @returns VBox status code.
2344 * @param pNode Parent node.
2345 * @param pszName Value name.
2346 * @param pwszValue The string value (UTF-16).
2347 */
2348VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue)
2349{
2350 char *pszValue;
2351 int rc = RTUtf16ToUtf8(pwszValue, &pszValue);
2352 if (RT_SUCCESS(rc))
2353 {
2354 rc = CFGMR3InsertString(pNode, pszName, pszValue);
2355 RTStrFree(pszValue);
2356 }
2357 return rc;
2358}
2359
2360
2361/**
2362 * Inserts a new bytes value.
2363 *
2364 * @returns VBox status code.
2365 * @param pNode Parent node.
2366 * @param pszName Value name.
2367 * @param pvBytes The value.
2368 * @param cbBytes The value size.
2369 */
2370VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes)
2371{
2372 int rc;
2373 if (pNode)
2374 {
2375 if (cbBytes == (RTUINT)cbBytes)
2376 {
2377 /*
2378 * Allocate string object first.
2379 */
2380 void *pvCopy = cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cbBytes);
2381 if (pvCopy || !cbBytes)
2382 {
2383 memcpy(pvCopy, pvBytes, cbBytes);
2384
2385 /*
2386 * Create value leaf and set it to string type.
2387 */
2388 PCFGMLEAF pLeaf;
2389 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2390 if (RT_SUCCESS(rc))
2391 {
2392 pLeaf->enmType = CFGMVALUETYPE_BYTES;
2393 pLeaf->Value.Bytes.cb = cbBytes;
2394 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
2395 }
2396 else
2397 cfgmR3MemFree(pNode->pVM, pvCopy);
2398 }
2399 else
2400 rc = VERR_NO_MEMORY;
2401 }
2402 else
2403 rc = VERR_OUT_OF_RANGE;
2404 }
2405 else
2406 rc = VERR_CFGM_NO_PARENT;
2407
2408 return rc;
2409}
2410
2411
2412/**
2413 * Inserts a new password value.
2414 *
2415 * This variant expects that the caller know the length of the password string
2416 * already so we can avoid calling strlen() here.
2417 *
2418 * @returns VBox status code.
2419 * @param pNode Parent node.
2420 * @param pszName Value name.
2421 * @param pszString The value. Must not be NULL.
2422 * @param cchString The length of the string excluding the terminator.
2423 */
2424VMMR3DECL(int) CFGMR3InsertPasswordN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString)
2425{
2426 Assert(RTStrNLen(pszString, cchString) == cchString);
2427
2428 int rc;
2429 if (pNode)
2430 {
2431 /*
2432 * Allocate string object first using the safer memory API since this
2433 * is considered sensitive information.
2434 */
2435 char *pszStringCopy = (char *)RTMemSaferAllocZ(cchString + 1);
2436 if (pszStringCopy)
2437 {
2438 memcpy(pszStringCopy, pszString, cchString);
2439 pszStringCopy[cchString] = '\0';
2440 RTMemSaferScramble(pszStringCopy, cchString + 1);
2441
2442 /*
2443 * Create value leaf and set it to string type.
2444 */
2445 PCFGMLEAF pLeaf;
2446 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2447 if (RT_SUCCESS(rc))
2448 {
2449 pLeaf->enmType = CFGMVALUETYPE_PASSWORD;
2450 pLeaf->Value.String.psz = pszStringCopy;
2451 pLeaf->Value.String.cb = cchString + 1;
2452 }
2453 else
2454 RTMemSaferFree(pszStringCopy, cchString + 1);
2455 }
2456 else
2457 rc = VERR_NO_MEMORY;
2458 }
2459 else
2460 rc = VERR_CFGM_NO_PARENT;
2461
2462 return rc;
2463}
2464
2465
2466/**
2467 * Inserts a new password value.
2468 *
2469 * Calls strlen(pszString) internally; if you know the length of the string,
2470 * CFGMR3InsertStringLengthKnown() is faster.
2471 *
2472 * @returns VBox status code.
2473 * @param pNode Parent node.
2474 * @param pszName Value name.
2475 * @param pszString The value.
2476 */
2477VMMR3DECL(int) CFGMR3InsertPassword(PCFGMNODE pNode, const char *pszName, const char *pszString)
2478{
2479 return CFGMR3InsertPasswordN(pNode, pszName, pszString, strlen(pszString));
2480}
2481
2482
2483/**
2484 * Make a copy of the specified value under the given node.
2485 *
2486 * @returns VBox status code.
2487 * @param pNode Parent node.
2488 * @param pValue The value to copy and insert.
2489 */
2490VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue)
2491{
2492 int rc;
2493 switch (pValue->enmType)
2494 {
2495 case CFGMVALUETYPE_INTEGER:
2496 rc = CFGMR3InsertInteger(pNode, pValue->szName, pValue->Value.Integer.u64);
2497 break;
2498
2499 case CFGMVALUETYPE_BYTES:
2500 rc = CFGMR3InsertBytes(pNode, pValue->szName, pValue->Value.Bytes.pau8, pValue->Value.Bytes.cb);
2501 break;
2502
2503 case CFGMVALUETYPE_STRING:
2504 rc = CFGMR3InsertStringN(pNode, pValue->szName, pValue->Value.String.psz, pValue->Value.String.cb - 1);
2505 break;
2506
2507 case CFGMVALUETYPE_PASSWORD:
2508 rc = CFGMR3InsertPasswordN(pNode, pValue->szName, pValue->Value.String.psz, pValue->Value.String.cb - 1);
2509 break;
2510
2511 default:
2512 rc = VERR_CFGM_IPE_1;
2513 AssertMsgFailed(("Invalid value type %d\n", pValue->enmType));
2514 break;
2515 }
2516 return rc;
2517}
2518
2519
2520/**
2521 * Remove a value.
2522 *
2523 * @returns VBox status code.
2524 * @param pNode Parent node.
2525 * @param pszName Name of the new child node.
2526 */
2527VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
2528{
2529 PCFGMLEAF pLeaf;
2530 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
2531 if (RT_SUCCESS(rc))
2532 cfgmR3RemoveLeaf(pNode, pLeaf);
2533 return rc;
2534}
2535
2536
2537
2538/*
2539 * -+- helper apis -+-
2540 */
2541
2542
2543/**
2544 * Query unsigned 64-bit integer value.
2545 *
2546 * @returns VBox status code.
2547 * @param pNode Which node to search for pszName in.
2548 * @param pszName Name of an integer value.
2549 * @param pu64 Where to store the integer value.
2550 */
2551VMMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
2552{
2553 return CFGMR3QueryInteger(pNode, pszName, pu64);
2554}
2555
2556
2557/**
2558 * Query unsigned 64-bit integer value with default.
2559 *
2560 * @returns VBox status code.
2561 * @param pNode Which node to search for pszName in.
2562 * @param pszName Name of an integer value.
2563 * @param pu64 Where to store the integer value. Set to default on failure.
2564 * @param u64Def The default value.
2565 */
2566VMMR3DECL(int) CFGMR3QueryU64Def(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
2567{
2568 return CFGMR3QueryIntegerDef(pNode, pszName, pu64, u64Def);
2569}
2570
2571
2572/**
2573 * Query signed 64-bit integer value.
2574 *
2575 * @returns VBox status code.
2576 * @param pNode Which node to search for pszName in.
2577 * @param pszName Name of an integer value.
2578 * @param pi64 Where to store the value.
2579 */
2580VMMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
2581{
2582 uint64_t u64;
2583 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2584 if (RT_SUCCESS(rc))
2585 *pi64 = (int64_t)u64;
2586 return rc;
2587}
2588
2589
2590/**
2591 * Query signed 64-bit integer value with default.
2592 *
2593 * @returns VBox status code.
2594 * @param pNode Which node to search for pszName in.
2595 * @param pszName Name of an integer value.
2596 * @param pi64 Where to store the value. Set to default on failure.
2597 * @param i64Def The default value.
2598 */
2599VMMR3DECL(int) CFGMR3QueryS64Def(PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)
2600{
2601 uint64_t u64;
2602 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i64Def);
2603 *pi64 = (int64_t)u64;
2604 return rc;
2605}
2606
2607
2608/**
2609 * Query unsigned 32-bit integer value.
2610 *
2611 * @returns VBox status code.
2612 * @param pNode Which node to search for pszName in.
2613 * @param pszName Name of an integer value.
2614 * @param pu32 Where to store the value.
2615 */
2616VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
2617{
2618 uint64_t u64;
2619 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2620 if (RT_SUCCESS(rc))
2621 {
2622 if (!(u64 & UINT64_C(0xffffffff00000000)))
2623 *pu32 = (uint32_t)u64;
2624 else
2625 rc = VERR_CFGM_INTEGER_TOO_BIG;
2626 }
2627 return rc;
2628}
2629
2630
2631/**
2632 * Query unsigned 32-bit integer value with default.
2633 *
2634 * @returns VBox status code.
2635 * @param pNode Which node to search for pszName in.
2636 * @param pszName Name of an integer value.
2637 * @param pu32 Where to store the value. Set to default on failure.
2638 * @param u32Def The default value.
2639 */
2640VMMR3DECL(int) CFGMR3QueryU32Def(PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)
2641{
2642 uint64_t u64;
2643 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u32Def);
2644 if (RT_SUCCESS(rc))
2645 {
2646 if (!(u64 & UINT64_C(0xffffffff00000000)))
2647 *pu32 = (uint32_t)u64;
2648 else
2649 rc = VERR_CFGM_INTEGER_TOO_BIG;
2650 }
2651 if (RT_FAILURE(rc))
2652 *pu32 = u32Def;
2653 return rc;
2654}
2655
2656
2657/**
2658 * Query signed 32-bit integer value.
2659 *
2660 * @returns VBox status code.
2661 * @param pNode Which node to search for pszName in.
2662 * @param pszName Name of an integer value.
2663 * @param pi32 Where to store the value.
2664 */
2665VMMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
2666{
2667 uint64_t u64;
2668 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2669 if (RT_SUCCESS(rc))
2670 {
2671 if ( !(u64 & UINT64_C(0xffffffff80000000))
2672 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2673 *pi32 = (int32_t)u64;
2674 else
2675 rc = VERR_CFGM_INTEGER_TOO_BIG;
2676 }
2677 return rc;
2678}
2679
2680
2681/**
2682 * Query signed 32-bit integer value with default.
2683 *
2684 * @returns VBox status code.
2685 * @param pNode Which node to search for pszName in.
2686 * @param pszName Name of an integer value.
2687 * @param pi32 Where to store the value. Set to default on failure.
2688 * @param i32Def The default value.
2689 */
2690VMMR3DECL(int) CFGMR3QueryS32Def(PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)
2691{
2692 uint64_t u64;
2693 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i32Def);
2694 if (RT_SUCCESS(rc))
2695 {
2696 if ( !(u64 & UINT64_C(0xffffffff80000000))
2697 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2698 *pi32 = (int32_t)u64;
2699 else
2700 rc = VERR_CFGM_INTEGER_TOO_BIG;
2701 }
2702 if (RT_FAILURE(rc))
2703 *pi32 = i32Def;
2704 return rc;
2705}
2706
2707
2708/**
2709 * Query unsigned 16-bit integer value.
2710 *
2711 * @returns VBox status code.
2712 * @param pNode Which node to search for pszName in.
2713 * @param pszName Name of an integer value.
2714 * @param pu16 Where to store the value.
2715 */
2716VMMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
2717{
2718 uint64_t u64;
2719 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2720 if (RT_SUCCESS(rc))
2721 {
2722 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2723 *pu16 = (int16_t)u64;
2724 else
2725 rc = VERR_CFGM_INTEGER_TOO_BIG;
2726 }
2727 return rc;
2728}
2729
2730
2731/**
2732 * Query unsigned 16-bit integer value with default.
2733 *
2734 * @returns VBox status code.
2735 * @param pNode Which node to search for pszName in.
2736 * @param pszName Name of an integer value.
2737 * @param pu16 Where to store the value. Set to default on failure.
2738 * @param u16Def The default value.
2739 */
2740VMMR3DECL(int) CFGMR3QueryU16Def(PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)
2741{
2742 uint64_t u64;
2743 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u16Def);
2744 if (RT_SUCCESS(rc))
2745 {
2746 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2747 *pu16 = (int16_t)u64;
2748 else
2749 rc = VERR_CFGM_INTEGER_TOO_BIG;
2750 }
2751 if (RT_FAILURE(rc))
2752 *pu16 = u16Def;
2753 return rc;
2754}
2755
2756
2757/**
2758 * Query signed 16-bit integer value.
2759 *
2760 * @returns VBox status code.
2761 * @param pNode Which node to search for pszName in.
2762 * @param pszName Name of an integer value.
2763 * @param pi16 Where to store the value.
2764 */
2765VMMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
2766{
2767 uint64_t u64;
2768 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2769 if (RT_SUCCESS(rc))
2770 {
2771 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2772 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2773 *pi16 = (int16_t)u64;
2774 else
2775 rc = VERR_CFGM_INTEGER_TOO_BIG;
2776 }
2777 return rc;
2778}
2779
2780
2781/**
2782 * Query signed 16-bit integer value with default.
2783 *
2784 * @returns VBox status code.
2785 * @param pNode Which node to search for pszName in.
2786 * @param pszName Name of an integer value.
2787 * @param pi16 Where to store the value. Set to default on failure.
2788 * @param i16Def The default value.
2789 */
2790VMMR3DECL(int) CFGMR3QueryS16Def(PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)
2791{
2792 uint64_t u64;
2793 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i16Def);
2794 if (RT_SUCCESS(rc))
2795 {
2796 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2797 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2798 *pi16 = (int16_t)u64;
2799 else
2800 rc = VERR_CFGM_INTEGER_TOO_BIG;
2801 }
2802 if (RT_FAILURE(rc))
2803 *pi16 = i16Def;
2804 return rc;
2805}
2806
2807
2808/**
2809 * Query unsigned 8-bit integer value.
2810 *
2811 * @returns VBox status code.
2812 * @param pNode Which node to search for pszName in.
2813 * @param pszName Name of an integer value.
2814 * @param pu8 Where to store the value.
2815 */
2816VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
2817{
2818 uint64_t u64;
2819 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2820 if (RT_SUCCESS(rc))
2821 {
2822 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2823 *pu8 = (uint8_t)u64;
2824 else
2825 rc = VERR_CFGM_INTEGER_TOO_BIG;
2826 }
2827 return rc;
2828}
2829
2830
2831/**
2832 * Query unsigned 8-bit integer value with default.
2833 *
2834 * @returns VBox status code.
2835 * @param pNode Which node to search for pszName in.
2836 * @param pszName Name of an integer value.
2837 * @param pu8 Where to store the value. Set to default on failure.
2838 * @param u8Def The default value.
2839 */
2840VMMR3DECL(int) CFGMR3QueryU8Def(PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)
2841{
2842 uint64_t u64;
2843 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u8Def);
2844 if (RT_SUCCESS(rc))
2845 {
2846 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2847 *pu8 = (uint8_t)u64;
2848 else
2849 rc = VERR_CFGM_INTEGER_TOO_BIG;
2850 }
2851 if (RT_FAILURE(rc))
2852 *pu8 = u8Def;
2853 return rc;
2854}
2855
2856
2857/**
2858 * Query signed 8-bit integer value.
2859 *
2860 * @returns VBox status code.
2861 * @param pNode Which node to search for pszName in.
2862 * @param pszName Name of an integer value.
2863 * @param pi8 Where to store the value.
2864 */
2865VMMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
2866{
2867 uint64_t u64;
2868 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2869 if (RT_SUCCESS(rc))
2870 {
2871 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2872 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2873 *pi8 = (int8_t)u64;
2874 else
2875 rc = VERR_CFGM_INTEGER_TOO_BIG;
2876 }
2877 return rc;
2878}
2879
2880
2881/**
2882 * Query signed 8-bit integer value with default.
2883 *
2884 * @returns VBox status code.
2885 * @param pNode Which node to search for pszName in.
2886 * @param pszName Name of an integer value.
2887 * @param pi8 Where to store the value. Set to default on failure.
2888 * @param i8Def The default value.
2889 */
2890VMMR3DECL(int) CFGMR3QueryS8Def(PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)
2891{
2892 uint64_t u64;
2893 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i8Def);
2894 if (RT_SUCCESS(rc))
2895 {
2896 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2897 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2898 *pi8 = (int8_t)u64;
2899 else
2900 rc = VERR_CFGM_INTEGER_TOO_BIG;
2901 }
2902 if (RT_FAILURE(rc))
2903 *pi8 = i8Def;
2904 return rc;
2905}
2906
2907
2908/**
2909 * Query boolean integer value.
2910 *
2911 * @returns VBox status code.
2912 * @param pNode Which node to search for pszName in.
2913 * @param pszName Name of an integer value.
2914 * @param pf Where to store the value.
2915 * @remark This function will interpret any non-zero value as true.
2916 */
2917VMMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
2918{
2919 uint64_t u64;
2920 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2921 if (RT_SUCCESS(rc))
2922 *pf = u64 ? true : false;
2923 return rc;
2924}
2925
2926
2927/**
2928 * Query boolean integer value with default.
2929 *
2930 * @returns VBox status code.
2931 * @param pNode Which node to search for pszName in.
2932 * @param pszName Name of an integer value.
2933 * @param pf Where to store the value. Set to default on failure.
2934 * @param fDef The default value.
2935 * @remark This function will interpret any non-zero value as true.
2936 */
2937VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
2938{
2939 uint64_t u64;
2940 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, fDef);
2941 *pf = u64 ? true : false;
2942 return rc;
2943}
2944
2945
2946/**
2947 * Query I/O port address value.
2948 *
2949 * @returns VBox status code.
2950 * @param pNode Which node to search for pszName in.
2951 * @param pszName Name of an integer value.
2952 * @param pPort Where to store the value.
2953 */
2954VMMR3DECL(int) CFGMR3QueryPort(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)
2955{
2956 AssertCompileSize(RTIOPORT, 2);
2957 return CFGMR3QueryU16(pNode, pszName, pPort);
2958}
2959
2960
2961/**
2962 * Query I/O port address value with default.
2963 *
2964 * @returns VBox status code.
2965 * @param pNode Which node to search for pszName in.
2966 * @param pszName Name of an integer value.
2967 * @param pPort Where to store the value. Set to default on failure.
2968 * @param PortDef The default value.
2969 */
2970VMMR3DECL(int) CFGMR3QueryPortDef(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)
2971{
2972 AssertCompileSize(RTIOPORT, 2);
2973 return CFGMR3QueryU16Def(pNode, pszName, pPort, PortDef);
2974}
2975
2976
2977/**
2978 * Query unsigned int address value.
2979 *
2980 * @returns VBox status code.
2981 * @param pNode Which node to search for pszName in.
2982 * @param pszName Name of an integer value.
2983 * @param pu Where to store the value.
2984 */
2985VMMR3DECL(int) CFGMR3QueryUInt(PCFGMNODE pNode, const char *pszName, unsigned int *pu)
2986{
2987 AssertCompileSize(unsigned int, 4);
2988 return CFGMR3QueryU32(pNode, pszName, (uint32_t *)pu);
2989}
2990
2991
2992/**
2993 * Query unsigned int address value with default.
2994 *
2995 * @returns VBox status code.
2996 * @param pNode Which node to search for pszName in.
2997 * @param pszName Name of an integer value.
2998 * @param pu Where to store the value. Set to default on failure.
2999 * @param uDef The default value.
3000 */
3001VMMR3DECL(int) CFGMR3QueryUIntDef(PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)
3002{
3003 AssertCompileSize(unsigned int, 4);
3004 return CFGMR3QueryU32Def(pNode, pszName, (uint32_t *)pu, uDef);
3005}
3006
3007
3008/**
3009 * Query signed int address value.
3010 *
3011 * @returns VBox status code.
3012 * @param pNode Which node to search for pszName in.
3013 * @param pszName Name of an integer value.
3014 * @param pi Where to store the value.
3015 */
3016VMMR3DECL(int) CFGMR3QuerySInt(PCFGMNODE pNode, const char *pszName, signed int *pi)
3017{
3018 AssertCompileSize(signed int, 4);
3019 return CFGMR3QueryS32(pNode, pszName, (int32_t *)pi);
3020}
3021
3022
3023/**
3024 * Query unsigned int address value with default.
3025 *
3026 * @returns VBox status code.
3027 * @param pNode Which node to search for pszName in.
3028 * @param pszName Name of an integer value.
3029 * @param pi Where to store the value. Set to default on failure.
3030 * @param iDef The default value.
3031 */
3032VMMR3DECL(int) CFGMR3QuerySIntDef(PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)
3033{
3034 AssertCompileSize(signed int, 4);
3035 return CFGMR3QueryS32Def(pNode, pszName, (int32_t *)pi, iDef);
3036}
3037
3038
3039/**
3040 * Query Guest Context pointer integer value.
3041 *
3042 * @returns VBox status code.
3043 * @param pNode Which node to search for pszName in.
3044 * @param pszName Name of an integer value.
3045 * @param pGCPtr Where to store the value.
3046 */
3047VMMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
3048{
3049 uint64_t u64;
3050 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
3051 if (RT_SUCCESS(rc))
3052 {
3053 RTGCPTR u = (RTGCPTR)u64;
3054 if (u64 == u)
3055 *pGCPtr = u;
3056 else
3057 rc = VERR_CFGM_INTEGER_TOO_BIG;
3058 }
3059 return rc;
3060}
3061
3062
3063/**
3064 * Query Guest Context pointer integer value with default.
3065 *
3066 * @returns VBox status code.
3067 * @param pNode Which node to search for pszName in.
3068 * @param pszName Name of an integer value.
3069 * @param pGCPtr Where to store the value. Set to default on failure.
3070 * @param GCPtrDef The default value.
3071 */
3072VMMR3DECL(int) CFGMR3QueryGCPtrDef(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)
3073{
3074 uint64_t u64;
3075 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
3076 if (RT_SUCCESS(rc))
3077 {
3078 RTGCPTR u = (RTGCPTR)u64;
3079 if (u64 == u)
3080 *pGCPtr = u;
3081 else
3082 rc = VERR_CFGM_INTEGER_TOO_BIG;
3083 }
3084 if (RT_FAILURE(rc))
3085 *pGCPtr = GCPtrDef;
3086 return rc;
3087}
3088
3089
3090/**
3091 * Query Guest Context unsigned pointer value.
3092 *
3093 * @returns VBox status code.
3094 * @param pNode Which node to search for pszName in.
3095 * @param pszName Name of an integer value.
3096 * @param pGCPtr Where to store the value.
3097 */
3098VMMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
3099{
3100 uint64_t u64;
3101 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
3102 if (RT_SUCCESS(rc))
3103 {
3104 RTGCUINTPTR u = (RTGCUINTPTR)u64;
3105 if (u64 == u)
3106 *pGCPtr = u;
3107 else
3108 rc = VERR_CFGM_INTEGER_TOO_BIG;
3109 }
3110 return rc;
3111}
3112
3113
3114/**
3115 * Query Guest Context unsigned pointer value with default.
3116 *
3117 * @returns VBox status code.
3118 * @param pNode Which node to search for pszName in.
3119 * @param pszName Name of an integer value.
3120 * @param pGCPtr Where to store the value. Set to default on failure.
3121 * @param GCPtrDef The default value.
3122 */
3123VMMR3DECL(int) CFGMR3QueryGCPtrUDef(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)
3124{
3125 uint64_t u64;
3126 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
3127 if (RT_SUCCESS(rc))
3128 {
3129 RTGCUINTPTR u = (RTGCUINTPTR)u64;
3130 if (u64 == u)
3131 *pGCPtr = u;
3132 else
3133 rc = VERR_CFGM_INTEGER_TOO_BIG;
3134 }
3135 if (RT_FAILURE(rc))
3136 *pGCPtr = GCPtrDef;
3137 return rc;
3138}
3139
3140
3141/**
3142 * Query Guest Context signed pointer value.
3143 *
3144 * @returns VBox status code.
3145 * @param pNode Which node to search for pszName in.
3146 * @param pszName Name of an integer value.
3147 * @param pGCPtr Where to store the value.
3148 */
3149VMMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
3150{
3151 uint64_t u64;
3152 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
3153 if (RT_SUCCESS(rc))
3154 {
3155 RTGCINTPTR u = (RTGCINTPTR)u64;
3156 if (u64 == (uint64_t)u)
3157 *pGCPtr = u;
3158 else
3159 rc = VERR_CFGM_INTEGER_TOO_BIG;
3160 }
3161 return rc;
3162}
3163
3164
3165/**
3166 * Query Guest Context signed pointer value with default.
3167 *
3168 * @returns VBox status code.
3169 * @param pNode Which node to search for pszName in.
3170 * @param pszName Name of an integer value.
3171 * @param pGCPtr Where to store the value. Set to default on failure.
3172 * @param GCPtrDef The default value.
3173 */
3174VMMR3DECL(int) CFGMR3QueryGCPtrSDef(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)
3175{
3176 uint64_t u64;
3177 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
3178 if (RT_SUCCESS(rc))
3179 {
3180 RTGCINTPTR u = (RTGCINTPTR)u64;
3181 if (u64 == (uint64_t)u)
3182 *pGCPtr = u;
3183 else
3184 rc = VERR_CFGM_INTEGER_TOO_BIG;
3185 }
3186 if (RT_FAILURE(rc))
3187 *pGCPtr = GCPtrDef;
3188 return rc;
3189}
3190
3191
3192/**
3193 * Query zero terminated character value storing it in a
3194 * buffer allocated from the MM heap.
3195 *
3196 * @returns VBox status code.
3197 * @param pNode Which node to search for pszName in.
3198 * @param pszName Value name. This value must be of zero terminated character string type.
3199 * @param ppszString Where to store the string pointer.
3200 * Free this using MMR3HeapFree() (or RTStrFree if not
3201 * associated with a pUVM - see CFGMR3CreateTree).
3202 */
3203VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
3204{
3205 size_t cbString;
3206 int rc = CFGMR3QuerySize(pNode, pszName, &cbString);
3207 if (RT_SUCCESS(rc))
3208 {
3209 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString);
3210 if (pszString)
3211 {
3212 rc = CFGMR3QueryString(pNode, pszName, pszString, cbString);
3213 if (RT_SUCCESS(rc))
3214 *ppszString = pszString;
3215 else
3216 cfgmR3StrFree(pNode->pVM, pszString);
3217 }
3218 else
3219 rc = VERR_NO_MEMORY;
3220 }
3221 return rc;
3222}
3223
3224
3225/**
3226 * Query zero terminated character value storing it in a
3227 * buffer allocated from the MM heap.
3228 *
3229 * @returns VBox status code.
3230 * @param pNode Which node to search for pszName in. This cannot be
3231 * NULL if @a pszDef is not NULL, because we need
3232 * somewhere way to get to the VM in order to call
3233 * MMR3HeapStrDup.
3234 * @param pszName Value name. This value must be of zero terminated character string type.
3235 * @param ppszString Where to store the string pointer. Not set on failure.
3236 * Free this using MMR3HeapFree() (or RTStrFree if not
3237 * associated with a pUVM - see CFGMR3CreateTree).
3238 * @param pszDef The default return value. This can be NULL.
3239 */
3240VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
3241{
3242 Assert(pNode || !pszDef); /* We need pVM if we need to duplicate the string later. */
3243
3244 /*
3245 * (Don't call CFGMR3QuerySize and CFGMR3QueryStringDef here as the latter
3246 * cannot handle pszDef being NULL.)
3247 */
3248 PCFGMLEAF pLeaf;
3249 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
3250 if (RT_SUCCESS(rc))
3251 {
3252 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
3253 {
3254 size_t const cbSrc = pLeaf->Value.String.cb;
3255 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbSrc);
3256 if (pszString)
3257 {
3258 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
3259 *ppszString = pszString;
3260 }
3261 else
3262 rc = VERR_NO_MEMORY;
3263 }
3264 else
3265 rc = VERR_CFGM_NOT_STRING;
3266 }
3267 if (RT_FAILURE(rc))
3268 {
3269 if (!pszDef)
3270 *ppszString = NULL;
3271 else
3272 {
3273 size_t const cbDef = strlen(pszDef) + 1;
3274 *ppszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbDef);
3275 memcpy(*ppszString, pszDef, cbDef);
3276 }
3277 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
3278 rc = VINF_SUCCESS;
3279 }
3280
3281 return rc;
3282}
3283
3284
3285/**
3286 * Dumps the configuration (sub)tree to the release log.
3287 *
3288 * @param pRoot The root node of the dump.
3289 */
3290VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
3291{
3292 bool fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/);
3293 LogRel(("************************* CFGM dump *************************\n"));
3294 cfgmR3Dump(pRoot, 0, DBGFR3InfoLogRelHlp());
3295 LogRel(("********************* End of CFGM dump **********************\n"));
3296 RTLogRelSetBuffering(fOldBuffered);
3297}
3298
3299
3300/**
3301 * Info handler, internal version.
3302 *
3303 * @param pVM The cross context VM structure.
3304 * @param pHlp Callback functions for doing output.
3305 * @param pszArgs Argument string. Optional and specific to the handler.
3306 */
3307static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
3308{
3309 /*
3310 * Figure where to start.
3311 */
3312 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
3313 if (pszArgs && *pszArgs)
3314 {
3315 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
3316 if (RT_FAILURE(rc))
3317 {
3318 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Rrc", pszArgs, rc);
3319 return;
3320 }
3321 }
3322
3323 /*
3324 * Dump the specified tree.
3325 */
3326 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
3327 cfgmR3DumpPath(pRoot, pHlp);
3328 pHlp->pfnPrintf(pHlp, "}\n");
3329 cfgmR3Dump(pRoot, 0, pHlp);
3330}
3331
3332
3333/**
3334 * Recursively prints a path name.
3335 */
3336static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
3337{
3338 if (pNode->pParent)
3339 cfgmR3DumpPath(pNode->pParent, pHlp);
3340 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
3341}
3342
3343
3344/**
3345 * Dumps a branch of a tree.
3346 */
3347static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
3348{
3349 /*
3350 * Path.
3351 */
3352 pHlp->pfnPrintf(pHlp, "[");
3353 cfgmR3DumpPath(pRoot, pHlp);
3354 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
3355
3356 /*
3357 * Values.
3358 */
3359 PCFGMLEAF pLeaf;
3360 size_t cchMax = 0;
3361 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3362 cchMax = RT_MAX(cchMax, pLeaf->cchName);
3363 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3364 {
3365 switch (CFGMR3GetValueType(pLeaf))
3366 {
3367 case CFGMVALUETYPE_INTEGER:
3368 {
3369 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%'lld",
3370 (int)cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
3371 if ( ( pLeaf->cchName >= 4
3372 && !RTStrCmp(&pLeaf->szName[pLeaf->cchName - 4], "Size"))
3373 || ( pLeaf->cchName >= 2
3374 && !RTStrNCmp(pLeaf->szName, "cb", 2)) )
3375 pHlp->pfnPrintf(pHlp, ", %' Rhcb)\n", pLeaf->Value.Integer.u64);
3376 else
3377 pHlp->pfnPrintf(pHlp, ")\n");
3378 break;
3379 }
3380
3381 case CFGMVALUETYPE_STRING:
3382 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cb=%zu)\n",
3383 (int)cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cb);
3384 break;
3385
3386 case CFGMVALUETYPE_BYTES:
3387 pHlp->pfnPrintf(pHlp, " %-*s <bytes> = \"%.*Rhxs\" (cb=%zu)\n",
3388 (int)cchMax, pLeaf->szName, pLeaf->Value.Bytes.cb, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
3389 break;
3390
3391 case CFGMVALUETYPE_PASSWORD:
3392 pHlp->pfnPrintf(pHlp, " %-*s <password>= \"***REDACTED***\" (cb=%zu)\n",
3393 (int)cchMax, pLeaf->szName, pLeaf->Value.String.cb);
3394 break;
3395
3396 default:
3397 AssertMsgFailed(("bad leaf!\n"));
3398 break;
3399 }
3400 }
3401 pHlp->pfnPrintf(pHlp, "\n");
3402
3403 /*
3404 * Children.
3405 */
3406 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
3407 {
3408 Assert(pChild->pNext != pChild);
3409 Assert(pChild->pPrev != pChild);
3410 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
3411 Assert(pChild->pFirstChild != pChild);
3412 Assert(pChild->pParent == pRoot);
3413 cfgmR3Dump(pChild, iLevel + 1, pHlp);
3414 }
3415}
3416
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use