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
RevLine 
[34587]1/* $Id: VBoxManageBandwidthControl.cpp 98298 2023-01-25 02:23:33Z vboxsync $ */
2/** @file
3 * VBoxManage - The bandwidth control related commands.
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[34587]8 *
[96407]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
[34587]26 */
27
[94236]28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[34587]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
[76366]38#include <iprt/err.h>
[34587]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
[92372]50DECLARE_TRANSLATION_CONTEXT(BWControl);
[34587]51
52// funcs
53///////////////////////////////////////////////////////////////////////////////
54
55
[40469]56/**
[41842]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 */
[41884]64static const char *parseLimit(const char *pcszLimit, int64_t *pLimit)
[41842]65{
66 int iMultiplier = _1M;
67 char *pszNext = NULL;
[98298]68 int vrc = RTStrToInt64Ex(pcszLimit, &pszNext, 10, pLimit);
[41842]69
[98298]70 switch (vrc)
[41842]71 {
72 case VINF_SUCCESS:
73 break;
74 case VWRN_NUMBER_TOO_BIG:
[92372]75 return BWControl::tr("Limit is too big\n");
[41842]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;
[92372]85 default: return BWControl::tr("Invalid unit suffix. Valid suffixes are: k, m, g, K, M, G\n");
[41842]86 }
87 break;
88 case VWRN_TRAILING_SPACES:
[92372]89 return BWControl::tr("Trailing spaces in limit!\n");
[41842]90 case VERR_NO_DIGITS:
[92372]91 return BWControl::tr("No digits in limit specifier\n");
[41842]92 default:
[92372]93 return BWControl::tr("Invalid limit specifier\n");
[41842]94 }
[41882]95 if (*pLimit < 0)
[92372]96 return BWControl::tr("Limit cannot be negative\n");
[41842]97 if (*pLimit > INT64_MAX / iMultiplier)
[92372]98 return BWControl::tr("Limit is too big\n");
[41842]99 *pLimit *= iMultiplier;
100
101 return NULL;
102}
103
104/**
[40469]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)
[34587]111{
[95140]112 HRESULT hrc = S_OK;
[40469]113 static const RTGETOPTDEF g_aBWCtlAddOptions[] =
114 {
115 { "--type", 't', RTGETOPT_REQ_STRING },
[41842]116 { "--limit", 'l', RTGETOPT_REQ_STRING }
[40469]117 };
[34587]118
[94181]119 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_ADD);
[40469]120
121 Bstr name(a->argv[2]);
[50085]122 if (name.isEmpty())
123 {
[92372]124 errorArgument(BWControl::tr("Bandwidth group name must not be empty!\n"));
[50085]125 return RTEXITCODE_FAILURE;
126 }
127
[34587]128 const char *pszType = NULL;
[41883]129 int64_t cMaxBytesPerSec = INT64_MAX;
[40469]130
131 int c;
[34587]132 RTGETOPTUNION ValueUnion;
133 RTGETOPTSTATE GetState;
[40469]134 RTGetOptInit(&GetState, a->argc, a->argv, g_aBWCtlAddOptions,
135 RT_ELEMENTS(g_aBWCtlAddOptions), 3, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
[34587]136
[95140]137 while ( SUCCEEDED(hrc)
[34587]138 && (c = RTGetOpt(&GetState, &ValueUnion)))
139 {
140 switch (c)
141 {
[40469]142 case 't': // bandwidth group type
[34587]143 {
144 if (ValueUnion.psz)
[40469]145 pszType = ValueUnion.psz;
[34587]146 else
[95140]147 hrc = E_FAIL;
[34587]148 break;
149 }
150
[40469]151 case 'l': // limit
[34587]152 {
[41842]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
[95140]163 hrc = E_FAIL;
[34587]164 break;
165 }
166
[40469]167 default:
[34587]168 {
[94181]169 errorGetOpt(c, &ValueUnion);
[95140]170 hrc = E_FAIL;
[34587]171 break;
172 }
[40469]173 }
174 }
[34587]175
[40469]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 {
[92372]184 errorArgument(BWControl::tr("Invalid bandwidth group type\n"));
[40469]185 return RTEXITCODE_FAILURE;
186 }
[48950]187
[56118]188 CHECK_ERROR2I_RET(bwCtrl, CreateBandwidthGroup(name.raw(), enmType, (LONG64)cMaxBytesPerSec), RTEXITCODE_FAILURE);
[40469]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{
[95140]201 HRESULT hrc = S_OK;
[40469]202 static const RTGETOPTDEF g_aBWCtlAddOptions[] =
203 {
[41842]204 { "--limit", 'l', RTGETOPT_REQ_STRING }
[40469]205 };
206
[94181]207 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_SET);
[40469]208
209 Bstr name(a->argv[2]);
[41883]210 int64_t cMaxBytesPerSec = INT64_MAX;
[40469]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
[95140]218 while ( SUCCEEDED(hrc)
[40469]219 && (c = RTGetOpt(&GetState, &ValueUnion)))
220 {
221 switch (c)
222 {
223 case 'l': // limit
[34587]224 {
[41842]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
[95140]235 hrc = E_FAIL;
[34587]236 break;
237 }
238
239 default:
240 {
[94181]241 errorGetOpt(c, &ValueUnion);
[95140]242 hrc = E_FAIL;
[34587]243 break;
244 }
245 }
246 }
247
[48950]248
[41842]249 if (cMaxBytesPerSec != INT64_MAX)
[40469]250 {
251 ComPtr<IBandwidthGroup> bwGroup;
[56118]252 CHECK_ERROR2I_RET(bwCtrl, GetBandwidthGroup(name.raw(), bwGroup.asOutParam()), RTEXITCODE_FAILURE);
[95140]253 if (SUCCEEDED(hrc))
[56422]254 {
[56118]255 CHECK_ERROR2I_RET(bwGroup, COMSETTER(MaxBytesPerSec)((LONG64)cMaxBytesPerSec), RTEXITCODE_FAILURE);
[56422]256 }
[40469]257 }
[34587]258
[40469]259 return RTEXITCODE_SUCCESS;
260}
[34587]261
[40469]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{
[94181]270 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_REMOVE);
271
[40469]272 Bstr name(a->argv[2]);
[56118]273 CHECK_ERROR2I_RET(bwCtrl, DeleteBandwidthGroup(name.raw()), RTEXITCODE_FAILURE);
[40469]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
[94181]290 setCurrentSubcommand(HELP_SCOPE_BANDWIDTHCTL_LIST);
[40469]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 {
[49621]301 case 'M':
302 enmDetails = VMINFO_MACHINEREADABLE;
303 break;
304 default:
[94181]305 return errorGetOpt(c, &ValueUnion);
[40469]306 }
307 }
308
[40470]309 if (FAILED(showBandwidthGroups(rptrBWControl, enmDetails)))
310 return RTEXITCODE_FAILURE;
[40469]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 */
[56118]321RTEXITCODE handleBandwidthControl(HandlerArg *a)
[40469]322{
[95140]323 HRESULT hrc = S_OK;
[40469]324 ComPtr<IMachine> machine;
325 ComPtr<IBandwidthControl> bwCtrl;
326
327 if (a->argc < 2)
[94181]328 return errorSyntax(BWControl::tr("Too few parameters"));
[40469]329 else if (a->argc > 7)
[94181]330 return errorSyntax(BWControl::tr("Too many parameters"));
[40469]331
[34587]332 /* try to find the given machine */
333 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
[56118]334 machine.asOutParam()), RTEXITCODE_FAILURE);
[34587]335
336 /* open a session for the VM (new or shared) */
[56118]337 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
[34587]338 SessionType_T st;
[56118]339 CHECK_ERROR_RET(a->session, COMGETTER(Type)(&st), RTEXITCODE_FAILURE);
[34587]340 bool fRunTime = (st == SessionType_Shared);
341
342 /* get the mutable session machine */
343 a->session->COMGETTER(Machine)(machine.asOutParam());
[95140]344 hrc = machine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam());
345 if (FAILED(hrc)) goto leave; /** @todo r=andy Argh!! */
[34587]346
[40469]347 if (!strcmp(a->argv[1], "add"))
[34587]348 {
[40469]349 if (fRunTime)
[34587]350 {
[92372]351 errorArgument(BWControl::tr("Bandwidth groups cannot be created while the VM is running\n"));
[34587]352 goto leave;
353 }
[95140]354 hrc = handleBandwidthControlAdd(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
[34587]355 }
[40469]356 else if (!strcmp(a->argv[1], "remove"))
[34587]357 {
[40469]358 if (fRunTime)
359 {
[92372]360 errorArgument(BWControl::tr("Bandwidth groups cannot be deleted while the VM is running\n"));
[40469]361 goto leave;
362 }
[95140]363 hrc = handleBandwidthControlRemove(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
[34587]364 }
[40469]365 else if (!strcmp(a->argv[1], "set"))
[95140]366 hrc = handleBandwidthControlSet(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
[40469]367 else if (!strcmp(a->argv[1], "list"))
[95140]368 hrc = handleBandwidthControlList(a, bwCtrl) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
[40469]369 else
[34587]370 {
[94181]371 errorSyntax(BWControl::tr("Invalid parameter '%s'"), a->argv[1]);
[95140]372 hrc = E_FAIL;
[34587]373 }
374
375 /* commit changes */
[95140]376 if (SUCCEEDED(hrc))
[34587]377 CHECK_ERROR(machine, SaveSettings());
378
379leave:
380 /* it's important to always close sessions */
381 a->session->UnlockMachine();
382
[95140]383 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[34587]384}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use