#include "vm_version.h"
#include "vm_tools_version.h"
#include "guestApp.h"
-#include "hgfs.h"
#include "backdoor.h"
#include "backdoor_def.h"
#include "conf.h"
#include "dictll.h"
#include "msg.h"
#include "file.h"
-#include "codeset.h"
#include "posix.h"
#include "vmware/guestrpc/tclodefs.h"
#include <shlobj.h>
#include "productState.h"
#include "winregistry.h"
+#include "win32util.h"
#endif
/*
char *fileName;
};
-/* Function pointer, used in GuestApp_GetConfPath. */
-#if defined(_WIN32)
-typedef HRESULT (WINAPI *PSHGETFOLDERPATH)(HWND, int, HANDLE, DWORD, LPWSTR);
-static PSHGETFOLDERPATH pfnSHGetFolderPath = NULL;
-#endif
-
/*
*----------------------------------------------------------------------
}
-/*
- *----------------------------------------------------------------------
- *
- * GuestApp_WasDictFileChanged --
- *
- * Has the dict file been changed since the last time we loaded
- * or wrote it?
- *
- * Results:
- * TRUE if it has; FALSE if it hasn't
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-GuestApp_WasDictFileChanged(GuestApp_Dict *dict)
-{
- ASSERT(dict);
- ASSERT(dict->fileName);
-
- return (File_GetModTime(dict->fileName) > dict->fileModTime);
-}
-
-
/*
*-----------------------------------------------------------------------------
*
}
-/*
- *----------------------------------------------------------------------
- *
- * GuestApp_GetUnifiedLoopCap --
- *
- * Check to see if the VMX supports TCLO as the medium for
- * updating all the config options.
- *
- * Return value:
- * TRUE: if VMware supports the unified TCLO loop (i.e. can send us options
-
- * via TCLO.
- * FALSE: if VMware doesn't support the unified loop or the rpc failed.
- *
- * Side effects:
- * If channel != NULL, the vmx will start sending options to that channel.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-GuestApp_GetUnifiedLoopCap(const char *channel) // IN: send options to which channel?
-{
- Bool unifiedLoopCap;
-
- if (channel) {
- unifiedLoopCap = RpcOut_sendOne(NULL, NULL,
- "vmx.capability.unified_loop %s",
- channel);
- } else {
- unifiedLoopCap = RpcOut_sendOne(NULL, NULL,
- "vmx.capability.unified_loop");
- }
-
- Debug("Unified loop capability is %d for '%s'\n", unifiedLoopCap,
-
- channel);
-
- return unifiedLoopCap;
-}
-
-
/*
*----------------------------------------------------------------------
*
* The return conf path is a dynamically allocated UTF-8 encoded
* string that should be freed by the caller.
*
- * XXX: Unfortunately, much of this function is duplicated in
- * lib/user/win32util.c because we can't use that file inside guest
- * code. If we do, we'll break Win95 Tools.
- *
- * XXX: For Windows, this function will only fail on pre-2k/Me systems
- * that haven't installed IE4 _and_ haven't ever used our installer
- * (it is thought that the installer will copy shfolder.dll if the
- * system needs it).
- *
* However, the function will also return NULL if we fail to create
* a "VMware/VMware Tools" directory. This can occur if we're not running
* as Administrator, which VMwareUser doesn't. But I believe that
GuestApp_GetConfPath(void)
{
#if defined(_WIN32)
- char *pathUtf8 = NULL;
- char *appFolderPathUtf8 = NULL;
- WCHAR appFolderPath[MAX_PATH] = L"";
- size_t pathUtf8Size = 0;
- const char *productName;
-
- /*
- * XXX: This is racy. But GuestApp_GetInstallPath is racy too. Clearly
- * that is a good enough justification.
- */
-
- if (!pfnSHGetFolderPath) {
- HMODULE h = LoadLibraryW(L"shfolder.dll");
- if (h) {
- pfnSHGetFolderPath = (PSHGETFOLDERPATH)
- GetProcAddress(h, "SHGetFolderPathW");
- }
-
- /* win32util.c avoids calling FreeLibrary() so we will too. */
- }
-
- /*
- * Get the Common Application data folder - create if it doesn't
- * exist.
- */
-
- if (!pfnSHGetFolderPath ||
- FAILED(pfnSHGetFolderPath(NULL, CSIDL_COMMON_APPDATA |
- CSIDL_FLAG_CREATE, NULL, 0, appFolderPath))) {
- return NULL;
- }
+ char *path = W32Util_GetVmwareCommonAppDataFilePath(NULL);
- ASSERT(appFolderPath[0]);
+ if (path != NULL) {
+ char *tmp = Str_SafeAsprintf(NULL, "%s%c%s", path, DIRSEPC,
+ ProductState_GetName());
+ free(path);
+ path = tmp;
- if (!CodeSet_Utf16leToUtf8((const char *)appFolderPath,
- wcslen(appFolderPath) * sizeof *appFolderPath,
- &appFolderPathUtf8,
- NULL)) {
- return NULL;
- }
-
- productName = ProductState_GetName();
-
- /*
- * Make sure there's enought space for
- * appFolderPath\PRODUCT_GENERIC_NAME\PRODUCT_NAME.
- */
-
- pathUtf8Size = strlen(appFolderPathUtf8) + 1 +
- strlen(PRODUCT_GENERIC_NAME) + 1 +
- strlen(productName) + 1;
- pathUtf8 = malloc(pathUtf8Size);
- if (pathUtf8 == NULL) {
- free(appFolderPathUtf8);
- goto error;
- }
-
- Str_Strcpy(pathUtf8, appFolderPathUtf8, pathUtf8Size);
- free(appFolderPathUtf8);
-
- /* Check to see if <product> subdirectories exist. */
- Str_Strcat(pathUtf8, "\\" PRODUCT_GENERIC_NAME, pathUtf8Size);
- if (!File_Exists(pathUtf8)) {
- if (!File_CreateDirectory(pathUtf8)) {
- goto error;
+ if (!File_EnsureDirectory(path)) {
+ free(path);
+ path = NULL;
}
}
- if (!File_IsDirectory(pathUtf8)) {
- goto error;
- }
-
- Str_Strcat(pathUtf8, "\\", MAX_PATH);
- Str_Strcat(pathUtf8, productName, pathUtf8Size);
- if (!File_Exists(pathUtf8)) {
- if (!File_CreateDirectory(pathUtf8)) {
- goto error;
- }
- }
-
- if (!File_IsDirectory(pathUtf8)) {
- goto error;
- }
-
- return pathUtf8;
-
-error:
- free(pathUtf8);
-
- return NULL;
+ return path;
#else
-
/* Just call into GuestApp_GetInstallPath. */
return GuestApp_GetInstallPath();
#endif
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2005 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-
-/*
- * guestAppPosix.c --
- *
- * Utility functions for guest applications, Posix specific implementations.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/wait.h>
-
-#include "guestApp.h"
-#include "str.h"
-#include "vm_assert.h"
-#include "guestAppPosixInt.h"
-
-/*
- * This variable is passed along to g_spawn_sync when launching (for example)
- * a web browser. If NULL, the child will inherit the parent's environment.
- * Users may set it with GuestApp_SetSpawnEnviron.
- */
-const char **guestAppSpawnEnviron = NULL;
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestApp_OpenUrl --
- *
- * Open a web browser on the URL. Copied from apps/vmuiLinux/app.cc
- *
- * Results:
- * TRUE on success, FALSE on otherwise
- *
- * Side effects:
- * Spawns off another process which runs a web browser.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-GuestApp_OpenUrl(const char *url, // IN
- Bool maximize) // IN: open the browser maximized? Ignored for now.
-{
-#ifdef GUESTAPP_HAS_X11
- return GuestAppX11OpenUrl(url, maximize);
-#else
- return FALSE;
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestApp_FindProgram --
- *
- * Find a program using the system path. Copy from apps/vmuiLinux/app.cc
- *
- * Results:
- * TRUE if found, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-GuestApp_FindProgram(const char *program) // IN: Wanted program name
-{
- const char *path = getenv("PATH");
- char *p;
- char fullpath[1000];
-
- for (; path != NULL; path = p == NULL ? p : p + 1) {
- int n;
- p = index(path, ':');
-
- if (p == NULL) { // last component
- n = strlen(path);
- } else {
- n = p - path;
- }
-
- Str_Snprintf(fullpath, sizeof fullpath, "%.*s/%s", n, path, program);
- if (strlen(fullpath) == sizeof fullpath - 1) { // overflow
- continue;
- } else if (access(fullpath, X_OK) != 0) { // no such file or not executable
- continue;
- }
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestApp_SetSpawnEnviron --
- *
- * Records a separate environment used when spawning applications.
- *
- * Results:
- * guestAppSpawnEnviron will point to caller's argument.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-GuestApp_SetSpawnEnviron(const char **spawnEnviron)
- // IN; Environment used when spawning. (Does not involve
- // Barry White, candlelight, etc.)
-{
- guestAppSpawnEnviron = spawnEnviron;
-}
-
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2008 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-
-/*
- * guestAppPosixX11.c --
- *
- * X11-support functions for guestAppPosix.c. These sources maintained
- * separately only to avoid forcing X11 library dependencies where they're
- * not needed.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <sys/wait.h>
-
-#include <stdio.h>
-#include <stdlib.h> // for free, system
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include <glib.h>
-
-#include <X11/Xlib.h>
-#undef Bool
-
-#include "guestApp.h"
-#include "guestAppPosixInt.h"
-#include "str.h"
-#include "escape.h"
-#include "util.h"
-#include "vm_assert.h"
-#include "system.h"
-#include "debug.h"
-
-static const char *gBrowser = NULL; // browser path
-static Bool gBrowserIsMalloced = FALSE;
-static Bool gBrowserIsNewNetscape = FALSE;
-static XErrorHandler gDefaultXErrorHandler;
-
-static void GuestAppDetectBrowser(void);
-static Bool GuestAppFindX11Client(const char *clientName);
-static int GuestAppXErrorHandler(Display *display, XErrorEvent *error_event);
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestAppX11OpenUrl --
- *
- * Open a web browser on the URL. Copied from apps/vmuiLinux/app.cc
- *
- * Results:
- * TRUE on success, FALSE on otherwise
- *
- * Side effects:
- * Spawns off another process which runs a web browser.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-GuestAppX11OpenUrl(const char *url, // IN
- Bool maximize) // IN: open the browser maximized? Ignored for now.
-{
- gboolean spawnSuccess;
- GError *gerror = NULL;
-
- char *argv[4];
- char **parsedArgv = NULL;
- char *newNetscapeBuf = NULL;
- Bool success = FALSE;
-
- ASSERT(url);
-
- if (!gBrowser) {
- GuestAppDetectBrowser();
- }
-
- if (!gBrowser) {
- goto abort;
- }
-
- if (gBrowserIsNewNetscape) {
- /*
- * Per RFC 2616 ยง3.2.1, HTTP places no bound on URIs. (Besides, this url
- * could really be -any- URI.) I.e., that's why I'm eating the cost of
- * allocating memory instead of playing with a static buffer.
- */
- newNetscapeBuf = Str_Asprintf(NULL, "openURL('%s', new-window)", url);
- if (!newNetscapeBuf) {
- goto abort;
- }
- argv[0] = (char *)gBrowser;
- argv[1] = "-remote";
- argv[2] = newNetscapeBuf;
- argv[3] = NULL;
- } else {
- gint argc;
- gboolean parsed;
- /*
- * See GuestAppDetectBrowser(): we already made sure we can parse the
- * command and that it has a placeholder, so just assert that is still
- * the case here.
- */
- parsed = g_shell_parse_argv(gBrowser, &argc, &parsedArgv, NULL);
- ASSERT(parsed);
-
- if (argc > 1) {
- gint i;
-
- for (i = 0; i < argc; i++) {
- if (strcmp(parsedArgv[i], "%s") == 0) {
- g_free(parsedArgv[i]);
- parsedArgv[i] = g_strdup(url);
- break;
- }
- }
- ASSERT(i < argc);
- } else {
- g_strfreev(parsedArgv);
- parsedArgv = NULL;
- argv[0] = (char *)gBrowser;
- argv[1] = (char *)url;
- argv[2] = NULL;
- }
- }
-
- /*
- * Spawn the child and hope for the best. Do not block our UI while the
- * help is showing.
- */
- spawnSuccess = g_spawn_async(NULL, // inherit working directory
- (parsedArgv != NULL) ? parsedArgv : argv,
- /*
- * XXX Please don't hate me for casting off the
- * qualifier here. Glib does -not- modify the
- * environment, at least not in the parent process,
- * but their prototype does not specify this argument
- * as being const.
- */
- (char **)guestAppSpawnEnviron,
- G_SPAWN_SEARCH_PATH
- | G_SPAWN_STDOUT_TO_DEV_NULL
- | G_SPAWN_STDERR_TO_DEV_NULL,
- NULL, // no child setup routine
- NULL, // param for child setup routine
- NULL, // no child pid
- &gerror); // GSpawnError
-
- if (!spawnSuccess) {
- Debug("%s: Unable to launch browser '%s': %d: %s\n", __func__, gBrowser,
- gerror->code, gerror->message);
- g_clear_error(&gerror);
- goto abort;
- }
-
- success = TRUE;
-
-abort:
- g_strfreev(parsedArgv);
- free(newNetscapeBuf);
- return success;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * GuestAppDetectBrowser --
- *
- * Figure out what browser to use, and note if it is a new Netscape.
- * Copied from apps/vmuiLinux/app.cc
- *
- * Results:
- * None.
- *
- * Side effects:
- * This routine is not thread-safe.
- *
- *----------------------------------------------------------------------
- */
-
-void
-GuestAppDetectBrowser(void)
-{
- const char *buf = NULL;
-
- if (gBrowser) {
- if (gBrowserIsMalloced) {
- g_free((void *)gBrowser);
- }
- gBrowser = NULL;
- gBrowserIsMalloced = FALSE;
- gBrowserIsNewNetscape = FALSE;
- }
-
- /*
- * XXX Since splitting guestd and vmware-user, vmware-user may be launched
- * by a -display- manager rather than a session manager, rendering exclusive
- * tests for "GNOME_DESKTOP_SESSION_ID" or "KDE_FULL_SESSION" environment
- * variables insufficient.
- *
- * The workaround (*cough*hack*cough*) for the GNOME case is to additionally
- * query the root X11 window, and testing for the existence of a "gnome-session"
- * window. (The assumption is that if gnome-session is attached to our X11
- * display, the user really is running a GNOME session.) For KDE, we look for
- * "ksmserver".
- *
- * XXX Pull this out s.t. we need only traverse the list of clients once.
- * XXX Added gnome-panel, startkde as they were previously in xautostart.conf.
- * On my Ubuntu VM, gnome-session is really started via a symlink of
- * /usr/bin/x-session-manager -> /etc/alternatives/x-session-manager ->
- * /usr/bin/gnome-session. Gnome-session never sets its window title
- * string, which I assumed it did, and as a result shows up as a client
- * named "x-session-manager". In this case, I'm falling back and
- * using existence of "gnome-panel" as a safe bet that the user is
- * in a GNOME session.
- * XXX This code should be destroyed.
- */
- if ((getenv("GNOME_DESKTOP_SESSION_ID") != NULL ||
- GuestAppFindX11Client("gnome-session") ||
- GuestAppFindX11Client("gnome-panel")) &&
- GuestApp_FindProgram("gconftool-2")) {
- /*
- * XXX: gnome-open is stupid and doesn't work if it receives a "file:" URL
- * with a query string, since it thinks the query string is part of
- * the path and refuses to open the URL. You can get the current browser
- * by using gconftool-2, in which case the string we get will contain
- * a "%s" where the URL should be, which is handled later.
- */
- char *argv[] = {
- "gconftool-2",
- "--get",
- "/desktop/gnome/url-handlers/http/command",
- NULL
- };
- gboolean success;
- gchar *out = NULL;
- gint status;
- GError *err = NULL;
-
- success = g_spawn_sync(NULL,
- argv,
- (char **)guestAppSpawnEnviron,
- G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
- NULL,
- NULL,
- &out,
- NULL,
- &status,
- &err);
-
- /*
- * gconftool-2 exits with a success status when the key we're querying is
- * empty (or doesn't exist?), so make sure the output string is also empty
- * (with no new lines or anything).
- */
- if (out != NULL) {
- g_strchomp(out);
- }
-
- if (!success || !WIFEXITED(status) || WEXITSTATUS(status) != 0 ||
- out == NULL || strlen(out) == 0) {
- Warning("Failed to invoke gconftool-2: exit code %d (%s)\n",
- WEXITSTATUS(status),
- (err != NULL) ? err->message : "");
- g_clear_error(&err);
- g_free(out);
- } else {
- /*
- * We got data from gconftool-2, but it may still be invalid (e.g., the
- * user has configured a browser that doesn't exist). Try to detect
- * that case and fallback to our regular "brute force" detection if
- * we can't use the command.
- */
- int argc = 0;
- char **command = NULL;
- if (g_shell_parse_argv(out, &argc, &command, NULL) && argc > 0) {
- if ((g_path_is_absolute(command[0]) && !access(command[0], X_OK)) ||
- !GuestApp_FindProgram(command[0])) {
- Debug("Cannot find or execute user-defined default browser '%s'.\n",
- command[0]);
- } else {
- /* We expect "%s" to be the URL placeholder. If not found, fall back. */
- gint i;
- for (i = 0; i < argc; i++) {
- if (strcmp(command[i], "%s") == 0) {
- break;
- }
- }
- if (i < argc) {
- buf = out;
- gBrowserIsMalloced = TRUE;
- g_strfreev(command);
- goto exit;
- } else {
- Debug("Browser command (%s) doesn't have an URL placeholder.\n", out);
- }
- }
- } else {
- Debug("Failed to parse custom user-defined browser command (%s).\n", out);
- }
-
- g_free(out);
- g_strfreev(command);
- }
- }
-
- if (((getenv("KDE_FULL_SESSION") != NULL &&
- !strcmp(getenv("KDE_FULL_SESSION"), "true")) ||
- GuestAppFindX11Client("ksmserver") ||
- GuestAppFindX11Client("startkde"))) {
- if (GuestApp_FindProgram("kde-open")) {
- buf = "kde-open";
- goto exit;
- } else if (GuestApp_FindProgram("konqueror")) {
- buf = "konqueror";
- goto exit;
- }
- }
-
- if (GuestApp_FindProgram("mozilla-firefox")) {
- buf = "mozilla-firefox";
- } else if (GuestApp_FindProgram("firefox")) {
- buf = "firefox";
- } else if (GuestApp_FindProgram("mozilla")) {
- buf = "mozilla";
- } else if (GuestApp_FindProgram("netscape")) {
- buf = "netscape";
- } else {
- return;
- }
-
-exit:
- /*
- * netscape >= 6.2 has a bug, in that if we try to reuse an existing
- * window, and fail, it will return a success code. We have to test for this
- * eventuality, so we can handle it better.
- */
- if (!strcmp(buf, "netscape")) {
- gBrowserIsNewNetscape =
- (system("netscape -remote 'openURL(file:/some/bad/path.htm, new-window'") == 0);
- }
- gBrowser = buf;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestAppFindX11Client --
- *
- * Searches for a top-level window names by clientName.
- *
- * Results:
- * TRUE if such a window was found, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-GuestAppFindX11Client(const char *clientName) // IN: window title to search for
-{
- Display *display;
- Window rootWindow;
- Window temp1; // throwaway
- Window temp2; // throwaway
- Window *children = NULL;
- unsigned int nchildren;
- unsigned int i;
- Bool found = FALSE;
-
- if ((display = XOpenDisplay(NULL)) == NULL) {
- return FALSE;
- }
-
- rootWindow = DefaultRootWindow(display);
- /*
- * I want to fall back to the original error handler for all but the BadWindow
- * case. Unfortunately I can't just pass that along, so I need to record the
- * original handler via a global variable.
- */
- gDefaultXErrorHandler = XSetErrorHandler(GuestAppXErrorHandler);
-
- if (XQueryTree(display, rootWindow, &temp1, &temp2, &children, &nchildren) == 0) {
- goto out;
- }
-
- for (i = 0; (i < nchildren) && !found; i++) {
- char *name = NULL;
- if ((XFetchName(display, children[i], &name) == 0) ||
- name == NULL) {
- continue;
- }
- if (strcmp(name, clientName) == 0) {
- found = TRUE;
- }
- XFree(name);
- }
-
-out:
- XFree(children);
- XSetErrorHandler(gDefaultXErrorHandler);
- XCloseDisplay(display);
-
- return found;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestAppXErrorHandler --
- *
- * Silently ignores BadWindow errors, and passes all others back to the
- * default error handler for further processing.
- *
- * Results:
- * Always zero. (Per Xlib, the return value is always ignored.)
- *
- * Side effects:
- * None, except those caused by the default error handler (e.g., killing
- * the client).
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-GuestAppXErrorHandler(Display *display,
- // IN: X11 display on which error occurred
- XErrorEvent *error_event)
- // IN: error received from X11 server
-{
- /* Handoff to the default handler for everything but BadWindow. */
- if ((error_event->error_code != BadWindow) &&
- gDefaultXErrorHandler) {
- gDefaultXErrorHandler(display, error_event);
- }
-
- return 0;
-}
-
-#ifdef __cplusplus
-}
-#endif