VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageBandwidthControl.cpp@ 94234

Last change on this file since 94234 was 94234, checked in by vboxsync, 3 years ago

FE/VBoxManage: Remove the now unused VBoxManageHelp build target and the VBOX_ONLY_DOCS #ifdef's in the code, ​bugref:9186

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: VBoxManageBandwidthControl.cpp 94234 2022-03-15 09:19:29Z vboxsync $ */
2/** @file
3 * VBoxManage - The bandwidth control related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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* Header Files *
20*********************************************************************************************************************************/
21#include <VBox/com/com.h>
22#include <VBox/com/array.h>
23#include <VBox/com/ErrorInfo.h>
24#include <VBox/com/errorprint.h>
25#include <VBox/com/VirtualBox.h>
26
27#include <iprt/err.h>
28#include <iprt/path.h>
29#include <iprt/param.h>
30#include <iprt/string.h>
31#include <iprt/ctype.h>
32#include <iprt/stream.h>
33#include <iprt/getopt.h>
34#include <VBox/log.h>
35
36#include "VBoxManage.h"
37using namespace com;
38
39DECLARE_TRANSLATION_CONTEXT(BWControl);
40
41// funcs
42///////////////////////////////////////////////////////////////////////////////
43
44
45/**
46 * Parses a string in the following format "n[k|m|g|K|M|G]". Stores the value
47 * of n expressed in bytes to *pLimit. k meas kilobit, while K means kilobyte.
48 *
49 * @returns Error message or NULL if successful.
50 * @param pcszLimit The string to parse.
51 * @param pLimit Where to store the result.
52 */
53static const char *parseLimit(const char *pcszLimit, int64_t *pLimit)
54{
55 int iMultiplier = _1M;
56 char *pszNext = NULL;
57 int rc = RTStrToInt64Ex(pcszLimit, &pszNext, 10, pLimit);
58
59 switch (rc)
60 {
61 case VINF_SUCCESS:
62 break;
63 case VWRN_NUMBER_TOO_BIG:
64 return BWControl::tr("Limit is too big\n");
65 case VWRN_TRAILING_CHARS:
66 switch (*pszNext)
67 {
68 case 'G': iMultiplier = _1G; break;
69 case 'M': iMultiplier = _1M; break;
70 case 'K': iMultiplier = _1K; break;
71 case 'g': iMultiplier = 125000000; break;
72 case 'm': iMultiplier = 125000; break;
73 case 'k': iMultiplier = 125; break;
74 default: return BWControl::tr("Invalid unit suffix. Valid suffixes are: k, m, g, K, M, G\n");
75 }
76 break;
77 case VWRN_TRAILING_SPACES:
78 return BWControl::tr("Trailing spaces in limit!\n");
79 case VERR_NO_DIGITS:
80 return BWControl::tr("No digits in limit specifier\n");
81 default:
82 return BWControl::tr("Invalid limit specifier\n");
83 }
84 if (*pLimit < 0)
85 return BWControl::tr("Limit cannot be negative\n");
86 if (*pLimit > INT64_MAX / iMultiplier)
87 return BWControl::tr("Limit is too big\n");
88 *pLimit *= iMultiplier;
89
90 return NULL;
91}
92
93/**
94 * Handles the 'bandwidthctl myvm add' sub-command.
95 * @returns Exit code.
96 * @param a The handler argument package.
97 * @param bwCtrl Reference to the bandwidth control interface.
98 */
99static RTEXITCODE handleBandwidthControlAdd(HandlerArg *a, ComPtr<IBandwidthControl> &bwCtrl)
100{
101 HRESULT rc = S_OK;
102 static const RTGETOPTDEF g_aBWCtlAddOptions[] =
103 {
104 { "--type", 't', RTGETOPT_REQ_STRING },
105 { "--limit", 'l', RTGETOPT_REQ_STRING }
106 };
107
108 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_ADD);
109
110 Bstr name(a->argv[2]);
111 if (name.isEmpty())
112 {
113 errorArgument(BWControl::tr("Bandwidth group name must not be empty!\n"));
114 return RTEXITCODE_FAILURE;
115 }
116
117 const char *pszType = NULL;
118 int64_t cMaxBytesPerSec = INT64_MAX;
119
120 int c;
121 RTGETOPTUNION ValueUnion;
122 RTGETOPTSTATE GetState;
123 RTGetOptInit(&GetState, a->argc, a->argv, g_aBWCtlAddOptions,
124 RT_ELEMENTS(g_aBWCtlAddOptions), 3, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
125
126 while ( SUCCEEDED(rc)
127 && (c = RTGetOpt(&GetState, &ValueUnion)))
128 {
129 switch (c)
130 {
131 case 't': // bandwidth group type
132 {
133 if (ValueUnion.psz)
134 pszType = ValueUnion.psz;
135 else
136 rc = E_FAIL;
137 break;
138 }
139
140 case 'l': // limit
141 {
142 if (ValueUnion.psz)
143 {
144 const char *pcszError = parseLimit(ValueUnion.psz, &cMaxBytesPerSec);
145 if (pcszError)
146 {
147 errorArgument(pcszError);
148 return RTEXITCODE_FAILURE;
149 }
150 }
151 else
152 rc = E_FAIL;
153 break;
154 }
155
156 default:
157 {
158 errorGetOpt(c, &ValueUnion);
159 rc = E_FAIL;
160 break;
161 }
162 }
163 }
164
165 BandwidthGroupType_T enmType;
166
167 if (!RTStrICmp(pszType, "disk"))
168 enmType = BandwidthGroupType_Disk;
169 else if (!RTStrICmp(pszType, "network"))
170 enmType = BandwidthGroupType_Network;
171 else
172 {
173 errorArgument(BWControl::tr("Invalid bandwidth group type\n"));
174 return RTEXITCODE_FAILURE;
175 }
176
177 CHECK_ERROR2I_RET(bwCtrl, CreateBandwidthGroup(name.raw(), enmType, (LONG64)cMaxBytesPerSec), RTEXITCODE_FAILURE);
178
179 return RTEXITCODE_SUCCESS;
180}
181
182/**
183 * Handles the 'bandwidthctl myvm set' sub-command.
184 * @returns Exit code.
185 * @param a The handler argument package.
186 * @param bwCtrl Reference to the bandwidth control interface.
187 */
188static RTEXITCODE handleBandwidthControlSet(HandlerArg *a, ComPtr<IBandwidthControl> &bwCtrl)
189{
190 HRESULT rc = S_OK;
191 static const RTGETOPTDEF g_aBWCtlAddOptions[] =
192 {
193 { "--limit", 'l', RTGETOPT_REQ_STRING }
194 };
195
196 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_SET);
197
198 Bstr name(a->argv[2]);
199 int64_t cMaxBytesPerSec = INT64_MAX;
200
201 int c;
202 RTGETOPTUNION ValueUnion;
203 RTGETOPTSTATE GetState;
204 RTGetOptInit(&GetState, a->argc, a->argv, g_aBWCtlAddOptions,
205 RT_ELEMENTS(g_aBWCtlAddOptions), 3, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
206
207 while ( SUCCEEDED(rc)
208 && (c = RTGetOpt(&GetState, &ValueUnion)))
209 {
210 switch (c)
211 {
212 case 'l': // limit
213 {
214 if (ValueUnion.psz)
215 {
216 const char *pcszError = parseLimit(ValueUnion.psz, &cMaxBytesPerSec);
217 if (pcszError)
218 {
219 errorArgument(pcszError);
220 return RTEXITCODE_FAILURE;
221 }
222 }
223 else
224 rc = E_FAIL;
225 break;
226 }
227
228 default:
229 {
230 errorGetOpt(c, &ValueUnion);
231 rc = E_FAIL;
232 break;
233 }
234 }
235 }
236
237
238 if (cMaxBytesPerSec != INT64_MAX)
239 {
240 ComPtr<IBandwidthGroup> bwGroup;
241 CHECK_ERROR2I_RET(bwCtrl, GetBandwidthGroup(name.raw(), bwGroup.asOutParam()), RTEXITCODE_FAILURE);
242 if (SUCCEEDED(rc))
243 {
244 CHECK_ERROR2I_RET(bwGroup, COMSETTER(MaxBytesPerSec)((LONG64)cMaxBytesPerSec), RTEXITCODE_FAILURE);
245 }
246 }
247
248 return RTEXITCODE_SUCCESS;
249}
250
251/**
252 * Handles the 'bandwidthctl myvm remove' sub-command.
253 * @returns Exit code.
254 * @param a The handler argument package.
255 * @param bwCtrl Reference to the bandwidth control interface.
256 */
257static RTEXITCODE handleBandwidthControlRemove(HandlerArg *a, ComPtr<IBandwidthControl> &bwCtrl)
258{
259 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_REMOVE);
260
261 Bstr name(a->argv[2]);
262 CHECK_ERROR2I_RET(bwCtrl, DeleteBandwidthGroup(name.raw()), RTEXITCODE_FAILURE);
263 return RTEXITCODE_SUCCESS;
264}
265
266/**
267 * Handles the 'bandwidthctl myvm list' sub-command.
268 * @returns Exit code.
269 * @param a The handler argument package.
270 * @param bwCtrl Reference to the bandwidth control interface.
271 */
272static RTEXITCODE handleBandwidthControlList(HandlerArg *pArgs, ComPtr<IBandwidthControl> &rptrBWControl)
273{
274 static const RTGETOPTDEF g_aOptions[] =
275 {
276 { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING },
277 };
278
279 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_LIST);
280 VMINFO_DETAILS enmDetails = VMINFO_STANDARD;
281
282 int c;
283 RTGETOPTUNION ValueUnion;
284 RTGETOPTSTATE GetState;
285 RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, g_aOptions, RT_ELEMENTS(g_aOptions), 2 /*iArg*/, 0 /*fFlags*/);
286 while ((c = RTGetOpt(&GetState, &ValueUnion)))
287 {
288 switch (c)
289 {
290 case 'M':
291 enmDetails = VMINFO_MACHINEREADABLE;
292 break;
293 default:
294 return errorGetOpt(c, &ValueUnion);
295 }
296 }
297
298 if (FAILED(showBandwidthGroups(rptrBWControl, enmDetails)))
299 return RTEXITCODE_FAILURE;
300
301 return RTEXITCODE_SUCCESS;
302}
303
304
305/**
306 * Handles the 'bandwidthctl' command.
307 * @returns Exit code.
308 * @param a The handler argument package.
309 */
310RTEXITCODE handleBandwidthControl(HandlerArg *a)
311{
312 HRESULT rc = S_OK;
313 ComPtr<IMachine> machine;
314 ComPtr<IBandwidthControl> bwCtrl;
315
316 if (a->argc < 2)
317 return errorSyntax(BWControl::tr("Too few parameters"));
318 else if (a->argc > 7)
319 return errorSyntax(BWControl::tr("Too many parameters"));
320
321 /* try to find the given machine */
322 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
323 machine.asOutParam()), RTEXITCODE_FAILURE);
324
325 /* open a session for the VM (new or shared) */
326 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
327 SessionType_T st;
328 CHECK_ERROR_RET(a->session, COMGETTER(Type)(&st), RTEXITCODE_FAILURE);
329 bool fRunTime = (st == SessionType_Shared);
330
331 /* get the mutable session machine */
332 a->session->COMGETTER(Machine)(machine.asOutParam());
333 rc = machine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam());
334 if (FAILED(rc)) goto leave;
335
336 if (!strcmp(a->argv[1], "add"))
337 {
338 if (fRunTime)
339 {
340 errorArgument(BWControl::tr("Bandwidth groups cannot be created while the VM is running\n"));
341 goto leave;
342 }
343 rc = handleBandwidthControlAdd(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
344 }
345 else if (!strcmp(a->argv[1], "remove"))
346 {
347 if (fRunTime)
348 {
349 errorArgument(BWControl::tr("Bandwidth groups cannot be deleted while the VM is running\n"));
350 goto leave;
351 }
352 rc = handleBandwidthControlRemove(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
353 }
354 else if (!strcmp(a->argv[1], "set"))
355 rc = handleBandwidthControlSet(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
356 else if (!strcmp(a->argv[1], "list"))
357 rc = handleBandwidthControlList(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
358 else
359 {
360 errorSyntax(BWControl::tr("Invalid parameter '%s'"), a->argv[1]);
361 rc = E_FAIL;
362 }
363
364 /* commit changes */
365 if (SUCCEEDED(rc))
366 CHECK_ERROR(machine, SaveSettings());
367
368leave:
369 /* it's important to always close sessions */
370 a->session->UnlockMachine();
371
372 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
373}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette