~ubuntu-branches/ubuntu/trusty/virtualbox-ose/trusty

« back to all changes in this revision

Viewing changes to src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2009-12-18 16:44:29 UTC
  • mfrom: (0.3.3 upstream) (0.4.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091218164429-jd34ccexpv5na11a
Tags: 3.1.2-dfsg-1ubuntu1
* Merge from Debian unstable (LP: #498219), remaining changes:
  - Disable update action
    - debian/patches/u01-disable-update-action.dpatch
  - VirtualBox should go in Accessories, not in System tools (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Add Launchpad integration
    - debian/control
    - debian/lpi-bug.xpm
    - debian/patches/u02-lp-integration.dpatch
* Fixes the following bugs:
  - Kernel module fails to build with Linux >= 2.6.32 (LP: #474625)
  - X.Org drivers need to be rebuilt against X-Server 1.7 (LP: #495935)
  - The *-source packages try to build the kernel modules even though the
    kernel headers aren't available (LP: #473334)
* Replace *-source packages with transitional packages for *-dkms.
* Adapt u01-disable-update-action.dpatch and u02-lp-integration.dpatch for
  new upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: VBoxManageMisc.cpp $ */
 
2
/** @file
 
3
 * VBoxManage - VirtualBox's command-line interface.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 *
 
17
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 
18
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 
19
 * additional information or have any questions.
 
20
 */
 
21
 
 
22
 
 
23
/*******************************************************************************
 
24
*   Header Files                                                               *
 
25
*******************************************************************************/
 
26
#ifndef VBOX_ONLY_DOCS
 
27
#include <VBox/com/com.h>
 
28
#include <VBox/com/string.h>
 
29
#include <VBox/com/Guid.h>
 
30
#include <VBox/com/array.h>
 
31
#include <VBox/com/ErrorInfo.h>
 
32
#include <VBox/com/errorprint.h>
 
33
#include <VBox/com/EventQueue.h>
 
34
 
 
35
#include <VBox/com/VirtualBox.h>
 
36
 
 
37
#include <vector>
 
38
#include <list>
 
39
#endif /* !VBOX_ONLY_DOCS */
 
40
 
 
41
#include <iprt/asm.h>
 
42
#include <iprt/buildconfig.h>
 
43
#include <iprt/cidr.h>
 
44
#include <iprt/ctype.h>
 
45
#include <iprt/dir.h>
 
46
#include <iprt/env.h>
 
47
#include <VBox/err.h>
 
48
#include <iprt/file.h>
 
49
#include <iprt/initterm.h>
 
50
#include <iprt/param.h>
 
51
#include <iprt/path.h>
 
52
#include <iprt/stream.h>
 
53
#include <iprt/string.h>
 
54
#include <iprt/stdarg.h>
 
55
#include <iprt/thread.h>
 
56
#include <iprt/uuid.h>
 
57
#include <iprt/getopt.h>
 
58
#include <iprt/ctype.h>
 
59
#include <VBox/version.h>
 
60
#include <VBox/log.h>
 
61
 
 
62
#include "VBoxManage.h"
 
63
 
 
64
using namespace com;
 
65
 
 
66
 
 
67
 
 
68
int handleRegisterVM(HandlerArg *a)
 
69
{
 
70
    HRESULT rc;
 
71
 
 
72
    if (a->argc != 1)
 
73
        return errorSyntax(USAGE_REGISTERVM, "Incorrect number of parameters");
 
74
 
 
75
    ComPtr<IMachine> machine;
 
76
    /** @todo Ugly hack to get both the API interpretation of relative paths
 
77
     * and the client's interpretation of relative paths. Remove after the API
 
78
     * has been redesigned. */
 
79
    rc = a->virtualBox->OpenMachine(Bstr(a->argv[0]), machine.asOutParam());
 
80
    if (rc == VBOX_E_FILE_ERROR)
 
81
    {
 
82
        char szVMFileAbs[RTPATH_MAX] = "";
 
83
        int vrc = RTPathAbs(a->argv[0], szVMFileAbs, sizeof(szVMFileAbs));
 
84
        if (RT_FAILURE(vrc))
 
85
        {
 
86
            RTPrintf("Cannot convert filename \"%s\" to absolute path\n", a->argv[0]);
 
87
            return 1;
 
88
        }
 
89
        CHECK_ERROR(a->virtualBox, OpenMachine(Bstr(szVMFileAbs), machine.asOutParam()));
 
90
    }
 
91
    else if (FAILED(rc))
 
92
        CHECK_ERROR(a->virtualBox, OpenMachine(Bstr(a->argv[0]), machine.asOutParam()));
 
93
    if (SUCCEEDED(rc))
 
94
    {
 
95
        ASSERT(machine);
 
96
        CHECK_ERROR(a->virtualBox, RegisterMachine(machine));
 
97
    }
 
98
    return SUCCEEDED(rc) ? 0 : 1;
 
99
}
 
100
 
 
101
static const RTGETOPTDEF g_aUnregisterVMOptions[] =
 
102
{
 
103
    { "--delete",       'd', RTGETOPT_REQ_NOTHING },
 
104
    { "-delete",        'd', RTGETOPT_REQ_NOTHING },    // deprecated
 
105
};
 
106
 
 
107
int handleUnregisterVM(HandlerArg *a)
 
108
{
 
109
    HRESULT rc;
 
110
    const char *VMName = NULL;
 
111
    bool fDelete = false;
 
112
 
 
113
    int c;
 
114
    RTGETOPTUNION ValueUnion;
 
115
    RTGETOPTSTATE GetState;
 
116
    // start at 0 because main() has hacked both the argc and argv given to us
 
117
    RTGetOptInit(&GetState, a->argc, a->argv, g_aUnregisterVMOptions, RT_ELEMENTS(g_aUnregisterVMOptions), 0, 0 /* fFlags */);
 
118
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
 
119
    {
 
120
        switch (c)
 
121
        {
 
122
            case 'd':   // --delete
 
123
                fDelete = true;
 
124
                break;
 
125
 
 
126
            case VINF_GETOPT_NOT_OPTION:
 
127
                if (!VMName)
 
128
                    VMName = ValueUnion.psz;
 
129
                else
 
130
                    return errorSyntax(USAGE_UNREGISTERVM, "Invalid parameter '%s'", ValueUnion.psz);
 
131
                break;
 
132
 
 
133
            default:
 
134
                if (c > 0)
 
135
                {
 
136
                    if (RT_C_IS_PRINT(c))
 
137
                        return errorSyntax(USAGE_UNREGISTERVM, "Invalid option -%c", c);
 
138
                    else
 
139
                        return errorSyntax(USAGE_UNREGISTERVM, "Invalid option case %i", c);
 
140
                }
 
141
                else if (c == VERR_GETOPT_UNKNOWN_OPTION)
 
142
                    return errorSyntax(USAGE_UNREGISTERVM, "unknown option: %s\n", ValueUnion.psz);
 
143
                else if (ValueUnion.pDef)
 
144
                    return errorSyntax(USAGE_UNREGISTERVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
 
145
                else
 
146
                    return errorSyntax(USAGE_UNREGISTERVM, "error: %Rrs", c);
 
147
        }
 
148
    }
 
149
 
 
150
    /* check for required options */
 
151
    if (!VMName)
 
152
        return errorSyntax(USAGE_UNREGISTERVM, "VM name required");
 
153
 
 
154
    ComPtr<IMachine> machine;
 
155
    /* assume it's a UUID */
 
156
    rc = a->virtualBox->GetMachine(Guid(VMName).toUtf16(), machine.asOutParam());
 
157
    if (FAILED(rc) || !machine)
 
158
    {
 
159
        /* must be a name */
 
160
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMName), machine.asOutParam()));
 
161
    }
 
162
    if (machine)
 
163
    {
 
164
        Bstr uuid;
 
165
        machine->COMGETTER(Id)(uuid.asOutParam());
 
166
        machine = NULL;
 
167
        CHECK_ERROR(a->virtualBox, UnregisterMachine(uuid, machine.asOutParam()));
 
168
        if (SUCCEEDED(rc) && machine && fDelete)
 
169
            CHECK_ERROR(machine, DeleteSettings());
 
170
    }
 
171
    return SUCCEEDED(rc) ? 0 : 1;
 
172
}
 
173
 
 
174
int handleCreateVM(HandlerArg *a)
 
175
{
 
176
    HRESULT rc;
 
177
    Bstr baseFolder;
 
178
    Bstr settingsFile;
 
179
    Bstr name;
 
180
    Bstr osTypeId;
 
181
    RTUUID id;
 
182
    bool fRegister = false;
 
183
 
 
184
    RTUuidClear(&id);
 
185
    for (int i = 0; i < a->argc; i++)
 
186
    {
 
187
        if (   !strcmp(a->argv[i], "--basefolder")
 
188
            || !strcmp(a->argv[i], "-basefolder"))
 
189
        {
 
190
            if (a->argc <= i + 1)
 
191
                return errorArgument("Missing argument to '%s'", a->argv[i]);
 
192
            i++;
 
193
            baseFolder = a->argv[i];
 
194
        }
 
195
        else if (   !strcmp(a->argv[i], "--settingsfile")
 
196
                 || !strcmp(a->argv[i], "-settingsfile"))
 
197
        {
 
198
            if (a->argc <= i + 1)
 
199
                return errorArgument("Missing argument to '%s'", a->argv[i]);
 
200
            i++;
 
201
            settingsFile = a->argv[i];
 
202
        }
 
203
        else if (   !strcmp(a->argv[i], "--name")
 
204
                 || !strcmp(a->argv[i], "-name"))
 
205
        {
 
206
            if (a->argc <= i + 1)
 
207
                return errorArgument("Missing argument to '%s'", a->argv[i]);
 
208
            i++;
 
209
            name = a->argv[i];
 
210
        }
 
211
        else if (   !strcmp(a->argv[i], "--ostype")
 
212
                 || !strcmp(a->argv[i], "-ostype"))
 
213
        {
 
214
            if (a->argc <= i + 1)
 
215
                return errorArgument("Missing argument to '%s'", a->argv[i]);
 
216
            i++;
 
217
            osTypeId = a->argv[i];
 
218
        }
 
219
        else if (   !strcmp(a->argv[i], "--uuid")
 
220
                 || !strcmp(a->argv[i], "-uuid"))
 
221
        {
 
222
            if (a->argc <= i + 1)
 
223
                return errorArgument("Missing argument to '%s'", a->argv[i]);
 
224
            i++;
 
225
            if (RT_FAILURE(RTUuidFromStr(&id, a->argv[i])))
 
226
                return errorArgument("Invalid UUID format %s\n", a->argv[i]);
 
227
        }
 
228
        else if (   !strcmp(a->argv[i], "--register")
 
229
                 || !strcmp(a->argv[i], "-register"))
 
230
        {
 
231
            fRegister = true;
 
232
        }
 
233
        else
 
234
            return errorSyntax(USAGE_CREATEVM, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
 
235
    }
 
236
    if (!name)
 
237
        return errorSyntax(USAGE_CREATEVM, "Parameter --name is required");
 
238
 
 
239
    if (!!baseFolder && !!settingsFile)
 
240
        return errorSyntax(USAGE_CREATEVM, "Either --basefolder or --settingsfile must be specified");
 
241
 
 
242
    do
 
243
    {
 
244
        ComPtr<IMachine> machine;
 
245
 
 
246
        if (!settingsFile)
 
247
            CHECK_ERROR_BREAK(a->virtualBox,
 
248
                CreateMachine(name, osTypeId, baseFolder, Guid(id).toUtf16(), machine.asOutParam()));
 
249
        else
 
250
            CHECK_ERROR_BREAK(a->virtualBox,
 
251
                CreateLegacyMachine(name, osTypeId, settingsFile, Guid(id).toUtf16(), machine.asOutParam()));
 
252
 
 
253
        CHECK_ERROR_BREAK(machine, SaveSettings());
 
254
        if (fRegister)
 
255
        {
 
256
            CHECK_ERROR_BREAK(a->virtualBox, RegisterMachine(machine));
 
257
        }
 
258
        Bstr uuid;
 
259
        CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
 
260
        CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
 
261
        RTPrintf("Virtual machine '%ls' is created%s.\n"
 
262
                 "UUID: %s\n"
 
263
                 "Settings file: '%ls'\n",
 
264
                 name.raw(), fRegister ? " and registered" : "",
 
265
                 Utf8Str(uuid).raw(), settingsFile.raw());
 
266
    }
 
267
    while (0);
 
268
 
 
269
    return SUCCEEDED(rc) ? 0 : 1;
 
270
}
 
271
 
 
272
int handleStartVM(HandlerArg *a)
 
273
{
 
274
    HRESULT rc;
 
275
    const char *VMName = NULL;
 
276
    Bstr sessionType = "gui";
 
277
 
 
278
    static const RTGETOPTDEF s_aStartVMOptions[] =
 
279
    {
 
280
        { "--type",         't', RTGETOPT_REQ_STRING },
 
281
        { "-type",          't', RTGETOPT_REQ_STRING },     // deprecated
 
282
    };
 
283
    int c;
 
284
    RTGETOPTUNION ValueUnion;
 
285
    RTGETOPTSTATE GetState;
 
286
    // start at 0 because main() has hacked both the argc and argv given to us
 
287
    RTGetOptInit(&GetState, a->argc, a->argv, s_aStartVMOptions, RT_ELEMENTS(s_aStartVMOptions), 0, 0 /* fFlags */);
 
288
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
 
289
    {
 
290
        switch (c)
 
291
        {
 
292
            case 't':   // --type
 
293
                if (!RTStrICmp(ValueUnion.psz, "gui"))
 
294
                {
 
295
                    sessionType = "gui";
 
296
                }
 
297
#ifdef VBOX_WITH_VBOXSDL
 
298
                else if (!RTStrICmp(ValueUnion.psz, "sdl"))
 
299
                {
 
300
                    sessionType = "sdl";
 
301
                }
 
302
#endif
 
303
#ifdef VBOX_WITH_VRDP
 
304
                else if (!RTStrICmp(ValueUnion.psz, "vrdp"))
 
305
                {
 
306
                    sessionType = "vrdp";
 
307
                }
 
308
#endif
 
309
#ifdef VBOX_WITH_HEADLESS
 
310
                else if (!RTStrICmp(ValueUnion.psz, "capture"))
 
311
                {
 
312
                    sessionType = "capture";
 
313
                }
 
314
                else if (!RTStrICmp(ValueUnion.psz, "headless"))
 
315
                {
 
316
                    sessionType = "headless";
 
317
                }
 
318
#endif
 
319
                else
 
320
                    return errorArgument("Invalid session type '%s'", ValueUnion.psz);
 
321
                break;
 
322
 
 
323
            case VINF_GETOPT_NOT_OPTION:
 
324
                if (!VMName)
 
325
                    VMName = ValueUnion.psz;
 
326
                else
 
327
                    return errorSyntax(USAGE_STARTVM, "Invalid parameter '%s'", ValueUnion.psz);
 
328
                break;
 
329
 
 
330
            default:
 
331
                if (c > 0)
 
332
                {
 
333
                    if (RT_C_IS_PRINT(c))
 
334
                        return errorSyntax(USAGE_STARTVM, "Invalid option -%c", c);
 
335
                    else
 
336
                        return errorSyntax(USAGE_STARTVM, "Invalid option case %i", c);
 
337
                }
 
338
                else if (c == VERR_GETOPT_UNKNOWN_OPTION)
 
339
                    return errorSyntax(USAGE_STARTVM, "unknown option: %s\n", ValueUnion.psz);
 
340
                else if (ValueUnion.pDef)
 
341
                    return errorSyntax(USAGE_STARTVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
 
342
                else
 
343
                    return errorSyntax(USAGE_STARTVM, "error: %Rrs", c);
 
344
        }
 
345
    }
 
346
 
 
347
    /* check for required options */
 
348
    if (!VMName)
 
349
        return errorSyntax(USAGE_STARTVM, "VM name required");
 
350
 
 
351
    ComPtr<IMachine> machine;
 
352
    /* assume it's a UUID */
 
353
    rc = a->virtualBox->GetMachine(Guid(VMName).toUtf16(), machine.asOutParam());
 
354
    if (FAILED(rc) || !machine)
 
355
    {
 
356
        /* must be a name */
 
357
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMName), machine.asOutParam()));
 
358
    }
 
359
    if (machine)
 
360
    {
 
361
        Bstr uuid;
 
362
        machine->COMGETTER(Id)(uuid.asOutParam());
 
363
 
 
364
 
 
365
        Bstr env;
 
366
#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
 
367
        /* make sure the VM process will start on the same display as VBoxManage */
 
368
        Utf8Str str;
 
369
        const char *pszDisplay = RTEnvGet("DISPLAY");
 
370
        if (pszDisplay)
 
371
            str = Utf8StrFmt("DISPLAY=%s\n", pszDisplay);
 
372
        const char *pszXAuth = RTEnvGet("XAUTHORITY");
 
373
        if (pszXAuth)
 
374
            str.append(Utf8StrFmt("XAUTHORITY=%s\n", pszXAuth));
 
375
        env = str;
 
376
#endif
 
377
        ComPtr<IProgress> progress;
 
378
        CHECK_ERROR_RET(a->virtualBox, OpenRemoteSession(a->session, uuid, sessionType,
 
379
                                                         env, progress.asOutParam()), rc);
 
380
        RTPrintf("Waiting for the remote session to open...\n");
 
381
        CHECK_ERROR_RET(progress, WaitForCompletion (-1), 1);
 
382
 
 
383
        BOOL completed;
 
384
        CHECK_ERROR_RET(progress, COMGETTER(Completed)(&completed), rc);
 
385
        ASSERT(completed);
 
386
 
 
387
        LONG iRc;
 
388
        CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
 
389
        if (FAILED(iRc))
 
390
        {
 
391
            ComPtr <IVirtualBoxErrorInfo> errorInfo;
 
392
            CHECK_ERROR_RET(progress, COMGETTER(ErrorInfo)(errorInfo.asOutParam()), 1);
 
393
            ErrorInfo info (errorInfo);
 
394
            com::GluePrintErrorInfo(info);
 
395
        }
 
396
        else
 
397
        {
 
398
            RTPrintf("Remote session has been successfully opened.\n");
 
399
        }
 
400
    }
 
401
 
 
402
    /* it's important to always close sessions */
 
403
    a->session->Close();
 
404
 
 
405
    return SUCCEEDED(rc) ? 0 : 1;
 
406
}
 
407
 
 
408
int handleDiscardState(HandlerArg *a)
 
409
{
 
410
    HRESULT rc;
 
411
 
 
412
    if (a->argc != 1)
 
413
        return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
 
414
 
 
415
    ComPtr<IMachine> machine;
 
416
    /* assume it's a UUID */
 
417
    rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
 
418
    if (FAILED(rc) || !machine)
 
419
    {
 
420
        /* must be a name */
 
421
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
 
422
    }
 
423
    if (machine)
 
424
    {
 
425
        do
 
426
        {
 
427
            /* we have to open a session for this task */
 
428
            Bstr guid;
 
429
            machine->COMGETTER(Id)(guid.asOutParam());
 
430
            CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
 
431
            do
 
432
            {
 
433
                ComPtr<IConsole> console;
 
434
                CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
 
435
                CHECK_ERROR_BREAK(console, ForgetSavedState(true));
 
436
            } while (0);
 
437
            CHECK_ERROR_BREAK(a->session, Close());
 
438
        } while (0);
 
439
    }
 
440
 
 
441
    return SUCCEEDED(rc) ? 0 : 1;
 
442
}
 
443
 
 
444
int handleAdoptdState(HandlerArg *a)
 
445
{
 
446
    HRESULT rc;
 
447
 
 
448
    if (a->argc != 2)
 
449
        return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
 
450
 
 
451
    ComPtr<IMachine> machine;
 
452
    /* assume it's a UUID */
 
453
    rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
 
454
    if (FAILED(rc) || !machine)
 
455
    {
 
456
        /* must be a name */
 
457
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
 
458
    }
 
459
    if (machine)
 
460
    {
 
461
        do
 
462
        {
 
463
            /* we have to open a session for this task */
 
464
            Bstr guid;
 
465
            machine->COMGETTER(Id)(guid.asOutParam());
 
466
            CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
 
467
            do
 
468
            {
 
469
                ComPtr<IConsole> console;
 
470
                CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
 
471
                CHECK_ERROR_BREAK(console, AdoptSavedState(Bstr(a->argv[1])));
 
472
            } while (0);
 
473
            CHECK_ERROR_BREAK(a->session, Close());
 
474
        } while (0);
 
475
    }
 
476
 
 
477
    return SUCCEEDED(rc) ? 0 : 1;
 
478
}
 
479
 
 
480
int handleGetExtraData(HandlerArg *a)
 
481
{
 
482
    HRESULT rc = S_OK;
 
483
 
 
484
    if (a->argc != 2)
 
485
        return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
 
486
 
 
487
    /* global data? */
 
488
    if (!strcmp(a->argv[0], "global"))
 
489
    {
 
490
        /* enumeration? */
 
491
        if (!strcmp(a->argv[1], "enumerate"))
 
492
        {
 
493
            SafeArray<BSTR> aKeys;
 
494
            CHECK_ERROR(a->virtualBox, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
 
495
 
 
496
            for (size_t i = 0;
 
497
                 i < aKeys.size();
 
498
                 ++i)
 
499
            {
 
500
                Bstr bstrKey(aKeys[i]);
 
501
                Bstr bstrValue;
 
502
                CHECK_ERROR(a->virtualBox, GetExtraData(bstrKey, bstrValue.asOutParam()));
 
503
 
 
504
                RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
 
505
            }
 
506
        }
 
507
        else
 
508
        {
 
509
            Bstr value;
 
510
            CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
 
511
            if (!value.isEmpty())
 
512
                RTPrintf("Value: %lS\n", value.raw());
 
513
            else
 
514
                RTPrintf("No value set!\n");
 
515
        }
 
516
    }
 
517
    else
 
518
    {
 
519
        ComPtr<IMachine> machine;
 
520
        /* assume it's a UUID */
 
521
        rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
 
522
        if (FAILED(rc) || !machine)
 
523
        {
 
524
            /* must be a name */
 
525
            CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
 
526
        }
 
527
        if (machine)
 
528
        {
 
529
            /* enumeration? */
 
530
            if (!strcmp(a->argv[1], "enumerate"))
 
531
            {
 
532
                SafeArray<BSTR> aKeys;
 
533
                CHECK_ERROR(machine, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
 
534
 
 
535
                for (size_t i = 0;
 
536
                    i < aKeys.size();
 
537
                    ++i)
 
538
                {
 
539
                    Bstr bstrKey(aKeys[i]);
 
540
                    Bstr bstrValue;
 
541
                    CHECK_ERROR(machine, GetExtraData(bstrKey, bstrValue.asOutParam()));
 
542
 
 
543
                    RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
 
544
                }
 
545
            }
 
546
            else
 
547
            {
 
548
                Bstr value;
 
549
                CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]), value.asOutParam()));
 
550
                if (!value.isEmpty())
 
551
                    RTPrintf("Value: %lS\n", value.raw());
 
552
                else
 
553
                    RTPrintf("No value set!\n");
 
554
            }
 
555
        }
 
556
    }
 
557
    return SUCCEEDED(rc) ? 0 : 1;
 
558
}
 
559
 
 
560
int handleSetExtraData(HandlerArg *a)
 
561
{
 
562
    HRESULT rc = S_OK;
 
563
 
 
564
    if (a->argc < 2)
 
565
        return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
 
566
 
 
567
    /* global data? */
 
568
    if (!strcmp(a->argv[0], "global"))
 
569
    {
 
570
        if (a->argc < 3)
 
571
            CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), NULL));
 
572
        else if (a->argc == 3)
 
573
            CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
 
574
        else
 
575
            return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
 
576
    }
 
577
    else
 
578
    {
 
579
        ComPtr<IMachine> machine;
 
580
        /* assume it's a UUID */
 
581
        rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
 
582
        if (FAILED(rc) || !machine)
 
583
        {
 
584
            /* must be a name */
 
585
            CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
 
586
        }
 
587
        if (machine)
 
588
        {
 
589
            if (a->argc < 3)
 
590
                CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), NULL));
 
591
            else if (a->argc == 3)
 
592
                CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]), Bstr(a->argv[2])));
 
593
            else
 
594
                return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
 
595
        }
 
596
    }
 
597
    return SUCCEEDED(rc) ? 0 : 1;
 
598
}
 
599
 
 
600
int handleSetProperty(HandlerArg *a)
 
601
{
 
602
    HRESULT rc;
 
603
 
 
604
    /* there must be two arguments: property name and value */
 
605
    if (a->argc != 2)
 
606
        return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
 
607
 
 
608
    ComPtr<ISystemProperties> systemProperties;
 
609
    a->virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
 
610
 
 
611
    if (!strcmp(a->argv[0], "hdfolder"))
 
612
    {
 
613
        /* reset to default? */
 
614
        if (!strcmp(a->argv[1], "default"))
 
615
            CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(NULL));
 
616
        else
 
617
            CHECK_ERROR(systemProperties, COMSETTER(DefaultHardDiskFolder)(Bstr(a->argv[1])));
 
618
    }
 
619
    else if (!strcmp(a->argv[0], "machinefolder"))
 
620
    {
 
621
        /* reset to default? */
 
622
        if (!strcmp(a->argv[1], "default"))
 
623
            CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
 
624
        else
 
625
            CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1])));
 
626
    }
 
627
    else if (!strcmp(a->argv[0], "vrdpauthlibrary"))
 
628
    {
 
629
        /* reset to default? */
 
630
        if (!strcmp(a->argv[1], "default"))
 
631
            CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(NULL));
 
632
        else
 
633
            CHECK_ERROR(systemProperties, COMSETTER(RemoteDisplayAuthLibrary)(Bstr(a->argv[1])));
 
634
    }
 
635
    else if (!strcmp(a->argv[0], "websrvauthlibrary"))
 
636
    {
 
637
        /* reset to default? */
 
638
        if (!strcmp(a->argv[1], "default"))
 
639
            CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
 
640
        else
 
641
            CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1])));
 
642
    }
 
643
    else if (!strcmp(a->argv[0], "loghistorycount"))
 
644
    {
 
645
        uint32_t uVal;
 
646
        int vrc;
 
647
        vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
 
648
        if (vrc != VINF_SUCCESS)
 
649
            return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
 
650
        CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
 
651
    }
 
652
    else
 
653
        return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
 
654
 
 
655
    return SUCCEEDED(rc) ? 0 : 1;
 
656
}
 
657
 
 
658
int handleSharedFolder(HandlerArg *a)
 
659
{
 
660
    HRESULT rc;
 
661
 
 
662
    /* we need at least a command and target */
 
663
    if (a->argc < 2)
 
664
        return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
 
665
 
 
666
    ComPtr<IMachine> machine;
 
667
    /* assume it's a UUID */
 
668
    rc = a->virtualBox->GetMachine(Bstr(a->argv[1]), machine.asOutParam());
 
669
    if (FAILED(rc) || !machine)
 
670
    {
 
671
        /* must be a name */
 
672
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]), machine.asOutParam()));
 
673
    }
 
674
    if (!machine)
 
675
        return 1;
 
676
    Bstr uuid;
 
677
    machine->COMGETTER(Id)(uuid.asOutParam());
 
678
 
 
679
    if (!strcmp(a->argv[0], "add"))
 
680
    {
 
681
        /* we need at least four more parameters */
 
682
        if (a->argc < 5)
 
683
            return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
 
684
 
 
685
        char *name = NULL;
 
686
        char *hostpath = NULL;
 
687
        bool fTransient = false;
 
688
        bool fWritable = true;
 
689
 
 
690
        for (int i = 2; i < a->argc; i++)
 
691
        {
 
692
            if (   !strcmp(a->argv[i], "--name")
 
693
                || !strcmp(a->argv[i], "-name"))
 
694
            {
 
695
                if (a->argc <= i + 1 || !*a->argv[i+1])
 
696
                    return errorArgument("Missing argument to '%s'", a->argv[i]);
 
697
                i++;
 
698
                name = a->argv[i];
 
699
            }
 
700
            else if (   !strcmp(a->argv[i], "--hostpath")
 
701
                     || !strcmp(a->argv[i], "-hostpath"))
 
702
            {
 
703
                if (a->argc <= i + 1 || !*a->argv[i+1])
 
704
                    return errorArgument("Missing argument to '%s'", a->argv[i]);
 
705
                i++;
 
706
                hostpath = a->argv[i];
 
707
            }
 
708
            else if (   !strcmp(a->argv[i], "--readonly")
 
709
                     || !strcmp(a->argv[i], "-readonly"))
 
710
            {
 
711
                fWritable = false;
 
712
            }
 
713
            else if (   !strcmp(a->argv[i], "--transient")
 
714
                     || !strcmp(a->argv[i], "-transient"))
 
715
            {
 
716
                fTransient = true;
 
717
            }
 
718
            else
 
719
                return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
 
720
        }
 
721
 
 
722
        if (NULL != strstr(name, " "))
 
723
            return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
 
724
 
 
725
        /* required arguments */
 
726
        if (!name || !hostpath)
 
727
        {
 
728
            return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters --name and --hostpath are required");
 
729
        }
 
730
 
 
731
        if (fTransient)
 
732
        {
 
733
            ComPtr <IConsole> console;
 
734
 
 
735
            /* open an existing session for the VM */
 
736
            CHECK_ERROR_RET(a->virtualBox, OpenExistingSession(a->session, uuid), 1);
 
737
            /* get the session machine */
 
738
            CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
 
739
            /* get the session console */
 
740
            CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
 
741
 
 
742
            CHECK_ERROR(console, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
 
743
 
 
744
            if (console)
 
745
                a->session->Close();
 
746
        }
 
747
        else
 
748
        {
 
749
            /* open a session for the VM */
 
750
            CHECK_ERROR_RET(a->virtualBox, OpenSession(a->session, uuid), 1);
 
751
 
 
752
            /* get the mutable session machine */
 
753
            a->session->COMGETTER(Machine)(machine.asOutParam());
 
754
 
 
755
            CHECK_ERROR(machine, CreateSharedFolder(Bstr(name), Bstr(hostpath), fWritable));
 
756
 
 
757
            if (SUCCEEDED(rc))
 
758
                CHECK_ERROR(machine, SaveSettings());
 
759
 
 
760
            a->session->Close();
 
761
        }
 
762
    }
 
763
    else if (!strcmp(a->argv[0], "remove"))
 
764
    {
 
765
        /* we need at least two more parameters */
 
766
        if (a->argc < 3)
 
767
            return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
 
768
 
 
769
        char *name = NULL;
 
770
        bool fTransient = false;
 
771
 
 
772
        for (int i = 2; i < a->argc; i++)
 
773
        {
 
774
            if (   !strcmp(a->argv[i], "--name")
 
775
                || !strcmp(a->argv[i], "-name"))
 
776
            {
 
777
                if (a->argc <= i + 1 || !*a->argv[i+1])
 
778
                    return errorArgument("Missing argument to '%s'", a->argv[i]);
 
779
                i++;
 
780
                name = a->argv[i];
 
781
            }
 
782
            else if (   !strcmp(a->argv[i], "--transient")
 
783
                     || !strcmp(a->argv[i], "-transient"))
 
784
            {
 
785
                fTransient = true;
 
786
            }
 
787
            else
 
788
                return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
 
789
        }
 
790
 
 
791
        /* required arguments */
 
792
        if (!name)
 
793
            return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter --name is required");
 
794
 
 
795
        if (fTransient)
 
796
        {
 
797
            ComPtr <IConsole> console;
 
798
 
 
799
            /* open an existing session for the VM */
 
800
            CHECK_ERROR_RET(a->virtualBox, OpenExistingSession(a->session, uuid), 1);
 
801
            /* get the session machine */
 
802
            CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
 
803
            /* get the session console */
 
804
            CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
 
805
 
 
806
            CHECK_ERROR(console, RemoveSharedFolder(Bstr(name)));
 
807
 
 
808
            if (console)
 
809
                a->session->Close();
 
810
        }
 
811
        else
 
812
        {
 
813
            /* open a session for the VM */
 
814
            CHECK_ERROR_RET(a->virtualBox, OpenSession(a->session, uuid), 1);
 
815
 
 
816
            /* get the mutable session machine */
 
817
            a->session->COMGETTER(Machine)(machine.asOutParam());
 
818
 
 
819
            CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name)));
 
820
 
 
821
            /* commit and close the session */
 
822
            CHECK_ERROR(machine, SaveSettings());
 
823
            a->session->Close();
 
824
        }
 
825
    }
 
826
    else
 
827
        return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", Utf8Str(a->argv[0]).raw());
 
828
 
 
829
    return 0;
 
830
}
 
831
 
 
832
int handleVMStatistics(HandlerArg *a)
 
833
{
 
834
    HRESULT rc;
 
835
 
 
836
    /* at least one option: the UUID or name of the VM */
 
837
    if (a->argc < 1)
 
838
        return errorSyntax(USAGE_VM_STATISTICS, "Incorrect number of parameters");
 
839
 
 
840
    /* try to find the given machine */
 
841
    ComPtr <IMachine> machine;
 
842
    Bstr uuid (a->argv[0]);
 
843
    if (!Guid (a->argv[0]).isEmpty())
 
844
        CHECK_ERROR(a->virtualBox, GetMachine(uuid, machine.asOutParam()));
 
845
    else
 
846
    {
 
847
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
 
848
        if (SUCCEEDED (rc))
 
849
            machine->COMGETTER(Id)(uuid.asOutParam());
 
850
    }
 
851
    if (FAILED(rc))
 
852
        return 1;
 
853
 
 
854
    /* parse arguments. */
 
855
    bool fReset = false;
 
856
    bool fWithDescriptions = false;
 
857
    const char *pszPattern = NULL; /* all */
 
858
    for (int i = 1; i < a->argc; i++)
 
859
    {
 
860
        if (   !strcmp(a->argv[i], "--pattern")
 
861
            || !strcmp(a->argv[i], "-pattern"))
 
862
        {
 
863
            if (pszPattern)
 
864
                return errorSyntax(USAGE_VM_STATISTICS, "Multiple --patterns options is not permitted");
 
865
            if (i + 1 >= a->argc)
 
866
                return errorArgument("Missing argument to '%s'", a->argv[i]);
 
867
            pszPattern = a->argv[++i];
 
868
        }
 
869
        else if (   !strcmp(a->argv[i], "--descriptions")
 
870
                 || !strcmp(a->argv[i], "-descriptions"))
 
871
            fWithDescriptions = true;
 
872
        /* add: --file <filename> and --formatted */
 
873
        else if (   !strcmp(a->argv[i], "--reset")
 
874
                 || !strcmp(a->argv[i], "-reset"))
 
875
            fReset = true;
 
876
        else
 
877
            return errorSyntax(USAGE_VM_STATISTICS, "Unknown option '%s'", a->argv[i]);
 
878
    }
 
879
    if (fReset && fWithDescriptions)
 
880
        return errorSyntax(USAGE_VM_STATISTICS, "The --reset and --descriptions options does not mix");
 
881
 
 
882
 
 
883
    /* open an existing session for the VM. */
 
884
    CHECK_ERROR(a->virtualBox, OpenExistingSession(a->session, uuid));
 
885
    if (SUCCEEDED(rc))
 
886
    {
 
887
        /* get the session console. */
 
888
        ComPtr <IConsole> console;
 
889
        CHECK_ERROR(a->session, COMGETTER(Console)(console.asOutParam()));
 
890
        if (SUCCEEDED(rc))
 
891
        {
 
892
            /* get the machine debugger. */
 
893
            ComPtr <IMachineDebugger> debugger;
 
894
            CHECK_ERROR(console, COMGETTER(Debugger)(debugger.asOutParam()));
 
895
            if (SUCCEEDED(rc))
 
896
            {
 
897
                if (fReset)
 
898
                    CHECK_ERROR(debugger, ResetStats(Bstr(pszPattern)));
 
899
                else
 
900
                {
 
901
                    Bstr stats;
 
902
                    CHECK_ERROR(debugger, GetStats(Bstr(pszPattern), fWithDescriptions, stats.asOutParam()));
 
903
                    if (SUCCEEDED(rc))
 
904
                    {
 
905
                        /* if (fFormatted)
 
906
                         { big mess }
 
907
                         else
 
908
                         */
 
909
                        RTPrintf("%ls\n", stats.raw());
 
910
                    }
 
911
                }
 
912
            }
 
913
            a->session->Close();
 
914
        }
 
915
    }
 
916
 
 
917
    return SUCCEEDED(rc) ? 0 : 1;
 
918
}
 
919