VirtualBox

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

Last change on this file was 98298, checked in by vboxsync, 16 months ago

VBoxManage: rc -> vrc/hrc. Make scm check. bugref:10223

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

© 2023 Oracle
ContactPrivacy policyTerms of Use