VirtualBox

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

Last change on this file since 41009 was 41009, checked in by vboxsync, 13 years ago

CFGM: thousand separator, GB, cb-prefix, and some nits.

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