VirtualBox

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

Last change on this file since 45733 was 45189, checked in by vboxsync, 12 years ago

STAM,VM: ring-3 only testing of pdmcritsectrw.h (disabled).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 92.0 KB
Line 
1/* $Id: CFGM.cpp 45189 2013-03-26 09:31:59Z vboxsync $ */
2/** @file
3 * CFGM - Configuration Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @page pg_cfgm CFGM - The Configuration Manager
19 *
20 * The configuration manager is a directory containing the VM configuration at
21 * run time. It works in a manner similar to the windows registry - it's like a
22 * file system hierarchy, but the files (values) live in a separate name space
23 * and can include the path separators.
24 *
25 * The configuration is normally created via a callback passed to VMR3Create()
26 * via the pfnCFGMConstructor parameter. To make testcase writing a bit simpler,
27 * we allow the callback to be NULL, in which case a simple default
28 * configuration will be created by CFGMR3ConstructDefaultTree(). The
29 * Console::configConstructor() method in Main/ConsoleImpl2.cpp creates the
30 * configuration from the XML.
31 *
32 * Devices, drivers, services and other PDM stuff are given their own subtree
33 * where they are protected from accessing information of any parents. This is
34 * is implemented via the CFGMR3SetRestrictedRoot() API.
35 *
36 * Data validation beyond the basic primitives is left to the caller. The caller
37 * is in a better position to know the proper validation rules of the individual
38 * properties.
39 *
40 * @see grp_cfgm
41 *
42 *
43 * @section sec_cfgm_primitives Data Primitives
44 *
45 * CFGM supports the following data primitives:
46 * - Integers. Representation is unsigned 64-bit. Boolean, unsigned and
47 * small integers, and pointers are all represented using this primitive.
48 * - Zero terminated character strings. These are of course UTF-8.
49 * - Variable length byte strings. This can be used to get/put binary
50 * objects like for instance RTMAC.
51 *
52 */
53
54/*******************************************************************************
55* Header Files *
56*******************************************************************************/
57#define LOG_GROUP LOG_GROUP_CFGM
58#include <VBox/vmm/cfgm.h>
59#include <VBox/vmm/dbgf.h>
60#include <VBox/vmm/mm.h>
61#include "CFGMInternal.h"
62#include <VBox/vmm/vm.h>
63#include <VBox/vmm/uvm.h>
64#include <VBox/err.h>
65
66#include <VBox/log.h>
67#include <iprt/assert.h>
68#include <iprt/param.h>
69#include <iprt/string.h>
70#include <iprt/uuid.h>
71
72
73/*******************************************************************************
74* Internal Functions *
75*******************************************************************************/
76static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp);
77static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp);
78static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
79static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild);
80static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
81static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
82static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf);
83static void cfgmR3FreeValue(PCFGMLEAF pLeaf);
84
85
86
87/**
88 * Constructs the configuration for the VM.
89 *
90 * @returns VBox status code.
91 * @param pVM Pointer to VM which configuration has not yet been loaded.
92 * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
93 * This is called in the EM.
94 * @param pvUser The user argument passed to pfnCFGMConstructor.
95 * @thread EMT.
96 * @internal
97 */
98VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser)
99{
100 LogFlow(("CFGMR3Init: pfnCFGMConstructor=%p pvUser=%p\n", pfnCFGMConstructor, pvUser));
101
102 /*
103 * Init data members.
104 */
105 pVM->cfgm.s.pRoot = NULL;
106
107 /*
108 * Register DBGF into item.
109 */
110 int rc = DBGFR3InfoRegisterInternal(pVM, "cfgm", "Dumps a part of the CFGM tree. The argument indicates where to start.",
111 cfgmR3Info);
112 AssertRCReturn(rc,rc);
113
114 /*
115 * Root Node.
116 */
117 PCFGMNODE pRoot = (PCFGMNODE)MMR3HeapAllocZ(pVM, MM_TAG_CFGM, sizeof(*pRoot));
118 if (!pRoot)
119 return VERR_NO_MEMORY;
120 pRoot->pVM = pVM;
121 pRoot->cchName = 0;
122 pVM->cfgm.s.pRoot = pRoot;
123
124 /*
125 * Call the constructor if specified, if not use the default one.
126 */
127 if (pfnCFGMConstructor)
128 rc = pfnCFGMConstructor(pVM->pUVM, pVM, pvUser);
129 else
130 rc = CFGMR3ConstructDefaultTree(pVM);
131 if (RT_SUCCESS(rc))
132 {
133 Log(("CFGMR3Init: Successfully constructed the configuration\n"));
134 CFGMR3Dump(CFGMR3GetRoot(pVM));
135 }
136 else
137 AssertMsgFailed(("Constructor failed with rc=%Rrc pfnCFGMConstructor=%p\n", rc, pfnCFGMConstructor));
138
139 return rc;
140}
141
142
143/**
144 * Terminates the configuration manager.
145 *
146 * @returns VBox status code.
147 * @param pVM Pointer to the VM.
148 * @internal
149 */
150VMMR3DECL(int) CFGMR3Term(PVM pVM)
151{
152 CFGMR3RemoveNode(pVM->cfgm.s.pRoot);
153 pVM->cfgm.s.pRoot = NULL;
154 return 0;
155}
156
157
158/**
159 * Gets the root node for the VM.
160 *
161 * @returns Pointer to root node.
162 * @param pVM Pointer to the VM.
163 */
164VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM)
165{
166 return pVM->cfgm.s.pRoot;
167}
168
169
170/**
171 * Gets the root node for the VM.
172 *
173 * @returns Pointer to root node.
174 * @param pVM Pointer to the VM.
175 */
176VMMR3DECL(PCFGMNODE) CFGMR3GetRootU(PUVM pUVM)
177{
178 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
179 PVM pVM = pUVM->pVM;
180 AssertReturn(pVM, NULL);
181 return pVM->cfgm.s.pRoot;
182}
183
184
185/**
186 * Gets the parent of a CFGM node.
187 *
188 * @returns Pointer to the parent node.
189 * @returns NULL if pNode is Root or pNode is the start of a
190 * restricted subtree (use CFGMr3GetParentEx() for that).
191 *
192 * @param pNode The node which parent we query.
193 */
194VMMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode)
195{
196 if (pNode && !pNode->fRestrictedRoot)
197 return pNode->pParent;
198 return NULL;
199}
200
201
202/**
203 * Gets the parent of a CFGM node.
204 *
205 * @returns Pointer to the parent node.
206 * @returns NULL if pNode is Root or pVM is not correct.
207 *
208 * @param pVM The VM handle, used as token that the caller is trusted.
209 * @param pNode The node which parent we query.
210 */
211VMMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode)
212{
213 if (pNode && pNode->pVM == pVM)
214 return pNode->pParent;
215 return NULL;
216}
217
218
219/**
220 * Query a child node.
221 *
222 * @returns Pointer to the specified node.
223 * @returns NULL if node was not found or pNode is NULL.
224 * @param pNode Node pszPath is relative to.
225 * @param pszPath Path to the child node or pNode.
226 * It's good style to end this with '/'.
227 */
228VMMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath)
229{
230 PCFGMNODE pChild;
231 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
232 if (RT_SUCCESS(rc))
233 return pChild;
234 return NULL;
235}
236
237
238/**
239 * Query a child node by a format string.
240 *
241 * @returns Pointer to the specified node.
242 * @returns NULL if node was not found or pNode is NULL.
243 * @param pNode Node pszPath is relative to.
244 * @param pszPathFormat Path to the child node or pNode.
245 * It's good style to end this with '/'.
246 * @param ... Arguments to pszPathFormat.
247 */
248VMMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...)
249{
250 va_list Args;
251 va_start(Args, pszPathFormat);
252 PCFGMNODE pRet = CFGMR3GetChildFV(pNode, pszPathFormat, Args);
253 va_end(Args);
254 return pRet;
255}
256
257
258/**
259 * Query a child node by a format string.
260 *
261 * @returns Pointer to the specified node.
262 * @returns NULL if node was not found or pNode is NULL.
263 * @param pNode Node pszPath is relative to.
264 * @param pszPathFormat Path to the child node or pNode.
265 * It's good style to end this with '/'.
266 * @param Args Arguments to pszPathFormat.
267 */
268VMMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args)
269{
270 char *pszPath;
271 RTStrAPrintfV(&pszPath, pszPathFormat, Args);
272 if (pszPath)
273 {
274 PCFGMNODE pChild;
275 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
276 RTStrFree(pszPath);
277 if (RT_SUCCESS(rc))
278 return pChild;
279 }
280 return NULL;
281}
282
283
284/**
285 * Gets the first child node.
286 * Use this to start an enumeration of child nodes.
287 *
288 * @returns Pointer to the first child.
289 * @returns NULL if no children.
290 * @param pNode Node to enumerate children for.
291 */
292VMMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode)
293{
294 return pNode ? pNode->pFirstChild : NULL;
295}
296
297
298/**
299 * Gets the next sibling node.
300 * Use this to continue an enumeration.
301 *
302 * @returns Pointer to the first child.
303 * @returns NULL if no children.
304 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
305 * or successive calls to this function.
306 */
307VMMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur)
308{
309 return pCur ? pCur->pNext : NULL;
310}
311
312
313/**
314 * Gets the name of the current node.
315 * (Needed for enumeration.)
316 *
317 * @returns VBox status code.
318 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
319 * or successive calls to CFGMR3GetNextChild().
320 * @param pszName Where to store the node name.
321 * @param cchName Size of the buffer pointed to by pszName (with terminator).
322 */
323VMMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName)
324{
325 int rc;
326 if (pCur)
327 {
328 if (cchName > pCur->cchName)
329 {
330 rc = VINF_SUCCESS;
331 memcpy(pszName, pCur->szName, pCur->cchName + 1);
332 }
333 else
334 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
335 }
336 else
337 rc = VERR_CFGM_NO_NODE;
338 return rc;
339}
340
341
342/**
343 * Gets the length of the current node's name.
344 * (Needed for enumeration.)
345 *
346 * @returns Node name length in bytes including the terminating null char.
347 * @returns 0 if pCur is NULL.
348 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
349 * or successive calls to CFGMR3GetNextChild().
350 */
351VMMR3DECL(size_t) CFGMR3GetNameLen(PCFGMNODE pCur)
352{
353 return pCur ? pCur->cchName + 1 : 0;
354}
355
356
357/**
358 * Validates that the child nodes are within a set of valid names.
359 *
360 * @returns true if all names are found in pszzAllowed.
361 * @returns false if not.
362 * @param pNode The node which children should be examined.
363 * @param pszzValid List of valid names separated by '\\0' and ending with
364 * a double '\\0'.
365 *
366 * @deprecated Use CFGMR3ValidateConfig.
367 */
368VMMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid)
369{
370 if (pNode)
371 {
372 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
373 {
374 /* search pszzValid for the name */
375 const char *psz = pszzValid;
376 while (*psz)
377 {
378 size_t cch = strlen(psz);
379 if ( cch == pChild->cchName
380 && !memcmp(psz, pChild->szName, cch))
381 break;
382
383 /* next */
384 psz += cch + 1;
385 }
386
387 /* if at end of pszzValid we didn't find it => failure */
388 if (!*psz)
389 {
390 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pChild->szName));
391 return false;
392 }
393 }
394 }
395
396 /* all ok. */
397 return true;
398}
399
400
401/**
402 * Gets the first value of a node.
403 * Use this to start an enumeration of values.
404 *
405 * @returns Pointer to the first value.
406 * @param pCur The node (Key) which values to enumerate.
407 */
408VMMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur)
409{
410 return pCur ? pCur->pFirstLeaf : NULL;
411}
412
413/**
414 * Gets the next value in enumeration.
415 *
416 * @returns Pointer to the next value.
417 * @param pCur The current value as returned by this function or CFGMR3GetFirstValue().
418 */
419VMMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur)
420{
421 return pCur ? pCur->pNext : NULL;
422}
423
424/**
425 * Get the value name.
426 * (Needed for enumeration.)
427 *
428 * @returns VBox status code.
429 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
430 * or successive calls to CFGMR3GetNextValue().
431 * @param pszName Where to store the value name.
432 * @param cchName Size of the buffer pointed to by pszName (with terminator).
433 */
434VMMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName)
435{
436 int rc;
437 if (pCur)
438 {
439 if (cchName > pCur->cchName)
440 {
441 rc = VINF_SUCCESS;
442 memcpy(pszName, pCur->szName, pCur->cchName + 1);
443 }
444 else
445 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
446 }
447 else
448 rc = VERR_CFGM_NO_NODE;
449 return rc;
450}
451
452
453/**
454 * Gets the length of the current node's name.
455 * (Needed for enumeration.)
456 *
457 * @returns Value name length in bytes including the terminating null char.
458 * @returns 0 if pCur is NULL.
459 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
460 * or successive calls to CFGMR3GetNextValue().
461 */
462VMMR3DECL(size_t) CFGMR3GetValueNameLen(PCFGMLEAF pCur)
463{
464 return pCur ? pCur->cchName + 1 : 0;
465}
466
467
468/**
469 * Gets the value type.
470 * (For enumeration.)
471 *
472 * @returns VBox status code.
473 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
474 * or successive calls to CFGMR3GetNextValue().
475 */
476VMMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur)
477{
478 Assert(pCur);
479 return pCur->enmType;
480}
481
482
483/**
484 * Validates that the values are within a set of valid names.
485 *
486 * @returns true if all names are found in pszzAllowed.
487 * @returns false if not.
488 * @param pNode The node which values should be examined.
489 * @param pszzValid List of valid names separated by '\\0' and ending with
490 * a double '\\0'.
491 * @deprecated Use CFGMR3ValidateConfig.
492 */
493VMMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid)
494{
495 if (pNode)
496 {
497 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
498 {
499 /* search pszzValid for the name */
500 const char *psz = pszzValid;
501 while (*psz)
502 {
503 size_t cch = strlen(psz);
504 if ( cch == pLeaf->cchName
505 && !memcmp(psz, pLeaf->szName, cch))
506 break;
507
508 /* next */
509 psz += cch + 1;
510 }
511
512 /* if at end of pszzValid we didn't find it => failure */
513 if (!*psz)
514 {
515 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pLeaf->szName));
516 return false;
517 }
518 }
519 }
520
521 /* all ok. */
522 return true;
523}
524
525
526
527/**
528 * Query value type.
529 *
530 * @returns VBox status code.
531 * @param pNode Which node to search for pszName in.
532 * @param pszName Name of an integer value.
533 * @param penmType Where to store the type.
534 */
535VMMR3DECL(int) CFGMR3QueryType(PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)
536{
537 PCFGMLEAF pLeaf;
538 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
539 if (RT_SUCCESS(rc))
540 {
541 if (penmType)
542 *penmType = pLeaf->enmType;
543 }
544 return rc;
545}
546
547
548/**
549 * Query value size.
550 * This works on all types of values.
551 *
552 * @returns VBox status code.
553 * @param pNode Which node to search for pszName in.
554 * @param pszName Name of an integer value.
555 * @param pcb Where to store the value size.
556 */
557VMMR3DECL(int) CFGMR3QuerySize(PCFGMNODE pNode, const char *pszName, size_t *pcb)
558{
559 PCFGMLEAF pLeaf;
560 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
561 if (RT_SUCCESS(rc))
562 {
563 switch (pLeaf->enmType)
564 {
565 case CFGMVALUETYPE_INTEGER:
566 *pcb = sizeof(pLeaf->Value.Integer.u64);
567 break;
568
569 case CFGMVALUETYPE_STRING:
570 *pcb = pLeaf->Value.String.cb;
571 break;
572
573 case CFGMVALUETYPE_BYTES:
574 *pcb = pLeaf->Value.Bytes.cb;
575 break;
576
577 default:
578 rc = VERR_CFGM_IPE_1;
579 AssertMsgFailed(("Invalid value type %d\n", pLeaf->enmType));
580 break;
581 }
582 }
583 return rc;
584}
585
586
587/**
588 * Query integer value.
589 *
590 * @returns VBox status code.
591 * @param pNode Which node to search for pszName in.
592 * @param pszName Name of an integer value.
593 * @param pu64 Where to store the integer value.
594 */
595VMMR3DECL(int) CFGMR3QueryInteger(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
596{
597 PCFGMLEAF pLeaf;
598 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
599 if (RT_SUCCESS(rc))
600 {
601 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
602 *pu64 = pLeaf->Value.Integer.u64;
603 else
604 rc = VERR_CFGM_NOT_INTEGER;
605 }
606 return rc;
607}
608
609
610/**
611 * Query integer value with default.
612 *
613 * @returns VBox status code.
614 * @param pNode Which node to search for pszName in.
615 * @param pszName Name of an integer value.
616 * @param pu64 Where to store the integer value. This is set to the default on failure.
617 * @param u64Def The default value. This is always set.
618 */
619VMMR3DECL(int) CFGMR3QueryIntegerDef(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
620{
621 PCFGMLEAF pLeaf;
622 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
623 if (RT_SUCCESS(rc))
624 {
625 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
626 *pu64 = pLeaf->Value.Integer.u64;
627 else
628 rc = VERR_CFGM_NOT_INTEGER;
629 }
630
631 if (RT_FAILURE(rc))
632 {
633 *pu64 = u64Def;
634 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
635 rc = VINF_SUCCESS;
636 }
637
638 return rc;
639}
640
641
642/**
643 * Query zero terminated character value.
644 *
645 * @returns VBox status code.
646 * @param pNode Which node to search for pszName in.
647 * @param pszName Name of a zero terminate character value.
648 * @param pszString Where to store the string.
649 * @param cchString Size of the string buffer. (Includes terminator.)
650 */
651VMMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
652{
653 PCFGMLEAF pLeaf;
654 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
655 if (RT_SUCCESS(rc))
656 {
657 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
658 {
659 size_t cbSrc = pLeaf->Value.String.cb;
660 if (cchString >= cbSrc)
661 {
662 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
663 memset(pszString + cbSrc, 0, cchString - cbSrc);
664 }
665 else
666 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
667 }
668 else
669 rc = VERR_CFGM_NOT_STRING;
670 }
671 return rc;
672}
673
674
675/**
676 * Query zero terminated character value with default.
677 *
678 * @returns VBox status code.
679 * @param pNode Which node to search for pszName in.
680 * @param pszName Name of a zero terminate character value.
681 * @param pszString Where to store the string. This will not be set on overflow error.
682 * @param cchString Size of the string buffer. (Includes terminator.)
683 * @param pszDef The default value.
684 */
685VMMR3DECL(int) CFGMR3QueryStringDef(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)
686{
687 PCFGMLEAF pLeaf;
688 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
689 if (RT_SUCCESS(rc))
690 {
691 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
692 {
693 size_t cbSrc = pLeaf->Value.String.cb;
694 if (cchString >= cbSrc)
695 {
696 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
697 memset(pszString + cbSrc, 0, cchString - cbSrc);
698 }
699 else
700 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
701 }
702 else
703 rc = VERR_CFGM_NOT_STRING;
704 }
705
706 if (RT_FAILURE(rc) && rc != VERR_CFGM_NOT_ENOUGH_SPACE)
707 {
708 size_t cchDef = strlen(pszDef);
709 if (cchString > cchDef)
710 {
711 memcpy(pszString, pszDef, cchDef);
712 memset(pszString + cchDef, 0, cchString - cchDef);
713 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
714 rc = VINF_SUCCESS;
715 }
716 else if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
717 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
718 }
719
720 return rc;
721}
722
723
724/**
725 * Query byte string value.
726 *
727 * @returns VBox status code.
728 * @param pNode Which node to search for pszName in.
729 * @param pszName Name of a byte string value.
730 * @param pvData Where to store the binary data.
731 * @param cbData Size of buffer pvData points too.
732 */
733VMMR3DECL(int) CFGMR3QueryBytes(PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)
734{
735 PCFGMLEAF pLeaf;
736 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
737 if (RT_SUCCESS(rc))
738 {
739 if (pLeaf->enmType == CFGMVALUETYPE_BYTES)
740 {
741 if (cbData >= pLeaf->Value.Bytes.cb)
742 {
743 memcpy(pvData, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
744 memset((char *)pvData + pLeaf->Value.Bytes.cb, 0, cbData - pLeaf->Value.Bytes.cb);
745 }
746 else
747 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
748 }
749 else
750 rc = VERR_CFGM_NOT_BYTES;
751 }
752 return rc;
753}
754
755
756/**
757 * Validate one level of a configuration node.
758 *
759 * This replaces the CFGMR3AreChildrenValid and CFGMR3AreValuesValid APIs.
760 *
761 * @returns VBox status code.
762 *
763 * When an error is returned, both VMSetError and AssertLogRelMsgFailed
764 * have been called. So, all the caller needs to do is to propagate
765 * the error status up to PDM.
766 *
767 * @param pNode The node to validate.
768 * @param pszNode The node path, always ends with a slash. Use
769 * "/" for the root config node.
770 * @param pszValidValues Patterns describing the valid value names. See
771 * RTStrSimplePatternMultiMatch for details on the
772 * pattern syntax.
773 * @param pszValidNodes Patterns describing the valid node (key) names.
774 * See RTStrSimplePatternMultiMatch for details on
775 * the pattern syntax.
776 * @param pszWho Who is calling.
777 * @param uInstance The instance number of the caller.
778 */
779VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode,
780 const char *pszValidValues, const char *pszValidNodes,
781 const char *pszWho, uint32_t uInstance)
782{
783 /* Input validation. */
784 AssertPtrNullReturn(pNode, VERR_INVALID_POINTER);
785 AssertPtrReturn(pszNode, VERR_INVALID_POINTER);
786 Assert(*pszNode && pszNode[strlen(pszNode) - 1] == '/');
787 AssertPtrReturn(pszValidValues, VERR_INVALID_POINTER);
788 AssertPtrReturn(pszValidNodes, VERR_INVALID_POINTER);
789 AssertPtrReturn(pszWho, VERR_INVALID_POINTER);
790
791 if (pNode)
792 {
793 /*
794 * Enumerate the leafs and check them against pszValidValues.
795 */
796 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
797 {
798 if (!RTStrSimplePatternMultiMatch(pszValidValues, RTSTR_MAX,
799 pLeaf->szName, pLeaf->cchName,
800 NULL))
801 {
802 AssertLogRelMsgFailed(("%s/%u: Value '%s/%s' didn't match '%s'\n",
803 pszWho, uInstance, pszNode, pLeaf->szName, pszValidValues));
804 return VMSetError(pNode->pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
805 N_("Unknown configuration value '%s/%s' found in the configuration of %s instance #%u"),
806 pszNode, pLeaf->szName, pszWho, uInstance);
807 }
808
809 }
810
811 /*
812 * Enumerate the child nodes and check them against pszValidNodes.
813 */
814 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
815 {
816 if (!RTStrSimplePatternMultiMatch(pszValidNodes, RTSTR_MAX,
817 pChild->szName, pChild->cchName,
818 NULL))
819 {
820 AssertLogRelMsgFailed(("%s/%u: Node '%s/%s' didn't match '%s'\n",
821 pszWho, uInstance, pszNode, pChild->szName, pszValidNodes));
822 return VMSetError(pNode->pVM, VERR_CFGM_CONFIG_UNKNOWN_NODE, RT_SRC_POS,
823 N_("Unknown configuration node '%s/%s' found in the configuration of %s instance #%u"),
824 pszNode, pChild->szName, pszWho, uInstance);
825 }
826 }
827 }
828
829 /* All is well. */
830 return VINF_SUCCESS;
831}
832
833
834
835/**
836 * Populates the CFGM tree with the default configuration.
837 *
838 * This assumes an empty tree and is intended for testcases and such that only
839 * need to do very small adjustments to the config.
840 *
841 * @returns VBox status code.
842 * @param pVM Pointer to the VM.
843 * @internal
844 */
845VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM)
846{
847 int rc;
848 int rcAll = VINF_SUCCESS;
849#define UPDATERC() do { if (RT_FAILURE(rc) && RT_SUCCESS(rcAll)) rcAll = rc; } while (0)
850
851 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
852 AssertReturn(pRoot, VERR_WRONG_ORDER);
853
854 /*
855 * Create VM default values.
856 */
857 rc = CFGMR3InsertString(pRoot, "Name", "Default VM");
858 UPDATERC();
859 rc = CFGMR3InsertInteger(pRoot, "RamSize", 128U * _1M);
860 UPDATERC();
861 rc = CFGMR3InsertInteger(pRoot, "RamHoleSize", 512U * _1M);
862 UPDATERC();
863 rc = CFGMR3InsertInteger(pRoot, "TimerMillies", 10);
864 UPDATERC();
865 rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled", 1);
866 UPDATERC();
867 /** @todo CFGM Defaults: RawR0, PATMEnabled and CASMEnabled needs attention later. */
868 rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled", 1);
869 UPDATERC();
870 rc = CFGMR3InsertInteger(pRoot, "PATMEnabled", 1);
871 UPDATERC();
872 rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled", 1);
873 UPDATERC();
874
875 /*
876 * PDM.
877 */
878 PCFGMNODE pPdm;
879 rc = CFGMR3InsertNode(pRoot, "PDM", &pPdm);
880 UPDATERC();
881 PCFGMNODE pDevices = NULL;
882 rc = CFGMR3InsertNode(pPdm, "Devices", &pDevices);
883 UPDATERC();
884 rc = CFGMR3InsertInteger(pDevices, "LoadBuiltin", 1); /* boolean */
885 UPDATERC();
886 PCFGMNODE pDrivers = NULL;
887 rc = CFGMR3InsertNode(pPdm, "Drivers", &pDrivers);
888 UPDATERC();
889 rc = CFGMR3InsertInteger(pDrivers, "LoadBuiltin", 1); /* boolean */
890 UPDATERC();
891
892
893 /*
894 * Devices
895 */
896 pDevices = NULL;
897 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);
898 UPDATERC();
899 /* device */
900 PCFGMNODE pDev = NULL;
901 PCFGMNODE pInst = NULL;
902 PCFGMNODE pCfg = NULL;
903#if 0
904 PCFGMNODE pLunL0 = NULL;
905 PCFGMNODE pLunL1 = NULL;
906#endif
907
908 /*
909 * PC Arch.
910 */
911 rc = CFGMR3InsertNode(pDevices, "pcarch", &pDev);
912 UPDATERC();
913 rc = CFGMR3InsertNode(pDev, "0", &pInst);
914 UPDATERC();
915 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
916 UPDATERC();
917 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
918 UPDATERC();
919
920 /*
921 * PC Bios.
922 */
923 rc = CFGMR3InsertNode(pDevices, "pcbios", &pDev);
924 UPDATERC();
925 rc = CFGMR3InsertNode(pDev, "0", &pInst);
926 UPDATERC();
927 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
928 UPDATERC();
929 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
930 UPDATERC();
931 rc = CFGMR3InsertInteger(pCfg, "RamSize", 128U * _1M);
932 UPDATERC();
933 rc = CFGMR3InsertInteger(pCfg, "RamHoleSize", 512U * _1M);
934 UPDATERC();
935 rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
936 UPDATERC();
937 rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
938 UPDATERC();
939 rc = CFGMR3InsertString(pCfg, "BootDevice2", "NONE");
940 UPDATERC();
941 rc = CFGMR3InsertString(pCfg, "BootDevice3", "NONE");
942 UPDATERC();
943 rc = CFGMR3InsertString(pCfg, "HardDiskDevice", "piix3ide");
944 UPDATERC();
945 rc = CFGMR3InsertString(pCfg, "FloppyDevice", "");
946 UPDATERC();
947 RTUUID Uuid;
948 RTUuidClear(&Uuid);
949 rc = CFGMR3InsertBytes(pCfg, "UUID", &Uuid, sizeof(Uuid));
950 UPDATERC();
951
952 /*
953 * PCI bus.
954 */
955 rc = CFGMR3InsertNode(pDevices, "pci", &pDev); /* piix3 */
956 UPDATERC();
957 rc = CFGMR3InsertNode(pDev, "0", &pInst);
958 UPDATERC();
959 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
960 UPDATERC();
961 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
962 UPDATERC();
963
964 /*
965 * PS/2 keyboard & mouse
966 */
967 rc = CFGMR3InsertNode(pDevices, "pckbd", &pDev);
968 UPDATERC();
969 rc = CFGMR3InsertNode(pDev, "0", &pInst);
970 UPDATERC();
971 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
972 UPDATERC();
973#if 0
974 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
975 UPDATERC();
976 rc = CFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue");
977 UPDATERC();
978 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
979 UPDATERC();
980 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 64);
981 UPDATERC();
982 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
983 UPDATERC();
984 rc = CFGMR3InsertString(pLunL1, "Driver", "MainKeyboard");
985 UPDATERC();
986 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
987 UPDATERC();
988#endif
989#if 0
990 rc = CFGMR3InsertNode(pInst, "LUN#1", &pLunL0);
991 UPDATERC();
992 rc = CFGMR3InsertString(pLunL0, "Driver", "MouseQueue");
993 UPDATERC();
994 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
995 UPDATERC();
996 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 128);
997 UPDATERC();
998 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
999 UPDATERC();
1000 rc = CFGMR3InsertString(pLunL1, "Driver", "MainMouse");
1001 UPDATERC();
1002 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
1003 UPDATERC();
1004#endif
1005
1006 /*
1007 * i8254 Programmable Interval Timer And Dummy Speaker
1008 */
1009 rc = CFGMR3InsertNode(pDevices, "i8254", &pDev);
1010 UPDATERC();
1011 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1012 UPDATERC();
1013#ifdef DEBUG
1014 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1015 UPDATERC();
1016#endif
1017 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1018 UPDATERC();
1019
1020 /*
1021 * i8259 Programmable Interrupt Controller.
1022 */
1023 rc = CFGMR3InsertNode(pDevices, "i8259", &pDev);
1024 UPDATERC();
1025 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1026 UPDATERC();
1027 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1028 UPDATERC();
1029 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1030 UPDATERC();
1031
1032 /*
1033 * RTC MC146818.
1034 */
1035 rc = CFGMR3InsertNode(pDevices, "mc146818", &pDev);
1036 UPDATERC();
1037 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1038 UPDATERC();
1039 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1040 UPDATERC();
1041
1042 /*
1043 * VGA.
1044 */
1045 rc = CFGMR3InsertNode(pDevices, "vga", &pDev);
1046 UPDATERC();
1047 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1048 UPDATERC();
1049 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1050 UPDATERC();
1051 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1052 UPDATERC();
1053 rc = CFGMR3InsertInteger(pCfg, "VRamSize", 4 * _1M);
1054 UPDATERC();
1055
1056 /* Bios logo. */
1057 rc = CFGMR3InsertInteger(pCfg, "FadeIn", 1);
1058 UPDATERC();
1059 rc = CFGMR3InsertInteger(pCfg, "FadeOut", 1);
1060 UPDATERC();
1061 rc = CFGMR3InsertInteger(pCfg, "LogoTime", 0);
1062 UPDATERC();
1063 rc = CFGMR3InsertString(pCfg, "LogoFile", "");
1064 UPDATERC();
1065
1066#if 0
1067 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
1068 UPDATERC();
1069 rc = CFGMR3InsertString(pLunL0, "Driver", "MainDisplay");
1070 UPDATERC();
1071#endif
1072
1073 /*
1074 * IDE controller.
1075 */
1076 rc = CFGMR3InsertNode(pDevices, "piix3ide", &pDev); /* piix3 */
1077 UPDATERC();
1078 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1079 UPDATERC();
1080 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1081 UPDATERC();
1082 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1083 UPDATERC();
1084
1085
1086
1087 /*
1088 * ...
1089 */
1090
1091#undef UPDATERC
1092 return rcAll;
1093}
1094
1095
1096
1097
1098/**
1099 * Resolves a path reference to a child node.
1100 *
1101 * @returns VBox status code.
1102 * @param pNode Which node to search for pszName in.
1103 * @param pszPath Path to the child node.
1104 * @param ppChild Where to store the pointer to the child node.
1105 */
1106static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild)
1107{
1108 *ppChild = NULL;
1109 if (!pNode)
1110 return VERR_CFGM_NO_PARENT;
1111 PCFGMNODE pChild = NULL;
1112 for (;;)
1113 {
1114 /* skip leading slashes. */
1115 while (*pszPath == '/')
1116 pszPath++;
1117
1118 /* End of path? */
1119 if (!*pszPath)
1120 {
1121 if (!pChild)
1122 return VERR_CFGM_INVALID_CHILD_PATH;
1123 *ppChild = pChild;
1124 return VINF_SUCCESS;
1125 }
1126
1127 /* find end of component. */
1128 const char *pszNext = strchr(pszPath, '/');
1129 if (!pszNext)
1130 pszNext = strchr(pszPath, '\0');
1131 RTUINT cchName = pszNext - pszPath;
1132
1133 /* search child list. */
1134 pChild = pNode->pFirstChild;
1135 for ( ; pChild; pChild = pChild->pNext)
1136 if (pChild->cchName == cchName)
1137 {
1138 int iDiff = memcmp(pszPath, pChild->szName, cchName);
1139 if (iDiff <= 0)
1140 {
1141 if (iDiff != 0)
1142 pChild = NULL;
1143 break;
1144 }
1145 }
1146 if (!pChild)
1147 return VERR_CFGM_CHILD_NOT_FOUND;
1148
1149 /* next iteration */
1150 pNode = pChild;
1151 pszPath = pszNext;
1152 }
1153
1154 /* won't get here */
1155}
1156
1157
1158/**
1159 * Resolves a path reference to a child node.
1160 *
1161 * @returns VBox status code.
1162 * @param pNode Which node to search for pszName in.
1163 * @param pszName Name of a byte string value.
1164 * @param ppLeaf Where to store the pointer to the leaf node.
1165 */
1166static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1167{
1168 *ppLeaf = NULL;
1169 if (!pNode)
1170 return VERR_CFGM_NO_PARENT;
1171
1172 size_t cchName = strlen(pszName);
1173 PCFGMLEAF pLeaf = pNode->pFirstLeaf;
1174 while (pLeaf)
1175 {
1176 if (cchName == pLeaf->cchName)
1177 {
1178 int iDiff = memcmp(pszName, pLeaf->szName, cchName);
1179 if (iDiff <= 0)
1180 {
1181 if (iDiff != 0)
1182 break;
1183 *ppLeaf = pLeaf;
1184 return VINF_SUCCESS;
1185 }
1186 }
1187
1188 /* next */
1189 pLeaf = pLeaf->pNext;
1190 }
1191 return VERR_CFGM_VALUE_NOT_FOUND;
1192}
1193
1194
1195
1196/**
1197 * Creates a CFGM tree.
1198 *
1199 * This is intended for creating device/driver configs can be
1200 * passed around and later attached to the main tree in the
1201 * correct location.
1202 *
1203 * @returns Pointer to the root node, NULL on error (out of memory or invalid
1204 * VM handle).
1205 * @param pUVM The user mode VM handle.
1206 */
1207VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM)
1208{
1209 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1210 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1211
1212 PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAllocU(pUVM, MM_TAG_CFGM, sizeof(*pNew));
1213 if (pNew)
1214 {
1215 pNew->pPrev = NULL;
1216 pNew->pNext = NULL;
1217 pNew->pParent = NULL;
1218 pNew->pFirstChild = NULL;
1219 pNew->pFirstLeaf = NULL;
1220 pNew->pVM = pUVM->pVM;
1221 pNew->fRestrictedRoot = false;
1222 pNew->cchName = 0;
1223 pNew->szName[0] = 0;
1224 }
1225 return pNew;
1226}
1227
1228
1229/**
1230 * Duplicates a CFGM sub-tree or a full tree.
1231 *
1232 * @returns Pointer to the root node. NULL if we run out of memory or the
1233 * input parameter is NULL.
1234 * @param pRoot The root of the tree to duplicate.
1235 * @param ppCopy Where to return the root of the duplicate.
1236 */
1237VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy)
1238{
1239 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1240
1241 /*
1242 * Create a new tree.
1243 */
1244 PCFGMNODE pNewRoot = CFGMR3CreateTree(pRoot->pVM->pUVM);
1245 if (!pNewRoot)
1246 return VERR_NO_MEMORY;
1247
1248 /*
1249 * Duplicate the content.
1250 */
1251 int rc = VINF_SUCCESS;
1252 PCFGMNODE pSrcCur = pRoot;
1253 PCFGMNODE pDstCur = pNewRoot;
1254 for (;;)
1255 {
1256 if ( !pDstCur->pFirstChild
1257 && !pDstCur->pFirstLeaf)
1258 {
1259 /*
1260 * Values first.
1261 */
1262 /** @todo this isn't the most efficient way to do it. */
1263 for (PCFGMLEAF pLeaf = pSrcCur->pFirstLeaf; pLeaf && RT_SUCCESS(rc); pLeaf = pLeaf->pNext)
1264 rc = CFGMR3InsertValue(pDstCur, pLeaf);
1265
1266 /*
1267 * Insert immediate child nodes.
1268 */
1269 /** @todo this isn't the most efficient way to do it. */
1270 for (PCFGMNODE pChild = pSrcCur->pFirstChild; pChild && RT_SUCCESS(rc); pChild = pChild->pNext)
1271 rc = CFGMR3InsertNode(pDstCur, pChild->szName, NULL);
1272
1273 AssertLogRelRCBreak(rc);
1274 }
1275
1276 /*
1277 * Deep copy of the children.
1278 */
1279 if (pSrcCur->pFirstChild)
1280 {
1281 Assert(pDstCur->pFirstChild && !strcmp(pDstCur->pFirstChild->szName, pSrcCur->pFirstChild->szName));
1282 pSrcCur = pSrcCur->pFirstChild;
1283 pDstCur = pDstCur->pFirstChild;
1284 }
1285 /*
1286 * If it's the root node, we're done.
1287 */
1288 else if (pSrcCur == pRoot)
1289 break;
1290 else
1291 {
1292 /*
1293 * Upon reaching the end of a sibling list, we must ascend and
1294 * resume the sibiling walk on an previous level.
1295 */
1296 if (!pSrcCur->pNext)
1297 {
1298 do
1299 {
1300 pSrcCur = pSrcCur->pParent;
1301 pDstCur = pDstCur->pParent;
1302 } while (!pSrcCur->pNext && pSrcCur != pRoot);
1303 if (pSrcCur == pRoot)
1304 break;
1305 }
1306
1307 /*
1308 * Next sibling.
1309 */
1310 Assert(pDstCur->pNext && !strcmp(pDstCur->pNext->szName, pSrcCur->pNext->szName));
1311 pSrcCur = pSrcCur->pNext;
1312 pDstCur = pDstCur->pNext;
1313 }
1314 }
1315
1316 if (RT_FAILURE(rc))
1317 {
1318 CFGMR3RemoveNode(pNewRoot);
1319 return rc;
1320 }
1321
1322 *ppCopy = pNewRoot;
1323 return VINF_SUCCESS;
1324}
1325
1326
1327/**
1328 * Insert subtree.
1329 *
1330 * This function inserts (no duplication) a tree created by CFGMR3CreateTree()
1331 * into the main tree.
1332 *
1333 * The root node of the inserted subtree will need to be reallocated, which
1334 * effectually means that the passed in pSubTree handle becomes invalid
1335 * upon successful return. Use the value returned in ppChild instead
1336 * of pSubTree.
1337 *
1338 * @returns VBox status code.
1339 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1340 * @param pNode Parent node.
1341 * @param pszName Name or path of the new child node.
1342 * @param pSubTree The subtree to insert. Must be returned by CFGMR3CreateTree().
1343 * @param ppChild Where to store the address of the new child node. (optional)
1344 */
1345VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild)
1346{
1347 /*
1348 * Validate input.
1349 */
1350 AssertPtrReturn(pNode, VERR_INVALID_POINTER);
1351 AssertPtrReturn(pSubTree, VERR_INVALID_POINTER);
1352 AssertReturn(pNode != pSubTree, VERR_INVALID_PARAMETER);
1353 AssertReturn(!pSubTree->pParent, VERR_INVALID_PARAMETER);
1354 AssertReturn(pSubTree->pVM, VERR_INVALID_PARAMETER);
1355 Assert(!pSubTree->pNext);
1356 Assert(!pSubTree->pPrev);
1357
1358 /*
1359 * Use CFGMR3InsertNode to create a new node and then
1360 * re-attach the children and leafs of the subtree to it.
1361 */
1362 PCFGMNODE pNewChild;
1363 int rc = CFGMR3InsertNode(pNode, pszName, &pNewChild);
1364 if (RT_SUCCESS(rc))
1365 {
1366 Assert(!pNewChild->pFirstChild);
1367 Assert(!pNewChild->pFirstLeaf);
1368
1369 pNewChild->pFirstChild = pSubTree->pFirstChild;
1370 pNewChild->pFirstLeaf = pSubTree->pFirstLeaf;
1371 for (PCFGMNODE pChild = pNewChild->pFirstChild; pChild; pChild = pChild->pNext)
1372 pChild->pParent = pNewChild;
1373
1374 if (ppChild)
1375 *ppChild = pNewChild;
1376
1377 /* free the old subtree root */
1378 pSubTree->pVM = NULL;
1379 pSubTree->pFirstLeaf = NULL;
1380 pSubTree->pFirstChild = NULL;
1381 MMR3HeapFree(pSubTree);
1382 }
1383 return rc;
1384}
1385
1386
1387/**
1388 * Replaces a (sub-)tree with new one.
1389 *
1390 * This function removes the exiting (sub-)tree, completely freeing it in the
1391 * process, and inserts (no duplication) the specified tree. The tree can
1392 * either be created by CFGMR3CreateTree or CFGMR3DuplicateSubTree.
1393 *
1394 * @returns VBox status code.
1395 * @param pRoot The sub-tree to replace. This node will remain valid
1396 * after the call.
1397 * @param pNewRoot The tree to replace @a pRoot with. This not will
1398 * become invalid after a successful call.
1399 */
1400VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot)
1401{
1402 /*
1403 * Validate input.
1404 */
1405 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1406 AssertPtrReturn(pNewRoot, VERR_INVALID_POINTER);
1407 AssertReturn(pRoot != pNewRoot, VERR_INVALID_PARAMETER);
1408 AssertReturn(!pNewRoot->pParent, VERR_INVALID_PARAMETER);
1409 AssertReturn(pNewRoot->pVM, VERR_INVALID_PARAMETER);
1410 AssertReturn(pNewRoot->pVM == pRoot->pVM, VERR_INVALID_PARAMETER);
1411 AssertReturn(!pNewRoot->pNext, VERR_INVALID_PARAMETER);
1412 AssertReturn(!pNewRoot->pPrev, VERR_INVALID_PARAMETER);
1413
1414 /*
1415 * Free the current properties fo pRoot.
1416 */
1417 while (pRoot->pFirstChild)
1418 CFGMR3RemoveNode(pRoot->pFirstChild);
1419
1420 while (pRoot->pFirstLeaf)
1421 cfgmR3RemoveLeaf(pRoot, pRoot->pFirstLeaf);
1422
1423 /*
1424 * Copy all the properties from the new root to the current one.
1425 */
1426 pRoot->pFirstLeaf = pNewRoot->pFirstLeaf;
1427 pRoot->pFirstChild = pNewRoot->pFirstChild;
1428 for (PCFGMNODE pChild = pRoot->pFirstChild; pChild; pChild = pChild->pNext)
1429 pChild->pParent = pRoot;
1430
1431 pNewRoot->pFirstLeaf = NULL;
1432 pNewRoot->pFirstChild = NULL;
1433 pNewRoot->pVM = NULL;
1434 MMR3HeapFree(pNewRoot);
1435
1436 return VINF_SUCCESS;
1437}
1438
1439
1440/**
1441 * Copies all values and keys from one tree onto another.
1442 *
1443 * The flags control what happens to keys and values with the same name
1444 * existing in both source and destination.
1445 *
1446 * @returns VBox status code.
1447 * @param pDstTree The destination tree.
1448 * @param pSrcTree The source tree.
1449 * @param fFlags Copy flags, see CFGM_COPY_FLAGS_XXX.
1450 */
1451VMMR3DECL(int) CFGMR3CopyTree(PCFGMNODE pDstTree, PCFGMNODE pSrcTree, uint32_t fFlags)
1452{
1453 /*
1454 * Input validation.
1455 */
1456 AssertPtrReturn(pSrcTree, VERR_INVALID_POINTER);
1457 AssertPtrReturn(pDstTree, VERR_INVALID_POINTER);
1458 AssertReturn(pDstTree != pSrcTree, VERR_INVALID_PARAMETER);
1459 AssertReturn(!(fFlags & ~(CFGM_COPY_FLAGS_VALUE_DISP_MASK | CFGM_COPY_FLAGS_KEY_DISP_MASK)), VERR_INVALID_PARAMETER);
1460 AssertReturn( (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_0
1461 && (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_1,
1462 VERR_INVALID_PARAMETER);
1463 AssertReturn((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_KEY_DISP,
1464 VERR_INVALID_PARAMETER);
1465
1466 /*
1467 * Copy the values.
1468 */
1469 int rc;
1470 for (PCFGMLEAF pValue = CFGMR3GetFirstValue(pSrcTree); pValue; pValue = CFGMR3GetNextValue(pValue))
1471 {
1472 rc = CFGMR3InsertValue(pDstTree, pValue);
1473 if (rc == VERR_CFGM_LEAF_EXISTS)
1474 {
1475 if ((fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_VALUES)
1476 {
1477 rc = CFGMR3RemoveValue(pDstTree, pValue->szName);
1478 if (RT_FAILURE(rc))
1479 break;
1480 rc = CFGMR3InsertValue(pDstTree, pValue);
1481 }
1482 else
1483 rc = VINF_SUCCESS;
1484 }
1485 AssertRCReturn(rc, rc);
1486 }
1487
1488 /*
1489 * Copy/merge the keys - merging results in recursion.
1490 */
1491 for (PCFGMNODE pSrcChild = CFGMR3GetFirstChild(pSrcTree); pSrcChild; pSrcChild = CFGMR3GetNextChild(pSrcChild))
1492 {
1493 PCFGMNODE pDstChild = CFGMR3GetChild(pDstTree, pSrcChild->szName);
1494 if ( pDstChild
1495 && (fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_KEYS)
1496 {
1497 CFGMR3RemoveNode(pDstChild);
1498 pDstChild = NULL;
1499 }
1500 if (!pDstChild)
1501 {
1502 PCFGMNODE pChildCopy;
1503 rc = CFGMR3DuplicateSubTree(pSrcChild, &pChildCopy);
1504 AssertRCReturn(rc, rc);
1505 rc = CFGMR3InsertSubTree(pDstTree, pSrcChild->szName, pChildCopy, NULL);
1506 AssertRCReturnStmt(rc, CFGMR3RemoveNode(pChildCopy), rc);
1507 }
1508 else if ((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_MERGE_KEYS)
1509 {
1510 rc = CFGMR3CopyTree(pDstChild, pSrcChild, fFlags);
1511 AssertRCReturn(rc, rc);
1512 }
1513 }
1514
1515 return VINF_SUCCESS;
1516}
1517
1518
1519
1520/**
1521 * Compares two names.
1522 *
1523 * @returns Similar to memcpy.
1524 * @param pszName1 The first name.
1525 * @param cchName1 The length of the first name.
1526 * @param pszName2 The second name.
1527 * @param cchName2 The length of the second name.
1528 */
1529DECLINLINE(int) cfgmR3CompareNames(const char *pszName1, size_t cchName1, const char *pszName2, size_t cchName2)
1530{
1531 int iDiff;
1532 if (cchName1 <= cchName2)
1533 {
1534 iDiff = memcmp(pszName1, pszName2, cchName1);
1535 if (!iDiff && cchName1 < cchName2)
1536 iDiff = -1;
1537 }
1538 else
1539 {
1540 iDiff = memcmp(pszName1, pszName2, cchName2);
1541 if (!iDiff)
1542 iDiff = 1;
1543 }
1544 return iDiff;
1545}
1546
1547
1548/**
1549 * Insert a node.
1550 *
1551 * @returns VBox status code.
1552 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1553 * @param pNode Parent node.
1554 * @param pszName Name or path of the new child node.
1555 * @param ppChild Where to store the address of the new child node. (optional)
1556 */
1557VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
1558{
1559 int rc;
1560 if (pNode)
1561 {
1562 /*
1563 * If given a path we have to deal with it component by component.
1564 */
1565 while (*pszName == '/')
1566 pszName++;
1567 if (strchr(pszName, '/'))
1568 {
1569 char *pszDup = RTStrDup(pszName);
1570 if (pszDup)
1571 {
1572 char *psz = pszDup;
1573 for (;;)
1574 {
1575 /* Terminate at '/' and find the next component. */
1576 char *pszNext = strchr(psz, '/');
1577 if (pszNext)
1578 {
1579 *pszNext++ = '\0';
1580 while (*pszNext == '/')
1581 pszNext++;
1582 if (*pszNext == '\0')
1583 pszNext = NULL;
1584 }
1585
1586 /* does it exist? */
1587 PCFGMNODE pChild = CFGMR3GetChild(pNode, psz);
1588 if (!pChild)
1589 {
1590 /* no, insert it */
1591 rc = CFGMR3InsertNode(pNode, psz, &pChild);
1592 if (RT_FAILURE(rc))
1593 break;
1594 if (!pszNext)
1595 {
1596 if (ppChild)
1597 *ppChild = pChild;
1598 break;
1599 }
1600
1601 }
1602 /* if last component fail */
1603 else if (!pszNext)
1604 {
1605 rc = VERR_CFGM_NODE_EXISTS;
1606 break;
1607 }
1608
1609 /* next */
1610 pNode = pChild;
1611 psz = pszNext;
1612 }
1613 RTStrFree(pszDup);
1614 }
1615 else
1616 rc = VERR_NO_TMP_MEMORY;
1617 }
1618 /*
1619 * Not multicomponent, just make sure it's a non-zero name.
1620 */
1621 else if (*pszName)
1622 {
1623 /*
1624 * Check if already exists and find last node in chain.
1625 */
1626 size_t cchName = strlen(pszName);
1627 PCFGMNODE pPrev = NULL;
1628 PCFGMNODE pNext = pNode->pFirstChild;
1629 if (pNext)
1630 {
1631 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1632 {
1633 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
1634 if (iDiff <= 0)
1635 {
1636 if (!iDiff)
1637 return VERR_CFGM_NODE_EXISTS;
1638 break;
1639 }
1640 }
1641 }
1642
1643 /*
1644 * Allocate and init node.
1645 */
1646 PCFGMNODE pNew = (PCFGMNODE)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1647 if (pNew)
1648 {
1649 pNew->pParent = pNode;
1650 pNew->pFirstChild = NULL;
1651 pNew->pFirstLeaf = NULL;
1652 pNew->pVM = pNode->pVM;
1653 pNew->fRestrictedRoot = false;
1654 pNew->cchName = cchName;
1655 memcpy(pNew->szName, pszName, cchName + 1);
1656
1657 /*
1658 * Insert into child list.
1659 */
1660 pNew->pPrev = pPrev;
1661 if (pPrev)
1662 pPrev->pNext = pNew;
1663 else
1664 pNode->pFirstChild = pNew;
1665 pNew->pNext = pNext;
1666 if (pNext)
1667 pNext->pPrev = pNew;
1668
1669 if (ppChild)
1670 *ppChild = pNew;
1671 rc = VINF_SUCCESS;
1672 }
1673 else
1674 rc = VERR_NO_MEMORY;
1675 }
1676 else
1677 {
1678 rc = VERR_CFGM_INVALID_NODE_PATH;
1679 AssertMsgFailed(("Invalid path %s\n", pszName));
1680 }
1681 }
1682 else
1683 {
1684 rc = VERR_CFGM_NO_PARENT;
1685 AssertMsgFailed(("No parent! path %s\n", pszName));
1686 }
1687
1688 return rc;
1689}
1690
1691
1692/**
1693 * Insert a node, format string name.
1694 *
1695 * @returns VBox status code.
1696 * @param pNode Parent node.
1697 * @param ppChild Where to store the address of the new child node. (optional)
1698 * @param pszNameFormat Name of or path the new child node.
1699 * @param ... Name format arguments.
1700 */
1701VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
1702{
1703 va_list Args;
1704 va_start(Args, pszNameFormat);
1705 int rc = CFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
1706 va_end(Args);
1707 return rc;
1708}
1709
1710
1711/**
1712 * Insert a node, format string name.
1713 *
1714 * @returns VBox status code.
1715 * @param pNode Parent node.
1716 * @param ppChild Where to store the address of the new child node. (optional)
1717 * @param pszNameFormat Name or path of the new child node.
1718 * @param Args Name format arguments.
1719 */
1720VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args)
1721{
1722 int rc;
1723 char *pszName;
1724 RTStrAPrintfV(&pszName, pszNameFormat, Args);
1725 if (pszName)
1726 {
1727 rc = CFGMR3InsertNode(pNode, pszName, ppChild);
1728 RTStrFree(pszName);
1729 }
1730 else
1731 rc = VERR_NO_MEMORY;
1732 return rc;
1733}
1734
1735
1736/**
1737 * Marks the node as the root of a restricted subtree, i.e. the end of
1738 * a CFGMR3GetParent() journey.
1739 *
1740 * @param pNode The node to mark.
1741 */
1742VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode)
1743{
1744 if (pNode)
1745 pNode->fRestrictedRoot = true;
1746}
1747
1748
1749/**
1750 * Insert a node.
1751 *
1752 * @returns VBox status code.
1753 * @param pNode Parent node.
1754 * @param pszName Name of the new child node.
1755 * @param ppLeaf Where to store the new leaf.
1756 * The caller must fill in the enmType and Value fields!
1757 */
1758static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1759{
1760 int rc;
1761 if (*pszName)
1762 {
1763 if (pNode)
1764 {
1765 /*
1766 * Check if already exists and find last node in chain.
1767 */
1768 size_t cchName = strlen(pszName);
1769 PCFGMLEAF pPrev = NULL;
1770 PCFGMLEAF pNext = pNode->pFirstLeaf;
1771 if (pNext)
1772 {
1773 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1774 {
1775 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
1776 if (iDiff <= 0)
1777 {
1778 if (!iDiff)
1779 return VERR_CFGM_LEAF_EXISTS;
1780 break;
1781 }
1782 }
1783 }
1784
1785 /*
1786 * Allocate and init node.
1787 */
1788 PCFGMLEAF pNew = (PCFGMLEAF)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1789 if (pNew)
1790 {
1791 pNew->cchName = cchName;
1792 memcpy(pNew->szName, pszName, cchName + 1);
1793
1794 /*
1795 * Insert into child list.
1796 */
1797 pNew->pPrev = pPrev;
1798 if (pPrev)
1799 pPrev->pNext = pNew;
1800 else
1801 pNode->pFirstLeaf = pNew;
1802 pNew->pNext = pNext;
1803 if (pNext)
1804 pNext->pPrev = pNew;
1805
1806 *ppLeaf = pNew;
1807 rc = VINF_SUCCESS;
1808 }
1809 else
1810 rc = VERR_NO_MEMORY;
1811 }
1812 else
1813 rc = VERR_CFGM_NO_PARENT;
1814 }
1815 else
1816 rc = VERR_CFGM_INVALID_CHILD_PATH;
1817 return rc;
1818}
1819
1820
1821/**
1822 * Remove a node.
1823 *
1824 * @param pNode Parent node.
1825 */
1826VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
1827{
1828 if (pNode)
1829 {
1830 /*
1831 * Free children.
1832 */
1833 while (pNode->pFirstChild)
1834 CFGMR3RemoveNode(pNode->pFirstChild);
1835
1836 /*
1837 * Free leafs.
1838 */
1839 while (pNode->pFirstLeaf)
1840 cfgmR3RemoveLeaf(pNode, pNode->pFirstLeaf);
1841
1842 /*
1843 * Unlink ourselves.
1844 */
1845 if (pNode->pPrev)
1846 pNode->pPrev->pNext = pNode->pNext;
1847 else
1848 {
1849 if (pNode->pParent)
1850 pNode->pParent->pFirstChild = pNode->pNext;
1851 else if (pNode == pNode->pVM->cfgm.s.pRoot) /* might be a different tree */
1852 pNode->pVM->cfgm.s.pRoot = NULL;
1853 }
1854 if (pNode->pNext)
1855 pNode->pNext->pPrev = pNode->pPrev;
1856
1857 /*
1858 * Free ourselves. (bit of paranoia first)
1859 */
1860 pNode->pVM = NULL;
1861 pNode->pNext = NULL;
1862 pNode->pPrev = NULL;
1863 pNode->pParent = NULL;
1864 MMR3HeapFree(pNode);
1865 }
1866}
1867
1868
1869/**
1870 * Removes a leaf.
1871 *
1872 * @param pNode Parent node.
1873 * @param pLeaf Leaf to remove.
1874 */
1875static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
1876{
1877 if (pNode && pLeaf)
1878 {
1879 /*
1880 * Unlink.
1881 */
1882 if (pLeaf->pPrev)
1883 pLeaf->pPrev->pNext = pLeaf->pNext;
1884 else
1885 pNode->pFirstLeaf = pLeaf->pNext;
1886 if (pLeaf->pNext)
1887 pLeaf->pNext->pPrev = pLeaf->pPrev;
1888
1889 /*
1890 * Free value and node.
1891 */
1892 cfgmR3FreeValue(pLeaf);
1893 pLeaf->pNext = NULL;
1894 pLeaf->pPrev = NULL;
1895 MMR3HeapFree(pLeaf);
1896 }
1897}
1898
1899
1900/**
1901 * Frees whatever resources the leaf value is owning.
1902 *
1903 * Use this before assigning a new value to a leaf.
1904 * The caller must either free the leaf or assign a new value to it.
1905 *
1906 * @param pLeaf Pointer to the leaf which value should be free.
1907 */
1908static void cfgmR3FreeValue(PCFGMLEAF pLeaf)
1909{
1910 if (pLeaf)
1911 {
1912 switch (pLeaf->enmType)
1913 {
1914 case CFGMVALUETYPE_BYTES:
1915 MMR3HeapFree(pLeaf->Value.Bytes.pau8);
1916 pLeaf->Value.Bytes.pau8 = NULL;
1917 pLeaf->Value.Bytes.cb = 0;
1918 break;
1919
1920 case CFGMVALUETYPE_STRING:
1921 MMR3HeapFree(pLeaf->Value.String.psz);
1922 pLeaf->Value.String.psz = NULL;
1923 pLeaf->Value.String.cb = 0;
1924 break;
1925
1926 case CFGMVALUETYPE_INTEGER:
1927 break;
1928 }
1929 pLeaf->enmType = (CFGMVALUETYPE)0;
1930 }
1931}
1932
1933
1934/**
1935 * Inserts a new integer value.
1936 *
1937 * @returns VBox status code.
1938 * @param pNode Parent node.
1939 * @param pszName Value name.
1940 * @param u64Integer The value.
1941 */
1942VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
1943{
1944 PCFGMLEAF pLeaf;
1945 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1946 if (RT_SUCCESS(rc))
1947 {
1948 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
1949 pLeaf->Value.Integer.u64 = u64Integer;
1950 }
1951 return rc;
1952}
1953
1954
1955/**
1956 * Inserts a new string value. This variant expects that the caller know the length
1957 * of the string already so we can avoid calling strlen() here.
1958 *
1959 * @returns VBox status code.
1960 * @param pNode Parent node.
1961 * @param pszName Value name.
1962 * @param pszString The value. Must not be NULL.
1963 * @param cchString The length of the string excluding the
1964 * terminator.
1965 */
1966VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString)
1967{
1968 Assert(RTStrNLen(pszString, cchString) == cchString);
1969
1970 int rc;
1971 if (pNode)
1972 {
1973 /*
1974 * Allocate string object first.
1975 */
1976 char *pszStringCopy = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cchString + 1);
1977 if (pszStringCopy)
1978 {
1979 memcpy(pszStringCopy, pszString, cchString);
1980 pszStringCopy[cchString] = '\0';
1981
1982 /*
1983 * Create value leaf and set it to string type.
1984 */
1985 PCFGMLEAF pLeaf;
1986 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
1987 if (RT_SUCCESS(rc))
1988 {
1989 pLeaf->enmType = CFGMVALUETYPE_STRING;
1990 pLeaf->Value.String.psz = pszStringCopy;
1991 pLeaf->Value.String.cb = cchString + 1;
1992 }
1993 else
1994 MMR3HeapFree(pszStringCopy);
1995 }
1996 else
1997 rc = VERR_NO_MEMORY;
1998 }
1999 else
2000 rc = VERR_CFGM_NO_PARENT;
2001
2002 return rc;
2003}
2004
2005
2006/**
2007 * Inserts a new string value. Calls strlen(pszString) internally; if you know the
2008 * length of the string, CFGMR3InsertStringLengthKnown() is faster.
2009 *
2010 * @returns VBox status code.
2011 * @param pNode Parent node.
2012 * @param pszName Value name.
2013 * @param pszString The value.
2014 */
2015VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
2016{
2017 return CFGMR3InsertStringN(pNode, pszName, pszString, strlen(pszString));
2018}
2019
2020
2021/**
2022 * Same as CFGMR3InsertString except the string value given in RTStrPrintfV
2023 * fashion.
2024 *
2025 * @returns VBox status code.
2026 * @param pNode Parent node.
2027 * @param pszName Value name.
2028 * @param pszFormat The value given as a format string.
2029 * @param va Argument to pszFormat.
2030 */
2031VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const char *pszFormat, va_list va)
2032{
2033 int rc;
2034 if (pNode)
2035 {
2036 /*
2037 * Allocate string object first.
2038 */
2039 char *pszString = MMR3HeapAPrintfVU(pNode->pVM->pUVM, MM_TAG_CFGM_STRING, pszFormat, va);
2040 if (pszString)
2041 {
2042 /*
2043 * Create value leaf and set it to string type.
2044 */
2045 PCFGMLEAF pLeaf;
2046 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2047 if (RT_SUCCESS(rc))
2048 {
2049 pLeaf->enmType = CFGMVALUETYPE_STRING;
2050 pLeaf->Value.String.psz = pszString;
2051 pLeaf->Value.String.cb = strlen(pszString) + 1;
2052 }
2053 else
2054 MMR3HeapFree(pszString);
2055 }
2056 else
2057 rc = VERR_NO_MEMORY;
2058 }
2059 else
2060 rc = VERR_CFGM_NO_PARENT;
2061
2062 return rc;
2063}
2064
2065
2066/**
2067 * Same as CFGMR3InsertString except the string value given in RTStrPrintf
2068 * fashion.
2069 *
2070 * @returns VBox status code.
2071 * @param pNode Parent node.
2072 * @param pszName Value name.
2073 * @param pszFormat The value given as a format string.
2074 * @param ... Argument to pszFormat.
2075 */
2076VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, const char *pszFormat, ...)
2077{
2078 va_list va;
2079 va_start(va, pszFormat);
2080 int rc = CFGMR3InsertStringFV(pNode, pszName, pszFormat, va);
2081 va_end(va);
2082 return rc;
2083}
2084
2085
2086/**
2087 * Same as CFGMR3InsertString except the string value given as a UTF-16 string.
2088 *
2089 * @returns VBox status code.
2090 * @param pNode Parent node.
2091 * @param pszName Value name.
2092 * @param pwszValue The string value (UTF-16).
2093 */
2094VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue)
2095{
2096 char *pszValue;
2097 int rc = RTUtf16ToUtf8(pwszValue, &pszValue);
2098 if (RT_SUCCESS(rc))
2099 {
2100 rc = CFGMR3InsertString(pNode, pszName, pszValue);
2101 RTStrFree(pszValue);
2102 }
2103 return rc;
2104}
2105
2106
2107/**
2108 * Inserts a new integer value.
2109 *
2110 * @returns VBox status code.
2111 * @param pNode Parent node.
2112 * @param pszName Value name.
2113 * @param pvBytes The value.
2114 * @param cbBytes The value size.
2115 */
2116VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes)
2117{
2118 int rc;
2119 if (pNode)
2120 {
2121 if (cbBytes == (RTUINT)cbBytes)
2122 {
2123 /*
2124 * Allocate string object first.
2125 */
2126 void *pvCopy = MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cbBytes);
2127 if (pvCopy || !cbBytes)
2128 {
2129 memcpy(pvCopy, pvBytes, cbBytes);
2130
2131 /*
2132 * Create value leaf and set it to string type.
2133 */
2134 PCFGMLEAF pLeaf;
2135 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2136 if (RT_SUCCESS(rc))
2137 {
2138 pLeaf->enmType = CFGMVALUETYPE_BYTES;
2139 pLeaf->Value.Bytes.cb = cbBytes;
2140 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
2141 }
2142 }
2143 else
2144 rc = VERR_NO_MEMORY;
2145 }
2146 else
2147 rc = VERR_OUT_OF_RANGE;
2148 }
2149 else
2150 rc = VERR_CFGM_NO_PARENT;
2151
2152 return rc;
2153}
2154
2155
2156/**
2157 * Make a copy of the specified value under the given node.
2158 *
2159 * @returns VBox status code.
2160 * @param pNode Parent node.
2161 * @param pValue The value to copy and insert.
2162 */
2163VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue)
2164{
2165 int rc;
2166 switch (pValue->enmType)
2167 {
2168 case CFGMVALUETYPE_INTEGER:
2169 rc = CFGMR3InsertInteger(pNode, pValue->szName, pValue->Value.Integer.u64);
2170 break;
2171
2172 case CFGMVALUETYPE_BYTES:
2173 rc = CFGMR3InsertBytes(pNode, pValue->szName, pValue->Value.Bytes.pau8, pValue->Value.Bytes.cb);
2174 break;
2175
2176 case CFGMVALUETYPE_STRING:
2177 rc = CFGMR3InsertStringN(pNode, pValue->szName, pValue->Value.String.psz, pValue->Value.String.cb - 1);
2178 break;
2179
2180 default:
2181 rc = VERR_CFGM_IPE_1;
2182 AssertMsgFailed(("Invalid value type %d\n", pValue->enmType));
2183 break;
2184 }
2185 return rc;
2186}
2187
2188
2189/**
2190 * Remove a value.
2191 *
2192 * @returns VBox status code.
2193 * @param pNode Parent node.
2194 * @param pszName Name of the new child node.
2195 */
2196VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
2197{
2198 PCFGMLEAF pLeaf;
2199 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
2200 if (RT_SUCCESS(rc))
2201 cfgmR3RemoveLeaf(pNode, pLeaf);
2202 return rc;
2203}
2204
2205
2206
2207/*
2208 * -+- helper apis -+-
2209 */
2210
2211
2212/**
2213 * Query unsigned 64-bit integer value.
2214 *
2215 * @returns VBox status code.
2216 * @param pNode Which node to search for pszName in.
2217 * @param pszName Name of an integer value.
2218 * @param pu64 Where to store the integer value.
2219 */
2220VMMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
2221{
2222 return CFGMR3QueryInteger(pNode, pszName, pu64);
2223}
2224
2225
2226/**
2227 * Query unsigned 64-bit integer value with default.
2228 *
2229 * @returns VBox status code.
2230 * @param pNode Which node to search for pszName in.
2231 * @param pszName Name of an integer value.
2232 * @param pu64 Where to store the integer value. Set to default on failure.
2233 * @param u64Def The default value.
2234 */
2235VMMR3DECL(int) CFGMR3QueryU64Def(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
2236{
2237 return CFGMR3QueryIntegerDef(pNode, pszName, pu64, u64Def);
2238}
2239
2240
2241/**
2242 * Query signed 64-bit integer value.
2243 *
2244 * @returns VBox status code.
2245 * @param pNode Which node to search for pszName in.
2246 * @param pszName Name of an integer value.
2247 * @param pi64 Where to store the value.
2248 */
2249VMMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
2250{
2251 uint64_t u64;
2252 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2253 if (RT_SUCCESS(rc))
2254 *pi64 = (int64_t)u64;
2255 return rc;
2256}
2257
2258
2259/**
2260 * Query signed 64-bit integer value with default.
2261 *
2262 * @returns VBox status code.
2263 * @param pNode Which node to search for pszName in.
2264 * @param pszName Name of an integer value.
2265 * @param pi64 Where to store the value. Set to default on failure.
2266 * @param i64Def The default value.
2267 */
2268VMMR3DECL(int) CFGMR3QueryS64Def(PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)
2269{
2270 uint64_t u64;
2271 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i64Def);
2272 *pi64 = (int64_t)u64;
2273 return rc;
2274}
2275
2276
2277/**
2278 * Query unsigned 32-bit integer value.
2279 *
2280 * @returns VBox status code.
2281 * @param pNode Which node to search for pszName in.
2282 * @param pszName Name of an integer value.
2283 * @param pu32 Where to store the value.
2284 */
2285VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
2286{
2287 uint64_t u64;
2288 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2289 if (RT_SUCCESS(rc))
2290 {
2291 if (!(u64 & UINT64_C(0xffffffff00000000)))
2292 *pu32 = (uint32_t)u64;
2293 else
2294 rc = VERR_CFGM_INTEGER_TOO_BIG;
2295 }
2296 return rc;
2297}
2298
2299
2300/**
2301 * Query unsigned 32-bit integer value with default.
2302 *
2303 * @returns VBox status code.
2304 * @param pNode Which node to search for pszName in.
2305 * @param pszName Name of an integer value.
2306 * @param pu32 Where to store the value. Set to default on failure.
2307 * @param u32Def The default value.
2308 */
2309VMMR3DECL(int) CFGMR3QueryU32Def(PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)
2310{
2311 uint64_t u64;
2312 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u32Def);
2313 if (RT_SUCCESS(rc))
2314 {
2315 if (!(u64 & UINT64_C(0xffffffff00000000)))
2316 *pu32 = (uint32_t)u64;
2317 else
2318 rc = VERR_CFGM_INTEGER_TOO_BIG;
2319 }
2320 if (RT_FAILURE(rc))
2321 *pu32 = u32Def;
2322 return rc;
2323}
2324
2325
2326/**
2327 * Query signed 32-bit integer value.
2328 *
2329 * @returns VBox status code.
2330 * @param pNode Which node to search for pszName in.
2331 * @param pszName Name of an integer value.
2332 * @param pi32 Where to store the value.
2333 */
2334VMMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
2335{
2336 uint64_t u64;
2337 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2338 if (RT_SUCCESS(rc))
2339 {
2340 if ( !(u64 & UINT64_C(0xffffffff80000000))
2341 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2342 *pi32 = (int32_t)u64;
2343 else
2344 rc = VERR_CFGM_INTEGER_TOO_BIG;
2345 }
2346 return rc;
2347}
2348
2349
2350/**
2351 * Query signed 32-bit integer value with default.
2352 *
2353 * @returns VBox status code.
2354 * @param pNode Which node to search for pszName in.
2355 * @param pszName Name of an integer value.
2356 * @param pi32 Where to store the value. Set to default on failure.
2357 * @param i32Def The default value.
2358 */
2359VMMR3DECL(int) CFGMR3QueryS32Def(PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)
2360{
2361 uint64_t u64;
2362 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i32Def);
2363 if (RT_SUCCESS(rc))
2364 {
2365 if ( !(u64 & UINT64_C(0xffffffff80000000))
2366 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2367 *pi32 = (int32_t)u64;
2368 else
2369 rc = VERR_CFGM_INTEGER_TOO_BIG;
2370 }
2371 if (RT_FAILURE(rc))
2372 *pi32 = i32Def;
2373 return rc;
2374}
2375
2376
2377/**
2378 * Query unsigned 16-bit integer value.
2379 *
2380 * @returns VBox status code.
2381 * @param pNode Which node to search for pszName in.
2382 * @param pszName Name of an integer value.
2383 * @param pu16 Where to store the value.
2384 */
2385VMMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
2386{
2387 uint64_t u64;
2388 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2389 if (RT_SUCCESS(rc))
2390 {
2391 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2392 *pu16 = (int16_t)u64;
2393 else
2394 rc = VERR_CFGM_INTEGER_TOO_BIG;
2395 }
2396 return rc;
2397}
2398
2399
2400/**
2401 * Query unsigned 16-bit integer value with default.
2402 *
2403 * @returns VBox status code.
2404 * @param pNode Which node to search for pszName in.
2405 * @param pszName Name of an integer value.
2406 * @param pu16 Where to store the value. Set to default on failure.
2407 * @param i16Def The default value.
2408 */
2409VMMR3DECL(int) CFGMR3QueryU16Def(PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)
2410{
2411 uint64_t u64;
2412 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u16Def);
2413 if (RT_SUCCESS(rc))
2414 {
2415 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2416 *pu16 = (int16_t)u64;
2417 else
2418 rc = VERR_CFGM_INTEGER_TOO_BIG;
2419 }
2420 if (RT_FAILURE(rc))
2421 *pu16 = u16Def;
2422 return rc;
2423}
2424
2425
2426/**
2427 * Query signed 16-bit integer value.
2428 *
2429 * @returns VBox status code.
2430 * @param pNode Which node to search for pszName in.
2431 * @param pszName Name of an integer value.
2432 * @param pi16 Where to store the value.
2433 */
2434VMMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
2435{
2436 uint64_t u64;
2437 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2438 if (RT_SUCCESS(rc))
2439 {
2440 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2441 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2442 *pi16 = (int16_t)u64;
2443 else
2444 rc = VERR_CFGM_INTEGER_TOO_BIG;
2445 }
2446 return rc;
2447}
2448
2449
2450/**
2451 * Query signed 16-bit integer value with default.
2452 *
2453 * @returns VBox status code.
2454 * @param pNode Which node to search for pszName in.
2455 * @param pszName Name of an integer value.
2456 * @param pi16 Where to store the value. Set to default on failure.
2457 * @param i16Def The default value.
2458 */
2459VMMR3DECL(int) CFGMR3QueryS16Def(PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)
2460{
2461 uint64_t u64;
2462 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i16Def);
2463 if (RT_SUCCESS(rc))
2464 {
2465 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2466 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2467 *pi16 = (int16_t)u64;
2468 else
2469 rc = VERR_CFGM_INTEGER_TOO_BIG;
2470 }
2471 if (RT_FAILURE(rc))
2472 *pi16 = i16Def;
2473 return rc;
2474}
2475
2476
2477/**
2478 * Query unsigned 8-bit integer value.
2479 *
2480 * @returns VBox status code.
2481 * @param pNode Which node to search for pszName in.
2482 * @param pszName Name of an integer value.
2483 * @param pu8 Where to store the value.
2484 */
2485VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
2486{
2487 uint64_t u64;
2488 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2489 if (RT_SUCCESS(rc))
2490 {
2491 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2492 *pu8 = (uint8_t)u64;
2493 else
2494 rc = VERR_CFGM_INTEGER_TOO_BIG;
2495 }
2496 return rc;
2497}
2498
2499
2500/**
2501 * Query unsigned 8-bit integer value with default.
2502 *
2503 * @returns VBox status code.
2504 * @param pNode Which node to search for pszName in.
2505 * @param pszName Name of an integer value.
2506 * @param pu8 Where to store the value. Set to default on failure.
2507 * @param u8Def The default value.
2508 */
2509VMMR3DECL(int) CFGMR3QueryU8Def(PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)
2510{
2511 uint64_t u64;
2512 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u8Def);
2513 if (RT_SUCCESS(rc))
2514 {
2515 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2516 *pu8 = (uint8_t)u64;
2517 else
2518 rc = VERR_CFGM_INTEGER_TOO_BIG;
2519 }
2520 if (RT_FAILURE(rc))
2521 *pu8 = u8Def;
2522 return rc;
2523}
2524
2525
2526/**
2527 * Query signed 8-bit integer value.
2528 *
2529 * @returns VBox status code.
2530 * @param pNode Which node to search for pszName in.
2531 * @param pszName Name of an integer value.
2532 * @param pi8 Where to store the value.
2533 */
2534VMMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
2535{
2536 uint64_t u64;
2537 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2538 if (RT_SUCCESS(rc))
2539 {
2540 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2541 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2542 *pi8 = (int8_t)u64;
2543 else
2544 rc = VERR_CFGM_INTEGER_TOO_BIG;
2545 }
2546 return rc;
2547}
2548
2549
2550/**
2551 * Query signed 8-bit integer value with default.
2552 *
2553 * @returns VBox status code.
2554 * @param pNode Which node to search for pszName in.
2555 * @param pszName Name of an integer value.
2556 * @param pi8 Where to store the value. Set to default on failure.
2557 * @param i8Def The default value.
2558 */
2559VMMR3DECL(int) CFGMR3QueryS8Def(PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)
2560{
2561 uint64_t u64;
2562 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i8Def);
2563 if (RT_SUCCESS(rc))
2564 {
2565 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2566 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2567 *pi8 = (int8_t)u64;
2568 else
2569 rc = VERR_CFGM_INTEGER_TOO_BIG;
2570 }
2571 if (RT_FAILURE(rc))
2572 *pi8 = i8Def;
2573 return rc;
2574}
2575
2576
2577/**
2578 * Query boolean integer value.
2579 *
2580 * @returns VBox status code.
2581 * @param pNode Which node to search for pszName in.
2582 * @param pszName Name of an integer value.
2583 * @param pf Where to store the value.
2584 * @remark This function will interpret any non-zero value as true.
2585 */
2586VMMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
2587{
2588 uint64_t u64;
2589 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2590 if (RT_SUCCESS(rc))
2591 *pf = u64 ? true : false;
2592 return rc;
2593}
2594
2595
2596/**
2597 * Query boolean integer value with default.
2598 *
2599 * @returns VBox status code.
2600 * @param pNode Which node to search for pszName in.
2601 * @param pszName Name of an integer value.
2602 * @param pf Where to store the value. Set to default on failure.
2603 * @param fDef The default value.
2604 * @remark This function will interpret any non-zero value as true.
2605 */
2606VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
2607{
2608 uint64_t u64;
2609 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, fDef);
2610 *pf = u64 ? true : false;
2611 return rc;
2612}
2613
2614
2615/**
2616 * Query I/O port address value.
2617 *
2618 * @returns VBox status code.
2619 * @param pNode Which node to search for pszName in.
2620 * @param pszName Name of an integer value.
2621 * @param pPort Where to store the value.
2622 */
2623VMMR3DECL(int) CFGMR3QueryPort(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)
2624{
2625 AssertCompileSize(RTIOPORT, 2);
2626 return CFGMR3QueryU16(pNode, pszName, pPort);
2627}
2628
2629
2630/**
2631 * Query I/O port address value with default.
2632 *
2633 * @returns VBox status code.
2634 * @param pNode Which node to search for pszName in.
2635 * @param pszName Name of an integer value.
2636 * @param pPort Where to store the value. Set to default on failure.
2637 * @param PortDef The default value.
2638 */
2639VMMR3DECL(int) CFGMR3QueryPortDef(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)
2640{
2641 AssertCompileSize(RTIOPORT, 2);
2642 return CFGMR3QueryU16Def(pNode, pszName, pPort, PortDef);
2643}
2644
2645
2646/**
2647 * Query unsigned int address value.
2648 *
2649 * @returns VBox status code.
2650 * @param pNode Which node to search for pszName in.
2651 * @param pszName Name of an integer value.
2652 * @param pu Where to store the value.
2653 */
2654VMMR3DECL(int) CFGMR3QueryUInt(PCFGMNODE pNode, const char *pszName, unsigned int *pu)
2655{
2656 AssertCompileSize(unsigned int, 4);
2657 return CFGMR3QueryU32(pNode, pszName, (uint32_t *)pu);
2658}
2659
2660
2661/**
2662 * Query unsigned int address value with default.
2663 *
2664 * @returns VBox status code.
2665 * @param pNode Which node to search for pszName in.
2666 * @param pszName Name of an integer value.
2667 * @param pu Where to store the value. Set to default on failure.
2668 * @param uDef The default value.
2669 */
2670VMMR3DECL(int) CFGMR3QueryUIntDef(PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)
2671{
2672 AssertCompileSize(unsigned int, 4);
2673 return CFGMR3QueryU32Def(pNode, pszName, (uint32_t *)pu, uDef);
2674}
2675
2676
2677/**
2678 * Query signed int address value.
2679 *
2680 * @returns VBox status code.
2681 * @param pNode Which node to search for pszName in.
2682 * @param pszName Name of an integer value.
2683 * @param pi Where to store the value.
2684 */
2685VMMR3DECL(int) CFGMR3QuerySInt(PCFGMNODE pNode, const char *pszName, signed int *pi)
2686{
2687 AssertCompileSize(signed int, 4);
2688 return CFGMR3QueryS32(pNode, pszName, (int32_t *)pi);
2689}
2690
2691
2692/**
2693 * Query unsigned int address value with default.
2694 *
2695 * @returns VBox status code.
2696 * @param pNode Which node to search for pszName in.
2697 * @param pszName Name of an integer value.
2698 * @param pi Where to store the value. Set to default on failure.
2699 * @param iDef The default value.
2700 */
2701VMMR3DECL(int) CFGMR3QuerySIntDef(PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)
2702{
2703 AssertCompileSize(signed int, 4);
2704 return CFGMR3QueryS32Def(pNode, pszName, (int32_t *)pi, iDef);
2705}
2706
2707
2708/**
2709 * Query pointer integer value.
2710 *
2711 * @returns VBox status code.
2712 * @param pNode Which node to search for pszName in.
2713 * @param pszName Name of an integer value.
2714 * @param ppv Where to store the value.
2715 */
2716VMMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
2717{
2718 uint64_t u64;
2719 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2720 if (RT_SUCCESS(rc))
2721 {
2722 uintptr_t u = (uintptr_t)u64;
2723 if (u64 == u)
2724 *ppv = (void *)u;
2725 else
2726 rc = VERR_CFGM_INTEGER_TOO_BIG;
2727 }
2728 return rc;
2729}
2730
2731
2732/**
2733 * Query pointer integer value with default.
2734 *
2735 * @returns VBox status code.
2736 * @param pNode Which node to search for pszName in.
2737 * @param pszName Name of an integer value.
2738 * @param ppv Where to store the value. Set to default on failure.
2739 * @param pvDef The default value.
2740 */
2741VMMR3DECL(int) CFGMR3QueryPtrDef(PCFGMNODE pNode, const char *pszName, void **ppv, void *pvDef)
2742{
2743 uint64_t u64;
2744 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, (uintptr_t)pvDef);
2745 if (RT_SUCCESS(rc))
2746 {
2747 uintptr_t u = (uintptr_t)u64;
2748 if (u64 == u)
2749 *ppv = (void *)u;
2750 else
2751 rc = VERR_CFGM_INTEGER_TOO_BIG;
2752 }
2753 if (RT_FAILURE(rc))
2754 *ppv = pvDef;
2755 return rc;
2756}
2757
2758
2759/**
2760 * Query Guest Context pointer integer value.
2761 *
2762 * @returns VBox status code.
2763 * @param pNode Which node to search for pszName in.
2764 * @param pszName Name of an integer value.
2765 * @param pGCPtr Where to store the value.
2766 */
2767VMMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
2768{
2769 uint64_t u64;
2770 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2771 if (RT_SUCCESS(rc))
2772 {
2773 RTGCPTR u = (RTGCPTR)u64;
2774 if (u64 == u)
2775 *pGCPtr = u;
2776 else
2777 rc = VERR_CFGM_INTEGER_TOO_BIG;
2778 }
2779 return rc;
2780}
2781
2782
2783/**
2784 * Query Guest Context pointer integer value with default.
2785 *
2786 * @returns VBox status code.
2787 * @param pNode Which node to search for pszName in.
2788 * @param pszName Name of an integer value.
2789 * @param pGCPtr Where to store the value. Set to default on failure.
2790 * @param GCPtrDef The default value.
2791 */
2792VMMR3DECL(int) CFGMR3QueryGCPtrDef(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)
2793{
2794 uint64_t u64;
2795 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2796 if (RT_SUCCESS(rc))
2797 {
2798 RTGCPTR u = (RTGCPTR)u64;
2799 if (u64 == u)
2800 *pGCPtr = u;
2801 else
2802 rc = VERR_CFGM_INTEGER_TOO_BIG;
2803 }
2804 if (RT_FAILURE(rc))
2805 *pGCPtr = GCPtrDef;
2806 return rc;
2807}
2808
2809
2810/**
2811 * Query Guest Context unsigned pointer value.
2812 *
2813 * @returns VBox status code.
2814 * @param pNode Which node to search for pszName in.
2815 * @param pszName Name of an integer value.
2816 * @param pGCPtr Where to store the value.
2817 */
2818VMMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
2819{
2820 uint64_t u64;
2821 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2822 if (RT_SUCCESS(rc))
2823 {
2824 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2825 if (u64 == u)
2826 *pGCPtr = u;
2827 else
2828 rc = VERR_CFGM_INTEGER_TOO_BIG;
2829 }
2830 return rc;
2831}
2832
2833
2834/**
2835 * Query Guest Context unsigned pointer value with default.
2836 *
2837 * @returns VBox status code.
2838 * @param pNode Which node to search for pszName in.
2839 * @param pszName Name of an integer value.
2840 * @param pGCPtr Where to store the value. Set to default on failure.
2841 * @param GCPtrDef The default value.
2842 */
2843VMMR3DECL(int) CFGMR3QueryGCPtrUDef(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)
2844{
2845 uint64_t u64;
2846 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2847 if (RT_SUCCESS(rc))
2848 {
2849 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2850 if (u64 == u)
2851 *pGCPtr = u;
2852 else
2853 rc = VERR_CFGM_INTEGER_TOO_BIG;
2854 }
2855 if (RT_FAILURE(rc))
2856 *pGCPtr = GCPtrDef;
2857 return rc;
2858}
2859
2860
2861/**
2862 * Query Guest Context signed pointer value.
2863 *
2864 * @returns VBox status code.
2865 * @param pNode Which node to search for pszName in.
2866 * @param pszName Name of an integer value.
2867 * @param pGCPtr Where to store the value.
2868 */
2869VMMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
2870{
2871 uint64_t u64;
2872 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2873 if (RT_SUCCESS(rc))
2874 {
2875 RTGCINTPTR u = (RTGCINTPTR)u64;
2876 if (u64 == (uint64_t)u)
2877 *pGCPtr = u;
2878 else
2879 rc = VERR_CFGM_INTEGER_TOO_BIG;
2880 }
2881 return rc;
2882}
2883
2884
2885/**
2886 * Query Guest Context signed pointer value with default.
2887 *
2888 * @returns VBox status code.
2889 * @param pNode Which node to search for pszName in.
2890 * @param pszName Name of an integer value.
2891 * @param pGCPtr Where to store the value. Set to default on failure.
2892 * @param GCPtrDef The default value.
2893 */
2894VMMR3DECL(int) CFGMR3QueryGCPtrSDef(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)
2895{
2896 uint64_t u64;
2897 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2898 if (RT_SUCCESS(rc))
2899 {
2900 RTGCINTPTR u = (RTGCINTPTR)u64;
2901 if (u64 == (uint64_t)u)
2902 *pGCPtr = u;
2903 else
2904 rc = VERR_CFGM_INTEGER_TOO_BIG;
2905 }
2906 if (RT_FAILURE(rc))
2907 *pGCPtr = GCPtrDef;
2908 return rc;
2909}
2910
2911
2912/**
2913 * Query zero terminated character value storing it in a
2914 * buffer allocated from the MM heap.
2915 *
2916 * @returns VBox status code.
2917 * @param pNode Which node to search for pszName in.
2918 * @param pszName Value name. This value must be of zero terminated character string type.
2919 * @param ppszString Where to store the string pointer.
2920 * Free this using MMR3HeapFree().
2921 */
2922VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
2923{
2924 size_t cbString;
2925 int rc = CFGMR3QuerySize(pNode, pszName, &cbString);
2926 if (RT_SUCCESS(rc))
2927 {
2928 char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString);
2929 if (pszString)
2930 {
2931 rc = CFGMR3QueryString(pNode, pszName, pszString, cbString);
2932 if (RT_SUCCESS(rc))
2933 *ppszString = pszString;
2934 else
2935 MMR3HeapFree(pszString);
2936 }
2937 else
2938 rc = VERR_NO_MEMORY;
2939 }
2940 return rc;
2941}
2942
2943
2944/**
2945 * Query zero terminated character value storing it in a
2946 * buffer allocated from the MM heap.
2947 *
2948 * @returns VBox status code.
2949 * @param pNode Which node to search for pszName in. This cannot be
2950 * NULL if @a pszDef is not NULL, because we need
2951 * somewhere way to get to the VM in order to call
2952 * MMR3HeapStrDup.
2953 * @param pszName Value name. This value must be of zero terminated character string type.
2954 * @param ppszString Where to store the string pointer. Not set on failure.
2955 * Free this using MMR3HeapFree().
2956 * @param pszDef The default return value. This can be NULL.
2957 */
2958VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
2959{
2960 Assert(pNode || !pszDef); /* We need pVM if we need to duplicate the string later. */
2961
2962 /*
2963 * (Don't call CFGMR3QuerySize and CFGMR3QueryStringDef here as the latter
2964 * cannot handle pszDef being NULL.)
2965 */
2966 PCFGMLEAF pLeaf;
2967 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
2968 if (RT_SUCCESS(rc))
2969 {
2970 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
2971 {
2972 size_t const cbSrc = pLeaf->Value.String.cb;
2973 char *pszString = (char *)MMR3HeapAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbSrc);
2974 if (pszString)
2975 {
2976 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
2977 *ppszString = pszString;
2978 }
2979 else
2980 rc = VERR_NO_MEMORY;
2981 }
2982 else
2983 rc = VERR_CFGM_NOT_STRING;
2984 }
2985 if (RT_FAILURE(rc))
2986 {
2987 if (!pszDef)
2988 *ppszString = NULL;
2989 else
2990 *ppszString = MMR3HeapStrDup(pNode->pVM, MM_TAG_CFGM_USER, pszDef);
2991 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
2992 rc = VINF_SUCCESS;
2993 }
2994
2995 return rc;
2996}
2997
2998
2999/**
3000 * Dumps the configuration (sub)tree to the release log.
3001 *
3002 * @param pRoot The root node of the dump.
3003 */
3004VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
3005{
3006 bool fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/);
3007 LogRel(("************************* CFGM dump *************************\n"));
3008 cfgmR3Dump(pRoot, 0, DBGFR3InfoLogRelHlp());
3009 LogRel(("********************* End of CFGM dump **********************\n"));
3010 RTLogRelSetBuffering(fOldBuffered);
3011}
3012
3013
3014/**
3015 * Info handler, internal version.
3016 *
3017 * @param pVM Pointer to the VM.
3018 * @param pHlp Callback functions for doing output.
3019 * @param pszArgs Argument string. Optional and specific to the handler.
3020 */
3021static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
3022{
3023 /*
3024 * Figure where to start.
3025 */
3026 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
3027 if (pszArgs && *pszArgs)
3028 {
3029 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
3030 if (RT_FAILURE(rc))
3031 {
3032 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Rrc", pszArgs, rc);
3033 return;
3034 }
3035 }
3036
3037 /*
3038 * Dump the specified tree.
3039 */
3040 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
3041 cfgmR3DumpPath(pRoot, pHlp);
3042 pHlp->pfnPrintf(pHlp, "}\n");
3043 cfgmR3Dump(pRoot, 0, pHlp);
3044}
3045
3046
3047/**
3048 * Recursively prints a path name.
3049 */
3050static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
3051{
3052 if (pNode->pParent)
3053 cfgmR3DumpPath(pNode->pParent, pHlp);
3054 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
3055}
3056
3057
3058/**
3059 * Dumps a branch of a tree.
3060 */
3061static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
3062{
3063 /*
3064 * Path.
3065 */
3066 pHlp->pfnPrintf(pHlp, "[");
3067 cfgmR3DumpPath(pRoot, pHlp);
3068 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
3069
3070 /*
3071 * Values.
3072 */
3073 PCFGMLEAF pLeaf;
3074 size_t cchMax = 0;
3075 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3076 cchMax = RT_MAX(cchMax, pLeaf->cchName);
3077 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3078 {
3079 switch (CFGMR3GetValueType(pLeaf))
3080 {
3081 case CFGMVALUETYPE_INTEGER:
3082 {
3083 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%'lld", (int)cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
3084 if ( ( pLeaf->cchName >= 4
3085 && !RTStrCmp(&pLeaf->szName[pLeaf->cchName - 4], "Size"))
3086 || ( pLeaf->cchName >= 2
3087 && !RTStrNCmp(pLeaf->szName, "cb", 2)) )
3088 {
3089 if (pLeaf->Value.Integer.u64 > _2G)
3090 pHlp->pfnPrintf(pHlp, ", %'lld GB", pLeaf->Value.Integer.u64 / _1G);
3091 else if (pLeaf->Value.Integer.u64 > _2M)
3092 pHlp->pfnPrintf(pHlp, ", %'lld MB", pLeaf->Value.Integer.u64 / _1M);
3093 else if (pLeaf->Value.Integer.u64 > _2K)
3094 pHlp->pfnPrintf(pHlp, ", %'lld KB", pLeaf->Value.Integer.u64 / _1K);
3095 }
3096 pHlp->pfnPrintf(pHlp, ")\n");
3097 break;
3098 }
3099
3100 case CFGMVALUETYPE_STRING:
3101 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cb=%zu)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cb);
3102 break;
3103
3104 case CFGMVALUETYPE_BYTES:
3105 pHlp->pfnPrintf(pHlp, " %-*s <bytes> = \"%.*Rhxs\" (cb=%zu)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.Bytes.cb, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
3106 break;
3107
3108 default:
3109 AssertMsgFailed(("bad leaf!\n"));
3110 break;
3111 }
3112 }
3113 pHlp->pfnPrintf(pHlp, "\n");
3114
3115 /*
3116 * Children.
3117 */
3118 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
3119 {
3120 Assert(pChild->pNext != pChild);
3121 Assert(pChild->pPrev != pChild);
3122 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
3123 Assert(pChild->pFirstChild != pChild);
3124 Assert(pChild->pParent == pRoot);
3125 cfgmR3Dump(pChild, iLevel + 1, pHlp);
3126 }
3127}
3128
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