VirtualBox

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

Last change on this file since 102468 was 99739, checked in by vboxsync, 20 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

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

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