VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp@ 35722

Last change on this file since 35722 was 35707, checked in by vboxsync, 14 years ago

VBoxManage: allow tot save the state of a VM which is already paused

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.9 KB
Line 
1/* $Id: VBoxManageControlVM.cpp 35707 2011-01-25 12:53:39Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the controlvm command.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <VBox/com/com.h>
23#include <VBox/com/string.h>
24#include <VBox/com/Guid.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/EventQueue.h>
29
30#include <VBox/com/VirtualBox.h>
31
32#include <iprt/ctype.h>
33#include <VBox/err.h>
34#include <iprt/getopt.h>
35#include <iprt/stream.h>
36#include <iprt/string.h>
37#include <iprt/uuid.h>
38#include <VBox/log.h>
39
40#include "VBoxManage.h"
41
42#include <list>
43
44
45/**
46 * Parses a number.
47 *
48 * @returns Valid number on success.
49 * @returns 0 if invalid number. All necessary bitching has been done.
50 * @param psz Pointer to the nic number.
51 */
52static unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
53{
54 uint32_t u32;
55 char *pszNext;
56 int rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u32);
57 if ( RT_SUCCESS(rc)
58 && *pszNext == '\0'
59 && u32 >= 1
60 && u32 <= cMaxNum)
61 return (unsigned)u32;
62 errorArgument("Invalid %s number '%s'", name, psz);
63 return 0;
64}
65
66
67int handleControlVM(HandlerArg *a)
68{
69 using namespace com;
70 HRESULT rc;
71
72 if (a->argc < 2)
73 return errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
74
75 /* try to find the given machine */
76 ComPtr <IMachine> machine;
77 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
78 machine.asOutParam()));
79 if (FAILED(rc))
80 return 1;
81
82 /* open a session for the VM */
83 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
84
85 do
86 {
87 /* get the associated console */
88 ComPtr<IConsole> console;
89 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
90 /* ... and session machine */
91 ComPtr<IMachine> sessionMachine;
92 CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
93
94 /* which command? */
95 if (!strcmp(a->argv[1], "pause"))
96 {
97 CHECK_ERROR_BREAK(console, Pause());
98 }
99 else if (!strcmp(a->argv[1], "resume"))
100 {
101 CHECK_ERROR_BREAK(console, Resume());
102 }
103 else if (!strcmp(a->argv[1], "reset"))
104 {
105 CHECK_ERROR_BREAK(console, Reset());
106 }
107 else if (!strcmp(a->argv[1], "unplugcpu"))
108 {
109 if (a->argc <= 1 + 1)
110 {
111 errorArgument("Missing argument to '%s'. Expected CPU number.", a->argv[1]);
112 rc = E_FAIL;
113 break;
114 }
115
116 unsigned n = parseNum(a->argv[2], 32, "CPU");
117
118 CHECK_ERROR_BREAK(sessionMachine, HotUnplugCPU(n));
119 }
120 else if (!strcmp(a->argv[1], "plugcpu"))
121 {
122 if (a->argc <= 1 + 1)
123 {
124 errorArgument("Missing argument to '%s'. Expected CPU number.", a->argv[1]);
125 rc = E_FAIL;
126 break;
127 }
128
129 unsigned n = parseNum(a->argv[2], 32, "CPU");
130
131 CHECK_ERROR_BREAK(sessionMachine, HotPlugCPU(n));
132 }
133 else if (!strcmp(a->argv[1], "cpuexecutioncap"))
134 {
135 if (a->argc <= 1 + 1)
136 {
137 errorArgument("Missing argument to '%s'. Expected execution cap number.", a->argv[1]);
138 rc = E_FAIL;
139 break;
140 }
141
142 unsigned n = parseNum(a->argv[2], 100, "ExecutionCap");
143
144 CHECK_ERROR_BREAK(sessionMachine, COMSETTER(CPUExecutionCap)(n));
145 }
146 else if (!strcmp(a->argv[1], "poweroff"))
147 {
148 ComPtr<IProgress> progress;
149 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
150
151 rc = showProgress(progress);
152 if (FAILED(rc))
153 {
154 com::ProgressErrorInfo info(progress);
155 if (info.isBasicAvailable())
156 RTMsgError("Failed to power off machine. Error message: %lS", info.getText().raw());
157 else
158 RTMsgError("Failed to power off machine. No error message available!");
159 }
160 }
161 else if (!strcmp(a->argv[1], "savestate"))
162 {
163 /* first pause so we don't trigger a live save which needs more time/resources */
164 rc = console->Pause();
165 if (FAILED(rc))
166 {
167 if (rc == VBOX_E_INVALID_VM_STATE)
168 {
169 /* check if we are already paused */
170 MachineState_T machineState;
171 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
172 if (machineState != MachineState_Paused)
173 {
174 RTMsgError("Machine in invalid state %d -- %s\n",
175 machineState, stateToName(machineState, false));
176 break;
177 }
178 }
179 }
180
181 ComPtr<IProgress> progress;
182 CHECK_ERROR(console, SaveState(progress.asOutParam()));
183 if (FAILED(rc))
184 {
185 console->Resume();
186 break;
187 }
188
189 rc = showProgress(progress);
190 if (FAILED(rc))
191 {
192 com::ProgressErrorInfo info(progress);
193 if (info.isBasicAvailable())
194 RTMsgError("Failed to save machine state. Error message: %lS", info.getText().raw());
195 else
196 RTMsgError("Failed to save machine state. No error message available!");
197 console->Resume();
198 }
199 }
200 else if (!strcmp(a->argv[1], "acpipowerbutton"))
201 {
202 CHECK_ERROR_BREAK(console, PowerButton());
203 }
204 else if (!strcmp(a->argv[1], "acpisleepbutton"))
205 {
206 CHECK_ERROR_BREAK(console, SleepButton());
207 }
208 else if (!strcmp(a->argv[1], "keyboardputscancode"))
209 {
210 ComPtr<IKeyboard> keyboard;
211 CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(keyboard.asOutParam()));
212
213 if (a->argc <= 1 + 1)
214 {
215 errorArgument("Missing argument to '%s'. Expected IBM PC AT set 2 keyboard scancode(s) as hex byte(s).", a->argv[1]);
216 rc = E_FAIL;
217 break;
218 }
219
220 std::list<LONG> llScancodes;
221
222 /* Process the command line. */
223 int i;
224 for (i = 1 + 1; i < a->argc; i++)
225 {
226 if ( RT_C_IS_XDIGIT (a->argv[i][0])
227 && RT_C_IS_XDIGIT (a->argv[i][1])
228 && a->argv[i][2] == 0)
229 {
230 uint8_t u8Scancode;
231 int irc = RTStrToUInt8Ex(a->argv[i], NULL, 16, &u8Scancode);
232 if (RT_FAILURE (irc))
233 {
234 RTMsgError("Converting '%s' returned %Rrc!", a->argv[i], rc);
235 rc = E_FAIL;
236 break;
237 }
238
239 llScancodes.push_back(u8Scancode);
240 }
241 else
242 {
243 RTMsgError("Error: '%s' is not a hex byte!", a->argv[i]);
244 rc = E_FAIL;
245 break;
246 }
247 }
248
249 if (FAILED(rc))
250 break;
251
252 /* Send scancodes to the VM. */
253 com::SafeArray<LONG> saScancodes(llScancodes);
254 ULONG codesStored = 0;
255 CHECK_ERROR_BREAK(keyboard, PutScancodes(ComSafeArrayAsInParam(saScancodes),
256 &codesStored));
257 if (codesStored < saScancodes.size())
258 {
259 RTMsgError("Only %d scancodes were stored", codesStored);
260 rc = E_FAIL;
261 break;
262 }
263 }
264 else if (!strncmp(a->argv[1], "setlinkstate", 12))
265 {
266 /* Get the number of network adapters */
267 ULONG NetworkAdapterCount = 0;
268 ComPtr <ISystemProperties> info;
269 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(SystemProperties)(info.asOutParam()));
270 CHECK_ERROR_BREAK(info, COMGETTER(NetworkAdapterCount)(&NetworkAdapterCount));
271
272 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
273 if (!n)
274 {
275 rc = E_FAIL;
276 break;
277 }
278 if (a->argc <= 1 + 1)
279 {
280 errorArgument("Missing argument to '%s'", a->argv[1]);
281 rc = E_FAIL;
282 break;
283 }
284 /* get the corresponding network adapter */
285 ComPtr<INetworkAdapter> adapter;
286 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
287 if (adapter)
288 {
289 if (!strcmp(a->argv[2], "on"))
290 {
291 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(TRUE));
292 }
293 else if (!strcmp(a->argv[2], "off"))
294 {
295 CHECK_ERROR_BREAK(adapter, COMSETTER(CableConnected)(FALSE));
296 }
297 else
298 {
299 errorArgument("Invalid link state '%s'", Utf8Str(a->argv[2]).c_str());
300 rc = E_FAIL;
301 break;
302 }
303 }
304 }
305 /* here the order in which strncmp is called is important
306 * cause nictracefile can be very well compared with
307 * nictrace and nic and thus everything will always fail
308 * if the order is changed
309 */
310 else if (!strncmp(a->argv[1], "nictracefile", 12))
311 {
312 /* Get the number of network adapters */
313 ULONG NetworkAdapterCount = 0;
314 ComPtr <ISystemProperties> info;
315 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(SystemProperties)(info.asOutParam()));
316 CHECK_ERROR_BREAK(info, COMGETTER(NetworkAdapterCount)(&NetworkAdapterCount));
317
318 unsigned n = parseNum(&a->argv[1][12], NetworkAdapterCount, "NIC");
319 if (!n)
320 {
321 rc = E_FAIL;
322 break;
323 }
324 if (a->argc <= 2)
325 {
326 errorArgument("Missing argument to '%s'", a->argv[1]);
327 rc = E_FAIL;
328 break;
329 }
330
331 /* get the corresponding network adapter */
332 ComPtr<INetworkAdapter> adapter;
333 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
334 if (adapter)
335 {
336 BOOL fEnabled;
337 adapter->COMGETTER(Enabled)(&fEnabled);
338 if (fEnabled)
339 {
340 if (a->argv[2])
341 {
342 CHECK_ERROR_RET(adapter, COMSETTER(TraceFile)(Bstr(a->argv[2]).raw()), 1);
343 }
344 else
345 {
346 errorArgument("Invalid filename or filename not specified for NIC %lu", n);
347 rc = E_FAIL;
348 break;
349 }
350 }
351 else
352 RTMsgError("The NIC %d is currently disabled and thus can't change its tracefile", n);
353 }
354 }
355 else if (!strncmp(a->argv[1], "nictrace", 8))
356 {
357 /* Get the number of network adapters */
358 ULONG NetworkAdapterCount = 0;
359 ComPtr <ISystemProperties> info;
360 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(SystemProperties)(info.asOutParam()));
361 CHECK_ERROR_BREAK(info, COMGETTER(NetworkAdapterCount)(&NetworkAdapterCount));
362
363 unsigned n = parseNum(&a->argv[1][8], NetworkAdapterCount, "NIC");
364 if (!n)
365 {
366 rc = E_FAIL;
367 break;
368 }
369 if (a->argc <= 2)
370 {
371 errorArgument("Missing argument to '%s'", a->argv[1]);
372 rc = E_FAIL;
373 break;
374 }
375
376 /* get the corresponding network adapter */
377 ComPtr<INetworkAdapter> adapter;
378 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
379 if (adapter)
380 {
381 BOOL fEnabled;
382 adapter->COMGETTER(Enabled)(&fEnabled);
383 if (fEnabled)
384 {
385 if (!strcmp(a->argv[2], "on"))
386 {
387 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(TRUE), 1);
388 }
389 else if (!strcmp(a->argv[2], "off"))
390 {
391 CHECK_ERROR_RET(adapter, COMSETTER(TraceEnabled)(FALSE), 1);
392 }
393 else
394 {
395 errorArgument("Invalid nictrace%lu argument '%s'", n, Utf8Str(a->argv[2]).c_str());
396 rc = E_FAIL;
397 break;
398 }
399 }
400 else
401 RTMsgError("The NIC %d is currently disabled and thus can't change its trace flag", n);
402 }
403 }
404 else if( a->argc > 2
405 && !strncmp(a->argv[1], "natpf", 5))
406 {
407 /* Get the number of network adapters */
408 ULONG NetworkAdapterCount = 0;
409 ComPtr <ISystemProperties> info;
410 ComPtr<INATEngine> engine;
411 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(SystemProperties)(info.asOutParam()));
412 CHECK_ERROR_BREAK(info, COMGETTER(NetworkAdapterCount)(&NetworkAdapterCount));
413 unsigned n = parseNum(&a->argv[1][5], NetworkAdapterCount, "NIC");
414 if (!n)
415 {
416 rc = E_FAIL;
417 break;
418 }
419 if (a->argc <= 2)
420 {
421 errorArgument("Missing argument to '%s'", a->argv[1]);
422 rc = E_FAIL;
423 break;
424 }
425
426 /* get the corresponding network adapter */
427 ComPtr<INetworkAdapter> adapter;
428 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
429 if (!adapter)
430 {
431 rc = E_FAIL;
432 break;
433 }
434 CHECK_ERROR(adapter, COMGETTER(NatDriver)(engine.asOutParam()));
435 if (!engine)
436 {
437 rc = E_FAIL;
438 break;
439 }
440
441 if (!strcmp(a->argv[2], "delete"))
442 {
443 if (a->argc >= 3)
444 CHECK_ERROR(engine, RemoveRedirect(Bstr(a->argv[3]).raw()));
445 }
446 else
447 {
448#define ITERATE_TO_NEXT_TERM(ch) \
449 do { \
450 while (*ch != ',') \
451 { \
452 if (*ch == 0) \
453 { \
454 return errorSyntax(USAGE_CONTROLVM, \
455 "Missing or invalid argument to '%s'", \
456 a->argv[1]); \
457 } \
458 ch++; \
459 } \
460 *ch = '\0'; \
461 ch++; \
462 } while(0)
463
464 char *strName;
465 char *strProto;
466 char *strHostIp;
467 char *strHostPort;
468 char *strGuestIp;
469 char *strGuestPort;
470 char *strRaw = RTStrDup(a->argv[2]);
471 char *ch = strRaw;
472 strName = RTStrStrip(ch);
473 ITERATE_TO_NEXT_TERM(ch);
474 strProto = RTStrStrip(ch);
475 ITERATE_TO_NEXT_TERM(ch);
476 strHostIp = RTStrStrip(ch);
477 ITERATE_TO_NEXT_TERM(ch);
478 strHostPort = RTStrStrip(ch);
479 ITERATE_TO_NEXT_TERM(ch);
480 strGuestIp = RTStrStrip(ch);
481 ITERATE_TO_NEXT_TERM(ch);
482 strGuestPort = RTStrStrip(ch);
483 NATProtocol_T proto;
484 if (RTStrICmp(strProto, "udp") == 0)
485 proto = NATProtocol_UDP;
486 else if (RTStrICmp(strProto, "tcp") == 0)
487 proto = NATProtocol_TCP;
488 else
489 {
490 return errorSyntax(USAGE_CONTROLVM,
491 "Wrong rule proto '%s' specified -- only 'udp' and 'tcp' are allowed.",
492 strProto);
493 }
494 CHECK_ERROR(engine, AddRedirect(Bstr(strName).raw(), proto, Bstr(strHostIp).raw(),
495 RTStrToUInt16(strHostPort), Bstr(strGuestIp).raw(), RTStrToUInt16(strGuestPort)));
496#undef ITERATE_TO_NEXT_TERM
497 }
498 /* commit changes */
499 if (SUCCEEDED(rc))
500 CHECK_ERROR(sessionMachine, SaveSettings());
501 }
502 else if (!strncmp(a->argv[1], "nic", 3))
503 {
504 /* Get the number of network adapters */
505 ULONG NetworkAdapterCount = 0;
506 ComPtr <ISystemProperties> info;
507 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(SystemProperties)(info.asOutParam()));
508 CHECK_ERROR_BREAK(info, COMGETTER(NetworkAdapterCount)(&NetworkAdapterCount));
509
510 unsigned n = parseNum(&a->argv[1][3], NetworkAdapterCount, "NIC");
511 if (!n)
512 {
513 rc = E_FAIL;
514 break;
515 }
516 if (a->argc <= 2)
517 {
518 errorArgument("Missing argument to '%s'", a->argv[1]);
519 rc = E_FAIL;
520 break;
521 }
522
523 /* get the corresponding network adapter */
524 ComPtr<INetworkAdapter> adapter;
525 CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
526 if (adapter)
527 {
528 BOOL fEnabled;
529 adapter->COMGETTER(Enabled)(&fEnabled);
530 if (fEnabled)
531 {
532 if (!strcmp(a->argv[2], "null"))
533 {
534 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
535 CHECK_ERROR_RET(adapter, Detach(), 1);
536 }
537 else if (!strcmp(a->argv[2], "nat"))
538 {
539 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
540 if (a->argc == 4)
541 CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), 1);
542 CHECK_ERROR_RET(adapter, AttachToNAT(), 1);
543 }
544 else if ( !strcmp(a->argv[2], "bridged")
545 || !strcmp(a->argv[2], "hostif")) /* backward compatibility */
546 {
547 if (a->argc <= 3)
548 {
549 errorArgument("Missing argument to '%s'", a->argv[2]);
550 rc = E_FAIL;
551 break;
552 }
553 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
554 CHECK_ERROR_RET(adapter, COMSETTER(HostInterface)(Bstr(a->argv[3]).raw()), 1);
555 CHECK_ERROR_RET(adapter, AttachToBridgedInterface(), 1);
556 }
557 else if (!strcmp(a->argv[2], "intnet"))
558 {
559 if (a->argc <= 3)
560 {
561 errorArgument("Missing argument to '%s'", a->argv[2]);
562 rc = E_FAIL;
563 break;
564 }
565 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
566 CHECK_ERROR_RET(adapter, COMSETTER(InternalNetwork)(Bstr(a->argv[3]).raw()), 1);
567 CHECK_ERROR_RET(adapter, AttachToInternalNetwork(), 1);
568 }
569#if defined(VBOX_WITH_NETFLT)
570 else if (!strcmp(a->argv[2], "hostonly"))
571 {
572 if (a->argc <= 3)
573 {
574 errorArgument("Missing argument to '%s'", a->argv[2]);
575 rc = E_FAIL;
576 break;
577 }
578 CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
579 CHECK_ERROR_RET(adapter, COMSETTER(HostInterface)(Bstr(a->argv[3]).raw()), 1);
580 CHECK_ERROR_RET(adapter, AttachToHostOnlyInterface(), 1);
581 }
582#endif
583 else
584 {
585 errorArgument("Invalid type '%s' specfied for NIC %lu", Utf8Str(a->argv[2]).c_str(), n);
586 rc = E_FAIL;
587 break;
588 }
589 }
590 else
591 RTMsgError("The NIC %d is currently disabled and thus can't change its attachment type", n);
592 }
593 }
594 else if ( !strcmp(a->argv[1], "vrde")
595 || !strcmp(a->argv[1], "vrdp"))
596 {
597 if (!strcmp(a->argv[1], "vrdp"))
598 RTStrmPrintf(g_pStdErr, "Warning: 'vrdp' is deprecated. Use 'vrde'.\n");
599
600 if (a->argc <= 1 + 1)
601 {
602 errorArgument("Missing argument to '%s'", a->argv[1]);
603 rc = E_FAIL;
604 break;
605 }
606 ComPtr<IVRDEServer> vrdeServer;
607 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
608 ASSERT(vrdeServer);
609 if (vrdeServer)
610 {
611 if (!strcmp(a->argv[2], "on"))
612 {
613 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(TRUE));
614 }
615 else if (!strcmp(a->argv[2], "off"))
616 {
617 CHECK_ERROR_BREAK(vrdeServer, COMSETTER(Enabled)(FALSE));
618 }
619 else
620 {
621 errorArgument("Invalid remote desktop server state '%s'", Utf8Str(a->argv[2]).c_str());
622 rc = E_FAIL;
623 break;
624 }
625 }
626 }
627 else if ( !strcmp(a->argv[1], "vrdeport")
628 || !strcmp(a->argv[1], "vrdpport"))
629 {
630 if (!strcmp(a->argv[1], "vrdpport"))
631 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpport' is deprecated. Use 'vrdeport'.\n");
632
633 if (a->argc <= 1 + 1)
634 {
635 errorArgument("Missing argument to '%s'", a->argv[1]);
636 rc = E_FAIL;
637 break;
638 }
639
640 ComPtr<IVRDEServer> vrdeServer;
641 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
642 ASSERT(vrdeServer);
643 if (vrdeServer)
644 {
645 Bstr ports;
646
647 if (!strcmp(a->argv[2], "default"))
648 ports = "0";
649 else
650 ports = a->argv[2];
651
652 CHECK_ERROR_BREAK(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), ports.raw()));
653 }
654 }
655 else if ( !strcmp(a->argv[1], "vrdevideochannelquality")
656 || !strcmp(a->argv[1], "vrdpvideochannelquality"))
657 {
658 if (!strcmp(a->argv[1], "vrdpvideochannelquality"))
659 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpvideochannelquality' is deprecated. Use 'vrdevideochannelquality'.\n");
660
661 if (a->argc <= 1 + 1)
662 {
663 errorArgument("Missing argument to '%s'", a->argv[1]);
664 rc = E_FAIL;
665 break;
666 }
667 ComPtr<IVRDEServer> vrdeServer;
668 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
669 ASSERT(vrdeServer);
670 if (vrdeServer)
671 {
672 Bstr value = a->argv[2];
673
674 CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("VideoChannel/Quality").raw(), value.raw()));
675 }
676 }
677 else if (!strcmp(a->argv[1], "vrdeproperty"))
678 {
679 if (a->argc <= 1 + 1)
680 {
681 errorArgument("Missing argument to '%s'", a->argv[1]);
682 rc = E_FAIL;
683 break;
684 }
685 ComPtr<IVRDEServer> vrdeServer;
686 sessionMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
687 ASSERT(vrdeServer);
688 if (vrdeServer)
689 {
690 /* Parse 'name=value' */
691 char *pszProperty = RTStrDup(a->argv[2]);
692 if (pszProperty)
693 {
694 char *pDelimiter = strchr(pszProperty, '=');
695 if (pDelimiter)
696 {
697 *pDelimiter = '\0';
698
699 Bstr bstrName = pszProperty;
700 Bstr bstrValue = &pDelimiter[1];
701 CHECK_ERROR(vrdeServer, SetVRDEProperty(bstrName.raw(), bstrValue.raw()));
702 }
703 else
704 {
705 errorArgument("Invalid --vrdeproperty argument '%s'", a->argv[2]);
706 rc = E_FAIL;
707 break;
708 }
709 RTStrFree(pszProperty);
710 }
711 else
712 {
713 RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for VRDE property '%s'\n", a->argv[2]);
714 rc = E_FAIL;
715 }
716 }
717 if (FAILED(rc))
718 {
719 break;
720 }
721 }
722 else if ( !strcmp(a->argv[1], "usbattach")
723 || !strcmp(a->argv[1], "usbdetach"))
724 {
725 if (a->argc < 3)
726 {
727 errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
728 rc = E_FAIL;
729 break;
730 }
731
732 bool attach = !strcmp(a->argv[1], "usbattach");
733
734 Bstr usbId = a->argv[2];
735 if (Guid(usbId).isEmpty())
736 {
737 // assume address
738 if (attach)
739 {
740 ComPtr <IHost> host;
741 CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
742 SafeIfaceArray <IHostUSBDevice> coll;
743 CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
744 ComPtr <IHostUSBDevice> dev;
745 CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
746 dev.asOutParam()));
747 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
748 }
749 else
750 {
751 SafeIfaceArray <IUSBDevice> coll;
752 CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
753 ComPtr <IUSBDevice> dev;
754 CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
755 dev.asOutParam()));
756 CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
757 }
758 }
759
760 if (attach)
761 CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw()));
762 else
763 {
764 ComPtr <IUSBDevice> dev;
765 CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
766 dev.asOutParam()));
767 }
768 }
769 else if (!strcmp(a->argv[1], "setvideomodehint"))
770 {
771 if (a->argc != 5 && a->argc != 6)
772 {
773 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
774 rc = E_FAIL;
775 break;
776 }
777 uint32_t xres = RTStrToUInt32(a->argv[2]);
778 uint32_t yres = RTStrToUInt32(a->argv[3]);
779 uint32_t bpp = RTStrToUInt32(a->argv[4]);
780 uint32_t displayIdx = 0;
781 if (a->argc == 6)
782 displayIdx = RTStrToUInt32(a->argv[5]);
783
784 ComPtr<IDisplay> display;
785 CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));
786 CHECK_ERROR_BREAK(display, SetVideoModeHint(xres, yres, bpp, displayIdx));
787 }
788 else if (!strcmp(a->argv[1], "setcredentials"))
789 {
790 bool fAllowLocalLogon = true;
791 if (a->argc == 7)
792 {
793 if ( strcmp(a->argv[5], "--allowlocallogon")
794 && strcmp(a->argv[5], "-allowlocallogon"))
795 {
796 errorArgument("Invalid parameter '%s'", a->argv[5]);
797 rc = E_FAIL;
798 break;
799 }
800 if (!strcmp(a->argv[6], "no"))
801 fAllowLocalLogon = false;
802 }
803 else if (a->argc != 5)
804 {
805 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
806 rc = E_FAIL;
807 break;
808 }
809
810 ComPtr<IGuest> guest;
811 CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
812 CHECK_ERROR_BREAK(guest, SetCredentials(Bstr(a->argv[2]).raw(),
813 Bstr(a->argv[3]).raw(),
814 Bstr(a->argv[4]).raw(),
815 fAllowLocalLogon));
816 }
817#if 0 /* TODO: review & remove */
818 else if (!strcmp(a->argv[1], "dvdattach"))
819 {
820 Bstr uuid;
821 if (a->argc != 3)
822 {
823 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
824 rc = E_FAIL;
825 break;
826 }
827
828 ComPtr<IMedium> dvdMedium;
829
830 /* unmount? */
831 if (!strcmp(a->argv[2], "none"))
832 {
833 /* nothing to do, NULL object will cause unmount */
834 }
835 /* host drive? */
836 else if (!strncmp(a->argv[2], "host:", 5))
837 {
838 ComPtr<IHost> host;
839 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
840
841 rc = host->FindHostDVDDrive(Bstr(a->argv[2] + 5), dvdMedium.asOutParam());
842 if (!dvdMedium)
843 {
844 errorArgument("Invalid host DVD drive name \"%s\"",
845 a->argv[2] + 5);
846 rc = E_FAIL;
847 break;
848 }
849 }
850 else
851 {
852 /* first assume it's a UUID */
853 uuid = a->argv[2];
854 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
855 if (FAILED(rc) || !dvdMedium)
856 {
857 /* must be a filename, check if it's in the collection */
858 rc = a->virtualBox->FindDVDImage(Bstr(a->argv[2]), dvdMedium.asOutParam());
859 /* not registered, do that on the fly */
860 if (!dvdMedium)
861 {
862 Bstr emptyUUID;
863 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(a->argv[2]), emptyUUID, dvdMedium.asOutParam()));
864 }
865 }
866 if (!dvdMedium)
867 {
868 rc = E_FAIL;
869 break;
870 }
871 }
872
873 /** @todo generalize this, allow arbitrary number of DVD drives
874 * and as a consequence multiple attachments and different
875 * storage controllers. */
876 if (dvdMedium)
877 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
878 else
879 uuid = Guid().toString();
880 CHECK_ERROR(machine, MountMedium(Bstr("IDE Controller"), 1, 0, uuid, FALSE /* aForce */));
881 }
882 else if (!strcmp(a->argv[1], "floppyattach"))
883 {
884 Bstr uuid;
885 if (a->argc != 3)
886 {
887 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
888 rc = E_FAIL;
889 break;
890 }
891
892 ComPtr<IMedium> floppyMedium;
893
894 /* unmount? */
895 if (!strcmp(a->argv[2], "none"))
896 {
897 /* nothing to do, NULL object will cause unmount */
898 }
899 /* host drive? */
900 else if (!strncmp(a->argv[2], "host:", 5))
901 {
902 ComPtr<IHost> host;
903 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
904 host->FindHostFloppyDrive(Bstr(a->argv[2] + 5), floppyMedium.asOutParam());
905 if (!floppyMedium)
906 {
907 errorArgument("Invalid host floppy drive name \"%s\"",
908 a->argv[2] + 5);
909 rc = E_FAIL;
910 break;
911 }
912 }
913 else
914 {
915 /* first assume it's a UUID */
916 uuid = a->argv[2];
917 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
918 if (FAILED(rc) || !floppyMedium)
919 {
920 /* must be a filename, check if it's in the collection */
921 rc = a->virtualBox->FindFloppyImage(Bstr(a->argv[2]), floppyMedium.asOutParam());
922 /* not registered, do that on the fly */
923 if (!floppyMedium)
924 {
925 Bstr emptyUUID;
926 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(a->argv[2]), emptyUUID, floppyMedium.asOutParam()));
927 }
928 }
929 if (!floppyMedium)
930 {
931 rc = E_FAIL;
932 break;
933 }
934 }
935 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
936 CHECK_ERROR(machine, MountMedium(Bstr("Floppy Controller"), 0, 0, uuid, FALSE /* aForce */));
937 }
938#endif /* obsolete dvdattach/floppyattach */
939 else if (!strcmp(a->argv[1], "guestmemoryballoon"))
940 {
941 if (a->argc != 3)
942 {
943 errorSyntax(USAGE_CONTROLVM, "Incorrect number of parameters");
944 rc = E_FAIL;
945 break;
946 }
947 uint32_t uVal;
948 int vrc;
949 vrc = RTStrToUInt32Ex(a->argv[2], NULL, 0, &uVal);
950 if (vrc != VINF_SUCCESS)
951 {
952 errorArgument("Error parsing guest memory balloon size '%s'", a->argv[2]);
953 rc = E_FAIL;
954 break;
955 }
956 /* guest is running; update IGuest */
957 ComPtr <IGuest> guest;
958 rc = console->COMGETTER(Guest)(guest.asOutParam());
959 if (SUCCEEDED(rc))
960 CHECK_ERROR(guest, COMSETTER(MemoryBalloonSize)(uVal));
961 }
962 else if (!strcmp(a->argv[1], "teleport"))
963 {
964 Bstr bstrHostname;
965 uint32_t uMaxDowntime = 250 /*ms*/;
966 uint32_t uPort = UINT32_MAX;
967 uint32_t cMsTimeout = 0;
968 Bstr bstrPassword("");
969 static const RTGETOPTDEF s_aTeleportOptions[] =
970 {
971 { "--host", 'h', RTGETOPT_REQ_STRING }, /** @todo RTGETOPT_FLAG_MANDATORY */
972 { "--hostname", 'h', RTGETOPT_REQ_STRING }, /** @todo remove this */
973 { "--maxdowntime", 'd', RTGETOPT_REQ_UINT32 },
974 { "--port", 'p', RTGETOPT_REQ_UINT32 }, /** @todo RTGETOPT_FLAG_MANDATORY */
975 { "--password", 'P', RTGETOPT_REQ_STRING },
976 { "--timeout", 't', RTGETOPT_REQ_UINT32 },
977 { "--detailed-progress", 'D', RTGETOPT_REQ_NOTHING }
978 };
979 RTGETOPTSTATE GetOptState;
980 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTeleportOptions, RT_ELEMENTS(s_aTeleportOptions), 2, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
981 int ch;
982 RTGETOPTUNION Value;
983 while ( SUCCEEDED(rc)
984 && (ch = RTGetOpt(&GetOptState, &Value)))
985 {
986 switch (ch)
987 {
988 case 'h': bstrHostname = Value.psz; break;
989 case 'd': uMaxDowntime = Value.u32; break;
990 case 'D': g_fDetailedProgress = true; break;
991 case 'p': uPort = Value.u32; break;
992 case 'P': bstrPassword = Value.psz; break;
993 case 't': cMsTimeout = Value.u32; break;
994 default:
995 errorGetOpt(USAGE_CONTROLVM, ch, &Value);
996 rc = E_FAIL;
997 break;
998 }
999 }
1000 if (FAILED(rc))
1001 break;
1002
1003 ComPtr<IProgress> progress;
1004 CHECK_ERROR_BREAK(console, Teleport(bstrHostname.raw(), uPort,
1005 bstrPassword.raw(),
1006 uMaxDowntime,
1007 progress.asOutParam()));
1008
1009 if (cMsTimeout)
1010 {
1011 rc = progress->COMSETTER(Timeout)(cMsTimeout);
1012 if (FAILED(rc) && rc != VBOX_E_INVALID_OBJECT_STATE)
1013 CHECK_ERROR_BREAK(progress, COMSETTER(Timeout)(cMsTimeout)); /* lazyness */
1014 }
1015
1016 rc = showProgress(progress);
1017 if (FAILED(rc))
1018 {
1019 com::ProgressErrorInfo info(progress);
1020 if (info.isBasicAvailable())
1021 RTMsgError("Teleportation failed. Error message: %lS", info.getText().raw());
1022 else
1023 RTMsgError("Teleportation failed. No error message available!");
1024 }
1025 }
1026 else
1027 {
1028 errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
1029 rc = E_FAIL;
1030 }
1031 } while (0);
1032
1033 a->session->UnlockMachine();
1034
1035 return SUCCEEDED(rc) ? 0 : 1;
1036}
1037
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