VirtualBox

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

Last change on this file since 2919 was 1009, checked in by vboxsync, 18 years ago

Fixed bug in CFGM node insertion when several intermediate nodes were
not yet existing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 54.4 KB
Line 
1/* $Id: CFGM.cpp 1009 2007-02-21 11:11:58Z vboxsync $ */
2/** @file
3 * CFGM - Configuration Manager.
4 *
5 * This is the main file of the \ref pg_cfgm "CFGM (Configuration Manager)".
6 */
7
8/*
9 * Copyright (C) 2006 InnoTek Systemberatung GmbH
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License as published by the Free Software Foundation,
15 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16 * distribution. VirtualBox OSE is distributed in the hope that it will
17 * be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * If you received this file as part of a commercial VirtualBox
20 * distribution, then only the terms of your commercial VirtualBox
21 * license agreement apply instead of the previous paragraph.
22 */
23
24/** @page pg_cfgm CFGM - The Configuration Manager
25 *
26 * The configuration manager will load and keep the configuration of a VM
27 * handy (thru query interface) while the VM is running. The VM properties
28 * are organized in a tree and individual nodes can be accessed by normal
29 * path walking.
30 *
31 * Exactly how the CFGM obtains the configuration is specific to the build.
32 * The default for a full build is to query it thru the IMachine interface and
33 * applies it onto a default setup. It's necessary to have a default in the
34 * bottom of this because the IMachine interface doesn't provide all the
35 * required details.
36 *
37 * Devices are given their own subtree where they are protected from accessing
38 * information of any parents. The exported PDM callback interfaces makes sure
39 * of this.
40 *
41 * Validating of the data obtained, except for validation of the primitive type,
42 * is all up to the user. The CFGM user is concidered in a better position to
43 * know the validation rules of the individual properties.
44 *
45 *
46 * @section sec_cfgm_primitives Data Primitives
47 *
48 * CFGM supports the following data primitives:
49 * - Integers. Representation is signed 64-bit. Boolean, unsigned and
50 * small integers are all represented using this primitive.
51 * - Zero terminated character strings. As everywhere else
52 * strings are UTF-8.
53 * - Variable length byte strings. This can be used to get/put binary
54 * objects.
55 *
56 */
57
58
59/*******************************************************************************
60* Header Files *
61*******************************************************************************/
62#define LOG_GROUP LOG_GROUP_CFGM
63#include <VBox/cfgm.h>
64#include <VBox/dbgf.h>
65#include <VBox/mm.h>
66#include "CFGMInternal.h"
67#include <VBox/vm.h>
68#include <VBox/err.h>
69
70#include <VBox/log.h>
71#include <iprt/assert.h>
72#include <iprt/string.h>
73
74
75/*******************************************************************************
76* Internal Functions *
77*******************************************************************************/
78static int cfgmR3CreateDefault(PVM pVM);
79static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp);
80static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp);
81static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
82static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild);
83static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
84static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
85static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf);
86static void cfgmR3FreeValue(PCFGMLEAF pLeaf);
87
88
89
90/**
91 * Constructs the configuration for the VM.
92 *
93 * @returns VBox status code.
94 * @param pVM Pointer to VM which configuration has not yet been loaded.
95 * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
96 * This is called in the EM.
97 * @param pvUser The user argument passed to pfnCFGMConstructor.
98 */
99CFGMR3DECL(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.offVM = RT_OFFSETOF(VM, cfgm);
107 pVM->cfgm.s.pRoot = NULL;
108
109 /*
110 * Register DBGF into item.
111 */
112 int rc = DBGFR3InfoRegisterInternal(pVM, "cfgm", "Dumps a part of the CFGM tree. The argument indicates where to start.", cfgmR3Info);
113 AssertRCReturn(rc,rc);
114
115 /*
116 * Create the configuration tree.
117 */
118 if (pfnCFGMConstructor)
119 {
120 /*
121 * Root Node.
122 */
123 PCFGMNODE pRoot = (PCFGMNODE)MMR3HeapAllocZ(pVM, MM_TAG_CFGM, sizeof(*pRoot));
124 if (!pRoot)
125 return VERR_NO_MEMORY;
126 pRoot->pVM = pVM;
127 pRoot->cchName = 0;
128 pVM->cfgm.s.pRoot = pRoot;
129
130 /*
131 * Call the constructor.
132 */
133 rc = pfnCFGMConstructor(pVM, pvUser);
134 }
135 else
136 rc = cfgmR3CreateDefault(pVM);
137 if (VBOX_SUCCESS(rc))
138 {
139 Log(("CFGMR3Init: Successfully constructed the configuration\n"));
140 CFGMR3Dump(CFGMR3GetRoot(pVM));
141
142 }
143 else
144 AssertMsgFailed(("Constructor failed with rc=%Vrc pfnCFGMConstructor=%p\n", rc, pfnCFGMConstructor));
145
146 return rc;
147}
148
149
150/**
151 * Terminates the configuration manager.
152 *
153 * @returns VBox status code.
154 * @param pVM VM handle.
155 */
156CFGMR3DECL(int) CFGMR3Term(PVM pVM)
157{
158 CFGMR3RemoveNode(pVM->cfgm.s.pRoot);
159 return 0;
160}
161
162
163/**
164 * Gets the root node for the VM.
165 *
166 * @returns Pointer to root node.
167 * @param pVM VM handle.
168 */
169CFGMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM)
170{
171 return pVM->cfgm.s.pRoot;
172}
173
174
175/**
176 * Gets the parent of a CFGM node.
177 *
178 * @returns Pointer to the parent node.
179 * @returns NULL if pNode is Root or pNode is the start of a
180 * restricted subtree (use CFGMr3GetParentEx() for that).
181 *
182 * @param pNode The node which parent we query.
183 */
184CFGMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode)
185{
186 if (pNode && !pNode->fRestrictedRoot)
187 return pNode->pParent;
188 return NULL;
189}
190
191
192/**
193 * Gets the parent of a CFGM node.
194 *
195 * @returns Pointer to the parent node.
196 * @returns NULL if pNode is Root or pVM is not correct.
197 *
198 * @param pVM The VM handle, used as token that the caller is trusted.
199 * @param pNode The node which parent we query.
200 */
201CFGMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode)
202{
203 if (pNode && pNode->pVM == pVM)
204 return pNode->pParent;
205 return NULL;
206}
207
208
209/**
210 * Query a child node.
211 *
212 * @returns Pointer to the specified node.
213 * @returns NULL if node was not found or pNode is NULL.
214 * @param pNode Node pszPath is relative to.
215 * @param pszPath Path to the child node or pNode.
216 * It's good style to end this with '/'.
217 */
218CFGMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath)
219{
220 PCFGMNODE pChild;
221 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
222 if (VBOX_SUCCESS(rc))
223 return pChild;
224 return NULL;
225}
226
227
228/**
229 * Query a child node by a format string.
230 *
231 * @returns Pointer to the specified node.
232 * @returns NULL if node was not found or pNode is NULL.
233 * @param pNode Node pszPath is relative to.
234 * @param pszPathFormat Path to the child node or pNode.
235 * It's good style to end this with '/'.
236 * @param ... Arguments to pszPathFormat.
237 */
238CFGMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...)
239{
240 va_list Args;
241 va_start(Args, pszPathFormat);
242 PCFGMNODE pRet = CFGMR3GetChildFV(pNode, pszPathFormat, Args);
243 va_end(Args);
244 return pRet;
245}
246
247
248/**
249 * Query a child node by a format string.
250 *
251 * @returns Pointer to the specified node.
252 * @returns NULL if node was not found or pNode is NULL.
253 * @param pNode Node pszPath is relative to.
254 * @param pszPathFormat Path to the child node or pNode.
255 * It's good style to end this with '/'.
256 * @param Args Arguments to pszPathFormat.
257 */
258CFGMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args)
259{
260 char *pszPath;
261 RTStrAPrintfV(&pszPath, pszPathFormat, Args);
262 if (pszPath)
263 {
264 PCFGMNODE pChild;
265 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
266 if (VBOX_SUCCESS(rc))
267 return pChild;
268 RTStrFree(pszPath);
269 }
270 return NULL;
271}
272
273
274/**
275 * Gets the first child node.
276 * Use this to start an enumeration of child nodes.
277 *
278 * @returns Pointer to the first child.
279 * @returns NULL if no children.
280 * @param pNode Node to enumerate children for.
281 */
282CFGMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode)
283{
284 return pNode ? pNode->pFirstChild : NULL;
285}
286
287
288/**
289 * Gets the next sibling node.
290 * Use this to continue an enumeration.
291 *
292 * @returns Pointer to the first child.
293 * @returns NULL if no children.
294 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
295 * or successive calls to this function.
296 */
297CFGMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur)
298{
299 return pCur ? pCur->pNext : NULL;
300}
301
302
303/**
304 * Gets the name of the current node.
305 * (Needed for enumeration.)
306 *
307 * @returns VBox status code.
308 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
309 * or successive calls to CFGMR3GetNextChild().
310 * @param pszName Where to store the node name.
311 * @param cchName Size of the buffer pointed to by pszName (with terminator).
312 */
313CFGMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName)
314{
315 int rc;
316 if (pCur)
317 {
318 if (cchName > pCur->cchName)
319 {
320 rc = VINF_SUCCESS;
321 memcpy(pszName, pCur->szName, pCur->cchName + 1);
322 }
323 else
324 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
325 }
326 else
327 rc = VERR_CFGM_NO_NODE;
328 return rc;
329}
330
331
332/**
333 * Gets the length of the current node's name.
334 * (Needed for enumeration.)
335 *
336 * @returns Node name length in bytes including the terminating null char.
337 * @returns 0 if pCur is NULL.
338 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
339 * or successive calls to CFGMR3GetNextChild().
340 */
341CFGMR3DECL(int) CFGMR3GetNameLen(PCFGMNODE pCur)
342{
343 return pCur ? pCur->cchName + 1 : 0;
344}
345
346
347/**
348 * Validates that the child nodes are within a set of valid names.
349 *
350 * @returns true if all names are found in pszzAllowed.
351 * @returns false if not.
352 * @param pNode The node which children should be examined.
353 * @param pszzValid List of valid names separated by '\\0' and ending with
354 * a double '\\0'.
355 */
356CFGMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid)
357{
358 if (pNode)
359 {
360 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
361 {
362 /* search pszzValid for the name */
363 const char *psz = pszzValid;
364 while (*psz)
365 {
366 size_t cch = strlen(psz);
367 if ( cch == pChild->cchName
368 && !memcmp(psz, pChild->szName, cch))
369 break;
370
371 /* next */
372 psz += cch + 1;
373 }
374
375 /* if at end of pszzValid we didn't find it => failure */
376 if (!*psz)
377 {
378 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pChild->szName));
379 return false;
380 }
381 }
382 }
383
384 /* all ok. */
385 return true;
386}
387
388
389/**
390 * Gets the first value of a node.
391 * Use this to start an enumeration of values.
392 *
393 * @returns Pointer to the first value.
394 * @param pCur The node (Key) which values to enumerate.
395 */
396CFGMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur)
397{
398 return pCur ? pCur->pFirstLeaf : NULL;
399}
400
401/**
402 * Gets the next value in enumeration.
403 *
404 * @returns Pointer to the next value.
405 * @param pCur The current value as returned by this function or CFGMR3GetFirstValue().
406 */
407CFGMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur)
408{
409 return pCur ? pCur->pNext : NULL;
410}
411
412/**
413 * Get the value name.
414 * (Needed for enumeration.)
415 *
416 * @returns VBox status code.
417 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
418 * or successive calls to CFGMR3GetNextValue().
419 * @param pszName Where to store the value name.
420 * @param cchName Size of the buffer pointed to by pszName (with terminator).
421 */
422CFGMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName)
423{
424 int rc;
425 if (pCur)
426 {
427 if (cchName > pCur->cchName)
428 {
429 rc = VINF_SUCCESS;
430 memcpy(pszName, pCur->szName, pCur->cchName + 1);
431 }
432 else
433 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
434 }
435 else
436 rc = VERR_CFGM_NO_NODE;
437 return rc;
438}
439
440
441/**
442 * Gets the length of the current node's name.
443 * (Needed for enumeration.)
444 *
445 * @returns Value name length in bytes including the terminating null char.
446 * @returns 0 if pCur is NULL.
447 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
448 * or successive calls to CFGMR3GetNextValue().
449 */
450CFGMR3DECL(int) CFGMR3GetValueNameLen(PCFGMLEAF pCur)
451{
452 return pCur ? pCur->cchName + 1 : 0;
453}
454
455/**
456 * Gets the value type.
457 * (For enumeration.)
458 *
459 * @returns VBox status code.
460 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
461 * or successive calls to CFGMR3GetNextValue().
462 */
463CFGMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur)
464{
465 Assert(pCur);
466 return pCur->enmType;
467}
468
469
470/**
471 * Validates that the values are within a set of valid names.
472 *
473 * @returns true if all names are found in pszzAllowed.
474 * @returns false if not.
475 * @param pNode The node which values should be examined.
476 * @param pszzValid List of valid names separated by '\\0' and ending with
477 * a double '\\0'.
478 */
479CFGMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid)
480{
481 if (pNode)
482 {
483 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
484 {
485 /* search pszzValid for the name */
486 const char *psz = pszzValid;
487 while (*psz)
488 {
489 size_t cch = strlen(psz);
490 if ( cch == pLeaf->cchName
491 && !memcmp(psz, pLeaf->szName, cch))
492 break;
493
494 /* next */
495 psz += cch + 1;
496 }
497
498 /* if at end of pszzValid we didn't find it => failure */
499 if (!*psz)
500 {
501 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pLeaf->szName));
502 return false;
503 }
504 }
505 }
506
507 /* all ok. */
508 return true;
509}
510
511
512
513/**
514 * Query value type.
515 *
516 * @returns VBox status code.
517 * @param pNode Which node to search for pszName in.
518 * @param pszName Name of an integer value.
519 * @param penmType Where to store the type.
520 */
521CFGMR3DECL(int) CFGMR3QueryType(PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)
522{
523 PCFGMLEAF pLeaf;
524 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
525 if (VBOX_SUCCESS(rc))
526 {
527 if (penmType)
528 *penmType = pLeaf->enmType;
529 }
530 return rc;
531}
532
533
534/**
535 * Query value size.
536 * This works on all types of values.
537 *
538 * @returns VBox status code.
539 * @param pNode Which node to search for pszName in.
540 * @param pszName Name of an integer value.
541 * @param pcb Where to store the value size.
542 */
543CFGMR3DECL(int) CFGMR3QuerySize(PCFGMNODE pNode, const char *pszName, size_t *pcb)
544{
545 PCFGMLEAF pLeaf;
546 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
547 if (VBOX_SUCCESS(rc))
548 {
549 switch (pLeaf->enmType)
550 {
551 case CFGMVALUETYPE_INTEGER:
552 *pcb = sizeof(pLeaf->Value.Integer.u64);
553 break;
554
555 case CFGMVALUETYPE_STRING:
556 *pcb = pLeaf->Value.String.cch;
557 break;
558
559 case CFGMVALUETYPE_BYTES:
560 *pcb = pLeaf->Value.Bytes.cb;
561 break;
562
563 default:
564 rc = VERR_INTERNAL_ERROR;
565 AssertMsgFailed(("Invalid value type %d\n", pLeaf->enmType));
566 break;
567 }
568 }
569 return rc;
570}
571
572
573/**
574 * Query integer value.
575 *
576 * @returns VBox status code.
577 * @param pNode Which node to search for pszName in.
578 * @param pszName Name of an integer value.
579 * @param pu64 Where to store the integer value.
580 */
581CFGMR3DECL(int) CFGMR3QueryInteger(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
582{
583 PCFGMLEAF pLeaf;
584 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
585 if (VBOX_SUCCESS(rc))
586 {
587 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
588 *pu64 = pLeaf->Value.Integer.u64;
589 else
590 rc = VERR_CFGM_NOT_INTEGER;
591 }
592 return rc;
593}
594
595
596/**
597 * Query zero terminated character value.
598 *
599 * @returns VBox status code.
600 * @param pNode Which node to search for pszName in.
601 * @param pszName Name of a zero terminate character value.
602 * @param pszString Where to store the string.
603 * @param cchString Size of the string buffer. (Includes terminator.)
604 */
605CFGMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
606{
607 PCFGMLEAF pLeaf;
608 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
609 if (VBOX_SUCCESS(rc))
610 {
611 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
612 {
613 if (cchString >= pLeaf->Value.String.cch)
614 {
615 memcpy(pszString, pLeaf->Value.String.psz, pLeaf->Value.String.cch);
616 memset(pszString + pLeaf->Value.String.cch, 0, cchString - pLeaf->Value.String.cch);
617 }
618 else
619 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
620 }
621 else
622 rc = VERR_CFGM_NOT_STRING;
623 }
624 return rc;
625}
626
627
628/**
629 * Query byte string value.
630 *
631 * @returns VBox status code.
632 * @param pNode Which node to search for pszName in.
633 * @param pszName Name of a byte string value.
634 * @param pvData Where to store the binary data.
635 * @param cbData Size of buffer pvData points too.
636 */
637CFGMR3DECL(int) CFGMR3QueryBytes(PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)
638{
639 PCFGMLEAF pLeaf;
640 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
641 if (VBOX_SUCCESS(rc))
642 {
643 if (pLeaf->enmType == CFGMVALUETYPE_BYTES)
644 {
645 if (cbData >= pLeaf->Value.Bytes.cb)
646 {
647 memcpy(pvData, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
648 memset((char *)pvData + pLeaf->Value.Bytes.cb, 0, cbData - pLeaf->Value.Bytes.cb);
649 }
650 else
651 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
652 }
653 else
654 rc = VERR_CFGM_NOT_BYTES;
655 }
656 return rc;
657}
658
659
660
661/*
662 * -+- internal apis -+-
663 */
664
665
666/**
667 * Creates the default configuration.
668 * This assumes an empty tree.
669 *
670 * @returns VBox status code.
671 * @param pVM VM handle.
672 */
673static int cfgmR3CreateDefault(PVM pVM)
674{
675 int rc;
676 int rcAll = VINF_SUCCESS;
677#define UPDATERC() do { if (VBOX_FAILURE(rc) && VBOX_SUCCESS(rcAll)) rcAll = rc; } while (0)
678
679 /*
680 * Root level.
681 */
682 PCFGMNODE pRoot = (PCFGMNODE)MMR3HeapAllocZ(pVM, MM_TAG_CFGM, sizeof(*pRoot));
683 if (!pRoot)
684 return VERR_NO_MEMORY;
685 pRoot->pVM = pVM;
686 pRoot->cchName = 0;
687
688 Assert(!pVM->cfgm.s.pRoot);
689 pVM->cfgm.s.pRoot = pRoot;
690
691 /*
692 * Create VM default values.
693 */
694 rc = CFGMR3InsertString(pRoot, "Name", "Default VM");
695 UPDATERC();
696 rc = CFGMR3InsertInteger(pRoot, "RamSize", 128 * _1M);
697 UPDATERC();
698 rc = CFGMR3InsertInteger(pRoot, "TimerMillies", 10);
699 UPDATERC();
700 rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled", 1);
701 UPDATERC();
702 /** @todo CFGM Defaults: RawR0, PATMEnabled and CASMEnabled needs attention later. */
703 rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled", 1);
704 UPDATERC();
705 rc = CFGMR3InsertInteger(pRoot, "PATMEnabled", 1);
706 UPDATERC();
707 rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled", 1);
708 UPDATERC();
709
710 /*
711 * PDM.
712 */
713 PCFGMNODE pPdm;
714 rc = CFGMR3InsertNode(pRoot, "PDM", &pPdm);
715 UPDATERC();
716 PCFGMNODE pDevices = NULL;
717 rc = CFGMR3InsertNode(pPdm, "Devices", &pDevices);
718 UPDATERC();
719 rc = CFGMR3InsertInteger(pDevices, "LoadBuiltin", 1); /* boolean */
720 UPDATERC();
721 PCFGMNODE pDrivers = NULL;
722 rc = CFGMR3InsertNode(pPdm, "Drivers", &pDrivers);
723 UPDATERC();
724 rc = CFGMR3InsertInteger(pDrivers, "LoadBuiltin", 1); /* boolean */
725 UPDATERC();
726
727
728 /*
729 * Devices
730 */
731 pDevices = NULL;
732 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);
733 UPDATERC();
734 /* device */
735 PCFGMNODE pDev = NULL;
736 PCFGMNODE pInst = NULL;
737 PCFGMNODE pCfg = NULL;
738#if 0
739 PCFGMNODE pLunL0 = NULL;
740 PCFGMNODE pLunL1 = NULL;
741#endif
742
743 /*
744 * PC Arch.
745 */
746 rc = CFGMR3InsertNode(pDevices, "pcarch", &pDev);
747 UPDATERC();
748 rc = CFGMR3InsertNode(pDev, "0", &pInst);
749 UPDATERC();
750 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
751 UPDATERC();
752 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
753 UPDATERC();
754
755 /*
756 * PC Bios.
757 */
758 rc = CFGMR3InsertNode(pDevices, "pcbios", &pDev);
759 UPDATERC();
760 rc = CFGMR3InsertNode(pDev, "0", &pInst);
761 UPDATERC();
762 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
763 UPDATERC();
764 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
765 UPDATERC();
766 rc = CFGMR3InsertInteger(pCfg, "RamSize", 128 * _1M);
767 UPDATERC();
768 rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
769 UPDATERC();
770 rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
771 UPDATERC();
772 rc = CFGMR3InsertString(pCfg, "BootDevice2", "NONE");
773 UPDATERC();
774 rc = CFGMR3InsertString(pCfg, "BootDevice3", "NONE");
775 UPDATERC();
776 rc = CFGMR3InsertString(pCfg, "HardDiskDevice", "piix3ide");
777 UPDATERC();
778 rc = CFGMR3InsertString(pCfg, "FloppyDevice", "");
779 UPDATERC();
780 /* Bios logo. */
781 rc = CFGMR3InsertInteger(pCfg, "FadeIn", 1);
782 UPDATERC();
783 rc = CFGMR3InsertInteger(pCfg, "FadeOut", 1);
784 UPDATERC();
785 rc = CFGMR3InsertInteger(pCfg, "LogoTime", 0);
786 UPDATERC();
787 rc = CFGMR3InsertString(pCfg, "LogoFile", "");
788 UPDATERC();
789
790 /*
791 * PCI bus.
792 */
793 rc = CFGMR3InsertNode(pDevices, "pci", &pDev); /* piix3 */
794 UPDATERC();
795 rc = CFGMR3InsertNode(pDev, "0", &pInst);
796 UPDATERC();
797 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
798 UPDATERC();
799 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
800 UPDATERC();
801
802 /*
803 * PS/2 keyboard & mouse
804 */
805 rc = CFGMR3InsertNode(pDevices, "pckbd", &pDev);
806 UPDATERC();
807 rc = CFGMR3InsertNode(pDev, "0", &pInst);
808 UPDATERC();
809 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
810 UPDATERC();
811#if 0
812 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
813 UPDATERC();
814 rc = CFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue");
815 UPDATERC();
816 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
817 UPDATERC();
818 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 64);
819 UPDATERC();
820 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
821 UPDATERC();
822 rc = CFGMR3InsertString(pLunL1, "Driver", "MainKeyboard");
823 UPDATERC();
824 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
825 UPDATERC();
826#endif
827#if 0
828 rc = CFGMR3InsertNode(pInst, "LUN#1", &pLunL0);
829 UPDATERC();
830 rc = CFGMR3InsertString(pLunL0, "Driver", "MouseQueue");
831 UPDATERC();
832 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
833 UPDATERC();
834 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 128);
835 UPDATERC();
836 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
837 UPDATERC();
838 rc = CFGMR3InsertString(pLunL1, "Driver", "MainMouse");
839 UPDATERC();
840 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
841 UPDATERC();
842#endif
843
844 /*
845 * i8254 Programmable Interval Timer And Dummy Speaker
846 */
847 rc = CFGMR3InsertNode(pDevices, "i8254", &pDev);
848 UPDATERC();
849 rc = CFGMR3InsertNode(pDev, "0", &pInst);
850 UPDATERC();
851#ifdef DEBUG
852 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
853 UPDATERC();
854#endif
855 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
856 UPDATERC();
857
858 /*
859 * i8259 Programmable Interrupt Controller.
860 */
861 rc = CFGMR3InsertNode(pDevices, "i8259", &pDev);
862 UPDATERC();
863 rc = CFGMR3InsertNode(pDev, "0", &pInst);
864 UPDATERC();
865 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
866 UPDATERC();
867 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
868 UPDATERC();
869
870 /*
871 * RTC MC146818.
872 */
873 rc = CFGMR3InsertNode(pDevices, "mc146818", &pDev);
874 UPDATERC();
875 rc = CFGMR3InsertNode(pDev, "0", &pInst);
876 UPDATERC();
877 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
878 UPDATERC();
879
880 /*
881 * VGA.
882 */
883 rc = CFGMR3InsertNode(pDevices, "vga", &pDev);
884 UPDATERC();
885 rc = CFGMR3InsertNode(pDev, "0", &pInst);
886 UPDATERC();
887 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
888 UPDATERC();
889 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
890 UPDATERC();
891 rc = CFGMR3InsertInteger(pCfg, "VRamSize", 4 * _1M);
892 UPDATERC();
893#if 0
894 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
895 UPDATERC();
896 rc = CFGMR3InsertString(pLunL0, "Driver", "MainDisplay");
897 UPDATERC();
898#endif
899
900 /*
901 * IDE controller.
902 */
903 rc = CFGMR3InsertNode(pDevices, "piix3ide", &pDev); /* piix3 */
904 UPDATERC();
905 rc = CFGMR3InsertNode(pDev, "0", &pInst);
906 UPDATERC();
907 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
908 UPDATERC();
909 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
910 UPDATERC();
911
912
913
914 /*
915 * ...
916 */
917
918#undef UPDATERC
919 return rcAll;
920}
921
922
923
924
925/**
926 * Resolves a path reference to a child node.
927 *
928 * @returns VBox status code.
929 * @param pNode Which node to search for pszName in.
930 * @param pszPath Path to the child node.
931 * @param ppChild Where to store the pointer to the child node.
932 */
933static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild)
934{
935 if (pNode)
936 {
937 PCFGMNODE pChild = NULL;
938 for (;;)
939 {
940 /* skip leading slashes. */
941 while (*pszPath == '/')
942 pszPath++;
943
944 /* End of path? */
945 if (!*pszPath)
946 {
947 if (!pChild)
948 return VERR_CFGM_INVALID_CHILD_PATH;
949 *ppChild = pChild;
950 return VINF_SUCCESS;
951 }
952
953 /* find end of component. */
954 const char *pszNext = strchr(pszPath, '/');
955 if (!pszNext)
956 pszNext = strchr(pszPath, '\0');
957 RTUINT cchName = pszNext - pszPath;
958
959 /* search child list. */
960 pChild = pNode->pFirstChild;
961 for ( ; pChild; pChild = pChild->pNext)
962 if ( pChild->cchName == cchName
963 && !memcmp(pszPath, pChild->szName, cchName) )
964 break;
965
966 /* if not found, we're done. */
967 if (!pChild)
968 return VERR_CFGM_CHILD_NOT_FOUND;
969
970 /* next iteration */
971 pNode = pChild;
972 pszPath = pszNext;
973 }
974
975 /* won't get here */
976 }
977 else
978 return VERR_CFGM_NO_PARENT;
979}
980
981
982/**
983 * Resolves a path reference to a child node.
984 *
985 * @returns VBox status code.
986 * @param pNode Which node to search for pszName in.
987 * @param pszName Name of a byte string value.
988 * @param ppLeaf Where to store the pointer to the leaf node.
989 */
990static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
991{
992 int rc;
993 if (pNode)
994 {
995 RTUINT cchName = strlen(pszName);
996 PCFGMLEAF pLeaf = pNode->pFirstLeaf;
997 while (pLeaf)
998 {
999 if ( cchName == pLeaf->cchName
1000 && !memcmp(pszName, pLeaf->szName, cchName) )
1001 {
1002 *ppLeaf = pLeaf;
1003 return VINF_SUCCESS;
1004 }
1005
1006 /* next */
1007 pLeaf = pLeaf->pNext;
1008 }
1009 rc = VERR_CFGM_VALUE_NOT_FOUND;
1010 }
1011 else
1012 rc = VERR_CFGM_NO_PARENT;
1013 return rc;
1014}
1015
1016
1017
1018/**
1019 * Insert a node.
1020 *
1021 * @returns VBox status code.
1022 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1023 * @param pNode Parent node.
1024 * @param pszName Name or path of the new child node.
1025 * @param ppChild Where to store the address of the new child node. (optional)
1026 */
1027CFGMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
1028{
1029 int rc;
1030 if (pNode)
1031 {
1032 /*
1033 * If given a path we have to deal with it component by compontent.
1034 */
1035 while (*pszName == '/')
1036 pszName++;
1037 if (strchr(pszName, '/'))
1038 {
1039 char *pszDup = RTStrDup(pszName);
1040 if (pszDup)
1041 {
1042 char *psz = pszDup;
1043 for (;;)
1044 {
1045 /* Terminate at '/' and find the next component. */
1046 char *pszNext = strchr(psz, '/');
1047 if (pszNext)
1048 {
1049 *pszNext++ = '\0';
1050 while (*pszNext == '/')
1051 pszNext++;
1052 if (*pszNext == '\0')
1053 pszNext = NULL;
1054 }
1055
1056 /* does it exist? */
1057 PCFGMNODE pChild = CFGMR3GetChild(pNode, psz);
1058 if (!pChild)
1059 {
1060 /* no, insert it */
1061 rc = CFGMR3InsertNode(pNode, psz, &pChild);
1062 if (VBOX_FAILURE(rc))
1063 break;
1064 if (!pszNext)
1065 {
1066 if (ppChild)
1067 *ppChild = pChild;
1068 break;
1069 }
1070
1071 }
1072 /* if last component fail */
1073 else if (!pszNext)
1074 {
1075 rc = VERR_CFGM_NODE_EXISTS;
1076 break;
1077 }
1078
1079 /* next */
1080 pNode = pChild;
1081 psz = pszNext;
1082 }
1083 RTStrFree(pszDup);
1084 }
1085 else
1086 rc = VERR_NO_TMP_MEMORY;
1087 }
1088 /*
1089 * Not multicomponent, just make sure it's a non-zero name.
1090 */
1091 else if (*pszName)
1092 {
1093 /*
1094 * Check if already exists and find last node in chain.
1095 */
1096 size_t cchName = strlen(pszName);
1097 PCFGMNODE pPrev = pNode->pFirstChild;
1098 if (pPrev)
1099 {
1100 for (;; pPrev = pPrev->pNext)
1101 {
1102 if ( cchName == pPrev->cchName
1103 && !memcmp(pszName, pPrev->szName, cchName))
1104 return VERR_CFGM_NODE_EXISTS;
1105 if (!pPrev->pNext)
1106 break;
1107 }
1108 }
1109
1110 /*
1111 * Allocate and init node.
1112 */
1113 PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1114 if (pNew)
1115 {
1116 pNew->pParent = pNode;
1117 pNew->pFirstChild = NULL;
1118 pNew->pFirstLeaf = NULL;
1119 pNew->pVM = pNode->pVM;
1120 pNew->fRestrictedRoot = false;
1121 pNew->cchName = cchName;
1122 memcpy(pNew->szName, pszName, cchName + 1);
1123
1124 /*
1125 * Insert into child list.
1126 */
1127 pNew->pNext = NULL;
1128 pNew->pPrev = pPrev;
1129 if (pPrev)
1130 pPrev->pNext = pNew;
1131 else
1132 pNode->pFirstChild = pNew;
1133 if (ppChild)
1134 *ppChild = pNew;
1135 rc = VINF_SUCCESS;
1136 }
1137 else
1138 rc = VERR_NO_MEMORY;
1139 }
1140 else
1141 {
1142 rc = VERR_CFGM_INVALID_NODE_PATH;
1143 AssertMsgFailed(("Invalid path %s\n", pszName));
1144 }
1145 }
1146 else
1147 {
1148 rc = VERR_CFGM_NO_PARENT;
1149 AssertMsgFailed(("No parent! path %s\n", pszName));
1150 }
1151
1152 return rc;
1153}
1154
1155
1156/**
1157 * Insert a node, format string name.
1158 *
1159 * @returns VBox status code.
1160 * @param pNode Parent node.
1161 * @param ppChild Where to store the address of the new child node. (optional)
1162 * @param pszNameFormat Name of or path the new child node.
1163 * @param ... Name format arguments.
1164 */
1165CFGMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
1166{
1167 va_list Args;
1168 va_start(Args, pszNameFormat);
1169 int rc = CFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
1170 va_end(Args);
1171 return rc;
1172}
1173
1174
1175/**
1176 * Insert a node, format string name.
1177 *
1178 * @returns VBox status code.
1179 * @param pNode Parent node.
1180 * @param ppChild Where to store the address of the new child node. (optional)
1181 * @param pszNameFormat Name or path of the new child node.
1182 * @param Args Name format arguments.
1183 */
1184CFGMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args)
1185{
1186 int rc;
1187 char *pszName;
1188 RTStrAPrintfV(&pszName, pszNameFormat, Args);
1189 if (pszName)
1190 {
1191 rc = CFGMR3InsertNode(pNode, pszName, ppChild);
1192 RTStrFree(pszName);
1193 }
1194 else
1195 rc = VERR_NO_MEMORY;
1196 return rc;
1197}
1198
1199
1200/**
1201 * Marks the node as the root of a restricted subtree, i.e. the end of
1202 * a CFGMR3GetParent() journey.
1203 *
1204 * @param pNode The node to mark.
1205 */
1206CFGMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode)
1207{
1208 if (pNode)
1209 pNode->fRestrictedRoot = true;
1210}
1211
1212
1213/**
1214 * Insert a node.
1215 *
1216 * @returns VBox status code.
1217 * @param pNode Parent node.
1218 * @param pszName Name of the new child node.
1219 * @param ppLeaf Where to store the new leaf.
1220 * The caller must fill in the enmType and Value fields!
1221 */
1222static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1223{
1224 int rc;
1225 if (*pszName)
1226 {
1227 if (pNode)
1228 {
1229 /*
1230 * Check if already exists and find last node in chain.
1231 */
1232 size_t cchName = strlen(pszName);
1233 PCFGMLEAF pPrev = pNode->pFirstLeaf;
1234 if (pPrev)
1235 {
1236 for (;; pPrev = pPrev->pNext)
1237 {
1238 if ( cchName == pPrev->cchName
1239 && !memcmp(pszName, pPrev->szName, cchName))
1240 return VERR_CFGM_LEAF_EXISTS;
1241 if (!pPrev->pNext)
1242 break;
1243 }
1244 }
1245
1246 /*
1247 * Allocate and init node.
1248 */
1249 PCFGMLEAF pNew = (PCFGMLEAF)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1250 if (pNew)
1251 {
1252 pNew->cchName = cchName;
1253 memcpy(pNew->szName, pszName, cchName + 1);
1254
1255 /*
1256 * Insert into child list.
1257 */
1258 pNew->pNext = NULL;
1259 pNew->pPrev = pPrev;
1260 if (pPrev)
1261 pPrev->pNext = pNew;
1262 else
1263 pNode->pFirstLeaf = pNew;
1264 *ppLeaf = pNew;
1265 rc = VINF_SUCCESS;
1266 }
1267 else
1268 rc = VERR_NO_MEMORY;
1269 }
1270 else
1271 rc = VERR_CFGM_NO_PARENT;
1272 }
1273 else
1274 rc = VERR_CFGM_INVALID_CHILD_PATH;
1275 return rc;
1276}
1277
1278
1279/**
1280 * Remove a node.
1281 *
1282 * @param pNode Parent node.
1283 */
1284CFGMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
1285{
1286 if (pNode)
1287 {
1288 /*
1289 * Free children.
1290 */
1291 while (pNode->pFirstChild)
1292 CFGMR3RemoveNode(pNode->pFirstChild);
1293
1294 /*
1295 * Free leafs.
1296 */
1297 while (pNode->pFirstLeaf)
1298 cfgmR3RemoveLeaf(pNode, pNode->pFirstLeaf);
1299
1300 /*
1301 * Unlink ourselves.
1302 */
1303 if (pNode->pPrev)
1304 pNode->pPrev->pNext = pNode->pNext;
1305 else
1306 {
1307 if (pNode->pParent)
1308 pNode->pParent->pFirstChild = pNode->pNext;
1309 else
1310 pNode->pVM->cfgm.s.pRoot = NULL;
1311 }
1312 if (pNode->pNext)
1313 pNode->pNext->pPrev = pNode->pPrev;
1314
1315 /*
1316 * Free ourselves. (bit of paranoia first)
1317 */
1318 pNode->pVM = NULL;
1319 pNode->pNext = NULL;
1320 pNode->pPrev = NULL;
1321 pNode->pParent = NULL;
1322 MMR3HeapFree(pNode);
1323
1324 }
1325}
1326
1327
1328/**
1329 * Removes a leaf.
1330 *
1331 * @param pNode Parent node.
1332 * @param pLeaf Leaf to remove.
1333 */
1334static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
1335{
1336 if (pNode && pLeaf)
1337 {
1338 /*
1339 * Unlink.
1340 */
1341 if (pLeaf->pPrev)
1342 pLeaf->pPrev->pNext = pLeaf->pNext;
1343 else
1344 pNode->pFirstLeaf = pLeaf->pNext;
1345 if (pLeaf->pNext)
1346 pLeaf->pNext->pPrev = pLeaf->pPrev;
1347
1348 /*
1349 * Free value and node.
1350 */
1351 cfgmR3FreeValue(pLeaf);
1352 pLeaf->pNext = NULL;
1353 pLeaf->pPrev = NULL;
1354 MMR3HeapFree(pLeaf);
1355 }
1356}
1357
1358
1359/**
1360 * Frees whatever resources the leaf value is owning.
1361 *
1362 * Use this before assigning a new value to a leaf.
1363 * The caller must either free the leaf or assign a new value to it.
1364 *
1365 * @param pLeaf Pointer to the leaf which value should be free.
1366 */
1367static void cfgmR3FreeValue(PCFGMLEAF pLeaf)
1368{
1369 if (pLeaf)
1370 {
1371 switch (pLeaf->enmType)
1372 {
1373 case CFGMVALUETYPE_BYTES:
1374 MMR3HeapFree(pLeaf->Value.Bytes.pau8);
1375 pLeaf->Value.Bytes.pau8 = NULL;
1376 pLeaf->Value.Bytes.cb = 0;
1377 break;
1378
1379 case CFGMVALUETYPE_STRING:
1380 MMR3HeapFree(pLeaf->Value.String.psz);
1381 pLeaf->Value.String.psz = NULL;
1382 pLeaf->Value.String.cch = 0;
1383 break;
1384
1385 case CFGMVALUETYPE_INTEGER:
1386 break;
1387 }
1388 pLeaf->enmType = (CFGMVALUETYPE)0;
1389 }
1390}
1391
1392
1393/**
1394 * Inserts a new integer value.
1395 *
1396 * @returns VBox status code.
1397 * @param pNode Parent node.
1398 * @param pszName Value name.
1399 * @param u64Integer The value.
1400 */
1401CFGMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
1402{
1403 PCFGMLEAF pLeaf;
1404 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1405 if (VBOX_SUCCESS(rc))
1406 {
1407 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
1408 pLeaf->Value.Integer.u64 = u64Integer;
1409 }
1410 return rc;
1411}
1412
1413
1414/**
1415 * Inserts a new string value.
1416 *
1417 * @returns VBox status code.
1418 * @param pNode Parent node.
1419 * @param pszName Value name.
1420 * @param pszString The value.
1421 */
1422CFGMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
1423{
1424 int rc;
1425 if (pNode)
1426 {
1427 /*
1428 * Allocate string object first.
1429 */
1430 size_t cchString = strlen(pszString) + 1;
1431 char *pszStringCopy = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, RT_ALIGN_Z(cchString, 16));
1432 if (pszStringCopy)
1433 {
1434 memcpy(pszStringCopy, pszString, cchString);
1435
1436 /*
1437 * Create value leaf and set it to string type.
1438 */
1439 PCFGMLEAF pLeaf;
1440 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1441 if (VBOX_SUCCESS(rc))
1442 {
1443 pLeaf->enmType = CFGMVALUETYPE_STRING;
1444 pLeaf->Value.String.psz = pszStringCopy;
1445 pLeaf->Value.String.cch = cchString;
1446 }
1447 }
1448 else
1449 rc = VERR_NO_MEMORY;
1450 }
1451 else
1452 rc = VERR_CFGM_NO_PARENT;
1453
1454 return rc;
1455}
1456
1457
1458
1459/**
1460 * Inserts a new integer value.
1461 *
1462 * @returns VBox status code.
1463 * @param pNode Parent node.
1464 * @param pszName Value name.
1465 * @param pvBytes The value.
1466 * @param cbBytes The value size.
1467 */
1468CFGMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, void *pvBytes, size_t cbBytes)
1469{
1470 int rc;
1471 if (pNode)
1472 {
1473 if (cbBytes == (RTUINT)cbBytes)
1474 {
1475 /*
1476 * Allocate string object first.
1477 */
1478 void *pvCopy = MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, RT_ALIGN_Z(cbBytes, 16));
1479 if (pvCopy || !cbBytes)
1480 {
1481 memcpy(pvCopy, pvBytes, cbBytes);
1482
1483 /*
1484 * Create value leaf and set it to string type.
1485 */
1486 PCFGMLEAF pLeaf;
1487 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1488 if (VBOX_SUCCESS(rc))
1489 {
1490 pLeaf->enmType = CFGMVALUETYPE_BYTES;
1491 pLeaf->Value.Bytes.cb = cbBytes;
1492 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
1493 }
1494 }
1495 else
1496 rc = VERR_NO_MEMORY;
1497 }
1498 else
1499 rc = VERR_OUT_OF_RANGE;
1500 }
1501 else
1502 rc = VERR_CFGM_NO_PARENT;
1503
1504 return rc;
1505}
1506
1507
1508/**
1509 * Remove a value.
1510 *
1511 * @returns VBox status code.
1512 * @param pNode Parent node.
1513 * @param pszName Name of the new child node.
1514 */
1515CFGMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
1516{
1517 PCFGMLEAF pLeaf;
1518 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
1519 if (VBOX_SUCCESS(rc))
1520 cfgmR3RemoveLeaf(pNode, pLeaf);
1521 return rc;
1522}
1523
1524
1525
1526/*
1527 * -+- helper apis -+-
1528 */
1529
1530
1531/**
1532 * Query unsigned 64-bit integer value.
1533 *
1534 * @returns VBox status code.
1535 * @param pNode Which node to search for pszName in.
1536 * @param pszName Name of an integer value.
1537 * @param pu64 Where to store the integer value.
1538 */
1539CFGMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
1540{
1541 return CFGMR3QueryInteger(pNode, pszName, pu64);
1542}
1543
1544
1545/**
1546 * Query signed 64-bit integer value.
1547 *
1548 * @returns VBox status code.
1549 * @param pNode Which node to search for pszName in.
1550 * @param pszName Name of an integer value.
1551 * @param pi64 Where to store the value.
1552 */
1553CFGMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
1554{
1555 uint64_t u64;
1556 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1557 if (VBOX_SUCCESS(rc))
1558 *pi64 = (int64_t)u64;
1559 return rc;
1560}
1561
1562
1563/**
1564 * Query unsigned 32-bit integer value.
1565 *
1566 * @returns VBox status code.
1567 * @param pNode Which node to search for pszName in.
1568 * @param pszName Name of an integer value.
1569 * @param pu32 Where to store the value.
1570 */
1571CFGMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
1572{
1573 uint64_t u64;
1574 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1575 if (VBOX_SUCCESS(rc))
1576 {
1577 if (!(u64 & 0xffffffff00000000ULL))
1578 *pu32 = (uint32_t)u64;
1579 else
1580 rc = VERR_CFGM_INTEGER_TOO_BIG;
1581 }
1582 return rc;
1583}
1584
1585
1586/**
1587 * Query signed 32-bit integer value.
1588 *
1589 * @returns VBox status code.
1590 * @param pNode Which node to search for pszName in.
1591 * @param pszName Name of an integer value.
1592 * @param pi32 Where to store the value.
1593 */
1594CFGMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
1595{
1596 uint64_t u64;
1597 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1598 if (VBOX_SUCCESS(rc))
1599 {
1600 if ( !(u64 & 0xffffffff80000000ULL)
1601 || (u64 & 0xffffffff80000000ULL) == 0xffffffff80000000ULL)
1602
1603 if (((uint32_t)(u64 >> 32) + 1) <= 1)
1604 *pi32 = (int32_t)u64;
1605 else
1606 rc = VERR_CFGM_INTEGER_TOO_BIG;
1607 }
1608 return rc;
1609}
1610
1611
1612/**
1613 * Query unsigned 16-bit integer value.
1614 *
1615 * @returns VBox status code.
1616 * @param pNode Which node to search for pszName in.
1617 * @param pszName Name of an integer value.
1618 * @param pu16 Where to store the value.
1619 */
1620CFGMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
1621{
1622 uint64_t u64;
1623 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1624 if (VBOX_SUCCESS(rc))
1625 {
1626 if (!(u64 & 0xffffffffffff0000ULL))
1627 *pu16 = (int16_t)u64;
1628 else
1629 rc = VERR_CFGM_INTEGER_TOO_BIG;
1630 }
1631 return rc;
1632}
1633
1634
1635/**
1636 * Query signed 16-bit integer value.
1637 *
1638 * @returns VBox status code.
1639 * @param pNode Which node to search for pszName in.
1640 * @param pszName Name of an integer value.
1641 * @param pi16 Where to store the value.
1642 */
1643CFGMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
1644{
1645 uint64_t u64;
1646 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1647 if (VBOX_SUCCESS(rc))
1648 {
1649 if ( !(u64 & 0xffffffffffff8000ULL)
1650 || (u64 & 0xffffffffffff8000ULL) == 0xffffffffffff8000ULL)
1651 *pi16 = (int16_t)u64;
1652 else
1653 rc = VERR_CFGM_INTEGER_TOO_BIG;
1654 }
1655 return rc;
1656}
1657
1658
1659/**
1660 * Query unsigned 8-bit integer value.
1661 *
1662 * @returns VBox status code.
1663 * @param pNode Which node to search for pszName in.
1664 * @param pszName Name of an integer value.
1665 * @param pu8 Where to store the value.
1666 */
1667CFGMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
1668{
1669 uint64_t u64;
1670 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1671 if (VBOX_SUCCESS(rc))
1672 {
1673 if (!(u64 & 0xffffffffffffff00ULL))
1674 *pu8 = (uint8_t)u64;
1675 else
1676 rc = VERR_CFGM_INTEGER_TOO_BIG;
1677 }
1678 return rc;
1679}
1680
1681
1682/**
1683 * Query signed 8-bit integer value.
1684 *
1685 * @returns VBox status code.
1686 * @param pNode Which node to search for pszName in.
1687 * @param pszName Name of an integer value.
1688 * @param pi8 Where to store the value.
1689 */
1690CFGMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
1691{
1692 uint64_t u64;
1693 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1694 if (VBOX_SUCCESS(rc))
1695 {
1696 if ( !(u64 & 0xffffffffffffff80ULL)
1697 || (u64 & 0xffffffffffffff80ULL) == 0xffffffffffffff80ULL)
1698 *pi8 = (int8_t)u64;
1699 else
1700 rc = VERR_CFGM_INTEGER_TOO_BIG;
1701 }
1702 return rc;
1703}
1704
1705
1706/**
1707 * Query boolean integer value.
1708 *
1709 * @returns VBox status code.
1710 * @param pNode Which node to search for pszName in.
1711 * @param pszName Name of an integer value.
1712 * @param pf Where to store the value.
1713 * @remark This function will interpret any non-zero value as true.
1714 */
1715CFGMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
1716{
1717 uint64_t u64;
1718 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1719 if (VBOX_SUCCESS(rc))
1720 *pf = u64 ? true : false;
1721 return rc;
1722}
1723
1724
1725/**
1726 * Query pointer integer value.
1727 *
1728 * @returns VBox status code.
1729 * @param pNode Which node to search for pszName in.
1730 * @param pszName Name of an integer value.
1731 * @param ppv Where to store the value.
1732 */
1733CFGMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
1734{
1735 uint64_t u64;
1736 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1737 if (VBOX_SUCCESS(rc))
1738 {
1739 uintptr_t u = (uintptr_t)u64;
1740 if (u64 == u)
1741 *ppv = (void *)u;
1742 else
1743 rc = VERR_CFGM_INTEGER_TOO_BIG;
1744 }
1745 return rc;
1746}
1747
1748
1749/**
1750 * Query Guest Context pointer integer value.
1751 *
1752 * @returns VBox status code.
1753 * @param pNode Which node to search for pszName in.
1754 * @param pszName Name of an integer value.
1755 * @param pGCPtr Where to store the value.
1756 */
1757CFGMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
1758{
1759 uint64_t u64;
1760 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1761 if (VBOX_SUCCESS(rc))
1762 {
1763 RTGCPTR u = (RTGCPTR)u64;
1764 if (u64 == u)
1765 *pGCPtr = u;
1766 else
1767 rc = VERR_CFGM_INTEGER_TOO_BIG;
1768 }
1769 return rc;
1770}
1771
1772
1773/**
1774 * Query Guest Context unsigned pointer value.
1775 *
1776 * @returns VBox status code.
1777 * @param pNode Which node to search for pszName in.
1778 * @param pszName Name of an integer value.
1779 * @param pGCPtr Where to store the value.
1780 */
1781CFGMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
1782{
1783 uint64_t u64;
1784 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1785 if (VBOX_SUCCESS(rc))
1786 {
1787 RTGCUINTPTR u = (RTGCUINTPTR)u64;
1788 if (u64 == u)
1789 *pGCPtr = u;
1790 else
1791 rc = VERR_CFGM_INTEGER_TOO_BIG;
1792 }
1793 return rc;
1794}
1795
1796
1797/**
1798 * Query Guest Context signed pointer value.
1799 *
1800 * @returns VBox status code.
1801 * @param pNode Which node to search for pszName in.
1802 * @param pszName Name of an integer value.
1803 * @param pGCPtr Where to store the value.
1804 */
1805CFGMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
1806{
1807 uint64_t u64;
1808 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
1809 if (VBOX_SUCCESS(rc))
1810 {
1811 RTGCINTPTR u = (RTGCINTPTR)u64;
1812 if (u64 == (uint64_t)u)
1813 *pGCPtr = u;
1814 else
1815 rc = VERR_CFGM_INTEGER_TOO_BIG;
1816 }
1817 return rc;
1818}
1819
1820
1821/**
1822 * Query zero terminated character value storing it in a
1823 * buffer allocated from the MM heap.
1824 *
1825 * @returns VBox status code.
1826 * @param pNode Which node to search for pszName in.
1827 * @param pszName Value name. This value must be of zero terminated character string type.
1828 * @param ppszString Where to store the string pointer.
1829 * Free this using MMR3HeapFree().
1830 */
1831CFGMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
1832{
1833 size_t cch;
1834 int rc = CFGMR3QuerySize(pNode, pszName, &cch);
1835 if (VBOX_SUCCESS(rc))
1836 {
1837 char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cch);
1838 if (pszString)
1839 {
1840 rc = CFGMR3QueryString(pNode, pszName, pszString, cch);
1841 if (VBOX_SUCCESS(rc))
1842 *ppszString = pszString;
1843 else
1844 MMR3HeapFree(pszString);
1845 }
1846 else
1847 rc = VERR_NO_MEMORY;
1848 }
1849 return rc;
1850}
1851
1852
1853
1854/**
1855 * Dumps the configuration (sub)tree to the release log.
1856 *
1857 * @param pRoot The root node of the dump.
1858 */
1859CFGMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
1860{
1861 LogRel(("************************* CFGM dump *************************\n"));
1862 cfgmR3Info(pRoot->pVM, DBGFR3InfoLogRelHlp(), NULL);
1863 LogRel(("********************* End of CFGM dump **********************\n"));
1864}
1865
1866
1867/**
1868 * Info handler, internal version.
1869 *
1870 * @param pVM The VM handle.
1871 * @param pHlp Callback functions for doing output.
1872 * @param pszArgs Argument string. Optional and specific to the handler.
1873 */
1874static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1875{
1876 /*
1877 * Figure where to start.
1878 */
1879 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
1880 if (pszArgs && *pszArgs)
1881 {
1882 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
1883 if (VBOX_FAILURE(rc))
1884 {
1885 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Vrc", pszArgs, rc);
1886 return;
1887 }
1888 }
1889
1890 /*
1891 * Dump the specified tree.
1892 */
1893 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
1894 cfgmR3DumpPath(pRoot, pHlp);
1895 pHlp->pfnPrintf(pHlp, "}\n");
1896 cfgmR3Dump(pRoot, 0, pHlp);
1897}
1898
1899
1900/**
1901 * Recursivly prints a path name.
1902 */
1903static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
1904{
1905 if (pNode->pParent)
1906 cfgmR3DumpPath(pNode->pParent, pHlp);
1907 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
1908}
1909
1910
1911/**
1912 * Dumps a branch of a tree.
1913 */
1914static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
1915{
1916 /*
1917 * Path.
1918 */
1919 pHlp->pfnPrintf(pHlp, "[");
1920 cfgmR3DumpPath(pRoot, pHlp);
1921 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
1922
1923 /*
1924 * Values.
1925 */
1926 PCFGMLEAF pLeaf;
1927 unsigned cchMax = 0;
1928 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
1929 cchMax = RT_MAX(cchMax, pLeaf->cchName);
1930 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
1931 {
1932 switch (CFGMR3GetValueType(pLeaf))
1933 {
1934 case CFGMVALUETYPE_INTEGER:
1935 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%lld)\n", cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
1936 break;
1937
1938 case CFGMVALUETYPE_STRING:
1939 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cch=%d)\n", cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cch);
1940 break;
1941
1942 case CFGMVALUETYPE_BYTES:
1943 pHlp->pfnPrintf(pHlp, " %-*s <bytes> = \"%.*Vhxs\" (cb=%d)\n", cchMax, pLeaf->szName, pLeaf->Value.Bytes.cb, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
1944 break;
1945
1946 default:
1947 AssertMsgFailed(("bad leaf!\n"));
1948 break;
1949 }
1950 }
1951 pHlp->pfnPrintf(pHlp, "\n");
1952
1953 /*
1954 * Children.
1955 */
1956 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
1957 {
1958 Assert(pChild->pNext != pChild);
1959 Assert(pChild->pPrev != pChild);
1960 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
1961 Assert(pChild->pFirstChild != pChild);
1962 Assert(pChild->pParent != pChild);
1963 cfgmR3Dump(pChild, iLevel + 1, pHlp);
1964 }
1965}
1966
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