VirtualBox

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

Last change on this file since 18770 was 18351, checked in by vboxsync, 16 years ago

CFGM: doc update.

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