1 | /** $Id: VBoxControl.cpp 10236 2008-07-04 16:06:22Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBoxControl - Guest Additions Command Line Management Interface
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2007 Sun Microsystems, Inc.
|
---|
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 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
---|
18 | * Clara, CA 95054 USA or visit http://www.sun.com if you need
|
---|
19 | * additional information or have any questions.
|
---|
20 | */
|
---|
21 |
|
---|
22 |
|
---|
23 |
|
---|
24 | /*******************************************************************************
|
---|
25 | * Header Files *
|
---|
26 | *******************************************************************************/
|
---|
27 | #include <iprt/thread.h>
|
---|
28 | #include <iprt/string.h>
|
---|
29 | #include <iprt/stream.h>
|
---|
30 | #include <iprt/path.h>
|
---|
31 | #include <iprt/initterm.h>
|
---|
32 | #include <VBox/VBoxGuest.h>
|
---|
33 | #include <VBox/version.h>
|
---|
34 | #ifdef VBOX_WITH_INFO_SVC
|
---|
35 | # include <VBox/HostServices/VBoxInfoSvc.h>
|
---|
36 | #endif
|
---|
37 | #include "VBoxControl.h"
|
---|
38 |
|
---|
39 | /*******************************************************************************
|
---|
40 | * Global Variables *
|
---|
41 | *******************************************************************************/
|
---|
42 | /** The program name (derived from argv[0]). */
|
---|
43 | char const *g_pszProgName = "";
|
---|
44 | /** The current verbosity level. */
|
---|
45 | int g_cVerbosity = 0;
|
---|
46 |
|
---|
47 |
|
---|
48 | /**
|
---|
49 | * Displays the program usage message.
|
---|
50 | *
|
---|
51 | * @param u64Which
|
---|
52 | *
|
---|
53 | * @{
|
---|
54 | */
|
---|
55 |
|
---|
56 | /** Helper function */
|
---|
57 | static void doUsage(char const *line, char const *name = "", char const *command = "")
|
---|
58 | {
|
---|
59 | RTPrintf("%s %-*s%s", name, 30 - strlen(name), command, line);
|
---|
60 | }
|
---|
61 |
|
---|
62 | /** Enumerate the different parts of the usage we might want to print out */
|
---|
63 | enum g_eUsage
|
---|
64 | {
|
---|
65 | #ifdef VBOX_WITH_INFO_SVC
|
---|
66 | GET_GUEST_PROP,
|
---|
67 | SET_GUEST_PROP,
|
---|
68 | #endif
|
---|
69 | USAGE_ALL = UINT32_MAX
|
---|
70 | };
|
---|
71 |
|
---|
72 | static void usage(g_eUsage eWhich = USAGE_ALL)
|
---|
73 | {
|
---|
74 | RTPrintf("Usage:\n\n");
|
---|
75 | RTPrintf("%s [-v|--version] print version number and exit\n", g_pszProgName);
|
---|
76 | RTPrintf("%s --nologo ... suppress the logo\n\n", g_pszProgName);
|
---|
77 |
|
---|
78 | #ifdef VBOX_WITH_INFO_SVC
|
---|
79 | if ((GET_GUEST_PROP == eWhich) || (USAGE_ALL == eWhich))
|
---|
80 | doUsage("<key>\n", g_pszProgName, "getguestproperty");
|
---|
81 | if ((SET_GUEST_PROP == eWhich) || (USAGE_ALL == eWhich))
|
---|
82 | doUsage("<key> [<value>] (no value deletes key)\n", g_pszProgName, "setguestproperty");
|
---|
83 | #endif
|
---|
84 | }
|
---|
85 | /** @} */
|
---|
86 |
|
---|
87 | /**
|
---|
88 | * Displays an error message.
|
---|
89 | *
|
---|
90 | * @param pszFormat The message text.
|
---|
91 | * @param ... Format arguments.
|
---|
92 | */
|
---|
93 | static void VBoxControlError(const char *pszFormat, ...)
|
---|
94 | {
|
---|
95 | // RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
|
---|
96 |
|
---|
97 | va_list va;
|
---|
98 | va_start(va, pszFormat);
|
---|
99 | RTStrmPrintfV(g_pStdErr, pszFormat, va);
|
---|
100 | va_end(va);
|
---|
101 | }
|
---|
102 |
|
---|
103 | #ifdef VBOX_WITH_INFO_SVC
|
---|
104 | /**
|
---|
105 | * Retrieves a value from the host/guest configuration registry.
|
---|
106 | * This is accessed through the "VBoxSharedInfoSvc" HGCM service.
|
---|
107 | *
|
---|
108 | * @returns 0 on success, 1 on failure
|
---|
109 | * @param key (string) the key which the value is stored under.
|
---|
110 | */
|
---|
111 | int getGuestProperty(int argc, char **argv)
|
---|
112 | {
|
---|
113 | using namespace svcInfo;
|
---|
114 |
|
---|
115 | uint32_t u32ClientID = 0;
|
---|
116 | int rc = VINF_SUCCESS;
|
---|
117 | char *pszKey = NULL;
|
---|
118 | char szValue[KEY_MAX_VALUE_LEN];
|
---|
119 |
|
---|
120 | if (argc != 1)
|
---|
121 | {
|
---|
122 | usage(GET_GUEST_PROP);
|
---|
123 | return 1;
|
---|
124 | }
|
---|
125 | rc = RTStrCurrentCPToUtf8(&pszKey, argv[0]);
|
---|
126 | if (!RT_SUCCESS(rc))
|
---|
127 | VBoxControlError("Failed to convert the key name to Utf8, error %Rrc\n", rc);
|
---|
128 | if (RT_SUCCESS(rc))
|
---|
129 | {
|
---|
130 | rc = VbglR3InfoSvcConnect(&u32ClientID);
|
---|
131 | if (!RT_SUCCESS(rc))
|
---|
132 | VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
|
---|
133 | }
|
---|
134 | if (RT_SUCCESS(rc))
|
---|
135 | {
|
---|
136 | rc = VbglR3InfoSvcReadKey(u32ClientID, argv[0], szValue, sizeof(szValue), NULL);
|
---|
137 | if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
|
---|
138 | VBoxControlError("Failed to retrieve the property value, error %Rrc\n", rc);
|
---|
139 | }
|
---|
140 | if (VERR_NOT_FOUND == rc)
|
---|
141 | RTPrintf("No value set!\n");
|
---|
142 | if (RT_SUCCESS(rc))
|
---|
143 | RTPrintf("Value: %S\n", szValue);
|
---|
144 | if (u32ClientID != 0)
|
---|
145 | VbglR3InfoSvcDisconnect(u32ClientID);
|
---|
146 | RTStrFree(pszKey);
|
---|
147 | return RT_SUCCESS(rc) ? 0 : 1;
|
---|
148 | }
|
---|
149 |
|
---|
150 |
|
---|
151 | /**
|
---|
152 | * Writes a value to the host/guest configuration registry.
|
---|
153 | * This is accessed through the "VBoxSharedInfoSvc" HGCM service.
|
---|
154 | *
|
---|
155 | * @returns 0 on success, 1 on failure
|
---|
156 | * @param key (string) the key which the value is stored under.
|
---|
157 | * @param value (string) the value to write. If empty, the key will be
|
---|
158 | * removed.
|
---|
159 | */
|
---|
160 | static int setGuestProperty(int argc, char *argv[])
|
---|
161 | {
|
---|
162 | uint32_t u32ClientID = 0;
|
---|
163 | int rc = VINF_SUCCESS;
|
---|
164 | char *pszKey = NULL;
|
---|
165 | char *pszValue = NULL;
|
---|
166 |
|
---|
167 | if (argc != 1 && argc != 2)
|
---|
168 | {
|
---|
169 | usage();
|
---|
170 | return 1;
|
---|
171 | }
|
---|
172 | rc = RTStrCurrentCPToUtf8(&pszKey, argv[0]);
|
---|
173 | if (!RT_SUCCESS(rc))
|
---|
174 | VBoxControlError("Failed to convert the key name to Utf8, error %Rrc\n", rc);
|
---|
175 | if (RT_SUCCESS(rc) && (2 == argc))
|
---|
176 | {
|
---|
177 | rc = RTStrCurrentCPToUtf8(&pszValue, argv[1]);
|
---|
178 | if (!RT_SUCCESS(rc))
|
---|
179 | VBoxControlError("Failed to convert the key value to Utf8, error %Rrc\n", rc);
|
---|
180 | }
|
---|
181 | if (RT_SUCCESS(rc))
|
---|
182 | {
|
---|
183 | rc = VbglR3InfoSvcConnect(&u32ClientID);
|
---|
184 | if (!RT_SUCCESS(rc))
|
---|
185 | VBoxControlError("Failed to connect to the host/guest registry service, error %Rrc\n", rc);
|
---|
186 | }
|
---|
187 | if (RT_SUCCESS(rc))
|
---|
188 | {
|
---|
189 | rc = VbglR3InfoSvcWriteKey(u32ClientID, argv[0], pszValue);
|
---|
190 | if (!RT_SUCCESS(rc))
|
---|
191 | VBoxControlError("Failed to store the property value, error %Rrc\n", rc);
|
---|
192 | }
|
---|
193 | if (u32ClientID != 0)
|
---|
194 | VbglR3InfoSvcDisconnect(u32ClientID);
|
---|
195 | RTStrFree(pszKey);
|
---|
196 | RTStrFree(pszValue);
|
---|
197 | return RT_SUCCESS(rc) ? 0 : 1;
|
---|
198 | }
|
---|
199 | #endif
|
---|
200 |
|
---|
201 | /** command handler type */
|
---|
202 | typedef DECLCALLBACK(int) FNHANDLER(int argc, char *argv[]);
|
---|
203 | typedef FNHANDLER *PFNHANDLER;
|
---|
204 |
|
---|
205 | /** The table of all registered command handlers. */
|
---|
206 | struct COMMANDHANDLER
|
---|
207 | {
|
---|
208 | const char *command;
|
---|
209 | PFNHANDLER handler;
|
---|
210 | } g_commandHandlers[] =
|
---|
211 | {
|
---|
212 | #ifdef VBOX_WITH_INFO_SVC
|
---|
213 | { "getguestproperty", getGuestProperty },
|
---|
214 | { "setguestproperty", setGuestProperty },
|
---|
215 | #endif
|
---|
216 | { NULL, NULL } /* terminator */
|
---|
217 | };
|
---|
218 |
|
---|
219 | /** Main function */
|
---|
220 | int main(int argc, char **argv)
|
---|
221 | {
|
---|
222 | /** The application's global return code */
|
---|
223 | int rc = 0;
|
---|
224 | /** An IPRT return code for local use */
|
---|
225 | int rrc = VINF_SUCCESS;
|
---|
226 | /** The index of the command line argument we are currently processing */
|
---|
227 | int iArg = 1;
|
---|
228 | /** Should we show the logo text? */
|
---|
229 | bool showlogo = true;
|
---|
230 | /** Should we print the usage after the logo? For the --help switch. */
|
---|
231 | bool dohelp = false;
|
---|
232 | /** Will we be executing a command or just printing information? */
|
---|
233 | bool onlyinfo = false;
|
---|
234 |
|
---|
235 | /*
|
---|
236 | * Start by handling command line switches
|
---|
237 | */
|
---|
238 |
|
---|
239 | /** Are we finished with handling switches? */
|
---|
240 | bool done = false;
|
---|
241 | while (!done && (iArg < argc))
|
---|
242 | {
|
---|
243 | if ( (0 == strcmp(argv[iArg], "-v"))
|
---|
244 | || (0 == strcmp(argv[iArg], "--version"))
|
---|
245 | )
|
---|
246 | {
|
---|
247 | /* Print version number, and do nothing else. */
|
---|
248 | RTPrintf("%sr%d\n", VBOX_VERSION_STRING, VBoxSVNRev ());
|
---|
249 | onlyinfo = true;
|
---|
250 | showlogo = false;
|
---|
251 | done = true;
|
---|
252 | }
|
---|
253 | else if (0 == strcmp(argv[iArg], "--nologo"))
|
---|
254 | showlogo = false;
|
---|
255 | else if (0 == strcmp(argv[iArg], "--help"))
|
---|
256 | {
|
---|
257 | onlyinfo = true;
|
---|
258 | dohelp = true;
|
---|
259 | done = true;
|
---|
260 | }
|
---|
261 | else
|
---|
262 | /* We have found an argument which isn't a switch. Exit to the
|
---|
263 | * command processing bit. */
|
---|
264 | done = true;
|
---|
265 | if (!done)
|
---|
266 | ++iArg;
|
---|
267 | }
|
---|
268 |
|
---|
269 | /*
|
---|
270 | * Find the application name, show our logo if the user hasn't suppressed it,
|
---|
271 | * and show the usage if the user asked us to
|
---|
272 | */
|
---|
273 |
|
---|
274 | g_pszProgName = RTPathFilename(argv[0]);
|
---|
275 | if (showlogo)
|
---|
276 | RTPrintf("VirtualBox Guest Additions Command Line Management Interface Version "
|
---|
277 | VBOX_VERSION_STRING "\n"
|
---|
278 | "(C) 2008 Sun Microsystems, Inc.\n"
|
---|
279 | "All rights reserved\n\n");
|
---|
280 | if (dohelp)
|
---|
281 | usage();
|
---|
282 |
|
---|
283 | /*
|
---|
284 | * Do global initialisation for the programme if we will be handling a command
|
---|
285 | */
|
---|
286 |
|
---|
287 | if (!onlyinfo)
|
---|
288 | {
|
---|
289 | rrc = RTR3Init(false, 0);
|
---|
290 | if (!RT_SUCCESS(rrc))
|
---|
291 | {
|
---|
292 | VBoxControlError("Failed to initialise the VirtualBox runtime - error %Rrc\n", rrc);
|
---|
293 | rc = 1;
|
---|
294 | }
|
---|
295 | if (0 == rc)
|
---|
296 | {
|
---|
297 | if (!RT_SUCCESS(VbglR3Init()))
|
---|
298 | {
|
---|
299 | VBoxControlError("Could not contact the host system. Make sure that you are running this\n"
|
---|
300 | "application inside a VirtualBox guest system, and that you have sufficient\n"
|
---|
301 | "user permissions.\n");
|
---|
302 | rc = 1;
|
---|
303 | }
|
---|
304 | }
|
---|
305 | }
|
---|
306 |
|
---|
307 | /*
|
---|
308 | * Now look for an actual command in the argument list and handle it.
|
---|
309 | */
|
---|
310 |
|
---|
311 | if (!onlyinfo && (0 == rc))
|
---|
312 | {
|
---|
313 | if (argc > iArg)
|
---|
314 | {
|
---|
315 | /** Is next parameter a known command? */
|
---|
316 | bool found = false;
|
---|
317 | /** And if so, what is its position in the table? */
|
---|
318 | unsigned index = 0;
|
---|
319 | while ( index < RT_ELEMENTS(g_commandHandlers)
|
---|
320 | && !found
|
---|
321 | && (g_commandHandlers[index].command != NULL))
|
---|
322 | {
|
---|
323 | if (0 == strcmp(argv[iArg], g_commandHandlers[index].command))
|
---|
324 | found = true;
|
---|
325 | else
|
---|
326 | ++index;
|
---|
327 | }
|
---|
328 | if (found)
|
---|
329 | rc = g_commandHandlers[index].handler(argc - iArg - 1, argv + iArg + 1);
|
---|
330 | else
|
---|
331 | {
|
---|
332 | rc = 1;
|
---|
333 | usage();
|
---|
334 | }
|
---|
335 | }
|
---|
336 | else
|
---|
337 | {
|
---|
338 | /* The user didn't specify a command. */
|
---|
339 | rc = 1;
|
---|
340 | usage();
|
---|
341 | }
|
---|
342 | }
|
---|
343 |
|
---|
344 | /*
|
---|
345 | * And exit, returning the status
|
---|
346 | */
|
---|
347 |
|
---|
348 | return rc;
|
---|
349 | }
|
---|