VirtualBox

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

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

Made the CFGMR3*Def() integer apis always return something, even on failure.

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