Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 55603)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 55604)
@@ -115,16 +115,15 @@
 # define USAGE_GSTCTRL_COPYFROM     RT_BIT(2)
 # define USAGE_GSTCTRL_COPYTO       RT_BIT(3)
-# define USAGE_GSTCTRL_CREATEDIR    RT_BIT(4)
-# define USAGE_GSTCTRL_REMOVEDIR    RT_BIT(5)
-# define USAGE_GSTCTRL_REMOVEFILE   RT_BIT(6)
-# define USAGE_GSTCTRL_RENAME       RT_BIT(7)
-# define USAGE_GSTCTRL_CREATETEMP   RT_BIT(8)
+# define USAGE_GSTCTRL_MKDIR        RT_BIT(4)
+# define USAGE_GSTCTRL_RMDIR        RT_BIT(5)
+# define USAGE_GSTCTRL_RM           RT_BIT(6)
+# define USAGE_GSTCTRL_MV           RT_BIT(7)
+# define USAGE_GSTCTRL_MKTEMP       RT_BIT(8)
 # define USAGE_GSTCTRL_LIST         RT_BIT(9)
-# define USAGE_GSTCTRL_PROCESS      RT_BIT(10)
-# define USAGE_GSTCTRL_KILL         RT_BIT(11)
-# define USAGE_GSTCTRL_SESSION      RT_BIT(12)
-# define USAGE_GSTCTRL_STAT         RT_BIT(13)
-# define USAGE_GSTCTRL_UPDATEADDS   RT_BIT(14)
-# define USAGE_GSTCTRL_WATCH        RT_BIT(15)
+# define USAGE_GSTCTRL_CLOSEPROCESS RT_BIT(10)
+# define USAGE_GSTCTRL_CLOSESESSION RT_BIT(11)
+# define USAGE_GSTCTRL_STAT         RT_BIT(12)
+# define USAGE_GSTCTRL_UPDATEGA     RT_BIT(13)
+# define USAGE_GSTCTRL_WATCH        RT_BIT(14)
 # define USAGE_GSTCTRL_EXEC         RT_BIT(31) /**< @deprecated Remember to remove. */
 #endif
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 55603)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 55604)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2010-2013 Oracle Corporation
+ * Copyright (C) 2010-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -64,8 +64,46 @@
 using namespace com;
 
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define GCTLCMD_COMMON_OPT_USER             999 /**< The --username option number. */
+#define GCTLCMD_COMMON_OPT_PASSWORD         998 /**< The --password option number. */
+#define GCTLCMD_COMMON_OPT_PASSWORD_FILE    997 /**< The --password-file option number. */
+#define GCTLCMD_COMMON_OPT_DOMAIN           996 /**< The --domain option number. */
+/** Common option definitions. */
+#define GCTLCMD_COMMON_OPTION_DEFS() \
+    { "--username",            GCTLCMD_COMMON_OPT_USER,         RTGETOPT_REQ_STRING  }, \
+    { "--passwordfile",        GCTLCMD_COMMON_OPT_PASSWORD_FILE,RTGETOPT_REQ_STRING  }, \
+    { "--password",            GCTLCMD_COMMON_OPT_PASSWORD,     RTGETOPT_REQ_STRING  }, \
+    { "--domain",              GCTLCMD_COMMON_OPT_DOMAIN,       RTGETOPT_REQ_STRING  }, \
+    { "--quiet",               'q',                             RTGETOPT_REQ_NOTHING }, \
+    { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING },
+
+/** Handles common options in the typical option parsing switch. */
+#define GCTLCMD_COMMON_OPTION_CASES(a_pCtx, a_ch, a_pValueUnion) \
+        case 'v': \
+        case 'q': \
+        case GCTLCMD_COMMON_OPT_USER: \
+        case GCTLCMD_COMMON_OPT_DOMAIN: \
+        case GCTLCMD_COMMON_OPT_PASSWORD: \
+        case GCTLCMD_COMMON_OPT_PASSWORD_FILE: \
+        { \
+            RTEXITCODE rcExitCommon = gctlCtxSetOption(a_pCtx, a_ch, a_pValueUnion); \
+            if (RT_UNLIKELY(rcExitCommon != RTEXITCODE_SUCCESS)) \
+                return rcExitCommon; \
+        } break
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
 /** Set by the signal handler when current guest control
  *  action shall be aborted. */
 static volatile bool g_fGuestCtrlCanceled = false;
 
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
 /**
  * Listener declarations.
@@ -76,16 +114,38 @@
 VBOX_LISTENER_DECLARE(GuestEventListenerImpl)
 
+
 /**
- * Command context flags.
+ * Definition of a guestcontrol command, with handler and various flags.
+ */
+typedef struct GCTLCMDDEF
+{
+    /** The command name. */
+    const char *pszName;
+
+    /**
+     * Actual command handler callback.
+     *
+     * @param   pCtx            Pointer to command context to use.
+     */
+    DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (struct GCTLCMDCTX *pCtx));
+
+    /** The command usage flags. */
+    uint32_t    fCmdUsage;
+    /** Command context flags (GCTLCMDCTX_F_XXX). */
+    uint32_t    fCmdCtx;
+} GCTLCMD;
+/** Pointer to a const guest control command definition. */
+typedef GCTLCMDDEF const *PCGCTLCMDDEF;
+
+/** @name GCTLCMDCTX_F_XXX - Command context flags.
+ * @{
  */
 /** No flags set. */
-#define CTLCMDCTX_FLAGS_NONE                0
+#define GCTLCMDCTX_F_NONE               0
 /** Don't install a signal handler (CTRL+C trap). */
-#define CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER   RT_BIT(0)
+#define GCTLCMDCTX_F_NO_SIGNAL_HANDLER  RT_BIT(0)
 /** No guest session needed. */
-#define CTLCMDCTX_FLAGS_SESSION_ANONYMOUS   RT_BIT(1)
-/** Detach the guest session. That is, don't close the
- *  guest session automatically on exit. */
-#define CTLCMDCTX_FLAGS_SESSION_DETACH      RT_BIT(2)
+#define GCTLCMDCTX_F_SESSION_ANONYMOUS  RT_BIT(1)
+/** @} */
 
 /**
@@ -94,15 +154,19 @@
 typedef struct GCTLCMDCTX
 {
-    HandlerArg handlerArg;
-    /** Command-specific argument count. */
-    int iArgc;
-    /** Command-specific argument vector. */
-    char **ppaArgv;
-    /** First argv to start parsing with. */
-    int iFirstArgc;
-    /** Command context flags. */
-    uint32_t uFlags;
-    /** Verbose flag. */
-    bool fVerbose;
+    HandlerArg *pArg;
+
+    /** Pointer to the command definition. */
+    PCGCTLCMDDEF pCmdDef;
+    /** The VM name or UUID. */
+    const char *pszVmNameOrUuid;
+
+    /** Whether we've locked the VM session. */
+    bool fLockedVmSession;
+    /** Whether to detach (@c true) or close the session. */
+    bool fDetachGuestSession;
+    /** Set if we've installed the signal handler.   */
+    bool fInstalledSignalHandler;
+    /** The verbosity level. */
+    uint32_t cVerbose;
     /** User name. */
     Utf8Str strUsername;
@@ -120,14 +184,4 @@
 } GCTLCMDCTX, *PGCTLCMDCTX;
 
-typedef struct GCTLCMD
-{
-    /**
-     * Actual command handler callback.
-     *
-     * @param   pCtx            Pointer to command context to use.
-     */
-    DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (PGCTLCMDCTX pCtx));
-
-} GCTLCMD, *PGCTLCMD;
 
 typedef struct COPYCONTEXT
@@ -220,28 +274,4 @@
 
 
-/*
- * Common getopt definitions, starting at 1000.
- * Specific command definitions will start all at 2000.
- */
-enum GETOPTDEF_COMMON
-{
-    GETOPTDEF_COMMON_PASSWORD = 1000
-};
-
-/**
- * Long option IDs for the guestcontrol run command.
- */
-enum kGstCtrlRunOpt
-{
-    kGstCtrlRunOpt_IgnoreOrphanedProcesses = 1000,
-    kGstCtrlRunOpt_NoProfile,
-    kGstCtrlRunOpt_Dos2Unix,
-    kGstCtrlRunOpt_Unix2Dos,
-    kGstCtrlRunOpt_WaitForStdOut,
-    kGstCtrlRunOpt_NoWaitForStdOut,
-    kGstCtrlRunOpt_WaitForStdErr,
-    kGstCtrlRunOpt_NoWaitForStdErr
-};
-
 /**
  * RTGetOpt-IDs for the guest execution control command line.
@@ -266,24 +296,4 @@
 };
 
-enum GETOPTDEF_MKDIR
-{
-};
-
-enum GETOPTDEF_RM
-{
-};
-
-enum GETOPTDEF_RMDIR
-{
-};
-
-enum GETOPTDEF_SESSIONCLOSE
-{
-    GETOPTDEF_SESSIONCLOSE_ALL = 2000
-};
-
-enum GETOPTDEF_STAT
-{
-};
 
 enum kStreamTransform
@@ -294,7 +304,13 @@
 };
 
-static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest, const char *pszDir, bool *fExists);
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static int gctlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest, const char *pszDir, bool *fExists);
 
 #endif /* VBOX_ONLY_DOCS */
+
+
 
 void usageGuestControl(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2, uint32_t uSubCmd)
@@ -304,10 +320,16 @@
                  pcszSep1, pcszSep2,
                  uSubCmd == ~0U ? "\n" : "");
+    /*                0         1         2         3         4         5         6         7         8XXXXXXXXXX */
+    /*                0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
+#define COMMON_OPTION_HELP \
+                     "                              [--username <name>] [--domain <domain>]\n" \
+                     "                              [--passwordfile <file> | --password <password>]\n" \
+                     "                              [--verbose|-v] [--quiet|-q]\n"
+#define COMMON_OPTION_HELP_ANON \
+                     "                              [--verbose|-v] [--quiet|-q]\n"
     if (uSubCmd & USAGE_GSTCTRL_RUN)
         RTStrmPrintf(pStrm,
-                     "                              run\n"
-                     "                              [--image <path to executable>] --username <name>\n"
-                     "                              [--passwordfile <file> | --password <password>]\n"
-                     "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
+                     "                              run\n" COMMON_OPTION_HELP
+                     "                              [--image <path to executable>] [--timeout <msec>]\n"
                      "                              [--putenv <NAME>[=<VALUE>]] [--unquoted-args]\n"
                      "                              [--no-wait-stdout|--wait-stdout]\n"
@@ -318,12 +340,11 @@
     if (uSubCmd & USAGE_GSTCTRL_START)
         RTStrmPrintf(pStrm,
-                     "                              start\n"
-                     "                              [--image <path to executable>] --username <name>\n"
-                     "                              [--passwordfile <file> | --password <password>]\n"
-                     "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
+                     "                              start\n" COMMON_OPTION_HELP
+                     "                              [--image <path to executable>] [--timeout <msec>]\n"
                      "                              [--putenv <NAME>[=<VALUE>]] [--unquoted-args]\n"
-                     "                              [--dos2unix] [--unix2dos]\n"
                      "                              -- <program/arg0> [argument1] ... [argumentN]]\n"
                  "\n");
+    /*            0         1         2         3         4         5         6         7         8XXXXXXXXXX */
+    /*            0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
     if (uSubCmd == USAGE_GSTCTRL_EXEC)
         RTStrmPrintf(pStrm,
@@ -339,93 +360,70 @@
     if (uSubCmd & USAGE_GSTCTRL_COPYFROM)
         RTStrmPrintf(pStrm,
-                 "                              copyfrom\n"
-                 "                              <guest source> <host dest> --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose]\n"
+                 "                              copyfrom\n" COMMON_OPTION_HELP
                  "                              [--dryrun] [--follow] [--recursive]\n"
+                 "                              <guest source> <host dest>\n"
                  "\n");
     if (uSubCmd & USAGE_GSTCTRL_COPYTO)
         RTStrmPrintf(pStrm,
-                 "                              copyto|cp\n"
-                 "                              <host source> <guest dest> --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose]\n"
+                 "                              copyto|cp\n" COMMON_OPTION_HELP
                  "                              [--dryrun] [--follow] [--recursive]\n"
+                 "                              <host source> <guest dest> "
                  "\n");
-    if (uSubCmd & USAGE_GSTCTRL_CREATEDIR)
+    if (uSubCmd & USAGE_GSTCTRL_MKDIR)
         RTStrmPrintf(pStrm,
-                 "                              createdir[ectory]|mkdir|md\n"
-                 "                              <guest directory>... --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose]\n"
+                 "                              mkdir|md|createdir[ectory]\n" COMMON_OPTION_HELP
                  "                              [--parents] [--mode <mode>]\n"
+                 "                              <guest directory> [...]\n"
                  "\n");
-    if (uSubCmd & USAGE_GSTCTRL_REMOVEDIR)
+    if (uSubCmd & USAGE_GSTCTRL_RMDIR)
         RTStrmPrintf(pStrm,
-                 "                              removedir[ectory]|rmdir\n"
-                 "                              <guest directory>... --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose]\n"
+                 "                              rmdir|removedir[ectory]\n" COMMON_OPTION_HELP
                  "                              [--recursive|-R|-r]\n"
+                 "                              <guest directory> [...]\n"
                  "\n");
-    if (uSubCmd & USAGE_GSTCTRL_REMOVEFILE)
+    if (uSubCmd & USAGE_GSTCTRL_RM)
         RTStrmPrintf(pStrm,
-                 "                              removefile|rm\n"
-                 "                              <guest file>... --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose]\n"
+                 "                              removefile|rm\n" COMMON_OPTION_HELP
+                 "                              <guest file> [...]\n"
                  "\n");
-    if (uSubCmd & USAGE_GSTCTRL_RENAME)
+    if (uSubCmd & USAGE_GSTCTRL_MV)
         RTStrmPrintf(pStrm,
-                 "                              ren[ame]|mv\n"
-                 "                              <source>... <dest> --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose]\n"
+                 "                              mv|move|ren[ame]\n" COMMON_OPTION_HELP
+                 "                              <source> [source1 [...]] <dest>\n"
                  "\n");
-    if (uSubCmd & USAGE_GSTCTRL_CREATETEMP)
+    if (uSubCmd & USAGE_GSTCTRL_MKTEMP)
         RTStrmPrintf(pStrm,
-                 "                              createtemp[orary]|mktemp\n"
-                 "                              <template> --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--directory] [--secure] [--tmpdir <directory>]\n"
-                 "                              [--domain <domain>] [--mode <mode>] [--verbose]\n"
-                 "\n");
-    if (uSubCmd & USAGE_GSTCTRL_LIST)
-        RTStrmPrintf(pStrm,
-                 "                              list <all|sessions|processes|files> [--verbose]\n"
-                 "\n");
-    /** @todo Add an own help group for "session" and "process" sub commands. */
-    if (uSubCmd & USAGE_GSTCTRL_PROCESS)
-         RTStrmPrintf(pStrm,
-                 "                              process kill --session-id <ID>\n"
-                 "                                           | --session-name <name or pattern>\n"
-                 "                                           [--verbose]\n"
-                 "                                           <PID> ... <PID n>\n"
-                 "\n");
-    if (uSubCmd & USAGE_GSTCTRL_KILL)
-        RTStrmPrintf(pStrm,
-                 "                              [p[s]]kill --session-id <ID>\n"
-                 "                                         | --session-name <name or pattern>\n"
-                 "                                         [--verbose]\n"
-                 "                                         <PID> ... <PID n>\n"
-                 "\n");
-    if (uSubCmd & USAGE_GSTCTRL_SESSION)
-        RTStrmPrintf(pStrm,
-                 "                              session close  --session-id <ID>\n"
-                 "                                           | --session-name <name or pattern>\n"
-                 "                                           | --all\n"
-                 "                                           [--verbose]\n"
+                 "                              mktemp|createtemp[orary]\n" COMMON_OPTION_HELP
+                 "                              [--secure] [--mode <mode>] [--tmpdir <directory>]\n"
+                 "                              <template>\n"
                  "\n");
     if (uSubCmd & USAGE_GSTCTRL_STAT)
         RTStrmPrintf(pStrm,
-                 "                              stat\n"
-                 "                              <file>... --username <name>\n"
-                 "                              [--passwordfile <file> | --password <password>]\n"
-                 "                              [--domain <domain>] [--verbose]\n"
+                 "                              stat\n" COMMON_OPTION_HELP
+                 "                              <file> [...]\n"
                  "\n");
-    if (uSubCmd & USAGE_GSTCTRL_UPDATEADDS)
+
+    /* Command not requiring authentication. */
+    if (uSubCmd & USAGE_GSTCTRL_LIST)
         RTStrmPrintf(pStrm,
-                 "                              updateadditions\n"
-                 "                              [--source <guest additions .ISO>] [--verbose]\n"
+                 "                              list <all|sessions|processes|files>\n" COMMON_OPTION_HELP_ANON
+                 "\n");
+    if (uSubCmd & USAGE_GSTCTRL_CLOSEPROCESS)
+        RTStrmPrintf(pStrm,
+                 "                              closeprocess|kill\n" COMMON_OPTION_HELP_ANON
+                 "                              <   --session-id <ID>\n"
+                 "                                | --session-name <name or pattern>\n"
+                 "                              <PID1> [PID1 [...]]\n"
+                 "\n");
+    if (uSubCmd & USAGE_GSTCTRL_CLOSESESSION)
+        RTStrmPrintf(pStrm,
+                 "                              closesession\n" COMMON_OPTION_HELP_ANON
+                 "                              <  --all | --session-id <ID>\n"
+                 "                                | --session-name <name or pattern> >\n"
+                 "\n");
+    if (uSubCmd & USAGE_GSTCTRL_UPDATEGA)
+        RTStrmPrintf(pStrm,
+                 "                              updatega|updateguestadditions|updateadditions\n" COMMON_OPTION_HELP_ANON
+                 "                              [--source <guest additions .ISO>]\n"
                  "                              [--wait-start]\n"
                  "                              [-- [<argument1>] ... [<argumentN>]]\n"
@@ -433,5 +431,5 @@
     if (uSubCmd & USAGE_GSTCTRL_WATCH)
         RTStrmPrintf(pStrm,
-                 "                              watch [--verbose]\n"
+                 "                              watch\n" COMMON_OPTION_HELP_ANON
                  "\n");
 }
@@ -439,6 +437,7 @@
 #ifndef VBOX_ONLY_DOCS
 
+
 #ifdef RT_OS_WINDOWS
-static BOOL WINAPI guestCtrlSignalHandler(DWORD dwCtrlType)
+static BOOL WINAPI gctlSignalHandler(DWORD dwCtrlType)
 {
     bool fEventHandled = FALSE;
@@ -468,5 +467,5 @@
  * unnecessary here.
  */
-static void guestCtrlSignalHandler(int iSignal)
+static void gctlSignalHandler(int iSignal)
 {
     NOREF(iSignal);
@@ -474,4 +473,5 @@
 }
 #endif
+
 
 /**
@@ -479,11 +479,13 @@
  * whenever the user wants to intercept the program.
  *
- ** @todo Make this handler available for all VBoxManage modules?
- */
-static int ctrlSignalHandlerInstall(void)
-{
+ * @todo Make this handler available for all VBoxManage modules?
+ */
+static int gctlSignalHandlerInstall(void)
+{
+    g_fGuestCtrlCanceled = false;
+
     int rc = VINF_SUCCESS;
 #ifdef RT_OS_WINDOWS
-    if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)guestCtrlSignalHandler, TRUE /* Add handler */))
+    if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)gctlSignalHandler, TRUE /* Add handler */))
     {
         rc = RTErrConvertFromWin32(GetLastError());
@@ -491,7 +493,7 @@
     }
 #else
-    signal(SIGINT,   guestCtrlSignalHandler);
+    signal(SIGINT,   gctlSignalHandler);
 # ifdef SIGBREAK
-    signal(SIGBREAK, guestCtrlSignalHandler);
+    signal(SIGBREAK, gctlSignalHandler);
 # endif
 #endif
@@ -499,8 +501,9 @@
 }
 
+
 /**
  * Uninstalls a previously installed signal handler.
  */
-static int ctrlSignalHandlerUninstall(void)
+static int gctlSignalHandlerUninstall(void)
 {
     int rc = VINF_SUCCESS;
@@ -520,9 +523,9 @@
 }
 
+
 /**
- * Translates a process status to a human readable
- * string.
- */
-const char *ctrlProcessStatusToText(ProcessStatus_T enmStatus)
+ * Translates a process status to a human readable string.
+ */
+const char *gctlProcessStatusToText(ProcessStatus_T enmStatus)
 {
     switch (enmStatus)
@@ -556,5 +559,8 @@
 }
 
-const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)
+/**
+ * Translates a guest process wait result to a human readable string.
+ */
+const char *gctlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)
 {
     switch (enmWaitResult)
@@ -585,8 +591,7 @@
 
 /**
- * Translates a guest session status to a human readable
- * string.
- */
-const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)
+ * Translates a guest session status to a human readable string.
+ */
+const char *gctlGuestSessionStatusToText(GuestSessionStatus_T enmStatus)
 {
     switch (enmStatus)
@@ -615,8 +620,7 @@
 
 /**
- * Translates a guest file status to a human readable
- * string.
- */
-const char *ctrlFileStatusToText(FileStatus_T enmStatus)
+ * Translates a guest file status to a human readable string.
+ */
+const char *gctlFileStatusToText(FileStatus_T enmStatus)
 {
     switch (enmStatus)
@@ -640,5 +644,5 @@
 }
 
-static int ctrlPrintError(com::ErrorInfo &errorInfo)
+static int gctlPrintError(com::ErrorInfo &errorInfo)
 {
     if (   errorInfo.isFullAvailable()
@@ -660,11 +664,11 @@
 }
 
-static int ctrlPrintError(IUnknown *pObj, const GUID &aIID)
+static int gctlPrintError(IUnknown *pObj, const GUID &aIID)
 {
     com::ErrorInfo ErrInfo(pObj, aIID);
-    return ctrlPrintError(ErrInfo);
-}
-
-static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)
+    return gctlPrintError(ErrInfo);
+}
+
+static int gctlPrintProgressError(ComPtr<IProgress> pProgress)
 {
     int vrc = VINF_SUCCESS;
@@ -682,5 +686,5 @@
             {
                 com::ProgressErrorInfo ErrInfo(pProgress);
-                vrc = ctrlPrintError(ErrInfo);
+                vrc = gctlPrintError(ErrInfo);
             }
         }
@@ -693,335 +697,397 @@
 }
 
+
+
+/*
+ *
+ *
+ * Guest Control Command Context
+ * Guest Control Command Context
+ * Guest Control Command Context
+ * Guest Control Command Context
+ *
+ *
+ *
+ */
+
+
 /**
+ * Initializes a guest control command context structure.
+ *
+ * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE on failure (after
+ *           informing the user of course).
+ * @param   pCtx                The command context to init.
+ * @param   pArg                The handle argument package.
+ * @param   pCmdDef             The command definition.
+ */
+static RTEXITCODE gctrCmdCtxInit(PGCTLCMDCTX pCtx, HandlerArg *pArg, PCGCTLCMDDEF pCmdDef)
+{
+    Assert(pArg->argc >= 2);
+    RT_ZERO(*pCtx);
+    pCtx->pArg = pArg;
+    pCtx->pCmdDef = pCmdDef;
+    pCtx->pszVmNameOrUuid = pArg->argv[0];
+
+    /*
+     * The user name defaults to the host one, if we can get at it.
+     */
+    char szUser[1024];
+    int rc = RTProcQueryUsername(RTProcSelf(), szUser, sizeof(szUser), NULL);
+    if (   RT_SUCCESS(rc)
+        && RTStrIsValidEncoding(szUser)) /* paranoia required on posix */
+    {
+        try
+        {
+            pCtx->strUsername = szUser;
+        }
+        catch (std::bad_alloc &)
+        {
+            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory");
+        }
+    }
+    /* else: ignore this failure. */
+
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Worker for GCTLCMD_COMMON_OPTION_CASES.
+ *
+ * @returns RTEXITCODE_SUCCESS if the option was handled successfully.  If not,
+ *          an error message is printed and an appropriate failure exit code is
+ *          returned.
+ * @param   pCtx                The guest control command context.
+ * @param   ch                  The option char or ordinal.
+ * @param   pValueUnion         The option value union.
+ */
+static RTEXITCODE gctlCtxSetOption(PGCTLCMDCTX pCtx, int ch, PRTGETOPTUNION pValueUnion)
+{
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    switch (ch)
+    {
+        case 'u': /* User name */
+            if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS))
+                pCtx->strUsername = pValueUnion->psz;
+            else
+                return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage,
+                                     "The --username|-u option is not valid with this command");
+            break;
+
+        case GCTLCMD_COMMON_OPT_PASSWORD: /* Password */
+            if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS))
+            {
+                if (pCtx->strPassword.isNotEmpty())
+                    RTMsgWarning("Password is given more than once.");
+                pCtx->strPassword = pValueUnion->psz;
+            }
+            else
+                return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage,
+                                     "The --password option is not valid with this command");
+            break;
+
+        case 'p': /* Password file */
+            if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS))
+                rcExit = readPasswordFile(pValueUnion->psz, &pCtx->strPassword);
+            else
+                return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage,
+                                     "The --password-file|-p option is not valid with this command");
+            break;
+
+        case 'd': /* domain */
+            if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS))
+                pCtx->strDomain = pValueUnion->psz;
+            else
+                return errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage,
+                                     "The --domain option is not valid with this command");
+            break;
+
+        case 'v': /* --verbose */
+            pCtx->cVerbose++;
+            break;
+
+        case 'q': /* --quiet */
+            if (pCtx->cVerbose)
+                pCtx->cVerbose--;
+            break;
+
+        default:
+            AssertFatalMsgFailed(("ch=%d (%c)\n", ch, ch));
+    }
+    return rcExit;
+}
+
+
+/**
+ * Initializes the VM for IGuest operation.
+ *
+ * This opens a shared session to a running VM and gets hold of IGuest.
+ *
+ * @returns RTEXITCODE_SUCCESS on success.  RTEXITCODE_FAILURE and user message
+ *          on failure.
+ * @param   pCtx            The guest control command context.
+ *                          GCTLCMDCTX::pGuest will be set on success.
+ */
+static RTEXITCODE gctlCtxInitVmSession(PGCTLCMDCTX pCtx)
+{
+    HRESULT rc;
+    AssertPtr(pCtx);
+    AssertPtr(pCtx->pArg);
+
+    /*
+     * Find the VM and check if it's running.
+     */
+    ComPtr<IMachine> machine;
+    CHECK_ERROR(pCtx->pArg->virtualBox, FindMachine(Bstr(pCtx->pszVmNameOrUuid).raw(), machine.asOutParam()));
+    if (SUCCEEDED(rc))
+    {
+        MachineState_T enmMachineState;
+        CHECK_ERROR(machine, COMGETTER(State)(&enmMachineState));
+        if (   SUCCEEDED(rc)
+            && enmMachineState == MachineState_Running)
+        {
+            /*
+             * It's running. So, open a session to it and get the IGuest interface.
+             */
+            CHECK_ERROR(machine, LockMachine(pCtx->pArg->session, LockType_Shared));
+            if (SUCCEEDED(rc))
+            {
+                pCtx->fLockedVmSession = true;
+                ComPtr<IConsole> ptrConsole;
+                CHECK_ERROR(pCtx->pArg->session, COMGETTER(Console)(ptrConsole.asOutParam()));
+                if (SUCCEEDED(rc))
+                {
+                    CHECK_ERROR(ptrConsole, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));
+                    if (SUCCEEDED(rc))
+                        return RTEXITCODE_SUCCESS;
+                }
+            }
+        }
+        else if(SUCCEEDED(rc))
+            RTMsgError("Machine \"%s\" is not running (currently %s)!\n",
+                       pCtx->pszVmNameOrUuid, machineStateToName(enmMachineState, false));
+    }
+    return RTEXITCODE_FAILURE;
+}
+
+
+/**
+ * Creates a guest session with the VM.
+ *
+ * @retval  RTEXITCODE_SUCCESS on success.
+ * @retval  RTEXITCODE_FAILURE and user message on failure.
+ * @param   pCtx            The guest control command context.
+ *                          GCTCMDCTX::pGuestSession and GCTLCMDCTX::uSessionID
+ *                          will be set.
+ */
+static RTEXITCODE gctlCtxInitGuestSession(PGCTLCMDCTX pCtx)
+{
+    HRESULT rc;
+    AssertPtr(pCtx);
+    Assert(!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS));
+    Assert(pCtx->pGuest.isNotNull());
+
+    /*
+     * Build up a reasonable guest session name. Useful for identifying
+     * a specific session when listing / searching for them.
+     */
+    char *pszSessionName;
+    if (RTStrAPrintf(&pszSessionName,
+                     "[%RU32] VBoxManage Guest Control [%s] - %s",
+                     RTProcSelf(), pCtx->pszVmNameOrUuid, pCtx->pCmdDef->pszName) < 0)
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name");
+
+    /*
+     * Create a guest session.
+     */
+    if (pCtx->cVerbose > 1)
+        RTPrintf("Creating guest session as user '%s'...\n", pCtx->strUsername.c_str());
+    try
+    {
+        CHECK_ERROR(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),
+                                                Bstr(pCtx->strPassword).raw(),
+                                                Bstr(pCtx->strDomain).raw(),
+                                                Bstr(pszSessionName).raw(),
+                                                pCtx->pGuestSession.asOutParam()));
+    }
+    catch (std::bad_alloc &)
+    {
+        RTMsgError("Out of memory setting up IGuest::CreateSession call");
+        rc = E_OUTOFMEMORY;
+    }
+    if (SUCCEEDED(rc))
+    {
+        /*
+         * Wait for guest session to start.
+         */
+        if (pCtx->cVerbose > 1)
+            RTPrintf("Waiting for guest session to start...\n");
+        GuestSessionWaitResult_T enmWaitResult;
+        try
+        {
+            com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
+            aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
+            CHECK_ERROR(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),
+                                                          /** @todo Make session handling timeouts configurable. */
+                                                          30 * 1000, &enmWaitResult));
+        }
+        catch (std::bad_alloc &)
+        {
+            RTMsgError("Out of memory setting up IGuestSession::WaitForArray call");
+            rc = E_OUTOFMEMORY;
+        }
+        if (SUCCEEDED(rc))
+        {
+            /* The WaitFlagNotSupported result may happen with GAs older than 4.3. */
+            if (   enmWaitResult == GuestSessionWaitResult_Start
+                || enmWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
+            {
+                /*
+                 * Get the session ID and we're ready to rumble.
+                 */
+                CHECK_ERROR(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));
+                if (SUCCEEDED(rc))
+                {
+                    if (pCtx->cVerbose > 1)
+                        RTPrintf("Successfully started guest session (ID %RU32)\n", pCtx->uSessionID);
+                    RTStrFree(pszSessionName);
+                    return RTEXITCODE_SUCCESS;
+                }
+            }
+            else
+            {
+                GuestSessionStatus_T enmSessionStatus;
+                CHECK_ERROR(pCtx->pGuestSession, COMGETTER(Status)(&enmSessionStatus));
+                RTMsgError("Error starting guest session (current status is: %s)\n",
+                           SUCCEEDED(rc) ? gctlGuestSessionStatusToText(enmSessionStatus) : "<unknown>");
+            }
+        }
+    }
+
+    RTStrFree(pszSessionName);
+    return RTEXITCODE_FAILURE;
+}
+
+
+/**
+ * Completes the guest control context initialization after parsing arguments.
+ *
+ * Will validate common arguments, open a VM session, and if requested open a
+ * guest session and install the CTRL-C signal handler.
+ *
+ * It is good to validate all the options and arguments you can before making
+ * this call.  However, the VM session, IGuest and IGuestSession interfaces are
+ * not availabe till after this call, so take care.
+ *
+ * @retval  RTEXITCODE_SUCCESS on success.
+ * @retval  RTEXITCODE_FAILURE and user message on failure.
+ * @param   pCtx            The guest control command context.
+ *                          GCTCMDCTX::pGuestSession and GCTLCMDCTX::uSessionID
+ *                          will be set.
+ */
+static RTEXITCODE gctlCtxPostArgParsingInit(PGCTLCMDCTX pCtx)
+{
+    /*
+     * Check that the user name isn't empty when we need it.
+     */
+    RTEXITCODE rcExit;
+    if (  (pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)
+        || pCtx->strUsername.isNotEmpty())
+    {
+        /*
+         * Open the VM session and if required, a guest session.
+         */
+        rcExit = gctlCtxInitVmSession(pCtx);
+        if (   rcExit == RTEXITCODE_SUCCESS
+            && !(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS))
+            rcExit = gctlCtxInitGuestSession(pCtx);
+        if (rcExit == RTEXITCODE_SUCCESS)
+        {
+            /*
+             * Install signal handler if requested (errors are ignored).
+             */
+            if (!(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_NO_SIGNAL_HANDLER))
+            {
+                int rc = gctlSignalHandlerInstall();
+                pCtx->fInstalledSignalHandler = RT_SUCCESS(rc);
+            }
+        }
+    }
+    else
+        rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, pCtx->pCmdDef->fCmdUsage, "No user name specified!");
+    return rcExit;
+}
+
+
+/**
+ * Cleans up the context when the command returns.
+ *
+ * This will close any open guest session, unless the DETACH flag is set.
+ * It will also close any VM session that may be been established.  Any signal
+ * handlers we've installed will also be removed.
+ *
  * Un-initializes the VM after guest control usage.
  * @param   pCmdCtx                 Pointer to command context.
- * @param   uFlags                  Command context flags.
- */
-static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags)
-{
-    AssertPtrReturnVoid(pCtx);
-
-    if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
-        ctrlSignalHandlerUninstall();
-
+ */
+static void gctlCtxTerm(PGCTLCMDCTX pCtx)
+{
     HRESULT rc;
-
-    do
-    {
-        if (!pCtx->pGuestSession.isNull())
-        {
-            if (   !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)
-                && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH))
-            {
-                if (pCtx->fVerbose)
-                    RTPrintf("Closing guest session ...\n");
-
-                CHECK_ERROR(pCtx->pGuestSession, Close());
-                /* Keep going - don't break here. Try to unlock the
-                 * machine down below. */
-            }
-            else if (   (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)
-                     && pCtx->fVerbose)
-                RTPrintf("Guest session detached\n");
-
-            pCtx->pGuestSession.setNull();
-        }
-
-        if (pCtx->handlerArg.session)
-            CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine());
-
-    } while (0);
-
-    for (int i = 0; i < pCtx->iArgc; i++)
-        RTStrFree(pCtx->ppaArgv[i]);
-    RTMemFree(pCtx->ppaArgv);
-    pCtx->iArgc = 0;
-}
-
-/**
- * Initializes the VM for IGuest operations.
- *
- * That is, checks whether it's up and running, if it can be locked (shared
- * only) and returns a valid IGuest pointer on success. Also, it does some
- * basic command line processing and opens a guest session, if required.
- *
- * @return  RTEXITCODE status code.
- * @param   pArg                    Pointer to command line argument structure.
- * @param   pCmdCtx                 Pointer to command context.
- * @param   uFlags                  Command context flags.
- */
-static RTEXITCODE ctrlInitVM(HandlerArg *pArg,
-                             PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage)
-{
-    AssertPtrReturn(pArg, RTEXITCODE_FAILURE);
-    AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE);
-    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
-
-#ifdef DEBUG_andy
-    RTPrintf("Original argv:\n");
-    for (int i=0; i<pArg->argc;i++)
-        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
-#endif
-
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-
-    const char *pszNameOrId = pArg->argv[0];
-    const char *pszCmd = pArg->argv[1];
-
-    /* Lookup VM. */
-    ComPtr<IMachine> machine;
-    /* Assume it's an UUID. */
-    HRESULT rc;
-    CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(),
-                                              machine.asOutParam()));
-    if (SUCCEEDED(rc))
-    {
-        /* Machine is running? */
-        MachineState_T machineState;
-        CHECK_ERROR(machine, COMGETTER(State)(&machineState));
-        if (   SUCCEEDED(rc)
-            && (machineState != MachineState_Running))
-            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n",
-                                    pszNameOrId, machineStateToName(machineState, false));
-    }
-    else
-        rcExit = RTEXITCODE_FAILURE;
-
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        /*
-         * Process standard options which are served by all commands.
-         */
-        static const RTGETOPTDEF s_aOptions[] =
-        {
-            { "--username",            'u',                             RTGETOPT_REQ_STRING  },
-            { "--passwordfile",        'p',                             RTGETOPT_REQ_STRING  },
-            { "--password",            GETOPTDEF_COMMON_PASSWORD,       RTGETOPT_REQ_STRING  },
-            { "--domain",              'd',                             RTGETOPT_REQ_STRING  },
-            { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
-        };
-
-
-
-        /** @todo r=bird: This is just SOOOO hackish and fragile, especially wrt to the
-         * exec/run commands. If you don't have the full option syntax, there is no way
-         * you can safely tell an option from an option value. sigh.
-         * The way to do this is by a defines with the above s_aOptions entries, calling
-         * a common function in the default case of each option parser, and a routine to
-         * be called at the end of option parsing to open the session. */
-
-
-
-        /*
-         * Allocate per-command argv. This then only contains the specific arguments
-         * the command needs.
-         */
-        pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1);
-        if (!pCtx->ppaArgv)
-        {
-            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n");
-        }
-        else
-        {
-            pCtx->iArgc = 0;
-
-            int iArgIdx = 2; /* Skip VM name and guest control command */
-            int ch;
-            RTGETOPTUNION ValueUnion;
-            RTGETOPTSTATE GetState;
-            RTGetOptInit(&GetState, pArg->argc, pArg->argv,
-                         s_aOptions, RT_ELEMENTS(s_aOptions),
-                         iArgIdx, 0);
-
-            while (   (ch = RTGetOpt(&GetState, &ValueUnion))
-                   && (rcExit == RTEXITCODE_SUCCESS))
-            {
-                /* For options that require an argument, ValueUnion has received the value. */
-                switch (ch)
-                {
-                    case 'u': /* User name */
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                            pCtx->strUsername = ValueUnion.psz;
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case GETOPTDEF_COMMON_PASSWORD: /* Password */
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                        {
-                            if (pCtx->strPassword.isEmpty())
-                                pCtx->strPassword = ValueUnion.psz;
-                        }
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case 'p': /* Password file */
-                    {
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                            rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword);
-                        iArgIdx = GetState.iNext;
-                        break;
-                    }
-
-                    case 'd': /* domain */
-                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-                            pCtx->strDomain = ValueUnion.psz;
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case 'v': /* Verbose */
-                        pCtx->fVerbose = true;
-                        iArgIdx = GetState.iNext;
-                        break;
-
-                    case 'h': /* Help */
-                        errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);
-                        return RTEXITCODE_SYNTAX;
-
-                    default:
-                        /* Simply skip; might be handled in a specific command
-                         * handler later. */
-                        break;
-
-                } /* switch */
-
-                int iArgDiff = GetState.iNext - iArgIdx;
-                if (iArgDiff)
-                {
-#ifdef DEBUG_andy
-                    RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx);
-#endif
-                    for (int i = iArgIdx; i < GetState.iNext; i++)
-                    {
-                        char *pszArg = RTStrDup(pArg->argv[i]);
-                        if (!pszArg)
-                        {
-                            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
-                                                    "Not enough memory for command line handling\n");
-                            break;
-                        }
-                        pCtx->ppaArgv[pCtx->iArgc] = pszArg;
-                        pCtx->iArgc++;
-#ifdef DEBUG_andy
-                        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
-#endif
-                    }
-
-                    iArgIdx = GetState.iNext;
-                }
-
-            } /* while RTGetOpt */
-        }
-    }
+    AssertPtr(pCtx);
 
     /*
-     * Check for mandatory stuff.
+     * Uninstall signal handler.
      */
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-#if 0
-        RTPrintf("argc=%d\n", pCtx->iArgc);
-        for (int i = 0; i < pCtx->iArgc; i++)
-            RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]);
-#endif
-        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-        {
-            if (pCtx->strUsername.isEmpty())
-                rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!");
-        }
-    }
-
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        /*
-         * Build up a reasonable guest session name. Useful for identifying
-         * a specific session when listing / searching for them.
-         */
-        char *pszSessionName;
-        if (0 >= RTStrAPrintf(&pszSessionName,
-                              "[%RU32] VBoxManage Guest Control [%s] - %s",
-                              RTProcSelf(), pszNameOrId, pszCmd))
-            return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n");
-
-        do
-        {
-            /* Open a session for the VM. */
-            CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));
-            /* Get the associated console. */
-            ComPtr<IConsole> console;
-            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));
-            /* ... and session machine. */
-            ComPtr<IMachine> sessionMachine;
-            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
-            /* Get IGuest interface. */
-            CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));
-            if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
-            {
-                if (pCtx->fVerbose)
-                    RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str());
-
-                /* Open a guest session. */
-                Assert(!pCtx->pGuest.isNull());
-                CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),
-                                                              Bstr(pCtx->strPassword).raw(),
-                                                              Bstr(pCtx->strDomain).raw(),
-                                                              Bstr(pszSessionName).raw(),
-                                                              pCtx->pGuestSession.asOutParam()));
-
-                /*
-                 * Wait for guest session to start.
-                 */
-                if (pCtx->fVerbose)
-                    RTPrintf("Waiting for guest session to start ...\n");
-
-                com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
-                aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
-                GuestSessionWaitResult_T sessionWaitResult;
-                CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),
-                                                                    /** @todo Make session handling timeouts configurable. */
-                                                                    30 * 1000, &sessionWaitResult));
-
-                if (   sessionWaitResult == GuestSessionWaitResult_Start
-                    /* Note: This might happen when Guest Additions < 4.3 are installed which don't
-                     *       support dedicated guest sessions. */
-                    || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
-                {
-                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));
-                    if (pCtx->fVerbose)
-                        RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID);
-                }
-                else
-                {
-                    GuestSessionStatus_T sessionStatus;
-                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus));
-                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n",
-                                            ctrlSessionStatusToText(sessionStatus));
-                    break;
-                }
-            }
-
-            if (   SUCCEEDED(rc)
-                && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
-            {
-                ctrlSignalHandlerInstall();
-            }
-
-        } while (0);
-
-        if (FAILED(rc))
-            rcExit = RTEXITCODE_FAILURE;
-
-        RTStrFree(pszSessionName);
-    }
-
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        pCtx->handlerArg = *pArg;
-        pCtx->uFlags = uFlags;
-    }
-    else /* Clean up on failure. */
-        ctrlUninitVM(pCtx, uFlags);
-
-    return rcExit;
-}
+    if (pCtx->fInstalledSignalHandler)
+    {
+        gctlSignalHandlerUninstall();
+        pCtx->fInstalledSignalHandler = false;
+    }
+
+    /*
+     * Close, or at least release, the guest session.
+     */
+    if (pCtx->pGuestSession.isNotNull())
+    {
+        if (   !(pCtx->pCmdDef->fCmdCtx & GCTLCMDCTX_F_SESSION_ANONYMOUS)
+            && !pCtx->fDetachGuestSession)
+        {
+            if (pCtx->cVerbose > 1)
+                RTPrintf("Closing guest session ...\n");
+
+            CHECK_ERROR(pCtx->pGuestSession, Close());
+        }
+        else if (   pCtx->fDetachGuestSession
+                 && pCtx->cVerbose > 1)
+            RTPrintf("Guest session detached\n");
+
+        pCtx->pGuestSession.setNull();
+    }
+
+    /*
+     * Close the VM session.
+     */
+    if (pCtx->fLockedVmSession)
+    {
+        Assert(pCtx->pArg->session.isNotNull());
+        CHECK_ERROR(pCtx->pArg->session, UnlockMachine());
+        pCtx->fLockedVmSession = false;
+    }
+}
+
+
+
+
+
+/*
+ *
+ *
+ * Guest Control Command Handling.
+ * Guest Control Command Handling.
+ * Guest Control Command Handling.
+ * Guest Control Command Handling.
+ * Guest Control Command Handling.
+ *
+ *
+ */
 
 
@@ -1044,5 +1110,5 @@
  * @note    The guest exit code mappings was introduced with 5.0 and the 'run'
  *          command, they are/was not supported by 'exec'.
- * @sa      ctrlRunCalculateExitCode
+ * @sa      gctlRunCalculateExitCode
  */
 /** Process exited normally but with an exit code <> 0. */
@@ -1079,5 +1145,5 @@
  *                              exit codes.
  */
-static RTEXITCODE ctrlRunCalculateExitCode(ProcessStatus_T enmStatus, ULONG uExitCode, bool fReturnExitCodes)
+static RTEXITCODE gctlRunCalculateExitCode(ProcessStatus_T enmStatus, ULONG uExitCode, bool fReturnExitCodes)
 {
     int vrc = RTEXITCODE_SUCCESS;
@@ -1134,5 +1200,5 @@
  *                          complete.
  */
-static int ctrlRunPumpOutput(IProcess *pProcess, RTVFSIOSTREAM hVfsIosDst, ULONG uHandle, RTMSINTERVAL cMsTimeout)
+static int gctlRunPumpOutput(IProcess *pProcess, RTVFSIOSTREAM hVfsIosDst, ULONG uHandle, RTMSINTERVAL cMsTimeout)
 {
     AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
@@ -1159,5 +1225,5 @@
     }
     else
-        vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
+        vrc = gctlPrintError(pProcess, COM_IIDOF(IProcess));
     return vrc;
 }
@@ -1174,5 +1240,5 @@
  * @param   phVfsIos            Where to return the resulting I/O stream handle.
  */
-static bool ctrlRunSetupHandle(bool fEnabled, RTHANDLESTD enmHandle, const char *pszName,
+static bool gctlRunSetupHandle(bool fEnabled, RTHANDLESTD enmHandle, const char *pszName,
                                kStreamTransform enmTransformation, PRTVFSIOSTREAM phVfsIos)
 {
@@ -1203,5 +1269,5 @@
  * @param   cMsTimeout      Timeout value (in ms).
  */
-static RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout)
+static RTMSINTERVAL gctlRunGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout)
 {
     if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */
@@ -1223,5 +1289,5 @@
  * @param   fHelp       The help flag for the command.
  */
-static RTEXITCODE handleCtrlProcessRunCommon(PGCTLCMDCTX pCtx, bool fRunCmd, uint32_t fHelp)
+static RTEXITCODE gctlHandleRunCommon(PGCTLCMDCTX pCtx, bool fRunCmd, uint32_t fHelp)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -1230,6 +1296,18 @@
      * Parse arguments.
      */
+    enum kGstCtrlRunOpt
+    {
+        kGstCtrlRunOpt_IgnoreOrphanedProcesses = 1000,
+        kGstCtrlRunOpt_NoProfile,
+        kGstCtrlRunOpt_Dos2Unix,
+        kGstCtrlRunOpt_Unix2Dos,
+        kGstCtrlRunOpt_WaitForStdOut,
+        kGstCtrlRunOpt_NoWaitForStdOut,
+        kGstCtrlRunOpt_WaitForStdErr,
+        kGstCtrlRunOpt_NoWaitForStdErr
+    };
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--putenv",                       'E',                                      RTGETOPT_REQ_STRING  },
         { "--executable",                   'e',                                      RTGETOPT_REQ_STRING  },
@@ -1249,6 +1327,6 @@
     RTGETOPTUNION           ValueUnion;
     RTGETOPTSTATE           GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions),
-                 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     com::SafeArray<ProcessCreateFlag_T>     aCreateFlags;
@@ -1276,4 +1354,6 @@
             switch (ch)
             {
+                GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
                 case 'E':
                     if (   ValueUnion.psz[0] == '\0'
@@ -1366,5 +1446,5 @@
         {
             aWaitFlags.push_back(ProcessWaitForFlag_Terminate);
-            fWaitForStdOut = ctrlRunSetupHandle(fWaitForStdOut, RTHANDLESTD_OUTPUT, "stdout", enmStdOutTransform, &hVfsStdOut);
+            fWaitForStdOut = gctlRunSetupHandle(fWaitForStdOut, RTHANDLESTD_OUTPUT, "stdout", enmStdOutTransform, &hVfsStdOut);
             if (fWaitForStdOut)
             {
@@ -1372,5 +1452,5 @@
                 aWaitFlags.push_back(ProcessWaitForFlag_StdOut);
             }
-            fWaitForStdErr = ctrlRunSetupHandle(fWaitForStdErr, RTHANDLESTD_ERROR, "stderr", enmStdErrTransform, &hVfsStdErr);
+            fWaitForStdErr = gctlRunSetupHandle(fWaitForStdErr, RTHANDLESTD_ERROR, "stderr", enmStdErrTransform, &hVfsStdErr);
             if (fWaitForStdErr)
             {
@@ -1385,5 +1465,8 @@
     }
 
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
     HRESULT rc;
 
@@ -1398,5 +1481,5 @@
              * Create the process.
              */
-            if (pCtx->fVerbose)
+            if (pCtx->cVerbose > 1)
             {
                 if (cMsTimeout == 0)
@@ -1410,5 +1493,5 @@
                                                                  ComSafeArrayAsInParam(aEnv),
                                                                  ComSafeArrayAsInParam(aCreateFlags),
-                                                                 ctrlExecGetRemainingTime(msStart, cMsTimeout),
+                                                                 gctlRunGetRemainingTime(msStart, cMsTimeout),
                                                                  pProcess.asOutParam()));
 
@@ -1420,9 +1503,9 @@
             ProcessWaitResult_T waitResult;
             CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags),
-                                                     ctrlExecGetRemainingTime(msStart, cMsTimeout), &waitResult));
+                                                     gctlRunGetRemainingTime(msStart, cMsTimeout), &waitResult));
 
             ULONG uPID = 0;
             CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
-            if (fRunCmd && pCtx->fVerbose)
+            if (fRunCmd && pCtx->cVerbose > 1)
                 RTPrintf("Process '%s' (PID %RU32) started\n", pszImage, uPID);
             else if (!fRunCmd) /** @todo Introduce a --quiet option for not printing this. */
@@ -1446,5 +1529,5 @@
                    && cMsTimeLeft > 0)
             {
-                cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
+                cMsTimeLeft = gctlRunGetRemainingTime(msStart, cMsTimeout);
                 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags),
                                                          RT_MIN(500 /*ms*/, RT_MAX(cMsTimeLeft, 1 /*ms*/)),
@@ -1462,5 +1545,5 @@
                         break;
                     case ProcessWaitResult_Terminate:
-                        if (pCtx->fVerbose)
+                        if (pCtx->cVerbose > 1)
                             RTPrintf("Process terminated\n");
                         /* Process terminated, we're done. */
@@ -1508,6 +1591,6 @@
                 if (fReadStdOut)
                 {
-                    cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
-                    int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdOut, 1 /* StdOut */, cMsTimeLeft);
+                    cMsTimeLeft = gctlRunGetRemainingTime(msStart, cMsTimeout);
+                    int vrc2 = gctlRunPumpOutput(pProcess, hVfsStdOut, 1 /* StdOut */, cMsTimeLeft);
                     if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc))
                         vrc = vrc2;
@@ -1516,6 +1599,6 @@
                 if (fReadStdErr)
                 {
-                    cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
-                    int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdErr, 2 /* StdErr */, cMsTimeLeft);
+                    cMsTimeLeft = gctlRunGetRemainingTime(msStart, cMsTimeout);
+                    int vrc2 = gctlRunPumpOutput(pProcess, hVfsStdErr, 2 /* StdErr */, cMsTimeLeft);
                     if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc))
                         vrc = vrc2;
@@ -1537,5 +1620,5 @@
             if (g_fGuestCtrlCanceled)
             {
-                if (pCtx->fVerbose)
+                if (pCtx->cVerbose > 1)
                     RTPrintf("Process execution aborted!\n");
                 rcExit = EXITCODEEXEC_CANCELED;
@@ -1543,5 +1626,5 @@
             else if (fCompletedStartCmd)
             {
-                if (pCtx->fVerbose)
+                if (pCtx->cVerbose > 1)
                     RTPrintf("Process successfully started!\n");
                 rcExit = RTEXITCODE_SUCCESS;
@@ -1557,14 +1640,14 @@
                     LONG lExitCode;
                     CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&lExitCode));
-                    if (pCtx->fVerbose)
+                    if (pCtx->cVerbose > 1)
                         RTPrintf("Exit code=%u (Status=%u [%s])\n",
-                                 lExitCode, procStatus, ctrlProcessStatusToText(procStatus));
-
-                    rcExit = ctrlRunCalculateExitCode(procStatus, lExitCode, true /*fReturnExitCodes*/);
+                                 lExitCode, procStatus, gctlProcessStatusToText(procStatus));
+
+                    rcExit = gctlRunCalculateExitCode(procStatus, lExitCode, true /*fReturnExitCodes*/);
                 }
                 else if (   procStatus == ProcessStatus_TimedOutKilled
                          || procStatus == ProcessStatus_TimedOutAbnormally)
                 {
-                    if (pCtx->fVerbose)
+                    if (pCtx->cVerbose > 1)
                         RTPrintf("Process timed out (guest side) and\n",
                                  procStatus == ProcessStatus_TimedOutAbnormally
@@ -1574,6 +1657,6 @@
                 else
                 {
-                    if (pCtx->fVerbose)
-                        RTPrintf("Process now is in status [%s] (unexpected)\n", ctrlProcessStatusToText(procStatus));
+                    if (pCtx->cVerbose > 1)
+                        RTPrintf("Process now is in status [%s] (unexpected)\n", gctlProcessStatusToText(procStatus));
                     rcExit = RTEXITCODE_FAILURE;
                 }
@@ -1581,5 +1664,5 @@
             else if (RT_FAILURE_NP(vrc))
             {
-                if (pCtx->fVerbose)
+                if (pCtx->cVerbose > 1)
                     RTPrintf("Process monitor loop quit with vrc=%Rrc\n", vrc);
                 rcExit = RTEXITCODE_FAILURE;
@@ -1587,5 +1670,5 @@
             else
             {
-                if (pCtx->fVerbose)
+                if (pCtx->cVerbose > 1)
                     RTPrintf("Process monitor loop timed out\n");
                 rcExit = EXITCODEEXEC_TIMEOUT;
@@ -1609,5 +1692,5 @@
      */
     if (!fRunCmd && SUCCEEDED(rc) && !g_fGuestCtrlCanceled)
-        pCtx->uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH;
+        pCtx->fDetachGuestSession = true;
 
     /* Make sure we return failure on failure. */
@@ -1618,13 +1701,13 @@
 
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlProcessRun(PGCTLCMDCTX pCtx)
-{
-    return handleCtrlProcessRunCommon(pCtx, true /*fRunCmd*/, USAGE_GSTCTRL_RUN);
-}
-
-
-static DECLCALLBACK(RTEXITCODE) handleCtrlProcessStart(PGCTLCMDCTX pCtx)
-{
-    return handleCtrlProcessRunCommon(pCtx, false /*fRunCmd*/, USAGE_GSTCTRL_START);
+static DECLCALLBACK(RTEXITCODE) gctlHandleRun(PGCTLCMDCTX pCtx)
+{
+    return gctlHandleRunCommon(pCtx, true /*fRunCmd*/, USAGE_GSTCTRL_RUN);
+}
+
+
+static DECLCALLBACK(RTEXITCODE) gctlHandleStart(PGCTLCMDCTX pCtx)
+{
+    return gctlHandleRunCommon(pCtx, false /*fRunCmd*/, USAGE_GSTCTRL_START);
 }
 
@@ -1749,10 +1832,10 @@
     }
     else
-        vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
+        vrc = gctlPrintError(pProcess, COM_IIDOF(IProcess));
     return vrc;
 }
 
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExecDeprecated(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleProcessExecDeprecated(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -1763,4 +1846,5 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--dos2unix",                     GETOPTDEF_EXEC_DOS2UNIX,                  RTGETOPT_REQ_NOTHING },
         { "--environment",                  'e',                                      RTGETOPT_REQ_STRING  },
@@ -1771,5 +1855,5 @@
         { "--timeout",                      't',                                      RTGETOPT_REQ_UINT32  },
         { "--unix2dos",                     GETOPTDEF_EXEC_UNIX2DOS,                  RTGETOPT_REQ_NOTHING },
-        { "--unquoted-args",                'u',                                      RTGETOPT_REQ_NOTHING },
+        { "--unquoted-args",                'U',                                      RTGETOPT_REQ_NOTHING },
         { "--wait-exit",                    GETOPTDEF_EXEC_WAITFOREXIT,               RTGETOPT_REQ_NOTHING },
         { "--wait-stdout",                  GETOPTDEF_EXEC_WAITFORSTDOUT,             RTGETOPT_REQ_NOTHING },
@@ -1777,15 +1861,9 @@
     };
 
-#ifdef DEBUG_andy
-    RTPrintf("first=%d\n", pCtx->iFirstArgc);
-    for (int i=0; i<pCtx->iArgc;i++)
-        RTPrintf("\targv[%d]=%s\n", i, pCtx->ppaArgv[i]);
-#endif
-
     int                     ch;
     RTGETOPTUNION           ValueUnion;
     RTGETOPTSTATE           GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions),
-                 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     Utf8Str                              strCmd;
@@ -1811,4 +1889,6 @@
             switch (ch)
             {
+                GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
                 case 'e': /* Environment */
                 {
@@ -1839,5 +1919,5 @@
                     break;
 
-                case 'u':
+                case 'U':
                     aCreateFlags.push_back(ProcessCreateFlag_UnquotedArguments);
                     break;
@@ -1907,5 +1987,8 @@
                              "No command to execute specified!");
 
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
     HRESULT rc;
 
@@ -1921,5 +2004,5 @@
             uint64_t u64StartMS = RTTimeMilliTS();
 
-            if (pCtx->fVerbose)
+            if (pCtx->cVerbose > 1)
             {
                 if (cMsTimeout == 0)
@@ -1937,5 +2020,5 @@
                                                                  ComSafeArrayAsInParam(aEnv),
                                                                  ComSafeArrayAsInParam(aCreateFlags),
-                                                                 ctrlExecGetRemainingTime(u64StartMS, cMsTimeout),
+                                                                 gctlRunGetRemainingTime(u64StartMS, cMsTimeout),
                                                                  pProcess.asOutParam()));
 
@@ -1948,10 +2031,10 @@
             ProcessWaitResult_T waitResult;
             CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags),
-                                                     ctrlExecGetRemainingTime(u64StartMS, cMsTimeout), &waitResult));
+                                                     gctlRunGetRemainingTime(u64StartMS, cMsTimeout), &waitResult));
             bool fCompleted = false;
 
             ULONG uPID = 0;
             CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
-            if (!fDetached && pCtx->fVerbose)
+            if (!fDetached && pCtx->cVerbose > 1)
             {
                 RTPrintf("Process '%s' (PID %RU32) started\n",
@@ -1981,5 +2064,5 @@
                    && cMsTimeLeft != 0)
             {
-                cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
+                cMsTimeLeft = gctlRunGetRemainingTime(u64StartMS, cMsTimeout);
                 CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags),
                                                          500 /* ms */, &waitResult));
@@ -2001,5 +2084,5 @@
                         break;
                     case ProcessWaitResult_Terminate:
-                        if (pCtx->fVerbose)
+                        if (pCtx->cVerbose > 1)
                             RTPrintf("Process terminated\n");
                         /* Process terminated, we're done. */
@@ -2028,5 +2111,5 @@
                 if (fReadStdOut) /* Do we need to fetch stdout data? */
                 {
-                    cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
+                    cMsTimeLeft = gctlRunGetRemainingTime(u64StartMS, cMsTimeout);
                     vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdOut,
                                                         1 /* StdOut */, cMsTimeLeft);
@@ -2036,5 +2119,5 @@
                 if (fReadStdErr) /* Do we need to fetch stdout data? */
                 {
-                    cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
+                    cMsTimeLeft = gctlRunGetRemainingTime(u64StartMS, cMsTimeout);
                     vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdErr,
                                                         2 /* StdErr */, cMsTimeLeft);
@@ -2071,17 +2154,17 @@
                             LONG exitCode;
                             CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&exitCode));
-                            if (pCtx->fVerbose)
+                            if (pCtx->cVerbose > 1)
                                 RTPrintf("Exit code=%u (Status=%u [%s])\n",
-                                         exitCode, procStatus, ctrlProcessStatusToText(procStatus));
+                                         exitCode, procStatus, gctlProcessStatusToText(procStatus));
 
                             rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCodeDeprecated(procStatus, exitCode);
                         }
-                        else if (pCtx->fVerbose)
-                            RTPrintf("Process now is in status [%s]\n", ctrlProcessStatusToText(procStatus));
+                        else if (pCtx->cVerbose > 1)
+                            RTPrintf("Process now is in status [%s]\n", gctlProcessStatusToText(procStatus));
                     }
                 }
                 else
                 {
-                    if (pCtx->fVerbose)
+                    if (pCtx->cVerbose > 1)
                         RTPrintf("Process execution aborted!\n");
 
@@ -2123,5 +2206,5 @@
 
     if (!fCloseSession)
-        pCtx->uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH;
+        pCtx->fDetachGuestSession = true;
 
     if (   rcExit == RTEXITCODE_SUCCESS
@@ -2139,5 +2222,5 @@
 /**
  * Creates a copy context structure which then can be used with various
- * guest control copy functions. Needs to be free'd with ctrlCopyContextFree().
+ * guest control copy functions. Needs to be free'd with gctlCopyContextFree().
  *
  * @return  IPRT status code.
@@ -2149,5 +2232,5 @@
  * @param   ppContext               Pointer which receives the allocated copy context.
  */
-static int ctrlCopyContextCreate(PGCTLCMDCTX pCtx, bool fDryRun, bool fHostToGuest,
+static int gctlCopyContextCreate(PGCTLCMDCTX pCtx, bool fDryRun, bool fHostToGuest,
                                  const Utf8Str &strSessionName,
                                  PCOPYCONTEXT *ppContext)
@@ -2179,5 +2262,5 @@
  * @param   pContext                Pointer to copy context to free.
  */
-static void ctrlCopyContextFree(PCOPYCONTEXT pContext)
+static void gctlCopyContextFree(PCOPYCONTEXT pContext)
 {
     if (pContext)
@@ -2199,5 +2282,5 @@
  *                                  path. Must be free'd with RTStrFree().
  */
-static int ctrlCopyTranslatePath(const char *pszSourceRoot, const char *pszSource,
+static int gctlCopyTranslatePath(const char *pszSourceRoot, const char *pszSource,
                                  const char *pszDest, char **ppszTranslated)
 {
@@ -2293,5 +2376,5 @@
 
         char *pszTranslated = NULL;
-        int iResult =  ctrlCopyTranslatePath(aTests[iTest].pszSourceRoot, aTests[iTest].pszSource,
+        int iResult =  gctlCopyTranslatePath(aTests[iTest].pszSourceRoot, aTests[iTest].pszSource,
                                              aTests[iTest].pszDest, &pszTranslated);
         if (iResult != aTests[iTest].iResult)
@@ -2326,5 +2409,5 @@
  * @param   pszDir                  Directory to create.
  */
-static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)
+static int gctlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)
 {
     AssertPtrReturn(pContext, VERR_INVALID_POINTER);
@@ -2332,9 +2415,9 @@
 
     bool fDirExists;
-    int vrc = ctrlCopyDirExists(pContext, pContext->fHostToGuest, pszDir, &fDirExists);
+    int vrc = gctlCopyDirExists(pContext, pContext->fHostToGuest, pszDir, &fDirExists);
     if (   RT_SUCCESS(vrc)
         && fDirExists)
     {
-        if (pContext->pCmdCtx->fVerbose)
+        if (pContext->pCmdCtx->cVerbose > 1)
             RTPrintf("Directory \"%s\" already exists\n", pszDir);
         return VINF_SUCCESS;
@@ -2346,5 +2429,5 @@
         return vrc;
 
-    if (pContext->pCmdCtx->fVerbose)
+    if (pContext->pCmdCtx->cVerbose > 1)
         RTPrintf("Creating directory \"%s\" ...\n", pszDir);
 
@@ -2359,5 +2442,5 @@
                                                                        0700, ComSafeArrayAsInParam(dirCreateFlags));
         if (FAILED(rc))
-            vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
+            vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
     }
     else /* ... or on the host. */
@@ -2381,5 +2464,5 @@
  *                                  given directory exists or not.
  */
-static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool fOnGuest,
+static int gctlCopyDirExists(PCOPYCONTEXT pContext, bool fOnGuest,
                              const char *pszDir, bool *fExists)
 {
@@ -2394,5 +2477,5 @@
         HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryExists(Bstr(pszDir).raw(), &fDirExists);
         if (FAILED(rc))
-            vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
+            vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
         else
             *fExists = fDirExists ? true : false;
@@ -2413,8 +2496,8 @@
  *                                  given directory exists or not.
  */
-static int ctrlCopyDirExistsOnDest(PCOPYCONTEXT pContext, const char *pszDir,
+static int gctlCopyDirExistsOnDest(PCOPYCONTEXT pContext, const char *pszDir,
                                    bool *fExists)
 {
-    return ctrlCopyDirExists(pContext, pContext->fHostToGuest,
+    return gctlCopyDirExists(pContext, pContext->fHostToGuest,
                              pszDir, fExists);
 }
@@ -2430,8 +2513,8 @@
  *                                  given directory exists or not.
  */
-static int ctrlCopyDirExistsOnSource(PCOPYCONTEXT pContext, const char *pszDir,
+static int gctlCopyDirExistsOnSource(PCOPYCONTEXT pContext, const char *pszDir,
                                      bool *fExists)
 {
-    return ctrlCopyDirExists(pContext, !pContext->fHostToGuest,
+    return gctlCopyDirExists(pContext, !pContext->fHostToGuest,
                              pszDir, fExists);
 }
@@ -2448,5 +2531,5 @@
  *                                  given file exists or not.
  */
-static int ctrlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest,
+static int gctlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest,
                               const char *pszFile, bool *fExists)
 {
@@ -2461,5 +2544,5 @@
         HRESULT rc = pContext->pCmdCtx->pGuestSession->FileExists(Bstr(pszFile).raw(), &fFileExists);
         if (FAILED(rc))
-            vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
+            vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
         else
             *fExists = fFileExists ? true : false;
@@ -2480,8 +2563,8 @@
  *                                  given file exists or not.
  */
-static int ctrlCopyFileExistsOnDest(PCOPYCONTEXT pContext, const char *pszFile,
+static int gctlCopyFileExistsOnDest(PCOPYCONTEXT pContext, const char *pszFile,
                                     bool *fExists)
 {
-    return ctrlCopyFileExists(pContext, pContext->fHostToGuest,
+    return gctlCopyFileExists(pContext, pContext->fHostToGuest,
                               pszFile, fExists);
 }
@@ -2497,8 +2580,8 @@
  *                                  given file exists or not.
  */
-static int ctrlCopyFileExistsOnSource(PCOPYCONTEXT pContext, const char *pszFile,
+static int gctlCopyFileExistsOnSource(PCOPYCONTEXT pContext, const char *pszFile,
                                       bool *fExists)
 {
-    return ctrlCopyFileExists(pContext, !pContext->fHostToGuest,
+    return gctlCopyFileExists(pContext, !pContext->fHostToGuest,
                               pszFile, fExists);
 }
@@ -2514,5 +2597,5 @@
  *                                  to be set to 0.
  */
-static int ctrlCopyFileToDest(PCOPYCONTEXT pContext, const char *pszFileSource,
+static int gctlCopyFileToDest(PCOPYCONTEXT pContext, const char *pszFileSource,
                               const char *pszFileDest, uint32_t fFlags)
 {
@@ -2522,5 +2605,5 @@
     AssertReturn(!fFlags, VERR_INVALID_POINTER); /* No flags supported yet. */
 
-    if (pContext->pCmdCtx->fVerbose)
+    if (pContext->pCmdCtx->cVerbose > 1)
         RTPrintf("Copying \"%s\" to \"%s\" ...\n",
                  pszFileSource, pszFileDest);
@@ -2549,9 +2632,9 @@
     if (FAILED(rc))
     {
-        vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
+        vrc = gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
     }
     else
     {
-        if (pContext->pCmdCtx->fVerbose)
+        if (pContext->pCmdCtx->cVerbose > 1)
             rc = showProgress(pProgress);
         else
@@ -2559,5 +2642,5 @@
         if (SUCCEEDED(rc))
             CHECK_PROGRESS_ERROR(pProgress, ("File copy failed"));
-        vrc = ctrlPrintProgressError(pProgress);
+        vrc = gctlPrintProgressError(pProgress);
     }
 
@@ -2577,5 +2660,5 @@
  *                                  is needed for recursion.
  */
-static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext,
+static int gctlCopyDirToGuest(PCOPYCONTEXT pContext,
                               const char *pszSource, const char *pszFilter,
                               const char *pszDest, uint32_t fFlags,
@@ -2596,5 +2679,5 @@
         vrc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir);
 
-    if (pContext->pCmdCtx->fVerbose)
+    if (pContext->pCmdCtx->cVerbose > 1)
         RTPrintf("Processing host directory: %s\n", szCurDir);
 
@@ -2641,5 +2724,5 @@
                         break;
 
-                    if (pContext->pCmdCtx->fVerbose)
+                    if (pContext->pCmdCtx->cVerbose > 1)
                         RTPrintf("Directory: %s\n", DirEntry.szName);
 
@@ -2657,5 +2740,5 @@
                         if (pszNewSub)
                         {
-                            vrc = ctrlCopyDirToGuest(pContext,
+                            vrc = gctlCopyDirToGuest(pContext,
                                                      pszSource, pszFilter,
                                                      pszDest, fFlags, pszNewSub);
@@ -2685,5 +2768,5 @@
                     }
 
-                    if (pContext->pCmdCtx->fVerbose)
+                    if (pContext->pCmdCtx->cVerbose > 1)
                         RTPrintf("File: %s\n", DirEntry.szName);
 
@@ -2691,9 +2774,9 @@
                     {
                         char *pszDestDir;
-                        vrc = ctrlCopyTranslatePath(pszSource, szCurDir,
+                        vrc = gctlCopyTranslatePath(pszSource, szCurDir,
                                                     pszDest, &pszDestDir);
                         if (RT_SUCCESS(vrc))
                         {
-                            vrc = ctrlCopyDirCreate(pContext, pszDestDir);
+                            vrc = gctlCopyDirCreate(pContext, pszDestDir);
                             RTStrFree(pszDestDir);
 
@@ -2708,9 +2791,9 @@
                         {
                             char *pszFileDest;
-                            vrc = ctrlCopyTranslatePath(pszSource, pszFileSource,
+                            vrc = gctlCopyTranslatePath(pszSource, pszFileSource,
                                                        pszDest, &pszFileDest);
                             if (RT_SUCCESS(vrc))
                             {
-                                vrc = ctrlCopyFileToDest(pContext, pszFileSource,
+                                vrc = gctlCopyFileToDest(pContext, pszFileSource,
                                                         pszFileDest, 0 /* Flags */);
                                 RTStrFree(pszFileDest);
@@ -2746,5 +2829,5 @@
  *                                  is needed for recursion.
  */
-static int ctrlCopyDirToHost(PCOPYCONTEXT pContext,
+static int gctlCopyDirToHost(PCOPYCONTEXT pContext,
                              const char *pszSource, const char *pszFilter,
                              const char *pszDest, uint32_t fFlags,
@@ -2768,5 +2851,5 @@
         return vrc;
 
-    if (pContext->pCmdCtx->fVerbose)
+    if (pContext->pCmdCtx->cVerbose > 1)
         RTPrintf("Processing guest directory: %s\n", szCurDir);
 
@@ -2780,5 +2863,5 @@
                                                         pDirectory.asOutParam());
     if (FAILED(rc))
-        return ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
+        return gctlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
     ComPtr<IFsObjInfo> dirEntry;
     while (true)
@@ -2805,5 +2888,5 @@
                     break;
 
-                if (pContext->pCmdCtx->fVerbose)
+                if (pContext->pCmdCtx->cVerbose > 1)
                 {
                     Utf8Str strDir(strName);
@@ -2824,5 +2907,5 @@
                     if (pszNewSub)
                     {
-                        vrc = ctrlCopyDirToHost(pContext,
+                        vrc = gctlCopyDirToHost(pContext,
                                                 pszSource, pszFilter,
                                                 pszDest, fFlags, pszNewSub);
@@ -2855,5 +2938,5 @@
                 }
 
-                if (pContext->pCmdCtx->fVerbose)
+                if (pContext->pCmdCtx->cVerbose > 1)
                     RTPrintf("File: %s\n", strFile.c_str());
 
@@ -2861,9 +2944,9 @@
                 {
                     char *pszDestDir;
-                    vrc = ctrlCopyTranslatePath(pszSource, szCurDir,
+                    vrc = gctlCopyTranslatePath(pszSource, szCurDir,
                                                 pszDest, &pszDestDir);
                     if (RT_SUCCESS(vrc))
                     {
-                        vrc = ctrlCopyDirCreate(pContext, pszDestDir);
+                        vrc = gctlCopyDirCreate(pContext, pszDestDir);
                         RTStrFree(pszDestDir);
 
@@ -2878,9 +2961,9 @@
                     {
                         char *pszFileDest;
-                        vrc = ctrlCopyTranslatePath(pszSource, pszFileSource,
+                        vrc = gctlCopyTranslatePath(pszSource, pszFileSource,
                                                    pszDest, &pszFileDest);
                         if (RT_SUCCESS(vrc))
                         {
-                            vrc = ctrlCopyFileToDest(pContext, pszFileSource,
+                            vrc = gctlCopyFileToDest(pContext, pszFileSource,
                                                     pszFileDest, 0 /* Flags */);
                             RTStrFree(pszFileDest);
@@ -2920,5 +3003,5 @@
 
             default:
-                vrc = ctrlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));
+                vrc = gctlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));
                 break;
         }
@@ -2928,5 +3011,5 @@
     if (FAILED(rc2))
     {
-        int vrc2 = ctrlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));
+        int vrc2 = gctlPrintError(pDirectory, COM_IIDOF(IGuestDirectory));
         if (RT_SUCCESS(vrc))
             vrc = vrc2;
@@ -2950,12 +3033,12 @@
  * @param   fFlags                  Copy flags, such as recursive copying.
  */
-static int ctrlCopyDirToDest(PCOPYCONTEXT pContext,
+static int gctlCopyDirToDest(PCOPYCONTEXT pContext,
                              const char *pszSource, const char *pszFilter,
                              const char *pszDest, uint32_t fFlags)
 {
     if (pContext->fHostToGuest)
-        return ctrlCopyDirToGuest(pContext, pszSource, pszFilter,
+        return gctlCopyDirToGuest(pContext, pszSource, pszFilter,
                                   pszDest, fFlags, NULL /* Sub directory, only for recursion. */);
-    return ctrlCopyDirToHost(pContext, pszSource, pszFilter,
+    return gctlCopyDirToHost(pContext, pszSource, pszFilter,
                              pszDest, fFlags, NULL /* Sub directory, only for recursion. */);
 }
@@ -2967,7 +3050,7 @@
  * @param   pszSource               Source to create source root for.
  * @param   ppszSourceRoot          Pointer that receives the allocated source root. Needs
- *                                  to be free'd with ctrlCopyFreeSourceRoot().
- */
-static int ctrlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot)
+ *                                  to be free'd with gctlCopyFreeSourceRoot().
+ */
+static int gctlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot)
 {
     AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
@@ -3013,10 +3096,10 @@
  * @param   pszSourceRoot           Source root to free.
  */
-static void ctrlCopyFreeSourceRoot(char *pszSourceRoot)
+static void gctlCopyFreeSourceRoot(char *pszSourceRoot)
 {
     RTStrFree(pszSourceRoot);
 }
 
-static RTEXITCODE handleCtrlCopy(PGCTLCMDCTX pCtx, bool fHostToGuest)
+static RTEXITCODE gctlHandleCopy(PGCTLCMDCTX pCtx, bool fHostToGuest)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -3038,4 +3121,5 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--dryrun",              GETOPTDEF_COPY_DRYRUN,           RTGETOPT_REQ_NOTHING },
         { "--follow",              GETOPTDEF_COPY_FOLLOW,           RTGETOPT_REQ_NOTHING },
@@ -3047,6 +3131,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     Utf8Str strSource;
@@ -3065,4 +3149,6 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case GETOPTDEF_COPY_DRYRUN:
                 fDryRun = true;
@@ -3086,5 +3172,5 @@
                  * --target-directory yet? Then use the current
                  * (= last) argument as destination. */
-                if (  pCtx->iArgc == GetState.iNext
+                if (   pCtx->pArg->argc == GetState.iNext
                     && strDest.isEmpty())
                 {
@@ -3112,8 +3198,12 @@
                              "No destination specified!");
 
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
     /*
      * Done parsing arguments, do some more preparations.
      */
-    if (pCtx->fVerbose)
+    if (pCtx->cVerbose > 1)
     {
         if (fHostToGuest)
@@ -3128,5 +3218,5 @@
      * the routines need to know when handling the actual copying. */
     PCOPYCONTEXT pContext = NULL;
-    vrc = ctrlCopyContextCreate(pCtx, fDryRun, fHostToGuest,
+    vrc = gctlCopyContextCreate(pCtx, fDryRun, fHostToGuest,
                                   fHostToGuest
                                 ? "VBoxManage Guest Control - Copy to guest"
@@ -3153,5 +3243,5 @@
     if (!RTPathFilename(pszDest))
     {
-        vrc = ctrlCopyDirCreate(pContext, pszDest);
+        vrc = gctlCopyDirCreate(pContext, pszDest);
     }
     else
@@ -3163,5 +3253,5 @@
         AssertPtr(pszDestDir);
         RTPathStripFilename(pszDestDir);
-        vrc = ctrlCopyDirCreate(pContext, pszDestDir);
+        vrc = gctlCopyDirCreate(pContext, pszDestDir);
         RTStrFree(pszDestDir);
     }
@@ -3182,5 +3272,5 @@
 
             char *pszSourceRoot;
-            vrc = ctrlCopyCreateSourceRoot(pszSource, &pszSourceRoot);
+            vrc = gctlCopyCreateSourceRoot(pszSource, &pszSourceRoot);
             if (RT_FAILURE(vrc))
             {
@@ -3189,5 +3279,5 @@
             }
 
-            if (pCtx->fVerbose)
+            if (pCtx->cVerbose > 1)
                 RTPrintf("Source: %s\n", pszSource);
 
@@ -3201,7 +3291,7 @@
             {
                 if (pszFilter) /* Directory with filter (so use source root w/o the actual filter). */
-                    vrc = ctrlCopyDirExistsOnSource(pContext, pszSourceRoot, &fSourceExists);
+                    vrc = gctlCopyDirExistsOnSource(pContext, pszSourceRoot, &fSourceExists);
                 else /* Regular directory without filter. */
-                    vrc = ctrlCopyDirExistsOnSource(pContext, pszSource, &fSourceExists);
+                    vrc = gctlCopyDirExistsOnSource(pContext, pszSource, &fSourceExists);
 
                 if (fSourceExists)
@@ -3214,5 +3304,5 @@
             else
             {
-                vrc = ctrlCopyFileExistsOnSource(pContext, pszSource, &fSourceExists);
+                vrc = gctlCopyFileExistsOnSource(pContext, pszSource, &fSourceExists);
                 if (   RT_SUCCESS(vrc)
                     && fSourceExists)
@@ -3229,9 +3319,9 @@
                     /* Single file. */
                     char *pszDestFile;
-                    vrc = ctrlCopyTranslatePath(pszSourceRoot, pszSource,
+                    vrc = gctlCopyTranslatePath(pszSourceRoot, pszSource,
                                                 strDest.c_str(), &pszDestFile);
                     if (RT_SUCCESS(vrc))
                     {
-                        vrc = ctrlCopyFileToDest(pContext, pszSource,
+                        vrc = gctlCopyFileToDest(pContext, pszSource,
                                                  pszDestFile, 0 /* Flags */);
                         RTStrFree(pszDestFile);
@@ -3244,10 +3334,10 @@
                 {
                     /* Directory (with filter?). */
-                    vrc = ctrlCopyDirToDest(pContext, pszSource, pszFilter,
+                    vrc = gctlCopyDirToDest(pContext, pszSource, pszFilter,
                                             strDest.c_str(), fFlags);
                 }
             }
 
-            ctrlCopyFreeSourceRoot(pszSourceRoot);
+            gctlCopyFreeSourceRoot(pszSourceRoot);
 
             if (   RT_SUCCESS(vrc)
@@ -3271,20 +3361,20 @@
     }
 
-    ctrlCopyContextFree(pContext);
+    gctlCopyContextFree(pContext);
 
     return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlCopyFrom(PGCTLCMDCTX pCtx)
-{
-    return handleCtrlCopy(pCtx, false /* Guest to host */);
-}
-
-static DECLCALLBACK(RTEXITCODE) handleCtrlCopyTo(PGCTLCMDCTX pCtx)
-{
-    return handleCtrlCopy(pCtx, true /* Host to guest */);
-}
-
-static DECLCALLBACK(RTEXITCODE) handleCtrlCreateDirectory(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleCopyFrom(PGCTLCMDCTX pCtx)
+{
+    return gctlHandleCopy(pCtx, false /* Guest to host */);
+}
+
+static DECLCALLBACK(RTEXITCODE) gctlHandleCopyTo(PGCTLCMDCTX pCtx)
+{
+    return gctlHandleCopy(pCtx, true /* Host to guest */);
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrtMkDir(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -3292,4 +3382,5 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--mode",                'm',                             RTGETOPT_REQ_UINT32  },
         { "--parents",             'P',                             RTGETOPT_REQ_NOTHING }
@@ -3299,6 +3390,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2,
+                 RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     SafeArray<DirectoryCreateFlag_T> dirCreateFlags;
@@ -3311,4 +3402,6 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case 'm': /* Mode */
                 fDirMode = ValueUnion.u32;
@@ -3324,5 +3417,5 @@
 
             default:
-                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATEDIR, ch, &ValueUnion);
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKDIR, ch, &ValueUnion);
         }
     }
@@ -3330,6 +3423,10 @@
     size_t cDirs = mapDirs.size();
     if (!cDirs)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATEDIR,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKDIR,
                              "No directory to create specified!");
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     /*
@@ -3337,5 +3434,5 @@
      */
     HRESULT rc = S_OK;
-    if (pCtx->fVerbose && cDirs)
+    if (pCtx->cVerbose > 1)
         RTPrintf("Creating %RU32 directories ...\n", cDirs);
 
@@ -3344,5 +3441,5 @@
            && !g_fGuestCtrlCanceled)
     {
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("Creating directory \"%s\" ...\n", it->first.c_str());
 
@@ -3355,5 +3452,5 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveDirectory(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleRmDir(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -3361,4 +3458,5 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--recursive",           'R',                             RTGETOPT_REQ_NOTHING }
     };
@@ -3367,6 +3465,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     bool fRecursive = false;
@@ -3378,4 +3476,6 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case 'R':
                 fRecursive = true;
@@ -3387,5 +3487,5 @@
 
             default:
-                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEDIR, ch, &ValueUnion);
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RMDIR, ch, &ValueUnion);
         }
     }
@@ -3393,6 +3493,10 @@
     size_t cDirs = mapDirs.size();
     if (!cDirs)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEDIR,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RMDIR,
                              "No directory to remove specified!");
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     /*
@@ -3400,5 +3504,5 @@
      */
     HRESULT rc = S_OK;
-    if (pCtx->fVerbose && cDirs)
+    if (pCtx->cVerbose > 1)
         RTPrintf("Removing %RU32 directories ...\n", cDirs);
 
@@ -3407,5 +3511,5 @@
            && !g_fGuestCtrlCanceled)
     {
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("%s directory \"%s\" ...\n",
                      fRecursive ? "Recursively removing" : "Removing",
@@ -3423,5 +3527,5 @@
                                                                                 ComSafeArrayAsInParam(aRemRecFlags),
                                                                                 pProgress.asOutParam()));
-                if (pCtx->fVerbose)
+                if (pCtx->cVerbose > 1)
                     rc = showProgress(pProgress);
                 else
@@ -3447,14 +3551,18 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveFile(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleRm(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        GCTLCMD_COMMON_OPTION_DEFS()
+    };
 
     int ch;
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 NULL /* s_aOptions */, 0 /* RT_ELEMENTS(s_aOptions) */,
-                 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     DESTDIRMAP mapDirs;
@@ -3465,4 +3573,6 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case VINF_GETOPT_NOT_OPTION:
                 mapDirs[ValueUnion.psz]; /* Add destination directory to map. */
@@ -3470,5 +3580,5 @@
 
             default:
-                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE, ch, &ValueUnion);
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RM, ch, &ValueUnion);
         }
     }
@@ -3476,6 +3586,9 @@
     size_t cFiles = mapDirs.size();
     if (!cFiles)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE,
-                             "No file to remove specified!");
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RM, "No file to remove specified!");
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     /*
@@ -3483,5 +3596,5 @@
      */
     HRESULT rc = S_OK;
-    if (pCtx->fVerbose && cFiles)
+    if (pCtx->cVerbose > 1)
         RTPrintf("Removing %RU32 file(s) ...\n", cFiles);
 
@@ -3490,5 +3603,5 @@
            && !g_fGuestCtrlCanceled)
     {
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("Removing file \"%s\" ...\n", it->first.c_str());
 
@@ -3501,15 +3614,18 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlRename(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleMv(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
 
-    static const RTGETOPTDEF s_aOptions[] = { { 0 } };
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        GCTLCMD_COMMON_OPTION_DEFS()
+    };
 
     int ch;
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 NULL /*s_aOptions*/, 0 /*RT_ELEMENTS(s_aOptions)*/, pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     int vrc = VINF_SUCCESS;
@@ -3531,4 +3647,6 @@
             switch (ch)
             {
+                GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
                 /** @todo Implement a --dryrun command. */
                 /** @todo Implement rename flags. */
@@ -3540,5 +3658,5 @@
 
                 default:
-                    return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME, ch, &ValueUnion);
+                    return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MV, ch, &ValueUnion);
             }
         }
@@ -3554,9 +3672,13 @@
     size_t cSources = vecSources.size();
     if (!cSources)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MV,
                              "No source(s) to move specified!");
     if (cSources < 2)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MV,
                              "No destination specified!");
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     /* Delete last element, which now is the destination. */
@@ -3577,8 +3699,6 @@
      * Rename (move) the entries.
      */
-    if (pCtx->fVerbose && cSources)
-        RTPrintf("Renaming %RU32 %s ...\n", cSources,
-                   cSources > 1
-                 ? "entries" : "entry");
+    if (pCtx->cVerbose > 1)
+        RTPrintf("Renaming %RU32 %s ...\n", cSources, cSources > 1 ? "entries" : "entry");
 
     std::vector< Utf8Str >::iterator it = vecSources.begin();
@@ -3600,5 +3720,5 @@
         if (FAILED(rc))
         {
-            if (pCtx->fVerbose)
+            if (pCtx->cVerbose > 1)
                 RTPrintf("Warning: Cannot stat for element \"%s\": No such element\n",
                          strCurSource.c_str());
@@ -3607,5 +3727,5 @@
         }
 
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("Renaming %s \"%s\" to \"%s\" ...\n",
                      fSourceIsDirectory ? "directory" : "file",
@@ -3635,5 +3755,5 @@
 
     if (   (it != vecSources.end())
-        && pCtx->fVerbose)
+        && pCtx->cVerbose > 1)
     {
         RTPrintf("Warning: Not all sources were renamed\n");
@@ -3643,5 +3763,5 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlCreateTemp(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleMkTemp(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -3649,4 +3769,5 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--mode",                'm',                             RTGETOPT_REQ_UINT32  },
         { "--directory",           'D',                             RTGETOPT_REQ_NOTHING },
@@ -3658,6 +3779,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     Utf8Str strTemplate;
@@ -3669,9 +3790,11 @@
     DESTDIRMAP mapDirs;
 
-    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
     {
         /* For options that require an argument, ValueUnion has received the value. */
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case 'm': /* Mode */
                 fMode = ValueUnion.u32;
@@ -3695,5 +3818,5 @@
                     strTemplate = ValueUnion.psz;
                 else
-                    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP,
+                    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP,
                                          "More than one template specified!\n");
                 break;
@@ -3701,20 +3824,24 @@
 
             default:
-                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP, ch, &ValueUnion);
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP, ch, &ValueUnion);
         }
     }
 
     if (strTemplate.isEmpty())
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP,
                              "No template specified!");
 
     if (!fDirectory)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_MKTEMP,
                              "Creating temporary files is currently not supported!");
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     /*
      * Create the directories.
      */
-    if (pCtx->fVerbose)
+    if (pCtx->cVerbose > 1)
     {
         if (fDirectory && !strTempDir.isEmpty())
@@ -3743,10 +3870,16 @@
             RTPrintf("Directory name: %ls\n", directory.raw());
     }
-    // else - temporary file not yet implemented
+    else
+    {
+        // else - temporary file not yet implemented
+        /** @todo implement temporary file creation (we fend it off above, no
+         *        worries). */
+        rc = E_FAIL;
+    }
 
     return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlStat(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleStat(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -3754,4 +3887,5 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--dereference",         'L',                             RTGETOPT_REQ_NOTHING },
         { "--file-system",         'f',                             RTGETOPT_REQ_NOTHING },
@@ -3763,6 +3897,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     DESTDIRMAP mapObjs;
@@ -3773,4 +3907,6 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case 'L': /* Dereference */
             case 'f': /* File-system */
@@ -3794,4 +3930,8 @@
                              "No element(s) to check specified!");
 
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
     HRESULT rc;
 
@@ -3799,9 +3939,8 @@
      * Doing the checks.
      */
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     DESTDIRMAPITER it = mapObjs.begin();
     while (it != mapObjs.end())
     {
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("Checking for element \"%s\" ...\n", it->first.c_str());
 
@@ -3815,5 +3954,5 @@
             /* If there's at least one element which does not exist on the guest,
              * drop out with exitcode 1. */
-            if (pCtx->fVerbose)
+            if (pCtx->cVerbose > 1)
                 RTPrintf("Cannot stat for element \"%s\": No such element\n",
                          it->first.c_str());
@@ -3852,5 +3991,5 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlUpdateAdditions(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleUpdateAdditions(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -3866,4 +4005,5 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--source",              's',         RTGETOPT_REQ_STRING  },
         { "--wait-start",          'w',         RTGETOPT_REQ_NOTHING }
@@ -3873,5 +4013,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, 0);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     int vrc = VINF_SUCCESS;
@@ -3881,4 +4022,6 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case 's':
                 strSource = ValueUnion.psz;
@@ -3897,9 +4040,9 @@
 
             default:
-                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_UPDATEADDS, ch, &ValueUnion);
-        }
-    }
-
-    if (pCtx->fVerbose)
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_UPDATEGA, ch, &ValueUnion);
+        }
+    }
+
+    if (pCtx->cVerbose > 1)
         RTPrintf("Updating Guest Additions ...\n");
 
@@ -3908,5 +4051,5 @@
     {
         ComPtr<ISystemProperties> pProperties;
-        CHECK_ERROR_BREAK(pCtx->handlerArg.virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam()));
+        CHECK_ERROR_BREAK(pCtx->pArg->virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam()));
         Bstr strISO;
         CHECK_ERROR_BREAK(pProperties, COMGETTER(DefaultAdditionsISO)(strISO.asOutParam()));
@@ -3929,6 +4072,12 @@
     if (RT_SUCCESS(vrc))
     {
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("Using source: %s\n", strSource.c_str());
+
+
+        RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+        if (rcExit != RTEXITCODE_SUCCESS)
+            return rcExit;
+
 
         com::SafeArray<AdditionsUpdateFlag_T> aUpdateFlags;
@@ -3936,5 +4085,5 @@
         {
             aUpdateFlags.push_back(AdditionsUpdateFlag_WaitForUpdateStartOnly);
-            if (pCtx->fVerbose)
+            if (pCtx->cVerbose > 1)
                 RTPrintf("Preparing and waiting for Guest Additions installer to start ...\n");
         }
@@ -3947,8 +4096,8 @@
                                                 pProgress.asOutParam()));
         if (FAILED(rc))
-            vrc = ctrlPrintError(pCtx->pGuest, COM_IIDOF(IGuest));
+            vrc = gctlPrintError(pCtx->pGuest, COM_IIDOF(IGuest));
         else
         {
-            if (pCtx->fVerbose)
+            if (pCtx->cVerbose > 1)
                 rc = showProgress(pProgress);
             else
@@ -3957,7 +4106,7 @@
             if (SUCCEEDED(rc))
                 CHECK_PROGRESS_ERROR(pProgress, ("Guest additions update failed"));
-            vrc = ctrlPrintProgressError(pProgress);
+            vrc = gctlPrintProgressError(pProgress);
             if (   RT_SUCCESS(vrc)
-                && pCtx->fVerbose)
+                && pCtx->cVerbose > 1)
             {
                 RTPrintf("Guest Additions update successful\n");
@@ -3969,57 +4118,87 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlList(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleList(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
 
-    if (pCtx->iArgc < 1)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST,
-                             "Must specify a listing category");
-
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-
-    /** Use RTGetOpt here when handling command line args gets more complex. */
-
-    bool fListAll = false;
-    bool fListSessions = false;
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        GCTLCMD_COMMON_OPTION_DEFS()
+    };
+
+    int ch;
+    RTGETOPTUNION ValueUnion;
+    RTGETOPTSTATE GetState;
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+    bool fSeenListArg   = false;
+    bool fListAll       = false;
+    bool fListSessions  = false;
     bool fListProcesses = false;
-    bool fListFiles = false;
-    if (   !RTStrICmp(pCtx->ppaArgv[0], "sessions")
-        || !RTStrICmp(pCtx->ppaArgv[0], "sess"))
-        fListSessions = true;
-    else if (   !RTStrICmp(pCtx->ppaArgv[0], "processes")
-             || !RTStrICmp(pCtx->ppaArgv[0], "procs"))
-        fListSessions = fListProcesses = true; /* Showing processes implies showing sessions. */
-    else if (   !RTStrICmp(pCtx->ppaArgv[0], "files"))
-        fListSessions = fListFiles = true;     /* Showing files implies showing sessions. */
-    else if (!RTStrICmp(pCtx->ppaArgv[0], "all"))
-        fListAll = true;
-
-    /** @todo Handle "--verbose" using RTGetOpt. */
+    bool fListFiles     = false;
+
+    int vrc = VINF_SUCCESS;
+    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
+           && RT_SUCCESS(vrc))
+    {
+        switch (ch)
+        {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
+            case VINF_GETOPT_NOT_OPTION:
+                if (   !RTStrICmp(ValueUnion.psz, "sessions")
+                    || !RTStrICmp(ValueUnion.psz, "sess"))
+                    fListSessions = true;
+                else if (   !RTStrICmp(ValueUnion.psz, "processes")
+                         || !RTStrICmp(ValueUnion.psz, "procs"))
+                    fListSessions = fListProcesses = true; /* Showing processes implies showing sessions. */
+                else if (!RTStrICmp(ValueUnion.psz, "files"))
+                    fListSessions = fListFiles = true;     /* Showing files implies showing sessions. */
+                else if (!RTStrICmp(ValueUnion.psz, "all"))
+                    fListAll = true;
+                else
+                    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST,
+                                         "Unknown list: '%s'", ValueUnion.psz);
+                fSeenListArg = true;
+                break;
+
+            default:
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_UPDATEGA, ch, &ValueUnion);
+        }
+    }
+
+    if (fSeenListArg)
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST, "Missing list name");
+    Assert(fListAll || fListSessions);
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
+
     /** @todo Do we need a machine-readable output here as well? */
 
-    if (   fListAll
-        || fListSessions)
-    {
-        HRESULT rc;
-        do
-        {
-            size_t cTotalProcs = 0;
-            size_t cTotalFiles = 0;
-
-            SafeIfaceArray <IGuestSession> collSessions;
-            CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));
-            size_t cSessions = collSessions.size();
-
-            if (cSessions)
-            {
-                RTPrintf("Active guest sessions:\n");
-
-                /** @todo Make this output a bit prettier. No time now. */
-
-                for (size_t i = 0; i < cSessions; i++)
+    HRESULT rc;
+    size_t cTotalProcs = 0;
+    size_t cTotalFiles = 0;
+
+    SafeIfaceArray <IGuestSession> collSessions;
+    CHECK_ERROR(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));
+    if (SUCCEEDED(rc))
+    {
+        size_t const cSessions = collSessions.size();
+        if (cSessions)
+        {
+            RTPrintf("Active guest sessions:\n");
+
+            /** @todo Make this output a bit prettier. No time now. */
+
+            for (size_t i = 0; i < cSessions; i++)
+            {
+                ComPtr<IGuestSession> pCurSession = collSessions[i];
+                if (!pCurSession.isNull())
                 {
-                    ComPtr<IGuestSession> pCurSession = collSessions[i];
-                    if (!pCurSession.isNull())
+                    do
                     {
                         ULONG uID;
@@ -4032,15 +4211,18 @@
                         CHECK_ERROR_BREAK(pCurSession, COMGETTER(Status)(&sessionStatus));
                         RTPrintf("\n\tSession #%-3zu ID=%-3RU32 User=%-16ls Status=[%s] Name=%ls",
-                                 i, uID, strUser.raw(), ctrlSessionStatusToText(sessionStatus), strName.raw());
-
-                        if (   fListAll
-                            || fListProcesses)
+                                 i, uID, strUser.raw(), gctlGuestSessionStatusToText(sessionStatus), strName.raw());
+                    } while (0);
+
+                    if (   fListAll
+                        || fListProcesses)
+                    {
+                        SafeIfaceArray <IGuestProcess> collProcesses;
+                        CHECK_ERROR_BREAK(pCurSession, COMGETTER(Processes)(ComSafeArrayAsOutParam(collProcesses)));
+                        for (size_t a = 0; a < collProcesses.size(); a++)
                         {
-                            SafeIfaceArray <IGuestProcess> collProcesses;
-                            CHECK_ERROR_BREAK(pCurSession, COMGETTER(Processes)(ComSafeArrayAsOutParam(collProcesses)));
-                            for (size_t a = 0; a < collProcesses.size(); a++)
+                            ComPtr<IGuestProcess> pCurProcess = collProcesses[a];
+                            if (!pCurProcess.isNull())
                             {
-                                ComPtr<IGuestProcess> pCurProcess = collProcesses[a];
-                                if (!pCurProcess.isNull())
+                                do
                                 {
                                     ULONG uPID;
@@ -4052,22 +4234,27 @@
 
                                     RTPrintf("\n\t\tProcess #%-03zu PID=%-6RU32 Status=[%s] Command=%ls",
-                                             a, uPID, ctrlProcessStatusToText(procStatus), strExecPath.raw());
-                                }
+                                             a, uPID, gctlProcessStatusToText(procStatus), strExecPath.raw());
+                                } while (0);
                             }
-
-                            cTotalProcs += collProcesses.size();
                         }
 
-                        if (   fListAll
-                            || fListFiles)
+                        cTotalProcs += collProcesses.size();
+                    }
+
+                    if (   fListAll
+                        || fListFiles)
+                    {
+                        SafeIfaceArray <IGuestFile> collFiles;
+                        CHECK_ERROR_BREAK(pCurSession, COMGETTER(Files)(ComSafeArrayAsOutParam(collFiles)));
+                        for (size_t a = 0; a < collFiles.size(); a++)
                         {
-                            SafeIfaceArray <IGuestFile> collFiles;
-                            CHECK_ERROR_BREAK(pCurSession, COMGETTER(Files)(ComSafeArrayAsOutParam(collFiles)));
-                            for (size_t a = 0; a < collFiles.size(); a++)
+                            ComPtr<IGuestFile> pCurFile = collFiles[a];
+                            if (!pCurFile.isNull())
                             {
-                                ComPtr<IGuestFile> pCurFile = collFiles[a];
-                                if (!pCurFile.isNull())
+                                do
                                 {
-                                    CHECK_ERROR_BREAK(pCurFile, COMGETTER(Id)(&uID));
+                                    ULONG idFile;
+                                    CHECK_ERROR_BREAK(pCurFile, COMGETTER(Id)(&idFile));
+                                    Bstr strName;
                                     CHECK_ERROR_BREAK(pCurFile, COMGETTER(FileName)(strName.asOutParam()));
                                     FileStatus_T fileStatus;
@@ -4075,44 +4262,37 @@
 
                                     RTPrintf("\n\t\tFile #%-03zu ID=%-6RU32 Status=[%s] Name=%ls",
-                                             a, uID, ctrlFileStatusToText(fileStatus), strName.raw());
-                                }
+                                             a, idFile, gctlFileStatusToText(fileStatus), strName.raw());
+                                } while (0);
                             }
-
-                            cTotalFiles += collFiles.size();
                         }
+
+                        cTotalFiles += collFiles.size();
                     }
                 }
-
-                RTPrintf("\n\nTotal guest sessions: %zu\n", collSessions.size());
-                if (fListAll || fListProcesses)
-                    RTPrintf("Total guest processes: %zu\n", cTotalProcs);
-                if (fListAll || fListFiles)
-                    RTPrintf("Total guest files: %zu\n", cTotalFiles);
-            }
-            else
-                RTPrintf("No active guest sessions found\n");
-
-        } while (0);
-
-        if (FAILED(rc))
-            rcExit = RTEXITCODE_FAILURE;
-    }
-    else
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST,
-                             "Invalid listing category '%s", pCtx->ppaArgv[0]);
+            }
+
+            RTPrintf("\n\nTotal guest sessions: %zu\n", collSessions.size());
+            if (fListAll || fListProcesses)
+                RTPrintf("Total guest processes: %zu\n", cTotalProcs);
+            if (fListAll || fListFiles)
+                RTPrintf("Total guest files: %zu\n", cTotalFiles);
+        }
+        else
+            RTPrintf("No active guest sessions found\n");
+    }
+
+    if (FAILED(rc))
+        rcExit = RTEXITCODE_FAILURE;
 
     return rcExit;
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlProcessClose(PGCTLCMDCTX pCtx)
+static DECLCALLBACK(RTEXITCODE) gctlHandleCloseProcess(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
 
-    if (pCtx->iArgc < 1)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
-                             "Must specify at least a PID to close");
-
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--session-id",          'i',                             RTGETOPT_REQ_UINT32  },
         { "--session-name",        'n',                             RTGETOPT_REQ_STRING  }
@@ -4122,6 +4302,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     std::vector < uint32_t > vecPID;
@@ -4129,12 +4309,11 @@
     Utf8Str strSessionName;
 
-    int vrc = VINF_SUCCESS;
-
-    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
-           && RT_SUCCESS(vrc))
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
     {
         /* For options that require an argument, ValueUnion has received the value. */
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case 'n': /* Session name (or pattern) */
                 strSessionName = ValueUnion.psz;
@@ -4146,45 +4325,54 @@
 
             case VINF_GETOPT_NOT_OPTION:
-                if (pCtx->iArgc == GetState.iNext)
+            {
+                /* Treat every else specified as a PID to kill. */
+                uint32_t uPid;
+                int rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 0, &uPid);
+                if (   RT_SUCCESS(rc)
+                    && rc != VWRN_TRAILING_CHARS
+                    && rc != VWRN_NUMBER_TOO_BIG
+                    && rc != VWRN_NEGATIVE_UNSIGNED)
                 {
-                    /* Treat every else specified as a PID to kill. */
-                    try
+                    if (uPid != 0)
                     {
-                        uint32_t uPID = RTStrToUInt32(ValueUnion.psz);
-                        if (uPID) /** @todo Is this what we want? If specifying PID 0
-                                            this is not going to work on most systems anyway. */
-                            vecPID.push_back(uPID);
-                        else
-                            vrc = VERR_INVALID_PARAMETER;
+                        try
+                        {
+                            vecPID.push_back(uPid);
+                        }
+                        catch (std::bad_alloc &)
+                        {
+                            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory");
+                        }
                     }
-                    catch(std::bad_alloc &)
-                    {
-                        vrc = VERR_NO_MEMORY;
-                    }
+                    else
+                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, "Invalid PID value: 0");
                 }
+                else
+                    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS,
+                                         "Error parsing PID value: %Rrc", rc);
                 break;
+            }
 
             default:
-                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS, ch, &ValueUnion);
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, ch, &ValueUnion);
         }
     }
 
     if (vecPID.empty())
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS,
                              "At least one PID must be specified to kill!");
 
     if (   strSessionName.isEmpty()
         && ulSessionID == UINT32_MAX)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
-                             "No session ID specified!");
-
-    if (   !strSessionName.isEmpty()
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS, "No session ID specified!");
+
+    if (   strSessionName.isNotEmpty()
         && ulSessionID != UINT32_MAX)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSEPROCESS,
                              "Either session ID or name (pattern) must be specified");
 
-    if (RT_FAILURE(vrc))
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
-                             "Invalid parameters specified");
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     HRESULT rc = S_OK;
@@ -4249,5 +4437,5 @@
                     if (fProcFound)
                     {
-                        if (pCtx->fVerbose)
+                        if (pCtx->cVerbose > 1)
                             RTPrintf("Terminating process (PID %RU32) (session ID %RU32) ...\n",
                                      uPID, uID);
@@ -4284,36 +4472,16 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlProcess(PGCTLCMDCTX pCtx)
+
+static DECLCALLBACK(RTEXITCODE) gctlHandleCloseSession(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
 
-    if (pCtx->iArgc < 1)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
-                             "Must specify an action");
-
-    /** Use RTGetOpt here when handling command line args gets more complex. */
-
-    if (   !RTStrICmp(pCtx->ppaArgv[0], "close")
-        || !RTStrICmp(pCtx->ppaArgv[0], "kill")
-        || !RTStrICmp(pCtx->ppaArgv[0], "terminate"))
-    {
-        pCtx->iFirstArgc++; /* Skip process action. */
-        return handleCtrlProcessClose(pCtx);
-    }
-
-    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
-                         "Invalid process action '%s'", pCtx->ppaArgv[0]);
-}
-
-static DECLCALLBACK(RTEXITCODE) handleCtrlSessionClose(PGCTLCMDCTX pCtx)
-{
-    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
-
-    if (pCtx->iArgc < 1)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
-                             "Must specify at least a session to close");
-
+    enum GETOPTDEF_SESSIONCLOSE
+    {
+        GETOPTDEF_SESSIONCLOSE_ALL = 2000
+    };
     static const RTGETOPTDEF s_aOptions[] =
     {
+        GCTLCMD_COMMON_OPTION_DEFS()
         { "--all",                 GETOPTDEF_SESSIONCLOSE_ALL,      RTGETOPT_REQ_NOTHING  },
         { "--session-id",          'i',                             RTGETOPT_REQ_UINT32  },
@@ -4324,6 +4492,6 @@
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     ULONG ulSessionID = UINT32_MAX;
@@ -4335,4 +4503,6 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case 'n': /* Session name pattern */
                 strSessionName = ValueUnion.psz;
@@ -4348,9 +4518,8 @@
 
             case VINF_GETOPT_NOT_OPTION:
-                /** @todo Supply a CSV list of IDs or patterns to close? */
-                break;
-
+                /** @todo Supply a CSV list of IDs or patterns to close?
+                 *  break; */
             default:
-                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION, ch, &ValueUnion);
+                return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSESESSION, ch, &ValueUnion);
         }
     }
@@ -4358,11 +4527,15 @@
     if (   strSessionName.isEmpty()
         && ulSessionID == UINT32_MAX)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSESESSION,
                              "No session ID specified!");
 
     if (   !strSessionName.isEmpty()
         && ulSessionID != UINT32_MAX)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
+        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CLOSESESSION,
                              "Either session ID or name (pattern) must be specified");
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     HRESULT rc = S_OK;
@@ -4403,9 +4576,9 @@
 
                 Assert(!pSession.isNull());
-                if (pCtx->fVerbose)
+                if (pCtx->cVerbose > 1)
                     RTPrintf("Closing guest session ID=#%RU32 \"%s\" ...\n",
                              uID, strNameUtf8.c_str());
                 CHECK_ERROR_BREAK(pSession, Close());
-                if (pCtx->fVerbose)
+                if (pCtx->cVerbose > 1)
                     RTPrintf("Guest session successfully closed\n");
 
@@ -4425,27 +4598,6 @@
 }
 
-static DECLCALLBACK(RTEXITCODE) handleCtrlSession(PGCTLCMDCTX pCtx)
-{
-    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
-
-    if (pCtx->iArgc < 1)
-        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
-                             "Must specify an action");
-
-    /** Use RTGetOpt here when handling command line args gets more complex. */
-
-    if (   !RTStrICmp(pCtx->ppaArgv[0], "close")
-        || !RTStrICmp(pCtx->ppaArgv[0], "kill")
-        || !RTStrICmp(pCtx->ppaArgv[0], "terminate"))
-    {
-        pCtx->iFirstArgc++; /* Skip session action. */
-        return handleCtrlSessionClose(pCtx);
-    }
-
-    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
-                         "Invalid session action '%s'", pCtx->ppaArgv[0]);
-}
-
-static DECLCALLBACK(RTEXITCODE) handleCtrlWatch(PGCTLCMDCTX pCtx)
+
+static DECLCALLBACK(RTEXITCODE) gctlHandleWatch(PGCTLCMDCTX pCtx)
 {
     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
@@ -4454,11 +4606,14 @@
      * Parse arguments.
      */
-    static const RTGETOPTDEF s_aOptions[] = { { 0 } };
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        GCTLCMD_COMMON_OPTION_DEFS()
+    };
 
     int ch;
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
-                 NULL /*s_aOptions*/, 0 /*RT_ELEMENTS(s_aOptions)*/, pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    RTGetOptInit(&GetState, pCtx->pArg->argc, pCtx->pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions),
+                 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
     while ((ch = RTGetOpt(&GetState, &ValueUnion)))
@@ -4467,7 +4622,7 @@
         switch (ch)
         {
+            GCTLCMD_COMMON_OPTION_CASES(pCtx, ch, &ValueUnion);
+
             case VINF_GETOPT_NOT_OPTION:
-                break;
-
             default:
                 return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_WATCH, ch, &ValueUnion);
@@ -4477,4 +4632,8 @@
     /** @todo Specify categories to watch for. */
     /** @todo Specify a --timeout for waiting only for a certain amount of time? */
+
+    RTEXITCODE rcExit = gctlCtxPostArgParsingInit(pCtx);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
 
     HRESULT rc;
@@ -4502,5 +4661,5 @@
         } while (0);
 
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("Waiting for events ...\n");
 
@@ -4511,5 +4670,5 @@
         }
 
-        if (pCtx->fVerbose)
+        if (pCtx->cVerbose > 1)
             RTPrintf("Signal caught, exiting ...\n");
 
@@ -4547,143 +4706,88 @@
 #endif
 
-    /* pArg->argv[0] contains the VM name. */
-    /* pArg->argv[1] contains the guest control command. */
-    if (pArg->argc < 2)
-        return errorSyntax(USAGE_GUESTCONTROL, "No sub command specified!");
-
-    uint32_t uCmdCtxFlags = 0;
-    uint32_t uUsage;
-    GCTLCMD gctlCmd;
-    if (   !RTStrICmp(pArg->argv[1], "exec")
-        || !RTStrICmp(pArg->argv[1], "execute"))
-    {
-        gctlCmd.pfnHandler = handleCtrlProcessExecDeprecated;
-        uUsage = USAGE_GSTCTRL_EXEC;
-    }
-    else if (!strcmp(pArg->argv[1], "run"))
-    {
-        gctlCmd.pfnHandler = handleCtrlProcessRun;
-        uUsage = USAGE_GSTCTRL_RUN;
-    }
-    else if (!strcmp(pArg->argv[1], "start"))
-    {
-        gctlCmd.pfnHandler = handleCtrlProcessStart;
-        uUsage = USAGE_GSTCTRL_START;
-    }
-    else if (!RTStrICmp(pArg->argv[1], "copyfrom"))
-    {
-        gctlCmd.pfnHandler = handleCtrlCopyFrom;
-        uUsage = USAGE_GSTCTRL_COPYFROM;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "copyto")
-             || !RTStrICmp(pArg->argv[1], "cp"))
-    {
-        gctlCmd.pfnHandler = handleCtrlCopyTo;
-        uUsage = USAGE_GSTCTRL_COPYTO;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "createdirectory")
-             || !RTStrICmp(pArg->argv[1], "createdir")
-             || !RTStrICmp(pArg->argv[1], "mkdir")
-             || !RTStrICmp(pArg->argv[1], "md"))
-    {
-        gctlCmd.pfnHandler = handleCtrlCreateDirectory;
-        uUsage = USAGE_GSTCTRL_CREATEDIR;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "removedirectory")
-             || !RTStrICmp(pArg->argv[1], "removedir")
-             || !RTStrICmp(pArg->argv[1], "rmdir"))
-    {
-        gctlCmd.pfnHandler = handleCtrlRemoveDirectory;
-        uUsage = USAGE_GSTCTRL_REMOVEDIR;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "rm")
-             || !RTStrICmp(pArg->argv[1], "removefile"))
-    {
-        gctlCmd.pfnHandler = handleCtrlRemoveFile;
-        uUsage = USAGE_GSTCTRL_REMOVEFILE;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "ren")
-             || !RTStrICmp(pArg->argv[1], "rename")
-             || !RTStrICmp(pArg->argv[1], "mv"))
-    {
-        gctlCmd.pfnHandler = handleCtrlRename;
-        uUsage = USAGE_GSTCTRL_RENAME;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "createtemporary")
-             || !RTStrICmp(pArg->argv[1], "createtemp")
-             || !RTStrICmp(pArg->argv[1], "mktemp"))
-    {
-        gctlCmd.pfnHandler = handleCtrlCreateTemp;
-        uUsage = USAGE_GSTCTRL_CREATETEMP;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "kill")    /* Linux. */
-             || !RTStrICmp(pArg->argv[1], "pkill")   /* Solaris / *BSD. */
-             || !RTStrICmp(pArg->argv[1], "pskill")) /* SysInternals version. */
-    {
-        /** @todo What about "taskkill" on Windows? */
-        uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
-                     | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
-        gctlCmd.pfnHandler = handleCtrlProcessClose;
-        uUsage = USAGE_GSTCTRL_KILL;
-    }
-    /** @todo Implement "killall"? */
-    else if (   !RTStrICmp(pArg->argv[1], "stat"))
-    {
-        gctlCmd.pfnHandler = handleCtrlStat;
-        uUsage = USAGE_GSTCTRL_STAT;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "updateadditions")
-             || !RTStrICmp(pArg->argv[1], "updateadds"))
-    {
-        uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
-                     | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
-        gctlCmd.pfnHandler = handleCtrlUpdateAdditions;
-        uUsage = USAGE_GSTCTRL_UPDATEADDS;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "list"))
-    {
-        uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
-                     | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
-        gctlCmd.pfnHandler = handleCtrlList;
-        uUsage = USAGE_GSTCTRL_LIST;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "session"))
-    {
-        uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
-                     | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
-        gctlCmd.pfnHandler = handleCtrlSession;
-        uUsage = USAGE_GSTCTRL_SESSION;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "process"))
-    {
-        uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
-                     | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
-        gctlCmd.pfnHandler = handleCtrlProcess;
-        uUsage = USAGE_GSTCTRL_PROCESS;
-    }
-    else if (   !RTStrICmp(pArg->argv[1], "watch"))
-    {
-        uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
-                     | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
-        gctlCmd.pfnHandler = handleCtrlWatch;
-        uUsage = USAGE_GSTCTRL_WATCH;
-    }
-    else
-        return errorSyntax(USAGE_GUESTCONTROL, "Unknown sub command '%s' specified!", pArg->argv[1]);
-
-    GCTLCMDCTX cmdCtx;
-    RT_ZERO(cmdCtx);
-
-    RTEXITCODE rcExit = ctrlInitVM(pArg, &cmdCtx, uCmdCtxFlags, uUsage);
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        /* Kick off the actual command handler. */
-        rcExit = gctlCmd.pfnHandler(&cmdCtx);
-
-        ctrlUninitVM(&cmdCtx, cmdCtx.uFlags);
-        return rcExit;
-    }
-
-    return rcExit;
+    /*
+     * Command definitions.
+     */
+    static const GCTLCMDDEF s_aCmdDefs[] =
+    {
+        { "exec",               gctlHandleProcessExecDeprecated,USAGE_GSTCTRL_EXEC,      0, },
+        { "execute",            gctlHandleProcessExecDeprecated,USAGE_GSTCTRL_EXEC,      0, },
+        { "run",                gctlHandleRun,              USAGE_GSTCTRL_RUN,       0, },
+        { "start",              gctlHandleStart,            USAGE_GSTCTRL_START,     0, },
+        { "copyfrom",           gctlHandleCopyFrom,         USAGE_GSTCTRL_COPYFROM,  0, },
+        { "copyto",             gctlHandleCopyTo,           USAGE_GSTCTRL_COPYTO,    0, },
+        { "cp",                 gctlHandleCopyTo,           USAGE_GSTCTRL_COPYTO,    0, },
+
+        { "mkdir",              handleCtrtMkDir,            USAGE_GSTCTRL_MKDIR,     0, },
+        { "md",                 handleCtrtMkDir,            USAGE_GSTCTRL_MKDIR,     0, },
+        { "createdirectory",    handleCtrtMkDir,            USAGE_GSTCTRL_MKDIR,     0, },
+        { "createdir",          handleCtrtMkDir,            USAGE_GSTCTRL_MKDIR,     0, },
+
+        { "rmdir",              gctlHandleRmDir,            USAGE_GSTCTRL_RMDIR,     0, },
+        { "removedir",          gctlHandleRmDir,            USAGE_GSTCTRL_RMDIR,     0, },
+        { "removedirectory",    gctlHandleRmDir,            USAGE_GSTCTRL_RMDIR,     0, },
+
+        { "rm",                 gctlHandleRm,               USAGE_GSTCTRL_RM,        0, },
+        { "removefile",         gctlHandleRm,               USAGE_GSTCTRL_RM,        0, },
+        { "erase",              gctlHandleRm,               USAGE_GSTCTRL_RM,        0, },
+        { "del",                gctlHandleRm,               USAGE_GSTCTRL_RM,        0, },
+        { "delete",             gctlHandleRm,               USAGE_GSTCTRL_RM,        0, },
+
+        { "mv",                 gctlHandleMv,               USAGE_GSTCTRL_MV,        0, },
+        { "move",               gctlHandleMv,               USAGE_GSTCTRL_MV,        0, },
+        { "ren",                gctlHandleMv,               USAGE_GSTCTRL_MV,        0, },
+        { "rename",             gctlHandleMv,               USAGE_GSTCTRL_MV,        0, },
+
+        { "mktemp",             gctlHandleMkTemp,           USAGE_GSTCTRL_MKTEMP,    0, },
+        { "createtemp",         gctlHandleMkTemp,           USAGE_GSTCTRL_MKTEMP,    0, },
+        { "createtemporary",    gctlHandleMkTemp,           USAGE_GSTCTRL_MKTEMP,    0, },
+
+        { "stat",               gctlHandleStat,             USAGE_GSTCTRL_STAT,      0, },
+
+        /** @todo r=bird: these just work on processes we created, would be better to
+         *        use some different command names here and leave the standard unix
+         *        kill commands for killing/signalling ANY guest process, unix style. */
+        { "closeprocess",       gctlHandleCloseProcess,     USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+        { "kill",               gctlHandleCloseProcess,     USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+        { "pkill",              gctlHandleCloseProcess,     USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+        { "pskill",             gctlHandleCloseProcess,     USAGE_GSTCTRL_CLOSEPROCESS, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+
+        { "closesession",       gctlHandleCloseSession,     USAGE_GSTCTRL_CLOSESESSION, GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+        { "list",               gctlHandleList,             USAGE_GSTCTRL_LIST,         GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+        { "watch",              gctlHandleWatch,            USAGE_GSTCTRL_WATCH,        GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+
+        {"updateguestadditions",gctlHandleUpdateAdditions,  USAGE_GSTCTRL_UPDATEGA,     GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+        { "updateadditions",    gctlHandleUpdateAdditions,  USAGE_GSTCTRL_UPDATEGA,     GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+        { "updatega",           gctlHandleUpdateAdditions,  USAGE_GSTCTRL_UPDATEGA,     GCTLCMDCTX_F_SESSION_ANONYMOUS | GCTLCMDCTX_F_NO_SIGNAL_HANDLER, },
+    };
+
+    /*
+     * Lookup the command and invoke the handler.
+     *
+     * Our Argument expectations:
+     *      argv[0] is the VM name.
+     *      argv[1] is the guest control command.
+     */
+    if (pArg->argc >= 2)
+    {
+        const char *pszCmd = pArg->argv[1];
+        uint32_t    iCmd;
+        for (iCmd = 0; iCmd < RT_ELEMENTS(s_aCmdDefs); iCmd++)
+            if (strcmp(s_aCmdDefs[iCmd].pszName, pszCmd) == 0)
+            {
+                GCTLCMDCTX CmdCtx;
+                RTEXITCODE rcExit = gctrCmdCtxInit(&CmdCtx, pArg, &s_aCmdDefs[iCmd]);
+                if (rcExit == RTEXITCODE_SUCCESS)
+                {
+                    rcExit = s_aCmdDefs[iCmd].pfnHandler(&CmdCtx);
+
+                    gctlCtxTerm(&CmdCtx);
+                }
+                return rcExit;
+            }
+
+        return errorSyntax(USAGE_GUESTCONTROL, "Unknown sub-command: '%s'", pszCmd);
+    }
+    return errorSyntax(USAGE_GUESTCONTROL, "Missing sub-command");
 }
 #endif /* !VBOX_ONLY_DOCS */
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h	(revision 55603)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h	(revision 55604)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2013 Oracle Corporation
+ * Copyright (C) 2013-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -29,7 +29,7 @@
 #include <map>
 
-const char *ctrlFileStatusToText(FileStatus_T enmStatus);
-const char *ctrlProcessStatusToText(ProcessStatus_T enmStatus);
-const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus);
+const char *gctlFileStatusToText(FileStatus_T enmStatus);
+const char *gctlProcessStatusToText(ProcessStatus_T enmStatus);
+const char *gctlGuestSessionStatusToText(GuestSessionStatus_T enmStatus);
 
 using namespace com;
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp	(revision 55603)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp	(revision 55604)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2013 Oracle Corporation
+ * Copyright (C) 2013-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -34,4 +34,12 @@
 #include <vector>
 
+
+
+/*
+ * GuestListenerBase
+ * GuestListenerBase
+ * GuestListenerBase
+ */
+
 GuestListenerBase::GuestListenerBase(void)
     : mfVerbose(false)
@@ -49,4 +57,11 @@
 }
 
+
+
+/*
+ * GuestFileEventListener
+ * GuestFileEventListener
+ * GuestFileEventListener
+ */
 
 GuestFileEventListener::GuestFileEventListener(void)
@@ -86,6 +101,5 @@
 
                 RTPrintf("File ID=%RU32 \"%s\" changed status to [%s]\n",
-                         uID, Utf8Str(strPath).c_str(),
-                         ctrlFileStatusToText(fileSts));
+                         uID, Utf8Str(strPath).c_str(), gctlFileStatusToText(fileSts));
 
             } while (0);
@@ -99,4 +113,11 @@
     return S_OK;
 }
+
+
+/*
+ * GuestProcessEventListener
+ * GuestProcessEventListener
+ * GuestProcessEventListener
+ */
 
 GuestProcessEventListener::GuestProcessEventListener(void)
@@ -136,6 +157,5 @@
 
                 RTPrintf("Process PID=%RU32 \"%s\" changed status to [%s]\n",
-                         uPID, Utf8Str(strPath).c_str(),
-                         ctrlProcessStatusToText(procSts));
+                         uPID, Utf8Str(strPath).c_str(), gctlProcessStatusToText(procSts));
 
             } while (0);
@@ -149,4 +169,11 @@
     return S_OK;
 }
+
+
+/*
+ * GuestSessionEventListener
+ * GuestSessionEventListener
+ * GuestSessionEventListener
+ */
 
 GuestSessionEventListener::GuestSessionEventListener(void)
@@ -356,6 +383,5 @@
 
                 RTPrintf("Session ID=%RU32 \"%s\" changed status to [%s]\n",
-                         uID, Utf8Str(strName).c_str(),
-                         ctrlSessionStatusToText(sessSts));
+                         uID, Utf8Str(strName).c_str(), gctlGuestSessionStatusToText(sessSts));
 
             } while (0);
@@ -369,4 +395,11 @@
     return S_OK;
 }
+
+
+/*
+ * GuestEventListener
+ * GuestEventListener
+ * GuestEventListener
+ */
 
 GuestEventListener::GuestEventListener(void)
@@ -481,4 +514,5 @@
     return S_OK;
 }
+
 #endif /* !VBOX_ONLY_DOCS */
 
