VirtualBox

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

Last change on this file since 3261 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 54.4 KB
Line 
1/* $Id: CFGM.cpp 2981 2007-06-01 16:01:28Z 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-2007 innotek 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