VirtualBox

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

最後變更 在這個檔案從23586是 23586,由 vboxsync 提交於 15 年 前

CFGM: Sort the key and value name so that ordering is predictable. (device creation order.)

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

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