VirtualBox

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

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

Frontends + Main: Adjust to the new rules wrt. to rc -> hrc,vrc usage. This also fixes quite a few bugs wrt shadow variables, wrong return values and output error translations / exit codes. Also see @todos added. ​​bugref:10223

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