VirtualBox

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

Last change on this file since 16524 was 14070, checked in by vboxsync, 16 years ago

CFGM: 64-bit MSC warning hunt.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 73.0 KB
Line 
1/* $Id: CFGM.cpp 14070 2008-11-10 23:45:24Z 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.
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", 128 * _1M);
772 UPDATERC();
773 rc = CFGMR3InsertInteger(pRoot, "TimerMillies", 10);
774 UPDATERC();
775 rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled", 1);
776 UPDATERC();
777 /** @todo CFGM Defaults: RawR0, PATMEnabled and CASMEnabled needs attention later. */
778 rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled", 1);
779 UPDATERC();
780 rc = CFGMR3InsertInteger(pRoot, "PATMEnabled", 1);
781 UPDATERC();
782 rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled", 1);
783 UPDATERC();
784
785 /*
786 * PDM.
787 */
788 PCFGMNODE pPdm;
789 rc = CFGMR3InsertNode(pRoot, "PDM", &pPdm);
790 UPDATERC();
791 PCFGMNODE pDevices = NULL;
792 rc = CFGMR3InsertNode(pPdm, "Devices", &pDevices);
793 UPDATERC();
794 rc = CFGMR3InsertInteger(pDevices, "LoadBuiltin", 1); /* boolean */
795 UPDATERC();
796 PCFGMNODE pDrivers = NULL;
797 rc = CFGMR3InsertNode(pPdm, "Drivers", &pDrivers);
798 UPDATERC();
799 rc = CFGMR3InsertInteger(pDrivers, "LoadBuiltin", 1); /* boolean */
800 UPDATERC();
801
802
803 /*
804 * Devices
805 */
806 pDevices = NULL;
807 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);
808 UPDATERC();
809 /* device */
810 PCFGMNODE pDev = NULL;
811 PCFGMNODE pInst = NULL;
812 PCFGMNODE pCfg = NULL;
813#if 0
814 PCFGMNODE pLunL0 = NULL;
815 PCFGMNODE pLunL1 = NULL;
816#endif
817
818 /*
819 * PC Arch.
820 */
821 rc = CFGMR3InsertNode(pDevices, "pcarch", &pDev);
822 UPDATERC();
823 rc = CFGMR3InsertNode(pDev, "0", &pInst);
824 UPDATERC();
825 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
826 UPDATERC();
827 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
828 UPDATERC();
829
830 /*
831 * PC Bios.
832 */
833 rc = CFGMR3InsertNode(pDevices, "pcbios", &pDev);
834 UPDATERC();
835 rc = CFGMR3InsertNode(pDev, "0", &pInst);
836 UPDATERC();
837 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
838 UPDATERC();
839 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
840 UPDATERC();
841 rc = CFGMR3InsertInteger(pCfg, "RamSize", 128 * _1M);
842 UPDATERC();
843 rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
844 UPDATERC();
845 rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
846 UPDATERC();
847 rc = CFGMR3InsertString(pCfg, "BootDevice2", "NONE");
848 UPDATERC();
849 rc = CFGMR3InsertString(pCfg, "BootDevice3", "NONE");
850 UPDATERC();
851 rc = CFGMR3InsertString(pCfg, "HardDiskDevice", "piix3ide");
852 UPDATERC();
853 rc = CFGMR3InsertString(pCfg, "FloppyDevice", "");
854 UPDATERC();
855 RTUUID Uuid;
856 RTUuidClear(&Uuid);
857 rc = CFGMR3InsertBytes(pCfg, "UUID", &Uuid, sizeof(Uuid));
858 UPDATERC();
859
860 /*
861 * PCI bus.
862 */
863 rc = CFGMR3InsertNode(pDevices, "pci", &pDev); /* piix3 */
864 UPDATERC();
865 rc = CFGMR3InsertNode(pDev, "0", &pInst);
866 UPDATERC();
867 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
868 UPDATERC();
869 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
870 UPDATERC();
871
872 /*
873 * PS/2 keyboard & mouse
874 */
875 rc = CFGMR3InsertNode(pDevices, "pckbd", &pDev);
876 UPDATERC();
877 rc = CFGMR3InsertNode(pDev, "0", &pInst);
878 UPDATERC();
879 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
880 UPDATERC();
881#if 0
882 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
883 UPDATERC();
884 rc = CFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue");
885 UPDATERC();
886 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
887 UPDATERC();
888 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 64);
889 UPDATERC();
890 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
891 UPDATERC();
892 rc = CFGMR3InsertString(pLunL1, "Driver", "MainKeyboard");
893 UPDATERC();
894 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
895 UPDATERC();
896#endif
897#if 0
898 rc = CFGMR3InsertNode(pInst, "LUN#1", &pLunL0);
899 UPDATERC();
900 rc = CFGMR3InsertString(pLunL0, "Driver", "MouseQueue");
901 UPDATERC();
902 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
903 UPDATERC();
904 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 128);
905 UPDATERC();
906 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
907 UPDATERC();
908 rc = CFGMR3InsertString(pLunL1, "Driver", "MainMouse");
909 UPDATERC();
910 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
911 UPDATERC();
912#endif
913
914 /*
915 * i8254 Programmable Interval Timer And Dummy Speaker
916 */
917 rc = CFGMR3InsertNode(pDevices, "i8254", &pDev);
918 UPDATERC();
919 rc = CFGMR3InsertNode(pDev, "0", &pInst);
920 UPDATERC();
921#ifdef DEBUG
922 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
923 UPDATERC();
924#endif
925 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
926 UPDATERC();
927
928 /*
929 * i8259 Programmable Interrupt Controller.
930 */
931 rc = CFGMR3InsertNode(pDevices, "i8259", &pDev);
932 UPDATERC();
933 rc = CFGMR3InsertNode(pDev, "0", &pInst);
934 UPDATERC();
935 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
936 UPDATERC();
937 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
938 UPDATERC();
939
940 /*
941 * RTC MC146818.
942 */
943 rc = CFGMR3InsertNode(pDevices, "mc146818", &pDev);
944 UPDATERC();
945 rc = CFGMR3InsertNode(pDev, "0", &pInst);
946 UPDATERC();
947 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
948 UPDATERC();
949
950 /*
951 * VGA.
952 */
953 rc = CFGMR3InsertNode(pDevices, "vga", &pDev);
954 UPDATERC();
955 rc = CFGMR3InsertNode(pDev, "0", &pInst);
956 UPDATERC();
957 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
958 UPDATERC();
959 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
960 UPDATERC();
961 rc = CFGMR3InsertInteger(pCfg, "VRamSize", 4 * _1M);
962 UPDATERC();
963
964 /* Bios logo. */
965 rc = CFGMR3InsertInteger(pCfg, "FadeIn", 1);
966 UPDATERC();
967 rc = CFGMR3InsertInteger(pCfg, "FadeOut", 1);
968 UPDATERC();
969 rc = CFGMR3InsertInteger(pCfg, "LogoTime", 0);
970 UPDATERC();
971 rc = CFGMR3InsertString(pCfg, "LogoFile", "");
972 UPDATERC();
973
974#if 0
975 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
976 UPDATERC();
977 rc = CFGMR3InsertString(pLunL0, "Driver", "MainDisplay");
978 UPDATERC();
979#endif
980
981 /*
982 * IDE controller.
983 */
984 rc = CFGMR3InsertNode(pDevices, "piix3ide", &pDev); /* piix3 */
985 UPDATERC();
986 rc = CFGMR3InsertNode(pDev, "0", &pInst);
987 UPDATERC();
988 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
989 UPDATERC();
990 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
991 UPDATERC();
992
993
994
995 /*
996 * ...
997 */
998
999#undef UPDATERC
1000 return rcAll;
1001}
1002
1003
1004
1005
1006/**
1007 * Resolves a path reference to a child node.
1008 *
1009 * @returns VBox status code.
1010 * @param pNode Which node to search for pszName in.
1011 * @param pszPath Path to the child node.
1012 * @param ppChild Where to store the pointer to the child node.
1013 */
1014static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild)
1015{
1016 if (pNode)
1017 {
1018 PCFGMNODE pChild = NULL;
1019 for (;;)
1020 {
1021 /* skip leading slashes. */
1022 while (*pszPath == '/')
1023 pszPath++;
1024
1025 /* End of path? */
1026 if (!*pszPath)
1027 {
1028 if (!pChild)
1029 return VERR_CFGM_INVALID_CHILD_PATH;
1030 *ppChild = pChild;
1031 return VINF_SUCCESS;
1032 }
1033
1034 /* find end of component. */
1035 const char *pszNext = strchr(pszPath, '/');
1036 if (!pszNext)
1037 pszNext = strchr(pszPath, '\0');
1038 RTUINT cchName = pszNext - pszPath;
1039
1040 /* search child list. */
1041 pChild = pNode->pFirstChild;
1042 for ( ; pChild; pChild = pChild->pNext)
1043 if ( pChild->cchName == cchName
1044 && !memcmp(pszPath, pChild->szName, cchName) )
1045 break;
1046
1047 /* if not found, we're done. */
1048 if (!pChild)
1049 return VERR_CFGM_CHILD_NOT_FOUND;
1050
1051 /* next iteration */
1052 pNode = pChild;
1053 pszPath = pszNext;
1054 }
1055
1056 /* won't get here */
1057 }
1058 else
1059 return VERR_CFGM_NO_PARENT;
1060}
1061
1062
1063/**
1064 * Resolves a path reference to a child node.
1065 *
1066 * @returns VBox status code.
1067 * @param pNode Which node to search for pszName in.
1068 * @param pszName Name of a byte string value.
1069 * @param ppLeaf Where to store the pointer to the leaf node.
1070 */
1071static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1072{
1073 int rc;
1074 if (pNode)
1075 {
1076 size_t cchName = strlen(pszName);
1077 PCFGMLEAF pLeaf = pNode->pFirstLeaf;
1078 while (pLeaf)
1079 {
1080 if ( cchName == pLeaf->cchName
1081 && !memcmp(pszName, pLeaf->szName, cchName) )
1082 {
1083 *ppLeaf = pLeaf;
1084 return VINF_SUCCESS;
1085 }
1086
1087 /* next */
1088 pLeaf = pLeaf->pNext;
1089 }
1090 rc = VERR_CFGM_VALUE_NOT_FOUND;
1091 }
1092 else
1093 rc = VERR_CFGM_NO_PARENT;
1094 return rc;
1095}
1096
1097
1098
1099/**
1100 * Creates a CFGM tree.
1101 *
1102 * This is intended for creating device/driver configs can be
1103 * passed around and later attached to the main tree in the
1104 * correct location.
1105 *
1106 * @returns Pointer to the root node.
1107 * @param pVM The VM handle.
1108 */
1109VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PVM pVM)
1110{
1111 PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pVM, MM_TAG_CFGM, sizeof(*pNew));
1112 if (pNew)
1113 {
1114 pNew->pPrev = NULL;
1115 pNew->pNext = NULL;
1116 pNew->pParent = NULL;
1117 pNew->pFirstChild = NULL;
1118 pNew->pFirstLeaf = NULL;
1119 pNew->pVM = pVM;
1120 pNew->fRestrictedRoot = false;
1121 pNew->cchName = 0;
1122 pNew->szName[0] = 0;
1123 }
1124 return pNew;
1125}
1126
1127
1128/**
1129 * Insert subtree.
1130 *
1131 * This function inserts (no duplication) a tree created by CFGMR3CreateTree()
1132 * into the main tree.
1133 *
1134 * The root node of the inserted subtree will need to be reallocated, which
1135 * effectually means that the passed in pSubTree handle becomes invalid
1136 * upon successful return. Use the value returned in ppChild instead
1137 * of pSubTree.
1138 *
1139 * @returns VBox status code.
1140 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1141 * @param pNode Parent node.
1142 * @param pszName Name or path of the new child node.
1143 * @param pSubTree The subtree to insert. Must be returned by CFGMR3CreateTree().
1144 * @param ppChild Where to store the address of the new child node. (optional)
1145 */
1146VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild)
1147{
1148 /*
1149 * Validate input.
1150 */
1151 AssertPtrReturn(pSubTree, VERR_INVALID_POINTER);
1152 AssertReturn(!pSubTree->pParent, VERR_INVALID_PARAMETER);
1153 AssertReturn(pSubTree->pVM, VERR_INVALID_PARAMETER);
1154 AssertReturn(pSubTree->pParent != pSubTree->pVM->cfgm.s.pRoot, VERR_INVALID_PARAMETER);
1155 Assert(!pSubTree->pNext);
1156 Assert(!pSubTree->pPrev);
1157
1158 /*
1159 * Use CFGMR3InsertNode to create a new node and then
1160 * re-attach the children and leafs of the subtree to it.
1161 */
1162 PCFGMNODE pNewChild;
1163 int rc = CFGMR3InsertNode(pNode, pszName, &pNewChild);
1164 if (RT_SUCCESS(rc))
1165 {
1166 Assert(!pNewChild->pFirstChild);
1167 pNewChild->pFirstChild = pSubTree->pFirstChild;
1168 Assert(!pNewChild->pFirstLeaf);
1169 pNewChild->pFirstLeaf = pSubTree->pFirstLeaf;
1170 if (ppChild)
1171 *ppChild = pNewChild;
1172
1173 /* free the old subtree root */
1174 pSubTree->pVM = NULL;
1175 pSubTree->pFirstLeaf = NULL;
1176 pSubTree->pFirstChild = NULL;
1177 MMR3HeapFree(pSubTree);
1178 }
1179 return rc;
1180}
1181
1182
1183/**
1184 * Insert a node.
1185 *
1186 * @returns VBox status code.
1187 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1188 * @param pNode Parent node.
1189 * @param pszName Name or path of the new child node.
1190 * @param ppChild Where to store the address of the new child node. (optional)
1191 */
1192VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
1193{
1194 int rc;
1195 if (pNode)
1196 {
1197 /*
1198 * If given a path we have to deal with it component by compontent.
1199 */
1200 while (*pszName == '/')
1201 pszName++;
1202 if (strchr(pszName, '/'))
1203 {
1204 char *pszDup = RTStrDup(pszName);
1205 if (pszDup)
1206 {
1207 char *psz = pszDup;
1208 for (;;)
1209 {
1210 /* Terminate at '/' and find the next component. */
1211 char *pszNext = strchr(psz, '/');
1212 if (pszNext)
1213 {
1214 *pszNext++ = '\0';
1215 while (*pszNext == '/')
1216 pszNext++;
1217 if (*pszNext == '\0')
1218 pszNext = NULL;
1219 }
1220
1221 /* does it exist? */
1222 PCFGMNODE pChild = CFGMR3GetChild(pNode, psz);
1223 if (!pChild)
1224 {
1225 /* no, insert it */
1226 rc = CFGMR3InsertNode(pNode, psz, &pChild);
1227 if (RT_FAILURE(rc))
1228 break;
1229 if (!pszNext)
1230 {
1231 if (ppChild)
1232 *ppChild = pChild;
1233 break;
1234 }
1235
1236 }
1237 /* if last component fail */
1238 else if (!pszNext)
1239 {
1240 rc = VERR_CFGM_NODE_EXISTS;
1241 break;
1242 }
1243
1244 /* next */
1245 pNode = pChild;
1246 psz = pszNext;
1247 }
1248 RTStrFree(pszDup);
1249 }
1250 else
1251 rc = VERR_NO_TMP_MEMORY;
1252 }
1253 /*
1254 * Not multicomponent, just make sure it's a non-zero name.
1255 */
1256 else if (*pszName)
1257 {
1258 /*
1259 * Check if already exists and find last node in chain.
1260 */
1261 size_t cchName = strlen(pszName);
1262 PCFGMNODE pPrev = pNode->pFirstChild;
1263 if (pPrev)
1264 {
1265 for (;; pPrev = pPrev->pNext)
1266 {
1267 if ( cchName == pPrev->cchName
1268 && !memcmp(pszName, pPrev->szName, cchName))
1269 return VERR_CFGM_NODE_EXISTS;
1270 if (!pPrev->pNext)
1271 break;
1272 }
1273 }
1274
1275 /*
1276 * Allocate and init node.
1277 */
1278 PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1279 if (pNew)
1280 {
1281 pNew->pParent = pNode;
1282 pNew->pFirstChild = NULL;
1283 pNew->pFirstLeaf = NULL;
1284 pNew->pVM = pNode->pVM;
1285 pNew->fRestrictedRoot = false;
1286 pNew->cchName = cchName;
1287 memcpy(pNew->szName, pszName, cchName + 1);
1288
1289 /*
1290 * Insert into child list.
1291 */
1292 pNew->pNext = NULL;
1293 pNew->pPrev = pPrev;
1294 if (pPrev)
1295 pPrev->pNext = pNew;
1296 else
1297 pNode->pFirstChild = pNew;
1298 if (ppChild)
1299 *ppChild = pNew;
1300 rc = VINF_SUCCESS;
1301 }
1302 else
1303 rc = VERR_NO_MEMORY;
1304 }
1305 else
1306 {
1307 rc = VERR_CFGM_INVALID_NODE_PATH;
1308 AssertMsgFailed(("Invalid path %s\n", pszName));
1309 }
1310 }
1311 else
1312 {
1313 rc = VERR_CFGM_NO_PARENT;
1314 AssertMsgFailed(("No parent! path %s\n", pszName));
1315 }
1316
1317 return rc;
1318}
1319
1320
1321/**
1322 * Insert a node, format string name.
1323 *
1324 * @returns VBox status code.
1325 * @param pNode Parent node.
1326 * @param ppChild Where to store the address of the new child node. (optional)
1327 * @param pszNameFormat Name of or path the new child node.
1328 * @param ... Name format arguments.
1329 */
1330VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
1331{
1332 va_list Args;
1333 va_start(Args, pszNameFormat);
1334 int rc = CFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
1335 va_end(Args);
1336 return rc;
1337}
1338
1339
1340/**
1341 * Insert a node, format string name.
1342 *
1343 * @returns VBox status code.
1344 * @param pNode Parent node.
1345 * @param ppChild Where to store the address of the new child node. (optional)
1346 * @param pszNameFormat Name or path of the new child node.
1347 * @param Args Name format arguments.
1348 */
1349VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args)
1350{
1351 int rc;
1352 char *pszName;
1353 RTStrAPrintfV(&pszName, pszNameFormat, Args);
1354 if (pszName)
1355 {
1356 rc = CFGMR3InsertNode(pNode, pszName, ppChild);
1357 RTStrFree(pszName);
1358 }
1359 else
1360 rc = VERR_NO_MEMORY;
1361 return rc;
1362}
1363
1364
1365/**
1366 * Marks the node as the root of a restricted subtree, i.e. the end of
1367 * a CFGMR3GetParent() journey.
1368 *
1369 * @param pNode The node to mark.
1370 */
1371VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode)
1372{
1373 if (pNode)
1374 pNode->fRestrictedRoot = true;
1375}
1376
1377
1378/**
1379 * Insert a node.
1380 *
1381 * @returns VBox status code.
1382 * @param pNode Parent node.
1383 * @param pszName Name of the new child node.
1384 * @param ppLeaf Where to store the new leaf.
1385 * The caller must fill in the enmType and Value fields!
1386 */
1387static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1388{
1389 int rc;
1390 if (*pszName)
1391 {
1392 if (pNode)
1393 {
1394 /*
1395 * Check if already exists and find last node in chain.
1396 */
1397 size_t cchName = strlen(pszName);
1398 PCFGMLEAF pPrev = pNode->pFirstLeaf;
1399 if (pPrev)
1400 {
1401 for (;; pPrev = pPrev->pNext)
1402 {
1403 if ( cchName == pPrev->cchName
1404 && !memcmp(pszName, pPrev->szName, cchName))
1405 return VERR_CFGM_LEAF_EXISTS;
1406 if (!pPrev->pNext)
1407 break;
1408 }
1409 }
1410
1411 /*
1412 * Allocate and init node.
1413 */
1414 PCFGMLEAF pNew = (PCFGMLEAF)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1415 if (pNew)
1416 {
1417 pNew->cchName = cchName;
1418 memcpy(pNew->szName, pszName, cchName + 1);
1419
1420 /*
1421 * Insert into child list.
1422 */
1423 pNew->pNext = NULL;
1424 pNew->pPrev = pPrev;
1425 if (pPrev)
1426 pPrev->pNext = pNew;
1427 else
1428 pNode->pFirstLeaf = pNew;
1429 *ppLeaf = pNew;
1430 rc = VINF_SUCCESS;
1431 }
1432 else
1433 rc = VERR_NO_MEMORY;
1434 }
1435 else
1436 rc = VERR_CFGM_NO_PARENT;
1437 }
1438 else
1439 rc = VERR_CFGM_INVALID_CHILD_PATH;
1440 return rc;
1441}
1442
1443
1444/**
1445 * Remove a node.
1446 *
1447 * @param pNode Parent node.
1448 */
1449VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
1450{
1451 if (pNode)
1452 {
1453 /*
1454 * Free children.
1455 */
1456 while (pNode->pFirstChild)
1457 CFGMR3RemoveNode(pNode->pFirstChild);
1458
1459 /*
1460 * Free leafs.
1461 */
1462 while (pNode->pFirstLeaf)
1463 cfgmR3RemoveLeaf(pNode, pNode->pFirstLeaf);
1464
1465 /*
1466 * Unlink ourselves.
1467 */
1468 if (pNode->pPrev)
1469 pNode->pPrev->pNext = pNode->pNext;
1470 else
1471 {
1472 if (pNode->pParent)
1473 pNode->pParent->pFirstChild = pNode->pNext;
1474 else if (pNode == pNode->pVM->cfgm.s.pRoot) /* might be a different tree */
1475 pNode->pVM->cfgm.s.pRoot = NULL;
1476 }
1477 if (pNode->pNext)
1478 pNode->pNext->pPrev = pNode->pPrev;
1479
1480 /*
1481 * Free ourselves. (bit of paranoia first)
1482 */
1483 pNode->pVM = NULL;
1484 pNode->pNext = NULL;
1485 pNode->pPrev = NULL;
1486 pNode->pParent = NULL;
1487 MMR3HeapFree(pNode);
1488 }
1489}
1490
1491
1492/**
1493 * Removes a leaf.
1494 *
1495 * @param pNode Parent node.
1496 * @param pLeaf Leaf to remove.
1497 */
1498static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
1499{
1500 if (pNode && pLeaf)
1501 {
1502 /*
1503 * Unlink.
1504 */
1505 if (pLeaf->pPrev)
1506 pLeaf->pPrev->pNext = pLeaf->pNext;
1507 else
1508 pNode->pFirstLeaf = pLeaf->pNext;
1509 if (pLeaf->pNext)
1510 pLeaf->pNext->pPrev = pLeaf->pPrev;
1511
1512 /*
1513 * Free value and node.
1514 */
1515 cfgmR3FreeValue(pLeaf);
1516 pLeaf->pNext = NULL;
1517 pLeaf->pPrev = NULL;
1518 MMR3HeapFree(pLeaf);
1519 }
1520}
1521
1522
1523/**
1524 * Frees whatever resources the leaf value is owning.
1525 *
1526 * Use this before assigning a new value to a leaf.
1527 * The caller must either free the leaf or assign a new value to it.
1528 *
1529 * @param pLeaf Pointer to the leaf which value should be free.
1530 */
1531static void cfgmR3FreeValue(PCFGMLEAF pLeaf)
1532{
1533 if (pLeaf)
1534 {
1535 switch (pLeaf->enmType)
1536 {
1537 case CFGMVALUETYPE_BYTES:
1538 MMR3HeapFree(pLeaf->Value.Bytes.pau8);
1539 pLeaf->Value.Bytes.pau8 = NULL;
1540 pLeaf->Value.Bytes.cb = 0;
1541 break;
1542
1543 case CFGMVALUETYPE_STRING:
1544 MMR3HeapFree(pLeaf->Value.String.psz);
1545 pLeaf->Value.String.psz = NULL;
1546 pLeaf->Value.String.cch = 0;
1547 break;
1548
1549 case CFGMVALUETYPE_INTEGER:
1550 break;
1551 }
1552 pLeaf->enmType = (CFGMVALUETYPE)0;
1553 }
1554}
1555
1556
1557/**
1558 * Inserts a new integer value.
1559 *
1560 * @returns VBox status code.
1561 * @param pNode Parent node.
1562 * @param pszName Value name.
1563 * @param u64Integer The value.
1564 */
1565VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
1566{
1567 PCFGMLEAF pLeaf;
1568 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1569 if (RT_SUCCESS(rc))
1570 {
1571 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
1572 pLeaf->Value.Integer.u64 = u64Integer;
1573 }
1574 return rc;
1575}
1576
1577
1578/**
1579 * Inserts a new string value.
1580 *
1581 * @returns VBox status code.
1582 * @param pNode Parent node.
1583 * @param pszName Value name.
1584 * @param pszString The value.
1585 */
1586VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
1587{
1588 int rc;
1589 if (pNode)
1590 {
1591 /*
1592 * Allocate string object first.
1593 */
1594 size_t cchString = strlen(pszString) + 1;
1595 char *pszStringCopy = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, RT_ALIGN_Z(cchString, 16));
1596 if (pszStringCopy)
1597 {
1598 memcpy(pszStringCopy, pszString, cchString);
1599
1600 /*
1601 * Create value leaf and set it to string type.
1602 */
1603 PCFGMLEAF pLeaf;
1604 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1605 if (RT_SUCCESS(rc))
1606 {
1607 pLeaf->enmType = CFGMVALUETYPE_STRING;
1608 pLeaf->Value.String.psz = pszStringCopy;
1609 pLeaf->Value.String.cch = cchString;
1610 }
1611 }
1612 else
1613 rc = VERR_NO_MEMORY;
1614 }
1615 else
1616 rc = VERR_CFGM_NO_PARENT;
1617
1618 return rc;
1619}
1620
1621
1622
1623/**
1624 * Inserts a new integer value.
1625 *
1626 * @returns VBox status code.
1627 * @param pNode Parent node.
1628 * @param pszName Value name.
1629 * @param pvBytes The value.
1630 * @param cbBytes The value size.
1631 */
1632VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes)
1633{
1634 int rc;
1635 if (pNode)
1636 {
1637 if (cbBytes == (RTUINT)cbBytes)
1638 {
1639 /*
1640 * Allocate string object first.
1641 */
1642 void *pvCopy = MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, RT_ALIGN_Z(cbBytes, 16));
1643 if (pvCopy || !cbBytes)
1644 {
1645 memcpy(pvCopy, pvBytes, cbBytes);
1646
1647 /*
1648 * Create value leaf and set it to string type.
1649 */
1650 PCFGMLEAF pLeaf;
1651 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1652 if (RT_SUCCESS(rc))
1653 {
1654 pLeaf->enmType = CFGMVALUETYPE_BYTES;
1655 pLeaf->Value.Bytes.cb = cbBytes;
1656 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
1657 }
1658 }
1659 else
1660 rc = VERR_NO_MEMORY;
1661 }
1662 else
1663 rc = VERR_OUT_OF_RANGE;
1664 }
1665 else
1666 rc = VERR_CFGM_NO_PARENT;
1667
1668 return rc;
1669}
1670
1671
1672/**
1673 * Remove a value.
1674 *
1675 * @returns VBox status code.
1676 * @param pNode Parent node.
1677 * @param pszName Name of the new child node.
1678 */
1679VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
1680{
1681 PCFGMLEAF pLeaf;
1682 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
1683 if (RT_SUCCESS(rc))
1684 cfgmR3RemoveLeaf(pNode, pLeaf);
1685 return rc;
1686}
1687
1688
1689
1690/*
1691 * -+- helper apis -+-
1692 */
1693
1694
1695/**
1696 * Query unsigned 64-bit integer value.
1697 *
1698 * @returns VBox status code.
1699 * @param pNode Which node to search for pszName in.
1700 * @param pszName Name of an integer value.
1701 * @param pu64 Where to store the integer value.
1702 */
1703VMMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
1704{
1705 return CFGMR3QueryInteger(pNode, pszName, pu64);
1706}
1707
1708
1709/**
1710 * Query unsigned 64-bit integer value with default.
1711 *
1712 * @returns VBox status code.
1713 * @param pNode Which node to search for pszName in.
1714 * @param pszName Name of an integer value.
1715 * @param pu64 Where to store the integer value. Set to default on failure.
1716 * @param u64Def The default value.
1717 */
1718VMMR3DECL(int) CFGMR3QueryU64Def(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
1719{
1720 return CFGMR3QueryIntegerDef(pNode, pszName, pu64, u64Def);
1721}
1722
1723
1724/**
1725 * Query signed 64-bit integer value.
1726 *
1727 * @returns VBox status code.
1728 * @param pNode Which node to search for pszName in.
1729 * @param pszName Name of an integer value.
1730 * @param pi64 Where to store the value.
1731 */
1732VMMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
1733{
1734 uint64_t u64;
1735 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1736 if (RT_SUCCESS(rc))
1737 *pi64 = (int64_t)u64;
1738 return rc;
1739}
1740
1741
1742/**
1743 * Query signed 64-bit integer value with default.
1744 *
1745 * @returns VBox status code.
1746 * @param pNode Which node to search for pszName in.
1747 * @param pszName Name of an integer value.
1748 * @param pi64 Where to store the value. Set to default on failure.
1749 * @param i64Def The default value.
1750 */
1751VMMR3DECL(int) CFGMR3QueryS64Def(PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)
1752{
1753 uint64_t u64;
1754 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i64Def);
1755 if (RT_SUCCESS(rc))
1756 *pi64 = (int64_t)u64;
1757 return rc;
1758}
1759
1760
1761/**
1762 * Query unsigned 32-bit integer value.
1763 *
1764 * @returns VBox status code.
1765 * @param pNode Which node to search for pszName in.
1766 * @param pszName Name of an integer value.
1767 * @param pu32 Where to store the value.
1768 */
1769VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
1770{
1771 uint64_t u64;
1772 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1773 if (RT_SUCCESS(rc))
1774 {
1775 if (!(u64 & UINT64_C(0xffffffff00000000)))
1776 *pu32 = (uint32_t)u64;
1777 else
1778 rc = VERR_CFGM_INTEGER_TOO_BIG;
1779 }
1780 return rc;
1781}
1782
1783
1784/**
1785 * Query unsigned 32-bit integer value with default.
1786 *
1787 * @returns VBox status code.
1788 * @param pNode Which node to search for pszName in.
1789 * @param pszName Name of an integer value.
1790 * @param pu32 Where to store the value. Set to default on failure.
1791 * @param u32Def The default value.
1792 */
1793VMMR3DECL(int) CFGMR3QueryU32Def(PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)
1794{
1795 uint64_t u64;
1796 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u32Def);
1797 if (RT_SUCCESS(rc))
1798 {
1799 if (!(u64 & UINT64_C(0xffffffff00000000)))
1800 *pu32 = (uint32_t)u64;
1801 else
1802 rc = VERR_CFGM_INTEGER_TOO_BIG;
1803 }
1804 return rc;
1805}
1806
1807
1808/**
1809 * Query signed 32-bit integer value.
1810 *
1811 * @returns VBox status code.
1812 * @param pNode Which node to search for pszName in.
1813 * @param pszName Name of an integer value.
1814 * @param pi32 Where to store the value.
1815 */
1816VMMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
1817{
1818 uint64_t u64;
1819 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1820 if (RT_SUCCESS(rc))
1821 {
1822 if ( !(u64 & UINT64_C(0xffffffff80000000))
1823 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
1824 *pi32 = (int32_t)u64;
1825 else
1826 rc = VERR_CFGM_INTEGER_TOO_BIG;
1827 }
1828 return rc;
1829}
1830
1831
1832/**
1833 * Query signed 32-bit integer value with default.
1834 *
1835 * @returns VBox status code.
1836 * @param pNode Which node to search for pszName in.
1837 * @param pszName Name of an integer value.
1838 * @param pi32 Where to store the value. Set to default on failure.
1839 * @param i32Def The default value.
1840 */
1841VMMR3DECL(int) CFGMR3QueryS32Def(PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)
1842{
1843 uint64_t u64;
1844 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i32Def);
1845 if (RT_SUCCESS(rc))
1846 {
1847 if ( !(u64 & UINT64_C(0xffffffff80000000))
1848 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
1849 *pi32 = (int32_t)u64;
1850 else
1851 rc = VERR_CFGM_INTEGER_TOO_BIG;
1852 }
1853 return rc;
1854}
1855
1856
1857/**
1858 * Query unsigned 16-bit integer value.
1859 *
1860 * @returns VBox status code.
1861 * @param pNode Which node to search for pszName in.
1862 * @param pszName Name of an integer value.
1863 * @param pu16 Where to store the value.
1864 */
1865VMMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
1866{
1867 uint64_t u64;
1868 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1869 if (RT_SUCCESS(rc))
1870 {
1871 if (!(u64 & UINT64_C(0xffffffffffff0000)))
1872 *pu16 = (int16_t)u64;
1873 else
1874 rc = VERR_CFGM_INTEGER_TOO_BIG;
1875 }
1876 return rc;
1877}
1878
1879
1880/**
1881 * Query unsigned 16-bit integer value with default.
1882 *
1883 * @returns VBox status code.
1884 * @param pNode Which node to search for pszName in.
1885 * @param pszName Name of an integer value.
1886 * @param pu16 Where to store the value. Set to default on failure.
1887 * @param i16Def The default value.
1888 */
1889VMMR3DECL(int) CFGMR3QueryU16Def(PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)
1890{
1891 uint64_t u64;
1892 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u16Def);
1893 if (RT_SUCCESS(rc))
1894 {
1895 if (!(u64 & UINT64_C(0xffffffffffff0000)))
1896 *pu16 = (int16_t)u64;
1897 else
1898 rc = VERR_CFGM_INTEGER_TOO_BIG;
1899 }
1900 return rc;
1901}
1902
1903
1904/**
1905 * Query signed 16-bit integer value.
1906 *
1907 * @returns VBox status code.
1908 * @param pNode Which node to search for pszName in.
1909 * @param pszName Name of an integer value.
1910 * @param pi16 Where to store the value.
1911 */
1912VMMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
1913{
1914 uint64_t u64;
1915 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1916 if (RT_SUCCESS(rc))
1917 {
1918 if ( !(u64 & UINT64_C(0xffffffffffff8000))
1919 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
1920 *pi16 = (int16_t)u64;
1921 else
1922 rc = VERR_CFGM_INTEGER_TOO_BIG;
1923 }
1924 return rc;
1925}
1926
1927
1928/**
1929 * Query signed 16-bit integer value with default.
1930 *
1931 * @returns VBox status code.
1932 * @param pNode Which node to search for pszName in.
1933 * @param pszName Name of an integer value.
1934 * @param pi16 Where to store the value. Set to default on failure.
1935 * @param i16Def The default value.
1936 */
1937VMMR3DECL(int) CFGMR3QueryS16Def(PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)
1938{
1939 uint64_t u64;
1940 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i16Def);
1941 if (RT_SUCCESS(rc))
1942 {
1943 if ( !(u64 & UINT64_C(0xffffffffffff8000))
1944 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
1945 *pi16 = (int16_t)u64;
1946 else
1947 rc = VERR_CFGM_INTEGER_TOO_BIG;
1948 }
1949 return rc;
1950}
1951
1952
1953/**
1954 * Query unsigned 8-bit integer value.
1955 *
1956 * @returns VBox status code.
1957 * @param pNode Which node to search for pszName in.
1958 * @param pszName Name of an integer value.
1959 * @param pu8 Where to store the value.
1960 */
1961VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
1962{
1963 uint64_t u64;
1964 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1965 if (RT_SUCCESS(rc))
1966 {
1967 if (!(u64 & UINT64_C(0xffffffffffffff00)))
1968 *pu8 = (uint8_t)u64;
1969 else
1970 rc = VERR_CFGM_INTEGER_TOO_BIG;
1971 }
1972 return rc;
1973}
1974
1975
1976/**
1977 * Query unsigned 8-bit integer value with default.
1978 *
1979 * @returns VBox status code.
1980 * @param pNode Which node to search for pszName in.
1981 * @param pszName Name of an integer value.
1982 * @param pu8 Where to store the value. Set to default on failure.
1983 * @param u8Def The default value.
1984 */
1985VMMR3DECL(int) CFGMR3QueryU8Def(PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)
1986{
1987 uint64_t u64;
1988 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u8Def);
1989 if (RT_SUCCESS(rc))
1990 {
1991 if (!(u64 & UINT64_C(0xffffffffffffff00)))
1992 *pu8 = (uint8_t)u64;
1993 else
1994 rc = VERR_CFGM_INTEGER_TOO_BIG;
1995 }
1996 return rc;
1997}
1998
1999
2000/**
2001 * Query signed 8-bit integer value.
2002 *
2003 * @returns VBox status code.
2004 * @param pNode Which node to search for pszName in.
2005 * @param pszName Name of an integer value.
2006 * @param pi8 Where to store the value.
2007 */
2008VMMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
2009{
2010 uint64_t u64;
2011 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2012 if (RT_SUCCESS(rc))
2013 {
2014 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2015 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2016 *pi8 = (int8_t)u64;
2017 else
2018 rc = VERR_CFGM_INTEGER_TOO_BIG;
2019 }
2020 return rc;
2021}
2022
2023
2024/**
2025 * Query signed 8-bit integer value with default.
2026 *
2027 * @returns VBox status code.
2028 * @param pNode Which node to search for pszName in.
2029 * @param pszName Name of an integer value.
2030 * @param pi8 Where to store the value. Set to default on failure.
2031 * @param i8Def The default value.
2032 */
2033VMMR3DECL(int) CFGMR3QueryS8Def(PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)
2034{
2035 uint64_t u64;
2036 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i8Def);
2037 if (RT_SUCCESS(rc))
2038 {
2039 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2040 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2041 *pi8 = (int8_t)u64;
2042 else
2043 rc = VERR_CFGM_INTEGER_TOO_BIG;
2044 }
2045 return rc;
2046}
2047
2048
2049/**
2050 * Query boolean integer value.
2051 *
2052 * @returns VBox status code.
2053 * @param pNode Which node to search for pszName in.
2054 * @param pszName Name of an integer value.
2055 * @param pf Where to store the value.
2056 * @remark This function will interpret any non-zero value as true.
2057 */
2058VMMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
2059{
2060 uint64_t u64;
2061 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2062 if (RT_SUCCESS(rc))
2063 *pf = u64 ? true : false;
2064 return rc;
2065}
2066
2067
2068/**
2069 * Query boolean integer value with default.
2070 *
2071 * @returns VBox status code.
2072 * @param pNode Which node to search for pszName in.
2073 * @param pszName Name of an integer value.
2074 * @param pf Where to store the value. Set to default on failure.
2075 * @param fDef The default value.
2076 * @remark This function will interpret any non-zero value as true.
2077 */
2078VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
2079{
2080 uint64_t u64;
2081 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, fDef);
2082 if (RT_SUCCESS(rc))
2083 *pf = u64 ? true : false;
2084 return rc;
2085}
2086
2087
2088/**
2089 * Query I/O port address value.
2090 *
2091 * @returns VBox status code.
2092 * @param pNode Which node to search for pszName in.
2093 * @param pszName Name of an integer value.
2094 * @param pPort Where to store the value.
2095 */
2096VMMR3DECL(int) CFGMR3QueryPort(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)
2097{
2098 AssertCompileSize(RTIOPORT, 2);
2099 return CFGMR3QueryU16(pNode, pszName, pPort);
2100}
2101
2102
2103/**
2104 * Query I/O port address value with default.
2105 *
2106 * @returns VBox status code.
2107 * @param pNode Which node to search for pszName in.
2108 * @param pszName Name of an integer value.
2109 * @param pPort Where to store the value. Set to default on failure.
2110 * @param PortDef The default value.
2111 */
2112VMMR3DECL(int) CFGMR3QueryPortDef(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)
2113{
2114 AssertCompileSize(RTIOPORT, 2);
2115 return CFGMR3QueryU16Def(pNode, pszName, pPort, PortDef);
2116}
2117
2118
2119/**
2120 * Query unsigned int address value.
2121 *
2122 * @returns VBox status code.
2123 * @param pNode Which node to search for pszName in.
2124 * @param pszName Name of an integer value.
2125 * @param pu Where to store the value.
2126 */
2127VMMR3DECL(int) CFGMR3QueryUInt(PCFGMNODE pNode, const char *pszName, unsigned int *pu)
2128{
2129 AssertCompileSize(unsigned int, 4);
2130 return CFGMR3QueryU32(pNode, pszName, (uint32_t *)pu);
2131}
2132
2133
2134/**
2135 * Query unsigned int address value with default.
2136 *
2137 * @returns VBox status code.
2138 * @param pNode Which node to search for pszName in.
2139 * @param pszName Name of an integer value.
2140 * @param pu Where to store the value. Set to default on failure.
2141 * @param uDef The default value.
2142 */
2143VMMR3DECL(int) CFGMR3QueryUIntDef(PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)
2144{
2145 AssertCompileSize(unsigned int, 4);
2146 return CFGMR3QueryU32Def(pNode, pszName, (uint32_t *)pu, uDef);
2147}
2148
2149
2150/**
2151 * Query signed int address value.
2152 *
2153 * @returns VBox status code.
2154 * @param pNode Which node to search for pszName in.
2155 * @param pszName Name of an integer value.
2156 * @param pi Where to store the value.
2157 */
2158VMMR3DECL(int) CFGMR3QuerySInt(PCFGMNODE pNode, const char *pszName, signed int *pi)
2159{
2160 AssertCompileSize(signed int, 4);
2161 return CFGMR3QueryS32(pNode, pszName, (int32_t *)pi);
2162}
2163
2164
2165/**
2166 * Query unsigned int address value with default.
2167 *
2168 * @returns VBox status code.
2169 * @param pNode Which node to search for pszName in.
2170 * @param pszName Name of an integer value.
2171 * @param pi Where to store the value. Set to default on failure.
2172 * @param iDef The default value.
2173 */
2174VMMR3DECL(int) CFGMR3QuerySIntDef(PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)
2175{
2176 AssertCompileSize(signed int, 4);
2177 return CFGMR3QueryS32Def(pNode, pszName, (int32_t *)pi, iDef);
2178}
2179
2180
2181/**
2182 * Query pointer integer value.
2183 *
2184 * @returns VBox status code.
2185 * @param pNode Which node to search for pszName in.
2186 * @param pszName Name of an integer value.
2187 * @param ppv Where to store the value.
2188 */
2189VMMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
2190{
2191 uint64_t u64;
2192 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2193 if (RT_SUCCESS(rc))
2194 {
2195 uintptr_t u = (uintptr_t)u64;
2196 if (u64 == u)
2197 *ppv = (void *)u;
2198 else
2199 rc = VERR_CFGM_INTEGER_TOO_BIG;
2200 }
2201 return rc;
2202}
2203
2204
2205/**
2206 * Query pointer integer value with default.
2207 *
2208 * @returns VBox status code.
2209 * @param pNode Which node to search for pszName in.
2210 * @param pszName Name of an integer value.
2211 * @param ppv Where to store the value. Set to default on failure.
2212 * @param pvDef The default value.
2213 */
2214VMMR3DECL(int) CFGMR3QueryPtrDef(PCFGMNODE pNode, const char *pszName, void **ppv, void *pvDef)
2215{
2216 uint64_t u64;
2217 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, (uintptr_t)pvDef);
2218 if (RT_SUCCESS(rc))
2219 {
2220 uintptr_t u = (uintptr_t)u64;
2221 if (u64 == u)
2222 *ppv = (void *)u;
2223 else
2224 rc = VERR_CFGM_INTEGER_TOO_BIG;
2225 }
2226 return rc;
2227}
2228
2229
2230/**
2231 * Query Guest Context pointer integer value.
2232 *
2233 * @returns VBox status code.
2234 * @param pNode Which node to search for pszName in.
2235 * @param pszName Name of an integer value.
2236 * @param pGCPtr Where to store the value.
2237 */
2238VMMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
2239{
2240 uint64_t u64;
2241 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2242 if (RT_SUCCESS(rc))
2243 {
2244 RTGCPTR u = (RTGCPTR)u64;
2245 if (u64 == u)
2246 *pGCPtr = u;
2247 else
2248 rc = VERR_CFGM_INTEGER_TOO_BIG;
2249 }
2250 return rc;
2251}
2252
2253
2254/**
2255 * Query Guest Context pointer integer value with default.
2256 *
2257 * @returns VBox status code.
2258 * @param pNode Which node to search for pszName in.
2259 * @param pszName Name of an integer value.
2260 * @param pGCPtr Where to store the value. Set to default on failure.
2261 * @param GCPtrDef The default value.
2262 */
2263VMMR3DECL(int) CFGMR3QueryGCPtrDef(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)
2264{
2265 uint64_t u64;
2266 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2267 if (RT_SUCCESS(rc))
2268 {
2269 RTGCPTR u = (RTGCPTR)u64;
2270 if (u64 == u)
2271 *pGCPtr = u;
2272 else
2273 rc = VERR_CFGM_INTEGER_TOO_BIG;
2274 }
2275 return rc;
2276}
2277
2278
2279/**
2280 * Query Guest Context unsigned pointer value.
2281 *
2282 * @returns VBox status code.
2283 * @param pNode Which node to search for pszName in.
2284 * @param pszName Name of an integer value.
2285 * @param pGCPtr Where to store the value.
2286 */
2287VMMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
2288{
2289 uint64_t u64;
2290 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2291 if (RT_SUCCESS(rc))
2292 {
2293 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2294 if (u64 == u)
2295 *pGCPtr = u;
2296 else
2297 rc = VERR_CFGM_INTEGER_TOO_BIG;
2298 }
2299 return rc;
2300}
2301
2302
2303/**
2304 * Query Guest Context unsigned pointer value with default.
2305 *
2306 * @returns VBox status code.
2307 * @param pNode Which node to search for pszName in.
2308 * @param pszName Name of an integer value.
2309 * @param pGCPtr Where to store the value. Set to default on failure.
2310 * @param GCPtrDef The default value.
2311 */
2312VMMR3DECL(int) CFGMR3QueryGCPtrUDef(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)
2313{
2314 uint64_t u64;
2315 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2316 if (RT_SUCCESS(rc))
2317 {
2318 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2319 if (u64 == u)
2320 *pGCPtr = u;
2321 else
2322 rc = VERR_CFGM_INTEGER_TOO_BIG;
2323 }
2324 return rc;
2325}
2326
2327
2328/**
2329 * Query Guest Context signed pointer value.
2330 *
2331 * @returns VBox status code.
2332 * @param pNode Which node to search for pszName in.
2333 * @param pszName Name of an integer value.
2334 * @param pGCPtr Where to store the value.
2335 */
2336VMMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
2337{
2338 uint64_t u64;
2339 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2340 if (RT_SUCCESS(rc))
2341 {
2342 RTGCINTPTR u = (RTGCINTPTR)u64;
2343 if (u64 == (uint64_t)u)
2344 *pGCPtr = u;
2345 else
2346 rc = VERR_CFGM_INTEGER_TOO_BIG;
2347 }
2348 return rc;
2349}
2350
2351
2352/**
2353 * Query Guest Context signed pointer value with default.
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 pGCPtr Where to store the value. Set to default on failure.
2359 * @param GCPtrDef The default value.
2360 */
2361VMMR3DECL(int) CFGMR3QueryGCPtrSDef(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)
2362{
2363 uint64_t u64;
2364 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2365 if (RT_SUCCESS(rc))
2366 {
2367 RTGCINTPTR u = (RTGCINTPTR)u64;
2368 if (u64 == (uint64_t)u)
2369 *pGCPtr = u;
2370 else
2371 rc = VERR_CFGM_INTEGER_TOO_BIG;
2372 }
2373 return rc;
2374}
2375
2376
2377/**
2378 * Query zero terminated character value storing it in a
2379 * buffer allocated from the MM heap.
2380 *
2381 * @returns VBox status code.
2382 * @param pNode Which node to search for pszName in.
2383 * @param pszName Value name. This value must be of zero terminated character string type.
2384 * @param ppszString Where to store the string pointer.
2385 * Free this using MMR3HeapFree().
2386 */
2387VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
2388{
2389 size_t cch;
2390 int rc = CFGMR3QuerySize(pNode, pszName, &cch);
2391 if (RT_SUCCESS(rc))
2392 {
2393 char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cch);
2394 if (pszString)
2395 {
2396 rc = CFGMR3QueryString(pNode, pszName, pszString, cch);
2397 if (RT_SUCCESS(rc))
2398 *ppszString = pszString;
2399 else
2400 MMR3HeapFree(pszString);
2401 }
2402 else
2403 rc = VERR_NO_MEMORY;
2404 }
2405 return rc;
2406}
2407
2408
2409/**
2410 * Query zero terminated character value storing it in a
2411 * buffer allocated from the MM heap.
2412 *
2413 * @returns VBox status code.
2414 * @param pNode Which node to search for pszName in.
2415 * @param pszName Value name. This value must be of zero terminated character string type.
2416 * @param ppszString Where to store the string pointer. Not set on failure.
2417 * Free this using MMR3HeapFree().
2418 */
2419VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
2420{
2421 size_t cch;
2422 int rc = CFGMR3QuerySize(pNode, pszName, &cch);
2423 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
2424 {
2425 cch = strlen(pszDef) + 1;
2426 rc = VINF_SUCCESS;
2427 }
2428 if (RT_SUCCESS(rc))
2429 {
2430 char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cch);
2431 if (pszString)
2432 {
2433 rc = CFGMR3QueryStringDef(pNode, pszName, pszString, cch, pszDef);
2434 if (RT_SUCCESS(rc))
2435 *ppszString = pszString;
2436 else
2437 MMR3HeapFree(pszString);
2438 }
2439 else
2440 rc = VERR_NO_MEMORY;
2441 }
2442 return rc;
2443}
2444
2445
2446/**
2447 * Dumps the configuration (sub)tree to the release log.
2448 *
2449 * @param pRoot The root node of the dump.
2450 */
2451VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
2452{
2453 LogRel(("************************* CFGM dump *************************\n"));
2454 cfgmR3Info(pRoot->pVM, DBGFR3InfoLogRelHlp(), NULL);
2455 LogRel(("********************* End of CFGM dump **********************\n"));
2456}
2457
2458
2459/**
2460 * Info handler, internal version.
2461 *
2462 * @param pVM The VM handle.
2463 * @param pHlp Callback functions for doing output.
2464 * @param pszArgs Argument string. Optional and specific to the handler.
2465 */
2466static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
2467{
2468 /*
2469 * Figure where to start.
2470 */
2471 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
2472 if (pszArgs && *pszArgs)
2473 {
2474 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
2475 if (RT_FAILURE(rc))
2476 {
2477 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Rrc", pszArgs, rc);
2478 return;
2479 }
2480 }
2481
2482 /*
2483 * Dump the specified tree.
2484 */
2485 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
2486 cfgmR3DumpPath(pRoot, pHlp);
2487 pHlp->pfnPrintf(pHlp, "}\n");
2488 cfgmR3Dump(pRoot, 0, pHlp);
2489}
2490
2491
2492/**
2493 * Recursivly prints a path name.
2494 */
2495static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
2496{
2497 if (pNode->pParent)
2498 cfgmR3DumpPath(pNode->pParent, pHlp);
2499 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
2500}
2501
2502
2503/**
2504 * Dumps a branch of a tree.
2505 */
2506static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
2507{
2508 /*
2509 * Path.
2510 */
2511 pHlp->pfnPrintf(pHlp, "[");
2512 cfgmR3DumpPath(pRoot, pHlp);
2513 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
2514
2515 /*
2516 * Values.
2517 */
2518 PCFGMLEAF pLeaf;
2519 size_t cchMax = 0;
2520 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
2521 cchMax = RT_MAX(cchMax, pLeaf->cchName);
2522 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
2523 {
2524 switch (CFGMR3GetValueType(pLeaf))
2525 {
2526 case CFGMVALUETYPE_INTEGER:
2527 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%lld)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
2528 break;
2529
2530 case CFGMVALUETYPE_STRING:
2531 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cch=%d)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cch);
2532 break;
2533
2534 case CFGMVALUETYPE_BYTES:
2535 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);
2536 break;
2537
2538 default:
2539 AssertMsgFailed(("bad leaf!\n"));
2540 break;
2541 }
2542 }
2543 pHlp->pfnPrintf(pHlp, "\n");
2544
2545 /*
2546 * Children.
2547 */
2548 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
2549 {
2550 Assert(pChild->pNext != pChild);
2551 Assert(pChild->pPrev != pChild);
2552 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
2553 Assert(pChild->pFirstChild != pChild);
2554 Assert(pChild->pParent != pChild);
2555 cfgmR3Dump(pChild, iLevel + 1, pHlp);
2556 }
2557}
2558
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