VirtualBox

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

Last change on this file since 44346 was 44340, checked in by vboxsync, 12 years ago

VMM,Main,Debugger,REM: VM API cleanup, prefering PUVM over PVM so we can use real reference counting and not have the memory backing the VM structure disappear on us.

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

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